summaryrefslogtreecommitdiffstats
path: root/service
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2015-02-26 12:27:39 +0100
committerJo-Philipp Wich <jow@openwrt.org>2015-02-26 14:34:18 +0100
commit9851e517f1c3e55228e2fdde913c9cf0b87a4bc7 (patch)
tree9c85993f55b0d39892791ba833428fddb506b214 /service
parent4bccbfa967d756b8c84a62ea4752e936d8545a73 (diff)
downloadunitd-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.c141
-rw-r--r--service/instance.h3
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;