diff options
author | Jo-Philipp Wich <jow@openwrt.org> | 2015-02-26 12:27:39 +0100 |
---|---|---|
committer | Jo-Philipp Wich <jow@openwrt.org> | 2015-02-26 14:34:18 +0100 |
commit | 9851e517f1c3e55228e2fdde913c9cf0b87a4bc7 (patch) | |
tree | 9c85993f55b0d39892791ba833428fddb506b214 /service | |
parent | 4bccbfa967d756b8c84a62ea4752e936d8545a73 (diff) | |
download | unitd-9851e517f1c3e55228e2fdde913c9cf0b87a4bc7.tar unitd-9851e517f1c3e55228e2fdde913c9cf0b87a4bc7.zip |
procd: support relayoing daemon stdout/stderr to syslog
This commit adds support to procd for relaying stdout and stderr streams to
the system log. That is mainly useful for services not using syslog, e.g.
uhttpd.
Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
Diffstat (limited to 'service')
-rw-r--r-- | service/instance.c | 141 | ||||
-rw-r--r-- | service/instance.h | 3 |
2 files changed, 134 insertions, 10 deletions
diff --git a/service/instance.c b/service/instance.c index 6dfc61b..6787ae0 100644 --- a/service/instance.c +++ b/service/instance.c @@ -20,6 +20,7 @@ #include <stdint.h> #include <fcntl.h> #include <pwd.h> +#include <libgen.h> #include <libubox/md5.h> @@ -42,6 +43,8 @@ enum { INSTANCE_ATTR_WATCH, INSTANCE_ATTR_ERROR, INSTANCE_ATTR_USER, + INSTANCE_ATTR_STDOUT, + INSTANCE_ATTR_STDERR, __INSTANCE_ATTR_MAX }; @@ -58,6 +61,8 @@ static const struct blobmsg_policy instance_attr[__INSTANCE_ATTR_MAX] = { [INSTANCE_ATTR_WATCH] = { "watch", BLOBMSG_TYPE_ARRAY }, [INSTANCE_ATTR_ERROR] = { "error", BLOBMSG_TYPE_ARRAY }, [INSTANCE_ATTR_USER] = { "user", BLOBMSG_TYPE_STRING }, + [INSTANCE_ATTR_STDOUT] = { "stdout", BLOBMSG_TYPE_BOOL }, + [INSTANCE_ATTR_STDERR] = { "stderr", BLOBMSG_TYPE_BOOL }, }; struct instance_netdev { @@ -93,6 +98,12 @@ static const struct rlimit_name rlimit_names[] = { { NULL, 0 } }; +static void closefd(int fd) +{ + if (fd > STDERR_FILENO) + close(fd); +} + static void instance_limits(const char *limit, const char *value) { @@ -126,13 +137,13 @@ instance_limits(const char *limit, const char *value) } static void -instance_run(struct service_instance *in) +instance_run(struct service_instance *in, int stdout, int stderr) { struct blobmsg_list_node *var; struct blob_attr *cur; char **argv; int argc = 1; /* NULL terminated */ - int rem, fd; + int rem, stdin; if (in->nice) setpriority(PRIO_PROCESS, 0, in->nice); @@ -153,14 +164,28 @@ instance_run(struct service_instance *in) argv[argc++] = blobmsg_data(cur); argv[argc] = NULL; - fd = open("/dev/null", O_RDWR); - if (fd > -1) { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - if (fd > STDERR_FILENO) - close(fd); + + stdin = open("/dev/null", O_RDONLY); + + if (stdout == -1) + stdout = open("/dev/null", O_WRONLY); + + if (stderr == -1) + stderr = open("/dev/null", O_WRONLY); + + if (stdin > -1) { + dup2(stdin, STDIN_FILENO); + closefd(stdin); } + if (stdout > -1) { + dup2(stdout, STDOUT_FILENO); + closefd(stdout); + } + if (stderr > -1) { + dup2(stderr, STDERR_FILENO); + closefd(stderr); + } + if (in->uid || in->gid) { setuid(in->uid); setgid(in->gid); @@ -173,6 +198,8 @@ void instance_start(struct service_instance *in) { int pid; + int opipe[2] = { -1, -1 }; + int epipe[2] = { -1, -1 }; if (!avl_is_empty(&in->errors.avl)) { LOG("Not starting instance %s::%s, an error was indicated\n", in->srv->name, in->name); @@ -182,6 +209,20 @@ instance_start(struct service_instance *in) if (in->proc.pending) return; + if (in->stdout.fd.fd > -2) { + if (pipe(opipe)) { + ULOG_WARN("pipe() failed: %d (%s)\n", errno, strerror(errno)); + opipe[0] = opipe[1] = -1; + } + } + + if (in->stderr.fd.fd > -2) { + if (pipe(epipe)) { + ULOG_WARN("pipe() failed: %d (%s)\n", errno, strerror(errno)); + epipe[0] = epipe[1] = -1; + } + } + in->restart = false; in->halt = !in->respawn; @@ -194,7 +235,9 @@ instance_start(struct service_instance *in) if (!pid) { uloop_done(); - instance_run(in); + closefd(opipe[0]); + closefd(epipe[0]); + instance_run(in, opipe[1], epipe[1]); return; } @@ -202,10 +245,64 @@ instance_start(struct service_instance *in) in->proc.pid = pid; clock_gettime(CLOCK_MONOTONIC, &in->start); uloop_process_add(&in->proc); + + if (opipe[0] > -1) { + ustream_fd_init(&in->stdout, opipe[0]); + closefd(opipe[1]); + } + + if (epipe[0] > -1) { + ustream_fd_init(&in->stderr, epipe[0]); + closefd(epipe[1]); + } + service_event("instance.start", in->srv->name, in->name); } static void +instance_stdio(struct ustream *s, int prio, struct service_instance *in) +{ + char *newline, *str, *arg0, ident[32]; + int len; + + do { + str = ustream_get_read_buf(s, NULL); + if (!str) + break; + + newline = strchr(str, '\n'); + if (!newline) + break; + + *newline = 0; + len = newline + 1 - str; + + arg0 = basename(blobmsg_data(blobmsg_data(in->command))); + snprintf(ident, sizeof(ident), "%s[%d]", arg0, in->proc.pid); + + ulog_open(ULOG_STDIO|ULOG_SYSLOG, LOG_DAEMON, ident); + ulog(prio, "%s\n", str); + ulog_open(ULOG_STDIO|ULOG_SYSLOG, LOG_DAEMON, "procd"); + + ustream_consume(s, len); + } while (1); +} + +static void +instance_stdout(struct ustream *s, int bytes) +{ + instance_stdio(s, LOG_INFO, + container_of(s, struct service_instance, stdout.stream)); +} + +static void +instance_stderr(struct ustream *s, int bytes) +{ + instance_stdio(s, LOG_ERR, + container_of(s, struct service_instance, stderr.stream)); +} + +static void instance_timeout(struct uloop_timeout *t) { struct service_instance *in; @@ -471,6 +568,12 @@ instance_config_parse(struct service_instance *in) } } + if (tb[INSTANCE_ATTR_STDOUT] && blobmsg_get_bool(tb[INSTANCE_ATTR_STDOUT])) + in->stdout.fd.fd = -1; + + if (tb[INSTANCE_ATTR_STDERR] && blobmsg_get_bool(tb[INSTANCE_ATTR_STDERR])) + in->stderr.fd.fd = -1; + instance_fill_any(&in->data, tb[INSTANCE_ATTR_DATA]); if (!instance_fill_array(&in->env, tb[INSTANCE_ATTR_ENV], NULL, false)) @@ -546,6 +649,16 @@ instance_update(struct service_instance *in, struct service_instance *in_new) void instance_free(struct service_instance *in) { + if (in->stdout.fd.fd > -1) { + ustream_free(&in->stdout.stream); + close(in->stdout.fd.fd); + } + + if (in->stderr.fd.fd > -1) { + ustream_free(&in->stderr.stream); + close(in->stderr.fd.fd); + } + uloop_process_delete(&in->proc); uloop_timeout_cancel(&in->timeout); trigger_del(in); @@ -565,6 +678,14 @@ instance_init(struct service_instance *in, struct service *s, struct blob_attr * in->timeout.cb = instance_timeout; in->proc.cb = instance_exit; + in->stdout.fd.fd = -2; + in->stdout.stream.string_data = true; + in->stdout.stream.notify_read = instance_stdout; + + in->stderr.fd.fd = -2; + in->stderr.stream.string_data = true; + in->stderr.stream.notify_read = instance_stderr; + blobmsg_list_init(&in->netdev, struct instance_netdev, node, instance_netdev_cmp); blobmsg_list_init(&in->file, struct instance_file, node, instance_file_cmp); blobmsg_list_simple_init(&in->env); diff --git a/service/instance.h b/service/instance.h index f76e795..56ce797 100644 --- a/service/instance.h +++ b/service/instance.h @@ -17,6 +17,7 @@ #include <libubox/vlist.h> #include <libubox/uloop.h> +#include <libubox/ustream.h> #include "../utils/utils.h" #define RESPAWN_ERROR (5 * 60) @@ -45,6 +46,8 @@ struct service_instance { struct blob_attr *config; struct uloop_process proc; struct uloop_timeout timeout; + struct ustream_fd stdout; + struct ustream_fd stderr; struct blob_attr *command; struct blob_attr *trigger; |