diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-01-21 11:05:45 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2015-01-21 11:13:33 +0200 |
commit | 5fe918d1f84af9b1f70deb152bf20d0b8a296524 (patch) | |
tree | bf97fd6460a92260a1f3563c7583febe6ca863d1 | |
parent | f896658fd2c2c2b832536adb8af5ae6789c387a2 (diff) | |
download | eclat-5fe918d1f84af9b1f70deb152bf20d0b8a296524.tar.gz eclat-5fe918d1f84af9b1f70deb152bf20d0b8a296524.tar.bz2 |
Add ispeek.
* src/ispeek.c: New file.
* src/ispeek-cl.opt: New file
* src/Makefile.am: Add ispeek
* src/io.c (dump, eclat_trace_fun): Moved to the library.
(eclat_io_setup): Use eclat_set_curl_trace.
* NEWS: Document ispeek.
* doc/Makefile.inc: Add ispeek.1
* doc/eclat.1man: Mention ispeek(1) in the "see also" section.
* doc/eclat.conf.5: Update.
* doc/ispeek.1: New file.
* lib/Makefile.am (libeclat_a_SOURCES): Add trace.c
* lib/libeclat.h (eclat_trace_fun)
(eclat_set_curl_trace): New proto.
* lib/trace.c: New file.
-rw-r--r-- | NEWS | 6 | ||||
-rw-r--r-- | doc/Makefile.inc | 3 | ||||
-rw-r--r-- | doc/eclat.1man | 7 | ||||
-rw-r--r-- | doc/eclat.conf.5 | 4 | ||||
-rw-r--r-- | doc/ispeek.1 | 97 | ||||
-rw-r--r-- | lib/Makefile.am | 1 | ||||
-rw-r--r-- | lib/libeclat.h | 6 | ||||
-rw-r--r-- | lib/trace.c | 121 | ||||
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/io.c | 95 | ||||
-rw-r--r-- | src/ispeek-cl.opt | 76 | ||||
-rw-r--r-- | src/ispeek.c | 262 |
12 files changed, 585 insertions, 101 deletions
@@ -1,4 +1,4 @@ -Eclat NEWS -- history of user-visible changes. 2015-01-20 +Eclat NEWS -- history of user-visible changes. 2015-01-21 Copyright (C) 2012-2015 Sergey Poznyakoff See the end of file for copying conditions. @@ -55,6 +55,10 @@ If authentication provider is set to "instance-store", its argument specifies IAM role name. The authentication credentials are then taken from the instance store. +* New program: ispeek + +Lists content of the instance store. + Version 1.0, 2013-12-20 diff --git a/doc/Makefile.inc b/doc/Makefile.inc index f777f59..8d9ae4c 100644 --- a/doc/Makefile.inc +++ b/doc/Makefile.inc @@ -59,7 +59,8 @@ MANPAGES1=\ eclat-setsattr.1\ eclat-sg.1\ eclat-start.1\ - eclat-stop.1 + eclat-stop.1\ + ispeek.1 MANPAGES5=\ eclat.conf.5 diff --git a/doc/eclat.1man b/doc/eclat.1man index 5030d7f..50cc3e2 100644 --- a/doc/eclat.1man +++ b/doc/eclat.1man @@ -13,7 +13,7 @@ .\" .\" You should have received a copy of the GNU General Public License .\" along with Eclat. If not, see <http://www.gnu.org/licenses/>. -.TH ECLAT 1 "January 20, 2015" "ECLAT" "Eclat User Reference" +.TH ECLAT 1 "January 21, 2015" "ECLAT" "Eclat User Reference" .SH NAME eclat \- EC2 Command Line Administrator Tool .SH SYNOPSIS @@ -530,13 +530,14 @@ These options are processed before the actual command line options. .SH "SEE ALSO" .BR eclat.conf (5), .so xref.man -.BR forlan (5). +.BR forlan (5), +.BR ispeek (1). .SH AUTHORS Sergey Poznyakoff .SH "BUG REPORTS" Report bugs to <bug\-eclat@gnu.org.ua>. .SH COPYRIGHT -Copyright \(co 2012-2014 Sergey Poznyakoff +Copyright \(co 2012-2015 Sergey Poznyakoff .br .na License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> diff --git a/doc/eclat.conf.5 b/doc/eclat.conf.5 index adf3796..dd9489c 100644 --- a/doc/eclat.conf.5 +++ b/doc/eclat.conf.5 @@ -13,7 +13,7 @@ .\" .\" You should have received a copy of the GNU General Public License .\" along with Eclat. If not, see <http://www.gnu.org/licenses/>. -.TH ECLAT.CONF 5 "January 20, 2015" "ECLAT" "Eclat User Reference" +.TH ECLAT.CONF 5 "January 21, 2015" "ECLAT" "Eclat User Reference" .SH NAME eclat.conf \- configuration file for .BR eclat (1). @@ -914,7 +914,7 @@ Sergey Poznyakoff .SH "BUG REPORTS" Report bugs to <bug\-eclat@gnu.org.ua>. .SH COPYRIGHT -Copyright \(co 2012-2014 Sergey Poznyakoff +Copyright \(co 2012-2015 Sergey Poznyakoff .br .na License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> diff --git a/doc/ispeek.1 b/doc/ispeek.1 new file mode 100644 index 0000000..2cfba44 --- /dev/null +++ b/doc/ispeek.1 @@ -0,0 +1,97 @@ +.\" This file is part of Eclat -*- nroff -*- +.\" 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 <http://www.gnu.org/licenses/>. +.TH INSPEEK 1 "January 21, 2015" "INSPEEK" "Eclat User Reference" +.SH NAME +ispeek \- EC2 instance store lister +.SH SYNOPSIS +\fBispeek\fR\ + [\fB\-Ndr\fR]\ + [\fB\-b\fR \fIURL\fR]\ + [\fB\-p\fR \fINUMBER\fR]\ + [\fB\-\-no\-names\fR]\ + [\fB\-\-base\-url=\fIURL\fR]\ + [\fB\-\-port=\fINUMBER\fR]\ + \fIPATH\fR\ + [\fIKEY\fR...] +.br +\fBispeek\fR\ + [\fB\-Vh\fR]\ + [\fB\-\-help\fR]\ + [\fB\-\-usage\fR]\ + [\fB\-\-version\fR] +.SH DESCRIPTION +Lists contents of the EC2 instance store. The \fIPATH\fR argument +specifies the pathname to list. It is relative to +.BR http://169.254.169.254/latest . +If \fIPATH\fR ends with a slash, it is treated as a directory and +its content is listed. Otherwise, it is treated as a file. +.PP +Optional \fIKEY\fR arguments are allowed when listing content of a +file. If one or more \fIKEY\fRs are given, the file is parsed as +a JSON object. For each \fIKEY\fR, a corresponding value is looked +up in the resulting object and printed on a separate line, prefixed +with \fIKEY\fR and a colon. +.PP +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 . +.TP +\fB\-d\fR, \fB-\-debug\fR +Increase debugging level. +.TP +\fB\-p\fR, \fB\-\-port=\fINUMBER\fR +Set remote port number, instead of the default \fB80\fR. +.TP +\fB\-r\fR, \fB\-\-recursive +List directories recursively. +.TP +\fB\-V\fR, \fB\-\-version\fR +Print program version. +.TP +\fB\-h\fR, \fB\-\-help\fR +Give a concise help summary. +.TP +\fB\-\-usage\fR +Give a short usage message. +.SH "SEE ALSO" +.BR eclat (1). +.SH AUTHORS +Sergey Poznyakoff +.SH "BUG REPORTS" +Report bugs to <bug\-eclat@gnu.org.ua>. +.SH COPYRIGHT +Copyright \(co 2012-2015 Sergey Poznyakoff +.br +.na +License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> +.br +.ad +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. +.\" Local variables: +.\" eval: (add-hook 'write-file-hooks 'time-stamp) +.\" time-stamp-start: ".TH [A-Z_][A-Z0-9_.-]* [0-9] \"" +.\" time-stamp-format: "%:B %:d, %:y" +.\" time-stamp-end: "\"" +.\" time-stamp-line-limit: 20 +.\" end: diff --git a/lib/Makefile.am b/lib/Makefile.am index 428de49..445d949 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -62,6 +62,7 @@ libeclat_a_SOURCES=\ sha1.h\ sha256.c\ sha256.h\ + trace.c\ urlencode.c\ xmltree.c\ $(maps) diff --git a/lib/libeclat.h b/lib/libeclat.h index 2265a7b..4d6882e 100644 --- a/lib/libeclat.h +++ b/lib/libeclat.h @@ -16,6 +16,7 @@ #include <stddef.h> #include <expat.h> +#include <curl/curl.h> #include "grecs.h" extern const char *program_name; @@ -50,6 +51,11 @@ void debug_printf(const char *fmt, ...); int parse_debug_level(const char *arg); int debug_register(char *name); +int eclat_trace_fun(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userp); +void eclat_set_curl_trace(CURL *curl, int lev); + void hmac_sha1(const void *text, size_t textlen, const void *key, size_t keylen, diff --git a/lib/trace.c b/lib/trace.c new file mode 100644 index 0000000..4438822 --- /dev/null +++ b/lib/trace.c @@ -0,0 +1,121 @@ +/* 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 <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include <curl/curl.h> + +static void +dump(const char *text, FILE *stream, unsigned char *ptr, size_t size, int hex) +{ + size_t i; + size_t c; + unsigned int width = 0x10; + + if (!hex) + /* without the hex output, we can fit more on screen */ + width = 0x40; + + fprintf(stream, "%s, %zd bytes (0x%zx)\n", text, size, size); + + for (i = 0; i < size; i += width) { + fprintf(stream, "%04zx: ", i); + + if (hex) { + for (c = 0; c < width; c++) + if (i+c < size) + fprintf(stream, "%02x ", ptr[i+c]); + else + fputs(" ", stream); + } + + for (c = 0; (c < width) && (i+c < size); c++) { + /* check for CRLf; if found, skip past and start a + new line of output */ + if (!hex && (i + c + 1 < size) && + ptr[i+c] == '\r' && ptr[i+c+1] == '\n') { + i += (c + 2 -width); + break; + } + fprintf(stream, "%c", + isprint(ptr[i+c]) ? ptr[i+c] : '.'); + /* check again for CRLF, to avoid an extra \n if + it's at width */ + if (!hex && (i + c + 2 < size) && + ptr[i+c+1] == '\r' && ptr[i+c+2] == '\n') { + i += (c + 3 - width); + break; + } + } + fputc('\n', stream); + } + fflush(stream); +} + +int +eclat_trace_fun(CURL *handle, curl_infotype type, + char *data, size_t size, + void *userp) +{ + int hex; + const char *text; + + hex = !!userp; + + switch (type) { + case CURLINFO_TEXT: + fprintf(stderr, "== Info: %s", data); + default: /* in case a new one is introduced to shock us */ + return 0; + + case CURLINFO_HEADER_OUT: + text = "=> Send header"; + break; + case CURLINFO_DATA_OUT: + text = "=> Send data"; + break; + case CURLINFO_SSL_DATA_OUT: + text = "=> Send SSL data"; + break; + case CURLINFO_HEADER_IN: + text = "<= Recv header"; + break; + case CURLINFO_DATA_IN: + text = "<= Recv data"; + break; + case CURLINFO_SSL_DATA_IN: + text = "<= Recv SSL data"; + break; + } + + dump(text, stderr, (unsigned char *)data, size, hex); + return 0; +} + +void +eclat_set_curl_trace(CURL *curl, int lev) +{ + if (lev == 0) + curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); + else { + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + if (lev > 1) { + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, + eclat_trace_fun); + if (lev > 2) + curl_easy_setopt(curl, CURLOPT_DEBUGDATA, 1L); + } + } +} diff --git a/src/Makefile.am b/src/Makefile.am index 1c83ec2..0cd910e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,7 +14,7 @@ # You should have received a copy of the GNU General Public License # along with Eclat. If not, see <http://www.gnu.org/licenses/>. -bin_PROGRAMS=eclat +bin_PROGRAMS=eclat ispeek eclat_SOURCES=\ accfile.c\ @@ -66,6 +66,10 @@ eclat_SOURCES=\ startstop.c\ util.c +ispeek_SOURCES = \ + ispeek.c\ + ispeek-cl.h + LDADD=../lib/libeclat.a @LIBOBJS@ ../grecs/src/libgrecs.a $(CURL_LIBS) @MAPLIBS@ AM_CPPFLAGS = \ -I$(top_srcdir)/grecs/src/ -I$(top_srcdir)/lib $(CURL_CFLAGS)\ @@ -103,12 +107,14 @@ eclat_SOURCES += $(OPTFILES:.opt=.h) BUILT_SOURCES=\ cmdline.h\ + ispeek-cl.h\ $(OPTFILES:.opt=.h)\ comtab.man\ xref.man EXTRA_DIST=\ cmdline.opt\ + ispeek-cl.opt\ $(OPTFILES)\ comtab.man\ xref.man\ @@ -1,5 +1,5 @@ /* This file is part of Eclat. - Copyright (C) 2012-2014 Sergey Poznyakoff. + 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 @@ -20,92 +20,6 @@ extern FILE *xml_dump_file; static void -dump(const char *text, FILE *stream, unsigned char *ptr, size_t size) -{ - size_t i; - size_t c; - unsigned int width = 0x10; - int hex = debug_level(ECLAT_DEBCAT_CURL) > 2; - - if (!hex) - /* without the hex output, we can fit more on screen */ - width = 0x40; - - fprintf(stream, "%s, %zd bytes (0x%zx)\n", text, size, size); - - for (i = 0; i < size; i += width) { - fprintf(stream, "%04zx: ", i); - - if (hex) { - for (c = 0; c < width; c++) - if (i+c < size) - fprintf(stream, "%02x ", ptr[i+c]); - else - fputs(" ", stream); - } - - for(c = 0; (c < width) && (i+c < size); c++) { - /* check for CRLf; if found, skip past and start a - new line of output */ - if (!hex && (i + c + 1 < size) && - ptr[i+c] == '\r' && ptr[i+c+1] == '\n') { - i += (c + 2 -width); - break; - } - fprintf(stream, "%c", - isprint(ptr[i+c]) ? ptr[i+c] : '.'); - /* check again for CRLF, to avoid an extra \n if - it's at width */ - if (!hex && (i + c + 2 < size) && - ptr[i+c+1] == '\r' && ptr[i+c+2] == '\n') { - i += (c + 3 - width); - break; - } - } - fputc('\n', stream); /* newline */ - } - fflush(stream); -} - -int -eclat_trace_fun(CURL *handle, curl_infotype type, - char *data, size_t size, - void *userp) -{ -/* struct data *config = (struct data *)userp;*/ - const char *text; - - switch (type) { - case CURLINFO_TEXT: - fprintf(stderr, "== Info: %s", data); - default: /* in case a new one is introduced to shock us */ - return 0; - - case CURLINFO_HEADER_OUT: - text = "=> Send header"; - break; - case CURLINFO_DATA_OUT: - text = "=> Send data"; - break; - case CURLINFO_SSL_DATA_OUT: - text = "=> Send SSL data"; - break; - case CURLINFO_HEADER_IN: - text = "<= Recv header"; - break; - case CURLINFO_DATA_IN: - text = "<= Recv data"; - break; - case CURLINFO_SSL_DATA_IN: - text = "<= Recv SSL data"; - break; - } - - dump(text, stderr, (unsigned char *)data, size); - return 0; -} - -static void dumpxml(void *ptr, size_t realsize) { static int open_failed = 0; @@ -163,12 +77,7 @@ eclat_io_setup(struct eclat_io *io, int errfatal) } } - if (debug_level(ECLAT_DEBCAT_CURL)) { - curl_easy_setopt(io->curl, CURLOPT_VERBOSE, 1L); - if (debug_level(ECLAT_DEBCAT_CURL) > 1) - curl_easy_setopt(io->curl, CURLOPT_DEBUGFUNCTION, - eclat_trace_fun); - } + eclat_set_curl_trace(io->curl, debug_level(ECLAT_DEBCAT_CURL)); /* Create XML parser */ io->parser = XML_ParserCreate("UTF-8"); diff --git a/src/ispeek-cl.opt b/src/ispeek-cl.opt new file mode 100644 index 0000000..0762f06 --- /dev/null +++ b/src/ispeek-cl.opt @@ -0,0 +1,76 @@ +/* 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 <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_GETOPT_H +# include <getopt.h> +#endif + +OPTIONS_BEGIN("ispeek", + [<EC2 instance store lister>], + [<PATH [KEY...]>], + [<gnu>], + [<copyright_year=2012-2015>], + [<copyright_holder=Sergey Poznyakoff>]) + +OPTION(base,b,URL, + [<base URL>]) +BEGIN + base_url = optarg; +END + +OPTION(port,p,NUMBER, + [<set remote port number>]) +BEGIN + char *p; + + errno = 0; + port = strtol(optarg, &p, 10); + if (port <= 0 || port > USHRT_MAX || errno || *p) + die(EX_USAGE, "invalid port number"); +END + +OPTION(recursive,r,, + [<list recursively>]) +BEGIN + recursive = 1; +END + +OPTION(no-names,N,, + [<don't print key names>]) +BEGIN + print_names = 0; +END + +OPTION(debug,d,, + [<increase debugging level>]) +BEGIN + debug_category[0].level++; +END + +OPTIONS_END + +static void +parse_options(int *pargc, char **pargv[]) +{ + int argc = *pargc; + char **argv = *pargv; + int index; + + GETOPT(argc, argv, index) + *pargc -= index; + *pargv += index; +} + diff --git a/src/ispeek.c b/src/ispeek.c new file mode 100644 index 0000000..c2e02ab --- /dev/null +++ b/src/ispeek.c @@ -0,0 +1,262 @@ +/* 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 <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <sysexits.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <curl/curl.h> +#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"; +int print_names = 1; +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 void +list(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)); + + 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); + + 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, curl, acc); + 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) +{ + 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; + + default: + die(EX_UNAVAILABLE, "CURL: got response %3d, url %s", + http_resp, url); + } + free(url); + + if (argv[0]) { + char *key; + struct json_object *obj; + + 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_names) + printf("%s:", key); + p = json_object_lookup(obj, key); + if (p) { + 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: + putchar('"'); + for (s = p->v.s; *s; s++) { + if (*s == '"' || *s == '\\') + putchar('\\'); + putchar(*s); + } + putchar('"'); + break; + case json_arr: + printf("array"); + break; + case json_obj: + printf("object"); + break; + default: + abort(); + } + } + 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++; + + curl = curl_easy_init(); + if (!curl) + die(EX_UNAVAILABLE, "curl_easy_init failed"); + if (port) + curl_easy_setopt(curl, CURLOPT_PORT, (long) port); + 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); + 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; +} |