diff options
author | Thomas Haller <thaller@redhat.com> | 2015-09-16 14:11:11 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-09-16 14:28:05 +0200 |
commit | 3383d5d0a66cf0def16694a90e8d72880f14cfe2 (patch) | |
tree | 4102c4a1a65942029f6001c3cca7466a08b6f857 /src/systemd/src/basic | |
parent | 8f4e6175268689575b84ef12821b1d293b68d4c5 (diff) | |
download | NetworkManager-3383d5d0a66cf0def16694a90e8d72880f14cfe2.tar.gz |
systemd: update code from upstream
This is a direct dump from systemd git on 2015-09-16, git commit
ac2896bab6.
======
SYSTEMD_DIR=../systemd
COMMIT=ac2896bab61bd8cd0b8a8b92f8347e2c11a088b5
(
cd "$SYSTEMD_DIR"
git checkout "$COMMIT"
git reset --hard
git clean -fdx
)
git ls-files :/src/systemd/src/ | xargs -d '\n' rm -f
nm_copy_sd() {
mkdir -p "./src/systemd/$(dirname "$1")"
cp "$SYSTEMD_DIR/$1" "./src/systemd/$1"
}
nm_copy_sd "src/basic/async.h"
nm_copy_sd "src/basic/fileio.c"
nm_copy_sd "src/basic/fileio.h"
nm_copy_sd "src/basic/hostname-util.c"
nm_copy_sd "src/basic/hostname-util.h"
nm_copy_sd "src/basic/in-addr-util.c"
nm_copy_sd "src/basic/in-addr-util.h"
nm_copy_sd "src/basic/list.h"
nm_copy_sd "src/basic/log.h"
nm_copy_sd "src/basic/macro.h"
nm_copy_sd "src/basic/path-util.c"
nm_copy_sd "src/basic/path-util.h"
nm_copy_sd "src/basic/random-util.c"
nm_copy_sd "src/basic/random-util.h"
nm_copy_sd "src/basic/refcnt.h"
nm_copy_sd "src/basic/siphash24.c"
nm_copy_sd "src/basic/siphash24.h"
nm_copy_sd "src/basic/socket-util.h"
nm_copy_sd "src/basic/sparse-endian.h"
nm_copy_sd "src/basic/strv.c"
nm_copy_sd "src/basic/strv.h"
nm_copy_sd "src/basic/time-util.c"
nm_copy_sd "src/basic/time-util.h"
nm_copy_sd "src/basic/unaligned.h"
nm_copy_sd "src/basic/utf8.c"
nm_copy_sd "src/basic/utf8.h"
nm_copy_sd "src/basic/util.c"
nm_copy_sd "src/basic/util.h"
nm_copy_sd "src/libsystemd-network/dhcp6-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp6-network.c"
nm_copy_sd "src/libsystemd-network/dhcp6-option.c"
nm_copy_sd "src/libsystemd-network/dhcp6-protocol.h"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.c"
nm_copy_sd "src/libsystemd-network/dhcp-identifier.h"
nm_copy_sd "src/libsystemd-network/dhcp-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-lease-internal.h"
nm_copy_sd "src/libsystemd-network/dhcp-network.c"
nm_copy_sd "src/libsystemd-network/dhcp-option.c"
nm_copy_sd "src/libsystemd-network/dhcp-packet.c"
nm_copy_sd "src/libsystemd-network/dhcp-protocol.h"
nm_copy_sd "src/libsystemd-network/ipv4ll-internal.h"
nm_copy_sd "src/libsystemd-network/ipv4ll-internal.h"
nm_copy_sd "src/libsystemd-network/ipv4ll-network.c"
nm_copy_sd "src/libsystemd-network/ipv4ll-packet.c"
nm_copy_sd "src/libsystemd-network/network-internal.c"
nm_copy_sd "src/libsystemd-network/network-internal.h"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp6-lease.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-client.c"
nm_copy_sd "src/libsystemd-network/sd-dhcp-lease.c"
nm_copy_sd "src/libsystemd-network/sd-ipv4ll.c"
nm_copy_sd "src/libsystemd/sd-id128/sd-id128.c"
nm_copy_sd "src/shared/dns-domain.c"
nm_copy_sd "src/shared/dns-domain.h"
nm_copy_sd "src/systemd/_sd-common.h"
nm_copy_sd "src/systemd/sd-dhcp6-client.h"
nm_copy_sd "src/systemd/sd-dhcp6-lease.h"
nm_copy_sd "src/systemd/sd-dhcp-client.h"
nm_copy_sd "src/systemd/sd-dhcp-lease.h"
nm_copy_sd "src/systemd/sd-event.h"
nm_copy_sd "src/systemd/sd-icmp6-nd.h"
nm_copy_sd "src/systemd/sd-id128.h"
nm_copy_sd "src/systemd/sd-ipv4ll.h"
Diffstat (limited to 'src/systemd/src/basic')
-rw-r--r-- | src/systemd/src/basic/hostname-util.c | 30 | ||||
-rw-r--r-- | src/systemd/src/basic/hostname-util.h | 5 | ||||
-rw-r--r-- | src/systemd/src/basic/macro.h | 3 | ||||
-rw-r--r-- | src/systemd/src/basic/refcnt.h | 4 | ||||
-rw-r--r-- | src/systemd/src/basic/strv.c | 30 | ||||
-rw-r--r-- | src/systemd/src/basic/strv.h | 3 | ||||
-rw-r--r-- | src/systemd/src/basic/time-util.c | 79 | ||||
-rw-r--r-- | src/systemd/src/basic/time-util.h | 6 | ||||
-rw-r--r-- | src/systemd/src/basic/util.c | 358 | ||||
-rw-r--r-- | src/systemd/src/basic/util.h | 53 |
10 files changed, 404 insertions, 167 deletions
diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c index d901a5e82b..1b816fb77a 100644 --- a/src/systemd/src/basic/hostname-util.c +++ b/src/systemd/src/basic/hostname-util.c @@ -62,16 +62,19 @@ static bool hostname_valid_char(char c) { } /** - * Check if s looks like a valid host name or fqdn. This does not do + * Check if s looks like a valid host name or FQDN. This does not do * full DNS validation, but only checks if the name is composed of * allowed characters and the length is not above the maximum allowed * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if - * relax is true and at least two components are present in the name. + * allow_trailing_dot is true and at least two components are present + * in the name. Note that due to the restricted charset and length + * this call is substantially more conservative than + * dns_domain_is_valid(). */ -bool hostname_is_valid(const char *s, bool relax) { +bool hostname_is_valid(const char *s, bool allow_trailing_dot) { + unsigned n_dots = 0; const char *p; bool dot; - unsigned dots = 0; if (isempty(s)) return false; @@ -87,7 +90,7 @@ bool hostname_is_valid(const char *s, bool relax) { return false; dot = true; - dots ++; + n_dots ++; } else { if (!hostname_valid_char(*p)) return false; @@ -96,10 +99,12 @@ bool hostname_is_valid(const char *s, bool relax) { } } - if (dot && (dots < 2 || !relax)) + if (dot && (n_dots < 2 || !allow_trailing_dot)) return false; - if (p-s > HOST_NAME_MAX) + if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on + * Linux, but DNS allows domain names + * up to 255 characters */ return false; return true; @@ -151,6 +156,17 @@ bool is_localhost(const char *hostname) { endswith_no_case(hostname, ".localdomain."); } +bool is_gateway_hostname(const char *hostname) { + assert(hostname); + + /* This tries to identify the valid syntaxes for the our + * synthetic "gateway" host. */ + + return + strcaseeq(hostname, "gateway") || + strcaseeq(hostname, "gateway."); +} + int sethostname_idempotent(const char *s) { char buf[HOST_NAME_MAX + 1] = {}; diff --git a/src/systemd/src/basic/hostname-util.h b/src/systemd/src/basic/hostname-util.h index 6f2b5b66ff..d4f5bfe45e 100644 --- a/src/systemd/src/basic/hostname-util.h +++ b/src/systemd/src/basic/hostname-util.h @@ -29,10 +29,13 @@ bool hostname_is_set(void); char* gethostname_malloc(void); -bool hostname_is_valid(const char *s, bool relax) _pure_; +bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_; char* hostname_cleanup(char *s); +#define machine_name_is_valid(s) hostname_is_valid(s, false) + bool is_localhost(const char *hostname); +bool is_gateway_hostname(const char *hostname); int sethostname_idempotent(const char *s); diff --git a/src/systemd/src/basic/macro.h b/src/systemd/src/basic/macro.h index 627d768b76..cbc3ca97b8 100644 --- a/src/systemd/src/basic/macro.h +++ b/src/systemd/src/basic/macro.h @@ -298,6 +298,9 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { #define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1)) #define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) +#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p)) +#define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) + #define memzero(x,l) (memset((x), 0, (l))) #define zero(x) (memzero(&(x), sizeof(x))) diff --git a/src/systemd/src/basic/refcnt.h b/src/systemd/src/basic/refcnt.h index 0502c20a2e..8a39d69fe4 100644 --- a/src/systemd/src/basic/refcnt.h +++ b/src/systemd/src/basic/refcnt.h @@ -21,7 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -/* A type-safe atomic refcounter */ +/* A type-safe atomic refcounter. + * + * DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */ typedef struct { volatile unsigned _value; diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c index d44a72fc48..b9aef64b15 100644 --- a/src/systemd/src/basic/strv.c +++ b/src/systemd/src/basic/strv.c @@ -270,15 +270,13 @@ char **strv_split_newlines(const char *s) { if (n <= 0) return l; - if (isempty(l[n-1])) { - free(l[n-1]); - l[n-1] = NULL; - } + if (isempty(l[n - 1])) + l[n - 1] = mfree(l[n - 1]); return l; } -int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) { +int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) { size_t n = 0, allocated = 0; _cleanup_strv_free_ char **l = NULL; int r; @@ -289,7 +287,7 @@ int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags) { for (;;) { _cleanup_free_ char *word = NULL; - r = unquote_first_word(&s, &word, flags); + r = extract_first_word(&s, &word, separators, flags); if (r < 0) return r; if (r == 0) @@ -693,6 +691,26 @@ char **strv_reverse(char **l) { return l; } +char **strv_shell_escape(char **l, const char *bad) { + char **s; + + /* Escapes every character in every string in l that is in bad, + * edits in-place, does not roll-back on error. */ + + STRV_FOREACH(s, l) { + char *v; + + v = shell_escape(*s, bad); + if (!v) + return NULL; + + free(*s); + *s = v; + } + + return l; +} + bool strv_fnmatch(char* const* patterns, const char *s, int flags) { char* const* p; diff --git a/src/systemd/src/basic/strv.h b/src/systemd/src/basic/strv.h index 22f8f98fda..f07da8cdf3 100644 --- a/src/systemd/src/basic/strv.h +++ b/src/systemd/src/basic/strv.h @@ -73,7 +73,7 @@ static inline bool strv_isempty(char * const *l) { char **strv_split(const char *s, const char *separator); char **strv_split_newlines(const char *s); -int strv_split_quoted(char ***t, const char *s, UnquoteFlags flags); +int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags); char *strv_join(char **l, const char *separator); char *strv_join_quoted(char **l); @@ -145,6 +145,7 @@ void strv_print(char **l); })) char **strv_reverse(char **l); +char **strv_shell_escape(char **l, const char *bad); bool strv_fnmatch(char* const* patterns, const char *s, int flags); diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index 12f1b193be..531931f6e1 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -26,6 +26,7 @@ #include "util.h" #include "time-util.h" +#include "path-util.h" #include "strv.h" usec_t now(clockid_t clock_id) { @@ -36,6 +37,14 @@ usec_t now(clockid_t clock_id) { return timespec_load(&ts); } +nsec_t now_nsec(clockid_t clock_id) { + struct timespec ts; + + assert_se(clock_gettime(clock_id, &ts) == 0); + + return timespec_load_nsec(&ts); +} + dual_timestamp* dual_timestamp_get(dual_timestamp *ts) { assert(ts); @@ -88,6 +97,32 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { return ts; } +dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) { + int64_t delta; + + if (u == USEC_INFINITY) { + ts->realtime = ts->monotonic = USEC_INFINITY; + return ts; + } + ts->realtime = now(CLOCK_REALTIME); + ts->monotonic = now(CLOCK_MONOTONIC); + + delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u; + + if ((int64_t) ts->realtime > delta) + ts->realtime -= delta; + else + ts->realtime = 0; + + if ((int64_t) ts->monotonic > delta) + ts->monotonic -= delta; + else + ts->monotonic = 0; + + return ts; +} + + usec_t timespec_load(const struct timespec *ts) { assert(ts); @@ -103,6 +138,18 @@ usec_t timespec_load(const struct timespec *ts) { (usec_t) ts->tv_nsec / NSEC_PER_USEC; } +nsec_t timespec_load_nsec(const struct timespec *ts) { + assert(ts); + + if (ts->tv_sec == (time_t) -1 && + ts->tv_nsec == (long) -1) + return NSEC_INFINITY; + + return + (nsec_t) ts->tv_sec * NSEC_PER_SEC + + (nsec_t) ts->tv_nsec; +} + struct timespec *timespec_store(struct timespec *ts, usec_t u) { assert(ts); @@ -945,7 +992,10 @@ bool timezone_is_valid(const char *name) { const char *p, *t; struct stat st; - if (!name || *name == 0 || *name == '/') + if (isempty(name)) + return false; + + if (name[0] == '/') return false; for (p = name; *p; p++) { @@ -995,3 +1045,30 @@ clockid_t clock_boottime_or_monotonic(void) { return clock; } + +int get_timezone(char **tz) { + _cleanup_free_ char *t = NULL; + const char *e; + char *z; + int r; + + r = readlink_malloc("/etc/localtime", &t); + if (r < 0) + return r; /* returns EINVAL if not a symlink */ + + e = path_startswith(t, "/usr/share/zoneinfo/"); + if (!e) + e = path_startswith(t, "../usr/share/zoneinfo/"); + if (!e) + return -EINVAL; + + if (!timezone_is_valid(e)) + return -EINVAL; + + z = strdup(e); + if (!z) + return -ENOMEM; + + *tz = z; + return 0; +} diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h index 7a64d454a0..de881e8fe1 100644 --- a/src/systemd/src/basic/time-util.h +++ b/src/systemd/src/basic/time-util.h @@ -70,10 +70,12 @@ typedef struct dual_timestamp { #define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL }) usec_t now(clockid_t clock); +nsec_t now_nsec(clockid_t clock); dual_timestamp* dual_timestamp_get(dual_timestamp *ts); dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u); +dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u); static inline bool dual_timestamp_is_set(dual_timestamp *ts) { return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || @@ -86,6 +88,8 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u); usec_t timeval_load(const struct timeval *tv) _pure_; struct timeval *timeval_store(struct timeval *tv, usec_t u); +nsec_t timespec_load_nsec(const struct timespec *ts) _pure_; + char *format_timestamp(char *buf, size_t l, usec_t t); char *format_timestamp_utc(char *buf, size_t l, usec_t t); char *format_timestamp_us(char *buf, size_t l, usec_t t); @@ -109,3 +113,5 @@ bool timezone_is_valid(const char *name); clockid_t clock_boottime_or_monotonic(void); #define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0) + +int get_timezone(char **timezone); diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index d4d3d3c83a..e3b2af8e02 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -327,6 +327,33 @@ void close_many(const int fds[], unsigned n_fd) { safe_close(fds[i]); } +int fclose_nointr(FILE *f) { + assert(f); + + /* Same as close_nointr(), but for fclose() */ + + if (fclose(f) == 0) + return 0; + + if (errno == EINTR) + return 0; + + return -errno; +} + +FILE* safe_fclose(FILE *f) { + + /* Same as safe_close(), but for fclose() */ + + if (f) { + PROTECT_ERRNO; + + assert_se(fclose_nointr(f) != EBADF); + } + + return NULL; +} + int unlink_noerrno(const char *path) { PROTECT_ERRNO; int r; @@ -373,6 +400,19 @@ int parse_pid(const char *s, pid_t* ret_pid) { return 0; } +bool uid_is_valid(uid_t uid) { + + /* Some libc APIs use UID_INVALID as special placeholder */ + if (uid == (uid_t) 0xFFFFFFFF) + return false; + + /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */ + if (uid == (uid_t) 0xFFFF) + return false; + + return true; +} + int parse_uid(const char *s, uid_t* ret_uid) { unsigned long ul = 0; uid_t uid; @@ -389,13 +429,11 @@ int parse_uid(const char *s, uid_t* ret_uid) { if ((unsigned long) uid != ul) return -ERANGE; - /* Some libc APIs use UID_INVALID as special placeholder */ - if (uid == (uid_t) 0xFFFFFFFF) - return -ENXIO; - - /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */ - if (uid == (uid_t) 0xFFFF) - return -ENXIO; + if (!uid_is_valid(uid)) + return -ENXIO; /* we return ENXIO instead of EINVAL + * here, to make it easy to distuingish + * invalid numeric uids invalid + * strings. */ if (ret_uid) *ret_uid = uid; @@ -2176,7 +2214,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { return 0; } -int parse_size(const char *t, off_t base, off_t *size) { +int parse_size(const char *t, uint64_t base, uint64_t *size) { /* Soo, sometimes we want to parse IEC binary suffixes, and * sometimes SI decimal suffixes. This function can parse @@ -2204,8 +2242,8 @@ int parse_size(const char *t, off_t base, off_t *size) { { "G", 1024ULL*1024ULL*1024ULL }, { "M", 1024ULL*1024ULL }, { "K", 1024ULL }, - { "B", 1 }, - { "", 1 }, + { "B", 1ULL }, + { "", 1ULL }, }; static const struct table si[] = { @@ -2215,8 +2253,8 @@ int parse_size(const char *t, off_t base, off_t *size) { { "G", 1000ULL*1000ULL*1000ULL }, { "M", 1000ULL*1000ULL }, { "K", 1000ULL }, - { "B", 1 }, - { "", 1 }, + { "B", 1ULL }, + { "", 1ULL }, }; const struct table *table; @@ -2238,33 +2276,32 @@ int parse_size(const char *t, off_t base, off_t *size) { p = t; do { - long long l; - unsigned long long l2; + unsigned long long l, tmp; double frac = 0; char *e; unsigned i; - errno = 0; - l = strtoll(p, &e, 10); + p += strspn(p, WHITESPACE); + if (*p == '-') + return -ERANGE; + errno = 0; + l = strtoull(p, &e, 10); if (errno > 0) return -errno; - - if (l < 0) - return -ERANGE; - if (e == p) return -EINVAL; if (*e == '.') { e++; + + /* strtoull() itself would accept space/+/- */ if (*e >= '0' && *e <= '9') { + unsigned long long l2; char *e2; - /* strotoull itself would accept space/+/- */ l2 = strtoull(e, &e2, 10); - - if (errno == ERANGE) + if (errno > 0) return -errno; /* Ignore failure. E.g. 10.M is valid */ @@ -2277,27 +2314,27 @@ int parse_size(const char *t, off_t base, off_t *size) { e += strspn(e, WHITESPACE); for (i = start_pos; i < n_entries; i++) - if (startswith(e, table[i].suffix)) { - unsigned long long tmp; - if ((unsigned long long) l + (frac > 0) > ULLONG_MAX / table[i].factor) - return -ERANGE; - tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); - if (tmp > ULLONG_MAX - r) - return -ERANGE; - - r += tmp; - if ((unsigned long long) (off_t) r != r) - return -ERANGE; - - p = e + strlen(table[i].suffix); - - start_pos = i + 1; + if (startswith(e, table[i].suffix)) break; - } if (i >= n_entries) return -EINVAL; + if (l + (frac > 0) > ULLONG_MAX / table[i].factor) + return -ERANGE; + + tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); + if (tmp > ULLONG_MAX - r) + return -ERANGE; + + r += tmp; + if ((unsigned long long) (uint64_t) r != r) + return -ERANGE; + + p = e + strlen(table[i].suffix); + + start_pos = i + 1; + } while (*p); *size = r; @@ -3006,21 +3043,6 @@ char* strshorten(char *s, size_t l) { return s; } -bool machine_name_is_valid(const char *s) { - - if (!hostname_is_valid(s, false)) - return false; - - /* Machine names should be useful hostnames, but also be - * useful in unit names, hence we enforce a stricter length - * limitation. */ - - if (strlen(s) > 64) - return false; - - return true; -} - int pipe_eof(int fd) { struct pollfd pollfd = { .fd = fd, @@ -3762,38 +3784,38 @@ int prot_from_flags(int flags) { } } -char *format_bytes(char *buf, size_t l, off_t t) { +char *format_bytes(char *buf, size_t l, uint64_t t) { unsigned i; static const struct { const char *suffix; - off_t factor; + uint64_t factor; } table[] = { - { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "M", 1024ULL*1024ULL }, - { "K", 1024ULL }, + { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "M", UINT64_C(1024)*UINT64_C(1024) }, + { "K", UINT64_C(1024) }, }; - if (t == (off_t) -1) + if (t == (uint64_t) -1) return NULL; for (i = 0; i < ELEMENTSOF(table); i++) { if (t >= table[i].factor) { snprintf(buf, l, - "%llu.%llu%s", - (unsigned long long) (t / table[i].factor), - (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL), + "%" PRIu64 ".%" PRIu64 "%s", + t / table[i].factor, + ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10), table[i].suffix); goto finish; } } - snprintf(buf, l, "%lluB", (unsigned long long) t); + snprintf(buf, l, "%" PRIu64 "B", t); finish: buf[l-1] = 0; @@ -4288,7 +4310,7 @@ bool is_locale_utf8(void) { /* Check result, but ignore the result if C was set * explicitly. */ cached_answer = - streq(set, "C") && + STR_IN_SET(set, "C", "POSIX") && !getenv("LC_ALL") && !getenv("LC_CTYPE") && !getenv("LANG"); @@ -4821,7 +4843,7 @@ int shall_restore_state(void) { int proc_cmdline(char **ret) { assert(ret); - if (detect_container(NULL) > 0) + if (detect_container() > 0) return get_process_cmdline(1, 0, false, ret); else return read_one_line_file("/proc/cmdline", ret); @@ -4843,7 +4865,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { _cleanup_free_ char *word = NULL; char *value = NULL; - r = unquote_first_word(&p, &word, UNQUOTE_RELAX); + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) return r; if (r == 0) @@ -4883,7 +4905,7 @@ int get_proc_cmdline_key(const char *key, char **value) { _cleanup_free_ char *word = NULL; const char *e; - r = unquote_first_word(&p, &word, UNQUOTE_RELAX); + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) return r; if (r == 0) @@ -4928,6 +4950,9 @@ int container_get_leader(const char *machine, pid_t *pid) { assert(machine); assert(pid); + if (!machine_name_is_valid(machine)) + return -EINVAL; + p = strjoina("/run/systemd/machines/", machine); r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); if (r == -ENOENT) @@ -4950,8 +4975,8 @@ int container_get_leader(const char *machine, pid_t *pid) { return 0; } -int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd) { - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1; +int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1; int rfd = -1; assert(pid >= 0); @@ -4983,6 +5008,15 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int * return -errno; } + if (userns_fd) { + const char *userns; + + userns = procfs_file_alloca(pid, "ns/user"); + usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (usernsfd < 0 && errno != ENOENT) + return -errno; + } + if (root_fd) { const char *root; @@ -5001,15 +5035,33 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int * if (netns_fd) *netns_fd = netnsfd; + if (userns_fd) + *userns_fd = usernsfd; + if (root_fd) *root_fd = rfd; - pidnsfd = mntnsfd = netnsfd = -1; + pidnsfd = mntnsfd = netnsfd = usernsfd = -1; return 0; } -int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) { +int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) { + if (userns_fd >= 0) { + /* Can't setns to your own userns, since then you could + * escalate from non-root to root in your own namespace, so + * check if namespaces equal before attempting to enter. */ + _cleanup_free_ char *userns_fd_path = NULL; + int r; + if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0) + return -ENOMEM; + + r = files_same(userns_fd_path, "/proc/self/ns/user"); + if (r < 0) + return r; + if (r) + userns_fd = -1; + } if (pidns_fd >= 0) if (setns(pidns_fd, CLONE_NEWPID) < 0) @@ -5023,6 +5075,10 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) { if (setns(netns_fd, CLONE_NEWNET) < 0) return -errno; + if (userns_fd >= 0) + if (setns(userns_fd, CLONE_NEWUSER) < 0) + return -errno; + if (root_fd >= 0) { if (fchdir(root_fd) < 0) return -errno; @@ -5698,7 +5754,7 @@ int is_device_node(const char *path) { return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); } -int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { _cleanup_free_ char *s = NULL; size_t allocated = 0, sz = 0; int r; @@ -5711,13 +5767,19 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { SINGLE_QUOTE_ESCAPE, DOUBLE_QUOTE, DOUBLE_QUOTE_ESCAPE, - SPACE, + SEPARATOR, } state = START; assert(p); - assert(*p); assert(ret); + if (!separators) + separators = WHITESPACE; + + /* Bail early if called after last value or with no input */ + if (!*p) + goto finish_force_terminate; + /* Parses the first word of a string, and returns it in * *ret. Removes all quotes in the process. When parsing fails * (because of an uneven number of quotes or similar), leaves @@ -5729,32 +5791,45 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { switch (state) { case START: + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + if (c == 0) - goto finish; - else if (strchr(WHITESPACE, c)) + goto finish_force_terminate; + else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + (*p) ++; + goto finish_force_next; + } break; + } + + /* We found a non-blank character, so we will always + * want to return a string (even if it is empty), + * allocate it here. */ + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; state = VALUE; /* fallthrough */ case VALUE: if (c == 0) - goto finish; - else if (c == '\'') { - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; - + goto finish_force_terminate; + else if (c == '\'' && (flags & EXTRACT_QUOTES)) state = SINGLE_QUOTE; - } else if (c == '\\') + else if (c == '\\') state = VALUE_ESCAPE; - else if (c == '\"') { - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; - + else if (c == '\"' && (flags & EXTRACT_QUOTES)) state = DOUBLE_QUOTE; - } else if (strchr(WHITESPACE, c)) - state = SPACE; - else { + else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + (*p) ++; + goto finish_force_next; + } + state = SEPARATOR; + } else { if (!GREEDY_REALLOC(s, allocated, sz+2)) return -ENOMEM; @@ -5765,8 +5840,8 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { case SINGLE_QUOTE: if (c == 0) { - if (flags & UNQUOTE_RELAX) - goto finish; + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; return -EINVAL; } else if (c == '\'') state = VALUE; @@ -5804,29 +5879,29 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) { return -ENOMEM; if (c == 0) { - if ((flags & UNQUOTE_CUNESCAPE_RELAX) && - (state == VALUE_ESCAPE || flags & UNQUOTE_RELAX)) { + if ((flags & EXTRACT_CUNESCAPE_RELAX) && + (state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) { /* If we find an unquoted trailing backslash and we're in - * UNQUOTE_CUNESCAPE_RELAX mode, keep it verbatim in the + * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the * output. * - * Unbalanced quotes will only be allowed in UNQUOTE_RELAX - * mode, UNQUOTE_CUNESCAP_RELAX mode does not allow them. + * Unbalanced quotes will only be allowed in EXTRACT_RELAX + * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. */ s[sz++] = '\\'; - goto finish; + goto finish_force_terminate; } - if (flags & UNQUOTE_RELAX) - goto finish; + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; return -EINVAL; } - if (flags & UNQUOTE_CUNESCAPE) { + if (flags & EXTRACT_CUNESCAPE) { uint32_t u; r = cunescape_one(*p, (size_t) -1, &c, &u); if (r < 0) { - if (flags & UNQUOTE_CUNESCAPE_RELAX) { + if (flags & EXTRACT_CUNESCAPE_RELAX) { s[sz++] = '\\'; s[sz++] = c; goto end_escape; @@ -5849,24 +5924,27 @@ end_escape: VALUE; break; - case SPACE: + case SEPARATOR: if (c == 0) + goto finish_force_terminate; + if (!strchr(separators, c)) goto finish; - if (!strchr(WHITESPACE, c)) - goto finish; - break; } (*p) ++; } +finish_force_terminate: + *p = NULL; finish: if (!s) { + *p = NULL; *ret = NULL; return 0; } +finish_force_next: s[sz] = 0; *ret = s; s = NULL; @@ -5874,26 +5952,27 @@ finish: return 1; } -int unquote_first_word_and_warn( +int extract_first_word_and_warn( const char **p, char **ret, - UnquoteFlags flags, + const char *separators, + ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue) { /* Try to unquote it, if it fails, warn about it and try again but this - * time using UNQUOTE_CUNESCAPE_RELAX to keep the backslashes verbatim + * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim * in invalid escape sequences. */ const char *save; int r; save = *p; - r = unquote_first_word(p, ret, flags); - if (r < 0 && !(flags&UNQUOTE_CUNESCAPE_RELAX)) { - /* Retry it with UNQUOTE_CUNESCAPE_RELAX. */ + r = extract_first_word(p, ret, separators, flags); + if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) { + /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ *p = save; - r = unquote_first_word(p, ret, flags|UNQUOTE_CUNESCAPE_RELAX); + r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); if (r < 0) log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue); @@ -5904,7 +5983,7 @@ int unquote_first_word_and_warn( return r; } -int unquote_many_words(const char **p, UnquoteFlags flags, ...) { +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) { va_list ap; char **l; int n = 0, i, c, r; @@ -5930,7 +6009,7 @@ int unquote_many_words(const char **p, UnquoteFlags flags, ...) { l = newa0(char*, n); for (c = 0; c < n; c++) { - r = unquote_first_word(p, &l[c], flags); + r = extract_first_word(p, &l[c], separators, flags); if (r < 0) { int j; @@ -6012,7 +6091,7 @@ int ptsname_malloc(int fd, char **ret) { } int openpt_in_namespace(pid_t pid, int flags) { - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; _cleanup_close_pair_ int pair[2] = { -1, -1 }; union { struct cmsghdr cmsghdr; @@ -6029,7 +6108,7 @@ int openpt_in_namespace(pid_t pid, int flags) { assert(pid > 0); - r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd); + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); if (r < 0) return r; @@ -6045,7 +6124,7 @@ int openpt_in_namespace(pid_t pid, int flags) { pair[0] = safe_close(pair[0]); - r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd); + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); if (r < 0) _exit(EXIT_FAILURE); @@ -6053,6 +6132,9 @@ int openpt_in_namespace(pid_t pid, int flags) { if (master < 0) _exit(EXIT_FAILURE); + if (unlockpt(master) < 0) + _exit(EXIT_FAILURE); + cmsg = CMSG_FIRSTHDR(&mh); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; @@ -6511,6 +6593,32 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char return 0; } +static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) { + assert(bad); + + for (; *s; s++) { + if (*s == '\\' || strchr(bad, *s)) + *(t++) = '\\'; + + *(t++) = *s; + } + + return t; +} + +char *shell_escape(const char *s, const char *bad) { + char *r, *t; + + r = new(char, strlen(s)*2+1); + if (!r) + return NULL; + + t = strcpy_backslash_escaped(r, s, bad); + *t = 0; + + return r; +} + char *shell_maybe_quote(const char *s) { const char *p; char *r, *t; @@ -6537,13 +6645,7 @@ char *shell_maybe_quote(const char *s) { *(t++) = '"'; t = mempcpy(t, s, p - s); - for (; *p; p++) { - - if (strchr(SHELL_NEED_ESCAPE, *p)) - *(t++) = '\\'; - - *(t++) = *p; - } + t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE); *(t++)= '"'; *t = 0; diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h index 426b7f7d16..c7dff9a86d 100644 --- a/src/systemd/src/basic/util.h +++ b/src/systemd/src/basic/util.h @@ -83,7 +83,7 @@ int strcmp_ptr(const char *a, const char *b) _pure_; #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) -#define malloc0(n) (calloc((n), 1)) +#define malloc0(n) (calloc(1, (n))) static inline void *mfree(void *memory) { free(memory); @@ -149,12 +149,18 @@ void safe_close_pair(int p[]); void close_many(const int fds[], unsigned n_fd); -int parse_size(const char *t, off_t base, off_t *size); +int fclose_nointr(FILE *f); +FILE* safe_fclose(FILE *f); + +int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_boolean(const char *v) _pure_; int parse_pid(const char *s, pid_t* ret_pid); int parse_uid(const char *s, uid_t* ret_uid); -#define parse_gid(s, ret_uid) parse_uid(s, ret_uid) +#define parse_gid(s, ret_gid) parse_uid(s, ret_gid) + +bool uid_is_valid(uid_t uid); +#define gid_is_valid(gid) uid_is_valid(gid) int safe_atou(const char *s, unsigned *ret_u); int safe_atoi(const char *s, int *ret_i); @@ -363,6 +369,9 @@ int fd_is_temporary_fs(int fd); int pipe_eof(int fd); +DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); +#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) + cpu_set_t* cpu_set_malloc(unsigned *ncpus); #define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf)) @@ -394,8 +403,6 @@ bool nulstr_contains(const char*nulstr, const char *needle); bool plymouth_running(void); -bool machine_name_is_valid(const char *s) _pure_; - char* strshorten(char *s, size_t l); int symlink_idempotent(const char *from, const char *to); @@ -471,7 +478,7 @@ bool kexec_loaded(void); int prot_from_flags(int flags) _const_; -char *format_bytes(char *buf, size_t l, off_t t); +char *format_bytes(char *buf, size_t l, uint64_t t); int fd_wait_for_event(int fd, int event, usec_t timeout); @@ -510,7 +517,10 @@ static inline void close_pairp(int (*p)[2]) { safe_close_pair(*p); } -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, fclose); +static inline void fclosep(FILE **f) { + safe_fclose(*f); +} + DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); @@ -563,6 +573,7 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, void *arg); #define _(String) gettext (String) +#define N_(String) String void init_gettext(void); bool is_locale_utf8(void); @@ -803,8 +814,8 @@ int get_proc_cmdline_key(const char *parameter, char **value); 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 *root_fd); -int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd); +int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd); +int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); int getpeercred(int fd, struct ucred *ucred); int getpeersec(int fd, char **ret); @@ -854,20 +865,17 @@ int is_symlink(const char *path); int is_dir(const char *path, bool follow); int is_device_node(const char *path); -typedef enum UnquoteFlags { - UNQUOTE_RELAX = 1, - UNQUOTE_CUNESCAPE = 2, - UNQUOTE_CUNESCAPE_RELAX = 4, -} UnquoteFlags; +typedef enum ExtractFlags { + EXTRACT_RELAX = 1, + EXTRACT_CUNESCAPE = 2, + EXTRACT_CUNESCAPE_RELAX = 4, + EXTRACT_QUOTES = 8, + EXTRACT_DONT_COALESCE_SEPARATORS = 16, +} ExtractFlags; -int unquote_first_word(const char **p, char **ret, UnquoteFlags flags); -int unquote_first_word_and_warn(const char **p, char **ret, UnquoteFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); -int unquote_many_words(const char **p, UnquoteFlags flags, ...) _sentinel_; - -static inline void free_and_replace(char **s, char *v) { - free(*s); - *s = v; -} +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); +int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; int free_and_strdup(char **p, const char *s); @@ -917,6 +925,7 @@ void cmsg_close_all(struct msghdr *mh); int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); +char *shell_escape(const char *s, const char *bad); char *shell_maybe_quote(const char *s); int parse_mode(const char *s, mode_t *ret); |