From 85f136b5d09168a7e4fd2ad27ef81dbe2d356c07 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 01:53:15 +0100 Subject: [PATCH 01/16] add non-failing close() variant --- util.c | 8 ++++++++ util.h | 1 + 2 files changed, 9 insertions(+) diff --git a/util.c b/util.c index 56f53eafd..38ed74fbc 100644 --- a/util.c +++ b/util.c @@ -97,6 +97,14 @@ int close_nointr(int fd) { } } +void close_nointr_nofail(int fd) { + + /* like close_nointr() but cannot fail, and guarantees errno + * is unchanged */ + + assert_se(close_nointr(fd) == 0); +} + int parse_boolean(const char *v) { assert(v); diff --git a/util.h b/util.h index 9aceaef47..c3d3aad7b 100644 --- a/util.h +++ b/util.h @@ -61,6 +61,7 @@ bool endswith(const char *s, const char *postfix); bool startswith(const char *s, const char *prefix); int close_nointr(int fd); +void close_nointr_nofail(int fd); int parse_boolean(const char *v); -- 2.30.2 From 431c32bf7976add2297c71f482cb2669765ed616 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 01:53:39 +0100 Subject: [PATCH 02/16] when resetting signal handlers, set them to SA_RESTART --- util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/util.c b/util.c index 38ed74fbc..654b93d79 100644 --- a/util.c +++ b/util.c @@ -488,6 +488,7 @@ int reset_all_signal_handlers(void) { zero(sa); sa.sa_handler = SIG_DFL; + sa.sa_flags = SA_RESTART; /* On Linux the first two RT signals are reserved by * glibc, and sigaction() will return EINVAL for them. */ -- 2.30.2 From d6ea93e31d96c67366feee0413a3c307fcffea2b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 01:59:41 +0100 Subject: [PATCH 03/16] when shortcutting states do not skip state transitions --- service.c | 55 ++++++++++++++++++++++++++++++------------------------- socket.c | 40 +++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/service.c b/service.c index 2001b9f4d..1cbfb3dce 100644 --- a/service.c +++ b/service.c @@ -30,7 +30,7 @@ static const char* const state_string_table[_SERVICE_STATE_MAX] = { [SERVICE_DEAD] = "dead", [SERVICE_START_PRE] = "start-pre", [SERVICE_START] = "start", - [SERVICE_START_POST] = "post", + [SERVICE_START_POST] = "start-post", [SERVICE_RUNNING] = "running", [SERVICE_RELOAD] = "reload", [SERVICE_STOP] = "stop", @@ -330,7 +330,7 @@ static void service_set_state(Service *s, ServiceState state) { state == SERVICE_AUTO_RESTART) service_notify_sockets(s); - log_debug("%s changing %s → %s", unit_id(UNIT(s)), state_string_table[old_state], state_string_table[state]); + log_debug("%s changed %s → %s", unit_id(UNIT(s)), state_string_table[old_state], state_string_table[state]); unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]); } @@ -471,13 +471,14 @@ static void service_enter_stop_post(Service *s, bool success) { if (!success) s->failure = true; - if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) { - + if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0) goto fail; - service_set_state(s, SERVICE_STOP_POST); - } else + + service_set_state(s, SERVICE_STOP_POST); + + if (!s->control_command) service_enter_dead(s, true, true); return; @@ -518,9 +519,11 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) { if (r < 0) goto fail; + } - service_set_state(s, state); - } else + service_set_state(s, state); + + if (s->main_pid <= 0 && s->control_pid <= 0) service_enter_dead(s, true, true); return; @@ -544,13 +547,13 @@ static void service_enter_stop(Service *s, bool success) { if (!success) s->failure = true; - if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) { - + if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0) goto fail; - service_set_state(s, SERVICE_STOP); - } else + service_set_state(s, SERVICE_STOP); + + if (!s->control_command) service_enter_signal(s, SERVICE_STOP_SIGTERM, true); return; @@ -564,13 +567,14 @@ static void service_enter_start_post(Service *s) { int r; assert(s); - if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) { - + if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0) goto fail; - service_set_state(s, SERVICE_START_POST); - } else + + service_set_state(s, SERVICE_START_POST); + + if (!s->control_command) service_set_state(s, SERVICE_RUNNING); return; @@ -592,6 +596,8 @@ static void service_enter_start(Service *s) { if ((r = service_spawn(s, s->exec_command[SERVICE_EXEC_START], s->type == SERVICE_FORKING, true, &pid)) < 0) goto fail; + service_set_state(s, SERVICE_START); + if (s->type == SERVICE_SIMPLE) { /* For simple services we immediately start * the START_POST binaries. */ @@ -607,7 +613,6 @@ static void service_enter_start(Service *s) { s->control_pid = pid; s->control_command = s->exec_command[SERVICE_EXEC_START]; - service_set_state(s, SERVICE_START); } else assert_not_reached("Unknown service type"); @@ -623,13 +628,13 @@ static void service_enter_start_pre(Service *s) { assert(s); - if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) { - + if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0) goto fail; - service_set_state(s, SERVICE_START_PRE); - } else + service_set_state(s, SERVICE_START_PRE); + + if (!s->control_command) service_enter_start(s); return; @@ -661,13 +666,13 @@ static void service_enter_reload(Service *s) { assert(s); - if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) { - + if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) if ((r = service_spawn(s, s->control_command, true, false, &s->control_pid)) < 0) goto fail; - service_set_state(s, SERVICE_RELOAD); - } else + service_set_state(s, SERVICE_RELOAD); + + if (!s->control_command) service_set_state(s, SERVICE_RUNNING); return; diff --git a/socket.c b/socket.c index 68a4d812d..7bcd11273 100644 --- a/socket.c +++ b/socket.c @@ -340,7 +340,7 @@ static void socket_set_state(Socket *s, SocketState state) { if (state != SOCKET_LISTENING) socket_unwatch_fds(s); - log_debug("%s changing %s → %s", unit_id(UNIT(s)), state_string_table[old_state], state_string_table[state]); + log_debug("%s changed %s → %s", unit_id(UNIT(s)), state_string_table[old_state], state_string_table[state]); unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]); } @@ -393,13 +393,13 @@ static void socket_enter_stop_post(Socket *s, bool success) { if (!success) s->failure = true; - if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) { - + if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) goto fail; - socket_set_state(s, SOCKET_STOP_POST); - } else + socket_set_state(s, SOCKET_STOP_POST); + + if (!s->control_command) socket_enter_dead(s, true); return; @@ -426,9 +426,11 @@ static void socket_enter_signal(Socket *s, SocketState state, bool success) { r = -errno; goto fail; } + } - socket_set_state(s, state); - } else + socket_set_state(s, state); + + if (s->control_pid <= 0) socket_enter_dead(s, true); return; @@ -449,13 +451,13 @@ static void socket_enter_stop_pre(Socket *s, bool success) { if (!success) s->failure = true; - if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) { - + if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) goto fail; - socket_set_state(s, SOCKET_STOP_PRE); - } else + socket_set_state(s, SOCKET_STOP_PRE); + + if (!s->control_command) socket_enter_stop_post(s, true); return; @@ -490,15 +492,15 @@ static void socket_enter_start_post(Socket *s) { goto fail; } - if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) { - + if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) { log_warning("%s failed to run start-post executable: %s", unit_id(UNIT(s)), strerror(-r)); goto fail; } - socket_set_state(s, SOCKET_START_POST); - } else + socket_set_state(s, SOCKET_START_POST); + + if (!s->control_command) socket_enter_listening(s); return; @@ -511,13 +513,13 @@ static void socket_enter_start_pre(Socket *s) { int r; assert(s); - if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) { - + if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) if ((r = socket_spawn(s, s->control_command, true, &s->control_pid)) < 0) goto fail; - socket_set_state(s, SOCKET_START_PRE); - } else + socket_set_state(s, SOCKET_START_PRE); + + if (!s->control_command) socket_enter_start_post(s); return; -- 2.30.2 From fdf88f5f3383dc4fdd7358b954c6b79e4fe0791b Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 02:00:07 +0100 Subject: [PATCH 04/16] unit_merge() needs a proper review --- unit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unit.c b/unit.c index e8d61c853..88615319d 100644 --- a/unit.c +++ b/unit.c @@ -243,7 +243,8 @@ static int ensure_merge(Set **s, Set *other) { return 0; } -/* FIXME: Does not rollback on failure! */ +/* FIXME: Does not rollback on failure! Needs to fix special unit + * pointers. Needs to merge names and dependencies properly.*/ int unit_merge(Unit *u, Unit *other) { int r; UnitDependency d; -- 2.30.2 From ba3895027eaba2814d980f4c02420ca553e8c39c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 02:00:33 +0100 Subject: [PATCH 05/16] minor cleanup --- target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target.c b/target.c index 6c84908e9..748dfeef1 100644 --- a/target.c +++ b/target.c @@ -33,7 +33,7 @@ static void target_set_state(Target *t, TargetState state) { old_state = t->state; t->state = state; - log_debug("%s changing %s → %s", unit_id(UNIT(t)), state_string_table[old_state], state_string_table[state]); + log_debug("%s changed %s → %s", unit_id(UNIT(t)), state_string_table[old_state], state_string_table[state]); unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state]); } -- 2.30.2 From ce578209aa4e061aa38d3a4727612bb388307bf9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 02:01:15 +0100 Subject: [PATCH 06/16] add infrastructure for special units --- manager.c | 75 +++++++++++++++++++++++++++++++++++++++++-------------- manager.h | 9 +++++++ 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/manager.c b/manager.c index cd97e67da..a32755ced 100644 --- a/manager.c +++ b/manager.c @@ -17,11 +17,63 @@ #include "log.h" #include "util.h" -Manager* manager_new(void) { - Manager *m; +static const char * const special_table[_SPECIAL_UNIT_MAX] = { + [SPECIAL_SYSLOG_SERVICE] = "syslog.service", + [SPECIAL_DBUS_SERVICE] = "messagebus.service", + [SPECIAL_LOGGER_SOCKET] = "systemd-logger.socket" +}; + +static int manager_setup_signals(Manager *m) { sigset_t mask; struct epoll_event ev; + assert(m); + + assert_se(reset_all_signal_handlers() == 0); + + assert_se(sigemptyset(&mask) == 0); + assert_se(sigaddset(&mask, SIGCHLD) == 0); + assert_se(sigaddset(&mask, SIGINT) == 0); /* Kernel sends us this on control-alt-del */ + assert_se(sigaddset(&mask, SIGWINCH) == 0); /* Kernel sends us this on kbrequest (alt-arrowup) */ + assert_se(sigaddset(&mask, SIGTERM) == 0); + assert_se(sigaddset(&mask, SIGHUP) == 0); + assert_se(sigaddset(&mask, SIGUSR1) == 0); + assert_se(sigaddset(&mask, SIGUSR2) == 0); + assert_se(sigaddset(&mask, SIGPIPE) == 0); + assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); + + m->signal_watch.type = WATCH_SIGNAL_FD; + if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) + return -errno; + + zero(ev); + ev.events = EPOLLIN; + ev.data.ptr = &m->signal_watch; + + if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0) + return -errno; + + return 0; +} + +static int manager_load_special_units(Manager *m) { + SpecialUnit c; + int r; + + assert(m); + + /* Loads all 'special' units, so that we have easy access to them later */ + + for (c = 0; c < _SPECIAL_UNIT_MAX; c++) + if ((r = manager_load_unit(m, special_table[c], m->special_units+c)) < 0) + return r; + + return 0; +}; + +Manager* manager_new(void) { + Manager *m; + if (!(m = new0(Manager, 1))) return NULL; @@ -42,25 +94,10 @@ Manager* manager_new(void) { if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0) goto fail; - assert_se(reset_all_signal_handlers() == 0); - - assert_se(sigemptyset(&mask) == 0); - assert_se(sigaddset(&mask, SIGCHLD) == 0); - assert_se(sigaddset(&mask, SIGINT) == 0); - assert_se(sigaddset(&mask, SIGTERM) == 0); - assert_se(sigaddset(&mask, SIGWINCH) == 0); - assert_se(sigaddset(&mask, SIGHUP) == 0); - assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); - - m->signal_watch.type = WATCH_SIGNAL_FD; - if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) + if (manager_setup_signals(m) < 0) goto fail; - zero(ev); - ev.events = EPOLLIN; - ev.data.ptr = &m->signal_watch; - - if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0) + if (manager_load_special_units(m) < 0) goto fail; return m; diff --git a/manager.h b/manager.h index 303201b74..0c923fcc7 100644 --- a/manager.h +++ b/manager.h @@ -30,6 +30,13 @@ struct Watch { #include "list.h" #include "set.h" +typedef enum SpecialUnit { + SPECIAL_SYSLOG_SERVICE, + SPECIAL_DBUS_SERVICE, + SPECIAL_LOGGER_SOCKET, + _SPECIAL_UNIT_MAX +} SpecialUnit; + struct Manager { uint32_t current_job_id; @@ -59,6 +66,8 @@ struct Manager { int epoll_fd; Watch signal_watch; + + Unit *special_units[_SPECIAL_UNIT_MAX]; /* some special units */ }; Manager* manager_new(void); -- 2.30.2 From 071830ff32351c19343ff1f0343c13d5c2b69250 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 02:06:20 +0100 Subject: [PATCH 07/16] implement proper logging for services --- execute.c | 119 +++++++++++++++++++++++++ execute.h | 20 ++++- fixme | 2 + load-fragment.c | 171 +++++++++++++++++++++++++++++++++++- test1/exec-demo.service | 4 +- test1/systemd-logger.socket | 2 +- 6 files changed, 312 insertions(+), 6 deletions(-) diff --git a/execute.c b/execute.c index 1ca91fddd..ccf951a25 100644 --- a/execute.c +++ b/execute.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "execute.h" #include "strv.h" @@ -139,6 +141,112 @@ static int flags_fds(int fds[], unsigned n_fds) { return 0; } +static int replace_null_fd(int fd, int flags) { + int nfd; + assert(fd >= 0); + + close_nointr(fd); + + if ((nfd = open("/dev/null", flags|O_NOCTTY)) < 0) + return -errno; + + if (nfd != fd) { + close_nointr_nofail(nfd); + return -EIO; + } + + return 0; +} + +static int setup_output(const ExecContext *context, const char *ident) { + int r; + + assert(context); + + switch (context->output) { + + case EXEC_CONSOLE: + return 0; + + case EXEC_NULL: + + if ((r = replace_null_fd(STDIN_FILENO, O_RDONLY)) < 0 || + (r = replace_null_fd(STDOUT_FILENO, O_WRONLY)) < 0 || + (r = replace_null_fd(STDERR_FILENO, O_WRONLY)) < 0) + return r; + + return 0; + + case EXEC_KERNEL: + case EXEC_SYSLOG: { + + int fd; + union { + struct sockaddr sa; + struct sockaddr_un un; + } sa; + + if ((r = replace_null_fd(STDIN_FILENO, O_RDONLY)) < 0) + return r; + + close_nointr(STDOUT_FILENO); + close_nointr(STDERR_FILENO); + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return -errno; + + if (fd != STDOUT_FILENO) { + close_nointr_nofail(fd); + return -EIO; + } + + zero(sa); + sa.sa.sa_family = AF_UNIX; + strncpy(sa.un.sun_path+1, LOGGER_SOCKET, sizeof(sa.un.sun_path)-1); + + if (connect(fd, &sa.sa, sizeof(sa)) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if (shutdown(fd, SHUT_RD) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if ((fd = dup(fd)) < 0) { + close_nointr_nofail(fd); + return -errno; + } + + if (fd != STDERR_FILENO) { + close_nointr_nofail(fd); + return -EIO; + } + + /* We speak a very simple protocol between log server + * and client: one line for the log destination (kmsg + * or syslog), followed by the priority field, + * followed by the process name. Since we replaced + * stdin/stderr we simple use stdio to write to + * it. Note that we use stderr, to minimize buffer + * flushing issues. */ + + fprintf(stderr, + "%s\n" + "%i\n" + "%s\n", + context->output == EXEC_KERNEL ? "kmsg" : "syslog", + context->syslog_priority, + context->syslog_identifier ? context->syslog_identifier : ident); + + return 0; + } + } + + assert_not_reached("Unknown logging type"); +} + int exec_spawn(const ExecCommand *command, const ExecContext *context, int *fds, unsigned n_fds, pid_t *ret) { pid_t pid; @@ -173,6 +281,11 @@ int exec_spawn(const ExecCommand *command, const ExecContext *context, int *fds, goto fail; } + if (setup_output(context, file_name_from_path(command->path)) < 0) { + r = EXIT_OUTPUT; + goto fail; + } + snprintf(t, sizeof(t), "%i", context->oom_adjust); char_array_0(t); @@ -251,6 +364,9 @@ void exec_context_init(ExecContext *c) { cap_clear(c->capabilities); c->oom_adjust = 0; c->nice = 0; + + c->output = 0; + c->syslog_priority = LOG_DAEMON|LOG_INFO; } void exec_context_done(ExecContext *c) { @@ -269,6 +385,9 @@ void exec_context_done(ExecContext *c) { free(c->directory); c->directory = NULL; + free(c->syslog_identifier); + c->syslog_identifier = NULL; + free(c->user); c->user = NULL; diff --git a/execute.h b/execute.h index b7dbe6849..3283e1f81 100644 --- a/execute.h +++ b/execute.h @@ -16,6 +16,16 @@ typedef struct ExecContext ExecContext; #include "list.h" #include "util.h" +/* Abstract namespace! */ +#define LOGGER_SOCKET "/systemd/logger" + +typedef enum ExecOutput { + EXEC_CONSOLE, + EXEC_NULL, + EXEC_SYSLOG, + EXEC_KERNEL +} ExecOutput; + struct ExecStatus { pid_t pid; usec_t timestamp; @@ -33,11 +43,16 @@ struct ExecCommand { struct ExecContext { char **environment; mode_t umask; - struct rlimit *rlimit[RLIMIT_NLIMITS]; + struct rlimit *rlimit[RLIMIT_NLIMITS]; /* FIXME: load-fragment parser missing */ int oom_adjust; int nice; char *directory; + ExecOutput output; + int syslog_priority; + char *syslog_identifier; + + /* FIXME: all privs related settings need parser and enforcer */ cap_t capabilities; bool capabilities_set:1; @@ -72,7 +87,8 @@ typedef enum ExitStatus { EXIT_MEMORY, EXIT_LIMITS, EXIT_OOM_ADJUST, - EXIT_SIGNAL_MASK + EXIT_SIGNAL_MASK, + EXIT_OUTPUT } ExitStatus; int exec_spawn(const ExecCommand *command, const ExecContext *context, int *fds, unsigned n_fds, pid_t *ret); diff --git a/fixme b/fixme index 800801c4e..4e82c92ed 100644 --- a/fixme +++ b/fixme @@ -42,3 +42,5 @@ - rate limit startups - automatically delete stale unix sockets + +- .socket needs to be notified not only by .service state changes, but also unsuccessful start jobs diff --git a/load-fragment.c b/load-fragment.c index 2df5c04f7..2757506ab 100644 --- a/load-fragment.c +++ b/load-fragment.c @@ -479,8 +479,151 @@ int config_parse_bindtodevice( return 0; } -#define FOLLOW_MAX 8 +int config_parse_output( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + const char *rvalue, + void *data, + void *userdata) { + + ExecOutput *o = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (streq(rvalue, "syslog")) + *o = EXEC_SYSLOG; + else if (streq(rvalue, "null")) + *o = EXEC_NULL; + else if (streq(rvalue, "syslog")) + *o = EXEC_SYSLOG; + else if (streq(rvalue, "kernel")) + *o = EXEC_KERNEL; + else { + log_error("[%s:%u] Failed to parse log output: %s", filename, line, rvalue); + return -EBADMSG; + } + + return 0; +} +int config_parse_facility( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + const char *rvalue, + void *data, + void *userdata) { + + static const char * const table[LOG_NFACILITIES] = { + [LOG_FAC(LOG_KERN)] = "kern", + [LOG_FAC(LOG_USER)] = "user", + [LOG_FAC(LOG_MAIL)] = "mail", + [LOG_FAC(LOG_DAEMON)] = "daemon", + [LOG_FAC(LOG_AUTH)] = "auth", + [LOG_FAC(LOG_SYSLOG)] = "syslog", + [LOG_FAC(LOG_LPR)] = "lpr", + [LOG_FAC(LOG_NEWS)] = "news", + [LOG_FAC(LOG_UUCP)] = "uucp", + [LOG_FAC(LOG_CRON)] = "cron", + [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", + [LOG_FAC(LOG_FTP)] = "ftp", + [LOG_FAC(LOG_LOCAL0)] = "local0", + [LOG_FAC(LOG_LOCAL1)] = "local1", + [LOG_FAC(LOG_LOCAL2)] = "local2", + [LOG_FAC(LOG_LOCAL3)] = "local3", + [LOG_FAC(LOG_LOCAL4)] = "local4", + [LOG_FAC(LOG_LOCAL5)] = "local5", + [LOG_FAC(LOG_LOCAL6)] = "local6", + [LOG_FAC(LOG_LOCAL7)] = "local7" + }; + + ExecOutput *o = data; + int i; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + for (i = 0; i < (int) ELEMENTSOF(table); i++) + if (streq(rvalue, table[i])) { + *o = LOG_MAKEPRI(i, LOG_PRI(*o)); + break; + } + + if (i >= (int) ELEMENTSOF(table)) { + + /* Second try, let's see if this is a number. */ + if (safe_atoi(rvalue, &i) >= 0 && + i >= 0 && + i < (int) ELEMENTSOF(table)) + *o = LOG_MAKEPRI(i, LOG_PRI(*o)); + else { + log_error("[%s:%u] Failed to parse log output: %s", filename, line, rvalue); + return -EBADMSG; + } + } + + return 0; +} + +int config_parse_level( + const char *filename, + unsigned line, + const char *section, + const char *lvalue, + const char *rvalue, + void *data, + void *userdata) { + + static const char * const table[LOG_DEBUG+1] = { + [LOG_EMERG] = "emerg", + [LOG_ALERT] = "alert", + [LOG_CRIT] = "crit", + [LOG_ERR] = "err", + [LOG_WARNING] = "warning", + [LOG_NOTICE] = "notice", + [LOG_INFO] = "info", + [LOG_DEBUG] = "debug" + }; + + ExecOutput *o = data; + int i; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + for (i = 0; i < (int) ELEMENTSOF(table); i++) + if (streq(rvalue, table[i])) { + *o = LOG_MAKEPRI(LOG_FAC(*o), i); + break; + } + + if (i >= LOG_NFACILITIES) { + + /* Second try, let's see if this is a number. */ + if (safe_atoi(rvalue, &i) >= 0 && + i >= 0 && + i < (int) ELEMENTSOF(table)) + *o = LOG_MAKEPRI(LOG_FAC(*o), i); + else { + log_error("[%s:%u] Failed to parse log output: %s", filename, line, rvalue); + return -EBADMSG; + } + } + + return 0; +} + +#define FOLLOW_MAX 8 static int open_follow(char **filename, FILE **_f, Set *names, char **_id) { unsigned c = 0; @@ -569,7 +712,11 @@ static int load_from_path(Unit *u, const char *path) { { "Nice", config_parse_nice, &(context).nice, section }, \ { "OOMAdjust", config_parse_oom_adjust, &(context).oom_adjust, section }, \ { "UMask", config_parse_umask, &(context).umask, section }, \ - { "Environment", config_parse_strv, &(context).environment, section } + { "Environment", config_parse_strv, &(context).environment, section }, \ + { "Output", config_parse_output, &(context).output, section }, \ + { "SyslogIdentifier", config_parse_string, &(context).syslog_identifier, section }, \ + { "SyslogFacility", config_parse_facility, &(context).syslog_priority, section }, \ + { "SyslogLevel", config_parse_level, &(context).syslog_priority, section } const ConfigItem items[] = { { "Names", config_parse_names, u, "Meta" }, @@ -678,6 +825,7 @@ finish: int unit_load_fragment(Unit *u) { int r = -ENOENT; + ExecContext *c; assert(u); assert(u->meta.load_state == UNIT_STUB); @@ -694,5 +842,24 @@ int unit_load_fragment(Unit *u) { return r; } + if (u->meta.type == UNIT_SOCKET) + c = &u->socket.exec_context; + else if (u->meta.type == UNIT_SERVICE) + c = &u->service.exec_context; + else + c = NULL; + + if (r >= 0 && c && + (c->output == EXEC_KERNEL || c->output == EXEC_SYSLOG)) { + /* If syslog or kernel logging is requested, make sure + * our own logging daemon is run first. */ + + if ((r = unit_add_dependency(u, UNIT_AFTER, u->meta.manager->special_units[SPECIAL_LOGGER_SOCKET])) < 0) + return r; + + if ((r = unit_add_dependency(u, UNIT_REQUIRES, u->meta.manager->special_units[SPECIAL_LOGGER_SOCKET])) < 0) + return r; + } + return r; } diff --git a/test1/exec-demo.service b/test1/exec-demo.service index ea40b1fec..b772518e3 100644 --- a/test1/exec-demo.service +++ b/test1/exec-demo.service @@ -2,4 +2,6 @@ Description=Simple Execution Demo [Service] -ExecStart=/bin/ls +ExecStart=/bin/cat /etc/hosts +Type=simple +Output=syslog diff --git a/test1/systemd-logger.socket b/test1/systemd-logger.socket index a013067ab..ae0c81a91 100644 --- a/test1/systemd-logger.socket +++ b/test1/systemd-logger.socket @@ -2,6 +2,6 @@ Description=systemd Logging Socket [Socket] -ExecStartPre=/bin/rm /tmp/systemd-logger +ExecStartPre=/bin/rm -f /tmp/systemd-logger ListenStream==/systemd/logger ListenStream=/tmp/systemd-logger -- 2.30.2 From 98b5b2986fa1b85fd2d2e80f867f1647b4e4e3b5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 02:43:52 +0100 Subject: [PATCH 08/16] add more special units --- manager.c | 4 +++- manager.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/manager.c b/manager.c index a32755ced..8ee560c55 100644 --- a/manager.c +++ b/manager.c @@ -20,7 +20,9 @@ static const char * const special_table[_SPECIAL_UNIT_MAX] = { [SPECIAL_SYSLOG_SERVICE] = "syslog.service", [SPECIAL_DBUS_SERVICE] = "messagebus.service", - [SPECIAL_LOGGER_SOCKET] = "systemd-logger.socket" + [SPECIAL_LOGGER_SOCKET] = "systemd-logger.socket", + [SPECIAL_KBREQUEST_TARGET] = "kbrequest.target", + [SPECIAL_CTRL_ALT_DEL_TARGET] = "ctrl-alt-del.target" }; static int manager_setup_signals(Manager *m) { diff --git a/manager.h b/manager.h index 0c923fcc7..a00a9b9cc 100644 --- a/manager.h +++ b/manager.h @@ -34,6 +34,8 @@ typedef enum SpecialUnit { SPECIAL_SYSLOG_SERVICE, SPECIAL_DBUS_SERVICE, SPECIAL_LOGGER_SOCKET, + SPECIAL_CTRL_ALT_DEL_TARGET, + SPECIAL_KBREQUEST_TARGET, _SPECIAL_UNIT_MAX } SpecialUnit; -- 2.30.2 From d46de8a1a249e179687361dcaeba27e1c586253a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 02:44:47 +0100 Subject: [PATCH 09/16] rework config file load logic --- automount.c | 2 +- load-fragment.c | 12 +++++++----- main.c | 6 +++--- mount.c | 2 +- service.c | 15 ++++++++------- socket.c | 5 ++++- target.c | 16 +++++++++++++++- timer.c | 17 ++++++++++++++++- unit.c | 6 ++++-- 9 files changed, 59 insertions(+), 22 deletions(-) diff --git a/automount.c b/automount.c index 7b397c9b9..eb9c3d3c1 100644 --- a/automount.c +++ b/automount.c @@ -17,7 +17,7 @@ static int automount_init(Unit *u) { exec_context_init(&a->exec_context); /* Load a .automount file */ - if ((r = unit_load_fragment(u)) < 0 && errno != -ENOENT) + if ((r = unit_load_fragment(u)) < 0) return r; /* Load entry from /etc/fstab */ diff --git a/load-fragment.c b/load-fragment.c index 2757506ab..9273fc8b8 100644 --- a/load-fragment.c +++ b/load-fragment.c @@ -824,7 +824,7 @@ finish: } int unit_load_fragment(Unit *u) { - int r = -ENOENT; + int r = 0; ExecContext *c; assert(u); @@ -851,14 +851,16 @@ int unit_load_fragment(Unit *u) { if (r >= 0 && c && (c->output == EXEC_KERNEL || c->output == EXEC_SYSLOG)) { + int k; + /* If syslog or kernel logging is requested, make sure * our own logging daemon is run first. */ - if ((r = unit_add_dependency(u, UNIT_AFTER, u->meta.manager->special_units[SPECIAL_LOGGER_SOCKET])) < 0) - return r; + if ((k = unit_add_dependency(u, UNIT_AFTER, u->meta.manager->special_units[SPECIAL_LOGGER_SOCKET])) < 0) + return k; - if ((r = unit_add_dependency(u, UNIT_REQUIRES, u->meta.manager->special_units[SPECIAL_LOGGER_SOCKET])) < 0) - return r; + if ((k = unit_add_dependency(u, UNIT_REQUIRES, u->meta.manager->special_units[SPECIAL_LOGGER_SOCKET])) < 0) + return k; } return r; diff --git a/main.c b/main.c index 624a73e17..2486f0629 100644 --- a/main.c +++ b/main.c @@ -26,14 +26,14 @@ int main(int argc, char *argv[]) { goto finish; } + printf("→ By units:\n"); + manager_dump_units(m, stdout, "\t"); + if ((r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &job)) < 0) { log_error("Failed to start default target: %s", strerror(-r)); goto finish; } - printf("→ By units:\n"); - manager_dump_units(m, stdout, "\t"); - printf("→ By jobs:\n"); manager_dump_jobs(m, stdout, "\t"); diff --git a/mount.c b/mount.c index f4a6d6f24..7a1ec087e 100644 --- a/mount.c +++ b/mount.c @@ -15,7 +15,7 @@ static int mount_init(Unit *u) { assert(m); /* Load a .mount file */ - if ((r = unit_load_fragment(u)) < 0 && errno != -ENOENT) + if ((r = unit_load_fragment(u)) < 0) return r; /* Load entry from /etc/fstab */ diff --git a/service.c b/service.c index 1cbfb3dce..70299dd06 100644 --- a/service.c +++ b/service.c @@ -101,17 +101,18 @@ static int service_init(Unit *u) { s->state = SERVICE_DEAD; /* Load a .service file */ - r = unit_load_fragment(u); - - /* Load a classic init script as a fallback */ - if (r == -ENOENT) - r = service_load_sysv(s); - - if (r < 0) { + if ((r = unit_load_fragment(u)) < 0) { service_done(u); return r; } + /* Load a classic init script as a fallback, if we couldn*t find anything */ + if (r == 0) + if ((r = service_load_sysv(s)) <= 0) { + service_done(u); + return r < 0 ? r : -ENOENT; + } + /* Load dropin directory data */ if ((r = unit_load_dropin(u)) < 0) { service_done(u); diff --git a/socket.c b/socket.c index 7bcd11273..926a0fb64 100644 --- a/socket.c +++ b/socket.c @@ -88,8 +88,11 @@ static int socket_init(Unit *u) { s->timeout_usec = DEFAULT_TIMEOUT_USEC; exec_context_init(&s->exec_context); - if ((r = unit_load_fragment_and_dropin(u)) < 0) + if ((r = unit_load_fragment_and_dropin(u)) <= 0) { + if (r == 0) + r = -ENOENT; goto fail; + } if (!(t = unit_name_change_suffix(unit_id(u), ".service"))) { r = -ENOMEM; diff --git a/target.c b/target.c index 748dfeef1..03f092e35 100644 --- a/target.c +++ b/target.c @@ -1,5 +1,7 @@ /*-*- Mode: C; c-basic-offset: 8 -*-*/ +#include + #include "unit.h" #include "target.h" #include "load-fragment.h" @@ -15,6 +17,18 @@ static const char* const state_string_table[_TARGET_STATE_MAX] = { [TARGET_ACTIVE] = "active" }; +static int target_init(Unit *u) { + int r; + assert(u); + + /* Make sure this config file actually exists */ + + if ((r = unit_load_fragment_and_dropin(u)) <= 0) + return r < 0 ? r : -ENOENT; + + return 0; +} + static void target_dump(Unit *u, FILE *f, const char *prefix) { Target *t = TARGET(u); @@ -67,7 +81,7 @@ static UnitActiveState target_active_state(Unit *u) { const UnitVTable target_vtable = { .suffix = ".target", - .init = unit_load_fragment_and_dropin, + .init = target_init, .dump = target_dump, diff --git a/timer.c b/timer.c index 29346204f..c3ebba0d1 100644 --- a/timer.c +++ b/timer.c @@ -1,5 +1,7 @@ /*-*- Mode: C; c-basic-offset: 8 -*-*/ +#include + #include "unit.h" #include "timer.h" @@ -9,6 +11,19 @@ static void timer_done(Unit *u) { assert(t); } +static int timer_init(Unit *u) { + int r; + + assert(u); + + /* Make sure this config file actually exists */ + + if ((r = unit_load_fragment_and_dropin(u)) <= 0) + return r < 0 ? r : -ENOENT; + + return 0; +} + static UnitActiveState timer_active_state(Unit *u) { static const UnitActiveState table[_TIMER_STATE_MAX] = { @@ -23,7 +38,7 @@ static UnitActiveState timer_active_state(Unit *u) { const UnitVTable timer_vtable = { .suffix = ".timer", - .init = unit_load_fragment_and_dropin, + .init = timer_init, .done = timer_done, .active_state = timer_active_state diff --git a/unit.c b/unit.c index 88615319d..407612092 100644 --- a/unit.c +++ b/unit.c @@ -372,7 +372,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { /* Common implementation for multiple backends */ int unit_load_fragment_and_dropin(Unit *u) { - int r; + int r, ret; assert(u); @@ -380,11 +380,13 @@ int unit_load_fragment_and_dropin(Unit *u) { if ((r = unit_load_fragment(u)) < 0) return r; + ret = r > 0; + /* Load drop-in directory data */ if ((r = unit_load_dropin(u)) < 0) return r; - return 0; + return ret; } int unit_load(Unit *u) { -- 2.30.2 From fb33a393e21a15ce3b4ac8c16d947fd9b6e77206 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 02:53:56 +0100 Subject: [PATCH 10/16] set nice/oom_adjust only when asked for --- execute.c | 42 ++++++++++++++++++++++++++---------------- execute.h | 5 ++++- load-fragment.c | 18 ++++++++++++------ 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/execute.c b/execute.c index ccf951a25..cbefadfca 100644 --- a/execute.c +++ b/execute.c @@ -263,7 +263,6 @@ int exec_spawn(const ExecCommand *command, const ExecContext *context, int *fds, if (pid == 0) { char **e, **f = NULL; int i, r; - char t[16]; sigset_t ss; /* child */ @@ -286,19 +285,24 @@ int exec_spawn(const ExecCommand *command, const ExecContext *context, int *fds, goto fail; } - snprintf(t, sizeof(t), "%i", context->oom_adjust); - char_array_0(t); + if (context->oom_adjust_set) { + char t[16]; - if (write_one_line_file("/proc/self/oom_adj", t) < 0) { - r = EXIT_OOM_ADJUST; - goto fail; - } + snprintf(t, sizeof(t), "%i", context->oom_adjust); + char_array_0(t); - if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) { - r = EXIT_NICE; - goto fail; + if (write_one_line_file("/proc/self/oom_adj", t) < 0) { + r = EXIT_OOM_ADJUST; + goto fail; + } } + if (context->nice_set) + if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) { + r = EXIT_NICE; + goto fail; + } + if (close_fds(fds, n_fds) < 0 || shift_fds(fds, n_fds) < 0 || flags_fds(fds, n_fds) < 0) { @@ -428,13 +432,19 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { fprintf(f, "%sUmask: %04o\n" - "%sDirectory: %s\n" - "%sNice: %i\n" - "%sOOMAdjust: %i\n", + "%sDirectory: %s\n", prefix, c->umask, - prefix, c->directory ? c->directory : "/", - prefix, c->nice, - prefix, c->oom_adjust); + prefix, c->directory ? c->directory : "/"); + + if (c->nice_set) + fprintf(f, + "%sNice: %i\n", + prefix, c->nice); + + if (c->oom_adjust_set) + fprintf(f, + "%sOOMAdjust: %i\n", + prefix, c->oom_adjust); } void exec_status_fill(ExecStatus *s, pid_t pid, int code, int status) { diff --git a/execute.h b/execute.h index 3283e1f81..04b9f6ef8 100644 --- a/execute.h +++ b/execute.h @@ -44,9 +44,12 @@ struct ExecContext { char **environment; mode_t umask; struct rlimit *rlimit[RLIMIT_NLIMITS]; /* FIXME: load-fragment parser missing */ + char *directory; int oom_adjust; int nice; - char *directory; + + bool oom_adjust_set:1; + bool nice_set:1; ExecOutput output; int syslog_priority; diff --git a/load-fragment.c b/load-fragment.c index 9273fc8b8..0db74b3ee 100644 --- a/load-fragment.c +++ b/load-fragment.c @@ -208,7 +208,8 @@ static int config_parse_nice( void *data, void *userdata) { - int *i = data, priority, r; + ExecContext *c = data; + int priority, r; assert(filename); assert(lvalue); @@ -225,7 +226,9 @@ static int config_parse_nice( return -ERANGE; } - *i = priority; + c->nice = priority; + c->nice_set = false; + return 0; } @@ -238,7 +241,8 @@ static int config_parse_oom_adjust( void *data, void *userdata) { - int *i = data, oa, r; + ExecContext *c = data; + int oa, r; assert(filename); assert(lvalue); @@ -255,7 +259,9 @@ static int config_parse_oom_adjust( return -ERANGE; } - *i = oa; + c->oom_adjust = oa; + c->oom_adjust_set = true; + return 0; } @@ -709,8 +715,8 @@ static int load_from_path(Unit *u, const char *path) { { "User", config_parse_string, &(context).user, section }, \ { "Group", config_parse_string, &(context).group, section }, \ { "SupplementaryGroups", config_parse_strv, &(context).supplementary_groups, section }, \ - { "Nice", config_parse_nice, &(context).nice, section }, \ - { "OOMAdjust", config_parse_oom_adjust, &(context).oom_adjust, section }, \ + { "Nice", config_parse_nice, &(context), section }, \ + { "OOMAdjust", config_parse_oom_adjust, &(context), section }, \ { "UMask", config_parse_umask, &(context).umask, section }, \ { "Environment", config_parse_strv, &(context).environment, section }, \ { "Output", config_parse_output, &(context).output, section }, \ -- 2.30.2 From 35355baba1feec37bf9f22e3a0e18f495fcf6014 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 02:54:35 +0100 Subject: [PATCH 11/16] the systemd logger only matters in the abstract namespace --- test1/systemd-logger.socket | 2 -- 1 file changed, 2 deletions(-) diff --git a/test1/systemd-logger.socket b/test1/systemd-logger.socket index ae0c81a91..3f05363cc 100644 --- a/test1/systemd-logger.socket +++ b/test1/systemd-logger.socket @@ -2,6 +2,4 @@ Description=systemd Logging Socket [Socket] -ExecStartPre=/bin/rm -f /tmp/systemd-logger ListenStream==/systemd/logger -ListenStream=/tmp/systemd-logger -- 2.30.2 From 1c24e7bd1286d16a7125aeeee0470ea0685c8318 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 04:50:28 +0100 Subject: [PATCH 12/16] Use @ instead = as abstract namespace socket prefix @ makes more sense since the NUL addr contained in the sockaddr's sun_path field can also be written as ^@. Also, in the .socket files writing "ListenStream==foo" is kinda ugly. Finally, tools like strace decode it with an @ too. --- socket-util.c | 4 ++-- test1/systemd-logger.socket | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/socket-util.c b/socket-util.c index 46a6e91bb..0282dd2f3 100644 --- a/socket-util.c +++ b/socket-util.c @@ -69,7 +69,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { memcpy(a->sockaddr.un.sun_path, s, l); a->size = sizeof(sa_family_t) + l + 1; - } else if (*s == '=') { + } else if (*s == '@') { /* Abstract AF_UNIX socket */ size_t l; @@ -261,7 +261,7 @@ int socket_address_print(const SocketAddress *a, char **p) { if (!(ret = new(char, sizeof(a->sockaddr.un.sun_path)+1))) return -ENOMEM; - ret[0] = '='; + ret[0] = '@'; memcpy(ret+1, a->sockaddr.un.sun_path+1, sizeof(a->sockaddr.un.sun_path)-1); ret[sizeof(a->sockaddr.un.sun_path)] = 0; diff --git a/test1/systemd-logger.socket b/test1/systemd-logger.socket index 3f05363cc..c964ab7da 100644 --- a/test1/systemd-logger.socket +++ b/test1/systemd-logger.socket @@ -2,4 +2,4 @@ Description=systemd Logging Socket [Socket] -ListenStream==/systemd/logger +ListenStream=@/systemd/logger -- 2.30.2 From 09b6b09f44b36b52b8a20ba18446e3ec2926c110 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 06:43:23 +0100 Subject: [PATCH 13/16] add new unit_add_dependency_by_name() call --- unit.c | 13 +++++++++++++ unit.h | 1 + 2 files changed, 14 insertions(+) diff --git a/unit.c b/unit.c index 407612092..a5f4ac767 100644 --- a/unit.c +++ b/unit.c @@ -836,6 +836,19 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other) { return 0; } +int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name) { + Unit *other; + int r; + + if ((r = manager_load_unit(u->meta.manager, name, &other)) < 0) + return r; + + if ((r = unit_add_dependency(u, d, other)) < 0) + return r; + + return 0; +} + const char *unit_path(void) { char *e; diff --git a/unit.h b/unit.h index a90baf022..a29c50ed9 100644 --- a/unit.h +++ b/unit.h @@ -196,6 +196,7 @@ void unit_free(Unit *u); int unit_add_name(Unit *u, const char *name); int unit_add_dependency(Unit *u, UnitDependency d, Unit *other); +int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name); void unit_add_to_load_queue(Unit *u); -- 2.30.2 From b19e7dc0104c8839835a90d7df20c2eeb631e07e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 06:43:49 +0100 Subject: [PATCH 14/16] make use of unit_add_dependency_by_name() where applicable --- load-dropin.c | 9 +-------- load-fragment.c | 6 +----- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/load-dropin.c b/load-dropin.c index a57bfc455..521eb0821 100644 --- a/load-dropin.c +++ b/load-dropin.c @@ -37,8 +37,6 @@ int unit_load_dropin(Unit *u) { free(path); while ((de = readdir(d))) { - Unit *other; - if (de->d_name[0] == '.') continue; @@ -58,18 +56,13 @@ int unit_load_dropin(Unit *u) { continue; } - r = manager_load_unit(u->meta.manager, path, &other); + r = unit_add_dependency_by_name(u, UNIT_WANTS, path); free(path); if (r < 0) { closedir(d); return r; } - - if ((r = unit_add_dependency(u, UNIT_WANTS, other)) < 0) { - closedir(d); - return r; - } } closedir(d); diff --git a/load-fragment.c b/load-fragment.c index 0db74b3ee..1a334bbc1 100644 --- a/load-fragment.c +++ b/load-fragment.c @@ -35,19 +35,15 @@ static int config_parse_deps( FOREACH_WORD(w, &l, rvalue, state) { char *t; int r; - Unit *other; if (!(t = strndup(w, l))) return -ENOMEM; - r = manager_load_unit(u->meta.manager, t, &other); + r = unit_add_dependency_by_name(u, d, t); free(t); if (r < 0) return r; - - if ((r = unit_add_dependency(u, d, other)) < 0) - return r; } return 0; -- 2.30.2 From b5ea5d95b40315ed9bb21a443480f717092d4981 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 06:44:13 +0100 Subject: [PATCH 15/16] relax unit name rules a bit --- unit.c | 2 +- unit.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/unit.c b/unit.c index a5f4ac767..2f39d887f 100644 --- a/unit.c +++ b/unit.c @@ -44,7 +44,7 @@ UnitType unit_name_to_type(const char *n) { "0123456789" \ "abcdefghijklmnopqrstuvwxyz" \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ - "-_" + "-_.\\" bool unit_name_is_valid(const char *n) { UnitType t; diff --git a/unit.h b/unit.h index a29c50ed9..5321d5f1a 100644 --- a/unit.h +++ b/unit.h @@ -23,7 +23,7 @@ typedef enum UnitDependency UnitDependency; #include "execute.h" #include "util.h" -#define UNIT_NAME_MAX 32 +#define UNIT_NAME_MAX 128 #define DEFAULT_TIMEOUT_USEC (20*USEC_PER_SEC) #define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC) -- 2.30.2 From 88066b3a67b78329a02ffca3ac76ba1230de6b12 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 28 Jan 2010 06:44:30 +0100 Subject: [PATCH 16/16] add unit_name_escape_path() call --- unit.c | 39 +++++++++++++++++++++++++++++++++++++++ unit.h | 1 + 2 files changed, 40 insertions(+) diff --git a/unit.c b/unit.c index 2f39d887f..c8a6f6696 100644 --- a/unit.c +++ b/unit.c @@ -887,3 +887,42 @@ int set_unit_path(const char *p) { return 0; } + +char *unit_name_escape_path(const char *path, const char *suffix) { + char *r, *t; + const char *f; + size_t a, b; + + assert(path); + assert(suffix); + + /* Takes a path and a util suffix and makes a nice unit name + * of it, escaping all weird chars on the way. + * + * / becomes _, and all chars not alloweed in a unit name get + * escaped as \xFF, including the _ and the \ itself, of + * course. This escaping is hence reversible. + */ + + a = strlen(path); + b = strlen(suffix); + + if (!(r = new(char, a*4+b+1))) + return NULL; + + for (f = path, t = r; *f; f++) { + if (*f == '/') + *(t++) = '_'; + else if (*f == '_' || *f == '\\' || !strchr(VALID_CHARS, *f)) { + *(t++) = '\\'; + *(t++) = 'x'; + *(t++) = hexchar(*f > 4); + *(t++) = hexchar(*f); + } else + *(t++) = *f; + } + + memcpy(t, suffix, b+1); + + return r; +} diff --git a/unit.h b/unit.h index 5321d5f1a..f9d96c7ef 100644 --- a/unit.h +++ b/unit.h @@ -235,5 +235,6 @@ bool unit_job_is_applicable(Unit *u, JobType j); const char *unit_path(void); int set_unit_path(const char *p); +char *unit_name_escape_path(const char *path, const char *suffix); #endif -- 2.30.2