diff options
Diffstat (limited to 'src')
27 files changed, 774 insertions, 210 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index ae6f2800d5..8699bd0a86 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -200,6 +200,8 @@ libsystemd_nm_la_SOURCES = \ systemd/src/libsystemd-network/sd-ipv4ll.c \ systemd/src/libsystemd-network/sd-lldp.c \ systemd/src/libsystemd/sd-event/sd-event.c \ + systemd/src/libsystemd/sd-id128/id128-util.c \ + systemd/src/libsystemd/sd-id128/id128-util.h \ systemd/src/libsystemd/sd-id128/sd-id128.c \ systemd/src/shared/dns-domain.c \ systemd/src/shared/dns-domain.h \ diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c index 7a13d28f8c..0be0ceff40 100644 --- a/src/systemd/src/basic/fd-util.c +++ b/src/systemd/src/basic/fd-util.c @@ -191,6 +191,12 @@ int fd_cloexec(int fd, bool cloexec) { } #if 0 /* NM_IGNORED */ +void stdio_unset_cloexec(void) { + fd_cloexec(STDIN_FILENO, false); + fd_cloexec(STDOUT_FILENO, false); + fd_cloexec(STDERR_FILENO, false); +} + _pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { unsigned i; diff --git a/src/systemd/src/basic/fd-util.h b/src/systemd/src/basic/fd-util.h index b86e41698a..34b98d4aec 100644 --- a/src/systemd/src/basic/fd-util.h +++ b/src/systemd/src/basic/fd-util.h @@ -63,6 +63,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); int fd_nonblock(int fd, bool nonblock); int fd_cloexec(int fd, bool cloexec); +void stdio_unset_cloexec(void); int close_all_fds(const int except[], unsigned n_except); diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c index b07cb9cb2d..b2fe15ca28 100644 --- a/src/systemd/src/basic/fileio.c +++ b/src/systemd/src/basic/fileio.c @@ -49,6 +49,8 @@ #include "umask-util.h" #include "utf8.h" +#define READ_FULL_BYTES_MAX (4U*1024U*1024U) + int write_string_stream(FILE *f, const char *line, bool enforce_newline) { assert(f); @@ -232,7 +234,7 @@ int read_full_stream(FILE *f, char **contents, size_t *size) { if (S_ISREG(st.st_mode)) { /* Safety check */ - if (st.st_size > 4*1024*1024) + if (st.st_size > READ_FULL_BYTES_MAX) return -E2BIG; /* Start with the right file size, but be prepared for @@ -247,26 +249,31 @@ int read_full_stream(FILE *f, char **contents, size_t *size) { char *t; size_t k; - t = realloc(buf, n+1); + t = realloc(buf, n + 1); if (!t) return -ENOMEM; buf = t; k = fread(buf + l, 1, n - l, f); + if (k > 0) + l += k; - if (k <= 0) { - if (ferror(f)) - return -errno; + if (ferror(f)) + return -errno; + if (feof(f)) break; - } - l += k; - n *= 2; + /* We aren't expecting fread() to return a short read outside + * of (error && eof), assert buffer is full and enlarge buffer. + */ + assert(l == n); /* Safety check */ - if (n > 4*1024*1024) + if (n >= READ_FULL_BYTES_MAX) return -E2BIG; + + n = MIN(n * 2, READ_FULL_BYTES_MAX); } buf[l] = 0; @@ -1071,7 +1078,7 @@ int fflush_and_check(FILE *f) { return 0; } -/* This is much like like mkostemp() but is subject to umask(). */ +/* This is much like mkostemp() but is subject to umask(). */ int mkostemp_safe(char *pattern, int flags) { _cleanup_umask_ mode_t u = 0; int fd; @@ -1161,12 +1168,13 @@ int tempfn_random(const char *p, const char *extra, char **ret) { return 0; } +#if 0 /* NM_IGNORED */ int tempfn_random_child(const char *p, const char *extra, char **ret) { char *t, *x; uint64_t u; unsigned i; + int r; - assert(p); assert(ret); /* Turns this: @@ -1175,6 +1183,12 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) { * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0 */ + if (!p) { + r = tmp_dir(&p); + if (r < 0) + return r; + } + if (!extra) extra = ""; @@ -1196,7 +1210,6 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) { return 0; } -#if 0 /* NM_IGNORED */ int write_timestamp_file_atomic(const char *fn, usec_t n) { char ln[DECIMAL_STR_MAX(n)+2]; @@ -1264,9 +1277,13 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) #if 0 /* NM_IGNORED */ int open_tmpfile_unlinkable(const char *directory, int flags) { char *p; - int fd; + int fd, r; - assert(directory); + if (!directory) { + r = tmp_dir(&directory); + if (r < 0) + return r; + } /* Returns an unlinked temporary file that cannot be linked into the file system anymore */ @@ -1361,4 +1378,45 @@ int link_tmpfile(int fd, const char *path, const char *target) { return 0; } + +int read_nul_string(FILE *f, char **ret) { + _cleanup_free_ char *x = NULL; + size_t allocated = 0, n = 0; + + assert(f); + assert(ret); + + /* Reads a NUL-terminated string from the specified file. */ + + for (;;) { + int c; + + if (!GREEDY_REALLOC(x, allocated, n+2)) + return -ENOMEM; + + c = fgetc(f); + if (c == 0) /* Terminate at NUL byte */ + break; + if (c == EOF) { + if (ferror(f)) + return -errno; + break; /* Terminate at EOF */ + } + + x[n++] = (char) c; + } + + if (x) + x[n] = 0; + else { + x = new0(char, 1); + if (!x) + return -ENOMEM; + } + + *ret = x; + x = NULL; + + return 0; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/fileio.h b/src/systemd/src/basic/fileio.h index 58dbc80c24..9ac497d9eb 100644 --- a/src/systemd/src/basic/fileio.h +++ b/src/systemd/src/basic/fileio.h @@ -86,3 +86,5 @@ int open_tmpfile_unlinkable(const char *directory, int flags); int open_tmpfile_linkable(const char *target, int flags, char **ret_path); int link_tmpfile(int fd, const char *path, const char *target); + +int read_nul_string(FILE *f, char **ret); diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c index 1e09366f20..b291c9fcf7 100644 --- a/src/systemd/src/basic/fs-util.c +++ b/src/systemd/src/basic/fs-util.c @@ -44,6 +44,9 @@ #endif /* NM_IGNORED */ #include "parse-util.h" #include "path-util.h" +#if 0 /* NM_IGNORED */ +#include "stat-util.h" +#endif /* NM_IGNORED */ #include "stdio-util.h" #include "string-util.h" #include "strv.h" @@ -508,6 +511,94 @@ int get_files_in_directory(const char *path, char ***list) { return n; } +static int getenv_tmp_dir(const char **ret_path) { + const char *n; + int r, ret = 0; + + assert(ret_path); + + /* We use the same order of environment variables python uses in tempfile.gettempdir(): + * https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */ + FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") { + const char *e; + + e = secure_getenv(n); + if (!e) + continue; + if (!path_is_absolute(e)) { + r = -ENOTDIR; + goto next; + } + if (!path_is_safe(e)) { + r = -EPERM; + goto next; + } + + r = is_dir(e, true); + if (r < 0) + goto next; + if (r == 0) { + r = -ENOTDIR; + goto next; + } + + *ret_path = e; + return 1; + + next: + /* Remember first error, to make this more debuggable */ + if (ret >= 0) + ret = r; + } + + if (ret < 0) + return ret; + + *ret_path = NULL; + return ret; +} + +static int tmp_dir_internal(const char *def, const char **ret) { + const char *e; + int r, k; + + assert(def); + assert(ret); + + r = getenv_tmp_dir(&e); + if (r > 0) { + *ret = e; + return 0; + } + + k = is_dir(def, true); + if (k == 0) + k = -ENOTDIR; + if (k < 0) + return r < 0 ? r : k; + + *ret = def; + return 0; +} + +int var_tmp_dir(const char **ret) { + + /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus + * even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is + * returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR, + * making it a variable that overrides all temporary file storage locations. */ + + return tmp_dir_internal("/var/tmp", ret); +} + +int tmp_dir(const char **ret) { + + /* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually + * backed by an in-memory file system: /tmp. */ + + return tmp_dir_internal("/tmp", ret); +} + int inotify_add_watch_fd(int fd, int what, uint32_t mask) { char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; int r; diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h index 517b599d6f..2c3b9a1c74 100644 --- a/src/systemd/src/basic/fs-util.h +++ b/src/systemd/src/basic/fs-util.h @@ -61,6 +61,9 @@ int mkfifo_atomic(const char *path, mode_t mode); int get_files_in_directory(const char *path, char ***list); +int tmp_dir(const char **ret); +int var_tmp_dir(const char **ret); + #define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) #define FOREACH_INOTIFY_EVENT(e, buffer, sz) \ diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c index 503586afb4..b2b503278b 100644 --- a/src/systemd/src/basic/parse-util.c +++ b/src/systemd/src/basic/parse-util.c @@ -31,6 +31,9 @@ #include "extract-word.h" #include "macro.h" #include "parse-util.h" +#if 0 /* NM_IGNORED */ +#include "process-util.h" +#endif /* NM_IGNORED */ #include "string-util.h" int parse_boolean(const char *v) { @@ -537,7 +540,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { return 0; } -int parse_percent(const char *p) { +int parse_percent_unbounded(const char *p) { const char *pc, *n; unsigned v; int r; @@ -550,8 +553,32 @@ int parse_percent(const char *p) { r = safe_atou(n, &v); if (r < 0) return r; + + return (int) v; +} + +int parse_percent(const char *p) { + int v; + + v = parse_percent_unbounded(p); if (v > 100) return -ERANGE; - return (int) v; + return v; } + +#if 0 /* NM_IGNORED */ +int parse_nice(const char *p, int *ret) { + int n, r; + + r = safe_atoi(p, &n); + if (r < 0) + return r; + + if (!nice_is_valid(n)) + return -ERANGE; + + *ret = n; + return 0; +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h index 73441bb6fd..461e1cd4d8 100644 --- a/src/systemd/src/basic/parse-util.h +++ b/src/systemd/src/basic/parse-util.h @@ -106,4 +106,7 @@ int safe_atod(const char *s, double *ret_d); int parse_fractional_part_u(const char **s, size_t digits, unsigned *res); +int parse_percent_unbounded(const char *p); int parse_percent(const char *p); + +int parse_nice(const char *p, int *ret); diff --git a/src/systemd/src/basic/set.h b/src/systemd/src/basic/set.h index 12f64a8c57..a5f8beb0c4 100644 --- a/src/systemd/src/basic/set.h +++ b/src/systemd/src/basic/set.h @@ -23,8 +23,8 @@ #include "hashmap.h" #include "macro.h" -Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); -#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS) +Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS) static inline Set *set_free(Set *s) { internal_hashmap_free(HASHMAP_BASE(s)); @@ -42,8 +42,8 @@ static inline Set *set_copy(Set *s) { return (Set*) internal_hashmap_copy(HASHMAP_BASE(s)); } -int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); -#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) +int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) int set_put(Set *s, const void *key); /* no set_update */ diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c index 853c5700ea..6a7dc28b5e 100644 --- a/src/systemd/src/basic/socket-util.c +++ b/src/systemd/src/basic/socket-util.c @@ -1056,3 +1056,17 @@ int flush_accept(int fd) { close(cfd); } } + +struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length) { + struct cmsghdr *cmsg; + + assert(mh); + + CMSG_FOREACH(cmsg, mh) + if (cmsg->cmsg_level == level && + cmsg->cmsg_type == type && + (length == (socklen_t) -1 || length == cmsg->cmsg_len)) + return cmsg; + + return NULL; +} diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h index e9230e4a9f..2536b085f9 100644 --- a/src/systemd/src/basic/socket-util.h +++ b/src/systemd/src/basic/socket-util.h @@ -142,6 +142,8 @@ int flush_accept(int fd); #define CMSG_FOREACH(cmsg, mh) \ for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) +struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t length); + /* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */ #define SOCKADDR_UN_LEN(sa) \ ({ \ diff --git a/src/systemd/src/basic/string-util.c b/src/systemd/src/basic/string-util.c index 68de772e9e..fe554ff4c1 100644 --- a/src/systemd/src/basic/string-util.c +++ b/src/systemd/src/basic/string-util.c @@ -24,6 +24,7 @@ #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include "alloc-util.h" #if 0 /* NM_IGNORED */ @@ -327,6 +328,14 @@ char ascii_tolower(char x) { return x; } +char ascii_toupper(char x) { + + if (x >= 'a' && x <= 'z') + return x - 'a' + 'A'; + + return x; +} + char *ascii_strlower(char *t) { char *p; @@ -338,6 +347,17 @@ char *ascii_strlower(char *t) { return t; } +char *ascii_strupper(char *t) { + char *p; + + assert(t); + + for (p = t; *p; p++) + *p = ascii_toupper(*p); + + return t; +} + char *ascii_strlower_n(char *t, size_t n) { size_t i; @@ -809,25 +829,20 @@ int free_and_strdup(char **p, const char *s) { return 1; } -#pragma GCC push_options -#pragma GCC optimize("O0") +/* + * Pointer to memset is volatile so that compiler must de-reference + * the pointer and can't assume that it points to any function in + * particular (such as memset, which it then might further "optimize") + * This approach is inspired by openssl's crypto/mem_clr.c. + */ +typedef void *(*memset_t)(void *,int,size_t); -void* memory_erase(void *p, size_t l) { - volatile uint8_t* x = (volatile uint8_t*) p; +static volatile memset_t memset_func = memset; - /* This basically does what memset() does, but hopefully isn't - * optimized away by the compiler. One of those days, when - * glibc learns memset_s() we should replace this call by - * memset_s(), but until then this has to do. */ - - for (; l > 0; l--) - *(x++) = 'x'; - - return p; +void* memory_erase(void *p, size_t l) { + return memset_func(p, 'x', l); } -#pragma GCC pop_options - char* string_erase(char *x) { if (!x) diff --git a/src/systemd/src/basic/string-util.h b/src/systemd/src/basic/string-util.h index 1209e1e2e1..b75aba63c2 100644 --- a/src/systemd/src/basic/string-util.h +++ b/src/systemd/src/basic/string-util.h @@ -137,6 +137,9 @@ char ascii_tolower(char x); char *ascii_strlower(char *s); char *ascii_strlower_n(char *s, size_t n); +char ascii_toupper(char x); +char *ascii_strupper(char *s); + int ascii_strcasecmp_n(const char *a, const char *b, size_t n); int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m); diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c index 6dd6c1a9ad..eeb8c1e094 100644 --- a/src/systemd/src/basic/strv.c +++ b/src/systemd/src/basic/strv.c @@ -642,6 +642,17 @@ char **strv_remove(char **l, const char *s) { } char **strv_parse_nulstr(const char *s, size_t l) { + /* l is the length of the input data, which will be split at NULs into + * elements of the resulting strv. Hence, the number of items in the resulting strv + * will be equal to one plus the number of NUL bytes in the l bytes starting at s, + * unless s[l-1] is NUL, in which case the final empty string is not stored in + * the resulting strv, and length is equal to the number of NUL bytes. + * + * Note that contrary to a normal nulstr which cannot contain empty strings, because + * the input data is terminated by any two consequent NUL bytes, this parser accepts + * empty strings in s. + */ + const char *p; unsigned c = 0, i = 0; char **v; @@ -704,6 +715,13 @@ char **strv_split_nulstr(const char *s) { } int strv_make_nulstr(char **l, char **p, size_t *q) { + /* A valid nulstr with two NULs at the end will be created, but + * q will be the length without the two trailing NULs. Thus the output + * string is a valid nulstr and can be iterated over using NULSTR_FOREACH, + * and can also be parsed by strv_parse_nulstr as long as the length + * is provided separately. + */ + size_t n_allocated = 0, n = 0; _cleanup_free_ char *m = NULL; char **i; @@ -716,7 +734,7 @@ int strv_make_nulstr(char **l, char **p, size_t *q) { z = strlen(*i); - if (!GREEDY_REALLOC(m, n_allocated, n + z + 1)) + if (!GREEDY_REALLOC(m, n_allocated, n + z + 2)) return -ENOMEM; memcpy(m + n, *i, z + 1); @@ -727,11 +745,14 @@ int strv_make_nulstr(char **l, char **p, size_t *q) { m = new0(char, 1); if (!m) return -ENOMEM; - n = 0; - } + n = 1; + } else + /* make sure there is a second extra NUL at the end of resulting nulstr */ + m[n] = '\0'; + assert(n > 0); *p = m; - *q = n; + *q = n - 1; m = NULL; @@ -807,9 +828,8 @@ char **strv_reverse(char **l) { if (n <= 1) return l; - for (i = 0; i < n / 2; i++) { + for (i = 0; i < n / 2; i++) SWAP_TWO(l[i], l[n-1-i]); - } return l; } @@ -880,7 +900,7 @@ int strv_extend_n(char ***l, const char *value, size_t n) { if (n == 0) return 0; - /* Adds the value value n times to l */ + /* Adds the value n times to l */ k = strv_length(*l); diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index b4dabdeb75..212c8f4ee4 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -257,32 +257,95 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) { return tv; } -static char *format_timestamp_internal(char *buf, size_t l, usec_t t, - bool utc, bool us) { +static char *format_timestamp_internal( + char *buf, + size_t l, + usec_t t, + bool utc, + bool us) { + + /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our + * generated timestamps may be parsed with parse_timestamp(), and always read the same. */ + static const char * const weekdays[] = { + [0] = "Sun", + [1] = "Mon", + [2] = "Tue", + [3] = "Wed", + [4] = "Thu", + [5] = "Fri", + [6] = "Sat", + }; + struct tm tm; time_t sec; - int k; + size_t n; assert(buf); - assert(l > 0); + if (l < + 3 + /* week day */ + 1 + 10 + /* space and date */ + 1 + 8 + /* space and time */ + (us ? 1 + 6 : 0) + /* "." and microsecond part */ + 1 + 1 + /* space and shortest possible zone */ + 1) + return NULL; /* Not enough space even for the shortest form. */ if (t <= 0 || t == USEC_INFINITY) + return NULL; /* Timestamp is unset */ + + sec = (time_t) (t / USEC_PER_SEC); /* Round down */ + if ((usec_t) sec != (t / USEC_PER_SEC)) + return NULL; /* overflow? */ + + if (!localtime_or_gmtime_r(&sec, &tm, utc)) return NULL; - sec = (time_t) (t / USEC_PER_SEC); - localtime_or_gmtime_r(&sec, &tm, utc); + /* Start with the week day */ + assert((size_t) tm.tm_wday < ELEMENTSOF(weekdays)); + memcpy(buf, weekdays[tm.tm_wday], 4); - if (us) - k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm); - else - k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm); + /* Add the main components */ + if (strftime(buf + 3, l - 3, " %Y-%m-%d %H:%M:%S", &tm) <= 0) + return NULL; /* Doesn't fit */ - if (k <= 0) - return NULL; + /* Append the microseconds part, if that's requested */ if (us) { - snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC)); - if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0) - return NULL; + n = strlen(buf); + if (n + 8 > l) + return NULL; /* Microseconds part doesn't fit. */ + + sprintf(buf + n, ".%06llu", (unsigned long long) (t % USEC_PER_SEC)); + } + + /* Append the timezone */ + n = strlen(buf); + if (utc) { + /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the + * obsolete "GMT" instead. */ + if (n + 5 > l) + return NULL; /* "UTC" doesn't fit. */ + + strcpy(buf + n, " UTC"); + + } else if (!isempty(tm.tm_zone)) { + size_t tn; + + /* An explicit timezone is specified, let's use it, if it fits */ + tn = strlen(tm.tm_zone); + if (n + 1 + tn + 1 > l) { + /* The full time zone does not fit in. Yuck. */ + + if (n + 1 + _POSIX_TZNAME_MAX + 1 > l) + return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */ + + /* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX + * minimum time zone length. In this case suppress the timezone entirely, in order not to dump + * an overly long, hard to read string on the user. This should be safe, because the user will + * assume the local timezone anyway if none is shown. And so does parse_timestamp(). */ + } else { + buf[n++] = ' '; + strcpy(buf + n, tm.tm_zone); + } } return buf; @@ -544,12 +607,11 @@ int parse_timestamp(const char *t, usec_t *usec) { { "Sat", 6 }, }; - const char *k; - const char *utc; + const char *k, *utc, *tzn = NULL; struct tm tm, copy; time_t x; usec_t x_usec, plus = 0, minus = 0, ret; - int r, weekday = -1; + int r, weekday = -1, dst = -1; unsigned i; /* @@ -614,15 +676,55 @@ int parse_timestamp(const char *t, usec_t *usec) { goto finish; } + /* See if the timestamp is suffixed with UTC */ utc = endswith_no_case(t, " UTC"); if (utc) t = strndupa(t, utc - t); + else { + const char *e = NULL; + int j; + + 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. */ + + for (j = 0; j <= 1; j++) { + + if (isempty(tzname[j])) + continue; + + e = endswith_no_case(t, tzname[j]); + if (!e) + continue; + if (e == t) + continue; + if (e[-1] != ' ') + continue; + + break; + } - x = ret / USEC_PER_SEC; + if (IN_SET(j, 0, 1)) { + /* Found one of the two timezones specified. */ + t = strndupa(t, e - t - 1); + dst = j; + tzn = tzname[j]; + } + } + + x = (time_t) (ret / USEC_PER_SEC); x_usec = 0; - assert_se(localtime_or_gmtime_r(&x, &tm, utc)); - tm.tm_isdst = -1; + if (!localtime_or_gmtime_r(&x, &tm, utc)) + return -EINVAL; + + tm.tm_isdst = dst; + if (tzn) + tm.tm_zone = tzn; if (streq(t, "today")) { tm.tm_sec = tm.tm_min = tm.tm_hour = 0; @@ -639,7 +741,6 @@ int parse_timestamp(const char *t, usec_t *usec) { goto from_tm; } - for (i = 0; i < ELEMENTSOF(day_nr); i++) { size_t skip; @@ -732,7 +833,6 @@ parse_usec: return -EINVAL; x_usec = add; - } from_tm: diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h index 1b058f0e49..99be5ce6ee 100644 --- a/src/systemd/src/basic/time-util.h +++ b/src/systemd/src/basic/time-util.h @@ -68,7 +68,9 @@ typedef struct triple_timestamp { #define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC)) #define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC)) -#define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1) /* weekdays can be unicode */ +/* We assume a maximum timezone length of 6. TZNAME_MAX is not defined on Linux, but glibc internally initializes this + * to 6. Let's rely on that. */ +#define FORMAT_TIMESTAMP_MAX (3+1+10+1+8+1+6+1+6+1) #define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */ #define FORMAT_TIMESTAMP_RELATIVE_MAX 256 #define FORMAT_TIMESPAN_MAX 64 diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index 586d77a69e..248a525ba0 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -598,47 +598,6 @@ int on_ac_power(void) { return found_online || !found_offline; } -bool id128_is_valid(const char *s) { - size_t i, l; - - l = strlen(s); - if (l == 32) { - - /* Simple formatted 128bit hex string */ - - for (i = 0; i < l; i++) { - char c = s[i]; - - if (!(c >= '0' && c <= '9') && - !(c >= 'a' && c <= 'z') && - !(c >= 'A' && c <= 'Z')) - return false; - } - - } else if (l == 36) { - - /* Formatted UUID */ - - for (i = 0; i < l; i++) { - char c = s[i]; - - if ((i == 8 || i == 13 || i == 18 || i == 23)) { - if (c != '-') - return false; - } else { - if (!(c >= '0' && c <= '9') && - !(c >= 'a' && c <= 'z') && - !(c >= 'A' && c <= 'Z')) - return false; - } - } - - } else - return false; - - return true; -} - int container_get_leader(const char *machine, pid_t *pid) { _cleanup_free_ char *s = NULL, *class = NULL; const char *p; @@ -849,6 +808,61 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max) { return r; } +uint64_t system_tasks_max(void) { + +#if SIZEOF_PID_T == 4 +#define TASKS_MAX ((uint64_t) (INT32_MAX-1)) +#elif SIZEOF_PID_T == 2 +#define TASKS_MAX ((uint64_t) (INT16_MAX-1)) +#else +#error "Unknown pid_t size" +#endif + + _cleanup_free_ char *value = NULL, *root = NULL; + uint64_t a = TASKS_MAX, b = TASKS_MAX; + + /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this + * limit: + * + * a) the maximum value for the pid_t type + * b) the cgroups pids_max attribute for the system + * c) the kernel's configure maximum PID value + * + * And then pick the smallest of the three */ + + if (read_one_line_file("/proc/sys/kernel/pid_max", &value) >= 0) + (void) safe_atou64(value, &a); + + if (cg_get_root_path(&root) >= 0) { + value = mfree(value); + + if (cg_get_attribute("pids", root, "pids.max", &value) >= 0) + (void) safe_atou64(value, &b); + } + + return MIN3(TASKS_MAX, + a <= 0 ? TASKS_MAX : a, + b <= 0 ? TASKS_MAX : b); +} + +uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { + uint64_t t, m; + + assert(max > 0); + + /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages + * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */ + + t = system_tasks_max(); + assert(t > 0); + + m = t * v; + if (m / t != v) /* overflow? */ + return UINT64_MAX; + + return m / max; +} + int update_reboot_parameter_and_warn(const char *param) { int r; diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h index 25b0dd1f5f..b8776636bf 100644 --- a/src/systemd/src/basic/util.h +++ b/src/systemd/src/basic/util.h @@ -65,6 +65,10 @@ static inline const char* one_zero(bool b) { return b ? "1" : "0"; } +static inline const char* enable_disable(bool b) { + return b ? "enable" : "disable"; +} + void execute_directories(const char* const* directories, usec_t timeout, char *argv[]); bool plymouth_running(void); @@ -180,8 +184,6 @@ static inline unsigned log2u_round_up(unsigned x) { return log2u(x - 1) + 1; } -bool id128_is_valid(const char *s) _pure_; - int container_get_leader(const char *machine, pid_t *pid); int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd); @@ -190,6 +192,9 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int uint64_t physical_memory(void); uint64_t physical_memory_scale(uint64_t v, uint64_t max); +uint64_t system_tasks_max(void); +uint64_t system_tasks_max_scale(uint64_t v, uint64_t max); + int update_reboot_parameter_and_warn(const char *param); int version(void); diff --git a/src/systemd/src/libsystemd-network/lldp-neighbor.c b/src/systemd/src/libsystemd-network/lldp-neighbor.c index 0ab04bf782..afede1e7e6 100644 --- a/src/systemd/src/libsystemd-network/lldp-neighbor.c +++ b/src/systemd/src/libsystemd-network/lldp-neighbor.c @@ -199,7 +199,7 @@ int lldp_neighbor_parse(sd_lldp_neighbor *n) { assert(n); if (n->raw_size < sizeof(struct ether_header)) { - log_lldp("Recieved truncated packet, ignoring."); + log_lldp("Received truncated packet, ignoring."); return -EBADMSG; } diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index fe88d18a70..292217fea2 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -107,16 +107,16 @@ bool net_match_config(const struct ether_addr *match_mac, const char *dev_type, const char *dev_name) { - if (match_host && !condition_test(match_host)) + if (match_host && condition_test(match_host) <= 0) return false; - if (match_virt && !condition_test(match_virt)) + if (match_virt && condition_test(match_virt) <= 0) return false; - if (match_kernel && !condition_test(match_kernel)) + if (match_kernel && condition_test(match_kernel) <= 0) return false; - if (match_arch && !condition_test(match_arch)) + if (match_arch && condition_test(match_arch) <= 0) return false; if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN))) diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 9b7d3edf3d..d91e3763c3 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -117,8 +117,8 @@ struct sd_event_source { int64_t priority; unsigned pending_index; unsigned prepare_index; - unsigned pending_iteration; - unsigned prepare_iteration; + uint64_t pending_iteration; + uint64_t prepare_iteration; LIST_FIELDS(sd_event_source, sources); @@ -223,7 +223,7 @@ struct sd_event { pid_t original_pid; - unsigned iteration; + uint64_t iteration; triple_timestamp timestamp; int state; @@ -2885,4 +2885,12 @@ _public_ int sd_event_get_watchdog(sd_event *e) { return e->watchdog; } + +_public_ int sd_event_get_iteration(sd_event *e, uint64_t *ret) { + assert_return(e, -EINVAL); + assert_return(!event_pid_changed(e), -ECHILD); + + *ret = e->iteration; + return 0; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c new file mode 100644 index 0000000000..c16052d818 --- /dev/null +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -0,0 +1,200 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 "nm-sd-adapt.h" + +#include <fcntl.h> +#include <unistd.h> + +#include "fd-util.h" +#include "hexdecoct.h" +#include "id128-util.h" +#include "io-util.h" +#include "stdio-util.h" + +#if 0 /* NM_IGNORED */ +char *id128_to_uuid_string(sd_id128_t id, char s[37]) { + unsigned n, k = 0; + + assert(s); + + /* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */ + + for (n = 0; n < 16; n++) { + + if (IN_SET(n, 4, 6, 8, 10)) + s[k++] = '-'; + + s[k++] = hexchar(id.bytes[n] >> 4); + s[k++] = hexchar(id.bytes[n] & 0xF); + } + + assert(k == 36); + + s[k] = 0; + + return s; +} + +bool id128_is_valid(const char *s) { + size_t i, l; + + assert(s); + + l = strlen(s); + if (l == 32) { + + /* Plain formatted 128bit hex string */ + + for (i = 0; i < l; i++) { + char c = s[i]; + + if (!(c >= '0' && c <= '9') && + !(c >= 'a' && c <= 'z') && + !(c >= 'A' && c <= 'Z')) + return false; + } + + } else if (l == 36) { + + /* Formatted UUID */ + + for (i = 0; i < l; i++) { + char c = s[i]; + + if ((i == 8 || i == 13 || i == 18 || i == 23)) { + if (c != '-') + return false; + } else { + if (!(c >= '0' && c <= '9') && + !(c >= 'a' && c <= 'z') && + !(c >= 'A' && c <= 'Z')) + return false; + } + } + + } else + return false; + + return true; +} +#endif /* NM_IGNORED */ + +int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) { + char buffer[36 + 2]; + ssize_t l; + + assert(fd >= 0); + assert(f < _ID128_FORMAT_MAX); + + /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both + * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they + * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you + * accept". */ + + l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */ + if (l < 0) + return (int) l; + if (l == 0) /* empty? */ + return -ENOMEDIUM; + + switch (l) { + + case 33: /* plain UUID with trailing newline */ + if (buffer[32] != '\n') + return -EINVAL; + + /* fall through */ + case 32: /* plain UUID without trailing newline */ + if (f == ID128_UUID) + return -EINVAL; + + buffer[32] = 0; + break; + + case 37: /* RFC UUID with trailing newline */ + if (buffer[36] != '\n') + return -EINVAL; + + /* fall through */ + case 36: /* RFC UUID without trailing newline */ + if (f == ID128_PLAIN) + return -EINVAL; + + buffer[36] = 0; + break; + + default: + return -EINVAL; + } + + return sd_id128_from_string(buffer, ret); +} + +int id128_read(const char *p, Id128Format f, sd_id128_t *ret) { + _cleanup_close_ int fd = -1; + + fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + return id128_read_fd(fd, f, ret); +} + +#if 0 /* NM_IGNORED */ +int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) { + char buffer[36 + 2]; + size_t sz; + int r; + + assert(fd >= 0); + assert(f < _ID128_FORMAT_MAX); + + if (f != ID128_UUID) { + sd_id128_to_string(id, buffer); + buffer[32] = '\n'; + sz = 33; + } else { + id128_to_uuid_string(id, buffer); + buffer[36] = '\n'; + sz = 37; + } + + r = loop_write(fd, buffer, sz, false); + if (r < 0) + return r; + + if (do_sync) { + if (fsync(fd) < 0) + return -errno; + } + + return r; +} + +int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) { + _cleanup_close_ int fd = -1; + + fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444); + if (fd < 0) + return -errno; + + return id128_write_fd(fd, f, id, do_sync); +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h new file mode 100644 index 0000000000..3ba59acbca --- /dev/null +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h @@ -0,0 +1,45 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> + +#include "sd-id128.h" +#include "macro.h" + +char *id128_to_uuid_string(sd_id128_t id, char s[37]); + +/* Like SD_ID128_FORMAT_STR, but formats as UUID, not in plain format */ +#define ID128_UUID_FORMAT_STR "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" + +bool id128_is_valid(const char *s) _pure_; + +typedef enum Id128Format { + ID128_ANY, + ID128_PLAIN, /* formatted as 32 hex chars as-is */ + ID128_UUID, /* formatted as 36 character uuid string */ + _ID128_FORMAT_MAX, +} Id128Format; + +int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret); +int id128_read(const char *p, Id128Format f, sd_id128_t *ret); + +int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync); +int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync); diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index 01b805a104..9408c32bd2 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -27,6 +27,7 @@ #include "fd-util.h" #include "hexdecoct.h" +#include "id128-util.h" #include "io-util.h" #include "macro.h" #include "random-util.h" @@ -47,6 +48,7 @@ _public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) { return s; } +#endif /* NM_IGNORED */ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { unsigned n, i; @@ -54,7 +56,6 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { bool is_guid = false; assert_return(s, -EINVAL); - assert_return(ret, -EINVAL); for (n = 0, i = 0; n < 16;) { int a, b; @@ -92,125 +93,60 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { if (s[i] != 0) return -EINVAL; - *ret = t; + if (ret) + *ret = t; return 0; } -static sd_id128_t make_v4_uuid(sd_id128_t id) { - /* Stolen from generate_random_uuid() of drivers/char/random.c - * in the kernel sources */ - - /* Set UUID version to 4 --- truly random generation */ - id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; - - /* Set the UUID variant to DCE */ - id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; - - return id; -} -#endif - _public_ int sd_id128_get_machine(sd_id128_t *ret) { - static thread_local sd_id128_t saved_machine_id; - static thread_local bool saved_machine_id_valid = false; - _cleanup_close_ int fd = -1; - char buf[33]; - unsigned j; - sd_id128_t t; + static thread_local sd_id128_t saved_machine_id = {}; int r; assert_return(ret, -EINVAL); - if (saved_machine_id_valid) { - *ret = saved_machine_id; - return 0; - } + if (sd_id128_is_null(saved_machine_id)) { + r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id); + if (r < 0) + return r; - fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return -errno; - - r = loop_read_exact(fd, buf, 33, false); - if (r < 0) - return r; - if (buf[32] !='\n') - return -EIO; - - for (j = 0; j < 16; j++) { - int a, b; - - a = unhexchar(buf[j*2]); - b = unhexchar(buf[j*2+1]); - - if (a < 0 || b < 0) - return -EIO; - - t.bytes[j] = a << 4 | b; + if (sd_id128_is_null(saved_machine_id)) + return -EINVAL; } - saved_machine_id = t; - saved_machine_id_valid = true; - - *ret = t; + *ret = saved_machine_id; return 0; } _public_ int sd_id128_get_boot(sd_id128_t *ret) { - static thread_local sd_id128_t saved_boot_id; - static thread_local bool saved_boot_id_valid = false; - _cleanup_close_ int fd = -1; - char buf[36]; - unsigned j; - sd_id128_t t; - char *p; + static thread_local sd_id128_t saved_boot_id = {}; int r; assert_return(ret, -EINVAL); - if (saved_boot_id_valid) { - *ret = saved_boot_id; - return 0; + if (sd_id128_is_null(saved_boot_id)) { + r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id); + if (r < 0) + return r; } - fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return -errno; - - r = loop_read_exact(fd, buf, 36, false); - if (r < 0) - return r; - - for (j = 0, p = buf; j < 16; j++) { - int a, b; - - if (p >= buf + 35) - return -EIO; - - if (*p == '-') { - p++; - if (p >= buf + 35) - return -EIO; - } - - a = unhexchar(p[0]); - b = unhexchar(p[1]); - - if (a < 0 || b < 0) - return -EIO; + *ret = saved_boot_id; + return 0; +} - t.bytes[j] = a << 4 | b; +#if 0 /* NM_IGNORED */ +static sd_id128_t make_v4_uuid(sd_id128_t id) { + /* Stolen from generate_random_uuid() of drivers/char/random.c + * in the kernel sources */ - p += 2; - } + /* Set UUID version to 4 --- truly random generation */ + id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; - saved_boot_id = t; - saved_boot_id_valid = true; + /* Set the UUID variant to DCE */ + id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; - *ret = t; - return 0; + return id; } -#if 0 /* NM_IGNORED */ _public_ int sd_id128_randomize(sd_id128_t *ret) { sd_id128_t t; int r; diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index 531ace1c34..cc26b7df55 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -104,6 +104,7 @@ int sd_event_get_tid(sd_event *e, pid_t *tid); int sd_event_get_exit_code(sd_event *e, int *code); int sd_event_set_watchdog(sd_event *e, int b); int sd_event_get_watchdog(sd_event *e); +int sd_event_get_iteration(sd_event *e, uint64_t *ret); sd_event_source* sd_event_source_ref(sd_event_source *s); sd_event_source* sd_event_source_unref(sd_event_source *s); diff --git a/src/tests/test-systemd.c b/src/tests/test-systemd.c index a6c0bf3f1f..744b55c992 100644 --- a/src/tests/test-systemd.c +++ b/src/tests/test-systemd.c @@ -84,6 +84,12 @@ test_dhcp_create (void) g_assert (r == 0); g_assert (client4); + if (/* never true */ client4 == (gpointer) &r) { + /* we don't want to call this, but ensure that the linker + * includes all these symbols. */ + sd_dhcp_client_start (client4); + } + sd_dhcp_client_unref (client4); } |