summaryrefslogtreecommitdiff
path: root/src/systemd/src/basic
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-09-16 16:53:25 +0200
committerThomas Haller <thaller@redhat.com>2015-09-16 16:54:03 +0200
commitc05557971c09782316ee7e39ae4e7a7675d338f1 (patch)
tree25595e64bb7f900b17766270b52e7696d4e615c7 /src/systemd/src/basic
parent08916936bce4c8ac36156c040999add99175b455 (diff)
parente82f430eae841032c7961d2eca694435425e4d51 (diff)
downloadNetworkManager-c05557971c09782316ee7e39ae4e7a7675d338f1.tar.gz
systemd: merge branch 'systemd-integration' into master
Diffstat (limited to 'src/systemd/src/basic')
-rw-r--r--src/systemd/src/basic/hostname-util.c30
-rw-r--r--src/systemd/src/basic/hostname-util.h5
-rw-r--r--src/systemd/src/basic/macro.h3
-rw-r--r--src/systemd/src/basic/refcnt.h4
-rw-r--r--src/systemd/src/basic/strv.c30
-rw-r--r--src/systemd/src/basic/strv.h3
-rw-r--r--src/systemd/src/basic/time-util.c85
-rw-r--r--src/systemd/src/basic/time-util.h6
-rw-r--r--src/systemd/src/basic/util.c364
-rw-r--r--src/systemd/src/basic/util.h55
10 files changed, 414 insertions, 171 deletions
diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c
index 7e2fa7c609..b8cd79e52d 100644
--- a/src/systemd/src/basic/hostname-util.c
+++ b/src/systemd/src/basic/hostname-util.c
@@ -64,16 +64,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;
@@ -89,7 +92,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;
@@ -98,10 +101,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;
@@ -154,6 +159,17 @@ bool is_localhost(const char *hostname) {
}
#if 0 /* NM_IGNORED */
+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 fd768ee3c0..a2e6920095 100644
--- a/src/systemd/src/basic/hostname-util.h
+++ b/src/systemd/src/basic/hostname-util.h
@@ -31,10 +31,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 b1cef217ab..80c64904e2 100644
--- a/src/systemd/src/basic/macro.h
+++ b/src/systemd/src/basic/macro.h
@@ -300,6 +300,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 e6e9a6bd6e..f7a26192ce 100644
--- a/src/systemd/src/basic/refcnt.h
+++ b/src/systemd/src/basic/refcnt.h
@@ -23,7 +23,9 @@
#include "nm-sd-adapt.h"
-/* 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 df44f61907..de0f371613 100644
--- a/src/systemd/src/basic/strv.c
+++ b/src/systemd/src/basic/strv.c
@@ -272,16 +272,14 @@ 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;
}
#if 0 /* NM_IGNORED */
-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;
@@ -292,7 +290,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)
@@ -697,6 +695,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 b583080739..df3855d9fa 100644
--- a/src/systemd/src/basic/strv.h
+++ b/src/systemd/src/basic/strv.h
@@ -75,7 +75,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);
@@ -147,6 +147,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 66f91825bc..5fb666a0c3 100644
--- a/src/systemd/src/basic/time-util.c
+++ b/src/systemd/src/basic/time-util.c
@@ -28,9 +28,8 @@
#include "util.h"
#include "time-util.h"
-#if 0 /* NM_IGNORED */
+#include "path-util.h"
#include "strv.h"
-#endif /* NM_IGNORED */
usec_t now(clockid_t clock_id) {
struct timespec ts;
@@ -40,6 +39,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);
@@ -92,6 +99,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);
@@ -107,6 +140,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);
@@ -946,13 +991,17 @@ int get_timezones(char ***ret) {
return 0;
}
+#endif /* NM_IGNORED */
bool timezone_is_valid(const char *name) {
bool slash = false;
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++) {
@@ -984,7 +1033,6 @@ bool timezone_is_valid(const char *name) {
return true;
}
-#endif /* NM_IGNORED */
clockid_t clock_boottime_or_monotonic(void) {
static clockid_t clock = -1;
@@ -1003,3 +1051,32 @@ clockid_t clock_boottime_or_monotonic(void) {
return clock;
}
+
+#if 0 /* NM_IGNORED */
+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;
+}
+#endif /* NM_IGNORED */
diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h
index 480c39d902..463d509b4a 100644
--- a/src/systemd/src/basic/time-util.h
+++ b/src/systemd/src/basic/time-util.h
@@ -72,10 +72,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) ||
@@ -88,6 +90,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);
@@ -111,3 +115,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 4293268857..3b41adad8d 100644
--- a/src/systemd/src/basic/util.c
+++ b/src/systemd/src/basic/util.c
@@ -339,6 +339,33 @@ void close_many(const int fds[], unsigned n_fd) {
}
#endif /* NM_IGNORED */
+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;
@@ -386,6 +413,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;
@@ -402,13 +442,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;
@@ -477,6 +515,7 @@ int safe_atou8(const char *s, uint8_t *ret) {
*ret = (uint8_t) l;
return 0;
}
+#endif /* NM_IGNORED */
int safe_atou16(const char *s, uint16_t *ret) {
char *x = NULL;
@@ -498,6 +537,7 @@ int safe_atou16(const char *s, uint16_t *ret) {
return 0;
}
+#if 0 /* NM_IGNORED */
int safe_atoi16(const char *s, int16_t *ret) {
char *x = NULL;
long l;
@@ -2201,7 +2241,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
@@ -2229,8 +2269,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[] = {
@@ -2240,8 +2280,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;
@@ -2263,33 +2303,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 */
@@ -2302,27 +2341,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;
@@ -3033,21 +3072,6 @@ char* strshorten(char *s, size_t l) {
}
#if 0 /* NM_IGNORED */
-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,
@@ -3793,38 +3817,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;
@@ -4325,7 +4349,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");
@@ -4752,7 +4776,6 @@ void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
return q;
}
-#if 0 /* NM_IGNORED */
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
size_t prev;
uint8_t *q;
@@ -4772,6 +4795,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
return q;
}
+#if 0 /* NM_IGNORED */
bool id128_is_valid(const char *s) {
size_t i, l;
@@ -4860,7 +4884,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);
@@ -4882,7 +4906,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)
@@ -4922,7 +4946,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)
@@ -4967,6 +4991,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)
@@ -4989,8 +5016,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);
@@ -5022,6 +5049,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;
@@ -5040,15 +5076,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)
@@ -5062,6 +5116,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;
@@ -5741,7 +5799,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;
@@ -5754,13 +5812,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
@@ -5772,32 +5836,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;
@@ -5808,8 +5885,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;
@@ -5847,29 +5924,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;
@@ -5892,24 +5969,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;
@@ -5917,26 +5997,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);
@@ -5947,7 +6028,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;
@@ -5973,7 +6054,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;
@@ -6055,7 +6136,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;
@@ -6072,7 +6153,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;
@@ -6088,7 +6169,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);
@@ -6096,6 +6177,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;
@@ -6555,7 +6639,35 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
return 0;
}
+#endif /* NM_IGNORED */
+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;
+}
+
+#if 0 /* NM_IGNORED */
char *shell_maybe_quote(const char *s) {
const char *p;
char *r, *t;
@@ -6582,13 +6694,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 9e3344ebb8..154aabadee 100644
--- a/src/systemd/src/basic/util.h
+++ b/src/systemd/src/basic/util.h
@@ -89,7 +89,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);
@@ -155,12 +155,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);
@@ -369,6 +375,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))
@@ -400,8 +409,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);
@@ -477,7 +484,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);
@@ -516,7 +523,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);
@@ -568,7 +578,10 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *, void *),
void *arg);
+#if 0 /* NM_IGNORED */
#define _(String) gettext (String)
+#define N_(String) String
+#endif
void init_gettext(void);
bool is_locale_utf8(void);
@@ -809,8 +822,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);
#if 0 /* NM_IGNORED */
int getpeercred(int fd, struct ucred *ucred);
@@ -864,20 +877,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);
@@ -927,6 +937,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);