add ifdefs to make service/instance.c compile on non-linux systems
[project/procd.git] / 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 <net/if.h>
21 #include <unistd.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <fcntl.h>
25 #include <pwd.h>
26 #include <libgen.h>
27 #include <unistd.h>
28
29 #include <libubox/md5.h>
30
31 #include "../procd.h"
32
33 #include "service.h"
34 #include "instance.h"
35
36
37 enum {
38         INSTANCE_ATTR_COMMAND,
39         INSTANCE_ATTR_ENV,
40         INSTANCE_ATTR_DATA,
41         INSTANCE_ATTR_NETDEV,
42         INSTANCE_ATTR_FILE,
43         INSTANCE_ATTR_TRIGGER,
44         INSTANCE_ATTR_RESPAWN,
45         INSTANCE_ATTR_NICE,
46         INSTANCE_ATTR_LIMITS,
47         INSTANCE_ATTR_WATCH,
48         INSTANCE_ATTR_ERROR,
49         INSTANCE_ATTR_USER,
50         INSTANCE_ATTR_STDOUT,
51         INSTANCE_ATTR_STDERR,
52         INSTANCE_ATTR_NO_NEW_PRIVS,
53         INSTANCE_ATTR_JAIL,
54         INSTANCE_ATTR_TRACE,
55         INSTANCE_ATTR_SECCOMP,
56         __INSTANCE_ATTR_MAX
57 };
58
59 static const struct blobmsg_policy instance_attr[__INSTANCE_ATTR_MAX] = {
60         [INSTANCE_ATTR_COMMAND] = { "command", BLOBMSG_TYPE_ARRAY },
61         [INSTANCE_ATTR_ENV] = { "env", BLOBMSG_TYPE_TABLE },
62         [INSTANCE_ATTR_DATA] = { "data", BLOBMSG_TYPE_TABLE },
63         [INSTANCE_ATTR_NETDEV] = { "netdev", BLOBMSG_TYPE_ARRAY },
64         [INSTANCE_ATTR_FILE] = { "file", BLOBMSG_TYPE_ARRAY },
65         [INSTANCE_ATTR_TRIGGER] = { "triggers", BLOBMSG_TYPE_ARRAY },
66         [INSTANCE_ATTR_RESPAWN] = { "respawn", BLOBMSG_TYPE_ARRAY },
67         [INSTANCE_ATTR_NICE] = { "nice", BLOBMSG_TYPE_INT32 },
68         [INSTANCE_ATTR_LIMITS] = { "limits", BLOBMSG_TYPE_TABLE },
69         [INSTANCE_ATTR_WATCH] = { "watch", BLOBMSG_TYPE_ARRAY },
70         [INSTANCE_ATTR_ERROR] = { "error", BLOBMSG_TYPE_ARRAY },
71         [INSTANCE_ATTR_USER] = { "user", BLOBMSG_TYPE_STRING },
72         [INSTANCE_ATTR_STDOUT] = { "stdout", BLOBMSG_TYPE_BOOL },
73         [INSTANCE_ATTR_STDERR] = { "stderr", BLOBMSG_TYPE_BOOL },
74         [INSTANCE_ATTR_NO_NEW_PRIVS] = { "no_new_privs", BLOBMSG_TYPE_BOOL },
75         [INSTANCE_ATTR_JAIL] = { "jail", BLOBMSG_TYPE_TABLE },
76         [INSTANCE_ATTR_TRACE] = { "trace", BLOBMSG_TYPE_BOOL },
77         [INSTANCE_ATTR_SECCOMP] = { "seccomp", BLOBMSG_TYPE_STRING },
78 };
79
80 enum {
81         JAIL_ATTR_NAME,
82         JAIL_ATTR_HOSTNAME,
83         JAIL_ATTR_PROCFS,
84         JAIL_ATTR_SYSFS,
85         JAIL_ATTR_UBUS,
86         JAIL_ATTR_LOG,
87         JAIL_ATTR_RONLY,
88         JAIL_ATTR_MOUNT,
89         __JAIL_ATTR_MAX,
90 };
91
92 static const struct blobmsg_policy jail_attr[__JAIL_ATTR_MAX] = {
93         [JAIL_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING },
94         [JAIL_ATTR_HOSTNAME] = { "hostname", BLOBMSG_TYPE_STRING },
95         [JAIL_ATTR_PROCFS] = { "procfs", BLOBMSG_TYPE_BOOL },
96         [JAIL_ATTR_SYSFS] = { "sysfs", BLOBMSG_TYPE_BOOL },
97         [JAIL_ATTR_UBUS] = { "ubus", BLOBMSG_TYPE_BOOL },
98         [JAIL_ATTR_LOG] = { "log", BLOBMSG_TYPE_BOOL },
99         [JAIL_ATTR_RONLY] = { "ronly", BLOBMSG_TYPE_BOOL },
100         [JAIL_ATTR_MOUNT] = { "mount", BLOBMSG_TYPE_TABLE },
101 };
102
103 struct instance_netdev {
104         struct blobmsg_list_node node;
105         int ifindex;
106 };
107
108 struct instance_file {
109         struct blobmsg_list_node node;
110         uint32_t md5[4];
111 };
112
113 struct rlimit_name {
114         const char *name;
115         int resource;
116 };
117
118 static const struct rlimit_name rlimit_names[] = {
119         { "as", RLIMIT_AS },
120         { "core", RLIMIT_CORE },
121         { "cpu", RLIMIT_CPU },
122         { "data", RLIMIT_DATA },
123         { "fsize", RLIMIT_FSIZE },
124         { "memlock", RLIMIT_MEMLOCK },
125         { "nofile", RLIMIT_NOFILE },
126         { "nproc", RLIMIT_NPROC },
127         { "rss", RLIMIT_RSS },
128         { "stack", RLIMIT_STACK },
129 #ifdef linux
130         { "nice", RLIMIT_NICE },
131         { "rtprio", RLIMIT_RTPRIO },
132         { "msgqueue", RLIMIT_MSGQUEUE },
133         { "sigpending", RLIMIT_SIGPENDING },
134 #endif
135         { NULL, 0 }
136 };
137
138 static char trace[] = "/sbin/utrace";
139
140 static void closefd(int fd)
141 {
142         if (fd > STDERR_FILENO)
143                 close(fd);
144 }
145
146 static void
147 instance_limits(const char *limit, const char *value)
148 {
149         int i;
150         struct rlimit rlim;
151         unsigned long cur, max;
152
153         for (i = 0; rlimit_names[i].name != NULL; i++) {
154                 if (strcmp(rlimit_names[i].name, limit))
155                         continue;
156                 if (!strcmp(value, "unlimited")) {
157                         rlim.rlim_cur = RLIM_INFINITY;
158                         rlim.rlim_max = RLIM_INFINITY;
159                 } else {
160                         if (getrlimit(rlimit_names[i].resource, &rlim))
161                                 return;
162
163                         cur = rlim.rlim_cur;
164                         max = rlim.rlim_max;
165
166                         if (sscanf(value, "%lu %lu", &cur, &max) < 1)
167                                 return;
168
169                         rlim.rlim_cur = cur;
170                         rlim.rlim_max = max;
171                 }
172
173                 setrlimit(rlimit_names[i].resource, &rlim);
174                 return;
175         }
176 }
177
178 static inline int
179 jail_run(struct service_instance *in, char **argv)
180 {
181         struct blobmsg_list_node *var;
182         struct jail *jail = &in->jail;
183         int argc = 0;
184
185         argv[argc++] = "/sbin/ujail";
186
187         if (jail->name) {
188                 argv[argc++] = "-n";
189                 argv[argc++] = jail->name;
190         }
191
192         if (jail->hostname) {
193                 argv[argc++] = "-h";
194                 argv[argc++] = jail->hostname;
195         }
196
197         if (in->seccomp) {
198                 argv[argc++] = "-S";
199                 argv[argc++] = in->seccomp;
200         }
201
202         if (in->no_new_privs)
203                 argv[argc++] = "-c";
204
205         if (jail->procfs)
206                 argv[argc++] = "-p";
207
208         if (jail->sysfs)
209                 argv[argc++] = "-s";
210
211         if (jail->ubus)
212                 argv[argc++] = "-u";
213
214         if (jail->log)
215                 argv[argc++] = "-l";
216
217         if (jail->ronly)
218                 argv[argc++] = "-o";
219
220         blobmsg_list_for_each(&jail->mount, var) {
221                 const char *type = blobmsg_data(var->data);
222
223                 if (*type == '1')
224                         argv[argc++] = "-w";
225                 else
226                         argv[argc++] = "-r";
227                 argv[argc++] = (char *) blobmsg_name(var->data);
228         }
229
230         argv[argc++] = "--";
231
232         return argc;
233 }
234
235 static void
236 instance_run(struct service_instance *in, int _stdout, int _stderr)
237 {
238         struct blobmsg_list_node *var;
239         struct blob_attr *cur;
240         char **argv;
241         char *ld_preload;
242         int argc = 1; /* NULL terminated */
243         int rem, _stdin;
244         bool seccomp = !in->trace && !in->has_jail && in->seccomp;
245         bool setlbf = _stdout >= 0;
246
247         if (in->nice)
248                 setpriority(PRIO_PROCESS, 0, in->nice);
249
250         blobmsg_for_each_attr(cur, in->command, rem)
251                 argc++;
252
253         blobmsg_list_for_each(&in->env, var)
254                 setenv(blobmsg_name(var->data), blobmsg_data(var->data), 1);
255
256         if (seccomp)
257                 setenv("SECCOMP_FILE", in->seccomp, 1);
258
259         if ((seccomp || setlbf) && asprintf(&ld_preload, "LD_PRELOAD=%s%s%s",
260                         seccomp ? "/lib/libpreload-seccomp.so" : "",
261                         seccomp && setlbf ? ":" : "",
262                         setlbf ? "/lib/libsetlbf.so" : "") > 0)
263                 putenv(ld_preload);
264
265         blobmsg_list_for_each(&in->limits, var)
266                 instance_limits(blobmsg_name(var->data), blobmsg_data(var->data));
267
268         if (in->trace)
269                 argc += 1;
270
271         argv = alloca(sizeof(char *) * (argc + in->jail.argc));
272         argc = 0;
273
274         if (in->trace)
275                 argv[argc++] = trace;
276
277         if (in->has_jail)
278                 argc = jail_run(in, argv);
279
280         blobmsg_for_each_attr(cur, in->command, rem)
281                 argv[argc++] = blobmsg_data(cur);
282
283         argv[argc] = NULL;
284
285         _stdin = open("/dev/null", O_RDONLY);
286
287         if (_stdout == -1)
288                 _stdout = open("/dev/null", O_WRONLY);
289
290         if (_stderr == -1)
291                 _stderr = open("/dev/null", O_WRONLY);
292
293         if (_stdin > -1) {
294                 dup2(_stdin, STDIN_FILENO);
295                 closefd(_stdin);
296         }
297         if (_stdout > -1) {
298                 dup2(_stdout, STDOUT_FILENO);
299                 closefd(_stdout);
300         }
301         if (_stderr > -1) {
302                 dup2(_stderr, STDERR_FILENO);
303                 closefd(_stderr);
304         }
305
306         if (in->gid && setgid(in->gid)) {
307                 ERROR("failed to set group id %d: %d (%s)\n", in->gid, errno, strerror(errno));
308                 exit(127);
309         }
310         if (in->uid && setuid(in->uid)) {
311                 ERROR("failed to set user id %d: %d (%s)\n", in->uid, errno, strerror(errno));
312                 exit(127);
313         }
314
315         execvp(argv[0], argv);
316         exit(127);
317 }
318
319 static void
320 instance_free_stdio(struct service_instance *in)
321 {
322         if (in->_stdout.fd.fd > -1) {
323                 ustream_free(&in->_stdout.stream);
324                 close(in->_stdout.fd.fd);
325                 in->_stdout.fd.fd = -1;
326         }
327
328         if (in->_stderr.fd.fd > -1) {
329                 ustream_free(&in->_stderr.stream);
330                 close(in->_stderr.fd.fd);
331                 in->_stderr.fd.fd = -1;
332         }
333 }
334
335 void
336 instance_start(struct service_instance *in)
337 {
338         int pid;
339         int opipe[2] = { -1, -1 };
340         int epipe[2] = { -1, -1 };
341
342         if (!avl_is_empty(&in->errors.avl)) {
343                 LOG("Not starting instance %s::%s, an error was indicated\n", in->srv->name, in->name);
344                 return;
345         }
346
347         if (in->proc.pending)
348                 return;
349
350         instance_free_stdio(in);
351         if (in->_stdout.fd.fd > -2) {
352                 if (pipe(opipe)) {
353                         ULOG_WARN("pipe() failed: %d (%s)\n", errno, strerror(errno));
354                         opipe[0] = opipe[1] = -1;
355                 }
356         }
357
358         if (in->_stderr.fd.fd > -2) {
359                 if (pipe(epipe)) {
360                         ULOG_WARN("pipe() failed: %d (%s)\n", errno, strerror(errno));
361                         epipe[0] = epipe[1] = -1;
362                 }
363         }
364
365         in->restart = false;
366         in->halt = !in->respawn;
367
368         if (!in->valid)
369                 return;
370
371         pid = fork();
372         if (pid < 0)
373                 return;
374
375         if (!pid) {
376                 uloop_done();
377                 closefd(opipe[0]);
378                 closefd(epipe[0]);
379                 instance_run(in, opipe[1], epipe[1]);
380                 return;
381         }
382
383         DEBUG(2, "Started instance %s::%s\n", in->srv->name, in->name);
384         in->proc.pid = pid;
385         clock_gettime(CLOCK_MONOTONIC, &in->start);
386         uloop_process_add(&in->proc);
387
388         if (opipe[0] > -1) {
389                 ustream_fd_init(&in->_stdout, opipe[0]);
390                 closefd(opipe[1]);
391         }
392
393         if (epipe[0] > -1) {
394                 ustream_fd_init(&in->_stderr, epipe[0]);
395                 closefd(epipe[1]);
396         }
397
398         service_event("instance.start", in->srv->name, in->name);
399 }
400
401 static void
402 instance_stdio(struct ustream *s, int prio, struct service_instance *in)
403 {
404         char *newline, *str, *arg0, ident[32];
405         int len;
406
407         arg0 = basename(blobmsg_data(blobmsg_data(in->command)));
408         snprintf(ident, sizeof(ident), "%s[%d]", arg0, in->proc.pid);
409         ulog_open(ULOG_SYSLOG, LOG_DAEMON, ident);
410
411         do {
412                 str = ustream_get_read_buf(s, NULL);
413                 if (!str)
414                         break;
415
416                 newline = strchr(str, '\n');
417                 if (!newline)
418                         break;
419
420                 *newline = 0;
421                 ulog(prio, "%s\n", str);
422
423                 len = newline + 1 - str;
424                 ustream_consume(s, len);
425         } while (1);
426
427         ulog_open(ULOG_SYSLOG, LOG_DAEMON, "procd");
428 }
429
430 static void
431 instance_stdout(struct ustream *s, int bytes)
432 {
433         instance_stdio(s, LOG_INFO,
434                        container_of(s, struct service_instance, _stdout.stream));
435 }
436
437 static void
438 instance_stderr(struct ustream *s, int bytes)
439 {
440         instance_stdio(s, LOG_ERR,
441                        container_of(s, struct service_instance, _stderr.stream));
442 }
443
444 static void
445 instance_timeout(struct uloop_timeout *t)
446 {
447         struct service_instance *in;
448
449         in = container_of(t, struct service_instance, timeout);
450
451         if (!in->halt && (in->restart || in->respawn))
452                 instance_start(in);
453 }
454
455 static void
456 instance_exit(struct uloop_process *p, int ret)
457 {
458         struct service_instance *in;
459         struct timespec tp;
460         long runtime;
461
462         in = container_of(p, struct service_instance, proc);
463
464         clock_gettime(CLOCK_MONOTONIC, &tp);
465         runtime = tp.tv_sec - in->start.tv_sec;
466
467         DEBUG(2, "Instance %s::%s exit with error code %d after %ld seconds\n", in->srv->name, in->name, ret, runtime);
468         if (upgrade_running)
469                 return;
470
471         uloop_timeout_cancel(&in->timeout);
472         if (in->halt) {
473                 /* no action */
474         } else if (in->restart) {
475                 instance_start(in);
476         } else if (in->respawn) {
477                 if (runtime < in->respawn_threshold)
478                         in->respawn_count++;
479                 else
480                         in->respawn_count = 0;
481                 if (in->respawn_count > in->respawn_retry && in->respawn_retry > 0 ) {
482                         LOG("Instance %s::%s s in a crash loop %d crashes, %ld seconds since last crash\n",
483                                                                 in->srv->name, in->name, in->respawn_count, runtime);
484                         in->restart = in->respawn = 0;
485                         in->halt = 1;
486                 } else {
487                         uloop_timeout_set(&in->timeout, in->respawn_timeout * 1000);
488                 }
489         }
490         service_event("instance.stop", in->srv->name, in->name);
491 }
492
493 void
494 instance_stop(struct service_instance *in)
495 {
496         if (!in->proc.pending)
497                 return;
498         in->halt = true;
499         in->restart = in->respawn = false;
500         kill(in->proc.pid, SIGTERM);
501 }
502
503 static void
504 instance_restart(struct service_instance *in)
505 {
506         if (!in->proc.pending)
507                 return;
508         in->halt = false;
509         in->restart = true;
510         kill(in->proc.pid, SIGTERM);
511 }
512
513 static bool
514 instance_config_changed(struct service_instance *in, struct service_instance *in_new)
515 {
516         if (!in->valid)
517                 return true;
518
519         if (!blob_attr_equal(in->command, in_new->command))
520                 return true;
521
522         if (!blobmsg_list_equal(&in->env, &in_new->env))
523                 return true;
524
525         if (!blobmsg_list_equal(&in->data, &in_new->data))
526                 return true;
527
528         if (!blobmsg_list_equal(&in->netdev, &in_new->netdev))
529                 return true;
530
531         if (!blobmsg_list_equal(&in->file, &in_new->file))
532                 return true;
533
534         if (in->nice != in_new->nice)
535                 return true;
536
537         if (in->uid != in_new->uid)
538                 return true;
539
540         if (in->gid != in_new->gid)
541                 return true;
542
543         if (!blobmsg_list_equal(&in->limits, &in_new->limits))
544                 return true;
545
546         if (!blobmsg_list_equal(&in->jail.mount, &in_new->jail.mount))
547                 return true;
548
549         if (!blobmsg_list_equal(&in->errors, &in_new->errors))
550                 return true;
551
552         return false;
553 }
554
555 static bool
556 instance_netdev_cmp(struct blobmsg_list_node *l1, struct blobmsg_list_node *l2)
557 {
558         struct instance_netdev *n1 = container_of(l1, struct instance_netdev, node);
559         struct instance_netdev *n2 = container_of(l2, struct instance_netdev, node);
560
561         return n1->ifindex == n2->ifindex;
562 }
563
564 static void
565 instance_netdev_update(struct blobmsg_list_node *l)
566 {
567         struct instance_netdev *n = container_of(l, struct instance_netdev, node);
568
569         n->ifindex = if_nametoindex(n->node.avl.key);
570 }
571
572 static bool
573 instance_file_cmp(struct blobmsg_list_node *l1, struct blobmsg_list_node *l2)
574 {
575         struct instance_file *f1 = container_of(l1, struct instance_file, node);
576         struct instance_file *f2 = container_of(l2, struct instance_file, node);
577
578         return !memcmp(f1->md5, f2->md5, sizeof(f1->md5));
579 }
580
581 static void
582 instance_file_update(struct blobmsg_list_node *l)
583 {
584         struct instance_file *f = container_of(l, struct instance_file, node);
585         md5_ctx_t md5;
586         char buf[256];
587         int len, fd;
588
589         memset(f->md5, 0, sizeof(f->md5));
590
591         fd = open(l->avl.key, O_RDONLY);
592         if (fd < 0)
593                 return;
594
595         md5_begin(&md5);
596         do {
597                 len = read(fd, buf, sizeof(buf));
598                 if (len < 0) {
599                         if (errno == EINTR)
600                                 continue;
601
602                         break;
603                 }
604                 if (!len)
605                         break;
606
607                 md5_hash(buf, len, &md5);
608         } while(1);
609
610         md5_end(f->md5, &md5);
611         close(fd);
612 }
613
614 static void
615 instance_fill_any(struct blobmsg_list *l, struct blob_attr *cur)
616 {
617         if (!cur)
618                 return;
619
620         blobmsg_list_fill(l, blobmsg_data(cur), blobmsg_data_len(cur), false);
621 }
622
623 static bool
624 instance_fill_array(struct blobmsg_list *l, struct blob_attr *cur, blobmsg_update_cb cb, bool array)
625 {
626         struct blobmsg_list_node *node;
627
628         if (!cur)
629                 return true;
630
631         if (!blobmsg_check_attr_list(cur, BLOBMSG_TYPE_STRING))
632                 return false;
633
634         blobmsg_list_fill(l, blobmsg_data(cur), blobmsg_data_len(cur), array);
635         if (cb) {
636                 blobmsg_list_for_each(l, node)
637                         cb(node);
638         }
639         return true;
640 }
641
642 static int
643 instance_jail_parse(struct service_instance *in, struct blob_attr *attr)
644 {
645         struct blob_attr *tb[__JAIL_ATTR_MAX];
646         struct jail *jail = &in->jail;
647         struct stat s;
648
649         if (stat("/sbin/ujail", &s))
650                 return 0;
651
652         blobmsg_parse(jail_attr, __JAIL_ATTR_MAX, tb,
653                 blobmsg_data(attr), blobmsg_data_len(attr));
654
655         jail->argc = 2;
656
657         if (tb[JAIL_ATTR_NAME]) {
658                 jail->name = blobmsg_get_string(tb[JAIL_ATTR_NAME]);
659                 jail->argc += 2;
660         }
661         if (tb[JAIL_ATTR_HOSTNAME]) {
662                 jail->hostname = blobmsg_get_string(tb[JAIL_ATTR_HOSTNAME]);
663                 jail->argc += 2;
664         }
665         if (tb[JAIL_ATTR_PROCFS]) {
666                 jail->procfs = blobmsg_get_bool(tb[JAIL_ATTR_PROCFS]);
667                 jail->argc++;
668         }
669         if (tb[JAIL_ATTR_SYSFS]) {
670                 jail->sysfs = blobmsg_get_bool(tb[JAIL_ATTR_SYSFS]);
671                 jail->argc++;
672         }
673         if (tb[JAIL_ATTR_UBUS]) {
674                 jail->ubus = blobmsg_get_bool(tb[JAIL_ATTR_UBUS]);
675                 jail->argc++;
676         }
677         if (tb[JAIL_ATTR_LOG]) {
678                 jail->log = blobmsg_get_bool(tb[JAIL_ATTR_LOG]);
679                 jail->argc++;
680         }
681         if (tb[JAIL_ATTR_RONLY]) {
682                 jail->ronly = blobmsg_get_bool(tb[JAIL_ATTR_RONLY]);
683                 jail->argc++;
684         }
685         if (tb[JAIL_ATTR_MOUNT]) {
686                 struct blob_attr *cur;
687                 int rem;
688
689                 blobmsg_for_each_attr(cur, tb[JAIL_ATTR_MOUNT], rem)
690                         jail->argc += 2;
691                 instance_fill_array(&jail->mount, tb[JAIL_ATTR_MOUNT], NULL, false);
692         }
693         if (in->seccomp)
694                 jail->argc += 2;
695
696         return 1;
697 }
698
699 static bool
700 instance_config_parse(struct service_instance *in)
701 {
702         struct blob_attr *tb[__INSTANCE_ATTR_MAX];
703         struct blob_attr *cur, *cur2;
704         int argc = 0;
705         int rem;
706
707         blobmsg_parse(instance_attr, __INSTANCE_ATTR_MAX, tb,
708                 blobmsg_data(in->config), blobmsg_data_len(in->config));
709
710         cur = tb[INSTANCE_ATTR_COMMAND];
711         if (!cur)
712                 return false;
713
714         if (!blobmsg_check_attr_list(cur, BLOBMSG_TYPE_STRING))
715                 return false;
716
717         blobmsg_for_each_attr(cur2, cur, rem) {
718                 argc++;
719                 break;
720         }
721         if (!argc)
722                 return false;
723
724         in->command = cur;
725
726         if (tb[INSTANCE_ATTR_RESPAWN]) {
727                 int i = 0;
728                 uint32_t vals[3] = { 3600, 5, 5};
729
730                 blobmsg_for_each_attr(cur2, tb[INSTANCE_ATTR_RESPAWN], rem) {
731                         if ((i >= 3) && (blobmsg_type(cur2) == BLOBMSG_TYPE_STRING))
732                                 continue;
733                         vals[i] = atoi(blobmsg_get_string(cur2));
734                         i++;
735                 }
736                 in->respawn = true;
737                 in->respawn_count = 0;
738                 in->respawn_threshold = vals[0];
739                 in->respawn_timeout = vals[1];
740                 in->respawn_retry = vals[2];
741         }
742         if (tb[INSTANCE_ATTR_TRIGGER]) {
743                 in->trigger = tb[INSTANCE_ATTR_TRIGGER];
744                 trigger_add(in->trigger, in);
745         }
746
747         if (tb[INSTANCE_ATTR_WATCH]) {
748                 blobmsg_for_each_attr(cur2, tb[INSTANCE_ATTR_WATCH], rem) {
749                         if (blobmsg_type(cur2) != BLOBMSG_TYPE_STRING)
750                                 continue;
751                         DEBUG(3, "watch for %s\n", blobmsg_get_string(cur2));
752                         watch_add(blobmsg_get_string(cur2), in);
753                 }
754         }
755
756         if ((cur = tb[INSTANCE_ATTR_NICE])) {
757                 in->nice = (int8_t) blobmsg_get_u32(cur);
758                 if (in->nice < -20 || in->nice > 20)
759                         return false;
760         }
761
762         if (tb[INSTANCE_ATTR_USER]) {
763                 struct passwd *p = getpwnam(blobmsg_get_string(tb[INSTANCE_ATTR_USER]));
764                 if (p) {
765                         in->uid = p->pw_uid;
766                         in->gid = p->pw_gid;
767                 }
768         }
769
770         if (tb[INSTANCE_ATTR_TRACE])
771                 in->trace = blobmsg_get_bool(tb[INSTANCE_ATTR_TRACE]);
772
773         if (tb[INSTANCE_ATTR_NO_NEW_PRIVS])
774                 in->no_new_privs = blobmsg_get_bool(tb[INSTANCE_ATTR_NO_NEW_PRIVS]);
775
776         if (!in->trace && tb[INSTANCE_ATTR_SECCOMP]) {
777                 char *seccomp = blobmsg_get_string(tb[INSTANCE_ATTR_SECCOMP]);
778                 struct stat s;
779
780                 if (stat(seccomp, &s))
781                         ERROR("%s: not starting seccomp as %s is missing\n", in->name, seccomp);
782                 else
783                         in->seccomp = seccomp;
784         }
785         if (!in->trace && tb[INSTANCE_ATTR_JAIL])
786                 in->has_jail = instance_jail_parse(in, tb[INSTANCE_ATTR_JAIL]);
787
788         if (tb[INSTANCE_ATTR_STDOUT] && blobmsg_get_bool(tb[INSTANCE_ATTR_STDOUT]))
789                 in->_stdout.fd.fd = -1;
790
791         if (tb[INSTANCE_ATTR_STDERR] && blobmsg_get_bool(tb[INSTANCE_ATTR_STDERR]))
792                 in->_stderr.fd.fd = -1;
793
794         instance_fill_any(&in->data, tb[INSTANCE_ATTR_DATA]);
795
796         if (!instance_fill_array(&in->env, tb[INSTANCE_ATTR_ENV], NULL, false))
797                 return false;
798
799         if (!instance_fill_array(&in->netdev, tb[INSTANCE_ATTR_NETDEV], instance_netdev_update, true))
800                 return false;
801
802         if (!instance_fill_array(&in->file, tb[INSTANCE_ATTR_FILE], instance_file_update, true))
803                 return false;
804
805         if (!instance_fill_array(&in->limits, tb[INSTANCE_ATTR_LIMITS], NULL, false))
806                 return false;
807
808         if (!instance_fill_array(&in->errors, tb[INSTANCE_ATTR_ERROR], NULL, true))
809                 return false;
810
811         return true;
812 }
813
814 static void
815 instance_config_cleanup(struct service_instance *in)
816 {
817         blobmsg_list_free(&in->env);
818         blobmsg_list_free(&in->data);
819         blobmsg_list_free(&in->netdev);
820         blobmsg_list_free(&in->file);
821         blobmsg_list_free(&in->limits);
822         blobmsg_list_free(&in->errors);
823         blobmsg_list_free(&in->jail.mount);
824 }
825
826 static void
827 instance_config_move(struct service_instance *in, struct service_instance *in_src)
828 {
829         instance_config_cleanup(in);
830         blobmsg_list_move(&in->env, &in_src->env);
831         blobmsg_list_move(&in->data, &in_src->data);
832         blobmsg_list_move(&in->netdev, &in_src->netdev);
833         blobmsg_list_move(&in->file, &in_src->file);
834         blobmsg_list_move(&in->limits, &in_src->limits);
835         blobmsg_list_move(&in->errors, &in_src->errors);
836         blobmsg_list_move(&in->jail.mount, &in_src->jail.mount);
837         in->trigger = in_src->trigger;
838         in->command = in_src->command;
839         in->name = in_src->name;
840         in->node.avl.key = in_src->node.avl.key;
841
842         free(in->config);
843         in->config = in_src->config;
844         in_src->config = NULL;
845 }
846
847 bool
848 instance_update(struct service_instance *in, struct service_instance *in_new)
849 {
850         bool changed = instance_config_changed(in, in_new);
851         bool running = in->proc.pending;
852
853         if (!changed && running)
854                 return false;
855
856         if (!running) {
857                 if (changed)
858                         instance_config_move(in, in_new);
859                 instance_start(in);
860         } else {
861                 instance_restart(in);
862                 instance_config_move(in, in_new);
863                 /* restart happens in the child callback handler */
864         }
865         return true;
866 }
867
868 void
869 instance_free(struct service_instance *in)
870 {
871         instance_free_stdio(in);
872         uloop_process_delete(&in->proc);
873         uloop_timeout_cancel(&in->timeout);
874         trigger_del(in);
875         watch_del(in);
876         instance_config_cleanup(in);
877         free(in->config);
878         free(in);
879 }
880
881 void
882 instance_init(struct service_instance *in, struct service *s, struct blob_attr *config)
883 {
884         config = blob_memdup(config);
885         in->srv = s;
886         in->name = blobmsg_name(config);
887         in->config = config;
888         in->timeout.cb = instance_timeout;
889         in->proc.cb = instance_exit;
890
891         in->_stdout.fd.fd = -2;
892         in->_stdout.stream.string_data = true;
893         in->_stdout.stream.notify_read = instance_stdout;
894
895         in->_stderr.fd.fd = -2;
896         in->_stderr.stream.string_data = true;
897         in->_stderr.stream.notify_read = instance_stderr;
898
899         blobmsg_list_init(&in->netdev, struct instance_netdev, node, instance_netdev_cmp);
900         blobmsg_list_init(&in->file, struct instance_file, node, instance_file_cmp);
901         blobmsg_list_simple_init(&in->env);
902         blobmsg_list_simple_init(&in->data);
903         blobmsg_list_simple_init(&in->limits);
904         blobmsg_list_simple_init(&in->errors);
905         blobmsg_list_simple_init(&in->jail.mount);
906         in->valid = instance_config_parse(in);
907 }
908
909 void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose)
910 {
911         void *i;
912
913         if (!in->valid)
914                 return;
915
916         i = blobmsg_open_table(b, in->name);
917         blobmsg_add_u8(b, "running", in->proc.pending);
918         if (in->proc.pending)
919                 blobmsg_add_u32(b, "pid", in->proc.pid);
920         blobmsg_add_blob(b, in->command);
921
922         if (!avl_is_empty(&in->errors.avl)) {
923                 struct blobmsg_list_node *var;
924                 void *e = blobmsg_open_array(b, "errors");
925                 blobmsg_list_for_each(&in->errors, var)
926                         blobmsg_add_string(b, NULL, blobmsg_data(var->data));
927                 blobmsg_close_table(b, e);
928         }
929
930         if (!avl_is_empty(&in->env.avl)) {
931                 struct blobmsg_list_node *var;
932                 void *e = blobmsg_open_table(b, "env");
933                 blobmsg_list_for_each(&in->env, var)
934                         blobmsg_add_string(b, blobmsg_name(var->data), blobmsg_data(var->data));
935                 blobmsg_close_table(b, e);
936         }
937
938         if (!avl_is_empty(&in->data.avl)) {
939                 struct blobmsg_list_node *var;
940                 void *e = blobmsg_open_table(b, "data");
941                 blobmsg_list_for_each(&in->data, var)
942                         blobmsg_add_blob(b, var->data);
943                 blobmsg_close_table(b, e);
944         }
945
946         if (!avl_is_empty(&in->limits.avl)) {
947                 struct blobmsg_list_node *var;
948                 void *e = blobmsg_open_table(b, "limits");
949                 blobmsg_list_for_each(&in->limits, var)
950                         blobmsg_add_string(b, blobmsg_name(var->data), blobmsg_data(var->data));
951                 blobmsg_close_table(b, e);
952         }
953
954         if (in->respawn) {
955                 void *r = blobmsg_open_table(b, "respawn");
956                 blobmsg_add_u32(b, "threshold", in->respawn_threshold);
957                 blobmsg_add_u32(b, "timeout", in->respawn_timeout);
958                 blobmsg_add_u32(b, "retry", in->respawn_retry);
959                 blobmsg_close_table(b, r);
960         }
961
962         if (in->trace)
963                 blobmsg_add_u8(b, "trace", true);
964
965         if (in->no_new_privs)
966                 blobmsg_add_u8(b, "no_new_privs", true);
967
968         if (in->seccomp)
969                 blobmsg_add_string(b, "seccomp", in->seccomp);
970
971         if (in->has_jail) {
972                 void *r = blobmsg_open_table(b, "jail");
973                 if (in->jail.name)
974                         blobmsg_add_string(b, "name", in->jail.name);
975                 if (in->jail.hostname)
976                         blobmsg_add_string(b, "hostname", in->jail.hostname);
977                 blobmsg_add_u8(b, "procfs", in->jail.procfs);
978                 blobmsg_add_u8(b, "sysfs", in->jail.sysfs);
979                 blobmsg_add_u8(b, "ubus", in->jail.ubus);
980                 blobmsg_add_u8(b, "log", in->jail.log);
981                 blobmsg_add_u8(b, "ronly", in->jail.ronly);
982                 blobmsg_close_table(b, r);
983                 if (!avl_is_empty(&in->jail.mount.avl)) {
984                         struct blobmsg_list_node *var;
985                         void *e = blobmsg_open_table(b, "mount");
986                         blobmsg_list_for_each(&in->jail.mount, var)
987                                 blobmsg_add_string(b, blobmsg_name(var->data), blobmsg_data(var->data));
988                         blobmsg_close_table(b, e);
989                 }
990         }
991
992         if (verbose && in->trigger)
993                 blobmsg_add_blob(b, in->trigger);
994
995         blobmsg_close_table(b, i);
996 }