diff options
Diffstat (limited to 'src/basic')
-rw-r--r-- | src/basic/cpu-set-util.c | 105 | ||||
-rw-r--r-- | src/basic/cpu-set-util.h | 34 | ||||
-rw-r--r-- | src/basic/fileio.c | 40 | ||||
-rw-r--r-- | src/basic/fileio.h | 2 | ||||
-rw-r--r-- | src/basic/log.c | 2 | ||||
-rw-r--r-- | src/basic/log.h | 12 | ||||
-rw-r--r-- | src/basic/missing.h | 13 | ||||
-rw-r--r-- | src/basic/prioq.c | 2 | ||||
-rw-r--r-- | src/basic/process-util.c | 2 | ||||
-rw-r--r-- | src/basic/selinux-util.c | 10 | ||||
-rw-r--r-- | src/basic/selinux-util.h | 6 | ||||
-rw-r--r-- | src/basic/socket-label.c | 7 | ||||
-rw-r--r-- | src/basic/strv.c | 25 | ||||
-rw-r--r-- | src/basic/strv.h | 4 | ||||
-rw-r--r-- | src/basic/terminal-util.c | 23 | ||||
-rw-r--r-- | src/basic/terminal-util.h | 2 | ||||
-rw-r--r-- | src/basic/unit-name.c | 164 | ||||
-rw-r--r-- | src/basic/unit-name.h | 227 | ||||
-rw-r--r-- | src/basic/util.c | 198 | ||||
-rw-r--r-- | src/basic/util.h | 15 | ||||
-rw-r--r-- | src/basic/virt.c | 2 |
21 files changed, 676 insertions, 219 deletions
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c new file mode 100644 index 0000000000..519583c167 --- /dev/null +++ b/src/basic/cpu-set-util.c @@ -0,0 +1,105 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2015 Lennart Poettering + Copyright 2015 Filipe Brandenburger + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "util.h" +#include "cpu-set-util.h" + +cpu_set_t* cpu_set_malloc(unsigned *ncpus) { + cpu_set_t *c; + unsigned n = 1024; + + /* Allocates the cpuset in the right size */ + + for (;;) { + c = CPU_ALLOC(n); + if (!c) + return NULL; + + if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) { + CPU_ZERO_S(CPU_ALLOC_SIZE(n), c); + + if (ncpus) + *ncpus = n; + + return c; + } + + CPU_FREE(c); + + if (errno != EINVAL) + return NULL; + + n *= 2; + } +} + +int parse_cpu_set_and_warn( + const char *rvalue, + cpu_set_t **cpu_set, + const char *unit, + const char *filename, + unsigned line, + const char *lvalue) { + + const char *whole_rvalue = rvalue; + _cleanup_cpu_free_ cpu_set_t *c = NULL; + unsigned ncpus = 0; + + assert(lvalue); + assert(rvalue); + + for (;;) { + _cleanup_free_ char *word = NULL; + unsigned cpu; + int r; + + r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue); + return r; + } + if (r == 0) + break; + + if (!c) { + c = cpu_set_malloc(&ncpus); + if (!c) + return log_oom(); + } + + r = safe_atou(word, &cpu); + if (r < 0 || cpu >= ncpus) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", rvalue); + return -EINVAL; + } + + CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); + } + + /* On success, sets *cpu_set and returns ncpus for the system. */ + if (c) { + *cpu_set = c; + c = NULL; + } + + return (int) ncpus; +} diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h new file mode 100644 index 0000000000..19b457a684 --- /dev/null +++ b/src/basic/cpu-set-util.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2015 Lennart Poettering + Copyright 2015 Filipe Brandenburger + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sched.h> + +#include "macro.h" + +DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); +#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) + +cpu_set_t* cpu_set_malloc(unsigned *ncpus); + +int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 4a9105f421..13a85e1158 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -775,15 +775,19 @@ int executable_is_script(const char *path, char **interpreter) { /** * Retrieve one field from a file like /proc/self/status. pattern - * should start with '\n' and end with a ':'. Whitespace and zeros - * after the ':' will be skipped. field must be freed afterwards. + * should not include whitespace or the delimiter (':'). pattern matches only + * the beginning of a line. Whitespace before ':' is skipped. Whitespace and + * zeros after the ':' will be skipped. field must be freed afterwards. + * terminator specifies the terminating characters of the field value (not + * included in the value). */ -int get_status_field(const char *filename, const char *pattern, char **field) { +int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) { _cleanup_free_ char *status = NULL; char *t, *f; size_t len; int r; + assert(terminator); assert(filename); assert(pattern); assert(field); @@ -792,11 +796,31 @@ int get_status_field(const char *filename, const char *pattern, char **field) { if (r < 0) return r; - t = strstr(status, pattern); - if (!t) - return -ENOENT; + t = status; + + do { + bool pattern_ok; + + do { + t = strstr(t, pattern); + if (!t) + return -ENOENT; + + /* Check that pattern occurs in beginning of line. */ + pattern_ok = (t == status || t[-1] == '\n'); + + t += strlen(pattern); + + } while (!pattern_ok); + + t += strspn(t, " \t"); + if (!*t) + return -ENOENT; + + } while (*t != ':'); + + t++; - t += strlen(pattern); if (*t) { t += strspn(t, " \t"); @@ -812,7 +836,7 @@ int get_status_field(const char *filename, const char *pattern, char **field) { t --; } - len = strcspn(t, WHITESPACE); + len = strcspn(t, terminator); f = strndup(t, len); if (!f) diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 2e8148ff24..4998d4d042 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -48,4 +48,4 @@ int write_env_file(const char *fname, char **l); int executable_is_script(const char *path, char **interpreter); -int get_status_field(const char *filename, const char *pattern, char **field); +int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field); diff --git a/src/basic/log.c b/src/basic/log.c index 38f42b3a6e..e6d7d15182 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -922,7 +922,7 @@ int log_set_max_level_from_string(const char *e) { t = log_level_from_string(e); if (t < 0) - return t; + return -EINVAL; log_set_max_level(t); return 0; diff --git a/src/basic/log.h b/src/basic/log.h index 569762d083..369d6b1127 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -227,3 +227,15 @@ int log_syntax_internal( ? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \ : -abs(_e); \ }) + +#define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ + ({ \ + int _level = (level); \ + if (log_get_max_level() >= LOG_PRI(_level)) { \ + _cleanup_free_ char *_p = NULL; \ + _p = utf8_escape_invalid(rvalue); \ + log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \ + "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \ + } \ + -EINVAL; \ + }) diff --git a/src/basic/missing.h b/src/basic/missing.h index 9811b6b23e..1e3af283bb 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -842,6 +842,19 @@ static inline int setns(int fd, int nstype) { #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) #endif +#if !HAVE_DECL_IFLA_BR_PRIORITY +#define IFLA_BR_UNSPEC 0 +#define IFLA_BR_FORWARD_DELAY 1 +#define IFLA_BR_HELLO_TIME 2 +#define IFLA_BR_MAX_AGE 3 +#define IFLA_BR_AGEING_TIME 4 +#define IFLA_BR_STP_STATE 5 +#define IFLA_BR_PRIORITY 6 +#define __IFLA_BR_MAX 7 + +#define IFLA_BR_MAX (__IFLA_BR_MAX - 1) +#endif + #if !HAVE_DECL_IFLA_BRPORT_LEARNING_SYNC #define IFLA_BRPORT_UNSPEC 0 #define IFLA_BRPORT_STATE 1 diff --git a/src/basic/prioq.c b/src/basic/prioq.c index 69ec45d97e..d55b348c22 100644 --- a/src/basic/prioq.c +++ b/src/basic/prioq.c @@ -111,7 +111,7 @@ static unsigned shuffle_up(Prioq *q, unsigned idx) { k = (idx-1)/2; - if (q->compare_func(q->items[k].data, q->items[idx].data) < 0) + if (q->compare_func(q->items[k].data, q->items[idx].data) <= 0) break; swap(q, idx, k); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index cff2d2a034..d8a94a4572 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -215,7 +215,7 @@ int get_process_capeff(pid_t pid, char **capeff) { p = procfs_file_alloca(pid, "status"); - r = get_status_field(p, "\nCapEff:", capeff); + r = get_proc_field(p, "CapEff", WHITESPACE, capeff); if (r == -ENOENT) return -ESRCH; diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index a39a0f775a..747e6f4dbb 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -295,14 +295,20 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * return r; } -void mac_selinux_free(char *label) { +char* mac_selinux_free(char *label) { #ifdef HAVE_SELINUX + if (!label) + return NULL; + if (!mac_selinux_use()) - return; + return NULL; + freecon((security_context_t) label); #endif + + return NULL; } int mac_selinux_create_file_prepare(const char *path, mode_t mode) { diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 8467185291..2afcaec183 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -24,6 +24,8 @@ #include <sys/socket.h> #include <stdbool.h> +#include "macro.h" + bool mac_selinux_use(void); void mac_selinux_retest(void); @@ -36,7 +38,7 @@ int mac_selinux_apply(const char *path, const char *label); int mac_selinux_get_create_label_from_exe(const char *exe, char **label); int mac_selinux_get_our_label(char **label); int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label); -void mac_selinux_free(char *label); +char* mac_selinux_free(char *label); int mac_selinux_create_file_prepare(const char *path, mode_t mode); void mac_selinux_create_file_clear(void); @@ -45,3 +47,5 @@ int mac_selinux_create_socket_prepare(const char *label); void mac_selinux_create_socket_clear(void); int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen); + +DEFINE_TRIVIAL_CLEANUP_FUNC(char*, mac_selinux_free); diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 144e6fd86e..937124cc02 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -146,11 +146,8 @@ int make_socket_fd(int log_level, const char* address, int flags) { int fd, r; r = socket_address_parse(&a, address); - if (r < 0) { - log_error("Failed to parse socket address \"%s\": %s", - address, strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address); fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT, NULL, false, false, false, 0755, 0644, NULL); diff --git a/src/basic/strv.c b/src/basic/strv.c index b9aef64b15..9524e80a6f 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -720,3 +720,28 @@ bool strv_fnmatch(char* const* patterns, const char *s, int flags) { return false; } + +char ***strv_free_free(char ***l) { + char ***i; + + if (!l) + return NULL; + + for (i = l; *i; i++) + strv_free(*i); + + free(l); + return NULL; +} + +char **strv_skip(char **l, size_t n) { + + while (n > 0) { + if (strv_isempty(l)) + return l; + + l++, n--; + } + + return l; +} diff --git a/src/basic/strv.h b/src/basic/strv.h index f07da8cdf3..4c4b6526de 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -154,3 +154,7 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i return strv_isempty(patterns) || strv_fnmatch(patterns, s, flags); } + +char ***strv_free_free(char ***l); + +char **strv_skip(char **l, size_t n); diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index dd3d525854..22ee6ad83f 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -48,7 +48,7 @@ int chvt(int vt) { if (fd < 0) return -errno; - if (vt < 0) { + if (vt <= 0) { int tiocl[2] = { TIOCL_GETKMSGREDIRECT, 0 @@ -607,27 +607,6 @@ int vt_disallocate(const char *name) { return 0; } -void warn_melody(void) { - _cleanup_close_ int fd = -1; - - fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return; - - /* Yeah, this is synchronous. Kinda sucks. But well... */ - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/440)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/220)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/220)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, 0); -} - int make_console_stdio(void) { int fd, r; diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index a9e325ccb3..da2a5b8897 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -67,8 +67,6 @@ bool tty_is_console(const char *tty) _pure_; int vtnr_from_tty(const char *tty); const char *default_term_for_tty(const char *tty); -void warn_melody(void); - int make_stdio(int fd); int make_null_stdio(void); int make_console_stdio(void); diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index 8742ee757f..a8b6b6dace 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -839,6 +839,170 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); +static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { + [UNIT_ACTIVE] = "active", + [UNIT_RELOADING] = "reloading", + [UNIT_INACTIVE] = "inactive", + [UNIT_FAILED] = "failed", + [UNIT_ACTIVATING] = "activating", + [UNIT_DEACTIVATING] = "deactivating" +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState); + +static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = { + [AUTOMOUNT_DEAD] = "dead", + [AUTOMOUNT_WAITING] = "waiting", + [AUTOMOUNT_RUNNING] = "running", + [AUTOMOUNT_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState); + +static const char* const busname_state_table[_BUSNAME_STATE_MAX] = { + [BUSNAME_DEAD] = "dead", + [BUSNAME_MAKING] = "making", + [BUSNAME_REGISTERED] = "registered", + [BUSNAME_LISTENING] = "listening", + [BUSNAME_RUNNING] = "running", + [BUSNAME_SIGTERM] = "sigterm", + [BUSNAME_SIGKILL] = "sigkill", + [BUSNAME_FAILED] = "failed", +}; + +DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState); + +static const char* const device_state_table[_DEVICE_STATE_MAX] = { + [DEVICE_DEAD] = "dead", + [DEVICE_TENTATIVE] = "tentative", + [DEVICE_PLUGGED] = "plugged", +}; + +DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState); + +static const char* const mount_state_table[_MOUNT_STATE_MAX] = { + [MOUNT_DEAD] = "dead", + [MOUNT_MOUNTING] = "mounting", + [MOUNT_MOUNTING_DONE] = "mounting-done", + [MOUNT_MOUNTED] = "mounted", + [MOUNT_REMOUNTING] = "remounting", + [MOUNT_UNMOUNTING] = "unmounting", + [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm", + [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill", + [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm", + [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill", + [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm", + [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill", + [MOUNT_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); + +static const char* const path_state_table[_PATH_STATE_MAX] = { + [PATH_DEAD] = "dead", + [PATH_WAITING] = "waiting", + [PATH_RUNNING] = "running", + [PATH_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(path_state, PathState); + +static const char* const scope_state_table[_SCOPE_STATE_MAX] = { + [SCOPE_DEAD] = "dead", + [SCOPE_RUNNING] = "running", + [SCOPE_ABANDONED] = "abandoned", + [SCOPE_STOP_SIGTERM] = "stop-sigterm", + [SCOPE_STOP_SIGKILL] = "stop-sigkill", + [SCOPE_FAILED] = "failed", +}; + +DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState); + +static const char* const service_state_table[_SERVICE_STATE_MAX] = { + [SERVICE_DEAD] = "dead", + [SERVICE_START_PRE] = "start-pre", + [SERVICE_START] = "start", + [SERVICE_START_POST] = "start-post", + [SERVICE_RUNNING] = "running", + [SERVICE_EXITED] = "exited", + [SERVICE_RELOAD] = "reload", + [SERVICE_STOP] = "stop", + [SERVICE_STOP_SIGABRT] = "stop-sigabrt", + [SERVICE_STOP_SIGTERM] = "stop-sigterm", + [SERVICE_STOP_SIGKILL] = "stop-sigkill", + [SERVICE_STOP_POST] = "stop-post", + [SERVICE_FINAL_SIGTERM] = "final-sigterm", + [SERVICE_FINAL_SIGKILL] = "final-sigkill", + [SERVICE_FAILED] = "failed", + [SERVICE_AUTO_RESTART] = "auto-restart", +}; + +DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); + +static const char* const slice_state_table[_SLICE_STATE_MAX] = { + [SLICE_DEAD] = "dead", + [SLICE_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState); + +static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = { + [SNAPSHOT_DEAD] = "dead", + [SNAPSHOT_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState); + +static const char* const socket_state_table[_SOCKET_STATE_MAX] = { + [SOCKET_DEAD] = "dead", + [SOCKET_START_PRE] = "start-pre", + [SOCKET_START_CHOWN] = "start-chown", + [SOCKET_START_POST] = "start-post", + [SOCKET_LISTENING] = "listening", + [SOCKET_RUNNING] = "running", + [SOCKET_STOP_PRE] = "stop-pre", + [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm", + [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill", + [SOCKET_STOP_POST] = "stop-post", + [SOCKET_FINAL_SIGTERM] = "final-sigterm", + [SOCKET_FINAL_SIGKILL] = "final-sigkill", + [SOCKET_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); + +static const char* const swap_state_table[_SWAP_STATE_MAX] = { + [SWAP_DEAD] = "dead", + [SWAP_ACTIVATING] = "activating", + [SWAP_ACTIVATING_DONE] = "activating-done", + [SWAP_ACTIVE] = "active", + [SWAP_DEACTIVATING] = "deactivating", + [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm", + [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill", + [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", + [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", + [SWAP_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); + +static const char* const target_state_table[_TARGET_STATE_MAX] = { + [TARGET_DEAD] = "dead", + [TARGET_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState); + +static const char* const timer_state_table[_TIMER_STATE_MAX] = { + [TIMER_DEAD] = "dead", + [TIMER_WAITING] = "waiting", + [TIMER_RUNNING] = "running", + [TIMER_ELAPSED] = "elapsed", + [TIMER_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState); + static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_REQUIRES] = "Requires", [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable", diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index 28b3a555f3..65b55d9554 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -27,11 +27,7 @@ #define UNIT_NAME_MAX 256 -typedef enum UnitType UnitType; -typedef enum UnitLoadState UnitLoadState; -typedef enum UnitDependency UnitDependency; - -enum UnitType { +typedef enum UnitType { UNIT_SERVICE = 0, UNIT_SOCKET, UNIT_BUSNAME, @@ -47,9 +43,9 @@ enum UnitType { UNIT_SCOPE, _UNIT_TYPE_MAX, _UNIT_TYPE_INVALID = -1 -}; +} UnitType; -enum UnitLoadState { +typedef enum UnitLoadState { UNIT_STUB = 0, UNIT_LOADED, UNIT_NOT_FOUND, @@ -58,9 +54,176 @@ enum UnitLoadState { UNIT_MASKED, _UNIT_LOAD_STATE_MAX, _UNIT_LOAD_STATE_INVALID = -1 -}; - -enum UnitDependency { +} UnitLoadState; + +typedef enum UnitActiveState { + UNIT_ACTIVE, + UNIT_RELOADING, + UNIT_INACTIVE, + UNIT_FAILED, + UNIT_ACTIVATING, + UNIT_DEACTIVATING, + _UNIT_ACTIVE_STATE_MAX, + _UNIT_ACTIVE_STATE_INVALID = -1 +} UnitActiveState; + +typedef enum AutomountState { + AUTOMOUNT_DEAD, + AUTOMOUNT_WAITING, + AUTOMOUNT_RUNNING, + AUTOMOUNT_FAILED, + _AUTOMOUNT_STATE_MAX, + _AUTOMOUNT_STATE_INVALID = -1 +} AutomountState; + +typedef enum BusNameState { + BUSNAME_DEAD, + BUSNAME_MAKING, + BUSNAME_REGISTERED, + BUSNAME_LISTENING, + BUSNAME_RUNNING, + BUSNAME_SIGTERM, + BUSNAME_SIGKILL, + BUSNAME_FAILED, + _BUSNAME_STATE_MAX, + _BUSNAME_STATE_INVALID = -1 +} BusNameState; + +/* We simply watch devices, we cannot plug/unplug them. That + * simplifies the state engine greatly */ +typedef enum DeviceState { + DEVICE_DEAD, + DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */ + DEVICE_PLUGGED, /* announced by udev */ + _DEVICE_STATE_MAX, + _DEVICE_STATE_INVALID = -1 +} DeviceState; + +typedef enum MountState { + MOUNT_DEAD, + MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */ + MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */ + MOUNT_MOUNTED, + MOUNT_REMOUNTING, + MOUNT_UNMOUNTING, + MOUNT_MOUNTING_SIGTERM, + MOUNT_MOUNTING_SIGKILL, + MOUNT_REMOUNTING_SIGTERM, + MOUNT_REMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_FAILED, + _MOUNT_STATE_MAX, + _MOUNT_STATE_INVALID = -1 +} MountState; + +typedef enum PathState { + PATH_DEAD, + PATH_WAITING, + PATH_RUNNING, + PATH_FAILED, + _PATH_STATE_MAX, + _PATH_STATE_INVALID = -1 +} PathState; + +typedef enum ScopeState { + SCOPE_DEAD, + SCOPE_RUNNING, + SCOPE_ABANDONED, + SCOPE_STOP_SIGTERM, + SCOPE_STOP_SIGKILL, + SCOPE_FAILED, + _SCOPE_STATE_MAX, + _SCOPE_STATE_INVALID = -1 +} ScopeState; + +typedef enum ServiceState { + SERVICE_DEAD, + SERVICE_START_PRE, + SERVICE_START, + SERVICE_START_POST, + SERVICE_RUNNING, + SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */ + SERVICE_RELOAD, + SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */ + SERVICE_STOP_SIGABRT, /* Watchdog timeout */ + SERVICE_STOP_SIGTERM, + SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */ + SERVICE_FINAL_SIGKILL, + SERVICE_FAILED, + SERVICE_AUTO_RESTART, + _SERVICE_STATE_MAX, + _SERVICE_STATE_INVALID = -1 +} ServiceState; + +typedef enum SliceState { + SLICE_DEAD, + SLICE_ACTIVE, + _SLICE_STATE_MAX, + _SLICE_STATE_INVALID = -1 +} SliceState; + +typedef enum SnapshotState { + SNAPSHOT_DEAD, + SNAPSHOT_ACTIVE, + _SNAPSHOT_STATE_MAX, + _SNAPSHOT_STATE_INVALID = -1 +} SnapshotState; + +typedef enum SocketState { + SOCKET_DEAD, + SOCKET_START_PRE, + SOCKET_START_CHOWN, + SOCKET_START_POST, + SOCKET_LISTENING, + SOCKET_RUNNING, + SOCKET_STOP_PRE, + SOCKET_STOP_PRE_SIGTERM, + SOCKET_STOP_PRE_SIGKILL, + SOCKET_STOP_POST, + SOCKET_FINAL_SIGTERM, + SOCKET_FINAL_SIGKILL, + SOCKET_FAILED, + _SOCKET_STATE_MAX, + _SOCKET_STATE_INVALID = -1 +} SocketState; + +typedef enum SwapState { + SWAP_DEAD, + SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */ + SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */ + SWAP_ACTIVE, + SWAP_DEACTIVATING, + SWAP_ACTIVATING_SIGTERM, + SWAP_ACTIVATING_SIGKILL, + SWAP_DEACTIVATING_SIGTERM, + SWAP_DEACTIVATING_SIGKILL, + SWAP_FAILED, + _SWAP_STATE_MAX, + _SWAP_STATE_INVALID = -1 +} SwapState; + + +typedef enum TargetState { + TARGET_DEAD, + TARGET_ACTIVE, + _TARGET_STATE_MAX, + _TARGET_STATE_INVALID = -1 +} TargetState; + +typedef enum TimerState { + TIMER_DEAD, + TIMER_WAITING, + TIMER_RUNNING, + TIMER_ELAPSED, + TIMER_FAILED, + _TIMER_STATE_MAX, + _TIMER_STATE_INVALID = -1 +} TimerState; + +typedef enum UnitDependency { /* Positive dependencies */ UNIT_REQUIRES, UNIT_REQUIRES_OVERRIDABLE, @@ -107,7 +270,7 @@ enum UnitDependency { _UNIT_DEPENDENCY_MAX, _UNIT_DEPENDENCY_INVALID = -1 -}; +} UnitDependency; typedef enum UnitNameFlags { UNIT_NAME_PLAIN = 1, /* Allow foo.service */ @@ -176,5 +339,47 @@ UnitType unit_type_from_string(const char *s) _pure_; const char *unit_load_state_to_string(UnitLoadState i) _const_; UnitLoadState unit_load_state_from_string(const char *s) _pure_; +const char *unit_active_state_to_string(UnitActiveState i) _const_; +UnitActiveState unit_active_state_from_string(const char *s) _pure_; + +const char* automount_state_to_string(AutomountState i) _const_; +AutomountState automount_state_from_string(const char *s) _pure_; + +const char* busname_state_to_string(BusNameState i) _const_; +BusNameState busname_state_from_string(const char *s) _pure_; + +const char* device_state_to_string(DeviceState i) _const_; +DeviceState device_state_from_string(const char *s) _pure_; + +const char* mount_state_to_string(MountState i) _const_; +MountState mount_state_from_string(const char *s) _pure_; + +const char* path_state_to_string(PathState i) _const_; +PathState path_state_from_string(const char *s) _pure_; + +const char* scope_state_to_string(ScopeState i) _const_; +ScopeState scope_state_from_string(const char *s) _pure_; + +const char* service_state_to_string(ServiceState i) _const_; +ServiceState service_state_from_string(const char *s) _pure_; + +const char* slice_state_to_string(SliceState i) _const_; +SliceState slice_state_from_string(const char *s) _pure_; + +const char* snapshot_state_to_string(SnapshotState i) _const_; +SnapshotState snapshot_state_from_string(const char *s) _pure_; + +const char* socket_state_to_string(SocketState i) _const_; +SocketState socket_state_from_string(const char *s) _pure_; + +const char* swap_state_to_string(SwapState i) _const_; +SwapState swap_state_from_string(const char *s) _pure_; + +const char* target_state_to_string(TargetState i) _const_; +TargetState target_state_from_string(const char *s) _pure_; + +const char *timer_state_to_string(TimerState i) _const_; +TimerState timer_state_from_string(const char *s) _pure_; + const char *unit_dependency_to_string(UnitDependency i) _const_; UnitDependency unit_dependency_from_string(const char *s) _pure_; diff --git a/src/basic/util.c b/src/basic/util.c index bc61ec0115..c63ec0ceb0 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -72,6 +72,7 @@ * otherwise conflicts with sys/mount.h. Yay, Linux is great! */ #include <linux/fs.h> +#include "build.h" #include "def.h" #include "device-nodes.h" #include "env-util.h" @@ -2550,90 +2551,6 @@ int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { return 0; } -cpu_set_t* cpu_set_malloc(unsigned *ncpus) { - cpu_set_t *r; - unsigned n = 1024; - - /* Allocates the cpuset in the right size */ - - for (;;) { - if (!(r = CPU_ALLOC(n))) - return NULL; - - if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) { - CPU_ZERO_S(CPU_ALLOC_SIZE(n), r); - - if (ncpus) - *ncpus = n; - - return r; - } - - CPU_FREE(r); - - if (errno != EINVAL) - return NULL; - - n *= 2; - } -} - -int parse_cpu_set( - const char *rvalue, - cpu_set_t **cpu_set, - const char *unit, - const char *filename, - unsigned line, - const char *lvalue) { - - const char *whole_rvalue = rvalue; - _cleanup_cpu_free_ cpu_set_t *c = NULL; - unsigned ncpus = 0; - - assert(filename); - assert(lvalue); - assert(rvalue); - - for (;;) { - _cleanup_free_ char *word = NULL; - unsigned cpu; - int r; - - r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Invalid value for %s: %s", lvalue, whole_rvalue); - return r; - } - if (r == 0) - break; - - r = safe_atou(word, &cpu); - - if (!c) - if (!(c = cpu_set_malloc(&ncpus))) - return log_oom(); - - if (r < 0 || cpu >= ncpus) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse CPU affinity '%s'", rvalue); - return -EBADMSG; - } - - CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); - } - if (!isempty(rvalue)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); - - /* On success, sets *cpu_set and returns ncpus for the system. */ - if (c) { - *cpu_set = c; - c = NULL; - } - return (int) ncpus; -} - int files_same(const char *filea, const char *fileb) { struct stat a, b; @@ -5427,15 +5344,13 @@ int update_reboot_param_file(const char *param) { int r = 0; if (param) { - r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE); if (r < 0) - log_error("Failed to write reboot param to " - REBOOT_PARAM_FILE": %s", strerror(-r)); + return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m"); } else - unlink(REBOOT_PARAM_FILE); + (void) unlink(REBOOT_PARAM_FILE); - return r; + return 0; } int umount_recursive(const char *prefix, int flags) { @@ -6069,6 +5984,7 @@ int extract_first_word_and_warn( const char *filename, unsigned line, const char *rvalue) { + /* Try to unquote it, if it fails, warn about it and try again but this * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim * in invalid escape sequences. */ @@ -6077,17 +5993,17 @@ int extract_first_word_and_warn( save = *p; r = extract_first_word(p, ret, separators, flags); - if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) { + if (r < 0 && !(flags & EXTRACT_CUNESCAPE_RELAX)) { + /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ *p = save; r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue); else - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, - "Invalid escape sequences in command line: \"%s\"", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid escape sequences in command line: \"%s\"", rvalue); } + return r; } @@ -6201,15 +6117,6 @@ int ptsname_malloc(int fd, char **ret) { int openpt_in_namespace(pid_t pid, int flags) { _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; _cleanup_close_pair_ int pair[2] = { -1, -1 }; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; siginfo_t si; pid_t child; int r; @@ -6243,15 +6150,7 @@ int openpt_in_namespace(pid_t pid, int flags) { if (unlockpt(master) < 0) _exit(EXIT_FAILURE); - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &master, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - - if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) + if (send_one_fd(pair[1], master, 0) < 0) _exit(EXIT_FAILURE); _exit(EXIT_SUCCESS); @@ -6265,26 +6164,7 @@ int openpt_in_namespace(pid_t pid, int flags) { if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) return -EIO; - if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) - return -errno; - - CMSG_FOREACH(cmsg, &mh) - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - int *fds; - unsigned n_fds; - - fds = (int*) CMSG_DATA(cmsg); - n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - - if (n_fds != 1) { - close_many(fds, n_fds); - return -EIO; - } - - return fds[0]; - } - - return -EIO; + return receive_one_fd(pair[0], 0); } ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) { @@ -6884,7 +6764,7 @@ int fgetxattr_malloc(int fd, const char *name, char **value) { } } -int send_one_fd(int transport_fd, int fd) { +int send_one_fd(int transport_fd, int fd, int flags) { union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(int))]; @@ -6894,7 +6774,6 @@ int send_one_fd(int transport_fd, int fd) { .msg_controllen = sizeof(control), }; struct cmsghdr *cmsg; - ssize_t k; assert(transport_fd >= 0); assert(fd >= 0); @@ -6906,14 +6785,13 @@ int send_one_fd(int transport_fd, int fd) { memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); mh.msg_controllen = CMSG_SPACE(sizeof(int)); - k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL); - if (k < 0) + if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0) return -errno; return 0; } -int receive_one_fd(int transport_fd) { +int receive_one_fd(int transport_fd, int flags) { union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(int))]; @@ -6922,33 +6800,45 @@ int receive_one_fd(int transport_fd) { .msg_control = &control, .msg_controllen = sizeof(control), }; - struct cmsghdr *cmsg; - ssize_t k; + struct cmsghdr *cmsg, *found = NULL; assert(transport_fd >= 0); /* - * Receive a single FD via @transport_fd. We don't care for the - * transport-type, but the caller must assure that no other CMSG types - * than SCM_RIGHTS is enabled. We also retrieve a single FD at most, so - * for packet-based transports, the caller must ensure to send only a - * single FD per packet. - * This is best used in combination with send_one_fd(). + * Receive a single FD via @transport_fd. We don't care for + * the transport-type. We retrieve a single FD at most, so for + * packet-based transports, the caller must ensure to send + * only a single FD per packet. This is best used in + * combination with send_one_fd(). */ - k = recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC); - if (k < 0) + if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0) return -errno; - cmsg = CMSG_FIRSTHDR(&mh); - if (!cmsg || CMSG_NXTHDR(&mh, cmsg) || - cmsg->cmsg_level != SOL_SOCKET || - cmsg->cmsg_type != SCM_RIGHTS || - cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || - *(const int *)CMSG_DATA(cmsg) < 0) { + CMSG_FOREACH(cmsg, &mh) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS && + cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { + assert(!found); + found = cmsg; + break; + } + } + + if (!found) { cmsg_close_all(&mh); return -EIO; } - return *(const int *)CMSG_DATA(cmsg); + return *(int*) CMSG_DATA(found); +} + +void nop_signal_handler(int sig) { + /* nothing here */ +} + +int version(void) { + puts(PACKAGE_STRING "\n" + SYSTEMD_FEATURES); + return 0; } diff --git a/src/basic/util.h b/src/basic/util.h index 56d9f037bf..a4e3672130 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -28,7 +28,6 @@ #include <limits.h> #include <locale.h> #include <mntent.h> -#include <sched.h> #include <stdarg.h> #include <stdbool.h> #include <stddef.h> @@ -371,12 +370,6 @@ int fd_is_temporary_fs(int fd); int pipe_eof(int fd); -DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); -#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) - -cpu_set_t* cpu_set_malloc(unsigned *ncpus); -int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue); - #define xsprintf(buf, fmt, ...) \ assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \ "xsprintf: " #buf "[] must be big enough") @@ -942,5 +935,9 @@ int reset_uid_gid(void); int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink); int fgetxattr_malloc(int fd, const char *name, char **value); -int send_one_fd(int transport_fd, int fd); -int receive_one_fd(int transport_fd); +int send_one_fd(int transport_fd, int fd, int flags); +int receive_one_fd(int transport_fd, int flags); + +void nop_signal_handler(int sig); + +int version(void); diff --git a/src/basic/virt.c b/src/basic/virt.c index 1fc6c1baba..70543177b6 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -240,7 +240,7 @@ static int detect_vm_zvm(void) { _cleanup_free_ char *t = NULL; int r; - r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t); + r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t); if (r == -ENOENT) return VIRTUALIZATION_NONE; if (r < 0) |