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

Sources/procd/service/instance.c

  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 
 15 #define _GNU_SOURCE
 16 #include <sys/resource.h>
 17 #include <sys/types.h>
 18 #include <sys/socket.h>
 19 #include <sys/stat.h>
 20 #include <grp.h>
 21 #include <net/if.h>
 22 #include <unistd.h>
 23 #include <stdint.h>
 24 #include <stdio.h>
 25 #include <fcntl.h>
 26 #include <pwd.h>
 27 #include <libgen.h>
 28 #include <unistd.h>
 29 #define SYSLOG_NAMES
 30 #include <syslog.h>
 31 
 32 #include <libubox/md5.h>
 33 #include <libubox/utils.h>
 34 
 35 #include "../procd.h"
 36 #include "../rcS.h"
 37 
 38 #include "service.h"
 39 #include "instance.h"
 40 
 41 #define UJAIL_BIN_PATH "/sbin/ujail"
 42 #define CGROUP_BASEDIR "/sys/fs/cgroup/services"
 43 
 44 enum {
 45         INSTANCE_ATTR_COMMAND,
 46         INSTANCE_ATTR_ENV,
 47         INSTANCE_ATTR_DATA,
 48         INSTANCE_ATTR_NETDEV,
 49         INSTANCE_ATTR_FILE,
 50         INSTANCE_ATTR_TRIGGER,
 51         INSTANCE_ATTR_RESPAWN,
 52         INSTANCE_ATTR_NICE,
 53         INSTANCE_ATTR_LIMITS,
 54         INSTANCE_ATTR_WATCH,
 55         INSTANCE_ATTR_ERROR,
 56         INSTANCE_ATTR_USER,
 57         INSTANCE_ATTR_GROUP,
 58         INSTANCE_ATTR_STDOUT,
 59         INSTANCE_ATTR_STDERR,
 60         INSTANCE_ATTR_NO_NEW_PRIVS,
 61         INSTANCE_ATTR_JAIL,
 62         INSTANCE_ATTR_TRACE,
 63         INSTANCE_ATTR_SECCOMP,
 64         INSTANCE_ATTR_SECCOMP_MODE,
 65         INSTANCE_ATTR_SECCOMP_LOG,
 66         INSTANCE_ATTR_CAPABILITIES,
 67         INSTANCE_ATTR_PIDFILE,
 68         INSTANCE_ATTR_RELOADSIG,
 69         INSTANCE_ATTR_TERMTIMEOUT,
 70         INSTANCE_ATTR_FACILITY,
 71         INSTANCE_ATTR_EXTROOT,
 72         INSTANCE_ATTR_OVERLAYDIR,
 73         INSTANCE_ATTR_TMPOVERLAYSIZE,
 74         INSTANCE_ATTR_BUNDLE,
 75         INSTANCE_ATTR_WATCHDOG,
 76         __INSTANCE_ATTR_MAX
 77 };
 78 
 79 static const struct blobmsg_policy instance_attr[__INSTANCE_ATTR_MAX] = {
 80         [INSTANCE_ATTR_COMMAND] = { "command", BLOBMSG_TYPE_ARRAY },
 81         [INSTANCE_ATTR_ENV] = { "env", BLOBMSG_TYPE_TABLE },
 82         [INSTANCE_ATTR_DATA] = { "data", BLOBMSG_TYPE_TABLE },
 83         [INSTANCE_ATTR_NETDEV] = { "netdev", BLOBMSG_TYPE_ARRAY },
 84         [INSTANCE_ATTR_FILE] = { "file", BLOBMSG_TYPE_ARRAY },
 85         [INSTANCE_ATTR_TRIGGER] = { "triggers", BLOBMSG_TYPE_ARRAY },
 86         [INSTANCE_ATTR_RESPAWN] = { "respawn", BLOBMSG_TYPE_ARRAY },
 87         [INSTANCE_ATTR_NICE] = { "nice", BLOBMSG_TYPE_INT32 },
 88         [INSTANCE_ATTR_LIMITS] = { "limits", BLOBMSG_TYPE_TABLE },
 89         [INSTANCE_ATTR_WATCH] = { "watch", BLOBMSG_TYPE_ARRAY },
 90         [INSTANCE_ATTR_ERROR] = { "error", BLOBMSG_TYPE_ARRAY },
 91         [INSTANCE_ATTR_USER] = { "user", BLOBMSG_TYPE_STRING },
 92         [INSTANCE_ATTR_GROUP] = { "group", BLOBMSG_TYPE_STRING },
 93         [INSTANCE_ATTR_STDOUT] = { "stdout", BLOBMSG_TYPE_BOOL },
 94         [INSTANCE_ATTR_STDERR] = { "stderr", BLOBMSG_TYPE_BOOL },
 95         [INSTANCE_ATTR_NO_NEW_PRIVS] = { "no_new_privs", BLOBMSG_TYPE_BOOL },
 96         [INSTANCE_ATTR_JAIL] = { "jail", BLOBMSG_TYPE_TABLE },
 97         [INSTANCE_ATTR_TRACE] = { "trace", BLOBMSG_TYPE_BOOL },
 98         [INSTANCE_ATTR_SECCOMP] = { "seccomp", BLOBMSG_TYPE_STRING },
 99         [INSTANCE_ATTR_SECCOMP_MODE] = { "seccomp_mode", BLOBMSG_TYPE_STRING },
100         [INSTANCE_ATTR_SECCOMP_LOG] = { "seccomp_log", BLOBMSG_TYPE_STRING },
101         [INSTANCE_ATTR_CAPABILITIES] = { "capabilities", BLOBMSG_TYPE_STRING },
102         [INSTANCE_ATTR_PIDFILE] = { "pidfile", BLOBMSG_TYPE_STRING },
103         [INSTANCE_ATTR_RELOADSIG] = { "reload_signal", BLOBMSG_TYPE_INT32 },
104         [INSTANCE_ATTR_TERMTIMEOUT] = { "term_timeout", BLOBMSG_TYPE_INT32 },
105         [INSTANCE_ATTR_FACILITY] = { "facility", BLOBMSG_TYPE_STRING },
106         [INSTANCE_ATTR_EXTROOT] = { "extroot", BLOBMSG_TYPE_STRING },
107         [INSTANCE_ATTR_OVERLAYDIR] = { "overlaydir", BLOBMSG_TYPE_STRING },
108         [INSTANCE_ATTR_TMPOVERLAYSIZE] = { "tmpoverlaysize", BLOBMSG_TYPE_STRING },
109         [INSTANCE_ATTR_BUNDLE] = { "bundle", BLOBMSG_TYPE_STRING },
110         [INSTANCE_ATTR_WATCHDOG] = { "watchdog", BLOBMSG_TYPE_ARRAY },
111 };
112 
113 enum {
114         JAIL_ATTR_NAME,
115         JAIL_ATTR_HOSTNAME,
116         JAIL_ATTR_PROCFS,
117         JAIL_ATTR_SYSFS,
118         JAIL_ATTR_UBUS,
119         JAIL_ATTR_UDEBUG,
120         JAIL_ATTR_LOG,
121         JAIL_ATTR_RONLY,
122         JAIL_ATTR_MOUNT,
123         JAIL_ATTR_NETNS,
124         JAIL_ATTR_USERNS,
125         JAIL_ATTR_CGROUPSNS,
126         JAIL_ATTR_CONSOLE,
127         JAIL_ATTR_REQUIREJAIL,
128         JAIL_ATTR_IMMEDIATELY,
129         JAIL_ATTR_PIDFILE,
130         JAIL_ATTR_SETNS,
131         JAIL_ATTR_IDMAP_OFFSET,
132         JAIL_ATTR_CONSOLESOCKET,
133         JAIL_ATTR_SYSTEMDCGROUP,
134         JAIL_ATTR_ENVFILE,
135         __JAIL_ATTR_MAX,
136 };
137 
138 static const struct blobmsg_policy jail_attr[__JAIL_ATTR_MAX] = {
139         [JAIL_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
140         [JAIL_ATTR_HOSTNAME] = { "hostname", BLOBMSG_TYPE_STRING },
141         [JAIL_ATTR_PROCFS] = { "procfs", BLOBMSG_TYPE_BOOL },
142         [JAIL_ATTR_SYSFS] = { "sysfs", BLOBMSG_TYPE_BOOL },
143         [JAIL_ATTR_UBUS] = { "ubus", BLOBMSG_TYPE_BOOL },
144         [JAIL_ATTR_UDEBUG] = { "udebug", BLOBMSG_TYPE_BOOL },
145         [JAIL_ATTR_LOG] = { "log", BLOBMSG_TYPE_BOOL },
146         [JAIL_ATTR_RONLY] = { "ronly", BLOBMSG_TYPE_BOOL },
147         [JAIL_ATTR_MOUNT] = { "mount", BLOBMSG_TYPE_TABLE },
148         [JAIL_ATTR_NETNS] = { "netns", BLOBMSG_TYPE_BOOL },
149         [JAIL_ATTR_USERNS] = { "userns", BLOBMSG_TYPE_BOOL },
150         [JAIL_ATTR_CGROUPSNS] = { "cgroupsns", BLOBMSG_TYPE_BOOL },
151         [JAIL_ATTR_CONSOLE] = { "console", BLOBMSG_TYPE_BOOL },
152         [JAIL_ATTR_REQUIREJAIL] = { "requirejail", BLOBMSG_TYPE_BOOL },
153         [JAIL_ATTR_IMMEDIATELY] = { "immediately", BLOBMSG_TYPE_BOOL },
154         [JAIL_ATTR_PIDFILE] = { "pidfile", BLOBMSG_TYPE_STRING },
155         [JAIL_ATTR_SETNS] = { "setns", BLOBMSG_TYPE_ARRAY },
156         [JAIL_ATTR_IDMAP_OFFSET] = { "idmap_offset", BLOBMSG_TYPE_STRING },
157         [JAIL_ATTR_CONSOLESOCKET] = { "consolesocket", BLOBMSG_TYPE_STRING },
158         [JAIL_ATTR_SYSTEMDCGROUP] = { "systemdcgroup", BLOBMSG_TYPE_BOOL },
159         [JAIL_ATTR_ENVFILE] = { "envfile", BLOBMSG_TYPE_STRING },
160 };
161 
162 enum {
163         JAIL_SETNS_ATTR_PID,
164         JAIL_SETNS_ATTR_NS,
165         __JAIL_SETNS_ATTR_MAX,
166 };
167 
168 static const struct blobmsg_policy jail_setns_attr[__JAIL_SETNS_ATTR_MAX] = {
169         [JAIL_SETNS_ATTR_PID] = { "pid", BLOBMSG_TYPE_INT32 },
170         [JAIL_SETNS_ATTR_NS] = { "namespaces", BLOBMSG_TYPE_ARRAY },
171 };
172 
173 struct instance_netdev {
174         struct blobmsg_list_node node;
175         int ifindex;
176 };
177 
178 struct instance_file {
179         struct blobmsg_list_node node;
180         uint32_t md5[4];
181 };
182 
183 struct rlimit_name {
184         const char *name;
185         int resource;
186 };
187 
188 static const struct rlimit_name rlimit_names[] = {
189         { "as", RLIMIT_AS },
190         { "core", RLIMIT_CORE },
191         { "cpu", RLIMIT_CPU },
192         { "data", RLIMIT_DATA },
193         { "fsize", RLIMIT_FSIZE },
194         { "memlock", RLIMIT_MEMLOCK },
195         { "nofile", RLIMIT_NOFILE },
196         { "nproc", RLIMIT_NPROC },
197         { "rss", RLIMIT_RSS },
198         { "stack", RLIMIT_STACK },
199 #ifdef linux
200         { "nice", RLIMIT_NICE },
201         { "rtprio", RLIMIT_RTPRIO },
202         { "msgqueue", RLIMIT_MSGQUEUE },
203         { "sigpending", RLIMIT_SIGPENDING },
204 #endif
205         { NULL, 0 }
206 };
207 
208 static void closefd(int fd)
209 {
210         if (fd > STDERR_FILENO)
211                 close(fd);
212 }
213 
214 /* convert a string into numeric syslog facility or return -1 if no match found */
215 static int
216 syslog_facility_str_to_int(const char *facility)
217 {
218         CODE *p = facilitynames;
219 
220         while (p->c_name && strcasecmp(p->c_name, facility))
221                 p++;
222 
223         return p->c_val;
224 }
225 
226 static void
227 instance_limits(const char *limit, const char *value)
228 {
229         int i;
230         struct rlimit rlim;
231         unsigned long cur, max;
232 
233         for (i = 0; rlimit_names[i].name != NULL; i++) {
234                 if (strcmp(rlimit_names[i].name, limit))
235                         continue;
236                 if (!strcmp(value, "unlimited")) {
237                         rlim.rlim_cur = RLIM_INFINITY;
238                         rlim.rlim_max = RLIM_INFINITY;
239                 } else {
240                         if (getrlimit(rlimit_names[i].resource, &rlim))
241                                 return;
242 
243                         cur = rlim.rlim_cur;
244                         max = rlim.rlim_max;
245 
246                         if (sscanf(value, "%lu %lu", &cur, &max) < 1)
247                                 return;
248 
249                         rlim.rlim_cur = cur;
250                         rlim.rlim_max = max;
251                 }
252 
253                 setrlimit(rlimit_names[i].resource, &rlim);
254                 return;
255         }
256 }
257 
258 static char *
259 instance_gen_setns_argstr(struct blob_attr *attr)
260 {
261         struct blob_attr *tb[__JAIL_SETNS_ATTR_MAX];
262         struct blob_attr *cur;
263         int rem, len, total;
264         char *ret;
265 
266         blobmsg_parse(jail_setns_attr, __JAIL_SETNS_ATTR_MAX, tb,
267                 blobmsg_data(attr), blobmsg_data_len(attr));
268 
269         if (!tb[JAIL_SETNS_ATTR_PID] || !tb[JAIL_SETNS_ATTR_NS])
270                 return NULL;
271 
272         len = snprintf(NULL, 0, "%d:", blobmsg_get_u32(tb[JAIL_SETNS_ATTR_PID]));
273 
274         blobmsg_for_each_attr(cur, tb[JAIL_SETNS_ATTR_NS], rem) {
275                 char *tmp;
276 
277                 if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
278                         return NULL;
279 
280                 tmp = blobmsg_get_string(cur);
281                 if (!tmp)
282                         return NULL;
283 
284                 len += strlen(tmp) + 1;
285         }
286 
287         total = len;
288         ret = malloc(total);
289         if (!ret)
290                 return NULL;
291 
292         len = snprintf(ret, total, "%d:", blobmsg_get_u32(tb[JAIL_SETNS_ATTR_PID]));
293 
294         blobmsg_for_each_attr(cur, tb[JAIL_SETNS_ATTR_NS], rem) {
295                 strncpy(&ret[len], blobmsg_get_string(cur), total - len);
296                 len += strlen(blobmsg_get_string(cur));
297                 ret[len++] = ',';
298         }
299         ret[total - 1] = '\0';
300 
301         return ret;
302 }
303 
304 static inline int
305 jail_run(struct service_instance *in, char **argv)
306 {
307         static char notify_fd_str[12];
308         char *term_timeout_str;
309         struct blobmsg_list_node *var;
310         struct jail *jail = &in->jail;
311         int argc = 0;
312 
313         argv[argc++] = UJAIL_BIN_PATH;
314 
315         if (asprintf(&term_timeout_str, "%d", in->term_timeout) == -1)
316                 exit(ENOMEM);
317 
318         argv[argc++] = "-t";
319         argv[argc++] = term_timeout_str;
320 
321         if (jail->name) {
322                 argv[argc++] = "-n";
323                 argv[argc++] = jail->name;
324         }
325 
326         if (jail->hostname) {
327                 argv[argc++] = "-h";
328                 argv[argc++] = jail->hostname;
329         }
330 
331         if (in->seccomp) {
332                 argv[argc++] = "-S";
333                 argv[argc++] = in->seccomp;
334         }
335 
336         if (in->seccomp_mode) {
337                 argv[argc++] = "-m";
338                 argv[argc++] = in->seccomp_mode;
339         }
340 
341         if (in->seccomp_log) {
342                 argv[argc++] = "-M";
343                 argv[argc++] = in->seccomp_log;
344         }
345 
346         if (in->user) {
347                 argv[argc++] = "-U";
348                 argv[argc++] = in->user;
349         }
350 
351         if (in->group) {
352                 argv[argc++] = "-G";
353                 argv[argc++] = in->group;
354         }
355 
356         if (in->capabilities) {
357                 argv[argc++] = "-C";
358                 argv[argc++] = in->capabilities;
359         }
360 
361         if (in->no_new_privs)
362                 argv[argc++] = "-c";
363 
364         if (jail->procfs)
365                 argv[argc++] = "-p";
366 
367         if (jail->sysfs)
368                 argv[argc++] = "-s";
369 
370         if (jail->ubus)
371                 argv[argc++] = "-u";
372 
373         if (jail->udebug)
374                 argv[argc++] = "-D";
375 
376         if (jail->log)
377                 argv[argc++] = "-l";
378 
379         if (jail->ronly)
380                 argv[argc++] = "-o";
381 
382         if (jail->netns)
383                 argv[argc++] = "-N";
384 
385         if (jail->userns)
386                 argv[argc++] = "-f";
387 
388         if (jail->cgroupsns)
389                 argv[argc++] = "-F";
390 
391         if (jail->console)
392                 argv[argc++] = "-y";
393 
394         if (in->extroot) {
395                 argv[argc++] = "-R";
396                 argv[argc++] = in->extroot;
397         }
398 
399         if (in->overlaydir) {
400                 argv[argc++] = "-O";
401                 argv[argc++] = in->overlaydir;
402         }
403 
404         if (in->tmpoverlaysize) {
405                 argv[argc++] = "-T";
406                 argv[argc++] = in->tmpoverlaysize;
407         }
408 
409         if (in->immediately)
410                 argv[argc++] = "-i";
411 
412         if (jail->pidfile) {
413                 argv[argc++] = "-P";
414                 argv[argc++] = jail->pidfile;
415         }
416 
417         if (jail->idmap_offset) {
418                 argv[argc++] = "-I";
419                 argv[argc++] = jail->idmap_offset;
420         }
421         if (jail->consolesocket) {
422                 argv[argc++] = "-Y";
423                 argv[argc++] = jail->consolesocket;
424         }
425 
426         if (jail->envfile) {
427                 argv[argc++] = "-x";
428                 argv[argc++] = jail->envfile;
429         }
430 
431         if (in->notify_fd > -1) {
432                 snprintf(notify_fd_str, sizeof(notify_fd_str), "%d", in->notify_fd);
433                 argv[argc++] = "-a";
434                 argv[argc++] = notify_fd_str;
435         }
436 
437         if (jail->systemd_cgroup)
438                 argv[argc++] = "-Z";
439 
440         if (in->bundle) {
441                 argv[argc++] = "-J";
442                 argv[argc++] = in->bundle;
443         }
444 
445         if (in->require_jail)
446                 argv[argc++] = "-E";
447 
448         blobmsg_list_for_each(&in->env, var) {
449                 argv[argc++] = "-e";
450                 argv[argc++] = (char *) blobmsg_name(var->data);
451         }
452 
453         blobmsg_list_for_each(&jail->mount, var) {
454                 const char *type = blobmsg_data(var->data);
455 
456                 if (*type == '4')
457                         argv[argc++] = "-b";
458                 else if (*type == '3')
459                         argv[argc++] = "-k";
460                 else if (*type == '2')
461                         argv[argc++] = "-V";
462                 else if (*type == '1')
463                         argv[argc++] = "-w";
464                 else
465                         argv[argc++] = "-r";
466                 argv[argc++] = (char *) blobmsg_name(var->data);
467         }
468 
469         blobmsg_list_for_each(&jail->setns, var) {
470                 char *setns_arg = instance_gen_setns_argstr(var->data);
471 
472                 if (setns_arg) {
473                         argv[argc++] = "-j";
474                         argv[argc++] = setns_arg;
475                 }
476         }
477 
478         argv[argc++] = "--";
479 
480         return argc;
481 }
482 
483 static int
484 instance_removepid(struct service_instance *in) {
485         if (!in->pidfile)
486                 return 0;
487         if (unlink(in->pidfile)) {
488                 ERROR("Failed to remove pidfile: %s: %m\n", in->pidfile);
489                 return 1;
490         }
491         return 0;
492 }
493 
494 static int
495 instance_writepid(struct service_instance *in)
496 {
497         FILE *_pidfile;
498 
499         if (!in->pidfile) {
500                 return 0;
501         }
502         _pidfile = fopen(in->pidfile, "w");
503         if (_pidfile == NULL) {
504                 ERROR("failed to open pidfile for writing: %s: %m", in->pidfile);
505                 return 1;
506         }
507         if (fprintf(_pidfile, "%d\n", in->proc.pid) < 0) {
508                 ERROR("failed to write pidfile: %s: %m", in->pidfile);
509                 fclose(_pidfile);
510                 return 2;
511         }
512         if (fclose(_pidfile)) {
513                 ERROR("failed to close pidfile: %s: %m", in->pidfile);
514                 return 3;
515         }
516 
517         return 0;
518 }
519 
520 static void
521 instance_run(struct service_instance *in, int _stdout, int _stderr)
522 {
523         struct blobmsg_list_node *var;
524         struct blob_attr *cur;
525         char **argv;
526         int argc = 1; /* NULL terminated */
527         int rem, _stdin;
528         int jail_argc = in->jail.argc;
529         bool seccomp = !in->trace && !in->has_jail && in->seccomp;
530         bool setlbf = _stdout >= 0;
531 
532         if (in->nice)
533                 setpriority(PRIO_PROCESS, 0, in->nice);
534 
535         blobmsg_for_each_attr(cur, in->command, rem)
536                 argc++;
537 
538         blobmsg_list_for_each(&in->env, var)
539                 setenv(blobmsg_name(var->data), blobmsg_data(var->data), 1);
540 
541         if (seccomp)
542                 setenv("SECCOMP_FILE", in->seccomp, 1);
543 
544         if (setlbf)
545                 setenv("LD_PRELOAD", "/lib/libsetlbf.so", 1);
546 
547         blobmsg_list_for_each(&in->limits, var)
548                 instance_limits(blobmsg_name(var->data), blobmsg_data(var->data));
549 
550         if (in->trace || seccomp)
551                 argc += 1;
552 
553         if (in->has_jail && in->notify_fd > -1) {
554                 fcntl(in->notify_fd, F_SETFD, 0);
555                 jail_argc += 2;
556         }
557 
558         argv = alloca(sizeof(char *) * (argc + jail_argc));
559         argc = 0;
560 
561 #ifdef SECCOMP_SUPPORT
562         if (in->trace)
563                 argv[argc++] = "/sbin/utrace";
564         else if (seccomp)
565                 argv[argc++] = "/sbin/seccomp-trace";
566 #else
567         if (in->trace || seccomp)
568                 ULOG_WARN("Seccomp support for %s::%s not available\n", in->srv->name, in->name);
569 #endif
570 
571         if (in->has_jail) {
572                 argc = jail_run(in, argv);
573                 if (argc != jail_argc)
574                         ULOG_WARN("expected %i jail params, used %i for %s::%s\n",
575                                 jail_argc, argc, in->srv->name, in->name);
576         }
577 
578         blobmsg_for_each_attr(cur, in->command, rem)
579                 argv[argc++] = blobmsg_data(cur);
580 
581         argv[argc] = NULL;
582 
583         if (in->stdio_fd[0] > -1)
584                 _stdin = in->stdio_fd[0];
585         else
586                 _stdin = open("/dev/null", O_RDONLY);
587 
588         if (in->stdio_fd[1] > -1)
589                 _stdout = in->stdio_fd[1];
590         else if (_stdout == -1)
591                 _stdout = open("/dev/null", O_WRONLY);
592 
593         if (in->stdio_fd[2] > -1)
594                 _stderr = in->stdio_fd[2];
595         else if (_stderr == -1)
596                 _stderr = open("/dev/null", O_WRONLY);
597 
598         if (_stdin > -1) {
599                 dup2(_stdin, STDIN_FILENO);
600                 closefd(_stdin);
601         }
602         if (_stdout > -1) {
603                 dup2(_stdout, STDOUT_FILENO);
604                 closefd(_stdout);
605         }
606         if (_stderr > -1) {
607                 dup2(_stderr, STDERR_FILENO);
608                 closefd(_stderr);
609         }
610 
611         if (!in->has_jail && in->user && in->pw_gid && initgroups(in->user, in->pw_gid)) {
612                 ERROR("failed to initgroups() for user %s: %m\n", in->user);
613                 exit(127);
614         }
615         if (!in->has_jail && in->gr_gid && setgid(in->gr_gid)) {
616                 ERROR("failed to set group id %d: %m\n", in->gr_gid);
617                 exit(127);
618         }
619         if (!in->has_jail && in->uid && setuid(in->uid)) {
620                 ERROR("failed to set user id %d: %m\n", in->uid);
621                 exit(127);
622         }
623 
624         execvp(argv[0], argv);
625         exit(127);
626 }
627 
628 static int
629 instance_add_cgroup(const char *service, const char *instance)
630 {
631         const char *cgroup_procs = "/cgroup.procs";
632         char cgnamebuf[256];
633         struct stat sb;
634         int fd, ret;
635 
636         if (stat("/sys/fs/cgroup/cgroup.subtree_control", &sb))
637                 return 0;
638 
639         ret = snprintf(cgnamebuf, sizeof(cgnamebuf), "%s/%s/%s", CGROUP_BASEDIR,
640                        service, instance);
641         if (ret >= sizeof(cgnamebuf))
642                 return -ENAMETOOLONG;
643 
644         if (mkdir_p(cgnamebuf, 0700))
645                 return -EPERM;
646 
647         if (strlen(cgnamebuf) + strlen(cgroup_procs) >= sizeof(cgnamebuf))
648                 return -ENAMETOOLONG;
649 
650         strcat(cgnamebuf, cgroup_procs);
651 
652         fd = open(cgnamebuf, O_WRONLY);
653         if (fd == -1)
654                 return -EIO;
655 
656         dprintf(fd, "%d", getpid());
657         close(fd);
658 
659         return 0;
660 }
661 
662 static void
663 instance_remove_cgroup(const char *service, const char *instance)
664 {
665         char cgnamebuf[256];
666         char *sep;
667         int fd, ret;
668 
669         ret = snprintf(cgnamebuf, sizeof(cgnamebuf), "%s/%s/%s/cgroup.kill",
670                        CGROUP_BASEDIR, service, instance);
671         if (ret >= (int)sizeof(cgnamebuf))
672                 return;
673 
674         fd = open(cgnamebuf, O_WRONLY);
675         if (fd >= 0) {
676                 if (write(fd, "1", 1) < 0)
677                         ret = -1;
678                 close(fd);
679         }
680 
681         sep = strrchr(cgnamebuf, '/');
682         if (sep)
683                 *sep = '\0';
684         (void)rmdir(cgnamebuf);
685 
686         sep = strrchr(cgnamebuf, '/');
687         if (sep)
688                 *sep = '\0';
689         (void)rmdir(cgnamebuf);
690 }
691 
692 static void
693 instance_free_stdio(struct service_instance *in)
694 {
695         if (in->_stdout.fd.fd > -1) {
696                 ustream_free(&in->_stdout.stream);
697                 close(in->_stdout.fd.fd);
698                 in->_stdout.fd.fd = -1;
699         }
700 
701         if (in->_stderr.fd.fd > -1) {
702                 ustream_free(&in->_stderr.stream);
703                 close(in->_stderr.fd.fd);
704                 in->_stderr.fd.fd = -1;
705         }
706 
707         if (in->console.fd.fd > -1) {
708                 ustream_free(&in->console.stream);
709                 close(in->console.fd.fd);
710                 in->console.fd.fd = -1;
711         }
712 
713         if (in->console_client.fd.fd > -1) {
714                 ustream_free(&in->console_client.stream);
715                 close(in->console_client.fd.fd);
716                 in->console_client.fd.fd = -1;
717         }
718 }
719 
720 void
721 instance_start(struct service_instance *in)
722 {
723         int pid, ret;
724         int opipe[2] = { -1, -1 };
725         int epipe[2] = { -1, -1 };
726 
727         if (!avl_is_empty(&in->errors.avl)) {
728                 LOG("Not starting instance %s::%s, an error was indicated\n", in->srv->name, in->name);
729                 return;
730         }
731 
732         if (!in->bundle && !in->command) {
733                 LOG("Not starting instance %s::%s, command not set\n", in->srv->name, in->name);
734                 return;
735         }
736 
737         if (in->proc.pending) {
738                 if (in->halt)
739                         in->restart = true;
740                 return;
741         }
742 
743         instance_free_stdio(in);
744         if (in->_stdout.fd.fd > -2 && in->stdio_fd[1] < 0) {
745                 if (pipe(opipe)) {
746                         ULOG_WARN("pipe() failed: %m\n");
747                         opipe[0] = opipe[1] = -1;
748                 }
749         }
750 
751         if (in->_stderr.fd.fd > -2 && in->stdio_fd[2] < 0) {
752                 if (pipe(epipe)) {
753                         ULOG_WARN("pipe() failed: %m\n");
754                         epipe[0] = epipe[1] = -1;
755                 }
756         }
757 
758         in->restart = false;
759         in->halt = false;
760 
761         if (!in->valid)
762                 return;
763 
764         pid = fork();
765         if (pid < 0)
766                 return;
767 
768         if (!pid) {
769                 uloop_done();
770                 closefd(opipe[0]);
771                 closefd(epipe[0]);
772                 ret = instance_add_cgroup(in->srv->name, in->name);
773                 if (ret)
774                         ULOG_WARN("failed adding instance cgroup for %s: %s\n",
775                                   in->srv->name, strerror(-ret));
776 
777                 instance_run(in, opipe[1], epipe[1]);
778                 return;
779         }
780 
781         P_DEBUG(2, "Started instance %s::%s[%d]\n", in->srv->name, in->name, pid);
782         in->proc.pid = pid;
783         instance_writepid(in);
784         clock_gettime(CLOCK_MONOTONIC, &in->start);
785         uloop_process_add(&in->proc);
786 
787         if (opipe[0] > -1) {
788                 ustream_fd_init(&in->_stdout, opipe[0]);
789                 closefd(opipe[1]);
790                 fcntl(opipe[0], F_SETFD, FD_CLOEXEC);
791         }
792 
793         if (epipe[0] > -1) {
794                 ustream_fd_init(&in->_stderr, epipe[0]);
795                 closefd(epipe[1]);
796                 fcntl(epipe[0], F_SETFD, FD_CLOEXEC);
797         }
798 
799         if (in->watchdog.mode != INSTANCE_WATCHDOG_MODE_DISABLED) {
800                 uloop_timeout_set(&in->watchdog.timeout, in->watchdog.freq * 1000);
801                 P_DEBUG(2, "Started instance %s::%s watchdog timer : timeout = %d\n", in->srv->name, in->name, in->watchdog.freq);
802         }
803 
804         service_event("instance.start", in->srv->name, in->name);
805 }
806 
807 static void
808 instance_stdio(struct ustream *s, int prio, struct service_instance *in)
809 {
810         char *newline, *str, *arg0, ident[32];
811         int len;
812 
813         arg0 = basename(blobmsg_data(blobmsg_data(in->command)));
814         snprintf(ident, sizeof(ident), "%s[%d]", arg0, in->proc.pid);
815         ulog_open(ULOG_SYSLOG, in->syslog_facility, ident);
816 
817         do {
818                 str = ustream_get_read_buf(s, &len);
819                 if (!str)
820                         break;
821 
822                 newline = memchr(str, '\n', len);
823                 if (!newline && (s->r.buffer_len != len))
824                         break;
825 
826                 if (newline) {
827                         *newline = 0;
828                         len = newline + 1 - str;
829                 }
830                 ulog(prio, "%s\n", str);
831 
832                 ustream_consume(s, len);
833         } while (1);
834 
835         ulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd");
836 }
837 
838 static void
839 instance_stdout(struct ustream *s, int bytes)
840 {
841         instance_stdio(s, LOG_INFO,
842                        container_of(s, struct service_instance, _stdout.stream));
843 }
844 
845 static void
846 instance_console(struct ustream *s, int bytes)
847 {
848         struct service_instance *in = container_of(s, struct service_instance, console.stream);
849         char *buf;
850         int len;
851 
852         do {
853                 buf = ustream_get_read_buf(s, &len);
854                 if (!buf)
855                         break;
856 
857                 DEBUG(LOG_INFO, "out: %s\n", buf);
858 
859                 /* test if console client is attached */
860                 if (in->console_client.fd.fd > -1)
861                         ustream_write(&in->console_client.stream, buf, len, false);
862 
863                 ustream_consume(s, len);
864         } while (1);
865 }
866 
867 static void
868 instance_console_client(struct ustream *s, int bytes)
869 {
870         struct service_instance *in = container_of(s, struct service_instance, console_client.stream);
871         char *buf;
872         int len;
873 
874         do {
875                 buf = ustream_get_read_buf(s, &len);
876                 if (!buf)
877                         break;
878 
879                 DEBUG(LOG_INFO, "in: %s\n", buf);
880                 ustream_write(&in->console.stream, buf, len, false);
881                 ustream_consume(s, len);
882         } while (1);
883 }
884 
885 static void
886 instance_stderr(struct ustream *s, int bytes)
887 {
888         instance_stdio(s, LOG_ERR,
889                        container_of(s, struct service_instance, _stderr.stream));
890 }
891 
892 static void
893 instance_timeout(struct uloop_timeout *t)
894 {
895         struct service_instance *in;
896 
897         in = container_of(t, struct service_instance, timeout);
898 
899         if (in->halt) {
900                 LOG("Instance %s::%s pid %d not stopped on SIGTERM, sending SIGKILL instead\n",
901                                 in->srv->name, in->name, in->proc.pid);
902                 kill(in->proc.pid, SIGKILL);
903         } else if (in->restart || in->respawn) {
904                 instance_start(in);
905                 rc(in->srv->name, "running");
906         }
907 }
908 
909 static void
910 instance_delete(struct service_instance *in)
911 {
912         struct service *s = in->srv;
913 
914         avl_delete(&s->instances.avl, &in->node.avl);
915         instance_free(in);
916         service_stopped(s);
917 }
918 
919 static int
920 instance_exit_code(int ret)
921 {
922         if (WIFEXITED(ret)) {
923                 return WEXITSTATUS(ret);
924         }
925 
926         if (WIFSIGNALED(ret)) {
927                 return SIGNALLED_OFFSET + WTERMSIG(ret);
928         }
929 
930         if (WIFSTOPPED(ret)) {
931                 return WSTOPSIG(ret);
932         }
933 
934         return 1;
935 }
936 
937 static void
938 instance_exit(struct uloop_process *p, int ret)
939 {
940         struct service_instance *in;
941         bool restart = false;
942         struct timespec tp;
943         long runtime;
944 
945         in = container_of(p, struct service_instance, proc);
946 
947         clock_gettime(CLOCK_MONOTONIC, &tp);
948         runtime = tp.tv_sec - in->start.tv_sec;
949 
950         P_DEBUG(2, "Instance %s::%s exit with error code %d after %ld seconds\n", in->srv->name, in->name, ret, runtime);
951 
952         in->exit_code = instance_exit_code(ret);
953         uloop_timeout_cancel(&in->timeout);
954         uloop_timeout_cancel(&in->watchdog.timeout);
955         service_event("instance.stop", in->srv->name, in->name);
956 
957         if (in->halt) {
958                 instance_removepid(in);
959                 if (in->restart)
960                         restart = true;
961                 else
962                         instance_delete(in);
963         } else if (in->restart) {
964                 restart = true;
965         } else if (in->respawn) {
966                 if (runtime < in->respawn_threshold)
967                         in->respawn_count++;
968                 else
969                         in->respawn_count = 0;
970                 if (in->respawn_count > in->respawn_retry && in->respawn_retry > 0 ) {
971                         LOG("Instance %s::%s s in a crash loop %d crashes, %ld seconds since last crash\n",
972                                                                 in->srv->name, in->name, in->respawn_count, runtime);
973                         in->restart = in->respawn = 0;
974                         in->halt = 1;
975                         service_event_instance_exit("instance.fail", in);
976                 } else {
977                         service_event_instance_exit("instance.respawn", in);
978                         uloop_timeout_set(&in->timeout, in->respawn_timeout * 1000);
979                 }
980         }
981 
982         if (restart) {
983                 instance_start(in);
984                 rc(in->srv->name, "running");
985         }
986 }
987 
988 void
989 instance_stop(struct service_instance *in, bool halt)
990 {
991         if (!in->proc.pending) {
992                 if (halt)
993                         instance_delete(in);
994                 return;
995         }
996         in->halt = halt;
997         in->restart = in->respawn = false;
998         kill(in->proc.pid, SIGTERM);
999         if (!in->has_jail)
1000                 uloop_timeout_set(&in->timeout, in->term_timeout * 1000);
1001 }
1002 
1003 static void
1004 instance_restart(struct service_instance *in)
1005 {
1006         if (!in->proc.pending)
1007                 return;
1008 
1009         if (in->reload_signal) {
1010                 kill(in->proc.pid, in->reload_signal);
1011                 return;
1012         }
1013 
1014         in->halt = true;
1015         in->restart = true;
1016         kill(in->proc.pid, SIGTERM);
1017         if (!in->has_jail)
1018                 uloop_timeout_set(&in->timeout, in->term_timeout * 1000);
1019 }
1020 
1021 static void
1022 instance_watchdog(struct uloop_timeout *t)
1023 {
1024         struct service_instance *in = container_of(t, struct service_instance, watchdog.timeout);
1025 
1026         P_DEBUG(3, "instance %s::%s watchdog timer expired\n", in->srv->name, in->name);
1027 
1028         if (in->respawn)
1029                 instance_restart(in);
1030         else
1031                 instance_stop(in, true);
1032 }
1033 
1034 static bool string_changed(const char *a, const char *b)
1035 {
1036         return !((!a && !b) || (a && b && !strcmp(a, b)));
1037 }
1038 
1039 static bool
1040 instance_config_changed(struct service_instance *in, struct service_instance *in_new)
1041 {
1042         if (!in->valid)
1043                 return true;
1044 
1045         if (!blob_attr_equal(in->command, in_new->command))
1046                 return true;
1047 
1048         if (string_changed(in->bundle, in_new->bundle))
1049                 return true;
1050 
1051         if (string_changed(in->extroot, in_new->extroot))
1052                 return true;
1053 
1054         if (string_changed(in->overlaydir, in_new->overlaydir))
1055                 return true;
1056 
1057         if (string_changed(in->tmpoverlaysize, in_new->tmpoverlaysize))
1058                 return true;
1059 
1060         if (!blobmsg_list_equal(&in->env, &in_new->env))
1061                 return true;
1062 
1063         if (!blobmsg_list_equal(&in->netdev, &in_new->netdev))
1064                 return true;
1065 
1066         if (!blobmsg_list_equal(&in->file, &in_new->file))
1067                 return true;
1068 
1069         if (in->nice != in_new->nice)
1070                 return true;
1071 
1072         if (in->syslog_facility != in_new->syslog_facility)
1073                 return true;
1074 
1075         if (string_changed(in->user, in_new->user))
1076                 return true;
1077 
1078         if (string_changed(in->group, in_new->group))
1079                 return true;
1080 
1081         if (in->uid != in_new->uid)
1082                 return true;
1083 
1084         if (in->pw_gid != in_new->pw_gid)
1085                 return true;
1086 
1087         if (in->gr_gid != in_new->gr_gid)
1088                 return true;
1089 
1090         if (string_changed(in->pidfile, in_new->pidfile))
1091                 return true;
1092 
1093         if (in->respawn_retry != in_new->respawn_retry)
1094                 return true;
1095         if (in->respawn_threshold != in_new->respawn_threshold)
1096                 return true;
1097         if (in->respawn_timeout != in_new->respawn_timeout)
1098                 return true;
1099 
1100         if (in->reload_signal != in_new->reload_signal)
1101                 return true;
1102 
1103         if (in->term_timeout != in_new->term_timeout)
1104                 return true;
1105 
1106         if (string_changed(in->seccomp, in_new->seccomp))
1107                 return true;
1108 
1109         if (string_changed(in->seccomp_mode, in_new->seccomp_mode))
1110                 return true;
1111 
1112         if (string_changed(in->seccomp_log, in_new->seccomp_log))
1113                 return true;
1114 
1115         if (string_changed(in->capabilities, in_new->capabilities))
1116                 return true;
1117 
1118         if (!blobmsg_list_equal(&in->limits, &in_new->limits))
1119                 return true;
1120 
1121         if (!blobmsg_list_equal(&in->jail.mount, &in_new->jail.mount))
1122                 return true;
1123 
1124         if (!blobmsg_list_equal(&in->jail.setns, &in_new->jail.setns))
1125                 return true;
1126 
1127         if (!blobmsg_list_equal(&in->errors, &in_new->errors))
1128                 return true;
1129 
1130         if (in->has_jail != in_new->has_jail)
1131                 return true;
1132 
1133         if (in->trace != in_new->trace)
1134                 return true;
1135 
1136         if (in->require_jail != in_new->require_jail)
1137                 return true;
1138 
1139         if (in->immediately != in_new->immediately)
1140                 return true;
1141 
1142         if (in->no_new_privs != in_new->no_new_privs)
1143                 return true;
1144 
1145         if (string_changed(in->jail.name, in_new->jail.name))
1146                 return true;
1147 
1148         if (string_changed(in->jail.hostname, in_new->jail.hostname))
1149                 return true;
1150 
1151         if (string_changed(in->jail.pidfile, in_new->jail.pidfile))
1152                 return true;
1153 
1154         if (string_changed(in->jail.consolesocket, in_new->jail.consolesocket))
1155                 return true;
1156 
1157         if (string_changed(in->jail.envfile, in_new->jail.envfile))
1158                 return true;
1159 
1160         if (in->jail.flags != in_new->jail.flags)
1161                 return true;
1162 
1163         if (!in->watchdog.self_managed && in->watchdog.mode != in_new->watchdog.mode)
1164                 return true;
1165 
1166         if (!in->watchdog.self_managed && in->watchdog.freq != in_new->watchdog.freq)
1167                 return true;
1168 
1169         return false;
1170 }
1171 
1172 static bool
1173 instance_netdev_cmp(struct blobmsg_list_node *l1, struct blobmsg_list_node *l2)
1174 {
1175         struct instance_netdev *n1 = container_of(l1, struct instance_netdev, node);
1176         struct instance_netdev *n2 = container_of(l2, struct instance_netdev, node);
1177 
1178         return n1->ifindex == n2->ifindex;
1179 }
1180 
1181 static void
1182 instance_netdev_update(struct blobmsg_list_node *l)
1183 {
1184         struct instance_netdev *n = container_of(l, struct instance_netdev, node);
1185 
1186         n->ifindex = if_nametoindex(n->node.avl.key);
1187 }
1188 
1189 static bool
1190 instance_file_cmp(struct blobmsg_list_node *l1, struct blobmsg_list_node *l2)
1191 {
1192         struct instance_file *f1 = container_of(l1, struct instance_file, node);
1193         struct instance_file *f2 = container_of(l2, struct instance_file, node);
1194 
1195         return !memcmp(f1->md5, f2->md5, sizeof(f1->md5));
1196 }
1197 
1198 static void
1199 instance_file_update(struct blobmsg_list_node *l)
1200 {
1201         struct instance_file *f = container_of(l, struct instance_file, node);
1202         md5_ctx_t md5;
1203         char buf[256];
1204         int len, fd;
1205 
1206         memset(f->md5, 0, sizeof(f->md5));
1207 
1208         fd = open(l->avl.key, O_RDONLY);
1209         if (fd < 0)
1210                 return;
1211 
1212         md5_begin(&md5);
1213         do {
1214                 len = read(fd, buf, sizeof(buf));
1215                 if (len < 0) {
1216                         if (errno == EINTR)
1217                                 continue;
1218 
1219                         break;
1220                 }
1221                 if (!len)
1222                         break;
1223 
1224                 md5_hash(buf, len, &md5);
1225         } while(1);
1226 
1227         md5_end(f->md5, &md5);
1228         close(fd);
1229 }
1230 
1231 static void
1232 instance_fill_any(struct blobmsg_list *l, struct blob_attr *cur)
1233 {
1234         if (!cur)
1235                 return;
1236 
1237         blobmsg_list_fill(l, blobmsg_data(cur), blobmsg_data_len(cur), false);
1238 }
1239 
1240 static bool
1241 instance_fill_array(struct blobmsg_list *l, struct blob_attr *cur, blobmsg_update_cb cb, bool array)
1242 {
1243         struct blobmsg_list_node *node;
1244 
1245         if (!cur)
1246                 return true;
1247 
1248         if (!blobmsg_check_attr_list(cur, BLOBMSG_TYPE_STRING))
1249                 return false;
1250 
1251         blobmsg_list_fill(l, blobmsg_data(cur), blobmsg_data_len(cur), array);
1252         if (cb) {
1253                 blobmsg_list_for_each(l, node)
1254                         cb(node);
1255         }
1256         return true;
1257 }
1258 
1259 static int
1260 instance_jail_parse(struct service_instance *in, struct blob_attr *attr)
1261 {
1262         struct blob_attr *tb[__JAIL_ATTR_MAX];
1263         struct jail *jail = &in->jail;
1264         struct blobmsg_list_node *var;
1265 
1266         blobmsg_parse(jail_attr, __JAIL_ATTR_MAX, tb,
1267                 blobmsg_data(attr), blobmsg_data_len(attr));
1268 
1269         jail->argc = 4;
1270 
1271         if (tb[JAIL_ATTR_REQUIREJAIL] && blobmsg_get_bool(tb[JAIL_ATTR_REQUIREJAIL])) {
1272                 in->require_jail = true;
1273                 jail->argc++;
1274         }
1275         if (tb[JAIL_ATTR_IMMEDIATELY] && blobmsg_get_bool(tb[JAIL_ATTR_IMMEDIATELY])) {
1276                 in->immediately = true;
1277                 jail->argc++;
1278         }
1279         if (tb[JAIL_ATTR_NAME]) {
1280                 jail->name = strdup(blobmsg_get_string(tb[JAIL_ATTR_NAME]));
1281                 jail->argc += 2;
1282         }
1283         if (tb[JAIL_ATTR_HOSTNAME]) {
1284                 jail->hostname = strdup(blobmsg_get_string(tb[JAIL_ATTR_HOSTNAME]));
1285                 jail->argc += 2;
1286         }
1287         if (tb[JAIL_ATTR_PROCFS] && blobmsg_get_bool(tb[JAIL_ATTR_PROCFS])) {
1288                 jail->procfs = true;
1289                 jail->argc++;
1290         }
1291         if (tb[JAIL_ATTR_SYSFS] && blobmsg_get_bool(tb[JAIL_ATTR_SYSFS])) {
1292                 jail->sysfs = true;
1293                 jail->argc++;
1294         }
1295         if (tb[JAIL_ATTR_UBUS] && blobmsg_get_bool(tb[JAIL_ATTR_UBUS])) {
1296                 jail->ubus = true;
1297                 jail->argc++;
1298         }
1299         if (tb[JAIL_ATTR_UDEBUG] && blobmsg_get_bool(tb[JAIL_ATTR_UDEBUG])) {
1300                 jail->udebug = true;
1301                 jail->argc++;
1302         }
1303         if (tb[JAIL_ATTR_LOG] && blobmsg_get_bool(tb[JAIL_ATTR_LOG])) {
1304                 jail->log = true;
1305                 jail->argc++;
1306         }
1307         if (tb[JAIL_ATTR_RONLY] && blobmsg_get_bool(tb[JAIL_ATTR_RONLY])) {
1308                 jail->ronly = true;
1309                 jail->argc++;
1310         }
1311         if (tb[JAIL_ATTR_NETNS] && blobmsg_get_bool(tb[JAIL_ATTR_NETNS])) {
1312                 jail->netns = true;
1313                 jail->argc++;
1314         }
1315         if (tb[JAIL_ATTR_USERNS] && blobmsg_get_bool(tb[JAIL_ATTR_USERNS])) {
1316                 jail->userns = true;
1317                 jail->argc++;
1318         }
1319         if (tb[JAIL_ATTR_CGROUPSNS] && blobmsg_get_bool(tb[JAIL_ATTR_CGROUPSNS])) {
1320                 jail->cgroupsns = true;
1321                 jail->argc++;
1322         }
1323         if (tb[JAIL_ATTR_CONSOLE] && blobmsg_get_bool(tb[JAIL_ATTR_CONSOLE])) {
1324                 jail->console = true;
1325                 jail->argc++;
1326         }
1327         if (tb[JAIL_ATTR_PIDFILE]) {
1328                 jail->pidfile = strdup(blobmsg_get_string(tb[JAIL_ATTR_PIDFILE]));
1329                 jail->argc += 2;
1330         }
1331 
1332         if (tb[JAIL_ATTR_IDMAP_OFFSET]) {
1333                 jail->idmap_offset = strdup(blobmsg_get_string(tb[JAIL_ATTR_IDMAP_OFFSET]));
1334                 jail->argc += 2;
1335         }
1336         if (tb[JAIL_ATTR_CONSOLESOCKET]) {
1337                 jail->consolesocket = strdup(blobmsg_get_string(tb[JAIL_ATTR_CONSOLESOCKET]));
1338                 jail->argc += 2;
1339         }
1340 
1341         if (tb[JAIL_ATTR_SYSTEMDCGROUP] && blobmsg_get_bool(tb[JAIL_ATTR_SYSTEMDCGROUP])) {
1342                 jail->systemd_cgroup = true;
1343                 jail->argc++;
1344         }
1345 
1346         if (tb[JAIL_ATTR_ENVFILE]) {
1347                 jail->envfile = strdup(blobmsg_get_string(tb[JAIL_ATTR_ENVFILE]));
1348                 jail->argc += 2;
1349         }
1350 
1351         if (tb[JAIL_ATTR_SETNS]) {
1352                 struct blob_attr *cur;
1353                 int rem;
1354 
1355                 blobmsg_for_each_attr(cur, tb[JAIL_ATTR_SETNS], rem)
1356                         jail->argc += 2;
1357                 blobmsg_list_fill(&jail->setns, blobmsg_data(tb[JAIL_ATTR_SETNS]),
1358                                   blobmsg_data_len(tb[JAIL_ATTR_SETNS]), true);
1359         }
1360 
1361         if (tb[JAIL_ATTR_MOUNT]) {
1362                 struct blob_attr *cur;
1363                 int rem;
1364 
1365                 blobmsg_for_each_attr(cur, tb[JAIL_ATTR_MOUNT], rem)
1366                         jail->argc += 2;
1367                 instance_fill_array(&jail->mount, tb[JAIL_ATTR_MOUNT], NULL, false);
1368         }
1369 
1370         blobmsg_list_for_each(&in->env, var)
1371                 jail->argc += 2;
1372 
1373         if (in->seccomp)
1374                 jail->argc += 2;
1375 
1376         if (in->seccomp_mode)
1377                 jail->argc += 2;
1378 
1379         if (in->seccomp_log)
1380                 jail->argc += 2;
1381 
1382         if (in->capabilities)
1383                 jail->argc += 2;
1384 
1385         if (in->user)
1386                 jail->argc += 2;
1387 
1388         if (in->group)
1389                 jail->argc += 2;
1390 
1391         if (in->extroot)
1392                 jail->argc += 2;
1393 
1394         if (in->overlaydir)
1395                 jail->argc += 2;
1396 
1397         if (in->tmpoverlaysize)
1398                 jail->argc += 2;
1399 
1400         if (in->no_new_privs)
1401                 jail->argc++;
1402 
1403         if (in->bundle)
1404                 jail->argc += 2;
1405 
1406         return true;
1407 }
1408 
1409 static bool
1410 instance_config_parse_command(struct service_instance *in, struct blob_attr **tb)
1411 {
1412         struct blob_attr *cur, *cur2;
1413         bool ret = false;
1414         int rem;
1415 
1416         cur = tb[INSTANCE_ATTR_COMMAND];
1417         if (!cur) {
1418                 in->command = NULL;
1419                 return true;
1420         }
1421 
1422         if (!blobmsg_check_attr_list(cur, BLOBMSG_TYPE_STRING))
1423                 return false;
1424 
1425         blobmsg_for_each_attr(cur2, cur, rem) {
1426                 ret = true;
1427                 break;
1428         }
1429 
1430         in->command = cur;
1431         return ret;
1432 }
1433 
1434 static bool
1435 instance_config_parse(struct service_instance *in)
1436 {
1437         struct blob_attr *tb[__INSTANCE_ATTR_MAX];
1438         struct blob_attr *cur, *cur2;
1439         struct stat s;
1440         int rem, r;
1441 
1442         blobmsg_parse(instance_attr, __INSTANCE_ATTR_MAX, tb,
1443                 blobmsg_data(in->config), blobmsg_data_len(in->config));
1444 
1445         if (!tb[INSTANCE_ATTR_BUNDLE] && !instance_config_parse_command(in, tb))
1446                         return false;
1447 
1448         if (tb[INSTANCE_ATTR_TERMTIMEOUT])
1449                 in->term_timeout = blobmsg_get_u32(tb[INSTANCE_ATTR_TERMTIMEOUT]);
1450         if (tb[INSTANCE_ATTR_RESPAWN]) {
1451                 int i = 0;
1452                 uint32_t vals[3] = { 3600, 5, 5};
1453 
1454                 blobmsg_for_each_attr(cur2, tb[INSTANCE_ATTR_RESPAWN], rem) {
1455                         if ((i >= 3) && (blobmsg_type(cur2) == BLOBMSG_TYPE_STRING))
1456                                 continue;
1457                         vals[i] = atoi(blobmsg_get_string(cur2));
1458                         i++;
1459                 }
1460                 in->respawn = true;
1461                 in->respawn_count = 0;
1462                 in->respawn_threshold = vals[0];
1463                 in->respawn_timeout = vals[1];
1464                 in->respawn_retry = vals[2];
1465         }
1466         if (tb[INSTANCE_ATTR_TRIGGER]) {
1467                 in->trigger = tb[INSTANCE_ATTR_TRIGGER];
1468                 trigger_add(in->trigger, in);
1469         }
1470 
1471         if (tb[INSTANCE_ATTR_WATCH]) {
1472                 blobmsg_for_each_attr(cur2, tb[INSTANCE_ATTR_WATCH], rem) {
1473                         if (blobmsg_type(cur2) != BLOBMSG_TYPE_STRING)
1474                                 continue;
1475                         P_DEBUG(3, "watch for %s\n", blobmsg_get_string(cur2));
1476                         watch_add(blobmsg_get_string(cur2), in);
1477                 }
1478         }
1479 
1480         if ((cur = tb[INSTANCE_ATTR_NICE])) {
1481                 in->nice = (int8_t) blobmsg_get_u32(cur);
1482                 if (in->nice < -20 || in->nice > 20)
1483                         return false;
1484         }
1485 
1486         if (tb[INSTANCE_ATTR_USER]) {
1487                 const char *user = blobmsg_get_string(tb[INSTANCE_ATTR_USER]);
1488                 struct passwd *p = getpwnam(user);
1489                 if (p) {
1490                         in->user = strdup(user);
1491                         in->uid = p->pw_uid;
1492                         in->gr_gid = in->pw_gid = p->pw_gid;
1493                 }
1494         }
1495 
1496         if (tb[INSTANCE_ATTR_GROUP]) {
1497                 const char *group = blobmsg_get_string(tb[INSTANCE_ATTR_GROUP]);
1498                 struct group *p = getgrnam(group);
1499                 if (p) {
1500                         in->group = strdup(group);
1501                         in->gr_gid = p->gr_gid;
1502                 }
1503         }
1504 
1505         if (tb[INSTANCE_ATTR_TRACE])
1506                 in->trace = blobmsg_get_bool(tb[INSTANCE_ATTR_TRACE]);
1507 
1508         if (tb[INSTANCE_ATTR_NO_NEW_PRIVS])
1509                 in->no_new_privs = blobmsg_get_bool(tb[INSTANCE_ATTR_NO_NEW_PRIVS]);
1510 
1511         if (!in->trace && tb[INSTANCE_ATTR_SECCOMP])
1512                 in->seccomp = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_SECCOMP]));
1513 
1514         if (tb[INSTANCE_ATTR_SECCOMP_MODE])
1515                 in->seccomp_mode = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_SECCOMP_MODE]));
1516 
1517         if (tb[INSTANCE_ATTR_SECCOMP_LOG])
1518                 in->seccomp_log = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_SECCOMP_LOG]));
1519 
1520         if (tb[INSTANCE_ATTR_CAPABILITIES])
1521                 in->capabilities = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_CAPABILITIES]));
1522 
1523         if (tb[INSTANCE_ATTR_EXTROOT])
1524                 in->extroot = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_EXTROOT]));
1525 
1526         if (tb[INSTANCE_ATTR_OVERLAYDIR])
1527                 in->overlaydir = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_OVERLAYDIR]));
1528 
1529         if (tb[INSTANCE_ATTR_TMPOVERLAYSIZE])
1530                 in->tmpoverlaysize = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_TMPOVERLAYSIZE]));
1531 
1532         if (tb[INSTANCE_ATTR_BUNDLE])
1533                 in->bundle = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_BUNDLE]));
1534 
1535         if (tb[INSTANCE_ATTR_PIDFILE]) {
1536                 char *pidfile = blobmsg_get_string(tb[INSTANCE_ATTR_PIDFILE]);
1537                 if (pidfile)
1538                         in->pidfile = strdup(pidfile);
1539         }
1540 
1541         if (tb[INSTANCE_ATTR_RELOADSIG])
1542                 in->reload_signal = blobmsg_get_u32(tb[INSTANCE_ATTR_RELOADSIG]);
1543 
1544         if (tb[INSTANCE_ATTR_STDOUT] && blobmsg_get_bool(tb[INSTANCE_ATTR_STDOUT]))
1545                 in->_stdout.fd.fd = -1;
1546 
1547         if (tb[INSTANCE_ATTR_STDERR] && blobmsg_get_bool(tb[INSTANCE_ATTR_STDERR]))
1548                 in->_stderr.fd.fd = -1;
1549 
1550         instance_fill_any(&in->data, tb[INSTANCE_ATTR_DATA]);
1551 
1552         if (!instance_fill_array(&in->env, tb[INSTANCE_ATTR_ENV], NULL, false))
1553                 return false;
1554 
1555         if (!instance_fill_array(&in->netdev, tb[INSTANCE_ATTR_NETDEV], instance_netdev_update, true))
1556                 return false;
1557 
1558         if (!instance_fill_array(&in->file, tb[INSTANCE_ATTR_FILE], instance_file_update, true))
1559                 return false;
1560 
1561         if (!instance_fill_array(&in->limits, tb[INSTANCE_ATTR_LIMITS], NULL, false))
1562                 return false;
1563 
1564         if (!instance_fill_array(&in->errors, tb[INSTANCE_ATTR_ERROR], NULL, true))
1565                 return false;
1566 
1567         if (tb[INSTANCE_ATTR_FACILITY]) {
1568                 int facility = syslog_facility_str_to_int(blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY]));
1569                 if (facility != -1) {
1570                         in->syslog_facility = facility;
1571                         P_DEBUG(3, "setting facility '%s'\n", blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY]));
1572                 } else
1573                         P_DEBUG(3, "unknown syslog facility '%s' given, using default (LOG_DAEMON)\n", blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY]));
1574         }
1575 
1576         if (tb[INSTANCE_ATTR_WATCHDOG]) {
1577                 int i = 0;
1578                 uint32_t vals[2] = { 0, 30 };
1579 
1580                 blobmsg_for_each_attr(cur2, tb[INSTANCE_ATTR_WATCHDOG], rem) {
1581                         if (i >= 2)
1582                                 break;
1583 
1584                         vals[i] = atoi(blobmsg_get_string(cur2));
1585                         i++;
1586                 }
1587 
1588                 if (vals[0] >= 0 && vals[0] < __INSTANCE_WATCHDOG_MODE_MAX) {
1589                         in->watchdog.mode = vals[0];
1590                         P_DEBUG(3, "setting watchdog mode (%d)\n", vals[0]);
1591                 } else {
1592                         in->watchdog.mode = 0;
1593                         P_DEBUG(3, "unknown watchdog mode (%d) given, using default (0)\n", vals[0]);
1594                 }
1595 
1596                 if (vals[1] > 0) {
1597                         in->watchdog.freq = vals[1];
1598                         P_DEBUG(3, "setting watchdog timeout (%d)\n", vals[0]);
1599                 } else {
1600                         in->watchdog.freq = 30;
1601                         P_DEBUG(3, "invalid watchdog timeout (%d) given, using default (30)\n", vals[1]);
1602                 }
1603         }
1604 
1605         if (!in->trace && tb[INSTANCE_ATTR_JAIL])
1606                 in->has_jail = instance_jail_parse(in, tb[INSTANCE_ATTR_JAIL]);
1607 
1608         if (in->has_jail) {
1609                 r = stat(UJAIL_BIN_PATH, &s);
1610                 if (r < 0) {
1611                         if (in->require_jail) {
1612                                 ERROR("Cannot jail service %s::%s. %s: %m (%d)\n",
1613                                                 in->srv->name, in->name, UJAIL_BIN_PATH, r);
1614                                 return false;
1615                         }
1616                         P_DEBUG(2, "unable to find %s: %m (%d)\n", UJAIL_BIN_PATH, r);
1617                         in->has_jail = false;
1618                 }
1619         }
1620 
1621         return true;
1622 }
1623 
1624 static void
1625 instance_config_cleanup(struct service_instance *in)
1626 {
1627         blobmsg_list_free(&in->env);
1628         blobmsg_list_free(&in->data);
1629         blobmsg_list_free(&in->netdev);
1630         blobmsg_list_free(&in->file);
1631         blobmsg_list_free(&in->limits);
1632         blobmsg_list_free(&in->errors);
1633         blobmsg_list_free(&in->jail.mount);
1634         blobmsg_list_free(&in->jail.setns);
1635 }
1636 
1637 static void
1638 instance_config_move_strdup(char **dst, char *src)
1639 {
1640         if (*dst) {
1641                 free(*dst);
1642                 *dst = NULL;
1643         }
1644 
1645         if (!src)
1646                 return;
1647 
1648         *dst = strdup(src);
1649 }
1650 
1651 static void
1652 instance_config_move(struct service_instance *in, struct service_instance *in_src)
1653 {
1654         instance_config_cleanup(in);
1655         blobmsg_list_move(&in->env, &in_src->env);
1656         blobmsg_list_move(&in->data, &in_src->data);
1657         blobmsg_list_move(&in->netdev, &in_src->netdev);
1658         blobmsg_list_move(&in->file, &in_src->file);
1659         blobmsg_list_move(&in->limits, &in_src->limits);
1660         blobmsg_list_move(&in->errors, &in_src->errors);
1661         blobmsg_list_move(&in->jail.mount, &in_src->jail.mount);
1662         blobmsg_list_move(&in->jail.setns, &in_src->jail.setns);
1663         in->trigger = in_src->trigger;
1664         in->command = in_src->command;
1665         in->respawn = in_src->respawn;
1666         in->respawn_retry = in_src->respawn_retry;
1667         in->respawn_threshold = in_src->respawn_threshold;
1668         in->respawn_timeout = in_src->respawn_timeout;
1669         in->reload_signal = in_src->reload_signal;
1670         in->term_timeout = in_src->term_timeout;
1671         if (!in->watchdog.self_managed) {
1672                 // Note: in->watchdog.timeout is in a linked list; do not copy
1673                 in->watchdog.mode = in_src->watchdog.mode;
1674                 in->watchdog.freq = in_src->watchdog.freq;
1675         }
1676         in->name = in_src->name;
1677         in->nice = in_src->nice;
1678         in->trace = in_src->trace;
1679         in->node.avl.key = in_src->node.avl.key;
1680         in->syslog_facility = in_src->syslog_facility;
1681         in->require_jail = in_src->require_jail;
1682         in->no_new_privs = in_src->no_new_privs;
1683         in->immediately = in_src->immediately;
1684         in->uid = in_src->uid;
1685         in->pw_gid = in_src->pw_gid;
1686         in->gr_gid = in_src->gr_gid;
1687 
1688         in->has_jail = in_src->has_jail;
1689         in->jail.flags = in_src->jail.flags;
1690         in->jail.argc = in_src->jail.argc;
1691 
1692         instance_config_move_strdup(&in->pidfile, in_src->pidfile);
1693         instance_config_move_strdup(&in->seccomp, in_src->seccomp);
1694         instance_config_move_strdup(&in->seccomp_mode, in_src->seccomp_mode);
1695         instance_config_move_strdup(&in->seccomp_log, in_src->seccomp_log);
1696         instance_config_move_strdup(&in->capabilities, in_src->capabilities);
1697         instance_config_move_strdup(&in->bundle, in_src->bundle);
1698         instance_config_move_strdup(&in->extroot, in_src->extroot);
1699         instance_config_move_strdup(&in->overlaydir, in_src->overlaydir);
1700         instance_config_move_strdup(&in->tmpoverlaysize, in_src->tmpoverlaysize);
1701         instance_config_move_strdup(&in->user, in_src->user);
1702         instance_config_move_strdup(&in->group, in_src->group);
1703         instance_config_move_strdup(&in->jail.name, in_src->jail.name);
1704         instance_config_move_strdup(&in->jail.hostname, in_src->jail.hostname);
1705         instance_config_move_strdup(&in->jail.pidfile, in_src->jail.pidfile);
1706         instance_config_move_strdup(&in->jail.consolesocket, in_src->jail.consolesocket);
1707         instance_config_move_strdup(&in->jail.envfile, in_src->jail.envfile);
1708 
1709         free(in->config);
1710         in->config = in_src->config;
1711         in_src->config = NULL;
1712 }
1713 
1714 void
1715 instance_update(struct service_instance *in, struct service_instance *in_new)
1716 {
1717         bool changed = instance_config_changed(in, in_new);
1718         bool running = in->proc.pending;
1719         bool stopping = in->halt;
1720 
1721         if (in_new->stdio_fd[1] > -1)
1722                 instance_stdio_set(in, in_new->stdio_fd);
1723 
1724         if (in_new->notify_fd > -1)
1725                 instance_notify_set(in, &in_new->notify_fd);
1726 
1727         if (!running || stopping) {
1728                 instance_config_move(in, in_new);
1729                 instance_start(in);
1730         } else {
1731                 if (changed)
1732                         instance_restart(in);
1733                 else if (!blobmsg_list_equal(&in->data, &in_new->data)) {
1734                         service_data_trigger(&in->data);
1735                         service_data_trigger(&in_new->data);
1736                 }
1737                 instance_config_move(in, in_new);
1738                 /* restart happens in the child callback handler */
1739         }
1740 }
1741 
1742 static void
1743 instance_free_stdio_fds(struct service_instance *in)
1744 {
1745         int i;
1746 
1747         for (i = 0; i < 3; i++) {
1748                 if (in->stdio_fd[i] < 0)
1749                         continue;
1750 
1751                 close(in->stdio_fd[i]);
1752                 in->stdio_fd[i] = -1;
1753         }
1754 }
1755 
1756 void
1757 instance_stdio_set(struct service_instance *in, int *fds)
1758 {
1759         int i;
1760 
1761         instance_free_stdio_fds(in);
1762 
1763         for (i = 0; i < 3; i++) {
1764                 in->stdio_fd[i] = fds[i];
1765                 fds[i] = -1;
1766         }
1767 }
1768 
1769 static void
1770 instance_free_notify_fd(struct service_instance *in)
1771 {
1772         if (in->notify_fd < 0)
1773                 return;
1774 
1775         close(in->notify_fd);
1776         in->notify_fd = -1;
1777 }
1778 
1779 void
1780 instance_notify_set(struct service_instance *in, int *fd)
1781 {
1782         instance_free_notify_fd(in);
1783 
1784         in->notify_fd = *fd;
1785         *fd = -1;
1786 }
1787 
1788 void
1789 instance_free(struct service_instance *in)
1790 {
1791         service_data_trigger(&in->data);
1792         instance_free_stdio(in);
1793         instance_free_stdio_fds(in);
1794         instance_free_notify_fd(in);
1795         uloop_process_delete(&in->proc);
1796         uloop_timeout_cancel(&in->timeout);
1797         uloop_timeout_cancel(&in->watchdog.timeout);
1798         trigger_del(in);
1799         watch_del(in);
1800         instance_remove_cgroup(in->srv->name, in->name);
1801         instance_config_cleanup(in);
1802         free(in->config);
1803         free(in->data_blob);
1804         free(in->user);
1805         free(in->group);
1806         free(in->extroot);
1807         free(in->overlaydir);
1808         free(in->tmpoverlaysize);
1809         free(in->bundle);
1810         free(in->jail.name);
1811         free(in->jail.hostname);
1812         free(in->jail.pidfile);
1813         free(in->jail.idmap_offset);
1814         free(in->jail.consolesocket);
1815         free(in->seccomp);
1816         free(in->seccomp_mode);
1817         free(in->seccomp_log);
1818         free(in->capabilities);
1819         free(in->pidfile);
1820         free(in);
1821 }
1822 
1823 void
1824 instance_init(struct service_instance *in, struct service *s, struct blob_attr *config)
1825 {
1826         config = blob_memdup(config);
1827         in->srv = s;
1828         in->name = blobmsg_name(config);
1829         in->config = config;
1830         in->timeout.cb = instance_timeout;
1831         in->proc.cb = instance_exit;
1832         in->term_timeout = 5;
1833         in->syslog_facility = LOG_DAEMON;
1834         in->exit_code = 0;
1835         in->require_jail = false;
1836         in->immediately = false;
1837 
1838         in->stdio_fd[0] = in->stdio_fd[1] = in->stdio_fd[2] = -1;
1839         in->notify_fd = -1;
1840 
1841         in->_stdout.fd.fd = -2;
1842         in->_stdout.stream.string_data = true;
1843         in->_stdout.stream.notify_read = instance_stdout;
1844 
1845         in->_stderr.fd.fd = -2;
1846         in->_stderr.stream.string_data = true;
1847         in->_stderr.stream.notify_read = instance_stderr;
1848 
1849         in->console.fd.fd = -2;
1850         in->console.stream.string_data = true;
1851         in->console.stream.notify_read = instance_console;
1852 
1853         in->console_client.fd.fd = -2;
1854         in->console_client.stream.string_data = true;
1855         in->console_client.stream.notify_read = instance_console_client;
1856 
1857         blobmsg_list_init(&in->netdev, struct instance_netdev, node, instance_netdev_cmp);
1858         blobmsg_list_init(&in->file, struct instance_file, node, instance_file_cmp);
1859         blobmsg_list_simple_init(&in->env);
1860         blobmsg_list_simple_init(&in->data);
1861         blobmsg_list_simple_init(&in->limits);
1862         blobmsg_list_simple_init(&in->errors);
1863         blobmsg_list_simple_init(&in->jail.mount);
1864         blobmsg_list_simple_init(&in->jail.setns);
1865 
1866         in->watchdog.timeout.cb = instance_watchdog;
1867 
1868         in->valid = instance_config_parse(in);
1869         service_data_trigger(&in->data);
1870 }
1871 
1872 void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose)
1873 {
1874         void *i;
1875 
1876         if (!in->valid)
1877                 return;
1878 
1879         i = blobmsg_open_table(b, in->name);
1880         blobmsg_add_u8(b, "running", in->proc.pending);
1881         if (in->proc.pending)
1882                 blobmsg_add_u32(b, "pid", in->proc.pid);
1883         if (in->command)
1884                 blobmsg_add_blob(b, in->command);
1885         if (in->bundle)
1886                 blobmsg_add_string(b, "bundle", in->bundle);
1887         blobmsg_add_u32(b, "term_timeout", in->term_timeout);
1888         if (!in->proc.pending)
1889                 blobmsg_add_u32(b, "exit_code", in->exit_code);
1890 
1891         if (!avl_is_empty(&in->errors.avl)) {
1892                 struct blobmsg_list_node *var;
1893                 void *e = blobmsg_open_array(b, "errors");
1894                 blobmsg_list_for_each(&in->errors, var)
1895                         blobmsg_add_string(b, NULL, blobmsg_data(var->data));
1896                 blobmsg_close_table(b, e);
1897         }
1898 
1899         if (!avl_is_empty(&in->env.avl)) {
1900                 struct blobmsg_list_node *var;
1901                 void *e = blobmsg_open_table(b, "env");
1902                 blobmsg_list_for_each(&in->env, var)
1903                         blobmsg_add_string(b, blobmsg_name(var->data), blobmsg_data(var->data));
1904                 blobmsg_close_table(b, e);
1905         }
1906 
1907         if (!avl_is_empty(&in->data.avl)) {
1908                 struct blobmsg_list_node *var;
1909                 void *e = blobmsg_open_table(b, "data");
1910                 blobmsg_list_for_each(&in->data, var)
1911                         blobmsg_add_blob(b, var->data);
1912                 blobmsg_close_table(b, e);
1913         }
1914 
1915         if (!avl_is_empty(&in->limits.avl)) {
1916                 struct blobmsg_list_node *var;
1917                 void *e = blobmsg_open_table(b, "limits");
1918                 blobmsg_list_for_each(&in->limits, var)
1919                         blobmsg_add_string(b, blobmsg_name(var->data), blobmsg_data(var->data));
1920                 blobmsg_close_table(b, e);
1921         }
1922 
1923         if (!avl_is_empty(&in->netdev.avl)) {
1924                 struct blobmsg_list_node *var;
1925                 void *n = blobmsg_open_array(b, "netdev");
1926 
1927                 blobmsg_list_for_each(&in->netdev, var)
1928                         blobmsg_add_string(b, NULL, blobmsg_data(var->data));
1929                 blobmsg_close_array(b, n);
1930         }
1931 
1932         if (in->reload_signal)
1933                 blobmsg_add_u32(b, "reload_signal", in->reload_signal);
1934 
1935         if (in->respawn) {
1936                 void *r = blobmsg_open_table(b, "respawn");
1937                 blobmsg_add_u32(b, "threshold", in->respawn_threshold);
1938                 blobmsg_add_u32(b, "timeout", in->respawn_timeout);
1939                 blobmsg_add_u32(b, "retry", in->respawn_retry);
1940                 blobmsg_close_table(b, r);
1941         }
1942 
1943         if (in->trace)
1944                 blobmsg_add_u8(b, "trace", true);
1945 
1946         if (in->no_new_privs)
1947                 blobmsg_add_u8(b, "no_new_privs", true);
1948 
1949         if (in->seccomp)
1950                 blobmsg_add_string(b, "seccomp", in->seccomp);
1951 
1952         if (in->capabilities)
1953                 blobmsg_add_string(b, "capabilities", in->capabilities);
1954 
1955         if (in->pidfile)
1956                 blobmsg_add_string(b, "pidfile", in->pidfile);
1957 
1958         if (in->user)
1959                 blobmsg_add_string(b, "user", in->user);
1960 
1961         if (in->group)
1962                 blobmsg_add_string(b, "group", in->group);
1963 
1964         if (in->has_jail) {
1965                 void *r = blobmsg_open_table(b, "jail");
1966                 if (in->jail.name)
1967                         blobmsg_add_string(b, "name", in->jail.name);
1968                 if (!in->bundle) {
1969                         if (in->jail.hostname)
1970                                 blobmsg_add_string(b, "hostname", in->jail.hostname);
1971 
1972                         blobmsg_add_u8(b, "procfs", in->jail.procfs);
1973                         blobmsg_add_u8(b, "sysfs", in->jail.sysfs);
1974                         blobmsg_add_u8(b, "ubus", in->jail.ubus);
1975                         blobmsg_add_u8(b, "log", in->jail.log);
1976                         blobmsg_add_u8(b, "ronly", in->jail.ronly);
1977                         blobmsg_add_u8(b, "netns", in->jail.netns);
1978                         blobmsg_add_u8(b, "userns", in->jail.userns);
1979                         blobmsg_add_u8(b, "cgroupsns", in->jail.cgroupsns);
1980                 } else {
1981                         if (in->jail.pidfile)
1982                                 blobmsg_add_string(b, "pidfile", in->jail.pidfile);
1983 
1984                         blobmsg_add_u8(b, "immediately", in->immediately);
1985                 }
1986                 blobmsg_add_u8(b, "console", (in->console.fd.fd > -1));
1987                 blobmsg_close_table(b, r);
1988                 if (!avl_is_empty(&in->jail.mount.avl)) {
1989                         struct blobmsg_list_node *var;
1990                         void *e = blobmsg_open_table(b, "mount");
1991                         blobmsg_list_for_each(&in->jail.mount, var)
1992                                 blobmsg_add_string(b, blobmsg_name(var->data), blobmsg_data(var->data));
1993                         blobmsg_close_table(b, e);
1994                 }
1995 
1996                 if (!avl_is_empty(&in->jail.setns.avl)) {
1997                         struct blobmsg_list_node *var;
1998                         void *s = blobmsg_open_array(b, "setns");
1999                         blobmsg_list_for_each(&in->jail.setns, var)
2000                                 blobmsg_add_blob(b, var->data);
2001                         blobmsg_close_array(b, s);
2002                 }
2003         }
2004 
2005         if (in->extroot)
2006                 blobmsg_add_string(b, "extroot", in->extroot);
2007         if (in->overlaydir)
2008                 blobmsg_add_string(b, "overlaydir", in->overlaydir);
2009         if (in->tmpoverlaysize)
2010                 blobmsg_add_string(b, "tmpoverlaysize", in->tmpoverlaysize);
2011 
2012         if (verbose && in->trigger)
2013                 blobmsg_add_blob(b, in->trigger);
2014 
2015         if (in->watchdog.mode != INSTANCE_WATCHDOG_MODE_DISABLED) {
2016                 void *r = blobmsg_open_table(b, "watchdog");
2017                 blobmsg_add_u32(b, "mode", in->watchdog.mode);
2018                 blobmsg_add_u32(b, "timeout", in->watchdog.freq);
2019                 blobmsg_close_table(b, r);
2020         }
2021 
2022         blobmsg_close_table(b, i);
2023 }
2024 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt