uxc.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  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. #ifndef _GNU_SOURCE
  14. #define _GNU_SOURCE
  15. #endif
  16. #include <stdlib.h>
  17. #include <stdbool.h>
  18. #include <fcntl.h>
  19. #include <libubus.h>
  20. #include <libubox/avl-cmp.h>
  21. #include <libubox/blobmsg.h>
  22. #include <libubox/blobmsg_json.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. #include <fcntl.h>
  27. #include <errno.h>
  28. #include <sys/stat.h>
  29. #include <sys/types.h>
  30. #include <glob.h>
  31. #include <signal.h>
  32. #include "log.h"
  33. #define OCI_VERSION_STRING "1.0.2"
  34. #define UXC_CONFDIR "/etc/uxc"
  35. #define UXC_RUNDIR "/var/run/uxc"
  36. struct runtime_state {
  37. struct avl_node avl;
  38. char *container_name;
  39. char *instance_name;
  40. char *jail_name;
  41. bool running;
  42. int runtime_pid;
  43. int exitcode;
  44. struct blob_attr *ocistate;
  45. };
  46. AVL_TREE(runtime, avl_strcmp, false, NULL);
  47. static struct blob_buf conf;
  48. static struct blob_buf state;
  49. static struct ubus_context *ctx;
  50. static int usage(void) {
  51. printf("syntax: uxc {command} [parameters ...]\n");
  52. printf("commands:\n");
  53. printf("\tlist\t\t\t\tlist all configured containers\n");
  54. printf("\tcreate {conf} [path] [enabled]\tcreate {conf} for OCI bundle at {path}\n");
  55. printf("\tstart {conf}\t\t\tstart container {conf}\n");
  56. printf("\tstate {conf}\t\t\tget state of container {conf}\n");
  57. printf("\tkill {conf} {signal}\t\tsend signal to container {conf}\n");
  58. printf("\tenable {conf}\t\t\tstart container {conf} on boot\n");
  59. printf("\tdisable {conf}\t\t\tdon't start container {conf} on boot\n");
  60. printf("\tdelete {conf}\t\t\tdelete {conf}\n");
  61. return EINVAL;
  62. }
  63. enum {
  64. CONF_NAME,
  65. CONF_PATH,
  66. CONF_JAIL,
  67. CONF_AUTOSTART,
  68. __CONF_MAX,
  69. };
  70. static const struct blobmsg_policy conf_policy[__CONF_MAX] = {
  71. [CONF_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  72. [CONF_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
  73. [CONF_JAIL] = { .name = "jail", .type = BLOBMSG_TYPE_STRING },
  74. [CONF_AUTOSTART] = { .name = "autostart", .type = BLOBMSG_TYPE_BOOL },
  75. };
  76. static int conf_load(bool load_state)
  77. {
  78. int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
  79. int j, res;
  80. glob_t gl;
  81. char *globstr;
  82. struct blob_buf *target = load_state?&state:&conf;
  83. void *c, *o;
  84. if (asprintf(&globstr, "%s/*.json", load_state?UXC_RUNDIR:UXC_CONFDIR) == -1)
  85. return ENOMEM;
  86. blob_buf_init(target, 0);
  87. c = blobmsg_open_table(target, NULL);
  88. res = glob(globstr, gl_flags, NULL, &gl);
  89. free(globstr);
  90. if (res < 0)
  91. return 0;
  92. for (j = 0; j < gl.gl_pathc; j++) {
  93. o = blobmsg_open_table(target, strdup(gl.gl_pathv[j]));
  94. if (!blobmsg_add_json_from_file(target, gl.gl_pathv[j])) {
  95. ERROR("uxc: failed to load %s\n", gl.gl_pathv[j]);
  96. continue;
  97. }
  98. blobmsg_close_table(target, o);
  99. }
  100. blobmsg_close_table(target, c);
  101. globfree(&gl);
  102. return 0;
  103. }
  104. enum {
  105. LIST_INSTANCES,
  106. __LIST_MAX,
  107. };
  108. static const struct blobmsg_policy list_policy[__LIST_MAX] = {
  109. [LIST_INSTANCES] = { .name = "instances", .type = BLOBMSG_TYPE_TABLE },
  110. };
  111. enum {
  112. INSTANCE_RUNNING,
  113. INSTANCE_PID,
  114. INSTANCE_EXITCODE,
  115. INSTANCE_JAIL,
  116. __INSTANCE_MAX,
  117. };
  118. static const struct blobmsg_policy instance_policy[__INSTANCE_MAX] = {
  119. [INSTANCE_RUNNING] = { .name = "running", .type = BLOBMSG_TYPE_BOOL },
  120. [INSTANCE_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 },
  121. [INSTANCE_EXITCODE] = { .name = "exit_code", .type = BLOBMSG_TYPE_INT32 },
  122. [INSTANCE_JAIL] = { .name = "jail", .type = BLOBMSG_TYPE_TABLE },
  123. };
  124. enum {
  125. JAIL_NAME,
  126. __JAIL_MAX,
  127. };
  128. static const struct blobmsg_policy jail_policy[__JAIL_MAX] = {
  129. [JAIL_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING },
  130. };
  131. static struct runtime_state *
  132. runtime_alloc(const char *container_name)
  133. {
  134. struct runtime_state *s;
  135. char *new_name;
  136. s = calloc_a(sizeof(*s), &new_name, strlen(container_name) + 1);
  137. strcpy(new_name, container_name);
  138. s->container_name = new_name;
  139. s->avl.key = s->container_name;
  140. return s;
  141. }
  142. enum {
  143. STATE_OCIVERSION,
  144. STATE_ID,
  145. STATE_STATUS,
  146. STATE_PID,
  147. STATE_BUNDLE,
  148. STATE_ANNOTATIONS,
  149. __STATE_MAX,
  150. };
  151. static const struct blobmsg_policy state_policy[__STATE_MAX] = {
  152. [STATE_OCIVERSION] = { .name = "ociVersion", .type = BLOBMSG_TYPE_STRING },
  153. [STATE_ID] = { .name = "id", .type = BLOBMSG_TYPE_STRING },
  154. [STATE_STATUS] = { .name = "status", .type = BLOBMSG_TYPE_STRING },
  155. [STATE_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 },
  156. [STATE_BUNDLE] = { .name = "bundle", .type = BLOBMSG_TYPE_STRING },
  157. [STATE_ANNOTATIONS] = { .name = "annotations", .type = BLOBMSG_TYPE_TABLE },
  158. };
  159. static void ocistate_cb(struct ubus_request *req, int type, struct blob_attr *msg)
  160. {
  161. struct blob_attr **ocistate = (struct blob_attr **)req->priv;
  162. struct blob_attr *tb[__STATE_MAX];
  163. blobmsg_parse(state_policy, __STATE_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
  164. if (!tb[STATE_OCIVERSION] ||
  165. !tb[STATE_ID] ||
  166. !tb[STATE_STATUS] ||
  167. !tb[STATE_BUNDLE])
  168. return;
  169. *ocistate = blob_memdup(msg);
  170. }
  171. static void get_ocistate(struct blob_attr **ocistate, const char *name)
  172. {
  173. char *objname;
  174. unsigned int id;
  175. int ret;
  176. *ocistate = NULL;
  177. asprintf(&objname, "container.%s", name);
  178. ret = ubus_lookup_id(ctx, objname, &id);
  179. free(objname);
  180. if (ret)
  181. return;
  182. ubus_invoke(ctx, id, "state", NULL, ocistate_cb, ocistate, 3000);
  183. }
  184. static void list_cb(struct ubus_request *req, int type, struct blob_attr *msg)
  185. {
  186. struct blob_attr *cur, *curi, *tl[__LIST_MAX], *ti[__INSTANCE_MAX], *tj[__JAIL_MAX];
  187. int rem, remi;
  188. const char *container_name, *instance_name, *jail_name;
  189. bool running;
  190. int pid, exitcode;
  191. struct runtime_state *rs;
  192. blobmsg_for_each_attr(cur, msg, rem) {
  193. container_name = blobmsg_name(cur);
  194. blobmsg_parse(list_policy, __LIST_MAX, tl, blobmsg_data(cur), blobmsg_len(cur));
  195. if (!tl[LIST_INSTANCES])
  196. continue;
  197. blobmsg_for_each_attr(curi, tl[LIST_INSTANCES], remi) {
  198. instance_name = blobmsg_name(curi);
  199. blobmsg_parse(instance_policy, __INSTANCE_MAX, ti, blobmsg_data(curi), blobmsg_len(curi));
  200. if (!ti[INSTANCE_JAIL])
  201. continue;
  202. blobmsg_parse(jail_policy, __JAIL_MAX, tj, blobmsg_data(ti[INSTANCE_JAIL]), blobmsg_len(ti[INSTANCE_JAIL]));
  203. if (!tj[JAIL_NAME])
  204. continue;
  205. jail_name = blobmsg_get_string(tj[JAIL_NAME]);
  206. running = ti[INSTANCE_RUNNING] && blobmsg_get_bool(ti[INSTANCE_RUNNING]);
  207. if (ti[INSTANCE_PID])
  208. pid = blobmsg_get_u32(ti[INSTANCE_PID]);
  209. else
  210. pid = -1;
  211. if (ti[INSTANCE_EXITCODE])
  212. exitcode = blobmsg_get_u32(ti[INSTANCE_EXITCODE]);
  213. else
  214. exitcode = -1;
  215. rs = runtime_alloc(container_name);
  216. rs->instance_name = strdup(instance_name);
  217. rs->jail_name = strdup(jail_name);
  218. rs->runtime_pid = pid;
  219. rs->exitcode = exitcode;
  220. rs->running = running;
  221. avl_insert(&runtime, &rs->avl);
  222. }
  223. }
  224. return;
  225. }
  226. static int runtime_load(void)
  227. {
  228. struct runtime_state *item, *tmp;
  229. uint32_t id;
  230. avl_init(&runtime, avl_strcmp, false, NULL);
  231. if (ubus_lookup_id(ctx, "container", &id) ||
  232. ubus_invoke(ctx, id, "list", NULL, list_cb, &runtime, 3000))
  233. return EIO;
  234. avl_for_each_element_safe(&runtime, item, avl, tmp)
  235. get_ocistate(&item->ocistate, item->jail_name);
  236. return 0;
  237. }
  238. static void runtime_free(void)
  239. {
  240. struct runtime_state *item, *tmp;
  241. avl_for_each_element_safe(&runtime, item, avl, tmp) {
  242. avl_delete(&runtime, &item->avl);
  243. free(item->instance_name);
  244. free(item->jail_name);
  245. free(item->ocistate);
  246. free(item);
  247. }
  248. return;
  249. }
  250. static int uxc_state(char *name)
  251. {
  252. struct runtime_state *s = avl_find_element(&runtime, name, s, avl);
  253. struct blob_attr *ocistate = NULL;
  254. struct blob_attr *cur, *tb[__CONF_MAX];
  255. int rem;
  256. char *bundle = NULL;
  257. char *jail_name = NULL;
  258. static struct blob_buf buf;
  259. if (s)
  260. ocistate = s->ocistate;
  261. if (ocistate) {
  262. printf("%s\n", blobmsg_format_json_indent(ocistate, true, 0));
  263. return 0;
  264. }
  265. blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
  266. blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
  267. if (!tb[CONF_NAME] || !tb[CONF_PATH])
  268. continue;
  269. if (!strcmp(name, blobmsg_get_string(tb[CONF_NAME]))) {
  270. if (tb[CONF_JAIL])
  271. jail_name = blobmsg_get_string(tb[CONF_JAIL]);
  272. else
  273. jail_name = name;
  274. bundle = blobmsg_get_string(tb[CONF_PATH]);
  275. break;
  276. }
  277. }
  278. if (!bundle)
  279. return ENOENT;
  280. blob_buf_init(&buf, 0);
  281. blobmsg_add_string(&buf, "ociVersion", OCI_VERSION_STRING);
  282. blobmsg_add_string(&buf, "id", jail_name);
  283. blobmsg_add_string(&buf, "status", s?"stopped":"uninitialized");
  284. blobmsg_add_string(&buf, "bundle", bundle);
  285. printf("%s\n", blobmsg_format_json_indent(buf.head, true, 0));
  286. blob_buf_free(&buf);
  287. return 0;
  288. }
  289. static int uxc_list(void)
  290. {
  291. struct blob_attr *cur, *tb[__CONF_MAX], *ts[__STATE_MAX];
  292. int rem;
  293. struct runtime_state *s = NULL;
  294. char *name;
  295. char *ocistatus;
  296. int container_pid = -1;
  297. bool autostart;
  298. blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
  299. blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
  300. if (!tb[CONF_NAME] || !tb[CONF_PATH])
  301. continue;
  302. autostart = tb[CONF_AUTOSTART] && blobmsg_get_bool(tb[CONF_AUTOSTART]);
  303. ocistatus = NULL;
  304. container_pid = 0;
  305. name = blobmsg_get_string(tb[CONF_NAME]);
  306. s = avl_find_element(&runtime, name, s, avl);
  307. if (s && s->ocistate) {
  308. blobmsg_parse(state_policy, __STATE_MAX, ts, blobmsg_data(s->ocistate), blobmsg_len(s->ocistate));
  309. ocistatus = blobmsg_get_string(ts[STATE_STATUS]);
  310. container_pid = blobmsg_get_u32(ts[STATE_PID]);
  311. }
  312. printf("[%c] %s %s", autostart?'*':' ', name, ocistatus?:(s && s->running)?"creating":"stopped");
  313. if (s && !s->running && (s->exitcode >= 0))
  314. printf(" exitcode: %d (%s)", s->exitcode, strerror(s->exitcode));
  315. if (s && s->running && (s->runtime_pid >= 0))
  316. printf(" runtime pid: %d", s->runtime_pid);
  317. if (s && s->running && (container_pid >= 0))
  318. printf(" container pid: %d", container_pid);
  319. printf("\n");
  320. }
  321. return 0;
  322. }
  323. static int uxc_create(char *name, bool immediately)
  324. {
  325. static struct blob_buf req;
  326. struct blob_attr *cur, *tb[__CONF_MAX];
  327. int rem, ret;
  328. uint32_t id;
  329. struct runtime_state *s = NULL;
  330. char *path = NULL, *jailname = NULL;
  331. void *in, *ins, *j;
  332. bool found = false;
  333. blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
  334. blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
  335. if (!tb[CONF_NAME] || !tb[CONF_PATH])
  336. continue;
  337. if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
  338. continue;
  339. found = true;
  340. path = strdup(blobmsg_get_string(tb[CONF_PATH]));
  341. break;
  342. }
  343. if (!found)
  344. return ENOENT;
  345. s = avl_find_element(&runtime, name, s, avl);
  346. if (s && (s->running))
  347. return EEXIST;
  348. if (tb[CONF_JAIL])
  349. jailname = strdup(blobmsg_get_string(tb[CONF_JAIL]));
  350. blob_buf_init(&req, 0);
  351. blobmsg_add_string(&req, "name", name);
  352. ins = blobmsg_open_table(&req, "instances");
  353. in = blobmsg_open_table(&req, name);
  354. blobmsg_add_string(&req, "bundle", path);
  355. j = blobmsg_open_table(&req, "jail");
  356. blobmsg_add_string(&req, "name", jailname?:name);
  357. blobmsg_add_u8(&req, "immediately", immediately);
  358. blobmsg_close_table(&req, j);
  359. blobmsg_close_table(&req, in);
  360. blobmsg_close_table(&req, ins);
  361. ret = 0;
  362. if (ubus_lookup_id(ctx, "container", &id) ||
  363. ubus_invoke(ctx, id, "add", req.head, NULL, NULL, 3000)) {
  364. ret = EIO;
  365. }
  366. free(jailname);
  367. free(path);
  368. blob_buf_free(&req);
  369. return ret;
  370. }
  371. static int uxc_start(const char *name)
  372. {
  373. char *objname;
  374. unsigned int id;
  375. asprintf(&objname, "container.%s", name);
  376. if (ubus_lookup_id(ctx, objname, &id))
  377. return ENOENT;
  378. return ubus_invoke(ctx, id, "start", NULL, NULL, NULL, 3000);
  379. }
  380. static int uxc_kill(char *name, int signal)
  381. {
  382. static struct blob_buf req;
  383. struct blob_attr *cur, *tb[__CONF_MAX];
  384. int rem, ret;
  385. char *objname;
  386. unsigned int id;
  387. struct runtime_state *s = NULL;
  388. bool found = false;
  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. if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
  394. continue;
  395. found = true;
  396. break;
  397. }
  398. if (!found)
  399. return ENOENT;
  400. s = avl_find_element(&runtime, name, s, avl);
  401. if (!s || !(s->running))
  402. return ENOENT;
  403. blob_buf_init(&req, 0);
  404. blobmsg_add_u32(&req, "signal", signal);
  405. blobmsg_add_string(&req, "name", name);
  406. asprintf(&objname, "container.%s", name);
  407. ret = ubus_lookup_id(ctx, objname, &id);
  408. free(objname);
  409. if (ret)
  410. return ENOENT;
  411. if (ubus_invoke(ctx, id, "kill", req.head, NULL, NULL, 3000))
  412. return EIO;
  413. return 0;
  414. }
  415. static int uxc_set(char *name, char *path, bool autostart, bool add)
  416. {
  417. static struct blob_buf req;
  418. struct blob_attr *cur, *tb[__CONF_MAX];
  419. int rem, ret;
  420. bool found = false;
  421. char *fname = NULL;
  422. char *keeppath = NULL;
  423. int f;
  424. struct stat sb;
  425. blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
  426. blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
  427. if (!tb[CONF_NAME] || !tb[CONF_PATH])
  428. continue;
  429. if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
  430. continue;
  431. found = true;
  432. break;
  433. }
  434. if (found && add)
  435. return EEXIST;
  436. if (!found && !add)
  437. return ENOENT;
  438. if (add && !path)
  439. return EINVAL;
  440. if (path) {
  441. if (stat(path, &sb) == -1)
  442. return ENOENT;
  443. if ((sb.st_mode & S_IFMT) != S_IFDIR)
  444. return ENOTDIR;
  445. }
  446. ret = mkdir(UXC_CONFDIR, 0755);
  447. if (ret && errno != EEXIST)
  448. return ret;
  449. if (asprintf(&fname, "%s/%s.json", UXC_CONFDIR, name) < 1)
  450. return ENOMEM;
  451. f = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  452. if (f < 0)
  453. return errno;
  454. if (!add)
  455. keeppath = strdup(blobmsg_get_string(tb[CONF_PATH]));
  456. blob_buf_init(&req, 0);
  457. blobmsg_add_string(&req, "name", name);
  458. blobmsg_add_string(&req, "path", path?:keeppath);
  459. blobmsg_add_u8(&req, "autostart", autostart);
  460. dprintf(f, "%s\n", blobmsg_format_json_indent(req.head, true, 0));
  461. if (!add)
  462. free(keeppath);
  463. blob_buf_free(&req);
  464. return 0;
  465. }
  466. static int uxc_boot(void)
  467. {
  468. struct blob_attr *cur, *tb[__CONF_MAX];
  469. int rem, ret = 0;
  470. char *name;
  471. blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
  472. blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
  473. if (!tb[CONF_NAME] || !tb[CONF_PATH] || !tb[CONF_AUTOSTART] || !blobmsg_get_bool(tb[CONF_AUTOSTART]))
  474. continue;
  475. name = strdup(blobmsg_get_string(tb[CONF_NAME]));
  476. ret += uxc_create(name, true);
  477. free(name);
  478. }
  479. return ret;
  480. }
  481. static int uxc_delete(char *name)
  482. {
  483. struct blob_attr *cur, *tb[__CONF_MAX];
  484. int rem, ret = 0;
  485. bool found = false;
  486. char *fname;
  487. struct stat sb;
  488. blobmsg_for_each_attr(cur, blob_data(conf.head), rem) {
  489. blobmsg_parse(conf_policy, __CONF_MAX, tb, blobmsg_data(cur), blobmsg_len(cur));
  490. if (!tb[CONF_NAME] || !tb[CONF_PATH])
  491. continue;
  492. if (strcmp(name, blobmsg_get_string(tb[CONF_NAME])))
  493. continue;
  494. fname = strdup(blobmsg_name(cur));
  495. if (!fname)
  496. return errno;
  497. found = true;
  498. break;
  499. }
  500. if (!found)
  501. return ENOENT;
  502. if (stat(fname, &sb) == -1) {
  503. ret=ENOENT;
  504. goto errout;
  505. }
  506. if (unlink(fname) == -1)
  507. ret=errno;
  508. errout:
  509. free(fname);
  510. return ret;
  511. }
  512. static void reload_conf(void)
  513. {
  514. blob_buf_free(&conf);
  515. conf_load(false);
  516. }
  517. int main(int argc, char **argv)
  518. {
  519. int ret = EINVAL;
  520. if (argc < 2)
  521. return usage();
  522. ctx = ubus_connect(NULL);
  523. if (!ctx)
  524. return ENODEV;
  525. ret = conf_load(false);
  526. if (ret)
  527. goto out;
  528. ret = mkdir(UXC_RUNDIR, 0755);
  529. if (ret && errno != EEXIST)
  530. goto conf_out;
  531. ret = conf_load(true);
  532. if (ret)
  533. goto conf_out;
  534. ret = runtime_load();
  535. if (ret)
  536. goto state_out;
  537. if (!strcmp("list", argv[1]))
  538. ret = uxc_list();
  539. else if (!strcmp("boot", argv[1]))
  540. ret = uxc_boot();
  541. else if(!strcmp("start", argv[1])) {
  542. if (argc < 3)
  543. goto usage_out;
  544. ret = uxc_start(argv[2]);
  545. } else if(!strcmp("state", argv[1])) {
  546. if (argc < 3)
  547. goto usage_out;
  548. ret = uxc_state(argv[2]);
  549. } else if(!strcmp("kill", argv[1])) {
  550. int signal = SIGTERM;
  551. if (argc < 3)
  552. goto usage_out;
  553. if (argc == 4)
  554. signal = atoi(argv[3]);
  555. ret = uxc_kill(argv[2], signal);
  556. } else if(!strcmp("enable", argv[1])) {
  557. if (argc < 3)
  558. goto usage_out;
  559. ret = uxc_set(argv[2], NULL, true, false);
  560. } else if(!strcmp("disable", argv[1])) {
  561. if (argc < 3)
  562. goto usage_out;
  563. ret = uxc_set(argv[2], NULL, false, false);
  564. } else if(!strcmp("delete", argv[1])) {
  565. if (argc < 3)
  566. goto usage_out;
  567. ret = uxc_delete(argv[2]);
  568. } else if(!strcmp("create", argv[1])) {
  569. bool autostart = false;
  570. if (argc < 3)
  571. goto usage_out;
  572. if (argc == 5) {
  573. if (!strncmp("true", argv[4], 5))
  574. autostart = true;
  575. else
  576. autostart = atoi(argv[4]);
  577. }
  578. if (argc >= 4) {
  579. ret = uxc_set(argv[2], argv[3], autostart, true);
  580. if (ret)
  581. goto runtime_out;
  582. reload_conf();
  583. }
  584. ret = uxc_create(argv[2], false);
  585. } else
  586. goto usage_out;
  587. goto runtime_out;
  588. usage_out:
  589. usage();
  590. runtime_out:
  591. runtime_free();
  592. state_out:
  593. blob_buf_free(&state);
  594. conf_out:
  595. blob_buf_free(&conf);
  596. out:
  597. ubus_free(ctx);
  598. if (ret != 0)
  599. fprintf(stderr, "uxc error: %s\n", strerror(ret));
  600. return ret;
  601. }