diff options
-rw-r--r-- | lib/Makefile.am | 7 | ||||
-rw-r--r-- | lib/filemap.c | 140 | ||||
-rw-r--r-- | lib/libeclat.h | 42 | ||||
-rw-r--r-- | lib/map.c | 335 | ||||
-rw-r--r-- | src/accfile.c | 1 | ||||
-rw-r--r-- | src/asscaddr.c | 1 | ||||
-rw-r--r-- | src/cmdline.opt | 6 | ||||
-rw-r--r-- | src/config.c | 11 | ||||
-rw-r--r-- | src/dscrinstattr.c | 1 | ||||
-rw-r--r-- | src/dscrinsts.c | 1 | ||||
-rw-r--r-- | src/dscrinststat.c | 3 | ||||
-rw-r--r-- | src/dscrsecgrps.c | 8 | ||||
-rw-r--r-- | src/eclat.c | 4 | ||||
-rw-r--r-- | src/eclat.h | 2 | ||||
-rw-r--r-- | src/getconout.c | 1 | ||||
-rw-r--r-- | src/startinst.c | 1 | ||||
-rw-r--r-- | src/util.c | 30 |
17 files changed, 589 insertions, 5 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 50b28a5..e7b9d20 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -16,6 +16,9 @@ noinst_LIBRARIES=libeclat.a +maps = \ + filemap.c + libeclat_a_SOURCES=\ base64.c\ diag.c\ @@ -26,6 +29,7 @@ libeclat_a_SOURCES=\ forlanlex.l\ hmac_sha1.c\ libeclat.h\ + map.c\ q2url.c\ qaddparm.c\ qcreat.c\ @@ -35,7 +39,8 @@ libeclat_a_SOURCES=\ sha1.c\ sha1.h\ urlencode.c\ - xmltree.c + xmltree.c\ + $(maps) AM_LDFLAGS = $(CURL_LIBS) INCLUDES = -I$(top_srcdir)/grecs/src/ $(CURL_CFLAGS) diff --git a/lib/filemap.c b/lib/filemap.c new file mode 100644 index 0000000..bced0d4 --- /dev/null +++ b/lib/filemap.c @@ -0,0 +1,140 @@ +/* This file is part of Eclat. + Copyright (C) 2012 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 <errno.h> + +struct filemap { + char *name; + FILE *fp; + struct grecs_locus locus; +}; + +static int +filemap_config(int dbg, struct grecs_node *node, void *data) +{ + struct filemap *filemap, **return_filemap = data; + const char *filename; + struct grecs_node *p; + + if (eclat_get_string_node(node, "file", 0, &p)) + return eclat_map_failure; + filemap = grecs_malloc(sizeof(*filemap)); + filemap->name = grecs_strdup(p->v.value->v.string); + filemap->locus = p->locus; + *return_filemap = filemap; + return eclat_map_ok; +} + +static void +filemap_free(int dbg, void *data) +{ + struct filemap *filemap = data; + free(filemap->name); + free(filemap); +} + +static int +filemap_open(int dbg, void *data) +{ + struct filemap *filemap = data; + + filemap->fp = fopen(filemap->name, "r"); + if (!filemap->fp) { + grecs_error(&filemap->locus, errno, "cannot open file"); + return eclat_map_failure; + } + return eclat_map_ok; +} + + +static int +filemap_close(int dbg, void *data) +{ + struct filemap *filemap = data; + fclose(filemap->fp); + return eclat_map_ok; +} + +static void +skipline(FILE *fp) +{ + int c; + + while ((c = getc(fp)) != EOF && c != '\n') + ; +} + +static int +filemap_get(int dbg, void *data, const char *key, char **return_value) +{ + struct filemap *filemap = data; + FILE *fp = filemap->fp; + int line = 0; + int rc, c; + const char *p; + + rewind(fp); + while ((c = getc(fp)) != EOF) { + line++; + while (c != EOF && (c == ' ' || c == '\t')) + c = getc(fp); + if (c == '\n') + continue; + if (c == '#') { + skipline(fp); + continue; + } + if (c == EOF) + break; + + for (p = key; c != EOF && c != ':' && *p == c; p++) + c = getc(fp); + if (c == EOF) + break; + if (c == '\n') + continue; + if (c == ':') + break; + skipline(fp); + } + + if (c == ':') { + struct grecs_txtacc *acc; + + debug(dbg, 2, ("%s:%d: found key", filemap->name, line)); + acc = grecs_txtacc_create(); + while ((c = getc(fp)) != EOF && c != '\n') + grecs_txtacc_grow_char(acc, c); + grecs_txtacc_grow_char(acc, 0); + *return_value = grecs_txtacc_finish(acc, 1); + grecs_txtacc_free(acc); + rc = eclat_map_ok; + } else + rc = eclat_map_not_found; + + return rc; +} + +struct eclat_map_drv eclat_map_drv_file = { + "file", + filemap_config, + filemap_open, + filemap_close, + filemap_get, + filemap_free +}; + diff --git a/lib/libeclat.h b/lib/libeclat.h index 5f37cc9..1f16d5d 100644 --- a/lib/libeclat.h +++ b/lib/libeclat.h @@ -101,6 +101,48 @@ void eclat_partial_tree_data_handler(void *data, const XML_Char *s, int len); void eclat_partial_tree_start_handler(void *data, const XML_Char *name, const XML_Char **atts); void eclat_partial_tree_end_handler(void *data, const XML_Char *name); + +#define ECLAT_MAP_OPEN 0x01 + +struct eclat_map_drv { + const char *name; + int (*map_config)(int, struct grecs_node *, void *); + int (*map_open)(int, void *); + int (*map_close)(int, void *); + int (*map_get)(int, void *, const char *, char **); + void (*map_free)(int, void *); +}; +struct eclat_map { + char *name; + char *keytrans; + struct eclat_map_drv *drv; + void *data; + int flags; +}; + +enum eclat_map_status { + eclat_map_ok, + eclat_map_failure, + eclat_map_not_found +}; +void eclat_map_init(void); +struct eclat_map *eclat_map_lookup(const char *name); +int eclat_map_config(struct grecs_node *node, struct eclat_map **return_map); +void eclat_map_free(struct eclat_map *map); +int eclat_map_open(struct eclat_map *map); +int eclat_map_close(struct eclat_map *map); +int eclat_map_get(struct eclat_map *map, const char *key, char **value); +const char *eclat_map_strerror(int rc); +int eclat_map_drv_register(struct eclat_map_drv *drv); +void eclat_map_foreach(int (*fun)(struct eclat_map *, void *), void *data); +void eclat_map_free_all(void); + +int eclat_get_string_node(struct grecs_node *node, const char *name, + int optional, + struct grecs_node **pret); + +extern struct eclat_map_drv eclat_map_drv_file; + diff --git a/lib/map.c b/lib/map.c new file mode 100644 index 0000000..5a8d2fd --- /dev/null +++ b/lib/map.c @@ -0,0 +1,335 @@ +/* This file is part of Eclat. + Copyright (C) 2012 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 "wordsplit.h" +#include <sysexits.h> +#include <string.h> + +static int map_dbg = -1; +static struct grecs_symtab *openmap_symtab, *mapdrv_symtab; + +void +eclat_map_init() +{ + map_dbg = debug_register("map"); +} + +int +eclat_get_string_node(struct grecs_node *node, const char *name, + int optional, + struct grecs_node **pret) +{ + struct grecs_node *p = grecs_find_node(node->down, name); + + if (!p) { + if (optional) + return eclat_map_not_found; + grecs_error(&node->locus, 0, + "no \"%s\" statement found", name); + return eclat_map_failure; + } + + if (p->type != grecs_node_stmt) { + grecs_error(&p->locus, 0, "must be simple statement"); + return eclat_map_failure; + } + + if (p->v.value->type != GRECS_TYPE_STRING) { + grecs_error(&p->locus, 0, "must be scalar"); + return eclat_map_failure; + } + + *pret = p; + return eclat_map_ok; +} + +static int +drv_copy(void *a, void *b) +{ + struct eclat_map_drv *drva = a; + struct eclat_map_drv *drvb = b; + + *drva = *drvb; + drva->name = strdup(drvb->name); + return drva->name == NULL; +} + +int +eclat_map_drv_register(struct eclat_map_drv *drv) +{ + struct eclat_map_drv *p; + int install; + + if (!mapdrv_symtab) { + mapdrv_symtab = grecs_symtab_create(sizeof(*drv), + NULL, + NULL, + drv_copy, + NULL, + NULL); + if (!mapdrv_symtab) + grecs_alloc_die(); + } + install = 1; + if (!grecs_symtab_lookup_or_install(mapdrv_symtab, drv, &install)) + die(EX_SOFTWARE, "cannot install map"); + return install ? eclat_map_ok : eclat_map_failure; +} + +struct eclat_map * +eclat_map_lookup(const char *name) +{ + struct eclat_map key; + + if (!openmap_symtab) + return NULL; + key.name = (char*) name; + return grecs_symtab_lookup_or_install(openmap_symtab, &key, NULL); +} + +static void +map_free(void *p) +{ + struct eclat_map *map = p; + if (map->flags & ECLAT_MAP_OPEN) + eclat_map_close(map); + if (map->data && map->drv->map_free) + map->drv->map_free(map_dbg, map->data); + free(map->name); + free(map->keytrans); + free(map); +} + +int +eclat_map_config(struct grecs_node *node, struct eclat_map **return_map) +{ + char *mapname; + struct grecs_node *p; + struct eclat_map key, *map; + struct eclat_map_drv dkey, *drv; + int install, rc; + + if (node->v.value->type != GRECS_TYPE_STRING) { + grecs_error(&p->locus, 0, "value must be scalar"); + return eclat_map_failure; + } + + mapname = node->v.value->v.string; + + if (debug_level(map_dbg) > 1) + diag(&node->locus, "debug", "configuring map \"%s\"", + mapname); + map = eclat_map_lookup(mapname); + if (map) { + debug(map_dbg, 1, + ("map \"%s\" already configured", mapname)); + *return_map = map; + return eclat_map_ok; + } + + if (eclat_get_string_node(node, "type", 0, &p)) + return eclat_map_failure; + + dkey.name = p->v.value->v.string; + if (!mapdrv_symtab) { + grecs_error(&p->locus, 0, "no drivers compiled"); + return eclat_map_failure; + } + + drv = grecs_symtab_lookup_or_install(mapdrv_symtab, &dkey, NULL); + if (!drv) { + grecs_error(&p->locus, 0, "no driver for this type"); + return eclat_map_failure; + } + + if (!openmap_symtab) { + openmap_symtab = grecs_symtab_create(sizeof(key), + NULL, + NULL, + NULL, + NULL, + map_free); + if (!openmap_symtab) + grecs_alloc_die(); + } + install = 1; + key.name = (char*) mapname; + map = grecs_symtab_lookup_or_install(openmap_symtab, &key, &install); + if (!map) + die(EX_SOFTWARE, "cannot install map"); + map->drv = drv; + + rc = drv->map_config(map_dbg, node, &map->data); + if (rc != eclat_map_ok) { + grecs_error(&node->locus, 0, "map configration failed"); + eclat_map_free(map); + return eclat_map_failure; + } + + if (eclat_get_string_node(node, "key", 1, &p) == 0) + map->keytrans = grecs_strdup(p->v.value->v.string); + + debug(map_dbg, 1, ("map \"%s\" configured", mapname)); + + *return_map = map; + return eclat_map_ok; +} + +void +eclat_map_free(struct eclat_map *map) +{ + grecs_symtab_remove(openmap_symtab, map); +} + +int +eclat_map_open(struct eclat_map *map) +{ + debug(map_dbg, 1, ("opening map \"%s\"", map->name)); + + if (map->flags & ECLAT_MAP_OPEN) { + debug(map_dbg, 1, ("map \"%s\" already open", map->name)); + return eclat_map_ok; + } + + if (map->drv->map_open(map_dbg, map->data)) { + err("failed to open map %s", map->name); + return eclat_map_failure; + } + + debug(map_dbg, 1, ("map \"%s\" opened successfully", map->name)); + map->flags |= ECLAT_MAP_OPEN; + return eclat_map_ok; +} + +int +eclat_map_close(struct eclat_map *map) +{ + int rc = eclat_map_ok; + + debug(map_dbg, 1, ("closing map \"%s\"", map->name)); + if (!(map->flags & ECLAT_MAP_OPEN)) { + debug(map_dbg, 1, ("map \"%s\" not open", map->name)); + return eclat_map_ok; + } + if (map->drv->map_close) + rc = map->drv->map_close(map_dbg, map->data); + + if (rc == eclat_map_ok) { + debug(map_dbg, 1, + ("map \"%s\" closed successfully", map->name)); + map->flags &= ~ECLAT_MAP_OPEN; + } else + err("failed to close map %s", map->name); + + return rc; +} + +int +eclat_map_get(struct eclat_map *map, const char *key, char **value) +{ + int rc; + struct wordsplit ws; + + debug(map_dbg, 1, + ("looking up \"%s\" in map \"%s\"", key, map->name)); + if (!(map->flags & ECLAT_MAP_OPEN)) { + debug(map_dbg, 1, ("map \"%s\" not open", map->name)); + return eclat_map_failure; + } + + if (map->keytrans) { + const char *kve[5]; + kve[0] = "key"; + kve[1] = key; + kve[2] = "map"; + kve[3] = map->name; + kve[4] = NULL; + + ws.ws_env = kve; + + if (wordsplit(map->keytrans, &ws, + WRDSF_NOSPLIT | WRDSF_NOCMD | + WRDSF_ENV | WRDSF_ENV_KV)) + die(EX_SOFTWARE, "error transforming key: %s", + wordsplit_strerror(&ws)); + debug(map_dbg, 1, + ("transformed key \"%s\" => \"%s\"", + key, ws.ws_wordv[0])); + key = ws.ws_wordv[0]; + } + + rc = map->drv->map_get(map_dbg, map->data, key, value); + + if (map->keytrans) + wordsplit_free(&ws); + + debug(map_dbg, 1, ("result: \"%s\"", eclat_map_strerror(rc))); + if (rc == eclat_map_ok) + debug(map_dbg, 2, ("found value: \"%s\"", *value)); + return rc; +} + +const char * +eclat_map_strerror(int rc) +{ + switch (rc) { + case eclat_map_ok: + return "success"; + case eclat_map_failure: + return "failure"; + case eclat_map_not_found: + return "not found"; + } + return "unknown error"; +} + +struct foreach_closure { + int (*fun)(struct eclat_map *, void *); + void *data; +}; + +static int +map_foreach(void *item, void *data) +{ + struct eclat_map *map = item; + struct foreach_closure *cp = data; + + return cp->fun(map, cp->data); +} + +void +eclat_map_foreach(int (*fun)(struct eclat_map *, void *), void *data) +{ + struct foreach_closure cl; + + if (!openmap_symtab) + return; + + cl.fun = fun; + cl.data = data; + grecs_symtab_enumerate(openmap_symtab, map_foreach, &cl); +} + +void +eclat_map_free_all() +{ + if (openmap_symtab) { + grecs_symtab_free(openmap_symtab); + openmap_symtab = NULL; + } +} + diff --git a/src/accfile.c b/src/accfile.c index 07c9c2e..3aa9bdb 100644 --- a/src/accfile.c +++ b/src/accfile.c @@ -121,6 +121,7 @@ access_file_lookup(const char *filename, grecs_txtacc_grow_char(acc, c); grecs_txtacc_grow_char(acc, 0); *secret_key_ptr = grecs_txtacc_finish(acc, 1); + grecs_txtacc_free(acc); rc = 0; } else rc = 1; diff --git a/src/asscaddr.c b/src/asscaddr.c index a5ba86e..ea4488d 100644 --- a/src/asscaddr.c +++ b/src/asscaddr.c @@ -36,6 +36,7 @@ eclat_associate_address(CURL *curl, int argc, char **argv) q = eclat_query_create(use_ssl ? EC2_QF_HTTPS : 0, endpoint, "/"); eclat_query_add_param(q, "Action", "AssociateAddress"); + translate_ids(1, argv, "InstanceId"); eclat_query_add_param(q, "InstanceId", argv[0]); if (vpc) { eclat_query_add_param(q, "AllocationId", argv[1]); diff --git a/src/cmdline.opt b/src/cmdline.opt index c19f628..94330ff 100644 --- a/src/cmdline.opt +++ b/src/cmdline.opt @@ -132,6 +132,12 @@ BEGIN sort_option = 1; END +OPTION(translate,x,, + [<translate resource IDs>]) +BEGIN + translate_option = 1; +END + GROUP(Preprocessor control) OPTION(include-directory,I,DIR, diff --git a/src/config.c b/src/config.c index 69835b9..7271b36 100644 --- a/src/config.c +++ b/src/config.c @@ -169,6 +169,8 @@ static struct grecs_keyword eclat_kw[] = { grecs_type_string, GRECS_MULT, NULL, 0, cb_define_format }, { "format-file", "file", "Read format from <file>", grecs_type_string, GRECS_DFLT, &format_file }, + { "map", "name: string", "Configure a map", + grecs_type_section, GRECS_INAC }, { NULL } }; @@ -207,6 +209,15 @@ config_finish(struct grecs_node *tree) { struct grecs_node *node; + for (node = tree; node; node = node->next) { + struct eclat_map *map; + + node = grecs_find_node(node, "map"); + if (!node) + break; + eclat_map_config(node, &map); + } + grecs_tree_reduce(tree, eclat_kw, GRECS_AGGR); if (debug_level(ECLAT_DEBCAT_CONF)) { grecs_print_node(tree, GRECS_NODE_FLAG_DEFAULT, stderr); diff --git a/src/dscrinstattr.c b/src/dscrinstattr.c index 543e456..7193bda 100644 --- a/src/dscrinstattr.c +++ b/src/dscrinstattr.c @@ -67,6 +67,7 @@ eclat_describe_instance_attribute(CURL *curl, int argc, char **argv) argc, argv, &i); argv += i; argc -= i; + translate_ids(argc, argv, "InstanceId"); if (argc != 2) die(EX_USAGE, "wrong number of arguments"); diff --git a/src/dscrinsts.c b/src/dscrinsts.c index 145c50d..865c2ce 100644 --- a/src/dscrinsts.c +++ b/src/dscrinsts.c @@ -147,6 +147,7 @@ eclat_describe_instances(CURL *curl, int argc, char **argv) parse_options(argc, argv, &i); argv += i; argc -= i; + translate_ids(argc, argv, "InstanceId"); q = describe_query_create(curl, "DescribeInstances", argc, argv, "InstanceId"); diff --git a/src/dscrinststat.c b/src/dscrinststat.c index 241e9ed..67e761a 100644 --- a/src/dscrinststat.c +++ b/src/dscrinststat.c @@ -27,7 +27,8 @@ eclat_describe_instance_status(CURL *curl, int argc, char **argv) parse_options(argc, argv, &i); argv += i; argc -= i; - + translate_ids(argc, argv, "InstanceId"); + q = describe_query_create(curl, "DescribeInstanceStatus", argc, argv, "InstanceId"); diff --git a/src/dscrsecgrps.c b/src/dscrsecgrps.c index 7049ddb..238c569 100644 --- a/src/dscrsecgrps.c +++ b/src/dscrsecgrps.c @@ -23,13 +23,15 @@ eclat_describe_security_groups(CURL *curl, int argc, char **argv) { int i; struct ec2_query *q; - + const char *resid = name_option ? "GroupName" : "GroupId"; + parse_options(argc, argv, &i); argv += i; argc -= i; - + translate_ids(argc, argv, resid); + q = describe_query_create(curl, "DescribeSecurityGroups", argc, argv, - name_option ? "GroupName" : "GroupId"); + resid); return eclat_send_query(curl, q); } diff --git a/src/eclat.c b/src/eclat.c index f229e77..704ac56 100644 --- a/src/eclat.c +++ b/src/eclat.c @@ -592,6 +592,8 @@ main(int argc, char **argv) proginfo.print_help_hook = listcmd; debug_init(); forlan_init(); + eclat_map_init(); + eclat_map_drv_register(&eclat_map_drv_file); config_init(); parse_options(argc, argv, &index); @@ -706,5 +708,7 @@ main(int argc, char **argv) fputc('\n', stdout); } + eclat_map_free_all(); + exit(rc); } diff --git a/src/eclat.h b/src/eclat.h index a82a28a..f371ea2 100644 --- a/src/eclat.h +++ b/src/eclat.h @@ -45,6 +45,7 @@ extern char *access_file_name; extern char *access_key; extern char *secret_key; extern char *format_file; +extern int translate_option; typedef int (*config_finish_hook_t) (void*); @@ -100,6 +101,7 @@ struct filter_descr *available_filters; void list_filters(FILE *fp); int get_scr_cols(void); +void translate_ids(int argc, char **argv, const char *mapname); int get_access_creds(const char *id, char **access_key_ptr, char **secret_key_ptr); diff --git a/src/getconout.c b/src/getconout.c index a5aab97..5ea5044 100644 --- a/src/getconout.c +++ b/src/getconout.c @@ -34,6 +34,7 @@ eclat_get_console_output(CURL *curl, int argc, char **argv) die(EX_USAGE, "not enough arguments"); else if (i > 1) die(EX_USAGE, "only one argument is allowed"); + translate_ids(argc, argv, "InstanceId"); q = describe_query_create(curl, "GetConsoleOutput", argc, argv, "InstanceId"); diff --git a/src/startinst.c b/src/startinst.c index d284694..3c34526 100644 --- a/src/startinst.c +++ b/src/startinst.c @@ -35,6 +35,7 @@ start_stop_instance(CURL *curl, const char *action, int argc, char **argv) if (argc == 0) die(EX_USAGE, "no instance ids"); + translate_ids(argc, argv, "InstanceId"); q = eclat_query_create(use_ssl ? EC2_QF_HTTPS : 0, endpoint, "/"); eclat_query_add_param(q, "Action", action); @@ -18,6 +18,36 @@ #include <termios.h> #include <sys/ioctl.h> +int translate_option; + +void +translate_ids(int argc, char **argv, const char *mapname) +{ + int i; + struct eclat_map *map; + char *val; + + if (!translate_option) + return; + map = eclat_map_lookup(mapname); + if (!map) + die(EX_UNAVAILABLE, "no such map: %s", mapname); + + if (eclat_map_open(map) != eclat_map_ok) + exit(EX_UNAVAILABLE); + + for (i = 0; i < argc; i++) { + if (!strchr(argv[i], '=')) { + int rc = eclat_map_get(map, argv[i], &val); + if (rc != eclat_map_ok) { + die(EX_UNAVAILABLE, "cannot translate %s: %s", + argv[i], eclat_map_strerror(rc)); + } + argv[i] = val; + } + } +} + int get_scr_cols() { |