aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2015-01-21 14:53:33 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2015-01-21 14:56:15 +0200
commit03c5b9aac73c6a70b1c67f467bbd484d2a532f10 (patch)
tree33f32c496f86708cce8c6b914a08ece723ba72ee
parent5fe918d1f84af9b1f70deb152bf20d0b8a296524 (diff)
downloadeclat-03c5b9aac73c6a70b1c67f467bbd484d2a532f10.tar.gz
eclat-03c5b9aac73c6a70b1c67f467bbd484d2a532f10.tar.bz2
Improve ispeek
* doc/ispeek.1: Update. * grecs: Upgrade * src/ispeek-cl.opt: New options. * src/ispeek.c: Optionally print variable types, quote strings, etc. Add heuristics to determine whether the obtained data are a directory listing or a text.
-rw-r--r--doc/ispeek.177
m---------grecs0
-rw-r--r--src/ispeek-cl.opt24
-rw-r--r--src/ispeek.c173
4 files changed, 204 insertions, 70 deletions
diff --git a/doc/ispeek.1 b/doc/ispeek.1
index 2cfba44..1ebc9f9 100644
--- a/doc/ispeek.1
+++ b/doc/ispeek.1
@@ -18,11 +18,15 @@
ispeek \- EC2 instance store lister
.SH SYNOPSIS
\fBispeek\fR\
- [\fB\-Ndr\fR]\
+ [\fB\-NQTdr\fR]\
+ [\fB\-D\fR \fISTRING\fR]\
[\fB\-b\fR \fIURL\fR]\
[\fB\-p\fR \fINUMBER\fR]\
- [\fB\-\-no\-names\fR]\
[\fB\-\-base\-url=\fIURL\fR]\
+ [\fB\-\-delimiter=\fISTRING\fR]\
+ [\fB\-\-names\fR]\
+ [\fB\-\-quote\fR]\
+ [\fB\-\-type\fR]\
[\fB\-\-port=\fINUMBER\fR]\
\fIPATH\fR\
[\fIKEY\fR...]
@@ -48,10 +52,6 @@ with \fIKEY\fR and a colon.
The utility must be run from a EC2 instance.
.SH OPTIONS
.TP
-\fB\-N\fR, \fB\-\-no\-names
-Don't print key names. This option takes effect only if at least one
-\fIKEY\fR is given.
-.TP
\fB\-b\fR, \fB\-\-base=\fIURL\fR
Base URL to use, instead of
.BR http://169.254.169.254/latest .
@@ -61,9 +61,41 @@ Increase debugging level.
.TP
\fB\-p\fR, \fB\-\-port=\fINUMBER\fR
Set remote port number, instead of the default \fB80\fR.
+.PP
+Following option applies only when listing directories:
.TP
\fB\-r\fR, \fB\-\-recursive
List directories recursively.
+.PP
+The options below configure output if at least one \fIKEY\fR is given:
+.TP
+\fB\-D\fR, \fB\-\-delimiter=\fISTRING\fR
+Delimit output values with \fISTRING\fR. Default delimiter is a colon.
+.TP
+\fB\-N\fR, \fB\-\-names
+Print key names.
+.TP
+\fB\-Q\fR, \fB\-\-quote\fR
+Quote string values. String values will be enclosed in
+double-quotes. Double-quote and backslash characters appearing within
+strings will be escaped with backslashes.
+.TP
+\fB\-T\fR, \fB\-\-type\fR
+Print type character. Type characters are:
+.BR 0 ,
+for \fBnull\fR values,
+.BR b ,
+for booleans,
+.BR n ,
+for numeric values,
+.BR s ,
+for strings ,
+.BR a ,
+for arrays, and
+.BR o ,
+for objects.
+.PP
+The order of printing is: key name, type, value.
.TP
\fB\-V\fR, \fB\-\-version\fR
Print program version.
@@ -73,6 +105,39 @@ Give a concise help summary.
.TP
\fB\-\-usage\fR
Give a short usage message.
+.SH EXAMPLES
+.SS Get instance ID
+.EX
+$ ispeek /meta-data/instance-id
+i-deadbeef
+.EE
+.SS Print instance data
+.EX
+$ ispeek /dynamic/instance-identity/document
+{
+ "instanceId" : "i-deadbeef",
+ "billingProducts" : null,
+ ...
+.EE
+.SS Read availability region and instance type
+.EX
+$ ispeek /dynamic/instance-identity/document region instanceType
+eu-west-1
+m3.xlarge
+.EE
+.SS Same, including key names and types in the output
+.EX
+$ ispeek -NT /dynamic/instance-identity/document region instanceType
+region:s:eu-west-1
+instanceType:s:m3.xlarge
+.SS Recursively list the contents of \fB/meta\-data/iam\fR:
+.EX
+$ ispeek \-r meta\-data/iam
+/meta-data/iam/info
+/meta-data/iam/security-credentials/
+/meta-data/iam/security-credentials/user
+.EE
+
.SH "SEE ALSO"
.BR eclat (1).
.SH AUTHORS
diff --git a/grecs b/grecs
-Subproject be602072f517f841ee29a76f8119b030ec3d869
+Subproject 7534b68099db68eb3f47c2dbcff51127d7c3e31
diff --git a/src/ispeek-cl.opt b/src/ispeek-cl.opt
index 0762f06..dd0698c 100644
--- a/src/ispeek-cl.opt
+++ b/src/ispeek-cl.opt
@@ -48,10 +48,28 @@ BEGIN
recursive = 1;
END
-OPTION(no-names,N,,
- [<don't print key names>])
+OPTION(names,N,,
+ [<print key names>])
BEGIN
- print_names = 0;
+ print_options |= PRINT_NAME;
+END
+
+OPTION(quote,Q,,
+ [<quote strings>])
+BEGIN
+ print_options |= PRINT_QUOTE;
+END
+
+OPTION(type,T,,
+ [<print value types>])
+BEGIN
+ print_options |= PRINT_TYPE;
+END
+
+OPTION(delimiter,D,STRING,
+ [<use STRING as a delimiter, instead of colon>])
+BEGIN
+ delim = optarg;
END
OPTION(debug,d,,
diff --git a/src/ispeek.c b/src/ispeek.c
index c2e02ab..95e1a4c 100644
--- a/src/ispeek.c
+++ b/src/ispeek.c
@@ -30,7 +30,13 @@
#include "json.h"
const char *base_url = "http://169.254.169.254/latest";
-int print_names = 1;
+
+#define PRINT_QUOTE 0x01
+#define PRINT_TYPE 0x02
+#define PRINT_NAME 0x04
+
+int print_options;
+char *delim = ":";
int recursive;
long port;
@@ -64,20 +70,17 @@ acc_cb(void *ptr, size_t size, size_t nmemb, void *data)
return realsize;
}
-static void
-list(const char *path, CURL *curl, struct grecs_txtacc *acc)
+static char *
+read_from(const char *path, CURL *curl, struct grecs_txtacc *acc)
{
CURLcode res;
long http_resp;
char *text;
char *url;
- struct wordsplit ws;
- size_t i;
- int isroot = strcmp(path, "/") == 0;
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));
@@ -85,7 +88,7 @@ list(const char *path, CURL *curl, struct grecs_txtacc *acc)
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);
@@ -95,13 +98,46 @@ list(const char *path, CURL *curl, struct grecs_txtacc *acc)
case 404:
grecs_txtacc_free_string(acc, text);
- return;
+ 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,
@@ -120,54 +156,31 @@ list(const char *path, CURL *curl, struct grecs_txtacc *acc)
url = make_url(path, ws.ws_wordv[i]);
} else
continue;
- list(url, curl, acc);
+ list(url, cl);
free(url);
}
}
wordsplit_free(&ws);
- grecs_txtacc_free_string(acc, text);
}
static void
-cat(const char *path, CURL *curl, struct grecs_txtacc *acc, char **argv)
+print_file(const char *path, struct closure *cl)
{
- CURLcode res;
- long http_resp;
- char *text;
- char *url;
-
- url = make_url(base_url, path);
- curl_easy_setopt(curl, CURLOPT_URL, url);
+ char *text = cl->text;
+ char **argv = cl->argv;
- 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;
-
- default:
- die(EX_UNAVAILABLE, "CURL: got response %3d, url %s",
- http_resp, url);
- }
- free(url);
-
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,
@@ -178,10 +191,12 @@ cat(const char *path, CURL *curl, struct grecs_txtacc *acc, char **argv)
struct json_object *p;
char *s;
- if (print_names)
- printf("%s:", key);
+ 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");
@@ -194,13 +209,17 @@ cat(const char *path, CURL *curl, struct grecs_txtacc *acc, char **argv)
printf("%e", p->v.n);
break;
case json_string:
- putchar('"');
- for (s = p->v.s; *s; s++) {
- if (*s == '"' || *s == '\\')
- putchar('\\');
- putchar(*s);
- }
- putchar('"');
+ 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");
@@ -208,8 +227,6 @@ cat(const char *path, CURL *curl, struct grecs_txtacc *acc, char **argv)
case json_obj:
printf("object");
break;
- default:
- abort();
}
}
putchar('\n');
@@ -226,23 +243,57 @@ ispeek_do(char **argv)
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);
- if (path[strlen(path) - 1] == '/')
- list(path, curl, acc);
- else
- cat(path, curl, acc, argv);
+ 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);
}

Return to:

Send suggestions and report system problems to the System administrator.