diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Kconfig | 2 | ||||
-rw-r--r-- | common/environment.c | 4 | ||||
-rw-r--r-- | common/globalvar.c | 134 |
3 files changed, 122 insertions, 18 deletions
diff --git a/common/Kconfig b/common/Kconfig index 832634047f..38225ebe63 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -172,6 +172,7 @@ config NVVAR default y if !SHELL_NONE depends on GLOBALVAR depends on ENV_HANDLING + select FNMATCH help Non volatile environment variables begin with "nv.". They behave like global variables above, but their values are saved in the environment @@ -424,6 +425,7 @@ config MAXARGS config GLOB bool + select FNMATCH prompt "globbing support" help If you want to use wildcards like * or ? say y here. diff --git a/common/environment.c b/common/environment.c index c3ad25266a..db127d71ad 100644 --- a/common/environment.c +++ b/common/environment.c @@ -364,6 +364,10 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags) ret = 0; +#ifdef CONFIG_NVVAR + if (!strcmp(filename, default_environment_path_get())) + nv_var_set_clean(); +#endif out: close(envfd); out1: diff --git a/common/globalvar.c b/common/globalvar.c index c0958e11ea..44e6528f6c 100644 --- a/common/globalvar.c +++ b/common/globalvar.c @@ -9,6 +9,10 @@ #include <fcntl.h> #include <libfile.h> #include <generated/utsrelease.h> +#include <envfs.h> +#include <fnmatch.h> + +static int nv_dirty; struct device_d global_device = { .name = "global", @@ -20,6 +24,11 @@ struct device_d nv_device = { .id = DEVICE_ID_SINGLE, }; +void nv_var_set_clean(void) +{ + nv_dirty = 0; +} + 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), @@ -43,16 +52,16 @@ void globalvar_remove(const char *name) dev_remove_param(param); } -static int nv_save(const char *name, const char *val) +static int __nv_save(const char *prefix, const char *name, const char *val) { int fd, ret; char *fname; - ret = make_directory("/env/nv"); + ret = make_directory(prefix); if (ret) return ret; - fname = basprintf("/env/nv/%s", name); + fname = basprintf("%s/%s", prefix, name); fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC); @@ -68,6 +77,25 @@ static int nv_save(const char *name, const char *val) return 0; } +static int nv_save(const char *name, const char *val) +{ + int ret; + static int once = 1; + + ret = __nv_save("/env/nv", name, val); + if (ret) + return ret; + + if (once) { + pr_info("nv variable modified, will save nv variables on shutdown\n"); + once = 0; + } + + nv_dirty = 1; + + return 0; +} + /** * dev_param_init_from_nv - initialize a device parameter from nv variable * @dev: The device @@ -180,15 +208,26 @@ static int nv_set(struct device_d *dev, struct param_d *p, const char *val) free(p->value); p->value = xstrdup(val); - return nv_save(p->name, val); + return 0; } -static const char *nv_get(struct device_d *dev, struct param_d *p) +static const char *nv_param_get(struct device_d *dev, struct param_d *p) { return p->value ? p->value : ""; } -int nvvar_add(const char *name, const char *value) +static int nv_param_set(struct device_d *dev, struct param_d *p, const char *val) +{ + int ret; + + ret = nv_set(dev, p, val); + if (ret) + return ret; + + return nv_save(p->name, val); +} + +static int __nvvar_add(const char *name, const char *value) { struct param_d *p, *gp; int ret; @@ -226,7 +265,7 @@ int nvvar_add(const char *name, const char *value) return ret; } - p = dev_add_param(&nv_device, name, nv_set, nv_get, 0); + p = dev_add_param(&nv_device, name, nv_param_set, nv_param_get, 0); if (IS_ERR(p)) return PTR_ERR(p); @@ -242,25 +281,36 @@ int nvvar_add(const char *name, const char *value) return nv_set(&nv_device, p, value); } +int nvvar_add(const char *name, const char *value) +{ + int ret; + + ret = __nvvar_add(name, value); + if (ret) + return ret; + + return nv_save(name, value); +} + int nvvar_remove(const char *name) { - struct param_d *p; + struct param_d *p, *tmp; char *fname; if (!IS_ENABLED(CONFIG_NVVAR)) return -ENOSYS; - p = get_param_by_name(&nv_device, name); - if (!p) - return -ENOENT; + list_for_each_entry_safe(p, tmp, &nv_device.parameters, list) { + if (fnmatch(name, p->name, 0)) + continue; - fname = basprintf("/env/nv/%s", p->name); - unlink(fname); - free(fname); + fname = basprintf("/env/nv/%s", p->name); + + dev_remove_param(p); - list_del(&p->list); - free(p->name); - free(p); + unlink(fname); + free(fname); + } return 0; } @@ -288,7 +338,7 @@ int nvvar_load(void) pr_debug("%s: Setting \"%s\" to \"%s\"\n", __func__, d->d_name, val); - ret = nvvar_add(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)); @@ -401,3 +451,51 @@ static int globalvar_init(void) pure_initcall(globalvar_init); BAREBOX_MAGICVAR_NAMED(global_version, global.version, "The barebox version"); + +/** + * nvvar_save - save NV variables to persistent environment + * + * This saves the NV variables to the persisitent environment without saving + * the other files in the environment that might be changed. + */ +int nvvar_save(void) +{ + struct param_d *param; + const char *env = default_environment_path_get(); + int ret; +#define TMPDIR "/.env.tmp" + if (!nv_dirty || !env) + return 0; + + if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT)) + defaultenv_load(TMPDIR, 0); + + envfs_load(env, TMPDIR, 0); + + list_for_each_entry(param, &nv_device.parameters, list) { + ret = __nv_save(TMPDIR "/nv", param->name, + dev_get_param(&nv_device, param->name)); + if (ret) { + pr_err("Cannot save NV var: %s\n", strerror(-ret)); + goto out; + } + } + + envfs_save(env, TMPDIR, 0); +out: + unlink_recursive(TMPDIR, NULL); + + if (!ret) + nv_dirty = 0; + + return ret; +} + +static void nv_exit(void) +{ + if (nv_dirty) + pr_info("nv variables modified, saving them\n"); + + nvvar_save(); +} +predevshutdown_exitcall(nv_exit); |