diff options
Diffstat (limited to 'src/basic')
201 files changed, 2610 insertions, 1179 deletions
diff --git a/src/basic/MurmurHash2.c b/src/basic/MurmurHash2.c index a282a21201..47adfb4d0a 100644 --- a/src/basic/MurmurHash2.c +++ b/src/basic/MurmurHash2.c @@ -15,6 +15,10 @@ #include "MurmurHash2.h" +#if __GNUC__ >= 7 +_Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") +#endif + //----------------------------------------------------------------------------- // Platform-specific functions and macros diff --git a/src/basic/af-list.c b/src/basic/af-list.c index 4b291d177b..fa81a69e0e 100644 --- a/src/basic/af-list.c +++ b/src/basic/af-list.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/af-list.h b/src/basic/af-list.h index 6a4cc03839..65656022cc 100644 --- a/src/basic/af-list.h +++ b/src/basic/af-list.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c index 948389f276..cdde4f2859 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. @@ -37,7 +38,7 @@ void* memdup(const void *p, size_t l) { return ret; } -void* memdup_suffix0(const void*p, size_t l) { +void* memdup_suffix0(const void *p, size_t l) { void *ret; assert(l == 0 || p); diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index 0a89691bae..02dee37d36 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 /*** @@ -54,7 +55,7 @@ static inline void *mfree(void *memory) { }) void* memdup(const void *p, size_t l) _alloc_(2); -void* memdup_suffix0(const void*p, size_t l) _alloc_(2); +void* memdup_suffix0(const void *p, size_t l) _alloc_(2); static inline void freep(void *p) { free(*(void**) p); diff --git a/src/basic/architecture.c b/src/basic/architecture.c index 2518dd8112..46157061ed 100644 --- a/src/basic/architecture.c +++ b/src/basic/architecture.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/architecture.h b/src/basic/architecture.h index 40a2ce6448..c81a1c2f44 100644 --- a/src/basic/architecture.h +++ b/src/basic/architecture.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/arphrd-list.c b/src/basic/arphrd-list.c index 2d598dc66f..5df93a59c1 100644 --- a/src/basic/arphrd-list.c +++ b/src/basic/arphrd-list.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/arphrd-list.h b/src/basic/arphrd-list.h index c0f8758dbe..2222e92c8a 100644 --- a/src/basic/arphrd-list.h +++ b/src/basic/arphrd-list.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/async.c b/src/basic/async.c index a1f163f27b..d368b92522 100644 --- a/src/basic/async.c +++ b/src/basic/async.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/async.h b/src/basic/async.h index 9bd13ff6e0..7eac54d8b2 100644 --- a/src/basic/async.h +++ b/src/basic/async.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 24a6c8a936..6a93c9109c 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 3088951326..dba15de8ee 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/barrier.c b/src/basic/barrier.c index 0c44e47b12..cd3638b676 100644 --- a/src/basic/barrier.c +++ b/src/basic/barrier.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/barrier.h b/src/basic/barrier.h index fbc2d9d98d..7260d751c4 100644 --- a/src/basic/barrier.h +++ b/src/basic/barrier.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c index f6212e6151..f1aa7c5e51 100644 --- a/src/basic/bitmap.c +++ b/src/basic/bitmap.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/bitmap.h b/src/basic/bitmap.h index 63fdbe8bea..f1d822c643 100644 --- a/src/basic/bitmap.h +++ b/src/basic/bitmap.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/blkid-util.h b/src/basic/blkid-util.h index 53340ec6f3..3aba76b79e 100644 --- a/src/basic/blkid-util.h +++ b/src/basic/blkid-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/bpf-program.c b/src/basic/bpf-program.c index ce6f9e4409..3690f812ae 100644 --- a/src/basic/bpf-program.c +++ b/src/basic/bpf-program.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/bpf-program.h b/src/basic/bpf-program.h index 35a41ffc44..146350d18e 100644 --- a/src/basic/bpf-program.h +++ b/src/basic/bpf-program.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index c2061addd1..ac96e63531 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -41,6 +42,7 @@ #include "btrfs-util.h" #include "chattr-util.h" #include "copy.h" +#include "device-nodes.h" #include "fd-util.h" #include "fileio.h" #include "io-util.h" @@ -909,7 +911,8 @@ int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, u int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) { struct btrfs_ioctl_vol_args args = {}; - _cleanup_free_ char *p = NULL, *loop = NULL, *backing = NULL; + char p[SYS_BLOCK_PATH_MAX("/loop/backing_file")]; + _cleanup_free_ char *backing = NULL; _cleanup_close_ int loop_fd = -1, backing_fd = -1; struct stat st; dev_t dev = 0; @@ -929,8 +932,7 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) { if (r == 0) return -ENODEV; - if (asprintf(&p, "/sys/dev/block/%u:%u/loop/backing_file", major(dev), minor(dev)) < 0) - return -ENOMEM; + xsprintf_sys_block_path(p, "/loop/backing_file", dev); r = read_one_line_file(p, &backing); if (r == -ENOENT) return -ENODEV; @@ -954,9 +956,8 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) { if (grow_only && new_size < (uint64_t) st.st_size) return -EINVAL; - if (asprintf(&loop, "/dev/block/%u:%u", major(dev), minor(dev)) < 0) - return -ENOMEM; - loop_fd = open(loop, O_RDWR|O_CLOEXEC|O_NOCTTY); + xsprintf_sys_block_path(p, NULL, dev); + loop_fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY); if (loop_fd < 0) return -errno; @@ -1212,7 +1213,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol if (!S_ISDIR(st.st_mode)) return -EINVAL; - subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW); if (subvol_fd < 0) return -errno; @@ -1292,7 +1293,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol * hence we need to open the * containing directory first */ - child_fd = openat(subvol_fd, ino_args.name, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + child_fd = openat(subvol_fd, ino_args.name, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW); if (child_fd < 0) return -errno; @@ -1641,7 +1642,7 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum if (!c) return -ENOMEM; - old_child_fd = openat(old_fd, c, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + old_child_fd = openat(old_fd, c, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW); if (old_child_fd < 0) return -errno; @@ -1649,7 +1650,7 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum if (!np) return -ENOMEM; - new_child_fd = openat(new_fd, np, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + new_child_fd = openat(new_fd, np, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW); if (new_child_fd < 0) return -errno; @@ -1660,7 +1661,7 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum * into place. */ if (subvolume_fd < 0) { - subvolume_fd = openat(new_fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + subvolume_fd = openat(new_fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW); if (subvolume_fd < 0) return -errno; } diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 04a2e1274b..2c78daa37b 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-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 9aaa6e3dae..ab2a838ce9 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 d4531c7947..a072d0ad5d 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 600268b767..5c6bc1f267 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/calendarspec.c b/src/basic/calendarspec.c index 1fc9e9b154..e6add0c383 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -23,6 +24,7 @@ #include <limits.h> #include <stddef.h> #include <stdio.h> +#include <stdio_ext.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> @@ -50,10 +52,10 @@ static void free_chain(CalendarComponent *c) { } } -void calendar_spec_free(CalendarSpec *c) { +CalendarSpec* calendar_spec_free(CalendarSpec *c) { if (!c) - return; + return NULL; free_chain(c->year); free_chain(c->month); @@ -63,7 +65,7 @@ void calendar_spec_free(CalendarSpec *c) { free_chain(c->microsecond); free(c->timezone); - free(c); + return mfree(c); } static int component_compare(const void *_a, const void *_b) { @@ -260,19 +262,19 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { if (l < 0) { if (need_comma) - fputc_unlocked(',', f); + fputc(',', f); else need_comma = true; - fputs_unlocked(days[x], f); + fputs(days[x], f); l = x; } } else if (l >= 0) { if (x > l + 1) { - fputs_unlocked(x > l + 2 ? ".." : ",", f); - fputs_unlocked(days[x-1], f); + fputs(x > l + 2 ? ".." : ",", f); + fputs(days[x-1], f); } l = -1; @@ -280,8 +282,8 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { } if (l >= 0 && x > l + 1) { - fputs_unlocked(x > l + 2 ? ".." : ",", f); - fputs_unlocked(days[x-1], f); + fputs(x > l + 2 ? ".." : ",", f); + fputs(days[x-1], f); } } @@ -291,12 +293,12 @@ static void format_chain(FILE *f, int space, const CalendarComponent *c, bool us assert(f); if (!c) { - fputc_unlocked('*', f); + fputc('*', f); return; } if (usec && c->start == 0 && c->repeat == USEC_PER_SEC && !c->next) { - fputc_unlocked('*', f); + fputc('*', f); return; } @@ -317,7 +319,7 @@ static void format_chain(FILE *f, int space, const CalendarComponent *c, bool us fprintf(f, ".%06i", c->repeat % d); if (c->next) { - fputc_unlocked(',', f); + fputc(',', f); format_chain(f, space, c->next, usec); } } @@ -335,28 +337,30 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) { if (!f) return -ENOMEM; + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + if (c->weekdays_bits > 0 && c->weekdays_bits <= BITS_WEEKDAYS) { format_weekdays(f, c); - fputc_unlocked(' ', f); + fputc(' ', f); } format_chain(f, 4, c->year, false); - fputc_unlocked('-', f); + fputc('-', f); format_chain(f, 2, c->month, false); - fputc_unlocked(c->end_of_month ? '~' : '-', f); + fputc(c->end_of_month ? '~' : '-', f); format_chain(f, 2, c->day, false); - fputc_unlocked(' ', f); + fputc(' ', f); format_chain(f, 2, c->hour, false); - fputc_unlocked(':', f); + fputc(':', f); format_chain(f, 2, c->minute, false); - fputc_unlocked(':', f); + fputc(':', f); format_chain(f, 2, c->microsecond, true); if (c->utc) - fputs_unlocked(" UTC", f); + fputs(" UTC", f); else if (c->timezone != NULL) { - fputc_unlocked(' ', f); - fputs_unlocked(c->timezone, f); + fputc(' ', f); + fputs(c->timezone, f); } else if (IN_SET(c->dst, 0, 1)) { /* If daylight saving is explicitly on or off, let's show the used timezone. */ @@ -364,8 +368,8 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) { tzset(); if (!isempty(tzname[c->dst])) { - fputc_unlocked(' ', f); - fputs_unlocked(tzname[c->dst], f); + fputc(' ', f); + fputs(tzname[c->dst], f); } } diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h index 8888251705..124f7f5880 100644 --- a/src/basic/calendarspec.h +++ b/src/basic/calendarspec.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -51,7 +52,7 @@ typedef struct CalendarSpec { CalendarComponent *microsecond; } CalendarSpec; -void calendar_spec_free(CalendarSpec *c); +CalendarSpec* calendar_spec_free(CalendarSpec *c); int calendar_spec_normalize(CalendarSpec *spec); bool calendar_spec_valid(CalendarSpec *spec); @@ -60,3 +61,5 @@ int calendar_spec_to_string(const CalendarSpec *spec, char **p); int calendar_spec_from_string(const char *p, CalendarSpec **spec); int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next); + +DEFINE_TRIVIAL_CLEANUP_FUNC(CalendarSpec*, calendar_spec_free); diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c index 2e9b2d9a55..c4557666ef 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. @@ -53,8 +54,12 @@ int capability_from_name(const char *name) { /* Try to parse numeric capability */ r = safe_atoi(name, &i); - if (r >= 0 && i >= 0) - return i; + if (r >= 0) { + if (i >= 0 && i < (int) ELEMENTSOF(capability_names)) + return i; + else + return -EINVAL; + } /* Try to parse string capability */ sc = lookup_capability(name, strlen(name)); diff --git a/src/basic/cap-list.h b/src/basic/cap-list.h index f9f6b70d80..ca9f4aa970 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 96c2e992bd..97778c55ab 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 3dc9429153..fd9370ecb7 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 d51c3efd22..f599d0f0f1 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 <limits.h> #include <signal.h> #include <stddef.h> +#include <stdio_ext.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> @@ -875,115 +877,87 @@ int cg_attach_fallback(const char *controller, const char *path, pid_t pid) { return r; } -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; + unified = cg_unified_controller(controller); + if (unified < 0) + return unified; - /* 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); + /* Configure access to the cgroup itself */ + r = cg_get_path(controller, path, NULL, &fs); if (r < 0) return r; - r = chmod_and_chown(fs, mode, uid, gid); + r = chmod_and_chown(fs, 0755, uid, gid); if (r < 0) return r; - r = cg_unified_controller(controller); - 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; + + log_debug_errno(r, "Failed to set access on cgroup %s, ignoring: %m", fs); + } + } - r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid); + 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 systemd cgroup %s, ignoring: %m", path); + } } return 0; @@ -1059,6 +1033,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; @@ -1103,6 +1079,11 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **path) { if (!p) return -ENOMEM; + /* Truncate suffix indicating the process is a zombie */ + e = endswith(p, " (deleted)"); + if (e) + *e = 0; + *path = p; return 0; } @@ -1278,7 +1259,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) { @@ -1331,7 +1312,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); @@ -1493,7 +1474,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) { @@ -1577,7 +1558,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) { @@ -1614,7 +1595,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) { @@ -2086,8 +2067,7 @@ int cg_get_keyed_attribute(const char *controller, const char *path, const char for (i = 0; keys[i]; i++) { if (!values[i]) { for (i = 0; keys[i]; i++) { - free(values[i]); - values[i] = NULL; + values[i] = mfree(values[i]); } return -ENOENT; } @@ -2244,10 +2224,10 @@ int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) } 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); @@ -2257,19 +2237,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; } @@ -2355,24 +2348,34 @@ int cg_mask_supported(CGroupMask *ret) { return 0; } -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); @@ -2407,6 +2410,9 @@ int cg_kernel_controllers(Set *controllers) { return r; } + *ret = controllers; + controllers = NULL; + return 0; } @@ -2436,28 +2442,39 @@ 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; - else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) { + } else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) { 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 systemd controller"); unified_cache = CGROUP_UNIFIED_SYSTEMD; unified_systemd_v232 = false; - } else if (statfs("/sys/fs/cgroup/systemd/", &fs) == 0 && - F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) { - unified_cache = CGROUP_UNIFIED_SYSTEMD; - unified_systemd_v232 = true; } else { if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0) - return -errno; - if (!F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC)) - return -ENOMEDIUM; - unified_cache = CGROUP_UNIFIED_NONE; + 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 + } else { + log_debug("Unknown filesystem type %llx mounted on /sys/fs/cgroup.", + (unsigned long long) fs.f_type); return -ENOMEDIUM; + } return 0; } @@ -2505,6 +2522,7 @@ int cg_unified_flush(void) { } 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; @@ -2538,7 +2556,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 c16a33723c..05c9f84505 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,14 +32,18 @@ #include "macro.h" #include "set.h" +#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=systemd" +#define SYSTEMD_CGROUP_CONTROLLER_HYBRID "name=unified" +#define SYSTEMD_CGROUP_CONTROLLER "_systemd" + /* An enum of well known cgroup controllers */ typedef enum CGroupController { CGROUP_CONTROLLER_CPU, - CGROUP_CONTROLLER_CPUACCT, - CGROUP_CONTROLLER_IO, - CGROUP_CONTROLLER_BLKIO, + CGROUP_CONTROLLER_CPUACCT, /* v1 only */ + CGROUP_CONTROLLER_IO, /* v2 only */ + CGROUP_CONTROLLER_BLKIO, /* v1 only */ CGROUP_CONTROLLER_MEMORY, - CGROUP_CONTROLLER_DEVICES, + CGROUP_CONTROLLER_DEVICES, /* v1 only */ CGROUP_CONTROLLER_PIDS, _CGROUP_CONTROLLER_MAX, _CGROUP_CONTROLLER_INVALID = -1, @@ -183,8 +188,7 @@ int cg_set_attribute(const char *controller, const char *path, const char *attri int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret); 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); @@ -238,7 +242,7 @@ int cg_mask_supported(CGroupMask *ret); int cg_mask_from_string(const char *s, CGroupMask *ret); int cg_mask_to_string(CGroupMask mask, char **ret); -int cg_kernel_controllers(Set *controllers); +int cg_kernel_controllers(Set **controllers); bool cg_ns_supported(void); diff --git a/src/basic/chattr-util.c b/src/basic/chattr-util.c index 2896a729af..3635deee4e 100644 --- a/src/basic/chattr-util.c +++ b/src/basic/chattr-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/chattr-util.h b/src/basic/chattr-util.h index 960cf6d5b3..a4ddaeeb8c 100644 --- a/src/basic/chattr-util.h +++ b/src/basic/chattr-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index 7fe8d35ea5..e2499099b6 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -72,7 +73,7 @@ int clock_set_hwclock(const struct tm *tm) { int clock_is_localtime(const char* adjtime_path) { _cleanup_fclose_ FILE *f; - if (adjtime_path == NULL) + if (!adjtime_path) adjtime_path = "/etc/adjtime"; /* diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h index 8830cd2f38..b90c31fb78 100644 --- a/src/basic/clock-util.h +++ b/src/basic/clock-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index 907d1350fe..c0ac202f57 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 20ecf6e5f1..75dfd05e7c 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 e120b9eb4e..0673ecd4a2 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 4f3e11423e..59da4c2425 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/cpu-set-util.c b/src/basic/cpu-set-util.c index aec0edc3dc..9f0a61a18e 100644 --- a/src/basic/cpu-set-util.c +++ b/src/basic/cpu-set-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -59,19 +60,19 @@ cpu_set_t* cpu_set_malloc(unsigned *ncpus) { } } -int parse_cpu_set_and_warn( +int parse_cpu_set_internal( const char *rvalue, cpu_set_t **cpu_set, + bool warn, const char *unit, const char *filename, unsigned line, const char *lvalue) { - const char *whole_rvalue = rvalue; _cleanup_cpu_free_ cpu_set_t *c = NULL; + const char *p = rvalue; unsigned ncpus = 0; - assert(lvalue); assert(rvalue); for (;;) { @@ -79,75 +80,34 @@ int parse_cpu_set_and_warn( unsigned cpu, cpu_lower, cpu_upper; int r; - r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES); + r = extract_first_word(&p, &word, WHITESPACE ",", EXTRACT_QUOTES); + if (r == -ENOMEM) + return warn ? log_oom() : -ENOMEM; if (r < 0) - return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue); + return warn ? log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, rvalue) : r; if (r == 0) break; if (!c) { c = cpu_set_malloc(&ncpus); if (!c) - return log_oom(); + return warn ? log_oom() : -ENOMEM; } r = parse_range(word, &cpu_lower, &cpu_upper); if (r < 0) - return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word); + return warn ? log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word) : r; if (cpu_lower >= ncpus || cpu_upper >= ncpus) - return log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus); - - if (cpu_lower > cpu_upper) - log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u", word, cpu_lower, cpu_upper); - else - for (cpu = cpu_lower; cpu <= cpu_upper; cpu++) - CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); - } - - /* On success, sets *cpu_set and returns ncpus for the system. */ - if (c) { - *cpu_set = c; - c = NULL; - } - - return (int) ncpus; -} - -int parse_cpu_set( - const char *rvalue, - cpu_set_t **cpu_set) { - - _cleanup_cpu_free_ cpu_set_t *c = NULL; - unsigned ncpus = 0; + return warn ? log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus) : -EINVAL; - assert(rvalue); - - for (;;) { - _cleanup_free_ char *word = NULL; - unsigned cpu, cpu_lower, cpu_upper; - int r; - - r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES); - if (r == -ENOMEM) - return r; - if (r <= 0) - break; - - if (!c) { - c = cpu_set_malloc(&ncpus); - if (!c) - return -ENOMEM; + if (cpu_lower > cpu_upper) { + if (warn) + log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u, ignoring", word, cpu_lower, cpu_upper); + continue; } - r = parse_range(word, &cpu_lower, &cpu_upper); - if (r < 0) - return r; - if (cpu_lower >= ncpus || cpu_upper >= ncpus) - return -EINVAL; - - if (cpu_lower <= cpu_upper) - for (cpu = cpu_lower; cpu <= cpu_upper; cpu++) - CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); + for (cpu = cpu_lower; cpu <= cpu_upper; cpu++) + CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); } /* On success, sets *cpu_set and returns ncpus for the system. */ diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h index 9b08ba0a67..c98149eaeb 100644 --- a/src/basic/cpu-set-util.h +++ b/src/basic/cpu-set-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -24,10 +25,31 @@ #include "macro.h" +#ifdef __NCPUBITS +#define CPU_SIZE_TO_NUM(n) ((n) * __NCPUBITS) +#else +#define CPU_SIZE_TO_NUM(n) ((n) * sizeof(cpu_set_t) * 8) +#endif + DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); #define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) +static inline cpu_set_t* cpu_set_mfree(cpu_set_t *p) { + if (p) + CPU_FREE(p); + return NULL; +} + cpu_set_t* cpu_set_malloc(unsigned *ncpus); -int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue); -int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set); +int parse_cpu_set_internal(const char *rvalue, cpu_set_t **cpu_set, bool warn, const char *unit, const char *filename, unsigned line, const char *lvalue); + +static inline int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue) { + assert(lvalue); + + return parse_cpu_set_internal(rvalue, cpu_set, true, unit, filename, line, lvalue); +} + +static inline int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set){ + return parse_cpu_set_internal(rvalue, cpu_set, false, NULL, NULL, 0, NULL); +} diff --git a/src/basic/crypt-util.c b/src/basic/crypt-util.c new file mode 100644 index 0000000000..193cf65dfc --- /dev/null +++ b/src/basic/crypt-util.c @@ -0,0 +1,27 @@ +/*** + This file is part of systemd. + + Copyright 2017 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#if HAVE_LIBCRYPTSETUP +#include "crypt-util.h" +#include "log.h" + +void cryptsetup_log_glue(int level, const char *msg, void *usrptr) { + log_debug("%s", msg); +} +#endif diff --git a/src/basic/crypt-util.h b/src/basic/crypt-util.h new file mode 100644 index 0000000000..537f785607 --- /dev/null +++ b/src/basic/crypt-util.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/*** + This file is part of systemd. + + Copyright 2017 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#if HAVE_LIBCRYPTSETUP +#include <libcryptsetup.h> + +#include "macro.h" + +/* libcryptsetup define for any LUKS version, compatible with libcryptsetup 1.x */ +#ifndef CRYPT_LUKS +#define CRYPT_LUKS NULL +#endif + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct crypt_device *, crypt_free); + +void cryptsetup_log_glue(int level, const char *msg, void *usrptr); +#endif diff --git a/src/basic/def.h b/src/basic/def.h index c04e58b57a..77ab735aed 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -36,10 +37,6 @@ /* The default value for the net.unix.max_dgram_qlen sysctl */ #define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL -#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=systemd" -#define SYSTEMD_CGROUP_CONTROLLER_HYBRID "name=unified" -#define SYSTEMD_CGROUP_CONTROLLER "_systemd" - #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT #define SIGNALS_IGNORE SIGPIPE diff --git a/src/basic/device-nodes.c b/src/basic/device-nodes.c index 38c0628a90..61dc49238c 100644 --- a/src/basic/device-nodes.c +++ b/src/basic/device-nodes.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -39,7 +40,7 @@ int whitelisted_char_for_devnode(char c, const char *white) { int encode_devnode_name(const char *str, char *str_enc, size_t len) { size_t i, j; - if (str == NULL || str_enc == NULL) + if (!str || !str_enc) return -EINVAL; for (i = 0, j = 0; str[i] != '\0'; i++) { diff --git a/src/basic/device-nodes.h b/src/basic/device-nodes.h index 94f385abcb..7dd8a772a5 100644 --- a/src/basic/device-nodes.h +++ b/src/basic/device-nodes.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -22,5 +23,18 @@ #include <stddef.h> #include <sys/types.h> +#include "macro.h" +#include "stdio-util.h" + int encode_devnode_name(const char *str, char *str_enc, size_t len); int whitelisted_char_for_devnode(char c, const char *additional); + +#define SYS_BLOCK_PATH_MAX(suffix) \ + (STRLEN("/sys/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t) + strlen_ptr(suffix)) +#define xsprintf_sys_block_path(buf, suffix, devno) \ + xsprintf(buf, "/sys/dev/block/%u:%u%s", major(devno), minor(devno), strempty(suffix)) + +#define DEV_NUM_PATH_MAX \ + (STRLEN("/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t)) +#define xsprintf_dev_num_path(buf, type, devno) \ + xsprintf(buf, "/dev/%s/%u:%u", type, major(devno), minor(devno)) diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index 5bf58bcdc3..e2b093bad3 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 18b9db9b28..94d5ee81a3 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 fa42edfa96..e77f9d6d3f 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. @@ -805,14 +806,9 @@ int deserialize_environment(char ***environment, const char *line) { assert(environment); assert(startswith(line, "env=")); - r = cunescape(line + 4, UNESCAPE_RELAX, &uce); + r = cunescape(line + 4, 0, &uce); if (r < 0) return r; - if (!env_assignment_is_valid(uce)) { - free(uce); - return -EINVAL; - } - return strv_env_replace(environment, uce); } diff --git a/src/basic/env-util.h b/src/basic/env-util.h index d5da8cd67b..956a2a8270 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 c6a01eec8b..d8eedfc0ad 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,7 +52,3 @@ int errno_from_name(const char *name) { assert(sc->id > 0); return sc->id; } - -int errno_max(void) { - return ELEMENTSOF(errno_names); -} diff --git a/src/basic/errno-list.h b/src/basic/errno-list.h index 4eec0cc786..4e9b75a7ea 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,7 +20,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +/* + * 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); - -int errno_max(void); diff --git a/src/basic/escape.c b/src/basic/escape.c index 0a6122c64a..7d77aef329 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 6f5cc60bc8..de89f43a82 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/ether-addr-util.c b/src/basic/ether-addr-util.c index 5697e8d132..bbe8bf0006 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -70,7 +71,7 @@ int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset if (s[pos] == '\0') \ break; \ hexoff = strchr(hex, s[pos]); \ - if (hexoff == NULL) \ + if (!hexoff) \ break; \ assert(hexoff >= hex); \ x = hexoff - hex; \ @@ -98,7 +99,7 @@ int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset sep = s[strspn(s, hex)]; if (sep == '\n') return -EINVAL; - if (strchr(":.-", sep) == NULL) + if (!strchr(":.-", sep)) return -EINVAL; if (sep == '.') { diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 74e125a95f..08d05a136f 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.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 ade8511466..82ccbdf5ec 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. @@ -255,7 +256,7 @@ int execute_directories( static int gather_environment_generate(int fd, void *arg) { char ***env = arg, **x, **y; _cleanup_fclose_ FILE *f = NULL; - _cleanup_strv_free_ char **new; + _cleanup_strv_free_ char **new = NULL; int r; /* Read a series of VAR=value assignments from fd, use them to update the list of diff --git a/src/basic/exec-util.h b/src/basic/exec-util.h index 72009799b2..d69bec7bc2 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/exit-status.c b/src/basic/exit-status.c index 7cfebbae72..c02681d4cc 100644 --- a/src/basic/exit-status.c +++ b/src/basic/exit-status.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h index 195b3bc486..1e10419f8b 100644 --- a/src/basic/exit-status.h +++ b/src/basic/exit-status.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index f4ac526eb1..5e42560487 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 04746c6d08..300c51bb77 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 9d61044c89..a4a5c6b3f6 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" @@ -365,7 +368,7 @@ bool fdname_is_valid(const char *s) { } int fd_get_path(int fd, char **ret) { - char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; int r; xsprintf(procfs_path, "/proc/self/fd/%i", fd); @@ -377,3 +380,202 @@ int fd_get_path(int fd, char **ret) { return r; } + +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/<fd>. 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 34b98d4aec..84a0816f03 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 /*** @@ -75,6 +76,18 @@ bool fdname_is_valid(const char *s); int fd_get_path(int fd, char **ret); +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 ef51c49395..bf5fec1faa 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 9854ea50b9..0adb895236 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 /*** @@ -24,6 +25,10 @@ #include "fileio.h" +/* These functions are split out of fileio.h (and not for examplement just as flags to the functions they wrap) in + * order to optimize linking: This way, -lselinux is needed only for the callers of these functions that need selinux, + * but not for all */ + int write_string_file_atomic_label_ts(const char *fn, const char *line, struct timespec *ts); static inline int write_string_file_atomic_label(const char *fn, const char *line) { return write_string_file_atomic_label_ts(fn, line, NULL); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 9ee7a4af38..4e02d5b344 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,8 +23,10 @@ #include <limits.h> #include <stdarg.h> #include <stdint.h> +#include <stdio_ext.h> #include <stdlib.h> #include <string.h> +#include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> @@ -96,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); @@ -138,7 +142,7 @@ int write_string_file_ts( return r; } else - assert(ts == NULL); + assert(!ts); if (flags & WRITE_STRING_FILE_CREATE) { f = fopen(fn, "we"); @@ -165,6 +169,11 @@ int write_string_file_ts( } } + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + + if (flags & WRITE_STRING_FILE_DISABLE_BUFFER) + setvbuf(f, NULL, _IONBF, 0); + r = write_string_stream_ts(f, line, flags, ts); if (r < 0) goto fail; @@ -198,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; } @@ -223,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); @@ -318,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); } @@ -874,7 +889,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); @@ -1189,7 +1205,7 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { if (!filename_is_valid(fn)) return -EINVAL; - if (extra == NULL) + if (!extra) extra = ""; t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1); @@ -1456,7 +1472,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); @@ -1527,9 +1543,7 @@ int mkdtemp_malloc(const char *template, char **ret) { return 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; @@ -1556,7 +1570,7 @@ int read_line(FILE *f, size_t limit, char **ret) { } { - _cleanup_(funlockfilep) FILE *flocked = f; + _unused_ _cleanup_(funlockfilep) FILE *flocked = f; flockfile(f); for (;;) { diff --git a/src/basic/fileio.h b/src/basic/fileio.h index eba05be2a9..da5d5c66b5 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -29,11 +30,17 @@ #include "time-util.h" typedef enum { - WRITE_STRING_FILE_CREATE = 1<<0, - WRITE_STRING_FILE_ATOMIC = 1<<1, - WRITE_STRING_FILE_AVOID_NEWLINE = 1<<2, + WRITE_STRING_FILE_CREATE = 1<<0, + WRITE_STRING_FILE_ATOMIC = 1<<1, + WRITE_STRING_FILE_AVOID_NEWLINE = 1<<2, WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1<<3, - WRITE_STRING_FILE_SYNC = 1<<4, + WRITE_STRING_FILE_SYNC = 1<<4, + WRITE_STRING_FILE_DISABLE_BUFFER = 1<<5, + + /* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one + more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file() + and friends. */ + } WriteStringFileFlags; int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts); diff --git a/src/basic/format-util.h b/src/basic/format-util.h index ae42a8f89e..d9a78f7811 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 b90f343ed3..4ca36faf09 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. @@ -104,7 +105,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; @@ -509,7 +509,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; } @@ -580,7 +580,7 @@ int tmp_dir(const char **ret) { } 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 */ @@ -621,10 +621,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this * function what to do when encountering a symlink with an absolute path as directory: prefix it by the - * specified path. - * - * Note: there's also chase_symlinks_prefix() (see below), which as first step prefixes the passed path by the - * passed root. */ + * specified path. */ if (original_root) { r = path_make_absolute_cwd(original_root, &root); @@ -661,9 +658,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, "/.")) @@ -707,12 +713,16 @@ 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 "./" * or something else weird. */ + /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */ + if (streq_ptr(done, "/")) + *done = '\0'; + if (!strextend(&done, first, todo, NULL)) return -ENOMEM; @@ -726,7 +736,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)) { @@ -766,12 +776,11 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -ENOMEM; } - } - - /* Prefix what's left to do with what we just read, and start the loop again, - * but remain in the current directory. */ - - joined = strjoin("/", destination, todo); + /* Prefix what's left to do with what we just read, and start the loop again, but + * remain in the current directory. */ + joined = strjoin(destination, todo); + } else + joined = strjoin("/", destination, todo); if (!joined) return -ENOMEM; @@ -786,6 +795,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, done = first; first = NULL; } else { + /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */ + if (streq(done, "/")) + *done = '\0'; + if (!strextend(&done, first, NULL)) return -ENOMEM; } @@ -810,3 +823,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 d3342d5cda..a7ba61625d 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 /*** @@ -98,3 +99,5 @@ static inline void unlink_and_free(char *p) { free(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free); + +int access_fd(int fd, int mode); diff --git a/src/basic/generate-gperfs.py b/src/basic/generate-gperfs.py index d4cc9aa45c..aca9ab1fe9 100755 --- a/src/basic/generate-gperfs.py +++ b/src/basic/generate-gperfs.py @@ -8,6 +8,12 @@ import sys name, prefix, input = sys.argv[1:] print("""\ +%{ +#if __GNUC__ >= 7 +_Pragma("GCC diagnostic ignored \\"-Wimplicit-fallthrough\\"") +#endif +%}""") +print("""\ struct {}_name {{ const char* name; int id; }}; %null-strings %%""".format(name)) diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c index f611c42e4c..6e80a1e23b 100644 --- a/src/basic/glob-util.c +++ b/src/basic/glob-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/glob-util.h b/src/basic/glob-util.h index e1f6083afa..911e6d2c1a 100644 --- a/src/basic/glob-util.h +++ b/src/basic/glob-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/hash-funcs.c b/src/basic/hash-funcs.c index c3a4a011b5..e69f81558d 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 299189d143..959e2c101d 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 4bfaa864b4..cc4423b2af 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. @@ -25,12 +26,14 @@ #include "alloc-util.h" #include "hashmap.h" +#include "fileio.h" #include "macro.h" #include "mempool.h" #include "process-util.h" #include "random-util.h" #include "set.h" #include "siphash24.h" +#include "string-util.h" #include "strv.h" #include "util.h" @@ -278,6 +281,28 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { }, }; +#ifdef VALGRIND +__attribute__((destructor)) static void cleanup_pools(void) { + _cleanup_free_ char *t = NULL; + int r; + + /* Be nice to valgrind */ + + /* The pool is only allocated by the main thread, but the memory can + * be passed to other threads. Let's clean up if we are the main thread + * and no other threads are live. */ + if (!is_main_thread()) + return; + + r = get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t); + if (r < 0 || !streq(t, "1")) + return; + + mempool_drop(&hashmap_pool); + mempool_drop(&ordered_hashmap_pool); +} +#endif + static unsigned n_buckets(HashmapBase *h) { return h->has_indirect ? h->indirect.n_buckets : hashmap_type_info[h->type].n_direct_buckets; diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index c1089652d3..0eb763944c 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -328,6 +329,29 @@ static inline void *ordered_hashmap_first(OrderedHashmap *h) { return internal_hashmap_first(HASHMAP_BASE(h)); } +#define hashmap_clear_with_destructor(_s, _f) \ + ({ \ + void *_item; \ + while ((_item = hashmap_steal_first(_s))) \ + _f(_item); \ + }) +#define hashmap_free_with_destructor(_s, _f) \ + ({ \ + hashmap_clear_with_destructor(_s, _f); \ + hashmap_free(_s); \ + }) +#define ordered_hashmap_clear_with_destructor(_s, _f) \ + ({ \ + void *_item; \ + while ((_item = ordered_hashmap_steal_first(_s))) \ + _f(_item); \ + }) +#define ordered_hashmap_free_with_destructor(_s, _f) \ + ({ \ + ordered_hashmap_clear_with_destructor(_s, _f); \ + ordered_hashmap_free(_s); \ + }) + /* no hashmap_next */ void *ordered_hashmap_next(OrderedHashmap *h, const void *key); diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index 766770389c..fe7e4954ef 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. @@ -96,7 +97,10 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) { assert(mem); assert(len); - assert(p); + assert(p || l == 0); + + if (l == (size_t) -1) + l = strlen(p); if (l % 2 != 0) return -EINVAL; @@ -160,6 +164,8 @@ char *base32hexmem(const void *p, size_t l, bool padding) { const uint8_t *x; size_t len; + assert(p || l == 0); + if (padding) /* five input bytes makes eight output bytes, padding is added so we must round up */ len = 8 * (l + 4) / 5; @@ -269,7 +275,12 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l size_t len; unsigned pad = 0; - assert(p); + assert(p || l == 0); + assert(mem); + assert(_len); + + if (l == (size_t) -1) + l = strlen(p); /* padding ensures any base32hex input has input divisible by 8 */ if (padding && l % 8 != 0) @@ -519,6 +530,9 @@ ssize_t base64mem(const void *p, size_t l, char **out) { char *r, *z; const uint8_t *x; + assert(p || l == 0); + assert(out); + /* three input bytes makes four output bytes, padding is added so we must round up */ z = r = malloc(4 * (l + 2) / 3 + 1); if (!r) @@ -554,10 +568,11 @@ ssize_t base64mem(const void *p, size_t l, char **out) { return z - r; } -static int base64_append_width(char **prefix, int plen, - const char *sep, int indent, - const void *p, size_t l, - int width) { +static int base64_append_width( + char **prefix, int plen, + const char *sep, int indent, + const void *p, size_t l, + int width) { _cleanup_free_ char *x = NULL; char *t, *s; @@ -596,118 +611,148 @@ static int base64_append_width(char **prefix, int plen, return 0; } -int base64_append(char **prefix, int plen, - const void *p, size_t l, - int indent, int width) { +int base64_append( + char **prefix, int plen, + const void *p, size_t l, + int indent, int width) { + if (plen > width / 2 || plen + indent > width) /* leave indent on the left, keep last column free */ return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1); else /* leave plen on the left, keep last column free */ return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1); -}; +} - -int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { - _cleanup_free_ uint8_t *r = NULL; - int a, b, c, d; - uint8_t *z; - const char *x; - size_t len; +static int unbase64_next(const char **p, size_t *l) { + int ret; assert(p); + assert(l); - /* padding ensures any base63 input has input divisible by 4 */ - if (l % 4 != 0) - return -EINVAL; - - /* strip the padding */ - if (l > 0 && p[l - 1] == '=') - l--; - if (l > 0 && p[l - 1] == '=') - l--; + /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We + * greedily skip all preceeding and all following whitespace. */ - /* a group of four input bytes needs three output bytes, in case of - padding we need to add two or three extra bytes */ - len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0); + for (;;) { + if (*l == 0) + return -EPIPE; - z = r = malloc(len + 1); - if (!r) - return -ENOMEM; + if (!strchr(WHITESPACE, **p)) + break; - for (x = p; x < p + (l / 4) * 4; x += 4) { - /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; + /* Skip leading whitespace */ + (*p)++, (*l)--; + } - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; + if (**p == '=') + ret = INT_MAX; /* return padding as INT_MAX */ + else { + ret = unbase64char(**p); + if (ret < 0) + return ret; + } - c = unbase64char(x[2]); - if (c < 0) - return -EINVAL; + for (;;) { + (*p)++, (*l)--; - d = unbase64char(x[3]); - if (d < 0) - return -EINVAL; + if (*l == 0) + break; + if (!strchr(WHITESPACE, **p)) + break; - *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ - *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ - *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ + /* Skip following whitespace */ } - switch (l % 4) { - case 3: - a = unbase64char(x[0]); + return ret; +} + +int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) { + _cleanup_free_ uint8_t *buf = NULL; + const char *x; + uint8_t *z; + size_t len; + + assert(p || l == 0); + assert(ret); + assert(ret_size); + + if (l == (size_t) -1) + l = strlen(p); + + /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra + bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */ + len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0); + + buf = malloc(len + 1); + if (!buf) + return -ENOMEM; + + for (x = p, z = buf;;) { + int a, b, c, d; /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ + + a = unbase64_next(&x, &l); + if (a == -EPIPE) /* End of string */ + break; if (a < 0) + return a; + if (a == INT_MAX) /* Padding is not allowed at the beginning of a 4ch block */ return -EINVAL; - b = unbase64char(x[1]); + b = unbase64_next(&x, &l); if (b < 0) + return b; + if (b == INT_MAX) /* Padding is not allowed at the second character of a 4ch block either */ return -EINVAL; - c = unbase64char(x[2]); + c = unbase64_next(&x, &l); if (c < 0) - return -EINVAL; + return c; - /* c == 00ZZZZ00 */ - if (c & 3) - return -EINVAL; + d = unbase64_next(&x, &l); + if (d < 0) + return d; - *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ - *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + if (c == INT_MAX) { /* Padding at the third character */ - break; - case 2: - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; + if (d != INT_MAX) /* If the third character is padding, the fourth must be too */ + return -EINVAL; - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; + /* b == 00YY0000 */ + if (b & 15) + return -EINVAL; - /* b == 00YY0000 */ - if (b & 15) - return -EINVAL; + if (l > 0) /* Trailing rubbish? */ + return -ENAMETOOLONG; - *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ + *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ + break; + } - break; - case 0: + if (d == INT_MAX) { + /* c == 00ZZZZ00 */ + if (c & 3) + return -EINVAL; - break; - default: - return -EINVAL; + if (l > 0) /* Trailing rubbish? */ + return -ENAMETOOLONG; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + break; + } + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ } *z = 0; - *mem = r; - r = NULL; - *_len = len; + if (ret_size) + *ret_size = (size_t) (z - buf); + + *ret = buf; + buf = NULL; return 0; } @@ -716,7 +761,10 @@ void hexdump(FILE *f, const void *p, size_t s) { const uint8_t *b = p; unsigned n = 0; - assert(s == 0 || b); + assert(b || s == 0); + + if (!f) + f = stdout; while (s > 0) { size_t i; diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h index 1ba2f69ebd..08d0a52276 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 ea9e77087f..b59e5425a5 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 <sys/utsname.h> #include <unistd.h> +#include "alloc-util.h" +#include "def.h" #include "fd-util.h" #include "fileio.h" #include "hostname-util.h" @@ -218,35 +221,87 @@ 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; } diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index 7af4e6c7ec..d837d6f28c 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 /*** @@ -38,4 +39,7 @@ bool is_gateway_hostname(const char *hostname); int sethostname_idempotent(const char *s); -int read_hostname_config(const char *path, char **hostname); +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/in-addr-util.c b/src/basic/in-addr-util.c index e27faba75f..572e172b33 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 59f8eb7edf..acaae6d287 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/io-util.c b/src/basic/io-util.c index cc6dfa8c1b..77c9bdc739 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. @@ -199,7 +200,6 @@ int fd_wait_for_event(int fd, int event, usec_t t) { r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); if (r < 0) return -errno; - if (r == 0) return 0; diff --git a/src/basic/io-util.h b/src/basic/io-util.h index d9b69adde9..d81610ad21 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/journal-importer.c b/src/basic/journal-importer.c index e750101165..6942c370cb 100644 --- a/src/basic/journal-importer.c +++ b/src/basic/journal-importer.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -95,7 +96,7 @@ static int get_line(JournalImporter *imp, char **line, size_t *size) { assert(imp->state == IMPORTER_STATE_LINE); assert(imp->offset <= imp->filled); assert(imp->filled <= imp->size); - assert(imp->buf == NULL || imp->size > 0); + assert(!imp->buf || imp->size > 0); assert(imp->fd >= 0); for (;;) { @@ -158,8 +159,8 @@ static int fill_fixed_size(JournalImporter *imp, void **data, size_t size) { assert(size <= DATA_SIZE_MAX); assert(imp->offset <= imp->filled); assert(imp->filled <= imp->size); - assert(imp->buf != NULL || imp->size == 0); - assert(imp->buf == NULL || imp->size > 0); + assert(imp->buf || imp->size == 0); + assert(!imp->buf || imp->size > 0); assert(imp->fd >= 0); assert(data); diff --git a/src/basic/journal-importer.h b/src/basic/journal-importer.h index b3e308dd6d..d11caa2396 100644 --- a/src/basic/journal-importer.h +++ b/src/basic/journal-importer.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/khash.c b/src/basic/khash.c index 84648dc1c9..694210512c 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. @@ -126,9 +127,7 @@ khash* khash_unref(khash *h) { safe_close(h->fd); free(h->algorithm); - free(h); - - return NULL; + return mfree(h); } int khash_dup(khash *h, khash **ret) { diff --git a/src/basic/khash.h b/src/basic/khash.h index 410f3020e0..7041d39993 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 f5ab855d32..ce81d286ab 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 3e9251aa71..86447c2e98 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 c3771a177f..7006c3e273 100644 --- a/src/basic/list.h +++ b/src/basic/list.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -182,3 +183,6 @@ for ((i) = (p)->name##_next ? (p)->name##_next : (head); \ (i) != (p); \ (i) = (i)->name##_next ? (i)->name##_next : (head)) + +#define LIST_IS_EMPTY(head) \ + (!(head)) diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index ada0a28cd8..266cb29936 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. @@ -20,6 +21,7 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> +#include <ftw.h> #include <langinfo.h> #include <libintl.h> #include <locale.h> @@ -30,6 +32,7 @@ #include <sys/mman.h> #include <sys/stat.h> +#include "def.h" #include "dirent-util.h" #include "fd-util.h" #include "hashmap.h" @@ -270,6 +273,99 @@ out: return (bool) cached_answer; } +static thread_local Set *keymaps = NULL; + +static int nftw_cb( + const char *fpath, + const struct stat *sb, + int tflag, + struct FTW *ftwbuf) { + + char *p, *e; + int r; + + if (tflag != FTW_F) + return 0; + + if (!endswith(fpath, ".map") && + !endswith(fpath, ".map.gz")) + return 0; + + p = strdup(basename(fpath)); + if (!p) + return FTW_STOP; + + e = endswith(p, ".map"); + if (e) + *e = 0; + + e = endswith(p, ".map.gz"); + if (e) + *e = 0; + + r = set_consume(keymaps, p); + if (r < 0 && r != -EEXIST) + return r; + + return 0; +} + +int get_keymaps(char ***ret) { + _cleanup_strv_free_ char **l = NULL; + const char *dir; + int r; + + keymaps = set_new(&string_hash_ops); + if (!keymaps) + return -ENOMEM; + + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + r = nftw(dir, nftw_cb, 20, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); + + if (r == FTW_STOP) + log_debug("Directory not found %s", dir); + else if (r < 0) + log_debug_errno(r, "Can't add keymap: %m"); + } + + l = set_get_strv(keymaps); + if (!l) { + set_free_free(keymaps); + return -ENOMEM; + } + + set_free(keymaps); + + if (strv_isempty(l)) + return -ENOENT; + + strv_sort(l); + + *ret = l; + l = NULL; + + return 0; +} + +bool keymap_is_valid(const char *name) { + + if (isempty(name)) + return false; + + if (strlen(name) >= 128) + return false; + + if (!utf8_is_valid(name)) + return false; + + if (!filename_is_valid(name)) + return false; + + if (!string_is_safe(name)) + return false; + + return true; +} const char *special_glyph(SpecialGlyph code) { diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index 0630a034ab..60ce017a15 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 /*** @@ -71,3 +72,6 @@ const char *special_glyph(SpecialGlyph code) _const_; const char* locale_variable_to_string(LocaleVariable i) _const_; LocaleVariable locale_variable_from_string(const char *s) _pure_; + +int get_keymaps(char ***l); +bool keymap_is_valid(const char *name); diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c index 3ee4191e4d..f4761a9d55 100644 --- a/src/basic/lockfile-util.c +++ b/src/basic/lockfile-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/lockfile-util.h b/src/basic/lockfile-util.h index 22491ee8e1..1e86ad7442 100644 --- a/src/basic/lockfile-util.h +++ b/src/basic/lockfile-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 4f0fe54579..20d9588e2f 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. @@ -358,7 +359,7 @@ static int write_to_console( highlight = LOG_PRI(level) <= LOG_ERR && show_color; if (show_location) { - snprintf(location, sizeof(location), "(%s:%i) ", file, line); + xsprintf(location, "(%s:%i) ", file, line); iovec[n++] = IOVEC_MAKE_STRING(location); } @@ -797,7 +798,7 @@ static void log_assert( return; DISABLE_WARNING_FORMAT_NONLITERAL; - snprintf(buffer, sizeof buffer, format, text, file, line, func); + xsprintf(buffer, format, text, file, line, func); REENABLE_WARNING; log_abort_msg = buffer; @@ -847,8 +848,8 @@ int log_oom_internal(LogRealm realm, const char *file, int line, const char *fun int log_format_iovec( struct iovec *iovec, - unsigned iovec_len, - unsigned *n, + size_t iovec_len, + size_t *n, bool newline_separator, int error, const char *format, @@ -928,7 +929,7 @@ int log_struct_internal( if (journal_fd >= 0) { char header[LINE_MAX]; struct iovec iovec[17] = {}; - unsigned n = 0, i; + size_t n = 0, i; int r; struct msghdr mh = { .msg_iov = iovec, @@ -1046,18 +1047,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 10a6032788..aa5976c3c0 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -180,8 +181,8 @@ int log_oom_internal( int log_format_iovec( struct iovec *iovec, - unsigned iovec_len, - unsigned *n, + size_t iovec_len, + size_t *n, bool newline_separator, int error, const char *format, diff --git a/src/basic/login-util.c b/src/basic/login-util.c index 339e94f12d..af4539453a 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 b01ee25c88..1c558bfe20 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 a51562db35..02d22de833 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -47,6 +48,11 @@ #define _weakref_(x) __attribute__((weakref(#x))) #define _alignas_(x) __attribute__((aligned(__alignof(x)))) #define _cleanup_(x) __attribute__((cleanup(x))) +#if __GNUC__ >= 7 +#define _fallthrough_ __attribute__((fallthrough)) +#else +#define _fallthrough_ +#endif /* Temporarily disable some warnings */ #define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT \ @@ -138,6 +144,14 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ sizeof(x)/sizeof((x)[0]), \ (void)0)) + +/* + * STRLEN - return the length of a string literal, minus the trailing NUL byte. + * Contrary to strlen(), this is a constant expression. + * @x: a string literal. + */ +#define STRLEN(x) (sizeof(""x"") - 1) + /* * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index 8f4f0e3a24..e7eb895462 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 46d4989e4c..1d66c98cce 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 f95e2beb0f..0da8e1f775 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 0618b8dd22..c9235c8361 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 1ddefb7fbb..a37e279e57 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -1,3 +1,20 @@ +# SPDX-License-Identifier: LGPL-2.1+ +# +# Copyright 2017 Zbigniew Jędrzejewski-Szmek +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see <http://www.gnu.org/licenses/>. + basic_sources_plain = files(''' MurmurHash2.c MurmurHash2.h @@ -44,6 +61,8 @@ basic_sources_plain = files(''' copy.h cpu-set-util.c cpu-set-util.h + crypt-util.c + crypt-util.h def.h device-nodes.c device-nodes.h @@ -113,6 +132,7 @@ basic_sources_plain = files(''' mkdir-label.c mkdir.c mkdir.h + module-util.h mount-util.c mount-util.h nss-util.h @@ -183,6 +203,8 @@ basic_sources_plain = files(''' unaligned.h unit-name.c unit-name.h + unit-def.c + unit-def.h user-util.c user-util.h utf8.c diff --git a/src/basic/missing.h b/src/basic/missing.h index 352d2b024b..790f9f55a5 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -542,10 +543,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 @@ -955,6 +952,10 @@ struct input_mask { #define IFLA_VRF_TABLE 1 #endif +#if !HAVE_VXCAN_INFO_PEER +#define VXCAN_INFO_PEER 1 +#endif + #if !HAVE_NDA_IFINDEX #define NDA_UNSPEC 0 #define NDA_DST 1 @@ -1266,4 +1267,16 @@ struct fib_rule_uid_range { #define AF_VSOCK 40 #endif +#ifndef EXT4_IOC_RESIZE_FS +# 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 3322e4e4d6..fd82c11e94 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 /*** @@ -319,6 +320,8 @@ static inline ssize_t copy_file_range(int fd_in, loff_t *off_in, } #endif +/* ======================================================================= */ + #if !HAVE_BPF # ifndef __NR_bpf # if defined __i386__ @@ -348,3 +351,31 @@ static inline int bpf(int cmd, union bpf_attr *attr, size_t size) { } #endif + +/* ======================================================================= */ + +#ifndef __IGNORE_pkey_mprotect +# ifndef __NR_pkey_mprotect +# if defined __i386__ +# define __NR_pkey_mprotect 380 +# elif defined __x86_64__ +# define __NR_pkey_mprotect 329 +# elif defined __arm__ +# define __NR_pkey_mprotect 394 +# elif defined __aarch64__ +# define __NR_pkey_mprotect 394 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_pkey_mprotect 4363 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_pkey_mprotect 6327 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_pkey_mprotect 5323 +# endif +# else +# warning "__NR_pkey_mprotect not defined for your architecture" +# endif +# endif +#endif diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c index aa6878cdf0..16eb7ce265 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); } int mkdir_parents_label(const char *path, mode_t mode) { diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 7db09fc6a1..4386b38c4a 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 <string.h> #include <sys/stat.h> +#include "alloc-util.h" #include "fs-util.h" #include "macro.h" #include "mkdir.h" @@ -29,7 +31,7 @@ #include "stat-util.h" #include "user-util.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; @@ -42,6 +44,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) || @@ -53,8 +68,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 d564a3547f..04a537f8a8 100644 --- a/src/basic/mkdir.h +++ b/src/basic/mkdir.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -22,17 +23,17 @@ #include <sys/types.h> -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); int mkdir_parents_label(const char *path, mode_t mode); 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/module-util.h b/src/basic/module-util.h new file mode 100644 index 0000000000..07956dbffd --- /dev/null +++ b/src/basic/module-util.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2017 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <libkmod.h> + +#include "macro.h" + +DEFINE_TRIVIAL_CLEANUP_FUNC(struct kmod_ctx*, kmod_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct kmod_module*, kmod_module_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct kmod_list*, kmod_module_unref_list); diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index c4d451db73..a8947cefc2 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 <errno.h> +#include <stdio_ext.h> #include <stdlib.h> #include <string.h> #include <sys/mount.h> @@ -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; @@ -60,7 +136,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ return -EOPNOTSUPP; if (r < 0) - return -errno; + return r; p = startswith(fdinfo, "mnt_id:"); if (!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; } int umount_recursive(const char *prefix, int flags) { @@ -258,6 +338,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; @@ -504,6 +586,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); } @@ -589,6 +673,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 1e066d8886..a81d019277 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); @@ -47,16 +52,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 } - int mount_verbose( int error_log_level, const char *what, diff --git a/src/basic/nss-util.h b/src/basic/nss-util.h index 9d927a8227..4fc676395f 100644 --- a/src/basic/nss-util.h +++ b/src/basic/nss-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/ordered-set.c b/src/basic/ordered-set.c index 2e0bdf6488..afcf2dbd1d 100644 --- a/src/basic/ordered-set.c +++ b/src/basic/ordered-set.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h index e1dfc86380..c4dbd79249 100644 --- a/src/basic/ordered-set.h +++ b/src/basic/ordered-set.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 4ae07b0a8e..d03f60e01a 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 <string.h> #include "alloc-util.h" +#include "errno-list.h" #include "extract-word.h" #include "macro.h" #include "parse-util.h" @@ -268,6 +270,64 @@ int parse_range(const char *t, unsigned *lower, unsigned *upper) { return 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 dc09782ca8..1eda1d7f9f 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 /*** @@ -37,6 +38,8 @@ int parse_ifindex(const char *s, int *ret); int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_range(const char *t, unsigned *lower, unsigned *upper); +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 6c06bd2acb..ab4778d4ed 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. @@ -222,8 +223,8 @@ int path_strv_make_absolute_cwd(char **l) { if (r < 0) return r; - free(*s); - *s = t; + path_kill_slashes(t); + free_and_replace(*s, t); } return 0; @@ -537,7 +538,7 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd assert(timestamp); - if (paths == NULL) + if (!paths) return false; STRV_FOREACH(i, paths) { @@ -702,6 +703,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; @@ -721,7 +753,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; @@ -735,7 +767,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; @@ -851,7 +882,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/systemd/libsystemd-shared-*.so\0" + "usr/lib/systemd/libsystemd-shared-*.so\0" + "usr/lib64/systemd/libsystemd-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 546246595c..f79cdf928e 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 /*** @@ -129,9 +130,10 @@ char *prefix_root(const char *root, const char *path); int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg); 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 4570b8e4ba..407b17e9bf 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 113c73d040..a222955dfe 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 8592a428d5..c5d1fb1d41 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. @@ -270,17 +271,21 @@ static const char * const rlmap_initrd[] = { }; const char* runlevel_to_target(const char *word) { + const char * const *rlmap_ptr; size_t i; - const char * const *rlmap_ptr = in_initrd() ? rlmap_initrd - : rlmap; if (!word) return NULL; - if (in_initrd() && (word = startswith(word, "rd.")) == NULL) - return NULL; + if (in_initrd()) { + word = startswith(word, "rd."); + if (!word) + return NULL; + } + + rlmap_ptr = in_initrd() ? rlmap_initrd : rlmap; - for (i = 0; rlmap_ptr[i] != NULL; i += 2) + for (i = 0; rlmap_ptr[i]; i += 2) if (streq(word, rlmap_ptr[i])) return rlmap_ptr[i+1]; diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h index ebfed355e9..16ccfbc2cb 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/process-util.c b/src/basic/process-util.c index 99b0946a03..17c94f44a0 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. @@ -25,6 +26,7 @@ #include <signal.h> #include <stdbool.h> #include <stdio.h> +#include <stdio_ext.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> @@ -129,6 +131,8 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return -errno; } + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + if (max_length == 1) { /* If there's only room for one byte, return the empty string */ @@ -405,6 +409,8 @@ int is_kernel_thread(pid_t pid) { return -errno; } + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + count = fread(&c, 1, 1, f); eof = feof(f); fclose(f); @@ -486,6 +492,8 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) { return -errno; } + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + FOREACH_LINE(line, f, return -errno) { char *l; @@ -564,6 +572,8 @@ int get_process_environ(pid_t pid, char **env) { return -errno; } + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + while ((c = fgetc(f)) != EOF) { if (!GREEDY_REALLOC(outcome, allocated, sz + 5)) return -ENOMEM; @@ -698,6 +708,67 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod return -EPROTO; } +/* + * Return values: + * < 0 : wait_for_terminate_with_timeout() failed to get the state of the + * process, the process timed out, the process was terminated by a + * signal, or failed for an unknown reason. + * >=0 : The process terminated normally with no failures. + * + * Success is indicated by a return value of zero, a timeout is indicated + * by ETIMEDOUT, and all other child failure states are indicated by error + * is indicated by a non-zero value. + */ +int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) { + sigset_t mask; + int r; + usec_t until; + + assert_se(sigemptyset(&mask) == 0); + assert_se(sigaddset(&mask, SIGCHLD) == 0); + + /* Drop into a sigtimewait-based timeout. Waiting for the + * pid to exit. */ + until = now(CLOCK_MONOTONIC) + timeout; + for (;;) { + usec_t n; + siginfo_t status = {}; + struct timespec ts; + + n = now(CLOCK_MONOTONIC); + if (n >= until) + break; + + r = sigtimedwait(&mask, NULL, timespec_store(&ts, until - n)) < 0 ? -errno : 0; + /* Assuming we woke due to the child exiting. */ + if (waitid(P_PID, pid, &status, WEXITED|WNOHANG) == 0) { + if (status.si_pid == pid) { + /* This is the correct child.*/ + if (status.si_code == CLD_EXITED) + return (status.si_status == 0) ? 0 : -EPROTO; + else + return -EPROTO; + } + } + /* Not the child, check for errors and proceed appropriately */ + if (r < 0) { + switch (r) { + case -EAGAIN: + /* Timed out, child is likely hung. */ + return -ETIMEDOUT; + case -EINTR: + /* Received a different signal and should retry */ + continue; + default: + /* Return any unexpected errors */ + return r; + } + } + } + + return -EPROTO; +} + void sigkill_wait(pid_t pid) { assert(pid > 1); @@ -748,6 +819,8 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { return -errno; } + (void) __fsetlocking(f, FSETLOCKING_BYCALLER); + l = strlen(field); r = 0; @@ -1052,6 +1125,15 @@ pid_t getpid_cached(void) { } } +int must_be_root(void) { + + if (geteuid() == 0) + return 0; + + log_error("Need to be root."); + return -EPERM; +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 82af2f9181..1b7e692060 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -32,6 +33,7 @@ #include "format-util.h" #include "ioprio.h" #include "macro.h" +#include "time-util.h" #define procfs_file_alloca(pid, field) \ ({ \ @@ -40,7 +42,7 @@ if (_pid_ == 0) { \ _r_ = ("/proc/self/" field); \ } else { \ - _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ + _r_ = alloca(STRLEN("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \ } \ _r_; \ @@ -60,6 +62,7 @@ int get_process_ppid(pid_t pid, pid_t *ppid); int wait_for_terminate(pid_t pid, siginfo_t *status); int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code); +int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout); void sigkill_wait(pid_t pid); void sigkill_waitp(pid_t *pid); @@ -137,3 +140,5 @@ static inline bool pid_is_valid(pid_t p) { int ioprio_parse_priority(const char *s, int *ret); pid_t getpid_cached(void); + +int must_be_root(void); diff --git a/src/basic/random-util.c b/src/basic/random-util.c index 146c8f55ed..1bc8000896 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 804e225fc1..dd8701515e 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/ratelimit.c b/src/basic/ratelimit.c index 3ca5625e4d..5b684e261a 100644 --- a/src/basic/ratelimit.c +++ b/src/basic/ratelimit.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/ratelimit.h b/src/basic/ratelimit.h index 9c8dddf5ad..19acf9c854 100644 --- a/src/basic/ratelimit.h +++ b/src/basic/ratelimit.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/raw-clone.h b/src/basic/raw-clone.h index c6e531ada4..f01b73a8fe 100644 --- a/src/basic/raw-clone.h +++ b/src/basic/raw-clone.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 1d77a6445a..ae2e446d6c 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/replace-var.c b/src/basic/replace-var.c index d2642812e7..c73ed9777e 100644 --- a/src/basic/replace-var.c +++ b/src/basic/replace-var.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/replace-var.h b/src/basic/replace-var.h index 31eb057803..3d5906198e 100644 --- a/src/basic/replace-var.h +++ b/src/basic/replace-var.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c index 5c41429f01..00648211d3 100644 --- a/src/basic/rlimit-util.c +++ b/src/basic/rlimit-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/rlimit-util.h b/src/basic/rlimit-util.h index d4594eccd6..4494b89c76 100644 --- a/src/basic/rlimit-util.h +++ b/src/basic/rlimit-util.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 0bbafb4cd7..2839f37cd9 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 e13f7003e3..1127e326b2 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/securebits-util.c b/src/basic/securebits-util.c index 011ec36af4..b5f6418a6c 100644 --- a/src/basic/securebits-util.c +++ b/src/basic/securebits-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/securebits-util.h b/src/basic/securebits-util.h index b4d970c366..aaa192f0a5 100644 --- a/src/basic/securebits-util.h +++ b/src/basic/securebits-util.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 93bcdb2160..0c6e99b1d7 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 5bf72364b4..9780dca81e 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 fd398b8212..e554e825eb 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. @@ -38,7 +39,7 @@ int set_make(Set **ret, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS, vo va_start(ap, add); - for(;;) { + for (;;) { void *arg = va_arg(ap, void*); if (!arg) diff --git a/src/basic/set.h b/src/basic/set.h index 12d0fda1ca..156ab4b081 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -107,6 +108,18 @@ static inline void *set_steal_first(Set *s) { return internal_hashmap_steal_first(HASHMAP_BASE(s)); } +#define set_clear_with_destructor(_s, _f) \ + ({ \ + void *_item; \ + while ((_item = set_steal_first(_s))) \ + _f(_item); \ + }) +#define set_free_with_destructor(_s, _f) \ + ({ \ + set_clear_with_destructor(_s, _f); \ + set_free(_s); \ + }) + /* no set_steal_first_key */ /* no set_first_key */ diff --git a/src/basic/sigbus.c b/src/basic/sigbus.c index 0ce4f75684..2416929e36 100644 --- a/src/basic/sigbus.c +++ b/src/basic/sigbus.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/sigbus.h b/src/basic/sigbus.h index 980243d9ce..90b0c9632e 100644 --- a/src/basic/sigbus.h +++ b/src/basic/sigbus.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index df6b742fde..27caabe471 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. @@ -225,7 +226,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 dfd6eb564d..76b239b1fc 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 /*** @@ -44,11 +45,11 @@ static inline void block_signals_reset(sigset_t *ss) { assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0); } -#define BLOCK_SIGNALS(...) \ - _cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \ - sigset_t t; \ - assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \ - t; \ +#define BLOCK_SIGNALS(...) \ + _cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \ + sigset_t _t; \ + assert_se(sigprocmask_many(SIG_BLOCK, &_t, __VA_ARGS__, -1) >= 0); \ + _t; \ }) static inline bool SIGNAL_VALID(int signo) { diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c index 4bb41786c8..d3a81b7cc1 100644 --- a/src/basic/siphash24.c +++ b/src/basic/siphash24.c @@ -127,25 +127,25 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { switch (left) { case 7: state->padding |= ((uint64_t) in[6]) << 48; - /* fall through */ + _fallthrough_; case 6: state->padding |= ((uint64_t) in[5]) << 40; - /* fall through */ + _fallthrough_; case 5: state->padding |= ((uint64_t) in[4]) << 32; - /* fall through */ + _fallthrough_; case 4: state->padding |= ((uint64_t) in[3]) << 24; - /* fall through */ + _fallthrough_; case 3: state->padding |= ((uint64_t) in[2]) << 16; - /* fall through */ + _fallthrough_; case 2: state->padding |= ((uint64_t) in[1]) << 8; - /* fall through */ + _fallthrough_; case 1: state->padding |= ((uint64_t) in[0]); - /* fall through */ + _fallthrough_; case 0: break; } diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index 3dcf150c59..e0f1c9f1c7 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 f90ba0a027..e4d46d7736 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-label.c b/src/basic/socket-label.c index 6e7cdaac63..20be406371 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 29c779552d..a458fc2902 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. @@ -121,7 +122,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 43edc05c63..272e74b0cc 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 a3573b84a9..5e59de5437 100644 --- a/src/basic/sparse-endian.h +++ b/src/basic/sparse-endian.h @@ -1,4 +1,6 @@ -/* Copyright (c) 2012 Josh Triplett <josh@joshtriplett.org> +/* SPDX-License-Identifier: MIT + * + * Copyright (c) 2012 Josh Triplett <josh@joshtriplett.org> * * 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/special.h b/src/basic/special.h index ddd4e84019..c058b1d852 100644 --- a/src/basic/special.h +++ b/src/basic/special.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index d87370e672..96fc8b3787 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. @@ -192,7 +193,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) @@ -201,14 +202,14 @@ int fd_check_fstype(int fd, statfs_f_type_t magic_value) { return is_fs_type(&s, magic_value); } -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); } bool is_temporary_fs(const struct statfs *s) { @@ -225,6 +226,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 cd204ac6cb..d8d3c20496 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 /*** @@ -56,11 +57,12 @@ 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); -int path_check_fstype(const char *path, statfs_f_type_t magic_value); +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_; int fd_is_temporary_fs(int fd); +int fd_is_network_ns(int fd); int path_is_temporary_fs(const char *path); /* Because statfs.t_type can be int on some architectures, we have to cast diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h index bd1144b4c9..dbfafba269 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/strbuf.c b/src/basic/strbuf.c index 00aaf9e621..8befffa66f 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/strbuf.h b/src/basic/strbuf.h index a1632da0e8..d5888a06dc 100644 --- a/src/basic/strbuf.h +++ b/src/basic/strbuf.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 a1499ab126..d4b7c69bdc 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 369610efc8..4306b90f46 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 3179fba3ba..7e2f596edc 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 <stdarg.h> #include <stdint.h> #include <stdio.h> +#include <stdio_ext.h> #include <stdlib.h> #include <string.h> @@ -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 */ @@ -295,7 +300,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)) @@ -309,6 +320,26 @@ char *delete_chars(char *s, const char *bad) { return s; } +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); @@ -472,6 +503,10 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne assert(s); assert(percent <= 100); + + if (new_length == (size_t) -1) + return strndup(s, old_length); + assert(new_length >= 3); /* if no multibyte characters use ascii_ellipsize_mem for speed */ @@ -539,6 +574,10 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne } char *ellipsize(const char *s, size_t length, unsigned percent) { + + if (length == (size_t) -1) + return strdup(s); + return ellipsize_mem(s, strlen(s), length, percent); } @@ -565,26 +604,26 @@ char* strshorten(char *s, size_t l) { } char *strreplace(const char *text, const char *old_string, const char *new_string) { + size_t l, old_len, new_len, allocated = 0; + char *t, *ret = NULL; const char *f; - char *t, *r; - size_t l, old_len, new_len; - assert(text); assert(old_string); assert(new_string); + if (!text) + return NULL; + old_len = strlen(old_string); new_len = strlen(new_string); l = strlen(text); - r = new(char, l+1); - if (!r) + if (!GREEDY_REALLOC(ret, allocated, l+1)) return NULL; f = text; - t = r; + t = ret; while (*f) { - char *a; size_t d, nl; if (!startswith(f, old_string)) { @@ -592,25 +631,21 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin continue; } - d = t - r; + d = t - ret; nl = l - old_len + new_len; - a = realloc(r, nl + 1); - if (!a) - goto oom; + + if (!GREEDY_REALLOC(ret, allocated, nl + 1)) + return mfree(ret); l = nl; - r = a; - t = r + d; + t = ret + d; t = stpcpy(t, new_string); f += old_len; } *t = 0; - return r; - -oom: - return mfree(r); + return ret; } char *strip_tab_ansi(char **ibuf, size_t *_isz) { @@ -635,10 +670,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++) { @@ -650,21 +685,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; } @@ -674,8 +709,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') @@ -700,16 +735,20 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) { return obuf; } -char *strextend(char **x, ...) { - va_list ap; - size_t f, l; +char *strextend_with_separator(char **x, const char *separator, ...) { + bool need_separator; + size_t f, l, l_separator; char *r, *p; + va_list ap; assert(x); l = f = strlen_ptr(*x); - va_start(ap, x); + need_separator = !isempty(*x); + l_separator = strlen_ptr(separator); + + va_start(ap, separator); for (;;) { const char *t; size_t n; @@ -719,22 +758,29 @@ char *strextend(char **x, ...) { break; n = strlen(t); + + if (need_separator) + n += l_separator; + if (n > ((size_t) -1) - l) { va_end(ap); return NULL; } l += n; + need_separator = true; } va_end(ap); + need_separator = !isempty(*x); + r = realloc(*x, l+1); if (!r) return NULL; p = r + f; - va_start(ap, x); + va_start(ap, separator); for (;;) { const char *t; @@ -742,10 +788,17 @@ char *strextend(char **x, ...) { if (!t) break; + if (need_separator && separator) + p = stpcpy(p, separator); + p = stpcpy(p, t); + + need_separator = true; } va_end(ap); + assert(p == r + l); + *p = 0; *x = r; diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 4c94b182c1..09a737ad37 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 /*** @@ -133,8 +134,20 @@ char *strjoin_real(const char *x, ...) _sentinel_; char *strstrip(char *s); char *delete_chars(char *s, const char *bad); +char *delete_trailing_chars(char *s, const char *bad); char *truncate_nl(char *s); +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); @@ -166,7 +179,9 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin char *strip_tab_ansi(char **p, size_t *l); -char *strextend(char **x, ...) _sentinel_; +char *strextend_with_separator(char **x, const char *separator, ...) _sentinel_; + +#define strextend(x, ...) strextend_with_separator(x, NULL, __VA_ARGS__) char *strrep(const char *s, unsigned n); diff --git a/src/basic/strv.c b/src/basic/strv.c index c63f11c6ad..54c701aee2 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 385ad17779..0ed6b74330 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -180,3 +181,11 @@ char **strv_skip(char **l, size_t n); int strv_extend_n(char ***l, const char *value, size_t n); int fputstrv(FILE *f, char **l, const char *separator, bool *space); + +#define strv_free_and_replace(a, b) \ + ({ \ + strv_free(a); \ + (a) = (b); \ + (b) = NULL; \ + 0; \ + }) diff --git a/src/basic/strxcpyx.c b/src/basic/strxcpyx.c index c6fbe79647..b440a9a725 100644 --- a/src/basic/strxcpyx.c +++ b/src/basic/strxcpyx.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/strxcpyx.h b/src/basic/strxcpyx.h index 80ff58726b..0554454fd2 100644 --- a/src/basic/strxcpyx.h +++ b/src/basic/strxcpyx.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c index db3405154e..4f4e2354b6 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 5cb606a1bf..8f44e3f8ef 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 28c8c35fe0..48ee799ad4 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. @@ -245,7 +246,6 @@ int ask_string(char **ret, const char *text, ...) { int reset_terminal_fd(int fd, bool switch_to_text) { struct termios termios; - _cleanup_free_ char *utf8 = NULL; int r = 0; /* Set terminal to some sane defaults */ @@ -992,7 +992,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 c3045eb09d..e82719b11b 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 f7f5e614f2..d56576ddbe 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. @@ -892,7 +893,7 @@ int parse_timestamp(const char *t, usec_t *usec) { if (last_space != NULL && timezone_is_valid(last_space + 1)) tz = last_space + 1; - if (tz == NULL || endswith_no_case(t, " UTC")) + if (!tz || endswith_no_case(t, " UTC")) return parse_timestamp_impl(t, usec, false); shared = mmap(NULL, sizeof *shared, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); @@ -1381,8 +1382,7 @@ bool clock_supported(clockid_t clock) { if (!clock_boottime_supported()) return false; - /* fall through */ - + _fallthrough_; default: /* For everything else, check properly */ return clock_gettime(clock, &ts) >= 0; @@ -1456,3 +1456,9 @@ usec_t usec_shift_clock(usec_t x, clockid_t from, clockid_t to) { /* x lies in the past */ return usec_sub_unsigned(b, usec_sub_unsigned(a, x)); } + +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 3b7f0e99c0..dc4a159310 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 /*** @@ -148,10 +149,6 @@ clockid_t clock_boottime_or_monotonic(void); usec_t usec_shift_clock(usec_t, clockid_t from, clockid_t to); -#define xstrftime(buf, fmt, tm) \ - assert_message_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0, \ - "xstrftime: " #buf "[] must be big enough") - int get_timezone(char **timezone); time_t mktime_or_timegm(struct tm *tm, bool utc); @@ -159,6 +156,8 @@ struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc); unsigned long usec_to_jiffies(usec_t usec); +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 359d87d27c..638b37d7de 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 7c847a3ccb..201b3d227e 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 0000000000..387533f597 --- /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 <http://www.gnu.org/licenses/>. +***/ + +#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 0000000000..c142e069a6 --- /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 <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> + +#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 f9c034c94b..403f288b57 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 <string.h> #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" @@ -385,19 +383,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); } @@ -440,7 +433,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; } @@ -575,68 +568,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; @@ -834,206 +765,3 @@ 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); - -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-name.h b/src/basic/unit-name.h index 15558b4fbd..b47327dcaf 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,232 +23,10 @@ #include <stdbool.h> #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; - -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; - typedef enum UnitNameFlags { UNIT_NAME_PLAIN = 1, /* Allow foo.service */ UNIT_NAME_INSTANCE = 2, /* Allow foo@bar.service */ @@ -288,12 +67,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, @@ -308,51 +81,3 @@ static inline int unit_name_mangle(const char *name, UnitNameMangle allow_globs, int slice_build_parent_slice(const char *slice, char **ret); 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_; - -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/user-util.c b/src/basic/user-util.c index a691a0d3fc..abb0b76866 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. @@ -116,15 +117,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; @@ -137,6 +137,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); @@ -217,7 +234,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) @@ -226,6 +243,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); @@ -257,6 +283,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; @@ -295,6 +323,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; @@ -386,7 +416,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"); @@ -396,6 +426,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; @@ -433,7 +471,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"); @@ -443,6 +481,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; @@ -605,7 +651,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 dfea561bde..79adf91ee9 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 /*** @@ -59,17 +60,25 @@ int take_etc_passwd_lock(const char *root); #define UID_INVALID ((uid_t) -1) #define GID_INVALID ((gid_t) -1) -/* Let's pick a UIDs within the 16bit range, so that we are compatible with containers using 16bit - * user namespacing. At least on Fedora normal users are allocated until UID 60000, hence do not - * allocate from below this. Also stay away from the upper end of the range as that is often used - * for overflow/nobody users. */ -#define DYNAMIC_UID_MIN ((uid_t) UINT32_C(0x0000EF00)) -#define DYNAMIC_UID_MAX ((uid_t) UINT32_C(0x0000FFEF)) +#define UID_NOBODY ((uid_t) 65534U) +#define GID_NOBODY ((gid_t) 65534U) static inline bool uid_is_dynamic(uid_t uid) { return DYNAMIC_UID_MIN <= uid && uid <= DYNAMIC_UID_MAX; } +static inline bool gid_is_dynamic(gid_t gid) { + return uid_is_dynamic((uid_t) gid); +} + +static inline bool uid_is_system(uid_t uid) { + return uid <= SYSTEM_UID_MAX; +} + +static inline bool gid_is_system(gid_t gid) { + return gid <= SYSTEM_GID_MAX; +} + /* The following macros add 1 when converting things, since UID 0 is a valid UID, while the pointer * NULL is special */ #define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1)) diff --git a/src/basic/utf8.c b/src/basic/utf8.c index 7a52fac621..4da9a405cb 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 f9b9c9468b..b0a7485aed 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 687de40993..8f9f2b902b 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" @@ -103,7 +105,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; @@ -117,75 +119,51 @@ int socket_from_display(const char *display, char **path) { } 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) { - bool loaded = false; - char *s; - - if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) { - if (s[0] == '1') - loaded = true; - free(s); - } - return loaded; + _cleanup_free_ char *s = NULL; + + if (read_one_line_file("/sys/kernel/kexec_loaded", &s) < 0) + return false; + + return s[0] == '1'; } int prot_from_flags(int flags) { @@ -751,7 +729,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; @@ -769,9 +748,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 b31dfd1c92..a79907de3e 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 d9cdb38d65..cb42e6dd08 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. @@ -32,7 +33,7 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) { const Verb *verb; const char *name; unsigned i; - int left; + int left, r; assert(verbs); assert(verbs[0].dispatch); @@ -88,6 +89,12 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) { return 0; } + if (verb->flags & VERB_MUSTBEROOT) { + r = must_be_root(); + if (r < 0) + return r; + } + if (name) return verb->dispatch(left, argv + optind, userdata); else { diff --git a/src/basic/verbs.h b/src/basic/verbs.h index 7b5e18510f..5f44a18f8e 100644 --- a/src/basic/verbs.h +++ b/src/basic/verbs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** @@ -20,13 +21,17 @@ ***/ #define VERB_ANY ((unsigned) -1) -#define VERB_DEFAULT 1U -#define VERB_NOCHROOT 2U + +typedef enum VerbFlags { + VERB_DEFAULT = 1 << 0, + VERB_NOCHROOT = 1 << 1, + VERB_MUSTBEROOT = 1 << 2, +} VerbFlags; typedef struct { const char *verb; unsigned min_args, max_args; - unsigned flags; + VerbFlags flags; int (* const dispatch)(int argc, char *argv[], void *userdata); } Verb; diff --git a/src/basic/virt.c b/src/basic/virt.c index d8eeb54dbf..b0db28add6 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. @@ -200,8 +201,6 @@ static int detect_vm_dmi(void) { return r; } - - for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++) if (startswith(s, dmi_vendor_table[j].vendor)) { log_debug("Virtualization %s found in DMI (%s)", s, dmi_vendors[i]); @@ -216,27 +215,48 @@ static int detect_vm_dmi(void) { } static int detect_vm_xen(void) { + /* Check for Dom0 will be executed later in detect_vm_xen_dom0 - Thats why we dont check the content of /proc/xen/capabilities here. */ - if (access("/proc/xen/capabilities", F_OK) < 0) { - log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist"); + The presence of /proc/xen indicates some form of a Xen domain */ + if (access("/proc/xen", F_OK) < 0) { + log_debug("Virtualization XEN not found, /proc/xen does not exist"); return VIRTUALIZATION_NONE; } - log_debug("Virtualization XEN found (/proc/xen/capabilities exists)"); - return VIRTUALIZATION_XEN; - + log_debug("Virtualization XEN found (/proc/xen exists)"); + return VIRTUALIZATION_XEN; } -static bool detect_vm_xen_dom0(void) { +#define XENFEAT_dom0 11 /* xen/include/public/features.h */ +#define PATH_FEATURES "/sys/hypervisor/properties/features" +/* Returns -errno, or 0 for domU, or 1 for dom0 */ +static int detect_vm_xen_dom0(void) { _cleanup_free_ char *domcap = NULL; char *cap, *i; int r; + r = read_one_line_file(PATH_FEATURES, &domcap); + if (r < 0 && r != -ENOENT) + return r; + if (r == 0) { + unsigned long features; + + r = safe_atolu(domcap, &features); + if (r == 0) { + r = !!(features & (1U << XENFEAT_dom0)); + log_debug("Virtualization XEN, found %s with value %08lx, " + "XENFEAT_dom0 (indicating the 'hardware domain') is%s set.", + PATH_FEATURES, features, r ? "" : " not"); + return r; + } + log_debug("Virtualization XEN, found %s, unhandled content '%s'", + PATH_FEATURES, domcap); + } + r = read_one_line_file("/proc/xen/capabilities", &domcap); if (r == -ENOENT) { - log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist"); - return false; + log_debug("Virtualization XEN because /proc/xen/capabilities does not exist"); + return 0; } if (r < 0) return r; @@ -247,11 +267,11 @@ static bool detect_vm_xen_dom0(void) { break; if (!cap) { log_debug("Virtualization XEN DomU found (/proc/xen/capabilites)"); - return false; + return 0; } log_debug("Virtualization XEN Dom0 ignored (/proc/xen/capabilities)"); - return true; + return 1; } static int detect_vm_hypervisor(void) { @@ -317,6 +337,7 @@ static int detect_vm_zvm(void) { int detect_vm(void) { static thread_local int cached_found = _VIRTUALIZATION_INVALID; int r, dmi; + bool other = false; if (cached_found >= 0) return cached_found; @@ -337,45 +358,68 @@ int detect_vm(void) { r = detect_vm_cpuid(); if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) - goto finish; + if (r != VIRTUALIZATION_NONE) { + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else + goto finish; + } r = dmi; if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) - goto finish; + if (r != VIRTUALIZATION_NONE) { + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else + goto finish; + } /* x86 xen will most likely be detected by cpuid. If not (most likely - * because we're not an x86 guest), then we should try the xen capabilities - * file next. If that's not found, then we check for the high-level - * hypervisor sysfs file: - * - * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */ + * because we're not an x86 guest), then we should try the /proc/xen + * directory next. If that's not found, then we check for the high-level + * hypervisor sysfs file. + */ r = detect_vm_xen(); if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) - goto finish; + if (r != VIRTUALIZATION_NONE) { + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else + goto finish; + } r = detect_vm_hypervisor(); if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) - goto finish; + if (r != VIRTUALIZATION_NONE) { + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else + goto finish; + } r = detect_vm_device_tree(); if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) - goto finish; + if (r != VIRTUALIZATION_NONE) { + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else + goto finish; + } r = detect_vm_uml(); if (r < 0) return r; - if (r != VIRTUALIZATION_NONE) - goto finish; + if (r != VIRTUALIZATION_NONE) { + if (r == VIRTUALIZATION_VM_OTHER) + other = true; + else + goto finish; + } r = detect_vm_zvm(); if (r < 0) @@ -385,8 +429,14 @@ finish: /* x86 xen Dom0 is detected as XEN in hypervisor and maybe others. * In order to detect the Dom0 as not virtualization we need to * double-check it */ - if (r == VIRTUALIZATION_XEN && detect_vm_xen_dom0()) - r = VIRTUALIZATION_NONE; + if (r == VIRTUALIZATION_XEN) { + int ret = detect_vm_xen_dom0(); + if (ret < 0) + return ret; + if (ret > 0) + r = VIRTUALIZATION_NONE; + } else if (r == VIRTUALIZATION_NONE && other) + r = VIRTUALIZATION_VM_OTHER; cached_found = r; log_debug("Found VM virtualization %s", virtualization_to_string(r)); diff --git a/src/basic/virt.h b/src/basic/virt.h index 7d15169112..d9badd8efe 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/web-util.c b/src/basic/web-util.c index 595688ed93..d721b02653 100644 --- a/src/basic/web-util.c +++ b/src/basic/web-util.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/web-util.h b/src/basic/web-util.h index e6bb6b53f5..ad8c850d1d 100644 --- a/src/basic/web-util.h +++ b/src/basic/web-util.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 e086376d7c..12d04eeffb 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. @@ -104,7 +105,7 @@ int fgetxattr_malloc(int fd, const char *name, char **value) { } 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 6fa097bf7e..1a78027aaa 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 /*** diff --git a/src/basic/xml.c b/src/basic/xml.c index a4337f4865..639c3438a0 100644 --- a/src/basic/xml.c +++ b/src/basic/xml.c @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ /*** This file is part of systemd. diff --git a/src/basic/xml.h b/src/basic/xml.h index 41cb69f0dc..d00b527232 100644 --- a/src/basic/xml.h +++ b/src/basic/xml.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ #pragma once /*** |