diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2014-06-18 15:12:05 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2014-11-06 10:58:54 +0100 |
commit | 3249006a2facd31a072fd2808991697b4727643e (patch) | |
tree | ec4e5dd4fbd1ea124349a23cb3664bda4ba2e1aa /common/globalvar.c | |
parent | fe39e8aadc3e2f3d87bb5b6f8c6ebb4fb1a84253 (diff) | |
download | barebox-3249006a2facd31a072fd2808991697b4727643e.tar.gz barebox-3249006a2facd31a072fd2808991697b4727643e.tar.xz |
Add support for non volatile variables
This adds (back) support for non volatile variables. Non volatile
variables are variables which are stored in the environment over
reboot. They are used in the same way as the global variables, but
with a 'nv' command and device. The variables are stored under
/env/nv/, one variable per file. Adding a nv variable automatically
adds a global variable with the same name. Changing a nv variable
also changes the same global variable, but not the other way round.
This allows for example to configure the username as:
nv user=sha; saveenv
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'common/globalvar.c')
-rw-r--r-- | common/globalvar.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/common/globalvar.c b/common/globalvar.c index c72f147d5f..ec23c24797 100644 --- a/common/globalvar.c +++ b/common/globalvar.c @@ -5,6 +5,9 @@ #include <init.h> #include <environment.h> #include <magicvar.h> +#include <fs.h> +#include <fcntl.h> +#include <libfile.h> #include <generated/utsrelease.h> struct device_d global_device = { @@ -12,6 +15,11 @@ struct device_d global_device = { .id = DEVICE_ID_SINGLE, }; +struct device_d nv_device = { + .name = "nv", + .id = DEVICE_ID_SINGLE, +}; + int globalvar_add(const char *name, int (*set)(struct device_d *dev, struct param_d *p, const char *val), const char *(*get)(struct device_d *, struct param_d *p), @@ -25,6 +33,170 @@ int globalvar_add(const char *name, return 0; } +static int nv_save(const char *name, const char *val) +{ + int fd, ret; + char *fname; + + ret = make_directory("/env/nv"); + if (ret) + return ret; + + fname = asprintf("/env/nv/%s", name); + + fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC); + + free(fname); + + if (fd < 0) + return fd; + + fprintf(fd, "%s", val); + + close(fd); + + return 0; +} + +static int nv_set(struct device_d *dev, struct param_d *p, const char *val) +{ + struct param_d *gp; + int ret; + + if (!val) + val = ""; + + gp = get_param_by_name(&global_device, p->name); + if (!gp) + return -EINVAL; + + ret = gp->set(&global_device, gp, val); + if (ret) + return ret; + + free(p->value); + p->value = xstrdup(val); + + return nv_save(p->name, val); +} + +static const char *nv_get(struct device_d *dev, struct param_d *p) +{ + return p->value ? p->value : ""; +} + +int nvvar_add(const char *name, const char *value) +{ + struct param_d *p, *gp; + int ret; + + gp = get_param_by_name(&nv_device, name); + if (gp) { + ret = dev_set_param(&global_device, name, value); + if (ret) + return ret; + + ret = dev_set_param(&nv_device, name, value); + if (ret) + return ret; + + return 0; + } + + ret = globalvar_add_simple(name, value); + if (ret && ret != -EEXIST) + return ret; + + p = dev_add_param(&nv_device, name, nv_set, nv_get, 0); + if (IS_ERR(p)) + return PTR_ERR(p); + + if (value) { + ret = dev_set_param(&global_device, name, value); + if (ret) + return ret; + } else { + value = dev_get_param(&global_device, name); + if (!value) + value = ""; + } + + p->value = xstrdup(value); + + return nv_save(p->name, value); +} + +int nvvar_remove(const char *name) +{ + struct param_d *p; + char *fname; + + p = get_param_by_name(&nv_device, name); + if (!p) + return -ENOENT; + + fname = asprintf("/env/nv/%s", p->name); + unlink(fname); + free(fname); + + list_del(&p->list); + free(p->name); + free(p); + + return 0; +} + +int nvvar_load(void) +{ + char *val; + int ret; + DIR *dir; + struct dirent *d; + + dir = opendir("/env/nv"); + if (!dir) + return -ENOENT; + + while ((d = readdir(dir))) { + if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) + continue; + + val = read_file_line("/env/nv/%s", d->d_name); + + pr_debug("%s: Setting \"%s\" to \"%s\"\n", + __func__, d->d_name, val); + + ret = nvvar_add(d->d_name, val); + if (ret) + pr_err("failed to create nv variable %s: %s\n", + d->d_name, strerror(-ret)); + } + + closedir(dir); + + return 0; +} + +static void device_param_print(struct device_d *dev) +{ + struct param_d *param; + + list_for_each_entry(param, &dev->parameters, list) { + const char *p = dev_get_param(dev, param->name); + const char *nv = NULL; + + if (dev != &nv_device) + nv = dev_get_param(&nv_device, param->name); + + printf("%s%s: %s\n", nv ? "* " : " ", param->name, p); + } +} + +void nvvar_print(void) +{ + device_param_print(&nv_device); +} + /* * globalvar_get_match * @@ -87,6 +259,7 @@ int globalvar_add_simple(const char *name, const char *value) static int globalvar_init(void) { register_device(&global_device); + register_device(&nv_device); globalvar_add_simple("version", UTS_RELEASE); |