summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2014-04-04 10:06:22 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2014-04-04 10:06:22 +0200
commita5c3b05b4d087a22a72b5d979a7539e3c5be2917 (patch)
treeea30315e0ffb84770631b9b70b7dc0da7dd3c4f0 /common
parent3753efa4271d674d9b3cc77a0e405b38711ac505 (diff)
parent294dc7160e55ffb6b940045fb00f01697dacd660 (diff)
downloadbarebox-a5c3b05b4d087a22a72b5d979a7539e3c5be2917.tar.gz
barebox-a5c3b05b4d087a22a72b5d979a7539e3c5be2917.tar.xz
Merge branch 'for-next/menutree'
Diffstat (limited to 'common')
-rw-r--r--common/Kconfig5
-rw-r--r--common/Makefile1
-rw-r--r--common/hush.c33
-rw-r--r--common/menutree.c181
4 files changed, 219 insertions, 1 deletions
diff --git a/common/Kconfig b/common/Kconfig
index 84c52fc398..0031cc8770 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -62,6 +62,9 @@ config STDDEV
config BAREBOX_UPDATE
bool
+config MENUTREE
+ bool
+
menu "General Settings"
config LOCALVERSION
@@ -602,7 +605,7 @@ config DEFAULT_ENVIRONMENT_GENERIC_NEW
config DEFAULT_ENVIRONMENT_GENERIC_NEW_MENU
bool
depends on DEFAULT_ENVIRONMENT_GENERIC_NEW
- depends on CMD_MENU_MANAGEMENT
+ depends on CMD_MENUTREE
default y
config DEFAULT_ENVIRONMENT_GENERIC_NEW_DFU
diff --git a/common/Makefile b/common/Makefile
index 667c7b36ba..204241c919 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_RESET_SOURCE) += reset_source.o
obj-$(CONFIG_SHELL_HUSH) += hush.o
obj-$(CONFIG_SHELL_SIMPLE) += parser.o
obj-$(CONFIG_UIMAGE) += image.o uimage.o
+obj-$(CONFIG_MENUTREE) += menutree.o
quiet_cmd_pwd_h = PWDH $@
ifdef CONFIG_PASSWORD
diff --git a/common/hush.c b/common/hush.c
index bd534c12f5..1447fdb7f1 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -1637,6 +1637,39 @@ static void update_ifs_map(void)
mapset(ifs, 2); /* also flow through if quoted */
}
+/*
+ * shell_expand - Expand shell variables in a string.
+ * @str: The input string containing shell variables like
+ * $var or ${var}
+ * Return: The expanded string. Must be freed with free().
+ */
+char *shell_expand(char *str)
+{
+ struct p_context ctx = {};
+ o_string o = {};
+ char *res, *parsed;
+
+ remove_quotes_in_str(str);
+
+ o.quote = 1;
+
+ initialize_context(&ctx);
+
+ parse_string(&o, &ctx, str);
+
+ parsed = xmemdup(o.data, o.length + 1);
+ parsed[o.length] = 0;
+
+ res = insert_var_value(parsed);
+ if (res != parsed)
+ free(parsed);
+
+ free_pipe_list(ctx.list_head, 0);
+ b_free(&o);
+
+ return res;
+}
+
/* most recursion does not come through here, the exeception is
* from builtin_source() */
static int parse_stream_outer(struct p_context *ctx, struct in_str *inp, int flag)
diff --git a/common/menutree.c b/common/menutree.c
new file mode 100644
index 0000000000..814512d7b7
--- /dev/null
+++ b/common/menutree.c
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+#include <environment.h>
+#include <libbb.h>
+#include <common.h>
+#include <glob.h>
+#include <menu.h>
+#include <fs.h>
+
+#include <linux/stat.h>
+
+struct menutree {
+ char *action;
+ struct menu_entry me;
+};
+
+static void menutree_action_subdir(struct menu *m, struct menu_entry *me)
+{
+ struct menutree *mt = container_of(me, struct menutree, me);
+
+ menutree(mt->action, 0);
+}
+
+static void menutree_action(struct menu *m, struct menu_entry *me)
+{
+ struct menutree *mt = container_of(me, struct menutree, me);
+
+ run_command(mt->action);
+}
+
+static void setenv_bool(const char *var, bool val)
+{
+ const char *str;
+
+ if (val)
+ str = "1";
+ else
+ str = "0";
+
+ setenv(var, str);
+}
+
+static void menutree_box(struct menu *m, struct menu_entry *me)
+{
+ struct menutree *mt = container_of(me, struct menutree, me);
+
+ setenv_bool(mt->action, me->box_state);
+}
+
+static void menutree_entry_free(struct menu_entry *me)
+{
+ struct menutree *mt = container_of(me, struct menutree, me);
+
+ free(mt->action);
+ free(mt->me.display);
+ free(mt);
+}
+
+/*
+ * menutree - show a menu constructed from a directory structure
+ * @path: the path to the directory structure
+ *
+ * Each menu entry is described by a subdirectory. Each subdirectory
+ * can contain the following files which further describe the entry:
+ *
+ * title - A file containing the title of the entry as shown in the menu
+ * box - If present, the entry is a 'bool' entry. The file contains a variable
+ * name from which the current state of the bool is taken from and saved
+ * to.
+ * action - if present this file contains a shell script which is executed when
+ * when the entry is selected.
+ *
+ * If neither 'box' or 'action' are present this entry is considered a submenu
+ * containing more entries.
+ */
+int menutree(const char *path, int toplevel)
+{
+ int ret;
+ struct menu *menu;
+ struct stat s;
+ char *box;
+ struct menutree *mt;
+ glob_t g;
+ int i;
+ char *globpath, *display;
+
+ menu = menu_alloc();
+
+ globpath = asprintf("%s/*", path);
+ ret = glob(globpath, 0, NULL, &g);
+ free(globpath);
+ if (ret == GLOB_NOMATCH) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ display = read_file_line("%s/title", path);
+ if (!display) {
+ eprintf("no title found in %s/title\n", path);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ menu->display = shell_expand(display);
+ free(display);
+
+ for (i = 0; i < g.gl_pathc; i++) {
+ ret = stat(g.gl_pathv[i], &s);
+ if (ret)
+ goto out;
+
+ if (!S_ISDIR(s.st_mode))
+ continue;
+
+ mt = xzalloc(sizeof(*mt));
+
+ display = read_file_line("%s/title", g.gl_pathv[i]);
+ if (!display) {
+ eprintf("no title found in %s/title\n", g.gl_pathv[i]);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ mt->me.display = shell_expand(display);
+ free(display);
+ mt->me.free = menutree_entry_free;
+
+ box = read_file_line("%s/box", g.gl_pathv[i]);
+ if (box) {
+ mt->me.type = MENU_ENTRY_BOX;
+ mt->me.action = menutree_box;
+ mt->action = box;
+ getenv_bool(box, &mt->me.box_state);
+ menu_add_entry(menu, &mt->me);
+ continue;
+ }
+
+ mt->me.type = MENU_ENTRY_NORMAL;
+
+ mt->action = asprintf("%s/action", g.gl_pathv[i]);
+
+ ret = stat(mt->action, &s);
+ if (ret) {
+ mt->me.action = menutree_action_subdir;
+ free(mt->action);
+ mt->action = xstrdup(g.gl_pathv[i]);
+ } else {
+ mt->me.action = menutree_action;
+ }
+
+ menu_add_entry(menu, &mt->me);
+ }
+
+ if (!toplevel) {
+ mt = xzalloc(sizeof(*mt));
+ mt->me.display = xstrdup("back");
+ mt->me.type = MENU_ENTRY_NORMAL;
+ mt->me.non_re_ent = 1;
+ mt->me.free = menutree_entry_free;
+ menu_add_entry(menu, &mt->me);
+ }
+
+ menu_show(menu);
+
+ ret = 0;
+out:
+ menu_free(menu);
+
+ globfree(&g);
+
+ return ret;
+}