Search code examples
copenwrt

UCI C API - How to work with list options


Using UCI we can retrieve entire lists with the following command:

$ uci get system.ntp.server

This would read the kind of configuration below:

config system
    option hostname 'OpenWrt'
    option timezone 'UTC'

config timeserver 'ntp'
    list server '0.openwrt.pool.ntp.org'
    list server '1.openwrt.pool.ntp.org'
    list server '2.openwrt.pool.ntp.org'
    list server '3.openwrt.pool.ntp.org'
    option enabled '1'
    option enable_server '0'

That returns all the ntp servers in one long string fine.

0.openwrt.pool.ntp.org 1.openwrt.pool.ntp.org 2.openwrt.pool.ntp.org 3.openwrt.pool.ntp.org

I wish to achieve the same (or equivalent) using the C api.

I put together the following code:

#include <uci.h>
#include <string.h>
void main()
{
    //char path[] = "system.ntp.enabled";
    char path[] = "system.ntp.server";
    char buffer[80];
    get_config_entry(path, &buffer);
    printf("%s\n", buffer);

}

int get_config_entry (char *path, char *buffer)
{
  struct uci_context *c;
  struct uci_ptr ptr;

  c = uci_alloc_context ();
  if (uci_lookup_ptr (c, &ptr, path, true) != UCI_OK)
    {
      uci_perror (c, "XXX");
      return 1;
    }

  strcpy(buffer, ptr.o->v.string);
  uci_free_context (c);
  return 0;
}

Running this just returns garbage in the output string.

How should I deal with list content using UCI C API?


Solution

  • If a list element is requested it is stored in v.list not v.string.

    I found the uci_show_value function in the uci cli code which helped a lot. I have managed to get the following code to work well with list options.

    #include <uci.h>
    #include <string.h>
    
    static const char *delimiter = " ";
    
    static void uci_show_value(struct uci_option *o)
    {
        struct uci_element *e;
        bool sep = false;
    
        switch(o->type) {
        case UCI_TYPE_STRING:
            printf("%s\n", o->v.string);
            break;
        case UCI_TYPE_LIST:
            uci_foreach_element(&o->v.list, e) {
                printf("%s%s", (sep ? delimiter : ""), e->name);
                sep = true;
            }
            printf("\n");
            break;
        default:
            printf("<unknown>\n");
            break;
        }
    }
    
    int show_config_entry (char *path)
    {
      struct uci_context *c;
      struct uci_ptr ptr;
    
      c = uci_alloc_context ();
      if (uci_lookup_ptr (c, &ptr, path, true) != UCI_OK)
        {
          uci_perror (c, "get_config_entry Error");
          return 1;
        }
    
      uci_show_value(ptr.o);
      uci_free_context (c);
      return 0;
    }
    
    void main()
    {
        char path[] = "system.ntp.server";
        show_config_entry(path);
    
    }