From 5a1765290e87f45b970657cfc8ac1e7ca5c50d6a Mon Sep 17 00:00:00 2001 From: Sven Eden Date: Tue, 13 Mar 2018 19:11:43 +0100 Subject: Prep v236 : Add missing SPDX-License-Identifier (2/9) src/basic --- src/basic/alloc-util.c | 1 + src/basic/alloc-util.h | 1 + src/basic/audit-util.c | 1 + src/basic/audit-util.h | 1 + src/basic/build.h | 1 + src/basic/bus-label.c | 1 + src/basic/bus-label.h | 1 + src/basic/cap-list.c | 1 + src/basic/cap-list.h | 1 + src/basic/capability-util.c | 1 + src/basic/capability-util.h | 1 + src/basic/cgroup-util.c | 254 ++++++++++++++++++++----------------- src/basic/cgroup-util.h | 12 +- src/basic/conf-files.c | 1 + src/basic/conf-files.h | 1 + src/basic/copy.c | 1 + src/basic/copy.h | 1 + src/basic/def.h | 5 +- src/basic/dirent-util.c | 1 + src/basic/dirent-util.h | 1 + src/basic/env-util.c | 1 + src/basic/env-util.h | 1 + src/basic/errno-list.c | 5 +- src/basic/errno-list.h | 9 +- src/basic/escape.c | 1 + src/basic/escape.h | 1 + src/basic/exec-util.c | 1 + src/basic/exec-util.h | 1 + src/basic/extract-word.c | 1 + src/basic/extract-word.h | 1 + src/basic/fd-util.c | 202 +++++++++++++++++++++++++++++ src/basic/fd-util.h | 13 ++ src/basic/fileio-label.c | 1 + src/basic/fileio-label.h | 1 + src/basic/fileio.c | 20 ++- src/basic/fileio.h | 1 + src/basic/format-util.h | 1 + src/basic/fs-util.c | 36 +++++- src/basic/fs-util.h | 5 +- src/basic/hash-funcs.c | 1 + src/basic/hash-funcs.h | 1 + src/basic/hashmap.c | 1 + src/basic/hashmap.h | 1 + src/basic/hexdecoct.c | 1 + src/basic/hexdecoct.h | 1 + src/basic/hostname-util.c | 101 +++++++++++---- src/basic/hostname-util.h | 6 +- src/basic/io-util.c | 1 + src/basic/io-util.h | 1 + src/basic/khash.c | 1 + src/basic/khash.h | 1 + src/basic/label.c | 1 + src/basic/label.h | 1 + src/basic/list.h | 1 + src/basic/locale-util.c | 1 + src/basic/locale-util.h | 1 + src/basic/log.c | 9 +- src/basic/log.h | 1 + src/basic/login-util.c | 1 + src/basic/login-util.h | 1 + src/basic/macro.h | 1 + src/basic/memfd-util.c | 1 + src/basic/memfd-util.h | 1 + src/basic/mempool.c | 1 + src/basic/mempool.h | 1 + src/basic/meson.build | 4 + src/basic/missing.h | 13 +- src/basic/missing_syscall.h | 1 + src/basic/mkdir-label.c | 5 +- src/basic/mkdir.c | 21 ++- src/basic/mkdir.h | 7 +- src/basic/mount-util.c | 174 +++++++++++++++++++------ src/basic/mount-util.h | 13 +- src/basic/parse-util.c | 60 +++++++++ src/basic/parse-util.h | 3 + src/basic/path-util.c | 39 +++++- src/basic/path-util.h | 4 +- src/basic/prioq.c | 1 + src/basic/prioq.h | 1 + src/basic/proc-cmdline.c | 1 + src/basic/proc-cmdline.h | 1 + src/basic/random-util.c | 1 + src/basic/random-util.h | 1 + src/basic/refcnt.h | 1 + src/basic/rm-rf.c | 1 + src/basic/rm-rf.h | 1 + src/basic/selinux-util.c | 1 + src/basic/selinux-util.h | 1 + src/basic/set.c | 1 + src/basic/set.h | 1 + src/basic/sigbus.c | 153 ++++++++++++++++++++++ src/basic/sigbus.h | 26 ++++ src/basic/signal-util.c | 3 +- src/basic/signal-util.h | 1 + src/basic/smack-util.c | 1 + src/basic/smack-util.h | 1 + src/basic/socket-util.c | 3 +- src/basic/socket-util.h | 1 + src/basic/sparse-endian.h | 4 +- src/basic/stat-util.c | 19 ++- src/basic/stat-util.h | 6 +- src/basic/stdio-util.h | 1 + src/basic/string-table.c | 1 + src/basic/string-table.h | 1 + src/basic/string-util.c | 55 ++++++-- src/basic/string-util.h | 13 ++ src/basic/strv.c | 1 + src/basic/strv.h | 9 ++ src/basic/syslog-util.c | 1 + src/basic/syslog-util.h | 1 + src/basic/terminal-util.c | 3 +- src/basic/terminal-util.h | 1 + src/basic/time-util.c | 7 + src/basic/time-util.h | 7 +- src/basic/umask-util.h | 1 + src/basic/unaligned.h | 1 + src/basic/unit-def.c | 290 ++++++++++++++++++++++++++++++++++++++++++ src/basic/unit-def.h | 302 ++++++++++++++++++++++++++++++++++++++++++++ src/basic/unit-name.c | 284 +---------------------------------------- src/basic/unit-name.h | 281 +---------------------------------------- src/basic/user-util.c | 62 +++++++-- src/basic/user-util.h | 1 + src/basic/utf8.c | 1 + src/basic/utf8.h | 1 + src/basic/util.c | 56 +++----- src/basic/util.h | 1 + src/basic/verbs.c | 1 + src/basic/verbs.h | 1 + src/basic/virt.c | 1 + src/basic/virt.h | 1 + src/basic/xattr-util.c | 3 +- src/basic/xattr-util.h | 1 + 132 files changed, 1838 insertions(+), 856 deletions(-) create mode 100644 src/basic/sigbus.c create mode 100644 src/basic/sigbus.h create mode 100644 src/basic/unit-def.c create mode 100644 src/basic/unit-def.h (limited to 'src/basic') diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c index ce7fb6b40..cdde4f285 100644 --- a/src/basic/alloc-util.c +++ b/src/basic/alloc-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index fb10c3279..02dee37d3 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c index f6b448aeb..973e2e6f8 100644 --- a/src/basic/audit-util.c +++ b/src/basic/audit-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/audit-util.h b/src/basic/audit-util.h index 3e354eea7..f6ca071b7 100644 --- a/src/basic/audit-util.h +++ b/src/basic/audit-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/build.h b/src/basic/build.h index a454c9465..b887e8e90 100644 --- a/src/basic/build.h +++ b/src/basic/build.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/bus-label.c b/src/basic/bus-label.c index d4531c794..a072d0ad5 100644 --- a/src/basic/bus-label.c +++ b/src/basic/bus-label.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/bus-label.h b/src/basic/bus-label.h index 600268b76..5c6bc1f26 100644 --- a/src/basic/bus-label.h +++ b/src/basic/bus-label.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c index 2b1779668..c4557666e 100644 --- a/src/basic/cap-list.c +++ b/src/basic/cap-list.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/cap-list.h b/src/basic/cap-list.h index f9f6b70d8..ca9f4aa97 100644 --- a/src/basic/cap-list.h +++ b/src/basic/cap-list.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index 66324021a..dae4dbc5b 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h index feaa3735e..97a797b19 100644 --- a/src/basic/capability-util.h +++ b/src/basic/capability-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index b57f20cad..79635cfe9 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -23,6 +24,7 @@ //#include #include //#include +#include #include #include #include @@ -882,115 +884,87 @@ int cg_attach_fallback(const char *controller, const char *path, pid_t pid) { } #if 0 /// UNNEEDED by elogind -int cg_set_group_access( +int cg_set_access( const char *controller, const char *path, - mode_t mode, uid_t uid, gid_t gid) { - _cleanup_free_ char *fs = NULL; - int r; - - if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID) - return 0; - - if (mode != MODE_INVALID) - mode &= 0777; - - r = cg_get_path(controller, path, NULL, &fs); - if (r < 0) - return r; - - r = chmod_and_chown(fs, mode, uid, gid); - if (r < 0) - return r; - - r = cg_hybrid_unified(); - if (r < 0) - return r; - if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) { - r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid); - if (r < 0) - log_debug_errno(r, "Failed to set group access on compatibility systemd cgroup %s, ignoring: %m", path); - } - - return 0; -} - -int cg_set_task_access( - const char *controller, - const char *path, - mode_t mode, - uid_t uid, - gid_t gid) { + struct Attribute { + const char *name; + bool fatal; + }; + + /* cgroupsv1, aka legacy/non-unified */ + static const struct Attribute legacy_attributes[] = { + { "cgroup.procs", true }, + { "tasks", false }, + { "cgroup.clone_children", false }, + {}, + }; + + /* cgroupsv2, aka unified */ + static const struct Attribute unified_attributes[] = { + { "cgroup.procs", true }, + { "cgroup.subtree_control", true }, + { "cgroup.threads", false }, + {}, + }; + + static const struct Attribute* const attributes[] = { + [false] = legacy_attributes, + [true] = unified_attributes, + }; _cleanup_free_ char *fs = NULL; - int r; + const struct Attribute *i; + int r, unified; assert(path); - if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID) + if (uid == UID_INVALID && gid == GID_INVALID) return 0; - if (mode != MODE_INVALID) - mode &= 0666; - - /* For both the legacy and unified hierarchies, "cgroup.procs" is the main entry point for PIDs */ - r = cg_get_path(controller, path, "cgroup.procs", &fs); - if (r < 0) - return r; + unified = cg_unified_controller(controller); + if (unified < 0) + return unified; - r = chmod_and_chown(fs, mode, uid, gid); + /* Configure access to the cgroup itself */ + r = cg_get_path(controller, path, NULL, &fs); if (r < 0) return r; - r = cg_unified_controller(controller); + r = chmod_and_chown(fs, 0755, uid, gid); if (r < 0) return r; - if (r == 0) { - const char *fn; - - /* Compatibility: on cgroupsv1 always keep values for the legacy files "tasks" and - * "cgroup.clone_children" in sync with "cgroup.procs". Since this is legacy stuff, we don't care if - * this fails. */ - - FOREACH_STRING(fn, - "tasks", - "cgroup.clone_children") { - - fs = mfree(fs); - - r = cg_get_path(controller, path, fn, &fs); - if (r < 0) - log_debug_errno(r, "Failed to get path for %s of %s, ignoring: %m", fn, path); - - r = chmod_and_chown(fs, mode, uid, gid); - if (r < 0) - log_debug_errno(r, "Failed to to change ownership/access mode for %s of %s, ignoring: %m", fn, path); - } - } else { - /* On the unified controller, we want to permit subtree controllers too. */ + /* Configure access to the cgroup's attributes */ + for (i = attributes[unified]; i->name; i++) { fs = mfree(fs); - r = cg_get_path(controller, path, "cgroup.subtree_control", &fs); - if (r < 0) - return r; - r = chmod_and_chown(fs, mode, uid, gid); + r = cg_get_path(controller, path, i->name, &fs); if (r < 0) return r; - } - r = cg_hybrid_unified(); - if (r < 0) - return r; - if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) { - /* Always propagate access mode from unified to legacy controller */ + r = chmod_and_chown(fs, 0644, uid, gid); + if (r < 0) { + if (i->fatal) + return r; - r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid); + log_debug_errno(r, "Failed to set access on cgroup %s, ignoring: %m", fs); + } + } + + if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) { + r = cg_hybrid_unified(); if (r < 0) - log_debug_errno(r, "Failed to set task access on compatibility systemd cgroup %s, ignoring: %m", path); + return r; + if (r > 0) { + /* Always propagate access mode from unified to legacy controller */ + r = cg_set_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, uid, gid); + if (r < 0) + log_debug_errno(r, "Failed to set access on compatibility elogind cgroup %s, ignoring: %m", path); + } } return 0; @@ -1073,6 +1047,8 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) { if (!f) return errno == ENOENT ? -ESRCH : -errno; + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + FOREACH_LINE(line, f, return -errno) { char *e, *p; @@ -1300,7 +1276,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) { assert(spec); if (*spec == '/') { - if (!path_is_safe(spec)) + if (!path_is_normalized(spec)) return -EINVAL; if (path) { @@ -1353,7 +1329,7 @@ int cg_split_spec(const char *spec, char **controller, char **path) { return -ENOMEM; } - if (!path_is_safe(u) || + if (!path_is_normalized(u) || !path_is_absolute(u)) { free(t); free(u); @@ -1528,7 +1504,7 @@ static bool valid_slice_name(const char *p, size_t n) { if (!p) return false; - if (n < strlen("x.slice")) + if (n < STRLEN("x.slice")) return false; if (memcmp(p + n - 6, ".slice", 6) == 0) { @@ -1612,7 +1588,7 @@ static const char *skip_session(const char *p) { p += strspn(p, "/"); n = strcspn(p, "/"); - if (n < strlen("session-x.scope")) + if (n < STRLEN("session-x.scope")) return NULL; if (memcmp(p, "session-", 8) == 0 && memcmp(p + n - 6, ".scope", 6) == 0) { @@ -1649,7 +1625,7 @@ static const char *skip_user_manager(const char *p) { p += strspn(p, "/"); n = strcspn(p, "/"); - if (n < strlen("user@x.service")) + if (n < STRLEN("user@x.service")) return NULL; if (memcmp(p, "user@", 5) == 0 && memcmp(p + n - 8, ".service", 8) == 0) { @@ -2355,10 +2331,10 @@ int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) #endif // 0 int cg_mask_to_string(CGroupMask mask, char **ret) { - const char *controllers[_CGROUP_CONTROLLER_MAX + 1]; + _cleanup_free_ char *s = NULL; + size_t n = 0, allocated = 0; + bool space = false; CGroupController c; - int i = 0; - char *s; assert(ret); @@ -2368,19 +2344,32 @@ int cg_mask_to_string(CGroupMask mask, char **ret) { } for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) { + const char *k; + size_t l; if (!(mask & CGROUP_CONTROLLER_TO_MASK(c))) continue; - controllers[i++] = cgroup_controller_to_string(c); - controllers[i] = NULL; + k = cgroup_controller_to_string(c); + l = strlen(k); + + if (!GREEDY_REALLOC(s, allocated, n + space + l + 1)) + return -ENOMEM; + + if (space) + s[n] = ' '; + memcpy(s + n + space, k, l); + n += space + l; + + space = true; } - s = strv_join((char **)controllers, NULL); - if (!s) - return -ENOMEM; + assert(s); + s[n] = 0; *ret = s; + s = NULL; + return 0; } @@ -2467,24 +2456,34 @@ int cg_mask_supported(CGroupMask *ret) { } #if 0 /// UNNEEDED by elogind -int cg_kernel_controllers(Set *controllers) { +int cg_kernel_controllers(Set **ret) { + _cleanup_set_free_free_ Set *controllers = NULL; _cleanup_fclose_ FILE *f = NULL; int r; - assert(controllers); + assert(ret); /* Determines the full list of kernel-known controllers. Might * include controllers we don't actually support, arbitrary * named hierarchies and controllers that aren't currently * accessible (because not mounted). */ + controllers = set_new(&string_hash_ops); + if (!controllers) + return -ENOMEM; + f = fopen("/proc/cgroups", "re"); if (!f) { - if (errno == ENOENT) + if (errno == ENOENT) { + *ret = NULL; return 0; + } + return -errno; } + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + /* Ignore the header line */ (void) read_line(f, (size_t) -1, NULL); @@ -2519,6 +2518,9 @@ int cg_kernel_controllers(Set *controllers) { return r; } + *ret = controllers; + controllers = NULL; + return 0; } #endif // 0 @@ -2549,39 +2551,48 @@ static int cg_unified_update(void) { return 0; if (statfs("/sys/fs/cgroup/", &fs) < 0) - return -errno; + return log_debug_errno(errno, "statfs(\"/sys/fs/cgroup/\" failed: %m"); - if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) + if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) { + log_debug("Found cgroup2 on /sys/fs/cgroup/, full unified hierarchy"); unified_cache = CGROUP_UNIFIED_ALL; #if 0 /// The handling of cgroups is a bit different with elogind - else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) { + } else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) { #else - else if (F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC) + } else if (F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC) || F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) { #endif // 0 if (statfs("/sys/fs/cgroup/unified/", &fs) == 0 && F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) { + log_debug("Found cgroup2 on /sys/fs/cgroup/unified, unified hierarchy for elogind controller"); unified_cache = CGROUP_UNIFIED_SYSTEMD; unified_systemd_v232 = false; -#if 0 /// elogind uses its own name - } else if (statfs("/sys/fs/cgroup/systemd/", &fs) == 0 && -#else - } else if (statfs("/sys/fs/cgroup/elogind/", &fs) == 0 && -#endif // 0 - F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) { - unified_cache = CGROUP_UNIFIED_SYSTEMD; - unified_systemd_v232 = true; } else { #if 0 /// There is no sub-grouping within elogind if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0) - return -errno; - if (!F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC)) - return -ENOMEDIUM; -#endif // 0 + return log_debug_errno(errno, "statfs(\"/sys/fs/cgroup/systemd\" failed: %m"); + + if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) { + log_debug("Found cgroup2 on /sys/fs/cgroup/systemd, unified hierarchy for systemd controller (v232 variant)"); + unified_cache = CGROUP_UNIFIED_SYSTEMD; + unified_systemd_v232 = true; + } else if (F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC)) { + log_debug("Found cgroup on /sys/fs/cgroup/systemd, legacy hierarchy"); + unified_cache = CGROUP_UNIFIED_NONE; + } else { + log_debug("Unexpected filesystem type %llx mounted on /sys/fs/cgroup/systemd, assuming legacy hierarchy", + (unsigned long long) fs.f_type); + unified_cache = CGROUP_UNIFIED_NONE; + } +#else unified_cache = CGROUP_UNIFIED_NONE; +#endif // 0 } - } else + } else { + log_debug("Unknown filesystem type %llx mounted on /sys/fs/cgroup.", + (unsigned long long) fs.f_type); return -ENOMEDIUM; + } return 0; } @@ -2634,6 +2645,7 @@ int cg_unified_flush(void) { #if 0 /// UNNEEDED by elogind int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) { + _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *fs = NULL; CGroupController c; int r; @@ -2667,7 +2679,15 @@ int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) { s[0] = mask & bit ? '+' : '-'; strcpy(s + 1, n); - r = write_string_file(fs, s, 0); + if (!f) { + f = fopen(fs, "we"); + if (!f) { + log_debug_errno(errno, "Failed to open cgroup.subtree_control file of %s: %m", p); + break; + } + } + + r = write_string_stream(f, s, 0); if (r < 0) log_debug_errno(r, "Failed to enable controller %s for %s (%s): %m", n, p, fs); } diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 95bea3111..455921d37 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -31,6 +32,12 @@ //#include "macro.h" #include "set.h" +#if 0 /// elogind has them set through config.h +#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=elogind" +#define SYSTEMD_CGROUP_CONTROLLER_HYBRID "name=unified" +#define SYSTEMD_CGROUP_CONTROLLER "_elogind" +#endif // 0 + /* An enum of well known cgroup controllers */ typedef enum CGroupController { CGROUP_CONTROLLER_CPU, @@ -190,8 +197,7 @@ int cg_get_attribute(const char *controller, const char *path, const char *attri #if 0 /// UNNEEDED by elogind int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, const char **keys, char **values); -int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid); -int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid); +int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid); int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags); int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size); @@ -255,7 +261,7 @@ int cg_mask_from_string(const char *s, CGroupMask *ret); int cg_mask_to_string(CGroupMask mask, char **ret); #if 0 /// UNNEEDED by elogind -int cg_kernel_controllers(Set *controllers); +int cg_kernel_controllers(Set **controllers); bool cg_ns_supported(void); #endif // 0 diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index 907d1350f..c0ac202f5 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h index 20ecf6e5f..75dfd05e7 100644 --- a/src/basic/conf-files.h +++ b/src/basic/conf-files.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/copy.c b/src/basic/copy.c index 6827290e2..7d5f2d37c 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/copy.h b/src/basic/copy.h index d46f1c92a..f22242ed8 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/def.h b/src/basic/def.h index 377c0008c..fdc202621 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -37,9 +38,6 @@ #define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL #if 0 /// elogind allows foreign cgroup controllers. (Well, needs them, actually) -#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=systemd" -#define SYSTEMD_CGROUP_CONTROLLER_HYBRID "name=unified" -#define SYSTEMD_CGROUP_CONTROLLER "_systemd" #else #ifndef SYSTEMD_CGROUP_CONTROLLER_LEGACY # define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=elogind" @@ -51,7 +49,6 @@ # define SYSTEMD_CGROUP_CONTROLLER "_elogind" #endif // SYSTEMD_CGROUP_CONTROLLER #endif // 0 - #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT #define SIGNALS_IGNORE SIGPIPE diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index 5bf58bcdc..e2b093bad 100644 --- a/src/basic/dirent-util.c +++ b/src/basic/dirent-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h index 18b9db9b2..94d5ee81a 100644 --- a/src/basic/dirent-util.h +++ b/src/basic/dirent-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/env-util.c b/src/basic/env-util.c index 7269000d9..648851bcb 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/env-util.h b/src/basic/env-util.h index e8ef51193..ca548e133 100644 --- a/src/basic/env-util.h +++ b/src/basic/env-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/errno-list.c b/src/basic/errno-list.c index c568629f7..ee48332db 100644 --- a/src/basic/errno-list.c +++ b/src/basic/errno-list.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -51,9 +52,5 @@ int errno_from_name(const char *name) { assert(sc->id > 0); return sc->id; } - #if 0 /// UNNEEDED by elogind -int errno_max(void) { - return ELEMENTSOF(errno_names); -} #endif // 0 diff --git a/src/basic/errno-list.h b/src/basic/errno-list.h index fb3d05e5e..acd70950d 100644 --- a/src/basic/errno-list.h +++ b/src/basic/errno-list.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -19,9 +20,13 @@ along with systemd; If not, see . ***/ +/* + * MAX_ERRNO is defined as 4095 in linux/err.h + * We use the same value here. + */ +#define ERRNO_MAX 4095 + const char *errno_to_name(int id); int errno_from_name(const char *name); - #if 0 /// UNNEEDED by elogind -int errno_max(void); #endif // 0 diff --git a/src/basic/escape.c b/src/basic/escape.c index 466dadc7c..fda015fcb 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/escape.h b/src/basic/escape.h index 2977145d6..5dcc24fb8 100644 --- a/src/basic/escape.h +++ b/src/basic/escape.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/exec-util.c b/src/basic/exec-util.c index f96a78aab..718fbf7ee 100644 --- a/src/basic/exec-util.c +++ b/src/basic/exec-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/exec-util.h b/src/basic/exec-util.h index a89f9bc68..b1ef16e5d 100644 --- a/src/basic/exec-util.h +++ b/src/basic/exec-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index 2a61a1e63..b900d7e19 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h index 36006a5b6..fbabf7a20 100644 --- a/src/basic/extract-word.h +++ b/src/basic/extract-word.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index a2d51d807..7fb99feb3 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -26,8 +27,10 @@ #include "dirent-util.h" #include "fd-util.h" +#include "fileio.h" #include "fs-util.h" #include "macro.h" +#include "memfd-util.h" #include "missing.h" #include "parse-util.h" #include "path-util.h" @@ -381,3 +384,202 @@ int fd_get_path(int fd, char **ret) { return r; } #endif // 0 + +int move_fd(int from, int to, int cloexec) { + int r; + + /* Move fd 'from' to 'to', make sure FD_CLOEXEC remains equal if requested, and release the old fd. If + * 'cloexec' is passed as -1, the original FD_CLOEXEC is inherited for the new fd. If it is 0, it is turned + * off, if it is > 0 it is turned on. */ + + if (from < 0) + return -EBADF; + if (to < 0) + return -EBADF; + + if (from == to) { + + if (cloexec >= 0) { + r = fd_cloexec(to, cloexec); + if (r < 0) + return r; + } + + return to; + } + + if (cloexec < 0) { + int fl; + + fl = fcntl(from, F_GETFD, 0); + if (fl < 0) + return -errno; + + cloexec = !!(fl & FD_CLOEXEC); + } + + r = dup3(from, to, cloexec ? O_CLOEXEC : 0); + if (r < 0) + return -errno; + + assert(r == to); + + safe_close(from); + + return to; +} + +int acquire_data_fd(const void *data, size_t size, unsigned flags) { + + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_close_pair_ int pipefds[2] = { -1, -1 }; + char pattern[] = "/dev/shm/data-fd-XXXXXX"; + _cleanup_close_ int fd = -1; + int isz = 0, r; + ssize_t n; + off_t f; + + assert(data || size == 0); + + /* Acquire a read-only file descriptor that when read from returns the specified data. This is much more + * complex than I wish it was. But here's why: + * + * a) First we try to use memfds. They are the best option, as we can seal them nicely to make them + * read-only. Unfortunately they require kernel 3.17, and – at the time of writing – we still support 3.14. + * + * b) Then, we try classic pipes. They are the second best options, as we can close the writing side, retaining + * a nicely read-only fd in the reading side. However, they are by default quite small, and unprivileged + * clients can only bump their size to a system-wide limit, which might be quite low. + * + * c) Then, we try an O_TMPFILE file in /dev/shm (that dir is the only suitable one known to exist from + * earliest boot on). To make it read-only we open the fd a second time with O_RDONLY via + * /proc/self/. Unfortunately O_TMPFILE is not available on older kernels on tmpfs. + * + * d) Finally, we try creating a regular file in /dev/shm, which we then delete. + * + * It sucks a bit that depending on the situation we return very different objects here, but that's Linux I + * figure. */ + + if (size == 0 && ((flags & ACQUIRE_NO_DEV_NULL) == 0)) { + /* As a special case, return /dev/null if we have been called for an empty data block */ + r = open("/dev/null", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (r < 0) + return -errno; + + return r; + } + + if ((flags & ACQUIRE_NO_MEMFD) == 0) { + fd = memfd_new("data-fd"); + if (fd < 0) + goto try_pipe; + + n = write(fd, data, size); + if (n < 0) + return -errno; + if ((size_t) n != size) + return -EIO; + + f = lseek(fd, 0, SEEK_SET); + if (f != 0) + return -errno; + + r = memfd_set_sealed(fd); + if (r < 0) + return r; + + r = fd; + fd = -1; + + return r; + } + +try_pipe: + if ((flags & ACQUIRE_NO_PIPE) == 0) { + if (pipe2(pipefds, O_CLOEXEC|O_NONBLOCK) < 0) + return -errno; + + isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0); + if (isz < 0) + return -errno; + + if ((size_t) isz < size) { + isz = (int) size; + if (isz < 0 || (size_t) isz != size) + return -E2BIG; + + /* Try to bump the pipe size */ + (void) fcntl(pipefds[1], F_SETPIPE_SZ, isz); + + /* See if that worked */ + isz = fcntl(pipefds[1], F_GETPIPE_SZ, 0); + if (isz < 0) + return -errno; + + if ((size_t) isz < size) + goto try_dev_shm; + } + + n = write(pipefds[1], data, size); + if (n < 0) + return -errno; + if ((size_t) n != size) + return -EIO; + + (void) fd_nonblock(pipefds[0], false); + + r = pipefds[0]; + pipefds[0] = -1; + + return r; + } + +try_dev_shm: + if ((flags & ACQUIRE_NO_TMPFILE) == 0) { + fd = open("/dev/shm", O_RDWR|O_TMPFILE|O_CLOEXEC, 0500); + if (fd < 0) + goto try_dev_shm_without_o_tmpfile; + + n = write(fd, data, size); + if (n < 0) + return -errno; + if ((size_t) n != size) + return -EIO; + + /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */ + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + r = open(procfs_path, O_RDONLY|O_CLOEXEC); + if (r < 0) + return -errno; + + return r; + } + +try_dev_shm_without_o_tmpfile: + if ((flags & ACQUIRE_NO_REGULAR) == 0) { + fd = mkostemp_safe(pattern); + if (fd < 0) + return fd; + + n = write(fd, data, size); + if (n < 0) { + r = -errno; + goto unlink_and_return; + } + if ((size_t) n != size) { + r = -EIO; + goto unlink_and_return; + } + + /* Let's reopen the thing, in order to get an O_RDONLY fd for the original O_RDWR one */ + r = open(pattern, O_RDONLY|O_CLOEXEC); + if (r < 0) + r = -errno; + + unlink_and_return: + (void) unlink(pattern); + return r; + } + + return -EOPNOTSUPP; +} diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index fe92b76c4..eeded4417 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -79,6 +80,18 @@ bool fdname_is_valid(const char *s); int fd_get_path(int fd, char **ret); #endif // 0 +int move_fd(int from, int to, int cloexec); + +enum { + ACQUIRE_NO_DEV_NULL = 1 << 0, + ACQUIRE_NO_MEMFD = 1 << 1, + ACQUIRE_NO_PIPE = 1 << 2, + ACQUIRE_NO_TMPFILE = 1 << 3, + ACQUIRE_NO_REGULAR = 1 << 4, +}; + +int acquire_data_fd(const void *data, size_t size, unsigned flags); + /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ #define ERRNO_IS_DISCONNECT(r) \ IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) diff --git a/src/basic/fileio-label.c b/src/basic/fileio-label.c index 4cb207742..6b942627a 100644 --- a/src/basic/fileio-label.c +++ b/src/basic/fileio-label.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/fileio-label.h b/src/basic/fileio-label.h index 42676a352..f6d33a678 100644 --- a/src/basic/fileio-label.h +++ b/src/basic/fileio-label.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 2f9d47019..5a918c1e7 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -22,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +99,7 @@ static int write_string_file_atomic( if (r < 0) return r; + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); (void) fchmod_umask(fileno(f), 0644); r = write_string_stream_ts(f, line, flags, ts); @@ -166,6 +169,8 @@ int write_string_file_ts( } } + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + if (flags & WRITE_STRING_FILE_DISABLE_BUFFER) setvbuf(f, NULL, _IONBF, 0); @@ -202,6 +207,8 @@ int read_one_line_file(const char *fn, char **line) { if (!f) return -errno; + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + r = read_line(f, LONG_LINE_MAX, line); return r < 0 ? r : 0; } @@ -227,6 +234,8 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { if (!f) return -errno; + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + /* We try to read one byte more than we need, so that we know whether we hit eof */ errno = 0; k = fread(buf, 1, l + accept_extra_nl + 1, f); @@ -322,6 +331,8 @@ int read_full_file(const char *fn, char **contents, size_t *size) { if (!f) return -errno; + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + return read_full_stream(f, contents, size); } @@ -881,7 +892,8 @@ int write_env_file(const char *fname, char **l) { if (r < 0) return r; - fchmod_umask(fileno(f), 0644); + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + (void) fchmod_umask(fileno(f), 0644); STRV_FOREACH(i, l) write_env_var(f, *i); @@ -1471,7 +1483,7 @@ int link_tmpfile(int fd, const char *path, const char *target) { if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0) return -errno; } else { - char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; + char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; xsprintf(proc_fd_path, "/proc/self/fd/%i", fd); @@ -1543,9 +1555,7 @@ int mkdtemp_malloc(const char *template, char **ret) { } #endif // 0 -static inline void funlockfilep(FILE **f) { - funlockfile(*f); -} +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile); int read_line(FILE *f, size_t limit, char **ret) { _cleanup_free_ char *buffer = NULL; diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 08423c1c9..4462056d7 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/format-util.h b/src/basic/format-util.h index ae42a8f89..d9a78f781 100644 --- a/src/basic/format-util.h +++ b/src/basic/format-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 82df411fd..354c97d8b 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -108,7 +109,6 @@ int rmdir_parents(const char *path, const char *stop) { return 0; } - int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { struct stat buf; int ret; @@ -520,7 +520,7 @@ static int getenv_tmp_dir(const char **ret_path) { r = -ENOTDIR; goto next; } - if (!path_is_safe(e)) { + if (!path_is_normalized(e)) { r = -EPERM; goto next; } @@ -594,7 +594,7 @@ int tmp_dir(const char **ret) { #if 0 /// UNNEEDED by elogind int inotify_add_watch_fd(int fd, int what, uint32_t mask) { - char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; int r; /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */ @@ -673,9 +673,18 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, todo += m; + /* Empty? Then we reached the end. */ + if (isempty(first)) + break; + /* Just a single slash? Then we reached the end. */ - if (isempty(first) || path_equal(first, "/")) + if (path_equal(first, "/")) { + /* Preserve the trailing slash */ + if (!strextend(&done, "/", NULL)) + return -ENOMEM; + break; + } /* Just a dot? Then let's eat this up. */ if (path_equal(first, "/.")) @@ -719,7 +728,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (errno == ENOENT && (flags & CHASE_NONEXISTENT) && - (isempty(todo) || path_is_safe(todo))) { + (isempty(todo) || path_is_normalized(todo))) { /* If CHASE_NONEXISTENT is set, and the path does not exist, then that's OK, return * what we got so far. But don't allow this if the remaining path contains "../ or "./" @@ -742,7 +751,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (fstat(child, &st) < 0) return -errno; if ((flags & CHASE_NO_AUTOFS) && - fd_check_fstype(child, AUTOFS_SUPER_MAGIC) > 0) + fd_is_fs_type(child, AUTOFS_SUPER_MAGIC) > 0) return -EREMOTE; if (S_ISLNK(st.st_mode)) { @@ -829,3 +838,18 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return exists; } + +int access_fd(int fd, int mode) { + char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; + int r; + + /* Like access() but operates on an already open fd */ + + xsprintf(p, "/proc/self/fd/%i", fd); + + r = access(p, mode); + if (r < 0) + r = -errno; + + return r; +} diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index f30b69550..c22e967f9 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -100,7 +101,6 @@ enum { int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret); -#if 0 /// UNNEEDED by elogind /* Useful for usage with _cleanup_(), removes a directory and frees the pointer */ static inline void rmdir_and_free(char *p) { (void) rmdir(p); @@ -108,9 +108,12 @@ static inline void rmdir_and_free(char *p) { } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rmdir_and_free); +#if 0 /// UNNEEDED by elogind static inline void unlink_and_free(char *p) { (void) unlink(p); free(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free); #endif // 0 + +int access_fd(int fd, int mode); diff --git a/src/basic/hash-funcs.c b/src/basic/hash-funcs.c index c3a4a011b..e69f81558 100644 --- a/src/basic/hash-funcs.c +++ b/src/basic/hash-funcs.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/hash-funcs.h b/src/basic/hash-funcs.h index 299189d14..959e2c101 100644 --- a/src/basic/hash-funcs.h +++ b/src/basic/hash-funcs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index b303fe74f..6d3412df9 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index 57809f50b..0eb763944 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index 954afbf66..fe7e4954e 100644 --- a/src/basic/hexdecoct.c +++ b/src/basic/hexdecoct.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h index 1ba2f69eb..08d0a5227 100644 --- a/src/basic/hexdecoct.h +++ b/src/basic/hexdecoct.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 5297b659d..f5435d523 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -24,6 +25,8 @@ #include #include +//#include "alloc-util.h" +//#include "def.h" //#include "fd-util.h" #include "fileio.h" #include "hostname-util.h" @@ -229,36 +232,88 @@ int sethostname_idempotent(const char *s) { return 1; } -int read_hostname_config(const char *path, char **hostname) { - _cleanup_fclose_ FILE *f = NULL; - char l[LINE_MAX]; - char *name = NULL; +int shorten_overlong(const char *s, char **ret) { + char *h, *p; - assert(path); - assert(hostname); + /* Shorten an overlong name to HOST_NAME_MAX or to the first dot, + * whatever comes earlier. */ - f = fopen(path, "re"); - if (!f) - return -errno; + assert(s); + + h = strdup(s); + if (!h) + return -ENOMEM; + + if (hostname_is_valid(h, false)) { + *ret = h; + return 0; + } + + p = strchr(h, '.'); + if (p) + *p = 0; + + strshorten(h, HOST_NAME_MAX); + + if (!hostname_is_valid(h, false)) { + free(h); + return -EDOM; + } + + *ret = h; + return 1; +} + +int read_etc_hostname_stream(FILE *f, char **ret) { + int r; - /* may have comments, ignore them */ - FOREACH_LINE(l, f, return -errno) { - truncate_nl(l); - if (!IN_SET(l[0], '\0', '#')) { - /* found line with value */ - name = hostname_cleanup(l); - name = strdup(name); - if (!name) + assert(f); + assert(ret); + + for (;;) { + _cleanup_free_ char *line = NULL; + char *p; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return r; + if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */ + return -ENOENT; + + p = strstrip(line); + + /* File may have empty lines or comments, ignore them */ + if (!IN_SET(*p, '\0', '#')) { + char *copy; + + hostname_cleanup(p); /* normalize the hostname */ + + if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */ + return -EBADMSG; + + copy = strdup(p); + if (!copy) return -ENOMEM; - break; + + *ret = copy; + return 0; } } +} - if (!name) - /* no non-empty line found */ - return -ENOENT; +int read_etc_hostname(const char *path, char **ret) { + _cleanup_fclose_ FILE *f = NULL; + + assert(ret); + + if (!path) + path = "/etc/hostname"; + + f = fopen(path, "re"); + if (!f) + return -errno; + + return read_etc_hostname_stream(f, ret); - *hostname = name; - return 0; } #endif // 0 diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index 4282d71ae..c10ba3261 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -45,5 +46,8 @@ bool is_gateway_hostname(const char *hostname); int sethostname_idempotent(const char *s); -int read_hostname_config(const char *path, char **hostname); #endif // 0 +int shorten_overlong(const char *s, char **ret); + +int read_etc_hostname_stream(FILE *f, char **ret); +int read_etc_hostname(const char *path, char **ret); diff --git a/src/basic/io-util.c b/src/basic/io-util.c index 2141634da..77c9bdc73 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/io-util.h b/src/basic/io-util.h index d9b69adde..d81610ad2 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/khash.c b/src/basic/khash.c index 2e89c2cb3..694210512 100644 --- a/src/basic/khash.c +++ b/src/basic/khash.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/khash.h b/src/basic/khash.h index 410f3020e..7041d3999 100644 --- a/src/basic/khash.h +++ b/src/basic/khash.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/label.c b/src/basic/label.c index 3556377d2..17857de1b 100644 --- a/src/basic/label.c +++ b/src/basic/label.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/label.h b/src/basic/label.h index dc702f5cb..fa49c2e20 100644 --- a/src/basic/label.h +++ b/src/basic/label.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/list.h b/src/basic/list.h index acc410aef..7006c3e27 100644 --- a/src/basic/list.h +++ b/src/basic/list.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 0e546c050..266cb2993 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index 104864501..60ce017a1 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/log.c b/src/basic/log.c index ce96ac443..43cb70096 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -1064,18 +1065,18 @@ int log_struct_iovec_internal( } for (i = 0; i < n_input_iovec; i++) { - if (input_iovec[i].iov_len < strlen("MESSAGE=")) + if (input_iovec[i].iov_len < STRLEN("MESSAGE=")) continue; - if (memcmp(input_iovec[i].iov_base, "MESSAGE=", strlen("MESSAGE=")) == 0) + if (memcmp(input_iovec[i].iov_base, "MESSAGE=", STRLEN("MESSAGE=")) == 0) break; } if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */ return -error; - m = strndupa(input_iovec[i].iov_base + strlen("MESSAGE="), - input_iovec[i].iov_len - strlen("MESSAGE=")); + m = strndupa(input_iovec[i].iov_base + STRLEN("MESSAGE="), + input_iovec[i].iov_len - STRLEN("MESSAGE=")); return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m); } diff --git a/src/basic/log.h b/src/basic/log.h index 7b67fd45b..78b097f0f 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/login-util.c b/src/basic/login-util.c index 339e94f12..af4539453 100644 --- a/src/basic/login-util.c +++ b/src/basic/login-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/login-util.h b/src/basic/login-util.h index b01ee25c8..1c558bfe2 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/macro.h b/src/basic/macro.h index d73adc021..02d22de83 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index 231c2de71..65b873ae0 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index 781d1a431..79a20a888 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/mempool.c b/src/basic/mempool.c index f95e2beb0..0da8e1f77 100644 --- a/src/basic/mempool.c +++ b/src/basic/mempool.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/mempool.h b/src/basic/mempool.h index 0618b8dd2..c9235c836 100644 --- a/src/basic/mempool.h +++ b/src/basic/mempool.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/meson.build b/src/basic/meson.build index 88000bfb3..3ea5e059a 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -319,6 +319,8 @@ basic_sources_plain = files(''' selinux-util.h set.c set.h + sigbus.c + sigbus.h signal-util.c signal-util.h siphash24.c @@ -345,6 +347,8 @@ basic_sources_plain = files(''' time-util.h umask-util.h unaligned.h + unit-def.c + unit-def.h unit-name.c unit-name.h user-util.c diff --git a/src/basic/missing.h b/src/basic/missing.h index d7165cbe2..9f174d453 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -547,10 +548,6 @@ struct btrfs_ioctl_quota_ctl_args { #define PR_SET_CHILD_SUBREAPER 36 #endif -#ifndef MAX_HANDLE_SZ -#define MAX_HANDLE_SZ 128 -#endif - #if ! HAVE_SECURE_GETENV # if HAVE___SECURE_GETENV # define secure_getenv __secure_getenv @@ -1283,4 +1280,12 @@ struct fib_rule_uid_range { # define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64) #endif +#ifndef NSFS_MAGIC +#define NSFS_MAGIC 0x6e736673 +#endif + +#ifndef NS_GET_NSTYPE +#define NS_GET_NSTYPE _IO(0xb7, 0x3) +#endif + #include "missing_syscall.h" diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index 54c174744..86b301d72 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c index a3bced293..7a2287f4a 100644 --- a/src/basic/mkdir-label.c +++ b/src/basic/mkdir-label.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -25,8 +26,8 @@ #include "label.h" #include "mkdir.h" -int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid) { - return mkdir_safe_internal(path, mode, uid, gid, mkdir_label); +int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink) { + return mkdir_safe_internal(path, mode, uid, gid, follow_symlink, mkdir_label); } #if 0 /// UNNEEDED by elogind diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 867219e4b..bab166b4d 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -22,6 +23,7 @@ #include #include +#include "alloc-util.h" #include "fs-util.h" #include "macro.h" #include "mkdir.h" @@ -32,7 +34,7 @@ /// Additional includes needed by elogind #include "missing.h" -int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) { +int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink, mkdir_func_t _mkdir) { struct stat st; int r; @@ -45,6 +47,19 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkd if (lstat(path, &st) < 0) return -errno; + if (follow_symlink && S_ISLNK(st.st_mode)) { + _cleanup_free_ char *p = NULL; + + r = chase_symlinks(path, NULL, CHASE_NONEXISTENT, &p); + if (r < 0) + return r; + if (r == 0) + return mkdir_safe_internal(p, mode, uid, gid, false, _mkdir); + + if (lstat(p, &st) < 0) + return -errno; + } + if ((st.st_mode & 0007) > (mode & 0007) || (st.st_mode & 0070) > (mode & 0070) || (st.st_mode & 0700) > (mode & 0700) || @@ -56,8 +71,8 @@ int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkd return 0; } -int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid) { - return mkdir_safe_internal(path, mode, uid, gid, mkdir); +int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink) { + return mkdir_safe_internal(path, mode, uid, gid, follow_symlink, mkdir); } int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir) { diff --git a/src/basic/mkdir.h b/src/basic/mkdir.h index 07ee10616..58d25a359 100644 --- a/src/basic/mkdir.h +++ b/src/basic/mkdir.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -22,12 +23,12 @@ #include -int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid); +int mkdir_safe(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink); int mkdir_parents(const char *path, mode_t mode); int mkdir_p(const char *path, mode_t mode); /* mandatory access control(MAC) versions */ -int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid); +int mkdir_safe_label(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink); #if 0 /// UNNEEDED by elogind int mkdir_parents_label(const char *path, mode_t mode); #endif // 0 @@ -35,6 +36,6 @@ int mkdir_p_label(const char *path, mode_t mode); /* internally used */ typedef int (*mkdir_func_t)(const char *pathname, mode_t mode); -int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir); +int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, bool follow_symlink, mkdir_func_t _mkdir); int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, mkdir_func_t _mkdir); diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 890bc41af..03e1b9a42 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -18,6 +19,7 @@ ***/ #include +//#include #include #include #include @@ -39,8 +41,82 @@ #include "string-util.h" #include "strv.h" +/* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of + * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code + * is recompiled then it would cease working on old kernels, as those refuse any sizes larger than this value with + * EINVAL right-away. Hence, let's disconnect ourselves from any such API changes, and stick to the original definition + * from when it was introduced. We use it as a start value only anyway (see below), and hence should be able to deal + * with large file handles anyway. */ +#define ORIGINAL_MAX_HANDLE_SZ 128 + +int name_to_handle_at_loop( + int fd, + const char *path, + struct file_handle **ret_handle, + int *ret_mnt_id, + int flags) { + + _cleanup_free_ struct file_handle *h = NULL; + size_t n = ORIGINAL_MAX_HANDLE_SZ; + + /* We need to invoke name_to_handle_at() in a loop, given that it might return EOVERFLOW when the specified + * buffer is too small. Note that in contrast to what the docs might suggest, MAX_HANDLE_SZ is only good as a + * start value, it is not an upper bound on the buffer size required. + * + * This improves on raw name_to_handle_at() also in one other regard: ret_handle and ret_mnt_id can be passed + * as NULL if there's no interest in either. */ + + for (;;) { + int mnt_id = -1; + + h = malloc0(offsetof(struct file_handle, f_handle) + n); + if (!h) + return -ENOMEM; + + h->handle_bytes = n; + + if (name_to_handle_at(fd, path, h, &mnt_id, flags) >= 0) { + + if (ret_handle) { + *ret_handle = h; + h = NULL; + } + + if (ret_mnt_id) + *ret_mnt_id = mnt_id; + + return 0; + } + if (errno != EOVERFLOW) + return -errno; + + if (!ret_handle && ret_mnt_id && mnt_id >= 0) { + + /* As it appears, name_to_handle_at() fills in mnt_id even when it returns EOVERFLOW when the + * buffer is too small, but that's undocumented. Hence, let's make use of this if it appears to + * be filled in, and the caller was interested in only the mount ID an nothing else. */ + + *ret_mnt_id = mnt_id; + return 0; + } + + /* If name_to_handle_at() didn't increase the byte size, then this EOVERFLOW is caused by something + * else (apparently EOVERFLOW is returned for untriggered nfs4 mounts sometimes), not by the too small + * buffer. In that case propagate EOVERFLOW */ + if (h->handle_bytes <= n) + return -EOVERFLOW; + + /* The buffer was too small. Size the new buffer by what name_to_handle_at() returned. */ + n = h->handle_bytes; + if (offsetof(struct file_handle, f_handle) + n < n) /* check for addition overflow */ + return -EOVERFLOW; + + h = mfree(h); + } +} + static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { - char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; + char path[STRLEN("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *fdinfo = NULL; _cleanup_close_ int subfd = -1; char *p; @@ -78,7 +154,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id } int fd_is_mount_point(int fd, const char *filename, int flags) { - union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; + _cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL; int mount_id = -1, mount_id_parent = -1; bool nosupp = false, check_st_dev = true; struct stat a, b; @@ -110,39 +186,32 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { * subvolumes have different st_dev, even though they aren't * real mounts of their own. */ - r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); - if (r < 0) { - if (IN_SET(errno, ENOSYS, EACCES, EPERM)) - /* This kernel does not support name_to_handle_at() at all, or the syscall was blocked (maybe - * through seccomp, because we are running inside of a container?): fall back to simpler - * logic. */ + r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags); + if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) + /* This kernel does not support name_to_handle_at() at all (ENOSYS), or the syscall was blocked + * (EACCES/EPERM; maybe through seccomp, because we are running inside of a container?), or the mount + * point is not triggered yet (EOVERFLOW, think nfs4), or some general name_to_handle_at() flakiness + * (EINVAL): fall back to simpler logic. */ + goto fallback_fdinfo; + else if (r == -EOPNOTSUPP) + /* This kernel or file system does not support name_to_handle_at(), hence let's see if the upper fs + * supports it (in which case it is a mount point), otherwise fallback to the traditional stat() + * logic */ + nosupp = true; + else if (r < 0) + return r; + + r = name_to_handle_at_loop(fd, "", &h_parent, &mount_id_parent, AT_EMPTY_PATH); + if (r == -EOPNOTSUPP) { + if (nosupp) + /* Neither parent nor child do name_to_handle_at()? We have no choice but to fall back. */ goto fallback_fdinfo; - else if (errno == EOPNOTSUPP) - /* This kernel or file system does not support - * name_to_handle_at(), hence let's see if the - * upper fs supports it (in which case it is a - * mount point), otherwise fallback to the - * traditional stat() logic */ - nosupp = true; else - return -errno; - } - - r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); - if (r < 0) { - if (errno == EOPNOTSUPP) { - if (nosupp) - /* Neither parent nor child do name_to_handle_at()? - We have no choice but to fall back. */ - goto fallback_fdinfo; - else - /* The parent can't do name_to_handle_at() but the - * directory we are interested in can? - * If so, it must be a mount point. */ - return 1; - } else - return -errno; - } + /* The parent can't do name_to_handle_at() but the directory we are interested in can? If so, + * it must be a mount point. */ + return 1; + } else if (r < 0) + return r; /* The parent can do name_to_handle_at() but the * directory we are interested in can't? If so, it @@ -155,9 +224,9 @@ int fd_is_mount_point(int fd, const char *filename, int flags) { * assume this is the root directory, which is a mount * point. */ - if (h.handle.handle_bytes == h_parent.handle.handle_bytes && - h.handle.handle_type == h_parent.handle.handle_type && - memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0) + if (h->handle_bytes == h_parent->handle_bytes && + h->handle_type == h_parent->handle_type && + memcmp(h->f_handle, h_parent->f_handle, h->handle_bytes) == 0) return 1; return mount_id != mount_id_parent; @@ -213,6 +282,7 @@ int path_is_mount_point(const char *t, const char *root, int flags) { int r; assert(t); + assert((flags & ~AT_SYMLINK_FOLLOW) == 0); if (path_equal(t, "/")) return 1; @@ -237,7 +307,17 @@ int path_is_mount_point(const char *t, const char *root, int flags) { if (fd < 0) return -errno; - return fd_is_mount_point(fd, basename(t), flags); + return fd_is_mount_point(fd, last_path_component(t), flags); +} + +int path_get_mnt_id(const char *path, int *ret) { + int r; + + r = name_to_handle_at_loop(AT_FDCWD, path, NULL, ret, 0); + if (IN_SET(r, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) /* kernel/fs don't support this, or seccomp blocks access, or untriggered mount, or name_to_handle_at() is flaky */ + return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret); + + return r; } #if 0 /// UNNEEDED by elogind @@ -259,6 +339,8 @@ int umount_recursive(const char *prefix, int flags) { if (!proc_self_mountinfo) return -errno; + (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER); + for (;;) { _cleanup_free_ char *path = NULL, *p = NULL; int k; @@ -505,6 +587,8 @@ int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) { if (!proc_self_mountinfo) return -errno; + (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER); + return bind_remount_recursive_with_mountinfo(prefix, ro, blacklist, proc_self_mountinfo); } @@ -590,6 +674,22 @@ bool fstype_can_discard(const char *fstype) { "xfs"); } +bool fstype_can_uid_gid(const char *fstype) { + + /* All file systems that have a uid=/gid= mount option that fixates the owners of all files and directories, + * current and future. */ + + return STR_IN_SET(fstype, + "adfs", + "fat", + "hfs", + "hpfs", + "iso9660", + "msdos", + "ntfs", + "vfat"); +} + int repeat_unmount(const char *path, int flags) { bool done = false; diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index 5e8b47c84..cfe30a625 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -29,6 +30,10 @@ #include "macro.h" #include "missing.h" +int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); + +int path_get_mnt_id(const char *path, int *ret); + int fd_is_mount_point(int fd, const char *filename, int flags); int path_is_mount_point(const char *path, const char *root, int flags); @@ -51,16 +56,10 @@ bool fstype_is_network(const char *fstype); bool fstype_is_api_vfs(const char *fstype); bool fstype_is_ro(const char *fsype); bool fstype_can_discard(const char *fstype); - -union file_handle_union { - struct file_handle handle; - char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; -}; +bool fstype_can_uid_gid(const char *fstype); const char* mode_to_inaccessible_node(mode_t mode); -#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ } - #if 0 /// UNNEEDED by elogind int mount_verbose( int error_log_level, diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index f47258edf..37f6a08c3 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -25,6 +26,7 @@ #include #include "alloc-util.h" +#include "errno-list.h" //#include "extract-word.h" #include "macro.h" #include "parse-util.h" @@ -273,6 +275,64 @@ int parse_range(const char *t, unsigned *lower, unsigned *upper) { } #endif // 0 +int parse_errno(const char *t) { + int r, e; + + assert(t); + + r = errno_from_name(t); + if (r > 0) + return r; + + r = safe_atoi(t, &e); + if (r < 0) + return r; + + if (e < 0 || e > ERRNO_MAX) + return -ERANGE; + + return e; +} + +int parse_syscall_and_errno(const char *in, char **name, int *error) { + _cleanup_free_ char *n = NULL; + char *p; + int e = -1; + + assert(in); + assert(name); + assert(error); + + /* + * This parse "syscall:errno" like "uname:EILSEQ", "@sync:255". + * If errno is omitted, then error is set to -1. + * Empty syscall name is not allowed. + * Here, we do not check that the syscall name is valid or not. + */ + + p = strchr(in, ':'); + if (p) { + e = parse_errno(p + 1); + if (e < 0) + return e; + + n = strndup(in, p - in); + } else + n = strdup(in); + + if (!n) + return -ENOMEM; + + if (isempty(n)) + return -EINVAL; + + *error = e; + *name = n; + n = NULL; + + return 0; +} + char *format_bytes(char *buf, size_t l, uint64_t t) { unsigned i; diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index ecbf4bdad..f35a61121 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -39,6 +40,8 @@ int parse_size(const char *t, uint64_t base, uint64_t *size); #if 0 /// UNNEEDED by elogind int parse_range(const char *t, unsigned *lower, unsigned *upper); #endif // 0 +int parse_errno(const char *t); +int parse_syscall_and_errno(const char *in, char **name, int *error); #define FORMAT_BYTES_MAX 8 char *format_bytes(char *buf, size_t l, uint64_t t); diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 2a766154b..e3c7622da 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -710,6 +711,37 @@ char* dirname_malloc(const char *path) { return dir2; } +const char *last_path_component(const char *path) { + /* Finds the last component of the path, preserving the + * optional trailing slash that signifies a directory. + * a/b/c → c + * a/b/c/ → c/ + * / → / + * // → / + * /foo/a → a + * /foo/a/ → a/ + * This is different than basename, which returns "" when + * a trailing slash is present. + */ + + unsigned l, k; + + l = k = strlen(path); + if (l == 0) /* special case — an empty string */ + return path; + + while (k > 0 && path[k-1] == '/') + k--; + + if (k == 0) /* the root directory */ + return path + l - 1; + + while (k > 0 && path[k-1] != '/') + k--; + + return path + k; +} + bool filename_is_valid(const char *p) { const char *e; @@ -729,7 +761,7 @@ bool filename_is_valid(const char *p) { return true; } -bool path_is_safe(const char *p) { +bool path_is_normalized(const char *p) { if (isempty(p)) return false; @@ -743,7 +775,6 @@ bool path_is_safe(const char *p) { if (strlen(p)+1 > PATH_MAX) return false; - /* The following two checks are not really dangerous, but hey, they still are confusing */ if (startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) return false; @@ -860,7 +891,9 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version) * for Gentoo which does a merge without making /lib a symlink. */ "lib/systemd/libsystemd-shared-*.so\0" - "usr/lib/systemd/libsystemd-shared-*.so\0") { + "lib64/elogind/libelogind-shared-*.so\0" + "usr/lib/elogind/libelogind-shared-*.so\0" + "usr/lib64/elogind/libelogind-shared-*.so\0") { _cleanup_strv_free_ char **names = NULL; _cleanup_free_ char *path = NULL; diff --git a/src/basic/path-util.h b/src/basic/path-util.h index ed305e012..38e6c927c 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -141,9 +142,10 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar #endif // 0 char* dirname_malloc(const char *path); +const char *last_path_component(const char *path); bool filename_is_valid(const char *p) _pure_; -bool path_is_safe(const char *p) _pure_; +bool path_is_normalized(const char *p) _pure_; char *file_in_same_dir(const char *path, const char *filename); diff --git a/src/basic/prioq.c b/src/basic/prioq.c index 4570b8e4b..407b17e9b 100644 --- a/src/basic/prioq.c +++ b/src/basic/prioq.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/prioq.h b/src/basic/prioq.h index 113c73d04..a222955df 100644 --- a/src/basic/prioq.h +++ b/src/basic/prioq.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index 8d4edb1cf..99d00ab0f 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h index 46d0d76ff..a80567b15 100644 --- a/src/basic/proc-cmdline.h +++ b/src/basic/proc-cmdline.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/random-util.c b/src/basic/random-util.c index 146c8f55e..1bc800089 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/random-util.h b/src/basic/random-util.h index 804e225fc..dd8701515 100644 --- a/src/basic/random-util.h +++ b/src/basic/random-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/refcnt.h b/src/basic/refcnt.h index 1d77a6445..ae2e446d6 100644 --- a/src/basic/refcnt.h +++ b/src/basic/refcnt.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index 6b865ff93..4bca7dc01 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/rm-rf.h b/src/basic/rm-rf.h index e13f7003e..1127e326b 100644 --- a/src/basic/rm-rf.h +++ b/src/basic/rm-rf.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 51b807b85..5d782ab5d 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 2a71afefa..4dfef4f06 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/set.c b/src/basic/set.c index 5356fba1f..e554e825e 100644 --- a/src/basic/set.c +++ b/src/basic/set.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/set.h b/src/basic/set.h index b424f3423..4ea0d96df 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/sigbus.c b/src/basic/sigbus.c new file mode 100644 index 000000000..2416929e3 --- /dev/null +++ b/src/basic/sigbus.c @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + 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 . +***/ + +#include +#include +#include +#include + +#include "macro.h" +#include "sigbus.h" +#include "util.h" + +#define SIGBUS_QUEUE_MAX 64 + +static struct sigaction old_sigaction; +static unsigned n_installed = 0; + +/* We maintain a fixed size list of page addresses that triggered a + SIGBUS. We access with list with atomic operations, so that we + don't have to deal with locks between signal handler and main + programs in possibly multiple threads. */ + +static void* volatile sigbus_queue[SIGBUS_QUEUE_MAX]; +static volatile sig_atomic_t n_sigbus_queue = 0; + +static void sigbus_push(void *addr) { + unsigned u; + + assert(addr); + + /* Find a free place, increase the number of entries and leave, if we can */ + for (u = 0; u < SIGBUS_QUEUE_MAX; u++) + if (__sync_bool_compare_and_swap(&sigbus_queue[u], NULL, addr)) { + __sync_fetch_and_add(&n_sigbus_queue, 1); + return; + } + + /* If we can't, make sure the queue size is out of bounds, to + * mark it as overflow */ + for (;;) { + unsigned c; + + __sync_synchronize(); + c = n_sigbus_queue; + + if (c > SIGBUS_QUEUE_MAX) /* already overflow */ + return; + + if (__sync_bool_compare_and_swap(&n_sigbus_queue, c, c + SIGBUS_QUEUE_MAX)) + return; + } +} + +int sigbus_pop(void **ret) { + assert(ret); + + for (;;) { + unsigned u, c; + + __sync_synchronize(); + c = n_sigbus_queue; + + if (_likely_(c == 0)) + return 0; + + if (_unlikely_(c >= SIGBUS_QUEUE_MAX)) + return -EOVERFLOW; + + for (u = 0; u < SIGBUS_QUEUE_MAX; u++) { + void *addr; + + addr = sigbus_queue[u]; + if (!addr) + continue; + + if (__sync_bool_compare_and_swap(&sigbus_queue[u], addr, NULL)) { + __sync_fetch_and_sub(&n_sigbus_queue, 1); + *ret = addr; + return 1; + } + } + } +} + +static void sigbus_handler(int sn, siginfo_t *si, void *data) { + unsigned long ul; + void *aligned; + + assert(sn == SIGBUS); + assert(si); + + if (si->si_code != BUS_ADRERR || !si->si_addr) { + assert_se(sigaction(SIGBUS, &old_sigaction, NULL) == 0); + raise(SIGBUS); + return; + } + + ul = (unsigned long) si->si_addr; + ul = ul / page_size(); + ul = ul * page_size(); + aligned = (void*) ul; + + /* Let's remember which address failed */ + sigbus_push(aligned); + + /* Replace mapping with an anonymous page, so that the + * execution can continue, however with a zeroed out page */ + assert_se(mmap(aligned, page_size(), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) == aligned); +} + +void sigbus_install(void) { + struct sigaction sa = { + .sa_sigaction = sigbus_handler, + .sa_flags = SA_SIGINFO, + }; + + n_installed++; + + if (n_installed == 1) + assert_se(sigaction(SIGBUS, &sa, &old_sigaction) == 0); + + return; +} + +void sigbus_reset(void) { + + if (n_installed <= 0) + return; + + n_installed--; + + if (n_installed == 0) + assert_se(sigaction(SIGBUS, &old_sigaction, NULL) == 0); + + return; +} diff --git a/src/basic/sigbus.h b/src/basic/sigbus.h new file mode 100644 index 000000000..90b0c9632 --- /dev/null +++ b/src/basic/sigbus.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + 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 . +***/ + +void sigbus_install(void); +void sigbus_reset(void); + +int sigbus_pop(void **ret); diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index 043c71466..fbaea0355 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -227,7 +228,7 @@ static const char *const __signal_table[] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); const char *signal_to_string(int signo) { - static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; + static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int) + 1]; const char *name; name = __signal_to_string(signo); diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index 5524c40b8..2343ca80f 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index 691c0670e..9a4d2b85d 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h index 797c7f0de..c691fdc12 100644 --- a/src/basic/smack-util.h +++ b/src/basic/smack-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index a94d89a63..67a4a5cf4 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -122,7 +123,7 @@ int socket_address_parse(SocketAddress *a, const char *s) { } else if (startswith(s, "vsock:")) { /* AF_VSOCK socket in vsock:cid:port notation */ - const char *cid_start = s + strlen("vsock:"); + const char *cid_start = s + STRLEN("vsock:"); e = strchr(cid_start, ':'); if (!e) diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index d4f573efb..333b32c48 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/sparse-endian.h b/src/basic/sparse-endian.h index a3573b84a..5e59de543 100644 --- a/src/basic/sparse-endian.h +++ b/src/basic/sparse-endian.h @@ -1,4 +1,6 @@ -/* Copyright (c) 2012 Josh Triplett +/* SPDX-License-Identifier: MIT + * + * Copyright (c) 2012 Josh Triplett * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 0c8c301b6..064e316fc 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -200,7 +201,7 @@ bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) { return F_TYPE_EQUAL(s->f_type, magic_value); } -int fd_check_fstype(int fd, statfs_f_type_t magic_value) { +int fd_is_fs_type(int fd, statfs_f_type_t magic_value) { struct statfs s; if (fstatfs(fd, &s) < 0) @@ -210,14 +211,14 @@ int fd_check_fstype(int fd, statfs_f_type_t magic_value) { } #if 0 /// UNNEEDED by elogind -int path_check_fstype(const char *path, statfs_f_type_t magic_value) { +int path_is_fs_type(const char *path, statfs_f_type_t magic_value) { _cleanup_close_ int fd = -1; fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); if (fd < 0) return -errno; - return fd_check_fstype(fd, magic_value); + return fd_is_fs_type(fd, magic_value); } #endif // 0 @@ -236,6 +237,18 @@ int fd_is_temporary_fs(int fd) { return is_temporary_fs(&s); } +int fd_is_network_ns(int fd) { + int r; + + r = fd_is_fs_type(fd, NSFS_MAGIC); + if (r <= 0) + return r; + r = ioctl(fd, NS_GET_NSTYPE); + if (r < 0) + return -errno; + return r == CLONE_NEWNET; +} + int path_is_temporary_fs(const char *path) { _cleanup_close_ int fd = -1; diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index 5a57f013c..db9012300 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -64,14 +65,15 @@ int files_same(const char *filea, const char *fileb, int flags); typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t; bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_; -int fd_check_fstype(int fd, statfs_f_type_t magic_value); #if 0 /// UNNEEDED by elogind -int path_check_fstype(const char *path, statfs_f_type_t magic_value); #endif // 0 +int fd_is_fs_type(int fd, statfs_f_type_t magic_value); +int path_is_fs_type(const char *path, statfs_f_type_t magic_value); bool is_temporary_fs(const struct statfs *s) _pure_; #if 0 /// UNNEEDED by elogind int fd_is_temporary_fs(int fd); +int fd_is_network_ns(int fd); int path_is_temporary_fs(const char *path); #endif // 0 diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h index 3e0ea04f6..f4dfa7629 100644 --- a/src/basic/stdio-util.h +++ b/src/basic/stdio-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/string-table.c b/src/basic/string-table.c index a1499ab12..d4b7c69bd 100644 --- a/src/basic/string-table.c +++ b/src/basic/string-table.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/string-table.h b/src/basic/string-table.h index 369610efc..4306b90f4 100644 --- a/src/basic/string-table.h +++ b/src/basic/string-table.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 704d020b2..3e19e43ac 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -21,6 +22,7 @@ #include #include #include +#include #include #include @@ -278,6 +280,9 @@ char *strjoin_real(const char *x, ...) { char *strstrip(char *s) { char *e; + if (!s) + return NULL; + /* Drops trailing whitespace. Modifies the string in * place. Returns pointer to first non-space character */ @@ -296,7 +301,13 @@ char *strstrip(char *s) { char *delete_chars(char *s, const char *bad) { char *f, *t; - /* Drops all whitespace, regardless where in the string */ + /* Drops all specified bad characters, regardless where in the string */ + + if (!s) + return NULL; + + if (!bad) + bad = WHITESPACE; for (f = s, t = s; *f; f++) { if (strchr(bad, *f)) @@ -311,6 +322,26 @@ char *delete_chars(char *s, const char *bad) { } #endif // 0 +char *delete_trailing_chars(char *s, const char *bad) { + char *p, *c = s; + + /* Drops all specified bad characters, at the end of the string */ + + if (!s) + return NULL; + + if (!bad) + bad = WHITESPACE; + + for (p = s; *p; p++) + if (!strchr(bad, *p)) + c = p + 1; + + *c = 0; + + return s; +} + char *truncate_nl(char *s) { assert(s); @@ -643,10 +674,10 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) { if (!f) return NULL; - /* Note we use the _unlocked() stdio variants on f for performance - * reasons. It's safe to do so since we created f here and it - * doesn't leave our scope. - */ + /* Note we turn off internal locking on f for performance reasons. It's safe to do so since we created f here + * and it doesn't leave our scope. */ + + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); for (i = *ibuf; i < *ibuf + isz + 1; i++) { @@ -658,21 +689,21 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) { else if (*i == '\x1B') state = STATE_ESCAPE; else if (*i == '\t') - fputs_unlocked(" ", f); + fputs(" ", f); else - fputc_unlocked(*i, f); + fputc(*i, f); break; case STATE_ESCAPE: if (i >= *ibuf + isz) { /* EOT */ - fputc_unlocked('\x1B', f); + fputc('\x1B', f); break; } else if (*i == '[') { state = STATE_BRACKET; begin = i + 1; } else { - fputc_unlocked('\x1B', f); - fputc_unlocked(*i, f); + fputc('\x1B', f); + fputc(*i, f); state = STATE_OTHER; } @@ -682,8 +713,8 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) { if (i >= *ibuf + isz || /* EOT */ (!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) { - fputc_unlocked('\x1B', f); - fputc_unlocked('[', f); + fputc('\x1B', f); + fputc('[', f); state = STATE_OTHER; i = begin-1; } else if (*i == 'm') diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 7276cfd6f..5ee7442d9 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -139,9 +140,21 @@ char *strstrip(char *s); #if 0 /// UNNEEDED by elogind char *delete_chars(char *s, const char *bad); #endif // 0 +char *delete_trailing_chars(char *s, const char *bad); char *truncate_nl(char *s); #if 0 /// UNNEEDED by elogind +static inline char *skip_leading_chars(const char *s, const char *bad) { + + if (!s) + return NULL; + + if (!bad) + bad = WHITESPACE; + + return (char*) s + strspn(s, bad); +} + char ascii_tolower(char x); char *ascii_strlower(char *s); char *ascii_strlower_n(char *s, size_t n); diff --git a/src/basic/strv.c b/src/basic/strv.c index 1f42046c6..0d46addbc 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/strv.h b/src/basic/strv.h index a01f685f9..32cd6ccd5 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -198,3 +199,11 @@ int strv_extend_n(char ***l, const char *value, size_t n); #if 0 /// UNNEEDED by elogind int fputstrv(FILE *f, char **l, const char *separator, bool *space); #endif // 0 + +#define strv_free_and_replace(a, b) \ + ({ \ + strv_free(a); \ + (a) = (b); \ + (b) = NULL; \ + 0; \ + }) diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c index 05d51b4be..6ce6ab2be 100644 --- a/src/basic/syslog-util.c +++ b/src/basic/syslog-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/syslog-util.h b/src/basic/syslog-util.h index 86b321c8d..75bf3b4ab 100644 --- a/src/basic/syslog-util.h +++ b/src/basic/syslog-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 20e22ad6e..9ef007d30 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -1003,7 +1004,7 @@ int get_ctty_devnr(pid_t pid, dev_t *d) { } int get_ctty(pid_t pid, dev_t *_devnr, char **r) { - char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL; + char fn[STRLEN("/dev/char/") + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL; _cleanup_free_ char *s = NULL; const char *p; dev_t devnr; diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index f710eac38..396d90d86 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/time-util.c b/src/basic/time-util.c index e9d17a8cc..c72094188 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -1488,3 +1489,9 @@ usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) { return usec_sub_unsigned(b, usec_sub_unsigned(a, x)); } #endif // 0 + +bool in_utc_timezone(void) { + tzset(); + + return timezone == 0 && daylight == 0; +} diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 6bf0f72ef..cac23e0ec 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -168,10 +169,6 @@ clockid_t clock_boottime_or_monotonic(void); usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to); #endif // 0 -#define xstrftime(buf, fmt, tm) \ - assert_message_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0, \ - "xstrftime: " #buf "[] must be big enough") - #if 0 /// UNNEEDED by elogind int get_timezone(char **timezone); @@ -183,6 +180,8 @@ struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc); unsigned long usec_to_jiffies(usec_t usec); #endif // 0 +bool in_utc_timezone(void); + static inline usec_t usec_add(usec_t a, usec_t b) { usec_t c; diff --git a/src/basic/umask-util.h b/src/basic/umask-util.h index 359d87d27..638b37d7d 100644 --- a/src/basic/umask-util.h +++ b/src/basic/umask-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/unaligned.h b/src/basic/unaligned.h index 7c847a3cc..201b3d227 100644 --- a/src/basic/unaligned.h +++ b/src/basic/unaligned.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c new file mode 100644 index 000000000..387533f59 --- /dev/null +++ b/src/basic/unit-def.c @@ -0,0 +1,290 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 . +***/ + +#include "alloc-util.h" +#include "bus-label.h" +#include "string-table.h" +#include "unit-def.h" +#include "unit-name.h" + +char *unit_dbus_path_from_name(const char *name) { + _cleanup_free_ char *e = NULL; + + assert(name); + + e = bus_label_escape(name); + if (!e) + return NULL; + + return strappend("/org/freedesktop/systemd1/unit/", e); +} + +int unit_name_from_dbus_path(const char *path, char **name) { + const char *e; + char *n; + + e = startswith(path, "/org/freedesktop/systemd1/unit/"); + if (!e) + return -EINVAL; + + n = bus_label_unescape(e); + if (!n) + return -ENOMEM; + + *name = n; + return 0; +} + +const char* unit_dbus_interface_from_type(UnitType t) { + + static const char *const table[_UNIT_TYPE_MAX] = { + [UNIT_SERVICE] = "org.freedesktop.systemd1.Service", + [UNIT_SOCKET] = "org.freedesktop.systemd1.Socket", + [UNIT_TARGET] = "org.freedesktop.systemd1.Target", + [UNIT_DEVICE] = "org.freedesktop.systemd1.Device", + [UNIT_MOUNT] = "org.freedesktop.systemd1.Mount", + [UNIT_AUTOMOUNT] = "org.freedesktop.systemd1.Automount", + [UNIT_SWAP] = "org.freedesktop.systemd1.Swap", + [UNIT_TIMER] = "org.freedesktop.systemd1.Timer", + [UNIT_PATH] = "org.freedesktop.systemd1.Path", + [UNIT_SLICE] = "org.freedesktop.systemd1.Slice", + [UNIT_SCOPE] = "org.freedesktop.systemd1.Scope", + }; + + if (t < 0) + return NULL; + if (t >= _UNIT_TYPE_MAX) + return NULL; + + return table[t]; +} + +const char *unit_dbus_interface_from_name(const char *name) { + UnitType t; + + t = unit_name_to_type(name); + if (t < 0) + return NULL; + + return unit_dbus_interface_from_type(t); +} + +static const char* const unit_type_table[_UNIT_TYPE_MAX] = { + [UNIT_SERVICE] = "service", + [UNIT_SOCKET] = "socket", + [UNIT_TARGET] = "target", + [UNIT_DEVICE] = "device", + [UNIT_MOUNT] = "mount", + [UNIT_AUTOMOUNT] = "automount", + [UNIT_SWAP] = "swap", + [UNIT_TIMER] = "timer", + [UNIT_PATH] = "path", + [UNIT_SLICE] = "slice", + [UNIT_SCOPE] = "scope", +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType); + +static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { + [UNIT_STUB] = "stub", + [UNIT_LOADED] = "loaded", + [UNIT_NOT_FOUND] = "not-found", + [UNIT_ERROR] = "error", + [UNIT_MERGED] = "merged", + [UNIT_MASKED] = "masked" +}; + +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 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_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 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_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_REQUISITE] = "Requisite", + [UNIT_WANTS] = "Wants", + [UNIT_BINDS_TO] = "BindsTo", + [UNIT_PART_OF] = "PartOf", + [UNIT_REQUIRED_BY] = "RequiredBy", + [UNIT_REQUISITE_OF] = "RequisiteOf", + [UNIT_WANTED_BY] = "WantedBy", + [UNIT_BOUND_BY] = "BoundBy", + [UNIT_CONSISTS_OF] = "ConsistsOf", + [UNIT_CONFLICTS] = "Conflicts", + [UNIT_CONFLICTED_BY] = "ConflictedBy", + [UNIT_BEFORE] = "Before", + [UNIT_AFTER] = "After", + [UNIT_ON_FAILURE] = "OnFailure", + [UNIT_TRIGGERS] = "Triggers", + [UNIT_TRIGGERED_BY] = "TriggeredBy", + [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo", + [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom", + [UNIT_JOINS_NAMESPACE_OF] = "JoinsNamespaceOf", + [UNIT_REFERENCES] = "References", + [UNIT_REFERENCED_BY] = "ReferencedBy", +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency); + +static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = { + [NOTIFY_NONE] = "none", + [NOTIFY_MAIN] = "main", + [NOTIFY_EXEC] = "exec", + [NOTIFY_ALL] = "all" +}; + +DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess); diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h new file mode 100644 index 000000000..c142e069a --- /dev/null +++ b/src/basic/unit-def.h @@ -0,0 +1,302 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + 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 . +***/ + +#include + +#include "macro.h" + +typedef enum UnitType { + UNIT_SERVICE = 0, + UNIT_SOCKET, + UNIT_TARGET, + UNIT_DEVICE, + UNIT_MOUNT, + UNIT_AUTOMOUNT, + UNIT_SWAP, + UNIT_TIMER, + UNIT_PATH, + UNIT_SLICE, + UNIT_SCOPE, + _UNIT_TYPE_MAX, + _UNIT_TYPE_INVALID = -1 +} UnitType; + +typedef enum UnitLoadState { + UNIT_STUB = 0, + UNIT_LOADED, + UNIT_NOT_FOUND, + UNIT_ERROR, + UNIT_MERGED, + UNIT_MASKED, + _UNIT_LOAD_STATE_MAX, + _UNIT_LOAD_STATE_INVALID = -1 +} 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; + +/* 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_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 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_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_REQUISITE, + UNIT_WANTS, + UNIT_BINDS_TO, + UNIT_PART_OF, + + /* Inverse of the above */ + UNIT_REQUIRED_BY, /* inverse of 'requires' is 'required_by' */ + UNIT_REQUISITE_OF, /* inverse of 'requisite' is 'requisite_of' */ + UNIT_WANTED_BY, /* inverse of 'wants' */ + UNIT_BOUND_BY, /* inverse of 'binds_to' */ + UNIT_CONSISTS_OF, /* inverse of 'part_of' */ + + /* Negative dependencies */ + UNIT_CONFLICTS, /* inverse of 'conflicts' is 'conflicted_by' */ + UNIT_CONFLICTED_BY, + + /* Order */ + UNIT_BEFORE, /* inverse of 'before' is 'after' and vice versa */ + UNIT_AFTER, + + /* On Failure */ + UNIT_ON_FAILURE, + + /* Triggers (i.e. a socket triggers a service) */ + UNIT_TRIGGERS, + UNIT_TRIGGERED_BY, + + /* Propagate reloads */ + UNIT_PROPAGATES_RELOAD_TO, + UNIT_RELOAD_PROPAGATED_FROM, + + /* Joins namespace of */ + UNIT_JOINS_NAMESPACE_OF, + + /* Reference information for GC logic */ + UNIT_REFERENCES, /* Inverse of 'references' is 'referenced_by' */ + UNIT_REFERENCED_BY, + + _UNIT_DEPENDENCY_MAX, + _UNIT_DEPENDENCY_INVALID = -1 +} UnitDependency; + +typedef enum NotifyAccess { + NOTIFY_NONE, + NOTIFY_ALL, + NOTIFY_MAIN, + NOTIFY_EXEC, + _NOTIFY_ACCESS_MAX, + _NOTIFY_ACCESS_INVALID = -1 +} NotifyAccess; + +char *unit_dbus_path_from_name(const char *name); +int unit_name_from_dbus_path(const char *path, char **name); + +const char* unit_dbus_interface_from_type(UnitType t); +const char *unit_dbus_interface_from_name(const char *name); + +const char *unit_type_to_string(UnitType i) _const_; +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* 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* 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_; + +const char* notify_access_to_string(NotifyAccess i) _const_; +NotifyAccess notify_access_from_string(const char *s) _pure_; diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index 2971b425d..106d39990 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -24,12 +25,9 @@ #include #include "alloc-util.h" -#include "bus-label.h" //#include "glob-util.h" #include "hexdecoct.h" -#include "macro.h" #include "path-util.h" -#include "string-table.h" #include "string-util.h" #include "strv.h" #include "unit-name.h" @@ -212,6 +210,7 @@ int unit_name_to_prefix_and_instance(const char *n, char **ret) { *ret = s; return 0; } +#endif // 0 UnitType unit_name_to_type(const char *n) { const char *e; @@ -226,6 +225,7 @@ UnitType unit_name_to_type(const char *n) { return unit_type_from_string(e + 1); } +#if 0 /// UNNEEDED by elogind int unit_name_change_suffix(const char *n, const char *suffix, char **ret) { char *e, *s; size_t a, b; @@ -388,19 +388,14 @@ int unit_name_path_escape(const char *f, char **ret) { if (STR_IN_SET(p, "/", "")) s = strdup("-"); else { - char *e; - - if (!path_is_safe(p)) + if (!path_is_normalized(p)) return -EINVAL; /* Truncate trailing slashes */ - e = endswith(p, "/"); - if (e) - *e = 0; + delete_trailing_chars(p, "/"); /* Truncate leading slashes */ - if (p[0] == '/') - p++; + p = skip_leading_chars(p, "/"); s = unit_name_escape(p); } @@ -443,7 +438,7 @@ int unit_name_path_unescape(const char *f, char **ret) { if (!s) return -ENOMEM; - if (!path_is_safe(s)) { + if (!path_is_normalized(s)) { free(s); return -EINVAL; } @@ -578,68 +573,6 @@ int unit_name_to_path(const char *name, char **ret) { return unit_name_path_unescape(prefix, ret); } -char *unit_dbus_path_from_name(const char *name) { - _cleanup_free_ char *e = NULL; - - assert(name); - - e = bus_label_escape(name); - if (!e) - return NULL; - - return strappend("/org/freedesktop/systemd1/unit/", e); -} - -int unit_name_from_dbus_path(const char *path, char **name) { - const char *e; - char *n; - - e = startswith(path, "/org/freedesktop/systemd1/unit/"); - if (!e) - return -EINVAL; - - n = bus_label_unescape(e); - if (!n) - return -ENOMEM; - - *name = n; - return 0; -} - -const char* unit_dbus_interface_from_type(UnitType t) { - - static const char *const table[_UNIT_TYPE_MAX] = { - [UNIT_SERVICE] = "org.freedesktop.systemd1.Service", - [UNIT_SOCKET] = "org.freedesktop.systemd1.Socket", - [UNIT_TARGET] = "org.freedesktop.systemd1.Target", - [UNIT_DEVICE] = "org.freedesktop.systemd1.Device", - [UNIT_MOUNT] = "org.freedesktop.systemd1.Mount", - [UNIT_AUTOMOUNT] = "org.freedesktop.systemd1.Automount", - [UNIT_SWAP] = "org.freedesktop.systemd1.Swap", - [UNIT_TIMER] = "org.freedesktop.systemd1.Timer", - [UNIT_PATH] = "org.freedesktop.systemd1.Path", - [UNIT_SLICE] = "org.freedesktop.systemd1.Slice", - [UNIT_SCOPE] = "org.freedesktop.systemd1.Scope", - }; - - if (t < 0) - return NULL; - if (t >= _UNIT_TYPE_MAX) - return NULL; - - return table[t]; -} - -const char *unit_dbus_interface_from_name(const char *name) { - UnitType t; - - t = unit_name_to_type(name); - if (t < 0) - return NULL; - - return unit_dbus_interface_from_type(t); -} - static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t) { const char *valid_chars; @@ -838,208 +771,5 @@ bool slice_name_is_valid(const char *name) { return true; } - -static const char* const unit_type_table[_UNIT_TYPE_MAX] = { - [UNIT_SERVICE] = "service", - [UNIT_SOCKET] = "socket", - [UNIT_TARGET] = "target", - [UNIT_DEVICE] = "device", - [UNIT_MOUNT] = "mount", - [UNIT_AUTOMOUNT] = "automount", - [UNIT_SWAP] = "swap", - [UNIT_TIMER] = "timer", - [UNIT_PATH] = "path", - [UNIT_SLICE] = "slice", - [UNIT_SCOPE] = "scope", -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_type, UnitType); - #if 0 /// UNNEEDED by elogind -static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { - [UNIT_STUB] = "stub", - [UNIT_LOADED] = "loaded", - [UNIT_NOT_FOUND] = "not-found", - [UNIT_ERROR] = "error", - [UNIT_MERGED] = "merged", - [UNIT_MASKED] = "masked" -}; - -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 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_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 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_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_REQUISITE] = "Requisite", - [UNIT_WANTS] = "Wants", - [UNIT_BINDS_TO] = "BindsTo", - [UNIT_PART_OF] = "PartOf", - [UNIT_REQUIRED_BY] = "RequiredBy", - [UNIT_REQUISITE_OF] = "RequisiteOf", - [UNIT_WANTED_BY] = "WantedBy", - [UNIT_BOUND_BY] = "BoundBy", - [UNIT_CONSISTS_OF] = "ConsistsOf", - [UNIT_CONFLICTS] = "Conflicts", - [UNIT_CONFLICTED_BY] = "ConflictedBy", - [UNIT_BEFORE] = "Before", - [UNIT_AFTER] = "After", - [UNIT_ON_FAILURE] = "OnFailure", - [UNIT_TRIGGERS] = "Triggers", - [UNIT_TRIGGERED_BY] = "TriggeredBy", - [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo", - [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom", - [UNIT_JOINS_NAMESPACE_OF] = "JoinsNamespaceOf", - [UNIT_REFERENCES] = "References", - [UNIT_REFERENCED_BY] = "ReferencedBy", -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency); #endif // 0 - -static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = { - [NOTIFY_NONE] = "none", - [NOTIFY_MAIN] = "main", - [NOTIFY_EXEC] = "exec", - [NOTIFY_ALL] = "all" -}; - -DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess); diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index 6ffe29076..0fcba1153 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -22,234 +23,12 @@ #include #include "macro.h" +#include "unit-def.h" #define UNIT_NAME_MAX 256 -typedef enum UnitType { - UNIT_SERVICE = 0, - UNIT_SOCKET, - UNIT_TARGET, - UNIT_DEVICE, - UNIT_MOUNT, - UNIT_AUTOMOUNT, - UNIT_SWAP, - UNIT_TIMER, - UNIT_PATH, - UNIT_SLICE, - UNIT_SCOPE, - _UNIT_TYPE_MAX, - _UNIT_TYPE_INVALID = -1 -} UnitType; - #if 0 /// UNNEEDED by elogind -typedef enum UnitLoadState { - UNIT_STUB = 0, - UNIT_LOADED, - UNIT_NOT_FOUND, - UNIT_ERROR, - UNIT_MERGED, - UNIT_MASKED, - _UNIT_LOAD_STATE_MAX, - _UNIT_LOAD_STATE_INVALID = -1 -} 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; - -/* 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_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 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_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_REQUISITE, - UNIT_WANTS, - UNIT_BINDS_TO, - UNIT_PART_OF, - - /* Inverse of the above */ - UNIT_REQUIRED_BY, /* inverse of 'requires' is 'required_by' */ - UNIT_REQUISITE_OF, /* inverse of 'requisite' is 'requisite_of' */ - UNIT_WANTED_BY, /* inverse of 'wants' */ - UNIT_BOUND_BY, /* inverse of 'binds_to' */ - UNIT_CONSISTS_OF, /* inverse of 'part_of' */ - - /* Negative dependencies */ - UNIT_CONFLICTS, /* inverse of 'conflicts' is 'conflicted_by' */ - UNIT_CONFLICTED_BY, - - /* Order */ - UNIT_BEFORE, /* inverse of 'before' is 'after' and vice versa */ - UNIT_AFTER, - - /* On Failure */ - UNIT_ON_FAILURE, - - /* Triggers (i.e. a socket triggers a service) */ - UNIT_TRIGGERS, - UNIT_TRIGGERED_BY, - - /* Propagate reloads */ - UNIT_PROPAGATES_RELOAD_TO, - UNIT_RELOAD_PROPAGATED_FROM, - - /* Joins namespace of */ - UNIT_JOINS_NAMESPACE_OF, - - /* Reference information for GC logic */ - UNIT_REFERENCES, /* Inverse of 'references' is 'referenced_by' */ - UNIT_REFERENCED_BY, - - _UNIT_DEPENDENCY_MAX, - _UNIT_DEPENDENCY_INVALID = -1 -} UnitDependency; #endif // 0 - -typedef enum NotifyAccess { - NOTIFY_NONE, - NOTIFY_ALL, - NOTIFY_MAIN, - NOTIFY_EXEC, - _NOTIFY_ACCESS_MAX, - _NOTIFY_ACCESS_INVALID = -1 -} NotifyAccess; - typedef enum UnitNameFlags { UNIT_NAME_PLAIN = 1, /* Allow foo.service */ UNIT_NAME_INSTANCE = 2, /* Allow foo@bar.service */ @@ -271,9 +50,11 @@ static inline int unit_prefix_and_instance_is_valid(const char *p) { int unit_name_to_prefix(const char *n, char **prefix); int unit_name_to_instance(const char *n, char **instance); int unit_name_to_prefix_and_instance(const char *n, char **ret); +#endif // 0 UnitType unit_name_to_type(const char *n) _pure_; +#if 0 /// UNNEEDED by elogind int unit_name_change_suffix(const char *n, const char *suffix, char **ret); #endif // 0 @@ -293,12 +74,6 @@ int unit_name_from_path(const char *path, const char *suffix, char **ret); int unit_name_from_path_instance(const char *prefix, const char *path, const char *suffix, char **ret); int unit_name_to_path(const char *name, char **ret); -char *unit_dbus_path_from_name(const char *name); -int unit_name_from_dbus_path(const char *path, char **name); - -const char* unit_dbus_interface_from_type(UnitType t); -const char *unit_dbus_interface_from_name(const char *name); - typedef enum UnitNameMangle { UNIT_NAME_NOGLOB, UNIT_NAME_GLOB, @@ -314,53 +89,5 @@ int slice_build_parent_slice(const char *slice, char **ret); #endif // 0 int slice_build_subslice(const char *slice, const char*name, char **subslice); bool slice_name_is_valid(const char *name); - -const char *unit_type_to_string(UnitType i) _const_; -UnitType unit_type_from_string(const char *s) _pure_; - #if 0 /// UNNEEDED by elogind -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* 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* 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_; #endif // 0 - -const char* notify_access_to_string(NotifyAccess i) _const_; -NotifyAccess notify_access_from_string(const char *s) _pure_; diff --git a/src/basic/user-util.c b/src/basic/user-util.c index d9cc580d8..ee42b10cb 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -118,15 +119,14 @@ int get_user_creds( assert(username); assert(*username); - /* We enforce some special rules for uid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ + /* We enforce some special rules for uid=0 and uid=65534: in order to avoid NSS lookups for root we hardcode + * their user record data. */ - if (streq(*username, "root") || streq(*username, "0")) { + if (STR_IN_SET(*username, "root", "0")) { *username = "root"; if (uid) *uid = 0; - if (gid) *gid = 0; @@ -139,6 +139,23 @@ int get_user_creds( return 0; } + if (STR_IN_SET(*username, NOBODY_USER_NAME, "65534")) { + *username = NOBODY_USER_NAME; + + if (uid) + *uid = UID_NOBODY; + if (gid) + *gid = GID_NOBODY; + + if (home) + *home = "/"; + + if (shell) + *shell = "/sbin/nologin"; + + return 0; + } + if (parse_uid(*username, &u) >= 0) { errno = 0; p = getpwuid(u); @@ -220,7 +237,7 @@ int get_group_creds(const char **groupname, gid_t *gid) { /* We enforce some special rules for gid=0: in order to avoid * NSS lookups for root we hardcode its data. */ - if (streq(*groupname, "root") || streq(*groupname, "0")) { + if (STR_IN_SET(*groupname, "root", "0")) { *groupname = "root"; if (gid) @@ -229,6 +246,15 @@ int get_group_creds(const char **groupname, gid_t *gid) { return 0; } + if (STR_IN_SET(*groupname, NOBODY_GROUP_NAME, "65534")) { + *groupname = NOBODY_GROUP_NAME; + + if (gid) + *gid = GID_NOBODY; + + return 0; + } + if (parse_gid(*groupname, &id) >= 0) { errno = 0; g = getgrgid(id); @@ -261,6 +287,8 @@ char* uid_to_name(uid_t uid) { /* Shortcut things to avoid NSS lookups */ if (uid == 0) return strdup("root"); + if (uid == UID_NOBODY) + return strdup(NOBODY_USER_NAME); if (uid_is_valid(uid)) { long bufsize; @@ -299,6 +327,8 @@ char* gid_to_name(gid_t gid) { if (gid == 0) return strdup("root"); + if (gid == GID_NOBODY) + return strdup(NOBODY_GROUP_NAME); if (gid_is_valid(gid)) { long bufsize; @@ -391,7 +421,7 @@ int get_home_dir(char **_h) { return 0; } - /* Hardcode home directory for root to avoid NSS */ + /* Hardcode home directory for root and nobody to avoid NSS */ u = getuid(); if (u == 0) { h = strdup("/root"); @@ -401,6 +431,14 @@ int get_home_dir(char **_h) { *_h = h; return 0; } + if (u == UID_NOBODY) { + h = strdup("/"); + if (!h) + return -ENOMEM; + + *_h = h; + return 0; + } /* Check the database... */ errno = 0; @@ -438,7 +476,7 @@ int get_shell(char **_s) { return 0; } - /* Hardcode home directory for root to avoid NSS */ + /* Hardcode shell for root and nobody to avoid NSS */ u = getuid(); if (u == 0) { s = strdup("/bin/sh"); @@ -448,6 +486,14 @@ int get_shell(char **_s) { *_s = s; return 0; } + if (u == UID_NOBODY) { + s = strdup("/sbin/nologin"); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } /* Check the database... */ errno = 0; @@ -613,7 +659,7 @@ bool valid_home(const char *p) { if (!path_is_absolute(p)) return false; - if (!path_is_safe(p)) + if (!path_is_normalized(p)) return false; /* Colons are used as field separators, and hence not OK */ diff --git a/src/basic/user-util.h b/src/basic/user-util.h index c9c96e6ae..858498940 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/utf8.c b/src/basic/utf8.c index 7a52fac62..4da9a405c 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/utf8.h b/src/basic/utf8.h index f9b9c9468..b0a7485ae 100644 --- a/src/basic/utf8.h +++ b/src/basic/utf8.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/util.c b/src/basic/util.c index be9f17a0a..c58bf5601 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -38,6 +39,7 @@ #include "build.h" #include "cgroup-util.h" //#include "def.h" +//#include "device-nodes.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" @@ -105,7 +107,7 @@ int socket_from_display(const char *display, char **path) { k = strspn(display+1, "0123456789"); - f = new(char, strlen("/tmp/.X11-unix/X") + k + 1); + f = new(char, STRLEN("/tmp/.X11-unix/X") + k + 1); if (!f) return -ENOMEM; @@ -120,63 +122,42 @@ int socket_from_display(const char *display, char **path) { #if 0 /// UNNEEDED by elogind int block_get_whole_disk(dev_t d, dev_t *ret) { - char *p, *s; + char p[SYS_BLOCK_PATH_MAX("/partition")]; + _cleanup_free_ char *s = NULL; int r; unsigned n, m; assert(ret); /* If it has a queue this is good enough for us */ - if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r >= 0) { + xsprintf_sys_block_path(p, "/queue", d); + if (access(p, F_OK) >= 0) { *ret = d; return 0; } /* If it is a partition find the originating device */ - if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r < 0) + xsprintf_sys_block_path(p, "/partition", d); + if (access(p, F_OK) < 0) return -ENOENT; /* Get parent dev_t */ - if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0) - return -ENOMEM; - + xsprintf_sys_block_path(p, "/../dev", d); r = read_one_line_file(p, &s); - free(p); - if (r < 0) return r; r = sscanf(s, "%u:%u", &m, &n); - free(s); - if (r != 2) return -EINVAL; /* Only return this if it is really good enough for us. */ - if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r >= 0) { - *ret = makedev(m, n); - return 0; - } + xsprintf_sys_block_path(p, "/queue", makedev(m, n)); + if (access(p, F_OK) < 0) + return -ENOENT; - return -ENOENT; + *ret = makedev(m, n); + return 0; } bool kexec_loaded(void) { @@ -757,7 +738,8 @@ int get_block_device(const char *path, dev_t *dev) { int get_block_device_harder(const char *path, dev_t *dev) { _cleanup_closedir_ DIR *d = NULL; - _cleanup_free_ char *p = NULL, *t = NULL; + _cleanup_free_ char *t = NULL; + char p[SYS_BLOCK_PATH_MAX("/slaves")]; struct dirent *de, *found = NULL; const char *q; unsigned maj, min; @@ -775,9 +757,7 @@ int get_block_device_harder(const char *path, dev_t *dev) { if (r <= 0) return r; - if (asprintf(&p, "/sys/dev/block/%u:%u/slaves", major(dt), minor(dt)) < 0) - return -ENOMEM; - + xsprintf_sys_block_path(p, "/slaves", dt); d = opendir(p); if (!d) { if (errno == ENOENT) diff --git a/src/basic/util.h b/src/basic/util.h index aa2830dcc..f4314c674 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/verbs.c b/src/basic/verbs.c index f446d1c9b..cb42e6dd0 100644 --- a/src/basic/verbs.c +++ b/src/basic/verbs.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/verbs.h b/src/basic/verbs.h index 05678af41..5f44a18f8 100644 --- a/src/basic/verbs.h +++ b/src/basic/verbs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/virt.c b/src/basic/virt.c index 406bd8214..eac5c0626 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/virt.h b/src/basic/virt.h index f448f4e8f..c531b3365 100644 --- a/src/basic/virt.h +++ b/src/basic/virt.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index f52d03457..1a309be2e 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -105,7 +106,7 @@ int fgetxattr_malloc(int fd, const char *name, char **value) { #if 0 /// UNNEEDED by elogind ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) { - char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; _cleanup_close_ int fd = -1; ssize_t l; diff --git a/src/basic/xattr-util.h b/src/basic/xattr-util.h index 254f5a038..63ac72f72 100644 --- a/src/basic/xattr-util.h +++ b/src/basic/xattr-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** -- cgit v1.2.3