summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-09-13 20:39:58 -0400
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-09-13 20:39:58 -0400
commitb3ec0a0674f4e499bcb6d2469acdf9d2d574c3d6 (patch)
tree374687545d464bb1e57991cf73b654a7fa0b83ba /src/basic
parentf6e7ffdf3fe8e3ed5e659f747946461350ade5a8 (diff)
parentae8150ecbd54765622aadf288100440d71a10ccd (diff)
Merge tag 'systemd/v231-1.parabola1' into systemd/parabola
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/bitmap.c17
-rw-r--r--src/basic/bitmap.h5
-rw-r--r--src/basic/calendarspec.c88
-rw-r--r--src/basic/cgroup-util.c69
-rw-r--r--src/basic/cgroup-util.h18
-rw-r--r--src/basic/copy.c2
-rw-r--r--src/basic/exit-status.c18
-rw-r--r--src/basic/exit-status.h16
-rw-r--r--src/basic/fd-util.c6
-rw-r--r--src/basic/fd-util.h1
-rw-r--r--src/basic/fdset.c273
-rw-r--r--src/basic/fdset.h58
-rw-r--r--src/basic/fileio.c46
-rw-r--r--src/basic/fileio.h2
-rw-r--r--src/basic/formats-util.h16
-rw-r--r--src/basic/fs-util.c29
-rw-r--r--src/basic/fs-util.h2
-rw-r--r--src/basic/hashmap.c25
-rw-r--r--src/basic/in-addr-util.c105
-rw-r--r--src/basic/in-addr-util.h5
-rw-r--r--src/basic/log.c4
-rw-r--r--src/basic/macro.h9
-rw-r--r--src/basic/missing.h28
-rw-r--r--src/basic/missing_syscall.h14
-rw-r--r--src/basic/mount-util.c50
-rw-r--r--src/basic/mount-util.h2
-rw-r--r--src/basic/nss-util.h2
-rw-r--r--src/basic/parse-util.c19
-rw-r--r--src/basic/parse-util.h2
-rw-r--r--src/basic/proc-cmdline.c18
-rw-r--r--src/basic/process-util.c120
-rw-r--r--src/basic/random-util.c2
-rw-r--r--src/basic/raw-clone.h81
-rw-r--r--src/basic/selinux-util.c24
-rw-r--r--src/basic/set.h2
-rw-r--r--src/basic/siphash24.c2
-rw-r--r--src/basic/socket-util.c24
-rw-r--r--src/basic/string-table.h2
-rw-r--r--src/basic/string-util.h4
-rw-r--r--src/basic/strv.c52
-rw-r--r--src/basic/strv.h4
-rw-r--r--src/basic/terminal-util.c88
-rw-r--r--src/basic/terminal-util.h2
-rw-r--r--src/basic/time-util.c72
-rw-r--r--src/basic/time-util.h27
-rw-r--r--src/basic/unaligned.h18
-rw-r--r--src/basic/unit-name.h1
-rw-r--r--src/basic/user-util.c2
-rw-r--r--src/basic/util.c176
-rw-r--r--src/basic/util.h7
50 files changed, 1082 insertions, 577 deletions
diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c
index ad1fda0198..f4b12fc261 100644
--- a/src/basic/bitmap.c
+++ b/src/basic/bitmap.c
@@ -50,6 +50,23 @@ Bitmap *bitmap_new(void) {
return new0(Bitmap, 1);
}
+Bitmap *bitmap_copy(Bitmap *b) {
+ Bitmap *ret;
+
+ ret = bitmap_new();
+ if (!ret)
+ return NULL;
+
+ ret->bitmaps = newdup(uint64_t, b->bitmaps, b->n_bitmaps);
+ if (!ret->bitmaps) {
+ free(ret);
+ return NULL;
+ }
+
+ ret->n_bitmaps = ret->bitmaps_allocated = b->n_bitmaps;
+ return ret;
+}
+
void bitmap_free(Bitmap *b) {
if (!b)
return;
diff --git a/src/basic/bitmap.h b/src/basic/bitmap.h
index f5f8f2f018..63fdbe8bea 100644
--- a/src/basic/bitmap.h
+++ b/src/basic/bitmap.h
@@ -27,10 +27,9 @@
typedef struct Bitmap Bitmap;
Bitmap *bitmap_new(void);
-
-void bitmap_free(Bitmap *b);
-
+Bitmap *bitmap_copy(Bitmap *b);
int bitmap_ensure_allocated(Bitmap **b);
+void bitmap_free(Bitmap *b);
int bitmap_set(Bitmap *b, unsigned n);
void bitmap_unset(Bitmap *b, unsigned n);
diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c
index 6e0bab9b94..e4cfab364e 100644
--- a/src/basic/calendarspec.c
+++ b/src/basic/calendarspec.c
@@ -32,6 +32,8 @@
#include "parse-util.h"
#include "string-util.h"
+/* Longest valid date/time range is 1970..2199 */
+#define MAX_RANGE_LEN 230
#define BITS_WEEKDAYS 127
static void free_chain(CalendarComponent *c) {
@@ -200,7 +202,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
};
int l, x;
- bool need_colon = false;
+ bool need_comma = false;
assert(f);
assert(c);
@@ -211,10 +213,10 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
if (c->weekdays_bits & (1 << x)) {
if (l < 0) {
- if (need_colon)
+ if (need_comma)
fputc(',', f);
else
- need_colon = true;
+ need_comma = true;
fputs(days[x], f);
l = x;
@@ -223,7 +225,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
} else if (l >= 0) {
if (x > l + 1) {
- fputc(x > l + 2 ? '-' : ',', f);
+ fputs(x > l + 2 ? ".." : ",", f);
fputs(days[x-1], f);
}
@@ -232,7 +234,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) {
}
if (l >= 0 && x > l + 1) {
- fputc(x > l + 2 ? '-' : ',', f);
+ fputs(x > l + 2 ? ".." : ",", f);
fputs(days[x-1], f);
}
}
@@ -357,6 +359,7 @@ static int parse_weekdays(const char **p, CalendarSpec *c) {
skip = strlen(day_nr[i].name);
if ((*p)[skip] != '-' &&
+ (*p)[skip] != '.' &&
(*p)[skip] != ',' &&
(*p)[skip] != ' ' &&
(*p)[skip] != 0)
@@ -394,7 +397,18 @@ static int parse_weekdays(const char **p, CalendarSpec *c) {
return 0;
}
- if (**p == '-') {
+ if (**p == '.') {
+ if (l >= 0)
+ return -EINVAL;
+
+ if ((*p)[1] != '.')
+ return -EINVAL;
+
+ l = day_nr[i].nr;
+ *p += 1;
+
+ /* Support ranges with "-" for backwards compatibility */
+ } else if (**p == '-') {
if (l >= 0)
return -EINVAL;
@@ -448,8 +462,26 @@ static int parse_component_decimal(const char **p, bool usec, unsigned long *res
return 0;
}
+static int const_chain(int value, CalendarComponent **c) {
+ CalendarComponent *cc = NULL;
+
+ assert(c);
+
+ cc = new0(CalendarComponent, 1);
+ if (!cc)
+ return -ENOMEM;
+
+ cc->value = value;
+ cc->repeat = 0;
+ cc->next = *c;
+
+ *c = cc;
+
+ return 0;
+}
+
static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
- unsigned long value, repeat = 0;
+ unsigned long i, value, range_end, range_inc, repeat = 0;
CalendarComponent *cc;
int r;
const char *e;
@@ -471,6 +503,30 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
if (repeat == 0)
return -ERANGE;
+ } else if (e[0] == '.' && e[1] == '.') {
+ e += 2;
+ r = parse_component_decimal(&e, usec, &range_end);
+ if (r < 0)
+ return r;
+
+ if (value >= range_end)
+ return -EINVAL;
+
+ range_inc = usec ? USEC_PER_SEC : 1;
+
+ /* Don't allow impossibly large ranges... */
+ if (range_end - value >= MAX_RANGE_LEN * range_inc)
+ return -EINVAL;
+
+ /* ...or ranges with only a single element */
+ if (range_end - value < range_inc)
+ return -EINVAL;
+
+ for (i = value; i <= range_end; i += range_inc) {
+ r = const_chain(i, c);
+ if (r < 0)
+ return r;
+ }
}
if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != ':')
@@ -495,24 +551,6 @@ static int prepend_component(const char **p, bool usec, CalendarComponent **c) {
return 0;
}
-static int const_chain(int value, CalendarComponent **c) {
- CalendarComponent *cc = NULL;
-
- assert(c);
-
- cc = new0(CalendarComponent, 1);
- if (!cc)
- return -ENOMEM;
-
- cc->value = value;
- cc->repeat = 0;
- cc->next = *c;
-
- *c = cc;
-
- return 0;
-}
-
static int parse_chain(const char **p, bool usec, CalendarComponent **c) {
const char *t;
CalendarComponent *cc = NULL;
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 7cdc97ee3c..472e24b7a3 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -197,7 +197,15 @@ int cg_rmdir(const char *controller, const char *path) {
return 0;
}
-int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s) {
+int cg_kill(
+ const char *controller,
+ const char *path,
+ int sig,
+ CGroupFlags flags,
+ Set *s,
+ cg_kill_log_func_t log_kill,
+ void *userdata) {
+
_cleanup_set_free_ Set *allocated_set = NULL;
bool done = false;
int r, ret = 0;
@@ -205,6 +213,11 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
assert(sig >= 0);
+ /* Don't send SIGCONT twice. Also, SIGKILL always works even when process is suspended, hence don't send
+ * SIGCONT on SIGKILL. */
+ if (IN_SET(sig, SIGCONT, SIGKILL))
+ flags &= ~CGROUP_SIGCONT;
+
/* This goes through the tasks list and kills them all. This
* is repeated until no further processes are added to the
* tasks list, to properly handle forking processes */
@@ -232,19 +245,22 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
while ((r = cg_read_pid(f, &pid)) > 0) {
- if (ignore_self && pid == my_pid)
+ if ((flags & CGROUP_IGNORE_SELF) && pid == my_pid)
continue;
if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
continue;
+ if (log_kill)
+ log_kill(pid, sig, userdata);
+
/* If we haven't killed this process yet, kill
* it */
if (kill(pid, sig) < 0) {
if (ret >= 0 && errno != ESRCH)
ret = -errno;
} else {
- if (sigcont && sig != SIGKILL)
+ if (flags & CGROUP_SIGCONT)
(void) kill(pid, SIGCONT);
if (ret == 0)
@@ -278,7 +294,15 @@ int cg_kill(const char *controller, const char *path, int sig, bool sigcont, boo
return ret;
}
-int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool rem, Set *s) {
+int cg_kill_recursive(
+ const char *controller,
+ const char *path,
+ int sig,
+ CGroupFlags flags,
+ Set *s,
+ cg_kill_log_func_t log_kill,
+ void *userdata) {
+
_cleanup_set_free_ Set *allocated_set = NULL;
_cleanup_closedir_ DIR *d = NULL;
int r, ret;
@@ -293,7 +317,7 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si
return -ENOMEM;
}
- ret = cg_kill(controller, path, sig, sigcont, ignore_self, s);
+ ret = cg_kill(controller, path, sig, flags, s, log_kill, userdata);
r = cg_enumerate_subgroups(controller, path, &d);
if (r < 0) {
@@ -311,15 +335,14 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si
if (!p)
return -ENOMEM;
- r = cg_kill_recursive(controller, p, sig, sigcont, ignore_self, rem, s);
+ r = cg_kill_recursive(controller, p, sig, flags, s, log_kill, userdata);
if (r != 0 && ret >= 0)
ret = r;
}
-
if (ret >= 0 && r < 0)
ret = r;
- if (rem) {
+ if (flags & CGROUP_REMOVE) {
r = cg_rmdir(controller, path);
if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
return r;
@@ -328,7 +351,13 @@ int cg_kill_recursive(const char *controller, const char *path, int sig, bool si
return ret;
}
-int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self) {
+int cg_migrate(
+ const char *cfrom,
+ const char *pfrom,
+ const char *cto,
+ const char *pto,
+ CGroupFlags flags) {
+
bool done = false;
_cleanup_set_free_ Set *s = NULL;
int r, ret = 0;
@@ -363,7 +392,7 @@ int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char
/* This might do weird stuff if we aren't a
* single-threaded program. However, we
* luckily know we are not */
- if (ignore_self && pid == my_pid)
+ if ((flags & CGROUP_IGNORE_SELF) && pid == my_pid)
continue;
if (set_get(s, PID_TO_PTR(pid)) == PID_TO_PTR(pid))
@@ -411,8 +440,7 @@ int cg_migrate_recursive(
const char *pfrom,
const char *cto,
const char *pto,
- bool ignore_self,
- bool rem) {
+ CGroupFlags flags) {
_cleanup_closedir_ DIR *d = NULL;
int r, ret = 0;
@@ -423,7 +451,7 @@ int cg_migrate_recursive(
assert(cto);
assert(pto);
- ret = cg_migrate(cfrom, pfrom, cto, pto, ignore_self);
+ ret = cg_migrate(cfrom, pfrom, cto, pto, flags);
r = cg_enumerate_subgroups(cfrom, pfrom, &d);
if (r < 0) {
@@ -441,7 +469,7 @@ int cg_migrate_recursive(
if (!p)
return -ENOMEM;
- r = cg_migrate_recursive(cfrom, p, cto, pto, ignore_self, rem);
+ r = cg_migrate_recursive(cfrom, p, cto, pto, flags);
if (r != 0 && ret >= 0)
ret = r;
}
@@ -449,7 +477,7 @@ int cg_migrate_recursive(
if (r < 0 && ret >= 0)
ret = r;
- if (rem) {
+ if (flags & CGROUP_REMOVE) {
r = cg_rmdir(cfrom, pfrom);
if (r < 0 && ret >= 0 && r != -ENOENT && r != -EBUSY)
return r;
@@ -463,8 +491,7 @@ int cg_migrate_recursive_fallback(
const char *pfrom,
const char *cto,
const char *pto,
- bool ignore_self,
- bool rem) {
+ CGroupFlags flags) {
int r;
@@ -473,7 +500,7 @@ int cg_migrate_recursive_fallback(
assert(cto);
assert(pto);
- r = cg_migrate_recursive(cfrom, pfrom, cto, pto, ignore_self, rem);
+ r = cg_migrate_recursive(cfrom, pfrom, cto, pto, flags);
if (r < 0) {
char prefix[strlen(pto) + 1];
@@ -482,7 +509,7 @@ int cg_migrate_recursive_fallback(
PATH_FOREACH_PREFIX(prefix, pto) {
int q;
- q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, ignore_self, rem);
+ q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, flags);
if (q >= 0)
return q;
}
@@ -1955,7 +1982,7 @@ int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to
int r = 0, unified;
if (!path_equal(from, to)) {
- r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, false, true);
+ r = cg_migrate_recursive(SYSTEMD_CGROUP_CONTROLLER, from, SYSTEMD_CGROUP_CONTROLLER, to, CGROUP_REMOVE);
if (r < 0)
return r;
}
@@ -1979,7 +2006,7 @@ int cg_migrate_everywhere(CGroupMask supported, const char *from, const char *to
if (!p)
p = to;
- (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, false, false);
+ (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, 0);
}
return 0;
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index 4bb5291296..14ebde5fc9 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -135,12 +135,20 @@ int cg_read_event(const char *controller, const char *path, const char *event,
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d);
int cg_read_subgroup(DIR *d, char **fn);
-int cg_kill(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, Set *s);
-int cg_kill_recursive(const char *controller, const char *path, int sig, bool sigcont, bool ignore_self, bool remove, Set *s);
+typedef enum CGroupFlags {
+ CGROUP_SIGCONT = 1,
+ CGROUP_IGNORE_SELF = 2,
+ CGROUP_REMOVE = 4,
+} CGroupFlags;
-int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self);
-int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool remove);
-int cg_migrate_recursive_fallback(const char *cfrom, const char *pfrom, const char *cto, const char *pto, bool ignore_self, bool rem);
+typedef void (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata);
+
+int cg_kill(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
+int cg_kill_recursive(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
+
+int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);
+int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);
+int cg_migrate_recursive_fallback(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);
int cg_split_spec(const char *spec, char **controller, char **path);
int cg_mangle_path(const char *path, char **result);
diff --git a/src/basic/copy.c b/src/basic/copy.c
index c3586728d0..9883f5fa31 100644
--- a/src/basic/copy.c
+++ b/src/basic/copy.c
@@ -169,7 +169,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
/* sendfile accepts at most SSIZE_MAX-offset bytes to copy,
* so reduce our maximum by the amount we already copied,
* but don't go below our copy buffer size, unless we are
- * close the the limit of bytes we are allowed to copy. */
+ * close the limit of bytes we are allowed to copy. */
m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n);
}
diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c
index 92fa5ace61..d488cfc59f 100644
--- a/src/basic/exit-status.c
+++ b/src/basic/exit-status.c
@@ -38,8 +38,7 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
return "FAILURE";
}
-
- if (level == EXIT_STATUS_SYSTEMD || level == EXIT_STATUS_LSB) {
+ if (IN_SET(level, EXIT_STATUS_SYSTEMD, EXIT_STATUS_LSB)) {
switch ((int) status) {
case EXIT_CHDIR:
@@ -189,13 +188,9 @@ bool is_clean_exit(int code, int status, ExitStatusSet *success_status) {
/* If a daemon does not implement handlers for some of the
* signals that's not considered an unclean shutdown */
if (code == CLD_KILLED)
- return
- status == SIGHUP ||
- status == SIGINT ||
- status == SIGTERM ||
- status == SIGPIPE ||
+ return IN_SET(status, SIGHUP, SIGINT, SIGTERM, SIGPIPE) ||
(success_status &&
- set_contains(success_status->signal, INT_TO_PTR(status)));
+ set_contains(success_status->signal, INT_TO_PTR(status)));
return false;
}
@@ -207,15 +202,14 @@ bool is_clean_exit_lsb(int code, int status, ExitStatusSet *success_status) {
return
code == CLD_EXITED &&
- (status == EXIT_NOTINSTALLED || status == EXIT_NOTCONFIGURED);
+ IN_SET(status, EXIT_NOTINSTALLED, EXIT_NOTCONFIGURED);
}
void exit_status_set_free(ExitStatusSet *x) {
assert(x);
- set_free(x->status);
- set_free(x->signal);
- x->status = x->signal = NULL;
+ x->status = set_free(x->status);
+ x->signal = set_free(x->signal);
}
bool exit_status_set_is_empty(ExitStatusSet *x) {
diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h
index 1208c8feed..2309f68815 100644
--- a/src/basic/exit-status.h
+++ b/src/basic/exit-status.h
@@ -25,6 +25,12 @@
#include "macro.h"
#include "set.h"
+/* This defines pretty names for the LSB 'start' verb exit codes. Note that they shouldn't be confused with the LSB
+ * 'status' verb exit codes which are defined very differently. For details see:
+ *
+ * https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
+ */
+
typedef enum ExitStatus {
/* EXIT_SUCCESS defined by libc */
/* EXIT_FAILURE defined by libc */
@@ -37,9 +43,7 @@ typedef enum ExitStatus {
/* The LSB suggests that error codes >= 200 are "reserved". We
* use them here under the assumption that they hence are
- * unused by init scripts.
- *
- * http://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html */
+ * unused by init scripts. */
EXIT_CHDIR = 200,
EXIT_NICE,
@@ -81,9 +85,9 @@ typedef enum ExitStatus {
} ExitStatus;
typedef enum ExitStatusLevel {
- EXIT_STATUS_MINIMAL,
- EXIT_STATUS_SYSTEMD,
- EXIT_STATUS_LSB,
+ EXIT_STATUS_MINIMAL, /* only cover libc EXIT_STATUS/EXIT_FAILURE */
+ EXIT_STATUS_SYSTEMD, /* cover libc and systemd's own exit codes */
+ EXIT_STATUS_LSB, /* cover libc, systemd's own and LSB exit codes */
EXIT_STATUS_FULL = EXIT_STATUS_LSB
} ExitStatusLevel;
diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c
index 8b466cff15..5c820332a5 100644
--- a/src/basic/fd-util.c
+++ b/src/basic/fd-util.c
@@ -186,6 +186,12 @@ int fd_cloexec(int fd, bool cloexec) {
return 0;
}
+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/basic/fd-util.h b/src/basic/fd-util.h
index b86e41698a..34b98d4aec 100644
--- a/src/basic/fd-util.h
+++ b/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/basic/fdset.c b/src/basic/fdset.c
deleted file mode 100644
index 527f27bc67..0000000000
--- a/src/basic/fdset.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <alloca.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stddef.h>
-
-#include "sd-daemon.h"
-
-#include "fd-util.h"
-#include "fdset.h"
-#include "log.h"
-#include "macro.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "set.h"
-
-#define MAKE_SET(s) ((Set*) s)
-#define MAKE_FDSET(s) ((FDSet*) s)
-
-FDSet *fdset_new(void) {
- return MAKE_FDSET(set_new(NULL));
-}
-
-int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds) {
- unsigned i;
- FDSet *s;
- int r;
-
- assert(ret);
-
- s = fdset_new();
- if (!s)
- return -ENOMEM;
-
- for (i = 0; i < n_fds; i++) {
-
- r = fdset_put(s, fds[i]);
- if (r < 0) {
- set_free(MAKE_SET(s));
- return r;
- }
- }
-
- *ret = s;
- return 0;
-}
-
-FDSet* fdset_free(FDSet *s) {
- void *p;
-
- while ((p = set_steal_first(MAKE_SET(s)))) {
- /* Valgrind's fd might have ended up in this set here,
- * due to fdset_new_fill(). We'll ignore all failures
- * here, so that the EBADFD that valgrind will return
- * us on close() doesn't influence us */
-
- /* When reloading duplicates of the private bus
- * connection fds and suchlike are closed here, which
- * has no effect at all, since they are only
- * duplicates. So don't be surprised about these log
- * messages. */
-
- log_debug("Closing left-over fd %i", PTR_TO_FD(p));
- close_nointr(PTR_TO_FD(p));
- }
-
- set_free(MAKE_SET(s));
- return NULL;
-}
-
-int fdset_put(FDSet *s, int fd) {
- assert(s);
- assert(fd >= 0);
-
- return set_put(MAKE_SET(s), FD_TO_PTR(fd));
-}
-
-int fdset_put_dup(FDSet *s, int fd) {
- int copy, r;
-
- assert(s);
- assert(fd >= 0);
-
- copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
- if (copy < 0)
- return -errno;
-
- r = fdset_put(s, copy);
- if (r < 0) {
- safe_close(copy);
- return r;
- }
-
- return copy;
-}
-
-bool fdset_contains(FDSet *s, int fd) {
- assert(s);
- assert(fd >= 0);
-
- return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
-}
-
-int fdset_remove(FDSet *s, int fd) {
- assert(s);
- assert(fd >= 0);
-
- return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
-}
-
-int fdset_new_fill(FDSet **_s) {
- _cleanup_closedir_ DIR *d = NULL;
- struct dirent *de;
- int r = 0;
- FDSet *s;
-
- assert(_s);
-
- /* Creates an fdset and fills in all currently open file
- * descriptors. */
-
- d = opendir("/proc/self/fd");
- if (!d)
- return -errno;
-
- s = fdset_new();
- if (!s) {
- r = -ENOMEM;
- goto finish;
- }
-
- while ((de = readdir(d))) {
- int fd = -1;
-
- if (hidden_or_backup_file(de->d_name))
- continue;
-
- r = safe_atoi(de->d_name, &fd);
- if (r < 0)
- goto finish;
-
- if (fd < 3)
- continue;
-
- if (fd == dirfd(d))
- continue;
-
- r = fdset_put(s, fd);
- if (r < 0)
- goto finish;
- }
-
- r = 0;
- *_s = s;
- s = NULL;
-
-finish:
- /* We won't close the fds here! */
- if (s)
- set_free(MAKE_SET(s));
-
- return r;
-}
-
-int fdset_cloexec(FDSet *fds, bool b) {
- Iterator i;
- void *p;
- int r;
-
- assert(fds);
-
- SET_FOREACH(p, MAKE_SET(fds), i) {
- r = fd_cloexec(PTR_TO_FD(p), b);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int fdset_new_listen_fds(FDSet **_s, bool unset) {
- int n, fd, r;
- FDSet *s;
-
- assert(_s);
-
- /* Creates an fdset and fills in all passed file descriptors */
-
- s = fdset_new();
- if (!s) {
- r = -ENOMEM;
- goto fail;
- }
-
- n = sd_listen_fds(unset);
- for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
- r = fdset_put(s, fd);
- if (r < 0)
- goto fail;
- }
-
- *_s = s;
- return 0;
-
-
-fail:
- if (s)
- set_free(MAKE_SET(s));
-
- return r;
-}
-
-int fdset_close_others(FDSet *fds) {
- void *e;
- Iterator i;
- int *a;
- unsigned j, m;
-
- j = 0, m = fdset_size(fds);
- a = alloca(sizeof(int) * m);
- SET_FOREACH(e, MAKE_SET(fds), i)
- a[j++] = PTR_TO_FD(e);
-
- assert(j == m);
-
- return close_all_fds(a, j);
-}
-
-unsigned fdset_size(FDSet *fds) {
- return set_size(MAKE_SET(fds));
-}
-
-bool fdset_isempty(FDSet *fds) {
- return set_isempty(MAKE_SET(fds));
-}
-
-int fdset_iterate(FDSet *s, Iterator *i) {
- void *p;
-
- if (!set_iterate(MAKE_SET(s), i, &p))
- return -ENOENT;
-
- return PTR_TO_FD(p);
-}
-
-int fdset_steal_first(FDSet *fds) {
- void *p;
-
- p = set_steal_first(MAKE_SET(fds));
- if (!p)
- return -ENOENT;
-
- return PTR_TO_FD(p);
-}
diff --git a/src/basic/fdset.h b/src/basic/fdset.h
deleted file mode 100644
index 16efe5bdf2..0000000000
--- a/src/basic/fdset.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-#include "hashmap.h"
-#include "macro.h"
-#include "set.h"
-
-typedef struct FDSet FDSet;
-
-FDSet* fdset_new(void);
-FDSet* fdset_free(FDSet *s);
-
-int fdset_put(FDSet *s, int fd);
-int fdset_put_dup(FDSet *s, int fd);
-
-bool fdset_contains(FDSet *s, int fd);
-int fdset_remove(FDSet *s, int fd);
-
-int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds);
-int fdset_new_fill(FDSet **ret);
-int fdset_new_listen_fds(FDSet **ret, bool unset);
-
-int fdset_cloexec(FDSet *fds, bool b);
-
-int fdset_close_others(FDSet *fds);
-
-unsigned fdset_size(FDSet *fds);
-bool fdset_isempty(FDSet *fds);
-
-int fdset_iterate(FDSet *s, Iterator *i);
-
-int fdset_steal_first(FDSet *fds);
-
-#define FDSET_FOREACH(fd, fds, i) \
- for ((i) = ITERATOR_FIRST, (fd) = fdset_iterate((fds), &(i)); (fd) >= 0; (fd) = fdset_iterate((fds), &(i)))
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(FDSet*, fdset_free);
-#define _cleanup_fdset_free_ _cleanup_(fdset_freep)
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 29f5374222..f183de4999 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -1067,7 +1067,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;
@@ -1259,7 +1259,8 @@ int open_tmpfile_unlinkable(const char *directory, int flags) {
char *p;
int fd;
- assert(directory);
+ if (!directory)
+ directory = "/tmp";
/* Returns an unlinked temporary file that cannot be linked into the file system anymore */
@@ -1354,3 +1355,44 @@ 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;
+}
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 58dbc80c24..9ac497d9eb 100644
--- a/src/basic/fileio.h
+++ b/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/basic/formats-util.h b/src/basic/formats-util.h
index 9b4e8e98fa..39a185f59b 100644
--- a/src/basic/formats-util.h
+++ b/src/basic/formats-util.h
@@ -61,3 +61,19 @@
#else
# error Unknown rlim_t size
#endif
+
+#if SIZEOF_DEV_T == 8
+# define DEV_FMT "%" PRIu64
+#elif SIZEOF_DEV_T == 4
+# define DEV_FMT "%" PRIu32
+#else
+# error Unknown dev_t size
+#endif
+
+#if SIZEOF_INO_T == 8
+# define INO_FMT "%" PRIu64
+#elif SIZEOF_INO_T == 4
+# define INO_FMT "%" PRIu32
+#else
+# error Unknown ino_t size
+#endif
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index e24e7036f7..f0c6f3265e 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -38,6 +38,7 @@
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
+#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
@@ -495,6 +496,34 @@ int get_files_in_directory(const char *path, char ***list) {
return n;
}
+int var_tmp(char **ret) {
+ const char *tmp_dir = NULL;
+ const char *env_tmp_dir = NULL;
+ char *c = NULL;
+ int r;
+
+ assert(ret);
+
+ env_tmp_dir = getenv("TMPDIR");
+ if (env_tmp_dir != NULL) {
+ r = is_dir(env_tmp_dir, true);
+ if (r < 0 && r != -ENOENT)
+ return r;
+ if (r > 0)
+ tmp_dir = env_tmp_dir;
+ }
+
+ if (!tmp_dir)
+ tmp_dir = "/var/tmp";
+
+ c = strdup(tmp_dir);
+ if (!c)
+ return -ENOMEM;
+ *ret = c;
+
+ return 0;
+}
+
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/basic/fs-util.h b/src/basic/fs-util.h
index 517b599d6f..075e5942b1 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -61,6 +61,8 @@ int mkfifo_atomic(const char *path, mode_t mode);
int get_files_in_directory(const char *path, char ***list);
+int var_tmp(char **ret);
+
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c
index 49a0479592..50fefb0b54 100644
--- a/src/basic/hashmap.c
+++ b/src/basic/hashmap.c
@@ -1764,6 +1764,9 @@ void *ordered_hashmap_next(OrderedHashmap *h, const void *key) {
int set_consume(Set *s, void *value) {
int r;
+ assert(s);
+ assert(value);
+
r = set_put(s, value);
if (r <= 0)
free(value);
@@ -1791,6 +1794,8 @@ int set_put_strdupv(Set *s, char **l) {
int n = 0, r;
char **i;
+ assert(s);
+
STRV_FOREACH(i, l) {
r = set_put_strdup(s, *i);
if (r < 0)
@@ -1801,3 +1806,23 @@ int set_put_strdupv(Set *s, char **l) {
return n;
}
+
+int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) {
+ const char *p = v;
+ int r;
+
+ assert(s);
+ assert(v);
+
+ for (;;) {
+ char *word;
+
+ r = extract_first_word(&p, &word, separators, flags);
+ if (r <= 0)
+ return r;
+
+ r = set_consume(s, word);
+ if (r < 0)
+ return r;
+ }
+}
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c
index 245107ebb8..aa7ccd1afd 100644
--- a/src/basic/in-addr-util.c
+++ b/src/basic/in-addr-util.c
@@ -20,26 +20,36 @@
#include <arpa/inet.h>
#include <endian.h>
#include <errno.h>
+#include <net/if.h>
#include <stdint.h>
#include <stdlib.h>
#include "alloc-util.h"
#include "in-addr-util.h"
#include "macro.h"
+#include "parse-util.h"
#include "util.h"
+bool in4_addr_is_null(const struct in_addr *a) {
+ return a->s_addr == 0;
+}
+
+bool in6_addr_is_null(const struct in6_addr *a) {
+ return
+ a->s6_addr32[0] == 0 &&
+ a->s6_addr32[1] == 0 &&
+ a->s6_addr32[2] == 0 &&
+ a->s6_addr32[3] == 0;
+}
+
int in_addr_is_null(int family, const union in_addr_union *u) {
assert(u);
if (family == AF_INET)
- return u->in.s_addr == 0;
+ return in4_addr_is_null(&u->in);
if (family == AF_INET6)
- return
- u->in6.s6_addr32[0] == 0 &&
- u->in6.s6_addr32[1] == 0 &&
- u->in6.s6_addr32[2] == 0 &&
- u->in6.s6_addr32[3] == 0;
+ return in6_addr_is_null(&u->in6);
return -EAFNOSUPPORT;
}
@@ -224,6 +234,48 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
return 0;
}
+int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
+ size_t l;
+ char *x;
+ int r;
+
+ assert(u);
+ assert(ret);
+
+ /* Much like in_addr_to_string(), but optionally appends the zone interface index to the address, to properly
+ * handle IPv6 link-local addresses. */
+
+ if (family != AF_INET6)
+ goto fallback;
+ if (ifindex <= 0)
+ goto fallback;
+
+ r = in_addr_is_link_local(family, u);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ goto fallback;
+
+ l = INET6_ADDRSTRLEN + 1 + DECIMAL_STR_MAX(ifindex) + 1;
+ x = new(char, l);
+ if (!x)
+ return -ENOMEM;
+
+ errno = 0;
+ if (!inet_ntop(family, u, x, l)) {
+ free(x);
+ return errno > 0 ? -errno : -EINVAL;
+ }
+
+ sprintf(strchr(x, 0), "%%%i", ifindex);
+ *ret = x;
+
+ return 0;
+
+fallback:
+ return in_addr_to_string(family, u, ret);
+}
+
int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
assert(s);
@@ -261,6 +313,47 @@ int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *re
return -EINVAL;
}
+int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex) {
+ const char *suffix;
+ int r, ifi = 0;
+
+ assert(s);
+ assert(family);
+ assert(ret);
+
+ /* Similar to in_addr_from_string_auto() but also parses an optionally appended IPv6 zone suffix ("scope id")
+ * if one is found. */
+
+ suffix = strchr(s, '%');
+ if (suffix) {
+
+ if (ifindex) {
+ /* If we shall return the interface index, try to parse it */
+ r = parse_ifindex(suffix + 1, &ifi);
+ if (r < 0) {
+ unsigned u;
+
+ u = if_nametoindex(suffix + 1);
+ if (u <= 0)
+ return -errno;
+
+ ifi = (int) u;
+ }
+ }
+
+ s = strndupa(s, suffix - s);
+ }
+
+ r = in_addr_from_string_auto(s, family, ret);
+ if (r < 0)
+ return r;
+
+ if (ifindex)
+ *ifindex = ifi;
+
+ return r;
+}
+
unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) {
assert(addr);
diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h
index 17798ce816..d60064aef8 100644
--- a/src/basic/in-addr-util.h
+++ b/src/basic/in-addr-util.h
@@ -36,6 +36,9 @@ struct in_addr_data {
union in_addr_union address;
};
+bool in4_addr_is_null(const struct in_addr *a);
+bool in6_addr_is_null(const struct in6_addr *a);
+
int in_addr_is_null(int family, const union in_addr_union *u);
int in_addr_is_link_local(int family, const union in_addr_union *u);
int in_addr_is_localhost(int family, const union in_addr_union *u);
@@ -43,8 +46,10 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_
int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
+int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret);
+int in_addr_ifindex_from_string_auto(const char *s, int *family, union in_addr_union *ret, int *ifindex);
unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr);
struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen);
int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen);
diff --git a/src/basic/log.c b/src/basic/log.c
index 3ea643b6e6..49b4598b7c 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -334,7 +334,7 @@ static int write_to_console(
const char *object,
const char *buffer) {
- char location[64], prefix[1 + DECIMAL_STR_MAX(int) + 2];
+ char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2];
struct iovec iovec[6] = {};
unsigned n = 0;
bool highlight;
@@ -350,7 +350,7 @@ static int write_to_console(
highlight = LOG_PRI(level) <= LOG_ERR && show_color;
if (show_location) {
- xsprintf(location, "(%s:%i) ", file, line);
+ snprintf(location, sizeof(location), "(%s:%i) ", file, line);
IOVEC_SET_STRING(iovec[n++], location);
}
diff --git a/src/basic/macro.h b/src/basic/macro.h
index e41aa4260f..6b2aeb933f 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -89,6 +89,15 @@
#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
#define UNIQ __COUNTER__
+/* builtins */
+#if __SIZEOF_INT__ == 4
+#define BUILTIN_FFS_U32(x) __builtin_ffs(x);
+#elif __SIZEOF_LONG__ == 4
+#define BUILTIN_FFS_U32(x) __builtin_ffsl(x);
+#else
+#error "neither int nor long are four bytes long?!?"
+#endif
+
/* Rounds up */
#define ALIGN4(l) (((l) + 3) & ~3)
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 651e414395..b1272f8799 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -453,6 +453,18 @@ struct btrfs_ioctl_quota_ctl_args {
#define MQUEUE_MAGIC 0x19800202
#endif
+#ifndef SECURITYFS_MAGIC
+#define SECURITYFS_MAGIC 0x73636673
+#endif
+
+#ifndef TRACEFS_MAGIC
+#define TRACEFS_MAGIC 0x74726163
+#endif
+
+#ifndef BPF_FS_MAGIC
+#define BPF_FS_MAGIC 0xcafe4a11
+#endif
+
#ifndef MS_MOVE
#define MS_MOVE 8192
#endif
@@ -567,6 +579,10 @@ struct btrfs_ioctl_quota_ctl_args {
#define IN6_ADDR_GEN_MODE_NONE 1
#endif
+#if !HAVE_DECL_IN6_ADDR_GEN_MODE_STABLE_PRIVACY
+#define IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2
+#endif
+
#if !HAVE_DECL_IFLA_MACVLAN_FLAGS
#define IFLA_MACVLAN_UNSPEC 0
#define IFLA_MACVLAN_MODE 1
@@ -746,6 +762,14 @@ struct btrfs_ioctl_quota_ctl_args {
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
#endif
+#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN
+#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
+#endif
+
+#ifndef BRIDGE_VLAN_INFO_RANGE_END
+#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
+#endif
+
#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID
#define IFLA_BR_UNSPEC 0
#define IFLA_BR_FORWARD_DELAY 1
@@ -813,6 +837,10 @@ struct btrfs_ioctl_quota_ctl_args {
#define IFLA_BRPORT_PROXYARP 10
#endif
+#if !HAVE_DECL_IFLA_VRF_TABLE
+#define IFLA_VRF_TABLE 1
+#endif
+
#if !HAVE_DECL_NDA_IFINDEX
#define NDA_UNSPEC 0
#define NDA_DST 1
diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h
index d502d3b9ca..e6fd67cb9d 100644
--- a/src/basic/missing_syscall.h
+++ b/src/basic/missing_syscall.h
@@ -178,18 +178,6 @@ static inline int setns(int fd, int nstype) {
/* ======================================================================= */
-static inline int raw_clone(unsigned long flags, void *child_stack) {
-#if defined(__s390__) || defined(__CRIS__)
- /* On s390 and cris the order of the first and second arguments
- * of the raw clone() system call is reversed. */
- return (int) syscall(__NR_clone, child_stack, flags);
-#else
- return (int) syscall(__NR_clone, flags, child_stack);
-#endif
-}
-
-/* ======================================================================= */
-
static inline pid_t raw_getpid(void) {
#if defined(__alpha__)
return (pid_t) syscall(__NR_getxpid);
@@ -291,6 +279,8 @@ static inline key_serial_t request_key(const char *type, const char *description
# define __NR_copy_file_range 391
# elif defined __aarch64__
# define __NR_copy_file_range 285
+# elif defined __powerpc__
+# define __NR_copy_file_range 379
# else
# warning "__NR_copy_file_range not defined for your architecture"
# endif
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
index ba698959b7..28dc778969 100644
--- a/src/basic/mount-util.c
+++ b/src/basic/mount-util.c
@@ -104,7 +104,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
*
* As last fallback we do traditional fstat() based st_dev
* comparisons. This is how things were traditionally done,
- * but unionfs breaks breaks this since it exposes file
+ * but unionfs breaks this since it exposes file
* systems with a variety of st_dev reported. Also, btrfs
* subvolumes have different st_dev, even though they aren't
* real mounts of their own. */
@@ -448,21 +448,21 @@ int bind_remount_recursive(const char *prefix, bool ro) {
if (r < 0)
return r;
- /* Try to reuse the original flag set, but
- * don't care for errors, in case of
- * obstructed mounts */
+ /* Deal with mount points that are obstructed by a
+ * later mount */
+ r = path_is_mount_point(x, 0);
+ if (r == -ENOENT || r == 0)
+ continue;
+ if (r < 0)
+ return r;
+
+ /* Try to reuse the original flag set */
orig_flags = 0;
(void) get_mount_flags(x, &orig_flags);
orig_flags &= ~MS_RDONLY;
- if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) {
-
- /* Deal with mount points that are
- * obstructed by a later mount */
-
- if (errno != ENOENT)
- return -errno;
- }
+ if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
+ return -errno;
}
}
@@ -500,6 +500,7 @@ bool fstype_is_network(const char *fstype) {
"gfs2\0"
"glusterfs\0"
"pvfs2\0" /* OrangeFS */
+ "ocfs2\0"
;
const char *x;
@@ -531,3 +532,28 @@ int repeat_unmount(const char *path, int flags) {
done = true;
}
}
+
+const char* mode_to_inaccessible_node(mode_t mode) {
+ /* This function maps a node type to the correspondent inaccessible node type.
+ * Character and block inaccessible devices may not be created (because major=0 and minor=0),
+ * in such case we map character and block devices to the inaccessible node type socket. */
+ switch(mode & S_IFMT) {
+ case S_IFREG:
+ return "/run/systemd/inaccessible/reg";
+ case S_IFDIR:
+ return "/run/systemd/inaccessible/dir";
+ case S_IFCHR:
+ if (access("/run/systemd/inaccessible/chr", F_OK) == 0)
+ return "/run/systemd/inaccessible/chr";
+ return "/run/systemd/inaccessible/sock";
+ case S_IFBLK:
+ if (access("/run/systemd/inaccessible/blk", F_OK) == 0)
+ return "/run/systemd/inaccessible/blk";
+ return "/run/systemd/inaccessible/sock";
+ case S_IFIFO:
+ return "/run/systemd/inaccessible/fifo";
+ case S_IFSOCK:
+ return "/run/systemd/inaccessible/sock";
+ }
+ return NULL;
+}
diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h
index bdb525d6b0..f46989ebb3 100644
--- a/src/basic/mount-util.h
+++ b/src/basic/mount-util.h
@@ -49,4 +49,6 @@ union file_handle_union {
char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ];
};
+const char* mode_to_inaccessible_node(mode_t mode);
+
#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ }
diff --git a/src/basic/nss-util.h b/src/basic/nss-util.h
index bf7c4854fc..e7844fff96 100644
--- a/src/basic/nss-util.h
+++ b/src/basic/nss-util.h
@@ -137,7 +137,7 @@ enum nss_status _nss_##module##_getpwnam_r( \
struct passwd *pwd, \
char *buffer, size_t buflen, \
int *errnop) _public_; \
-enum nss_status _nss_mymachines_getpwuid_r( \
+enum nss_status _nss_##module##_getpwuid_r( \
uid_t uid, \
struct passwd *pwd, \
char *buffer, size_t buflen, \
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 6c11b605a9..503a895731 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -532,3 +532,22 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
return 0;
}
+
+int parse_percent(const char *p) {
+ const char *pc, *n;
+ unsigned v;
+ int r;
+
+ pc = endswith(p, "%");
+ if (!pc)
+ return -EINVAL;
+
+ n = strndupa(p, pc - p);
+ r = safe_atou(n, &v);
+ if (r < 0)
+ return r;
+ if (v > 100)
+ return -ERANGE;
+
+ return (int) v;
+}
diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h
index 7dc579a159..73441bb6fd 100644
--- a/src/basic/parse-util.h
+++ b/src/basic/parse-util.h
@@ -105,3 +105,5 @@ static inline int safe_atozu(const char *s, size_t *ret_u) {
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(const char *p);
diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c
index 3505fa9c9a..0430beadaa 100644
--- a/src/basic/proc-cmdline.c
+++ b/src/basic/proc-cmdline.c
@@ -160,17 +160,29 @@ static const char * const rlmap[] = {
"3", SPECIAL_MULTI_USER_TARGET,
"4", SPECIAL_MULTI_USER_TARGET,
"5", SPECIAL_GRAPHICAL_TARGET,
+ NULL
+};
+
+static const char * const rlmap_initrd[] = {
+ "emergency", SPECIAL_EMERGENCY_TARGET,
+ "rescue", SPECIAL_RESCUE_TARGET,
+ NULL
};
const char* runlevel_to_target(const char *word) {
size_t i;
+ const char * const *rlmap_ptr = in_initrd() ? rlmap_initrd
+ : rlmap;
if (!word)
return NULL;
- for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
- if (streq(word, rlmap[i]))
- return rlmap[i+1];
+ if (in_initrd() && (word = startswith(word, "rd.")) == NULL)
+ return NULL;
+
+ for (i = 0; rlmap_ptr[i] != NULL; i += 2)
+ if (streq(word, rlmap_ptr[i]))
+ return rlmap_ptr[i+1];
return NULL;
}
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 1ad8816206..54b644ad56 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -48,6 +48,7 @@
#include "macro.h"
#include "missing.h"
#include "process-util.h"
+#include "raw-clone.h"
#include "signal-util.h"
#include "stat-util.h"
#include "string-table.h"
@@ -101,6 +102,7 @@ int get_process_comm(pid_t pid, char **name) {
int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
_cleanup_fclose_ FILE *f = NULL;
+ bool space = false;
char *r = NULL, *k;
const char *p;
int c;
@@ -108,6 +110,15 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
assert(line);
assert(pid >= 0);
+ /* Retrieves a process' command line. Replaces unprintable characters while doing so by whitespace (coalescing
+ * multiple sequential ones into one). If max_length is != 0 will return a string of the specified size at most
+ * (the trailing NUL byte does count towards the length here!), abbreviated with a "..." ellipsis. If
+ * comm_fallback is true and the process has no command line set (the case for kernel threads), or has a
+ * command line that resolves to the empty string will return the "comm" name of the process instead.
+ *
+ * Returns -ESRCH if the process doesn't exist, and -ENOENT if the process has no command line (and
+ * comm_fallback is false). */
+
p = procfs_file_alloca(pid, "cmdline");
f = fopen(p, "re");
@@ -117,24 +128,44 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
return -errno;
}
- if (max_length == 0) {
+ if (max_length == 1) {
+
+ /* If there's only room for one byte, return the empty string */
+ r = new0(char, 1);
+ if (!r)
+ return -ENOMEM;
+
+ *line = r;
+ return 0;
+
+ } else if (max_length == 0) {
size_t len = 0, allocated = 0;
while ((c = getc(f)) != EOF) {
- if (!GREEDY_REALLOC(r, allocated, len+2)) {
+ if (!GREEDY_REALLOC(r, allocated, len+3)) {
free(r);
return -ENOMEM;
}
- r[len++] = isprint(c) ? c : ' ';
- }
+ if (isprint(c)) {
+ if (space) {
+ r[len++] = ' ';
+ space = false;
+ }
+
+ r[len++] = c;
+ } else if (len > 0)
+ space = true;
+ }
if (len > 0)
- r[len-1] = 0;
+ r[len] = 0;
+ else
+ r = mfree(r);
} else {
- bool space = false;
+ bool dotdotdot = false;
size_t left;
r = new(char, max_length);
@@ -146,28 +177,46 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
while ((c = getc(f)) != EOF) {
if (isprint(c)) {
+
if (space) {
- if (left <= 4)
+ if (left <= 2) {
+ dotdotdot = true;
break;
+ }
*(k++) = ' ';
left--;
space = false;
}
- if (left <= 4)
+ if (left <= 1) {
+ dotdotdot = true;
break;
+ }
*(k++) = (char) c;
left--;
- } else
+ } else if (k > r)
space = true;
}
- if (left <= 4) {
- size_t n = MIN(left-1, 3U);
- memcpy(k, "...", n);
- k[n] = 0;
+ if (dotdotdot) {
+ if (max_length <= 4) {
+ k = r;
+ left = max_length;
+ } else {
+ k = r + max_length - 4;
+ left = 4;
+
+ /* Eat up final spaces */
+ while (k > r && isspace(k[-1])) {
+ k--;
+ left++;
+ }
+ }
+
+ strncpy(k, "...", left-1);
+ k[left-1] = 0;
} else
*k = 0;
}
@@ -186,7 +235,37 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
if (h < 0)
return h;
- r = strjoin("[", t, "]", NULL);
+ if (max_length == 0)
+ r = strjoin("[", t, "]", NULL);
+ else {
+ size_t l;
+
+ l = strlen(t);
+
+ if (l + 3 <= max_length)
+ r = strjoin("[", t, "]", NULL);
+ else if (max_length <= 6) {
+
+ r = new(char, max_length);
+ if (!r)
+ return -ENOMEM;
+
+ memcpy(r, "[...]", max_length-1);
+ r[max_length-1] = 0;
+ } else {
+ char *e;
+
+ t[max_length - 6] = 0;
+
+ /* Chop off final spaces */
+ e = strchr(t, 0);
+ while (e > t && isspace(e[-1]))
+ e--;
+ *e = 0;
+
+ r = strjoin("[", t, "...]", NULL);
+ }
+ }
if (!r)
return -ENOMEM;
}
@@ -316,9 +395,6 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) {
assert(field);
assert(uid);
- if (pid == 0)
- return getuid();
-
p = procfs_file_alloca(pid, "status");
f = fopen(p, "re");
if (!f) {
@@ -477,7 +553,7 @@ int wait_for_terminate(pid_t pid, siginfo_t *status) {
if (errno == EINTR)
continue;
- return -errno;
+ return negative_errno();
}
return 0;
@@ -549,8 +625,10 @@ int kill_and_sigcont(pid_t pid, int sig) {
r = kill(pid, sig) < 0 ? -errno : 0;
- if (r >= 0)
- kill(pid, SIGCONT);
+ /* If this worked, also send SIGCONT, unless we already just sent a SIGCONT, or SIGKILL was sent which isn't
+ * affected by a process being suspended anyway. */
+ if (r >= 0 && !IN_SET(SIGCONT, SIGKILL))
+ (void) kill(pid, SIGCONT);
return r;
}
@@ -726,7 +804,7 @@ void valgrind_summary_hack(void) {
#ifdef HAVE_VALGRIND_VALGRIND_H
if (getpid() == 1 && RUNNING_ON_VALGRIND) {
pid_t pid;
- pid = raw_clone(SIGCHLD, NULL);
+ pid = raw_clone(SIGCHLD);
if (pid < 0)
log_emergency_errno(errno, "Failed to fork off valgrind helper: %m");
else if (pid == 0)
diff --git a/src/basic/random-util.c b/src/basic/random-util.c
index 2f468db770..ad7b3eedf2 100644
--- a/src/basic/random-util.c
+++ b/src/basic/random-util.c
@@ -46,7 +46,7 @@ int dev_urandom(void *p, size_t n) {
* never block, and will always return some data from the
* kernel, regardless if the random pool is fully initialized
* or not. It thus makes no guarantee for the quality of the
- * returned entropy, but is good enough for or usual usecases
+ * returned entropy, but is good enough for our usual usecases
* of seeding the hash functions for hashtable */
/* Use the getrandom() syscall unless we know we don't have
diff --git a/src/basic/raw-clone.h b/src/basic/raw-clone.h
new file mode 100644
index 0000000000..d473828999
--- /dev/null
+++ b/src/basic/raw-clone.h
@@ -0,0 +1,81 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+ Copyright 2016 Michael Karcher
+ 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 <sched.h>
+#include <sys/syscall.h>
+
+#include "log.h"
+#include "macro.h"
+
+/**
+ * raw_clone() - uses clone to create a new process with clone flags
+ * @flags: Flags to pass to the clone system call
+ *
+ * Uses the clone system call to create a new process with the cloning
+ * flags and termination signal passed in the flags parameter. Opposed
+ * to glibc's clone funtion, using this function does not set up a
+ * separate stack for the child, but relies on copy-on-write semantics
+ * on the one stack at a common virtual address, just as fork does.
+ *
+ * To obtain copy-on-write semantics, flags must not contain CLONE_VM,
+ * and thus CLONE_THREAD and CLONE_SIGHAND (which require CLONE_VM) are
+ * not usabale.
+ * Additionally, as this function does not pass the ptid, newtls and ctid
+ * parameters to the kernel, flags must not contain CLONE_PARENT_SETTID,
+ * CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID or CLONE_SETTLS.
+ *
+ * Returns: 0 in the child process and the child process id in the parent.
+ */
+static inline int raw_clone(unsigned long flags) {
+ assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID|
+ CLONE_CHILD_CLEARTID|CLONE_SETTLS)) == 0);
+#if defined(__s390__) || defined(__CRIS__)
+ /* On s390 and cris the order of the first and second arguments
+ * of the raw clone() system call is reversed. */
+ return (int) syscall(__NR_clone, NULL, flags);
+#elif defined(__sparc__) && defined(__arch64__)
+ {
+ /**
+ * sparc64 always returns the other process id in %o0, and
+ * a boolean flag whether this is the child or the parent in
+ * %o1. Inline assembly is needed to get the flag returned
+ * in %o1.
+ */
+ int in_child;
+ int child_pid;
+ asm volatile("mov %2, %%g1\n\t"
+ "mov %3, %%o0\n\t"
+ "mov 0 , %%o1\n\t"
+ "t 0x6d\n\t"
+ "mov %%o1, %0\n\t"
+ "mov %%o0, %1" :
+ "=r"(in_child), "=r"(child_pid) :
+ "i"(__NR_clone), "r"(flags) :
+ "%o1", "%o0", "%g1" );
+ if (in_child)
+ return 0;
+ else
+ return child_pid;
+ }
+#else
+ return (int) syscall(__NR_clone, flags, NULL);
+#endif
+}
diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
index 10c2f39369..bc07654668 100644
--- a/src/basic/selinux-util.c
+++ b/src/basic/selinux-util.c
@@ -41,10 +41,10 @@
#include "util.h"
#ifdef HAVE_SELINUX
-DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon);
+DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon);
DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
-#define _cleanup_security_context_free_ _cleanup_(freeconp)
+#define _cleanup_freecon_ _cleanup_(freeconp)
#define _cleanup_context_free_ _cleanup_(context_freep)
static int cached_use = -1;
@@ -143,7 +143,7 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
r = lstat(path, &st);
if (r >= 0) {
- _cleanup_security_context_free_ security_context_t fcon = NULL;
+ _cleanup_freecon_ char* fcon = NULL;
r = selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode);
@@ -186,7 +186,7 @@ int mac_selinux_apply(const char *path, const char *label) {
assert(path);
assert(label);
- if (setfilecon(path, (security_context_t) label) < 0) {
+ if (setfilecon(path, label) < 0) {
log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path);
if (security_getenforce() > 0)
return -errno;
@@ -199,7 +199,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
int r = -EOPNOTSUPP;
#ifdef HAVE_SELINUX
- _cleanup_security_context_free_ security_context_t mycon = NULL, fcon = NULL;
+ _cleanup_freecon_ char *mycon = NULL, *fcon = NULL;
security_class_t sclass;
assert(exe);
@@ -217,7 +217,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
return -errno;
sclass = string_to_security_class("process");
- r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label);
+ r = security_compute_create_raw(mycon, fcon, sclass, label);
if (r < 0)
return -errno;
#endif
@@ -246,7 +246,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
int r = -EOPNOTSUPP;
#ifdef HAVE_SELINUX
- _cleanup_security_context_free_ security_context_t mycon = NULL, peercon = NULL, fcon = NULL;
+ _cleanup_freecon_ char *mycon = NULL, *peercon = NULL, *fcon = NULL;
_cleanup_context_free_ context_t pcon = NULL, bcon = NULL;
security_class_t sclass;
const char *range = NULL;
@@ -296,7 +296,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
return -ENOMEM;
sclass = string_to_security_class("process");
- r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label);
+ r = security_compute_create_raw(mycon, fcon, sclass, label);
if (r < 0)
return -errno;
#endif
@@ -314,7 +314,7 @@ char* mac_selinux_free(char *label) {
return NULL;
- freecon((security_context_t) label);
+ freecon(label);
#endif
return NULL;
@@ -323,7 +323,7 @@ char* mac_selinux_free(char *label) {
int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
#ifdef HAVE_SELINUX
- _cleanup_security_context_free_ security_context_t filecon = NULL;
+ _cleanup_freecon_ char *filecon = NULL;
int r;
assert(path);
@@ -383,7 +383,7 @@ int mac_selinux_create_socket_prepare(const char *label) {
assert(label);
- if (setsockcreatecon((security_context_t) label) < 0) {
+ if (setsockcreatecon(label) < 0) {
log_enforcing("Failed to set SELinux security context %s for sockets: %m", label);
if (security_getenforce() == 1)
@@ -411,7 +411,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
/* Binds a socket and label its file system object according to the SELinux policy */
#ifdef HAVE_SELINUX
- _cleanup_security_context_free_ security_context_t fcon = NULL;
+ _cleanup_freecon_ char *fcon = NULL;
const struct sockaddr_un *un;
bool context_changed = false;
char *path;
diff --git a/src/basic/set.h b/src/basic/set.h
index e0d9dd001c..12f64a8c57 100644
--- a/src/basic/set.h
+++ b/src/basic/set.h
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "extract-word.h"
#include "hashmap.h"
#include "macro.h"
@@ -122,6 +123,7 @@ static inline char **set_get_strv(Set *s) {
int set_consume(Set *s, void *value);
int set_put_strdup(Set *s, const char *p);
int set_put_strdupv(Set *s, char **l);
+int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags);
#define SET_FOREACH(e, s, i) \
for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); )
diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c
index 060e8ba387..8c1cdc3db6 100644
--- a/src/basic/siphash24.c
+++ b/src/basic/siphash24.c
@@ -17,6 +17,8 @@
coding style)
*/
+#include <stdio.h>
+
#include "macro.h"
#include "siphash24.h"
#include "unaligned.h"
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index c8769a54f4..385c3e4df3 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -85,7 +85,7 @@ int socket_address_parse(SocketAddress *a, const char *s) {
return -EINVAL;
a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htons((uint16_t) u);
+ a->sockaddr.in6.sin6_port = htobe16((uint16_t)u);
a->size = sizeof(struct sockaddr_in6);
} else if (*s == '/') {
@@ -133,7 +133,7 @@ int socket_address_parse(SocketAddress *a, const char *s) {
if (r > 0) {
/* Gotcha, it's a traditional IPv4 address */
a->sockaddr.in.sin_family = AF_INET;
- a->sockaddr.in.sin_port = htons((uint16_t) u);
+ a->sockaddr.in.sin_port = htobe16((uint16_t)u);
a->size = sizeof(struct sockaddr_in);
} else {
unsigned idx;
@@ -147,7 +147,7 @@ int socket_address_parse(SocketAddress *a, const char *s) {
return -EINVAL;
a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htons((uint16_t) u);
+ a->sockaddr.in6.sin6_port = htobe16((uint16_t)u);
a->sockaddr.in6.sin6_scope_id = idx;
a->sockaddr.in6.sin6_addr = in6addr_any;
a->size = sizeof(struct sockaddr_in6);
@@ -164,12 +164,12 @@ int socket_address_parse(SocketAddress *a, const char *s) {
if (socket_ipv6_is_supported()) {
a->sockaddr.in6.sin6_family = AF_INET6;
- a->sockaddr.in6.sin6_port = htons((uint16_t) u);
+ a->sockaddr.in6.sin6_port = htobe16((uint16_t)u);
a->sockaddr.in6.sin6_addr = in6addr_any;
a->size = sizeof(struct sockaddr_in6);
} else {
a->sockaddr.in.sin_family = AF_INET;
- a->sockaddr.in.sin_port = htons((uint16_t) u);
+ a->sockaddr.in.sin_port = htobe16((uint16_t)u);
a->sockaddr.in.sin_addr.s_addr = INADDR_ANY;
a->size = sizeof(struct sockaddr_in);
}
@@ -488,9 +488,7 @@ int sockaddr_port(const struct sockaddr *_sa) {
if (!IN_SET(sa->sa.sa_family, AF_INET, AF_INET6))
return -EAFNOSUPPORT;
- return ntohs(sa->sa.sa_family == AF_INET6 ?
- sa->in6.sin6_port :
- sa->in.sin_port);
+ return be16toh(sa->sa.sa_family == AF_INET6 ? sa->in6.sin6_port : sa->in.sin_port);
}
int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret) {
@@ -506,13 +504,13 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
case AF_INET: {
uint32_t a;
- a = ntohl(sa->in.sin_addr.s_addr);
+ a = be32toh(sa->in.sin_addr.s_addr);
if (include_port)
r = asprintf(&p,
"%u.%u.%u.%u:%u",
a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
- ntohs(sa->in.sin_port));
+ be16toh(sa->in.sin_port));
else
r = asprintf(&p,
"%u.%u.%u.%u",
@@ -534,7 +532,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
r = asprintf(&p,
"%u.%u.%u.%u:%u",
a[0], a[1], a[2], a[3],
- ntohs(sa->in6.sin6_port));
+ be16toh(sa->in6.sin6_port));
else
r = asprintf(&p,
"%u.%u.%u.%u",
@@ -550,7 +548,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
r = asprintf(&p,
"[%s]:%u",
a,
- ntohs(sa->in6.sin6_port));
+ be16toh(sa->in6.sin6_port));
if (r < 0)
return -ENOMEM;
} else {
@@ -988,7 +986,7 @@ ssize_t next_datagram_size_fd(int fd) {
l = recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC);
if (l < 0) {
- if (errno == EOPNOTSUPP)
+ if (errno == EOPNOTSUPP || errno == EFAULT)
goto fallback;
return -errno;
diff --git a/src/basic/string-table.h b/src/basic/string-table.h
index d88625fca7..369610efc8 100644
--- a/src/basic/string-table.h
+++ b/src/basic/string-table.h
@@ -48,6 +48,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
scope type name##_from_string(const char *s) { \
int b; \
+ if (!s) \
+ return -1; \
b = parse_boolean(s); \
if (b == 0) \
return (type) 0; \
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index 139cc8c91b..1209e1e2e1 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -66,6 +66,10 @@ static inline bool isempty(const char *p) {
return !p || !p[0];
}
+static inline const char *empty_to_null(const char *p) {
+ return isempty(p) ? NULL : p;
+}
+
static inline char *startswith(const char *s, const char *prefix) {
size_t l;
diff --git a/src/basic/strv.c b/src/basic/strv.c
index 97a96e5762..34e464d253 100644
--- a/src/basic/strv.c
+++ b/src/basic/strv.c
@@ -139,16 +139,16 @@ char **strv_new_ap(const char *x, va_list ap) {
va_list aq;
/* As a special trick we ignore all listed strings that equal
- * (const char*) -1. This is supposed to be used with the
+ * STRV_IGNORE. This is supposed to be used with the
* STRV_IFNOTNULL() macro to include possibly NULL strings in
* the string list. */
if (x) {
- n = x == (const char*) -1 ? 0 : 1;
+ n = x == STRV_IGNORE ? 0 : 1;
va_copy(aq, ap);
while ((s = va_arg(aq, const char*))) {
- if (s == (const char*) -1)
+ if (s == STRV_IGNORE)
continue;
n++;
@@ -162,7 +162,7 @@ char **strv_new_ap(const char *x, va_list ap) {
return NULL;
if (x) {
- if (x != (const char*) -1) {
+ if (x != STRV_IGNORE) {
a[i] = strdup(x);
if (!a[i])
goto fail;
@@ -171,7 +171,7 @@ char **strv_new_ap(const char *x, va_list ap) {
while ((s = va_arg(ap, const char*))) {
- if (s == (const char*) -1)
+ if (s == STRV_IGNORE)
continue;
a[i] = strdup(s);
@@ -638,6 +638,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;
@@ -700,6 +711,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;
@@ -712,7 +730,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);
@@ -723,11 +741,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;
@@ -803,13 +824,8 @@ char **strv_reverse(char **l) {
if (n <= 1)
return l;
- for (i = 0; i < n / 2; i++) {
- char *t;
-
- t = l[i];
- l[i] = l[n-1-i];
- l[n-1-i] = t;
- }
+ for (i = 0; i < n / 2; i++)
+ SWAP_TWO(l[i], l[n-1-i]);
return l;
}
@@ -838,7 +854,7 @@ bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
char* const* p;
STRV_FOREACH(p, patterns)
- if (fnmatch(*p, s, 0) == 0)
+ if (fnmatch(*p, s, flags) == 0)
return true;
return false;
@@ -880,7 +896,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/basic/strv.h b/src/basic/strv.h
index f61bbb5386..683ce83a2a 100644
--- a/src/basic/strv.h
+++ b/src/basic/strv.h
@@ -69,8 +69,10 @@ bool strv_equal(char **a, char **b);
char **strv_new(const char *x, ...) _sentinel_;
char **strv_new_ap(const char *x, va_list ap);
+#define STRV_IGNORE ((const char *) -1)
+
static inline const char* STRV_IFNOTNULL(const char *x) {
- return x ? x : (const char *) -1;
+ return x ? x : STRV_IGNORE;
}
static inline bool strv_isempty(char * const *l) {
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index 9521b79daa..df56d85317 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -50,6 +50,7 @@
#include "socket-util.h"
#include "stat-util.h"
#include "string-util.h"
+#include "strv.h"
#include "terminal-util.h"
#include "time-util.h"
#include "util.h"
@@ -154,14 +155,14 @@ int ask_char(char *ret, const char *replies, const char *text, ...) {
char c;
bool need_nl = true;
- if (on_tty())
+ if (colors_enabled())
fputs(ANSI_HIGHLIGHT, stdout);
va_start(ap, text);
vprintf(text, ap);
va_end(ap);
- if (on_tty())
+ if (colors_enabled())
fputs(ANSI_NORMAL, stdout);
fflush(stdout);
@@ -198,14 +199,14 @@ int ask_string(char **ret, const char *text, ...) {
char line[LINE_MAX];
va_list ap;
- if (on_tty())
+ if (colors_enabled())
fputs(ANSI_HIGHLIGHT, stdout);
va_start(ap, text);
vprintf(text, ap);
va_end(ap);
- if (on_tty())
+ if (colors_enabled())
fputs(ANSI_NORMAL, stdout);
fflush(stdout);
@@ -708,6 +709,64 @@ char *resolve_dev_console(char **active) {
return tty;
}
+int get_kernel_consoles(char ***consoles) {
+ _cleanup_strv_free_ char **con = NULL;
+ _cleanup_free_ char *line = NULL;
+ const char *active;
+ int r;
+
+ assert(consoles);
+
+ r = read_one_line_file("/sys/class/tty/console/active", &line);
+ if (r < 0)
+ return r;
+
+ active = line;
+ for (;;) {
+ _cleanup_free_ char *tty = NULL;
+ char *path;
+
+ r = extract_first_word(&active, &tty, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ if (streq(tty, "tty0")) {
+ tty = mfree(tty);
+ r = read_one_line_file("/sys/class/tty/tty0/active", &tty);
+ if (r < 0)
+ return r;
+ }
+
+ path = strappend("/dev/", tty);
+ if (!path)
+ return -ENOMEM;
+
+ if (access(path, F_OK) < 0) {
+ log_debug_errno(errno, "Console device %s is not accessible, skipping: %m", path);
+ free(path);
+ continue;
+ }
+
+ r = strv_consume(&con, path);
+ if (r < 0)
+ return r;
+ }
+
+ if (strv_isempty(con)) {
+ log_debug("No devices found for system console");
+
+ r = strv_extend(&con, "/dev/console");
+ if (r < 0)
+ return r;
+ }
+
+ *consoles = con;
+ con = NULL;
+ return 0;
+}
+
bool tty_is_vc_resolve(const char *tty) {
_cleanup_free_ char *active = NULL;
@@ -829,9 +888,7 @@ int make_stdio(int fd) {
/* Explicitly unset O_CLOEXEC, since if fd was < 3, then
* dup2() was a NOP and the bit hence possibly set. */
- fd_cloexec(STDIN_FILENO, false);
- fd_cloexec(STDOUT_FILENO, false);
- fd_cloexec(STDERR_FILENO, false);
+ stdio_unset_cloexec();
return 0;
}
@@ -1134,6 +1191,19 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
return receive_one_fd(pair[0], 0);
}
+bool terminal_is_dumb(void) {
+ const char *e;
+
+ if (!on_tty())
+ return true;
+
+ e = getenv("TERM");
+ if (!e)
+ return true;
+
+ return streq(e, "dumb");
+}
+
bool colors_enabled(void) {
static int enabled = -1;
@@ -1143,10 +1213,8 @@ bool colors_enabled(void) {
colors = getenv("SYSTEMD_COLORS");
if (colors)
enabled = parse_boolean(colors) != 0;
- else if (streq_ptr(getenv("TERM"), "dumb"))
- enabled = false;
else
- enabled = on_tty();
+ enabled = !terminal_is_dumb();
}
return enabled;
diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h
index a7c96a77cb..169ab772ff 100644
--- a/src/basic/terminal-util.h
+++ b/src/basic/terminal-util.h
@@ -62,6 +62,7 @@ int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
int vt_disallocate(const char *name);
char *resolve_dev_console(char **active);
+int get_kernel_consoles(char ***consoles);
bool tty_is_vc(const char *tty);
bool tty_is_vc_resolve(const char *tty);
bool tty_is_console(const char *tty) _pure_;
@@ -79,6 +80,7 @@ unsigned lines(void);
void columns_lines_cache_reset(int _unused_ signum);
bool on_tty(void);
+bool terminal_is_dumb(void);
bool colors_enabled(void);
static inline const char *ansi_underline(void) {
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index edd9179cb8..24e681bf85 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -87,6 +87,16 @@ dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
return ts;
}
+triple_timestamp* triple_timestamp_get(triple_timestamp *ts) {
+ assert(ts);
+
+ ts->realtime = now(CLOCK_REALTIME);
+ ts->monotonic = now(CLOCK_MONOTONIC);
+ ts->boottime = clock_boottime_supported() ? now(CLOCK_BOOTTIME) : USEC_INFINITY;
+
+ return ts;
+}
+
dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
int64_t delta;
assert(ts);
@@ -104,6 +114,24 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
return ts;
}
+triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u) {
+ int64_t delta;
+
+ assert(ts);
+
+ if (u == USEC_INFINITY || u <= 0) {
+ ts->realtime = ts->monotonic = ts->boottime = u;
+ return ts;
+ }
+
+ ts->realtime = u;
+ delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
+ ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta);
+ ts->boottime = clock_boottime_supported() ? usec_sub(now(CLOCK_BOOTTIME), delta) : USEC_INFINITY;
+
+ return ts;
+}
+
dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) {
int64_t delta;
assert(ts);
@@ -136,6 +164,26 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us
return ts;
}
+usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock) {
+
+ switch (clock) {
+
+ case CLOCK_REALTIME:
+ case CLOCK_REALTIME_ALARM:
+ return ts->realtime;
+
+ case CLOCK_MONOTONIC:
+ return ts->monotonic;
+
+ case CLOCK_BOOTTIME:
+ case CLOCK_BOOTTIME_ALARM:
+ return ts->boottime;
+
+ default:
+ return USEC_INFINITY;
+ }
+}
+
usec_t timespec_load(const struct timespec *ts) {
assert(ts);
@@ -1107,6 +1155,30 @@ clockid_t clock_boottime_or_monotonic(void) {
return CLOCK_MONOTONIC;
}
+bool clock_supported(clockid_t clock) {
+ struct timespec ts;
+
+ switch (clock) {
+
+ case CLOCK_MONOTONIC:
+ case CLOCK_REALTIME:
+ return true;
+
+ case CLOCK_BOOTTIME:
+ return clock_boottime_supported();
+
+ case CLOCK_BOOTTIME_ALARM:
+ if (!clock_boottime_supported())
+ return false;
+
+ /* fall through, after checking the cached value for CLOCK_BOOTTIME. */
+
+ default:
+ /* For everything else, check properly */
+ return clock_gettime(clock, &ts) >= 0;
+ }
+}
+
int get_timezone(char **tz) {
_cleanup_free_ char *t = NULL;
const char *e;
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index a5e3f567ec..1b058f0e49 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -39,6 +39,12 @@ typedef struct dual_timestamp {
usec_t monotonic;
} dual_timestamp;
+typedef struct triple_timestamp {
+ usec_t realtime;
+ usec_t monotonic;
+ usec_t boottime;
+} triple_timestamp;
+
#define USEC_INFINITY ((usec_t) -1)
#define NSEC_INFINITY ((nsec_t) -1)
@@ -69,7 +75,8 @@ typedef struct dual_timestamp {
#define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
-#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL })
+#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) {})
+#define TRIPLE_TIMESTAMP_NULL ((struct triple_timestamp) {})
usec_t now(clockid_t clock);
nsec_t now_nsec(clockid_t clock);
@@ -79,11 +86,28 @@ 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);
+triple_timestamp* triple_timestamp_get(triple_timestamp *ts);
+triple_timestamp* triple_timestamp_from_realtime(triple_timestamp *ts, usec_t u);
+
+#define DUAL_TIMESTAMP_HAS_CLOCK(clock) \
+ IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC)
+
+#define TRIPLE_TIMESTAMP_HAS_CLOCK(clock) \
+ IN_SET(clock, CLOCK_REALTIME, CLOCK_REALTIME_ALARM, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM)
+
static inline bool dual_timestamp_is_set(dual_timestamp *ts) {
return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) ||
(ts->monotonic > 0 && ts->monotonic != USEC_INFINITY));
}
+static inline bool triple_timestamp_is_set(triple_timestamp *ts) {
+ return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) ||
+ (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY) ||
+ (ts->boottime > 0 && ts->boottime != USEC_INFINITY));
+}
+
+usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock);
+
usec_t timespec_load(const struct timespec *ts) _pure_;
struct timespec *timespec_store(struct timespec *ts, usec_t u);
@@ -113,6 +137,7 @@ int get_timezones(char ***l);
bool timezone_is_valid(const char *name);
bool clock_boottime_supported(void);
+bool clock_supported(clockid_t clock);
clockid_t clock_boottime_or_monotonic(void);
#define xstrftime(buf, fmt, tm) \
diff --git a/src/basic/unaligned.h b/src/basic/unaligned.h
index 79be645bed..7c847a3ccb 100644
--- a/src/basic/unaligned.h
+++ b/src/basic/unaligned.h
@@ -109,3 +109,21 @@ static inline void unaligned_write_le64(void *_u, uint64_t a) {
unaligned_write_le32(u, (uint32_t) a);
unaligned_write_le32(u + 4, (uint32_t) (a >> 32));
}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define unaligned_read_ne16 unaligned_read_be16
+#define unaligned_read_ne32 unaligned_read_be32
+#define unaligned_read_ne64 unaligned_read_be64
+
+#define unaligned_write_ne16 unaligned_write_be16
+#define unaligned_write_ne32 unaligned_write_be32
+#define unaligned_write_ne64 unaligned_write_be64
+#else
+#define unaligned_read_ne16 unaligned_read_le16
+#define unaligned_read_ne32 unaligned_read_le32
+#define unaligned_read_ne64 unaligned_read_le64
+
+#define unaligned_write_ne16 unaligned_write_le16
+#define unaligned_write_ne32 unaligned_write_le32
+#define unaligned_write_ne64 unaligned_write_le64
+#endif
diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h
index f209a84634..44eadf0347 100644
--- a/src/basic/unit-name.h
+++ b/src/basic/unit-name.h
@@ -195,7 +195,6 @@ typedef enum SwapState {
_SWAP_STATE_INVALID = -1
} SwapState;
-
typedef enum TargetState {
TARGET_DEAD,
TARGET_ACTIVE,
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index f65ca3edaa..e9d668ddfc 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -458,7 +458,7 @@ int take_etc_passwd_lock(const char *root) {
*
* Note that shadow-utils also takes per-database locks in
* addition to lckpwdf(). However, we don't given that they
- * are redundant as they they invoke lckpwdf() first and keep
+ * are redundant as they invoke lckpwdf() first and keep
* it during everything they do. The per-database locks are
* awfully racy, and thus we just won't do them. */
diff --git a/src/basic/util.c b/src/basic/util.c
index 756c663be4..9d66d28eb7 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -36,6 +36,7 @@
#include "alloc-util.h"
#include "build.h"
+#include "cgroup-util.h"
#include "def.h"
#include "dirent-util.h"
#include "fd-util.h"
@@ -64,6 +65,7 @@ assert_cc(EAGAIN == EWOULDBLOCK);
int saved_argc = 0;
char **saved_argv = NULL;
+static int saved_in_initrd = -1;
size_t page_size(void) {
static thread_local size_t pgsz = 0;
@@ -454,11 +456,10 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
}
bool in_initrd(void) {
- static int saved = -1;
struct statfs s;
- if (saved >= 0)
- return saved;
+ if (saved_in_initrd >= 0)
+ return saved_in_initrd;
/* We make two checks here:
*
@@ -470,11 +471,15 @@ bool in_initrd(void) {
* emptying when transititioning to the main systemd.
*/
- saved = access("/etc/initrd-release", F_OK) >= 0 &&
- statfs("/", &s) >= 0 &&
- is_temporary_fs(&s);
+ saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 &&
+ statfs("/", &s) >= 0 &&
+ is_temporary_fs(&s);
- return saved;
+ return saved_in_initrd;
+}
+
+void in_initrd_force(bool value) {
+ saved_in_initrd = value;
}
/* hey glibc, APIs with callbacks without a user pointer are so useless */
@@ -576,47 +581,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;
@@ -767,15 +731,119 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
}
uint64_t physical_memory(void) {
- long mem;
+ _cleanup_free_ char *root = NULL, *value = NULL;
+ uint64_t mem, lim;
+ size_t ps;
+ long sc;
+
+ /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
+ * memory.
+ *
+ * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
+ * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
+
+ sc = sysconf(_SC_PHYS_PAGES);
+ assert(sc > 0);
+
+ ps = page_size();
+ mem = (uint64_t) sc * (uint64_t) ps;
+
+ if (cg_get_root_path(&root) < 0)
+ return mem;
+
+ if (cg_get_attribute("memory", root, "memory.limit_in_bytes", &value))
+ return mem;
+
+ if (safe_atou64(value, &lim) < 0)
+ return mem;
+
+ /* Make sure the limit is a multiple of our own page size */
+ lim /= ps;
+ lim *= ps;
+
+ return MIN(mem, lim);
+}
+
+uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
+ uint64_t p, m, ps, r;
+
+ assert(max > 0);
+
+ /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
+ * the result is a multiple of the page size (rounds down). */
+
+ ps = page_size();
+ assert(ps > 0);
+
+ p = physical_memory() / ps;
+ assert(p > 0);
+
+ m = p * v;
+ if (m / p != v)
+ return UINT64_MAX;
+
+ m /= max;
+
+ r = m * ps;
+ if (r / ps != m)
+ return UINT64_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. */
- /* We return this as uint64_t in case we are running as 32bit
- * process on a 64bit kernel with huge amounts of memory */
+ t = system_tasks_max();
+ assert(t > 0);
- mem = sysconf(_SC_PHYS_PAGES);
- assert(mem > 0);
+ m = t * v;
+ if (m / t != v) /* overflow? */
+ return UINT64_MAX;
- return (uint64_t) mem * (uint64_t) page_size();
+ return m / max;
}
int update_reboot_parameter_and_warn(const char *param) {
diff --git a/src/basic/util.h b/src/basic/util.h
index 1c032c15c9..44497dcd78 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -86,6 +86,7 @@ int prot_from_flags(int flags) _const_;
int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...);
bool in_initrd(void);
+void in_initrd_force(bool value);
void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
int (*compar) (const void *, const void *, void *),
@@ -175,14 +176,16 @@ 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);
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
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);