static int package_cmd(int cmd, char *tuple)
{
- struct uci_package *p = NULL;
+ struct uci_package *p;
+ struct uci_section *s;
struct uci_element *e = NULL;
- char *package = NULL;
- char *section = NULL;
- char *option = NULL;
- char **ptr = NULL;
- int ret;
- if (uci_parse_tuple(ctx, tuple, &package, §ion, &option, ptr) != UCI_OK)
- return 1;
- if (section && !section[0])
- return 1;
-
- ret = uci_load(ctx, package, &p);
-
- if (ret != UCI_OK) {
+ if (uci_lookup_ext(ctx, &e, tuple) != UCI_OK) {
cli_perror();
return 1;
}
- if (!p)
+ switch(e->type) {
+ case UCI_TYPE_PACKAGE:
+ p = uci_to_package(e);
+ break;
+ case UCI_TYPE_SECTION:
+ s = uci_to_section(e);
+ p = s->package;
+ break;
+ case UCI_TYPE_OPTION:
+ s = uci_to_option(e)->section;
+ p = s->package;
+ break;
+ default:
return 0;
+ }
+
switch(cmd) {
case CMD_CHANGES:
uci_show_changes(p);
uci_export(ctx, stdout, p, true);
break;
case CMD_SHOW:
- if (!section) {
- uci_show_package(p);
- return 0;
- }
- if (uci_lookup(ctx, &e, p, section, option) != UCI_OK)
- return 1;
-
switch(e->type) {
+ case UCI_TYPE_PACKAGE:
+ uci_show_package(p);
+ break;
case UCI_TYPE_SECTION:
uci_show_section(uci_to_section(e));
break;
static int uci_do_section_cmd(int cmd, int argc, char **argv)
{
struct uci_package *p = NULL;
+ struct uci_section *s = NULL;
struct uci_element *e = NULL;
- char *package = NULL;
char *section = NULL;
char *option = NULL;
char *value = NULL;
- char **ptr = NULL;
int ret = UCI_OK;
if (argc != 2)
return 255;
- switch(cmd) {
- case CMD_SET:
- case CMD_RENAME:
- ptr = &value;
- break;
- default:
- break;
+ value = strchr(argv[1], '=');
+ if (value) {
+ *value = 0;
+ value++;
+ if (!uci_validate_text(value))
+ return 1;
}
- if (uci_parse_tuple(ctx, argv[1], &package, §ion, &option, ptr) != UCI_OK)
- return 1;
- if (section && !section[0])
+
+ if (value && (cmd != CMD_SET) && (cmd != CMD_RENAME))
return 1;
- if (uci_load(ctx, package, &p) != UCI_OK) {
+ if (uci_lookup_ext(ctx, &e, argv[1]) != UCI_OK) {
cli_perror();
return 1;
}
- if (!p)
- return 0;
+
+ switch(e->type) {
+ case UCI_TYPE_SECTION:
+ s = uci_to_section(e);
+ break;
+ case UCI_TYPE_OPTION:
+ option = e->name;
+ s = uci_to_option(e)->section;
+ break;
+ default:
+ return 1;
+ }
+ section = s->e.name;
+ p = s->package;
switch(cmd) {
case CMD_GET:
- if (uci_lookup(ctx, &e, p, section, option) != UCI_OK)
- return 1;
-
switch(e->type) {
case UCI_TYPE_SECTION:
- value = uci_to_section(e)->type;
+ value = s->type;
break;
case UCI_TYPE_OPTION:
value = uci_to_option(e)->value;
break;
default:
- /* should not happen */
- return 1;
+ break;
}
/* throw the value to stdout */
printf("%s\n", value);
return NULL;
}
+int uci_lookup_ext(struct uci_context *ctx, struct uci_element **res, char *ptr)
+{
+ struct uci_package *p = NULL;
+ struct uci_element *e;
+ struct uci_section *s;
+ char *package = NULL;
+ char *section = NULL;
+ char *option = NULL;
+ char *idxstr, *t;
+ int idx, c;
+
+ UCI_HANDLE_ERR(ctx);
+ UCI_ASSERT(ctx, res != NULL);
+ UCI_ASSERT(ctx, ptr != NULL);
+
+ UCI_INTERNAL(uci_parse_tuple, ctx, ptr, &package, §ion, &option, NULL);
+
+ /* look up the package first */
+ e = uci_lookup_list(&ctx->root, package);
+ if (!e) {
+ UCI_INTERNAL(uci_load, ctx, package, &p);
+ if (!p)
+ goto notfound;
+ e = &p->e;
+ } else {
+ p = uci_to_package(e);
+ }
+
+ if (!section)
+ goto done;
+
+ /* if the section name validates as a regular name, pass through
+ * to the regular uci_lookup function call */
+ if (!*section || uci_validate_name(section)) {
+ UCI_INTERNAL(uci_lookup, ctx, &e, p, section, option);
+ goto done;
+ }
+
+ /* name did not validate, that means we have an extended lookup call
+ * parse it here. for now only the section index syntax is supported */
+ if (section[0] != '@')
+ goto error;
+
+ section++;
+
+ /* parse the section index part */
+ idxstr = strchr(section, '[');
+ if (!idxstr)
+ goto error;
+ *idxstr = 0;
+ idxstr++;
+
+ t = strchr(idxstr, ']');
+ if (!t)
+ goto error;
+ if (t[1] != 0)
+ goto error;
+ *t = 0;
+
+ t = NULL;
+ idx = strtol(idxstr, &t, 10);
+ if (t && *t)
+ goto error;
+
+ if (!*section)
+ section = NULL;
+ if (section && !uci_validate_str(section, false))
+ goto error;
+
+ /* if the given index is negative, it specifies the section number from
+ * the end of the list */
+ if (idx < 0) {
+ c = 0;
+ uci_foreach_element(&p->sections, e) {
+ s = uci_to_section(e);
+ if (section && (strcmp(s->type, section) != 0))
+ continue;
+
+ c++;
+ }
+ idx += c;
+ }
+
+ c = 0;
+ uci_foreach_element(&p->sections, e) {
+ s = uci_to_section(e);
+ if (section && (strcmp(s->type, section) != 0))
+ continue;
+
+ if (idx == c)
+ goto found;
+ c++;
+ }
+ goto notfound;
+
+found:
+ if (option)
+ e = uci_lookup_list(&s->options, option);
+done:
+ *res = e;
+ return 0;
+
+notfound:
+ UCI_THROW(ctx, UCI_ERR_NOTFOUND);
+error:
+ UCI_THROW(ctx, UCI_ERR_INVAL);
+ return 0;
+}
+
int uci_lookup(struct uci_context *ctx, struct uci_element **res, struct uci_package *p, const char *section, const char *option)
{
struct uci_element *e;
*/
extern int uci_lookup(struct uci_context *ctx, struct uci_element **res, struct uci_package *package, const char *section, const char *option);
+/**
+ * uci_lookup_ext: Extended lookup for an uci element
+ *
+ * @ctx: uci context
+ * @res: where to store the result
+ * @ptr: uci pointer tuple
+ *
+ * Looks up an element using the extended syntax, which is a superset of what
+ * uci_parse_tuple accepts. It can look up sections by an index with an optional
+ * type.
+ *
+ * Examples:
+ * network.@interface[0].ifname ('ifname' option of the first interface section)
+ * network.@interface[-1] (last interface section)
+ * Note: uci_lookup_ext will automatically load a config package if necessary
+ */
+extern int uci_lookup_ext(struct uci_context *ctx, struct uci_element **res, char *ptr);
+
/**
* uci_add_section: Add an unnamed section
* @ctx: uci context
*/
extern int uci_set_backend(struct uci_context *ctx, const char *name);
+/**
+ * uci_validate_text: validate a value string for uci options
+ * @str: value
+ *
+ * this function checks whether a given string is acceptable as value
+ * for uci options
+ */
+extern bool uci_validate_text(const char *str);
+
/* UCI data structures */
enum uci_type {
UCI_TYPE_HISTORY = 0,
return uci_validate_str(str, true);
}
-static inline bool uci_validate_text(const char *str)
+bool uci_validate_text(const char *str)
{
while (*str) {
if ((*str == '\r') || (*str == '\n') ||
int uci_parse_tuple(struct uci_context *ctx, char *str, char **package, char **section, char **option, char **value)
{
char *last = NULL;
+ bool internal = ctx->internal;
UCI_HANDLE_ERR(ctx);
UCI_ASSERT(ctx, str && package && section && option);
*value = last;
}
- if (*section && *section[0] && !uci_validate_name(*section))
+ if (*section && *section[0] && !internal && !uci_validate_name(*section))
goto error;
if (*option && !uci_validate_name(*option))
goto error;