summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/barrier.c1
-rw-r--r--src/basic/bitmap.c12
-rw-r--r--src/basic/btrfs-util.c7
-rw-r--r--src/basic/capability-util.c71
-rw-r--r--src/basic/capability-util.h15
-rw-r--r--src/basic/cgroup-util.c9
-rw-r--r--src/basic/clock-util.c18
-rw-r--r--src/basic/clock-util.h1
-rw-r--r--src/basic/conf-files.c22
-rw-r--r--src/basic/errno-list.c5
-rw-r--r--src/basic/escape.c57
-rw-r--r--src/basic/escape.h4
-rw-r--r--src/basic/extract-word.c11
-rw-r--r--src/basic/fd-util.h4
-rw-r--r--src/basic/fileio.c33
-rw-r--r--src/basic/fileio.h2
-rw-r--r--src/basic/fs-util.c5
-rw-r--r--src/basic/glob-util.c4
-rw-r--r--src/basic/hash-funcs.c83
-rw-r--r--src/basic/hash-funcs.h67
-rw-r--r--src/basic/hashmap.c61
-rw-r--r--src/basic/hashmap.h43
-rw-r--r--src/basic/hexdecoct.c61
-rw-r--r--src/basic/hexdecoct.h5
-rw-r--r--src/basic/in-addr-util.c4
-rw-r--r--src/basic/in-addr-util.h5
-rw-r--r--src/basic/io-util.h18
-rw-r--r--src/basic/json.c6
-rw-r--r--src/basic/log.c93
-rw-r--r--src/basic/log.h10
-rw-r--r--src/basic/macro.h53
-rw-r--r--src/basic/missing.h45
-rw-r--r--src/basic/nss-util.h2
-rw-r--r--src/basic/ordered-set.c64
-rw-r--r--src/basic/ordered-set.h6
-rw-r--r--src/basic/parse-util.c22
-rw-r--r--src/basic/path-util.c2
-rw-r--r--src/basic/process-util.c32
-rw-r--r--src/basic/process-util.h3
-rw-r--r--src/basic/random-util.c15
-rw-r--r--src/basic/rlimit-util.c200
-rw-r--r--src/basic/rlimit-util.h5
-rw-r--r--src/basic/rm-rf.c2
-rw-r--r--src/basic/signal-util.c5
-rw-r--r--src/basic/signal-util.h11
-rw-r--r--src/basic/siphash24.h2
-rw-r--r--src/basic/socket-label.c6
-rw-r--r--src/basic/socket-util.c4
-rw-r--r--src/basic/socket-util.h4
-rw-r--r--src/basic/string-table.h18
-rw-r--r--src/basic/string-util.c66
-rw-r--r--src/basic/string-util.h7
-rw-r--r--src/basic/strv.c20
-rw-r--r--src/basic/strv.h2
-rw-r--r--src/basic/terminal-util.c21
-rw-r--r--src/basic/terminal-util.h17
-rw-r--r--src/basic/time-util.h15
-rw-r--r--src/basic/unit-name.c45
-rw-r--r--src/basic/user-util.c2
-rw-r--r--src/basic/utf8.c48
-rw-r--r--src/basic/utf8.h14
-rw-r--r--src/basic/util.c2
-rw-r--r--src/basic/verbs.c6
-rw-r--r--src/basic/verbs.h3
64 files changed, 1169 insertions, 337 deletions
diff --git a/src/basic/barrier.c b/src/basic/barrier.c
index 9a78a80eb2..26ae123341 100644
--- a/src/basic/barrier.c
+++ b/src/basic/barrier.c
@@ -197,6 +197,7 @@ static bool barrier_write(Barrier *b, uint64_t buf) {
if (barrier_i_aborted(b))
return false;
+ assert(b->me >= 0);
do {
len = write(b->me, &buf, sizeof(buf));
} while (len < 0 && IN_SET(errno, EAGAIN, EINTR));
diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c
index 95f59e400a..50078822a7 100644
--- a/src/basic/bitmap.c
+++ b/src/basic/bitmap.c
@@ -140,7 +140,8 @@ bool bitmap_isset(Bitmap *b, unsigned n) {
bool bitmap_isclear(Bitmap *b) {
unsigned i;
- assert(b);
+ if (!b)
+ return true;
for (i = 0; i < b->n_bitmaps; i++)
if (b->bitmaps[i] != 0)
@@ -150,7 +151,9 @@ bool bitmap_isclear(Bitmap *b) {
}
void bitmap_clear(Bitmap *b) {
- assert(b);
+
+ if (!b)
+ return;
b->bitmaps = mfree(b->bitmaps);
b->n_bitmaps = 0;
@@ -197,7 +200,10 @@ bool bitmap_equal(Bitmap *a, Bitmap *b) {
Bitmap *c;
unsigned i;
- if (!a ^ !b)
+ if (a == b)
+ return true;
+
+ if (!a != !b)
return false;
if (!a)
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index acd48f6954..03c7609c92 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -43,6 +43,7 @@
#include "copy.h"
#include "fd-util.h"
#include "fileio.h"
+#include "io-util.h"
#include "macro.h"
#include "missing.h"
#include "path-util.h"
@@ -913,6 +914,10 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) {
dev_t dev = 0;
int r;
+ /* In contrast to btrfs quota ioctls ftruncate() cannot make sense of "infinity" or file sizes > 2^31 */
+ if (!FILE_SIZE_VALID(new_size))
+ return -EINVAL;
+
/* btrfs cannot handle file systems < 16M, hence use this as minimum */
if (new_size < 16*1024*1024)
new_size = 16*1024*1024;
@@ -2051,7 +2056,7 @@ int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) {
args.key.nr_items = 256;
if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0)
- return -errno;
+ return negative_errno();
if (args.key.nr_items <= 0)
break;
diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c
index fef722b6f2..49c2d61afe 100644
--- a/src/basic/capability-util.c
+++ b/src/basic/capability-util.c
@@ -96,7 +96,62 @@ unsigned long cap_last_cap(void) {
return p;
}
-int capability_bounding_set_drop(uint64_t drop, bool right_now) {
+int capability_update_inherited_set(cap_t caps, uint64_t set) {
+ unsigned long i;
+
+ /* Add capabilities in the set to the inherited caps. Do not apply
+ * them yet. */
+
+ for (i = 0; i < cap_last_cap(); i++) {
+
+ if (set & (UINT64_C(1) << i)) {
+ cap_value_t v;
+
+ v = (cap_value_t) i;
+
+ /* Make the capability inheritable. */
+ if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, CAP_SET) < 0)
+ return -errno;
+ }
+ }
+
+ return 0;
+}
+
+int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
+ unsigned long i;
+ _cleanup_cap_free_ cap_t caps = NULL;
+
+ /* Add the capabilities to the ambient set. */
+
+ if (also_inherit) {
+ int r;
+ caps = cap_get_proc();
+ if (!caps)
+ return -errno;
+
+ r = capability_update_inherited_set(caps, set);
+ if (r < 0)
+ return -errno;
+
+ if (cap_set_proc(caps) < 0)
+ return -errno;
+ }
+
+ for (i = 0; i < cap_last_cap(); i++) {
+
+ if (set & (UINT64_C(1) << i)) {
+
+ /* Add the capability to the ambient set. */
+ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0)
+ return -errno;
+ }
+ }
+
+ return 0;
+}
+
+int capability_bounding_set_drop(uint64_t keep, bool right_now) {
_cleanup_cap_free_ cap_t after_cap = NULL;
cap_flag_value_t fv;
unsigned long i;
@@ -137,7 +192,7 @@ int capability_bounding_set_drop(uint64_t drop, bool right_now) {
for (i = 0; i <= cap_last_cap(); i++) {
- if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
+ if (!(keep & (UINT64_C(1) << i))) {
cap_value_t v;
/* Drop it from the bounding set */
@@ -176,7 +231,7 @@ finish:
return r;
}
-static int drop_from_file(const char *fn, uint64_t drop) {
+static int drop_from_file(const char *fn, uint64_t keep) {
int r, k;
uint32_t hi, lo;
uint64_t current, after;
@@ -196,7 +251,7 @@ static int drop_from_file(const char *fn, uint64_t drop) {
return -EIO;
current = (uint64_t) lo | ((uint64_t) hi << 32ULL);
- after = current & ~drop;
+ after = current & keep;
if (current == after)
return 0;
@@ -213,14 +268,14 @@ static int drop_from_file(const char *fn, uint64_t drop) {
return r;
}
-int capability_bounding_set_drop_usermode(uint64_t drop) {
+int capability_bounding_set_drop_usermode(uint64_t keep) {
int r;
- r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", drop);
+ r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", keep);
if (r < 0)
return r;
- r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", drop);
+ r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", keep);
if (r < 0)
return r;
@@ -257,7 +312,7 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
return log_error_errno(errno, "Failed to disable keep capabilities flag: %m");
/* Drop all caps from the bounding set, except the ones we want */
- r = capability_bounding_set_drop(~keep_capabilities, true);
+ r = capability_bounding_set_drop(keep_capabilities, true);
if (r < 0)
return log_error_errno(r, "Failed to drop capabilities: %m");
diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h
index 6bbf7318fd..be41475441 100644
--- a/src/basic/capability-util.h
+++ b/src/basic/capability-util.h
@@ -29,10 +29,15 @@
#include "macro.h"
#include "util.h"
+#define CAP_ALL (uint64_t) -1
+
unsigned long cap_last_cap(void);
int have_effective_cap(int value);
-int capability_bounding_set_drop(uint64_t drop, bool right_now);
-int capability_bounding_set_drop_usermode(uint64_t drop);
+int capability_bounding_set_drop(uint64_t keep, bool right_now);
+int capability_bounding_set_drop_usermode(uint64_t keep);
+
+int capability_ambient_set_apply(uint64_t set, bool also_inherit);
+int capability_update_inherited_set(cap_t caps, uint64_t ambient_set);
int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities);
@@ -46,3 +51,9 @@ static inline void cap_free_charpp(char **p) {
cap_free(*p);
}
#define _cleanup_cap_free_charp_ _cleanup_(cap_free_charpp)
+
+static inline bool cap_test_all(uint64_t caps) {
+ uint64_t m;
+ m = (UINT64_C(1) << (cap_last_cap() + 1)) - 1;
+ return (caps & m) == m;
+}
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 639f9f3db1..f873fb89d3 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -53,6 +53,7 @@
#include "set.h"
#include "special.h"
#include "stat-util.h"
+#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
#include "unit-name.h"
@@ -92,7 +93,7 @@ int cg_read_pid(FILE *f, pid_t *_pid) {
if (feof(f))
return 0;
- return errno ? -errno : -EIO;
+ return errno > 0 ? -errno : -EIO;
}
if (ul <= 0)
@@ -647,7 +648,7 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) {
if (errno == ENOENT)
r = 0;
- else if (errno != 0)
+ else if (errno > 0)
r = -errno;
else
r = -EIO;
@@ -716,7 +717,7 @@ int cg_attach(const char *controller, const char *path, pid_t pid) {
if (pid == 0)
pid = getpid();
- snprintf(c, sizeof(c), PID_FMT"\n", pid);
+ xsprintf(c, PID_FMT "\n", pid);
return write_string_file(fs, c, 0);
}
@@ -2090,7 +2091,7 @@ int cg_kernel_controllers(Set *controllers) {
if (feof(f))
break;
- if (ferror(f) && errno != 0)
+ if (ferror(f) && errno > 0)
return -errno;
return -EBADMSG;
diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c
index 00f549c023..c64b2e5e8c 100644
--- a/src/basic/clock-util.c
+++ b/src/basic/clock-util.c
@@ -33,6 +33,7 @@
#include "fd-util.h"
#include "macro.h"
#include "string-util.h"
+#include "util.h"
int clock_get_hwclock(struct tm *tm) {
_cleanup_close_ int fd = -1;
@@ -121,7 +122,8 @@ int clock_set_timezone(int *min) {
* have read from the RTC.
*/
if (settimeofday(tv_null, &tz) < 0)
- return -errno;
+ return negative_errno();
+
if (min)
*min = minutesdelta;
return 0;
@@ -144,3 +146,17 @@ int clock_reset_timewarp(void) {
return 0;
}
+
+#define TIME_EPOCH_USEC ((usec_t) TIME_EPOCH * USEC_PER_SEC)
+
+int clock_apply_epoch(void) {
+ struct timespec ts;
+
+ if (now(CLOCK_REALTIME) >= TIME_EPOCH_USEC)
+ return 0;
+
+ if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, TIME_EPOCH_USEC)) < 0)
+ return -errno;
+
+ return 1;
+}
diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h
index fef2d471a6..09d46758f4 100644
--- a/src/basic/clock-util.h
+++ b/src/basic/clock-util.h
@@ -28,3 +28,4 @@ int clock_set_timezone(int *min);
int clock_reset_timewarp(void);
int clock_get_hwclock(struct tm *tm);
int clock_set_hwclock(const struct tm *tm);
+int clock_apply_epoch(void);
diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c
index 75dad228e3..5854caeb51 100644
--- a/src/basic/conf-files.c
+++ b/src/basic/conf-files.c
@@ -41,6 +41,7 @@
static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) {
_cleanup_closedir_ DIR *dir = NULL;
const char *dirpath;
+ struct dirent *de;
int r;
assert(path);
@@ -55,18 +56,9 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char
return -errno;
}
- for (;;) {
- struct dirent *de;
+ FOREACH_DIRENT(de, dir, return -errno) {
char *p;
- errno = 0;
- de = readdir(dir);
- if (!de && errno != 0)
- return -errno;
-
- if (!de)
- break;
-
if (!dirent_is_file_with_suffix(de, suffix))
continue;
@@ -116,17 +108,15 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const
STRV_FOREACH(p, dirs) {
r = files_add(fh, root, *p, suffix);
- if (r == -ENOMEM) {
+ if (r == -ENOMEM)
return r;
- } else if (r < 0)
- log_debug_errno(r, "Failed to search for files in %s: %m",
- *p);
+ if (r < 0)
+ log_debug_errno(r, "Failed to search for files in %s, ignoring: %m", *p);
}
files = hashmap_get_strv(fh);
- if (files == NULL) {
+ if (!files)
return -ENOMEM;
- }
qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp);
*strv = files;
diff --git a/src/basic/errno-list.c b/src/basic/errno-list.c
index 0a66902ac9..b4d080103b 100644
--- a/src/basic/errno-list.c
+++ b/src/basic/errno-list.c
@@ -25,7 +25,7 @@
#include "macro.h"
static const struct errno_name* lookup_errno(register const char *str,
- register unsigned int len);
+ register unsigned int len);
#include "errno-from-name.h"
#include "errno-to-name.h"
@@ -48,8 +48,9 @@ int errno_from_name(const char *name) {
sc = lookup_errno(name, strlen(name));
if (!sc)
- return 0;
+ return -EINVAL;
+ assert(sc->id > 0);
return sc->id;
}
diff --git a/src/basic/escape.c b/src/basic/escape.c
index ab282efa3c..f276c36c56 100644
--- a/src/basic/escape.c
+++ b/src/basic/escape.c
@@ -119,16 +119,18 @@ char *cescape(const char *s) {
return cescape_length(s, strlen(s));
}
-int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
+int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) {
int r = 1;
assert(p);
assert(*p);
assert(ret);
- /* Unescapes C style. Returns the unescaped character in ret,
- * unless we encountered a \u sequence in which case the full
- * unicode character is returned in ret_unicode, instead. */
+ /* Unescapes C style. Returns the unescaped character in ret.
+ * Sets *eight_bit to true if the escaped sequence either fits in
+ * one byte in UTF-8 or is a non-unicode literal byte and should
+ * instead be copied directly.
+ */
if (length != (size_t) -1 && length < 1)
return -EINVAL;
@@ -190,7 +192,8 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode
if (a == 0 && b == 0)
return -EINVAL;
- *ret = (char) ((a << 4U) | b);
+ *ret = (a << 4U) | b;
+ *eight_bit = true;
r = 3;
break;
}
@@ -217,16 +220,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode
if (c == 0)
return -EINVAL;
- if (c < 128)
- *ret = c;
- else {
- if (!ret_unicode)
- return -EINVAL;
-
- *ret = 0;
- *ret_unicode = c;
- }
-
+ *ret = c;
r = 5;
break;
}
@@ -236,7 +230,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode
int a[8];
unsigned i;
- uint32_t c;
+ char32_t c;
if (length != (size_t) -1 && length < 9)
return -EINVAL;
@@ -258,16 +252,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode
if (!unichar_is_valid(c))
return -EINVAL;
- if (c < 128)
- *ret = c;
- else {
- if (!ret_unicode)
- return -EINVAL;
-
- *ret = 0;
- *ret_unicode = c;
- }
-
+ *ret = c;
r = 9;
break;
}
@@ -282,7 +267,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode
case '7': {
/* octal encoding */
int a, b, c;
- uint32_t m;
+ char32_t m;
if (length != (size_t) -1 && length < 3)
return -EINVAL;
@@ -309,6 +294,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode
return -EINVAL;
*ret = m;
+ *eight_bit = true;
r = 3;
break;
}
@@ -341,8 +327,8 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
for (f = s, t = r + pl; f < s + length; f++) {
size_t remaining;
- uint32_t u;
- char c;
+ bool eight_bit = false;
+ char32_t u;
int k;
remaining = s + length - f;
@@ -365,7 +351,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
return -EINVAL;
}
- k = cunescape_one(f + 1, remaining - 1, &c, &u);
+ k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit);
if (k < 0) {
if (flags & UNESCAPE_RELAX) {
/* Invalid escape code, let's take it literal then */
@@ -377,14 +363,13 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
return k;
}
- if (c != 0)
- /* Non-Unicode? Let's encode this directly */
- *(t++) = c;
+ f += k;
+ if (eight_bit)
+ /* One byte? Set directly as specified */
+ *(t++) = u;
else
- /* Unicode? Then let's encode this in UTF-8 */
+ /* Otherwise encode as multi-byte UTF-8 */
t += utf8_encode_unichar(t, u);
-
- f += k;
}
*t = 0;
diff --git a/src/basic/escape.h b/src/basic/escape.h
index c710f01743..ac8f5f3910 100644
--- a/src/basic/escape.h
+++ b/src/basic/escape.h
@@ -25,8 +25,10 @@
#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
+#include <uchar.h>
#include "string-util.h"
+#include "missing.h"
/* What characters are special in the shell? */
/* must be escaped outside and inside double-quotes */
@@ -45,7 +47,7 @@ size_t cescape_char(char c, char *buf);
int cunescape(const char *s, UnescapeFlags flags, char **ret);
int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret);
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
-int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode);
+int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit);
char *xescape(const char *s, const char *bad);
diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c
index 7cc2a1de13..6dcd4f9f5b 100644
--- a/src/basic/extract-word.c
+++ b/src/basic/extract-word.c
@@ -107,9 +107,10 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
}
if (flags & EXTRACT_CUNESCAPE) {
- uint32_t u;
+ bool eight_bit = false;
+ char32_t u;
- r = cunescape_one(*p, (size_t) -1, &c, &u);
+ r = cunescape_one(*p, (size_t) -1, &u, &eight_bit);
if (r < 0) {
if (flags & EXTRACT_CUNESCAPE_RELAX) {
s[sz++] = '\\';
@@ -119,10 +120,10 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
} else {
(*p) += r - 1;
- if (c != 0)
- s[sz++] = c; /* normal explicit char */
+ if (eight_bit)
+ s[sz++] = u;
else
- sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
+ sz += utf8_encode_unichar(s + sz, u);
}
} else
s[sz++] = c;
diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h
index 5ce1592eeb..20890e3279 100644
--- a/src/basic/fd-util.h
+++ b/src/basic/fd-util.h
@@ -73,3 +73,7 @@ int same_fd(int a, int b);
void cmsg_close_all(struct msghdr *mh);
bool fdname_is_valid(const char *s);
+
+/* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */
+#define ERRNO_IS_DISCONNECT(r) \
+ IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH)
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 3a237252b5..3ff70310e1 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -165,7 +165,7 @@ int read_one_line_file(const char *fn, char **line) {
if (!fgets(t, sizeof(t), f)) {
if (ferror(f))
- return errno ? -errno : -EIO;
+ return errno > 0 ? -errno : -EIO;
t[0] = 0;
}
@@ -1064,7 +1064,7 @@ int fflush_and_check(FILE *f) {
fflush(f);
if (ferror(f))
- return errno ? -errno : -EIO;
+ return errno > 0 ? -errno : -EIO;
return 0;
}
@@ -1251,3 +1251,32 @@ int read_timestamp_file(const char *fn, usec_t *ret) {
*ret = (usec_t) t;
return 0;
}
+
+int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
+ int r;
+
+ assert(s);
+
+ /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
+ * when specified shall initially point to a boolean variable initialized to false. It is set to true after the
+ * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
+ * element, but not before the first one. */
+
+ if (!f)
+ f = stdout;
+
+ if (space) {
+ if (!separator)
+ separator = " ";
+
+ if (*space) {
+ r = fputs(separator, f);
+ if (r < 0)
+ return r;
+ }
+
+ *space = true;
+ }
+
+ return fputs(s, f);
+}
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 95e8698941..9e09574133 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -82,3 +82,5 @@ int tempfn_random_child(const char *p, const char *extra, char **ret);
int write_timestamp_file_atomic(const char *fn, usec_t n);
int read_timestamp_file(const char *fn, usec_t *ret);
+
+int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index fb760abe18..61b651b573 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -341,7 +341,8 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
if (parents)
mkdir_parents(path, 0755);
- fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
+ fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY,
+ (mode == 0 || mode == MODE_INVALID) ? 0644 : mode);
if (fd < 0)
return -errno;
@@ -481,7 +482,7 @@ int get_files_in_directory(const char *path, char ***list) {
errno = 0;
de = readdir(d);
- if (!de && errno != 0)
+ if (!de && errno > 0)
return -errno;
if (!de)
break;
diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c
index a0be0efd40..811ab6ec36 100644
--- a/src/basic/glob-util.c
+++ b/src/basic/glob-util.c
@@ -40,7 +40,7 @@ int glob_exists(const char *path) {
if (k == GLOB_NOSPACE)
return -ENOMEM;
if (k != 0)
- return errno ? -errno : -EIO;
+ return errno > 0 ? -errno : -EIO;
return !strv_isempty(g.gl_pathv);
}
@@ -58,7 +58,7 @@ int glob_extend(char ***strv, const char *path) {
if (k == GLOB_NOSPACE)
return -ENOMEM;
if (k != 0)
- return errno ? -errno : -EIO;
+ return errno > 0 ? -errno : -EIO;
if (strv_isempty(g.gl_pathv))
return -ENOENT;
diff --git a/src/basic/hash-funcs.c b/src/basic/hash-funcs.c
new file mode 100644
index 0000000000..d4affaffee
--- /dev/null
+++ b/src/basic/hash-funcs.c
@@ -0,0 +1,83 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+ Copyright 2014 Michal Schmidt
+
+ 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 "hash-funcs.h"
+
+void string_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(p, strlen(p) + 1, state);
+}
+
+int string_compare_func(const void *a, const void *b) {
+ return strcmp(a, b);
+}
+
+const struct hash_ops string_hash_ops = {
+ .hash = string_hash_func,
+ .compare = string_compare_func
+};
+
+void trivial_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(&p, sizeof(p), state);
+}
+
+int trivial_compare_func(const void *a, const void *b) {
+ return a < b ? -1 : (a > b ? 1 : 0);
+}
+
+const struct hash_ops trivial_hash_ops = {
+ .hash = trivial_hash_func,
+ .compare = trivial_compare_func
+};
+
+void uint64_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(p, sizeof(uint64_t), state);
+}
+
+int uint64_compare_func(const void *_a, const void *_b) {
+ uint64_t a, b;
+ a = *(const uint64_t*) _a;
+ b = *(const uint64_t*) _b;
+ return a < b ? -1 : (a > b ? 1 : 0);
+}
+
+const struct hash_ops uint64_hash_ops = {
+ .hash = uint64_hash_func,
+ .compare = uint64_compare_func
+};
+
+#if SIZEOF_DEV_T != 8
+void devt_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(p, sizeof(dev_t), state);
+}
+
+int devt_compare_func(const void *_a, const void *_b) {
+ dev_t a, b;
+ a = *(const dev_t*) _a;
+ b = *(const dev_t*) _b;
+ return a < b ? -1 : (a > b ? 1 : 0);
+}
+
+const struct hash_ops devt_hash_ops = {
+ .hash = devt_hash_func,
+ .compare = devt_compare_func
+};
+#endif
diff --git a/src/basic/hash-funcs.h b/src/basic/hash-funcs.h
new file mode 100644
index 0000000000..c640eaf4d1
--- /dev/null
+++ b/src/basic/hash-funcs.h
@@ -0,0 +1,67 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+ Copyright 2014 Michal Schmidt
+
+ 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 "macro.h"
+#include "siphash24.h"
+
+typedef void (*hash_func_t)(const void *p, struct siphash *state);
+typedef int (*compare_func_t)(const void *a, const void *b);
+
+struct hash_ops {
+ hash_func_t hash;
+ compare_func_t compare;
+};
+
+void string_hash_func(const void *p, struct siphash *state);
+int string_compare_func(const void *a, const void *b) _pure_;
+extern const struct hash_ops string_hash_ops;
+
+/* This will compare the passed pointers directly, and will not
+ * dereference them. This is hence not useful for strings or
+ * suchlike. */
+void trivial_hash_func(const void *p, struct siphash *state);
+int trivial_compare_func(const void *a, const void *b) _const_;
+extern const struct hash_ops trivial_hash_ops;
+
+/* 32bit values we can always just embed in the pointer itself, but
+ * in order to support 32bit archs we need store 64bit values
+ * indirectly, since they don't fit in a pointer. */
+void uint64_hash_func(const void *p, struct siphash *state);
+int uint64_compare_func(const void *a, const void *b) _pure_;
+extern const struct hash_ops uint64_hash_ops;
+
+/* On some archs dev_t is 32bit, and on others 64bit. And sometimes
+ * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */
+#if SIZEOF_DEV_T != 8
+void devt_hash_func(const void *p, struct siphash *state) _pure_;
+int devt_compare_func(const void *a, const void *b) _pure_;
+extern const struct hash_ops devt_hash_ops = {
+ .hash = devt_hash_func,
+ .compare = devt_compare_func
+};
+#else
+#define devt_hash_func uint64_hash_func
+#define devt_compare_func uint64_compare_func
+#define devt_hash_ops uint64_hash_ops
+#endif
diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c
index b3954e3223..dcd8ae412d 100644
--- a/src/basic/hashmap.c
+++ b/src/basic/hashmap.c
@@ -37,6 +37,7 @@
#include "util.h"
#ifdef ENABLE_DEBUG_HASHMAP
+#include <pthread.h>
#include "list.h"
#endif
@@ -279,66 +280,6 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
},
};
-void string_hash_func(const void *p, struct siphash *state) {
- siphash24_compress(p, strlen(p) + 1, state);
-}
-
-int string_compare_func(const void *a, const void *b) {
- return strcmp(a, b);
-}
-
-const struct hash_ops string_hash_ops = {
- .hash = string_hash_func,
- .compare = string_compare_func
-};
-
-void trivial_hash_func(const void *p, struct siphash *state) {
- siphash24_compress(&p, sizeof(p), state);
-}
-
-int trivial_compare_func(const void *a, const void *b) {
- return a < b ? -1 : (a > b ? 1 : 0);
-}
-
-const struct hash_ops trivial_hash_ops = {
- .hash = trivial_hash_func,
- .compare = trivial_compare_func
-};
-
-void uint64_hash_func(const void *p, struct siphash *state) {
- siphash24_compress(p, sizeof(uint64_t), state);
-}
-
-int uint64_compare_func(const void *_a, const void *_b) {
- uint64_t a, b;
- a = *(const uint64_t*) _a;
- b = *(const uint64_t*) _b;
- return a < b ? -1 : (a > b ? 1 : 0);
-}
-
-const struct hash_ops uint64_hash_ops = {
- .hash = uint64_hash_func,
- .compare = uint64_compare_func
-};
-
-#if SIZEOF_DEV_T != 8
-void devt_hash_func(const void *p, struct siphash *state) {
- siphash24_compress(p, sizeof(dev_t), state);
-}
-
-int devt_compare_func(const void *_a, const void *_b) {
- dev_t a, b;
- a = *(const dev_t*) _a;
- b = *(const dev_t*) _b;
- return a < b ? -1 : (a > b ? 1 : 0);
-}
-
-const struct hash_ops devt_hash_ops = {
- .hash = devt_hash_func,
- .compare = devt_compare_func
-};
-#endif
-
static unsigned n_buckets(HashmapBase *h) {
return h->has_indirect ? h->indirect.n_buckets
: hashmap_type_info[h->type].n_direct_buckets;
diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h
index 708811124b..fdba9c61ff 100644
--- a/src/basic/hashmap.h
+++ b/src/basic/hashmap.h
@@ -26,8 +26,8 @@
#include <stdbool.h>
#include <stddef.h>
+#include "hash-funcs.h"
#include "macro.h"
-#include "siphash24.h"
#include "util.h"
/*
@@ -70,47 +70,6 @@ typedef struct {
#define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
#define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL })
-typedef void (*hash_func_t)(const void *p, struct siphash *state);
-typedef int (*compare_func_t)(const void *a, const void *b);
-
-struct hash_ops {
- hash_func_t hash;
- compare_func_t compare;
-};
-
-void string_hash_func(const void *p, struct siphash *state);
-int string_compare_func(const void *a, const void *b) _pure_;
-extern const struct hash_ops string_hash_ops;
-
-/* This will compare the passed pointers directly, and will not
- * dereference them. This is hence not useful for strings or
- * suchlike. */
-void trivial_hash_func(const void *p, struct siphash *state);
-int trivial_compare_func(const void *a, const void *b) _const_;
-extern const struct hash_ops trivial_hash_ops;
-
-/* 32bit values we can always just embedd in the pointer itself, but
- * in order to support 32bit archs we need store 64bit values
- * indirectly, since they don't fit in a pointer. */
-void uint64_hash_func(const void *p, struct siphash *state);
-int uint64_compare_func(const void *a, const void *b) _pure_;
-extern const struct hash_ops uint64_hash_ops;
-
-/* On some archs dev_t is 32bit, and on others 64bit. And sometimes
- * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */
-#if SIZEOF_DEV_T != 8
-void devt_hash_func(const void *p, struct siphash *state) _pure_;
-int devt_compare_func(const void *a, const void *b) _pure_;
-extern const struct hash_ops devt_hash_ops = {
- .hash = devt_hash_func,
- .compare = devt_compare_func
-};
-#else
-#define devt_hash_func uint64_hash_func
-#define devt_compare_func uint64_compare_func
-#define devt_hash_ops uint64_hash_ops
-#endif
-
/* Macros for type checking */
#define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \
(__builtin_types_compatible_p(typeof(h), HashmapBase*) || \
diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c
index 1e907de228..f30e028f45 100644
--- a/src/basic/hexdecoct.c
+++ b/src/basic/hexdecoct.c
@@ -514,14 +514,14 @@ int unbase64char(char c) {
return -EINVAL;
}
-char *base64mem(const void *p, size_t l) {
+ssize_t base64mem(const void *p, size_t l, char **out) {
char *r, *z;
const uint8_t *x;
/* three input bytes makes four output bytes, padding is added so we must round up */
z = r = malloc(4 * (l + 2) / 3 + 1);
if (!r)
- return NULL;
+ return -ENOMEM;
for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
@@ -549,9 +549,64 @@ char *base64mem(const void *p, size_t l) {
}
*z = 0;
- return r;
+ *out = r;
+ return z - r;
+}
+
+static int base64_append_width(char **prefix, int plen,
+ const char *sep, int indent,
+ const void *p, size_t l,
+ int width) {
+
+ _cleanup_free_ char *x = NULL;
+ char *t, *s;
+ ssize_t slen, len, avail;
+ int line, lines;
+
+ len = base64mem(p, l, &x);
+ if (len <= 0)
+ return len;
+
+ lines = (len + width - 1) / width;
+
+ slen = sep ? strlen(sep) : 0;
+ t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
+ if (!t)
+ return -ENOMEM;
+
+ memcpy(t + plen, sep, slen);
+
+ for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
+ int act = MIN(width, avail);
+
+ if (line > 0 || sep) {
+ memset(s, ' ', indent);
+ s += indent;
+ }
+
+ memcpy(s, x + width * line, act);
+ s += act;
+ *(s++) = line < lines - 1 ? '\n' : '\0';
+ avail -= act;
+ }
+ assert(avail == 0);
+
+ *prefix = t;
+ return 0;
}
+int base64_append(char **prefix, int plen,
+ const void *p, size_t l,
+ int indent, int width) {
+ if (plen > width / 2 || plen + indent > width)
+ /* leave indent on the left, keep last column free */
+ return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1);
+ else
+ /* leave plen on the left, keep last column free */
+ return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1);
+};
+
+
int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
_cleanup_free_ uint8_t *r = NULL;
int a, b, c, d;
diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h
index d9eb54a8a1..243c5e921e 100644
--- a/src/basic/hexdecoct.h
+++ b/src/basic/hexdecoct.h
@@ -49,7 +49,10 @@ int unbase64char(char c) _const_;
char *base32hexmem(const void *p, size_t l, bool padding);
int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
-char *base64mem(const void *p, size_t l);
+ssize_t base64mem(const void *p, size_t l, char **out);
+int base64_append(char **prefix, int plen,
+ const void *p, size_t l,
+ int margin, int width);
int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
void hexdump(FILE *f, const void *p, size_t s);
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c
index 5143dddf8f..8609ffb3c9 100644
--- a/src/basic/in-addr-util.c
+++ b/src/basic/in-addr-util.c
@@ -219,7 +219,7 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
errno = 0;
if (!inet_ntop(family, u, x, l)) {
free(x);
- return errno ? -errno : -EINVAL;
+ return errno > 0 ? -errno : -EINVAL;
}
*ret = x;
@@ -236,7 +236,7 @@ int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
errno = 0;
if (inet_pton(family, s, ret) <= 0)
- return errno ? -errno : -EINVAL;
+ return errno > 0 ? -errno : -EINVAL;
return 0;
}
diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h
index bcc116c783..f2b8865df5 100644
--- a/src/basic/in-addr-util.h
+++ b/src/basic/in-addr-util.h
@@ -33,6 +33,11 @@ union in_addr_union {
struct in6_addr in6;
};
+struct in_addr_data {
+ int family;
+ union in_addr_union address;
+};
+
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);
diff --git a/src/basic/io-util.h b/src/basic/io-util.h
index 5f77a556c0..7d0d2bd810 100644
--- a/src/basic/io-util.h
+++ b/src/basic/io-util.h
@@ -77,3 +77,21 @@ static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) {
return k;
}
+
+static inline bool FILE_SIZE_VALID(uint64_t l) {
+ /* ftruncate() and friends take an unsigned file size, but actually cannot deal with file sizes larger than
+ * 2^63 since the kernel internally handles it as signed value. This call allows checking for this early. */
+
+ return (l >> 63) == 0;
+}
+
+static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
+
+ /* Same as above, but allows one extra value: -1 as indication for infinity. */
+
+ if (l == (uint64_t) -1)
+ return true;
+
+ return FILE_SIZE_VALID(l);
+
+}
diff --git a/src/basic/json.c b/src/basic/json.c
index 1523e9fb09..3a3d1ad1e1 100644
--- a/src/basic/json.c
+++ b/src/basic/json.c
@@ -322,7 +322,7 @@ static int json_parse_string(const char **p, char **ret) {
else if (*c == 't')
ch = '\t';
else if (*c == 'u') {
- uint16_t x;
+ char16_t x;
int r;
r = unhex_ucs2(c + 1, &x);
@@ -335,11 +335,11 @@ static int json_parse_string(const char **p, char **ret) {
return -ENOMEM;
if (!utf16_is_surrogate(x))
- n += utf8_encode_unichar(s + n, x);
+ n += utf8_encode_unichar(s + n, (char32_t) x);
else if (utf16_is_trailing_surrogate(x))
return -EINVAL;
else {
- uint16_t y;
+ char16_t y;
if (c[0] != '\\' || c[1] != 'u')
return -EINVAL;
diff --git a/src/basic/log.c b/src/basic/log.c
index 1a9e6bdb91..18d4b82be2 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -352,7 +352,7 @@ static int write_to_console(
highlight = LOG_PRI(level) <= LOG_ERR && show_color;
if (show_location) {
- snprintf(location, sizeof(location), "(%s:%i) ", file, line);
+ xsprintf(location, "(%s:%i) ", file, line);
IOVEC_SET_STRING(iovec[n++], location);
}
@@ -777,7 +777,7 @@ static void log_assert(
return;
DISABLE_WARNING_FORMAT_NONLITERAL;
- snprintf(buffer, sizeof(buffer), format, text, file, line, func);
+ xsprintf(buffer, format, text, file, line, func);
REENABLE_WARNING;
log_abort_msg = buffer;
@@ -805,6 +805,52 @@ int log_oom_internal(const char *file, int line, const char *func) {
return -ENOMEM;
}
+int log_format_iovec(
+ struct iovec *iovec,
+ unsigned iovec_len,
+ unsigned *n,
+ bool newline_separator,
+ int error,
+ const char *format,
+ va_list ap) {
+
+ static const char nl = '\n';
+
+ while (format && *n + 1 < iovec_len) {
+ va_list aq;
+ char *m;
+ int r;
+
+ /* We need to copy the va_list structure,
+ * since vasprintf() leaves it afterwards at
+ * an undefined location */
+
+ if (error != 0)
+ errno = error;
+
+ va_copy(aq, ap);
+ r = vasprintf(&m, format, aq);
+ va_end(aq);
+ if (r < 0)
+ return -EINVAL;
+
+ /* Now, jump enough ahead, so that we point to
+ * the next format string */
+ VA_FORMAT_ADVANCE(format, ap);
+
+ IOVEC_SET_STRING(iovec[(*n)++], m);
+
+ if (newline_separator) {
+ iovec[*n].iov_base = (char*) &nl;
+ iovec[*n].iov_len = 1;
+ (*n)++;
+ }
+
+ format = va_arg(ap, char *);
+ }
+ return 0;
+}
+
int log_struct_internal(
int level,
int error,
@@ -837,10 +883,10 @@ int log_struct_internal(
char header[LINE_MAX];
struct iovec iovec[17] = {};
unsigned n = 0, i;
+ int r;
struct msghdr mh = {
.msg_iov = iovec,
};
- static const char nl = '\n';
bool fallback = false;
/* If the journal is available do structured logging */
@@ -848,43 +894,14 @@ int log_struct_internal(
IOVEC_SET_STRING(iovec[n++], header);
va_start(ap, format);
- while (format && n + 1 < ELEMENTSOF(iovec)) {
- va_list aq;
- char *m;
-
- /* We need to copy the va_list structure,
- * since vasprintf() leaves it afterwards at
- * an undefined location */
-
- if (error != 0)
- errno = error;
-
- va_copy(aq, ap);
- if (vasprintf(&m, format, aq) < 0) {
- va_end(aq);
- fallback = true;
- goto finish;
- }
- va_end(aq);
-
- /* Now, jump enough ahead, so that we point to
- * the next format string */
- VA_FORMAT_ADVANCE(format, ap);
-
- IOVEC_SET_STRING(iovec[n++], m);
-
- iovec[n].iov_base = (char*) &nl;
- iovec[n].iov_len = 1;
- n++;
-
- format = va_arg(ap, char *);
+ r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap);
+ if (r < 0)
+ fallback = true;
+ else {
+ mh.msg_iovlen = n;
+ (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
}
- mh.msg_iovlen = n;
-
- (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL);
-
- finish:
va_end(ap);
for (i = 1; i < n; i += 2)
free(iovec[i].iov_base);
diff --git a/src/basic/log.h b/src/basic/log.h
index cda1e45cc8..8c7c5e4598 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -26,6 +26,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <sys/signalfd.h>
+#include <sys/socket.h>
#include <syslog.h>
#include "sd-id128.h"
@@ -127,6 +128,15 @@ int log_oom_internal(
int line,
const char *func);
+int log_format_iovec(
+ struct iovec *iovec,
+ unsigned iovec_len,
+ unsigned *n,
+ bool newline_separator,
+ int error,
+ const char *format,
+ va_list ap);
+
/* This modifies the buffer passed! */
int log_dump_internal(
int level,
diff --git a/src/basic/macro.h b/src/basic/macro.h
index 5088e6720d..c529c6ecad 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -320,18 +320,47 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
#define SET_FLAG(v, flag, b) \
(v) = (b) ? ((v) | (flag)) : ((v) & ~(flag))
-#define IN_SET(x, y, ...) \
- ({ \
- static const typeof(y) _array[] = { (y), __VA_ARGS__ }; \
- const typeof(y) _x = (x); \
- unsigned _i; \
- bool _found = false; \
- for (_i = 0; _i < ELEMENTSOF(_array); _i++) \
- if (_array[_i] == _x) { \
- _found = true; \
- break; \
- } \
- _found; \
+#define CASE_F(X) case X:
+#define CASE_F_1(CASE, X) CASE_F(X)
+#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__)
+#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__)
+#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__)
+#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__)
+#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__)
+#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__)
+#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__)
+#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__)
+#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__)
+#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__)
+#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__)
+#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__)
+#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__)
+#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__)
+#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__)
+#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__)
+#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__)
+#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__)
+#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__)
+
+#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME
+#define FOR_EACH_MAKE_CASE(...) \
+ GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \
+ CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \
+ (CASE_F,__VA_ARGS__)
+
+#define IN_SET(x, ...) \
+ ({ \
+ bool _found = false; \
+ /* If the build breaks in the line below, you need to extend the case macros */ \
+ static _unused_ char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){__VA_ARGS__})/sizeof(int)]; \
+ switch(x) { \
+ FOR_EACH_MAKE_CASE(__VA_ARGS__) \
+ _found = true; \
+ break; \
+ default: \
+ break; \
+ } \
+ _found; \
})
/* Define C11 thread_local attribute even on older gcc compiler
diff --git a/src/basic/missing.h b/src/basic/missing.h
index d539ed00e4..48ca04a8a1 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -36,6 +36,7 @@
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/syscall.h>
+#include <uchar.h>
#include <unistd.h>
#ifdef HAVE_AUDIT
@@ -131,6 +132,10 @@
#define NETLINK_LIST_MEMBERSHIPS 9
#endif
+#ifndef SOL_SCTP
+#define SOL_SCTP 132
+#endif
+
#if !HAVE_DECL_PIVOT_ROOT
static inline int pivot_root(const char *new_root, const char *put_old) {
return syscall(SYS_pivot_root, new_root, put_old);
@@ -970,6 +975,10 @@ static inline int setns(int fd, int nstype) {
#define IFA_FLAGS 8
#endif
+#ifndef IFA_F_MANAGETEMPADDR
+#define IFA_F_MANAGETEMPADDR 0x100
+#endif
+
#ifndef IFA_F_NOPREFIXROUTE
#define IFA_F_NOPREFIXROUTE 0x200
#endif
@@ -1125,3 +1134,39 @@ static inline key_serial_t request_key(const char *type, const char *description
#ifndef KEY_SPEC_USER_KEYRING
#define KEY_SPEC_USER_KEYRING -4
#endif
+
+#ifndef PR_CAP_AMBIENT
+#define PR_CAP_AMBIENT 47
+#endif
+
+#ifndef PR_CAP_AMBIENT_IS_SET
+#define PR_CAP_AMBIENT_IS_SET 1
+#endif
+
+#ifndef PR_CAP_AMBIENT_RAISE
+#define PR_CAP_AMBIENT_RAISE 2
+#endif
+
+#ifndef PR_CAP_AMBIENT_CLEAR_ALL
+#define PR_CAP_AMBIENT_CLEAR_ALL 4
+#endif
+
+/* The following two defines are actually available in the kernel headers for longer, but we define them here anyway,
+ * since that makes it easier to use them in conjunction with the glibc net/if.h header which conflicts with
+ * linux/if.h. */
+#ifndef IF_OPER_UNKNOWN
+#define IF_OPER_UNKNOWN 0
+#endif
+
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+
+#ifndef HAVE_DECL_CHAR32_T
+#define char32_t uint32_t
+#endif
+
+#ifndef HAVE_DECL_CHAR16_T
+#define char16_t uint16_t
+#endif
+
+#endif
diff --git a/src/basic/nss-util.h b/src/basic/nss-util.h
index cc30d93aad..4be0136da6 100644
--- a/src/basic/nss-util.h
+++ b/src/basic/nss-util.h
@@ -27,6 +27,8 @@
#include <pwd.h>
#include <resolv.h>
+#define NSS_SIGNALS_BLOCK SIGALRM,SIGVTALRM,SIGPIPE,SIGCHLD,SIGTSTP,SIGIO,SIGHUP,SIGUSR1,SIGUSR2,SIGPROF,SIGURG,SIGWINCH
+
#define NSS_GETHOSTBYNAME_PROTOTYPES(module) \
enum nss_status _nss_##module##_gethostbyname4_r( \
const char *name, \
diff --git a/src/basic/ordered-set.c b/src/basic/ordered-set.c
new file mode 100644
index 0000000000..2e0bdf6488
--- /dev/null
+++ b/src/basic/ordered-set.c
@@ -0,0 +1,64 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "ordered-set.h"
+#include "strv.h"
+
+int ordered_set_consume(OrderedSet *s, void *p) {
+ int r;
+
+ r = ordered_set_put(s, p);
+ if (r <= 0)
+ free(p);
+
+ return r;
+}
+
+int ordered_set_put_strdup(OrderedSet *s, const char *p) {
+ char *c;
+ int r;
+
+ assert(s);
+ assert(p);
+
+ c = strdup(p);
+ if (!c)
+ return -ENOMEM;
+
+ r = ordered_set_consume(s, c);
+ if (r == -EEXIST)
+ return 0;
+
+ return r;
+}
+
+int ordered_set_put_strdupv(OrderedSet *s, char **l) {
+ int n = 0, r;
+ char **i;
+
+ STRV_FOREACH(i, l) {
+ r = ordered_set_put_strdup(s, *i);
+ if (r < 0)
+ return r;
+
+ n += r;
+ }
+
+ return n;
+}
diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h
index da10e90ff2..ab185c11aa 100644
--- a/src/basic/ordered-set.h
+++ b/src/basic/ordered-set.h
@@ -62,9 +62,15 @@ static inline bool ordered_set_iterate(OrderedSet *s, Iterator *i, void **value)
return ordered_hashmap_iterate((OrderedHashmap*) s, i, value, NULL);
}
+int ordered_set_consume(OrderedSet *s, void *p);
+int ordered_set_put_strdup(OrderedSet *s, const char *p);
+int ordered_set_put_strdupv(OrderedSet *s, char **l);
+
#define ORDERED_SET_FOREACH(e, s, i) \
for ((i) = ITERATOR_FIRST; ordered_set_iterate((s), &(i), (void**)&(e)); )
DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free_free);
#define _cleanup_ordered_set_free_ _cleanup_(ordered_set_freep)
+#define _cleanup_ordered_set_free_free_ _cleanup_(ordered_set_free_freep)
diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c
index 618ef5d564..d8de6f90ea 100644
--- a/src/basic/parse-util.c
+++ b/src/basic/parse-util.c
@@ -81,7 +81,7 @@ int parse_mode(const char *s, mode_t *ret) {
errno = 0;
l = strtol(s, &x, 8);
- if (errno != 0)
+ if (errno > 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
@@ -176,7 +176,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
errno = 0;
l = strtoull(p, &e, 10);
- if (errno != 0)
+ if (errno > 0)
return -errno;
if (e == p)
return -EINVAL;
@@ -192,7 +192,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) {
char *e2;
l2 = strtoull(e, &e2, 10);
- if (errno != 0)
+ if (errno > 0)
return -errno;
/* Ignore failure. E.g. 10.M is valid */
@@ -330,7 +330,7 @@ int safe_atou(const char *s, unsigned *ret_u) {
errno = 0;
l = strtoul(s, &x, 0);
- if (errno != 0)
+ if (errno > 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
@@ -352,7 +352,7 @@ int safe_atoi(const char *s, int *ret_i) {
errno = 0;
l = strtol(s, &x, 0);
- if (errno != 0)
+ if (errno > 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
@@ -374,7 +374,7 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) {
errno = 0;
l = strtoull(s, &x, 0);
- if (errno != 0)
+ if (errno > 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
@@ -394,7 +394,7 @@ int safe_atolli(const char *s, long long int *ret_lli) {
errno = 0;
l = strtoll(s, &x, 0);
- if (errno != 0)
+ if (errno > 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
@@ -414,7 +414,7 @@ int safe_atou8(const char *s, uint8_t *ret) {
errno = 0;
l = strtoul(s, &x, 0);
- if (errno != 0)
+ if (errno > 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
@@ -438,7 +438,7 @@ int safe_atou16(const char *s, uint16_t *ret) {
errno = 0;
l = strtoul(s, &x, 0);
- if (errno != 0)
+ if (errno > 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
@@ -460,7 +460,7 @@ int safe_atoi16(const char *s, int16_t *ret) {
errno = 0;
l = strtol(s, &x, 0);
- if (errno != 0)
+ if (errno > 0)
return -errno;
if (!x || x == s || *x)
return -EINVAL;
@@ -485,7 +485,7 @@ int safe_atod(const char *s, double *ret_d) {
errno = 0;
d = strtod_l(s, &x, loc);
- if (errno != 0) {
+ if (errno > 0) {
freelocale(loc);
return -errno;
}
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 61fab0e087..4837bb2d7d 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -102,7 +102,7 @@ int path_make_absolute_cwd(const char *p, char **ret) {
cwd = get_current_dir_name();
if (!cwd)
- return -errno;
+ return negative_errno();
c = strjoin(cwd, "/", p, NULL);
}
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index 4cc54a51fb..189ef9ab60 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -33,6 +33,9 @@
#include <sys/wait.h>
#include <syslog.h>
#include <unistd.h>
+#ifdef HAVE_VALGRIND_VALGRIND_H
+#include <valgrind/valgrind.h>
+#endif
#include "alloc-util.h"
#include "escape.h"
@@ -45,6 +48,7 @@
#include "missing.h"
#include "process-util.h"
#include "signal-util.h"
+#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
#include "user-util.h"
@@ -634,6 +638,17 @@ bool pid_is_alive(pid_t pid) {
return true;
}
+int pid_from_same_root_fs(pid_t pid) {
+ const char *root;
+
+ if (pid < 0)
+ return 0;
+
+ root = procfs_file_alloca(pid, "root");
+
+ return files_same(root, "/proc/1/root");
+}
+
bool is_main_thread(void) {
static thread_local int cached = 0;
@@ -730,6 +745,23 @@ const char* personality_to_string(unsigned long p) {
return NULL;
}
+void valgrind_summary_hack(void) {
+#ifdef HAVE_VALGRIND_VALGRIND_H
+ if (getpid() == 1 && RUNNING_ON_VALGRIND) {
+ pid_t pid;
+ pid = raw_clone(SIGCHLD, NULL);
+ if (pid < 0)
+ log_emergency_errno(errno, "Failed to fork off valgrind helper: %m");
+ else if (pid == 0)
+ exit(EXIT_SUCCESS);
+ else {
+ log_info("Spawned valgrind helper as PID "PID_FMT".", pid);
+ (void) wait_for_terminate(pid, NULL);
+ }
+ }
+#endif
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/basic/process-util.h b/src/basic/process-util.h
index f4c4437624..f5d193e762 100644
--- a/src/basic/process-util.h
+++ b/src/basic/process-util.h
@@ -70,6 +70,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value);
bool pid_is_alive(pid_t pid);
bool pid_is_unwaited(pid_t pid);
+int pid_from_same_root_fs(pid_t pid);
bool is_main_thread(void);
@@ -98,3 +99,5 @@ int sched_policy_from_string(const char *s);
#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p))
#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
+
+void valgrind_summary_hack(void);
diff --git a/src/basic/random-util.c b/src/basic/random-util.c
index e1543da5a3..2f468db770 100644
--- a/src/basic/random-util.c
+++ b/src/basic/random-util.c
@@ -95,17 +95,18 @@ void initialize_srand(void) {
if (srand_called)
return;
- x = 0;
-
#ifdef HAVE_SYS_AUXV_H
- /* The kernel provides us with a bit of entropy in auxv, so
- * let's try to make use of that to seed the pseudo-random
- * generator. It's better than nothing... */
+ /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed the
+ * pseudo-random generator. It's better than nothing... */
auxv = (void*) getauxval(AT_RANDOM);
- if (auxv)
- x ^= *(unsigned*) auxv;
+ if (auxv) {
+ assert_cc(sizeof(x) < 16);
+ memcpy(&x, auxv, sizeof(x));
+ } else
#endif
+ x = 0;
+
x ^= (unsigned) now(CLOCK_REALTIME);
x ^= (unsigned) gettid();
diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c
index 44f885db16..8a921a27cb 100644
--- a/src/basic/rlimit-util.c
+++ b/src/basic/rlimit-util.c
@@ -22,10 +22,14 @@
#include <errno.h>
#include <sys/resource.h>
+#include "alloc-util.h"
+#include "extract-word.h"
+#include "formats-util.h"
#include "macro.h"
#include "missing.h"
#include "rlimit-util.h"
#include "string-table.h"
+#include "time-util.h"
int setrlimit_closest(int resource, const struct rlimit *rlim) {
struct rlimit highest, fixed;
@@ -51,6 +55,202 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) {
return 0;
}
+static int rlimit_parse_u64(const char *val, rlim_t *ret) {
+ uint64_t u;
+ int r;
+
+ assert(val);
+ assert(ret);
+
+ if (streq(val, "infinity")) {
+ *ret = RLIM_INFINITY;
+ return 0;
+ }
+
+ /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
+ assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
+
+ r = safe_atou64(val, &u);
+ if (r < 0)
+ return r;
+ if (u >= (uint64_t) RLIM_INFINITY)
+ return -ERANGE;
+
+ *ret = (rlim_t) u;
+ return 0;
+}
+
+static int rlimit_parse_size(const char *val, rlim_t *ret) {
+ uint64_t u;
+ int r;
+
+ assert(val);
+ assert(ret);
+
+ if (streq(val, "infinity")) {
+ *ret = RLIM_INFINITY;
+ return 0;
+ }
+
+ r = parse_size(val, 1024, &u);
+ if (r < 0)
+ return r;
+ if (u >= (uint64_t) RLIM_INFINITY)
+ return -ERANGE;
+
+ *ret = (rlim_t) u;
+ return 0;
+}
+
+static int rlimit_parse_sec(const char *val, rlim_t *ret) {
+ uint64_t u;
+ usec_t t;
+ int r;
+
+ assert(val);
+ assert(ret);
+
+ if (streq(val, "infinity")) {
+ *ret = RLIM_INFINITY;
+ return 0;
+ }
+
+ r = parse_sec(val, &t);
+ if (r < 0)
+ return r;
+ if (t == USEC_INFINITY) {
+ *ret = RLIM_INFINITY;
+ return 0;
+ }
+
+ u = (uint64_t) DIV_ROUND_UP(t, USEC_PER_SEC);
+ if (u >= (uint64_t) RLIM_INFINITY)
+ return -ERANGE;
+
+ *ret = (rlim_t) u;
+ return 0;
+}
+
+static int rlimit_parse_usec(const char *val, rlim_t *ret) {
+ usec_t t;
+ int r;
+
+ assert(val);
+ assert(ret);
+
+ if (streq(val, "infinity")) {
+ *ret = RLIM_INFINITY;
+ return 0;
+ }
+
+ r = parse_time(val, &t, 1);
+ if (r < 0)
+ return r;
+ if (t == USEC_INFINITY) {
+ *ret = RLIM_INFINITY;
+ return 0;
+ }
+
+ *ret = (rlim_t) t;
+ return 0;
+}
+
+static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = {
+ [RLIMIT_CPU] = rlimit_parse_sec,
+ [RLIMIT_FSIZE] = rlimit_parse_size,
+ [RLIMIT_DATA] = rlimit_parse_size,
+ [RLIMIT_STACK] = rlimit_parse_size,
+ [RLIMIT_CORE] = rlimit_parse_size,
+ [RLIMIT_RSS] = rlimit_parse_size,
+ [RLIMIT_NOFILE] = rlimit_parse_u64,
+ [RLIMIT_AS] = rlimit_parse_size,
+ [RLIMIT_NPROC] = rlimit_parse_u64,
+ [RLIMIT_MEMLOCK] = rlimit_parse_size,
+ [RLIMIT_LOCKS] = rlimit_parse_u64,
+ [RLIMIT_SIGPENDING] = rlimit_parse_u64,
+ [RLIMIT_MSGQUEUE] = rlimit_parse_size,
+ [RLIMIT_NICE] = rlimit_parse_u64,
+ [RLIMIT_RTPRIO] = rlimit_parse_u64,
+ [RLIMIT_RTTIME] = rlimit_parse_usec,
+};
+
+int rlimit_parse_one(int resource, const char *val, rlim_t *ret) {
+ assert(val);
+ assert(ret);
+
+ if (resource < 0)
+ return -EINVAL;
+ if (resource >= _RLIMIT_MAX)
+ return -EINVAL;
+
+ return rlimit_parse_table[resource](val, ret);
+}
+
+int rlimit_parse(int resource, const char *val, struct rlimit *ret) {
+ _cleanup_free_ char *hard = NULL, *soft = NULL;
+ rlim_t hl, sl;
+ int r;
+
+ assert(val);
+ assert(ret);
+
+ r = extract_first_word(&val, &soft, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -EINVAL;
+
+ r = rlimit_parse_one(resource, soft, &sl);
+ if (r < 0)
+ return r;
+
+ r = extract_first_word(&val, &hard, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return r;
+ if (!isempty(val))
+ return -EINVAL;
+ if (r == 0)
+ hl = sl;
+ else {
+ r = rlimit_parse_one(resource, hard, &hl);
+ if (r < 0)
+ return r;
+ if (sl > hl)
+ return -EILSEQ;
+ }
+
+ *ret = (struct rlimit) {
+ .rlim_cur = sl,
+ .rlim_max = hl,
+ };
+
+ return 0;
+}
+
+int rlimit_format(const struct rlimit *rl, char **ret) {
+ char *s = NULL;
+
+ assert(rl);
+ assert(ret);
+
+ if (rl->rlim_cur >= RLIM_INFINITY && rl->rlim_max >= RLIM_INFINITY)
+ s = strdup("infinity");
+ else if (rl->rlim_cur >= RLIM_INFINITY)
+ (void) asprintf(&s, "infinity:" RLIM_FMT, rl->rlim_max);
+ else if (rl->rlim_max >= RLIM_INFINITY)
+ (void) asprintf(&s, RLIM_FMT ":infinity", rl->rlim_cur);
+ else if (rl->rlim_cur == rl->rlim_max)
+ (void) asprintf(&s, RLIM_FMT, rl->rlim_cur);
+ else
+ (void) asprintf(&s, RLIM_FMT ":" RLIM_FMT, rl->rlim_cur, rl->rlim_max);
+
+ if (!s)
+ return -ENOMEM;
+
+ *ret = s;
+ return 0;
+}
+
static const char* const rlimit_table[_RLIMIT_MAX] = {
[RLIMIT_CPU] = "LimitCPU",
[RLIMIT_FSIZE] = "LimitFSIZE",
diff --git a/src/basic/rlimit-util.h b/src/basic/rlimit-util.h
index 262f86dd04..abf3c57934 100644
--- a/src/basic/rlimit-util.h
+++ b/src/basic/rlimit-util.h
@@ -30,4 +30,9 @@ int rlimit_from_string(const char *s) _pure_;
int setrlimit_closest(int resource, const struct rlimit *rlim);
+int rlimit_parse_one(int resource, const char *val, rlim_t *ret);
+int rlimit_parse(int resource, const char *val, struct rlimit *ret);
+
+int rlimit_format(const struct rlimit *rl, char **ret);
+
#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim })
diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c
index 14f8474da0..4807561723 100644
--- a/src/basic/rm-rf.c
+++ b/src/basic/rm-rf.c
@@ -82,7 +82,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
errno = 0;
de = readdir(d);
if (!de) {
- if (errno != 0 && ret == 0)
+ if (errno > 0 && ret == 0)
ret = -errno;
return ret;
}
diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c
index 7637fccb2f..315efadd93 100644
--- a/src/basic/signal-util.c
+++ b/src/basic/signal-util.c
@@ -26,6 +26,7 @@
#include "macro.h"
#include "parse-util.h"
#include "signal-util.h"
+#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
@@ -234,9 +235,9 @@ const char *signal_to_string(int signo) {
return name;
if (signo >= SIGRTMIN && signo <= SIGRTMAX)
- snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
+ xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN);
else
- snprintf(buf, sizeof(buf), "%d", signo);
+ xsprintf(buf, "%d", signo);
return buf;
}
diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h
index e7393e2dac..5d94d1c363 100644
--- a/src/basic/signal-util.h
+++ b/src/basic/signal-util.h
@@ -41,3 +41,14 @@ int signal_from_string(const char *s) _pure_;
int signal_from_string_try_harder(const char *s);
void nop_signal_handler(int sig);
+
+static inline void block_signals_reset(sigset_t *ss) {
+ assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0);
+}
+
+#define BLOCK_SIGNALS(...) \
+ _cleanup_(block_signals_reset) sigset_t _saved_sigset = ({ \
+ sigset_t t; \
+ assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \
+ t; \
+ })
diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h
index 3f7e20362b..54e2420cc6 100644
--- a/src/basic/siphash24.h
+++ b/src/basic/siphash24.h
@@ -16,6 +16,8 @@ struct siphash {
void siphash24_init(struct siphash *state, const uint8_t k[16]);
void siphash24_compress(const void *in, size_t inlen, struct siphash *state);
+#define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state))
+
uint64_t siphash24_finalize(struct siphash *state);
uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]);
diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c
index e169439e04..bd206586ce 100644
--- a/src/basic/socket-label.c
+++ b/src/basic/socket-label.c
@@ -147,7 +147,7 @@ int socket_address_listen(
return r;
}
-int make_socket_fd(int log_level, const char* address, int flags) {
+int make_socket_fd(int log_level, const char* address, int type, int flags) {
SocketAddress a;
int fd, r;
@@ -155,7 +155,9 @@ int make_socket_fd(int log_level, const char* address, int flags) {
if (r < 0)
return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
- fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
+ a.type = type;
+
+ fd = socket_address_listen(&a, type | flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
NULL, false, false, false, 0755, 0644, NULL);
if (fd < 0 || log_get_max_level() >= log_level) {
_cleanup_free_ char *p = NULL;
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index be144e157d..f2bb3bab86 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -601,7 +601,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
return 0;
}
-int getpeername_pretty(int fd, char **ret) {
+int getpeername_pretty(int fd, bool include_port, char **ret) {
union sockaddr_union sa;
socklen_t salen = sizeof(sa);
int r;
@@ -631,7 +631,7 @@ int getpeername_pretty(int fd, char **ret) {
/* For remote sockets we translate IPv6 addresses back to IPv4
* if applicable, since that's nicer. */
- return sockaddr_pretty(&sa.sa, salen, true, true, ret);
+ return sockaddr_pretty(&sa.sa, salen, true, include_port, ret);
}
int getsockname_pretty(int fd, char **ret) {
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index 6da1df68d8..2323ccf3ab 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -89,7 +89,7 @@ int socket_address_listen(
mode_t directory_mode,
mode_t socket_mode,
const char *label);
-int make_socket_fd(int log_level, const char* address, int flags);
+int make_socket_fd(int log_level, const char* address, int type, int flags);
bool socket_address_is(const SocketAddress *a, const char *s, int type);
bool socket_address_is_netlink(const SocketAddress *a, const char *s);
@@ -105,7 +105,7 @@ bool socket_ipv6_is_supported(void);
int sockaddr_port(const struct sockaddr *_sa) _pure_;
int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret);
-int getpeername_pretty(int fd, char **ret);
+int getpeername_pretty(int fd, bool include_port, char **ret);
int getsockname_pretty(int fd, char **ret);
int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret);
diff --git a/src/basic/string-table.h b/src/basic/string-table.h
index 2181a3a767..588404ab5a 100644
--- a/src/basic/string-table.h
+++ b/src/basic/string-table.h
@@ -47,16 +47,34 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
}
+#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
+ scope type name##_from_string(const char *s) { \
+ int b; \
+ b = parse_boolean(s); \
+ if (b == 0) \
+ return (type) 0; \
+ else if (b > 0) \
+ return yes; \
+ return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
+ }
+
#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
_DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
_DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
struct __useless_struct_to_allow_trailing_semicolon__
+#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \
+ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
+ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
+#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,)
+
/* For string conversions where numbers are also acceptable */
#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
int name##_to_string_alloc(type i, char **str) { \
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 8178c7093f..cb75b09c74 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -317,18 +317,67 @@ char *truncate_nl(char *s) {
return s;
}
+char ascii_tolower(char x) {
+
+ if (x >= 'A' && x <= 'Z')
+ return x - 'A' + 'a';
+
+ return x;
+}
+
char *ascii_strlower(char *t) {
char *p;
assert(t);
for (p = t; *p; p++)
- if (*p >= 'A' && *p <= 'Z')
- *p = *p - 'A' + 'a';
+ *p = ascii_tolower(*p);
return t;
}
+char *ascii_strlower_n(char *t, size_t n) {
+ size_t i;
+
+ if (n <= 0)
+ return t;
+
+ for (i = 0; i < n; i++)
+ t[i] = ascii_tolower(t[i]);
+
+ return t;
+}
+
+int ascii_strcasecmp_n(const char *a, const char *b, size_t n) {
+
+ for (; n > 0; a++, b++, n--) {
+ int x, y;
+
+ x = (int) (uint8_t) ascii_tolower(*a);
+ y = (int) (uint8_t) ascii_tolower(*b);
+
+ if (x != y)
+ return x - y;
+ }
+
+ return 0;
+}
+
+int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m) {
+ int r;
+
+ r = ascii_strcasecmp_n(a, b, MIN(n, m));
+ if (r != 0)
+ return r;
+
+ if (n < m)
+ return -1;
+ else if (n > m)
+ return 1;
+ else
+ return 0;
+}
+
bool chars_intersect(const char *a, const char *b) {
const char *p;
@@ -401,6 +450,7 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
char *e;
const char *i, *j;
unsigned k, len, len2;
+ int r;
assert(s);
assert(percent <= 100);
@@ -420,10 +470,10 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
k = 0;
for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
- int c;
+ char32_t c;
- c = utf8_encoded_to_unichar(i);
- if (c < 0)
+ r = utf8_encoded_to_unichar(i, &c);
+ if (r < 0)
return NULL;
k += unichar_iswide(c) ? 2 : 1;
}
@@ -432,11 +482,11 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
x ++;
for (j = s + old_length; k < new_length && j > i; ) {
- int c;
+ char32_t c;
j = utf8_prev_char(j);
- c = utf8_encoded_to_unichar(j);
- if (c < 0)
+ r = utf8_encoded_to_unichar(j, &c);
+ if (r < 0)
return NULL;
k += unichar_iswide(c) ? 2 : 1;
}
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index b59b9b5a71..8ea18f45aa 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -130,7 +130,12 @@ char *strstrip(char *s);
char *delete_chars(char *s, const char *bad);
char *truncate_nl(char *s);
-char *ascii_strlower(char *path);
+char ascii_tolower(char x);
+char *ascii_strlower(char *s);
+char *ascii_strlower_n(char *s, size_t n);
+
+int ascii_strcasecmp_n(const char *a, const char *b, size_t n);
+int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m);
bool chars_intersect(const char *a, const char *b) _pure_;
diff --git a/src/basic/strv.c b/src/basic/strv.c
index 0a3d15706f..5532c53ad1 100644
--- a/src/basic/strv.c
+++ b/src/basic/strv.c
@@ -29,6 +29,7 @@
#include "alloc-util.h"
#include "escape.h"
#include "extract-word.h"
+#include "fileio.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
@@ -871,3 +872,22 @@ rollback:
nl[k] = NULL;
return -ENOMEM;
}
+
+int fputstrv(FILE *f, char **l, const char *separator, bool *space) {
+ bool b = false;
+ char **s;
+ int r;
+
+ /* Like fputs(), but for strv, and with a less stupid argument order */
+
+ if (!space)
+ space = &b;
+
+ STRV_FOREACH(s, l) {
+ r = fputs_with_space(f, *s, separator, space);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
diff --git a/src/basic/strv.h b/src/basic/strv.h
index bb61db2638..560f90115c 100644
--- a/src/basic/strv.h
+++ b/src/basic/strv.h
@@ -169,3 +169,5 @@ char ***strv_free_free(char ***l);
char **strv_skip(char **l, size_t n);
int strv_extend_n(char ***l, const char *value, size_t n);
+
+int fputstrv(FILE *f, char **l, const char *separator, bool *space);
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index a39764472b..0a9d2bbdef 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -128,7 +128,7 @@ int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
errno = 0;
if (!fgets(line, sizeof(line), f))
- return errno ? -errno : -EIO;
+ return errno > 0 ? -errno : -EIO;
truncate_nl(line);
@@ -212,7 +212,7 @@ int ask_string(char **ret, const char *text, ...) {
errno = 0;
if (!fgets(line, sizeof(line), stdin))
- return errno ? -errno : -EIO;
+ return errno > 0 ? -errno : -EIO;
if (!endswith(line, "\n"))
putchar('\n');
@@ -726,9 +726,7 @@ bool tty_is_vc_resolve(const char *tty) {
}
const char *default_term_for_tty(const char *tty) {
- assert(tty);
-
- return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
+ return tty && tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
}
int fd_columns(int fd) {
@@ -1135,3 +1133,16 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
return receive_one_fd(pair[0], 0);
}
+
+bool colors_enabled(void) {
+ const char *colors;
+
+ colors = getenv("SYSTEMD_COLORS");
+ if (!colors) {
+ if (streq_ptr(getenv("TERM"), "dumb"))
+ return false;
+ return on_tty();
+ }
+
+ return parse_boolean(colors) != 0;
+}
diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h
index 597a0060ad..a7c96a77cb 100644
--- a/src/basic/terminal-util.h
+++ b/src/basic/terminal-util.h
@@ -79,37 +79,38 @@ unsigned lines(void);
void columns_lines_cache_reset(int _unused_ signum);
bool on_tty(void);
+bool colors_enabled(void);
static inline const char *ansi_underline(void) {
- return on_tty() ? ANSI_UNDERLINE : "";
+ return colors_enabled() ? ANSI_UNDERLINE : "";
}
static inline const char *ansi_highlight(void) {
- return on_tty() ? ANSI_HIGHLIGHT : "";
+ return colors_enabled() ? ANSI_HIGHLIGHT : "";
}
static inline const char *ansi_highlight_underline(void) {
- return on_tty() ? ANSI_HIGHLIGHT_UNDERLINE : "";
+ return colors_enabled() ? ANSI_HIGHLIGHT_UNDERLINE : "";
}
static inline const char *ansi_highlight_red(void) {
- return on_tty() ? ANSI_HIGHLIGHT_RED : "";
+ return colors_enabled() ? ANSI_HIGHLIGHT_RED : "";
}
static inline const char *ansi_highlight_green(void) {
- return on_tty() ? ANSI_HIGHLIGHT_GREEN : "";
+ return colors_enabled() ? ANSI_HIGHLIGHT_GREEN : "";
}
static inline const char *ansi_highlight_yellow(void) {
- return on_tty() ? ANSI_HIGHLIGHT_YELLOW : "";
+ return colors_enabled() ? ANSI_HIGHLIGHT_YELLOW : "";
}
static inline const char *ansi_highlight_blue(void) {
- return on_tty() ? ANSI_HIGHLIGHT_BLUE : "";
+ return colors_enabled() ? ANSI_HIGHLIGHT_BLUE : "";
}
static inline const char *ansi_normal(void) {
- return on_tty() ? ANSI_NORMAL : "";
+ return colors_enabled() ? ANSI_NORMAL : "";
}
int get_ctty_devnr(pid_t pid, dev_t *d);
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index 7321e3c670..9c7758a959 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -69,7 +69,7 @@ typedef struct dual_timestamp {
#define FORMAT_TIMESTAMP_RELATIVE_MAX 256
#define FORMAT_TIMESPAN_MAX 64
-#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
+#define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL })
@@ -127,3 +127,16 @@ time_t mktime_or_timegm(struct tm *tm, bool utc);
struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
unsigned long usec_to_jiffies(usec_t usec);
+
+static inline usec_t usec_add(usec_t a, usec_t b) {
+ usec_t c;
+
+ /* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output, and doesn't
+ * overflow. */
+
+ c = a + b;
+ if (c < a || c < b) /* overflow check */
+ return USEC_INFINITY;
+
+ return c;
+}
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
index 5fc3b9d6fd..d4a3062658 100644
--- a/src/basic/unit-name.c
+++ b/src/basic/unit-name.c
@@ -27,6 +27,7 @@
#include "alloc-util.h"
#include "bus-label.h"
+#include "glob-util.h"
#include "hexdecoct.h"
#include "macro.h"
#include "path-util.h"
@@ -35,10 +36,22 @@
#include "strv.h"
#include "unit-name.h"
+/* Characters valid in a unit name. */
#define VALID_CHARS \
- DIGITS LETTERS \
+ DIGITS \
+ LETTERS \
":-_.\\"
+/* The same, but also permits the single @ character that may appear */
+#define VALID_CHARS_WITH_AT \
+ "@" \
+ VALID_CHARS
+
+/* All chars valid in a unit name glob */
+#define VALID_CHARS_GLOB \
+ VALID_CHARS_WITH_AT \
+ "[]!-*?"
+
bool unit_name_is_valid(const char *n, UnitNameFlags flags) {
const char *e, *i, *at;
@@ -637,7 +650,7 @@ static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t
/* We'll only escape the obvious characters here, to play
* safe. */
- valid_chars = allow_globs == UNIT_NAME_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS;
+ valid_chars = allow_globs == UNIT_NAME_GLOB ? VALID_CHARS_GLOB : VALID_CHARS_WITH_AT;
for (; *f; f++) {
if (*f == '/')
@@ -672,15 +685,15 @@ int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, c
if (!unit_suffix_is_valid(suffix))
return -EINVAL;
- if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
- /* No mangling necessary... */
- s = strdup(name);
- if (!s)
- return -ENOMEM;
+ /* Already a fully valid unit name? If so, no mangling is necessary... */
+ if (unit_name_is_valid(name, UNIT_NAME_ANY))
+ goto good;
- *ret = s;
- return 0;
- }
+ /* Already a fully valid globbing expression? If so, no mangling is necessary either... */
+ if (allow_globs == UNIT_NAME_GLOB &&
+ string_is_glob(name) &&
+ in_charset(name, VALID_CHARS_GLOB))
+ goto good;
if (is_device_path(name)) {
r = unit_name_from_path(name, ".device", ret);
@@ -705,11 +718,21 @@ int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, c
t = do_escape_mangle(name, allow_globs, s);
*t = 0;
- if (unit_name_to_type(s) < 0)
+ /* Append a suffix if it doesn't have any, but only if this is not a glob, so that we can allow "foo.*" as a
+ * valid glob. */
+ if ((allow_globs != UNIT_NAME_GLOB || !string_is_glob(s)) && unit_name_to_type(s) < 0)
strcpy(t, suffix);
*ret = s;
return 1;
+
+good:
+ s = strdup(name);
+ if (!s)
+ return -ENOMEM;
+
+ *ret = s;
+ return 0;
}
int slice_build_parent_slice(const char *slice, char **ret) {
diff --git a/src/basic/user-util.c b/src/basic/user-util.c
index 56e1a3be48..70a6e1f5e4 100644
--- a/src/basic/user-util.c
+++ b/src/basic/user-util.c
@@ -68,7 +68,7 @@ int parse_uid(const char *s, uid_t *ret) {
if (!uid_is_valid(uid))
return -ENXIO; /* we return ENXIO instead of EINVAL
* here, to make it easy to distuingish
- * invalid numeric uids invalid
+ * invalid numeric uids from invalid
* strings. */
if (ret)
diff --git a/src/basic/utf8.c b/src/basic/utf8.c
index 124effd6df..3f024f7e58 100644
--- a/src/basic/utf8.c
+++ b/src/basic/utf8.c
@@ -53,7 +53,7 @@
#include "macro.h"
#include "utf8.h"
-bool unichar_is_valid(uint32_t ch) {
+bool unichar_is_valid(char32_t ch) {
if (ch >= 0x110000) /* End of unicode space */
return false;
@@ -67,7 +67,7 @@ bool unichar_is_valid(uint32_t ch) {
return true;
}
-static bool unichar_is_control(uint32_t ch) {
+static bool unichar_is_control(char32_t ch) {
/*
0 to ' '-1 is the C0 range.
@@ -103,8 +103,9 @@ static int utf8_encoded_expected_len(const char *str) {
}
/* decode one unicode char */
-int utf8_encoded_to_unichar(const char *str) {
- int unichar, len, i;
+int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
+ char32_t unichar;
+ int len, i;
assert(str);
@@ -112,34 +113,37 @@ int utf8_encoded_to_unichar(const char *str) {
switch (len) {
case 1:
- return (int)str[0];
+ *ret_unichar = (char32_t)str[0];
+ return 0;
case 2:
unichar = str[0] & 0x1f;
break;
case 3:
- unichar = (int)str[0] & 0x0f;
+ unichar = (char32_t)str[0] & 0x0f;
break;
case 4:
- unichar = (int)str[0] & 0x07;
+ unichar = (char32_t)str[0] & 0x07;
break;
case 5:
- unichar = (int)str[0] & 0x03;
+ unichar = (char32_t)str[0] & 0x03;
break;
case 6:
- unichar = (int)str[0] & 0x01;
+ unichar = (char32_t)str[0] & 0x01;
break;
default:
return -EINVAL;
}
for (i = 1; i < len; i++) {
- if (((int)str[i] & 0xc0) != 0x80)
+ if (((char32_t)str[i] & 0xc0) != 0x80)
return -EINVAL;
unichar <<= 6;
- unichar |= (int)str[i] & 0x3f;
+ unichar |= (char32_t)str[i] & 0x3f;
}
- return unichar;
+ *ret_unichar = unichar;
+
+ return 0;
}
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
@@ -148,15 +152,16 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
assert(str);
for (p = str; length;) {
- int encoded_len, val;
+ int encoded_len, r;
+ char32_t val;
encoded_len = utf8_encoded_valid_unichar(p);
if (encoded_len < 0 ||
(size_t) encoded_len > length)
return false;
- val = utf8_encoded_to_unichar(p);
- if (val < 0 ||
+ r = utf8_encoded_to_unichar(p, &val);
+ if (r < 0 ||
unichar_is_control(val) ||
(!newline && val == '\n'))
return false;
@@ -276,7 +281,7 @@ char *ascii_is_valid(const char *str) {
* Returns: The length in bytes that the UTF-8 representation does or would
* occupy.
*/
-size_t utf8_encode_unichar(char *out_utf8, uint32_t g) {
+size_t utf8_encode_unichar(char *out_utf8, char32_t g) {
if (g < (1 << 7)) {
if (out_utf8)
@@ -320,7 +325,7 @@ char *utf16_to_utf8(const void *s, size_t length) {
t = r;
while (f < (const uint8_t*) s + length) {
- uint16_t w1, w2;
+ char16_t w1, w2;
/* see RFC 2781 section 2.2 */
@@ -354,7 +359,7 @@ char *utf16_to_utf8(const void *s, size_t length) {
}
/* expected size used to encode one unicode char */
-static int utf8_unichar_to_encoded_len(int unichar) {
+static int utf8_unichar_to_encoded_len(char32_t unichar) {
if (unichar < 0x80)
return 1;
@@ -372,7 +377,8 @@ static int utf8_unichar_to_encoded_len(int unichar) {
/* validate one encoded unicode char and return its length */
int utf8_encoded_valid_unichar(const char *str) {
- int len, unichar, i;
+ int len, i, r;
+ char32_t unichar;
assert(str);
@@ -389,7 +395,9 @@ int utf8_encoded_valid_unichar(const char *str) {
if ((str[i] & 0x80) != 0x80)
return -EINVAL;
- unichar = utf8_encoded_to_unichar(str);
+ r = utf8_encoded_to_unichar(str, &unichar);
+ if (r < 0)
+ return r;
/* check if encoded length matches encoded value */
if (utf8_unichar_to_encoded_len(unichar) != len)
diff --git a/src/basic/utf8.h b/src/basic/utf8.h
index 16c4b5b55d..3e2e35b967 100644
--- a/src/basic/utf8.h
+++ b/src/basic/utf8.h
@@ -24,12 +24,14 @@
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include <uchar.h>
#include "macro.h"
+#include "missing.h"
#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd"
-bool unichar_is_valid(uint32_t c);
+bool unichar_is_valid(char32_t c);
const char *utf8_is_valid(const char *s) _pure_;
char *ascii_is_valid(const char *s) _pure_;
@@ -40,20 +42,20 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pu
char *utf8_escape_invalid(const char *s);
char *utf8_escape_non_printable(const char *str);
-size_t utf8_encode_unichar(char *out_utf8, uint32_t g);
+size_t utf8_encode_unichar(char *out_utf8, char32_t g);
char *utf16_to_utf8(const void *s, size_t length);
int utf8_encoded_valid_unichar(const char *str);
-int utf8_encoded_to_unichar(const char *str);
+int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar);
-static inline bool utf16_is_surrogate(uint16_t c) {
+static inline bool utf16_is_surrogate(char16_t c) {
return (0xd800 <= c && c <= 0xdfff);
}
-static inline bool utf16_is_trailing_surrogate(uint16_t c) {
+static inline bool utf16_is_trailing_surrogate(char16_t c) {
return (0xdc00 <= c && c <= 0xdfff);
}
-static inline uint32_t utf16_surrogate_pair_to_unichar(uint16_t lead, uint16_t trail) {
+static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail) {
return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000;
}
diff --git a/src/basic/util.c b/src/basic/util.c
index 9e0b576283..4434ecfdf6 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -513,7 +513,7 @@ int on_ac_power(void) {
errno = 0;
de = readdir(d);
- if (!de && errno != 0)
+ if (!de && errno > 0)
return -errno;
if (!de)
diff --git a/src/basic/verbs.c b/src/basic/verbs.c
index 7feb47c48e..6dded9fb77 100644
--- a/src/basic/verbs.c
+++ b/src/basic/verbs.c
@@ -28,6 +28,7 @@
#include "macro.h"
#include "string-util.h"
#include "verbs.h"
+#include "virt.h"
int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
const Verb *verb;
@@ -84,6 +85,11 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) {
return -EINVAL;
}
+ if ((verb->flags & VERB_NOCHROOT) && running_in_chroot() > 0) {
+ log_info("Running in chroot, ignoring request.");
+ return 0;
+ }
+
if (name)
return verb->dispatch(left, argv + optind, userdata);
else {
diff --git a/src/basic/verbs.h b/src/basic/verbs.h
index d59e4d59b8..4132cad773 100644
--- a/src/basic/verbs.h
+++ b/src/basic/verbs.h
@@ -22,7 +22,8 @@
***/
#define VERB_ANY ((unsigned) -1)
-#define VERB_DEFAULT 1
+#define VERB_DEFAULT 1U
+#define VERB_NOCHROOT 2U
typedef struct {
const char *verb;