diff options
Diffstat (limited to 'src')
134 files changed, 3460 insertions, 2196 deletions
diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index adc9286612..6d53dd982c 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -34,6 +34,7 @@ static const char *arg_keyname = NULL; static char *arg_message = NULL; static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; static bool arg_multiple = false; +static bool arg_no_output = false; static AskPasswordFlags arg_flags = ASK_PASSWORD_PUSH_CACHE; static void help(void) { @@ -48,6 +49,7 @@ static void help(void) { " --no-tty Ask question via agent even on TTY\n" " --accept-cached Accept cached passwords\n" " --multiple List multiple passwords if available\n" + " --no-output Do not print password to standard output\n" , program_invocation_short_name); } @@ -62,6 +64,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_MULTIPLE, ARG_ID, ARG_KEYNAME, + ARG_NO_OUTPUT, }; static const struct option options[] = { @@ -74,6 +77,7 @@ static int parse_argv(int argc, char *argv[]) { { "multiple", no_argument, NULL, ARG_MULTIPLE }, { "id", required_argument, NULL, ARG_ID }, { "keyname", required_argument, NULL, ARG_KEYNAME }, + { "no-output", no_argument, NULL, ARG_NO_OUTPUT }, {} }; @@ -125,6 +129,10 @@ static int parse_argv(int argc, char *argv[]) { arg_keyname = optarg; break; + case ARG_NO_OUTPUT: + arg_no_output = true; + break; + case '?': return -EINVAL; @@ -166,7 +174,8 @@ int main(int argc, char *argv[]) { } STRV_FOREACH(p, l) { - puts(*p); + if (!arg_no_output) + puts(*p); if (!arg_multiple) break; diff --git a/src/basic/c-rbtree.c b/src/basic/c-rbtree.c index 914d7e5229..cf5a7242df 100644 --- a/src/basic/c-rbtree.c +++ b/src/basic/c-rbtree.c @@ -195,11 +195,6 @@ static inline void c_rbnode_set_parent_and_color(CRBNode *n, CRBNode *p, unsigne n->__parent_and_color = (CRBNode*)((unsigned long)p | c); } -/* same as c_rbnode_set_parent_and_color(), but keeps the current parent */ -static inline void c_rbnode_set_color(CRBNode *n, unsigned long c) { - c_rbnode_set_parent_and_color(n, c_rbnode_parent(n), c); -} - /* same as c_rbnode_set_parent_and_color(), but keeps the current color */ static inline void c_rbnode_set_parent(CRBNode *n, CRBNode *p) { c_rbnode_set_parent_and_color(n, p, c_rbnode_color(n)); diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index 507e757ff0..7fe8d35ea5 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -69,9 +69,12 @@ int clock_set_hwclock(const struct tm *tm) { return 0; } -int clock_is_localtime(void) { +int clock_is_localtime(const char* adjtime_path) { _cleanup_fclose_ FILE *f; + if (adjtime_path == NULL) + adjtime_path = "/etc/adjtime"; + /* * The third line of adjtime is "UTC" or "LOCAL" or nothing. * # /etc/adjtime @@ -79,7 +82,7 @@ int clock_is_localtime(void) { * 0 * UTC */ - f = fopen("/etc/adjtime", "re"); + f = fopen(adjtime_path, "re"); if (f) { char line[LINE_MAX]; bool b; @@ -88,7 +91,8 @@ int clock_is_localtime(void) { fgets(line, sizeof(line), f) && fgets(line, sizeof(line), f); if (!b) - return -EIO; + /* less than three lines -> default to UTC */ + return 0; truncate_nl(line); return streq(line, "LOCAL"); @@ -96,6 +100,7 @@ int clock_is_localtime(void) { } else if (errno != ENOENT) return -errno; + /* adjtime not present -> default to UTC */ return 0; } diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h index f471f2abcf..8830cd2f38 100644 --- a/src/basic/clock-util.h +++ b/src/basic/clock-util.h @@ -21,7 +21,7 @@ #include <time.h> -int clock_is_localtime(void); +int clock_is_localtime(const char* adjtime_path); int clock_set_timezone(int *min); int clock_reset_timewarp(void); int clock_get_hwclock(struct tm *tm); diff --git a/src/basic/copy.c b/src/basic/copy.c index 519b412941..41dc8ca79a 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -40,17 +40,38 @@ #include "fs-util.h" #include "io-util.h" #include "macro.h" +#include "missing.h" #include "string-util.h" #include "strv.h" #include "time-util.h" #include "umask-util.h" #include "xattr-util.h" -#define COPY_BUFFER_SIZE (16*1024) +#define COPY_BUFFER_SIZE (16*1024u) + +static ssize_t try_copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { + static int have = -1; + ssize_t r; + + if (have == false) + return -ENOSYS; + + r = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags); + if (_unlikely_(have < 0)) + have = r >= 0 || errno != ENOSYS; + if (r >= 0) + return r; + else + return -errno; +} int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { - bool try_sendfile = true, try_splice = true; + bool try_cfr = true, try_sendfile = true, try_splice = true; int r; + size_t m = SSIZE_MAX; /* that the maximum that sendfile and c_f_r accept */ assert(fdf >= 0); assert(fdt >= 0); @@ -67,11 +88,9 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { } for (;;) { - size_t m = COPY_BUFFER_SIZE; ssize_t n; if (max_bytes != (uint64_t) -1) { - if (max_bytes <= 0) return 1; /* return > 0 if we hit the max_bytes limit */ @@ -79,44 +98,59 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { m = (size_t) max_bytes; } + /* First try copy_file_range(), unless we already tried */ + if (try_cfr) { + n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u); + if (n < 0) { + if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV)) + return n; + + try_cfr = false; + /* use fallback below */ + } else if (n == 0) /* EOF */ + break; + else + /* Success! */ + goto next; + } + /* First try sendfile(), unless we already tried */ if (try_sendfile) { - n = sendfile(fdt, fdf, NULL, m); if (n < 0) { - if (errno != EINVAL && errno != ENOSYS) + if (!IN_SET(errno, EINVAL, ENOSYS)) return -errno; try_sendfile = false; /* use fallback below */ } else if (n == 0) /* EOF */ break; - else if (n > 0) + else /* Success! */ goto next; } - /* The try splice, unless we already tried */ + /* Then try splice, unless we already tried */ if (try_splice) { n = splice(fdf, NULL, fdt, NULL, m, 0); if (n < 0) { - if (errno != EINVAL && errno != ENOSYS) + if (!IN_SET(errno, EINVAL, ENOSYS)) return -errno; try_splice = false; /* use fallback below */ } else if (n == 0) /* EOF */ break; - else if (n > 0) + else /* Success! */ goto next; } /* As a fallback just copy bits by hand */ { - uint8_t buf[m]; + uint8_t buf[MIN(m, COPY_BUFFER_SIZE)]; - n = read(fdf, buf, m); + n = read(fdf, buf, sizeof buf); if (n < 0) return -errno; if (n == 0) /* EOF */ @@ -132,6 +166,11 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) { assert(max_bytes >= (uint64_t) n); max_bytes -= n; } + /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, + * so reduce our maximum by the amount we already copied, + * but don't go below our copy buffer size, unless we are + * close the the limit of bytes we are allowed to copy. */ + m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n); } return 0; /* return 0 if we hit EOF earlier than the size limit */ diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 2c454e8ea2..69590941e5 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -588,7 +588,7 @@ static int parse_env_file_push( va_list aq, *ap = userdata; if (!utf8_is_valid(key)) { - _cleanup_free_ char *p; + _cleanup_free_ char *p = NULL; p = utf8_escape_invalid(key); log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p); @@ -596,7 +596,7 @@ static int parse_env_file_push( } if (value && !utf8_is_valid(value)) { - _cleanup_free_ char *p; + _cleanup_free_ char *p = NULL; p = utf8_escape_invalid(value); log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p); @@ -1069,7 +1069,7 @@ int fflush_and_check(FILE *f) { /* This is much like like mkostemp() but is subject to umask(). */ int mkostemp_safe(char *pattern, int flags) { - _cleanup_umask_ mode_t u; + _cleanup_umask_ mode_t u = 0; int fd; assert(pattern); diff --git a/src/basic/formats-util.h b/src/basic/formats-util.h index ce516b117d..9b4e8e98fa 100644 --- a/src/basic/formats-util.h +++ b/src/basic/formats-util.h @@ -49,7 +49,7 @@ #if SIZEOF_TIME_T == 8 # define PRI_TIME PRIi64 #elif SIZEOF_TIME_T == 4 -# define PRI_TIME PRIu32 +# define PRI_TIME "li" #else # error Unknown time_t size #endif diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 6f1a049d47..85b8d812b3 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -176,7 +176,7 @@ enum HashmapType { }; struct _packed_ indirect_storage { - char *storage; /* where buckets and DIBs are stored */ + void *storage; /* where buckets and DIBs are stored */ uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */ unsigned n_entries; /* number of stored entries */ @@ -193,7 +193,7 @@ struct direct_storage { /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit. * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit, * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */ - char storage[sizeof(struct indirect_storage)]; + uint8_t storage[sizeof(struct indirect_storage)]; }; #define DIRECT_BUCKETS(entry_t) \ @@ -302,7 +302,7 @@ static void n_entries_dec(HashmapBase *h) { h->n_direct_entries--; } -static char *storage_ptr(HashmapBase *h) { +static void *storage_ptr(HashmapBase *h) { return h->has_indirect ? h->indirect.storage : h->direct.storage; } @@ -347,7 +347,7 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) { return (struct hashmap_base_entry*) - (storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); + ((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); } static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) { @@ -381,7 +381,7 @@ static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_ static dib_raw_t *dib_raw_ptr(HashmapBase *h) { return (dib_raw_t*) - (storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h)); + ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h)); } static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) { @@ -1028,7 +1028,7 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx, */ static int resize_buckets(HashmapBase *h, unsigned entries_add) { struct swap_entries swap; - char *new_storage; + void *new_storage; dib_raw_t *old_dibs, *new_dibs; const struct hashmap_type_info *hi; unsigned idx, optimal_idx; @@ -1095,7 +1095,7 @@ static int resize_buckets(HashmapBase *h, unsigned entries_add) { h->indirect.n_buckets = (1U << new_shift) / (hi->entry_size + sizeof(dib_raw_t)); - old_dibs = (dib_raw_t*)(new_storage + hi->entry_size * old_n_buckets); + old_dibs = (dib_raw_t*)((uint8_t*) new_storage + hi->entry_size * old_n_buckets); new_dibs = dib_raw_ptr(h); /* diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 3cd2f2c872..5a7ee87a20 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -150,6 +150,8 @@ char* hostname_cleanup(char *s) { assert(s); + strshorten(s, HOST_NAME_MAX); + for (p = s, d = s, dot = true; *p; p++) { if (*p == '.') { if (dot) @@ -169,8 +171,6 @@ char* hostname_cleanup(char *s) { else *d = 0; - strshorten(s, HOST_NAME_MAX); - return s; } diff --git a/src/basic/log.h b/src/basic/log.h index f9fb1742a1..b6356228d9 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -246,5 +246,4 @@ int log_syntax_internal( 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 ddf0968d1b..e41aa4260f 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -23,10 +23,15 @@ #include <inttypes.h> #include <stdbool.h> #include <sys/param.h> +#include <sys/sysmacros.h> #include <sys/types.h> #define _printf_(a,b) __attribute__ ((format (printf, a, b))) -#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) +#ifdef __clang__ +# define _alloc_(...) +#else +# define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) +#endif #define _sentinel_ __attribute__ ((sentinel)) #define _unused_ __attribute__ ((unused)) #define _destructor_ __attribute__ ((destructor)) @@ -361,6 +366,12 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { _found; \ }) +#define SWAP_TWO(x, y) do { \ + typeof(x) _t = (x); \ + (x) = (y); \ + (y) = (_t); \ + } while (false) + /* Define C11 thread_local attribute even on older gcc compiler * version */ #ifndef thread_local diff --git a/src/basic/missing.h b/src/basic/missing.h index 417604aa64..034e334e66 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -135,84 +135,6 @@ #define SOL_SCTP 132 #endif -#if !HAVE_DECL_PIVOT_ROOT -static inline int pivot_root(const char *new_root, const char *put_old) { - return syscall(SYS_pivot_root, new_root, put_old); -} -#endif - -#ifndef __NR_memfd_create -# if defined __x86_64__ -# define __NR_memfd_create 319 -# elif defined __arm__ -# 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 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_memfd_create 6318 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_memfd_create 5314 -# endif -# elif defined __i386__ -# define __NR_memfd_create 356 -# else -# warning "__NR_memfd_create unknown for your architecture" -# define __NR_memfd_create 0xffffffff -# endif -#endif - -#if !HAVE_DECL_MEMFD_CREATE -static inline int memfd_create(const char *name, unsigned int flags) { - return syscall(__NR_memfd_create, name, flags); -} -#endif - -#ifndef __NR_getrandom -# if defined __x86_64__ -# define __NR_getrandom 318 -# elif defined(__i386__) -# define __NR_getrandom 355 -# elif defined(__arm__) -# define __NR_getrandom 384 -# elif defined(__aarch64__) -# define __NR_getrandom 278 -# elif defined(__ia64__) -# define __NR_getrandom 1339 -# elif defined(__m68k__) -# define __NR_getrandom 352 -# elif defined(__s390x__) -# define __NR_getrandom 349 -# elif defined(__powerpc__) -# define __NR_getrandom 359 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_getrandom 4353 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_getrandom 6317 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_getrandom 5313 -# endif -# else -# warning "__NR_getrandom unknown for your architecture" -# define __NR_getrandom 0xffffffff -# endif -#endif - -#if !HAVE_DECL_GETRANDOM -static inline int getrandom(void *buffer, size_t count, unsigned flags) { - return syscall(__NR_getrandom, buffer, count, flags); -} -#endif - #ifndef GRND_NONBLOCK #define GRND_NONBLOCK 0x0001 #endif @@ -527,12 +449,6 @@ struct btrfs_ioctl_quota_ctl_args { #define MS_PRIVATE (1 << 18) #endif -#if !HAVE_DECL_GETTID -static inline pid_t gettid(void) { - return (pid_t) syscall(SYS_gettid); -} -#endif - #ifndef SCM_SECURITY #define SCM_SECURITY 0x03 #endif @@ -561,32 +477,6 @@ static inline pid_t gettid(void) { #define MAX_HANDLE_SZ 128 #endif -#ifndef __NR_name_to_handle_at -# if defined(__x86_64__) -# define __NR_name_to_handle_at 303 -# elif defined(__i386__) -# define __NR_name_to_handle_at 341 -# elif defined(__arm__) -# define __NR_name_to_handle_at 370 -# elif defined(__powerpc__) -# define __NR_name_to_handle_at 345 -# else -# error "__NR_name_to_handle_at is not defined" -# endif -#endif - -#if !HAVE_DECL_NAME_TO_HANDLE_AT -struct file_handle { - unsigned int handle_bytes; - int handle_type; - unsigned char f_handle[0]; -}; - -static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { - return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); -} -#endif - #ifndef HAVE_SECURE_GETENV # ifdef HAVE___SECURE_GETENV # define secure_getenv __secure_getenv @@ -635,22 +525,6 @@ static inline int name_to_handle_at(int fd, const char *name, struct file_handle #endif -#ifndef __NR_setns -# if defined(__x86_64__) -# define __NR_setns 308 -# elif defined(__i386__) -# define __NR_setns 346 -# else -# error "__NR_setns is not defined" -# endif -#endif - -#if !HAVE_DECL_SETNS -static inline int setns(int fd, int nstype) { - return syscall(__NR_setns, fd, nstype); -} -#endif - #if !HAVE_DECL_LO_FLAGS_PARTSCAN #define LO_FLAGS_PARTSCAN 8 #endif @@ -1018,69 +892,10 @@ static inline int setns(int fd, int nstype) { #define CAP_AUDIT_READ 37 #endif -static inline int raw_clone(unsigned long flags, void *child_stack) { -#if defined(__s390__) || defined(__CRIS__) - /* On s390 and cris the order of the first and second arguments - * of the raw clone() system call is reversed. */ - return (int) syscall(__NR_clone, child_stack, flags); -#else - return (int) syscall(__NR_clone, flags, child_stack); -#endif -} - -static inline pid_t raw_getpid(void) { -#if defined(__alpha__) - return (pid_t) syscall(__NR_getxpid); -#else - return (pid_t) syscall(__NR_getpid); -#endif -} - -#if !HAVE_DECL_RENAMEAT2 - -#ifndef __NR_renameat2 -# if defined __x86_64__ -# define __NR_renameat2 316 -# elif defined __arm__ -# define __NR_renameat2 382 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define __NR_renameat2 4351 -# endif -# if _MIPS_SIM == _MIPS_SIM_NABI32 -# define __NR_renameat2 6315 -# endif -# if _MIPS_SIM == _MIPS_SIM_ABI64 -# define __NR_renameat2 5311 -# endif -# elif defined __i386__ -# define __NR_renameat2 353 -# else -# warning "__NR_renameat2 unknown for your architecture" -# define __NR_renameat2 0xffffffff -# endif -#endif - -static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { - return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); -} -#endif - #ifndef RENAME_NOREPLACE #define RENAME_NOREPLACE (1 << 0) #endif -#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 - #ifndef KCMP_FILE #define KCMP_FILE 0 #endif @@ -1097,35 +912,6 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns 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 @@ -1177,3 +963,5 @@ static inline key_serial_t request_key(const char *type, const char *description #endif #endif + +#include "missing_syscall.h" diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h new file mode 100644 index 0000000000..d502d3b9ca --- /dev/null +++ b/src/basic/missing_syscall.h @@ -0,0 +1,310 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +/* Missing glibc definitions to access certain kernel APIs */ + +#if !HAVE_DECL_PIVOT_ROOT +static inline int pivot_root(const char *new_root, const char *put_old) { + return syscall(SYS_pivot_root, new_root, put_old); +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_MEMFD_CREATE +# ifndef __NR_memfd_create +# if defined __x86_64__ +# define __NR_memfd_create 319 +# elif defined __arm__ +# 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 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_memfd_create 6318 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_memfd_create 5314 +# endif +# elif defined __i386__ +# define __NR_memfd_create 356 +# else +# warning "__NR_memfd_create unknown for your architecture" +# endif +# endif + +static inline int memfd_create(const char *name, unsigned int flags) { +# ifdef __NR_memfd_create + return syscall(__NR_memfd_create, name, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_GETRANDOM +# ifndef __NR_getrandom +# if defined __x86_64__ +# define __NR_getrandom 318 +# elif defined(__i386__) +# define __NR_getrandom 355 +# elif defined(__arm__) +# define __NR_getrandom 384 +# elif defined(__aarch64__) +# define __NR_getrandom 278 +# elif defined(__ia64__) +# define __NR_getrandom 1339 +# elif defined(__m68k__) +# define __NR_getrandom 352 +# elif defined(__s390x__) +# define __NR_getrandom 349 +# elif defined(__powerpc__) +# define __NR_getrandom 359 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_getrandom 4353 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_getrandom 6317 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_getrandom 5313 +# endif +# else +# warning "__NR_getrandom unknown for your architecture" +# endif +# endif + +static inline int getrandom(void *buffer, size_t count, unsigned flags) { +# ifdef __NR_getrandom + return syscall(__NR_getrandom, buffer, count, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_GETTID +static inline pid_t gettid(void) { + return (pid_t) syscall(SYS_gettid); +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_NAME_TO_HANDLE_AT +# ifndef __NR_name_to_handle_at +# if defined(__x86_64__) +# define __NR_name_to_handle_at 303 +# elif defined(__i386__) +# define __NR_name_to_handle_at 341 +# elif defined(__arm__) +# define __NR_name_to_handle_at 370 +# elif defined(__powerpc__) +# define __NR_name_to_handle_at 345 +# else +# error "__NR_name_to_handle_at is not defined" +# endif +# endif + +struct file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char f_handle[0]; +}; + +static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) { +# ifdef __NR_name_to_handle_at + return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_SETNS +# ifndef __NR_setns +# if defined(__x86_64__) +# define __NR_setns 308 +# elif defined(__i386__) +# define __NR_setns 346 +# else +# error "__NR_setns is not defined" +# endif +# endif + +static inline int setns(int fd, int nstype) { +# ifdef __NR_setns + return syscall(__NR_setns, fd, nstype); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +static inline int raw_clone(unsigned long flags, void *child_stack) { +#if defined(__s390__) || defined(__CRIS__) + /* On s390 and cris the order of the first and second arguments + * of the raw clone() system call is reversed. */ + return (int) syscall(__NR_clone, child_stack, flags); +#else + return (int) syscall(__NR_clone, flags, child_stack); +#endif +} + +/* ======================================================================= */ + +static inline pid_t raw_getpid(void) { +#if defined(__alpha__) + return (pid_t) syscall(__NR_getxpid); +#else + return (pid_t) syscall(__NR_getpid); +#endif +} + +/* ======================================================================= */ + +#if !HAVE_DECL_RENAMEAT2 +# ifndef __NR_renameat2 +# if defined __x86_64__ +# define __NR_renameat2 316 +# elif defined __arm__ +# define __NR_renameat2 382 +# elif defined _MIPS_SIM +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define __NR_renameat2 4351 +# endif +# if _MIPS_SIM == _MIPS_SIM_NABI32 +# define __NR_renameat2 6315 +# endif +# if _MIPS_SIM == _MIPS_SIM_ABI64 +# define __NR_renameat2 5311 +# endif +# elif defined __i386__ +# define __NR_renameat2 353 +# else +# warning "__NR_renameat2 unknown for your architecture" +# endif +# endif + +static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { +# ifdef __NR_renameat2 + return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_KCMP +static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { +# ifdef __NR_kcmp + return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_KEYCTL +static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) { +# ifdef __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) { +# ifdef __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) { +# ifdef __NR_request_key + return syscall(__NR_request_key, type, description, callout_info, destringid); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif + +/* ======================================================================= */ + +#if !HAVE_DECL_COPY_FILE_RANGE +# ifndef __NR_copy_file_range +# if defined(__x86_64__) +# define __NR_copy_file_range 326 +# elif defined(__i386__) +# define __NR_copy_file_range 377 +# elif defined __s390__ +# define __NR_copy_file_range 375 +# elif defined __arm__ +# define __NR_copy_file_range 391 +# elif defined __aarch64__ +# define __NR_copy_file_range 285 +# else +# warning "__NR_copy_file_range not defined for your architecture" +# endif +# endif + +static inline ssize_t copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { +# ifdef __NR_copy_file_range + return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 33f2ee96d8..5faa2eba05 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -47,7 +47,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id if ((flags & AT_EMPTY_PATH) && isempty(filename)) xsprintf(path, "/proc/self/fdinfo/%i", fd); else { - subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); + subfd = openat(fd, filename, O_CLOEXEC|O_PATH); if (subfd < 0) return -errno; @@ -230,7 +230,7 @@ int path_is_mount_point(const char *t, int flags) { if (!parent) return -ENOMEM; - fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); + fd = openat(AT_FDCWD, parent, O_DIRECTORY|O_CLOEXEC|O_PATH); if (fd < 0) return -errno; diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 6c63b9d652..10c2f39369 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -80,31 +80,23 @@ void mac_selinux_retest(void) { #endif } -int mac_selinux_init(const char *prefix) { +int mac_selinux_init(void) { int r = 0; #ifdef HAVE_SELINUX usec_t before_timestamp, after_timestamp; struct mallinfo before_mallinfo, after_mallinfo; - if (!mac_selinux_use()) + if (label_hnd) return 0; - if (label_hnd) + if (!mac_selinux_use()) return 0; before_mallinfo = mallinfo(); before_timestamp = now(CLOCK_MONOTONIC); - if (prefix) { - struct selinux_opt options[] = { - { .type = SELABEL_OPT_SUBSET, .value = prefix }, - }; - - label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options)); - } else - label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); - + label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); if (!label_hnd) { log_enforcing("Failed to initialize SELinux context: %m"); r = security_getenforce() == 1 ? -errno : 0; @@ -160,7 +152,7 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { return 0; if (r >= 0) { - r = lsetfilecon(path, fcon); + r = lsetfilecon_raw(path, fcon); /* If the FS doesn't support labels, then exit without warning */ if (r < 0 && errno == EOPNOTSUPP) @@ -225,7 +217,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) { return -errno; sclass = string_to_security_class("process"); - r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); + r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label); if (r < 0) return -errno; #endif @@ -270,7 +262,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * if (r < 0) return -errno; - r = getpeercon(socket_fd, &peercon); + r = getpeercon_raw(socket_fd, &peercon); if (r < 0) return -errno; @@ -304,7 +296,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * return -ENOMEM; sclass = string_to_security_class("process"); - r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label); + r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label); if (r < 0) return -errno; #endif @@ -358,7 +350,7 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) { log_enforcing("Failed to determine SELinux security context for %s: %m", path); } else { - if (setfscreatecon(filecon) >= 0) + if (setfscreatecon_raw(filecon) >= 0) return 0; /* Success! */ log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path); @@ -379,7 +371,7 @@ void mac_selinux_create_file_clear(void) { if (!mac_selinux_use()) return; - setfscreatecon(NULL); + setfscreatecon_raw(NULL); #endif } @@ -410,7 +402,7 @@ void mac_selinux_create_socket_clear(void) { if (!mac_selinux_use()) return; - setsockcreatecon(NULL); + setsockcreatecon_raw(NULL); #endif } @@ -469,7 +461,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { return -errno; } else { - if (setfscreatecon(fcon) < 0) { + if (setfscreatecon_raw(fcon) < 0) { log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path); if (security_getenforce() > 0) return -errno; @@ -480,7 +472,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { r = bind(fd, addr, addrlen) < 0 ? -errno : 0; if (context_changed) - setfscreatecon(NULL); + setfscreatecon_raw(NULL); return r; diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 27e8edb41b..ce6bc8e44c 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -29,7 +29,7 @@ bool mac_selinux_use(void); bool mac_selinux_have(void); void mac_selinux_retest(void); -int mac_selinux_init(const char *prefix); +int mac_selinux_init(void); void mac_selinux_finish(void); int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs); diff --git a/src/basic/set.h b/src/basic/set.h index 2bff5062da..e0d9dd001c 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -126,6 +126,9 @@ int set_put_strdupv(Set *s, char **l); #define SET_FOREACH(e, s, i) \ for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); ) +#define SET_FOREACH_MOVE(e, d, s) \ + for (; ({ e = set_first(s); assert_se(!e || set_move_one(d, s, e) >= 0); e; }); ) + DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 35e9573aa4..6d1dc83874 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -23,7 +23,6 @@ #include <stddef.h> #include <string.h> #include <sys/socket.h> -#include <sys/stat.h> #include <sys/un.h> #include <unistd.h> @@ -35,6 +34,7 @@ #include "mkdir.h" #include "selinux-util.h" #include "socket-util.h" +#include "umask-util.h" int socket_address_listen( const SocketAddress *a, @@ -112,28 +112,24 @@ int socket_address_listen( return -errno; if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) { - mode_t old_mask; - /* Create parents */ - mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode); + (void) mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode); /* Enforce the right access mode for the socket */ - old_mask = umask(~ socket_mode); - - r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); - - if (r < 0 && errno == EADDRINUSE) { - /* Unlink and try again */ - unlink(a->sockaddr.un.sun_path); - r = bind(fd, &a->sockaddr.sa, a->size); + RUN_WITH_UMASK(~socket_mode) { + r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size); + if (r == -EADDRINUSE) { + /* Unlink and try again */ + unlink(a->sockaddr.un.sun_path); + if (bind(fd, &a->sockaddr.sa, a->size) < 0) + return -errno; + } else if (r < 0) + return r; } - - umask(old_mask); - } else - r = bind(fd, &a->sockaddr.sa, a->size); - - if (r < 0) - return -errno; + } else { + if (bind(fd, &a->sockaddr.sa, a->size) < 0) + return -errno; + } if (socket_address_can_accept(a)) if (listen(fd, backlog) < 0) diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 7ca764abeb..c16460a198 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -47,12 +47,15 @@ static clockid_t map_clock_id(clockid_t c) { /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on - * those archs. */ + * those archs. + * + * Also, older kernels don't support CLOCK_BOOTTIME: fall back to CLOCK_MONOTONIC. */ switch (c) { + case CLOCK_BOOTTIME: case CLOCK_BOOTTIME_ALARM: - return CLOCK_BOOTTIME; + return clock_boottime_or_monotonic (); case CLOCK_REALTIME_ALARM: return CLOCK_REALTIME; diff --git a/src/basic/util.h b/src/basic/util.h index e095254b57..286db05159 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -36,6 +36,7 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/statfs.h> +#include <sys/sysmacros.h> #include <sys/types.h> #include <time.h> #include <unistd.h> diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index 8d7f14f382..8256899eda 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -110,7 +110,7 @@ ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ - fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); + fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); if (fd < 0) return -errno; diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index f939196397..00372b92b4 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -139,7 +139,7 @@ static int property_get_tainted( if (access("/proc/cgroups", F_OK) < 0) e = stpcpy(e, "cgroups-missing:"); - if (clock_is_localtime() > 0) + if (clock_is_localtime(NULL) > 0) e = stpcpy(e, "local-hwclock:"); /* remove the last ':' */ diff --git a/src/core/device.c b/src/core/device.c index d201dc5e4b..28e4039da2 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -318,7 +318,7 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa * the GC to have garbaged it. That's desired since the device * unit may have a dependency on the mount unit which was * added during the loading of the later. */ - if (u && DEVICE(u)->state == DEVICE_PLUGGED) { + if (dev && u && DEVICE(u)->state == DEVICE_PLUGGED) { /* This unit is in plugged state: we're sure it's * attached to a device. */ if (!path_equal(DEVICE(u)->sysfs, sysfs)) { diff --git a/src/core/execute.c b/src/core/execute.c index 0c311ec330..ac2ac39892 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1882,7 +1882,7 @@ static int exec_child( * also to the context secure_bits so that we don't try to * drop the bit away next. */ - secure_bits |= 1<<SECURE_KEEP_CAPS; + secure_bits |= 1<<SECURE_KEEP_CAPS; } } diff --git a/src/core/failure-action.c b/src/core/failure-action.c index 39f5519ca1..bb2bc3f399 100644 --- a/src/core/failure-action.c +++ b/src/core/failure-action.c @@ -62,7 +62,8 @@ int failure_action( log_and_status(m, "Rebooting as result of failure."); update_reboot_param_file(reboot_arg); - (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, NULL); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, + JOB_REPLACE_IRREVERSIBLY, NULL); break; @@ -89,7 +90,8 @@ int failure_action( case FAILURE_ACTION_POWEROFF: log_and_status(m, "Powering off as result of failure."); - (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, NULL); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, + JOB_REPLACE_IRREVERSIBLY, NULL); break; case FAILURE_ACTION_POWEROFF_FORCE: diff --git a/src/core/job.c b/src/core/job.c index 012cf72d1f..719cb0a3e5 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -690,17 +690,20 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR } static void job_print_status_message(Unit *u, JobType t, JobResult result) { - static const char* const job_result_status_table[_JOB_RESULT_MAX] = { - [JOB_DONE] = ANSI_GREEN " OK " ANSI_NORMAL, - [JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED " TIME " ANSI_NORMAL, - [JOB_FAILED] = ANSI_HIGHLIGHT_RED "FAILED" ANSI_NORMAL, - [JOB_DEPENDENCY] = ANSI_HIGHLIGHT_YELLOW "DEPEND" ANSI_NORMAL, - [JOB_SKIPPED] = ANSI_HIGHLIGHT " INFO " ANSI_NORMAL, - [JOB_ASSERT] = ANSI_HIGHLIGHT_YELLOW "ASSERT" ANSI_NORMAL, - [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW "UNSUPP" ANSI_NORMAL, + static struct { + const char *color, *word; + } const statuses[_JOB_RESULT_MAX] = { + [JOB_DONE] = {ANSI_GREEN, " OK "}, + [JOB_TIMEOUT] = {ANSI_HIGHLIGHT_RED, " TIME "}, + [JOB_FAILED] = {ANSI_HIGHLIGHT_RED, "FAILED"}, + [JOB_DEPENDENCY] = {ANSI_HIGHLIGHT_YELLOW, "DEPEND"}, + [JOB_SKIPPED] = {ANSI_HIGHLIGHT, " INFO "}, + [JOB_ASSERT] = {ANSI_HIGHLIGHT_YELLOW, "ASSERT"}, + [JOB_UNSUPPORTED] = {ANSI_HIGHLIGHT_YELLOW, "UNSUPP"}, }; const char *format; + const char *status; assert(u); assert(t >= 0); @@ -714,11 +717,16 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { if (!format) return; + if (log_get_show_color()) + status = strjoina(statuses[result].color, statuses[result].word, ANSI_NORMAL); + else + status = statuses[result].word; + if (result != JOB_DONE) manager_flip_auto_status(u->manager, true); DISABLE_WARNING_FORMAT_NONLITERAL; - unit_status_printf(u, job_result_status_table[result], format); + unit_status_printf(u, status, format); REENABLE_WARNING; if (t == JOB_START && result == JOB_FAILED) { diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index e1bfdccbca..d078924c5b 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -3507,7 +3507,19 @@ static int merge_by_names(Unit **u, Set *names, const char *id) { * ours? Then let's try it the other way * round */ - other = manager_get_unit((*u)->manager, k); + /* If the symlink name we are looking at is unit template, then + we must search for instance of this template */ + if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE)) { + _cleanup_free_ char *instance = NULL; + + r = unit_name_replace_instance(k, (*u)->instance, &instance); + if (r < 0) + return r; + + other = manager_get_unit((*u)->manager, instance); + } else + other = manager_get_unit((*u)->manager, k); + free(k); if (other) { diff --git a/src/core/main.c b/src/core/main.c index b4e96fd6f4..78701805ea 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1218,10 +1218,15 @@ static int status_welcome(void) { if (r < 0 && r != -ENOENT) log_warning_errno(r, "Failed to read os-release file: %m"); - return status_printf(NULL, false, false, - "\nWelcome to \x1B[%sm%s\x1B[0m!\n", - isempty(ansi_color) ? "1" : ansi_color, - isempty(pretty_name) ? "Linux" : pretty_name); + if (log_get_show_color()) + return status_printf(NULL, false, false, + "\nWelcome to \x1B[%sm%s\x1B[0m!\n", + isempty(ansi_color) ? "1" : ansi_color, + isempty(pretty_name) ? "Linux" : pretty_name); + else + return status_printf(NULL, false, false, + "\nWelcome to %s!\n", + isempty(pretty_name) ? "Linux" : pretty_name); } static int write_container_id(void) { @@ -1369,13 +1374,13 @@ int main(int argc, char *argv[]) { dual_timestamp_get(&security_finish_timestamp); } - if (mac_selinux_init(NULL) < 0) { + if (mac_selinux_init() < 0) { error_message = "Failed to initialize SELinux policy"; goto finish; } if (!skip_setup) { - if (clock_is_localtime() > 0) { + if (clock_is_localtime(NULL) > 0) { int min; /* @@ -1435,9 +1440,7 @@ int main(int argc, char *argv[]) { /* clear the kernel timestamp, * because we are in a container */ - kernel_timestamp.monotonic = 0ULL; - kernel_timestamp.realtime = 0ULL; - + kernel_timestamp = DUAL_TIMESTAMP_NULL; } else { /* Running as user instance */ arg_running_as = MANAGER_USER; diff --git a/src/core/mount.c b/src/core/mount.c index 93d2bd595c..0fd880df5d 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -104,6 +104,14 @@ static bool mount_is_auto(const MountParameters *p) { return !fstab_test_option(p->options, "noauto\0"); } +static bool mount_is_automount(const MountParameters *p) { + assert(p); + + return fstab_test_option(p->options, + "comment=systemd.automount\0" + "x-systemd.automount\0"); +} + static bool needs_quota(const MountParameters *p) { assert(p); @@ -328,7 +336,8 @@ static int mount_add_device_links(Mount *m) { if (path_equal(m->where, "/")) return 0; - if (mount_is_auto(p) && UNIT(m)->manager->running_as == MANAGER_SYSTEM) + if (mount_is_auto(p) && !mount_is_automount(p) && + UNIT(m)->manager->running_as == MANAGER_SYSTEM) device_wants_mount = true; r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES); @@ -369,7 +378,8 @@ static bool should_umount(Mount *m) { MountParameters *p; if (path_equal(m->where, "/") || - path_equal(m->where, "/usr")) + path_equal(m->where, "/usr") || + path_startswith(m->where, "/run/initramfs")) return false; p = get_mount_parameters(m); @@ -393,13 +403,15 @@ static int mount_add_default_dependencies(Mount *m) { if (UNIT(m)->manager->running_as != MANAGER_SYSTEM) return 0; - /* We do not add any default dependencies to / and /usr, since - * they are guaranteed to stay mounted the whole time, since - * our system is on it. Also, don't bother with anything - * mounted below virtual file systems, it's also going to be - * virtual, and hence not worth the effort. */ + /* We do not add any default dependencies to /, /usr or + * /run/initramfs/, since they are guaranteed to stay + * mounted the whole time, since our system is on it. + * Also, don't bother with anything mounted below virtual + * file systems, it's also going to be virtual, and hence + * not worth the effort. */ if (path_equal(m->where, "/") || path_equal(m->where, "/usr") || + path_startswith(m->where, "/run/initramfs") || path_startswith(m->where, "/proc") || path_startswith(m->where, "/sys") || path_startswith(m->where, "/dev")) diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index 9a115a4387..4072df58e6 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -88,7 +88,7 @@ int mac_selinux_setup(bool *loaded_policy) { log_open(); log_error("Failed to compute init label, ignoring."); } else { - r = setcon(label); + r = setcon_raw(label); log_open(); if (r < 0) diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c index 0c26e85460..5a6d11cfa1 100644 --- a/src/core/smack-setup.c +++ b/src/core/smack-setup.c @@ -261,7 +261,7 @@ static int write_netlabel_rules(const char* srcdir) { } } - return r; + return r; } #endif diff --git a/src/core/transaction.c b/src/core/transaction.c index b28fc76785..c894001cf9 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -391,6 +391,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi if (delete) { + const char *status; /* logging for j not k here here to provide consistent narrative */ log_unit_warning(j->unit, "Breaking ordering cycle by deleting job %s/%s", @@ -399,7 +400,13 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi "Job %s/%s deleted to break ordering cycle starting with %s/%s", delete->unit->id, job_type_to_string(delete->type), j->unit->id, job_type_to_string(j->type)); - unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL, + + if (log_get_show_color()) + status = ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL; + else + status = " SKIP "; + + unit_status_printf(delete->unit, status, "Ordering cycle found, skipping %s"); transaction_delete_unit(tr, delete->unit); return -EAGAIN; diff --git a/src/core/umount.c b/src/core/umount.c index b953fcc152..c21a2be54e 100644 --- a/src/core/umount.c +++ b/src/core/umount.c @@ -412,6 +412,7 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e #ifndef HAVE_SPLIT_USR || path_equal(m->path, "/usr") #endif + || path_startswith(m->path, "/run/initramfs") ) continue; diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 7790ab865d..435e3805c4 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -245,7 +245,7 @@ static int process_locale(void) { int r; etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf"); - if (faccessat(AT_FDCWD, etc_localeconf, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_localeconf, F_OK) >= 0) return 0; if (arg_copy_locale && arg_root) { @@ -319,7 +319,7 @@ static int process_timezone(void) { int r; etc_localtime = prefix_roota(arg_root, "/etc/localtime"); - if (faccessat(AT_FDCWD, etc_localtime, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_localtime, F_OK) >= 0) return 0; if (arg_copy_timezone && arg_root) { @@ -399,7 +399,7 @@ static int process_hostname(void) { int r; etc_hostname = prefix_roota(arg_root, "/etc/hostname"); - if (faccessat(AT_FDCWD, etc_hostname, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_hostname, F_OK) >= 0) return 0; r = prompt_hostname(); @@ -424,7 +424,7 @@ static int process_machine_id(void) { int r; etc_machine_id = prefix_roota(arg_root, "/etc/machine-id"); - if (faccessat(AT_FDCWD, etc_machine_id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_machine_id, F_OK) >= 0) return 0; if (sd_id128_equal(arg_machine_id, SD_ID128_NULL)) @@ -450,7 +450,7 @@ static int prompt_root_password(void) { return 0; etc_shadow = prefix_roota(arg_root, "/etc/shadow"); - if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_shadow, F_OK) >= 0) return 0; print_welcome(); @@ -533,7 +533,7 @@ static int process_root_password(void) { int r; etc_shadow = prefix_roota(arg_root, "/etc/shadow"); - if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0) + if (laccess(etc_shadow, F_OK) >= 0) return 0; mkdir_parents(etc_shadow, 0755); diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 97a48764ae..6f576b5ecf 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -336,8 +336,8 @@ static int add_mount( if (r < 0) return log_error_errno(r, "Failed to write unit file %s: %m", unit); - if (!noauto) { - lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL); + if (!noauto && !automount) { + lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", name, NULL); if (!lnk) return log_oom(); diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index c37e32e96b..d11756e615 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -706,7 +706,7 @@ int main(int argc, char *argv[]) { log_open(); umask(0022); - mac_selinux_init("/etc"); + mac_selinux_init(); if (argc != 1) { log_error("This program takes no arguments."); diff --git a/src/journal/compress.c b/src/journal/compress.c index 1933b87b00..c43849c46a 100644 --- a/src/journal/compress.c +++ b/src/journal/compress.c @@ -17,6 +17,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> @@ -498,7 +499,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { total_out += n; if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { - log_debug("Compressed stream longer than %zd bytes", max_bytes); + log_debug("Compressed stream longer than %"PRIu64" bytes", max_bytes); return -EFBIG; } @@ -649,7 +650,7 @@ int decompress_stream_lz4(int in, int out, uint64_t max_bytes) { total_out += produced; if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { - log_debug("Decompressed stream longer than %zd bytes", max_bytes); + log_debug("Decompressed stream longer than %"PRIu64" bytes", max_bytes); r = -EFBIG; goto cleanup; } diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index ac75e39312..3c21d4129e 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -19,6 +19,7 @@ #include <errno.h> #include <fcntl.h> +#include <inttypes.h> #include <linux/magic.h> #include <poll.h> #include <stddef.h> @@ -1957,7 +1958,7 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** &f->compress_buffer, &f->compress_buffer_size, field, field_length, '='); if (r < 0) - log_debug_errno(r, "Cannot decompress %s object of length %zu at offset "OFSfmt": %m", + log_debug_errno(r, "Cannot decompress %s object of length %"PRIu64" at offset "OFSfmt": %m", object_compressed_to_string(compression), l, p); else if (r > 0) { diff --git a/src/journal/test-compress-benchmark.c b/src/journal/test-compress-benchmark.c index 5b2d130cd6..0ef6d36a50 100644 --- a/src/journal/test-compress-benchmark.c +++ b/src/journal/test-compress-benchmark.c @@ -105,6 +105,8 @@ static void test_compress_decompress(const char* label, const char* type, int r; size = permute(i); + if (size == 0) + continue; log_debug("%s %zu %zu", type, i, size); diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 1d9ec7be82..1bef368852 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -43,7 +43,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { if (r < 0) return r; - unaligned_write_be16(&duid->type, DHCP6_DUID_EN); + unaligned_write_be16(&duid->type, DHCP_DUID_TYPE_EN); unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); *len = sizeof(duid->type) + sizeof(duid->en); diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 93f06f5938..cb953cb416 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -25,13 +25,23 @@ #include "sparse-endian.h" #include "unaligned.h" +typedef enum DHCPDUIDType { + DHCP_DUID_TYPE_RAW = 0, + DHCP_DUID_TYPE_LLT = 1, + DHCP_DUID_TYPE_EN = 2, + DHCP_DUID_TYPE_LL = 3, + DHCP_DUID_TYPE_UUID = 4, + _DHCP_DUID_TYPE_MAX, + _DHCP_DUID_TYPE_INVALID = -1, +} DHCPDUIDType; + /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). */ #define MAX_DUID_LEN 128 struct duid { - uint16_t type; + be16_t type; union { struct { /* DHCP6_DUID_LLT */ @@ -61,3 +71,32 @@ struct duid { int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); + +static inline int dhcp_validate_duid_len(be16_t duid_type, size_t duid_len) { + struct duid d; + + assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); + + switch (be16toh(duid_type)) { + case DHCP_DUID_TYPE_LLT: + if (duid_len <= sizeof(d.llt)) + return -EINVAL; + break; + case DHCP_DUID_TYPE_EN: + if (duid_len != sizeof(d.en)) + return -EINVAL; + break; + case DHCP_DUID_TYPE_LL: + if (duid_len <= sizeof(d.ll)) + return -EINVAL; + break; + case DHCP_DUID_TYPE_UUID: + if (duid_len != sizeof(d.uuid)) + return -EINVAL; + break; + default: + /* accept unknown type in order to be forward compatible */ + break; + } + return 0; +} diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index ee4bdfb07f..2487c470ab 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -62,13 +62,6 @@ enum { #define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC #define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC -enum { - DHCP6_DUID_LLT = 1, - DHCP6_DUID_EN = 2, - DHCP6_DUID_LL = 3, - DHCP6_DUID_UUID = 4, -}; - enum DHCP6State { DHCP6_STATE_STOPPED = 0, DHCP6_STATE_INFORMATION_REQUEST = 1, diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index c61941cd70..190c9baece 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -446,7 +446,7 @@ static int format_mac_address(const void *data, size_t sz, char **ret) { static int format_network_address(const void *data, size_t sz, char **ret) { union in_addr_union a; - int family; + int family, r; if (sz == 6 && ((uint8_t*) data)[1] == 1) { memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in)); @@ -457,7 +457,10 @@ static int format_network_address(const void *data, size_t sz, char **ret) { } else return 0; - return in_addr_to_string(family, &a, ret); + r = in_addr_to_string(family, &a, ret); + if (r < 0) + return r; + return 1; } _public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) { diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index cb7252bbeb..7c21f42591 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -335,6 +335,34 @@ int config_parse_hwaddr(const char *unit, return 0; } +int config_parse_iaid_value(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + uint32_t iaid_value; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if ((r = safe_atou32(rvalue, &iaid_value)) < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to read IAID: %s", rvalue); + return r; + } + + *((be32_t *)data) = htobe32(iaid_value); + + return 0; +} + void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { unsigned i; diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index c8a531ab0f..d8b551e8ce 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -62,6 +62,10 @@ int config_parse_ifalias(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_iaid_value(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); const char *net_get_name(struct udev_device *device); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index d484c37a73..b108e35386 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -82,7 +82,7 @@ struct sd_dhcp_client { } _packed_ ll; struct { /* 255: Node-specific (RFC 4361) */ - uint32_t iaid; + be32_t iaid; struct duid duid; } _packed_ ns; struct { @@ -298,6 +298,51 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, return 0; } +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, be32_t iaid, + size_t duid_len, struct duid *duid) { + DHCP_CLIENT_DONT_DESTROY(client); + int r; + assert_return(client, -EINVAL); + zero(client->client_id); + + client->client_id.type = 255; + + /* If IAID is not configured, generate it. */ + if (iaid == 0) { + r = dhcp_identifier_set_iaid(client->index, client->mac_addr, + client->mac_addr_len, + &client->client_id.ns.iaid); + if (r < 0) + return r; + } else + client->client_id.ns.iaid = iaid; + + /* If DUID is not configured, generate DUID-EN. */ + if (duid_len == 0) { + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, + &duid_len); + if (r < 0) + return r; + } else { + r = dhcp_validate_duid_len(client->client_id.type, + duid_len - sizeof(client->client_id.type)); + if (r < 0) + return r; + memcpy(&client->client_id.ns.duid, duid, duid_len); + } + + client->client_id_len = sizeof(client->client_id.type) + duid_len + + sizeof(client->client_id.ns.iaid); + + if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { + log_dhcp_client(client, "Configured IAID+DUID, restarting."); + client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); + sd_dhcp_client_start(client); + } + + return 0; +} + int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname) { char *new_hostname = NULL; @@ -408,7 +453,7 @@ static void client_stop(sd_dhcp_client *client, int error) { static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, uint8_t type, size_t *_optlen, size_t *_optoffset) { - _cleanup_free_ DHCPPacket *packet; + _cleanup_free_ DHCPPacket *packet = NULL; size_t optlen, optoffset, size; be16_t max_size; usec_t time_now; @@ -469,7 +514,6 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, if (client->arp_type == ARPHRD_ETHER) memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN); - /* If no client identifier exists, construct an RFC 4361-compliant one */ if (client->client_id_len == 0) { size_t duid_len; diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 7a119fd488..ef50ed17a1 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -825,7 +825,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len); if (r >= 0) { - _cleanup_free_ char *client_id_hex; + _cleanup_free_ char *client_id_hex = NULL; client_id_hex = hexmem(client_id, client_id_len); if (!client_id_hex) { diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index af4709d788..7cecba120c 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -180,41 +180,30 @@ static int client_ensure_duid(sd_dhcp6_client *client) { return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); } -int sd_dhcp6_client_set_duid( - sd_dhcp6_client *client, - uint16_t type, - uint8_t *duid, size_t duid_len) { +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, size_t duid_len, + struct duid *duid) { + int r; assert_return(client, -EINVAL); - assert_return(duid, -EINVAL); - assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); - switch (type) { - case DHCP6_DUID_LLT: - if (duid_len <= sizeof(client->duid.llt)) - return -EINVAL; - break; - case DHCP6_DUID_EN: - if (duid_len != sizeof(client->duid.en)) - return -EINVAL; - break; - case DHCP6_DUID_LL: - if (duid_len <= sizeof(client->duid.ll)) - return -EINVAL; - break; - case DHCP6_DUID_UUID: - if (duid_len != sizeof(client->duid.uuid)) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; + if (duid_len > 0) { + r = dhcp_validate_duid_len(duid->type, + duid_len - sizeof(duid->type)); + if (r < 0) + return r; + + memcpy(&client->duid, duid, duid_len); + client->duid_len = duid_len; } - client->duid.type = htobe16(type); - memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len + sizeof(client->duid.type); + return 0; +} + +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, be32_t iaid) { + assert_return(client, -EINVAL); + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->ia_na.id = iaid; return 0; } diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index d0743cf3e2..9d4587c80e 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -112,6 +112,8 @@ static bool lldp_keep_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { return true; } +static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor); + static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL; bool keep; @@ -136,7 +138,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { if (lldp_neighbor_equal(n, old)) { /* Is this equal, then restart the TTL counter, but don't do anyting else. */ - lldp_neighbor_start_ttl(old); + lldp_start_timer(lldp, old); lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old); return 0; } @@ -162,7 +164,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { n->lldp = lldp; - lldp_neighbor_start_ttl(n); + lldp_start_timer(lldp, n); lldp_callback(lldp, old ? SD_LLDP_EVENT_UPDATED : SD_LLDP_EVENT_ADDED, n); return 1; @@ -368,8 +370,6 @@ static int neighbor_compare_func(const void *a, const void *b) { return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id); } -static int lldp_start_timer(sd_lldp *lldp); - static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { sd_lldp *lldp = userdata; int r, q; @@ -378,19 +378,22 @@ static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { if (r < 0) return log_lldp_errno(r, "Failed to make space: %m"); - q = lldp_start_timer(lldp); + q = lldp_start_timer(lldp, NULL); if (q < 0) return log_lldp_errno(q, "Failed to restart timer: %m"); return 0; } -static int lldp_start_timer(sd_lldp *lldp) { +static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) { sd_lldp_neighbor *n; int r; assert(lldp); + if (neighbor) + lldp_neighbor_start_ttl(neighbor); + n = prioq_peek(lldp->neighbor_by_expiry); if (!n) { @@ -440,7 +443,7 @@ _public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { if (!l) return -ENOMEM; - r = lldp_start_timer(lldp); + r = lldp_start_timer(lldp, NULL); if (r < 0) { free(l); return r; diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 542c37e41b..b8958ec7bb 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -1131,10 +1131,7 @@ _public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) { assert_return(!m->sealed, -EPERM); assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM); - if (b) - m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED; - else - m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED; + SET_FLAG(m->header->flags, BUS_MESSAGE_NO_REPLY_EXPECTED, !b); return 0; } @@ -1143,10 +1140,7 @@ _public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) { assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - if (b) - m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START; - else - m->header->flags |= BUS_MESSAGE_NO_AUTO_START; + SET_FLAG(m->header->flags, BUS_MESSAGE_NO_AUTO_START, !b); return 0; } @@ -1155,10 +1149,7 @@ _public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message * assert_return(m, -EINVAL); assert_return(!m->sealed, -EPERM); - if (b) - m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION; - else - m->header->flags &= ~BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION; + SET_FLAG(m->header->flags, BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION, b); return 0; } diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index cc15afeb1c..862f26aad7 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -313,10 +313,7 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) { assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM); assert_return(!bus_pid_changed(bus), -ECHILD); - if (b) - bus->creds_mask |= mask; - else - bus->creds_mask &= ~mask; + SET_FLAG(bus->creds_mask, mask, b); /* The well knowns we need unconditionally, so that matches can work */ bus->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME; diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 3924300817..f56798674c 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -107,10 +107,7 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) { m->hdr->nlmsg_type == RTM_GETNEIGH, -EINVAL); - if (dump) - m->hdr->nlmsg_flags |= NLM_F_DUMP; - else - m->hdr->nlmsg_flags &= ~NLM_F_DUMP; + SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump); return 0; } diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c index 480f1ad065..b7aec1f20a 100644 --- a/src/libsystemd/sd-path/sd-path.c +++ b/src/libsystemd/sd-path/sd-path.c @@ -89,7 +89,8 @@ static int from_home_dir(const char *envname, const char *suffix, char **buffer, static int from_user_dir(const char *field, char **buffer, const char **ret) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *b = NULL; - const char *fn = NULL; + _cleanup_free_ const char *fn = NULL; + const char *c = NULL; char line[LINE_MAX]; size_t n; int r; @@ -98,10 +99,14 @@ static int from_user_dir(const char *field, char **buffer, const char **ret) { assert(buffer); assert(ret); - r = from_home_dir(NULL, ".config/user-dirs.dirs", &b, &fn); + r = from_home_dir("XDG_CONFIG_HOME", ".config", &b, &c); if (r < 0) return r; + fn = strappend(c, "/user-dirs.dirs"); + if (!fn) + return -ENOMEM; + f = fopen(fn, "re"); if (!f) { if (errno == ENOENT) diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h index eb58740d26..3f6d0ed16c 100644 --- a/src/libudev/libudev.h +++ b/src/libudev/libudev.h @@ -21,6 +21,7 @@ #define _LIBUDEV_H_ #include <stdarg.h> +#include <sys/sysmacros.h> #include <sys/types.h> #ifdef __cplusplus diff --git a/src/locale/localed.c b/src/locale/localed.c index cc86c61edb..46405ca68a 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -1296,7 +1296,7 @@ int main(int argc, char *argv[]) { log_open(); umask(0022); - mac_selinux_init("/etc"); + mac_selinux_init(); if (argc != 1) { log_error("This program takes no arguments."); diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules index 694df2cfc8..ff3e68e961 100644 --- a/src/login/70-uaccess.rules +++ b/src/login/70-uaccess.rules @@ -42,8 +42,9 @@ SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", TAG+="uaccess" SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", TAG+="uaccess" SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess" -# DRI video devices +# DRI and frame buffer video devices SUBSYSTEM=="drm", KERNEL=="card*|renderD*", TAG+="uaccess" +SUBSYSTEM=="graphics", KERNEL=="fb*", TAG+="uaccess" # KVM SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess" diff --git a/src/login/logind.c b/src/login/logind.c index 933602eb08..d5f6757bd3 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -1126,7 +1126,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = mac_selinux_init("/run"); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "Could not initialize labelling: %m"); goto finish; diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 0679114f74..6ec7a911ca 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -45,6 +45,7 @@ #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "strxcpyx.h" #include "terminal-util.h" #include "util.h" #include "verbs.h" @@ -147,7 +148,6 @@ static int link_info_compare(const void *a, const void *b) { } static int decode_link(sd_netlink_message *m, LinkInfo *info) { - static const struct ether_addr null_address = {}; const char *name; uint16_t type; int r; @@ -174,11 +174,11 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info) { if (r < 0) return r; - strncpy(info->name, name, sizeof(info->name)); + strscpy(info->name, sizeof info->name, name); info->has_mac_address = sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 && - memcmp(&info->mac_address, &null_address, sizeof(struct ether_addr)) != 0; + memcmp(&info->mac_address, ÐER_ADDR_NULL, sizeof(struct ether_addr)) != 0; info->has_mtu = sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu) && diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c new file mode 100644 index 0000000000..4bc92b8171 --- /dev/null +++ b/src/network/networkd-conf.c @@ -0,0 +1,133 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen <teg@jklm.no> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. + ***/ + +#include <ctype.h> + +#include "conf-parser.h" +#include "def.h" +#include "dhcp-identifier.h" +#include "networkd-conf.h" +#include "string-table.h" + +int manager_parse_config_file(Manager *m) { + assert(m); + + return config_parse_many(PKGSYSCONFDIR "/networkd.conf", + CONF_PATHS_NULSTR("systemd/networkd.conf.d"), + "DUID\0", + config_item_perf_lookup, networkd_gperf_lookup, + false, m); +} + +static const char* const dhcp_duid_type_table[_DHCP_DUID_TYPE_MAX] = { + [DHCP_DUID_TYPE_RAW] = "raw", + [DHCP_DUID_TYPE_LLT] = "link-layer-time", + [DHCP_DUID_TYPE_EN] = "vendor", + [DHCP_DUID_TYPE_LL] = "link-layer", + [DHCP_DUID_TYPE_UUID] = "uuid" +}; +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_duid_type, DHCPDUIDType); +DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_duid_type, dhcp_duid_type, DHCPDUIDType, "Failed to parse DHCP DUID type"); + +int config_parse_dhcp_duid_raw( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + int r; + long byte; + char *cbyte, *pnext; + const char *pduid = (const char *)rvalue; + size_t count = 0, duid_len = 0; + Manager *m = userdata; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(m); + assert(m->dhcp_duid_type != _DHCP_DUID_TYPE_INVALID); + + switch (m->dhcp_duid_type) { + case DHCP_DUID_TYPE_LLT: + /* RawData contains DUID-LLT link-layer address (offset 6) */ + duid_len = 6; + break; + case DHCP_DUID_TYPE_EN: + /* RawData contains DUID-EN identifier (offset 4) */ + duid_len = 4; + break; + case DHCP_DUID_TYPE_LL: + /* RawData contains DUID-LL link-layer address (offset 2) */ + duid_len = 2; + break; + case DHCP_DUID_TYPE_UUID: + /* RawData specifies UUID (offset 0) - fall thru */ + case DHCP_DUID_TYPE_RAW: + /* First two bytes of RawData is DUID Type - fall thru */ + default: + break; + } + + if (m->dhcp_duid_type != DHCP_DUID_TYPE_RAW) + m->dhcp_duid.type = htobe16(m->dhcp_duid_type); + + /* RawData contains DUID in format " NN:NN:NN... " */ + while (true) { + r = extract_first_word(&pduid, &cbyte, ":", 0); + if (r < 0) { + log_error("Failed to read DUID."); + return -EINVAL; + } + if (r == 0) + break; + if (duid_len >= MAX_DUID_LEN) { + log_error("DUID length exceeds maximum length."); + return -EINVAL; + } + + errno = 0; + byte = strtol(cbyte, &pnext, 16); + if ((errno == ERANGE && (byte == LONG_MAX || byte == LONG_MIN)) + || (errno != 0 && byte == 0) || (cbyte == pnext)) { + log_error("Invalid DUID byte: %s.", cbyte); + return -EINVAL; + } + + /* If DHCP_DUID_TYPE_RAW, first two bytes holds DUID Type */ + if ((m->dhcp_duid_type == DHCP_DUID_TYPE_RAW) && (count < 2)) { + m->dhcp_duid.type |= (byte << (8 * count)); + count++; + continue; + } + + m->dhcp_duid.raw.data[duid_len++] = byte; + } + + m->dhcp_duid_len = sizeof(m->dhcp_duid.type) + duid_len; + + return 0; +} diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h new file mode 100644 index 0000000000..6d9ce010e3 --- /dev/null +++ b/src/network/networkd-conf.h @@ -0,0 +1,32 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen <teg@jklm.no> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "networkd.h" + + +int manager_parse_config_file(Manager *m); + +const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length); + +int config_parse_dhcp_duid_type(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp_duid_raw(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 68998eabf2..3bbb21295c 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -625,7 +625,13 @@ int dhcp4_configure(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: - /* Library defaults to this. */ + /* If configured, apply user specified DUID and/or IAID */ + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid_value, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + return r; break; case DHCP_CLIENT_ID_MAC: r = sd_dhcp_client_set_client_id(link->dhcp_client, diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 5f7a005c36..9f59cb3f8a 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -230,6 +230,16 @@ int dhcp6_configure(Link *link) { if (r < 0) goto error; + r = sd_dhcp6_client_set_iaid(client, link->network->iaid_value); + if (r < 0) + goto error; + + r = sd_dhcp6_client_set_duid(client, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + goto error; + r = sd_dhcp6_client_set_index(client, link->ifindex); if (r < 0) goto error; diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf new file mode 100644 index 0000000000..3ef4155476 --- /dev/null +++ b/src/network/networkd-gperf.gperf @@ -0,0 +1,18 @@ +%{ +#include <stddef.h> +#include "conf-parser.h" +#include "networkd-conf.h" +%} +struct ConfigPerfItem; +%null_strings +%language=ANSI-C +%define slot-name section_and_lvalue +%define hash-function-name networkd_gperf_hash +%define lookup-function-name networkd_gperf_lookup +%readonly-tables +%omit-struct-type +%struct-type +%includes +%% +DUID.Type, config_parse_dhcp_duid_type, 0, offsetof(Manager, dhcp_duid_type) +DUID.RawData, config_parse_dhcp_duid_raw, 0, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ff4bd76554..67b04560cd 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2781,6 +2781,13 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m"); + + r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, + link->network->iaid_value, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m"); } if (link->dhcp6_client) { @@ -2790,6 +2797,17 @@ int link_update(Link *link, sd_netlink_message *m) { ARPHRD_ETHER); if (r < 0) return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m"); + + r = sd_dhcp6_client_set_iaid(link->dhcp6_client, + link->network->iaid_value); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m"); + + r = sd_dhcp6_client_set_duid(link->dhcp6_client, + link->manager->dhcp_duid_len, + &link->manager->dhcp_duid); + if (r < 0) + return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m"); } } } diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b8cb7f875d..8d443f7b0f 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1037,6 +1037,8 @@ int manager_new(Manager **ret) { if (r < 0) return r; + m->dhcp_duid_type = _DHCP_DUID_TYPE_INVALID; + *ret = m; m = NULL; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index a5d1714293..7a9a136d5b 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -26,6 +26,7 @@ Match.KernelCommandLine, config_parse_net_condition, Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) +Link.IAIDValue, config_parse_iaid_value, 0, offsetof(Network, iaid_value) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index f175788977..491b9a3efa 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -629,10 +629,7 @@ int config_parse_ipv4ll( * config_parse_address_family_boolean(), except that it * applies only to IPv4 */ - if (parse_boolean(rvalue)) - *link_local |= ADDRESS_FAMILY_IPV4; - else - *link_local &= ~ADDRESS_FAMILY_IPV4; + SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue)); return 0; } diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 4a13e2b574..c5530cdfba 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -30,6 +30,7 @@ typedef struct Network Network; #include "networkd-route.h" #include "networkd-util.h" #include "networkd.h" +#include "sparse-endian.h" #define DHCP_ROUTE_METRIC 1024 #define IPV4LL_ROUTE_METRIC 2048 @@ -144,6 +145,7 @@ struct Network { struct ether_addr *mac; unsigned mtu; + be32_t iaid_value; LLDPMode lldp_mode; /* LLDP reception */ bool lldp_emit; /* LLDP transmission */ diff --git a/src/network/networkd.c b/src/network/networkd.c index 3a2615e6fd..c8f81a2ca6 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -21,6 +21,7 @@ #include "capability-util.h" #include "networkd.h" +#include "networkd-conf.h" #include "signal-util.h" #include "user-util.h" @@ -89,6 +90,10 @@ int main(int argc, char *argv[]) { goto out; } + r = manager_parse_config_file(m); + if (r < 0) + log_warning_errno(r, "Failed to parse configuration file: %m"); + r = manager_load_config(m); if (r < 0) { log_error_errno(r, "Could not load configuration files: %m"); diff --git a/src/network/networkd.h b/src/network/networkd.h index 6bdd8302a0..d815f30610 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -35,6 +35,7 @@ typedef struct Manager Manager; #include "networkd-link.h" #include "networkd-network.h" #include "networkd-util.h" +#include "dhcp-identifier.h" struct Manager { sd_netlink *rtnl; @@ -61,6 +62,10 @@ struct Manager { LIST_HEAD(AddressPool, address_pools); usec_t network_dirs_ts_usec; + + DHCPDUIDType dhcp_duid_type; + size_t dhcp_duid_len; + struct duid dhcp_duid; }; extern const char* const network_dirs[]; diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index 1db5ba7116..9f9a4759d1 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -73,7 +73,7 @@ int sync_cgroup(pid_t pid, bool unified_requested) { unified = cg_unified(); if (unified < 0) - return log_error_errno(unified, "Failed to determine whether the unified hierachy is used: %m"); + return log_error_errno(unified, "Failed to determine whether the unified hierarchy is used: %m"); if ((unified > 0) == unified_requested) return 0; @@ -135,7 +135,7 @@ int create_subcgroup(pid_t pid, bool unified_requested) { unified = cg_unified(); if (unified < 0) - return log_error_errno(unified, "Failed to determine whether the unified hierachy is used: %m"); + return log_error_errno(unified, "Failed to determine whether the unified hierarchy is used: %m"); if (unified == 0) return 0; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 4851c439c9..eb89916b7e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -87,6 +87,7 @@ #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif +#include "selinux-util.h" #include "signal-util.h" #include "socket-util.h" #include "stat-util.h" @@ -976,6 +977,13 @@ static int verify_arguments(void) { return -EINVAL; } +#ifndef HAVE_LIBIPTC + if (arg_expose_ports) { + log_error("--port= is not supported, compiled without libiptc support."); + return -EOPNOTSUPP; + } +#endif + if (arg_start_mode == START_BOOT && arg_kill_signal <= 0) arg_kill_signal = SIGRTMIN+3; @@ -3284,6 +3292,12 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_selinux_apifs_context) { + r = mac_selinux_apply(console, arg_selinux_apifs_context); + if (r < 0) + goto finish; + } + if (unlockpt(master) < 0) { r = log_error_errno(errno, "Failed to unlock tty: %m"); goto finish; diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c index 484fbb4d92..009cc73aec 100644 --- a/src/resolve/resolve-tool.c +++ b/src/resolve/resolve-tool.c @@ -1280,40 +1280,28 @@ static int parse_argv(int argc, char *argv[]) { r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --cname= argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_CNAME; - else - arg_flags &= ~SD_RESOLVED_NO_CNAME; + SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0); break; case ARG_SERVICE_ADDRESS: r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --service-address= argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_ADDRESS; - else - arg_flags &= ~SD_RESOLVED_NO_ADDRESS; + SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0); break; case ARG_SERVICE_TXT: r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --service-txt= argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_TXT; - else - arg_flags &= ~SD_RESOLVED_NO_TXT; + SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0); break; case ARG_SEARCH: r = parse_boolean(optarg); if (r < 0) return log_error_errno(r, "Failed to parse --search argument."); - if (r == 0) - arg_flags |= SD_RESOLVED_NO_SEARCH; - else - arg_flags &= ~SD_RESOLVED_NO_SEARCH; + SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0); break; case ARG_STATISTICS: diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index a46674f6fe..706f8c14ed 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -62,6 +62,7 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) { while ((t = set_steal_first(c->transactions))) { set_remove(t->notify_query_candidates, c); + set_remove(t->notify_query_candidates_done, c); dns_transaction_gc(t); } } @@ -139,6 +140,10 @@ static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResource if (r < 0) goto gc; + r = set_ensure_allocated(&t->notify_query_candidates_done, NULL); + if (r < 0) + goto gc; + r = set_put(t->notify_query_candidates, c); if (r < 0) goto gc; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 57f9455131..a5129c201e 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -52,6 +52,7 @@ static void dns_transaction_flush_dnssec_transactions(DnsTransaction *t) { while ((z = set_steal_first(t->dnssec_transactions))) { set_remove(z->notify_transactions, t); + set_remove(z->notify_transactions_done, t); dns_transaction_gc(z); } } @@ -100,14 +101,26 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { set_remove(c->transactions, t); set_free(t->notify_query_candidates); + while ((c = set_steal_first(t->notify_query_candidates_done))) + set_remove(c->transactions, t); + set_free(t->notify_query_candidates_done); + while ((i = set_steal_first(t->notify_zone_items))) i->probe_transaction = NULL; set_free(t->notify_zone_items); + while ((i = set_steal_first(t->notify_zone_items_done))) + i->probe_transaction = NULL; + set_free(t->notify_zone_items_done); + while ((z = set_steal_first(t->notify_transactions))) set_remove(z->dnssec_transactions, t); set_free(t->notify_transactions); + while ((z = set_steal_first(t->notify_transactions_done))) + set_remove(z->dnssec_transactions, t); + set_free(t->notify_transactions_done); + dns_transaction_flush_dnssec_transactions(t); set_free(t->dnssec_transactions); @@ -127,8 +140,11 @@ bool dns_transaction_gc(DnsTransaction *t) { return true; if (set_isempty(t->notify_query_candidates) && + set_isempty(t->notify_query_candidates_done) && set_isempty(t->notify_zone_items) && - set_isempty(t->notify_transactions)) { + set_isempty(t->notify_zone_items_done) && + set_isempty(t->notify_transactions) && + set_isempty(t->notify_transactions_done)) { dns_transaction_free(t); return false; } @@ -266,6 +282,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { log_debug("We have the lexicographically larger IP address and thus lost in the conflict."); t->block_gc++; + while ((z = set_first(t->notify_zone_items))) { /* First, make sure the zone item drops the reference * to us */ @@ -284,7 +301,6 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { DnsQueryCandidate *c; DnsZoneItem *z; DnsTransaction *d; - Iterator i; const char *st; char key_str[DNS_RESOURCE_KEY_STRING_MAX]; @@ -333,39 +349,17 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { * transaction isn't freed while we are still looking at it */ t->block_gc++; - SET_FOREACH(c, t->notify_query_candidates, i) + SET_FOREACH_MOVE(c, t->notify_query_candidates_done, t->notify_query_candidates) dns_query_candidate_notify(c); - SET_FOREACH(z, t->notify_zone_items, i) - dns_zone_item_notify(z); + SWAP_TWO(t->notify_query_candidates, t->notify_query_candidates_done); - if (!set_isempty(t->notify_transactions)) { - DnsTransaction **nt; - unsigned j, n = 0; - - /* We need to be careful when notifying other - * transactions, as that might destroy other - * transactions in our list. Hence, in order to be - * able to safely iterate through the list of - * transactions, take a GC lock on all of them - * first. Then, in a second loop, notify them, but - * first unlock that specific transaction. */ - - nt = newa(DnsTransaction*, set_size(t->notify_transactions)); - SET_FOREACH(d, t->notify_transactions, i) { - nt[n++] = d; - d->block_gc++; - } - - assert(n == set_size(t->notify_transactions)); + SET_FOREACH_MOVE(z, t->notify_zone_items_done, t->notify_zone_items) + dns_zone_item_notify(z); + SWAP_TWO(t->notify_zone_items, t->notify_zone_items_done); - for (j = 0; j < n; j++) { - if (set_contains(t->notify_transactions, nt[j])) - dns_transaction_notify(nt[j], t); - - nt[j]->block_gc--; - dns_transaction_gc(nt[j]); - } - } + SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions) + dns_transaction_notify(d, t); + SWAP_TWO(t->notify_transactions, t->notify_transactions_done); t->block_gc--; dns_transaction_gc(t); @@ -1626,6 +1620,10 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource if (r < 0) goto gc; + r = set_ensure_allocated(&aux->notify_transactions_done, NULL); + if (r < 0) + goto gc; + r = set_put(t->dnssec_transactions, aux); if (r < 0) goto gc; diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 491c62d772..eaece91533 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -118,17 +118,17 @@ struct DnsTransaction { /* Query candidates this transaction is referenced by and that * shall be notified about this specific transaction * completing. */ - Set *notify_query_candidates; + Set *notify_query_candidates, *notify_query_candidates_done; /* Zone items this transaction is referenced by and that shall * be notified about completion. */ - Set *notify_zone_items; + Set *notify_zone_items, *notify_zone_items_done; /* Other transactions that this transactions is referenced by * and that shall be notified about completion. This is used * when transactions want to validate their RRsets, but need * another DNSKEY or DS RR to do so. */ - Set *notify_transactions; + Set *notify_transactions, *notify_transactions_done; /* The opposite direction: the transactions this transaction * created in order to request DNSKEY or DS RRs. */ diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 03813da6a2..850eed8cb8 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -38,6 +38,7 @@ void dns_zone_item_probe_stop(DnsZoneItem *i) { i->probe_transaction = NULL; set_remove(t->notify_zone_items, i); + set_remove(t->notify_zone_items_done, i); dns_transaction_gc(t); } @@ -186,6 +187,10 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) { if (r < 0) goto gc; + r = set_ensure_allocated(&t->notify_zone_items_done, NULL); + if (r < 0) + goto gc; + r = set_put(t->notify_zone_items, i); if (r < 0) goto gc; diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index c7e2ab14d6..161ea03412 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = mac_selinux_init(NULL); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "SELinux setup failed: %m"); goto finish; diff --git a/src/run/run.c b/src/run/run.c index e7f4c21f73..1ed1bd96bf 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -83,8 +83,8 @@ static void polkit_agent_open_if_enabled(void) { static void help(void) { printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n" "Run the specified command in a transient scope or service or timer\n" - "unit. If timer option is specified and unit is exist which is\n" - "specified with --unit option then command can be omitted.\n\n" + "unit. If a timer option is specified and the unit specified with\n" + "the --unit option exists, the command can be omitted.\n\n" " -h --help Show this help\n" " --version Show package version\n" " --no-ask-password Do not prompt for password\n" diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 3cb9e781fd..6779691c28 100644 --- a/src/shared/acpi-fpdt.c +++ b/src/shared/acpi-fpdt.c @@ -119,7 +119,7 @@ int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) { } if (ptr == 0) - return -EINVAL; + return -ENODATA; /* read Firmware Basic Boot Performance Data Record */ fd = open("/dev/mem", O_CLOEXEC|O_RDONLY); @@ -146,6 +146,10 @@ int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) { if (brec.type != ACPI_FPDT_BOOT_REC) return -EINVAL; + if (brec.exit_services_exit == 0) + /* Non-UEFI compatible boot. */ + return -ENODATA; + if (brec.startup_start == 0 || brec.exit_services_exit < brec.startup_start) return -EINVAL; if (brec.exit_services_exit > NSEC_PER_HOUR) diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index f080b849a4..23890c63a0 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -139,7 +139,7 @@ static int setup_machine_raw(uint64_t size, sd_bus_error *error) { execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL); if (errno == ENOENT) - return 99; + _exit(99); _exit(EXIT_FAILURE); } @@ -239,10 +239,8 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) { } r = mkfs_exists("btrfs"); - if (r == -ENOENT) { - log_debug("mkfs.btrfs is missing, cannot create loopback file for /var/lib/machines."); - return 0; - } + if (r == 0) + return sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing"); if (r < 0) return r; diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 061d31f4de..02c03b98d8 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -461,10 +461,7 @@ int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) { if (!!(f->flags & PTY_FORWARD_IGNORE_VHANGUP) == b) return 0; - if (b) - f->flags |= PTY_FORWARD_IGNORE_VHANGUP; - else - f->flags &= ~PTY_FORWARD_IGNORE_VHANGUP; + SET_FLAG(f->flags, PTY_FORWARD_IGNORE_VHANGUP, b); if (!ignore_vhangup(f)) { diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c index 91eace90e2..ce8efce3d5 100644 --- a/src/stdio-bridge/stdio-bridge.c +++ b/src/stdio-bridge/stdio-bridge.c @@ -190,7 +190,7 @@ int main(int argc, char *argv[]) { } for (;;) { - _cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL; int events_a, events_b, fd; uint64_t timeout_a, timeout_b, t; struct timespec _ts, *ts; @@ -234,12 +234,14 @@ int main(int argc, char *argv[]) { fd = sd_bus_get_fd(a); if (fd < 0) { + r = fd; log_error_errno(r, "Failed to get fd: %m"); goto finish; } events_a = sd_bus_get_events(a); if (events_a < 0) { + r = events_a; log_error_errno(r, "Failed to get events mask: %m"); goto finish; } @@ -252,6 +254,7 @@ int main(int argc, char *argv[]) { events_b = sd_bus_get_events(b); if (events_b < 0) { + r = events_b; log_error_errno(r, "Failed to get events mask: %m"); goto finish; } @@ -294,8 +297,6 @@ int main(int argc, char *argv[]) { } } - r = 0; - finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index a4491692a9..180c8f9656 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -152,7 +152,7 @@ static bool arg_now = false; static int daemon_reload(int argc, char *argv[], void* userdata); static int halt_now(enum action a); -static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet); +static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state); static bool original_stdout_is_tty; @@ -1630,11 +1630,27 @@ static int list_dependencies_one( if (arg_plain) printf(" "); else { - int state; + UnitActiveState active_state = _UNIT_ACTIVE_STATE_INVALID; const char *on; - state = check_one_unit(bus, *c, "activating\0active\0reloading\0", true); - on = state > 0 ? ansi_highlight_green() : ansi_highlight_red(); + (void) get_state_one_unit(bus, *c, &active_state); + switch (active_state) { + case UNIT_ACTIVE: + case UNIT_RELOADING: + case UNIT_ACTIVATING: + on = ansi_highlight_green(); + break; + + case UNIT_INACTIVE: + case UNIT_DEACTIVATING: + on = ansi_normal(); + break; + + default: + on = ansi_highlight_red(); + break; + } + printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_normal()); } @@ -2399,18 +2415,19 @@ static int unit_find_paths( return r; } -static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet) { +static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *buf = NULL; - const char *path, *state; + UnitActiveState state; + const char *path; int r; assert(name); + assert(active_state); /* We don't use unit_dbus_path_from_name() directly since we don't want to load the unit unnecessarily, if it * isn't loaded. */ - r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -2426,7 +2443,7 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states /* The unit is currently not loaded, hence say it's "inactive", since all units that aren't loaded are * considered inactive. */ - state = "inactive"; + state = UNIT_INACTIVE; } else { r = sd_bus_message_read(reply, "o", &path); @@ -2444,13 +2461,15 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states if (r < 0) return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r)); - state = buf; + state = unit_active_state_from_string(buf); + if (state == _UNIT_ACTIVE_STATE_INVALID) { + log_error("Invalid unit state '%s' for: %s", buf, name); + return -EINVAL; + } } - if (!quiet) - puts(state); - - return nulstr_contains(good_states, state); + *active_state = state; + return 0; } static int check_triggering_units( @@ -2458,9 +2477,10 @@ static int check_triggering_units( const char *name) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_free_ char *path = NULL, *n = NULL, *state = NULL; + _cleanup_free_ char *path = NULL, *n = NULL, *load_state = NULL; _cleanup_strv_free_ char **triggered_by = NULL; bool print_warning_label = true; + UnitActiveState active_state; char **i; int r; @@ -2479,11 +2499,11 @@ static int check_triggering_units( "org.freedesktop.systemd1.Unit", "LoadState", &error, - &state); + &load_state); if (r < 0) return log_error_errno(r, "Failed to get load state of %s: %s", n, bus_error_message(&error, r)); - if (streq(state, "masked")) + if (streq(load_state, "masked")) return 0; r = sd_bus_get_property_strv( @@ -2498,11 +2518,11 @@ static int check_triggering_units( return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r)); STRV_FOREACH(i, triggered_by) { - r = check_one_unit(bus, *i, "active\0reloading\0", true); + r = get_state_one_unit(bus, *i, &active_state); if (r < 0) - return log_error_errno(r, "Failed to check unit: %m"); + return r; - if (r == 0) + if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING)) continue; if (print_warning_label) { @@ -2596,7 +2616,10 @@ static int start_unit_one( if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) && !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED)) - log_error("See system logs and 'systemctl status %s' for details.", name); + log_error("See %s logs and 'systemctl%s status %s' for details.", + arg_scope == UNIT_FILE_SYSTEM ? "system" : "user", + arg_scope == UNIT_FILE_SYSTEM ? "" : " --user", + name); return r; } @@ -3163,11 +3186,12 @@ static int start_special(int argc, char *argv[], void *userdata) { return start_unit(argc, argv, userdata); } -static int check_unit_generic(int code, const char *good_states, char **args) { +static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) { _cleanup_strv_free_ char **names = NULL; + UnitActiveState active_state; sd_bus *bus; char **name; - int r; + int r, i; bool found = false; r = acquire_bus(BUS_MANAGER, &bus); @@ -3179,13 +3203,16 @@ static int check_unit_generic(int code, const char *good_states, char **args) { return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { - int state; + r = get_state_one_unit(bus, *name, &active_state); + if (r < 0) + return r; + + if (!arg_quiet) + puts(unit_active_state_to_string(active_state)); - state = check_one_unit(bus, *name, good_states, arg_quiet); - if (state < 0) - return state; - if (state > 0) - found = true; + for (i = 0; i < nb_states; ++i) + if (good_states[i] == active_state) + found = true; } /* use the given return code for the case that we won't find @@ -3194,12 +3221,14 @@ static int check_unit_generic(int code, const char *good_states, char **args) { } static int check_unit_active(int argc, char *argv[], void *userdata) { + const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING }; /* According to LSB: 3, "program is not running" */ - return check_unit_generic(3, "active\0reloading\0", strv_skip(argv, 1)); + return check_unit_generic(3, states, ELEMENTSOF(states), strv_skip(argv, 1)); } static int check_unit_failed(int argc, char *argv[], void *userdata) { - return check_unit_generic(1, "failed\0", strv_skip(argv, 1)); + const UnitActiveState states[] = { UNIT_FAILED }; + return check_unit_generic(1, states, ELEMENTSOF(states), strv_skip(argv, 1)); } static int kill_unit(int argc, char *argv[], void *userdata) { @@ -6162,9 +6191,24 @@ static int edit(int argc, char *argv[], void *userdata) { r = daemon_reload(argc, argv, userdata); end: - STRV_FOREACH_PAIR(original, tmp, paths) + STRV_FOREACH_PAIR(original, tmp, paths) { (void) unlink(*tmp); + /* Removing empty dropin dirs */ + if (!arg_full) { + _cleanup_free_ char *dir; + + dir = dirname_malloc(*original); + if (!dir) + return log_oom(); + + /* no need to check if the dir is empty, rmdir + * does nothing if it is not the case. + */ + (void) rmdir(dir); + } + } + return r; } @@ -7263,6 +7307,7 @@ static int parse_argv(int argc, char *argv[]) { return systemctl_parse_argv(argc, argv); } +#ifdef HAVE_SYSV_COMPAT _pure_ static int action_to_runlevel(void) { static const char table[_ACTION_MAX] = { @@ -7280,6 +7325,7 @@ _pure_ static int action_to_runlevel(void) { return table[arg_action]; } +#endif static int talk_initctl(void) { #ifdef HAVE_SYSV_COMPAT diff --git a/src/systemd/_sd-common.h b/src/systemd/_sd-common.h index 2d4e1f26e1..3bb886be75 100644 --- a/src/systemd/_sd-common.h +++ b/src/systemd/_sd-common.h @@ -74,7 +74,7 @@ #endif #define _SD_DEFINE_POINTER_CLEANUP_FUNC(type, func) \ - static inline void func##p(type **p) { \ + static __inline__ void func##p(type **p) { \ if (*p) \ func(*p); \ } \ diff --git a/src/systemd/sd-bus-protocol.h b/src/systemd/sd-bus-protocol.h index 47b256d5b9..623cee0c50 100644 --- a/src/systemd/sd-bus-protocol.h +++ b/src/systemd/sd-bus-protocol.h @@ -59,7 +59,7 @@ enum { SD_BUS_TYPE_STRUCT_END = ')', SD_BUS_TYPE_DICT_ENTRY = 'e', /* not actually used in signatures */ SD_BUS_TYPE_DICT_ENTRY_BEGIN = '{', - SD_BUS_TYPE_DICT_ENTRY_END = '}', + SD_BUS_TYPE_DICT_ENTRY_END = '}' }; /* Well-known errors. Note that this is only a sanitized subset of the diff --git a/src/systemd/sd-bus-vtable.h b/src/systemd/sd-bus-vtable.h index 6ad6d51979..e8f84eb545 100644 --- a/src/systemd/sd-bus-vtable.h +++ b/src/systemd/sd-bus-vtable.h @@ -34,7 +34,7 @@ enum { _SD_BUS_VTABLE_METHOD = 'M', _SD_BUS_VTABLE_SIGNAL = 'S', _SD_BUS_VTABLE_PROPERTY = 'P', - _SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W', + _SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W' }; enum { diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 2a2ef0eb98..295989cd69 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -89,13 +89,13 @@ enum { SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 32, SD_BUS_CREDS_DESCRIPTION = 1ULL << 33, SD_BUS_CREDS_AUGMENT = 1ULL << 63, /* special flag, if on sd-bus will augment creds struct, in a potentially race-full way. */ - _SD_BUS_CREDS_ALL = (1ULL << 34) -1, + _SD_BUS_CREDS_ALL = (1ULL << 34) -1 }; enum { SD_BUS_NAME_REPLACE_EXISTING = 1ULL << 0, SD_BUS_NAME_ALLOW_REPLACEMENT = 1ULL << 1, - SD_BUS_NAME_QUEUE = 1ULL << 2, + SD_BUS_NAME_QUEUE = 1ULL << 2 }; /* Callbacks */ diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index 5bfca6ecec..c1d07561d7 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -22,6 +22,7 @@ ***/ #include <inttypes.h> +#include <sys/sysmacros.h> #include <sys/types.h> #include "_sd-common.h" diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index ef45370505..7873cb1e04 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -27,6 +27,7 @@ #include "sd-dhcp-lease.h" #include "sd-event.h" +#include "sparse-endian.h" #include "_sd-common.h" @@ -82,6 +83,7 @@ enum { SD_DHCP_OPTION_END = 255, }; +struct duid; typedef struct sd_dhcp_client sd_dhcp_client; typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, @@ -98,6 +100,8 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, const uint8_t *data, size_t data_len); +int sd_dhcp_client_set_iaid_duid(sd_dhcp_client *client, be32_t iaid, + size_t duid_len, struct duid *duid); int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, const uint8_t **data, size_t *data_len); int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 1bedc941aa..ebdd017628 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -26,6 +26,7 @@ #include "sd-dhcp6-lease.h" #include "sd-event.h" +#include "sparse-endian.h" #include "_sd-common.h" @@ -74,6 +75,7 @@ enum { /* option codes 144-65535 are unassigned */ }; +struct duid; typedef struct sd_dhcp6_client sd_dhcp6_client; typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, @@ -85,8 +87,9 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, - size_t duid_len); +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, size_t duid_len, + struct duid *duid); +int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, be32_t iaid); int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 1ea97e47f8..531ace1c34 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -55,7 +55,7 @@ enum { SD_EVENT_RUNNING, SD_EVENT_EXITING, SD_EVENT_FINISHED, - SD_EVENT_PREPARING, + SD_EVENT_PREPARING }; enum { @@ -69,7 +69,11 @@ typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); +#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); +#else +typedef void* sd_event_child_handler_t; +#endif int sd_event_default(sd_event **e); diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h index a3bf5897b8..4dff0b9b81 100644 --- a/src/systemd/sd-id128.h +++ b/src/systemd/sd-id128.h @@ -100,11 +100,11 @@ int sd_id128_get_boot(sd_id128_t *ret); ((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \ 0 }) -_sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) { +_sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) { return memcmp(&a, &b, 16) == 0; } -_sd_pure_ static inline int sd_id128_is_null(sd_id128_t a) { +_sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) { return a.qwords[0] == 0 && a.qwords[1] == 0; } diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index abb9eca576..d4c6f409cd 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -72,7 +72,7 @@ enum { SD_JOURNAL_SYSTEM = 4, SD_JOURNAL_CURRENT_USER = 8, - SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM, /* deprecated name */ + SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM /* deprecated name */ }; /* Wakeup event types */ diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 863c628323..4377f1b910 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1820,7 +1820,7 @@ int main(int argc, char *argv[]) { umask(0022); - r = mac_selinux_init(NULL); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "SELinux setup failed: %m"); goto finish; diff --git a/src/test/test-alloc-util.c b/src/test/test-alloc-util.c new file mode 100644 index 0000000000..cc4821eaf5 --- /dev/null +++ b/src/test/test-alloc-util.c @@ -0,0 +1,55 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "macro.h" +#include "util.h" + +static void test_alloca(void) { + static const uint8_t zero[997] = { }; + char *t; + + t = alloca_align(17, 512); + assert_se(!((uintptr_t)t & 0xff)); + memzero(t, 17); + + t = alloca0_align(997, 1024); + assert_se(!((uintptr_t)t & 0x1ff)); + assert_se(!memcmp(t, zero, 997)); +} + +static void test_memdup_multiply(void) { + int org[] = {1, 2, 3}; + int *dup; + + dup = (int*)memdup_multiply(org, sizeof(int), 3); + + assert_se(dup); + assert_se(dup[0] == 1); + assert_se(dup[1] == 2); + assert_se(dup[2] == 3); + free(dup); +} + +int main(int argc, char *argv[]) { + test_alloca(); + test_memdup_multiply(); + + return 0; +} diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c index d2add5880c..8e68d6510d 100644 --- a/src/test/test-boot-timestamps.c +++ b/src/test/test-boot-timestamps.c @@ -34,17 +34,18 @@ static int test_acpi_fpdt(void) { r = acpi_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { - if (r != -ENOENT) - log_error_errno(r, "Failed to read ACPI FPDT: %m"); - return r; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -ENODATA; + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read ACPI FPDT: %m"); + return ok ? 0 : r; } log_info("ACPI FPDT: loader start=%s exit=%s duration=%s", format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); - - return 0; + return 1; } static int test_efi_loader(void) { @@ -57,33 +58,34 @@ static int test_efi_loader(void) { r = efi_loader_get_boot_usec(&loader_start, &loader_exit); if (r < 0) { - if (r != -ENOENT) - log_error_errno(r, "Failed to read EFI loader data: %m"); - return r; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read EFI loader data: %m"); + return ok ? 0 : r; } log_info("EFI Loader: start=%s exit=%s duration=%s", format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC), format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC), format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC)); - - return 0; + return 1; } -int main(int argc, char* argv[]) { +static int test_boot_timestamps(void) { char s[MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)]; int r; dual_timestamp fw, l, k; - test_acpi_fpdt(); - test_efi_loader(); - dual_timestamp_from_monotonic(&k, 0); r = boot_timestamps(NULL, &fw, &l); if (r < 0) { - log_error_errno(r, "Failed to read variables: %m"); - return 1; + bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES); + + log_full_errno(ok ? LOG_DEBUG : LOG_ERR, + r, "Failed to read variables: %m"); + return ok ? 0 : r; } log_info("Firmware began %s before kernel.", format_timespan(s, sizeof(s), fw.monotonic, 0)); @@ -91,6 +93,21 @@ int main(int argc, char* argv[]) { log_info("Firmware began %s.", format_timestamp(s, sizeof(s), fw.realtime)); log_info("Loader began %s.", format_timestamp(s, sizeof(s), l.realtime)); log_info("Kernel began %s.", format_timestamp(s, sizeof(s), k.realtime)); + return 1; +} + +int main(int argc, char* argv[]) { + int p, q, r; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + p = test_acpi_fpdt(); + assert(p >= 0); + q = test_efi_loader(); + assert(q >= 0); + r = test_boot_timestamps(); + assert(r >= 0); - return 0; + return (p > 0 || q > 0 || r >> 0) ? EXIT_SUCCESS : EXIT_TEST_SKIP; } diff --git a/src/test/test-clock.c b/src/test/test-clock.c new file mode 100644 index 0000000000..84f775e5bc --- /dev/null +++ b/src/test/test-clock.c @@ -0,0 +1,96 @@ +/*** + This file is part of systemd. + + Copyright (C) 2016 Canonical Ltd. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <unistd.h> +#include <fcntl.h> + +#include "clock-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "log.h" +#include "macro.h" + +static void test_clock_is_localtime(void) { + char adjtime[] = "/tmp/test-adjtime.XXXXXX"; + int fd = -1; + _cleanup_fclose_ FILE* f = NULL; + + static const struct scenario { + const char* contents; + int expected_result; + } scenarios[] = { + /* adjtime configures UTC */ + {"0.0 0 0\n0\nUTC\n", 0}, + /* adjtime configures local time */ + {"0.0 0 0\n0\nLOCAL\n", 1}, + /* no final EOL */ + {"0.0 0 0\n0\nUTC", 0}, + {"0.0 0 0\n0\nLOCAL", 1}, + /* empty value -> defaults to UTC */ + {"0.0 0 0\n0\n", 0}, + /* unknown value -> defaults to UTC */ + {"0.0 0 0\n0\nFOO\n", 0}, + /* no third line */ + {"0.0 0 0", 0}, + {"0.0 0 0\n", 0}, + {"0.0 0 0\n0", 0}, + }; + + /* without an adjtime file we default to UTC */ + assert_se(clock_is_localtime("/nonexisting/adjtime") == 0); + + fd = mkostemp_safe(adjtime, O_WRONLY|O_CLOEXEC); + assert_se(fd >= 0); + log_info("adjtime test file: %s", adjtime); + f = fdopen(fd, "w"); + assert_se(f); + + for (size_t i = 0; i < ELEMENTSOF(scenarios); ++i) { + log_info("scenario #%zu:, expected result %i", i, scenarios[i].expected_result); + log_info("%s", scenarios[i].contents); + rewind(f); + ftruncate(fd, 0); + assert_se(write_string_stream(f, scenarios[i].contents, false) == 0); + assert_se(clock_is_localtime(adjtime) == scenarios[i].expected_result); + } + + unlink(adjtime); +} + +/* Test with the real /etc/adjtime */ +static void test_clock_is_localtime_system(void) { + int r; + r = clock_is_localtime(NULL); + + if (access("/etc/adjtime", F_OK) == 0) { + log_info("/etc/adjtime exists, clock_is_localtime() == %i", r); + /* if /etc/adjtime exists we expect some answer, no error or + * crash */ + assert_se(r == 0 || r == 1); + } else + /* default is UTC if there is no /etc/adjtime */ + assert_se(r == 0); +} + +int main(int argc, char *argv[]) { + test_clock_is_localtime(); + test_clock_is_localtime_system(); + + return 0; +} diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index b3a4c40339..be5d2611f8 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -215,6 +215,14 @@ static void test_config_parse_nsec(void) { test_config_parse_nsec_one("garbage", 0); } +static void test_config_parse_iec_uint64(void) { + uint64_t offset = 0; + assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); + assert_se(offset == 4 * 1024 * 1024); + + assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); +} + int main(int argc, char **argv) { log_parse_environment(); log_open(); @@ -230,6 +238,7 @@ int main(int argc, char **argv) { test_config_parse_mode(); test_config_parse_sec(); test_config_parse_nsec(); + test_config_parse_iec_uint64(); return 0; } diff --git a/src/test/test-copy.c b/src/test/test-copy.c index ad57cb0202..1462affbcf 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -24,6 +24,7 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "log.h" #include "macro.h" #include "mkdir.h" #include "path-util.h" @@ -39,6 +40,8 @@ static void test_copy_file(void) { size_t sz = 0; int fd; + log_info("%s", __func__); + fd = mkostemp_safe(fn, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); close(fd); @@ -66,6 +69,8 @@ static void test_copy_file_fd(void) { char text[] = "boohoo\nfoo\n\tbar\n"; char buf[64] = {0}; + log_info("%s", __func__); + in_fd = mkostemp_safe(in_fn, O_RDWR); assert_se(in_fd >= 0); out_fd = mkostemp_safe(out_fn, O_RDWR); @@ -91,6 +96,8 @@ static void test_copy_tree(void) { "link2", "dir1/file"); char **p, **link; + log_info("%s", __func__); + (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL); (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL); @@ -173,11 +180,65 @@ static void test_copy_bytes(void) { assert_se(r == -EBADF); } +static void test_copy_bytes_regular_file(const char *src, bool try_reflink, size_t max_bytes) { + char fn2[] = "/tmp/test-copy-file-XXXXXX"; + char fn3[] = "/tmp/test-copy-file-XXXXXX"; + _cleanup_close_ int fd = -1, fd2 = -1, fd3 = -1; + int r; + struct stat buf, buf2, buf3; + + log_info("%s try_reflink=%s max_bytes=%zu", __func__, yes_no(try_reflink), max_bytes); + + fd = open(src, O_RDONLY | O_CLOEXEC | O_NOCTTY); + assert_se(fd >= 0); + + fd2 = mkostemp_safe(fn2, O_RDWR); + assert_se(fd2 >= 0); + + fd3 = mkostemp_safe(fn3, O_WRONLY); + assert_se(fd3 >= 0); + + r = copy_bytes(fd, fd2, max_bytes, try_reflink); + if (max_bytes == (uint64_t) -1) + assert_se(r == 0); + else + assert_se(IN_SET(r, 0, 1)); + + assert_se(lseek(fd2, 0, SEEK_SET) == 0); + + r = copy_bytes(fd2, fd3, max_bytes, try_reflink); + if (max_bytes == (uint64_t) -1) + assert_se(r == 0); + else + /* We cannot distinguish between the input being exactly max_bytes + * or longer than max_bytes (without trying to read one more byte, + * or calling stat, or FION_READ, etc, and we don't want to do any + * of that). So we expect "truncation" since we know that file we + * are copying is exactly max_bytes bytes. */ + assert_se(r == 1); + + assert_se(fstat(fd, &buf) == 0); + assert_se(fstat(fd2, &buf2) == 0); + assert_se(fstat(fd3, &buf3) == 0); + + assert_se((size_t) buf2.st_size == MIN((size_t) buf.st_size, max_bytes)); + assert_se(buf3.st_size == buf2.st_size); + + unlink(fn2); + unlink(fn3); +} + int main(int argc, char *argv[]) { test_copy_file(); test_copy_file_fd(); test_copy_tree(); test_copy_bytes(); + test_copy_bytes_regular_file(argv[0], false, (uint64_t) -1); + test_copy_bytes_regular_file(argv[0], true, (uint64_t) -1); + test_copy_bytes_regular_file(argv[0], false, 1000); /* smaller than copy buffer size */ + test_copy_bytes_regular_file(argv[0], true, 1000); + test_copy_bytes_regular_file(argv[0], false, 32000); /* larger than copy buffer size */ + test_copy_bytes_regular_file(argv[0], true, 32000); return 0; } diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c new file mode 100644 index 0000000000..8818d1ffb7 --- /dev/null +++ b/src/test/test-cpu-set-util.c @@ -0,0 +1,143 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "cpu-set-util.h" +#include "macro.h" + +static void test_parse_cpu_set(void) { + cpu_set_t *c = NULL; + int ncpus; + int cpu; + + /* Simple range (from CPUAffinity example) */ + ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); + c = mfree(c); + + /* A more interesting range */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Quoted strings */ + ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Use commas as separators */ + ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Commas with spaces (and trailing comma, space) */ + ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 8; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Ranges */ + ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Ranges with trailing comma, space */ + ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Negative range (returns empty cpu_set) */ + ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); + c = mfree(c); + + /* Overlapping ranges */ + ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); + for (cpu = 0; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Mix ranges and individual CPUs */ + ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); + assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 4; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Garbage */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Range with garbage */ + ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + + /* Empty string */ + c = NULL; + ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus == 0); /* empty string returns 0 */ + assert_se(!c); + + /* Runnaway quoted string */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); +} + +int main(int argc, char *argv[]) { + test_parse_cpu_set(); + + return 0; +} diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c index 4ce00f4b1f..a7cb426282 100644 --- a/src/test/test-daemon.c +++ b/src/test/test-daemon.c @@ -38,27 +38,27 @@ int main(int argc, char*argv[]) { sd_notify(0, "STATUS=Starting up"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Running\n" "READY=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Reloading\n" "RELOADING=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Running\n" "READY=1"); - sleep(5); + sleep(1); sd_notify(0, "STATUS=Quitting\n" "STOPPING=1"); - sleep(5); + sleep(1); return EXIT_SUCCESS; } diff --git a/src/test/test-escape.c b/src/test/test-escape.c new file mode 100644 index 0000000000..6cbb8443fe --- /dev/null +++ b/src/test/test-escape.c @@ -0,0 +1,114 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "escape.h" +#include "macro.h" + +static void test_cescape(void) { + _cleanup_free_ char *escaped; + + assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); + assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); +} + +static void test_cunescape(void) { + _cleanup_free_ char *unescaped; + + assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0); + assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00")); + unescaped = mfree(unescaped); + + /* incomplete sequences */ + assert_se(cunescape("\\x0", 0, &unescaped) < 0); + assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\x0")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\x", 0, &unescaped) < 0); + assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\x")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\", 0, &unescaped) < 0); + assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\11", 0, &unescaped) < 0); + assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\11")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\1", 0, &unescaped) < 0); + assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "\\1")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\u0000", 0, &unescaped) < 0); + assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, "ßßΠA")); + unescaped = mfree(unescaped); + + assert_se(cunescape("\\073", 0, &unescaped) >= 0); + assert_se(streq_ptr(unescaped, ";")); +} + +static void test_shell_escape_one(const char *s, const char *bad, const char *expected) { + _cleanup_free_ char *r; + + assert_se(r = shell_escape(s, bad)); + assert_se(streq_ptr(r, expected)); +} + +static void test_shell_escape(void) { + test_shell_escape_one("", "", ""); + test_shell_escape_one("\\", "", "\\\\"); + test_shell_escape_one("foobar", "", "foobar"); + test_shell_escape_one("foobar", "o", "f\\o\\obar"); + test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz"); +} + +static void test_shell_maybe_quote_one(const char *s, const char *expected) { + _cleanup_free_ char *r; + + assert_se(r = shell_maybe_quote(s)); + assert_se(streq(r, expected)); +} + +static void test_shell_maybe_quote(void) { + + test_shell_maybe_quote_one("", ""); + test_shell_maybe_quote_one("\\", "\"\\\\\""); + test_shell_maybe_quote_one("\"", "\"\\\"\""); + test_shell_maybe_quote_one("foobar", "foobar"); + test_shell_maybe_quote_one("foo bar", "\"foo bar\""); + test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\""); + test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\""); +} + +int main(int argc, char *argv[]) { + test_cescape(); + test_cunescape(); + test_shell_escape(); + test_shell_maybe_quote(); + + return 0; +} diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c new file mode 100644 index 0000000000..421d3bdeb3 --- /dev/null +++ b/src/test/test-fd-util.c @@ -0,0 +1,103 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "macro.h" + +static void test_close_many(void) { + int fds[3]; + char name0[] = "/tmp/test-close-many.XXXXXX"; + char name1[] = "/tmp/test-close-many.XXXXXX"; + char name2[] = "/tmp/test-close-many.XXXXXX"; + + fds[0] = mkostemp_safe(name0, O_RDWR|O_CLOEXEC); + fds[1] = mkostemp_safe(name1, O_RDWR|O_CLOEXEC); + fds[2] = mkostemp_safe(name2, O_RDWR|O_CLOEXEC); + + close_many(fds, 2); + + assert_se(fcntl(fds[0], F_GETFD) == -1); + assert_se(fcntl(fds[1], F_GETFD) == -1); + assert_se(fcntl(fds[2], F_GETFD) >= 0); + + safe_close(fds[2]); + + unlink(name0); + unlink(name1); + unlink(name2); +} + +static void test_close_nointr(void) { + char name[] = "/tmp/test-test-close_nointr.XXXXXX"; + int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(close_nointr(fd) >= 0); + assert_se(close_nointr(fd) < 0); + + unlink(name); +} + +static void test_same_fd(void) { + _cleanup_close_pair_ int p[2] = { -1, -1 }; + _cleanup_close_ int a = -1, b = -1, c = -1; + + assert_se(pipe2(p, O_CLOEXEC) >= 0); + assert_se((a = dup(p[0])) >= 0); + assert_se((b = open("/dev/null", O_RDONLY|O_CLOEXEC)) >= 0); + assert_se((c = dup(a)) >= 0); + + assert_se(same_fd(p[0], p[0]) > 0); + assert_se(same_fd(p[1], p[1]) > 0); + assert_se(same_fd(a, a) > 0); + assert_se(same_fd(b, b) > 0); + + assert_se(same_fd(a, p[0]) > 0); + assert_se(same_fd(p[0], a) > 0); + assert_se(same_fd(c, p[0]) > 0); + assert_se(same_fd(p[0], c) > 0); + assert_se(same_fd(a, c) > 0); + assert_se(same_fd(c, a) > 0); + + assert_se(same_fd(p[0], p[1]) == 0); + assert_se(same_fd(p[1], p[0]) == 0); + assert_se(same_fd(p[0], b) == 0); + assert_se(same_fd(b, p[0]) == 0); + assert_se(same_fd(p[1], a) == 0); + assert_se(same_fd(a, p[1]) == 0); + assert_se(same_fd(p[1], b) == 0); + assert_se(same_fd(b, p[1]) == 0); + + assert_se(same_fd(a, b) == 0); + assert_se(same_fd(b, a) == 0); +} + +int main(int argc, char *argv[]) { + test_close_many(); + test_close_nointr(); + test_same_fd(); + + return 0; +} diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 5586a2d6c1..ec9f173da2 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -27,6 +27,7 @@ #include "env-util.h" #include "fd-util.h" #include "fileio.h" +#include "io-util.h" #include "parse-util.h" #include "process-util.h" #include "string-util.h" @@ -425,6 +426,134 @@ static void test_load_env_file_pairs(void) { unlink(fn); } +static void test_search_and_fopen(void) { + const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL}; + char name[] = "/tmp/test-search_and_fopen.XXXXXX"; + int fd = -1; + int r; + FILE *f; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + r = search_and_fopen(basename(name), "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen(name, "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen(basename(name), "r", "/", dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); + assert_se(r < 0); + r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); + assert_se(r < 0); + + r = unlink(name); + assert_se(r == 0); + + r = search_and_fopen(basename(name), "r", NULL, dirs, &f); + assert_se(r < 0); +} + + +static void test_search_and_fopen_nulstr(void) { + const char dirs[] = "/tmp/foo/bar\0/tmp\0"; + char name[] = "/tmp/test-search_and_fopen.XXXXXX"; + int fd = -1; + int r; + FILE *f; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f); + assert_se(r >= 0); + fclose(f); + + r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); + assert_se(r < 0); + r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); + assert_se(r < 0); + + r = unlink(name); + assert_se(r == 0); + + r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); + assert_se(r < 0); +} + +static void test_writing_tmpfile(void) { + char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX"; + _cleanup_free_ char *contents = NULL; + size_t size; + int fd, r; + struct iovec iov[3]; + + IOVEC_SET_STRING(iov[0], "abc\n"); + IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n"); + IOVEC_SET_STRING(iov[2], ""); + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + printf("tmpfile: %s", name); + + r = writev(fd, iov, 3); + assert_se(r >= 0); + + r = read_full_file(name, &contents, &size); + assert_se(r == 0); + printf("contents: %s", contents); + assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n")); + + unlink(name); +} + +static void test_tempfn(void) { + char *ret = NULL, *p; + + assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX")); + free(ret); + + assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0); + assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX")); + free(ret); + + assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/.#waldo")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/waldo/.#")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); + + assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0); + assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]")); + assert_se(strlen(p) == 16); + assert_se(in_charset(p, "0123456789abcdef")); + free(ret); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -439,6 +568,10 @@ int main(int argc, char *argv[]) { test_write_string_file_no_create(); test_write_string_file_verify(); test_load_env_file_pairs(); + test_search_and_fopen(); + test_search_and_fopen_nulstr(); + test_writing_tmpfile(); + test_tempfn(); return 0; } diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c new file mode 100644 index 0000000000..6db2c2b6f1 --- /dev/null +++ b/src/test/test-fs-util.c @@ -0,0 +1,91 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <unistd.h> + +#include "alloc-util.h" +#include "fileio.h" +#include "fd-util.h" +#include "fs-util.h" +#include "macro.h" +#include "mkdir.h" +#include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" + +static void test_unlink_noerrno(void) { + char name[] = "/tmp/test-close_nointr.XXXXXX"; + int fd; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(close_nointr(fd) >= 0); + + { + PROTECT_ERRNO; + errno = -42; + assert_se(unlink_noerrno(name) >= 0); + assert_se(errno == -42); + assert_se(unlink_noerrno(name) < 0); + assert_se(errno == -42); + } +} + +static void test_readlink_and_make_absolute(void) { + char tempdir[] = "/tmp/test-readlink_and_make_absolute"; + char name[] = "/tmp/test-readlink_and_make_absolute/original"; + char name2[] = "test-readlink_and_make_absolute/original"; + char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; + char *r = NULL; + + assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); + assert_se(touch(name) >= 0); + + assert_se(symlink(name, name_alias) >= 0); + assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); + assert_se(streq(r, name)); + free(r); + assert_se(unlink(name_alias) >= 0); + + assert_se(chdir(tempdir) >= 0); + assert_se(symlink(name2, name_alias) >= 0); + assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); + assert_se(streq(r, name)); + free(r); + assert_se(unlink(name_alias) >= 0); + + assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); +} + +static void test_get_files_in_directory(void) { + _cleanup_strv_free_ char **l = NULL, **t = NULL; + + assert_se(get_files_in_directory("/tmp", &l) >= 0); + assert_se(get_files_in_directory(".", &t) >= 0); + assert_se(get_files_in_directory(".", NULL) >= 0); +} + +int main(int argc, char *argv[]) { + test_unlink_noerrno(); + test_readlink_and_make_absolute(); + test_get_files_in_directory(); + + return 0; +} diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c index ea3d1a6909..63a4b8c243 100644 --- a/src/test/test-fstab-util.c +++ b/src/test/test-fstab-util.c @@ -131,8 +131,45 @@ static void test_fstab_yes_no_option(void) { assert_se(fstab_test_yes_no_option("nofail,nofail=0,fail=0", "nofail\0fail\0") == false); } +static void test_fstab_node_to_udev_node(void) { + char *n; + + n = fstab_node_to_udev_node("LABEL=applé/jack"); + puts(n); + assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack")); + free(n); + + n = fstab_node_to_udev_node("PARTLABEL=pinkié pie"); + puts(n); + assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie")); + free(n); + + n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); + puts(n); + assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); + free(n); + + n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); + puts(n); + assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); + free(n); + + n = fstab_node_to_udev_node("PONIES=awesome"); + puts(n); + assert_se(streq(n, "PONIES=awesome")); + free(n); + + n = fstab_node_to_udev_node("/dev/xda1"); + puts(n); + assert_se(streq(n, "/dev/xda1")); + free(n); +} + int main(void) { test_fstab_filter_options(); test_fstab_find_pri(); test_fstab_yes_no_option(); + test_fstab_node_to_udev_node(); + + return 0; } diff --git a/src/test/test-glob-util.c b/src/test/test-glob-util.c new file mode 100644 index 0000000000..227d4290f0 --- /dev/null +++ b/src/test/test-glob-util.c @@ -0,0 +1,50 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fileio.h" +#include "glob-util.h" +#include "macro.h" + +static void test_glob_exists(void) { + char name[] = "/tmp/test-glob_exists.XXXXXX"; + int fd = -1; + int r; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + close(fd); + + r = glob_exists("/tmp/test-glob_exists*"); + assert_se(r == 1); + + r = unlink(name); + assert_se(r == 0); + r = glob_exists("/tmp/test-glob_exists*"); + assert_se(r == 0); +} + +int main(void) { + test_glob_exists(); + + return 0; +} diff --git a/src/test/test-hexdecoct.c b/src/test/test-hexdecoct.c new file mode 100644 index 0000000000..276f25d091 --- /dev/null +++ b/src/test/test-hexdecoct.c @@ -0,0 +1,387 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "hexdecoct.h" +#include "macro.h" +#include "string-util.h" + +static void test_hexchar(void) { + assert_se(hexchar(0xa) == 'a'); + assert_se(hexchar(0x0) == '0'); +} + +static void test_unhexchar(void) { + assert_se(unhexchar('a') == 0xA); + assert_se(unhexchar('A') == 0xA); + assert_se(unhexchar('0') == 0x0); +} + +static void test_base32hexchar(void) { + assert_se(base32hexchar(0) == '0'); + assert_se(base32hexchar(9) == '9'); + assert_se(base32hexchar(10) == 'A'); + assert_se(base32hexchar(31) == 'V'); +} + +static void test_unbase32hexchar(void) { + assert_se(unbase32hexchar('0') == 0); + assert_se(unbase32hexchar('9') == 9); + assert_se(unbase32hexchar('A') == 10); + assert_se(unbase32hexchar('V') == 31); + assert_se(unbase32hexchar('=') == -EINVAL); +} + +static void test_base64char(void) { + assert_se(base64char(0) == 'A'); + assert_se(base64char(26) == 'a'); + assert_se(base64char(63) == '/'); +} + +static void test_unbase64char(void) { + assert_se(unbase64char('A') == 0); + assert_se(unbase64char('Z') == 25); + assert_se(unbase64char('a') == 26); + assert_se(unbase64char('z') == 51); + assert_se(unbase64char('0') == 52); + assert_se(unbase64char('9') == 61); + assert_se(unbase64char('+') == 62); + assert_se(unbase64char('/') == 63); + assert_se(unbase64char('=') == -EINVAL); +} + +static void test_octchar(void) { + assert_se(octchar(00) == '0'); + assert_se(octchar(07) == '7'); +} + +static void test_unoctchar(void) { + assert_se(unoctchar('0') == 00); + assert_se(unoctchar('7') == 07); +} + +static void test_decchar(void) { + assert_se(decchar(0) == '0'); + assert_se(decchar(9) == '9'); +} + +static void test_undecchar(void) { + assert_se(undecchar('0') == 0); + assert_se(undecchar('9') == 9); +} + +static void test_unhexmem(void) { + const char *hex = "efa214921"; + const char *hex_invalid = "efa214921o"; + _cleanup_free_ char *hex2 = NULL; + _cleanup_free_ void *mem = NULL; + size_t len; + + assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0); + assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL); + assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL); + + assert_se((hex2 = hexmem(mem, len))); + + free(mem); + + assert_se(memcmp(hex, hex2, strlen(hex)) == 0); + + free(hex2); + + assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0); + assert_se((hex2 = hexmem(mem, len))); + assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0); +} + +/* https://tools.ietf.org/html/rfc4648#section-10 */ +static void test_base32hexmem(void) { + char *b32; + + b32 = base32hexmem("", strlen(""), true); + assert_se(b32); + assert_se(streq(b32, "")); + free(b32); + + b32 = base32hexmem("f", strlen("f"), true); + assert_se(b32); + assert_se(streq(b32, "CO======")); + free(b32); + + b32 = base32hexmem("fo", strlen("fo"), true); + assert_se(b32); + assert_se(streq(b32, "CPNG====")); + free(b32); + + b32 = base32hexmem("foo", strlen("foo"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMU===")); + free(b32); + + b32 = base32hexmem("foob", strlen("foob"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOG=")); + free(b32); + + b32 = base32hexmem("fooba", strlen("fooba"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1")); + free(b32); + + b32 = base32hexmem("foobar", strlen("foobar"), true); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1E8======")); + free(b32); + + b32 = base32hexmem("", strlen(""), false); + assert_se(b32); + assert_se(streq(b32, "")); + free(b32); + + b32 = base32hexmem("f", strlen("f"), false); + assert_se(b32); + assert_se(streq(b32, "CO")); + free(b32); + + b32 = base32hexmem("fo", strlen("fo"), false); + assert_se(b32); + assert_se(streq(b32, "CPNG")); + free(b32); + + b32 = base32hexmem("foo", strlen("foo"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMU")); + free(b32); + + b32 = base32hexmem("foob", strlen("foob"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOG")); + free(b32); + + b32 = base32hexmem("fooba", strlen("fooba"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1")); + free(b32); + + b32 = base32hexmem("foobar", strlen("foobar"), false); + assert_se(b32); + assert_se(streq(b32, "CPNMUOJ1E8")); + free(b32); +} + +static void test_unbase32hexmem(void) { + void *mem; + size_t len; + + assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL); + + assert_se(unbase32hexmem("XPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CXNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPXMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNXUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMXOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUXJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOX1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOJX", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); + + assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL); + assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL); +} + +/* https://tools.ietf.org/html/rfc4648#section-10 */ +static void test_base64mem(void) { + char *b64; + + assert_se(base64mem("", strlen(""), &b64) == 0); + assert_se(streq(b64, "")); + free(b64); + + assert_se(base64mem("f", strlen("f"), &b64) == 4); + assert_se(streq(b64, "Zg==")); + free(b64); + + assert_se(base64mem("fo", strlen("fo"), &b64) == 4); + assert_se(streq(b64, "Zm8=")); + free(b64); + + assert_se(base64mem("foo", strlen("foo"), &b64) == 4); + assert_se(streq(b64, "Zm9v")); + free(b64); + + assert_se(base64mem("foob", strlen("foob"), &b64) == 8); + assert_se(streq(b64, "Zm9vYg==")); + free(b64); + + assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8); + assert_se(streq(b64, "Zm9vYmE=")); + free(b64); + + assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8); + assert_se(streq(b64, "Zm9vYmFy")); + free(b64); +} + +static void test_unbase64mem(void) { + void *mem; + size_t len; + + assert_se(unbase64mem("", strlen(""), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "")); + free(mem); + + assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "f")); + free(mem); + + assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fo")); + free(mem); + + assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foo")); + free(mem); + + assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foob")); + free(mem); + + assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "fooba")); + free(mem); + + assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0); + assert_se(streq(strndupa(mem, len), "foobar")); + free(mem); + + assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL); + assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL); + assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL); + assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL); +} + +static void test_hexdump(void) { + uint8_t data[146]; + unsigned i; + + hexdump(stdout, NULL, 0); + hexdump(stdout, "", 0); + hexdump(stdout, "", 1); + hexdump(stdout, "x", 1); + hexdump(stdout, "x", 2); + hexdump(stdout, "foobar", 7); + hexdump(stdout, "f\nobar", 7); + hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23); + + for (i = 0; i < ELEMENTSOF(data); i++) + data[i] = i*2; + + hexdump(stdout, data, sizeof(data)); +} + +int main(int argc, char *argv[]) { + test_hexchar(); + test_unhexchar(); + test_base32hexchar(); + test_unbase32hexchar(); + test_base64char(); + test_unbase64char(); + test_octchar(); + test_unoctchar(); + test_decchar(); + test_undecchar(); + test_unhexmem(); + test_base32hexmem(); + test_unbase32hexmem(); + test_base64mem(); + test_unbase64mem(); + test_hexdump(); + + return 0; +} diff --git a/src/test/test-io-util.c b/src/test/test-io-util.c new file mode 100644 index 0000000000..10bd3833bc --- /dev/null +++ b/src/test/test-io-util.c @@ -0,0 +1,69 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" +#include "macro.h" + +static void test_sparse_write_one(int fd, const char *buffer, size_t n) { + char check[n]; + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(ftruncate(fd, 0) >= 0); + assert_se(sparse_write(fd, buffer, n, 4) == (ssize_t) n); + + assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n); + assert_se(ftruncate(fd, n) >= 0); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(read(fd, check, n) == (ssize_t) n); + + assert_se(memcmp(buffer, check, n) == 0); +} + +static void test_sparse_write(void) { + const char test_a[] = "test"; + const char test_b[] = "\0\0\0\0test\0\0\0\0"; + const char test_c[] = "\0\0test\0\0\0\0"; + const char test_d[] = "\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0\0\0\0"; + const char test_e[] = "test\0\0\0\0test"; + _cleanup_close_ int fd = -1; + char fn[] = "/tmp/sparseXXXXXX"; + + fd = mkostemp(fn, O_CLOEXEC); + assert_se(fd >= 0); + unlink(fn); + + test_sparse_write_one(fd, test_a, sizeof(test_a)); + test_sparse_write_one(fd, test_b, sizeof(test_b)); + test_sparse_write_one(fd, test_c, sizeof(test_c)); + test_sparse_write_one(fd, test_d, sizeof(test_d)); + test_sparse_write_one(fd, test_e, sizeof(test_e)); +} + +int main(void) { + test_sparse_write(); + + return 0; +} diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c index 2464d32458..c5bcaf47bb 100644 --- a/src/test/test-ipcrm.c +++ b/src/test/test-ipcrm.c @@ -23,9 +23,14 @@ int main(int argc, char *argv[]) { uid_t uid; - - assert_se(argc == 2); - assert_se(parse_uid(argv[1], &uid) >= 0); + int r; + const char* name = argv[1] ?: "nfsnobody"; + + r = get_user_creds(&name, &uid, NULL, NULL, NULL); + if (r < 0) { + log_error_errno(r, "Failed to resolve \"%s\": %m", name); + return EXIT_FAILURE; + } return clean_ipc(uid) < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index a7eb60e8cf..e28de9b37b 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -24,170 +24,140 @@ #include "libudev.h" +#include "fd-util.h" +#include "log.h" #include "stdio-util.h" #include "string-util.h" #include "udev-util.h" #include "util.h" -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - static void print_device(struct udev_device *device) { const char *str; dev_t devnum; int count; struct udev_list_entry *list_entry; - printf("*** device: %p ***\n", device); + log_info("*** device: %p ***", device); str = udev_device_get_action(device); if (str != NULL) - printf("action: '%s'\n", str); + log_info("action: '%s'", str); str = udev_device_get_syspath(device); - printf("syspath: '%s'\n", str); + log_info("syspath: '%s'", str); str = udev_device_get_sysname(device); - printf("sysname: '%s'\n", str); + log_info("sysname: '%s'", str); str = udev_device_get_sysnum(device); if (str != NULL) - printf("sysnum: '%s'\n", str); + log_info("sysnum: '%s'", str); str = udev_device_get_devpath(device); - printf("devpath: '%s'\n", str); + log_info("devpath: '%s'", str); str = udev_device_get_subsystem(device); if (str != NULL) - printf("subsystem: '%s'\n", str); + log_info("subsystem: '%s'", str); str = udev_device_get_devtype(device); if (str != NULL) - printf("devtype: '%s'\n", str); + log_info("devtype: '%s'", str); str = udev_device_get_driver(device); if (str != NULL) - printf("driver: '%s'\n", str); + log_info("driver: '%s'", str); str = udev_device_get_devnode(device); if (str != NULL) - printf("devname: '%s'\n", str); + log_info("devname: '%s'", str); devnum = udev_device_get_devnum(device); if (major(devnum) > 0) - printf("devnum: %u:%u\n", major(devnum), minor(devnum)); + log_info("devnum: %u:%u", major(devnum), minor(devnum)); count = 0; udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) { - printf("link: '%s'\n", udev_list_entry_get_name(list_entry)); + log_info("link: '%s'", udev_list_entry_get_name(list_entry)); count++; } if (count > 0) - printf("found %i links\n", count); + log_info("found %i links", count); count = 0; udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) { - printf("property: '%s=%s'\n", + log_info("property: '%s=%s'", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); count++; } if (count > 0) - printf("found %i properties\n", count); + log_info("found %i properties", count); str = udev_device_get_property_value(device, "MAJOR"); if (str != NULL) - printf("MAJOR: '%s'\n", str); + log_info("MAJOR: '%s'", str); str = udev_device_get_sysattr_value(device, "dev"); if (str != NULL) - printf("attr{dev}: '%s'\n", str); - - printf("\n"); + log_info("attr{dev}: '%s'", str); } -static int test_device(struct udev *udev, const char *syspath) { +static void test_device(struct udev *udev, const char *syspath) { _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking at device: %s\n", syspath); + log_info("looking at device: %s", syspath); device = udev_device_new_from_syspath(udev, syspath); - if (device == NULL) { - printf("no device found\n"); - return -1; - } - print_device(device); - - return 0; + if (device == NULL) + log_warning_errno(errno, "udev_device_new_from_syspath: %m"); + else + print_device(device); } -static int test_device_parents(struct udev *udev, const char *syspath) { +static void test_device_parents(struct udev *udev, const char *syspath) { _cleanup_udev_device_unref_ struct udev_device *device; struct udev_device *device_parent; - printf("looking at device: %s\n", syspath); + log_info("looking at device: %s", syspath); device = udev_device_new_from_syspath(udev, syspath); if (device == NULL) - return -1; + return; - printf("looking at parents\n"); + log_info("looking at parents"); device_parent = device; do { print_device(device_parent); device_parent = udev_device_get_parent(device_parent); } while (device_parent != NULL); - printf("looking at parents again\n"); + log_info("looking at parents again"); device_parent = device; do { print_device(device_parent); device_parent = udev_device_get_parent(device_parent); } while (device_parent != NULL); - - return 0; } -static int test_device_devnum(struct udev *udev) { +static void test_device_devnum(struct udev *udev) { dev_t devnum = makedev(1, 3); - struct udev_device *device; + _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking up device: %u:%u\n", major(devnum), minor(devnum)); + log_info("looking up device: %u:%u", major(devnum), minor(devnum)); device = udev_device_new_from_devnum(udev, 'c', devnum); if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - return 0; + log_warning_errno(errno, "udev_device_new_from_devnum: %m"); + else + print_device(device); } -static int test_device_subsys_name(struct udev *udev) { - struct udev_device *device; - - printf("looking up device: 'block':'sda'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "block", "sda"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'subsystem':'pci'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'drivers':'scsi:sd'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); +static void test_device_subsys_name(struct udev *udev, const char *subsys, const char *dev) { + _cleanup_udev_device_unref_ struct udev_device *device; - printf("looking up device: 'module':'printk'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "module", "printk"); + log_info("looking up device: '%s:%s'", subsys, dev); + device = udev_device_new_from_subsystem_sysname(udev, subsys, dev); if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - return 0; + log_warning_errno(errno, "udev_device_new_from_subsystem_sysname: %m"); + else + print_device(device); } static int test_enumerate_print_list(struct udev_enumerate *enumerate) { @@ -200,63 +170,45 @@ static int test_enumerate_print_list(struct udev_enumerate *enumerate) { device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), udev_list_entry_get_name(list_entry)); if (device != NULL) { - printf("device: '%s' (%s)\n", - udev_device_get_syspath(device), - udev_device_get_subsystem(device)); + log_info("device: '%s' (%s)", + udev_device_get_syspath(device), + udev_device_get_subsystem(device)); udev_device_unref(device); count++; } } - printf("found %i devices\n\n", count); + log_info("found %i devices", count); return count; } -static int test_monitor(struct udev *udev) { - struct udev_monitor *udev_monitor = NULL; - int fd_ep; - int fd_udev = -1; - struct epoll_event ep_udev, ep_stdin; +static void test_monitor(struct udev *udev) { + _cleanup_udev_monitor_unref_ struct udev_monitor *udev_monitor; + _cleanup_close_ int fd_ep; + int fd_udev; + struct epoll_event ep_udev = { + .events = EPOLLIN, + }, ep_stdin = { + .events = EPOLLIN, + .data.fd = STDIN_FILENO, + }; fd_ep = epoll_create1(EPOLL_CLOEXEC); - if (fd_ep < 0) { - printf("error creating epoll fd: %m\n"); - goto out; - } + assert_se(fd_ep >= 0); udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); - if (udev_monitor == NULL) { - printf("no socket\n"); - goto out; - } + assert_se(udev_monitor != NULL); + fd_udev = udev_monitor_get_fd(udev_monitor); + ep_udev.data.fd = fd_udev; - if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 || - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 || - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) { - printf("filter failed\n"); - goto out; - } + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) >= 0); + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) >= 0); + assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") >= 0); - if (udev_monitor_enable_receiving(udev_monitor) < 0) { - printf("bind failed\n"); - goto out; - } + assert_se(udev_monitor_enable_receiving(udev_monitor) >= 0); - memzero(&ep_udev, sizeof(struct epoll_event)); - ep_udev.events = EPOLLIN; - ep_udev.data.fd = fd_udev; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) { - printf("fail to add fd to epoll: %m\n"); - goto out; - } - - memzero(&ep_stdin, sizeof(struct epoll_event)); - ep_stdin.events = EPOLLIN; - ep_stdin.data.fd = STDIN_FILENO; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) { - printf("fail to add fd to epoll: %m\n"); - goto out; - } + assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) >= 0); + assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) >= 0); for (;;) { int fdcount; @@ -265,7 +217,7 @@ static int test_monitor(struct udev *udev) { int i; printf("waiting for events from udev, press ENTER to exit\n"); - fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); + fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1); printf("epoll fd count: %i\n", fdcount); for (i = 0; i < fdcount; i++) { @@ -279,36 +231,29 @@ static int test_monitor(struct udev *udev) { udev_device_unref(device); } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) { printf("exiting loop\n"); - goto out; + return; } } } -out: - if (fd_ep >= 0) - close(fd_ep); - udev_monitor_unref(udev_monitor); - return 0; } -static int test_queue(struct udev *udev) { +static void test_queue(struct udev *udev) { struct udev_queue *udev_queue; + bool empty; udev_queue = udev_queue_new(udev); - if (udev_queue == NULL) - return -1; - - if (udev_queue_get_queue_is_empty(udev_queue)) - printf("queue is empty\n"); + assert_se(udev_queue); + empty = udev_queue_get_queue_is_empty(udev_queue); + log_info("queue is %s", empty ? "empty" : "not empty"); udev_queue_unref(udev_queue); - return 0; } static int test_enumerate(struct udev *udev, const char *subsystem) { struct udev_enumerate *udev_enumerate; int r; - printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem); + log_info("enumerate '%s'", subsystem == NULL ? "<all>" : subsystem); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -317,7 +262,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'net' + duplicated scan + null + zero\n"); + log_info("enumerate 'net' + duplicated scan + null + zero"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -337,7 +282,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'block'\n"); + log_info("enumerate 'block'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -351,7 +296,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'not block'\n"); + log_info("enumerate 'not block'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -360,7 +305,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'pci, mem, vc'\n"); + log_info("enumerate 'pci, mem, vc'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -371,7 +316,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'subsystem'\n"); + log_info("enumerate 'subsystem'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -379,7 +324,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) { test_enumerate_print_list(udev_enumerate); udev_enumerate_unref(udev_enumerate); - printf("enumerate 'property IF_FS_*=filesystem'\n"); + log_info("enumerate 'property IF_FS_*=filesystem'"); udev_enumerate = udev_enumerate_new(udev); if (udev_enumerate == NULL) return -1; @@ -397,32 +342,32 @@ static void test_hwdb(struct udev *udev, const char *modalias) { hwdb = udev_hwdb_new(udev); udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0)) - printf("'%s'='%s'\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); - printf("\n"); + log_info("'%s'='%s'", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry)); hwdb = udev_hwdb_unref(hwdb); assert_se(hwdb == NULL); } int main(int argc, char *argv[]) { - struct udev *udev = NULL; + _cleanup_udev_unref_ struct udev *udev = NULL; + bool arg_monitor = false; static const struct option options[] = { - { "syspath", required_argument, NULL, 'p' }, + { "syspath", required_argument, NULL, 'p' }, { "subsystem", required_argument, NULL, 's' }, - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "monitor", no_argument, NULL, 'm' }, {} }; const char *syspath = "/devices/virtual/mem/null"; const char *subsystem = NULL; - char path[1024]; int c; udev = udev_new(); - printf("context: %p\n", udev); + log_info("context: %p", udev); if (udev == NULL) { - printf("no context\n"); + log_info("no context"); return 1; } @@ -444,14 +389,18 @@ int main(int argc, char *argv[]) { case 'h': printf("--debug --syspath= --subsystem= --help\n"); - goto out; + return EXIT_SUCCESS; case 'V': printf("%s\n", VERSION); - goto out; + return EXIT_SUCCESS; + + case 'm': + arg_monitor = true; + break; case '?': - goto out; + return EXIT_FAILURE; default: assert_not_reached("Unhandled option code."); @@ -459,14 +408,16 @@ int main(int argc, char *argv[]) { /* add sys path if needed */ - if (!startswith(syspath, "/sys")) { - xsprintf(path, "/sys/%s", syspath); - syspath = path; - } + if (!startswith(syspath, "/sys")) + syspath = strjoina("/sys/", syspath); test_device(udev, syspath); test_device_devnum(udev); - test_device_subsys_name(udev); + test_device_subsys_name(udev, "block", "sda"); + test_device_subsys_name(udev, "subsystem", "pci"); + test_device_subsys_name(udev, "drivers", "scsi:sd"); + test_device_subsys_name(udev, "module", "printk"); + test_device_parents(udev, syspath); test_enumerate(udev, subsystem); @@ -475,8 +426,8 @@ int main(int argc, char *argv[]) { test_hwdb(udev, "usb:v0D50p0011*"); - test_monitor(udev); -out: - udev_unref(udev); - return 0; + if (arg_monitor) + test_monitor(udev); + + return EXIT_SUCCESS; } diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c index 2748395ade..7b67337331 100644 --- a/src/test/test-loopback.c +++ b/src/test/test-loopback.c @@ -31,7 +31,7 @@ int main(int argc, char* argv[]) { r = loopback_setup(); if (r < 0) - fprintf(stderr, "loopback: %s\n", strerror(-r)); + log_error("loopback: %m"); - return 0; + return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 53a585290a..d376dd56c5 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -433,6 +433,50 @@ static void test_path_is_mount_point(void) { assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0); } +static void test_file_in_same_dir(void) { + char *t; + + t = file_in_same_dir("/", "a"); + assert_se(streq(t, "/a")); + free(t); + + t = file_in_same_dir("/", "/a"); + assert_se(streq(t, "/a")); + free(t); + + t = file_in_same_dir("", "a"); + assert_se(streq(t, "a")); + free(t); + + t = file_in_same_dir("a/", "a"); + assert_se(streq(t, "a/a")); + free(t); + + t = file_in_same_dir("bar/foo", "bar"); + assert_se(streq(t, "bar/bar")); + free(t); +} + +static void test_filename_is_valid(void) { + char foo[FILENAME_MAX+2]; + int i; + + assert_se(!filename_is_valid("")); + assert_se(!filename_is_valid("/bar/foo")); + assert_se(!filename_is_valid("/")); + assert_se(!filename_is_valid(".")); + assert_se(!filename_is_valid("..")); + + for (i=0; i<FILENAME_MAX+1; i++) + foo[i] = 'a'; + foo[FILENAME_MAX+1] = '\0'; + + assert_se(!filename_is_valid(foo)); + + assert_se(filename_is_valid("foo_bar-333")); + assert_se(filename_is_valid("o.o")); +} + int main(int argc, char **argv) { test_path(); test_find_binary(argv[0]); @@ -444,6 +488,8 @@ int main(int argc, char **argv) { test_path_startswith(); test_prefix_root(); test_path_is_mount_point(); + test_file_in_same_dir(); + test_filename_is_valid(); return 0; } diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c new file mode 100644 index 0000000000..a7a8f621a2 --- /dev/null +++ b/src/test/test-proc-cmdline.c @@ -0,0 +1,52 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "log.h" +#include "macro.h" +#include "proc-cmdline.h" +#include "special.h" +#include "string-util.h" + +static int parse_item(const char *key, const char *value) { + assert_se(key); + + log_info("kernel cmdline option <%s> = <%s>", key, strna(value)); + return 0; +} + +static void test_parse_proc_cmdline(void) { + assert_se(parse_proc_cmdline(parse_item) >= 0); +} + +static void test_runlevel_to_target(void) { + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); +} + +int main(void) { + log_parse_environment(); + log_open(); + + test_parse_proc_cmdline(); + test_runlevel_to_target(); + + return 0; +} diff --git a/src/test/test-selinux.c b/src/test/test-selinux.c new file mode 100644 index 0000000000..7545ad3764 --- /dev/null +++ b/src/test/test-selinux.c @@ -0,0 +1,122 @@ +/*** + This file is part of systemd. + + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/stat.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "log.h" +#include "selinux-util.h" +#include "string-util.h" +#include "time-util.h" +#include "util.h" + +static void test_testing(void) { + bool b; + + log_info("============ %s ==========", __func__); + + b = mac_selinux_use(); + log_info("mac_selinux_use → %s", yes_no(b)); + + b = mac_selinux_have(); + log_info("mac_selinux_have → %s", yes_no(b)); + + mac_selinux_retest(); + + b = mac_selinux_use(); + log_info("mac_selinux_use → %s", yes_no(b)); + + b = mac_selinux_have(); + log_info("mac_selinux_have → %s", yes_no(b)); +} + +static void test_loading(void) { + usec_t n1, n2; + int r; + + log_info("============ %s ==========", __func__); + + n1 = now(CLOCK_MONOTONIC); + r = mac_selinux_init(); + n2 = now(CLOCK_MONOTONIC); + log_info_errno(r, "mac_selinux_init → %d (%m) %.2fs", r, (n2 - n1)/1e6); +} + +static void test_cleanup(void) { + usec_t n1, n2; + + log_info("============ %s ==========", __func__); + + n1 = now(CLOCK_MONOTONIC); + mac_selinux_finish(); + n2 = now(CLOCK_MONOTONIC); + log_info("mac_selinux_finish → %.2fs", (n2 - n1)/1e6); +} + +static void test_misc(const char* fname) { + _cleanup_(mac_selinux_freep) char *label = NULL, *label2 = NULL, *label3 = NULL; + int r; + _cleanup_close_ int fd = -1; + + log_info("============ %s ==========", __func__); + + r = mac_selinux_get_our_label(&label); + log_info_errno(r, "mac_selinux_get_our_label → %d (%m), \"%s\"", + r, strnull(label)); + + r = mac_selinux_get_create_label_from_exe(fname, &label2); + log_info_errno(r, "mac_selinux_create_label_from_exe → %d (%m), \"%s\"", + r, strnull(label2)); + + fd = socket(AF_INET, SOCK_DGRAM, 0); + assert_se(fd >= 0); + + r = mac_selinux_get_child_mls_label(fd, fname, label2, &label3); + log_info_errno(r, "mac_selinux_get_child_mls_label → %d (%m), \"%s\"", + r, strnull(label3)); +} + +static void test_create_file_prepare(const char* fname) { + int r; + + log_info("============ %s ==========", __func__); + + r = mac_selinux_create_file_prepare(fname, S_IRWXU); + log_info_errno(r, "mac_selinux_create_file_prepare → %d (%m)", r); + + mac_selinux_create_file_clear(); +} + +int main(int argc, char **argv) { + const char *path = SYSTEMD_BINARY_PATH; + if (argc >= 2) + path = argv[1]; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + + test_testing(); + test_loading(); + test_misc(path); + test_create_file_prepare(path); + test_cleanup(); + + return 0; +} diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c index 3083501ce9..671eb869cb 100644 --- a/src/test/test-signal-util.c +++ b/src/test/test-signal-util.c @@ -17,6 +17,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <signal.h> +#include <unistd.h> + +#include "macro.h" #include "signal-util.h" static void test_block_signals(void) { @@ -44,6 +48,20 @@ static void test_block_signals(void) { assert_se(sigismember(&ss, SIGVTALRM) == 0); } +static void test_ignore_signals(void) { + assert_se(ignore_signals(SIGINT, -1) >= 0); + assert_se(kill(getpid(), SIGINT) >= 0); + assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); + assert_se(kill(getpid(), SIGUSR1) >= 0); + assert_se(kill(getpid(), SIGUSR2) >= 0); + assert_se(kill(getpid(), SIGTERM) >= 0); + assert_se(kill(getpid(), SIGPIPE) >= 0); + assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); +} + int main(int argc, char *argv[]) { test_block_signals(); + test_ignore_signals(); + + return 0; } diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c new file mode 100644 index 0000000000..8f99a13772 --- /dev/null +++ b/src/test/test-sizeof.c @@ -0,0 +1,53 @@ +/*** + This file is part of systemd. + + Copyright 2016 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "log.h" +#include "time-util.h" + +/* Print information about various types. Useful when diagnosing + * gcc diagnostics on an unfamiliar architecture. */ + +#pragma GCC diagnostic ignored "-Wtype-limits" + +#define info(t) \ + log_info("%s → %zu bits%s", STRINGIFY(t), \ + sizeof(t)*CHAR_BIT, \ + strstr(STRINGIFY(t), "signed") ? "" : \ + ((t)-1 < (t)0 ? ", signed" : ", unsigned")); + +int main(void) { + info(char); + info(signed char); + info(unsigned char); + info(short unsigned); + info(unsigned); + info(long unsigned); + info(long long unsigned); + + info(float); + info(double); + info(long double); + + info(size_t); + info(ssize_t); + info(time_t); + info(usec_t); + + return 0; +} diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c new file mode 100644 index 0000000000..a10227f823 --- /dev/null +++ b/src/test/test-stat-util.c @@ -0,0 +1,68 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "macro.h" +#include "stat-util.h" + +static void test_files_same(void) { + _cleanup_close_ int fd = -1; + char name[] = "/tmp/test-files_same.XXXXXX"; + char name_alias[] = "/tmp/test-files_same.alias"; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(symlink(name, name_alias) >= 0); + + assert_se(files_same(name, name)); + assert_se(files_same(name, name_alias)); + + unlink(name); + unlink(name_alias); +} + +static void test_is_symlink(void) { + char name[] = "/tmp/test-is_symlink.XXXXXX"; + char name_link[] = "/tmp/test-is_symlink.link"; + _cleanup_close_ int fd = -1; + + fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + assert_se(symlink(name, name_link) >= 0); + + assert_se(is_symlink(name) == 0); + assert_se(is_symlink(name_link) == 1); + assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); + + + unlink(name); + unlink(name_link); +} + +int main(int argc, char *argv[]) { + test_files_same(); + test_is_symlink(); + + return 0; +} diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 9b48e95998..d0f84d70bc 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -17,7 +17,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "macro.h" #include "string-util.h" +#include "strv.h" static void test_string_erase(void) { char *x; @@ -97,9 +100,271 @@ static void test_ascii_strcasecmp_nn(void) { assert_se(ascii_strcasecmp_nn("BBbb", 4, "aaaa", 4) > 0); } +static void test_streq_ptr(void) { + assert_se(streq_ptr(NULL, NULL)); + assert_se(!streq_ptr("abc", "cdef")); +} + +static void test_strstrip(void) { + char *r; + char input[] = " hello, waldo. "; + + r = strstrip(input); + assert_se(streq(r, "hello, waldo.")); +} + +static void test_strextend(void) { + _cleanup_free_ char *str = strdup("0123"); + strextend(&str, "456", "78", "9", NULL); + assert_se(streq(str, "0123456789")); +} + +static void test_strrep(void) { + _cleanup_free_ char *one, *three, *zero; + one = strrep("waldo", 1); + three = strrep("waldo", 3); + zero = strrep("waldo", 0); + + assert_se(streq(one, "waldo")); + assert_se(streq(three, "waldowaldowaldo")); + assert_se(streq(zero, "")); +} + + +static void test_strappend(void) { + _cleanup_free_ char *t1, *t2, *t3, *t4; + + t1 = strappend(NULL, NULL); + assert_se(streq(t1, "")); + + t2 = strappend(NULL, "suf"); + assert_se(streq(t2, "suf")); + + t3 = strappend("pre", NULL); + assert_se(streq(t3, "pre")); + + t4 = strappend("pre", "suf"); + assert_se(streq(t4, "presuf")); +} + +static void test_string_has_cc(void) { + assert_se(string_has_cc("abc\1", NULL)); + assert_se(string_has_cc("abc\x7f", NULL)); + assert_se(string_has_cc("abc\x7f", NULL)); + assert_se(string_has_cc("abc\t\x7f", "\t")); + assert_se(string_has_cc("abc\t\x7f", "\t")); + assert_se(string_has_cc("\x7f", "\t")); + assert_se(string_has_cc("\x7f", "\t\a")); + + assert_se(!string_has_cc("abc\t\t", "\t")); + assert_se(!string_has_cc("abc\t\t\a", "\t\a")); + assert_se(!string_has_cc("a\ab\tc", "\t\a")); +} + +static void test_ascii_strlower(void) { + char a[] = "AabBcC Jk Ii Od LKJJJ kkd LK"; + assert_se(streq(ascii_strlower(a), "aabbcc jk ii od lkjjj kkd lk")); +} + +static void test_strshorten(void) { + char s[] = "foobar"; + + assert_se(strlen(strshorten(s, 6)) == 6); + assert_se(strlen(strshorten(s, 12)) == 6); + assert_se(strlen(strshorten(s, 2)) == 2); + assert_se(strlen(strshorten(s, 0)) == 0); +} + +static void test_strjoina(void) { + char *actual; + + actual = strjoina("", "foo", "bar"); + assert_se(streq(actual, "foobar")); + + actual = strjoina("foo", "bar", "baz"); + assert_se(streq(actual, "foobarbaz")); + + actual = strjoina("foo", "", "bar", "baz"); + assert_se(streq(actual, "foobarbaz")); + + actual = strjoina("foo"); + assert_se(streq(actual, "foo")); + + actual = strjoina(NULL); + assert_se(streq(actual, "")); + + actual = strjoina(NULL, "foo"); + assert_se(streq(actual, "")); + + actual = strjoina("foo", NULL, "bar"); + assert_se(streq(actual, "foo")); +} + +static void test_strcmp_ptr(void) { + assert_se(strcmp_ptr(NULL, NULL) == 0); + assert_se(strcmp_ptr("", NULL) > 0); + assert_se(strcmp_ptr("foo", NULL) > 0); + assert_se(strcmp_ptr(NULL, "") < 0); + assert_se(strcmp_ptr(NULL, "bar") < 0); + assert_se(strcmp_ptr("foo", "bar") > 0); + assert_se(strcmp_ptr("bar", "baz") < 0); + assert_se(strcmp_ptr("foo", "foo") == 0); + assert_se(strcmp_ptr("", "") == 0); +} + +static void test_foreach_word(void) { + const char *word, *state; + size_t l; + int i = 0; + const char test[] = "test abc d\te f "; + const char * const expected[] = { + "test", + "abc", + "d", + "e", + "f", + "", + NULL + }; + + FOREACH_WORD(word, l, test, state) + assert_se(strneq(expected[i++], word, l)); +} + +static void check(const char *test, char** expected, bool trailing) { + const char *word, *state; + size_t l; + int i = 0; + + printf("<<<%s>>>\n", test); + FOREACH_WORD_QUOTED(word, l, test, state) { + _cleanup_free_ char *t = NULL; + + assert_se(t = strndup(word, l)); + assert_se(strneq(expected[i++], word, l)); + printf("<%s>\n", t); + } + printf("<<<%s>>>\n", state); + assert_se(expected[i] == NULL); + assert_se(isempty(state) == !trailing); +} + +static void test_foreach_word_quoted(void) { + check("test a b c 'd' e '' '' hhh '' '' \"a b c\"", + STRV_MAKE("test", + "a", + "b", + "c", + "d", + "e", + "", + "", + "hhh", + "", + "", + "a b c"), + false); + + check("test \"xxx", + STRV_MAKE("test"), + true); + + check("test\\", + STRV_MAKE_EMPTY, + true); +} + +static void test_endswith(void) { + assert_se(endswith("foobar", "bar")); + assert_se(endswith("foobar", "")); + assert_se(endswith("foobar", "foobar")); + assert_se(endswith("", "")); + + assert_se(!endswith("foobar", "foo")); + assert_se(!endswith("foobar", "foobarfoofoo")); +} + +static void test_endswith_no_case(void) { + assert_se(endswith_no_case("fooBAR", "bar")); + assert_se(endswith_no_case("foobar", "")); + assert_se(endswith_no_case("foobar", "FOOBAR")); + assert_se(endswith_no_case("", "")); + + assert_se(!endswith_no_case("foobar", "FOO")); + assert_se(!endswith_no_case("foobar", "FOOBARFOOFOO")); +} + +static void test_delete_chars(void) { + char *r; + char input[] = " hello, waldo. abc"; + + r = delete_chars(input, WHITESPACE); + assert_se(streq(r, "hello,waldo.abc")); +} + +static void test_in_charset(void) { + assert_se(in_charset("dddaaabbbcccc", "abcd")); + assert_se(!in_charset("dddaaabbbcccc", "abc f")); +} + +static void test_split_pair(void) { + _cleanup_free_ char *a = NULL, *b = NULL; + + assert_se(split_pair("", "", &a, &b) == -EINVAL); + assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL); + assert_se(split_pair("", "=", &a, &b) == -EINVAL); + assert_se(split_pair("foo=bar", "=", &a, &b) >= 0); + assert_se(streq(a, "foo")); + assert_se(streq(b, "bar")); + free(a); + free(b); + assert_se(split_pair("==", "==", &a, &b) >= 0); + assert_se(streq(a, "")); + assert_se(streq(b, "")); + free(a); + free(b); + + assert_se(split_pair("===", "==", &a, &b) >= 0); + assert_se(streq(a, "")); + assert_se(streq(b, "=")); +} + +static void test_first_word(void) { + assert_se(first_word("Hello", "")); + assert_se(first_word("Hello", "Hello")); + assert_se(first_word("Hello world", "Hello")); + assert_se(first_word("Hello\tworld", "Hello")); + assert_se(first_word("Hello\nworld", "Hello")); + assert_se(first_word("Hello\rworld", "Hello")); + assert_se(first_word("Hello ", "Hello")); + + assert_se(!first_word("Hello", "Hellooo")); + assert_se(!first_word("Hello", "xxxxx")); + assert_se(!first_word("Hellooo", "Hello")); +} + int main(int argc, char *argv[]) { test_string_erase(); test_ascii_strcasecmp_n(); test_ascii_strcasecmp_nn(); + test_streq_ptr(); + test_strstrip(); + test_strextend(); + test_strrep(); + test_strappend(); + test_string_has_cc(); + test_ascii_strlower(); + test_strshorten(); + test_strjoina(); + test_strcmp_ptr(); + test_foreach_word(); + test_foreach_word_quoted(); + test_endswith(); + test_endswith_no_case(); + test_delete_chars(); + test_in_charset(); + test_split_pair(); + test_first_word(); + return 0; } diff --git a/src/test/test-strv.c b/src/test/test-strv.c index ef451c6abf..fea1f848cd 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -660,6 +660,25 @@ static void test_strv_make_nulstr(void) { test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux")); } +static void test_foreach_string(void) { + const char * const t[] = { + "foo", + "bar", + "waldo", + NULL + }; + const char *x; + unsigned i = 0; + + FOREACH_STRING(x, "foo", "bar", "waldo") + assert_se(streq_ptr(t[i++], x)); + + assert_se(i == 3); + + FOREACH_STRING(x, "zzz") + assert_se(streq(x, "zzz")); +} + int main(int argc, char *argv[]) { test_specifier_printf(); test_strv_foreach(); @@ -724,5 +743,7 @@ int main(int argc, char *argv[]) { test_strv_extend_n(); test_strv_make_nulstr(); + test_foreach_string(); + return 0; } diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 9cc64f7c68..d01789fe08 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -93,7 +93,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; log_debug("version %s", VERSION); - mac_selinux_init("/dev"); + mac_selinux_init(); action = argv[1]; if (action == NULL) { diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index 42c6a8d5e2..8d1ec19f17 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -37,6 +37,30 @@ static void test_gid_to_name_one(gid_t gid, const char *name) { assert_se(streq_ptr(t, name)); } +static void test_parse_uid(void) { + int r; + uid_t uid; + + r = parse_uid("100", &uid); + assert_se(r == 0); + assert_se(uid == 100); + + r = parse_uid("65535", &uid); + assert_se(r == -ENXIO); + + r = parse_uid("asdsdas", &uid); + assert_se(r == -EINVAL); +} + +static void test_uid_ptr(void) { + + assert_se(UID_TO_PTR(0) != NULL); + assert_se(UID_TO_PTR(1000) != NULL); + + assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0); + assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000); +} + int main(int argc, char*argv[]) { test_uid_to_name_one(0, "root"); @@ -48,5 +72,8 @@ int main(int argc, char*argv[]) { test_gid_to_name_one(0xFFFF, "65535"); test_gid_to_name_one(0xFFFFFFFF, "4294967295"); + test_parse_uid(); + test_uid_ptr(); + return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index 9a8a265790..05cb1eae76 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -19,47 +19,16 @@ ***/ #include <errno.h> -#include <fcntl.h> -#include <signal.h> #include <string.h> -#include <sys/types.h> #include <sys/wait.h> -#include <sys/xattr.h> #include <unistd.h> -#include "alloc-util.h" -#include "conf-parser.h" -#include "cpu-set-util.h" #include "def.h" -#include "escape.h" -#include "fd-util.h" #include "fileio.h" #include "fs-util.h" -#include "fstab-util.h" -#include "glob-util.h" -#include "hexdecoct.h" -#include "io-util.h" -#include "mkdir.h" -#include "parse-util.h" -#include "path-util.h" -#include "proc-cmdline.h" -#include "process-util.h" #include "rm-rf.h" -#include "signal-util.h" -#include "special.h" -#include "stat-util.h" #include "string-util.h" -#include "strv.h" -#include "user-util.h" #include "util.h" -#include "virt.h" -#include "web-util.h" -#include "xattr-util.h" - -static void test_streq_ptr(void) { - assert_se(streq_ptr(NULL, NULL)); - assert_se(!streq_ptr("abc", "cdef")); -} static void test_align_power2(void) { unsigned long i, p2; @@ -151,19 +120,6 @@ static void test_container_of(void) { v1) == &myval); } -static void test_alloca(void) { - static const uint8_t zero[997] = { }; - char *t; - - t = alloca_align(17, 512); - assert_se(!((uintptr_t)t & 0xff)); - memzero(t, 17); - - t = alloca0_align(997, 1024); - assert_se(!((uintptr_t)t & 0x1ff)); - assert_se(!memcmp(t, zero, 997)); -} - static void test_div_round_up(void) { int div; @@ -197,544 +153,6 @@ static void test_div_round_up(void) { assert_se(0xfffffffdU / 10U + !!(0xfffffffdU % 10U) == 429496730U); } -static void test_first_word(void) { - assert_se(first_word("Hello", "")); - assert_se(first_word("Hello", "Hello")); - assert_se(first_word("Hello world", "Hello")); - assert_se(first_word("Hello\tworld", "Hello")); - assert_se(first_word("Hello\nworld", "Hello")); - assert_se(first_word("Hello\rworld", "Hello")); - assert_se(first_word("Hello ", "Hello")); - - assert_se(!first_word("Hello", "Hellooo")); - assert_se(!first_word("Hello", "xxxxx")); - assert_se(!first_word("Hellooo", "Hello")); -} - -static void test_close_many(void) { - int fds[3]; - char name0[] = "/tmp/test-close-many.XXXXXX"; - char name1[] = "/tmp/test-close-many.XXXXXX"; - char name2[] = "/tmp/test-close-many.XXXXXX"; - - fds[0] = mkostemp_safe(name0, O_RDWR|O_CLOEXEC); - fds[1] = mkostemp_safe(name1, O_RDWR|O_CLOEXEC); - fds[2] = mkostemp_safe(name2, O_RDWR|O_CLOEXEC); - - close_many(fds, 2); - - assert_se(fcntl(fds[0], F_GETFD) == -1); - assert_se(fcntl(fds[1], F_GETFD) == -1); - assert_se(fcntl(fds[2], F_GETFD) >= 0); - - safe_close(fds[2]); - - unlink(name0); - unlink(name1); - unlink(name2); -} - -static void test_parse_uid(void) { - int r; - uid_t uid; - - r = parse_uid("100", &uid); - assert_se(r == 0); - assert_se(uid == 100); - - r = parse_uid("65535", &uid); - assert_se(r == -ENXIO); - - r = parse_uid("asdsdas", &uid); - assert_se(r == -EINVAL); -} - -static void test_strappend(void) { - _cleanup_free_ char *t1, *t2, *t3, *t4; - - t1 = strappend(NULL, NULL); - assert_se(streq(t1, "")); - - t2 = strappend(NULL, "suf"); - assert_se(streq(t2, "suf")); - - t3 = strappend("pre", NULL); - assert_se(streq(t3, "pre")); - - t4 = strappend("pre", "suf"); - assert_se(streq(t4, "presuf")); -} - -static void test_strstrip(void) { - char *r; - char input[] = " hello, waldo. "; - - r = strstrip(input); - assert_se(streq(r, "hello, waldo.")); -} - -static void test_delete_chars(void) { - char *r; - char input[] = " hello, waldo. abc"; - - r = delete_chars(input, WHITESPACE); - assert_se(streq(r, "hello,waldo.abc")); -} - -static void test_in_charset(void) { - assert_se(in_charset("dddaaabbbcccc", "abcd")); - assert_se(!in_charset("dddaaabbbcccc", "abc f")); -} - -static void test_hexchar(void) { - assert_se(hexchar(0xa) == 'a'); - assert_se(hexchar(0x0) == '0'); -} - -static void test_unhexchar(void) { - assert_se(unhexchar('a') == 0xA); - assert_se(unhexchar('A') == 0xA); - assert_se(unhexchar('0') == 0x0); -} - -static void test_base32hexchar(void) { - assert_se(base32hexchar(0) == '0'); - assert_se(base32hexchar(9) == '9'); - assert_se(base32hexchar(10) == 'A'); - assert_se(base32hexchar(31) == 'V'); -} - -static void test_unbase32hexchar(void) { - assert_se(unbase32hexchar('0') == 0); - assert_se(unbase32hexchar('9') == 9); - assert_se(unbase32hexchar('A') == 10); - assert_se(unbase32hexchar('V') == 31); - assert_se(unbase32hexchar('=') == -EINVAL); -} - -static void test_base64char(void) { - assert_se(base64char(0) == 'A'); - assert_se(base64char(26) == 'a'); - assert_se(base64char(63) == '/'); -} - -static void test_unbase64char(void) { - assert_se(unbase64char('A') == 0); - assert_se(unbase64char('Z') == 25); - assert_se(unbase64char('a') == 26); - assert_se(unbase64char('z') == 51); - assert_se(unbase64char('0') == 52); - assert_se(unbase64char('9') == 61); - assert_se(unbase64char('+') == 62); - assert_se(unbase64char('/') == 63); - assert_se(unbase64char('=') == -EINVAL); -} - -static void test_octchar(void) { - assert_se(octchar(00) == '0'); - assert_se(octchar(07) == '7'); -} - -static void test_unoctchar(void) { - assert_se(unoctchar('0') == 00); - assert_se(unoctchar('7') == 07); -} - -static void test_decchar(void) { - assert_se(decchar(0) == '0'); - assert_se(decchar(9) == '9'); -} - -static void test_undecchar(void) { - assert_se(undecchar('0') == 0); - assert_se(undecchar('9') == 9); -} - -static void test_unhexmem(void) { - const char *hex = "efa214921"; - const char *hex_invalid = "efa214921o"; - _cleanup_free_ char *hex2 = NULL; - _cleanup_free_ void *mem = NULL; - size_t len; - - assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0); - assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL); - assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL); - - assert_se((hex2 = hexmem(mem, len))); - - free(mem); - - assert_se(memcmp(hex, hex2, strlen(hex)) == 0); - - free(hex2); - - assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0); - assert_se((hex2 = hexmem(mem, len))); - assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0); -} - -/* https://tools.ietf.org/html/rfc4648#section-10 */ -static void test_base32hexmem(void) { - char *b32; - - b32 = base32hexmem("", strlen(""), true); - assert_se(b32); - assert_se(streq(b32, "")); - free(b32); - - b32 = base32hexmem("f", strlen("f"), true); - assert_se(b32); - assert_se(streq(b32, "CO======")); - free(b32); - - b32 = base32hexmem("fo", strlen("fo"), true); - assert_se(b32); - assert_se(streq(b32, "CPNG====")); - free(b32); - - b32 = base32hexmem("foo", strlen("foo"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMU===")); - free(b32); - - b32 = base32hexmem("foob", strlen("foob"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOG=")); - free(b32); - - b32 = base32hexmem("fooba", strlen("fooba"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1")); - free(b32); - - b32 = base32hexmem("foobar", strlen("foobar"), true); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1E8======")); - free(b32); - - b32 = base32hexmem("", strlen(""), false); - assert_se(b32); - assert_se(streq(b32, "")); - free(b32); - - b32 = base32hexmem("f", strlen("f"), false); - assert_se(b32); - assert_se(streq(b32, "CO")); - free(b32); - - b32 = base32hexmem("fo", strlen("fo"), false); - assert_se(b32); - assert_se(streq(b32, "CPNG")); - free(b32); - - b32 = base32hexmem("foo", strlen("foo"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMU")); - free(b32); - - b32 = base32hexmem("foob", strlen("foob"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOG")); - free(b32); - - b32 = base32hexmem("fooba", strlen("fooba"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1")); - free(b32); - - b32 = base32hexmem("foobar", strlen("foobar"), false); - assert_se(b32); - assert_se(streq(b32, "CPNMUOJ1E8")); - free(b32); -} - -static void test_unbase32hexmem(void) { - void *mem; - size_t len; - - assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL); - - assert_se(unbase32hexmem("XPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CXNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPXMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNXUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMXOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUXJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUOX1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUOJX", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL); - - assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL); - assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL); -} - -/* https://tools.ietf.org/html/rfc4648#section-10 */ -static void test_base64mem(void) { - char *b64; - - assert_se(base64mem("", strlen(""), &b64) == 0); - assert_se(streq(b64, "")); - free(b64); - - assert_se(base64mem("f", strlen("f"), &b64) == 4); - assert_se(streq(b64, "Zg==")); - free(b64); - - assert_se(base64mem("fo", strlen("fo"), &b64) == 4); - assert_se(streq(b64, "Zm8=")); - free(b64); - - assert_se(base64mem("foo", strlen("foo"), &b64) == 4); - assert_se(streq(b64, "Zm9v")); - free(b64); - - assert_se(base64mem("foob", strlen("foob"), &b64) == 8); - assert_se(streq(b64, "Zm9vYg==")); - free(b64); - - assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8); - assert_se(streq(b64, "Zm9vYmE=")); - free(b64); - - assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8); - assert_se(streq(b64, "Zm9vYmFy")); - free(b64); -} - -static void test_unbase64mem(void) { - void *mem; - size_t len; - - assert_se(unbase64mem("", strlen(""), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "")); - free(mem); - - assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "f")); - free(mem); - - assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fo")); - free(mem); - - assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foo")); - free(mem); - - assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foob")); - free(mem); - - assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "fooba")); - free(mem); - - assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0); - assert_se(streq(strndupa(mem, len), "foobar")); - free(mem); - - assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL); - assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL); - assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL); - assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL); -} - -static void test_cescape(void) { - _cleanup_free_ char *escaped; - - assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313")); - assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313")); -} - -static void test_cunescape(void) { - _cleanup_free_ char *unescaped; - - assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0); - assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00")); - unescaped = mfree(unescaped); - - /* incomplete sequences */ - assert_se(cunescape("\\x0", 0, &unescaped) < 0); - assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\x0")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\x", 0, &unescaped) < 0); - assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\x")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\", 0, &unescaped) < 0); - assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\11", 0, &unescaped) < 0); - assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\11")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\1", 0, &unescaped) < 0); - assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "\\1")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\u0000", 0, &unescaped) < 0); - assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, "ßßΠA")); - unescaped = mfree(unescaped); - - assert_se(cunescape("\\073", 0, &unescaped) >= 0); - assert_se(streq_ptr(unescaped, ";")); -} - -static void test_foreach_word(void) { - const char *word, *state; - size_t l; - int i = 0; - const char test[] = "test abc d\te f "; - const char * const expected[] = { - "test", - "abc", - "d", - "e", - "f", - "", - NULL - }; - - FOREACH_WORD(word, l, test, state) - assert_se(strneq(expected[i++], word, l)); -} - -static void check(const char *test, char** expected, bool trailing) { - const char *word, *state; - size_t l; - int i = 0; - - printf("<<<%s>>>\n", test); - FOREACH_WORD_QUOTED(word, l, test, state) { - _cleanup_free_ char *t = NULL; - - assert_se(t = strndup(word, l)); - assert_se(strneq(expected[i++], word, l)); - printf("<%s>\n", t); - } - printf("<<<%s>>>\n", state); - assert_se(expected[i] == NULL); - assert_se(isempty(state) == !trailing); -} - -static void test_foreach_word_quoted(void) { - check("test a b c 'd' e '' '' hhh '' '' \"a b c\"", - STRV_MAKE("test", - "a", - "b", - "c", - "d", - "e", - "", - "", - "hhh", - "", - "", - "a b c"), - false); - - check("test \"xxx", - STRV_MAKE("test"), - true); - - check("test\\", - STRV_MAKE_EMPTY, - true); -} - -static void test_memdup_multiply(void) { - int org[] = {1, 2, 3}; - int *dup; - - dup = (int*)memdup_multiply(org, sizeof(int), 3); - - assert_se(dup); - assert_se(dup[0] == 1); - assert_se(dup[1] == 2); - assert_se(dup[2] == 3); - free(dup); -} - static void test_u64log2(void) { assert_se(u64log2(0) == 0); assert_se(u64log2(8) == 3); @@ -754,210 +172,6 @@ static void test_protect_errno(void) { assert_se(errno == 12); } -static void test_parse_cpu_set(void) { - cpu_set_t *c = NULL; - int ncpus; - int cpu; - - /* Simple range (from CPUAffinity example) */ - ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2); - c = mfree(c); - - /* A more interesting range */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Quoted strings */ - ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Use commas as separators */ - ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Commas with spaces (and trailing comma, space) */ - ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 8; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Ranges */ - ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Ranges with trailing comma, space */ - ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); - for (cpu = 0; cpu < 4; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 8; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Negative range (returns empty cpu_set) */ - ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); - c = mfree(c); - - /* Overlapping ranges */ - ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); - for (cpu = 0; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Mix ranges and individual CPUs */ - ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus >= 1024); - assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); - assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); - assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); - for (cpu = 4; cpu < 12; cpu++) - assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); - c = mfree(c); - - /* Garbage */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); - - /* Range with garbage */ - ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); - - /* Empty string */ - c = NULL; - ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus == 0); /* empty string returns 0 */ - assert_se(!c); - - /* Runnaway quoted string */ - ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); -} - -static void test_config_parse_iec_uint64(void) { - uint64_t offset = 0; - assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0); - assert_se(offset == 4 * 1024 * 1024); - - assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0); -} - -static void test_strextend(void) { - _cleanup_free_ char *str = strdup("0123"); - strextend(&str, "456", "78", "9", NULL); - assert_se(streq(str, "0123456789")); -} - -static void test_strrep(void) { - _cleanup_free_ char *one, *three, *zero; - one = strrep("waldo", 1); - three = strrep("waldo", 3); - zero = strrep("waldo", 0); - - assert_se(streq(one, "waldo")); - assert_se(streq(three, "waldowaldowaldo")); - assert_se(streq(zero, "")); -} - -static void test_split_pair(void) { - _cleanup_free_ char *a = NULL, *b = NULL; - - assert_se(split_pair("", "", &a, &b) == -EINVAL); - assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL); - assert_se(split_pair("", "=", &a, &b) == -EINVAL); - assert_se(split_pair("foo=bar", "=", &a, &b) >= 0); - assert_se(streq(a, "foo")); - assert_se(streq(b, "bar")); - free(a); - free(b); - assert_se(split_pair("==", "==", &a, &b) >= 0); - assert_se(streq(a, "")); - assert_se(streq(b, "")); - free(a); - free(b); - - assert_se(split_pair("===", "==", &a, &b) >= 0); - assert_se(streq(a, "")); - assert_se(streq(b, "=")); -} - -static void test_fstab_node_to_udev_node(void) { - char *n; - - n = fstab_node_to_udev_node("LABEL=applé/jack"); - puts(n); - assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack")); - free(n); - - n = fstab_node_to_udev_node("PARTLABEL=pinkié pie"); - puts(n); - assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie")); - free(n); - - n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); - puts(n); - assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); - free(n); - - n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535"); - puts(n); - assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535")); - free(n); - - n = fstab_node_to_udev_node("PONIES=awesome"); - puts(n); - assert_se(streq(n, "PONIES=awesome")); - free(n); - - n = fstab_node_to_udev_node("/dev/xda1"); - puts(n); - assert_se(streq(n, "/dev/xda1")); - free(n); -} - -static void test_get_files_in_directory(void) { - _cleanup_strv_free_ char **l = NULL, **t = NULL; - - assert_se(get_files_in_directory("/tmp", &l) >= 0); - assert_se(get_files_in_directory(".", &t) >= 0); - assert_se(get_files_in_directory(".", NULL) >= 0); -} - static void test_in_set(void) { assert_se(IN_SET(1, 1)); assert_se(IN_SET(1, 1, 2, 3, 4)); @@ -968,50 +182,6 @@ static void test_in_set(void) { assert_se(!IN_SET(0, 1, 2, 3, 4)); } -static void test_writing_tmpfile(void) { - char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX"; - _cleanup_free_ char *contents = NULL; - size_t size; - int fd, r; - struct iovec iov[3]; - - IOVEC_SET_STRING(iov[0], "abc\n"); - IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n"); - IOVEC_SET_STRING(iov[2], ""); - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - printf("tmpfile: %s", name); - - r = writev(fd, iov, 3); - assert_se(r >= 0); - - r = read_full_file(name, &contents, &size); - assert_se(r == 0); - printf("contents: %s", contents); - assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n")); - - unlink(name); -} - -static void test_hexdump(void) { - uint8_t data[146]; - unsigned i; - - hexdump(stdout, NULL, 0); - hexdump(stdout, "", 0); - hexdump(stdout, "", 1); - hexdump(stdout, "x", 1); - hexdump(stdout, "x", 2); - hexdump(stdout, "foobar", 7); - hexdump(stdout, "f\nobar", 7); - hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23); - - for (i = 0; i < ELEMENTSOF(data); i++) - data[i] = i*2; - - hexdump(stdout, data, sizeof(data)); -} - static void test_log2i(void) { assert_se(log2i(1) == 0); assert_se(log2i(2) == 1); @@ -1023,341 +193,6 @@ static void test_log2i(void) { assert_se(log2i(INT_MAX) == sizeof(int)*8-2); } -static void test_foreach_string(void) { - const char * const t[] = { - "foo", - "bar", - "waldo", - NULL - }; - const char *x; - unsigned i = 0; - - FOREACH_STRING(x, "foo", "bar", "waldo") - assert_se(streq_ptr(t[i++], x)); - - assert_se(i == 3); - - FOREACH_STRING(x, "zzz") - assert_se(streq(x, "zzz")); -} - -static void test_filename_is_valid(void) { - char foo[FILENAME_MAX+2]; - int i; - - assert_se(!filename_is_valid("")); - assert_se(!filename_is_valid("/bar/foo")); - assert_se(!filename_is_valid("/")); - assert_se(!filename_is_valid(".")); - assert_se(!filename_is_valid("..")); - - for (i=0; i<FILENAME_MAX+1; i++) - foo[i] = 'a'; - foo[FILENAME_MAX+1] = '\0'; - - assert_se(!filename_is_valid(foo)); - - assert_se(filename_is_valid("foo_bar-333")); - assert_se(filename_is_valid("o.o")); -} - -static void test_string_has_cc(void) { - assert_se(string_has_cc("abc\1", NULL)); - assert_se(string_has_cc("abc\x7f", NULL)); - assert_se(string_has_cc("abc\x7f", NULL)); - assert_se(string_has_cc("abc\t\x7f", "\t")); - assert_se(string_has_cc("abc\t\x7f", "\t")); - assert_se(string_has_cc("\x7f", "\t")); - assert_se(string_has_cc("\x7f", "\t\a")); - - assert_se(!string_has_cc("abc\t\t", "\t")); - assert_se(!string_has_cc("abc\t\t\a", "\t\a")); - assert_se(!string_has_cc("a\ab\tc", "\t\a")); -} - -static void test_ascii_strlower(void) { - char a[] = "AabBcC Jk Ii Od LKJJJ kkd LK"; - assert_se(streq(ascii_strlower(a), "aabbcc jk ii od lkjjj kkd lk")); -} - -static void test_files_same(void) { - _cleanup_close_ int fd = -1; - char name[] = "/tmp/test-files_same.XXXXXX"; - char name_alias[] = "/tmp/test-files_same.alias"; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(symlink(name, name_alias) >= 0); - - assert_se(files_same(name, name)); - assert_se(files_same(name, name_alias)); - - unlink(name); - unlink(name_alias); -} - -static void test_is_valid_documentation_url(void) { - assert_se(documentation_url_is_valid("http://www.freedesktop.org/wiki/Software/systemd")); - assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/binfmt_misc.txt")); - assert_se(documentation_url_is_valid("file:/foo/foo")); - assert_se(documentation_url_is_valid("man:systemd.special(7)")); - assert_se(documentation_url_is_valid("info:bar")); - - assert_se(!documentation_url_is_valid("foo:")); - assert_se(!documentation_url_is_valid("info:")); - assert_se(!documentation_url_is_valid("")); -} - -static void test_file_in_same_dir(void) { - char *t; - - t = file_in_same_dir("/", "a"); - assert_se(streq(t, "/a")); - free(t); - - t = file_in_same_dir("/", "/a"); - assert_se(streq(t, "/a")); - free(t); - - t = file_in_same_dir("", "a"); - assert_se(streq(t, "a")); - free(t); - - t = file_in_same_dir("a/", "a"); - assert_se(streq(t, "a/a")); - free(t); - - t = file_in_same_dir("bar/foo", "bar"); - assert_se(streq(t, "bar/bar")); - free(t); -} - -static void test_endswith(void) { - assert_se(endswith("foobar", "bar")); - assert_se(endswith("foobar", "")); - assert_se(endswith("foobar", "foobar")); - assert_se(endswith("", "")); - - assert_se(!endswith("foobar", "foo")); - assert_se(!endswith("foobar", "foobarfoofoo")); -} - -static void test_endswith_no_case(void) { - assert_se(endswith_no_case("fooBAR", "bar")); - assert_se(endswith_no_case("foobar", "")); - assert_se(endswith_no_case("foobar", "FOOBAR")); - assert_se(endswith_no_case("", "")); - - assert_se(!endswith_no_case("foobar", "FOO")); - assert_se(!endswith_no_case("foobar", "FOOBARFOOFOO")); -} - -static void test_close_nointr(void) { - char name[] = "/tmp/test-test-close_nointr.XXXXXX"; - int fd; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(close_nointr(fd) >= 0); - assert_se(close_nointr(fd) < 0); - - unlink(name); -} - - -static void test_unlink_noerrno(void) { - char name[] = "/tmp/test-close_nointr.XXXXXX"; - int fd; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(close_nointr(fd) >= 0); - - { - PROTECT_ERRNO; - errno = -42; - assert_se(unlink_noerrno(name) >= 0); - assert_se(errno == -42); - assert_se(unlink_noerrno(name) < 0); - assert_se(errno == -42); - } -} - -static void test_readlink_and_make_absolute(void) { - char tempdir[] = "/tmp/test-readlink_and_make_absolute"; - char name[] = "/tmp/test-readlink_and_make_absolute/original"; - char name2[] = "test-readlink_and_make_absolute/original"; - char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias"; - char *r = NULL; - - assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); - assert_se(touch(name) >= 0); - - assert_se(symlink(name, name_alias) >= 0); - assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); - assert_se(streq(r, name)); - free(r); - assert_se(unlink(name_alias) >= 0); - - assert_se(chdir(tempdir) >= 0); - assert_se(symlink(name2, name_alias) >= 0); - assert_se(readlink_and_make_absolute(name_alias, &r) >= 0); - assert_se(streq(r, name)); - free(r); - assert_se(unlink(name_alias) >= 0); - - assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); -} - -static void test_ignore_signals(void) { - assert_se(ignore_signals(SIGINT, -1) >= 0); - assert_se(kill(getpid(), SIGINT) >= 0); - assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); - assert_se(kill(getpid(), SIGUSR1) >= 0); - assert_se(kill(getpid(), SIGUSR2) >= 0); - assert_se(kill(getpid(), SIGTERM) >= 0); - assert_se(kill(getpid(), SIGPIPE) >= 0); - assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); -} - -static void test_strshorten(void) { - char s[] = "foobar"; - - assert_se(strlen(strshorten(s, 6)) == 6); - assert_se(strlen(strshorten(s, 12)) == 6); - assert_se(strlen(strshorten(s, 2)) == 2); - assert_se(strlen(strshorten(s, 0)) == 0); -} - -static void test_strjoina(void) { - char *actual; - - actual = strjoina("", "foo", "bar"); - assert_se(streq(actual, "foobar")); - - actual = strjoina("foo", "bar", "baz"); - assert_se(streq(actual, "foobarbaz")); - - actual = strjoina("foo", "", "bar", "baz"); - assert_se(streq(actual, "foobarbaz")); - - actual = strjoina("foo"); - assert_se(streq(actual, "foo")); - - actual = strjoina(NULL); - assert_se(streq(actual, "")); - - actual = strjoina(NULL, "foo"); - assert_se(streq(actual, "")); - - actual = strjoina("foo", NULL, "bar"); - assert_se(streq(actual, "foo")); -} - -static void test_is_symlink(void) { - char name[] = "/tmp/test-is_symlink.XXXXXX"; - char name_link[] = "/tmp/test-is_symlink.link"; - _cleanup_close_ int fd = -1; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - assert_se(symlink(name, name_link) >= 0); - - assert_se(is_symlink(name) == 0); - assert_se(is_symlink(name_link) == 1); - assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0); - - - unlink(name); - unlink(name_link); -} - -static void test_search_and_fopen(void) { - const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL}; - char name[] = "/tmp/test-search_and_fopen.XXXXXX"; - int fd = -1; - int r; - FILE *f; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - close(fd); - - r = search_and_fopen(basename(name), "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen(name, "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen(basename(name), "r", "/", dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); - assert_se(r < 0); - r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); - assert_se(r < 0); - - r = unlink(name); - assert_se(r == 0); - - r = search_and_fopen(basename(name), "r", NULL, dirs, &f); - assert_se(r < 0); -} - - -static void test_search_and_fopen_nulstr(void) { - const char dirs[] = "/tmp/foo/bar\0/tmp\0"; - char name[] = "/tmp/test-search_and_fopen.XXXXXX"; - int fd = -1; - int r; - FILE *f; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - close(fd); - - r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f); - assert_se(r >= 0); - fclose(f); - - r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f); - assert_se(r < 0); - r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f); - assert_se(r < 0); - - r = unlink(name); - assert_se(r == 0); - - r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f); - assert_se(r < 0); -} - -static void test_glob_exists(void) { - char name[] = "/tmp/test-glob_exists.XXXXXX"; - int fd = -1; - int r; - - fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); - assert_se(fd >= 0); - close(fd); - - r = glob_exists("/tmp/test-glob_exists*"); - assert_se(r == 1); - - r = unlink(name); - assert_se(r == 0); - r = glob_exists("/tmp/test-glob_exists*"); - assert_se(r == 0); -} - static void test_execute_directory(void) { char template_lo[] = "/tmp/test-readlink_and_make_absolute-lo.XXXXXXX"; char template_hi[] = "/tmp/test-readlink_and_make_absolute-hi.XXXXXXX"; @@ -1402,17 +237,6 @@ static void test_execute_directory(void) { (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL); } -static int parse_item(const char *key, const char *value) { - assert_se(key); - - log_info("kernel cmdline option <%s> = <%s>", key, strna(value)); - return 0; -} - -static void test_parse_proc_cmdline(void) { - assert_se(parse_proc_cmdline(parse_item) >= 0); -} - static void test_raw_clone(void) { pid_t parent, pid, pid2; @@ -1438,285 +262,20 @@ static void test_raw_clone(void) { } } -static void test_same_fd(void) { - _cleanup_close_pair_ int p[2] = { -1, -1 }; - _cleanup_close_ int a = -1, b = -1, c = -1; - - assert_se(pipe2(p, O_CLOEXEC) >= 0); - assert_se((a = dup(p[0])) >= 0); - assert_se((b = open("/dev/null", O_RDONLY|O_CLOEXEC)) >= 0); - assert_se((c = dup(a)) >= 0); - - assert_se(same_fd(p[0], p[0]) > 0); - assert_se(same_fd(p[1], p[1]) > 0); - assert_se(same_fd(a, a) > 0); - assert_se(same_fd(b, b) > 0); - - assert_se(same_fd(a, p[0]) > 0); - assert_se(same_fd(p[0], a) > 0); - assert_se(same_fd(c, p[0]) > 0); - assert_se(same_fd(p[0], c) > 0); - assert_se(same_fd(a, c) > 0); - assert_se(same_fd(c, a) > 0); - - assert_se(same_fd(p[0], p[1]) == 0); - assert_se(same_fd(p[1], p[0]) == 0); - assert_se(same_fd(p[0], b) == 0); - assert_se(same_fd(b, p[0]) == 0); - assert_se(same_fd(p[1], a) == 0); - assert_se(same_fd(a, p[1]) == 0); - assert_se(same_fd(p[1], b) == 0); - assert_se(same_fd(b, p[1]) == 0); - - assert_se(same_fd(a, b) == 0); - assert_se(same_fd(b, a) == 0); -} - -static void test_uid_ptr(void) { - - assert_se(UID_TO_PTR(0) != NULL); - assert_se(UID_TO_PTR(1000) != NULL); - - assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0); - assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000); -} - -static void test_sparse_write_one(int fd, const char *buffer, size_t n) { - char check[n]; - - assert_se(lseek(fd, 0, SEEK_SET) == 0); - assert_se(ftruncate(fd, 0) >= 0); - assert_se(sparse_write(fd, buffer, n, 4) == (ssize_t) n); - - assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n); - assert_se(ftruncate(fd, n) >= 0); - - assert_se(lseek(fd, 0, SEEK_SET) == 0); - assert_se(read(fd, check, n) == (ssize_t) n); - - assert_se(memcmp(buffer, check, n) == 0); -} - -static void test_sparse_write(void) { - const char test_a[] = "test"; - const char test_b[] = "\0\0\0\0test\0\0\0\0"; - const char test_c[] = "\0\0test\0\0\0\0"; - const char test_d[] = "\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0\0\0\0"; - const char test_e[] = "test\0\0\0\0test"; - _cleanup_close_ int fd = -1; - char fn[] = "/tmp/sparseXXXXXX"; - - fd = mkostemp(fn, O_CLOEXEC); - assert_se(fd >= 0); - unlink(fn); - - test_sparse_write_one(fd, test_a, sizeof(test_a)); - test_sparse_write_one(fd, test_b, sizeof(test_b)); - test_sparse_write_one(fd, test_c, sizeof(test_c)); - test_sparse_write_one(fd, test_d, sizeof(test_d)); - test_sparse_write_one(fd, test_e, sizeof(test_e)); -} - -static void test_shell_escape_one(const char *s, const char *bad, const char *expected) { - _cleanup_free_ char *r; - - assert_se(r = shell_escape(s, bad)); - assert_se(streq_ptr(r, expected)); -} - -static void test_shell_escape(void) { - test_shell_escape_one("", "", ""); - test_shell_escape_one("\\", "", "\\\\"); - test_shell_escape_one("foobar", "", "foobar"); - test_shell_escape_one("foobar", "o", "f\\o\\obar"); - test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz"); -} - -static void test_shell_maybe_quote_one(const char *s, const char *expected) { - _cleanup_free_ char *r; - - assert_se(r = shell_maybe_quote(s)); - assert_se(streq(r, expected)); -} - -static void test_shell_maybe_quote(void) { - - test_shell_maybe_quote_one("", ""); - test_shell_maybe_quote_one("\\", "\"\\\\\""); - test_shell_maybe_quote_one("\"", "\"\\\"\""); - test_shell_maybe_quote_one("foobar", "foobar"); - test_shell_maybe_quote_one("foo bar", "\"foo bar\""); - test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\""); - test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\""); -} - -static void test_tempfn(void) { - char *ret = NULL, *p; - - assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0); - assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX")); - free(ret); - - assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0); - assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX")); - free(ret); - - assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/.#waldo")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); - - assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); - - assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/waldo/.#")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); - - assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0); - assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]")); - assert_se(strlen(p) == 16); - assert_se(in_charset(p, "0123456789abcdef")); - free(ret); -} - -static void test_strcmp_ptr(void) { - assert_se(strcmp_ptr(NULL, NULL) == 0); - assert_se(strcmp_ptr("", NULL) > 0); - assert_se(strcmp_ptr("foo", NULL) > 0); - assert_se(strcmp_ptr(NULL, "") < 0); - assert_se(strcmp_ptr(NULL, "bar") < 0); - assert_se(strcmp_ptr("foo", "bar") > 0); - assert_se(strcmp_ptr("bar", "baz") < 0); - assert_se(strcmp_ptr("foo", "foo") == 0); - assert_se(strcmp_ptr("", "") == 0); -} - -static void test_fgetxattrat_fake(void) { - char t[] = "/var/tmp/xattrtestXXXXXX"; - _cleanup_close_ int fd = -1; - const char *x; - char v[3] = {}; - int r; - - assert_se(mkdtemp(t)); - x = strjoina(t, "/test"); - assert_se(touch(x) >= 0); - - r = setxattr(x, "user.foo", "bar", 3, 0); - if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */ - goto cleanup; - assert_se(r >= 0); - - fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); - assert_se(fd >= 0); - - assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0); - assert_se(memcmp(v, "bar", 3) == 0); - - safe_close(fd); - fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); - assert_se(fd >= 0); - assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA); - -cleanup: - assert_se(unlink(x) >= 0); - assert_se(rmdir(t) >= 0); -} - -static void test_runlevel_to_target(void) { - assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); - assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); - assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); -} - int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - test_streq_ptr(); test_align_power2(); test_max(); test_container_of(); - test_alloca(); test_div_round_up(); - test_first_word(); - test_close_many(); - test_parse_uid(); - test_strappend(); - test_strstrip(); - test_delete_chars(); - test_in_charset(); - test_hexchar(); - test_unhexchar(); - test_base32hexchar(); - test_unbase32hexchar(); - test_base64char(); - test_unbase64char(); - test_octchar(); - test_unoctchar(); - test_decchar(); - test_undecchar(); - test_unhexmem(); - test_base32hexmem(); - test_unbase32hexmem(); - test_base64mem(); - test_unbase64mem(); - test_cescape(); - test_cunescape(); - test_foreach_word(); - test_foreach_word_quoted(); - test_memdup_multiply(); test_u64log2(); test_protect_errno(); - test_parse_cpu_set(); - test_config_parse_iec_uint64(); - test_strextend(); - test_strrep(); - test_split_pair(); - test_fstab_node_to_udev_node(); - test_get_files_in_directory(); test_in_set(); - test_writing_tmpfile(); - test_hexdump(); test_log2i(); - test_foreach_string(); - test_filename_is_valid(); - test_string_has_cc(); - test_ascii_strlower(); - test_files_same(); - test_is_valid_documentation_url(); - test_file_in_same_dir(); - test_endswith(); - test_endswith_no_case(); - test_close_nointr(); - test_unlink_noerrno(); - test_readlink_and_make_absolute(); - test_ignore_signals(); - test_strshorten(); - test_strjoina(); - test_is_symlink(); - test_search_and_fopen(); - test_search_and_fopen_nulstr(); - test_glob_exists(); test_execute_directory(); - test_parse_proc_cmdline(); test_raw_clone(); - test_same_fd(); - test_uid_ptr(); - test_sparse_write(); - test_shell_escape(); - test_shell_maybe_quote(); - test_tempfn(); - test_strcmp_ptr(); - test_fgetxattrat_fake(); - test_runlevel_to_target(); return 0; } diff --git a/src/test/test-web-util.c b/src/test/test-web-util.c new file mode 100644 index 0000000000..79a3a13af6 --- /dev/null +++ b/src/test/test-web-util.c @@ -0,0 +1,39 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "macro.h" +#include "web-util.h" + +static void test_is_valid_documentation_url(void) { + assert_se(documentation_url_is_valid("http://www.freedesktop.org/wiki/Software/systemd")); + assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/binfmt_misc.txt")); + assert_se(documentation_url_is_valid("file:/foo/foo")); + assert_se(documentation_url_is_valid("man:systemd.special(7)")); + assert_se(documentation_url_is_valid("info:bar")); + + assert_se(!documentation_url_is_valid("foo:")); + assert_se(!documentation_url_is_valid("info:")); + assert_se(!documentation_url_is_valid("")); +} + +int main(int argc, char *argv[]) { + test_is_valid_documentation_url(); + + return 0; +} diff --git a/src/test/test-xattr-util.c b/src/test/test-xattr-util.c new file mode 100644 index 0000000000..267f29426c --- /dev/null +++ b/src/test/test-xattr-util.c @@ -0,0 +1,69 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/xattr.h> +#include <unistd.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "macro.h" +#include "string-util.h" +#include "xattr-util.h" + +static void test_fgetxattrat_fake(void) { + char t[] = "/var/tmp/xattrtestXXXXXX"; + _cleanup_close_ int fd = -1; + const char *x; + char v[3] = {}; + int r; + + assert_se(mkdtemp(t)); + x = strjoina(t, "/test"); + assert_se(touch(x) >= 0); + + r = setxattr(x, "user.foo", "bar", 3, 0); + if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */ + goto cleanup; + assert_se(r >= 0); + + fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + + assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0); + assert_se(memcmp(v, "bar", 3) == 0); + + safe_close(fd); + fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA); + +cleanup: + assert_se(unlink(x) >= 0); + assert_se(rmdir(t) >= 0); +} + +int main(void) { + test_fgetxattrat_fake(); + + return 0; +} diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 2a10135fba..ffec609c69 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -78,7 +78,7 @@ static int context_read_data(Context *c) { c->zone = t; t = NULL; - c->local_rtc = clock_is_localtime() > 0; + c->local_rtc = clock_is_localtime(NULL) > 0; return 0; } @@ -125,30 +125,44 @@ static int context_write_data_local_rtc(Context *c) { if (!w) return -ENOMEM; } else { - char *p, *e; + char *p; + const char *e = "\n"; /* default if there is less than 3 lines */ + const char *prepend = ""; size_t a, b; - p = strchr(s, '\n'); - if (!p) - return -EIO; - - p = strchr(p+1, '\n'); - if (!p) - return -EIO; - - p++; - e = strchr(p, '\n'); - if (!e) - return -EIO; + p = strchrnul(s, '\n'); + if (*p == '\0') + /* only one line, no \n terminator */ + prepend = "\n0\n"; + else if (p[1] == '\0') { + /* only one line, with \n terminator */ + ++p; + prepend = "0\n"; + } else { + p = strchr(p+1, '\n'); + if (!p) { + /* only two lines, no \n terminator */ + prepend = "\n"; + p = s + strlen(s); + } else { + char *end; + /* third line might have a \n terminator or not */ + p++; + end = strchr(p, '\n'); + /* if we actually have a fourth line, use that as suffix "e", otherwise the default \n */ + if (end) + e = end; + } + } a = p - s; b = strlen(e); - w = new(char, a + (c->local_rtc ? 5 : 3) + b + 1); + w = new(char, a + (c->local_rtc ? 5 : 3) + strlen(prepend) + b + 1); if (!w) return -ENOMEM; - *(char*) mempcpy(stpcpy(mempcpy(w, s, a), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0; + *(char*) mempcpy(stpcpy(stpcpy(mempcpy(w, s, a), prepend), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0; if (streq(w, NULL_ADJTIME_UTC)) { if (unlink("/etc/adjtime") < 0) @@ -159,7 +173,7 @@ static int context_write_data_local_rtc(Context *c) { } } - mac_selinux_init("/etc"); + mac_selinux_init(); return write_string_file_atomic_label("/etc/adjtime", w); } diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 23e19159e0..b67d672a6a 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -122,7 +122,7 @@ int main(int argc, char *argv[]) { goto finish; } - if (clock_is_localtime() > 0) { + if (clock_is_localtime(NULL) > 0) { log_info("The system is configured to read the RTC time in the local time zone. " "This mode can not be fully supported. All system time to RTC updates are disabled."); m->rtc_local_time = true; diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 7b105a6bd4..efd264b34d 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -613,7 +613,7 @@ static int path_set_perms(Item *i, const char *path) { * with AT_SYMLINK_NOFOLLOW, hence we emulate it here via * O_PATH. */ - fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME); + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); if (fd < 0) return log_error_errno(errno, "Adjusting owner and mode for %s failed: %m", path); @@ -804,7 +804,7 @@ static int path_set_acls(Item *item, const char *path) { assert(item); assert(path); - fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME); + fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); if (fd < 0) return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path); @@ -917,10 +917,7 @@ static int parse_attribute_from_arg(Item *item) { v = attributes[i].value; - if (mode == MODE_ADD || mode == MODE_SET) - value |= v; - else - value &= ~v; + SET_FLAG(value, v, (mode == MODE_ADD || mode == MODE_SET)); mask |= v; } @@ -2288,7 +2285,7 @@ int main(int argc, char *argv[]) { umask(0022); - mac_selinux_init(NULL); + mac_selinux_init(); items = ordered_hashmap_new(&string_hash_ops); globs = ordered_hashmap_new(&string_hash_ops); diff --git a/src/udev/udev.h b/src/udev/udev.h index 56590517ef..8433e8d9f2 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -19,6 +19,7 @@ */ #include <sys/param.h> +#include <sys/sysmacros.h> #include <sys/types.h> #include "libudev.h" diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 7bd2c1ea42..a6a873e5de 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -93,7 +93,7 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - mac_selinux_init("/dev"); + mac_selinux_init(); while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0) switch (c) { diff --git a/src/udev/udevd.c b/src/udev/udevd.c index bb92f16352..243df7386f 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1695,7 +1695,7 @@ int main(int argc, char *argv[]) { umask(022); - r = mac_selinux_init("/dev"); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "could not initialize labelling: %m"); goto exit; diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index 931e583785..da306a4444 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -101,7 +101,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - r = mac_selinux_init(NULL); + r = mac_selinux_init(); if (r < 0) { log_error_errno(r, "SELinux setup failed: %m"); goto finish; diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index 8bf44e2100..9b29b5ba1d 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -40,7 +40,7 @@ int main(int argc, char*argv[]) { umask(0022); - mac_selinux_init(NULL); + mac_selinux_init(); if (streq(argv[1], "start")) { int r = 0; |