sys: use "Auto-Installed" field for packagelist
[project/rpcd.git] / rc.c
diff --git a/rc.c b/rc.c
index b4787d582b252a0c1ee782dbcc63665ee301ee20..3d192f17a587115b81eeb3b5604d4322cdb5ead7 100644 (file)
--- a/rc.c
+++ b/rc.c
 
 #define RC_LIST_EXEC_TIMEOUT_MS                        3000
 
+enum {
+       RC_LIST_NAME,
+       RC_LIST_SKIP_RUNNING_CHECK,
+       __RC_LIST_MAX
+};
+
+static const struct blobmsg_policy rc_list_policy[] = {
+       [RC_LIST_NAME] = { "name", BLOBMSG_TYPE_STRING },
+       [RC_LIST_SKIP_RUNNING_CHECK] = { "skip_running_check", BLOBMSG_TYPE_BOOL },
+};
+
 enum {
        RC_INIT_NAME,
        RC_INIT_ACTION,
@@ -38,15 +49,18 @@ struct rc_list_context {
        struct ubus_request_data req;
        struct blob_buf *buf;
        DIR *dir;
+       bool skip_running_check;
+       const char *req_name;
 
        /* Info about currently processed init.d entry */
        struct {
                char path[PATH_MAX];
                const char *d_name;
-               unsigned int start;
-               unsigned int stop;
+               int start;
+               int stop;
                bool enabled;
                bool running;
+               bool use_procd;
        } entry;
 };
 
@@ -76,12 +90,13 @@ static void rc_list_add_table(struct rc_list_context *c)
 
        e = blobmsg_open_table(c->buf, c->entry.d_name);
 
-       if (c->entry.start)
+       if (c->entry.start >= 0)
                blobmsg_add_u16(c->buf, "start", c->entry.start);
-       if (c->entry.stop)
+       if (c->entry.stop >= 0)
                blobmsg_add_u16(c->buf, "stop", c->entry.stop);
        blobmsg_add_u8(c->buf, "enabled", c->entry.enabled);
-       blobmsg_add_u8(c->buf, "running", c->entry.running);
+       if (!c->skip_running_check && c->entry.use_procd)
+               blobmsg_add_u8(c->buf, "running", c->entry.running);
 
        blobmsg_close_table(c->buf, e);
 }
@@ -112,6 +127,12 @@ static int rc_list_exec(struct rc_list_context *c, const char *action, uloop_pro
        case -1:
                return -errno;
        case 0:
+               if (c->skip_running_check)
+                       exit(-EFAULT);
+
+               if (!c->entry.use_procd)
+                       exit(-EOPNOTSUPP);
+
                /* Set stdin, stdout & stderr to /dev/null */
                fd = open("/dev/null", O_RDWR);
                if (fd >= 0) {
@@ -163,7 +184,12 @@ static void rc_list_readdir(struct rc_list_context *c)
        FILE *fp;
 
        e = readdir(c->dir);
-       if (!e) {
+       /* 
+        * If scanning for a specific script and entry.d_name is set
+        * we can assume we found a matching one in the previous
+        * iteration since entry.d_name is set only if a match is found.
+        */
+       if (!e || (c->req_name && c->entry.d_name)) {
                closedir(c->dir);
                ubus_send_reply(c->ctx, &c->req, c->buf->head);
                ubus_complete_deferred_request(c->ctx, &c->req, UBUS_STATUS_OK);
@@ -173,7 +199,12 @@ static void rc_list_readdir(struct rc_list_context *c)
        if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, ".."))
                goto next;
 
+       if (c->req_name && strcmp(e->d_name, c->req_name))
+               goto next;
+
        memset(&c->entry, 0, sizeof(c->entry));
+       c->entry.start = -1;
+       c->entry.stop = -1;
 
        snprintf(c->entry.path, sizeof(c->entry.path), "/etc/init.d/%s", e->d_name);
        if (rc_check_script(c->entry.path))
@@ -185,26 +216,34 @@ static void rc_list_readdir(struct rc_list_context *c)
        if (fp) {
                struct stat s;
                char path[PATH_MAX];
-               char line[32];
+               char line[255];
                bool beginning;
+               int count = 0;
 
                beginning = true;
-               while (!c->entry.start && !c->entry.stop && fgets(line, sizeof(line), fp)) {
+               while ((c->entry.start < 0 || c->entry.stop < 0 ||
+                      (!c->skip_running_check && !c->entry.use_procd)) &&
+                      count <= 10 && fgets(line, sizeof(line), fp)) {
                        if (beginning) {
                                if (!strncmp(line, "START=", 6)) {
                                        c->entry.start = strtoul(line + 6, NULL, 0);
                                } else if (!strncmp(line, "STOP=", 5)) {
                                        c->entry.stop = strtoul(line + 5, NULL, 0);
+                               } else if (!c->skip_running_check && !strncmp(line, "USE_PROCD=", 10)) {
+                                       c->entry.use_procd = !!strtoul(line + 10, NULL, 0);
                                }
+                               count++;
                        }
 
                        beginning = !!strchr(line, '\n');
                }
                fclose(fp);
 
-               snprintf(path, sizeof(path), "/etc/rc.d/S%02d%s", c->entry.start, c->entry.d_name);
-               if (!stat(path, &s) && (s.st_mode & S_IXUSR))
-                       c->entry.enabled = true;
+               if (c->entry.start >= 0) {
+                       snprintf(path, sizeof(path), "/etc/rc.d/S%02d%s", c->entry.start, c->entry.d_name);
+                       if (!stat(path, &s) && (s.st_mode & S_IXUSR))
+                               c->entry.enabled = true;
+               }
        }
 
        if (rc_list_exec(c, "running", rc_list_exec_running_cb))
@@ -222,9 +261,12 @@ static int rc_list(struct ubus_context *ctx, struct ubus_object *obj,
                   struct ubus_request_data *req, const char *method,
                   struct blob_attr *msg)
 {
+       struct blob_attr *tb[__RC_LIST_MAX];
        static struct blob_buf buf;
        struct rc_list_context *c;
 
+       blobmsg_parse(rc_list_policy, __RC_LIST_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
+
        blob_buf_init(&buf, 0);
 
        c = calloc(1, sizeof(*c));
@@ -238,6 +280,10 @@ static int rc_list(struct ubus_context *ctx, struct ubus_object *obj,
                free(c);
                return UBUS_STATUS_UNKNOWN_ERROR;
        }
+       if (tb[RC_LIST_SKIP_RUNNING_CHECK])
+               c->skip_running_check = blobmsg_get_bool(tb[RC_LIST_SKIP_RUNNING_CHECK]);
+       if (tb[RC_LIST_NAME])
+               c->req_name = blobmsg_get_string(tb[RC_LIST_NAME]);
 
        ubus_defer_request(ctx, req, &c->req);
 
@@ -345,7 +391,7 @@ static int rc_init(struct ubus_context *ctx, struct ubus_object *obj,
 int rpc_rc_api_init(struct ubus_context *ctx)
 {
        static const struct ubus_method rc_methods[] = {
-               UBUS_METHOD_NOARG("list", rc_list),
+               UBUS_METHOD("list", rc_list, rc_list_policy),
                UBUS_METHOD("init", rc_init, rc_init_policy),
        };