X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=service%2Finstance.c;h=ed5d0a490532e915fdc83976f190fd6078432320;hb=7e6c6efd6fbcc7955801c5e2ac915a90697e1fd9;hp=142208a41e84d5f467829575ce824f592bbdb62b;hpb=1ab539b3a8a0070b493112c8263ab380a689db66;p=project%2Fprocd.git diff --git a/service/instance.c b/service/instance.c index 142208a..ed5d0a4 100644 --- a/service/instance.c +++ b/service/instance.c @@ -37,6 +37,7 @@ #include "instance.h" #define UJAIL_BIN_PATH "/sbin/ujail" +#define CGROUP_BASEDIR "/sys/fs/cgroup/services" enum { INSTANCE_ATTR_COMMAND, @@ -58,6 +59,7 @@ enum { INSTANCE_ATTR_JAIL, INSTANCE_ATTR_TRACE, INSTANCE_ATTR_SECCOMP, + INSTANCE_ATTR_CAPABILITIES, INSTANCE_ATTR_PIDFILE, INSTANCE_ATTR_RELOADSIG, INSTANCE_ATTR_TERMTIMEOUT, @@ -65,6 +67,8 @@ enum { INSTANCE_ATTR_EXTROOT, INSTANCE_ATTR_OVERLAYDIR, INSTANCE_ATTR_TMPOVERLAYSIZE, + INSTANCE_ATTR_BUNDLE, + INSTANCE_ATTR_WATCHDOG, __INSTANCE_ATTR_MAX }; @@ -88,6 +92,7 @@ static const struct blobmsg_policy instance_attr[__INSTANCE_ATTR_MAX] = { [INSTANCE_ATTR_JAIL] = { "jail", BLOBMSG_TYPE_TABLE }, [INSTANCE_ATTR_TRACE] = { "trace", BLOBMSG_TYPE_BOOL }, [INSTANCE_ATTR_SECCOMP] = { "seccomp", BLOBMSG_TYPE_STRING }, + [INSTANCE_ATTR_CAPABILITIES] = { "capabilities", BLOBMSG_TYPE_STRING }, [INSTANCE_ATTR_PIDFILE] = { "pidfile", BLOBMSG_TYPE_STRING }, [INSTANCE_ATTR_RELOADSIG] = { "reload_signal", BLOBMSG_TYPE_INT32 }, [INSTANCE_ATTR_TERMTIMEOUT] = { "term_timeout", BLOBMSG_TYPE_INT32 }, @@ -95,6 +100,8 @@ static const struct blobmsg_policy instance_attr[__INSTANCE_ATTR_MAX] = { [INSTANCE_ATTR_EXTROOT] = { "extroot", BLOBMSG_TYPE_STRING }, [INSTANCE_ATTR_OVERLAYDIR] = { "overlaydir", BLOBMSG_TYPE_STRING }, [INSTANCE_ATTR_TMPOVERLAYSIZE] = { "tmpoverlaysize", BLOBMSG_TYPE_STRING }, + [INSTANCE_ATTR_BUNDLE] = { "bundle", BLOBMSG_TYPE_STRING }, + [INSTANCE_ATTR_WATCHDOG] = { "watchdog", BLOBMSG_TYPE_ARRAY }, }; enum { @@ -111,6 +118,9 @@ enum { JAIL_ATTR_CGROUPSNS, JAIL_ATTR_CONSOLE, JAIL_ATTR_REQUIREJAIL, + JAIL_ATTR_IMMEDIATELY, + JAIL_ATTR_PIDFILE, + JAIL_ATTR_SETNS, __JAIL_ATTR_MAX, }; @@ -128,6 +138,20 @@ static const struct blobmsg_policy jail_attr[__JAIL_ATTR_MAX] = { [JAIL_ATTR_CGROUPSNS] = { "cgroupsns", BLOBMSG_TYPE_BOOL }, [JAIL_ATTR_CONSOLE] = { "console", BLOBMSG_TYPE_BOOL }, [JAIL_ATTR_REQUIREJAIL] = { "requirejail", BLOBMSG_TYPE_BOOL }, + [JAIL_ATTR_IMMEDIATELY] = { "immediately", BLOBMSG_TYPE_BOOL }, + [JAIL_ATTR_PIDFILE] = { "pidfile", BLOBMSG_TYPE_STRING }, + [JAIL_ATTR_SETNS] = { "setns", BLOBMSG_TYPE_ARRAY }, +}; + +enum { + JAIL_SETNS_ATTR_PID, + JAIL_SETNS_ATTR_NS, + __JAIL_SETNS_ATTR_MAX, +}; + +static const struct blobmsg_policy jail_setns_attr[__JAIL_SETNS_ATTR_MAX] = { + [JAIL_SETNS_ATTR_PID] = { "pid", BLOBMSG_TYPE_INT32 }, + [JAIL_SETNS_ATTR_NS] = { "namespaces", BLOBMSG_TYPE_ARRAY }, }; struct instance_netdev { @@ -215,15 +239,68 @@ instance_limits(const char *limit, const char *value) } } +static char * +instance_gen_setns_argstr(struct blob_attr *attr) +{ + struct blob_attr *tb[__JAIL_SETNS_ATTR_MAX]; + struct blob_attr *cur; + int rem, len, total; + char *ret; + + blobmsg_parse(jail_setns_attr, __JAIL_SETNS_ATTR_MAX, tb, + blobmsg_data(attr), blobmsg_data_len(attr)); + + if (!tb[JAIL_SETNS_ATTR_PID] || !tb[JAIL_SETNS_ATTR_NS]) + return NULL; + + len = snprintf(NULL, 0, "%d:", blobmsg_get_u32(tb[JAIL_SETNS_ATTR_PID])); + + blobmsg_for_each_attr(cur, tb[JAIL_SETNS_ATTR_NS], rem) { + char *tmp; + + if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) + return NULL; + + tmp = blobmsg_get_string(cur); + if (!tmp) + return NULL; + + len += strlen(tmp) + 1; + } + + total = len; + ret = malloc(total); + if (!ret) + return NULL; + + len = snprintf(ret, total, "%d:", blobmsg_get_u32(tb[JAIL_SETNS_ATTR_PID])); + + blobmsg_for_each_attr(cur, tb[JAIL_SETNS_ATTR_NS], rem) { + strncpy(&ret[len], blobmsg_get_string(cur), total - len); + len += strlen(blobmsg_get_string(cur)); + ret[len++] = ','; + } + ret[total - 1] = '\0'; + + return ret; +} + static inline int jail_run(struct service_instance *in, char **argv) { + char *term_timeout_str; struct blobmsg_list_node *var; struct jail *jail = &in->jail; int argc = 0; argv[argc++] = UJAIL_BIN_PATH; + if (asprintf(&term_timeout_str, "%d", in->term_timeout) == -1) + exit(ENOMEM); + + argv[argc++] = "-t"; + argv[argc++] = term_timeout_str; + if (jail->name) { argv[argc++] = "-n"; argv[argc++] = jail->name; @@ -249,6 +326,11 @@ jail_run(struct service_instance *in, char **argv) argv[argc++] = in->group; } + if (in->capabilities) { + argv[argc++] = "-C"; + argv[argc++] = in->capabilities; + } + if (in->no_new_privs) argv[argc++] = "-c"; @@ -294,9 +376,27 @@ jail_run(struct service_instance *in, char **argv) argv[argc++] = in->tmpoverlaysize; } + if (in->immediately) + argv[argc++] = "-i"; + + if (jail->pidfile) { + argv[argc++] = "-P"; + argv[argc++] = jail->pidfile; + } + + if (in->bundle) { + argv[argc++] = "-J"; + argv[argc++] = in->bundle; + } + if (in->require_jail) argv[argc++] = "-E"; + blobmsg_list_for_each(&in->env, var) { + argv[argc++] = "-e"; + argv[argc++] = (char *) blobmsg_name(var->data); + } + blobmsg_list_for_each(&jail->mount, var) { const char *type = blobmsg_data(var->data); @@ -307,6 +407,15 @@ jail_run(struct service_instance *in, char **argv) argv[argc++] = (char *) blobmsg_name(var->data); } + blobmsg_list_for_each(&jail->setns, var) { + char *setns_arg = instance_gen_setns_argstr(var->data); + + if (setns_arg) { + argv[argc++] = "-j"; + argv[argc++] = setns_arg; + } + } + argv[argc++] = "--"; return argc; @@ -444,6 +553,32 @@ instance_run(struct service_instance *in, int _stdout, int _stderr) exit(127); } +static void +instance_add_cgroup(const char *service, const char *instance) +{ + struct stat sb; + char cgnamebuf[256]; + int fd; + + if (stat("/sys/fs/cgroup/cgroup.subtree_control", &sb)) + return; + + mkdir(CGROUP_BASEDIR, 0700); + + snprintf(cgnamebuf, sizeof(cgnamebuf), "%s/%s", CGROUP_BASEDIR, service); + mkdir(cgnamebuf, 0700); + snprintf(cgnamebuf, sizeof(cgnamebuf), "%s/%s/%s", CGROUP_BASEDIR, service, instance); + mkdir(cgnamebuf, 0700); + strcat(cgnamebuf, "/cgroup.procs"); + + fd = open(cgnamebuf, O_WRONLY); + if (fd == -1) + return; + + dprintf(fd, "%d", getpid()); + close(fd); +} + static void instance_free_stdio(struct service_instance *in) { @@ -484,7 +619,7 @@ instance_start(struct service_instance *in) return; } - if (!in->command) { + if (!in->bundle && !in->command) { LOG("Not starting instance %s::%s, command not set\n", in->srv->name, in->name); return; } @@ -524,11 +659,12 @@ instance_start(struct service_instance *in) uloop_done(); closefd(opipe[0]); closefd(epipe[0]); + instance_add_cgroup(in->srv->name, in->name); instance_run(in, opipe[1], epipe[1]); return; } - DEBUG(2, "Started instance %s::%s[%d]\n", in->srv->name, in->name, pid); + P_DEBUG(2, "Started instance %s::%s[%d]\n", in->srv->name, in->name, pid); in->proc.pid = pid; instance_writepid(in); clock_gettime(CLOCK_MONOTONIC, &in->start); @@ -546,6 +682,11 @@ instance_start(struct service_instance *in) fcntl(epipe[0], F_SETFD, FD_CLOEXEC); } + if (in->watchdog.mode != INSTANCE_WATCHDOG_MODE_DISABLED) { + uloop_timeout_set(&in->watchdog.timeout, in->watchdog.freq * 1000); + P_DEBUG(2, "Started instance %s::%s watchdog timer : timeout = %d\n", in->srv->name, in->name, in->watchdog.freq); + } + service_event("instance.start", in->srv->name, in->name); } @@ -689,10 +830,11 @@ instance_exit(struct uloop_process *p, int ret) clock_gettime(CLOCK_MONOTONIC, &tp); runtime = tp.tv_sec - in->start.tv_sec; - DEBUG(2, "Instance %s::%s exit with error code %d after %ld seconds\n", in->srv->name, in->name, ret, runtime); + P_DEBUG(2, "Instance %s::%s exit with error code %d after %ld seconds\n", in->srv->name, in->name, ret, runtime); in->exit_code = instance_exit_code(ret); uloop_timeout_cancel(&in->timeout); + uloop_timeout_cancel(&in->watchdog.timeout); service_event("instance.stop", in->srv->name, in->name); if (in->halt) { @@ -732,7 +874,8 @@ instance_stop(struct service_instance *in, bool halt) in->halt = halt; in->restart = in->respawn = false; kill(in->proc.pid, SIGTERM); - uloop_timeout_set(&in->timeout, in->term_timeout * 1000); + if (!in->has_jail) + uloop_timeout_set(&in->timeout, in->term_timeout * 1000); } static void @@ -749,7 +892,21 @@ instance_restart(struct service_instance *in) in->halt = true; in->restart = true; kill(in->proc.pid, SIGTERM); - uloop_timeout_set(&in->timeout, in->term_timeout * 1000); + if (!in->has_jail) + uloop_timeout_set(&in->timeout, in->term_timeout * 1000); +} + +static void +instance_watchdog(struct uloop_timeout *t) +{ + struct service_instance *in = container_of(t, struct service_instance, watchdog.timeout); + + P_DEBUG(3, "instance %s::%s watchdog timer expired\n", in->srv->name, in->name); + + if (in->respawn) + instance_restart(in); + else + instance_stop(in, true); } static bool string_changed(const char *a, const char *b) @@ -766,6 +923,18 @@ instance_config_changed(struct service_instance *in, struct service_instance *in if (!blob_attr_equal(in->command, in_new->command)) return true; + if (string_changed(in->bundle, in_new->bundle)) + return true; + + if (string_changed(in->extroot, in_new->extroot)) + return true; + + if (string_changed(in->overlaydir, in_new->overlaydir)) + return true; + + if (string_changed(in->tmpoverlaysize, in_new->tmpoverlaysize)) + return true; + if (!blobmsg_list_equal(&in->env, &in_new->env)) return true; @@ -793,6 +962,9 @@ instance_config_changed(struct service_instance *in, struct service_instance *in if (in->pw_gid != in_new->pw_gid) return true; + if (in->gr_gid != in_new->gr_gid) + return true; + if (string_changed(in->pidfile, in_new->pidfile)) return true; @@ -803,9 +975,16 @@ instance_config_changed(struct service_instance *in, struct service_instance *in if (in->respawn_timeout != in_new->respawn_timeout) return true; - if ((!in->seccomp && in_new->seccomp) || - (in->seccomp && !in_new->seccomp) || - (in->seccomp && in_new->seccomp && strcmp(in->seccomp, in_new->seccomp))) + if (in->reload_signal != in_new->reload_signal) + return true; + + if (in->term_timeout != in_new->term_timeout) + return true; + + if (string_changed(in->seccomp, in_new->seccomp)) + return true; + + if (string_changed(in->capabilities, in_new->capabilities)) return true; if (!blobmsg_list_equal(&in->limits, &in_new->limits)) @@ -814,9 +993,69 @@ instance_config_changed(struct service_instance *in, struct service_instance *in if (!blobmsg_list_equal(&in->jail.mount, &in_new->jail.mount)) return true; + if (!blobmsg_list_equal(&in->jail.setns, &in_new->jail.setns)) + return true; + if (!blobmsg_list_equal(&in->errors, &in_new->errors)) return true; + if (in->has_jail != in_new->has_jail) + return true; + + if (in->trace != in_new->trace) + return true; + + if (in->require_jail != in_new->require_jail) + return true; + + if (in->immediately != in_new->immediately) + return true; + + if (in->no_new_privs != in_new->no_new_privs) + return true; + + if (string_changed(in->jail.name, in_new->jail.name)) + return true; + + if (string_changed(in->jail.hostname, in_new->jail.hostname)) + return true; + + if (string_changed(in->jail.pidfile, in_new->jail.pidfile)) + return true; + + if (in->jail.procfs != in_new->jail.procfs) + return true; + + if (in->jail.sysfs != in_new->jail.sysfs) + return true; + + if (in->jail.ubus != in_new->jail.ubus) + return true; + + if (in->jail.log != in_new->jail.log) + return true; + + if (in->jail.ronly != in_new->jail.ronly) + return true; + + if (in->jail.netns != in_new->jail.netns) + return true; + + if (in->jail.userns != in_new->jail.userns) + return true; + + if (in->jail.cgroupsns != in_new->jail.cgroupsns) + return true; + + if (in->jail.console != in_new->jail.console) + return true; + + if (in->watchdog.mode != in_new->watchdog.mode) + return true; + + if (in->watchdog.freq != in_new->watchdog.freq) + return true; + return false; } @@ -912,16 +1151,21 @@ instance_jail_parse(struct service_instance *in, struct blob_attr *attr) { struct blob_attr *tb[__JAIL_ATTR_MAX]; struct jail *jail = &in->jail; + struct blobmsg_list_node *var; blobmsg_parse(jail_attr, __JAIL_ATTR_MAX, tb, blobmsg_data(attr), blobmsg_data_len(attr)); - jail->argc = 2; + jail->argc = 4; - if (tb[JAIL_ATTR_REQUIREJAIL]) { + if (tb[JAIL_ATTR_REQUIREJAIL] && blobmsg_get_bool(tb[JAIL_ATTR_REQUIREJAIL])) { in->require_jail = true; jail->argc++; } + if (tb[JAIL_ATTR_IMMEDIATELY] && blobmsg_get_bool(tb[JAIL_ATTR_IMMEDIATELY])) { + in->immediately = true; + jail->argc++; + } if (tb[JAIL_ATTR_NAME]) { jail->name = strdup(blobmsg_get_string(tb[JAIL_ATTR_NAME])); jail->argc += 2; @@ -930,42 +1174,56 @@ instance_jail_parse(struct service_instance *in, struct blob_attr *attr) jail->hostname = strdup(blobmsg_get_string(tb[JAIL_ATTR_HOSTNAME])); jail->argc += 2; } - if (tb[JAIL_ATTR_PROCFS]) { - jail->procfs = blobmsg_get_bool(tb[JAIL_ATTR_PROCFS]); + if (tb[JAIL_ATTR_PROCFS] && blobmsg_get_bool(tb[JAIL_ATTR_PROCFS])) { + jail->procfs = true; jail->argc++; } - if (tb[JAIL_ATTR_SYSFS]) { - jail->sysfs = blobmsg_get_bool(tb[JAIL_ATTR_SYSFS]); + if (tb[JAIL_ATTR_SYSFS] && blobmsg_get_bool(tb[JAIL_ATTR_SYSFS])) { + jail->sysfs = true; jail->argc++; } - if (tb[JAIL_ATTR_UBUS]) { - jail->ubus = blobmsg_get_bool(tb[JAIL_ATTR_UBUS]); + if (tb[JAIL_ATTR_UBUS] && blobmsg_get_bool(tb[JAIL_ATTR_UBUS])) { + jail->ubus = true; jail->argc++; } - if (tb[JAIL_ATTR_LOG]) { - jail->log = blobmsg_get_bool(tb[JAIL_ATTR_LOG]); + if (tb[JAIL_ATTR_LOG] && blobmsg_get_bool(tb[JAIL_ATTR_LOG])) { + jail->log = true; jail->argc++; } - if (tb[JAIL_ATTR_RONLY]) { - jail->ronly = blobmsg_get_bool(tb[JAIL_ATTR_RONLY]); + if (tb[JAIL_ATTR_RONLY] && blobmsg_get_bool(tb[JAIL_ATTR_RONLY])) { + jail->ronly = true; jail->argc++; } - if (tb[JAIL_ATTR_NETNS]) { - jail->netns = blobmsg_get_bool(tb[JAIL_ATTR_NETNS]); + if (tb[JAIL_ATTR_NETNS] && blobmsg_get_bool(tb[JAIL_ATTR_NETNS])) { + jail->netns = true; jail->argc++; } - if (tb[JAIL_ATTR_USERNS]) { - jail->userns = blobmsg_get_bool(tb[JAIL_ATTR_USERNS]); + if (tb[JAIL_ATTR_USERNS] && blobmsg_get_bool(tb[JAIL_ATTR_USERNS])) { + jail->userns = true; jail->argc++; } - if (tb[JAIL_ATTR_CGROUPSNS]) { - jail->cgroupsns = blobmsg_get_bool(tb[JAIL_ATTR_CGROUPSNS]); + if (tb[JAIL_ATTR_CGROUPSNS] && blobmsg_get_bool(tb[JAIL_ATTR_CGROUPSNS])) { + jail->cgroupsns = true; jail->argc++; } - if (tb[JAIL_ATTR_CONSOLE]) { - jail->console = blobmsg_get_bool(tb[JAIL_ATTR_CONSOLE]); + if (tb[JAIL_ATTR_CONSOLE] && blobmsg_get_bool(tb[JAIL_ATTR_CONSOLE])) { + jail->console = true; jail->argc++; } + if (tb[JAIL_ATTR_PIDFILE]) { + jail->pidfile = strdup(blobmsg_get_string(tb[JAIL_ATTR_PIDFILE])); + jail->argc += 2; + } + + if (tb[JAIL_ATTR_SETNS]) { + struct blob_attr *cur; + int rem; + + blobmsg_for_each_attr(cur, tb[JAIL_ATTR_SETNS], rem) + jail->argc += 2; + blobmsg_list_fill(&jail->setns, blobmsg_data(tb[JAIL_ATTR_SETNS]), + blobmsg_data_len(tb[JAIL_ATTR_SETNS]), true); + } if (tb[JAIL_ATTR_MOUNT]) { struct blob_attr *cur; @@ -975,9 +1233,16 @@ instance_jail_parse(struct service_instance *in, struct blob_attr *attr) jail->argc += 2; instance_fill_array(&jail->mount, tb[JAIL_ATTR_MOUNT], NULL, false); } + + blobmsg_list_for_each(&in->env, var) + jail->argc += 2; + if (in->seccomp) jail->argc += 2; + if (in->capabilities) + jail->argc += 2; + if (in->user) jail->argc += 2; @@ -996,6 +1261,9 @@ instance_jail_parse(struct service_instance *in, struct blob_attr *attr) if (in->no_new_privs) jail->argc++; + if (in->bundle) + jail->argc += 2; + return true; } @@ -1035,8 +1303,8 @@ instance_config_parse(struct service_instance *in) blobmsg_parse(instance_attr, __INSTANCE_ATTR_MAX, tb, blobmsg_data(in->config), blobmsg_data_len(in->config)); - if (!instance_config_parse_command(in, tb)) - return false; + if (!tb[INSTANCE_ATTR_BUNDLE] && !instance_config_parse_command(in, tb)) + return false; if (tb[INSTANCE_ATTR_TERMTIMEOUT]) in->term_timeout = blobmsg_get_u32(tb[INSTANCE_ATTR_TERMTIMEOUT]); @@ -1065,7 +1333,7 @@ instance_config_parse(struct service_instance *in) blobmsg_for_each_attr(cur2, tb[INSTANCE_ATTR_WATCH], rem) { if (blobmsg_type(cur2) != BLOBMSG_TYPE_STRING) continue; - DEBUG(3, "watch for %s\n", blobmsg_get_string(cur2)); + P_DEBUG(3, "watch for %s\n", blobmsg_get_string(cur2)); watch_add(blobmsg_get_string(cur2), in); } } @@ -1104,6 +1372,9 @@ instance_config_parse(struct service_instance *in) if (!in->trace && tb[INSTANCE_ATTR_SECCOMP]) in->seccomp = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_SECCOMP])); + if (tb[INSTANCE_ATTR_CAPABILITIES]) + in->capabilities = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_CAPABILITIES])); + if (tb[INSTANCE_ATTR_EXTROOT]) in->extroot = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_EXTROOT])); @@ -1113,6 +1384,9 @@ instance_config_parse(struct service_instance *in) if (tb[INSTANCE_ATTR_TMPOVERLAYSIZE]) in->tmpoverlaysize = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_TMPOVERLAYSIZE])); + if (tb[INSTANCE_ATTR_BUNDLE]) + in->bundle = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_BUNDLE])); + if (tb[INSTANCE_ATTR_PIDFILE]) { char *pidfile = blobmsg_get_string(tb[INSTANCE_ATTR_PIDFILE]); if (pidfile) @@ -1122,22 +1396,6 @@ instance_config_parse(struct service_instance *in) if (tb[INSTANCE_ATTR_RELOADSIG]) in->reload_signal = blobmsg_get_u32(tb[INSTANCE_ATTR_RELOADSIG]); - if (!in->trace && tb[INSTANCE_ATTR_JAIL]) - in->has_jail = instance_jail_parse(in, tb[INSTANCE_ATTR_JAIL]); - - if (in->has_jail) { - r = stat(UJAIL_BIN_PATH, &s); - if (r < 0) { - if (in->require_jail) { - ERROR("Cannot jail service %s::%s. %s: %m (%d)\n", - in->srv->name, in->name, UJAIL_BIN_PATH, r); - return false; - } - DEBUG(2, "unable to find %s: %m (%d)\n", UJAIL_BIN_PATH, r); - in->has_jail = false; - } - } - if (tb[INSTANCE_ATTR_STDOUT] && blobmsg_get_bool(tb[INSTANCE_ATTR_STDOUT])) in->_stdout.fd.fd = -1; @@ -1165,9 +1423,54 @@ instance_config_parse(struct service_instance *in) int facility = syslog_facility_str_to_int(blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY])); if (facility != -1) { in->syslog_facility = facility; - DEBUG(3, "setting facility '%s'\n", blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY])); + P_DEBUG(3, "setting facility '%s'\n", blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY])); } else - DEBUG(3, "unknown syslog facility '%s' given, using default (LOG_DAEMON)\n", blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY])); + P_DEBUG(3, "unknown syslog facility '%s' given, using default (LOG_DAEMON)\n", blobmsg_get_string(tb[INSTANCE_ATTR_FACILITY])); + } + + if (tb[INSTANCE_ATTR_WATCHDOG]) { + int i = 0; + uint32_t vals[2] = { 0, 30 }; + + blobmsg_for_each_attr(cur2, tb[INSTANCE_ATTR_WATCHDOG], rem) { + if (i >= 2) + break; + + vals[i] = atoi(blobmsg_get_string(cur2)); + i++; + } + + if (vals[0] >= 0 && vals[0] < __INSTANCE_WATCHDOG_MODE_MAX) { + in->watchdog.mode = vals[0]; + P_DEBUG(3, "setting watchdog mode (%d)\n", vals[0]); + } else { + in->watchdog.mode = 0; + P_DEBUG(3, "unknown watchdog mode (%d) given, using default (0)\n", vals[0]); + } + + if (vals[1] > 0) { + in->watchdog.freq = vals[1]; + P_DEBUG(3, "setting watchdog timeout (%d)\n", vals[0]); + } else { + in->watchdog.freq = 30; + P_DEBUG(3, "invalid watchdog timeout (%d) given, using default (30)\n", vals[1]); + } + } + + if (!in->trace && tb[INSTANCE_ATTR_JAIL]) + in->has_jail = instance_jail_parse(in, tb[INSTANCE_ATTR_JAIL]); + + if (in->has_jail) { + r = stat(UJAIL_BIN_PATH, &s); + if (r < 0) { + if (in->require_jail) { + ERROR("Cannot jail service %s::%s. %s: %m (%d)\n", + in->srv->name, in->name, UJAIL_BIN_PATH, r); + return false; + } + P_DEBUG(2, "unable to find %s: %m (%d)\n", UJAIL_BIN_PATH, r); + in->has_jail = false; + } } return true; @@ -1183,6 +1486,7 @@ instance_config_cleanup(struct service_instance *in) blobmsg_list_free(&in->limits); blobmsg_list_free(&in->errors); blobmsg_list_free(&in->jail.mount); + blobmsg_list_free(&in->jail.setns); } static void @@ -1210,21 +1514,53 @@ instance_config_move(struct service_instance *in, struct service_instance *in_sr blobmsg_list_move(&in->limits, &in_src->limits); blobmsg_list_move(&in->errors, &in_src->errors); blobmsg_list_move(&in->jail.mount, &in_src->jail.mount); + blobmsg_list_move(&in->jail.setns, &in_src->jail.setns); in->trigger = in_src->trigger; in->command = in_src->command; in->respawn = in_src->respawn; in->respawn_retry = in_src->respawn_retry; in->respawn_threshold = in_src->respawn_threshold; in->respawn_timeout = in_src->respawn_timeout; + in->reload_signal = in_src->reload_signal; + in->term_timeout = in_src->term_timeout; + in->watchdog.mode = in_src->watchdog.mode; + in->watchdog.freq = in_src->watchdog.freq; + in->watchdog.timeout = in_src->watchdog.timeout; in->name = in_src->name; + in->nice = in_src->nice; in->trace = in_src->trace; in->node.avl.key = in_src->node.avl.key; in->syslog_facility = in_src->syslog_facility; + in->require_jail = in_src->require_jail; + in->no_new_privs = in_src->no_new_privs; + in->immediately = in_src->immediately; + in->uid = in_src->uid; + in->pw_gid = in_src->pw_gid; + in->gr_gid = in_src->gr_gid; + + in->has_jail = in_src->has_jail; + in->jail.procfs = in_src->jail.procfs; + in->jail.sysfs = in_src->jail.sysfs; + in->jail.ubus = in_src->jail.ubus; + in->jail.log = in_src->jail.log; + in->jail.ronly = in_src->jail.ronly; + in->jail.netns = in_src->jail.netns; + in->jail.cgroupsns = in_src->jail.cgroupsns; + in->jail.console = in_src->jail.console; + in->jail.argc = in_src->jail.argc; instance_config_move_strdup(&in->pidfile, in_src->pidfile); instance_config_move_strdup(&in->seccomp, in_src->seccomp); + instance_config_move_strdup(&in->capabilities, in_src->capabilities); + instance_config_move_strdup(&in->bundle, in_src->bundle); + instance_config_move_strdup(&in->extroot, in_src->extroot); + instance_config_move_strdup(&in->overlaydir, in_src->overlaydir); + instance_config_move_strdup(&in->tmpoverlaysize, in_src->tmpoverlaysize); + instance_config_move_strdup(&in->user, in_src->user); + instance_config_move_strdup(&in->group, in_src->group); instance_config_move_strdup(&in->jail.name, in_src->jail.name); instance_config_move_strdup(&in->jail.hostname, in_src->jail.hostname); + instance_config_move_strdup(&in->jail.pidfile, in_src->jail.pidfile); free(in->config); in->config = in_src->config; @@ -1255,6 +1591,7 @@ instance_free(struct service_instance *in) instance_free_stdio(in); uloop_process_delete(&in->proc); uloop_timeout_cancel(&in->timeout); + uloop_timeout_cancel(&in->watchdog.timeout); trigger_del(in); watch_del(in); instance_config_cleanup(in); @@ -1264,9 +1601,12 @@ instance_free(struct service_instance *in) free(in->extroot); free(in->overlaydir); free(in->tmpoverlaysize); + free(in->bundle); free(in->jail.name); free(in->jail.hostname); + free(in->jail.pidfile); free(in->seccomp); + free(in->capabilities); free(in->pidfile); free(in); } @@ -1284,6 +1624,7 @@ instance_init(struct service_instance *in, struct service *s, struct blob_attr * in->syslog_facility = LOG_DAEMON; in->exit_code = 0; in->require_jail = false; + in->immediately = false; in->_stdout.fd.fd = -2; in->_stdout.stream.string_data = true; @@ -1308,6 +1649,10 @@ instance_init(struct service_instance *in, struct service *s, struct blob_attr * blobmsg_list_simple_init(&in->limits); blobmsg_list_simple_init(&in->errors); blobmsg_list_simple_init(&in->jail.mount); + blobmsg_list_simple_init(&in->jail.setns); + + in->watchdog.timeout.cb = instance_watchdog; + in->valid = instance_config_parse(in); } @@ -1324,6 +1669,8 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) blobmsg_add_u32(b, "pid", in->proc.pid); if (in->command) blobmsg_add_blob(b, in->command); + if (in->bundle) + blobmsg_add_string(b, "bundle", in->bundle); blobmsg_add_u32(b, "term_timeout", in->term_timeout); if (!in->proc.pending) blobmsg_add_u32(b, "exit_code", in->exit_code); @@ -1360,6 +1707,15 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) blobmsg_close_table(b, e); } + if (!avl_is_empty(&in->netdev.avl)) { + struct blobmsg_list_node *var; + void *n = blobmsg_open_array(b, "netdev"); + + blobmsg_list_for_each(&in->netdev, var) + blobmsg_add_string(b, NULL, blobmsg_data(var->data)); + blobmsg_close_array(b, n); + } + if (in->reload_signal) blobmsg_add_u32(b, "reload_signal", in->reload_signal); @@ -1380,6 +1736,9 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) if (in->seccomp) blobmsg_add_string(b, "seccomp", in->seccomp); + if (in->capabilities) + blobmsg_add_string(b, "capabilities", in->capabilities); + if (in->pidfile) blobmsg_add_string(b, "pidfile", in->pidfile); @@ -1393,17 +1752,24 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) void *r = blobmsg_open_table(b, "jail"); if (in->jail.name) blobmsg_add_string(b, "name", in->jail.name); - if (in->jail.hostname) - blobmsg_add_string(b, "hostname", in->jail.hostname); - - blobmsg_add_u8(b, "procfs", in->jail.procfs); - blobmsg_add_u8(b, "sysfs", in->jail.sysfs); - blobmsg_add_u8(b, "ubus", in->jail.ubus); - blobmsg_add_u8(b, "log", in->jail.log); - blobmsg_add_u8(b, "ronly", in->jail.ronly); - blobmsg_add_u8(b, "netns", in->jail.netns); - blobmsg_add_u8(b, "userns", in->jail.userns); - blobmsg_add_u8(b, "cgroupsns", in->jail.cgroupsns); + if (!in->bundle) { + if (in->jail.hostname) + blobmsg_add_string(b, "hostname", in->jail.hostname); + + blobmsg_add_u8(b, "procfs", in->jail.procfs); + blobmsg_add_u8(b, "sysfs", in->jail.sysfs); + blobmsg_add_u8(b, "ubus", in->jail.ubus); + blobmsg_add_u8(b, "log", in->jail.log); + blobmsg_add_u8(b, "ronly", in->jail.ronly); + blobmsg_add_u8(b, "netns", in->jail.netns); + blobmsg_add_u8(b, "userns", in->jail.userns); + blobmsg_add_u8(b, "cgroupsns", in->jail.cgroupsns); + } else { + if (in->jail.pidfile) + blobmsg_add_string(b, "pidfile", in->jail.pidfile); + + blobmsg_add_u8(b, "immediately", in->immediately); + } blobmsg_add_u8(b, "console", (in->console.fd.fd > -1)); blobmsg_close_table(b, r); if (!avl_is_empty(&in->jail.mount.avl)) { @@ -1413,6 +1779,14 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) blobmsg_add_string(b, blobmsg_name(var->data), blobmsg_data(var->data)); blobmsg_close_table(b, e); } + + if (!avl_is_empty(&in->jail.setns.avl)) { + struct blobmsg_list_node *var; + void *s = blobmsg_open_array(b, "setns"); + blobmsg_list_for_each(&in->jail.setns, var) + blobmsg_add_blob(b, var->data); + blobmsg_close_array(b, s); + } } if (in->extroot) @@ -1425,5 +1799,12 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) if (verbose && in->trigger) blobmsg_add_blob(b, in->trigger); + if (in->watchdog.mode != INSTANCE_WATCHDOG_MODE_DISABLED) { + void *r = blobmsg_open_table(b, "watchdog"); + blobmsg_add_u32(b, "mode", in->watchdog.mode); + blobmsg_add_u32(b, "timeout", in->watchdog.freq); + blobmsg_close_table(b, r); + } + blobmsg_close_table(b, i); }