diff options
Diffstat (limited to 'src/systemd')
41 files changed, 853 insertions, 193 deletions
diff --git a/src/systemd/sd-adapt/nm-sd-adapt.h b/src/systemd/sd-adapt/nm-sd-adapt.h index 1ff2a345be..380cbc60e2 100644 --- a/src/systemd/sd-adapt/nm-sd-adapt.h +++ b/src/systemd/sd-adapt/nm-sd-adapt.h @@ -142,6 +142,8 @@ G_STMT_START { \ # endif #endif +#define VALGRIND 0 + static inline pid_t raw_getpid (void) { #if defined(__alpha__) diff --git a/src/systemd/src/basic/alloc-util.h b/src/systemd/src/basic/alloc-util.h index 88cd6b0bc2..bae6a28451 100644 --- a/src/systemd/src/basic/alloc-util.h +++ b/src/systemd/src/basic/alloc-util.h @@ -18,9 +18,17 @@ #define new0(t, n) ((t*) calloc((n), sizeof(t))) -#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) +#define newa(t, n) \ + ({ \ + assert(!size_multiply_overflow(sizeof(t), n)); \ + (t*) alloca(sizeof(t)*(n)); \ + }) -#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n))) +#define newa0(t, n) \ + ({ \ + assert(!size_multiply_overflow(sizeof(t), n)); \ + (t*) alloca0(sizeof(t)*(n)); \ + }) #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) diff --git a/src/systemd/src/basic/escape.c b/src/systemd/src/basic/escape.c index 53bfb4204a..f51de788f7 100644 --- a/src/systemd/src/basic/escape.c +++ b/src/systemd/src/basic/escape.c @@ -190,7 +190,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) /* C++11 style 16bit unicode */ int a[4]; - unsigned i; + size_t i; uint32_t c; if (length != (size_t) -1 && length < 5) @@ -217,7 +217,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) /* C++11 style 32bit unicode */ int a[8]; - unsigned i; + size_t i; char32_t c; if (length != (size_t) -1 && length < 9) diff --git a/src/systemd/src/basic/ether-addr-util.c b/src/systemd/src/basic/ether-addr-util.c index cc16e059c5..75de9a1902 100644 --- a/src/systemd/src/basic/ether-addr-util.c +++ b/src/systemd/src/basic/ether-addr-util.c @@ -35,19 +35,23 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR return buffer; } -bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) { +int ether_addr_compare(const void *a, const void *b) { assert(a); assert(b); - return a->ether_addr_octet[0] == b->ether_addr_octet[0] && - a->ether_addr_octet[1] == b->ether_addr_octet[1] && - a->ether_addr_octet[2] == b->ether_addr_octet[2] && - a->ether_addr_octet[3] == b->ether_addr_octet[3] && - a->ether_addr_octet[4] == b->ether_addr_octet[4] && - a->ether_addr_octet[5] == b->ether_addr_octet[5]; + return memcmp(a, b, ETH_ALEN); } -int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset) { +static void ether_addr_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(struct ether_addr), state); +} + +const struct hash_ops ether_addr_hash_ops = { + .hash = ether_addr_hash_func, + .compare = ether_addr_compare +}; + +int ether_addr_from_string(const char *s, struct ether_addr *ret) { size_t pos = 0, n, field; char sep = '\0'; const char *hex = HEXDIGITS, *hexoff; @@ -86,31 +90,35 @@ int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset assert(s); assert(ret); + s += strspn(s, WHITESPACE); sep = s[strspn(s, hex)]; - if (sep == '\n') - return -EINVAL; - if (!strchr(":.-", sep)) - return -EINVAL; if (sep == '.') { uint16_t shorts[3] = { 0 }; parse_fields(shorts); + if (s[pos] != '\0') + return -EINVAL; + for (n = 0; n < ELEMENTSOF(shorts); n++) { ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8); ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff); } - } else { - struct ether_addr out = { .ether_addr_octet = { 0 } }; + + } else if (IN_SET(sep, ':', '-')) { + struct ether_addr out = ETHER_ADDR_NULL; parse_fields(out.ether_addr_octet); + if (s[pos] != '\0') + return -EINVAL; + for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++) ret->ether_addr_octet[n] = out.ether_addr_octet[n]; - } - if (offset) - *offset = pos; + } else + return -EINVAL; + return 0; } diff --git a/src/systemd/src/basic/ether-addr-util.h b/src/systemd/src/basic/ether-addr-util.h index 29d7f36294..f7e0de54cc 100644 --- a/src/systemd/src/basic/ether-addr-util.h +++ b/src/systemd/src/basic/ether-addr-util.h @@ -10,13 +10,18 @@ #include <net/ethernet.h> #include <stdbool.h> +#include "hash-funcs.h" + #define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X" #define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5] #define ETHER_ADDR_TO_STRING_MAX (3*6) char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); -bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b); +int ether_addr_compare(const void *a, const void *b); +static inline bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) { + return ether_addr_compare(a, b) == 0; +} #define ETHER_ADDR_NULL ((const struct ether_addr){}) @@ -24,4 +29,6 @@ static inline bool ether_addr_is_null(const struct ether_addr *addr) { return ether_addr_equal(addr, ÐER_ADDR_NULL); } -int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset); +int ether_addr_from_string(const char *s, struct ether_addr *ret); + +extern const struct hash_ops ether_addr_hash_ops; diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c index 2668a0d1cd..6a753195df 100644 --- a/src/systemd/src/basic/fd-util.c +++ b/src/systemd/src/basic/fd-util.c @@ -87,8 +87,8 @@ void safe_close_pair(int p[]) { p[1] = safe_close(p[1]); } -void close_many(const int fds[], unsigned n_fd) { - unsigned i; +void close_many(const int fds[], size_t n_fd) { + size_t i; assert(fds || n_fd <= 0); @@ -181,8 +181,8 @@ int fd_cloexec(int fd, bool cloexec) { } #if 0 /* NM_IGNORED */ -_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { - unsigned i; +_pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) { + size_t i; assert(n_fdset == 0 || fdset); @@ -193,7 +193,7 @@ _pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { return false; } -int close_all_fds(const int except[], unsigned n_except) { +int close_all_fds(const int except[], size_t n_except) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; int r = 0; @@ -202,15 +202,22 @@ int close_all_fds(const int except[], unsigned n_except) { d = opendir("/proc/self/fd"); if (!d) { - int fd; struct rlimit rl; + int fd, max_fd; - /* When /proc isn't available (for example in chroots) - * the fallback is brute forcing through the fd + /* When /proc isn't available (for example in chroots) the fallback is brute forcing through the fd * table */ assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); - for (fd = 3; fd < (int) rl.rlim_max; fd ++) { + + if (rl.rlim_max == 0) + return -EINVAL; + + /* Let's take special care if the resource limit is set to unlimited, or actually larger than the range + * of 'int'. Let's avoid implicit overflows. */ + max_fd = (rl.rlim_max == RLIM_INFINITY || rl.rlim_max > INT_MAX) ? INT_MAX : (int) (rl.rlim_max - 1); + + for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) { int q; if (fd_in_set(fd, except, n_except)) diff --git a/src/systemd/src/basic/fd-util.h b/src/systemd/src/basic/fd-util.h index ded022f738..89c3f34c7b 100644 --- a/src/systemd/src/basic/fd-util.h +++ b/src/systemd/src/basic/fd-util.h @@ -29,7 +29,7 @@ static inline int safe_close_above_stdio(int fd) { return safe_close(fd); } -void close_many(const int fds[], unsigned n_fd); +void close_many(const int fds[], size_t n_fd); int fclose_nointr(FILE *f); FILE* safe_fclose(FILE *f); @@ -59,7 +59,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); int fd_nonblock(int fd, bool nonblock); int fd_cloexec(int fd, bool cloexec); -int close_all_fds(const int except[], unsigned n_except); +int close_all_fds(const int except[], size_t n_except); int same_fd(int a, int b); diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c index 9e037042d7..4f71384e39 100644 --- a/src/systemd/src/basic/fileio.c +++ b/src/systemd/src/basic/fileio.c @@ -53,6 +53,7 @@ int write_string_stream_ts( struct timespec *ts) { bool needs_nl; + int r; assert(f); assert(line); @@ -77,6 +78,13 @@ int write_string_stream_ts( if (fputc('\n', f) == EOF) return -errno; + if (flags & WRITE_STRING_FILE_SYNC) + r = fflush_sync_and_check(f); + else + r = fflush_and_check(f); + if (r < 0) + return r; + if (ts) { struct timespec twice[2] = {*ts, *ts}; @@ -84,10 +92,7 @@ int write_string_stream_ts( return -errno; } - if (flags & WRITE_STRING_FILE_SYNC) - return fflush_sync_and_check(f); - else - return fflush_and_check(f); + return 0; } static int write_string_file_atomic( diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c index da9b670337..049b238e8d 100644 --- a/src/systemd/src/basic/fs-util.c +++ b/src/systemd/src/basic/fs-util.c @@ -248,6 +248,21 @@ int fchmod_umask(int fd, mode_t m) { } #if 0 /* NM_IGNORED */ +int fchmod_opath(int fd, mode_t m) { + char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + + /* This function operates also on fd that might have been opened with + * O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like + * fchownat() does. */ + + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + + if (chmod(procfs_path, m) < 0) + return -errno; + + return 0; +} + int fd_warn_permissions(const char *path, int fd) { struct stat st; @@ -911,25 +926,12 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return exists; chased_one: - if (ret) { char *c; - if (done) { - if (todo) { - c = strjoin(done, todo); - if (!c) - return -ENOMEM; - } else - c = TAKE_PTR(done); - } else { - if (todo) - c = strdup(todo); - else - c = strdup("/"); - if (!c) - return -ENOMEM; - } + c = strjoin(strempty(done), todo); + if (!c) + return -ENOMEM; *ret = c; } diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h index 2b1d2097fd..6157fe81bf 100644 --- a/src/systemd/src/basic/fs-util.h +++ b/src/systemd/src/basic/fs-util.h @@ -33,6 +33,7 @@ int readlink_and_make_absolute(const char *p, char **r); int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); int fchmod_umask(int fd, mode_t mode); +int fchmod_opath(int fd, mode_t m); int fd_warn_permissions(const char *path, int fd); diff --git a/src/systemd/src/basic/hashmap.c b/src/systemd/src/basic/hashmap.c index c305f1c5fa..b8a8e37b5c 100644 --- a/src/systemd/src/basic/hashmap.c +++ b/src/systemd/src/basic/hashmap.c @@ -283,7 +283,7 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { }, }; -#ifdef VALGRIND +#if VALGRIND __attribute__((destructor)) static void cleanup_pools(void) { _cleanup_free_ char *t = NULL; int r; diff --git a/src/systemd/src/basic/hexdecoct.c b/src/systemd/src/basic/hexdecoct.c index 16a35156bf..1fe410f56a 100644 --- a/src/systemd/src/basic/hexdecoct.c +++ b/src/systemd/src/basic/hexdecoct.c @@ -79,33 +79,69 @@ char *hexmem(const void *p, size_t l) { return r; } -int unhexmem(const char *p, size_t l, void **mem, size_t *len) { - _cleanup_free_ uint8_t *r = NULL; - uint8_t *z; +static int unhex_next(const char **p, size_t *l) { + int r; + + assert(p); + assert(l); + + /* Find the next non-whitespace character, and decode it. We + * greedily skip all preceeding and all following whitespace. */ + + for (;;) { + if (*l == 0) + return -EPIPE; + + if (!strchr(WHITESPACE, **p)) + break; + + /* Skip leading whitespace */ + (*p)++, (*l)--; + } + + r = unhexchar(**p); + if (r < 0) + return r; + + for (;;) { + (*p)++, (*l)--; + + if (*l == 0 || !strchr(WHITESPACE, **p)) + break; + + /* Skip following whitespace */ + } + + return r; +} + +int unhexmem(const char *p, size_t l, void **ret, size_t *ret_len) { + _cleanup_free_ uint8_t *buf = NULL; const char *x; + uint8_t *z; - assert(mem); - assert(len); + assert(ret); + assert(ret_len); assert(p || l == 0); if (l == (size_t) -1) l = strlen(p); - if (l % 2 != 0) - return -EINVAL; - - z = r = malloc((l + 1) / 2 + 1); - if (!r) + /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */ + buf = malloc((l + 1) / 2 + 1); + if (!buf) return -ENOMEM; - for (x = p; x < p + l; x += 2) { + for (x = p, z = buf;;) { int a, b; - a = unhexchar(x[0]); + a = unhex_next(&x, &l); + if (a == -EPIPE) /* End of string */ + break; if (a < 0) return a; - b = unhexchar(x[1]); + b = unhex_next(&x, &l); if (b < 0) return b; @@ -114,8 +150,8 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) { *z = 0; - *mem = TAKE_PTR(r); - *len = (l + 1) / 2; + *ret_len = (size_t) (z - buf); + *ret = TAKE_PTR(buf); return 0; } @@ -184,7 +220,7 @@ char *base32hexmem(const void *p, size_t l, bool padding) { for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) { /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ - x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ + * x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ @@ -284,7 +320,7 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l } /* a group of eight input bytes needs five output bytes, in case of - padding we need to add some extra bytes */ + * padding we need to add some extra bytes */ len = (l / 8) * 5; switch (l % 8) { @@ -312,7 +348,7 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l for (x = p; x < p + (l / 8) * 8; x += 8) { /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW - e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ + * e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ a = unbase32hexchar(x[0]); if (a < 0) return -EINVAL; @@ -668,7 +704,7 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) { l = strlen(p); /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra - bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */ + * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */ len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0); buf = malloc(len + 1); @@ -736,9 +772,7 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) { *z = 0; - if (ret_size) - *ret_size = (size_t) (z - buf); - + *ret_size = (size_t) (z - buf); *ret = TAKE_PTR(buf); return 0; diff --git a/src/systemd/src/basic/io-util.h b/src/systemd/src/basic/io-util.h index c34d97c653..e4717b6f30 100644 --- a/src/systemd/src/basic/io-util.h +++ b/src/systemd/src/basic/io-util.h @@ -28,9 +28,8 @@ int fd_wait_for_event(int fd, int event, usec_t timeout); ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); -static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { - unsigned j; - size_t r = 0; +static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, size_t n) { + size_t j, r = 0; for (j = 0; j < n; j++) r += i[j].iov_len; @@ -38,8 +37,8 @@ static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { return r; } -static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { - unsigned j; +static inline size_t IOVEC_INCREMENT(struct iovec *i, size_t n, size_t k) { + size_t j; for (j = 0; j < n; j++) { size_t sub; diff --git a/src/systemd/src/basic/mempool.c b/src/systemd/src/basic/mempool.c index 16aca7a3e6..0709676696 100644 --- a/src/systemd/src/basic/mempool.c +++ b/src/systemd/src/basic/mempool.c @@ -17,12 +17,12 @@ struct pool { struct pool *next; - unsigned n_tiles; - unsigned n_used; + size_t n_tiles; + size_t n_used; }; void* mempool_alloc_tile(struct mempool *mp) { - unsigned i; + size_t i; /* When a tile is released we add it to the list and simply * place the next pointer at its offset 0. */ @@ -40,8 +40,7 @@ void* mempool_alloc_tile(struct mempool *mp) { if (_unlikely_(!mp->first_pool) || _unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) { - unsigned n; - size_t size; + size_t size, n; struct pool *p; n = mp->first_pool ? mp->first_pool->n_tiles : 0; @@ -79,7 +78,7 @@ void mempool_free_tile(struct mempool *mp, void *p) { mp->freelist = p; } -#ifdef VALGRIND +#if VALGRIND void mempool_drop(struct mempool *mp) { struct pool *p = mp->first_pool; diff --git a/src/systemd/src/basic/mempool.h b/src/systemd/src/basic/mempool.h index 5322fd480d..68249cd881 100644 --- a/src/systemd/src/basic/mempool.h +++ b/src/systemd/src/basic/mempool.h @@ -30,6 +30,6 @@ static struct mempool pool_name = { \ } -#ifdef VALGRIND +#if VALGRIND void mempool_drop(struct mempool *mp); #endif diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c index b2d3689e1e..ae43a0411b 100644 --- a/src/systemd/src/basic/parse-util.c +++ b/src/systemd/src/basic/parse-util.c @@ -13,12 +13,14 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/socket.h> #include "alloc-util.h" #include "errno-list.h" #include "extract-word.h" #include "locale-util.h" #include "macro.h" +#include "missing.h" #include "parse-util.h" #include "process-util.h" #include "string-util.h" @@ -96,6 +98,30 @@ int parse_ifindex(const char *s, int *ret) { return 0; } +int parse_mtu(int family, const char *s, uint32_t *ret) { + uint64_t u; + size_t m; + int r; + + r = parse_size(s, 1024, &u); + if (r < 0) + return r; + + if (u > UINT32_MAX) + return -ERANGE; + + if (family == AF_INET6) + m = IPV6_MIN_MTU; /* This is 1280 */ + else + m = IPV4_MIN_MTU; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */ + + if (u < m) + return -ERANGE; + + *ret = (uint32_t) u; + return 0; +} + int parse_size(const char *t, uint64_t base, uint64_t *size) { /* Soo, sometimes we want to parse IEC binary suffixes, and @@ -655,4 +681,21 @@ int parse_dev(const char *s, dev_t *ret) { *ret = d; return 0; } + +int parse_oom_score_adjust(const char *s, int *ret) { + int r, v; + + assert(s); + assert(ret); + + r = safe_atoi(s, &v); + if (r < 0) + return r; + + if (v < OOM_SCORE_ADJ_MIN || v > OOM_SCORE_ADJ_MAX) + return -ERANGE; + + *ret = v; + return 0; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h index 74c30b5570..2b75b938c7 100644 --- a/src/systemd/src/basic/parse-util.h +++ b/src/systemd/src/basic/parse-util.h @@ -22,6 +22,7 @@ int parse_dev(const char *s, dev_t *ret); int parse_pid(const char *s, pid_t* ret_pid); int parse_mode(const char *s, mode_t *ret); int parse_ifindex(const char *s, int *ret); +int parse_mtu(int family, const char *s, uint32_t *ret); int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_range(const char *t, unsigned *lower, unsigned *upper); @@ -117,3 +118,5 @@ int parse_percent(const char *p); int parse_nice(const char *p, int *ret); int parse_ip_port(const char *s, uint16_t *ret); + +int parse_oom_score_adjust(const char *s, int *ret); diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c index 32fbfbb490..567fc61cea 100644 --- a/src/systemd/src/basic/path-util.c +++ b/src/systemd/src/basic/path-util.c @@ -690,11 +690,12 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path); path_kill_slashes(p); - if (suppress_root && path_equal(p, "/")) + if (suppress_root && empty_or_root(p)) p = mfree(p); free(*arg); *arg = p; + return 0; } diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h index a1829c41b1..79db819e4d 100644 --- a/src/systemd/src/basic/path-util.h +++ b/src/systemd/src/basic/path-util.h @@ -166,3 +166,6 @@ static inline const char *skip_dev_prefix(const char *p) { } bool empty_or_root(const char *root); +static inline const char *empty_to_root(const char *path) { + return isempty(path) ? "/" : path; +} diff --git a/src/systemd/src/basic/process-util.c b/src/systemd/src/basic/process-util.c index 80bf4d435e..4af99957d2 100644 --- a/src/systemd/src/basic/process-util.c +++ b/src/systemd/src/basic/process-util.c @@ -885,7 +885,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) { do { char line[LINE_MAX]; - unsigned i; + size_t i; for (i = 0; i < sizeof(line)-1; i++) { int c; @@ -1384,9 +1384,9 @@ int safe_fork_full( return 0; } -int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *ret_pid, const char *path, ...) { +int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) { bool stdout_is_tty, stderr_is_tty; - unsigned n, i; + size_t n, i; va_list ap; char **l; int r; @@ -1442,7 +1442,7 @@ int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *r va_end(ap); /* Allocate strv */ - l = alloca(sizeof(char *) * (n + 1)); + l = newa(char*, n + 1); /* Fill in arguments */ va_start(ap, path); @@ -1454,6 +1454,15 @@ int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *r _exit(EXIT_FAILURE); } +int set_oom_score_adjust(int value) { + char t[DECIMAL_STR_MAX(int)]; + + sprintf(t, "%i", value); + + return write_string_file("/proc/self/oom_score_adj", t, + WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER); +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/systemd/src/basic/process-util.h b/src/systemd/src/basic/process-util.h index 3641e6e8d0..e3bf36bf04 100644 --- a/src/systemd/src/basic/process-util.h +++ b/src/systemd/src/basic/process-util.h @@ -173,7 +173,9 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) { return safe_fork_full(name, NULL, 0, flags, ret_pid); } -int fork_agent(const char *name, const int except[], unsigned n_except, pid_t *pid, const char *path, ...); +int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...); + +int set_oom_score_adjust(int value); #if SIZEOF_PID_T == 4 /* The highest possibly (theoretic) pid_t value on this architecture. */ diff --git a/src/systemd/src/basic/random-util.c b/src/systemd/src/basic/random-util.c index 9447d6b32a..d80751cfe9 100644 --- a/src/systemd/src/basic/random-util.c +++ b/src/systemd/src/basic/random-util.c @@ -37,7 +37,7 @@ int acquire_random_bytes(void *p, size_t n, bool high_quality_required) { static int have_syscall = -1; _cleanup_close_ int fd = -1; - unsigned already_done = 0; + size_t already_done = 0; int r; /* Gathers some randomness from the kernel. This call will never block. If diff --git a/src/systemd/src/basic/set.h b/src/systemd/src/basic/set.h index 6f937af929..dc0f1e17e6 100644 --- a/src/systemd/src/basic/set.h +++ b/src/systemd/src/basic/set.h @@ -136,5 +136,3 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); #define _cleanup_set_free_ _cleanup_(set_freep) #define _cleanup_set_free_free_ _cleanup_(set_free_freep) - -int set_make(Set **ret, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS, void *add, ...); diff --git a/src/systemd/src/basic/signal-util.h b/src/systemd/src/basic/signal-util.h index de2364fac4..0c43467b63 100644 --- a/src/systemd/src/basic/signal-util.h +++ b/src/systemd/src/basic/signal-util.h @@ -24,8 +24,6 @@ int sigprocmask_many(int how, sigset_t *old, ...); const char *signal_to_string(int i) _const_; int signal_from_string(const char *s) _pure_; -int signal_from_string_try_harder(const char *s); - void nop_signal_handler(int sig); static inline void block_signals_reset(sigset_t *ss) { diff --git a/src/systemd/src/basic/stat-util.c b/src/systemd/src/basic/stat-util.c new file mode 100644 index 0000000000..28e75618bc --- /dev/null +++ b/src/systemd/src/basic/stat-util.c @@ -0,0 +1,292 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering +***/ + +#include "nm-sd-adapt.h" + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <linux/magic.h> +#include <sched.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <sys/types.h> +#include <unistd.h> + +#include "dirent-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "macro.h" +#include "missing.h" +#include "stat-util.h" +#include "string-util.h" + +#if 0 /* NM_IGNORED */ +int is_symlink(const char *path) { + struct stat info; + + assert(path); + + if (lstat(path, &info) < 0) + return -errno; + + return !!S_ISLNK(info.st_mode); +} + +int is_dir(const char* path, bool follow) { + struct stat st; + int r; + + assert(path); + + if (follow) + r = stat(path, &st); + else + r = lstat(path, &st); + if (r < 0) + return -errno; + + return !!S_ISDIR(st.st_mode); +} + +int is_device_node(const char *path) { + struct stat info; + + assert(path); + + if (lstat(path, &info) < 0) + return -errno; + + return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); +} + +int dir_is_empty(const char *path) { + _cleanup_closedir_ DIR *d; + struct dirent *de; + + d = opendir(path); + if (!d) + return -errno; + + FOREACH_DIRENT(de, d, return -errno) + return 0; + + return 1; +} + +bool null_or_empty(struct stat *st) { + assert(st); + + if (S_ISREG(st->st_mode) && st->st_size <= 0) + return true; + + /* We don't want to hardcode the major/minor of /dev/null, + * hence we do a simpler "is this a device node?" check. */ + + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) + return true; + + return false; +} + +int null_or_empty_path(const char *fn) { + struct stat st; + + assert(fn); + + if (stat(fn, &st) < 0) + return -errno; + + return null_or_empty(&st); +} + +int null_or_empty_fd(int fd) { + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + return null_or_empty(&st); +} + +int path_is_read_only_fs(const char *path) { + struct statvfs st; + + assert(path); + + if (statvfs(path, &st) < 0) + return -errno; + + if (st.f_flag & ST_RDONLY) + return true; + + /* On NFS, statvfs() might not reflect whether we can actually + * write to the remote share. Let's try again with + * access(W_OK) which is more reliable, at least sometimes. */ + if (access(path, W_OK) < 0 && errno == EROFS) + return true; + + return false; +} + +int path_is_os_tree(const char *path) { + int r; + + assert(path); + + /* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir + * always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from + * the case where just the os-release file is missing. */ + if (laccess(path, F_OK) < 0) + return -errno; + + /* We use /usr/lib/os-release as flag file if something is an OS */ + r = chase_symlinks("/usr/lib/os-release", path, CHASE_PREFIX_ROOT, NULL); + if (r == -ENOENT) { + + /* Also check for the old location in /etc, just in case. */ + r = chase_symlinks("/etc/os-release", path, CHASE_PREFIX_ROOT, NULL); + if (r == -ENOENT) + return 0; /* We got nothing */ + } + if (r < 0) + return r; + + return 1; +} + +int files_same(const char *filea, const char *fileb, int flags) { + struct stat a, b; + + assert(filea); + assert(fileb); + + if (fstatat(AT_FDCWD, filea, &a, flags) < 0) + return -errno; + + if (fstatat(AT_FDCWD, fileb, &b, flags) < 0) + return -errno; + + return a.st_dev == b.st_dev && + a.st_ino == b.st_ino; +} + +bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) { + assert(s); + assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type)); + + return F_TYPE_EQUAL(s->f_type, magic_value); +} + +int fd_is_fs_type(int fd, statfs_f_type_t magic_value) { + struct statfs s; + + if (fstatfs(fd, &s) < 0) + return -errno; + + return is_fs_type(&s, magic_value); +} + +int path_is_fs_type(const char *path, statfs_f_type_t magic_value) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); + if (fd < 0) + return -errno; + + return fd_is_fs_type(fd, magic_value); +} + +bool is_temporary_fs(const struct statfs *s) { + return is_fs_type(s, TMPFS_MAGIC) || + is_fs_type(s, RAMFS_MAGIC); +} + +bool is_network_fs(const struct statfs *s) { + return is_fs_type(s, CIFS_MAGIC_NUMBER) || + is_fs_type(s, CODA_SUPER_MAGIC) || + is_fs_type(s, NCP_SUPER_MAGIC) || + is_fs_type(s, NFS_SUPER_MAGIC) || + is_fs_type(s, SMB_SUPER_MAGIC) || + is_fs_type(s, V9FS_MAGIC) || + is_fs_type(s, AFS_SUPER_MAGIC) || + is_fs_type(s, OCFS2_SUPER_MAGIC); +} + +int fd_is_temporary_fs(int fd) { + struct statfs s; + + if (fstatfs(fd, &s) < 0) + return -errno; + + return is_temporary_fs(&s); +} + +int fd_is_network_fs(int fd) { + struct statfs s; + + if (fstatfs(fd, &s) < 0) + return -errno; + + return is_network_fs(&s); +} + +int fd_is_network_ns(int fd) { + int r; + + r = fd_is_fs_type(fd, NSFS_MAGIC); + if (r <= 0) + return r; + + r = ioctl(fd, NS_GET_NSTYPE); + if (r < 0) + return -errno; + + return r == CLONE_NEWNET; +} + +int path_is_temporary_fs(const char *path) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); + if (fd < 0) + return -errno; + + return fd_is_temporary_fs(fd); +} +#endif /* NM_IGNORED */ + +int stat_verify_regular(const struct stat *st) { + assert(st); + + /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error + * code. */ + + if (S_ISDIR(st->st_mode)) + return -EISDIR; + + if (S_ISLNK(st->st_mode)) + return -ELOOP; + + if (!S_ISREG(st->st_mode)) + return -EBADFD; + + return 0; +} + +int fd_verify_regular(int fd) { + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + return stat_verify_regular(&st); +} diff --git a/src/systemd/src/basic/stat-util.h b/src/systemd/src/basic/stat-util.h new file mode 100644 index 0000000000..d1e8d33001 --- /dev/null +++ b/src/systemd/src/basic/stat-util.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering +***/ + +#include <stdbool.h> +#include <stddef.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <sys/types.h> +#include <sys/vfs.h> + +#include "macro.h" + +int is_symlink(const char *path); +int is_dir(const char *path, bool follow); +int is_device_node(const char *path); + +int dir_is_empty(const char *path); + +static inline int dir_is_populated(const char *path) { + int r; + r = dir_is_empty(path); + if (r < 0) + return r; + return !r; +} + +bool null_or_empty(struct stat *st) _pure_; +int null_or_empty_path(const char *fn); +int null_or_empty_fd(int fd); + +int path_is_read_only_fs(const char *path); +int path_is_os_tree(const char *path); + +int files_same(const char *filea, const char *fileb, int flags); + +/* The .f_type field of struct statfs is really weird defined on + * different archs. Let's give its type a name. */ +typedef typeof(((struct statfs*)NULL)->f_type) statfs_f_type_t; + +bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_; +int fd_is_fs_type(int fd, statfs_f_type_t magic_value); +int path_is_fs_type(const char *path, statfs_f_type_t magic_value); + +bool is_temporary_fs(const struct statfs *s) _pure_; +bool is_network_fs(const struct statfs *s) _pure_; + +int fd_is_temporary_fs(int fd); +int fd_is_network_fs(int fd); + +int fd_is_network_ns(int fd); + +int path_is_temporary_fs(const char *path); + +/* Because statfs.t_type can be int on some architectures, we have to cast + * the const magic to the type, otherwise the compiler warns about + * signed/unsigned comparison, because the magic can be 32 bit unsigned. + */ +#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) + +int stat_verify_regular(const struct stat *st); +int fd_verify_regular(int fd); diff --git a/src/systemd/src/basic/string-util.c b/src/systemd/src/basic/string-util.c index a7b3f09620..a60c7dccfe 100644 --- a/src/systemd/src/basic/string-util.c +++ b/src/systemd/src/basic/string-util.c @@ -23,6 +23,7 @@ #include "terminal-util.h" #include "utf8.h" #include "util.h" +#include "fileio.h" int strcmp_ptr(const char *a, const char *b) { @@ -700,7 +701,8 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { enum { STATE_OTHER, STATE_ESCAPE, - STATE_BRACKET + STATE_CSI, + STATE_CSO, } state = STATE_OTHER; char *obuf = NULL; size_t osz = 0, isz, shift[2] = {}; @@ -709,7 +711,17 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { assert(ibuf); assert(*ibuf); - /* Strips ANSI color and replaces TABs by 8 spaces */ + /* This does three things: + * + * 1. Replaces TABs by 8 spaces + * 2. Strips ANSI color sequences (a subset of CSI), i.e. ESC '[' … 'm' sequences + * 3. Strips ANSI operating system sequences (CSO), i.e. ESC ']' … BEL sequences + * + * Everything else will be left as it is. In particular other ANSI sequences are left as they are, as are any + * other special characters. Truncated ANSI sequences are left-as is too. This call is supposed to suppress the + * most basic formatting noise, but nothing else. + * + * Why care for CSO sequences? Well, to undo what terminal_urlify() and friends generate. */ isz = _isz ? *_isz : strlen(*ibuf); @@ -744,8 +756,11 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { fputc('\x1B', f); advance_offsets(i - *ibuf, highlight, shift, 1); break; - } else if (*i == '[') { - state = STATE_BRACKET; + } else if (*i == '[') { /* ANSI CSI */ + state = STATE_CSI; + begin = i + 1; + } else if (*i == ']') { /* ANSI CSO */ + state = STATE_CSO; begin = i + 1; } else { fputc('\x1B', f); @@ -756,10 +771,10 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { break; - case STATE_BRACKET: + case STATE_CSI: - if (i >= *ibuf + isz || /* EOT */ - (!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) { + if (i >= *ibuf + isz || /* EOT … */ + !strchr("01234567890;m", *i)) { /* … or invalid chars in sequence */ fputc('\x1B', f); fputc('[', f); advance_offsets(i - *ibuf, highlight, shift, 2); @@ -767,11 +782,26 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { i = begin-1; } else if (*i == 'm') state = STATE_OTHER; + + break; + + case STATE_CSO: + + if (i >= *ibuf + isz || /* EOT … */ + (*i != '\a' && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */ + fputc('\x1B', f); + fputc(']', f); + advance_offsets(i - *ibuf, highlight, shift, 2); + state = STATE_OTHER; + i = begin-1; + } else if (*i == '\a') + state = STATE_OTHER; + break; } } - if (ferror(f)) { + if (fflush_and_check(f) < 0) { fclose(f); return mfree(obuf); } diff --git a/src/systemd/src/basic/string-util.h b/src/systemd/src/basic/string-util.h index 4f500c87d4..5a10eeabfe 100644 --- a/src/systemd/src/basic/string-util.h +++ b/src/systemd/src/basic/string-util.h @@ -58,7 +58,7 @@ static inline const char *empty_to_null(const char *p) { return isempty(p) ? NULL : p; } -static inline const char *strdash_if_empty(const char *str) { +static inline const char *empty_to_dash(const char *str) { return isempty(str) ? "-" : str; } @@ -109,7 +109,7 @@ char *strjoin_real(const char *x, ...) _sentinel_; const char *_appendees_[] = { a, __VA_ARGS__ }; \ char *_d_, *_p_; \ size_t _len_ = 0; \ - unsigned _i_; \ + size_t _i_; \ for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ _len_ += strlen(_appendees_[_i_]); \ _p_ = _d_ = alloca(_len_ + 1); \ diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c index 5bde3826fc..9d5000aac1 100644 --- a/src/systemd/src/basic/strv.c +++ b/src/systemd/src/basic/strv.c @@ -109,8 +109,8 @@ char **strv_copy(char * const *l) { return r; } -unsigned strv_length(char * const *l) { - unsigned n = 0; +size_t strv_length(char * const *l) { + size_t n = 0; if (!l) return 0; @@ -123,8 +123,8 @@ unsigned strv_length(char * const *l) { char **strv_new_ap(const char *x, va_list ap) { const char *s; - char **a; - unsigned n = 0, i = 0; + _cleanup_strv_free_ char **a = NULL; + size_t n = 0, i = 0; va_list aq; /* As a special trick we ignore all listed strings that equal @@ -154,7 +154,7 @@ char **strv_new_ap(const char *x, va_list ap) { if (x != STRV_IGNORE) { a[i] = strdup(x); if (!a[i]) - goto fail; + return NULL; i++; } @@ -165,7 +165,7 @@ char **strv_new_ap(const char *x, va_list ap) { a[i] = strdup(s); if (!a[i]) - goto fail; + return NULL; i++; } @@ -173,11 +173,7 @@ char **strv_new_ap(const char *x, va_list ap) { a[i] = NULL; - return a; - -fail: - strv_free(a); - return NULL; + return TAKE_PTR(a); } char **strv_new(const char *x, ...) { @@ -259,7 +255,7 @@ int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { char **strv_split(const char *s, const char *separator) { const char *word, *state; size_t l; - unsigned n, i; + size_t n, i; char **r; assert(s); @@ -289,7 +285,7 @@ char **strv_split(const char *s, const char *separator) { char **strv_split_newlines(const char *s) { char **l; - unsigned n; + size_t n; assert(s); @@ -384,7 +380,7 @@ char *strv_join(char **l, const char *separator) { int strv_push(char ***l, char *value) { char **c; - unsigned n, m; + size_t n, m; if (!value) return 0; @@ -409,7 +405,7 @@ int strv_push(char ***l, char *value) { int strv_push_pair(char ***l, char *a, char *b) { char **c; - unsigned n, m; + size_t n, m; if (!a && !b) return 0; @@ -435,9 +431,9 @@ int strv_push_pair(char ***l, char *a, char *b) { return 0; } -int strv_insert(char ***l, unsigned position, char *value) { +int strv_insert(char ***l, size_t position, char *value) { char **c; - unsigned n, m, i; + size_t n, m, i; if (!value) return 0; @@ -605,7 +601,7 @@ char **strv_parse_nulstr(const char *s, size_t l) { */ const char *p; - unsigned c = 0, i = 0; + size_t c = 0, i = 0; char **v; assert(s || l <= 0); @@ -769,7 +765,7 @@ int strv_extendf(char ***l, const char *format, ...) { } char **strv_reverse(char **l) { - unsigned n, i; + size_t n, i; n = strv_length(l); if (n <= 1) diff --git a/src/systemd/src/basic/strv.h b/src/systemd/src/basic/strv.h index 79512c0ce3..958c5f3a98 100644 --- a/src/systemd/src/basic/strv.h +++ b/src/systemd/src/basic/strv.h @@ -32,7 +32,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase); void strv_clear(char **l); char **strv_copy(char * const *l); -unsigned strv_length(char * const *l) _pure_; +size_t strv_length(char * const *l) _pure_; int strv_extend_strv(char ***a, char **b, bool filter_duplicates); int strv_extend_strv_concat(char ***a, char **b, const char *suffix); @@ -41,7 +41,7 @@ int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); int strv_extend_front(char ***l, const char *value); int strv_push(char ***l, char *value); int strv_push_pair(char ***l, char *a, char *b); -int strv_insert(char ***l, unsigned position, char *value); +int strv_insert(char ***l, size_t position, char *value); static inline int strv_push_prepend(char ***l, char *value) { return strv_insert(l, 0, value); @@ -113,7 +113,7 @@ void strv_print(char **l); if (!first) \ _l = (char**) &first; \ else { \ - unsigned _n; \ + size_t _n; \ va_list _ap; \ \ _n = 1; \ diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index 962d3dceeb..fa9f66f2ae 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -23,11 +23,13 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "io-util.h" #include "log.h" #include "macro.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "stat-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -438,7 +440,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { { "us", 1 }, }; - unsigned i; + size_t i; char *p = buf; bool something = false; @@ -617,10 +619,9 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) { time_t x; usec_t x_usec, plus = 0, minus = 0, ret; int r, weekday = -1, dst = -1; - unsigned i; + size_t i; - /* - * Allowed syntaxes: + /* Allowed syntaxes: * * 2012-09-22 16:34:22 * 2012-09-22 16:34 (seconds will be set to 0) @@ -634,7 +635,6 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) { * +5min * -5days * @2147483647 (seconds since epoch) - * */ assert(t); @@ -693,10 +693,10 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) { tzset(); /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only - * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because - * there are no nice APIs available to cover this. By accepting the local time zone strings, we make - * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't - * support arbitrary timezone specifications. */ + * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because + * there are no nice APIs available to cover this. By accepting the local time zone strings, we make + * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't + * support arbitrary timezone specifications. */ for (j = 0; j <= 1; j++) { @@ -882,7 +882,7 @@ int parse_timestamp(const char *t, usec_t *usec) { int r; last_space = strrchr(t, ' '); - if (last_space != NULL && timezone_is_valid(last_space + 1)) + if (last_space != NULL && timezone_is_valid(last_space + 1, LOG_DEBUG)) tz = last_space + 1; if (!tz || endswith_no_case(t, " UTC")) @@ -908,10 +908,10 @@ int parse_timestamp(const char *t, usec_t *usec) { tzset(); /* If there is a timezone that matches the tzname fields, leave the parsing to the implementation. - * Otherwise just cut it off */ + * Otherwise just cut it off. */ with_tz = !STR_IN_SET(tz, tzname[0], tzname[1]); - /*cut off the timezone if we dont need it*/ + /* Cut off the timezone if we dont need it. */ if (with_tz) t = strndupa(t, last_space - t); @@ -965,7 +965,7 @@ static char* extract_multiplier(char *p, usec_t *multiplier) { { "us", 1ULL }, { "µs", 1ULL }, }; - unsigned i; + size_t i; for (i = 0; i < ELEMENTSOF(table); i++) { char *e; @@ -1139,8 +1139,8 @@ int parse_nsec(const char *t, nsec_t *nsec) { for (;;) { long long l, z = 0; + size_t n = 0, i; char *e; - unsigned i, n = 0; p += strspn(p, WHITESPACE); @@ -1281,10 +1281,12 @@ int get_timezones(char ***ret) { } #endif /* NM_IGNORED */ -bool timezone_is_valid(const char *name) { +bool timezone_is_valid(const char *name, int log_level) { bool slash = false; const char *p, *t; - struct stat st; + _cleanup_close_ int fd = -1; + char buf[4]; + int r; if (isempty(name)) return false; @@ -1313,11 +1315,30 @@ bool timezone_is_valid(const char *name) { return false; t = strjoina("/usr/share/zoneinfo/", name); - if (stat(t, &st) < 0) + + fd = open(t, O_RDONLY|O_CLOEXEC); + if (fd < 0) { + log_full_errno(log_level, errno, "Failed to open timezone file '%s': %m", t); return false; + } - if (!S_ISREG(st.st_mode)) + r = fd_verify_regular(fd); + if (r < 0) { + log_full_errno(log_level, r, "Timezone file '%s' is not a regular file: %m", t); return false; + } + + r = loop_read_exact(fd, buf, 4, false); + if (r < 0) { + log_full_errno(log_level, r, "Failed to read from timezone file '%s': %m", t); + return false; + } + + /* Magic from tzfile(5) */ + if (memcmp(buf, "TZif", 4) != 0) { + log_full(log_level, "Timezone file '%s' has wrong magic bytes", t); + return false; + } return true; } @@ -1389,7 +1410,7 @@ int get_timezone(char **tz) { if (!e) return -EINVAL; - if (!timezone_is_valid(e)) + if (!timezone_is_valid(e, LOG_DEBUG)) return -EINVAL; z = strdup(e); diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h index 5b2674a4b6..e720688c2b 100644 --- a/src/systemd/src/basic/time-util.h +++ b/src/systemd/src/basic/time-util.h @@ -128,7 +128,7 @@ int parse_nsec(const char *t, nsec_t *nsec); bool ntp_synced(void); int get_timezones(char ***l); -bool timezone_is_valid(const char *name); +bool timezone_is_valid(const char *name, int log_level); bool clock_boottime_supported(void); bool clock_supported(clockid_t clock); diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c index 746eba006d..6f8adfa610 100644 --- a/src/systemd/src/libsystemd-network/dhcp-identifier.c +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -86,7 +86,7 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i #if 0 /* NM_IGNORED */ /* name is a pointer to memory in the udev_device struct, so must have the same scope */ - _cleanup_udev_device_unref_ struct udev_device *device = NULL; + _cleanup_(udev_device_unrefp) struct udev_device *device = NULL; #else /* NM_IGNORED */ char name_buf[IF_NAMESIZE]; #endif /* NM_IGNORED */ @@ -96,7 +96,7 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i #if 0 /* NM_IGNORED */ if (detect_container() <= 0) { /* not in a container, udev will be around */ - _cleanup_udev_unref_ struct udev *udev; + _cleanup_(udev_unrefp) struct udev *udev; char ifindex_str[2 + DECIMAL_STR_MAX(int)]; udev = udev_new(); diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c index 4e39665e70..86e67358c3 100644 --- a/src/systemd/src/libsystemd-network/dhcp-option.c +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -14,6 +14,7 @@ #include "alloc-util.h" #include "utf8.h" +#include "strv.h" #include "dhcp-internal.h" @@ -37,6 +38,34 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, *offset += 1; break; + case SD_DHCP_OPTION_USER_CLASS: { + size_t len = 0; + char **s; + + STRV_FOREACH(s, (char **) optval) + len += strlen(*s) + 1; + + if (size < *offset + len + 2) + return -ENOBUFS; + + options[*offset] = code; + options[*offset + 1] = len; + *offset += 2; + + STRV_FOREACH(s, (char **) optval) { + len = strlen(*s); + + if (len > 255) + return -ENAMETOOLONG; + + options[*offset] = len; + + memcpy_safe(&options[*offset + 1], *s, len); + *offset += len + 1; + } + + break; + } default: if (size < *offset + optlen + 2) return -ENOBUFS; diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index f23318cb9a..e05f52d454 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -86,7 +86,7 @@ static bool net_condition_test_strv(char * const *raw_patterns, /* If the patterns begin with "!", edit it out and negate the test. */ if (raw_patterns[0][0] == '!') { char **patterns; - unsigned i, length; + size_t i, length; length = strv_length(raw_patterns) + 1; /* Include the NULL. */ patterns = newa(char*, length); @@ -100,7 +100,7 @@ static bool net_condition_test_strv(char * const *raw_patterns, return string && strv_fnmatch(raw_patterns, string, 0); } -bool net_match_config(const struct ether_addr *match_mac, +bool net_match_config(Set *match_mac, char * const *match_paths, char * const *match_drivers, char * const *match_types, @@ -132,7 +132,7 @@ bool net_match_config(const struct ether_addr *match_mac, if (match_arch && condition_test(match_arch) <= 0) return false; - if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN))) + if (match_mac && dev_mac && !set_contains(match_mac, dev_mac)) return false; if (!net_condition_test_strv(match_paths, dev_path)) @@ -284,10 +284,9 @@ int config_parse_hwaddr(const char *unit, const char *rvalue, void *data, void *userdata) { + + _cleanup_free_ struct ether_addr *n = NULL; struct ether_addr **hwaddr = data; - struct ether_addr *n; - const char *start; - size_t offset; int r; assert(filename); @@ -299,17 +298,86 @@ int config_parse_hwaddr(const char *unit, if (!n) return log_oom(); - start = rvalue + strspn(rvalue, WHITESPACE); - r = ether_addr_from_string(start, n, &offset); + r = ether_addr_from_string(rvalue, n); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue); + return 0; + } + + *hwaddr = TAKE_PTR(n); + + return 0; +} + +int config_parse_hwaddrs(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) { + + _cleanup_set_free_free_ Set *s = NULL; + const char *p = rvalue; + Set **hwaddrs = data; + int r; - if (r || (start[offset + strspn(start + offset, WHITESPACE)] != '\0')) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue); - free(n); + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + *hwaddrs = set_free_free(*hwaddrs); return 0; } - free(*hwaddr); - *hwaddr = n; + s = set_new(ðer_addr_hash_ops); + if (!s) + return log_oom(); + + for (;;) { + _cleanup_free_ char *word = NULL; + _cleanup_free_ struct ether_addr *n = NULL; + + r = extract_first_word(&p, &word, NULL, 0); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + + n = new(struct ether_addr, 1); + if (!n) + return log_oom(); + + r = ether_addr_from_string(word, n); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring: %s", word); + continue; + } + + r = set_put(s, n); + if (r < 0) + return log_oom(); + if (r > 0) + n = NULL; /* avoid cleanup */ + } + + r = set_ensure_allocated(hwaddrs, ðer_addr_hash_ops); + if (r < 0) + return log_oom(); + + r = set_move(*hwaddrs, s); + if (r < 0) + return log_oom(); return 0; } @@ -592,14 +660,3 @@ int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t siz return 0; } - -int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) { - assert(data); - assert(data_len); - assert(string); - - if (strlen(string) % 2) - return -EINVAL; - - return unhexmem(string, strlen(string), (void **)data, data_len); -} diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index e7fc337e6b..d0076f453d 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -12,12 +12,13 @@ #include "sd-dhcp-lease.h" #include "condition.h" +#include "set.h" #include "udev.h" #define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 #define LINK_BRIDGE_PORT_PRIORITY_MAX 63 -bool net_match_config(const struct ether_addr *match_mac, +bool net_match_config(Set *match_mac, char * const *match_path, char * const *match_driver, char * const *match_type, @@ -42,6 +43,10 @@ int config_parse_hwaddr(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_hwaddrs(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_ifnames(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); @@ -73,5 +78,5 @@ struct sd_dhcp_route; void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size); int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string); +/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */ int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); -int deserialize_dhcp_option(void **data, size_t *data_len, const char *string); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index d1bd1cc910..ef2620f437 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -29,6 +29,7 @@ #include "random-util.h" #include "string-util.h" #include "util.h" +#include "strv.h" #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) @@ -85,6 +86,7 @@ struct sd_dhcp_client { size_t client_id_len; char *hostname; char *vendor_class_identifier; + char **user_class; uint32_t mtu; uint32_t xid; usec_t start_time; @@ -445,6 +447,26 @@ int sd_dhcp_client_set_vendor_class_identifier( return free_and_strdup(&client->vendor_class_identifier, vci); } +int sd_dhcp_client_set_user_class( + sd_dhcp_client *client, + const char* const* user_class) { + + _cleanup_strv_free_ char **s = NULL; + char **p; + + STRV_FOREACH(p, (char **) user_class) + if (strlen(*p) > 255) + return -ENAMETOOLONG; + + s = strv_copy((char **) user_class); + if (!s) + return -ENOMEM; + + client->user_class = TAKE_PTR(s); + + return 0; +} + int sd_dhcp_client_set_client_port( sd_dhcp_client *client, uint16_t port) { @@ -768,6 +790,15 @@ static int client_send_discover(sd_dhcp_client *client) { return r; } + if (client->user_class) { + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_USER_CLASS, + strv_length(client->user_class), + client->user_class); + if (r < 0) + return r; + } + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL); if (r < 0) @@ -1923,6 +1954,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { free(client->req_opts); free(client->hostname); free(client->vendor_class_identifier); + client->user_class = strv_free(client->user_class); return mfree(client); } diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index 591c1f3420..d92c512604 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -223,7 +223,7 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) { } int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) { - unsigned r; + size_t r; assert_return(lease, -EINVAL); assert_return(domains, -EINVAL); @@ -669,7 +669,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void return 0; } - if (!timezone_is_valid(tz)) { + if (!timezone_is_valid(tz, LOG_DEBUG)) { log_debug_errno(r, "Timezone is not valid, ignoring: %m"); return 0; } @@ -1195,13 +1195,13 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { } if (client_id_hex) { - r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex); + r = unhexmem(client_id_hex, (size_t) -1, &lease->client_id, &lease->client_id_len); if (r < 0) log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex); } if (vendor_specific_hex) { - r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex); + r = unhexmem(vendor_specific_hex, (size_t) -1, &lease->vendor_specific, &lease->vendor_specific_len); if (r < 0) log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex); } @@ -1213,7 +1213,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (!options[i]) continue; - r = deserialize_dhcp_option(&data, &len, options[i]); + r = unhexmem(options[i], (size_t) -1, &data, &len); if (r < 0) { log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]); continue; diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c index 9ef3fab74f..3952cd99f0 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -250,8 +250,7 @@ int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval, if (r < 0) return 0; - strv_free(lease->domains); - lease->domains = domains; + strv_free_and_replace(lease->domains, domains); lease->domains_count = r; return r; @@ -310,8 +309,7 @@ int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { if (r < 0) return 0; - lease->ntp_fqdn = strv_free(lease->ntp_fqdn); - lease->ntp_fqdn = servers; + strv_free_and_replace(lease->ntp_fqdn, servers); lease->ntp_fqdn_count = r; break; diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c index bb15d94ecf..d88a0c6f2d 100644 --- a/src/systemd/src/libsystemd-network/sd-lldp.c +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -404,15 +404,15 @@ static int neighbor_compare_func(const void *a, const void *b) { static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { sd_lldp *lldp = userdata; - int r, q; + int r; r = lldp_make_space(lldp, 0); if (r < 0) return log_lldp_errno(r, "Failed to make space: %m"); - q = lldp_start_timer(lldp, NULL); - if (q < 0) - return log_lldp_errno(q, "Failed to restart timer: %m"); + r = lldp_start_timer(lldp, NULL); + if (r < 0) + return log_lldp_errno(r, "Failed to restart timer: %m"); return 0; } diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index 789cc50174..fd0a569362 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -82,6 +82,7 @@ enum { SD_DHCP_OPTION_REBINDING_T2_TIME = 59, SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61, + SD_DHCP_OPTION_USER_CLASS = 77, SD_DHCP_OPTION_FQDN = 81, SD_DHCP_OPTION_NEW_POSIX_TIMEZONE = 100, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE = 101, @@ -154,6 +155,9 @@ int sd_dhcp_client_set_hostname( int sd_dhcp_client_set_vendor_class_identifier( sd_dhcp_client *client, const char *vci); +int sd_dhcp_client_set_user_class( + sd_dhcp_client *client, + const char* const *user_class); int sd_dhcp_client_get_lease( sd_dhcp_client *client, sd_dhcp_lease **ret); |