From c4e0057fa78ebb524b9241ad7245fcd1074ba414 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:19 -0600 Subject: env: Refactor do_apply to a flag Use a flag in hsearch_r for insert mode passed from import to allow the behavior be different based on use. Now that "do_check" is called for all imports, ensure console init is complete before updating the console on relocation import Signed-off-by: Joe Hershberger --- lib/hashtable.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'lib/hashtable.c') diff --git a/lib/hashtable.c b/lib/hashtable.c index 94a7b61717a..f0056acf6cd 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -142,7 +142,7 @@ int hcreate_r(size_t nel, struct hsearch_data *htab) * be freed and the local static variable can be marked as not used. */ -void hdestroy_r(struct hsearch_data *htab, int do_apply) +void hdestroy_r(struct hsearch_data *htab) { int i; @@ -156,10 +156,7 @@ void hdestroy_r(struct hsearch_data *htab, int do_apply) for (i = 1; i <= htab->size; ++i) { if (htab->table[i].used > 0) { ENTRY *ep = &htab->table[i].entry; - if (do_apply && htab->apply != NULL) { - /* deletion is always forced */ - htab->apply(ep->key, ep->data, NULL, H_FORCE); - } + free((void *)ep->key); free(ep->data); } @@ -251,7 +248,7 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval, } int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, - struct hsearch_data *htab) + struct hsearch_data *htab, int flag) { unsigned int hval; unsigned int count; @@ -404,7 +401,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, * do that. */ -int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply) +int hdelete_r(const char *key, struct hsearch_data *htab, int flag) { ENTRY e, *ep; int idx; @@ -413,15 +410,21 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int do_apply) e.key = (char *)key; - if ((idx = hsearch_r(e, FIND, &ep, htab)) == 0) { + idx = hsearch_r(e, FIND, &ep, htab, 0); + if (idx == 0) { __set_errno(ESRCH); return 0; /* not found */ } + /* Check for permission */ + if (htab->apply != NULL && + htab->apply(ep->key, ep->data, NULL, flag)) { + __set_errno(EPERM); + return 0; + } + /* free used ENTRY */ debug("hdelete: DELETING key \"%s\"\n", key); - if (do_apply && htab->apply != NULL) - htab->apply(ep->key, ep->data, NULL, H_FORCE); free((void *)ep->key); free(ep->data); htab->table[idx].used = -1; @@ -674,7 +677,7 @@ static int drop_var_from_set(const char *name, int nvars, char * vars[]) int himport_r(struct hsearch_data *htab, const char *env, size_t size, const char sep, int flag, - int nvars, char * const vars[], int do_apply) + int nvars, char * const vars[]) { char *data, *sp, *dp, *name, *value; char *localvars[nvars]; @@ -704,7 +707,7 @@ int himport_r(struct hsearch_data *htab, debug("Destroy Hash Table: %p table = %p\n", htab, htab->table); if (htab->table) - hdestroy_r(htab, do_apply); + hdestroy_r(htab); } /* @@ -770,7 +773,7 @@ int himport_r(struct hsearch_data *htab, if (!drop_var_from_set(name, nvars, localvars)) continue; - if (hdelete_r(name, htab, do_apply) == 0) + if (hdelete_r(name, htab, flag) == 0) debug("DELETE ERROR ##############################\n"); continue; @@ -795,14 +798,14 @@ int himport_r(struct hsearch_data *htab, e.data = value; /* if there is an apply function, check what it has to say */ - if (do_apply && htab->apply != NULL) { + if (htab->apply != NULL) { debug("searching before calling cb function" " for %s\n", name); /* * Search for variable in existing env, so to pass * its previous value to the apply callback */ - hsearch_r(e, FIND, &rv, htab); + hsearch_r(e, FIND, &rv, htab, 0); debug("previous value was %s\n", rv ? rv->data : ""); if (htab->apply(name, rv ? rv->data : NULL, value, flag)) { @@ -812,7 +815,7 @@ int himport_r(struct hsearch_data *htab, } } - hsearch_r(e, ENTER, &rv, htab); + hsearch_r(e, ENTER, &rv, htab, flag); if (rv == NULL) { printf("himport_r: can't insert \"%s=%s\" into hash table\n", name, value); @@ -839,7 +842,7 @@ int himport_r(struct hsearch_data *htab, * b) if the variable was not present in current env, we notify * it might be a typo */ - if (hdelete_r(localvars[i], htab, do_apply) == 0) + if (hdelete_r(localvars[i], htab, flag) == 0) printf("WARNING: '%s' neither in running nor in imported env!\n", localvars[i]); else printf("WARNING: '%s' not in imported env, deleting it!\n", localvars[i]); -- cgit v1.2.3 From 3d3b52f2586a8bf1c53496547062594fd4386454 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:20 -0600 Subject: env: Consolidate common code in hsearch_r() The same chunk of code was replicated in two places and the following changes will make that chunk grow a bit, so combine into a static func. Signed-off-by: Joe Hershberger --- lib/hashtable.c | 71 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 34 deletions(-) (limited to 'lib/hashtable.c') diff --git a/lib/hashtable.c b/lib/hashtable.c index f0056acf6cd..f4d57950591 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -247,6 +247,34 @@ int hmatch_r(const char *match, int last_idx, ENTRY ** retval, return 0; } +/* + * Compare an existing entry with the desired key, and overwrite if the action + * is ENTER. This is simply a helper function for hsearch_r(). + */ +static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, + ENTRY **retval, struct hsearch_data *htab, int flag, + unsigned int hval, unsigned int idx) +{ + if (htab->table[idx].used == hval + && strcmp(item.key, htab->table[idx].entry.key) == 0) { + /* Overwrite existing value? */ + if ((action == ENTER) && (item.data != NULL)) { + free(htab->table[idx].entry.data); + htab->table[idx].entry.data = strdup(item.data); + if (!htab->table[idx].entry.data) { + __set_errno(ENOMEM); + *retval = NULL; + return 0; + } + } + /* return found entry */ + *retval = &htab->table[idx].entry; + return idx; + } + /* keep searching */ + return -1; +} + int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, struct hsearch_data *htab, int flag) { @@ -255,6 +283,7 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, unsigned int len = strlen(item.key); unsigned int idx; unsigned int first_deleted = 0; + int ret; /* Compute an value for the given string. Perhaps use a better method. */ hval = len; @@ -286,23 +315,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, && !first_deleted) first_deleted = idx; - if (htab->table[idx].used == hval - && strcmp(item.key, htab->table[idx].entry.key) == 0) { - /* Overwrite existing value? */ - if ((action == ENTER) && (item.data != NULL)) { - free(htab->table[idx].entry.data); - htab->table[idx].entry.data = - strdup(item.data); - if (!htab->table[idx].entry.data) { - __set_errno(ENOMEM); - *retval = NULL; - return 0; - } - } - /* return found entry */ - *retval = &htab->table[idx].entry; - return idx; - } + ret = _compare_and_overwrite_entry(item, action, retval, htab, + flag, hval, idx); + if (ret != -1) + return ret; /* * Second hash function: @@ -328,23 +344,10 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, break; /* If entry is found use it. */ - if ((htab->table[idx].used == hval) - && strcmp(item.key, htab->table[idx].entry.key) == 0) { - /* Overwrite existing value? */ - if ((action == ENTER) && (item.data != NULL)) { - free(htab->table[idx].entry.data); - htab->table[idx].entry.data = - strdup(item.data); - if (!htab->table[idx].entry.data) { - __set_errno(ENOMEM); - *retval = NULL; - return 0; - } - } - /* return found entry */ - *retval = &htab->table[idx].entry; - return idx; - } + ret = _compare_and_overwrite_entry(item, action, retval, + htab, flag, hval, idx); + if (ret != -1) + return ret; } while (htab->table[idx].used); } -- cgit v1.2.3 From 7afcf3a55b5f484b3d3442053fae8186a3fb92d7 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:21 -0600 Subject: env: Refactor apply into change_ok Move the read of the old value to inside the check function. In some cases it can be avoided all together and at the least the code is only called from one place. Also name the function and the callback to more clearly describe what it does. Pass the ENTRY instead of just the name for direct access to the whole data structure. Pass an enum to the callback that specifies the operation being approved. Signed-off-by: Joe Hershberger --- lib/hashtable.c | 70 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 43 insertions(+), 27 deletions(-) (limited to 'lib/hashtable.c') diff --git a/lib/hashtable.c b/lib/hashtable.c index f4d57950591..6861a42029c 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -66,12 +66,16 @@ * Instead the interface of all functions is extended to take an argument * which describes the current status. */ + typedef struct _ENTRY { int used; ENTRY entry; } _ENTRY; +static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, + int idx); + /* * hcreate() */ @@ -259,6 +263,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, && strcmp(item.key, htab->table[idx].entry.key) == 0) { /* Overwrite existing value? */ if ((action == ENTER) && (item.data != NULL)) { + /* check for permission */ + if (htab->change_ok != NULL && htab->change_ok( + &htab->table[idx].entry, item.data, + env_op_overwrite, flag)) { + debug("change_ok() rejected setting variable " + "%s, skipping it!\n", item.key); + __set_errno(EPERM); + *retval = NULL; + return 0; + } + free(htab->table[idx].entry.data); htab->table[idx].entry.data = strdup(item.data); if (!htab->table[idx].entry.data) { @@ -383,6 +398,17 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, ++htab->filled; + /* check for permission */ + if (htab->change_ok != NULL && htab->change_ok( + &htab->table[idx].entry, item.data, env_op_create, flag)) { + debug("change_ok() rejected setting variable " + "%s, skipping it!\n", item.key); + _hdelete(item.key, htab, &htab->table[idx].entry, idx); + __set_errno(EPERM); + *retval = NULL; + return 0; + } + /* return new entry */ *retval = &htab->table[idx].entry; return 1; @@ -404,6 +430,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, * do that. */ +static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, + int idx) +{ + /* free used ENTRY */ + debug("hdelete: DELETING key \"%s\"\n", key); + free((void *)ep->key); + free(ep->data); + htab->table[idx].used = -1; + + --htab->filled; +} + int hdelete_r(const char *key, struct hsearch_data *htab, int flag) { ENTRY e, *ep; @@ -420,19 +458,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag) } /* Check for permission */ - if (htab->apply != NULL && - htab->apply(ep->key, ep->data, NULL, flag)) { + if (htab->change_ok != NULL && + htab->change_ok(ep, NULL, env_op_delete, flag)) { + debug("change_ok() rejected deleting variable " + "%s, skipping it!\n", key); __set_errno(EPERM); return 0; } - /* free used ENTRY */ - debug("hdelete: DELETING key \"%s\"\n", key); - free((void *)ep->key); - free(ep->data); - htab->table[idx].used = -1; - - --htab->filled; + _hdelete(key, htab, ep, idx); return 1; } @@ -800,24 +834,6 @@ int himport_r(struct hsearch_data *htab, e.key = name; e.data = value; - /* if there is an apply function, check what it has to say */ - if (htab->apply != NULL) { - debug("searching before calling cb function" - " for %s\n", name); - /* - * Search for variable in existing env, so to pass - * its previous value to the apply callback - */ - hsearch_r(e, FIND, &rv, htab, 0); - debug("previous value was %s\n", rv ? rv->data : ""); - if (htab->apply(name, rv ? rv->data : NULL, - value, flag)) { - debug("callback function refused to set" - " variable %s, skipping it!\n", name); - continue; - } - } - hsearch_r(e, ENTER, &rv, htab, flag); if (rv == NULL) { printf("himport_r: can't insert \"%s=%s\" into hash table\n", -- cgit v1.2.3 From be11235ab802844e12d84921a38fd8ae4ddda080 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:23 -0600 Subject: env: Hide '.' variables in env print by default When printing all variables with env print, don't print variables that begin with '.'. If env print is called with a '-a' switch, then include variables that begin with '.' (just like the ls command). Variables printed explicitly will be printed even without the -a. Signed-off-by: Joe Hershberger --- lib/hashtable.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib/hashtable.c') diff --git a/lib/hashtable.c b/lib/hashtable.c index 6861a42029c..7c6b96cac87 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -522,7 +522,7 @@ static int cmpkey(const void *p1, const void *p2) return (strcmp(e1->key, e2->key)); } -ssize_t hexport_r(struct hsearch_data *htab, const char sep, +ssize_t hexport_r(struct hsearch_data *htab, const char sep, int flag, char **resp, size_t size, int argc, char * const argv[]) { @@ -559,6 +559,9 @@ ssize_t hexport_r(struct hsearch_data *htab, const char sep, if ((argc > 0) && (found == 0)) continue; + if ((flag & H_HIDE_DOT) && ep->key[0] == '.') + continue; + list[n++] = ep; totlen += strlen(ep->key) + 2; -- cgit v1.2.3 From 170ab11075d3be56e89d6444abf1148329130f4b Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:24 -0600 Subject: env: Add support for callbacks to environment vars Add support for per-variable callbacks to the "hashtable" functions. Signed-off-by: Joe Hershberger !!!fix comment in callback --- lib/hashtable.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 4 deletions(-) (limited to 'lib/hashtable.c') diff --git a/lib/hashtable.c b/lib/hashtable.c index 7c6b96cac87..e9226665f34 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -54,7 +54,8 @@ #define CONFIG_ENV_MAX_ENTRIES 512 #endif -#include "search.h" +#include +#include /* * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 @@ -274,6 +275,17 @@ static inline int _compare_and_overwrite_entry(ENTRY item, ACTION action, return 0; } + /* If there is a callback, call it */ + if (htab->table[idx].entry.callback && + htab->table[idx].entry.callback(item.key, + item.data, env_op_overwrite, flag)) { + debug("callback() rejected setting variable " + "%s, skipping it!\n", item.key); + __set_errno(EINVAL); + *retval = NULL; + return 0; + } + free(htab->table[idx].entry.data); htab->table[idx].entry.data = strdup(item.data); if (!htab->table[idx].entry.data) { @@ -398,6 +410,9 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, ++htab->filled; + /* This is a new entry, so look up a possible callback */ + env_callback_init(&htab->table[idx].entry); + /* check for permission */ if (htab->change_ok != NULL && htab->change_ok( &htab->table[idx].entry, item.data, env_op_create, flag)) { @@ -409,6 +424,18 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, return 0; } + /* If there is a callback, call it */ + if (htab->table[idx].entry.callback && + htab->table[idx].entry.callback(item.key, item.data, + env_op_create, flag)) { + debug("callback() rejected setting variable " + "%s, skipping it!\n", item.key); + _hdelete(item.key, htab, &htab->table[idx].entry, idx); + __set_errno(EINVAL); + *retval = NULL; + return 0; + } + /* return new entry */ *retval = &htab->table[idx].entry; return 1; @@ -437,6 +464,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, debug("hdelete: DELETING key \"%s\"\n", key); free((void *)ep->key); free(ep->data); + ep->callback = NULL; htab->table[idx].used = -1; --htab->filled; @@ -466,6 +494,15 @@ int hdelete_r(const char *key, struct hsearch_data *htab, int flag) return 0; } + /* If there is a callback, call it */ + if (htab->table[idx].entry.callback && + htab->table[idx].entry.callback(key, NULL, env_op_delete, flag)) { + debug("callback() rejected deleting variable " + "%s, skipping it!\n", key); + __set_errno(EINVAL); + return 0; + } + _hdelete(key, htab, ep, idx); return 1; @@ -838,11 +875,9 @@ int himport_r(struct hsearch_data *htab, e.data = value; hsearch_r(e, ENTER, &rv, htab, flag); - if (rv == NULL) { + if (rv == NULL) printf("himport_r: can't insert \"%s=%s\" into hash table\n", name, value); - return 0; - } debug("INSERT: table %p, filled %d/%d rv %p ==> name=\"%s\" value=\"%s\"\n", htab, htab->filled, htab->size, @@ -873,3 +908,27 @@ int himport_r(struct hsearch_data *htab, debug("INSERT: done\n"); return 1; /* everything OK */ } + +/* + * hwalk_r() + */ + +/* + * Walk all of the entries in the hash, calling the callback for each one. + * this allows some generic operation to be performed on each element. + */ +int hwalk_r(struct hsearch_data *htab, int (*callback)(ENTRY *)) +{ + int i; + int retval; + + for (i = 1; i <= htab->size; ++i) { + if (htab->table[i].used > 0) { + retval = callback(&htab->table[i].entry); + if (retval) + return retval; + } + } + + return 0; +} -- cgit v1.2.3 From 2598090b7e17f8bdca95b22e7f27217054730e02 Mon Sep 17 00:00:00 2001 From: Joe Hershberger Date: Tue, 11 Dec 2012 22:16:31 -0600 Subject: env: Add environment variable flags Currently just validates variable types as decimal, hexidecimal, boolean, ip address, and mac address. If the entry is not found in the env ".flags", then look in the static one. This allows the env to override the static definitions, but prevents the need to have every definition in the environment distracting you. Signed-off-by: Joe Hershberger --- lib/hashtable.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/hashtable.c') diff --git a/lib/hashtable.c b/lib/hashtable.c index e9226665f34..07ebfb218f8 100644 --- a/lib/hashtable.c +++ b/lib/hashtable.c @@ -55,6 +55,7 @@ #endif #include +#include #include /* @@ -412,6 +413,8 @@ int hsearch_r(ENTRY item, ACTION action, ENTRY ** retval, /* This is a new entry, so look up a possible callback */ env_callback_init(&htab->table[idx].entry); + /* Also look for flags */ + env_flags_init(&htab->table[idx].entry); /* check for permission */ if (htab->change_ok != NULL && htab->change_ok( @@ -465,6 +468,7 @@ static void _hdelete(const char *key, struct hsearch_data *htab, ENTRY *ep, free((void *)ep->key); free(ep->data); ep->callback = NULL; + ep->flags = 0; htab->table[idx].used = -1; --htab->filled; -- cgit v1.2.3