make procd wait for ubus to come up
[project/procd.git] / service / instance.c
index a01a35a..6dfc61b 100644 (file)
@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <stdint.h>
 #include <fcntl.h>
+#include <pwd.h>
 
 #include <libubox/md5.h>
 
@@ -40,6 +41,7 @@ enum {
        INSTANCE_ATTR_LIMITS,
        INSTANCE_ATTR_WATCH,
        INSTANCE_ATTR_ERROR,
+       INSTANCE_ATTR_USER,
        __INSTANCE_ATTR_MAX
 };
 
@@ -55,6 +57,7 @@ static const struct blobmsg_policy instance_attr[__INSTANCE_ATTR_MAX] = {
        [INSTANCE_ATTR_LIMITS] = { "limits", BLOBMSG_TYPE_TABLE },
        [INSTANCE_ATTR_WATCH] = { "watch", BLOBMSG_TYPE_ARRAY },
        [INSTANCE_ATTR_ERROR] = { "error", BLOBMSG_TYPE_ARRAY },
+       [INSTANCE_ATTR_USER] = { "user", BLOBMSG_TYPE_STRING },
 };
 
 struct instance_netdev {
@@ -158,6 +161,10 @@ instance_run(struct service_instance *in)
                if (fd > STDERR_FILENO)
                        close(fd);
        }
+       if (in->uid || in->gid) {
+               setuid(in->uid);
+               setgid(in->gid);
+       }
        execvp(argv[0], argv);
        exit(127);
 }
@@ -291,6 +298,12 @@ instance_config_changed(struct service_instance *in, struct service_instance *in
        if (in->nice != in_new->nice)
                return true;
 
+       if (in->uid != in_new->uid)
+               return true;
+
+       if (in->gid != in_new->gid)
+               return true;
+
        if (!blobmsg_list_equal(&in->limits, &in_new->limits))
                return true;
 
@@ -359,6 +372,15 @@ instance_file_update(struct blobmsg_list_node *l)
        close(fd);
 }
 
+static void
+instance_fill_any(struct blobmsg_list *l, struct blob_attr *cur)
+{
+       if (!cur)
+               return;
+
+       blobmsg_list_fill(l, blobmsg_data(cur), blobmsg_data_len(cur), false);
+}
+
 static bool
 instance_fill_array(struct blobmsg_list *l, struct blob_attr *cur, blobmsg_update_cb cb, bool array)
 {
@@ -422,9 +444,7 @@ instance_config_parse(struct service_instance *in)
                in->respawn_retry = vals[2];
        }
        if (tb[INSTANCE_ATTR_TRIGGER]) {
-               in->trigger = blob_memdup(tb[INSTANCE_ATTR_TRIGGER]);
-               if (!in->trigger)
-                       return -1;
+               in->trigger = tb[INSTANCE_ATTR_TRIGGER];
                trigger_add(in->trigger, in);
        }
 
@@ -443,10 +463,17 @@ instance_config_parse(struct service_instance *in)
                        return false;
        }
 
-       if (!instance_fill_array(&in->env, tb[INSTANCE_ATTR_ENV], NULL, false))
-               return false;
+       if (tb[INSTANCE_ATTR_USER]) {
+               struct passwd *p = getpwnam(blobmsg_get_string(tb[INSTANCE_ATTR_USER]));
+               if (p) {
+                       in->uid = p->pw_uid;
+                       in->gid = p->pw_gid;
+               }
+       }
+
+       instance_fill_any(&in->data, tb[INSTANCE_ATTR_DATA]);
 
-       if (!instance_fill_array(&in->data, tb[INSTANCE_ATTR_DATA], NULL, false))
+       if (!instance_fill_array(&in->env, tb[INSTANCE_ATTR_ENV], NULL, false))
                return false;
 
        if (!instance_fill_array(&in->netdev, tb[INSTANCE_ATTR_NETDEV], instance_netdev_update, true))
@@ -523,7 +550,6 @@ instance_free(struct service_instance *in)
        uloop_timeout_cancel(&in->timeout);
        trigger_del(in);
        watch_del(in);
-       free(in->trigger);
        instance_config_cleanup(in);
        free(in->config);
        free(in);
@@ -574,6 +600,14 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose)
                blobmsg_close_table(b, e);
        }
 
+       if (!avl_is_empty(&in->data.avl)) {
+               struct blobmsg_list_node *var;
+               void *e = blobmsg_open_table(b, "data");
+               blobmsg_list_for_each(&in->data, var)
+                       blobmsg_add_blob(b, var->data);
+               blobmsg_close_table(b, e);
+       }
+
        if (!avl_is_empty(&in->limits.avl)) {
                struct blobmsg_list_node *var;
                void *e = blobmsg_open_table(b, "limits");