diff --git a/bsp/buildroot_external/package/procd/procd.mk b/bsp/buildroot_external/package/procd/procd.mk index a7b7e047..1f13c710 100644 --- a/bsp/buildroot_external/package/procd/procd.mk +++ b/bsp/buildroot_external/package/procd/procd.mk @@ -4,13 +4,13 @@ # ################################################################################ -PROCD_VERSION:= 2016.07.29 +PROCD_VERSION:= 2017.02.08 PROCD_SITE = $(TOPDIR)/../../src/3P/procd/builders/cmake PROCD_SITE_METHOD = local PROCD_INSTALL_STAGING = YES -PROCD_DEPENDENCIES = libubox json-c ubus +PROCD_DEPENDENCIES = libubox ubus json-c PROCD_CONF = SRC_DIR=$(TOPDIR)/../.. diff --git a/src/3P/procd/CMakeLists.txt b/src/3P/procd/CMakeLists.txt index b66fad16..444dd205 100644 --- a/src/3P/procd/CMakeLists.txt +++ b/src/3P/procd/CMakeLists.txt @@ -28,7 +28,7 @@ ENDIF() SET(LIBS ubox ubus json-c blobmsg_json json_script) IF(DEBUG) - ADD_DEFINITIONS(-DDEBUG -g3) + ADD_DEFINITIONS(-DUDEV_DEBUG -g3) ENDIF() IF(EARLY_PATH) diff --git a/src/3P/procd/initd/init.c b/src/3P/procd/initd/init.c index 1683e012..e453cff2 100644 --- a/src/3P/procd/initd/init.c +++ b/src/3P/procd/initd/init.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/src/3P/procd/initd/mkdev.c b/src/3P/procd/initd/mkdev.c index e6d3d0c2..e8267072 100644 --- a/src/3P/procd/initd/mkdev.c +++ b/src/3P/procd/initd/mkdev.c @@ -121,5 +121,6 @@ int mkdev(const char *name, int _mode) n_patterns = 1; find_devs(true); find_devs(false); + free(pattern); return chdir("/"); } diff --git a/src/3P/procd/initd/preinit.c b/src/3P/procd/initd/preinit.c index 121fb172..729978ea 100644 --- a/src/3P/procd/initd/preinit.c +++ b/src/3P/procd/initd/preinit.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include diff --git a/src/3P/procd/initd/zram.c b/src/3P/procd/initd/zram.c index 49480afa..9fab794a 100644 --- a/src/3P/procd/initd/zram.c +++ b/src/3P/procd/initd/zram.c @@ -124,5 +124,11 @@ mount_zram_on_tmp(void) LOG("Using up to %ld kB of RAM as ZRAM storage on /mnt\n", zramsize); + ret = chmod("/tmp", 01777); + if (ret < 0) { + ERROR("Can't set /tmp mode to 1777: %s\n", strerror(errno)); + return errno; + } + return 0; } diff --git a/src/3P/procd/inittab.c b/src/3P/procd/inittab.c index 3ae561a4..011d7a67 100644 --- a/src/3P/procd/inittab.c +++ b/src/3P/procd/inittab.c @@ -12,7 +12,7 @@ * GNU General Public License for more details. */ -//AWOX #define _GNU_SOURCE +#define _GNU_SOURCE #include #include #include @@ -31,6 +31,10 @@ #include "procd.h" #include "rcS.h" +#ifndef O_PATH +#define O_PATH 010000000 +#endif + #define TAG_ID 0 #define TAG_RUNLVL 1 #define TAG_ACTION 2 @@ -224,6 +228,14 @@ static struct init_handler handlers[] = { .name = "respawn", .cb = rcrespawn, .multi = 1, + }, { + .name = "askconsolelate", + .cb = askconsole, + .multi = 1, + }, { + .name = "respawnlate", + .cb = rcrespawn, + .multi = 1, } }; diff --git a/src/3P/procd/jail/jail.c b/src/3P/procd/jail/jail.c index c4428471..9d7483c9 100644 --- a/src/3P/procd/jail/jail.c +++ b/src/3P/procd/jail/jail.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "capabilities.h" #include "elf.h" @@ -269,8 +270,14 @@ static int exec_jail(void *_notused) static int jail_running = 1; static int jail_return_code = 0; +static void jail_process_timeout_cb(struct uloop_timeout *t); +static struct uloop_timeout jail_process_timeout = { + .cb = jail_process_timeout_cb, +}; + static void jail_process_handler(struct uloop_process *c, int ret) { + uloop_timeout_cancel(&jail_process_timeout); if (WIFEXITED(ret)) { jail_return_code = WEXITSTATUS(ret); INFO("jail (%d) exited with exit: %d\n", c->pid, jail_return_code); @@ -286,12 +293,25 @@ static struct uloop_process jail_process = { .cb = jail_process_handler, }; +static void jail_process_timeout_cb(struct uloop_timeout *t) +{ + DEBUG("jail process failed to stop, sending SIGKILL\n"); + kill(jail_process.pid, SIGKILL); +} + +static void jail_handle_signal(int signo) +{ + DEBUG("forwarding signal %d to the jailed process\n", signo); + kill(jail_process.pid, signo); +} + int main(int argc, char **argv) { + sigset_t sigmask; uid_t uid = getuid(); char log[] = "/dev/log"; char ubus[] = "/var/run/ubus.sock"; - int ch; + int ch, i; if (uid) { ERROR("not root, aborting: %s\n", strerror(errno)); @@ -385,7 +405,26 @@ int main(int argc, char **argv) prctl(PR_SET_NAME, opts.name, NULL, NULL, NULL); uloop_init(); + + sigfillset(&sigmask); + for (i = 0; i < _NSIG; i++) { + struct sigaction s = { 0 }; + + if (!sigismember(&sigmask, i)) + continue; + if ((i == SIGCHLD) || (i == SIGPIPE)) + continue; + + s.sa_handler = jail_handle_signal; + sigaction(i, &s, NULL); + } + if (opts.namespace) { + add_mount("/dev/full", 0, -1); + add_mount("/dev/null", 0, -1); + add_mount("/dev/urandom", 0, -1); + add_mount("/dev/zero", 0, -1); + int flags = CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | SIGCHLD; if (opts.hostname) flags |= CLONE_NEWUTS; @@ -398,12 +437,13 @@ int main(int argc, char **argv) /* parent process */ uloop_process_add(&jail_process); uloop_run(); - uloop_done(); if (jail_running) { DEBUG("uloop interrupted, killing jail process\n"); kill(jail_process.pid, SIGTERM); - waitpid(jail_process.pid, NULL, 0); + uloop_timeout_set(&jail_process_timeout, 1000); + uloop_run(); } + uloop_done(); return jail_return_code; } else if (jail_process.pid == 0) { /* fork child process */ diff --git a/src/3P/procd/plug/hotplug.c b/src/3P/procd/plug/hotplug.c index 85959155..ae972f60 100644 --- a/src/3P/procd/plug/hotplug.c +++ b/src/3P/procd/plug/hotplug.c @@ -130,6 +130,7 @@ static void handle_makedev(struct blob_attr *msg, struct blob_attr *data) char *minor = hotplug_msg_find_var(msg, "MINOR"); char *major = hotplug_msg_find_var(msg, "MAJOR"); char *subsystem = hotplug_msg_find_var(msg, "SUBSYSTEM"); + int ret = 0; blobmsg_parse_array(mkdev_policy, 3, tb, blobmsg_data(data), blobmsg_data_len(data)); if (tb[0] && tb[1] && minor && major && subsystem) { @@ -149,8 +150,9 @@ static void handle_makedev(struct blob_attr *msg, struct blob_attr *data) struct group *g = getgrnam(blobmsg_get_string(tb[2])); if (g) - chown(blobmsg_get_string(tb[0]), 0, g->gr_gid); - else + ret = chown(blobmsg_get_string(tb[0]), 0, g->gr_gid); + + if (!g || ret < 0) ERROR("cannot set group %s for %s\n", blobmsg_get_string(tb[2]), blobmsg_get_string(tb[0])); diff --git a/src/3P/procd/plug/udevtrigger.c b/src/3P/procd/plug/udevtrigger.c index 3eba19a6..6bb34535 100644 --- a/src/3P/procd/plug/udevtrigger.c +++ b/src/3P/procd/plug/udevtrigger.c @@ -66,7 +66,7 @@ static void log_message(int priority, const char *format, ...) log_message(LOG_INFO ,"%s: " format ,__FUNCTION__ ,## arg); \ } while (0) -#ifdef DEBUG +#ifdef UDEV_DEBUG #undef dbg #define dbg(format, arg...) \ do { \ diff --git a/src/3P/procd/procd.h b/src/3P/procd/procd.h index 6ec46d3a..88886a3e 100644 --- a/src/3P/procd/procd.h +++ b/src/3P/procd/procd.h @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include diff --git a/src/3P/procd/service/instance.c b/src/3P/procd/service/instance.c index ef4aac63..018db3c6 100644 --- a/src/3P/procd/service/instance.c +++ b/src/3P/procd/service/instance.c @@ -12,7 +12,7 @@ * GNU General Public License for more details. */ -//AWOX #define _GNU_SOURCE +#define _GNU_SOURCE #include #include #include @@ -54,6 +54,7 @@ enum { INSTANCE_ATTR_TRACE, INSTANCE_ATTR_SECCOMP, INSTANCE_ATTR_PIDFILE, + INSTANCE_ATTR_RELOADSIG, __INSTANCE_ATTR_MAX }; @@ -77,6 +78,7 @@ static const struct blobmsg_policy instance_attr[__INSTANCE_ATTR_MAX] = { [INSTANCE_ATTR_TRACE] = { "trace", BLOBMSG_TYPE_BOOL }, [INSTANCE_ATTR_SECCOMP] = { "seccomp", BLOBMSG_TYPE_STRING }, [INSTANCE_ATTR_PIDFILE] = { "pidfile", BLOBMSG_TYPE_STRING }, + [INSTANCE_ATTR_RELOADSIG] = { "reload_signal", BLOBMSG_TYPE_INT32 }, }; enum { @@ -263,6 +265,7 @@ instance_writepid(struct service_instance *in) if (fprintf(_pidfile, "%d\n", in->proc.pid) < 0) { ERROR("failed to write pidfile: %s: %d (%s)", in->pidfile, errno, strerror(errno)); + fclose(_pidfile); return 2; } if (fclose(_pidfile)) { @@ -386,7 +389,7 @@ instance_start(struct service_instance *in) return; } - if (in->proc.pending) + if (in->proc.pending || !in->command) return; instance_free_stdio(in); @@ -526,7 +529,9 @@ instance_exit(struct uloop_process *p, int ret) in->srv->name, in->name, in->respawn_count, runtime); in->restart = in->respawn = 0; in->halt = 1; + service_event("instance.fail", in->srv->name, in->name); } else { + service_event("instance.respawn", in->srv->name, in->name); uloop_timeout_set(&in->timeout, in->respawn_timeout * 1000); } } @@ -548,6 +553,12 @@ instance_restart(struct service_instance *in) { if (!in->proc.pending) return; + + if (in->reload_signal) { + kill(in->proc.pid, in->reload_signal); + return; + } + in->halt = false; in->restart = true; kill(in->proc.pid, SIGTERM); @@ -566,9 +577,6 @@ instance_config_changed(struct service_instance *in, struct service_instance *in if (!blobmsg_list_equal(&in->env, &in_new->env)) return true; - if (!blobmsg_list_equal(&in->data, &in_new->data)) - return true; - if (!blobmsg_list_equal(&in->netdev, &in_new->netdev)) return true; @@ -751,31 +759,42 @@ instance_jail_parse(struct service_instance *in, struct blob_attr *attr) } static bool -instance_config_parse(struct service_instance *in) +instance_config_parse_command(struct service_instance *in, struct blob_attr **tb) { - struct blob_attr *tb[__INSTANCE_ATTR_MAX]; struct blob_attr *cur, *cur2; - int argc = 0; + bool ret = false; int rem; - blobmsg_parse(instance_attr, __INSTANCE_ATTR_MAX, tb, - blobmsg_data(in->config), blobmsg_data_len(in->config)); - cur = tb[INSTANCE_ATTR_COMMAND]; - if (!cur) - return false; + if (!cur) { + in->command = NULL; + return true; + } if (!blobmsg_check_attr_list(cur, BLOBMSG_TYPE_STRING)) return false; blobmsg_for_each_attr(cur2, cur, rem) { - argc++; + ret = true; break; } - if (!argc) - return false; in->command = cur; + return ret; +} + +static bool +instance_config_parse(struct service_instance *in) +{ + struct blob_attr *tb[__INSTANCE_ATTR_MAX]; + struct blob_attr *cur, *cur2; + int rem; + + 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_RESPAWN]) { int i = 0; @@ -843,6 +862,9 @@ instance_config_parse(struct service_instance *in) in->pidfile = pidfile; } + 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]); @@ -906,25 +928,21 @@ instance_config_move(struct service_instance *in, struct service_instance *in_sr in_src->config = NULL; } -bool +void instance_update(struct service_instance *in, struct service_instance *in_new) { bool changed = instance_config_changed(in, in_new); bool running = in->proc.pending; - if (!changed && running) - return false; - if (!running) { - if (changed) - instance_config_move(in, in_new); + instance_config_move(in, in_new); instance_start(in); } else { - instance_restart(in); + if (changed) + instance_restart(in); instance_config_move(in, in_new); /* restart happens in the child callback handler */ } - return true; } void @@ -979,7 +997,8 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) blobmsg_add_u8(b, "running", in->proc.pending); if (in->proc.pending) blobmsg_add_u32(b, "pid", in->proc.pid); - blobmsg_add_blob(b, in->command); + if (in->command) + blobmsg_add_blob(b, in->command); if (!avl_is_empty(&in->errors.avl)) { struct blobmsg_list_node *var; @@ -1013,6 +1032,9 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) blobmsg_close_table(b, e); } + if (in->reload_signal) + blobmsg_add_u32(b, "reload_signal", in->reload_signal); + if (in->respawn) { void *r = blobmsg_open_table(b, "respawn"); blobmsg_add_u32(b, "threshold", in->respawn_threshold); diff --git a/src/3P/procd/service/instance.h b/src/3P/procd/service/instance.h index 1ee04292..3cc20093 100644 --- a/src/3P/procd/service/instance.h +++ b/src/3P/procd/service/instance.h @@ -49,6 +49,7 @@ struct service_instance { bool restart; bool respawn; int respawn_count; + int reload_signal; struct timespec start; bool trace; @@ -80,7 +81,7 @@ struct service_instance { void instance_start(struct service_instance *in); void instance_stop(struct service_instance *in); -bool instance_update(struct service_instance *in, struct service_instance *in_new); +void instance_update(struct service_instance *in, struct service_instance *in_new); void instance_init(struct service_instance *in, struct service *s, struct blob_attr *config); void instance_free(struct service_instance *in); void instance_dump(struct blob_buf *b, struct service_instance *in, int debug); diff --git a/src/3P/procd/service/service.c b/src/3P/procd/service/service.c index 0796adbb..2c739015 100644 --- a/src/3P/procd/service/service.c +++ b/src/3P/procd/service/service.c @@ -189,6 +189,19 @@ static const struct blobmsg_policy service_list_attrs[__SERVICE_LIST_ATTR_MAX] = [SERVICE_LIST_ATTR_VERBOSE] = { "verbose", BLOBMSG_TYPE_BOOL }, }; +enum { + SERVICE_SIGNAL_ATTR_NAME, + SERVICE_SIGNAL_ATTR_INSTANCE, + SERVICE_SIGNAL_ATTR_SIGNAL, + __SERVICE_SIGNAL_ATTR_MAX, +}; + +static const struct blobmsg_policy service_signal_attrs[__SERVICE_SIGNAL_ATTR_MAX] = { + [SERVICE_SIGNAL_ATTR_NAME] = { "name", BLOBMSG_TYPE_STRING }, + [SERVICE_SIGNAL_ATTR_INSTANCE] = { "instance", BLOBMSG_TYPE_STRING }, + [SERVICE_SIGNAL_ATTR_SIGNAL] = { "signal", BLOBMSG_TYPE_INT32 }, +}; + enum { EVENT_TYPE, EVENT_DATA, @@ -353,6 +366,63 @@ service_handle_delete(struct ubus_context *ctx, struct ubus_object *obj, return 0; } +static int +service_handle_kill(struct service_instance *in, int sig) +{ + if (kill(in->proc.pid, sig) == 0) + return 0; + + switch (errno) { + case EINVAL: return UBUS_STATUS_INVALID_ARGUMENT; + case EPERM: return UBUS_STATUS_PERMISSION_DENIED; + case ESRCH: return UBUS_STATUS_NOT_FOUND; + } + + return UBUS_STATUS_UNKNOWN_ERROR; +} + +static int +service_handle_signal(struct ubus_context *ctx, struct ubus_object *obj, + struct ubus_request_data *req, const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__SERVICE_SIGNAL_ATTR_MAX], *cur; + struct service *s; + struct service_instance *in; + int sig = SIGHUP; + int rv = 0; + + blobmsg_parse(service_signal_attrs, __SERVICE_SIGNAL_ATTR_MAX, tb, blob_data(msg), blob_len(msg)); + + cur = tb[SERVICE_SIGNAL_ATTR_SIGNAL]; + if (cur) + sig = blobmsg_get_u32(cur); + + cur = tb[SERVICE_SIGNAL_ATTR_NAME]; + if (!cur) + return UBUS_STATUS_NOT_FOUND; + + s = avl_find_element(&services, blobmsg_data(cur), s, avl); + if (!s) + return UBUS_STATUS_NOT_FOUND; + + cur = tb[SERVICE_SIGNAL_ATTR_INSTANCE]; + if (!cur) { + vlist_for_each_element(&s->instances, in, node) + rv = service_handle_kill(in, sig); + + return rv; + } + + in = vlist_find(&s->instances, blobmsg_data(cur), in, node); + if (!in) { + ERROR("instance %s not found\n", blobmsg_get_string(cur)); + return UBUS_STATUS_NOT_FOUND; + } + + return service_handle_kill(in, sig); +} + static int service_handle_update(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, @@ -363,7 +433,7 @@ service_handle_update(struct ubus_context *ctx, struct ubus_object *obj, blobmsg_parse(service_attrs, __SERVICE_ATTR_MAX, tb, blob_data(msg), blob_len(msg)); - cur = tb[SERVICE_ATTR_NAME]; + cur = tb[SERVICE_SET_NAME]; if (!cur) return UBUS_STATUS_INVALID_ARGUMENT; @@ -490,6 +560,7 @@ static struct ubus_method main_object_methods[] = { UBUS_METHOD("add", service_handle_set, service_set_attrs), UBUS_METHOD("list", service_handle_list, service_list_attrs), UBUS_METHOD("delete", service_handle_delete, service_del_attrs), + UBUS_METHOD("signal", service_handle_signal, service_signal_attrs), UBUS_METHOD("update_start", service_handle_update, service_attrs), UBUS_METHOD("update_complete", service_handle_update, service_attrs), UBUS_METHOD("event", service_handle_event, event_policy), diff --git a/src/3P/procd/state.c b/src/3P/procd/state.c index 4ad9e2d8..3b56bd0b 100644 --- a/src/3P/procd/state.c +++ b/src/3P/procd/state.c @@ -128,6 +128,8 @@ static void state_enter(void) case STATE_RUNNING: LOG("- init complete -\n"); + procd_inittab_run("respawnlate"); + procd_inittab_run("askconsolelate"); break; case STATE_SHUTDOWN: diff --git a/src/3P/procd/trace/trace.c b/src/3P/procd/trace/trace.c index b0005b8a..fdffaba5 100644 --- a/src/3P/procd/trace/trace.c +++ b/src/3P/procd/trace/trace.c @@ -176,7 +176,7 @@ int main(int argc, char **argv, char **envp) if (child == 0) { char **_argv = calloc(argc + 1, sizeof(char *)); char **_envp; - char preload[] = "LD_PRELOAD=/lib/libpreload-trace.so"; + char *preload = "LD_PRELOAD=/lib/libpreload-trace.so"; int envc = 1; int ret; @@ -187,10 +187,13 @@ int main(int argc, char **argv, char **envp) _envp = calloc(envc, sizeof(char *)); memcpy(&_envp[1], _envp, envc * sizeof(char *)); - *envp = preload; + *_envp = preload; - ret = execve(_argv[0], _argv, envp); + ret = execve(_argv[0], _argv, _envp); ERROR("failed to exec %s: %s\n", _argv[0], strerror(errno)); + + free(_argv); + free(_envp); return ret; } diff --git a/src/3P/procd/utils/utils.c b/src/3P/procd/utils/utils.c index eef1bdbb..e239eda5 100644 --- a/src/3P/procd/utils/utils.c +++ b/src/3P/procd/utils/utils.c @@ -12,7 +12,7 @@ * GNU General Public License for more details. */ -//AWOX #define _GNU_SOURCE +#define _GNU_SOURCE #include #include #include "utils.h" @@ -26,6 +26,10 @@ #include "../log.h" +#ifndef O_PATH +#define O_PATH 010000000 +#endif + void __blobmsg_list_init(struct blobmsg_list *list, int offset, int len, blobmsg_list_cmp cmp) {