From 63a3b3cb70cb8e27ce20e698abd5548671c31265 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 22 Mar 2019 20:05:08 +0100 Subject: [PATCH] systemctl: split out some SysV compat stuff into its own C file systemctl.c is way to large already. Let's split out some stuff out that is easy to split out. --- meson.build | 5 +- src/systemctl/systemctl.c | 113 +----------------------------------- src/systemctl/sysv-compat.c | 100 +++++++++++++++++++++++++++++++ src/systemctl/sysv-compat.h | 30 ++++++++++ 4 files changed, 136 insertions(+), 112 deletions(-) create mode 100644 src/systemctl/sysv-compat.c create mode 100644 src/systemctl/sysv-compat.h diff --git a/meson.build b/meson.build index d242888f37..20bcb9d8b1 100644 --- a/meson.build +++ b/meson.build @@ -1950,7 +1950,10 @@ else libbasic_gcrypt] endif -exe = executable('systemctl', 'src/systemctl/systemctl.c', +exe = executable('systemctl', + 'src/systemctl/systemctl.c', + 'src/systemctl/sysv-compat.h', + 'src/systemctl/sysv-compat.c', include_directories : includes, link_with : systemctl_link_with, dependencies : [threads, diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 948dacd190..b948ebe8ca 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -75,6 +75,7 @@ #include "stat-util.h" #include "string-table.h" #include "strv.h" +#include "sysv-compat.h" #include "terminal-util.h" #include "tmpfile-util.h" #include "unit-def.h" @@ -85,25 +86,6 @@ #include "verbs.h" #include "virt.h" -/* The init script exit status codes - 0 program is running or service is OK - 1 program is dead and /var/run pid file exists - 2 program is dead and /var/lock lock file exists - 3 program is not running - 4 program or service status is unknown - 5-99 reserved for future LSB use - 100-149 reserved for distribution use - 150-199 reserved for application use - 200-254 reserved -*/ -enum { - EXIT_PROGRAM_RUNNING_OR_SERVICE_OK = 0, - EXIT_PROGRAM_DEAD_AND_PID_EXISTS = 1, - EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS = 2, - EXIT_PROGRAM_NOT_RUNNING = 3, - EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN = 4, -}; - static char **arg_types = NULL; static char **arg_states = NULL; static char **arg_properties = NULL; @@ -8465,56 +8447,6 @@ static int halt_parse_argv(int argc, char *argv[]) { return 1; } -static int parse_shutdown_time_spec(const char *t, usec_t *_u) { - assert(t); - assert(_u); - - if (streq(t, "now")) - *_u = 0; - else if (!strchr(t, ':')) { - uint64_t u; - - if (safe_atou64(t, &u) < 0) - return -EINVAL; - - *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u; - } else { - char *e = NULL; - long hour, minute; - struct tm tm = {}; - time_t s; - usec_t n; - - errno = 0; - hour = strtol(t, &e, 10); - if (errno > 0 || *e != ':' || hour < 0 || hour > 23) - return -EINVAL; - - minute = strtol(e+1, &e, 10); - if (errno > 0 || *e != 0 || minute < 0 || minute > 59) - return -EINVAL; - - n = now(CLOCK_REALTIME); - s = (time_t) (n / USEC_PER_SEC); - - assert_se(localtime_r(&s, &tm)); - - tm.tm_hour = (int) hour; - tm.tm_min = (int) minute; - tm.tm_sec = 0; - - s = mktime(&tm); - assert(s >= 0); - - *_u = (usec_t) s * USEC_PER_SEC; - - while (*_u <= n) - *_u += USEC_PER_DAY; - } - - return 0; -} - static int shutdown_parse_argv(int argc, char *argv[]) { enum { ARG_HELP = 0x100, @@ -8820,47 +8752,6 @@ _pure_ static int action_to_runlevel(void) { } #endif -static int talk_initctl(void) { -#if HAVE_SYSV_COMPAT - struct init_request request = { - .magic = INIT_MAGIC, - .sleeptime = 0, - .cmd = INIT_CMD_RUNLVL - }; - - _cleanup_close_ int fd = -1; - char rl; - int r; - const char *p; - - rl = action_to_runlevel(); - if (!rl) - return 0; - - request.runlevel = rl; - - FOREACH_STRING(p, "/run/initctl", "/dev/initctl") { - fd = open(p, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY); - if (fd >= 0 || errno != ENOENT) - break; - } - if (fd < 0) { - if (errno == ENOENT) - return 0; - - return log_error_errno(errno, "Failed to open initctl fifo: %m"); - } - - r = loop_write(fd, &request, sizeof(request), false); - if (r < 0) - return log_error_errno(r, "Failed to write to %s: %m", p); - - return 1; -#else - return 0; -#endif -} - static int systemctl_main(int argc, char *argv[]) { static const Verb verbs[] = { { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, list_units }, @@ -8956,7 +8847,7 @@ static int start_with_fallback(void) { return 0; /* Nothing else worked, so let's try /dev/initctl */ - if (talk_initctl() > 0) + if (talk_initctl(action_to_runlevel()) > 0) return 0; return log_error_errno(SYNTHETIC_ERRNO(EIO), diff --git a/src/systemctl/sysv-compat.c b/src/systemctl/sysv-compat.c new file mode 100644 index 0000000000..72a2f57965 --- /dev/null +++ b/src/systemctl/sysv-compat.c @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "fd-util.h" +#include "initreq.h" +#include "io-util.h" +#include "parse-util.h" +#include "strv.h" +#include "sysv-compat.h" + +int talk_initctl(char rl) { +#if HAVE_SYSV_COMPAT + struct init_request request; + _cleanup_close_ int fd = -1; + const char *p; + int r; + + /* Try to switch to the specified SysV runlevel. Returns == 0 if the operation does not apply on this + * system, and > 0 on success. */ + + if (rl == 0) + return 0; + + FOREACH_STRING(p, "/run/initctl", "/dev/initctl") { + fd = open(p, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY); + if (fd >= 0 || errno != ENOENT) + break; + } + if (fd < 0) { + if (errno == ENOENT) + return 0; + + return log_error_errno(errno, "Failed to open initctl fifo: %m"); + } + + request = (struct init_request) { + .magic = INIT_MAGIC, + .sleeptime = 0, + .cmd = INIT_CMD_RUNLVL, + .runlevel = rl, + }; + + r = loop_write(fd, &request, sizeof(request), false); + if (r < 0) + return log_error_errno(r, "Failed to write to %s: %m", p); + + return 1; +#else + return 0; +#endif +} + +int parse_shutdown_time_spec(const char *t, usec_t *ret) { + assert(t); + assert(ret); + + if (streq(t, "now")) + *ret = 0; + else if (!strchr(t, ':')) { + uint64_t u; + + if (safe_atou64(t, &u) < 0) + return -EINVAL; + + *ret = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u; + } else { + char *e = NULL; + long hour, minute; + struct tm tm = {}; + time_t s; + usec_t n; + + errno = 0; + hour = strtol(t, &e, 10); + if (errno > 0 || *e != ':' || hour < 0 || hour > 23) + return -EINVAL; + + minute = strtol(e+1, &e, 10); + if (errno > 0 || *e != 0 || minute < 0 || minute > 59) + return -EINVAL; + + n = now(CLOCK_REALTIME); + s = (time_t) (n / USEC_PER_SEC); + + assert_se(localtime_r(&s, &tm)); + + tm.tm_hour = (int) hour; + tm.tm_min = (int) minute; + tm.tm_sec = 0; + + s = mktime(&tm); + assert(s >= 0); + + *ret = (usec_t) s * USEC_PER_SEC; + + while (*ret <= n) + *ret += USEC_PER_DAY; + } + + return 0; +} diff --git a/src/systemctl/sysv-compat.h b/src/systemctl/sysv-compat.h new file mode 100644 index 0000000000..73329ec42a --- /dev/null +++ b/src/systemctl/sysv-compat.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "time-util.h" + +int talk_initctl(char runlevel); +int parse_shutdown_time_spec(const char *t, usec_t *ret); + +/* The init script exit codes for the LSB 'status' verb. (This is different from the 'start' verb, whose exit + codes are defined in exit-status.h.) + + 0 program is running or service is OK + 1 program is dead and /var/run pid file exists + 2 program is dead and /var/lock lock file exists + 3 program is not running + 4 program or service status is unknown + 5-99 reserved for future LSB use + 100-149 reserved for distribution use + 150-199 reserved for application use + 200-254 reserved + + https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html +*/ +enum { + EXIT_PROGRAM_RUNNING_OR_SERVICE_OK = 0, + EXIT_PROGRAM_DEAD_AND_PID_EXISTS = 1, + EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS = 2, + EXIT_PROGRAM_NOT_RUNNING = 3, + EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN = 4, +};