/* This file is part of Eclat.
Copyright (C) 2012-2018 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 "grecs/opt.h"
#include "wordsplit.h"
#include "libeclat.h"
#include "grecs/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;
struct closure {
char *text;
CURL *curl;
struct grecs_txtacc *acc;
char **argv;
};
static int
is_user_data(const char *s)
{
size_t len;
while (*s == '/')
++s;
len = strlen(s);
while (len > 0 && s[len-1] == '/')
--len;
return len && memcmp(s, "user-data", len) == 0;
}
static char *
read_from(const char *path, CURL *curl, struct grecs_txtacc *acc)
{
char *url;
url = path_concat(base_url, path);
if (instance_store_read(url, curl))
return NULL;
grecs_txtacc_grow_char(acc, 0);
return grecs_txtacc_finish(acc, 0);
}
static void print_dir(const char *path, struct closure *cl);
static void
list(const char *path, struct closure *cl)
{
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 && !is_user_data(ws.ws_wordv[i])) {
if (isroot) {
char *p = path_concat(path,
ws.ws_wordv[i]);
url = path_concat(p, "/");
free(p);
} else if (ws.ws_wordv[i][strlen(ws.ws_wordv[i]) - 1] == '/') {
url = path_concat(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_value *obj;
static char typestr[] = {
[json_null] = '0',
[json_bool] = 'b',
[json_number] = 'n',
[json_string] = 's',
[json_arr] = 'a',
[json_object] = 'o'
};
obj = json_parse_string(text, strlen(text));
if (!obj) {
char *str = NULL;
size_t len = 0;
grecs_asprint_locus(&str, &len, &json_err_locus);
die(EX_DATAERR, "%s: %s", str, json_err_diag);
}
while ((key = *argv++)) {
struct json_value *p;
char *s;
if (print_options & PRINT_NAME)
printf("%s%s", key, delim);
p = json_value_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_object:
printf("object");
break;
}
}
putchar('\n');
}
} else {
printf("%s\n", text);
}
}
static void
ispeek_do(char **argv)
{
struct grecs_txtacc *acc;
CURL *curl;
const char *path = *argv++;
char *text;
acc = grecs_txtacc_create();
curl = instance_store_curl_new(acc);
if (port)
curl_easy_setopt(curl, CURLOPT_PORT, (long) port);
eclat_set_curl_trace(curl, debug_level(0));
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] == '{' || is_user_data(path))
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;
}