/* * env.c - environment variables storage * * Copyright (c) 2007 Sascha Hauer , Pengutronix * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /** * @file * @brief Environment support */ #include #include #include #include #include #include #include #define VARIABLE_D_SIZE(name, value) (sizeof(struct variable_d) + strlen(name) + strlen(value) + 2) static struct env_context *context; /** * Remove a list of environment variables * @param[in] v Variable anchor to remove */ static void free_variables(struct variable_d *v) { struct variable_d *next; while (v) { next = v->next; free(v); v = next; } } /** Read back current context */ struct env_context *get_current_context(void) { return context; } EXPORT_SYMBOL(get_current_context); /** * FIXME */ int env_push_context(void) { struct env_context *c = xzalloc(sizeof(struct env_context)); c->local = xzalloc(VARIABLE_D_SIZE("", "")); c->global = xzalloc(VARIABLE_D_SIZE("", "")); if (!context) { context = c; return 0; } c->parent = context; context = c; return 0; } postcore_initcall(env_push_context); /** * FIXME */ int env_pop_context(void) { struct env_context *c = context; if (context->parent) { c = context->parent; free_variables(context->local); free_variables(context->global); free(context); context = c; return 0; } return -EINVAL; } /** * Return variable's value * @param[in] var Variable of interest * @return Value as text */ char *var_val(struct variable_d *var) { return &var->data[strlen(var->data) + 1]; } /** * Return variable's name * @param[in] var Variable of interest * @return Name as text */ char *var_name(struct variable_d *var) { return var->data; } static const char *getenv_raw(struct variable_d *var, const char *name) { while (var) { if (!strcmp(var_name(var), name)) return var_val(var); var = var->next; } return NULL; } const char *getenv (const char *name) { struct env_context *c; const char *val; if (strchr(name, '.')) { const char *ret = NULL; char *devstr = strdup(name); char *par = strchr(devstr, '.'); struct device_d *dev; *par = 0; dev = get_device_by_name(devstr); if (dev) { par++; ret = dev_get_param(dev, par); } free(devstr); return ret; } c = context; val = getenv_raw(c->local, name); if (val) return val; while (c) { val = getenv_raw(c->global, name); if (val) return val; c = c->parent; } return NULL; } EXPORT_SYMBOL(getenv); static int setenv_raw(struct variable_d *var, const char *name, const char *value) { struct variable_d *newvar = NULL; if (value) { newvar = xzalloc(VARIABLE_D_SIZE(name, value)); strcpy(&newvar->data[0], name); strcpy(&newvar->data[strlen(name) + 1], value); } while (var->next) { if (!strcmp(var->next->data, name)) { if (value) { newvar->next = var->next->next; free(var->next); var->next = newvar; return 0; } else { struct variable_d *tmp; tmp = var->next; var->next = var->next->next; free(tmp); return 0; } } var = var->next; } var->next = newvar; return 0; } int setenv(const char *_name, const char *value) { char *name = strdup(_name); char *par; struct variable_d *var; int ret = 0; if (value && !*value) value = NULL; if ((par = strchr(name, '.'))) { struct device_d *dev; *par++ = 0; dev = get_device_by_name(name); if (dev) ret = dev_set_param(dev, par, value); else ret = -ENODEV; errno = -ret; if (ret < 0) perror("set parameter"); goto out; } if (getenv_raw(context->global, name)) var = context->global; else var = context->local; ret = setenv_raw(var, name, value); out: free(name); return ret; } EXPORT_SYMBOL(setenv); int export(const char *varname) { const char *val = getenv_raw(context->local, varname); if (val) { setenv_raw(context->global, varname, val); setenv_raw(context->local, varname, NULL); } return 0; } EXPORT_SYMBOL(export); void export_env_ull(const char *name, unsigned long long val) { char *valstr = asprintf("%lld", val); setenv(name, valstr); export(name); kfree(valstr); } EXPORT_SYMBOL(export_env_ull); unsigned long long getenv_ull(const char *name) { const char *valstr = getenv(name); if (!valstr) return 0; return simple_strtoull(valstr, NULL, 0); } EXPORT_SYMBOL(getenv_ull);