diff options
Diffstat (limited to 'src/basic')
36 files changed, 1686 insertions, 700 deletions
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 5cbe45a7e..502fe4609 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -2073,9 +2073,10 @@ int cg_mask_supported(CGroupMask *ret) { mask |= CGROUP_CONTROLLER_TO_MASK(v); } - /* Currently, we only support the memory controller in - * the unified hierarchy, mask everything else off. */ - mask &= CGROUP_MASK_MEMORY; + /* Currently, we only support the memory and pids + * controller in the unified hierarchy, mask + * everything else off. */ + mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_PIDS; } else { CGroupController c; @@ -2280,12 +2281,57 @@ bool cg_is_legacy_wanted(void) { } #endif // 0 +/// UNNEEDED by elogind +#if 0 +int cg_cpu_shares_parse(const char *s, uint64_t *ret) { + uint64_t u; + int r; + + if (isempty(s)) { + *ret = CGROUP_CPU_SHARES_INVALID; + return 0; + } + + r = safe_atou64(s, &u); + if (r < 0) + return r; + + if (u < CGROUP_CPU_SHARES_MIN || u > CGROUP_CPU_SHARES_MAX) + return -ERANGE; + + *ret = u; + return 0; +} + +int cg_blkio_weight_parse(const char *s, uint64_t *ret) { + uint64_t u; + int r; + + if (isempty(s)) { + *ret = CGROUP_BLKIO_WEIGHT_INVALID; + return 0; + } + + r = safe_atou64(s, &u); + if (r < 0) + return r; + + if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX) + return -ERANGE; + + *ret = u; + return 0; +} +#endif // 0 + static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = { [CGROUP_CONTROLLER_CPU] = "cpu", [CGROUP_CONTROLLER_CPUACCT] = "cpuacct", [CGROUP_CONTROLLER_BLKIO] = "blkio", [CGROUP_CONTROLLER_MEMORY] = "memory", - [CGROUP_CONTROLLER_DEVICE] = "devices", + [CGROUP_CONTROLLER_DEVICES] = "devices", + [CGROUP_CONTROLLER_PIDS] = "pids", + [CGROUP_CONTROLLER_NET_CLS] = "net_cls", }; DEFINE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController); diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 974355957..e3f3bf080 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -34,7 +34,9 @@ typedef enum CGroupController { CGROUP_CONTROLLER_CPUACCT, CGROUP_CONTROLLER_BLKIO, CGROUP_CONTROLLER_MEMORY, - CGROUP_CONTROLLER_DEVICE, + CGROUP_CONTROLLER_DEVICES, + CGROUP_CONTROLLER_PIDS, + CGROUP_CONTROLLER_NET_CLS, _CGROUP_CONTROLLER_MAX, _CGROUP_CONTROLLER_INVALID = -1, } CGroupController; @@ -47,10 +49,36 @@ typedef enum CGroupMask { CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT), CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO), CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY), - CGROUP_MASK_DEVICE = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICE), + CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES), + CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS), + CGROUP_MASK_NET_CLS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_NET_CLS), _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1 } CGroupMask; +/* Special values for the cpu.shares attribute */ +#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1) +#define CGROUP_CPU_SHARES_MIN UINT64_C(2) +#define CGROUP_CPU_SHARES_MAX UINT64_C(262144) +#define CGROUP_CPU_SHARES_DEFAULT UINT64_C(1024) + +static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) { + return + x == CGROUP_CPU_SHARES_INVALID || + (x >= CGROUP_CPU_SHARES_MIN && x <= CGROUP_CPU_SHARES_MAX); +} + +/* Special values for the blkio.weight attribute */ +#define CGROUP_BLKIO_WEIGHT_INVALID ((uint64_t) -1) +#define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10) +#define CGROUP_BLKIO_WEIGHT_MAX UINT64_C(1000) +#define CGROUP_BLKIO_WEIGHT_DEFAULT UINT64_C(500) + +static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) { + return + x == CGROUP_BLKIO_WEIGHT_INVALID || + (x >= CGROUP_BLKIO_WEIGHT_MIN && x <= CGROUP_BLKIO_WEIGHT_MAX); +} + /* * General rules: * @@ -159,3 +187,6 @@ bool cg_is_legacy_wanted(void); const char* cgroup_controller_to_string(CGroupController c) _const_; CGroupController cgroup_controller_from_string(const char *s) _pure_; + +// UNNEEDED int cg_cpu_shares_parse(const char *s, uint64_t *ret); +// UNNEEDED int cg_blkio_weight_parse(const char *s, uint64_t *ret); diff --git a/src/basic/copy.c b/src/basic/copy.c index 163bbf7c7..3c02fd41e 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -29,7 +29,7 @@ #define COPY_BUFFER_SIZE (16*1024) -int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { +int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { bool try_sendfile = true, try_splice = true; int r; @@ -37,22 +37,26 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { assert(fdt >= 0); #if 0 /* Try btrfs reflinks first. */ - if (try_reflink && max_bytes == (off_t) -1) { + if (try_reflink && + max_bytes == (uint64_t) -1 && + lseek(fdf, 0, SEEK_CUR) == 0 && + lseek(fdt, 0, SEEK_CUR) == 0) { + r = btrfs_reflink(fdf, fdt); if (r >= 0) - return r; + return 0; /* we copied the whole thing, hence hit EOF, return 0 */ } #endif // 0 for (;;) { size_t m = COPY_BUFFER_SIZE; ssize_t n; - if (max_bytes != (off_t) -1) { + if (max_bytes != (uint64_t) -1) { if (max_bytes <= 0) return -EFBIG; - if ((off_t) m > max_bytes) + if ((uint64_t) m > max_bytes) m = (size_t) max_bytes; } @@ -91,7 +95,7 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { /* As a fallback just copy bits by hand */ { - char buf[m]; + uint8_t buf[m]; n = read(fdf, buf, m); if (n < 0) @@ -105,13 +109,13 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { } next: - if (max_bytes != (off_t) -1) { - assert(max_bytes >= n); + if (max_bytes != (uint64_t) -1) { + assert(max_bytes >= (uint64_t) n); max_bytes -= n; } } - return 0; + return 0; /* return 0 if we hit EOF earlier than the size limit */ } // UNNEEDED by elogind @@ -154,7 +158,7 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int if (fdt < 0) return -errno; - r = copy_bytes(fdf, fdt, (off_t) -1, true); + r = copy_bytes(fdf, fdt, (uint64_t) -1, true); if (r < 0) { unlinkat(dt, to, 0); return r; @@ -373,7 +377,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) { if (fdf < 0) return -errno; - r = copy_bytes(fdf, fdt, (off_t) -1, try_reflink); + r = copy_bytes(fdf, fdt, (uint64_t) -1, try_reflink); (void) copy_times(fdf, fdt); (void) copy_xattr(fdf, fdt); diff --git a/src/basic/copy.h b/src/basic/copy.h index 1909de4b8..0cb8cf766 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -30,6 +30,6 @@ // UNNEEDED int copy_tree(const char *from, const char *to, bool merge); // UNNEEDED int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge); // UNNEEDED int copy_directory_fd(int dirfd, const char *to, bool merge); -int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink); +int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink); // UNNEEDED int copy_times(int fdf, int fdt); // UNNEEDED int copy_xattr(int fdf, int fdt); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index f666380a4..a3f8d42f5 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -784,15 +784,19 @@ int executable_is_script(const char *path, char **interpreter) { /** * Retrieve one field from a file like /proc/self/status. pattern - * should start with '\n' and end with a ':'. Whitespace and zeros - * after the ':' will be skipped. field must be freed afterwards. + * should not include whitespace or the delimiter (':'). pattern matches only + * the beginning of a line. Whitespace before ':' is skipped. Whitespace and + * zeros after the ':' will be skipped. field must be freed afterwards. + * terminator specifies the terminating characters of the field value (not + * included in the value). */ -int get_status_field(const char *filename, const char *pattern, char **field) { +int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) { _cleanup_free_ char *status = NULL; char *t, *f; size_t len; int r; + assert(terminator); assert(filename); assert(pattern); assert(field); @@ -801,11 +805,31 @@ int get_status_field(const char *filename, const char *pattern, char **field) { if (r < 0) return r; - t = strstr(status, pattern); + t = status; + + do { + bool pattern_ok; + + do { + t = strstr(t, pattern); if (!t) return -ENOENT; + /* Check that pattern occurs in beginning of line. */ + pattern_ok = (t == status || t[-1] == '\n'); + t += strlen(pattern); + + } while (!pattern_ok); + + t += strspn(t, " \t"); + if (!*t) + return -ENOENT; + + } while (*t != ':'); + + t++; + if (*t) { t += strspn(t, " \t"); @@ -821,7 +845,7 @@ int get_status_field(const char *filename, const char *pattern, char **field) { t --; } - len = strcspn(t, WHITESPACE); + len = strcspn(t, terminator); f = strndup(t, len); if (!f) diff --git a/src/basic/fileio.h b/src/basic/fileio.h index edae438e4..e071bea3a 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -48,4 +48,4 @@ int write_env_file(const char *fname, char **l); // UNNEEDED int executable_is_script(const char *path, char **interpreter); -int get_status_field(const char *filename, const char *pattern, char **field); +int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field); diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 83c76ae0d..3c0e70b9c 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -276,10 +276,8 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { }, }; -unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, p, strlen(p), hash_key); - return (unsigned long) u; +void string_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, strlen(p) + 1, state); } int string_compare_func(const void *a, const void *b) { @@ -291,10 +289,8 @@ const struct hash_ops string_hash_ops = { .compare = string_compare_func }; -unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, &p, sizeof(p), hash_key); - return (unsigned long) u; +void trivial_hash_func(const void *p, struct siphash *state) { + siphash24_compress(&p, sizeof(p), state); } int trivial_compare_func(const void *a, const void *b) { @@ -306,10 +302,8 @@ const struct hash_ops trivial_hash_ops = { .compare = trivial_compare_func }; -unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, p, sizeof(uint64_t), hash_key); - return (unsigned long) u; +void uint64_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(uint64_t), state); } int uint64_compare_func(const void *_a, const void *_b) { @@ -325,10 +319,8 @@ const struct hash_ops uint64_hash_ops = { }; #if SIZEOF_DEV_T != 8 -unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, p, sizeof(dev_t), hash_key); - return (unsigned long) u; +void devt_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(dev_t), state); } int devt_compare_func(const void *_a, const void *_b) { @@ -379,7 +371,16 @@ static uint8_t *hash_key(HashmapBase *h) { } static unsigned base_bucket_hash(HashmapBase *h, const void *p) { - return (unsigned) (h->hash_ops->hash(p, hash_key(h)) % n_buckets(h)); + struct siphash state; + uint64_t hash; + + siphash24_init(&state, hash_key(h)); + + h->hash_ops->hash(p, &state); + + siphash24_finalize((uint8_t*)&hash, &state); + + return (unsigned) (hash % n_buckets(h)); } #define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p) @@ -1823,6 +1824,7 @@ void *ordered_hashmap_next(OrderedHashmap *h, const void *key) { return ordered_bucket_at(h, e->iterate_next)->p.value; } #endif // 0 + int set_consume(Set *s, void *value) { int r; diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index 03c8ae1c5..54f60258d 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -25,6 +25,7 @@ #include <stdbool.h> #include "macro.h" +#include "siphash24.h" #include "util.h" /* @@ -67,7 +68,7 @@ typedef struct { #define _IDX_ITERATOR_FIRST (UINT_MAX - 1) #define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL }) -typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); +typedef void (*hash_func_t)(const void *p, struct siphash *state); typedef int (*compare_func_t)(const void *a, const void *b); struct hash_ops { @@ -75,28 +76,28 @@ struct hash_ops { compare_func_t compare; }; -unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +void string_hash_func(const void *p, struct siphash *state); int string_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops string_hash_ops; /* This will compare the passed pointers directly, and will not * dereference them. This is hence not useful for strings or * suchlike. */ -unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +void trivial_hash_func(const void *p, struct siphash *state); int trivial_compare_func(const void *a, const void *b) _const_; extern const struct hash_ops trivial_hash_ops; /* 32bit values we can always just embedd in the pointer itself, but * in order to support 32bit archs we need store 64bit values * indirectly, since they don't fit in a pointer. */ -unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +void uint64_hash_func(const void *p, struct siphash *state); int uint64_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops uint64_hash_ops; /* On some archs dev_t is 32bit, and on others 64bit. And sometimes * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ #if SIZEOF_DEV_T != 8 -unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +void devt_hash_func(const void *p, struct siphash *state) _pure_; int devt_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops devt_hash_ops = { .hash = devt_hash_func, diff --git a/src/basic/log.c b/src/basic/log.c index 921c952f8..c6f70a187 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -351,10 +351,10 @@ static int write_to_console( } if (highlight) - IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON); + IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED); IOVEC_SET_STRING(iovec[n++], buffer); if (highlight) - IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF); + IOVEC_SET_STRING(iovec[n++], ANSI_NORMAL); IOVEC_SET_STRING(iovec[n++], "\n"); if (writev(console_fd, iovec, n) < 0) { @@ -942,7 +942,7 @@ int log_set_max_level_from_string(const char *e) { t = log_level_from_string(e); if (t < 0) - return t; + return -EINVAL; log_set_max_level(t); return 0; diff --git a/src/basic/log.h b/src/basic/log.h index 5fb223de5..fe59fb0ad 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -236,3 +236,15 @@ int log_syntax_internal( ? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \ : -abs(_e); \ }) + +#define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ + ({ \ + int _level = (level); \ + if (log_get_max_level() >= LOG_PRI(_level)) { \ + _cleanup_free_ char *_p = NULL; \ + _p = utf8_escape_invalid(rvalue); \ + log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \ + "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \ + } \ + -EINVAL; \ + }) diff --git a/src/basic/macro.h b/src/basic/macro.h index 7715c6e69..53d7f9baf 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -124,8 +124,11 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL)); } -#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) - +#define ELEMENTSOF(x) \ + __extension__ (__builtin_choose_expr( \ + !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ + sizeof(x)/sizeof((x)[0]), \ + (void)0)) /* * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. @@ -214,18 +217,20 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { (__x / __y + !!(__x % __y)); \ }) -#define assert_se(expr) \ +#define assert_message_se(expr, message) \ do { \ if (_unlikely_(!(expr))) \ - log_assert_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } while (false) \ + log_assert_failed(message, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } while (false) + +#define assert_se(expr) assert_message_se(expr, #expr) /* We override the glibc assert() here. */ #undef assert #ifdef NDEBUG #define assert(expr) do {} while(false) #else -#define assert(expr) assert_se(expr) +#define assert(expr) assert_message_se(expr, #expr) #endif #define assert_not_reached(t) \ @@ -250,19 +255,19 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { REENABLE_WARNING #endif -#define assert_log(expr) ((_likely_(expr)) \ - ? (true) \ - : (log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__), false)) +#define assert_log(expr, message) ((_likely_(expr)) \ + ? (true) \ + : (log_assert_failed_return(message, __FILE__, __LINE__, __PRETTY_FUNCTION__), false)) #define assert_return(expr, r) \ do { \ - if (!assert_log(expr)) \ + if (!assert_log(expr, #expr)) \ return (r); \ } while (false) #define assert_return_errno(expr, r, err) \ do { \ - if (!assert_log(expr)) { \ + if (!assert_log(expr, #expr)) { \ errno = err; \ return (r); \ } \ @@ -466,18 +471,6 @@ do { \ #define GID_INVALID ((gid_t) -1) #define MODE_INVALID ((mode_t) -1) -static inline bool UID_IS_INVALID(uid_t uid) { - /* We consider both the old 16bit -1 user and the newer 32bit - * -1 user invalid, since they are or used to be incompatible - * with syscalls such as setresuid() or chown(). */ - - return uid == (uid_t) ((uint32_t) -1) || uid == (uid_t) ((uint16_t) -1); -} - -static inline bool GID_IS_INVALID(gid_t gid) { - return gid == (gid_t) ((uint32_t) -1) || gid == (gid_t) ((uint16_t) -1); -} - #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ static inline void func##p(type *p) { \ if (*p) \ diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index b6dc19082..fef163457 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -70,6 +70,8 @@ int memfd_new(const char *name) { return fd; } +/// UNNEEDED by elogind +#if 0 int memfd_map(int fd, uint64_t offset, size_t size, void **p) { void *q; int sealed; @@ -93,6 +95,7 @@ int memfd_map(int fd, uint64_t offset, size_t size, void **p) { *p = q; return 0; } +#endif // 0 int memfd_set_sealed(int fd) { int r; @@ -118,6 +121,8 @@ int memfd_get_sealed(int fd) { return r == (F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL); } +/// UNNEEDED by elogind +#if 0 int memfd_get_size(int fd, uint64_t *sz) { struct stat stat; int r; @@ -132,6 +137,7 @@ int memfd_get_size(int fd, uint64_t *sz) { *sz = stat.st_size; return 0; } +#endif // 0 int memfd_set_size(int fd, uint64_t sz) { int r; diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index 9aa87b783..d96fd160e 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -26,10 +26,10 @@ int memfd_new(const char *name); // UNNEEDED int memfd_new_and_map(const char *name, size_t sz, void **p); -int memfd_map(int fd, uint64_t offset, size_t size, void **p); +// UNNEEDED int memfd_map(int fd, uint64_t offset, size_t size, void **p); int memfd_set_sealed(int fd); int memfd_get_sealed(int fd); -int memfd_get_size(int fd, uint64_t *sz); +// UNNEEDED int memfd_get_size(int fd, uint64_t *sz); int memfd_set_size(int fd, uint64_t sz); diff --git a/src/basic/missing.h b/src/basic/missing.h index bc6fbc539..7ba1c68e8 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -39,6 +39,10 @@ #include "musl_missing.h" +#ifdef HAVE_AUDIT +#include <libaudit.h> +#endif + #ifdef ARCH_MIPS #include <asm/sgidefs.h> #endif @@ -137,6 +141,8 @@ static inline int pivot_root(const char *new_root, const char *put_old) { # define __NR_memfd_create 385 # elif defined __aarch64__ # define __NR_memfd_create 279 +# elif defined __s390__ +# define __NR_memfd_create 350 # elif defined _MIPS_SIM # if _MIPS_SIM == _MIPS_SIM_ABI32 # define __NR_memfd_create 4354 @@ -838,6 +844,19 @@ static inline int setns(int fd, int nstype) { #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) #endif +#if !HAVE_DECL_IFLA_BR_PRIORITY +#define IFLA_BR_UNSPEC 0 +#define IFLA_BR_FORWARD_DELAY 1 +#define IFLA_BR_HELLO_TIME 2 +#define IFLA_BR_MAX_AGE 3 +#define IFLA_BR_AGEING_TIME 4 +#define IFLA_BR_STP_STATE 5 +#define IFLA_BR_PRIORITY 6 +#define __IFLA_BR_MAX 7 + +#define IFLA_BR_MAX (__IFLA_BR_MAX - 1) +#endif + #if !HAVE_DECL_IFLA_BRPORT_LEARNING_SYNC #define IFLA_BRPORT_UNSPEC 0 #define IFLA_BRPORT_STATE 1 @@ -1026,7 +1045,12 @@ static inline int renameat2(int oldfd, const char *oldname, int newfd, const cha #if !HAVE_DECL_KCMP static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { +#if defined(__NR_kcmp) return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); +#else + errno = ENOSYS; + return -1; +#endif } #endif @@ -1041,3 +1065,48 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns #ifndef INPUT_PROP_ACCELEROMETER #define INPUT_PROP_ACCELEROMETER 0x06 #endif + +#if !HAVE_DECL_KEY_SERIAL_T +typedef int32_t key_serial_t; +#endif + +#if !HAVE_DECL_KEYCTL +static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) { +#if defined(__NR_keyctl) + return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); +#else + errno = ENOSYS; + return -1; +#endif +} + +static inline key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) { +#if defined (__NR_add_key) + return syscall(__NR_add_key, type, description, payload, plen, ringid); +#else + errno = ENOSYS; + return -1; +#endif +} + +static inline key_serial_t request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) { +#if defined (__NR_request_key) + return syscall(__NR_request_key, type, description, callout_info, destringid); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +#ifndef KEYCTL_READ +#define KEYCTL_READ 11 +#endif + +#ifndef KEYCTL_SET_TIMEOUT +#define KEYCTL_SET_TIMEOUT 15 +#endif + +#ifndef KEY_SPEC_USER_KEYRING +#define KEY_SPEC_USER_KEYRING -4 +#endif diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 238252eeb..3998fc98a 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -219,7 +219,6 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) { *_r = r; return 0; } -#endif // 0 char **path_strv_make_absolute_cwd(char **l) { char **s; @@ -241,6 +240,7 @@ char **path_strv_make_absolute_cwd(char **l) { return l; } +#endif // 0 char **path_strv_resolve(char **l, const char *prefix) { char **s; diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 90b405dc8..a0a8dc619 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -49,7 +49,7 @@ bool path_equal(const char *a, const char *b) _pure_; // UNNEEDED bool path_equal_or_files_same(const char *a, const char *b); // UNNEEDED char* path_join(const char *root, const char *path, const char *rest); -char** path_strv_make_absolute_cwd(char **l); +// UNNEEDED char** path_strv_make_absolute_cwd(char **l); char** path_strv_resolve(char **l, const char *prefix); char** path_strv_resolve_uniq(char **l, const char *prefix); diff --git a/src/basic/prioq.c b/src/basic/prioq.c index b89888be0..d55b348c2 100644 --- a/src/basic/prioq.c +++ b/src/basic/prioq.c @@ -19,6 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +/* + * Priority Queue + * The prioq object implements a priority queue. That is, it orders objects by + * their priority and allows O(1) access to the object with the highest + * priority. Insertion and removal are Θ(log n). Optionally, the caller can + * provide a pointer to an index which will be kept up-to-date by the prioq. + * + * The underlying algorithm used in this implementation is a Heap. + */ + #include "util.h" #include "prioq.h" @@ -101,7 +111,7 @@ static unsigned shuffle_up(Prioq *q, unsigned idx) { k = (idx-1)/2; - if (q->compare_func(q->items[k].data, q->items[idx].data) < 0) + if (q->compare_func(q->items[k].data, q->items[idx].data) <= 0) break; swap(q, idx, k); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 0fc9ba463..8a1f54db8 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -217,7 +217,7 @@ int get_process_capeff(pid_t pid, char **capeff) { p = procfs_file_alloca(pid, "status"); - r = get_status_field(p, "\nCapEff:", capeff); + r = get_proc_field(p, "CapEff", WHITESPACE, capeff); if (r == -ENOENT) return -ESRCH; @@ -368,7 +368,6 @@ int get_process_environ(pid_t pid, char **env) { return 0; } -#endif // 0 int get_parent_of_pid(pid_t pid, pid_t *_ppid) { int r; @@ -414,6 +413,7 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) { return 0; } +#endif // 0 int wait_for_terminate(pid_t pid, siginfo_t *status) { siginfo_t dummy; diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 1482cca34..8e0b58975 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -56,7 +56,7 @@ 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); // UNNEEDED int kill_and_sigcont(pid_t pid, int sig); -pid_t get_parent_of_pid(pid_t pid, pid_t *ppid); +// UNNEEDED pid_t get_parent_of_pid(pid_t pid, pid_t *ppid); // UNNEEDED void rename_process(const char name[8]); int is_kernel_thread(pid_t pid); int getenv_for_pid(pid_t pid, const char *field, char **_value); diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index cea80b678..239900b79 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -303,14 +303,20 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * return r; } -void mac_selinux_free(char *label) { +char* mac_selinux_free(char *label) { #ifdef HAVE_SELINUX + if (!label) + return NULL; + if (!mac_selinux_use()) - return; + return NULL; + freecon((security_context_t) label); #endif + + return NULL; } #endif // 0 diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 559b0d6df..caac8dfb7 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -21,10 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <sys/socket.h> #include <stdbool.h> +#include "macro.h" + bool mac_selinux_use(void); // UNNEEDED void mac_selinux_retest(void); diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c index f68bd283a..fa94f80ae 100644 --- a/src/basic/siphash24.c +++ b/src/basic/siphash24.c @@ -13,123 +13,170 @@ this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd) + (Refactored by Tom Gundersen to split up in several functions and follow systemd + coding style) */ -#include <stdint.h> -#include <stdio.h> -#include <string.h> + +#include "sparse-endian.h" #include "siphash24.h" +#include "util.h" -typedef uint64_t u64; -typedef uint32_t u32; -typedef uint8_t u8; - -#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) ) - -#define U32TO8_LE(p, v) \ - (p)[0] = (u8)((v) ); (p)[1] = (u8)((v) >> 8); \ - (p)[2] = (u8)((v) >> 16); (p)[3] = (u8)((v) >> 24); - -#define U64TO8_LE(p, v) \ - U32TO8_LE((p), (u32)((v) )); \ - U32TO8_LE((p) + 4, (u32)((v) >> 32)); - -#define U8TO64_LE(p) \ - (((u64)((p)[0]) ) | \ - ((u64)((p)[1]) << 8) | \ - ((u64)((p)[2]) << 16) | \ - ((u64)((p)[3]) << 24) | \ - ((u64)((p)[4]) << 32) | \ - ((u64)((p)[5]) << 40) | \ - ((u64)((p)[6]) << 48) | \ - ((u64)((p)[7]) << 56)) - -#define SIPROUND \ - do { \ - v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \ - v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \ - v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \ - v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \ - } while(0) +static inline uint64_t rotate_left(uint64_t x, uint8_t b) { + assert(b < 64); + + return (x << b) | (x >> (64 - b)); +} + +static inline void sipround(struct siphash *state) { + assert(state); + + state->v0 += state->v1; + state->v1 = rotate_left(state->v1, 13); + state->v1 ^= state->v0; + state->v0 = rotate_left(state->v0, 32); + state->v2 += state->v3; + state->v3 = rotate_left(state->v3, 16); + state->v3 ^= state->v2; + state->v0 += state->v3; + state->v3 = rotate_left(state->v3, 21); + state->v3 ^= state->v0; + state->v2 += state->v1; + state->v1 = rotate_left(state->v1, 17); + state->v1 ^= state->v2; + state->v2 = rotate_left(state->v2, 32); +} + +void siphash24_init(struct siphash *state, const uint8_t k[16]) { + uint64_t k0, k1; + + assert(state); + assert(k); + + k0 = le64toh(*(le64_t*) k); + k1 = le64toh(*(le64_t*) (k + 8)); -/* SipHash-2-4 */ -void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) -{ /* "somepseudorandomlygeneratedbytes" */ - u64 v0 = 0x736f6d6570736575ULL; - u64 v1 = 0x646f72616e646f6dULL; - u64 v2 = 0x6c7967656e657261ULL; - u64 v3 = 0x7465646279746573ULL; - u64 b; - u64 k0 = U8TO64_LE( k ); - u64 k1 = U8TO64_LE( k + 8 ); - u64 m; - const u8 *in = _in; - const u8 *end = in + inlen - ( inlen % sizeof( u64 ) ); - const int left = inlen & 7; - b = ( ( u64 )inlen ) << 56; - v3 ^= k1; - v2 ^= k0; - v1 ^= k1; - v0 ^= k0; - - for ( ; in != end; in += 8 ) - { - m = U8TO64_LE( in ); + state->v0 = 0x736f6d6570736575ULL ^ k0; + state->v1 = 0x646f72616e646f6dULL ^ k1; + state->v2 = 0x6c7967656e657261ULL ^ k0; + state->v3 = 0x7465646279746573ULL ^ k1; + state->padding = 0; + state->inlen = 0; +} + +void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { + uint64_t m; + const uint8_t *in = _in; + const uint8_t *end = in + inlen; + unsigned left = state->inlen & 7; + + assert(in); + assert(state); + + /* update total length */ + state->inlen += inlen; + + /* if padding exists, fill it out */ + if (left > 0) { + for ( ; in < end && left < 8; in ++, left ++ ) + state->padding |= ( ( uint64_t )*in ) << (left * 8); + + if (in == end && left < 8) + /* we did not have enough input to fill out the padding completely */ + return; + #ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); - printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m ); + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); + printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding); #endif - v3 ^= m; - SIPROUND; - SIPROUND; - v0 ^= m; + state->v3 ^= state->padding; + sipround(state); + sipround(state); + state->v0 ^= state->padding; + + state->padding = 0; + } + + end -= ( state->inlen % sizeof (uint64_t) ); + + for ( ; in < end; in += 8 ) { + m = le64toh(*(le64_t*) in); +#ifdef DEBUG + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); + printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m); +#endif + state->v3 ^= m; + sipround(state); + sipround(state); + state->v0 ^= m; } + left = state->inlen & 7; + switch( left ) { - case 7: b |= ( ( u64 )in[ 6] ) << 48; + case 7: state->padding |= ((uint64_t) in[6]) << 48; - case 6: b |= ( ( u64 )in[ 5] ) << 40; + case 6: state->padding |= ((uint64_t) in[5]) << 40; - case 5: b |= ( ( u64 )in[ 4] ) << 32; + case 5: state->padding |= ((uint64_t) in[4]) << 32; - case 4: b |= ( ( u64 )in[ 3] ) << 24; + case 4: state->padding |= ((uint64_t) in[3]) << 24; - case 3: b |= ( ( u64 )in[ 2] ) << 16; + case 3: state->padding |= ((uint64_t) in[2]) << 16; - case 2: b |= ( ( u64 )in[ 1] ) << 8; + case 2: state->padding |= ((uint64_t) in[1]) << 8; - case 1: b |= ( ( u64 )in[ 0] ); break; + case 1: state->padding |= ((uint64_t) in[0]); break; case 0: break; } +} +void siphash24_finalize(uint8_t out[8], struct siphash *state) { + uint64_t b; + + b = state->padding | (( ( uint64_t )state->inlen ) << 56); #ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); - printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b ); + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t)state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t)state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t)state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t)state->v3); + printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding); #endif - v3 ^= b; - SIPROUND; - SIPROUND; - v0 ^= b; + state->v3 ^= b; + sipround(state); + sipround(state); + state->v0 ^= b; + #ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); #endif - v2 ^= 0xff; - SIPROUND; - SIPROUND; - SIPROUND; - SIPROUND; - b = v0 ^ v1 ^ v2 ^ v3; - U64TO8_LE( out, b ); + state->v2 ^= 0xff; + + sipround(state); + sipround(state); + sipround(state); + sipround(state); + + *(le64_t*)out = htole64(state->v0 ^ state->v1 ^ state->v2 ^ state->v3); +} + +/* SipHash-2-4 */ +void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) { + struct siphash state; + + siphash24_init(&state, k); + siphash24_compress(_in, inlen, &state); + siphash24_finalize(out, &state); } diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h index 62e1168a7..6c5cd98ee 100644 --- a/src/basic/siphash24.h +++ b/src/basic/siphash24.h @@ -3,4 +3,17 @@ #include <inttypes.h> #include <sys/types.h> +struct siphash { + uint64_t v0; + uint64_t v1; + uint64_t v2; + uint64_t v3; + uint64_t padding; + size_t inlen; +}; + +void siphash24_init(struct siphash *state, const uint8_t k[16]); +void siphash24_compress(const void *in, size_t inlen, struct siphash *state); +void siphash24_finalize(uint8_t out[8], struct siphash *state); + void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]); diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index 6d5c20511..a5fd687b8 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -29,9 +29,6 @@ #include "fileio.h" #include "smack-util.h" -#define SMACK_FLOOR_LABEL "_" -#define SMACK_STAR_LABEL "*" - #ifdef HAVE_SMACK bool mac_smack_use(void) { static int cached_use = -1; @@ -42,6 +39,8 @@ bool mac_smack_use(void) { return cached_use; } +/// UNNEEDED by elogind +#if 0 static const char* const smack_attr_table[_SMACK_ATTR_MAX] = { [SMACK_ATTR_ACCESS] = "security.SMACK64", [SMACK_ATTR_EXEC] = "security.SMACK64EXEC", @@ -129,6 +128,7 @@ int mac_smack_apply_pid(pid_t pid, const char *label) { return r; } +#endif // 0 int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { struct stat st; @@ -185,12 +185,34 @@ int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { return r; } +/// UNNEEDED by elogind +#if 0 +int mac_smack_copy(const char *dest, const char *src) { + int r = 0; + _cleanup_free_ char *label = NULL; + + assert(dest); + assert(src); + + r = mac_smack_read(src, SMACK_ATTR_ACCESS, &label); + if (r < 0) + return r; + + r = mac_smack_apply(dest, SMACK_ATTR_ACCESS, label); + if (r < 0) + return r; + + return r; +} +#endif // 0 #else bool mac_smack_use(void) { return false; } +/// UNNEEDED by elogind +#if 0 int mac_smack_read(const char *path, SmackAttr attr, char **label) { return -EOPNOTSUPP; } @@ -210,8 +232,16 @@ int mac_smack_apply_fd(int fd, SmackAttr attr, const char *label) { int mac_smack_apply_pid(pid_t pid, const char *label) { return 0; } +#endif // 0 int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { return 0; } + +/// UNNEEDED by elogind +#if 0 +int mac_smack_copy(const char *dest, const char *src) { + return 0; +} +#endif // 0 #endif diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h index 1052cecf4..327a07821 100644 --- a/src/basic/smack-util.h +++ b/src/basic/smack-util.h @@ -27,6 +27,11 @@ #include "macro.h" +#define SMACK_FLOOR_LABEL "_" +#define SMACK_STAR_LABEL "*" + +/// UNNEEDED by elogind +#if 0 typedef enum SmackAttr { SMACK_ATTR_ACCESS = 0, SMACK_ATTR_EXEC = 1, @@ -37,16 +42,17 @@ typedef enum SmackAttr { _SMACK_ATTR_MAX, _SMACK_ATTR_INVALID = -1, } SmackAttr; +#endif // 0 bool mac_smack_use(void); int mac_smack_fix(const char *path, bool ignore_enoent, bool ignore_erofs); -const char* smack_attr_to_string(SmackAttr i) _const_; -SmackAttr smack_attr_from_string(const char *s) _pure_; -int mac_smack_read(const char *path, SmackAttr attr, char **label); -int mac_smack_read_fd(int fd, SmackAttr attr, char **label); -int mac_smack_apply(const char *path, SmackAttr attr, const char *label); -int mac_smack_apply_fd(int fd, SmackAttr attr, const char *label); - -int mac_smack_apply_pid(pid_t pid, const char *label); +// UNNEEDED const char* smack_attr_to_string(SmackAttr i) _const_; +// UNNEEDED SmackAttr smack_attr_from_string(const char *s) _pure_; +// UNNEEDED int mac_smack_read(const char *path, SmackAttr attr, char **label); +// UNNEEDED int mac_smack_read_fd(int fd, SmackAttr attr, char **label); +// UNNEEDED int mac_smack_apply(const char *path, SmackAttr attr, const char *label); +// UNNEEDED int mac_smack_apply_fd(int fd, SmackAttr attr, const char *label); +// UNNEEDED int mac_smack_apply_pid(pid_t pid, const char *label); +// UNNEEDED int mac_smack_copy(const char *dest, const char *src); diff --git a/src/basic/strv.c b/src/basic/strv.c index dab34d8e7..d4a1b80d0 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -188,17 +188,48 @@ char **strv_new(const char *x, ...) { return r; } -int strv_extend_strv(char ***a, char **b) { - int r; - char **s; +int strv_extend_strv(char ***a, char **b, bool filter_duplicates) { + char **s, **t; + size_t p, q, i = 0, j; + + assert(a); + + if (strv_isempty(b)) + return 0; + + p = strv_length(*a); + q = strv_length(b); + + t = realloc(*a, sizeof(char*) * (p + q + 1)); + if (!t) + return -ENOMEM; + + t[p] = NULL; + *a = t; STRV_FOREACH(s, b) { - r = strv_extend(a, *s); - if (r < 0) - return r; + + if (filter_duplicates && strv_contains(t, *s)) + continue; + + t[p+i] = strdup(*s); + if (!t[p+i]) + goto rollback; + + i++; + t[p+i] = NULL; } - return 0; + assert(i <= q); + + return (int) i; + +rollback: + for (j = 0; j < i; j++) + free(t[p + j]); + + t[p] = NULL; + return -ENOMEM; } /// UNNEEDED by elogind @@ -275,16 +306,15 @@ char **strv_split_newlines(const char *s) { if (n <= 0) return l; - if (isempty(l[n-1])) { + if (isempty(l[n - 1])) l[n-1] = mfree(l[n-1]); - } return l; } int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) { - size_t n = 0, allocated = 0; _cleanup_strv_free_ char **l = NULL; + size_t n = 0, allocated = 0; int r; assert(t); @@ -296,9 +326,8 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract r = extract_first_word(&s, &word, separators, flags); if (r < 0) return r; - if (r == 0) { + if (r == 0) break; - } if (!GREEDY_REALLOC(l, allocated, n + 2)) return -ENOMEM; @@ -309,13 +338,16 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract l[n] = NULL; } - if (!l) + if (!l) { l = new0(char*, 1); + if (!l) + return -ENOMEM; + } *t = l; l = NULL; - return 0; + return (int) n; } #endif // 0 @@ -632,6 +664,41 @@ char **strv_split_nulstr(const char *s) { return r; } +int strv_make_nulstr(char **l, char **p, size_t *q) { + size_t n_allocated = 0, n = 0; + _cleanup_free_ char *m = NULL; + char **i; + + assert(p); + assert(q); + + STRV_FOREACH(i, l) { + size_t z; + + z = strlen(*i); + + if (!GREEDY_REALLOC(m, n_allocated, n + z + 1)) + return -ENOMEM; + + memcpy(m + n, *i, z + 1); + n += z + 1; + } + + if (!m) { + m = new0(char, 1); + if (!m) + return -ENOMEM; + n = 0; + } + + *p = m; + *q = n; + + m = NULL; + + return 0; +} + /// UNNEEDED by elogind #if 0 bool strv_overlap(char **a, char **b) { @@ -660,8 +727,12 @@ char **strv_sort(char **l) { } bool strv_equal(char **a, char **b) { - if (!a || !b) - return a == b; + + if (strv_isempty(a)) + return strv_isempty(b); + + if (strv_isempty(b)) + return false; for ( ; *a || *b; ++a, ++b) if (!streq_ptr(*a, *b)) @@ -740,3 +811,66 @@ bool strv_fnmatch(char* const* patterns, const char *s, int flags) { return false; } + +char ***strv_free_free(char ***l) { + char ***i; + + if (!l) + return NULL; + + for (i = l; *i; i++) + strv_free(*i); + + free(l); + return NULL; +} + +char **strv_skip(char **l, size_t n) { + + while (n > 0) { + if (strv_isempty(l)) + return l; + + l++, n--; + } + + return l; +} + +int strv_extend_n(char ***l, const char *value, size_t n) { + size_t i, j, k; + char **nl; + + assert(l); + + if (!value) + return 0; + if (n == 0) + return 0; + + /* Adds the value value n times to l */ + + k = strv_length(*l); + + nl = realloc(*l, sizeof(char*) * (k + n + 1)); + if (!nl) + return -ENOMEM; + + *l = nl; + + for (i = k; i < k + n; i++) { + nl[i] = strdup(value); + if (!nl[i]) + goto rollback; + } + + nl[i] = NULL; + return 0; + +rollback: + for (j = k; j < i; j++) + free(nl[j]); + + nl[k] = NULL; + return -ENOMEM; +} diff --git a/src/basic/strv.h b/src/basic/strv.h index 682bb3f75..5ab17acc9 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -40,7 +40,7 @@ void strv_clear(char **l); char **strv_copy(char * const *l); unsigned strv_length(char * const *l) _pure_; -int strv_extend_strv(char ***a, char **b); +int strv_extend_strv(char ***a, char **b, bool filter_duplicates); // UNNEEDED int strv_extend_strv_concat(char ***a, char **b, const char *suffix); int strv_extend(char ***l, const char *value); // UNNEEDED int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); @@ -80,6 +80,7 @@ char *strv_join(char **l, const char *separator); char **strv_parse_nulstr(const char *s, size_t l); char **strv_split_nulstr(const char *s); +int strv_make_nulstr(char **l, char **p, size_t *n); // UNNEEDED bool strv_overlap(char **a, char **b) _pure_; @@ -154,3 +155,9 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i return strv_isempty(patterns) || strv_fnmatch(patterns, s, flags); } + +char ***strv_free_free(char ***l); + +char **strv_skip(char **l, size_t n); + +int strv_extend_n(char ***l, const char *value, size_t n); diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 8e101c60a..8f63695cf 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -48,7 +48,7 @@ int chvt(int vt) { if (fd < 0) return -errno; - if (vt < 0) { + if (vt <= 0) { int tiocl[2] = { TIOCL_GETKMSGREDIRECT, 0 @@ -141,14 +141,14 @@ int ask_char(char *ret, const char *replies, const char *text, ...) { bool need_nl = true; if (on_tty()) - fputs(ANSI_HIGHLIGHT_ON, stdout); + fputs(ANSI_HIGHLIGHT, stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); if (on_tty()) - fputs(ANSI_HIGHLIGHT_OFF, stdout); + fputs(ANSI_NORMAL, stdout); fflush(stdout); @@ -185,14 +185,14 @@ int ask_string(char **ret, const char *text, ...) { va_list ap; if (on_tty()) - fputs(ANSI_HIGHLIGHT_ON, stdout); + fputs(ANSI_HIGHLIGHT, stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); if (on_tty()) - fputs(ANSI_HIGHLIGHT_OFF, stdout); + fputs(ANSI_NORMAL, stdout); fflush(stdout); @@ -613,27 +613,6 @@ int vt_disallocate(const char *name) { return 0; } -void warn_melody(void) { - _cleanup_close_ int fd = -1; - - fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return; - - /* Yeah, this is synchronous. Kinda sucks. But well... */ - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/440)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/220)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/220)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, 0); -} - /// UNNEEDED by elogind #if 0 int make_console_stdio(void) { diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index 7fddb2959..41a7a725e 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -26,16 +26,22 @@ #include "macro.h" #include "time-util.h" -#define ANSI_HIGHLIGHT_ON "\x1B[1;39m" -#define ANSI_RED_ON "\x1B[31m" -#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m" -#define ANSI_GREEN_ON "\x1B[32m" -#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m" -#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m" -#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m" -#define ANSI_HIGHLIGHT_OFF "\x1B[0m" +#define ANSI_RED "\x1B[0;31m" +#define ANSI_GREEN "\x1B[0;32m" +#define ANSI_UNDERLINE "\x1B[0;4m" +#define ANSI_HIGHLIGHT "\x1B[0;1;39m" +#define ANSI_HIGHLIGHT_RED "\x1B[0;1;31m" +#define ANSI_HIGHLIGHT_GREEN "\x1B[0;1;32m" +#define ANSI_HIGHLIGHT_YELLOW "\x1B[0;1;33m" +#define ANSI_HIGHLIGHT_BLUE "\x1B[0;1;34m" +#define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m" +#define ANSI_NORMAL "\x1B[0m" + #define ANSI_ERASE_TO_END_OF_LINE "\x1B[K" +/* Set cursor to top left corner and clear screen */ +#define ANSI_HOME_CLEAR "\x1B[H\x1B[2J" + int reset_terminal_fd(int fd, bool switch_to_text); int reset_terminal(const char *name); @@ -61,8 +67,6 @@ bool tty_is_console(const char *tty) _pure_; int vtnr_from_tty(const char *tty); // UNNEEDED const char *default_term_for_tty(const char *tty); -void warn_melody(void); - int make_stdio(int fd); int make_null_stdio(void); // UNNEEDED int make_console_stdio(void); @@ -78,28 +82,36 @@ unsigned lines(void); bool on_tty(void); +static inline const char *ansi_underline(void) { + return on_tty() ? ANSI_UNDERLINE : ""; +} + static inline const char *ansi_highlight(void) { - return on_tty() ? ANSI_HIGHLIGHT_ON : ""; + return on_tty() ? ANSI_HIGHLIGHT : ""; +} + +static inline const char *ansi_highlight_underline(void) { + return on_tty() ? ANSI_HIGHLIGHT_UNDERLINE : ""; } static inline const char *ansi_highlight_red(void) { - return on_tty() ? ANSI_HIGHLIGHT_RED_ON : ""; + return on_tty() ? ANSI_HIGHLIGHT_RED : ""; } static inline const char *ansi_highlight_green(void) { - return on_tty() ? ANSI_HIGHLIGHT_GREEN_ON : ""; + return on_tty() ? ANSI_HIGHLIGHT_GREEN : ""; } static inline const char *ansi_highlight_yellow(void) { - return on_tty() ? ANSI_HIGHLIGHT_YELLOW_ON : ""; + return on_tty() ? ANSI_HIGHLIGHT_YELLOW : ""; } static inline const char *ansi_highlight_blue(void) { - return on_tty() ? ANSI_HIGHLIGHT_BLUE_ON : ""; + return on_tty() ? ANSI_HIGHLIGHT_BLUE : ""; } -static inline const char *ansi_highlight_off(void) { - return on_tty() ? ANSI_HIGHLIGHT_OFF : ""; +static inline const char *ansi_normal(void) { + return on_tty() ? ANSI_NORMAL : ""; } int get_ctty_devnr(pid_t pid, dev_t *d); diff --git a/src/basic/time-util.h b/src/basic/time-util.h index a0c850b08..ef49343a8 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -112,6 +112,8 @@ int parse_sec(const char *t, usec_t *usec); // UNNEEDED clockid_t clock_boottime_or_monotonic(void); -#define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0) +#define xstrftime(buf, fmt, tm) \ + assert_message_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0, \ + "xstrftime: " #buf "[] must be big enough") // UNNEEDED int get_timezone(char **timezone); diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index de1683536..d7a6927ef 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -847,6 +847,170 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); +static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { + [UNIT_ACTIVE] = "active", + [UNIT_RELOADING] = "reloading", + [UNIT_INACTIVE] = "inactive", + [UNIT_FAILED] = "failed", + [UNIT_ACTIVATING] = "activating", + [UNIT_DEACTIVATING] = "deactivating" +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState); + +static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = { + [AUTOMOUNT_DEAD] = "dead", + [AUTOMOUNT_WAITING] = "waiting", + [AUTOMOUNT_RUNNING] = "running", + [AUTOMOUNT_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState); + +static const char* const busname_state_table[_BUSNAME_STATE_MAX] = { + [BUSNAME_DEAD] = "dead", + [BUSNAME_MAKING] = "making", + [BUSNAME_REGISTERED] = "registered", + [BUSNAME_LISTENING] = "listening", + [BUSNAME_RUNNING] = "running", + [BUSNAME_SIGTERM] = "sigterm", + [BUSNAME_SIGKILL] = "sigkill", + [BUSNAME_FAILED] = "failed", +}; + +DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState); + +static const char* const device_state_table[_DEVICE_STATE_MAX] = { + [DEVICE_DEAD] = "dead", + [DEVICE_TENTATIVE] = "tentative", + [DEVICE_PLUGGED] = "plugged", +}; + +DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState); + +static const char* const mount_state_table[_MOUNT_STATE_MAX] = { + [MOUNT_DEAD] = "dead", + [MOUNT_MOUNTING] = "mounting", + [MOUNT_MOUNTING_DONE] = "mounting-done", + [MOUNT_MOUNTED] = "mounted", + [MOUNT_REMOUNTING] = "remounting", + [MOUNT_UNMOUNTING] = "unmounting", + [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm", + [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill", + [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm", + [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill", + [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm", + [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill", + [MOUNT_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); + +static const char* const path_state_table[_PATH_STATE_MAX] = { + [PATH_DEAD] = "dead", + [PATH_WAITING] = "waiting", + [PATH_RUNNING] = "running", + [PATH_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(path_state, PathState); + +static const char* const scope_state_table[_SCOPE_STATE_MAX] = { + [SCOPE_DEAD] = "dead", + [SCOPE_RUNNING] = "running", + [SCOPE_ABANDONED] = "abandoned", + [SCOPE_STOP_SIGTERM] = "stop-sigterm", + [SCOPE_STOP_SIGKILL] = "stop-sigkill", + [SCOPE_FAILED] = "failed", +}; + +DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState); + +static const char* const service_state_table[_SERVICE_STATE_MAX] = { + [SERVICE_DEAD] = "dead", + [SERVICE_START_PRE] = "start-pre", + [SERVICE_START] = "start", + [SERVICE_START_POST] = "start-post", + [SERVICE_RUNNING] = "running", + [SERVICE_EXITED] = "exited", + [SERVICE_RELOAD] = "reload", + [SERVICE_STOP] = "stop", + [SERVICE_STOP_SIGABRT] = "stop-sigabrt", + [SERVICE_STOP_SIGTERM] = "stop-sigterm", + [SERVICE_STOP_SIGKILL] = "stop-sigkill", + [SERVICE_STOP_POST] = "stop-post", + [SERVICE_FINAL_SIGTERM] = "final-sigterm", + [SERVICE_FINAL_SIGKILL] = "final-sigkill", + [SERVICE_FAILED] = "failed", + [SERVICE_AUTO_RESTART] = "auto-restart", +}; + +DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); + +static const char* const slice_state_table[_SLICE_STATE_MAX] = { + [SLICE_DEAD] = "dead", + [SLICE_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState); + +static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = { + [SNAPSHOT_DEAD] = "dead", + [SNAPSHOT_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState); + +static const char* const socket_state_table[_SOCKET_STATE_MAX] = { + [SOCKET_DEAD] = "dead", + [SOCKET_START_PRE] = "start-pre", + [SOCKET_START_CHOWN] = "start-chown", + [SOCKET_START_POST] = "start-post", + [SOCKET_LISTENING] = "listening", + [SOCKET_RUNNING] = "running", + [SOCKET_STOP_PRE] = "stop-pre", + [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm", + [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill", + [SOCKET_STOP_POST] = "stop-post", + [SOCKET_FINAL_SIGTERM] = "final-sigterm", + [SOCKET_FINAL_SIGKILL] = "final-sigkill", + [SOCKET_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); + +static const char* const swap_state_table[_SWAP_STATE_MAX] = { + [SWAP_DEAD] = "dead", + [SWAP_ACTIVATING] = "activating", + [SWAP_ACTIVATING_DONE] = "activating-done", + [SWAP_ACTIVE] = "active", + [SWAP_DEACTIVATING] = "deactivating", + [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm", + [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill", + [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", + [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", + [SWAP_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); + +static const char* const target_state_table[_TARGET_STATE_MAX] = { + [TARGET_DEAD] = "dead", + [TARGET_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState); + +static const char* const timer_state_table[_TIMER_STATE_MAX] = { + [TIMER_DEAD] = "dead", + [TIMER_WAITING] = "waiting", + [TIMER_RUNNING] = "running", + [TIMER_ELAPSED] = "elapsed", + [TIMER_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState); + static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_REQUIRES] = "Requires", [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable", diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index e07f7917b..c23ccc803 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -27,11 +27,7 @@ #define UNIT_NAME_MAX 256 -typedef enum UnitType UnitType; -// UNNEEDED typedef enum UnitLoadState UnitLoadState; -// UNNNEEDED typedef enum UnitDependency UnitDependency; - -enum UnitType { +typedef enum UnitType { UNIT_SERVICE = 0, UNIT_SOCKET, UNIT_BUSNAME, @@ -47,11 +43,11 @@ enum UnitType { UNIT_SCOPE, _UNIT_TYPE_MAX, _UNIT_TYPE_INVALID = -1 -}; +} UnitType; /// UNNEEDED by elogind #if 0 -enum UnitLoadState { +typedef enum UnitLoadState { UNIT_STUB = 0, UNIT_LOADED, UNIT_NOT_FOUND, @@ -60,9 +56,176 @@ enum UnitLoadState { UNIT_MASKED, _UNIT_LOAD_STATE_MAX, _UNIT_LOAD_STATE_INVALID = -1 -}; - -enum UnitDependency { +} UnitLoadState; + +typedef enum UnitActiveState { + UNIT_ACTIVE, + UNIT_RELOADING, + UNIT_INACTIVE, + UNIT_FAILED, + UNIT_ACTIVATING, + UNIT_DEACTIVATING, + _UNIT_ACTIVE_STATE_MAX, + _UNIT_ACTIVE_STATE_INVALID = -1 +} UnitActiveState; + +typedef enum AutomountState { + AUTOMOUNT_DEAD, + AUTOMOUNT_WAITING, + AUTOMOUNT_RUNNING, + AUTOMOUNT_FAILED, + _AUTOMOUNT_STATE_MAX, + _AUTOMOUNT_STATE_INVALID = -1 +} AutomountState; + +typedef enum BusNameState { + BUSNAME_DEAD, + BUSNAME_MAKING, + BUSNAME_REGISTERED, + BUSNAME_LISTENING, + BUSNAME_RUNNING, + BUSNAME_SIGTERM, + BUSNAME_SIGKILL, + BUSNAME_FAILED, + _BUSNAME_STATE_MAX, + _BUSNAME_STATE_INVALID = -1 +} BusNameState; + +/* We simply watch devices, we cannot plug/unplug them. That + * simplifies the state engine greatly */ +typedef enum DeviceState { + DEVICE_DEAD, + DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */ + DEVICE_PLUGGED, /* announced by udev */ + _DEVICE_STATE_MAX, + _DEVICE_STATE_INVALID = -1 +} DeviceState; + +typedef enum MountState { + MOUNT_DEAD, + MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */ + MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */ + MOUNT_MOUNTED, + MOUNT_REMOUNTING, + MOUNT_UNMOUNTING, + MOUNT_MOUNTING_SIGTERM, + MOUNT_MOUNTING_SIGKILL, + MOUNT_REMOUNTING_SIGTERM, + MOUNT_REMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_FAILED, + _MOUNT_STATE_MAX, + _MOUNT_STATE_INVALID = -1 +} MountState; + +typedef enum PathState { + PATH_DEAD, + PATH_WAITING, + PATH_RUNNING, + PATH_FAILED, + _PATH_STATE_MAX, + _PATH_STATE_INVALID = -1 +} PathState; + +typedef enum ScopeState { + SCOPE_DEAD, + SCOPE_RUNNING, + SCOPE_ABANDONED, + SCOPE_STOP_SIGTERM, + SCOPE_STOP_SIGKILL, + SCOPE_FAILED, + _SCOPE_STATE_MAX, + _SCOPE_STATE_INVALID = -1 +} ScopeState; + +typedef enum ServiceState { + SERVICE_DEAD, + SERVICE_START_PRE, + SERVICE_START, + SERVICE_START_POST, + SERVICE_RUNNING, + SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */ + SERVICE_RELOAD, + SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */ + SERVICE_STOP_SIGABRT, /* Watchdog timeout */ + SERVICE_STOP_SIGTERM, + SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */ + SERVICE_FINAL_SIGKILL, + SERVICE_FAILED, + SERVICE_AUTO_RESTART, + _SERVICE_STATE_MAX, + _SERVICE_STATE_INVALID = -1 +} ServiceState; + +typedef enum SliceState { + SLICE_DEAD, + SLICE_ACTIVE, + _SLICE_STATE_MAX, + _SLICE_STATE_INVALID = -1 +} SliceState; + +typedef enum SnapshotState { + SNAPSHOT_DEAD, + SNAPSHOT_ACTIVE, + _SNAPSHOT_STATE_MAX, + _SNAPSHOT_STATE_INVALID = -1 +} SnapshotState; + +typedef enum SocketState { + SOCKET_DEAD, + SOCKET_START_PRE, + SOCKET_START_CHOWN, + SOCKET_START_POST, + SOCKET_LISTENING, + SOCKET_RUNNING, + SOCKET_STOP_PRE, + SOCKET_STOP_PRE_SIGTERM, + SOCKET_STOP_PRE_SIGKILL, + SOCKET_STOP_POST, + SOCKET_FINAL_SIGTERM, + SOCKET_FINAL_SIGKILL, + SOCKET_FAILED, + _SOCKET_STATE_MAX, + _SOCKET_STATE_INVALID = -1 +} SocketState; + +typedef enum SwapState { + SWAP_DEAD, + SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */ + SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */ + SWAP_ACTIVE, + SWAP_DEACTIVATING, + SWAP_ACTIVATING_SIGTERM, + SWAP_ACTIVATING_SIGKILL, + SWAP_DEACTIVATING_SIGTERM, + SWAP_DEACTIVATING_SIGKILL, + SWAP_FAILED, + _SWAP_STATE_MAX, + _SWAP_STATE_INVALID = -1 +} SwapState; + + +typedef enum TargetState { + TARGET_DEAD, + TARGET_ACTIVE, + _TARGET_STATE_MAX, + _TARGET_STATE_INVALID = -1 +} TargetState; + +typedef enum TimerState { + TIMER_DEAD, + TIMER_WAITING, + TIMER_RUNNING, + TIMER_ELAPSED, + TIMER_FAILED, + _TIMER_STATE_MAX, + _TIMER_STATE_INVALID = -1 +} TimerState; + +typedef enum UnitDependency { /* Positive dependencies */ UNIT_REQUIRES, UNIT_REQUIRES_OVERRIDABLE, @@ -109,7 +272,7 @@ enum UnitDependency { _UNIT_DEPENDENCY_MAX, _UNIT_DEPENDENCY_INVALID = -1 -}; +} UnitDependency; #endif // 0 typedef enum UnitNameFlags { @@ -185,5 +348,47 @@ UnitType unit_type_from_string(const char *s) _pure_; // UNNEEDED const char *unit_load_state_to_string(UnitLoadState i) _const_; // UNNEEDED UnitLoadState unit_load_state_from_string(const char *s) _pure_; +// UNNEEDED const char *unit_active_state_to_string(UnitActiveState i) _const_; +// UNNEEDED UnitActiveState unit_active_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* automount_state_to_string(AutomountState i) _const_; +// UNNEEDED AutomountState automount_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* busname_state_to_string(BusNameState i) _const_; +// UNNEEDED BusNameState busname_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* device_state_to_string(DeviceState i) _const_; +// UNNEEDED DeviceState device_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* mount_state_to_string(MountState i) _const_; +// UNNEEDED MountState mount_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* path_state_to_string(PathState i) _const_; +// UNNEEDED PathState path_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* scope_state_to_string(ScopeState i) _const_; +// UNNEEDED ScopeState scope_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* service_state_to_string(ServiceState i) _const_; +// UNNEEDED ServiceState service_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* slice_state_to_string(SliceState i) _const_; +// UNNEEDED SliceState slice_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* snapshot_state_to_string(SnapshotState i) _const_; +// UNNEEDED SnapshotState snapshot_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* socket_state_to_string(SocketState i) _const_; +// UNNEEDED SocketState socket_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* swap_state_to_string(SwapState i) _const_; +// UNNEEDED SwapState swap_state_from_string(const char *s) _pure_; + +// UNNEEDED const char* target_state_to_string(TargetState i) _const_; +// UNNEEDED TargetState target_state_from_string(const char *s) _pure_; + +// UNNEEDED const char *timer_state_to_string(TimerState i) _const_; +// UNNEEDED TimerState timer_state_from_string(const char *s) _pure_; + // UNNEEDED const char *unit_dependency_to_string(UnitDependency i) _const_; // UNNEEDED UnitDependency unit_dependency_from_string(const char *s) _pure_; diff --git a/src/basic/util.c b/src/basic/util.c index 7e0a913f5..97a07b93c 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -19,82 +19,85 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -// #include <string.h> -// #include <unistd.h> -#include <errno.h> -// #include <stdlib.h> -// #include <signal.h> -// #include <libintl.h> -// #include <stdio.h> -// #include <syslog.h> -// #include <sched.h> -// #include <sys/resource.h> -// #include <linux/sched.h> -// #include <sys/types.h> -// #include <sys/stat.h> -// #include <fcntl.h> -// #include <dirent.h> -// #include <sys/ioctl.h> -// #include <stdarg.h> -#include <poll.h> -// #include <ctype.h> -#include <sys/prctl.h> -// #include <sys/utsname.h> -#include <pwd.h> -#include <netinet/ip.h> -// #include <sys/wait.h> -// #include <sys/time.h> -// #include <glob.h> -#include <grp.h> -// #include <sys/mman.h> -// #include <sys/vfs.h> -// #include <sys/mount.h> -#include <linux/magic.h> -// #include <limits.h> -#include <langinfo.h> -// #include <locale.h> -// #include <sys/personality.h> -#include <sys/xattr.h> -// #include <sys/statvfs.h> -// #include <sys/file.h> -#include <linux/fs.h> +//#include <ctype.h> +//#include <dirent.h> +//#include <errno.h> +//#include <fcntl.h> +//#include <glob.h> +#include <grp.h> +#include <langinfo.h> +//#include <libintl.h> +//#include <limits.h> +#include <linux/magic.h> +//#include <linux/sched.h> +//#include <locale.h> +#include <netinet/ip.h> +#include <poll.h> +#include <pwd.h> +#include <sched.h> +//#include <signal.h> +//#include <stdarg.h> +//#include <stdio.h> +//#include <stdlib.h> +//#include <string.h> +//#include <sys/file.h> +//#include <sys/ioctl.h> +//#include <sys/mman.h> +//#include <sys/mount.h> +//#include <sys/personality.h> +#include <sys/prctl.h> +//#include <sys/resource.h> +//#include <sys/stat.h> +//#include <sys/statvfs.h> +//#include <sys/time.h> +//#include <sys/types.h> +//#include <sys/utsname.h> +//#include <sys/vfs.h> +//#include <sys/wait.h> +#include <sys/xattr.h> +//#include <syslog.h> +//#include <unistd.h> /* When we include libgen.h because we need dirname() we immediately - * undefine basename() since libgen.h defines it as a macro to the POSIX - * version which is really broken. We prefer GNU basename(). */ -// #include <libgen.h> -// #undef basename + * undefine basename() since libgen.h defines it as a macro to the + * POSIX version which is really broken. We prefer GNU basename(). */ +//#include <libgen.h> +//#undef basename #ifdef HAVE_SYS_AUXV_H #include <sys/auxv.h> #endif -#include "config.h" -#include "macro.h" -#include "util.h" -// #include "ioprio.h" -// #include "missing.h" -// #include "log.h" -#include "strv.h" -#include "mkdir.h" -#include "path-util.h" -// #include "exit-status.h" -#include "hashmap.h" -#include "set.h" -// #include "env-util.h" -#include "fileio.h" -// #include "device-nodes.h" -#include "utf8.h" -#include "gunicode.h" -#include "virt.h" -// #include "def.h" -#include "sparse-endian.h" -// #include "formats-util.h" -#include "process-util.h" -#include "random-util.h" -// #include "terminal-util.h" -#include "hostname-util.h" -#include "signal-util.h" +/* We include linux/fs.h as last of the system headers, as it + * otherwise conflicts with sys/mount.h. Yay, Linux is great! */ +//#include <linux/fs.h> + +#include "build.h" +//#include "def.h" +//#include "device-nodes.h" +//#include "env-util.h" +//#include "exit-status.h" +#include "fileio.h" +//#include "formats-util.h" +#include "gunicode.h" +#include "hashmap.h" +#include "hostname-util.h" +//#include "ioprio.h" +//#include "log.h" +//#include "macro.h" +//#include "missing.h" +#include "mkdir.h" +#include "path-util.h" +#include "process-util.h" +#include "random-util.h" +#include "signal-util.h" +#include "sparse-endian.h" +#include "strv.h" +//#include "terminal-util.h" +#include "utf8.h" +#include "util.h" +#include "virt.h" +#include "set.h" /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); @@ -328,6 +331,44 @@ void close_many(const int fds[], unsigned n_fd) { safe_close(fds[i]); } +int fclose_nointr(FILE *f) { + assert(f); + + /* Same as close_nointr(), but for fclose() */ + + if (fclose(f) == 0) + return 0; + + if (errno == EINTR) + return 0; + + return -errno; +} + +FILE* safe_fclose(FILE *f) { + + /* Same as safe_close(), but for fclose() */ + + if (f) { + PROTECT_ERRNO; + + assert_se(fclose_nointr(f) != EBADF); + } + + return NULL; +} + +DIR* safe_closedir(DIR *d) { + + if (d) { + PROTECT_ERRNO; + + assert_se(closedir(d) >= 0 || errno != EBADF); + } + + return NULL; +} + int unlink_noerrno(const char *path) { PROTECT_ERRNO; int r; @@ -2125,7 +2166,13 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { assert(fd >= 0); assert(buf); - while (nbytes > 0) { + /* If called with nbytes == 0, let's call read() at least + * once, to validate the operation */ + + if (nbytes > (size_t) SSIZE_MAX) + return -EINVAL; + + do { ssize_t k; k = read(fd, p, nbytes); @@ -2139,7 +2186,7 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { * and expect that any error/EOF is reported * via read() */ - fd_wait_for_event(fd, POLLIN, USEC_INFINITY); + (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY); continue; } @@ -2149,10 +2196,12 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { if (k == 0) return n; + assert((size_t) k <= nbytes); + p += k; nbytes -= k; n += k; - } + } while (nbytes > 0); return n; } @@ -2162,9 +2211,10 @@ int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { n = loop_read(fd, buf, nbytes, do_poll); if (n < 0) - return n; + return (int) n; if ((size_t) n != nbytes) return -EIO; + return 0; } @@ -2174,7 +2224,8 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { assert(fd >= 0); assert(buf); - errno = 0; + if (nbytes > (size_t) SSIZE_MAX) + return -EINVAL; do { ssize_t k; @@ -2189,16 +2240,18 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { * and expect that any error/EOF is reported * via write() */ - fd_wait_for_event(fd, POLLOUT, USEC_INFINITY); + (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY); continue; } return -errno; } - if (nbytes > 0 && k == 0) /* Can't really happen */ + if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */ return -EIO; + assert((size_t) k <= nbytes); + p += k; nbytes -= k; } while (nbytes > 0); @@ -2206,7 +2259,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { return 0; } -int parse_size(const char *t, off_t base, off_t *size) { +int parse_size(const char *t, uint64_t base, uint64_t *size) { /* Soo, sometimes we want to parse IEC binary suffixes, and * sometimes SI decimal suffixes. This function can parse @@ -2234,8 +2287,8 @@ int parse_size(const char *t, off_t base, off_t *size) { { "G", 1024ULL*1024ULL*1024ULL }, { "M", 1024ULL*1024ULL }, { "K", 1024ULL }, - { "B", 1 }, - { "", 1 }, + { "B", 1ULL }, + { "", 1ULL }, }; static const struct table si[] = { @@ -2245,8 +2298,8 @@ int parse_size(const char *t, off_t base, off_t *size) { { "G", 1000ULL*1000ULL*1000ULL }, { "M", 1000ULL*1000ULL }, { "K", 1000ULL }, - { "B", 1 }, - { "", 1 }, + { "B", 1ULL }, + { "", 1ULL }, }; const struct table *table; @@ -2268,33 +2321,32 @@ int parse_size(const char *t, off_t base, off_t *size) { p = t; do { - long long l; - unsigned long long l2; + unsigned long long l, tmp; double frac = 0; char *e; unsigned i; - errno = 0; - l = strtoll(p, &e, 10); + p += strspn(p, WHITESPACE); + if (*p == '-') + return -ERANGE; + errno = 0; + l = strtoull(p, &e, 10); if (errno > 0) return -errno; - - if (l < 0) - return -ERANGE; - if (e == p) return -EINVAL; if (*e == '.') { e++; + + /* strtoull() itself would accept space/+/- */ if (*e >= '0' && *e <= '9') { + unsigned long long l2; char *e2; - /* strotoull itself would accept space/+/- */ l2 = strtoull(e, &e2, 10); - - if (errno == ERANGE) + if (errno > 0) return -errno; /* Ignore failure. E.g. 10.M is valid */ @@ -2307,26 +2359,26 @@ int parse_size(const char *t, off_t base, off_t *size) { e += strspn(e, WHITESPACE); for (i = start_pos; i < n_entries; i++) - if (startswith(e, table[i].suffix)) { - unsigned long long tmp; - if ((unsigned long long) l + (frac > 0) > ULLONG_MAX / table[i].factor) + if (startswith(e, table[i].suffix)) + break; + + if (i >= n_entries) + return -EINVAL; + + if (l + (frac > 0) > ULLONG_MAX / table[i].factor) return -ERANGE; + tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); if (tmp > ULLONG_MAX - r) return -ERANGE; r += tmp; - if ((unsigned long long) (off_t) r != r) + if ((unsigned long long) (uint64_t) r != r) return -ERANGE; p = e + strlen(table[i].suffix); start_pos = i + 1; - break; - } - - if (i >= n_entries) - return -EINVAL; } while (*p); @@ -2526,33 +2578,6 @@ int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { return 0; } -cpu_set_t* cpu_set_malloc(unsigned *ncpus) { - cpu_set_t *r; - unsigned n = 1024; - - /* Allocates the cpuset in the right size */ - - for (;;) { - if (!(r = CPU_ALLOC(n))) - return NULL; - - if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) { - CPU_ZERO_S(CPU_ALLOC_SIZE(n), r); - - if (ncpus) - *ncpus = n; - - return r; - } - - CPU_FREE(r); - - if (errno != EINVAL) - return NULL; - - n *= 2; - } -} #endif // 0 int files_same(const char *filea, const char *fileb) { @@ -3686,7 +3711,6 @@ static const char *const ioprio_class_table[] = { }; DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); -#endif // 0 static const char *const sigchld_code_table[] = { [CLD_EXITED] = "exited", @@ -3723,6 +3747,7 @@ static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { }; DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); +#endif // 0 static const char *const log_level_table[] = { [LOG_EMERG] = "emerg", @@ -3737,6 +3762,8 @@ static const char *const log_level_table[] = { DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); +/// UNNEEDED by elogind +#if 0 static const char* const sched_policy_table[] = { [SCHED_OTHER] = "other", [SCHED_BATCH] = "batch", @@ -3746,6 +3773,7 @@ static const char* const sched_policy_table[] = { }; DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); +#endif // 0 static const char* const rlimit_table[_RLIMIT_MAX] = { [RLIMIT_CPU] = "LimitCPU", @@ -3768,6 +3796,8 @@ static const char* const rlimit_table[_RLIMIT_MAX] = { DEFINE_STRING_TABLE_LOOKUP(rlimit, int); +/// UNNEEDED by elogind +#if 0 static const char* const ip_tos_table[] = { [IPTOS_LOWDELAY] = "low-delay", [IPTOS_THROUGHPUT] = "throughput", @@ -3789,8 +3819,6 @@ bool kexec_loaded(void) { return loaded; } -/// UNNEEDED by elogind -#if 0 int prot_from_flags(int flags) { switch (flags & O_ACCMODE) { @@ -3809,38 +3837,38 @@ int prot_from_flags(int flags) { } } -char *format_bytes(char *buf, size_t l, off_t t) { +char *format_bytes(char *buf, size_t l, uint64_t t) { unsigned i; static const struct { const char *suffix; - off_t factor; + uint64_t factor; } table[] = { - { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "M", 1024ULL*1024ULL }, - { "K", 1024ULL }, + { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "M", UINT64_C(1024)*UINT64_C(1024) }, + { "K", UINT64_C(1024) }, }; - if (t == (off_t) -1) + if (t == (uint64_t) -1) return NULL; for (i = 0; i < ELEMENTSOF(table); i++) { if (t >= table[i].factor) { snprintf(buf, l, - "%llu.%llu%s", - (unsigned long long) (t / table[i].factor), - (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL), + "%" PRIu64 ".%" PRIu64 "%s", + t / table[i].factor, + ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10), table[i].suffix); goto finish; } } - snprintf(buf, l, "%lluB", (unsigned long long) t); + snprintf(buf, l, "%" PRIu64 "B", t); finish: buf[l-1] = 0; @@ -4887,7 +4915,7 @@ int shall_restore_state(void) { int proc_cmdline(char **ret) { assert(ret); - if (detect_container(NULL) > 0) + if (detect_container() > 0) return get_process_cmdline(1, 0, false, ret); else return read_one_line_file("/proc/cmdline", ret); @@ -5285,6 +5313,19 @@ unsigned long personality_from_string(const char *p) { if (streq(p, "x86")) return PER_LINUX; + +#elif defined(__s390x__) + + if (streq(p, "s390")) + return PER_LINUX32; + + if (streq(p, "s390x")) + return PER_LINUX; + +#elif defined(__s390__) + + if (streq(p, "s390")) + return PER_LINUX; #endif return PERSONALITY_INVALID; @@ -5304,6 +5345,20 @@ const char* personality_to_string(unsigned long p) { if (p == PER_LINUX) return "x86"; + +#elif defined(__s390x__) + + if (p == PER_LINUX) + return "s390x"; + + if (p == PER_LINUX32) + return "s390"; + +#elif defined(__s390__) + + if (p == PER_LINUX) + return "s390"; + #endif return NULL; @@ -5371,15 +5426,13 @@ int update_reboot_param_file(const char *param) { int r = 0; if (param) { - r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE); if (r < 0) - log_error("Failed to write reboot param to " - REBOOT_PARAM_FILE": %s", strerror(-r)); + return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m"); } else - unlink(REBOOT_PARAM_FILE); + (void) unlink(REBOOT_PARAM_FILE); - return r; + return 0; } int umount_recursive(const char *prefix, int flags) { @@ -6022,6 +6075,7 @@ int extract_first_word_and_warn( const char *filename, unsigned line, const char *rvalue) { + /* Try to unquote it, if it fails, warn about it and try again but this * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim * in invalid escape sequences. */ @@ -6031,16 +6085,16 @@ int extract_first_word_and_warn( save = *p; r = extract_first_word(p, ret, separators, flags); if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) { + /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ *p = save; r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue); else - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, - "Invalid escape sequences in command line: \"%s\"", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid escape sequences in command line: \"%s\"", rvalue); } + return r; } @@ -6157,15 +6211,6 @@ int ptsname_malloc(int fd, char **ret) { int openpt_in_namespace(pid_t pid, int flags) { _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; _cleanup_close_pair_ int pair[2] = { -1, -1 }; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; siginfo_t si; pid_t child; int r; @@ -6199,15 +6244,7 @@ int openpt_in_namespace(pid_t pid, int flags) { if (unlockpt(master) < 0) _exit(EXIT_FAILURE); - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &master, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - - if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) + if (send_one_fd(pair[1], master, 0) < 0) _exit(EXIT_FAILURE); _exit(EXIT_SUCCESS); @@ -6221,40 +6258,24 @@ int openpt_in_namespace(pid_t pid, int flags) { if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) return -EIO; - if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) - return -errno; - - CMSG_FOREACH(cmsg, &mh) - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - int *fds; - unsigned n_fds; - - fds = (int*) CMSG_DATA(cmsg); - n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - - if (n_fds != 1) { - close_many(fds, n_fds); - return -EIO; - } - - return fds[0]; - } - - return -EIO; + return receive_one_fd(pair[0], 0); } #endif // 0 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]; _cleanup_close_ int fd = -1; ssize_t l; /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ - fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOATIME|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); + fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); if (fd < 0) return -errno; - l = fgetxattr(fd, attribute, value, size); + xsprintf(fn, "/proc/self/fd/%i", fd); + + l = getxattr(fn, attribute, value, size); if (l < 0) return -errno; @@ -6403,7 +6424,6 @@ int same_fd(int a, int b) { return fa == fb; } -#endif // 0 int chattr_fd(int fd, unsigned value, unsigned mask) { unsigned old_attr, new_attr; @@ -6439,8 +6459,6 @@ int chattr_fd(int fd, unsigned value, unsigned mask) { return 1; } -/// UNNEEDED by elogind -#if 0 int chattr_path(const char *p, unsigned value, unsigned mask) { _cleanup_close_ int fd = -1; @@ -6455,7 +6473,6 @@ int chattr_path(const char *p, unsigned value, unsigned mask) { return chattr_fd(fd, value, mask); } -#endif // 0 int read_attr_fd(int fd, unsigned *ret) { struct stat st; @@ -6474,8 +6491,6 @@ int read_attr_fd(int fd, unsigned *ret) { return 0; } -/// UNNEEDED by elogind -#if 0 int read_attr_path(const char *p, unsigned *ret) { _cleanup_close_ int fd = -1; @@ -6615,7 +6630,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k for (i = 0; i < len; ++i) if (streq_ptr(table[i], key)) - return (ssize_t)i; + return (ssize_t) i; return -1; } @@ -6858,3 +6873,115 @@ int fgetxattr_malloc(int fd, const char *name, char **value) { return -errno; } } + +int send_one_fd(int transport_fd, int fd, int flags) { + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + + assert(transport_fd >= 0); + assert(fd >= 0); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); + + mh.msg_controllen = CMSG_SPACE(sizeof(int)); + if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0) + return -errno; + + return 0; +} + +/// UNNEEDED by elogind +#if 0 +int receive_one_fd(int transport_fd, int flags) { + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg, *found = NULL; + + assert(transport_fd >= 0); + + /* + * Receive a single FD via @transport_fd. We don't care for + * the transport-type. We retrieve a single FD at most, so for + * packet-based transports, the caller must ensure to send + * only a single FD per packet. This is best used in + * combination with send_one_fd(). + */ + + if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0) + return -errno; + + CMSG_FOREACH(cmsg, &mh) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS && + cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { + assert(!found); + found = cmsg; + break; + } + } + + if (!found) { + cmsg_close_all(&mh); + return -EIO; + } + + return *(int*) CMSG_DATA(found); +} + +void nop_signal_handler(int sig) { + /* nothing here */ +} +#endif // 0 + +int version(void) { + puts(PACKAGE_STRING "\n" + SYSTEMD_FEATURES); + return 0; +} + +/// UNNEEDED by elogind +#if 0 +bool fdname_is_valid(const char *s) { + const char *p; + + /* Validates a name for $LISTEN_FDNAMES. We basically allow + * everything ASCII that's not a control character. Also, as + * special exception the ":" character is not allowed, as we + * use that as field separator in $LISTEN_FDNAMES. + * + * Note that the empty string is explicitly allowed + * here. However, we limit the length of the names to 255 + * characters. */ + + if (!s) + return false; + + for (p = s; *p; p++) { + if (*p < ' ') + return false; + if (*p >= 127) + return false; + if (*p == ':') + return false; + } + + return p - s < 256; +} +#endif // 0 diff --git a/src/basic/util.h b/src/basic/util.h index 42117ed31..f55480abe 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -22,31 +22,30 @@ ***/ #include <alloca.h> +#include <dirent.h> #include <fcntl.h> #include <inttypes.h> -#include <time.h> +#include <limits.h> +#include <locale.h> +#include <mntent.h> #include <stdarg.h> #include <stdbool.h> -#include <stdlib.h> +#include <stddef.h> #include <stdio.h> -#include <sched.h> -#include <limits.h> -#include <sys/types.h> +#include <stdlib.h> +#include <sys/inotify.h> #include <sys/socket.h> #include <sys/stat.h> -#include <dirent.h> -#include <stddef.h> -#include <unistd.h> -#include <locale.h> -#include <mntent.h> -#include <sys/inotify.h> #include <sys/statfs.h> #include <sys/sysmacros.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> +#include "formats-util.h" #include "macro.h" #include "missing.h" #include "time-util.h" -#include "formats-util.h" /* What is interpreted as whitespace? */ #define WHITESPACE " \t\n\r" @@ -150,7 +149,11 @@ void safe_close_pair(int p[]); void close_many(const int fds[], unsigned n_fd); -int parse_size(const char *t, off_t base, off_t *size); +int fclose_nointr(FILE *f); +FILE* safe_fclose(FILE *f); +DIR* safe_closedir(DIR *f); + +int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_boolean(const char *v) _pure_; int parse_pid(const char *s, pid_t* ret_pid); @@ -158,7 +161,10 @@ int parse_uid(const char *s, uid_t* ret_uid); #define parse_gid(s, ret_gid) parse_uid(s, ret_gid) bool uid_is_valid(uid_t uid); -#define gid_is_valid(gid) uid_is_valid(gid) + +static inline bool gid_is_valid(gid_t gid) { + return uid_is_valid((uid_t) gid); +} int safe_atou(const char *s, unsigned *ret_u); int safe_atoi(const char *s, int *ret_i); @@ -287,9 +293,9 @@ bool chars_intersect(const char *a, const char *b) _pure_; ssize_t string_table_lookup(const char * const *table, size_t len, const char *key); -#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ - scope inline type name##_from_string(const char *s) { \ - return (type)string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ +#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ + scope type name##_from_string(const char *s) { \ + return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ } #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ @@ -306,17 +312,15 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ int name##_to_string_alloc(type i, char **str) { \ char *s; \ - int r; \ if (i < 0 || i > max) \ return -ERANGE; \ if (i < (type) ELEMENTSOF(name##_table)) { \ s = strdup(name##_table[i]); \ if (!s) \ - return log_oom(); \ + return -ENOMEM; \ } else { \ - r = asprintf(&s, "%i", i); \ - if (r < 0) \ - return log_oom(); \ + if (asprintf(&s, "%i", i) < 0) \ + return -ENOMEM; \ } \ *str = s; \ return 0; \ @@ -324,10 +328,10 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k type name##_from_string(const char *s) { \ type i; \ unsigned u = 0; \ - assert(s); \ - for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ - if (name##_table[i] && \ - streq(name##_table[i], s)) \ + if (!s) \ + return (type) -1; \ + for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \ + if (streq_ptr(name##_table[i], s)) \ return i; \ if (safe_atou(s, &u) >= 0 && u <= max) \ return (type) u; \ @@ -367,12 +371,9 @@ int fd_is_temporary_fs(int fd); int pipe_eof(int fd); -DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); -#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) - -// UNNEEDED cpu_set_t* cpu_set_malloc(unsigned *ncpus); - -#define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf)) +#define xsprintf(buf, fmt, ...) \ + assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \ + "xsprintf: " #buf "[] must be big enough") int files_same(const char *filea, const char *fileb); @@ -451,28 +452,28 @@ static inline bool _pure_ in_charset(const char *s, const char* charset) { int ioprio_class_to_string_alloc(int i, char **s); int ioprio_class_from_string(const char *s); -const char *sigchld_code_to_string(int i) _const_; -int sigchld_code_from_string(const char *s) _pure_; +// UNNEEDED const char *sigchld_code_to_string(int i) _const_; +// UNNEEDED int sigchld_code_from_string(const char *s) _pure_; -int log_facility_unshifted_to_string_alloc(int i, char **s); -int log_facility_unshifted_from_string(const char *s); +// UNNEEDED int log_facility_unshifted_to_string_alloc(int i, char **s); +// UNNEEDED int log_facility_unshifted_from_string(const char *s); int log_level_to_string_alloc(int i, char **s); int log_level_from_string(const char *s); -int sched_policy_to_string_alloc(int i, char **s); -int sched_policy_from_string(const char *s); +// UNNEEDED int sched_policy_to_string_alloc(int i, char **s); +// UNNEEDED int sched_policy_from_string(const char *s); const char *rlimit_to_string(int i) _const_; int rlimit_from_string(const char *s) _pure_; -int ip_tos_to_string_alloc(int i, char **s); -int ip_tos_from_string(const char *s); +// UNNEEDED int ip_tos_to_string_alloc(int i, char **s); +// UNNEEDED int ip_tos_from_string(const char *s); extern int saved_argc; extern char **saved_argv; -bool kexec_loaded(void); +// UNNEEDED bool kexec_loaded(void); // UNNEEDED int prot_from_flags(int flags) _const_; @@ -515,7 +516,10 @@ static inline void close_pairp(int (*p)[2]) { safe_close_pair(*p); } -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, fclose); +static inline void fclosep(FILE **f) { + safe_fclose(*f); +} + DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); @@ -872,11 +876,6 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra // UNNEEDED int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); // UNNEEDED int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; -static inline void free_and_replace(char **s, char *v) { - free(*s); - *s = v; -} - int free_and_strdup(char **p, const char *s); #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) @@ -910,10 +909,10 @@ int fd_getcrtime(int fd, usec_t *usec); // UNNEEDED int same_fd(int a, int b); -int chattr_fd(int fd, unsigned value, unsigned mask); +// UNNEEDED int chattr_fd(int fd, unsigned value, unsigned mask); // UNNEEDED int chattr_path(const char *p, unsigned value, unsigned mask); -int read_attr_fd(int fd, unsigned *ret); +// UNNEEDED int read_attr_fd(int fd, unsigned *ret); // UNNEEDED int read_attr_path(const char *p, unsigned *ret); #define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim }) @@ -940,3 +939,12 @@ int reset_uid_gid(void); int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink); int fgetxattr_malloc(int fd, const char *name, char **value); + +int send_one_fd(int transport_fd, int fd, int flags); +// UNNEEDED int receive_one_fd(int transport_fd, int flags); + +// UNNEEDED void nop_signal_handler(int sig); + +int version(void); + +// UNNEEDED bool fdname_is_valid(const char *s); diff --git a/src/basic/virt.c b/src/basic/virt.c index 1f9843bab..8e398e506 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -28,25 +28,24 @@ #include "virt.h" #include "fileio.h" -static int detect_vm_cpuid(const char **_id) { +static int detect_vm_cpuid(void) { /* Both CPUID and DMI are x86 specific interfaces... */ #if defined(__i386__) || defined(__x86_64__) - static const char cpuid_vendor_table[] = - "XenVMMXenVMM\0" "xen\0" - "KVMKVMKVM\0" "kvm\0" + static const struct { + const char *cpuid; + int id; + } cpuid_vendor_table[] = { + { "XenVMMXenVMM", VIRTUALIZATION_XEN }, + { "KVMKVMKVM", VIRTUALIZATION_KVM }, /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ - "VMwareVMware\0" "vmware\0" + { "VMwareVMware", VIRTUALIZATION_VMWARE }, /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */ - "Microsoft Hv\0" "microsoft\0"; + { "Microsoft Hv", VIRTUALIZATION_MICROSOFT }, + }; uint32_t eax, ecx; - union { - uint32_t sig32[3]; - char text[13]; - } sig = {}; - const char *j, *k; bool hypervisor; /* http://lwn.net/Articles/301888/ */ @@ -74,6 +73,11 @@ static int detect_vm_cpuid(const char **_id) { hypervisor = !!(ecx & 0x80000000U); if (hypervisor) { + union { + uint32_t sig32[3]; + char text[13]; + } sig = {}; + unsigned j; /* There is a hypervisor, see what it is */ eax = 0x40000000U; @@ -88,57 +92,54 @@ static int detect_vm_cpuid(const char **_id) { : "0" (eax) ); - NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table) - if (streq(sig.text, j)) { - *_id = k; - return 1; - } + for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++) + if (streq(sig.text, cpuid_vendor_table[j].cpuid)) + return cpuid_vendor_table[j].id; - *_id = "other"; - return 0; + return VIRTUALIZATION_VM_OTHER; } #endif - return 0; + return VIRTUALIZATION_NONE; } -static int detect_vm_devicetree(const char **_id) { +static int detect_vm_device_tree(void) { #if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__) _cleanup_free_ char *hvtype = NULL; int r; r = read_one_line_file("/proc/device-tree/hypervisor/compatible", &hvtype); - if (r >= 0) { - if (streq(hvtype, "linux,kvm")) { - *_id = "kvm"; - return 1; - } else if (strstr(hvtype, "xen")) { - *_id = "xen"; - return 1; - } - } else if (r == -ENOENT) { + if (r == -ENOENT) { _cleanup_closedir_ DIR *dir = NULL; struct dirent *dent; dir = opendir("/proc/device-tree"); if (!dir) { if (errno == ENOENT) - return 0; + return VIRTUALIZATION_NONE; return -errno; } - FOREACH_DIRENT(dent, dir, return -errno) { - if (strstr(dent->d_name, "fw-cfg")) { - *_id = "qemu"; - return 1; - } - } - } + FOREACH_DIRENT(dent, dir, return -errno) + if (strstr(dent->d_name, "fw-cfg")) + return VIRTUALIZATION_QEMU; + + return VIRTUALIZATION_NONE; + } else if (r < 0) + return r; + + if (streq(hvtype, "linux,kvm")) + return VIRTUALIZATION_KVM; + else if (strstr(hvtype, "xen")) + return VIRTUALIZATION_XEN; + else + return VIRTUALIZATION_VM_OTHER; +#else + return VIRTUALIZATION_NONE; #endif - return 0; } -static int detect_vm_dmi(const char **_id) { +static int detect_vm_dmi(void) { /* Both CPUID and DMI are x86 specific interfaces... */ #if defined(__i386__) || defined(__x86_64__) @@ -149,188 +150,195 @@ static int detect_vm_dmi(const char **_id) { "/sys/class/dmi/id/bios_vendor" }; - static const char dmi_vendor_table[] = - "QEMU\0" "qemu\0" + static const struct { + const char *vendor; + int id; + } dmi_vendor_table[] = { + { "QEMU", VIRTUALIZATION_QEMU }, /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ - "VMware\0" "vmware\0" - "VMW\0" "vmware\0" - "innotek GmbH\0" "oracle\0" - "Xen\0" "xen\0" - "Bochs\0" "bochs\0" - "Parallels\0" "parallels\0"; + { "VMware", VIRTUALIZATION_VMWARE }, + { "VMW", VIRTUALIZATION_VMWARE }, + { "innotek GmbH", VIRTUALIZATION_ORACLE }, + { "Xen", VIRTUALIZATION_XEN }, + { "Bochs", VIRTUALIZATION_BOCHS }, + { "Parallels", VIRTUALIZATION_PARALLELS }, + }; unsigned i; + int r; for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) { _cleanup_free_ char *s = NULL; - const char *j, *k; - int r; + unsigned j; r = read_one_line_file(dmi_vendors[i], &s); if (r < 0) { - if (r != -ENOENT) - return r; - + if (r == -ENOENT) continue; - } - NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table) - if (startswith(s, j)) { - *_id = k; - return 1; + return r; } + + for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++) + if (startswith(s, dmi_vendor_table[j].vendor)) + return dmi_vendor_table[j].id; } #endif - return 0; + return VIRTUALIZATION_NONE; } -/* Returns a short identifier for the various VM implementations */ -int detect_vm(const char **id) { - _cleanup_free_ char *domcap = NULL, *cpuinfo_contents = NULL; - static thread_local int cached_found = -1; - static thread_local const char *cached_id = NULL; - const char *_id = NULL, *_id_cpuid = NULL; +static int detect_vm_xen(void) { + _cleanup_free_ char *domcap = NULL; + char *cap, *i; int r; - if (_likely_(cached_found >= 0)) { - - if (id) - *id = cached_id; - - return cached_found; - } - - /* Try xen capabilities file first, if not found try high-level hypervisor sysfs file: - * - * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */ r = read_one_line_file("/proc/xen/capabilities", &domcap); - if (r >= 0) { - char *cap, *i = domcap; + if (r == -ENOENT) + return VIRTUALIZATION_NONE; + i = domcap; while ((cap = strsep(&i, ","))) if (streq(cap, "control_d")) break; - if (!cap) { - _id = "xen"; - r = 1; + return cap ? VIRTUALIZATION_NONE : VIRTUALIZATION_XEN; } - goto finish; - - } else if (r == -ENOENT) { +static int detect_vm_hypervisor(void) { _cleanup_free_ char *hvtype = NULL; + int r; r = read_one_line_file("/sys/hypervisor/type", &hvtype); - if (r >= 0) { - if (streq(hvtype, "xen")) { - _id = "xen"; - r = 1; - goto finish; - } - } else if (r != -ENOENT) - return r; - } else + if (r == -ENOENT) + return VIRTUALIZATION_NONE; + if (r < 0) return r; - /* this will set _id to "other" and return 0 for unknown hypervisors */ - r = detect_vm_cpuid(&_id); + if (streq(hvtype, "xen")) + return VIRTUALIZATION_XEN; + else + return VIRTUALIZATION_VM_OTHER; +} - /* finish when found a known hypervisor other than kvm */ - if (r < 0 || (r > 0 && !streq(_id, "kvm"))) - goto finish; +static int detect_vm_uml(void) { + _cleanup_free_ char *cpuinfo_contents = NULL; + int r; + + /* Detect User-Mode Linux by reading /proc/cpuinfo */ + r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL); + if (r < 0) + return r; + if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) + return VIRTUALIZATION_UML; - _id_cpuid = _id; + return VIRTUALIZATION_NONE; +} - r = detect_vm_dmi(&_id); +static int detect_vm_zvm(void) { - /* kvm with and without Virtualbox */ - /* Parallels exports KVMKVMKVM leaf */ - if (streq_ptr(_id_cpuid, "kvm")) { - if (r > 0 && (streq(_id, "oracle") || streq(_id, "parallels"))) - goto finish; +#if defined(__s390__) + _cleanup_free_ char *t = NULL; + int r; - _id = _id_cpuid; - r = 1; - goto finish; + r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t); + if (r == -ENOENT) + return VIRTUALIZATION_NONE; + if (r < 0) + return r; + + if (streq(t, "z/VM")) + return VIRTUALIZATION_ZVM; + else + return VIRTUALIZATION_KVM; +#else + return VIRTUALIZATION_NONE; +#endif } - /* information from dmi */ - if (r != 0) - goto finish; +/* Returns a short identifier for the various VM implementations */ +int detect_vm(void) { + static thread_local int cached_found = _VIRTUALIZATION_INVALID; + int r; - r = detect_vm_devicetree(&_id); - if (r != 0) + if (cached_found >= 0) + return cached_found; + + /* Try xen capabilities file first, if not found try + * high-level hypervisor sysfs file: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */ + + r = detect_vm_xen(); + if (r < 0) + return r; + if (r != VIRTUALIZATION_NONE) goto finish; - if (_id) { - /* "other" */ - r = 1; + r = detect_vm_dmi(); + if (r < 0) + return r; + if (r != VIRTUALIZATION_NONE) goto finish; - } - /* Detect User-Mode Linux by reading /proc/cpuinfo */ - r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL); + r = detect_vm_cpuid(); if (r < 0) return r; - if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) { - _id = "uml"; - r = 1; + if (r != VIRTUALIZATION_NONE) goto finish; - } -#if defined(__s390__) - { - _cleanup_free_ char *t = NULL; + r = detect_vm_hypervisor(); + if (r < 0) + return r; + if (r != VIRTUALIZATION_NONE) + goto finish; - r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t); - if (r >= 0) { - if (streq(t, "z/VM")) - _id = "zvm"; - else - _id = "kvm"; - r = 1; + r = detect_vm_device_tree(); + if (r < 0) + return r; + if (r != VIRTUALIZATION_NONE) + goto finish; + r = detect_vm_uml(); + if (r < 0) + return r; + if (r != VIRTUALIZATION_NONE) goto finish; - } - } -#endif - r = 0; + r = detect_vm_zvm(); + if (r < 0) + return r; finish: cached_found = r; - - cached_id = _id; - if (id) - *id = _id; - return r; } -int detect_container(const char **id) { +int detect_container(void) { - static thread_local int cached_found = -1; - static thread_local const char *cached_id = NULL; + static const struct { + const char *value; + int id; + } value_table[] = { + { "lxc", VIRTUALIZATION_LXC }, + { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT }, + { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN }, + { "docker", VIRTUALIZATION_DOCKER }, + }; + static thread_local int cached_found = _VIRTUALIZATION_INVALID; _cleanup_free_ char *m = NULL; - const char *_id = NULL, *e = NULL; + const char *e = NULL; + unsigned j; int r; - if (_likely_(cached_found >= 0)) { - - if (id) - *id = cached_id; - + if (cached_found >= 0) return cached_found; - } /* /proc/vz exists in container and outside of the container, * /proc/bc only outside of the container. */ if (access("/proc/vz", F_OK) >= 0 && access("/proc/bc", F_OK) < 0) { - _id = "openvz"; - r = 1; + r = VIRTUALIZATION_OPENVZ; goto finish; } @@ -340,7 +348,7 @@ int detect_container(const char **id) { e = getenv("container"); if (isempty(e)) { - r = 0; + r = VIRTUALIZATION_NONE; goto finish; } } else { @@ -369,7 +377,7 @@ int detect_container(const char **id) { * as /proc/1/environ is only readable * with privileges. */ - r = 0; + r = VIRTUALIZATION_NONE; goto finish; } } @@ -379,49 +387,52 @@ int detect_container(const char **id) { e = m; } - /* We only recognize a selected few here, since we want to - * enforce a redacted namespace */ - if (streq(e, "lxc")) - _id ="lxc"; - else if (streq(e, "lxc-libvirt")) - _id = "lxc-libvirt"; - else if (streq(e, "systemd-nspawn")) - _id = "systemd-nspawn"; - else if (streq(e, "docker")) - _id = "docker"; - else - _id = "other"; + for (j = 0; j < ELEMENTSOF(value_table); j++) + if (streq(e, value_table[j].value)) { + r = value_table[j].id; + goto finish; + } - r = 1; + r = VIRTUALIZATION_NONE; finish: cached_found = r; - - cached_id = _id; - if (id) - *id = _id; - return r; } /// UNNEEDED by elogind #if 0 -/* Returns a short identifier for the various VM/container implementations */ -int detect_virtualization(const char **id) { +int detect_virtualization(void) { int r; - r = detect_container(id); - if (r < 0) - return r; - if (r > 0) - return VIRTUALIZATION_CONTAINER; - - r = detect_vm(id); - if (r < 0) + r = detect_container(); + if (r != 0) return r; - if (r > 0) - return VIRTUALIZATION_VM; - return VIRTUALIZATION_NONE; + return detect_vm(); } #endif // 0 + +static const char *const virtualization_table[_VIRTUALIZATION_MAX] = { + [VIRTUALIZATION_NONE] = "none", + [VIRTUALIZATION_KVM] = "kvm", + [VIRTUALIZATION_QEMU] = "qemu", + [VIRTUALIZATION_BOCHS] = "bochs", + [VIRTUALIZATION_XEN] = "xen", + [VIRTUALIZATION_UML] = "uml", + [VIRTUALIZATION_VMWARE] = "vmware", + [VIRTUALIZATION_ORACLE] = "oracle", + [VIRTUALIZATION_MICROSOFT] = "microsoft", + [VIRTUALIZATION_ZVM] = "zvm", + [VIRTUALIZATION_PARALLELS] = "parallels", + [VIRTUALIZATION_VM_OTHER] = "vm-other", + + [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn", + [VIRTUALIZATION_LXC_LIBVIRT] = "lxc-libvirt", + [VIRTUALIZATION_LXC] = "lxc", + [VIRTUALIZATION_OPENVZ] = "openvz", + [VIRTUALIZATION_DOCKER] = "docker", + [VIRTUALIZATION_CONTAINER_OTHER] = "container-other", +}; + +DEFINE_STRING_TABLE_LOOKUP(virtualization, int); diff --git a/src/basic/virt.h b/src/basic/virt.h index 0f390981d..d63e028a2 100644 --- a/src/basic/virt.h +++ b/src/basic/virt.h @@ -21,15 +21,51 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -int detect_vm(const char **id); -int detect_container(const char **id); +#include <stdbool.h> + +#include "macro.h" enum { VIRTUALIZATION_NONE = 0, - VIRTUALIZATION_VM, - VIRTUALIZATION_CONTAINER, + + VIRTUALIZATION_VM_FIRST, + VIRTUALIZATION_KVM = VIRTUALIZATION_VM_FIRST, + VIRTUALIZATION_QEMU, + VIRTUALIZATION_BOCHS, + VIRTUALIZATION_XEN, + VIRTUALIZATION_UML, + VIRTUALIZATION_VMWARE, + VIRTUALIZATION_ORACLE, + VIRTUALIZATION_MICROSOFT, + VIRTUALIZATION_ZVM, + VIRTUALIZATION_PARALLELS, + VIRTUALIZATION_VM_OTHER, + VIRTUALIZATION_VM_LAST = VIRTUALIZATION_VM_OTHER, + + VIRTUALIZATION_CONTAINER_FIRST, + VIRTUALIZATION_SYSTEMD_NSPAWN = VIRTUALIZATION_CONTAINER_FIRST, + VIRTUALIZATION_LXC_LIBVIRT, + VIRTUALIZATION_LXC, + VIRTUALIZATION_OPENVZ, + VIRTUALIZATION_DOCKER, + VIRTUALIZATION_CONTAINER_OTHER, + VIRTUALIZATION_CONTAINER_LAST = VIRTUALIZATION_CONTAINER_OTHER, + _VIRTUALIZATION_MAX, _VIRTUALIZATION_INVALID = -1 }; -// UNNEEDED int detect_virtualization(const char **id); +static inline bool VIRTUALIZATION_IS_VM(int x) { + return x >= VIRTUALIZATION_VM_FIRST && x <= VIRTUALIZATION_VM_LAST; +} + +static inline bool VIRTUALIZATION_IS_CONTAINER(int x) { + return x >= VIRTUALIZATION_CONTAINER_FIRST && x <= VIRTUALIZATION_CONTAINER_LAST; +} + +int detect_vm(void); +int detect_container(void); +// UNNEEDED int detect_virtualization(void); + +const char *virtualization_to_string(int v) _const_; +int virtualization_from_string(const char *s) _pure_; |