summaryrefslogtreecommitdiffstats
path: root/common/globalvar.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2014-06-18 15:12:05 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2014-11-06 10:58:54 +0100
commit3249006a2facd31a072fd2808991697b4727643e (patch)
treeec4e5dd4fbd1ea124349a23cb3664bda4ba2e1aa /common/globalvar.c
parentfe39e8aadc3e2f3d87bb5b6f8c6ebb4fb1a84253 (diff)
downloadbarebox-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.c173
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);