• 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 <getopt.h>
 31 #include <sys/stat.h>
 32 #include <sys/types.h>
 33 #include <glob.h>
 34 #include <signal.h>
 35 
 36 #include "log.h"
 37 
 38 #define UXC_VERSION "0.1"
 39 #define OCI_VERSION_STRING "1.0.2"
 40 #define UXC_CONFDIR "/etc/uxc"
 41 #define UXC_RUNDIR "/var/run/uxc"
 42 
 43 struct runtime_state {
 44         struct avl_node avl;
 45         char *container_name;
 46         char *instance_name;
 47         char *jail_name;
 48         bool running;
 49         int runtime_pid;
 50         int exitcode;
 51         struct blob_attr *ocistate;
 52 };
 53 
 54 enum uxc_cmd {
 55         CMD_LIST,
 56         CMD_BOOT,
 57         CMD_START,
 58         CMD_STATE,
 59         CMD_KILL,
 60         CMD_ENABLE,
 61         CMD_DISABLE,
 62         CMD_DELETE,
 63         CMD_CREATE,
 64         CMD_UNKNOWN
 65 };
 66 
 67 #define OPT_ARGS "ab:fp:vV"
 68 static struct option long_options[] = {
 69         {"autostart",   no_argument,            0,      'a'     },
 70         {"bundle",      required_argument,      0,      'b'     },
 71         {"force",       no_argument,            0,      'f'     },
 72         {"pid-file",    required_argument,      0,      'p'     },
 73         {"verbose",     no_argument,            0,      'v'     },
 74         {"version",     no_argument,            0,      'V'     },
 75         {0,             0,                      0,      0       }
 76 };
 77 
 78 AVL_TREE(runtime, avl_strcmp, false, NULL);
 79 static struct blob_buf conf;
 80 static struct blob_buf state;
 81 static struct ubus_context *ctx;
 82 
 83 static int usage(void) {
 84         printf("syntax: uxc <command> [parameters ...]\n");
 85         printf("commands:\n");
 86         printf("\tlist\t\t\t\t\t\tlist all configured containers\n");
 87         printf("\tcreate <conf> [--bundle <path>] [--autostart]\tcreate <conf> for OCI bundle at <path>\n");
 88         printf("\tstart <conf>\t\t\t\t\tstart container <conf>\n");
 89         printf("\tstate <conf>\t\t\t\t\tget state of container <conf>\n");
 90         printf("\tkill <conf> [<signal>]\t\t\t\tsend signal to container <conf>\n");
 91         printf("\tenable <conf>\t\t\t\t\tstart container <conf> on boot\n");
 92         printf("\tdisable <conf>\t\t\t\t\tdon't start container <conf> on boot\n");
 93         printf("\tdelete <conf> [--force]\t\t\t\tdelete <conf>\n");
 94         return EINVAL;
 95 }
 96 
 97 enum {
 98         CONF_NAME,
 99         CONF_PATH,
100         CONF_JAIL,
101         CONF_AUTOSTART,
102         CONF_PIDFILE,
103         __CONF_MAX,
104 };
105 
106 static const struct blobmsg_policy conf_policy[__CONF_MAX] = {
107         [CONF_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
108         [CONF_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
109         [CONF_JAIL] = { .name = "jail", .type = BLOBMSG_TYPE_STRING },
110         [CONF_AUTOSTART] = { .name = "autostart", .type = BLOBMSG_TYPE_BOOL },
111         [CONF_PIDFILE] = { .name = "pidfile", .type = BLOBMSG_TYPE_STRING },
112 };
113 
114 static int conf_load(bool load_state)
115 {
116         int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
117         int j, res;
118         glob_t gl;
119         char *globstr;
120         struct blob_buf *target = load_state?&state:&conf;
121         void *c, *o;
122 
123         if (asprintf(&globstr, "%s/*.json", load_state?UXC_RUNDIR:UXC_CONFDIR) == -1)
124                 return ENOMEM;
125 
126         blob_buf_init(target, 0);
127         c = blobmsg_open_table(target, NULL);
128 
129         res = glob(globstr, gl_flags, NULL, &gl);
130         free(globstr);
131         if (res < 0)
132                 return 0;
133 
134         for (j = 0; j < gl.gl_pathc; j++) {
135                 o = blobmsg_open_table(target, strdup(gl.gl_pathv[j]));
136                 if (!blobmsg_add_json_from_file(target, gl.gl_pathv[j])) {
137                         ERROR("uxc: failed to load %s\n", gl.gl_pathv[j]);
138                         continue;
139                 }
140                 blobmsg_close_table(target, o);
141         }
142         blobmsg_close_table(target, c);
143         globfree(&gl);
144 
145         return 0;
146 }
147 
148 enum {
149         LIST_INSTANCES,
150         __LIST_MAX,
151 };
152 
153 static const struct blobmsg_policy list_policy[__LIST_MAX] = {
154         [LIST_INSTANCES] = { .name = "instances", .type = BLOBMSG_TYPE_TABLE },
155 };
156 
157 enum {
158         INSTANCE_RUNNING,
159         INSTANCE_PID,
160         INSTANCE_EXITCODE,
161         INSTANCE_JAIL,
162         __INSTANCE_MAX,
163 };
164 
165 static const struct blobmsg_policy instance_policy[__INSTANCE_MAX] = {
166         [INSTANCE_RUNNING] = { .name = "running", .type = BLOBMSG_TYPE_BOOL },
167         [INSTANCE_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 },
168         [INSTANCE_EXITCODE] = { .name = "exit_code", .type = BLOBMSG_TYPE_INT32 },
169         [INSTANCE_JAIL] = { .name = "jail", .type = BLOBMSG_TYPE_TABLE },
170 };
171 
172 enum {
173         JAIL_NAME,
174         __JAIL_MAX,
175 };
176 
177 static const struct blobmsg_policy jail_policy[__JAIL_MAX] = {
178         [JAIL_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
179 };
180 
181 static struct runtime_state *
182 runtime_alloc(const char *container_name)
183 {
184         struct runtime_state *s;
185         char *new_name;
186         s = calloc_a(sizeof(*s), &new_name, strlen(container_name) + 1);
187         strcpy(new_name, container_name);
188         s->container_name = new_name;
189         s->avl.key = s->container_name;
190         return s;
191 }
192 
193 enum {
194         STATE_OCIVERSION,
195         STATE_ID,
196         STATE_STATUS,
197         STATE_PID,
198         STATE_BUNDLE,
199         STATE_ANNOTATIONS,
200         __STATE_MAX,
201 };
202 
203 static const struct blobmsg_policy state_policy[__STATE_MAX] = {
204         [STATE_OCIVERSION] = { .name = "ociVersion", .type = BLOBMSG_TYPE_STRING },
205         [STATE_ID] = { .name = "id", .type = BLOBMSG_TYPE_STRING },
206         [STATE_STATUS] = { .name = "status", .type = BLOBMSG_TYPE_STRING },
207         [STATE_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 },
208         [STATE_BUNDLE] = { .name = "bundle", .type = BLOBMSG_TYPE_STRING },
209         [STATE_ANNOTATIONS] = { .name = "annotations", .type = BLOBMSG_TYPE_TABLE },
210 };
211 
212 
213 static void ocistate_cb(struct ubus_request *req, int type, struct blob_attr *msg)
214 {
215         struct blob_attr **ocistate = (struct blob_attr **)req->priv;
216         struct blob_attr *tb[__STATE_MAX];
217 
218         blobmsg_parse(state_policy, __STATE_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
219 
220         if (!tb[STATE_OCIVERSION] ||
221             !tb[STATE_ID] ||
222             !tb[STATE_STATUS] ||
223             !tb[STATE_BUNDLE])
224                 return;
225 
226         *ocistate = blob_memdup(msg);
227 }
228 
229 static void get_ocistate(struct blob_attr **ocistate, const char *name)
230 {
231         char *objname;
232         unsigned int id;
233         int ret;
234         *ocistate = NULL;
235 
236         asprintf(&objname, "container.%s", name);
237         ret = ubus_lookup_id(ctx, objname, &id);
238         free(objname);
239         if (ret)
240                 return;
241 
242         ubus_invoke(ctx, id, "state", NULL, ocistate_cb, ocistate, 3000);
243 }
244 
245 static void list_cb(struct ubus_request *req, int type, struct blob_attr *msg)
246 {
247         struct blob_attr *cur, *curi, *tl[__LIST_MAX], *ti[__INSTANCE_MAX], *tj[__JAIL_MAX];
248         int rem, remi;
249         const char *container_name, *instance_name, *jail_name;
250         bool running;
251         int pid, exitcode;
252         struct runtime_state *rs;
253 
254         blobmsg_for_each_attr(cur, msg, rem) {
255                 container_name = blobmsg_name(cur);
256                 blobmsg_parse(list_policy, __LIST_MAX, tl, blobmsg_data(cur), blobmsg_len(cur));
257                 if (!tl[LIST_INSTANCES])
258                         continue;
259 
260                 blobmsg_for_each_attr(curi, tl[LIST_INSTANCES], remi) {
261                         instance_name = blobmsg_name(curi);
262                         blobmsg_parse(instance_policy, __INSTANCE_MAX, ti, blobmsg_data(curi), blobmsg_len(curi));
263 
264                         if (!ti[INSTANCE_JAIL])
265                                 continue;
266 
267                         blobmsg_parse(jail_policy, __JAIL_MAX, tj, blobmsg_data(ti[INSTANCE_JAIL]), blobmsg_len(ti[INSTANCE_JAIL]));
268                         if (!tj[JAIL_NAME])
269                                 continue;
270 
271                         jail_name = blobmsg_get_string(tj[JAIL_NAME]);
272 
273                         running = ti[INSTANCE_RUNNING] && blobmsg_get_bool(ti[INSTANCE_RUNNING]);
274 
275                         if (ti[INSTANCE_PID])
276                                 pid = blobmsg_get_u32(ti[INSTANCE_PID]);
277                         else
278                                 pid = -1;
279 
280                         if (ti[INSTANCE_EXITCODE])
281                                 exitcode = blobmsg_get_u32(ti[INSTANCE_EXITCODE]);
282                         else
283                                 exitcode = -1;
284 
285                         rs = runtime_alloc(container_name);
286                         rs->instance_name = strdup(instance_name);
287                         rs->jail_name = strdup(jail_name);
288                         rs->runtime_pid = pid;
289                         rs->exitcode = exitcode;
290                         rs->running = running;
291                         avl_insert(&runtime, &rs->avl);
292                 }
293         }
294 
295         return;
296 }
297 
298 static int runtime_load(void)
299 {
300         struct runtime_state *item, *tmp;
301         uint32_t id;
302 
303         avl_init(&runtime, avl_strcmp, false, NULL);
304         if (ubus_lookup_id(ctx, "container", &id) ||
305                 ubus_invoke(ctx, id, "list", NULL, list_cb, &runtime, 3000))
306                 return EIO;
307 
308 
309         avl_for_each_element_safe(&runtime, item, avl, tmp)
310                 get_ocistate(&item->ocistate, item->jail_name);
311 
312         return 0;
313 }
314 
315 static void runtime_free(void)
316 {
317         struct runtime_state *item, *tmp;
318 
319         avl_for_each_element_safe(&runtime, item, avl, tmp) {
320                 avl_delete(&runtime, &item->avl);
321                 free(item->instance_name);
322                 free(item->jail_name);
323                 free(item->ocistate);
324                 free(item);
325         }
326 
327         return;
328 }
329 
330 static int uxc_state(char *name)
331 {
332         struct runtime_state *s = avl_find_element(&runtime, name, s, avl);
333         struct blob_attr *ocistate = NULL;
334         struct blob_attr *cur, *tb[__CONF_MAX];
335         int rem;
336         char *bundle = NULL;
337         char *jail_name = NULL;
338         static struct blob_buf buf;
339 
340         if (s)
341                 ocistate = s->ocistate;
342 
343         if (ocistate) {
344                 printf("%s\n", blobmsg_format_json_indent(ocistate, true, 0));
345                 return 0;
346         }
347 
348         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
349                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
350                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
351                         continue;
352 
353                 if (!strcmp(name, blobmsg_get_string(tb[CONF_NAME]))) {
354                         if (tb[CONF_JAIL])
355                                 jail_name = blobmsg_get_string(tb[CONF_JAIL]);
356                         else
357                                 jail_name = name;
358 
359                         bundle = blobmsg_get_string(tb[CONF_PATH]);
360                         break;
361                 }
362         }
363 
364         if (!bundle)
365                 return ENOENT;
366 
367         blob_buf_init(&buf, 0);
368         blobmsg_add_string(&buf, "ociVersion", OCI_VERSION_STRING);
369         blobmsg_add_string(&buf, "id", jail_name);
370         blobmsg_add_string(&buf, "status", s?"stopped":"uninitialized");
371         blobmsg_add_string(&buf, "bundle", bundle);
372 
373         printf("%s\n", blobmsg_format_json_indent(buf.head, true, 0));
374         blob_buf_free(&buf);
375 
376         return 0;
377 }
378 
379 static int uxc_list(void)
380 {
381         struct blob_attr *cur, *tb[__CONF_MAX], *ts[__STATE_MAX];
382         int rem;
383         struct runtime_state *s = NULL;
384         char *name;
385         char *ocistatus;
386         int container_pid = -1;
387         bool autostart;
388 
389         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
390                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
391                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
392                         continue;
393 
394                 autostart = tb[CONF_AUTOSTART] && blobmsg_get_bool(tb[CONF_AUTOSTART]);
395                 ocistatus = NULL;
396                 container_pid = 0;
397                 name = blobmsg_get_string(tb[CONF_NAME]);
398                 s = avl_find_element(&runtime, name, s, avl);
399 
400                 if (s && s->ocistate) {
401                         blobmsg_parse(state_policy, __STATE_MAX, ts, blobmsg_data(s->ocistate), blobmsg_len(s->ocistate));
402                         ocistatus = blobmsg_get_string(ts[STATE_STATUS]);
403                         container_pid = blobmsg_get_u32(ts[STATE_PID]);
404                 }
405 
406                 printf("[%c] %s %s", autostart?'*':' ', name, ocistatus?:(s && s->running)?"creating":"stopped");
407 
408                 if (s && !s->running && (s->exitcode >= 0))
409                         printf(" exitcode: %d (%s)", s->exitcode, strerror(s->exitcode));
410 
411                 if (s && s->running && (s->runtime_pid >= 0))
412                         printf(" runtime pid: %d", s->runtime_pid);
413 
414                 if (s && s->running && (container_pid >= 0))
415                         printf(" container pid: %d", container_pid);
416 
417                 printf("\n");
418         }
419 
420         return 0;
421 }
422 
423 static int uxc_create(char *name, bool immediately)
424 {
425         static struct blob_buf req;
426         struct blob_attr *cur, *tb[__CONF_MAX];
427         int rem, ret;
428         uint32_t id;
429         struct runtime_state *s = NULL;
430         char *path = NULL, *jailname = NULL, *pidfile = NULL;
431         void *in, *ins, *j;
432         bool found = false;
433 
434         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
435                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
436                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
437                         continue;
438 
439                 if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
440                         continue;
441 
442                 found = true;
443                 path = strdup(blobmsg_get_string(tb[CONF_PATH]));
444 
445                 if (tb[CONF_PIDFILE])
446                         pidfile = strdup(blobmsg_get_string(tb[CONF_PIDFILE]));
447                 break;
448         }
449 
450         if (!found)
451                 return ENOENT;
452 
453         s = avl_find_element(&runtime, name, s, avl);
454 
455         if (s && (s->running))
456                 return EEXIST;
457 
458         if (tb[CONF_JAIL])
459                 jailname = strdup(blobmsg_get_string(tb[CONF_JAIL]));
460 
461         blob_buf_init(&req, 0);
462         blobmsg_add_string(&req, "name", name);
463         ins = blobmsg_open_table(&req, "instances");
464         in = blobmsg_open_table(&req, name);
465         blobmsg_add_string(&req, "bundle", path);
466         j = blobmsg_open_table(&req, "jail");
467         blobmsg_add_string(&req, "name", jailname?:name);
468         blobmsg_add_u8(&req, "immediately", immediately);
469         if (pidfile)
470                 blobmsg_add_string(&req, "pidfile", pidfile);
471 
472         blobmsg_close_table(&req, j);
473         blobmsg_close_table(&req, in);
474         blobmsg_close_table(&req, ins);
475 
476         ret = 0;
477         if (ubus_lookup_id(ctx, "container", &id) ||
478                 ubus_invoke(ctx, id, "add", req.head, NULL, NULL, 3000)) {
479                 ret = EIO;
480         }
481 
482         free(jailname);
483         free(path);
484         blob_buf_free(&req);
485 
486         return ret;
487 }
488 
489 static int uxc_start(const char *name)
490 {
491         char *objname;
492         unsigned int id;
493 
494         asprintf(&objname, "container.%s", name);
495         if (ubus_lookup_id(ctx, objname, &id))
496                 return ENOENT;
497 
498         return ubus_invoke(ctx, id, "start", NULL, NULL, NULL, 3000);
499 }
500 
501 static int uxc_kill(char *name, int signal)
502 {
503         static struct blob_buf req;
504         struct blob_attr *cur, *tb[__CONF_MAX];
505         int rem, ret;
506         char *objname;
507         unsigned int id;
508         struct runtime_state *s = NULL;
509         bool found = false;
510 
511         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
512                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
513                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
514                         continue;
515 
516                 if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
517                         continue;
518 
519                 found = true;
520                 break;
521         }
522 
523         if (!found)
524                 return ENOENT;
525 
526         s = avl_find_element(&runtime, name, s, avl);
527 
528         if (!s || !(s->running))
529                 return ENOENT;
530 
531         blob_buf_init(&req, 0);
532         blobmsg_add_u32(&req, "signal", signal);
533         blobmsg_add_string(&req, "name", name);
534 
535         asprintf(&objname, "container.%s", name);
536         ret = ubus_lookup_id(ctx, objname, &id);
537         free(objname);
538         if (ret)
539                 return ENOENT;
540 
541         if (ubus_invoke(ctx, id, "kill", req.head, NULL, NULL, 3000))
542                 return EIO;
543 
544         return 0;
545 }
546 
547 
548 static int uxc_set(char *name, char *path, bool autostart, bool add, char *pidfile)
549 {
550         static struct blob_buf req;
551         struct blob_attr *cur, *tb[__CONF_MAX];
552         int rem, ret;
553         bool found = false;
554         char *fname = NULL;
555         char *keeppath = NULL;
556         int f;
557         struct stat sb;
558 
559         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
560                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
561                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
562                         continue;
563 
564                 if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
565                         continue;
566 
567                 found = true;
568                 break;
569         }
570 
571         if (found && add)
572                 return EEXIST;
573 
574         if (!found && !add)
575                 return ENOENT;
576 
577         if (add && !path)
578                 return EINVAL;
579 
580         if (path) {
581                 if (stat(path, &sb) == -1)
582                         return ENOENT;
583 
584                 if ((sb.st_mode & S_IFMT) != S_IFDIR)
585                         return ENOTDIR;
586         }
587 
588         ret = mkdir(UXC_CONFDIR, 0755);
589 
590         if (ret && errno != EEXIST)
591                 return ret;
592 
593         if (asprintf(&fname, "%s/%s.json", UXC_CONFDIR, name) < 1)
594                 return ENOMEM;
595 
596         f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
597         if (f < 0)
598                 return errno;
599 
600         if (!add)
601                 keeppath = strdup(blobmsg_get_string(tb[CONF_PATH]));
602 
603         blob_buf_init(&req, 0);
604         blobmsg_add_string(&req, "name", name);
605         blobmsg_add_string(&req, "path", path?:keeppath);
606         blobmsg_add_u8(&req, "autostart", autostart);
607         if (pidfile)
608                 blobmsg_add_string(&req, "pidfile", pidfile);
609 
610         dprintf(f, "%s\n", blobmsg_format_json_indent(req.head, true, 0));
611 
612         if (!add)
613                 free(keeppath);
614 
615         blob_buf_free(&req);
616 
617         return 0;
618 }
619 
620 static int uxc_boot(void)
621 {
622         struct blob_attr *cur, *tb[__CONF_MAX];
623         int rem, ret = 0;
624         char *name;
625 
626         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
627                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
628                 if (!tb[CONF_NAME] || !tb[CONF_PATH] || !tb[CONF_AUTOSTART] || !blobmsg_get_bool(tb[CONF_AUTOSTART]))
629                         continue;
630 
631                 name = strdup(blobmsg_get_string(tb[CONF_NAME]));
632                 ret += uxc_create(name, true);
633                 free(name);
634         }
635 
636         return ret;
637 }
638 
639 static int uxc_delete(char *name, bool force)
640 {
641         struct blob_attr *cur, *tb[__CONF_MAX];
642         struct runtime_state *s = NULL;
643         static struct blob_buf req;
644         uint32_t id;
645         int rem, ret = 0;
646         bool found = false;
647         char *fname;
648         struct stat sb;
649 
650         blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
651                 blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
652                 if (!tb[CONF_NAME] || !tb[CONF_PATH])
653                         continue;
654 
655                 if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
656                         continue;
657 
658                 fname = strdup(blobmsg_name(cur));
659                 if (!fname)
660                         return errno;
661 
662                 found = true;
663                 break;
664         }
665 
666         if (!found)
667                 return ENOENT;
668 
669         s = avl_find_element(&runtime, name, s, avl);
670 
671         if (s && s->running) {
672                 if (force) {
673                         ret = uxc_kill(name, SIGKILL);
674                         if (ret)
675                                 goto errout;
676 
677                 } else {
678                         ret = EWOULDBLOCK;
679                         goto errout;
680                 }
681         }
682 
683         if (s) {
684                 ret = ubus_lookup_id(ctx, "container", &id);
685                 if (ret)
686                         goto errout;
687 
688                 blob_buf_init(&req, 0);
689                 blobmsg_add_string(&req, "name", s->container_name);
690                 blobmsg_add_string(&req, "instance", s->instance_name);
691 
692                 if (ubus_invoke(ctx, id, "delete", req.head, NULL, NULL, 3000)) {
693                         blob_buf_free(&req);
694                         ret=EIO;
695                         goto errout;
696                 }
697         }
698 
699         if (stat(fname, &sb) == -1) {
700                 ret=ENOENT;
701                 goto errout;
702         }
703 
704         if (unlink(fname) == -1)
705                 ret=errno;
706 
707 errout:
708         free(fname);
709         return ret;
710 }
711 
712 static void reload_conf(void)
713 {
714         blob_buf_free(&conf);
715         conf_load(false);
716 }
717 
718 
719 int main(int argc, char **argv)
720 {
721         enum uxc_cmd cmd = CMD_UNKNOWN;
722         int ret = EINVAL;
723         char *bundle = NULL;
724         char *pidfile = NULL;
725         bool autostart = false;
726         bool force = false;
727         bool verbose = false;
728         int signal = SIGTERM;
729         int c;
730 
731         if (argc < 2)
732                 return usage();
733 
734         ctx = ubus_connect(NULL);
735         if (!ctx)
736                 return ENODEV;
737 
738         ret = conf_load(false);
739         if (ret)
740                 goto out;
741 
742         ret = mkdir(UXC_RUNDIR, 0755);
743         if (ret && errno != EEXIST)
744                 goto conf_out;
745 
746         ret = conf_load(true);
747         if (ret)
748                 goto conf_out;
749 
750         ret = runtime_load();
751         if (ret)
752                 goto state_out;
753 
754         while (true) {
755                 int option_index = 0;
756                 c = getopt_long(argc, argv, OPT_ARGS, long_options, &option_index);
757                 if (c == -1)
758                         break;
759 
760                 switch (c) {
761                         case 'a':
762                                 autostart = true;
763                                 break;
764 
765                         case 'b':
766                                 bundle = optarg;
767                                 break;
768 
769                         case 'f':
770                                 force = true;
771                                 break;
772 
773                         case 'p':
774                                 pidfile = optarg;
775                                 break;
776 
777                         case 'v':
778                                 verbose = true;
779                                 break;
780 
781                         case 'V':
782                                 printf("uxc %s\n", UXC_VERSION);
783                                 exit(0);
784                 }
785         }
786 
787         if (optind == argc)
788                 goto usage_out;
789 
790         if (!strcmp("list", argv[optind]))
791                 cmd = CMD_LIST;
792         else if (!strcmp("boot", argv[optind]))
793                 cmd = CMD_BOOT;
794         else if(!strcmp("start", argv[optind]))
795                 cmd = CMD_START;
796         else if(!strcmp("state", argv[optind]))
797                 cmd = CMD_STATE;
798         else if(!strcmp("kill", argv[optind]))
799                 cmd = CMD_KILL;
800         else if(!strcmp("enable", argv[optind]))
801                 cmd = CMD_ENABLE;
802         else if(!strcmp("disable", argv[optind]))
803                 cmd = CMD_DISABLE;
804         else if(!strcmp("delete", argv[optind]))
805                 cmd = CMD_DELETE;
806         else if(!strcmp("create", argv[optind]))
807                 cmd = CMD_CREATE;
808 
809         switch (cmd) {
810                 case CMD_LIST:
811                         ret = uxc_list();
812                         break;
813 
814                 case CMD_BOOT:
815                         ret = uxc_boot();
816                         break;
817 
818                 case CMD_START:
819                         if (optind != argc - 2)
820                                 goto usage_out;
821 
822                         ret = uxc_start(argv[optind + 1]);
823                         break;
824 
825                 case CMD_STATE:
826                         if (optind != argc - 2)
827                                 goto usage_out;
828 
829                         ret = uxc_state(argv[optind + 1]);
830                         break;
831 
832                 case CMD_KILL:
833                         if (optind == (argc - 3))
834                                 signal = atoi(argv[optind + 2]);
835                         else if (optind > argc - 2)
836                                 goto usage_out;
837 
838                         ret = uxc_kill(argv[optind + 1], signal);
839                         break;
840 
841                 case CMD_ENABLE:
842                         if (optind != argc - 2)
843                                 goto usage_out;
844 
845                         ret = uxc_set(argv[optind + 1], NULL, true, false, NULL);
846                         break;
847 
848                 case CMD_DISABLE:
849                         if (optind != argc - 2)
850                                 goto usage_out;
851 
852                         ret = uxc_set(argv[optind + 1], NULL, false, false, NULL);
853                         break;
854 
855                 case CMD_DELETE:
856                         if (optind != argc - 2)
857                                 goto usage_out;
858 
859                         ret = uxc_delete(argv[optind + 1], force);
860                         break;
861 
862                 case CMD_CREATE:
863                         if (optind != argc - 2)
864                                 goto usage_out;
865 
866                         if (bundle) {
867                                 ret = uxc_set(argv[optind + 1], bundle, autostart, true, pidfile);
868                                 if (ret)
869                                         goto runtime_out;
870 
871                                 reload_conf();
872                         }
873 
874                         ret = uxc_create(argv[optind + 1], false);
875                         break;
876 
877                 default:
878                         goto usage_out;
879         }
880 
881         goto runtime_out;
882 
883 usage_out:
884         usage();
885 runtime_out:
886         runtime_free();
887 state_out:
888         blob_buf_free(&state);
889 conf_out:
890         blob_buf_free(&conf);
891 out:
892         ubus_free(ctx);
893 
894         if (ret != 0)
895                 fprintf(stderr, "uxc error: %s\n", strerror(ret));
896 
897         return ret;
898 }
899 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt