/* This file is part of Eclat.
Copyright (C) 2012-2015 Sergey Poznyakoff.
Eclat is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
Eclat is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Eclat. If not, see . */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "grecs.h"
#include "grecsopt.h"
#include "wordsplit.h"
#include "libeclat.h"
#include "json.h"
const char *base_url = "http://169.254.169.254/latest";
#define PRINT_QUOTE 0x01
#define PRINT_TYPE 0x02
#define PRINT_NAME 0x04
int print_options;
char *delim = ":";
int recursive;
long port;
static char *
make_url(const char *url, const char *path)
{
char *p;
size_t len = strlen(url);
while (len > 0 && url[len-1] == '/')
--len;
while (*path == '/')
++path;
p = grecs_malloc(len + strlen(path) + 2);
memcpy(p, url, len);
p[len++] = '/';
strcpy(p + len, path);
return p;
}
static size_t
acc_cb(void *ptr, size_t size, size_t nmemb, void *data)
{
size_t realsize = size * nmemb;
struct grecs_txtacc *acc = data;
grecs_txtacc_grow(acc, ptr, realsize);
return realsize;
}
static char *
read_from(const char *path, CURL *curl, struct grecs_txtacc *acc)
{
CURLcode res;
long http_resp;
char *text;
char *url;
url = make_url(base_url, path);
curl_easy_setopt(curl, CURLOPT_URL, url);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
die(EX_UNAVAILABLE, "CURL: %s", curl_easy_strerror(res));
res = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp);
if (res != CURLE_OK)
die(EX_UNAVAILABLE, "CURL: %s", curl_easy_strerror(res));
grecs_txtacc_grow_char(acc, 0);
text = grecs_txtacc_finish(acc, 0);
switch (http_resp) {
case 200:
break;
case 404:
grecs_txtacc_free_string(acc, text);
return NULL;
default:
die(EX_UNAVAILABLE, "CURL: got response %3d, url %s",
http_resp, url);
}
free(url);
return text;
}
struct closure {
char *text;
CURL *curl;
struct grecs_txtacc *acc;
char **argv;
};
static void print_dir(const char *path, struct closure *cl);
static void
list(const char *path, struct closure *cl)
{
char *text;
cl->text = read_from(path, cl->curl, cl->acc);
if (!cl->text)
return;
print_dir(path, cl);
grecs_txtacc_free_string(cl->acc, cl->text);
cl->text = NULL;
}
static void
print_dir(const char *path, struct closure *cl)
{
char *text = cl->text;
char *url;
struct wordsplit ws;
size_t i;
int isroot = strcmp(path, "/") == 0;
ws.ws_delim = "\r\n";
if (wordsplit(text, &ws,
WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_SQUEEZE_DELIMS |
WRDSF_DELIM | WRDSF_SHOWERR | WRDSF_ENOMEMABRT))
exit(EX_UNAVAILABLE);
for (i = 0; i < ws.ws_wordc; i++) {
printf("%s%s\n", path, ws.ws_wordv[i]);
if (recursive) {
if (isroot) {
char *p = make_url(path, ws.ws_wordv[i]);
url = make_url(p, "/");
free(p);
} else if (ws.ws_wordv[i][strlen(ws.ws_wordv[i]) - 1] == '/') {
url = make_url(path, ws.ws_wordv[i]);
} else
continue;
list(url, cl);
free(url);
}
}
wordsplit_free(&ws);
}
static void
print_file(const char *path, struct closure *cl)
{
char *text = cl->text;
char **argv = cl->argv;
if (argv[0]) {
char *key;
struct json_object *obj;
static char typestr[] = {
[json_null] = '0',
[json_bool] = 'b',
[json_number] = 'n',
[json_string] = 's',
[json_arr] = 'a',
[json_obj] = 'o'
};
obj = json_parse_string(text, strlen(text));
if (!obj)
die(EX_DATAERR,
"%s: near %s",
json_err_diag,
json_err_ptr);
while (key = *argv++) {
struct json_object *p;
char *s;
if (print_options & PRINT_NAME)
printf("%s%s", key, delim);
p = json_object_lookup(obj, key);
if (p) {
if (print_options & PRINT_TYPE)
printf("%c%s", typestr[p->type], delim);
switch (p->type) {
case json_null:
printf("null");
break;
case json_bool:
printf("%s",
p->v.b ? "true" : "false");
break;
case json_number:
printf("%e", p->v.n);
break;
case json_string:
if (print_options & PRINT_QUOTE) {
putchar('"');
for (s = p->v.s; *s; s++) {
if (*s == '"' ||
*s == '\\')
putchar('\\');
putchar(*s);
}
putchar('"');
} else
printf("%s", p->v.s);
break;
case json_arr:
printf("array");
break;
case json_obj:
printf("object");
break;
}
}
putchar('\n');
}
} else {
printf("%s\n", text);
}
}
static void
ispeek_do(char **argv)
{
CURLcode res;
struct grecs_txtacc *acc;
CURL *curl;
const char *path = *argv++;
char *text;
curl = curl_easy_init();
if (!curl)
die(EX_UNAVAILABLE, "curl_easy_init failed");
if (port)
curl_easy_setopt(curl, CURLOPT_PORT, (long) port);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
eclat_set_curl_trace(curl, debug_level(0));
acc = grecs_txtacc_create();
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, acc_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, acc);
text = read_from(path, curl, acc);
if (text) {
struct closure clos;
void (*printer)(const char *, struct closure *);
/* Decide how to print the data */
if (text[0] == '{')
printer = print_file;
else {
CURLcode res;
char *url;
res = curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL,
&url);
if (res != CURLE_OK)
die(EX_UNAVAILABLE, "CURL: %s",
curl_easy_strerror(res));
if (url[strlen(url) - 1] == '/') {
if (path[strlen(path) - 1] != '/') {
url = grecs_malloc(strlen(path) + 2);
strcpy(url, path);
strcat(url, "/");
path = url;
}
printer = print_dir;
} else
printer = print_file;
}
clos.text = text;
clos.curl = curl;
clos.acc = acc;
clos.argv = argv;
printer(path, &clos);
}
grecs_txtacc_free(acc);
curl_easy_cleanup(curl);
}
#include "ispeek-cl.h"
int
main(int argc, char **argv)
{
set_program_name(argv[0]);
debug_register("main");
parse_options(&argc, &argv);
if (argc == 0)
die(EX_USAGE, "not enough arguments");
ispeek_do(argv);
return 0;
}