instance.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810
  1. /*
  2. * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  3. * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU Lesser General Public License version 2.1
  7. * as published by the Free Software Foundation
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #define _GNU_SOURCE
  15. #include <sys/resource.h>
  16. #include <sys/types.h>
  17. #include <sys/socket.h>
  18. #include <sys/stat.h>
  19. #include <grp.h>
  20. #include <net/if.h>
  21. #include <unistd.h>
  22. #include <stdint.h>
  23. #include <stdio.h>
  24. #include <fcntl.h>
  25. #include <pwd.h>
  26. #include <libgen.h>
  27. #include <unistd.h>
  28. #define SYSLOG_NAMES
  29. #include <syslog.h>
  30. #include <libubox/md5.h>
  31. #include "../procd.h"
  32. #include "service.h"
  33. #include "instance.h"
  34. #define UJAIL_BIN_PATH "/sbin/ujail"
  35. #define CGROUP_BASEDIR "/sys/fs/cgroup/services"
  36. enum {
  37. INSTANCE_ATTR_COMMAND,
  38. INSTANCE_ATTR_ENV,
  39. INSTANCE_ATTR_DATA,
  40. INSTANCE_ATTR_NETDEV,
  41. INSTANCE_ATTR_FILE,
  42. INSTANCE_ATTR_TRIGGER,
  43. INSTANCE_ATTR_RESPAWN,
  44. INSTANCE_ATTR_NICE,
  45. INSTANCE_ATTR_LIMITS,
  46. INSTANCE_ATTR_WATCH,
  47. INSTANCE_ATTR_ERROR,
  48. INSTANCE_ATTR_USER,
  49. INSTANCE_ATTR_GROUP,
  50. INSTANCE_ATTR_STDOUT,
  51. INSTANCE_ATTR_STDERR,
  52. INSTANCE_ATTR_NO_NEW_PRIVS,
  53. INSTANCE_ATTR_JAIL,
  54. INSTANCE_ATTR_TRACE,
  55. INSTANCE_ATTR_SECCOMP,
  56. INSTANCE_ATTR_CAPABILITIES,
  57. INSTANCE_ATTR_PIDFILE,
  58. INSTANCE_ATTR_RELOADSIG,
  59. INSTANCE_ATTR_TERMTIMEOUT,
  60. INSTANCE_ATTR_FACILITY,
  61. INSTANCE_ATTR_EXTROOT,
  62. INSTANCE_ATTR_OVERLAYDIR,
  63. INSTANCE_ATTR_TMPOVERLAYSIZE,
  64. INSTANCE_ATTR_BUNDLE,
  65. INSTANCE_ATTR_WATCHDOG,
  66. __INSTANCE_ATTR_MAX
  67. };
  68. static const struct blobmsg_policy instance_attr[__INSTANCE_ATTR_MAX] = {
  69. [INSTANCE_ATTR_COMMAND] = { "command", BLOBMSG_TYPE_ARRAY },
  70. [INSTANCE_ATTR_ENV] = { "env", BLOBMSG_TYPE_TABLE },
  71. [INSTANCE_ATTR_DATA] = { "data", BLOBMSG_TYPE_TABLE },
  72. [INSTANCE_ATTR_NETDEV] = { "netdev", BLOBMSG_TYPE_ARRAY },
  73. [INSTANCE_ATTR_FILE] = { "file", BLOBMSG_TYPE_ARRAY },
  74. [INSTANCE_ATTR_TRIGGER] = { "triggers", BLOBMSG_TYPE_ARRAY },
  75. [INSTANCE_ATTR_RESPAWN] = { "respawn", BLOBMSG_TYPE_ARRAY },
  76. [INSTANCE_ATTR_NICE] = { "nice", BLOBMSG_TYPE_INT32 },
  77. [INSTANCE_ATTR_LIMITS] = { "limits", BLOBMSG_TYPE_TABLE },
  78. [INSTANCE_ATTR_WATCH] = { "watch", BLOBMSG_TYPE_ARRAY },
  79. [INSTANCE_ATTR_ERROR] = { "error", BLOBMSG_TYPE_ARRAY },
  80. [INSTANCE_ATTR_USER] = { "user", BLOBMSG_TYPE_STRING },
  81. [INSTANCE_ATTR_GROUP] = { "group", BLOBMSG_TYPE_STRING },
  82. [INSTANCE_ATTR_STDOUT] = { "stdout", BLOBMSG_TYPE_BOOL },
  83. [INSTANCE_ATTR_STDERR] = { "stderr", BLOBMSG_TYPE_BOOL },
  84. [INSTANCE_ATTR_NO_NEW_PRIVS] = { "no_new_privs", BLOBMSG_TYPE_BOOL },
  85. [INSTANCE_ATTR_JAIL] = { "jail", BLOBMSG_TYPE_TABLE },
  86. [INSTANCE_ATTR_TRACE] = { "trace", BLOBMSG_TYPE_BOOL },
  87. [INSTANCE_ATTR_SECCOMP] = { "seccomp", BLOBMSG_TYPE_STRING },
  88. [INSTANCE_ATTR_CAPABILITIES] = { "capabilities", BLOBMSG_TYPE_STRING },
  89. [INSTANCE_ATTR_PIDFILE] = { "pidfile", BLOBMSG_TYPE_STRING },
  90. [INSTANCE_ATTR_RELOADSIG] = { "reload_signal", BLOBMSG_TYPE_INT32 },
  91. [INSTANCE_ATTR_TERMTIMEOUT] = { "term_timeout", BLOBMSG_TYPE_INT32 },
  92. [INSTANCE_ATTR_FACILITY] = { "facility", BLOBMSG_TYPE_STRING },
  93. [INSTANCE_ATTR_EXTROOT] = { "extroot", BLOBMSG_TYPE_STRING },
  94. [INSTANCE_ATTR_OVERLAYDIR] = { "overlaydir", BLOBMSG_TYPE_STRING },
  95. [INSTANCE_ATTR_TMPOVERLAYSIZE] = { "tmpoverlaysize", BLOBMSG_TYPE_STRING },
  96. [INSTANCE_ATTR_BUNDLE] = { "bundle", BLOBMSG_TYPE_STRING },
  97. [INSTANCE_ATTR_WATCHDOG] = { "watchdog", BLOBMSG_TYPE_ARRAY },
  98. };
  99. enum {
  100. JAIL_ATTR_NAME,
  101. JAIL_ATTR_HOSTNAME,
  102. JAIL_ATTR_PROCFS,
  103. JAIL_ATTR_SYSFS,
  104. JAIL_ATTR_UBUS,
  105. JAIL_ATTR_LOG,
  106. JAIL_ATTR_RONLY,
  107. JAIL_ATTR_MOUNT,
  108. JAIL_ATTR_NETNS,
  109. JAIL_ATTR_USERNS,
  110. JAIL_ATTR_CGROUPSNS,
  111. JAIL_ATTR_CONSOLE,
  112. JAIL_ATTR_REQUIREJAIL,
  113. JAIL_ATTR_IMMEDIATELY,
  114. JAIL_ATTR_PIDFILE,
  115. JAIL_ATTR_SETNS,
  116. __JAIL_ATTR_MAX,
  117. };
  118. static const struct blobmsg_policy jail_attr[__JAIL_ATTR_MAX] = {
  119. [JAIL_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
  120. [JAIL_ATTR_HOSTNAME] = { "hostname", BLOBMSG_TYPE_STRING },
  121. [JAIL_ATTR_PROCFS] = { "procfs", BLOBMSG_TYPE_BOOL },
  122. [JAIL_ATTR_SYSFS] = { "sysfs", BLOBMSG_TYPE_BOOL },
  123. [JAIL_ATTR_UBUS] = { "ubus", BLOBMSG_TYPE_BOOL },
  124. [JAIL_ATTR_LOG] = { "log", BLOBMSG_TYPE_BOOL },
  125. [JAIL_ATTR_RONLY] = { "ronly", BLOBMSG_TYPE_BOOL },
  126. [JAIL_ATTR_MOUNT] = { "mount", BLOBMSG_TYPE_TABLE },
  127. [JAIL_ATTR_NETNS] = { "netns", BLOBMSG_TYPE_BOOL },
  128. [JAIL_ATTR_USERNS] = { "userns", BLOBMSG_TYPE_BOOL },
  129. [JAIL_ATTR_CGROUPSNS] = { "cgroupsns", BLOBMSG_TYPE_BOOL },
  130. [JAIL_ATTR_CONSOLE] = { "console", BLOBMSG_TYPE_BOOL },
  131. [JAIL_ATTR_REQUIREJAIL] = { "requirejail", BLOBMSG_TYPE_BOOL },
  132. [JAIL_ATTR_IMMEDIATELY] = { "immediately", BLOBMSG_TYPE_BOOL },
  133. [JAIL_ATTR_PIDFILE] = { "pidfile", BLOBMSG_TYPE_STRING },
  134. [JAIL_ATTR_SETNS] = { "setns", BLOBMSG_TYPE_ARRAY },
  135. };
  136. enum {
  137. JAIL_SETNS_ATTR_PID,
  138. JAIL_SETNS_ATTR_NS,
  139. __JAIL_SETNS_ATTR_MAX,
  140. };
  141. static const struct blobmsg_policy jail_setns_attr[__JAIL_SETNS_ATTR_MAX] = {
  142. [JAIL_SETNS_ATTR_PID] = { "pid", BLOBMSG_TYPE_INT32 },
  143. [JAIL_SETNS_ATTR_NS] = { "namespaces", BLOBMSG_TYPE_ARRAY },
  144. };
  145. struct instance_netdev {
  146. struct blobmsg_list_node node;
  147. int ifindex;
  148. };
  149. struct instance_file {
  150. struct blobmsg_list_node node;
  151. uint32_t md5[4];
  152. };
  153. struct rlimit_name {
  154. const char *name;
  155. int resource;
  156. };
  157. static const struct rlimit_name rlimit_names[] = {
  158. { "as", RLIMIT_AS },
  159. { "core", RLIMIT_CORE },
  160. { "cpu", RLIMIT_CPU },
  161. { "data", RLIMIT_DATA },
  162. { "fsize", RLIMIT_FSIZE },
  163. { "memlock", RLIMIT_MEMLOCK },
  164. { "nofile", RLIMIT_NOFILE },
  165. { "nproc", RLIMIT_NPROC },
  166. { "rss", RLIMIT_RSS },
  167. { "stack", RLIMIT_STACK },
  168. #ifdef linux
  169. { "nice", RLIMIT_NICE },
  170. { "rtprio", RLIMIT_RTPRIO },
  171. { "msgqueue", RLIMIT_MSGQUEUE },
  172. { "sigpending", RLIMIT_SIGPENDING },
  173. #endif
  174. { NULL, 0 }
  175. };
  176. static void closefd(int fd)
  177. {
  178. if (fd > STDERR_FILENO)
  179. close(fd);
  180. }
  181. /* convert a string into numeric syslog facility or return -1 if no match found */
  182. static int
  183. syslog_facility_str_to_int(const char *facility)
  184. {
  185. CODE *p = facilitynames;
  186. while (p->c_name && strcasecmp(p->c_name, facility))
  187. p++;
  188. return p->c_val;
  189. }
  190. static void
  191. instance_limits(const char *limit, const char *value)
  192. {
  193. int i;
  194. struct rlimit rlim;
  195. unsigned long cur, max;
  196. for (i = 0; rlimit_names[i].name != NULL; i++) {
  197. if (strcmp(rlimit_names[i].name, limit))
  198. continue;
  199. if (!strcmp(value, "unlimited")) {
  200. rlim.rlim_cur = RLIM_INFINITY;
  201. rlim.rlim_max = RLIM_INFINITY;
  202. } else {
  203. if (getrlimit(rlimit_names[i].resource, &rlim))
  204. return;
  205. cur = rlim.rlim_cur;
  206. max = rlim.rlim_max;
  207. if (sscanf(value, "%lu %lu", &cur, &max) < 1)
  208. return;
  209. rlim.rlim_cur = cur;
  210. rlim.rlim_max = max;
  211. }
  212. setrlimit(rlimit_names[i].resource, &rlim);
  213. return;
  214. }
  215. }
  216. static char *
  217. instance_gen_setns_argstr(struct blob_attr *attr)
  218. {
  219. struct blob_attr *tb[__JAIL_SETNS_ATTR_MAX];
  220. struct blob_attr *cur;
  221. int rem, len, total;
  222. char *ret;
  223. blobmsg_parse(jail_setns_attr, __JAIL_SETNS_ATTR_MAX, tb,
  224. blobmsg_data(attr), blobmsg_data_len(attr));
  225. if (!tb[JAIL_SETNS_ATTR_PID] || !tb[JAIL_SETNS_ATTR_NS])
  226. return NULL;
  227. len = snprintf(NULL, 0, "%d:", blobmsg_get_u32(tb[JAIL_SETNS_ATTR_PID]));
  228. blobmsg_for_each_attr(cur, tb[JAIL_SETNS_ATTR_NS], rem) {
  229. char *tmp;
  230. if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
  231. return NULL;
  232. tmp = blobmsg_get_string(cur);
  233. if (!tmp)
  234. return NULL;
  235. len += strlen(tmp) + 1;
  236. }
  237. total = len;
  238. ret = malloc(total);
  239. if (!ret)
  240. return NULL;
  241. len = snprintf(ret, total, "%d:", blobmsg_get_u32(tb[JAIL_SETNS_ATTR_PID]));
  242. blobmsg_for_each_attr(cur, tb[JAIL_SETNS_ATTR_NS], rem) {
  243. strncpy(&ret[len], blobmsg_get_string(cur), total - len);
  244. len += strlen(blobmsg_get_string(cur));
  245. ret[len++] = ',';
  246. }
  247. ret[total - 1] = '\0';
  248. return ret;
  249. }
  250. static inline int
  251. jail_run(struct service_instance *in, char **argv)
  252. {
  253. char *term_timeout_str;
  254. struct blobmsg_list_node *var;
  255. struct jail *jail = &in->jail;
  256. int argc = 0;
  257. argv[argc++] = UJAIL_BIN_PATH;
  258. if (asprintf(&term_timeout_str, "%d", in->term_timeout) == -1)
  259. exit(ENOMEM);
  260. argv[argc++] = "-t";
  261. argv[argc++] = term_timeout_str;
  262. if (jail->name) {
  263. argv[argc++] = "-n";
  264. argv[argc++] = jail->name;
  265. }
  266. if (jail->hostname) {
  267. argv[argc++] = "-h";
  268. argv[argc++] = jail->hostname;
  269. }
  270. if (in->seccomp) {
  271. argv[argc++] = "-S";
  272. argv[argc++] = in->seccomp;
  273. }
  274. if (in->user) {
  275. argv[argc++] = "-U";
  276. argv[argc++] = in->user;
  277. }
  278. if (in->group) {
  279. argv[argc++] = "-G";
  280. argv[argc++] = in->group;
  281. }
  282. if (in->capabilities) {
  283. argv[argc++] = "-C";
  284. argv[argc++] = in->capabilities;
  285. }
  286. if (in->no_new_privs)
  287. argv[argc++] = "-c";
  288. if (jail->procfs)
  289. argv[argc++] = "-p";
  290. if (jail->sysfs)
  291. argv[argc++] = "-s";
  292. if (jail->ubus)
  293. argv[argc++] = "-u";
  294. if (jail->log)
  295. argv[argc++] = "-l";
  296. if (jail->ronly)
  297. argv[argc++] = "-o";
  298. if (jail->netns)
  299. argv[argc++] = "-N";
  300. if (jail->userns)
  301. argv[argc++] = "-f";
  302. if (jail->cgroupsns)
  303. argv[argc++] = "-F";
  304. if (jail->console)
  305. argv[argc++] = "-y";
  306. if (in->extroot) {
  307. argv[argc++] = "-R";
  308. argv[argc++] = in->extroot;
  309. }
  310. if (in->overlaydir) {
  311. argv[argc++] = "-O";
  312. argv[argc++] = in->overlaydir;
  313. }
  314. if (in->tmpoverlaysize) {
  315. argv[argc++] = "-T";
  316. argv[argc++] = in->tmpoverlaysize;
  317. }
  318. if (in->immediately)
  319. argv[argc++] = "-i";
  320. if (jail->pidfile) {
  321. argv[argc++] = "-P";
  322. argv[argc++] = jail->pidfile;
  323. }
  324. if (in->bundle) {
  325. argv[argc++] = "-J";
  326. argv[argc++] = in->bundle;
  327. }
  328. if (in->require_jail)
  329. argv[argc++] = "-E";
  330. blobmsg_list_for_each(&in->env, var) {
  331. argv[argc++] = "-e";
  332. argv[argc++] = (char *) blobmsg_name(var->data);
  333. }
  334. blobmsg_list_for_each(&jail->mount, var) {
  335. const char *type = blobmsg_data(var->data);
  336. if (*type == '1')
  337. argv[argc++] = "-w";
  338. else
  339. argv[argc++] = "-r";
  340. argv[argc++] = (char *) blobmsg_name(var->data);
  341. }
  342. blobmsg_list_for_each(&jail->setns, var) {
  343. char *setns_arg = instance_gen_setns_argstr(var->data);
  344. if (setns_arg) {
  345. argv[argc++] = "-j";
  346. argv[argc++] = setns_arg;
  347. }
  348. }
  349. argv[argc++] = "--";
  350. return argc;
  351. }
  352. static int
  353. instance_removepid(struct service_instance *in) {
  354. if (!in->pidfile)
  355. return 0;
  356. if (unlink(in->pidfile)) {
  357. ERROR("Failed to remove pidfile: %s: %m\n", in->pidfile);
  358. return 1;
  359. }
  360. return 0;
  361. }
  362. static int
  363. instance_writepid(struct service_instance *in)
  364. {
  365. FILE *_pidfile;
  366. if (!in->pidfile) {
  367. return 0;
  368. }
  369. _pidfile = fopen(in->pidfile, "w");
  370. if (_pidfile == NULL) {
  371. ERROR("failed to open pidfile for writing: %s: %m", in->pidfile);
  372. return 1;
  373. }
  374. if (fprintf(_pidfile, "%d\n", in->proc.pid) < 0) {
  375. ERROR("failed to write pidfile: %s: %m", in->pidfile);
  376. fclose(_pidfile);
  377. return 2;
  378. }
  379. if (fclose(_pidfile)) {
  380. ERROR("failed to close pidfile: %s: %m", in->pidfile);
  381. return 3;
  382. }
  383. return 0;
  384. }
  385. static void
  386. instance_run(struct service_instance *in, int _stdout, int _stderr)
  387. {
  388. struct blobmsg_list_node *var;
  389. struct blob_attr *cur;
  390. char **argv;
  391. int argc = 1; /* NULL terminated */
  392. int rem, _stdin;
  393. bool seccomp = !in->trace && !in->has_jail && in->seccomp;
  394. bool setlbf = _stdout >= 0;
  395. if (in->nice)
  396. setpriority(PRIO_PROCESS, 0, in->nice);
  397. blobmsg_for_each_attr(cur, in->command, rem)
  398. argc++;
  399. blobmsg_list_for_each(&in->env, var)
  400. setenv(blobmsg_name(var->data), blobmsg_data(var->data), 1);
  401. if (seccomp)
  402. setenv("SECCOMP_FILE", in->seccomp, 1);
  403. if (setlbf)
  404. setenv("LD_PRELOAD", "/lib/libsetlbf.so", 1);
  405. blobmsg_list_for_each(&in->limits, var)
  406. instance_limits(blobmsg_name(var->data), blobmsg_data(var->data));
  407. if (in->trace || seccomp)
  408. argc += 1;
  409. argv = alloca(sizeof(char *) * (argc + in->jail.argc));
  410. argc = 0;
  411. #ifdef SECCOMP_SUPPORT
  412. if (in->trace)
  413. argv[argc++] = "/sbin/utrace";
  414. else if (seccomp)
  415. argv[argc++] = "/sbin/seccomp-trace";
  416. #else
  417. if (in->trace || seccomp)
  418. ULOG_WARN("Seccomp support for %s::%s not available\n", in->srv->name, in->name);
  419. #endif
  420. if (in->has_jail) {
  421. argc = jail_run(in, argv);
  422. if (argc != in->jail.argc)
  423. ULOG_WARN("expected %i jail params, used %i for %s::%s\n",
  424. in->jail.argc, argc, in->srv->name, in->name);
  425. }
  426. blobmsg_for_each_attr(cur, in->command, rem)
  427. argv[argc++] = blobmsg_data(cur);
  428. argv[argc] = NULL;
  429. _stdin = open("/dev/null", O_RDONLY);
  430. if (_stdout == -1)
  431. _stdout = open("/dev/null", O_WRONLY);
  432. if (_stderr == -1)
  433. _stderr = open("/dev/null", O_WRONLY);
  434. if (_stdin > -1) {
  435. dup2(_stdin, STDIN_FILENO);
  436. closefd(_stdin);
  437. }
  438. if (_stdout > -1) {
  439. dup2(_stdout, STDOUT_FILENO);
  440. closefd(_stdout);
  441. }
  442. if (_stderr > -1) {
  443. dup2(_stderr, STDERR_FILENO);
  444. closefd(_stderr);
  445. }
  446. if (!in->has_jail && in->user && in->pw_gid && initgroups(in->user, in->pw_gid)) {
  447. ERROR("failed to initgroups() for user %s: %m\n", in->user);
  448. exit(127);
  449. }
  450. if (!in->has_jail && in->gr_gid && setgid(in->gr_gid)) {
  451. ERROR("failed to set group id %d: %m\n", in->gr_gid);
  452. exit(127);
  453. }
  454. if (!in->has_jail && in->uid && setuid(in->uid)) {
  455. ERROR("failed to set user id %d: %m\n", in->uid);
  456. exit(127);
  457. }
  458. execvp(argv[0], argv);
  459. exit(127);
  460. }
  461. static void
  462. instance_add_cgroup(const char *service, const char *instance)
  463. {
  464. struct stat sb;
  465. char cgnamebuf[256];
  466. int fd;
  467. if (stat("/sys/fs/cgroup/cgroup.subtree_control", &sb))
  468. return;
  469. mkdir(CGROUP_BASEDIR, 0700);
  470. snprintf(cgnamebuf, sizeof(cgnamebuf), "%s/%s", CGROUP_BASEDIR, service);
  471. mkdir(cgnamebuf, 0700);
  472. snprintf(cgnamebuf, sizeof(cgnamebuf), "%s/%s/%s", CGROUP_BASEDIR, service, instance);
  473. mkdir(cgnamebuf, 0700);
  474. strcat(cgnamebuf, "/cgroup.procs");
  475. fd = open(cgnamebuf, O_WRONLY);
  476. if (fd == -1)
  477. return;
  478. dprintf(fd, "%d", getpid());
  479. close(fd);
  480. }
  481. static void
  482. instance_free_stdio(struct service_instance *in)
  483. {
  484. if (in->_stdout.fd.fd > -1) {
  485. ustream_free(&in->_stdout.stream);
  486. close(in->_stdout.fd.fd);
  487. in->_stdout.fd.fd = -1;
  488. }
  489. if (in->_stderr.fd.fd > -1) {
  490. ustream_free(&in->_stderr.stream);
  491. close(in->_stderr.fd.fd);
  492. in->_stderr.fd.fd = -1;
  493. }
  494. if (in->console.fd.fd > -1) {
  495. ustream_free(&in->console.stream);
  496. close(in->console.fd.fd);
  497. in->console.fd.fd = -1;
  498. }
  499. if (in->console_client.fd.fd > -1) {
  500. ustream_free(&in->console_client.stream);
  501. close(in->console_client.fd.fd);
  502. in->console_client.fd.fd = -1;
  503. }
  504. }
  505. void
  506. instance_start(struct service_instance *in)
  507. {
  508. int pid;
  509. int opipe[2] = { -1, -1 };
  510. int epipe[2] = { -1, -1 };
  511. if (!avl_is_empty(&in->errors.avl)) {
  512. LOG("Not starting instance %s::%s, an error was indicated\n", in->srv->name, in->name);
  513. return;
  514. }
  515. if (!in->bundle && !in->command) {
  516. LOG("Not starting instance %s::%s, command not set\n", in->srv->name, in->name);
  517. return;
  518. }
  519. if (in->proc.pending) {
  520. if (in->halt)
  521. in->restart = true;
  522. return;
  523. }
  524. instance_free_stdio(in);
  525. if (in->_stdout.fd.fd > -2) {
  526. if (pipe(opipe)) {
  527. ULOG_WARN("pipe() failed: %m\n");
  528. opipe[0] = opipe[1] = -1;
  529. }
  530. }
  531. if (in->_stderr.fd.fd > -2) {
  532. if (pipe(epipe)) {
  533. ULOG_WARN("pipe() failed: %m\n");
  534. epipe[0] = epipe[1] = -1;
  535. }
  536. }
  537. in->restart = false;
  538. in->halt = false;
  539. if (!in->valid)
  540. return;
  541. pid = fork();
  542. if (pid < 0)
  543. return;
  544. if (!pid) {
  545. uloop_done();
  546. closefd(opipe[0]);
  547. closefd(epipe[0]);
  548. instance_add_cgroup(in->srv->name, in->name);
  549. instance_run(in, opipe[1], epipe[1]);
  550. return;
  551. }
  552. P_DEBUG(2, "Started instance %s::%s[%d]\n", in->srv->name, in->name, pid);
  553. in->proc.pid = pid;
  554. instance_writepid(in);
  555. clock_gettime(CLOCK_MONOTONIC, &in->start);
  556. uloop_process_add(&in->proc);
  557. if (opipe[0] > -1) {
  558. ustream_fd_init(&in->_stdout, opipe[0]);
  559. closefd(opipe[1]);
  560. fcntl(opipe[0], F_SETFD, FD_CLOEXEC);
  561. }
  562. if (epipe[0] > -1) {
  563. ustream_fd_init(&in->_stderr, epipe[0]);
  564. closefd(epipe[1]);
  565. fcntl(epipe[0], F_SETFD, FD_CLOEXEC);
  566. }
  567. if (in->watchdog.mode != INSTANCE_WATCHDOG_MODE_DISABLED) {
  568. uloop_timeout_set(&in->watchdog.timeout, in->watchdog.freq * 1000);
  569. P_DEBUG(2, "Started instance %s::%s watchdog timer : timeout = %d\n", in->srv->name, in->name, in->watchdog.freq);
  570. }
  571. service_event("instance.start", in->srv->name, in->name);
  572. }
  573. static void
  574. instance_stdio(struct ustream *s, int prio, struct service_instance *in)
  575. {
  576. char *newline, *str, *arg0, ident[32];
  577. int len;
  578. arg0 = basename(blobmsg_data(blobmsg_data(in->command)));
  579. snprintf(ident, sizeof(ident), "%s[%d]", arg0, in->proc.pid);
  580. ulog_open(ULOG_SYSLOG, in->syslog_facility, ident);
  581. do {
  582. str = ustream_get_read_buf(s, &len);
  583. if (!str)
  584. break;
  585. newline = memchr(str, '\n', len);
  586. if (!newline && (s->r.buffer_len != len))
  587. break;
  588. if (newline) {
  589. *newline = 0;
  590. len = newline + 1 - str;
  591. }
  592. ulog(prio, "%s\n", str);
  593. ustream_consume(s, len);
  594. } while (1);
  595. ulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd");
  596. }
  597. static void
  598. instance_stdout(struct ustream *s, int bytes)
  599. {
  600. instance_stdio(s, LOG_INFO,
  601. container_of(s, struct service_instance, _stdout.stream));
  602. }
  603. static void
  604. instance_console(struct ustream *s, int bytes)
  605. {
  606. struct service_instance *in = container_of(s, struct service_instance, console.stream);
  607. char *buf;
  608. int len;
  609. do {
  610. buf = ustream_get_read_buf(s, &len);
  611. if (!buf)
  612. break;
  613. ulog(LOG_INFO, "out: %s\n", buf);
  614. /* test if console client is attached */
  615. if (in->console_client.fd.fd > -1)
  616. ustream_write(&in->console_client.stream, buf, len, false);
  617. ustream_consume(s, len);
  618. } while (1);
  619. }
  620. static void
  621. instance_console_client(struct ustream *s, int bytes)
  622. {
  623. struct service_instance *in = container_of(s, struct service_instance, console_client.stream);
  624. char *buf;
  625. int len;
  626. do {
  627. buf = ustream_get_read_buf(s, &len);
  628. if (!buf)
  629. break;
  630. ulog(LOG_INFO, "in: %s\n", buf);
  631. ustream_write(&in->console.stream, buf, len, false);
  632. ustream_consume(s, len);
  633. } while (1);
  634. }
  635. static void
  636. instance_stderr(struct ustream *s, int bytes)
  637. {
  638. instance_stdio(s, LOG_ERR,
  639. container_of(s, struct service_instance, _stderr.stream));
  640. }
  641. static void
  642. instance_timeout(struct uloop_timeout *t)
  643. {
  644. struct service_instance *in;
  645. in = container_of(t, struct service_instance, timeout);
  646. if (in->halt) {
  647. LOG("Instance %s::%s pid %d not stopped on SIGTERM, sending SIGKILL instead\n",
  648. in->srv->name, in->name, in->proc.pid);
  649. kill(in->proc.pid, SIGKILL);
  650. } else if (in->restart || in->respawn)
  651. instance_start(in);
  652. }
  653. static void
  654. instance_delete(struct service_instance *in)
  655. {
  656. struct service *s = in->srv;
  657. avl_delete(&s->instances.avl, &in->node.avl);
  658. instance_free(in);
  659. service_stopped(s);
  660. }
  661. static int
  662. instance_exit_code(int ret)
  663. {
  664. if (WIFEXITED(ret)) {
  665. return WEXITSTATUS(ret);
  666. }
  667. if (WIFSIGNALED(ret)) {
  668. return SIGNALLED_OFFSET + WTERMSIG(ret);
  669. }
  670. if (WIFSTOPPED(ret)) {
  671. return WSTOPSIG(ret);
  672. }
  673. return 1;
  674. }
  675. static void
  676. instance_exit(struct uloop_process *p, int ret)
  677. {
  678. struct service_instance *in;
  679. struct timespec tp;
  680. long runtime;
  681. in = container_of(p, struct service_instance, proc);
  682. clock_gettime(CLOCK_MONOTONIC, &tp);
  683. runtime = tp.tv_sec - in->start.tv_sec;
  684. P_DEBUG(2, "Instance %s::%s exit with error code %d after %ld seconds\n", in->srv->name, in->name, ret, runtime);
  685. in->exit_code = instance_exit_code(ret);
  686. uloop_timeout_cancel(&in->timeout);
  687. uloop_timeout_cancel(&in->watchdog.timeout);
  688. service_event("instance.stop", in->srv->name, in->name);
  689. if (in->halt) {
  690. instance_removepid(in);
  691. if (in->restart)
  692. instance_start(in);
  693. else
  694. instance_delete(in);
  695. } else if (in->restart) {
  696. instance_start(in);
  697. } else if (in->respawn) {
  698. if (runtime < in->respawn_threshold)
  699. in->respawn_count++;
  700. else
  701. in->respawn_count = 0;
  702. if (in->respawn_count > in->respawn_retry && in->respawn_retry > 0 ) {
  703. LOG("Instance %s::%s s in a crash loop %d crashes, %ld seconds since last crash\n",
  704. in->srv->name, in->name, in->respawn_count, runtime);
  705. in->restart = in->respawn = 0;
  706. in->halt = 1;
  707. service_event("instance.fail", in->srv->name, in->name);
  708. } else {
  709. service_event("instance.respawn", in->srv->name, in->name);
  710. uloop_timeout_set(&in->timeout, in->respawn_timeout * 1000);
  711. }
  712. }
  713. }
  714. void
  715. instance_stop(struct service_instance *in, bool halt)
  716. {
  717. if (!in->proc.pending) {
  718. if (halt)
  719. instance_delete(in);
  720. return;
  721. }
  722. in->halt = halt;
  723. in->restart = in->respawn = false;
  724. kill(in->proc.pid, SIGTERM);
  725. if (!in->has_jail)
  726. uloop_timeout_set(&in->timeout, in->term_timeout * 1000);
  727. }
  728. static void
  729. instance_restart(struct service_instance *in)
  730. {
  731. if (!in->proc.pending)
  732. return;
  733. if (in->reload_signal) {
  734. kill(in->proc.pid, in->reload_signal);
  735. return;
  736. }
  737. in->halt = true;
  738. in->restart = true;
  739. kill(in->proc.pid, SIGTERM);
  740. if (!in->has_jail)
  741. uloop_timeout_set(&in->timeout, in->term_timeout * 1000);
  742. }
  743. static void
  744. instance_watchdog(struct uloop_timeout *t)
  745. {
  746. struct service_instance *in = container_of(t, struct service_instance, watchdog.timeout);
  747. P_DEBUG(3, "instance %s::%s watchdog timer expired\n", in->srv->name, in->name);
  748. if (in->respawn)
  749. instance_restart(in);
  750. else
  751. instance_stop(in, true);
  752. }
  753. static bool string_changed(const char *a, const char *b)
  754. {
  755. return !((!a && !b) || (a && b && !strcmp(a, b)));
  756. }
  757. static bool
  758. instance_config_changed(struct service_instance *in, struct service_instance *in_new)
  759. {
  760. if (!in->valid)
  761. return true;
  762. if (!blob_attr_equal(in->command, in_new->command))
  763. return true;
  764. if (string_changed(in->bundle, in_new->bundle))
  765. return true;
  766. if (string_changed(in->extroot, in_new->extroot))
  767. return true;
  768. if (string_changed(in->overlaydir, in_new->overlaydir))
  769. return true;
  770. if (string_changed(in->tmpoverlaysize, in_new->tmpoverlaysize))
  771. return true;
  772. if (!blobmsg_list_equal(&in->env, &in_new->env))
  773. return true;
  774. if (!blobmsg_list_equal(&in->netdev, &in_new->netdev))
  775. return true;
  776. if (!blobmsg_list_equal(&in->file, &in_new->file))
  777. return true;
  778. if (in->nice != in_new->nice)
  779. return true;
  780. if (in->syslog_facility != in_new->syslog_facility)
  781. return true;
  782. if (string_changed(in->user, in_new->user))
  783. return true;
  784. if (string_changed(in->group, in_new->group))
  785. return true;
  786. if (in->uid != in_new->uid)
  787. return true;
  788. if (in->pw_gid != in_new->pw_gid)
  789. return true;
  790. if (in->gr_gid != in_new->gr_gid)
  791. return true;
  792. if (string_changed(in->pidfile, in_new->pidfile))
  793. return true;
  794. if (in->respawn_retry != in_new->respawn_retry)
  795. return true;
  796. if (in->respawn_threshold != in_new->respawn_threshold)
  797. return true;
  798. if (in->respawn_timeout != in_new->respawn_timeout)
  799. return true;
  800. if (in->reload_signal != in_new->reload_signal)
  801. return true;
  802. if (in->term_timeout != in_new->term_timeout)
  803. return true;
  804. if (string_changed(in->seccomp, in_new->seccomp))
  805. return true;
  806. if (string_changed(in->capabilities, in_new->capabilities))
  807. return true;
  808. if (!blobmsg_list_equal(&in->limits, &in_new->limits))
  809. return true;
  810. if (!blobmsg_list_equal(&in->jail.mount, &in_new->jail.mount))
  811. return true;
  812. if (!blobmsg_list_equal(&in->jail.setns, &in_new->jail.setns))
  813. return true;
  814. if (!blobmsg_list_equal(&in->errors, &in_new->errors))
  815. return true;
  816. if (in->has_jail != in_new->has_jail)
  817. return true;
  818. if (in->trace != in_new->trace)
  819. return true;
  820. if (in->require_jail != in_new->require_jail)
  821. return true;
  822. if (in->immediately != in_new->immediately)
  823. return true;
  824. if (in->no_new_privs != in_new->no_new_privs)
  825. return true;
  826. if (string_changed(in->jail.name, in_new->jail.name))
  827. return true;
  828. if (string_changed(in->jail.hostname, in_new->jail.hostname))
  829. return true;
  830. if (string_changed(in->jail.pidfile, in_new->jail.pidfile))
  831. return true;
  832. if (in->jail.procfs != in_new->jail.procfs)
  833. return true;
  834. if (in->jail.sysfs != in_new->jail.sysfs)
  835. return true;
  836. if (in->jail.ubus != in_new->jail.ubus)
  837. return true;
  838. if (in->jail.log != in_new->jail.log)
  839. return true;
  840. if (in->jail.ronly != in_new->jail.ronly)
  841. return true;
  842. if (in->jail.netns != in_new->jail.netns)
  843. return true;
  844. if (in->jail.userns != in_new->jail.userns)
  845. return true;
  846. if (in->jail.cgroupsns != in_new->jail.cgroupsns)
  847. return true;
  848. if (in->jail.console != in_new->jail.console)
  849. return true;
  850. if (in->watchdog.mode != in_new->watchdog.mode)
  851. return true;
  852. if (in->watchdog.freq != in_new->watchdog.freq)
  853. return true;
  854. return false;
  855. }
  856. static bool
  857. instance_netdev_cmp(struct blobmsg_list_node *l1, struct blobmsg_list_node *l2)
  858. {
  859. struct instance_netdev *n1 = container_of(l1, struct instance_netdev, node);
  860. struct instance_netdev *n2 = container_of(l2, struct instance_netdev, node);
  861. return n1->ifindex == n2->ifindex;
  862. }
  863. static void
  864. instance_netdev_update(struct blobmsg_list_node *l)
  865. {
  866. struct instance_netdev *n = container_of(l, struct instance_netdev, node);
  867. n->ifindex = if_nametoindex(n->node.avl.key);
  868. }
  869. static bool
  870. instance_file_cmp(struct blobmsg_list_node *l1, struct blobmsg_list_node *l2)
  871. {
  872. struct instance_file *f1 = container_of(l1, struct instance_file, node);
  873. struct instance_file *f2 = container_of(l2, struct instance_file, node);
  874. return !memcmp(f1->md5, f2->md5, sizeof(f1->md5));
  875. }
  876. static void
  877. instance_file_update(struct blobmsg_list_node *l)
  878. {
  879. struct instance_file *f = container_of(l, struct instance_file, node);
  880. md5_ctx_t md5;
  881. char buf[256];
  882. int len, fd;
  883. memset(f->md5, 0, sizeof(f->md5));
  884. fd = open(l->avl.key, O_RDONLY);
  885. if (fd < 0)
  886. return;
  887. md5_begin(&md5);
  888. do {
  889. len = read(fd, buf, sizeof(buf));
  890. if (len < 0) {
  891. if (errno == EINTR)
  892. continue;
  893. break;
  894. }
  895. if (!len)
  896. break;
  897. md5_hash(buf, len, &md5);
  898. } while(1);
  899. md5_end(f->md5, &md5);
  900. close(fd);
  901. }
  902. static void
  903. instance_fill_any(struct blobmsg_list *l, struct blob_attr *cur)
  904. {
  905. if (!cur)
  906. return;
  907. blobmsg_list_fill(l, blobmsg_data(cur), blobmsg_data_len(cur), false);
  908. }
  909. static bool
  910. instance_fill_array(struct blobmsg_list *l, struct blob_attr *cur, blobmsg_update_cb cb, bool array)
  911. {
  912. struct blobmsg_list_node *node;
  913. if (!cur)
  914. return true;
  915. if (!blobmsg_check_attr_list(cur, BLOBMSG_TYPE_STRING))
  916. return false;
  917. blobmsg_list_fill(l, blobmsg_data(cur), blobmsg_data_len(cur), array);
  918. if (cb) {
  919. blobmsg_list_for_each(l, node)
  920. cb(node);
  921. }
  922. return true;
  923. }
  924. static int
  925. instance_jail_parse(struct service_instance *in, struct blob_attr *attr)
  926. {
  927. struct blob_attr *tb[__JAIL_ATTR_MAX];
  928. struct jail *jail = &in->jail;
  929. struct blobmsg_list_node *var;
  930. blobmsg_parse(jail_attr, __JAIL_ATTR_MAX, tb,
  931. blobmsg_data(attr), blobmsg_data_len(attr));
  932. jail->argc = 4;
  933. if (tb[JAIL_ATTR_REQUIREJAIL] && blobmsg_get_bool(tb[JAIL_ATTR_REQUIREJAIL])) {
  934. in->require_jail = true;
  935. jail->argc++;
  936. }
  937. if (tb[JAIL_ATTR_IMMEDIATELY] && blobmsg_get_bool(tb[JAIL_ATTR_IMMEDIATELY])) {
  938. in->immediately = true;
  939. jail->argc++;
  940. }
  941. if (tb[JAIL_ATTR_NAME]) {
  942. jail->name = strdup(blobmsg_get_string(tb[JAIL_ATTR_NAME]));
  943. jail->argc += 2;
  944. }
  945. if (tb[JAIL_ATTR_HOSTNAME]) {
  946. jail->hostname = strdup(blobmsg_get_string(tb[JAIL_ATTR_HOSTNAME]));
  947. jail->argc += 2;
  948. }
  949. if (tb[JAIL_ATTR_PROCFS] && blobmsg_get_bool(tb[JAIL_ATTR_PROCFS])) {
  950. jail->procfs = true;
  951. jail->argc++;
  952. }
  953. if (tb[JAIL_ATTR_SYSFS] && blobmsg_get_bool(tb[JAIL_ATTR_SYSFS])) {
  954. jail->sysfs = true;
  955. jail->argc++;
  956. }
  957. if (tb[JAIL_ATTR_UBUS] && blobmsg_get_bool(tb[JAIL_ATTR_UBUS])) {
  958. jail->ubus = true;
  959. jail->argc++;
  960. }
  961. if (tb[JAIL_ATTR_LOG] && blobmsg_get_bool(tb[JAIL_ATTR_LOG])) {
  962. jail->log = true;
  963. jail->argc++;
  964. }
  965. if (tb[JAIL_ATTR_RONLY] && blobmsg_get_bool(tb[JAIL_ATTR_RONLY])) {
  966. jail->ronly = true;
  967. jail->argc++;
  968. }
  969. if (tb[JAIL_ATTR_NETNS] && blobmsg_get_bool(tb[JAIL_ATTR_NETNS])) {
  970. jail->netns = true;
  971. jail->argc++;
  972. }
  973. if (tb[JAIL_ATTR_USERNS] && blobmsg_get_bool(tb[JAIL_ATTR_USERNS])) {
  974. jail->userns = true;
  975. jail->argc++;
  976. }
  977. if (tb[JAIL_ATTR_CGROUPSNS] && blobmsg_get_bool(tb[JAIL_ATTR_CGROUPSNS])) {
  978. jail->cgroupsns = true;
  979. jail->argc++;
  980. }
  981. if (tb[JAIL_ATTR_CONSOLE] && blobmsg_get_bool(tb[JAIL_ATTR_CONSOLE])) {
  982. jail->console = true;
  983. jail->argc++;
  984. }
  985. if (tb[JAIL_ATTR_PIDFILE]) {
  986. jail->pidfile = strdup(blobmsg_get_string(tb[JAIL_ATTR_PIDFILE]));
  987. jail->argc += 2;
  988. }
  989. if (tb[JAIL_ATTR_SETNS]) {
  990. struct blob_attr *cur;
  991. int rem;
  992. blobmsg_for_each_attr(cur, tb[JAIL_ATTR_SETNS], rem)
  993. jail->argc += 2;
  994. blobmsg_list_fill(&jail->setns, blobmsg_data(tb[JAIL_ATTR_SETNS]),
  995. blobmsg_data_len(tb[JAIL_ATTR_SETNS]), true);
  996. }
  997. if (tb[JAIL_ATTR_MOUNT]) {
  998. struct blob_attr *cur;
  999. int rem;
  1000. blobmsg_for_each_attr(cur, tb[JAIL_ATTR_MOUNT], rem)
  1001. jail->argc += 2;
  1002. instance_fill_array(&jail->mount, tb[JAIL_ATTR_MOUNT], NULL, false);
  1003. }
  1004. blobmsg_list_for_each(&in->env, var)
  1005. jail->argc += 2;
  1006. if (in->seccomp)
  1007. jail->argc += 2;
  1008. if (in->capabilities)
  1009. jail->argc += 2;
  1010. if (in->user)
  1011. jail->argc += 2;
  1012. if (in->group)
  1013. jail->argc += 2;
  1014. if (in->extroot)
  1015. jail->argc += 2;
  1016. if (in->overlaydir)
  1017. jail->argc += 2;
  1018. if (in->tmpoverlaysize)
  1019. jail->argc += 2;
  1020. if (in->no_new_privs)
  1021. jail->argc++;
  1022. if (in->bundle)
  1023. jail->argc += 2;
  1024. return true;
  1025. }
  1026. static bool
  1027. instance_config_parse_command(struct service_instance *in, struct blob_attr **tb)
  1028. {
  1029. struct blob_attr *cur, *cur2;
  1030. bool ret = false;
  1031. int rem;
  1032. cur = tb[INSTANCE_ATTR_COMMAND];
  1033. if (!cur) {
  1034. in->command = NULL;
  1035. return true;
  1036. }
  1037. if (!blobmsg_check_attr_list(cur, BLOBMSG_TYPE_STRING))
  1038. return false;
  1039. blobmsg_for_each_attr(cur2, cur, rem) {
  1040. ret = true;
  1041. break;
  1042. }
  1043. in->command = cur;
  1044. return ret;
  1045. }
  1046. static bool
  1047. instance_config_parse(struct service_instance *in)
  1048. {
  1049. struct blob_attr *tb[__INSTANCE_ATTR_MAX];
  1050. struct blob_attr *cur, *cur2;
  1051. struct stat s;
  1052. int rem, r;
  1053. blobmsg_parse(instance_attr, __INSTANCE_ATTR_MAX, tb,
  1054. blobmsg_data(in->config), blobmsg_data_len(in->config));
  1055. if (!tb[INSTANCE_ATTR_BUNDLE] && !instance_config_parse_command(in, tb))
  1056. return false;
  1057. if (tb[INSTANCE_ATTR_TERMTIMEOUT])
  1058. in->term_timeout = blobmsg_get_u32(tb[INSTANCE_ATTR_TERMTIMEOUT]);
  1059. if (tb[INSTANCE_ATTR_RESPAWN]) {
  1060. int i = 0;
  1061. uint32_t vals[3] = { 3600, 5, 5};
  1062. blobmsg_for_each_attr(cur2, tb[INSTANCE_ATTR_RESPAWN], rem) {
  1063. if ((i >= 3) && (blobmsg_type(cur2) == BLOBMSG_TYPE_STRING))
  1064. continue;
  1065. vals[i] = atoi(blobmsg_get_string(cur2));
  1066. i++;
  1067. }
  1068. in->respawn = true;
  1069. in->respawn_count = 0;
  1070. in->respawn_threshold = vals[0];
  1071. in->respawn_timeout = vals[1];
  1072. in->respawn_retry = vals[2];
  1073. }
  1074. if (tb[INSTANCE_ATTR_TRIGGER]) {
  1075. in->trigger = tb[INSTANCE_ATTR_TRIGGER];
  1076. trigger_add(in->trigger, in);
  1077. }
  1078. if (tb[INSTANCE_ATTR_WATCH]) {
  1079. blobmsg_for_each_attr(cur2, tb[INSTANCE_ATTR_WATCH], rem) {
  1080. if (blobmsg_type(cur2) != BLOBMSG_TYPE_STRING)
  1081. continue;
  1082. P_DEBUG(3, "watch for %s\n", blobmsg_get_string(cur2));
  1083. watch_add(blobmsg_get_string(cur2), in);
  1084. }
  1085. }
  1086. if ((cur = tb[INSTANCE_ATTR_NICE])) {
  1087. in->nice = (int8_t) blobmsg_get_u32(cur);
  1088. if (in->nice < -20 || in->nice > 20)
  1089. return false;
  1090. }
  1091. if (tb[INSTANCE_ATTR_USER]) {
  1092. const char *user = blobmsg_get_string(tb[INSTANCE_ATTR_USER]);
  1093. struct passwd *p = getpwnam(user);
  1094. if (p) {
  1095. in->user = strdup(user);
  1096. in->uid = p->pw_uid;
  1097. in->gr_gid = in->pw_gid = p->pw_gid;
  1098. }
  1099. }
  1100. if (tb[INSTANCE_ATTR_GROUP]) {
  1101. const char *group = blobmsg_get_string(tb[INSTANCE_ATTR_GROUP]);
  1102. struct group *p = getgrnam(group);
  1103. if (p) {
  1104. in->group = strdup(group);
  1105. in->gr_gid = p->gr_gid;
  1106. }
  1107. }
  1108. if (tb[INSTANCE_ATTR_TRACE])
  1109. in->trace = blobmsg_get_bool(tb[INSTANCE_ATTR_TRACE]);
  1110. if (tb[INSTANCE_ATTR_NO_NEW_PRIVS])
  1111. in->no_new_privs = blobmsg_get_bool(tb[INSTANCE_ATTR_NO_NEW_PRIVS]);
  1112. if (!in->trace && tb[INSTANCE_ATTR_SECCOMP])
  1113. in->seccomp = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_SECCOMP]));
  1114. if (tb[INSTANCE_ATTR_CAPABILITIES])
  1115. in->capabilities = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_CAPABILITIES]));
  1116. if (tb[INSTANCE_ATTR_EXTROOT])
  1117. in->extroot = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_EXTROOT]));
  1118. if (tb[INSTANCE_ATTR_OVERLAYDIR])
  1119. in->overlaydir = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_OVERLAYDIR]));
  1120. if (tb[INSTANCE_ATTR_TMPOVERLAYSIZE])
  1121. in->tmpoverlaysize = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_TMPOVERLAYSIZE]));
  1122. if (tb[INSTANCE_ATTR_BUNDLE])
  1123. in->bundle = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_BUNDLE]));
  1124. if (tb[INSTANCE_ATTR_PIDFILE]) {
  1125. char *pidfile = blobmsg_get_string(tb[INSTANCE_ATTR_PIDFILE]);
  1126. if (pidfile)
  1127. in->pidfile = strdup(pidfile);
  1128. }
  1129. if (tb[INSTANCE_ATTR_RELOADSIG])
  1130. in->reload_signal = blobmsg_get_u32(tb[INSTANCE_ATTR_RELOADSIG]);
  1131. if (tb[INSTANCE_ATTR_STDOUT] && blobmsg_get_bool(tb[INSTANCE_ATTR_STDOUT]))
  1132. in->_stdout.fd.fd = -1;
  1133. if (tb[INSTANCE_ATTR_STDERR] && blobmsg_get_bool(tb[INSTANCE_ATTR_STDERR]))
  1134. in->_stderr.fd.fd = -1;
  1135. instance_fill_any(&in->data, tb[INSTANCE_ATTR_DATA]);
  1136. if (!instance_fill_array(&in->env, tb[INSTANCE_ATTR_ENV], NULL, false))
  1137. return false;
  1138. if (!instance_fill_array(&in->netdev, tb[INSTANCE_ATTR_NETDEV], instance_netdev_update, true))
  1139. return false;
  1140. if (!instance_fill_array(&in->file, tb[INSTANCE_ATTR_FILE], instance_file_update, true))
  1141. return false;
  1142. if (!instance_fill_array(&in->limits, tb[INSTANCE_ATTR_LIMITS], NULL, false))
  1143. return false;
  1144. if (!instance_fill_array(&in->errors, tb[INSTANCE_ATTR_ERROR], NULL, true))
  1145. return false;
  1146. if (tb[INSTANCE_ATTR_FACILITY]) {
  1147. int facility = syslog_facility_str_to_int(blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY]));
  1148. if (facility != -1) {
  1149. in->syslog_facility = facility;
  1150. P_DEBUG(3, "setting facility '%s'\n", blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY]));
  1151. } else
  1152. P_DEBUG(3, "unknown syslog facility '%s' given, using default (LOG_DAEMON)\n", blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY]));
  1153. }
  1154. if (tb[INSTANCE_ATTR_WATCHDOG]) {
  1155. int i = 0;
  1156. uint32_t vals[2] = { 0, 30 };
  1157. blobmsg_for_each_attr(cur2, tb[INSTANCE_ATTR_WATCHDOG], rem) {
  1158. if (i >= 2)
  1159. break;
  1160. vals[i] = atoi(blobmsg_get_string(cur2));
  1161. i++;
  1162. }
  1163. if (vals[0] >= 0 && vals[0] < __INSTANCE_WATCHDOG_MODE_MAX) {
  1164. in->watchdog.mode = vals[0];
  1165. P_DEBUG(3, "setting watchdog mode (%d)\n", vals[0]);
  1166. } else {
  1167. in->watchdog.mode = 0;
  1168. P_DEBUG(3, "unknown watchdog mode (%d) given, using default (0)\n", vals[0]);
  1169. }
  1170. if (vals[1] > 0) {
  1171. in->watchdog.freq = vals[1];
  1172. P_DEBUG(3, "setting watchdog timeout (%d)\n", vals[0]);
  1173. } else {
  1174. in->watchdog.freq = 30;
  1175. P_DEBUG(3, "invalid watchdog timeout (%d) given, using default (30)\n", vals[1]);
  1176. }
  1177. }
  1178. if (!in->trace && tb[INSTANCE_ATTR_JAIL])
  1179. in->has_jail = instance_jail_parse(in, tb[INSTANCE_ATTR_JAIL]);
  1180. if (in->has_jail) {
  1181. r = stat(UJAIL_BIN_PATH, &s);
  1182. if (r < 0) {
  1183. if (in->require_jail) {
  1184. ERROR("Cannot jail service %s::%s. %s: %m (%d)\n",
  1185. in->srv->name, in->name, UJAIL_BIN_PATH, r);
  1186. return false;
  1187. }
  1188. P_DEBUG(2, "unable to find %s: %m (%d)\n", UJAIL_BIN_PATH, r);
  1189. in->has_jail = false;
  1190. }
  1191. }
  1192. return true;
  1193. }
  1194. static void
  1195. instance_config_cleanup(struct service_instance *in)
  1196. {
  1197. blobmsg_list_free(&in->env);
  1198. blobmsg_list_free(&in->data);
  1199. blobmsg_list_free(&in->netdev);
  1200. blobmsg_list_free(&in->file);
  1201. blobmsg_list_free(&in->limits);
  1202. blobmsg_list_free(&in->errors);
  1203. blobmsg_list_free(&in->jail.mount);
  1204. blobmsg_list_free(&in->jail.setns);
  1205. }
  1206. static void
  1207. instance_config_move_strdup(char **dst, char *src)
  1208. {
  1209. if (*dst) {
  1210. free(*dst);
  1211. *dst = NULL;
  1212. }
  1213. if (!src)
  1214. return;
  1215. *dst = strdup(src);
  1216. }
  1217. static void
  1218. instance_config_move(struct service_instance *in, struct service_instance *in_src)
  1219. {
  1220. instance_config_cleanup(in);
  1221. blobmsg_list_move(&in->env, &in_src->env);
  1222. blobmsg_list_move(&in->data, &in_src->data);
  1223. blobmsg_list_move(&in->netdev, &in_src->netdev);
  1224. blobmsg_list_move(&in->file, &in_src->file);
  1225. blobmsg_list_move(&in->limits, &in_src->limits);
  1226. blobmsg_list_move(&in->errors, &in_src->errors);
  1227. blobmsg_list_move(&in->jail.mount, &in_src->jail.mount);
  1228. blobmsg_list_move(&in->jail.setns, &in_src->jail.setns);
  1229. in->trigger = in_src->trigger;
  1230. in->command = in_src->command;
  1231. in->respawn = in_src->respawn;
  1232. in->respawn_retry = in_src->respawn_retry;
  1233. in->respawn_threshold = in_src->respawn_threshold;
  1234. in->respawn_timeout = in_src->respawn_timeout;
  1235. in->reload_signal = in_src->reload_signal;
  1236. in->term_timeout = in_src->term_timeout;
  1237. in->watchdog.mode = in_src->watchdog.mode;
  1238. in->watchdog.freq = in_src->watchdog.freq;
  1239. in->watchdog.timeout = in_src->watchdog.timeout;
  1240. in->name = in_src->name;
  1241. in->nice = in_src->nice;
  1242. in->trace = in_src->trace;
  1243. in->node.avl.key = in_src->node.avl.key;
  1244. in->syslog_facility = in_src->syslog_facility;
  1245. in->require_jail = in_src->require_jail;
  1246. in->no_new_privs = in_src->no_new_privs;
  1247. in->immediately = in_src->immediately;
  1248. in->uid = in_src->uid;
  1249. in->pw_gid = in_src->pw_gid;
  1250. in->gr_gid = in_src->gr_gid;
  1251. in->has_jail = in_src->has_jail;
  1252. in->jail.procfs = in_src->jail.procfs;
  1253. in->jail.sysfs = in_src->jail.sysfs;
  1254. in->jail.ubus = in_src->jail.ubus;
  1255. in->jail.log = in_src->jail.log;
  1256. in->jail.ronly = in_src->jail.ronly;
  1257. in->jail.netns = in_src->jail.netns;
  1258. in->jail.cgroupsns = in_src->jail.cgroupsns;
  1259. in->jail.console = in_src->jail.console;
  1260. in->jail.argc = in_src->jail.argc;
  1261. instance_config_move_strdup(&in->pidfile, in_src->pidfile);
  1262. instance_config_move_strdup(&in->seccomp, in_src->seccomp);
  1263. instance_config_move_strdup(&in->capabilities, in_src->capabilities);
  1264. instance_config_move_strdup(&in->bundle, in_src->bundle);
  1265. instance_config_move_strdup(&in->extroot, in_src->extroot);
  1266. instance_config_move_strdup(&in->overlaydir, in_src->overlaydir);
  1267. instance_config_move_strdup(&in->tmpoverlaysize, in_src->tmpoverlaysize);
  1268. instance_config_move_strdup(&in->user, in_src->user);
  1269. instance_config_move_strdup(&in->group, in_src->group);
  1270. instance_config_move_strdup(&in->jail.name, in_src->jail.name);
  1271. instance_config_move_strdup(&in->jail.hostname, in_src->jail.hostname);
  1272. instance_config_move_strdup(&in->jail.pidfile, in_src->jail.pidfile);
  1273. free(in->config);
  1274. in->config = in_src->config;
  1275. in_src->config = NULL;
  1276. }
  1277. void
  1278. instance_update(struct service_instance *in, struct service_instance *in_new)
  1279. {
  1280. bool changed = instance_config_changed(in, in_new);
  1281. bool running = in->proc.pending;
  1282. bool stopping = in->halt;
  1283. if (!running || stopping) {
  1284. instance_config_move(in, in_new);
  1285. instance_start(in);
  1286. } else {
  1287. if (changed)
  1288. instance_restart(in);
  1289. instance_config_move(in, in_new);
  1290. /* restart happens in the child callback handler */
  1291. }
  1292. }
  1293. void
  1294. instance_free(struct service_instance *in)
  1295. {
  1296. instance_free_stdio(in);
  1297. uloop_process_delete(&in->proc);
  1298. uloop_timeout_cancel(&in->timeout);
  1299. uloop_timeout_cancel(&in->watchdog.timeout);
  1300. trigger_del(in);
  1301. watch_del(in);
  1302. instance_config_cleanup(in);
  1303. free(in->config);
  1304. free(in->user);
  1305. free(in->group);
  1306. free(in->extroot);
  1307. free(in->overlaydir);
  1308. free(in->tmpoverlaysize);
  1309. free(in->bundle);
  1310. free(in->jail.name);
  1311. free(in->jail.hostname);
  1312. free(in->jail.pidfile);
  1313. free(in->seccomp);
  1314. free(in->capabilities);
  1315. free(in->pidfile);
  1316. free(in);
  1317. }
  1318. void
  1319. instance_init(struct service_instance *in, struct service *s, struct blob_attr *config)
  1320. {
  1321. config = blob_memdup(config);
  1322. in->srv = s;
  1323. in->name = blobmsg_name(config);
  1324. in->config = config;
  1325. in->timeout.cb = instance_timeout;
  1326. in->proc.cb = instance_exit;
  1327. in->term_timeout = 5;
  1328. in->syslog_facility = LOG_DAEMON;
  1329. in->exit_code = 0;
  1330. in->require_jail = false;
  1331. in->immediately = false;
  1332. in->_stdout.fd.fd = -2;
  1333. in->_stdout.stream.string_data = true;
  1334. in->_stdout.stream.notify_read = instance_stdout;
  1335. in->_stderr.fd.fd = -2;
  1336. in->_stderr.stream.string_data = true;
  1337. in->_stderr.stream.notify_read = instance_stderr;
  1338. in->console.fd.fd = -2;
  1339. in->console.stream.string_data = true;
  1340. in->console.stream.notify_read = instance_console;
  1341. in->console_client.fd.fd = -2;
  1342. in->console_client.stream.string_data = true;
  1343. in->console_client.stream.notify_read = instance_console_client;
  1344. blobmsg_list_init(&in->netdev, struct instance_netdev, node, instance_netdev_cmp);
  1345. blobmsg_list_init(&in->file, struct instance_file, node, instance_file_cmp);
  1346. blobmsg_list_simple_init(&in->env);
  1347. blobmsg_list_simple_init(&in->data);
  1348. blobmsg_list_simple_init(&in->limits);
  1349. blobmsg_list_simple_init(&in->errors);
  1350. blobmsg_list_simple_init(&in->jail.mount);
  1351. blobmsg_list_simple_init(&in->jail.setns);
  1352. in->watchdog.timeout.cb = instance_watchdog;
  1353. in->valid = instance_config_parse(in);
  1354. }
  1355. void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose)
  1356. {
  1357. void *i;
  1358. if (!in->valid)
  1359. return;
  1360. i = blobmsg_open_table(b, in->name);
  1361. blobmsg_add_u8(b, "running", in->proc.pending);
  1362. if (in->proc.pending)
  1363. blobmsg_add_u32(b, "pid", in->proc.pid);
  1364. if (in->command)
  1365. blobmsg_add_blob(b, in->command);
  1366. if (in->bundle)
  1367. blobmsg_add_string(b, "bundle", in->bundle);
  1368. blobmsg_add_u32(b, "term_timeout", in->term_timeout);
  1369. if (!in->proc.pending)
  1370. blobmsg_add_u32(b, "exit_code", in->exit_code);
  1371. if (!avl_is_empty(&in->errors.avl)) {
  1372. struct blobmsg_list_node *var;
  1373. void *e = blobmsg_open_array(b, "errors");
  1374. blobmsg_list_for_each(&in->errors, var)
  1375. blobmsg_add_string(b, NULL, blobmsg_data(var->data));
  1376. blobmsg_close_table(b, e);
  1377. }
  1378. if (!avl_is_empty(&in->env.avl)) {
  1379. struct blobmsg_list_node *var;
  1380. void *e = blobmsg_open_table(b, "env");
  1381. blobmsg_list_for_each(&in->env, var)
  1382. blobmsg_add_string(b, blobmsg_name(var->data), blobmsg_data(var->data));
  1383. blobmsg_close_table(b, e);
  1384. }
  1385. if (!avl_is_empty(&in->data.avl)) {
  1386. struct blobmsg_list_node *var;
  1387. void *e = blobmsg_open_table(b, "data");
  1388. blobmsg_list_for_each(&in->data, var)
  1389. blobmsg_add_blob(b, var->data);
  1390. blobmsg_close_table(b, e);
  1391. }
  1392. if (!avl_is_empty(&in->limits.avl)) {
  1393. struct blobmsg_list_node *var;
  1394. void *e = blobmsg_open_table(b, "limits");
  1395. blobmsg_list_for_each(&in->limits, var)
  1396. blobmsg_add_string(b, blobmsg_name(var->data), blobmsg_data(var->data));
  1397. blobmsg_close_table(b, e);
  1398. }
  1399. if (!avl_is_empty(&in->netdev.avl)) {
  1400. struct blobmsg_list_node *var;
  1401. void *n = blobmsg_open_array(b, "netdev");
  1402. blobmsg_list_for_each(&in->netdev, var)
  1403. blobmsg_add_string(b, NULL, blobmsg_data(var->data));
  1404. blobmsg_close_array(b, n);
  1405. }
  1406. if (in->reload_signal)
  1407. blobmsg_add_u32(b, "reload_signal", in->reload_signal);
  1408. if (in->respawn) {
  1409. void *r = blobmsg_open_table(b, "respawn");
  1410. blobmsg_add_u32(b, "threshold", in->respawn_threshold);
  1411. blobmsg_add_u32(b, "timeout", in->respawn_timeout);
  1412. blobmsg_add_u32(b, "retry", in->respawn_retry);
  1413. blobmsg_close_table(b, r);
  1414. }
  1415. if (in->trace)
  1416. blobmsg_add_u8(b, "trace", true);
  1417. if (in->no_new_privs)
  1418. blobmsg_add_u8(b, "no_new_privs", true);
  1419. if (in->seccomp)
  1420. blobmsg_add_string(b, "seccomp", in->seccomp);
  1421. if (in->capabilities)
  1422. blobmsg_add_string(b, "capabilities", in->capabilities);
  1423. if (in->pidfile)
  1424. blobmsg_add_string(b, "pidfile", in->pidfile);
  1425. if (in->user)
  1426. blobmsg_add_string(b, "user", in->user);
  1427. if (in->group)
  1428. blobmsg_add_string(b, "group", in->group);
  1429. if (in->has_jail) {
  1430. void *r = blobmsg_open_table(b, "jail");
  1431. if (in->jail.name)
  1432. blobmsg_add_string(b, "name", in->jail.name);
  1433. if (!in->bundle) {
  1434. if (in->jail.hostname)
  1435. blobmsg_add_string(b, "hostname", in->jail.hostname);
  1436. blobmsg_add_u8(b, "procfs", in->jail.procfs);
  1437. blobmsg_add_u8(b, "sysfs", in->jail.sysfs);
  1438. blobmsg_add_u8(b, "ubus", in->jail.ubus);
  1439. blobmsg_add_u8(b, "log", in->jail.log);
  1440. blobmsg_add_u8(b, "ronly", in->jail.ronly);
  1441. blobmsg_add_u8(b, "netns", in->jail.netns);
  1442. blobmsg_add_u8(b, "userns", in->jail.userns);
  1443. blobmsg_add_u8(b, "cgroupsns", in->jail.cgroupsns);
  1444. } else {
  1445. if (in->jail.pidfile)
  1446. blobmsg_add_string(b, "pidfile", in->jail.pidfile);
  1447. blobmsg_add_u8(b, "immediately", in->immediately);
  1448. }
  1449. blobmsg_add_u8(b, "console", (in->console.fd.fd > -1));
  1450. blobmsg_close_table(b, r);
  1451. if (!avl_is_empty(&in->jail.mount.avl)) {
  1452. struct blobmsg_list_node *var;
  1453. void *e = blobmsg_open_table(b, "mount");
  1454. blobmsg_list_for_each(&in->jail.mount, var)
  1455. blobmsg_add_string(b, blobmsg_name(var->data), blobmsg_data(var->data));
  1456. blobmsg_close_table(b, e);
  1457. }
  1458. if (!avl_is_empty(&in->jail.setns.avl)) {
  1459. struct blobmsg_list_node *var;
  1460. void *s = blobmsg_open_array(b, "setns");
  1461. blobmsg_list_for_each(&in->jail.setns, var)
  1462. blobmsg_add_blob(b, var->data);
  1463. blobmsg_close_array(b, s);
  1464. }
  1465. }
  1466. if (in->extroot)
  1467. blobmsg_add_string(b, "extroot", in->extroot);
  1468. if (in->overlaydir)
  1469. blobmsg_add_string(b, "overlaydir", in->overlaydir);
  1470. if (in->tmpoverlaysize)
  1471. blobmsg_add_string(b, "tmpoverlaysize", in->tmpoverlaysize);
  1472. if (verbose && in->trigger)
  1473. blobmsg_add_blob(b, in->trigger);
  1474. if (in->watchdog.mode != INSTANCE_WATCHDOG_MODE_DISABLED) {
  1475. void *r = blobmsg_open_table(b, "watchdog");
  1476. blobmsg_add_u32(b, "mode", in->watchdog.mode);
  1477. blobmsg_add_u32(b, "timeout", in->watchdog.freq);
  1478. blobmsg_close_table(b, r);
  1479. }
  1480. blobmsg_close_table(b, i);
  1481. }