• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/procd/uxc.c

  1 /*
  2  * Copyright (C) 2020 Daniel Golle <daniel@makrotopia.org>
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU Lesser General Public License version 2.1
  6  * as published by the Free Software Foundation
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  * GNU General Public License for more details.
 12  */
 13 
 14 #ifndef _GNU_SOURCE
 15 #define _GNU_SOURCE
 16 #endif
 17 
 18 #include <stdlib.h>
 19 #include <stdbool.h>
 20 #include <fcntl.h>
 21 #include <libubus.h>
 22 #include <libubox/avl-cmp.h>
 23 #include <libubox/blobmsg.h>
 24 #include <libubox/blobmsg_json.h>
 25 #include <stdio.h>
 26 #include <stdlib.h>
 27 #include <unistd.h>
 28 #include <fcntl.h>
 29 #include <errno.h>
 30 #include <sys/stat.h>
 31 #include <sys/types.h>
 32 #include <glob.h>
 33 #include <signal.h>
 34 
 35 #include "log.h"
 36 
 37 #define OCI_VERSION_STRING "1.0.2"
 38 #define UXC_CONFDIR "/etc/uxc"
 39 #define UXC_RUNDIR "/var/run/uxc"
 40 
 41 struct runtime_state {
 42         struct avl_node avl;
 43         char *container_name;
 44         char *instance_name;
 45         char *jail_name;
 46         bool running;
 47         int runtime_pid;
 48         int exitcode;
 49         struct blob_attr *ocistate;
 50 };
 51 
 52 AVL_TREE(runtime, avl_strcmp, false, NULL);
 53 static struct blob_buf conf;
 54 static struct blob_buf state;
 55 
 56 static struct ubus_context *ctx;
 57 
 58 static int usage(void) {
 59         printf("syntax: uxc {command} [parameters ...]\n");
 60         printf("commands:\n");
 61         printf("\tlist\t\t\t\tlist all configured containers\n");
 62         printf("\tcreate {conf} [path] [enabled]\tcreate {conf} for OCI bundle at {path}\n");
 63         printf("\tstart {conf}\t\t\tstart container {conf}\n");
 64         printf("\tstate {conf}\t\t\tget state of container {conf}\n");
 65         printf("\tkill {conf} {signal}\t\tsend signal to container {conf}\n");
 66         printf("\tenable {conf}\t\t\tstart container {conf} on boot\n");
 67         printf("\tdisable {conf}\t\t\tdon't start container {conf} on boot\n");
 68         printf("\tdelete {conf}\t\t\tdelete {conf}\n");
 69         return EINVAL;
 70 }
 71 
 72 enum {
 73         CONF_NAME,
 74         CONF_PATH,
 75         CONF_JAIL,
 76         CONF_AUTOSTART,
 77         __CONF_MAX,
 78 };
 79 
 80 static const struct blobmsg_policy conf_policy[__CONF_MAX] = {
 81         [CONF_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
 82         [CONF_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
 83         [CONF_JAIL] = { .name = "jail", .type = BLOBMSG_TYPE_STRING },
 84         [CONF_AUTOSTART] = { .name = "autostart", .type = BLOBMSG_TYPE_BOOL },
 85 };
 86 
 87 static int conf_load(bool load_state)
 88 {
 89         int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
 90         int j, res;
 91         glob_t gl;
 92         char *globstr;
 93         struct blob_buf *target = load_state?&state:&conf;
 94         void *c, *o;
 95 
 96         if (asprintf(&globstr, "%s/*.json", load_state?UXC_RUNDIR:UXC_CONFDIR) == -1)
 97                 return ENOMEM;
 98 
 99         blob_buf_init(target, 0);
100         c = blobmsg_open_table(target, NULL);
101 
102         res = glob(globstr, gl_flags, NULL, &gl);
103         free(globstr);
104         if (res < 0)
105                 return 0;
106 
107         for (j = 0; j < gl.gl_pathc; j++) {
108                 o = blobmsg_open_table(target, strdup(gl.gl_pathv[j]));
109                 if (!blobmsg_add_json_from_file(target, gl.gl_pathv[j])) {
110                         ERROR("uxc: failed to load %s\n", gl.gl_pathv[j]);
111                         continue;
112                 }
113                 blobmsg_close_table(target, o);
114         }
115         blobmsg_close_table(target, c);
116         globfree(&gl);
117 
118         return 0;
119 }
120 
121 enum {
122         LIST_INSTANCES,
123         __LIST_MAX,
124 };
125 
126 static const struct blobmsg_policy list_policy[__LIST_MAX] = {
127         [LIST_INSTANCES] = { .name = "instances", .type = BLOBMSG_TYPE_TABLE },
128 };
129 
130 enum {
131         INSTANCE_RUNNING,
132         INSTANCE_PID,
133         INSTANCE_EXITCODE,
134         INSTANCE_JAIL,
135         __INSTANCE_MAX,
136 };
137 
138 static const struct blobmsg_policy instance_policy[__INSTANCE_MAX] = {
139         [INSTANCE_RUNNING] = { .name = "running", .type = BLOBMSG_TYPE_BOOL },
140         [INSTANCE_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 },
141         [INSTANCE_EXITCODE] = { .name = "exit_code", .type = BLOBMSG_TYPE_INT32 },
142         [INSTANCE_JAIL] = { .name = "jail", .type = BLOBMSG_TYPE_TABLE },
143 };
144 
145 enum {
146         JAIL_NAME,
147         __JAIL_MAX,
148 };
149 
150 static const struct blobmsg_policy jail_policy[__JAIL_MAX] = {
151         [JAIL_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
152 };
153 
154 static struct runtime_state *
155 runtime_alloc(const char *container_name)
156 {
157         struct runtime_state *s;
158         char *new_name;
159         s = calloc_a(sizeof(*s), &new_name, strlen(container_name) + 1);
160         strcpy(new_name, container_name);
161         s->container_name = new_name;
162         s->avl.key = s->container_name;
163         return s;
164 }
165 
166 enum {
167         STATE_OCIVERSION,
168         STATE_ID,
169         STATE_STATUS,
170         STATE_PID,
171         STATE_BUNDLE,
172         STATE_ANNOTATIONS,
173         __STATE_MAX,
174 };
175 
176 static const struct blobmsg_policy state_policy[__STATE_MAX] = {
177         [STATE_OCIVERSION] = { .name = "ociVersion", .type = BLOBMSG_TYPE_STRING },
178         [STATE_ID] = { .name = "id", .type = BLOBMSG_TYPE_STRING },
179         [STATE_STATUS] = { .name = "status", .type = BLOBMSG_TYPE_STRING },
180         [STATE_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 },
181         [STATE_BUNDLE] = { .name = "bundle", .type = BLOBMSG_TYPE_STRING },
182         [STATE_ANNOTATIONS] = { .name = "annotations", .type = BLOBMSG_TYPE_TABLE },
183 };
184 
185 
186 static void ocistate_cb(struct ubus_request *req, int type, struct blob_attr *msg)
187 {
188         struct blob_attr **ocistate = (struct blob_attr **)req->priv;
189         struct blob_attr *tb[__STATE_MAX];
190 
191         blobmsg_parse(state_policy, __STATE_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
192 
193         if (!tb[STATE_OCIVERSION] ||
194             !tb[STATE_ID] ||
195             !tb[STATE_STATUS] ||
196             !tb[STATE_BUNDLE])
197                 return;
198 
199         *ocistate = blob_memdup(msg);
200 }
201 
202 static void get_ocistate(struct blob_attr **ocistate, const char *name)
203 {
204         char *objname;
205         unsigned int id;
206         int ret;
207         *ocistate = NULL;
208 
209         asprintf(&objname, "container.%s", name);
210         ret = ubus_lookup_id(ctx, objname, &id);
211         free(objname);
212         if (ret)
213                 return;
214 
215         ubus_invoke(ctx, id, "state", NULL, ocistate_cb, ocistate, 3000);
216 }
217 
218 static void list_cb(struct ubus_request *req, int type, struct blob_attr *msg)
219 {
220         struct blob_attr *cur, *curi, *tl[__LIST_MAX], *ti[__INSTANCE_MAX], *tj[__JAIL_MAX];
221         int rem, remi;
222         const char *container_name, *instance_name, *jail_name;
223         bool running;
224         int pid, exitcode;
225         struct runtime_state *rs;
226 
227         blobmsg_for_each_attr(cur, msg, rem) {
228                 container_name = blobmsg_name(cur);
229                 blobmsg_parse(list_policy, __LIST_MAX, tl, blobmsg_data(cur), blobmsg_len(cur));
230                 if (!tl[LIST_INSTANCES])
231                         continue;
232 
233                 blobmsg_for_each_attr(curi, tl[LIST_INSTANCES], remi) {
234                         instance_name = blobmsg_name(curi);
235                         blobmsg_parse(instance_policy, __INSTANCE_MAX, ti, blobmsg_data(curi), blobmsg_len(curi));
236 
237                         if (!ti[INSTANCE_JAIL])
238                                 continue;
239 
240                         blobmsg_parse(jail_policy, __JAIL_MAX, tj, blobmsg_data(ti[INSTANCE_JAIL]), blobmsg_len(ti[INSTANCE_JAIL]));
241                         if (!tj[JAIL_NAME])
242                                 continue;
243 
244                         jail_name = blobmsg_get_string(tj[JAIL_NAME]);
245 
246                         running = ti[INSTANCE_RUNNING] && blobmsg_get_bool(ti[INSTANCE_RUNNING]);
247 
248                         if (ti[INSTANCE_PID])
249                                 pid = blobmsg_get_u32(ti[INSTANCE_PID]);
250                         else
251                                 pid = -1;
252 
253                         if (ti[INSTANCE_EXITCODE])
254                                 exitcode = blobmsg_get_u32(ti[INSTANCE_EXITCODE]);
255                         else
256                                 exitcode = -1;
257 
258                         rs = runtime_alloc(container_name);
259                         rs->instance_name = strdup(instance_name);
260                         rs->jail_name = strdup(jail_name);
261                         rs->runtime_pid = pid;
262                         rs->exitcode = exitcode;
263                         rs->running = running;
264                         avl_insert(&runtime, &rs->avl);
265                 }
266         }
267 
268         return;
269 }
270 
271 static int runtime_load(void)
272 {
273         struct runtime_state *item, *tmp;
274         uint32_t id;
275 
276         avl_init(&runtime, avl_strcmp, false, NULL);
277         if (ubus_lookup_id(ctx, "container", &id) ||
278                 ubus_invoke(ctx, id, "list", NULL, list_cb, &runtime, 3000))
279                 return EIO;
280 
281 
282         avl_for_each_element_safe(&runtime, item, avl, tmp)
283                 get_ocistate(&item->ocistate, item->jail_name);
284 
285         return 0;
286 }
287 
288 static void runtime_free(void)
289 {
290         struct runtime_state *item, *tmp;
291 
292         avl_for_each_element_safe(&runtime, item, avl, tmp) {
293                 avl_delete(&runtime, &item->avl);
294                 free(item->instance_name);
295                 free(item->jail_name);
296                 free(item->ocistate);
297                 free(item);
298         }
299 
300         return;
301 }
302 
303 static int uxc_state(char *name)
304 {
305         struct runtime_state *s = avl_find_element(&runtime, name, s, avl);
306         struct blob_attr *ocistate = NULL;
307         struct blob_attr *cur, *tb[__CONF_MAX];
308         int rem;
309         char *bundle = NULL;
310         char *jail_name = NULL;
311         static struct blob_buf buf;
312 
313         if (s)
314                 ocistate = s->ocistate;
315 
316         if (ocistate) {
317                 printf("%s\n", blobmsg_format_json_indent(ocistate, true, 0));
318                 return 0;
319         }
320 
321         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
322                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
323                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
324                         continue;
325 
326                 if (!strcmp(name, blobmsg_get_string(tb[CONF_NAME]))) {
327                         if (tb[CONF_JAIL])
328                                 jail_name = blobmsg_get_string(tb[CONF_JAIL]);
329                         else
330                                 jail_name = name;
331 
332                         bundle = blobmsg_get_string(tb[CONF_PATH]);
333                         break;
334                 }
335         }
336 
337         if (!bundle)
338                 return ENOENT;
339 
340         blob_buf_init(&buf, 0);
341         blobmsg_add_string(&buf, "ociVersion", OCI_VERSION_STRING);
342         blobmsg_add_string(&buf, "id", jail_name);
343         blobmsg_add_string(&buf, "status", s?"stopped":"uninitialized");
344         blobmsg_add_string(&buf, "bundle", bundle);
345 
346         printf("%s\n", blobmsg_format_json_indent(buf.head, true, 0));
347         blob_buf_free(&buf);
348 
349         return 0;
350 }
351 
352 static int uxc_list(void)
353 {
354         struct blob_attr *cur, *tb[__CONF_MAX], *ts[__STATE_MAX];
355         int rem;
356         struct runtime_state *s = NULL;
357         char *name;
358         char *ocistatus;
359         int container_pid = -1;
360         bool autostart;
361 
362         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
363                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
364                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
365                         continue;
366 
367                 autostart = tb[CONF_AUTOSTART] && blobmsg_get_bool(tb[CONF_AUTOSTART]);
368                 ocistatus = NULL;
369                 container_pid = 0;
370                 name = blobmsg_get_string(tb[CONF_NAME]);
371                 s = avl_find_element(&runtime, name, s, avl);
372 
373                 if (s && s->ocistate) {
374                         blobmsg_parse(state_policy, __STATE_MAX, ts, blobmsg_data(s->ocistate), blobmsg_len(s->ocistate));
375                         ocistatus = blobmsg_get_string(ts[STATE_STATUS]);
376                         container_pid = blobmsg_get_u32(ts[STATE_PID]);
377                 }
378 
379                 printf("[%c] %s %s", autostart?'*':' ', name, ocistatus?:(s && s->running)?"creating":"stopped");
380 
381                 if (s && !s->running && (s->exitcode >= 0))
382                         printf(" exitcode: %d (%s)", s->exitcode, strerror(s->exitcode));
383 
384                 if (s && s->running && (s->runtime_pid >= 0))
385                         printf(" runtime pid: %d", s->runtime_pid);
386 
387                 if (s && s->running && (container_pid >= 0))
388                         printf(" container pid: %d", container_pid);
389 
390                 printf("\n");
391         }
392 
393         return 0;
394 }
395 
396 static int uxc_create(char *name, bool immediately)
397 {
398         static struct blob_buf req;
399         struct blob_attr *cur, *tb[__CONF_MAX];
400         int rem, ret;
401         uint32_t id;
402         struct runtime_state *s = NULL;
403         char *path = NULL, *jailname = NULL;
404         void *in, *ins, *j;
405         bool found = false;
406 
407         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
408                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
409                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
410                         continue;
411 
412                 if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
413                         continue;
414 
415                 found = true;
416                 path = strdup(blobmsg_get_string(tb[CONF_PATH]));
417 
418                 break;
419         }
420 
421         if (!found)
422                 return ENOENT;
423 
424         s = avl_find_element(&runtime, name, s, avl);
425 
426         if (s && (s->running))
427                 return EEXIST;
428 
429         if (tb[CONF_JAIL])
430                 jailname = strdup(blobmsg_get_string(tb[CONF_JAIL]));
431 
432         blob_buf_init(&req, 0);
433         blobmsg_add_string(&req, "name", name);
434         ins = blobmsg_open_table(&req, "instances");
435         in = blobmsg_open_table(&req, name);
436         blobmsg_add_string(&req, "bundle", path);
437         j = blobmsg_open_table(&req, "jail");
438         blobmsg_add_string(&req, "name", jailname?:name);
439         blobmsg_add_u8(&req, "immediately", immediately);
440         blobmsg_close_table(&req, j);
441         blobmsg_close_table(&req, in);
442         blobmsg_close_table(&req, ins);
443 
444         ret = 0;
445         if (ubus_lookup_id(ctx, "container", &id) ||
446                 ubus_invoke(ctx, id, "add", req.head, NULL, NULL, 3000)) {
447                 ret = EIO;
448         }
449 
450         free(jailname);
451         free(path);
452         blob_buf_free(&req);
453 
454         return ret;
455 }
456 
457 static int uxc_start(const char *name)
458 {
459         char *objname;
460         unsigned int id;
461 
462         asprintf(&objname, "container.%s", name);
463         if (ubus_lookup_id(ctx, objname, &id))
464                 return ENOENT;
465 
466         return ubus_invoke(ctx, id, "start", NULL, NULL, NULL, 3000);
467 }
468 
469 static int uxc_kill(char *name, int signal)
470 {
471         static struct blob_buf req;
472         struct blob_attr *cur, *tb[__CONF_MAX];
473         int rem, ret;
474         char *objname;
475         unsigned int id;
476         struct runtime_state *s = NULL;
477         bool found = false;
478 
479         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
480                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
481                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
482                         continue;
483 
484                 if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
485                         continue;
486 
487                 found = true;
488                 break;
489         }
490 
491         if (!found)
492                 return ENOENT;
493 
494         s = avl_find_element(&runtime, name, s, avl);
495 
496         if (!s || !(s->running))
497                 return ENOENT;
498 
499         blob_buf_init(&req, 0);
500         blobmsg_add_u32(&req, "signal", signal);
501         blobmsg_add_string(&req, "name", name);
502 
503         asprintf(&objname, "container.%s", name);
504         ret = ubus_lookup_id(ctx, objname, &id);
505         free(objname);
506         if (ret)
507                 return ENOENT;
508 
509         if (ubus_invoke(ctx, id, "kill", req.head, NULL, NULL, 3000))
510                 return EIO;
511 
512         return 0;
513 }
514 
515 
516 static int uxc_set(char *name, char *path, bool autostart, bool add)
517 {
518         static struct blob_buf req;
519         struct blob_attr *cur, *tb[__CONF_MAX];
520         int rem, ret;
521         bool found = false;
522         char *fname = NULL;
523         char *keeppath = NULL;
524         int f;
525         struct stat sb;
526 
527         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
528                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
529                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
530                         continue;
531 
532                 if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
533                         continue;
534 
535                 found = true;
536                 break;
537         }
538 
539         if (found && add)
540                 return EEXIST;
541 
542         if (!found && !add)
543                 return ENOENT;
544 
545         if (add && !path)
546                 return EINVAL;
547 
548         if (path) {
549                 if (stat(path, &sb) == -1)
550                         return ENOENT;
551 
552                 if ((sb.st_mode & S_IFMT) != S_IFDIR)
553                         return ENOTDIR;
554         }
555 
556         ret = mkdir(UXC_CONFDIR, 0755);
557 
558         if (ret && errno != EEXIST)
559                 return ret;
560 
561         if (asprintf(&fname, "%s/%s.json", UXC_CONFDIR, name) < 1)
562                 return ENOMEM;
563 
564         f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
565         if (f < 0)
566                 return errno;
567 
568         if (!add)
569                 keeppath = strdup(blobmsg_get_string(tb[CONF_PATH]));
570 
571         blob_buf_init(&req, 0);
572         blobmsg_add_string(&req, "name", name);
573         blobmsg_add_string(&req, "path", path?:keeppath);
574         blobmsg_add_u8(&req, "autostart", autostart);
575 
576         dprintf(f, "%s\n", blobmsg_format_json_indent(req.head, true, 0));
577 
578         if (!add)
579                 free(keeppath);
580 
581         blob_buf_free(&req);
582 
583         return 0;
584 }
585 
586 static int uxc_boot(void)
587 {
588         struct blob_attr *cur, *tb[__CONF_MAX];
589         int rem, ret = 0;
590         char *name;
591 
592         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
593                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
594                 if (!tb[CONF_NAME] || !tb[CONF_PATH] || !tb[CONF_AUTOSTART] || !blobmsg_get_bool(tb[CONF_AUTOSTART]))
595                         continue;
596 
597                 name = strdup(blobmsg_get_string(tb[CONF_NAME]));
598                 ret += uxc_create(name, true);
599                 free(name);
600         }
601 
602         return ret;
603 }
604 
605 static int uxc_delete(char *name)
606 {
607         struct blob_attr *cur, *tb[__CONF_MAX];
608         int rem, ret = 0;
609         bool found = false;
610         char *fname;
611         struct stat sb;
612 
613         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
614                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
615                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
616                         continue;
617 
618                 if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
619                         continue;
620 
621                 fname = strdup(blobmsg_name(cur));
622                 if (!fname)
623                         return errno;
624 
625                 found = true;
626                 break;
627         }
628 
629         if (!found)
630                 return ENOENT;
631 
632         if (stat(fname, &sb) == -1) {
633                 ret=ENOENT;
634                 goto errout;
635         }
636 
637         if (unlink(fname) == -1)
638                 ret=errno;
639 
640 errout:
641         free(fname);
642         return ret;
643 }
644 
645 static void reload_conf(void)
646 {
647         blob_buf_free(&conf);
648         conf_load(false);
649 }
650 
651 int main(int argc, char **argv)
652 {
653         int ret = EINVAL;
654 
655         if (argc < 2)
656                 return usage();
657 
658         ctx = ubus_connect(NULL);
659         if (!ctx)
660                 return ENODEV;
661 
662         ret = conf_load(false);
663         if (ret)
664                 goto out;
665 
666         ret = mkdir(UXC_RUNDIR, 0755);
667         if (ret && errno != EEXIST)
668                 goto conf_out;
669 
670         ret = conf_load(true);
671         if (ret)
672                 goto conf_out;
673 
674         ret = runtime_load();
675         if (ret)
676                 goto state_out;
677 
678         if (!strcmp("list", argv[1]))
679                 ret = uxc_list();
680         else if (!strcmp("boot", argv[1]))
681                 ret = uxc_boot();
682         else if(!strcmp("start", argv[1])) {
683                 if (argc < 3)
684                         goto usage_out;
685 
686                 ret = uxc_start(argv[2]);
687         } else if(!strcmp("state", argv[1])) {
688                 if (argc < 3)
689                         goto usage_out;
690 
691                 ret = uxc_state(argv[2]);
692         } else if(!strcmp("kill", argv[1])) {
693                 int signal = SIGTERM;
694                 if (argc < 3)
695                         goto usage_out;
696 
697                 if (argc == 4)
698                         signal = atoi(argv[3]);
699 
700                 ret = uxc_kill(argv[2], signal);
701         } else if(!strcmp("enable", argv[1])) {
702                 if (argc < 3)
703                         goto usage_out;
704 
705                 ret = uxc_set(argv[2], NULL, true, false);
706         } else if(!strcmp("disable", argv[1])) {
707                 if (argc < 3)
708                         goto usage_out;
709 
710                 ret = uxc_set(argv[2], NULL, false, false);
711         } else if(!strcmp("delete", argv[1])) {
712                 if (argc < 3)
713                         goto usage_out;
714 
715                 ret = uxc_delete(argv[2]);
716         } else if(!strcmp("create", argv[1])) {
717                 bool autostart = false;
718                 if (argc < 3)
719                         goto usage_out;
720 
721                 if (argc == 5) {
722                         if (!strncmp("true", argv[4], 5))
723                                 autostart = true;
724                         else
725                                 autostart = atoi(argv[4]);
726                 }
727 
728                 if (argc >= 4) {
729                         ret = uxc_set(argv[2], argv[3], autostart, true);
730                         if (ret)
731                                 goto runtime_out;
732 
733                         reload_conf();
734                 }
735                 ret = uxc_create(argv[2], false);
736         } else
737                 goto usage_out;
738 
739         goto runtime_out;
740 
741 usage_out:
742         usage();
743 runtime_out:
744         runtime_free();
745 state_out:
746         blob_buf_free(&state);
747 conf_out:
748         blob_buf_free(&conf);
749 out:
750         ubus_free(ctx);
751 
752         if (ret != 0)
753                 fprintf(stderr, "uxc error: %s\n", strerror(ret));
754 
755         return ret;
756 }
757 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt