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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt