diff options
Diffstat (limited to 'src/shared')
35 files changed, 970 insertions, 289 deletions
diff --git a/src/shared/architecture.c b/src/shared/architecture.c index 884abdd3ea..8e72e7a36a 100644 --- a/src/shared/architecture.c +++ b/src/shared/architecture.c @@ -35,7 +35,7 @@ int uname_architecture(void) { * 1:1. Instead we try to clean it up and break down the * confusion on x86 and arm in particular. * - * We do not try to distuingish CPUs not CPU features, but + * We do not try to distinguish CPUs not CPU features, but * actual architectures, i.e. that have genuinely different * code. */ diff --git a/src/shared/architecture.h b/src/shared/architecture.h index cb82418a5e..f5bbf65a90 100644 --- a/src/shared/architecture.h +++ b/src/shared/architecture.h @@ -27,7 +27,7 @@ /* A cleaned up architecture definition. We don't want to get lost in * processor features, models, generations or even ABIs. Hence we - * focus on general family, and distuignish word width and + * focus on general family, and distinguish word width and * endianness. */ enum { diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index a3a2e51bb9..ef3788be68 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -37,7 +37,7 @@ #include "strv.h" #include "random-util.h" #include "terminal-util.h" - +#include "signal-util.h" #include "ask-password-api.h" static void backspace_chars(int ttyfd, size_t p) { diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c index 11e0947407..ab6fc171b0 100644 --- a/src/shared/base-filesystem.c +++ b/src/shared/base-filesystem.c @@ -41,13 +41,16 @@ static const BaseFilesystem table[] = { { "lib", 0, "usr/lib\0", NULL }, { "root", 0755, NULL, NULL }, { "sbin", 0, "usr/sbin\0", NULL }, + { "usr", 0755, NULL, NULL }, + { "var", 0755, NULL, NULL }, + { "etc", 0755, NULL, NULL }, #if defined(__i386__) || defined(__x86_64__) { "lib64", 0, "usr/lib/x86_64-linux-gnu\0" "usr/lib64\0", "ld-linux-x86-64.so.2" }, #endif }; -int base_filesystem_create(const char *root) { +int base_filesystem_create(const char *root, uid_t uid, gid_t gid) { _cleanup_close_ int fd = -1; unsigned i; int r = 0; @@ -90,6 +93,12 @@ int base_filesystem_create(const char *root) { r = symlinkat(target, fd, table[i].dir); if (r < 0 && errno != EEXIST) return log_error_errno(errno, "Failed to create symlink at %s/%s: %m", root, table[i].dir); + + if (uid != UID_INVALID || gid != UID_INVALID) { + if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0) + return log_error_errno(errno, "Failed to chown symlink at %s/%s: %m", root, table[i].dir); + } + continue; } @@ -97,6 +106,11 @@ int base_filesystem_create(const char *root) { r = mkdirat(fd, table[i].dir, table[i].mode); if (r < 0 && errno != EEXIST) return log_error_errno(errno, "Failed to create directory at %s/%s: %m", root, table[i].dir); + + if (uid != UID_INVALID || gid != UID_INVALID) { + if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0) + return log_error_errno(errno, "Failed to chown directory at %s/%s: %m", root, table[i].dir); + } } return 0; diff --git a/src/shared/base-filesystem.h b/src/shared/base-filesystem.h index 03201f7083..39a496090f 100644 --- a/src/shared/base-filesystem.h +++ b/src/shared/base-filesystem.h @@ -21,4 +21,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -int base_filesystem_create(const char *root); +#include <sys/types.h> + +int base_filesystem_create(const char *root, uid_t uid, gid_t gid); diff --git a/src/shared/capability.h b/src/shared/capability.h index 8260ae1a81..4eb5c2a835 100644 --- a/src/shared/capability.h +++ b/src/shared/capability.h @@ -31,7 +31,7 @@ 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 drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilites); +int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities); int drop_capability(cap_value_t cv); diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c index c0b0ca4cf2..9988e5c574 100644 --- a/src/shared/cgroup-util.c +++ b/src/shared/cgroup-util.c @@ -489,7 +489,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch if (_unlikely_(!good)) { int r; - r = path_is_mount_point("/sys/fs/cgroup", false); + r = path_is_mount_point("/sys/fs/cgroup", 0); if (r < 0) return r; if (r == 0) diff --git a/src/shared/condition.c b/src/shared/condition.c index 9f2574c2f6..24871b0dae 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -349,7 +349,7 @@ static int condition_test_path_is_mount_point(Condition *c) { assert(c->parameter); assert(c->type == CONDITION_PATH_IS_MOUNT_POINT); - return path_is_mount_point(c->parameter, true) > 0; + return path_is_mount_point(c->parameter, AT_SYMLINK_FOLLOW) > 0; } static int condition_test_path_is_read_write(Condition *c) { diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 2c855157a9..7370c786f9 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -444,7 +444,7 @@ int config_parse_many(const char *conf_file, if (r < 0) \ log_syntax(unit, LOG_ERR, filename, line, -r, \ "Failed to parse %s value, ignoring: %s", \ - #vartype, rvalue); \ + #type, rvalue); \ \ return 0; \ } diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c index cb15da8a5d..25ad918b85 100644 --- a/src/shared/dev-setup.c +++ b/src/shared/dev-setup.c @@ -23,13 +23,12 @@ #include <stdlib.h> #include <unistd.h> -#include "dev-setup.h" #include "util.h" #include "label.h" +#include "path-util.h" +#include "dev-setup.h" -int dev_setup(const char *prefix) { - const char *j, *k; - +int dev_setup(const char *prefix, uid_t uid, gid_t gid) { static const char symlinks[] = "-/proc/kcore\0" "/dev/core\0" "/proc/self/fd\0" "/dev/fd\0" @@ -37,7 +36,13 @@ int dev_setup(const char *prefix) { "/proc/self/fd/1\0" "/dev/stdout\0" "/proc/self/fd/2\0" "/dev/stderr\0"; + const char *j, *k; + int r; + NULSTR_FOREACH_PAIR(j, k, symlinks) { + _cleanup_free_ char *link_name = NULL; + const char *n; + if (j[0] == '-') { j++; @@ -46,15 +51,21 @@ int dev_setup(const char *prefix) { } if (prefix) { - _cleanup_free_ char *link_name = NULL; - - link_name = strjoin(prefix, "/", k, NULL); + link_name = prefix_root(prefix, k); if (!link_name) return -ENOMEM; - symlink_label(j, link_name); + n = link_name; } else - symlink_label(j, k); + n = k; + + r = symlink_label(j, n); + if (r < 0) + log_debug_errno(r, "Failed to symlink %s to %s: %m", j, n); + + if (uid != UID_INVALID || gid != GID_INVALID) + if (lchown(n, uid, gid) < 0) + log_debug_errno(errno, "Failed to chown %s: %m", n); } return 0; diff --git a/src/shared/dev-setup.h b/src/shared/dev-setup.h index d41b6eefba..ab2748db7f 100644 --- a/src/shared/dev-setup.h +++ b/src/shared/dev-setup.h @@ -21,4 +21,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -int dev_setup(const char *pathprefix); +#include <sys/types.h> + +int dev_setup(const char *prefix, uid_t uid, gid_t gid); diff --git a/src/shared/fdset.c b/src/shared/fdset.c index 31849272bd..6101b628ec 100644 --- a/src/shared/fdset.c +++ b/src/shared/fdset.c @@ -32,7 +32,7 @@ #define MAKE_SET(s) ((Set*) s) #define MAKE_FDSET(s) ((FDSet*) s) -/* Make sure we can distuingish fd 0 and NULL */ +/* Make sure we can distinguish fd 0 and NULL */ #define FD_TO_PTR(fd) INT_TO_PTR((fd)+1) #define PTR_TO_FD(p) (PTR_TO_INT(p)-1) diff --git a/src/shared/generator.c b/src/shared/generator.c index 81284995f5..807569a1b8 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -61,7 +61,7 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) { "[Service]\n" "Type=oneshot\n" "RemainAfterExit=yes\n" - "ExecStart=/usr/lib/systemd/systemd-fsck %2$s\n" + "ExecStart=" SYSTEMD_FSCK_PATH " %2$s\n" "TimeoutSec=0\n", program_invocation_short_name, what, diff --git a/src/shared/hostname-util.c b/src/shared/hostname-util.c index 2998fdf2c7..e336f269fa 100644 --- a/src/shared/hostname-util.c +++ b/src/shared/hostname-util.c @@ -158,3 +158,36 @@ int sethostname_idempotent(const char *s) { return 1; } + +int read_hostname_config(const char *path, char **hostname) { + _cleanup_fclose_ FILE *f = NULL; + char l[LINE_MAX]; + char *name = NULL; + + assert(path); + assert(hostname); + + f = fopen(path, "re"); + if (!f) + return -errno; + + /* may have comments, ignore them */ + FOREACH_LINE(l, f, return -errno) { + truncate_nl(l); + if (l[0] != '\0' && l[0] != '#') { + /* found line with value */ + name = hostname_cleanup(l, false); + name = strdup(name); + if (!name) + return -ENOMEM; + break; + } + } + + if (!name) + /* no non-empty line found */ + return -ENOENT; + + *hostname = name; + return 0; +} diff --git a/src/shared/hostname-util.h b/src/shared/hostname-util.h index f2821c3078..0c4763cf5a 100644 --- a/src/shared/hostname-util.h +++ b/src/shared/hostname-util.h @@ -35,3 +35,5 @@ char* hostname_cleanup(char *s, bool lowercase); bool is_localhost(const char *hostname); int sethostname_idempotent(const char *s); + +int read_hostname_config(const char *path, char **hostname); diff --git a/src/shared/import-util.c b/src/shared/import-util.c index 660d92ac5d..001a8a37e8 100644 --- a/src/shared/import-util.c +++ b/src/shared/import-util.c @@ -150,6 +150,27 @@ int raw_strip_suffixes(const char *p, char **ret) { return 0; } +bool dkr_digest_is_valid(const char *digest) { + /* 7 chars for prefix, 64 chars for the digest itself */ + if (strlen(digest) != 71) + return false; + + return startswith(digest, "sha256:") && in_charset(digest + 7, "0123456789abcdef"); +} + +bool dkr_ref_is_valid(const char *ref) { + const char *colon; + + if (isempty(ref)) + return false; + + colon = strchr(ref, ':'); + if (!colon) + return filename_is_valid(ref); + + return dkr_digest_is_valid(ref); +} + bool dkr_name_is_valid(const char *name) { const char *slash, *p; diff --git a/src/shared/import-util.h b/src/shared/import-util.h index ff155b0ff2..7bf7d4ca40 100644 --- a/src/shared/import-util.h +++ b/src/shared/import-util.h @@ -44,4 +44,6 @@ int raw_strip_suffixes(const char *name, char **ret); bool dkr_name_is_valid(const char *name); bool dkr_id_is_valid(const char *id); +bool dkr_ref_is_valid(const char *ref); +bool dkr_digest_is_valid(const char *digest); #define dkr_tag_is_valid(tag) filename_is_valid(tag) diff --git a/src/shared/json.c b/src/shared/json.c index 45c8ecedb3..be40a0d203 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -21,17 +21,178 @@ #include <sys/types.h> #include <math.h> - #include "macro.h" -#include "util.h" #include "utf8.h" #include "json.h" -enum { - STATE_NULL, - STATE_VALUE, - STATE_VALUE_POST, -}; +int json_variant_new(JsonVariant **ret, JsonVariantType type) { + JsonVariant *v; + + v = new0(JsonVariant, 1); + if (!v) + return -ENOMEM; + v->type = type; + *ret = v; + return 0; +} + +static int json_variant_deep_copy(JsonVariant *ret, JsonVariant *variant) { + int r; + + assert(ret); + assert(variant); + + ret->type = variant->type; + ret->size = variant->size; + + if (variant->type == JSON_VARIANT_STRING) { + ret->string = memdup(variant->string, variant->size+1); + if (!ret->string) + return -ENOMEM; + } else if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT) { + size_t i; + + ret->objects = new0(JsonVariant, variant->size); + if (!ret->objects) + return -ENOMEM; + + for (i = 0; i < variant->size; ++i) { + r = json_variant_deep_copy(&ret->objects[i], &variant->objects[i]); + if (r < 0) + return r; + } + } else + ret->value = variant->value; + + return 0; +} + +static JsonVariant *json_object_unref(JsonVariant *variant); + +static JsonVariant *json_variant_unref_inner(JsonVariant *variant) { + if (!variant) + return NULL; + + if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT) + return json_object_unref(variant); + else if (variant->type == JSON_VARIANT_STRING) + free(variant->string); + + return NULL; +} + +static JsonVariant *json_raw_unref(JsonVariant *variant, size_t size) { + if (!variant) + return NULL; + + for (size_t i = 0; i < size; ++i) + json_variant_unref_inner(&variant[i]); + + free(variant); + return NULL; +} + +static JsonVariant *json_object_unref(JsonVariant *variant) { + size_t i; + + assert(variant); + + if (!variant->objects) + return NULL; + + for (i = 0; i < variant->size; ++i) + json_variant_unref_inner(&variant->objects[i]); + + free(variant->objects); + return NULL; +} + +static JsonVariant **json_variant_array_unref(JsonVariant **variant) { + size_t i = 0; + JsonVariant *p = NULL; + + if (!variant) + return NULL; + + while((p = (variant[i++])) != NULL) { + if (p->type == JSON_VARIANT_STRING) + free(p->string); + free(p); + } + + free(variant); + + return NULL; +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant **, json_variant_array_unref); + +JsonVariant *json_variant_unref(JsonVariant *variant) { + if (!variant) + return NULL; + + if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT) + json_object_unref(variant); + else if (variant->type == JSON_VARIANT_STRING) + free(variant->string); + + free(variant); + + return NULL; +} + +char *json_variant_string(JsonVariant *variant){ + assert(variant); + assert(variant->type == JSON_VARIANT_STRING); + + return variant->string; +} + +bool json_variant_bool(JsonVariant *variant) { + assert(variant); + assert(variant->type == JSON_VARIANT_BOOLEAN); + + return variant->value.boolean; +} + +intmax_t json_variant_integer(JsonVariant *variant) { + assert(variant); + assert(variant->type == JSON_VARIANT_INTEGER); + + return variant->value.integer; +} + +double json_variant_real(JsonVariant *variant) { + assert(variant); + assert(variant->type == JSON_VARIANT_REAL); + + return variant->value.real; +} + +JsonVariant *json_variant_element(JsonVariant *variant, unsigned index) { + assert(variant); + assert(variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT); + assert(index < variant->size); + assert(variant->objects); + + return &variant->objects[index]; +} + +JsonVariant *json_variant_value(JsonVariant *variant, const char *key) { + size_t i; + + assert(variant); + assert(variant->type == JSON_VARIANT_OBJECT); + assert(variant->objects); + + for (i = 0; i < variant->size; i += 2) { + JsonVariant *p = &variant->objects[i]; + if (p->type == JSON_VARIANT_STRING && streq(key, p->string)) + return &variant->objects[i + 1]; + } + + return NULL; +} static void inc_lines(unsigned *line, const char *s, size_t n) { const char *p = s; @@ -285,9 +446,6 @@ static int json_parse_number(const char **p, union json_value *ret) { } while (strchr("0123456789", *c) && *c != 0); } - if (*c != 0) - return -EINVAL; - *p = c; if (is_double) { @@ -310,6 +468,12 @@ int json_tokenize( int t; int r; + enum { + STATE_NULL, + STATE_VALUE, + STATE_VALUE_POST, + }; + assert(p); assert(*p); assert(ret_string); @@ -443,3 +607,260 @@ int json_tokenize( } } + +static bool json_is_value(JsonVariant *var) { + assert(var); + + return var->type != JSON_VARIANT_CONTROL; +} + +static int json_scoped_parse(JsonVariant **tokens, size_t *i, size_t n, JsonVariant *scope) { + bool arr = scope->type == JSON_VARIANT_ARRAY; + int terminator = arr ? JSON_ARRAY_CLOSE : JSON_OBJECT_CLOSE; + size_t allocated = 0, size = 0; + JsonVariant *key = NULL, *value = NULL, *var = NULL, *items = NULL; + enum { + STATE_KEY, + STATE_COLON, + STATE_COMMA, + STATE_VALUE + } state = arr ? STATE_VALUE : STATE_KEY; + + assert(tokens); + assert(i); + assert(scope); + + while((var = *i < n ? tokens[(*i)++] : NULL) != NULL) { + bool stopper; + int r; + + stopper = !json_is_value(var) && var->value.integer == terminator; + + if (stopper) { + if (state != STATE_COMMA && size > 0) + goto error; + + goto out; + } + + if (state == STATE_KEY) { + if (var->type != JSON_VARIANT_STRING) + goto error; + else { + key = var; + state = STATE_COLON; + } + } + else if (state == STATE_COLON) { + if (key == NULL) + goto error; + + if (json_is_value(var)) + goto error; + + if (var->value.integer != JSON_COLON) + goto error; + + state = STATE_VALUE; + } + else if (state == STATE_VALUE) { + _cleanup_json_variant_unref_ JsonVariant *v = NULL; + size_t toadd = arr ? 1 : 2; + + if (!json_is_value(var)) { + int type = (var->value.integer == JSON_ARRAY_OPEN) ? JSON_VARIANT_ARRAY : JSON_VARIANT_OBJECT; + + r = json_variant_new(&v, type); + if (r < 0) + goto error; + + r = json_scoped_parse(tokens, i, n, v); + if (r < 0) + goto error; + + value = v; + } + else + value = var; + + if(!GREEDY_REALLOC(items, allocated, size + toadd)) + goto error; + + if (arr) { + r = json_variant_deep_copy(&items[size], value); + if (r < 0) + goto error; + } else { + r = json_variant_deep_copy(&items[size], key); + if (r < 0) + goto error; + + r = json_variant_deep_copy(&items[size+1], value); + if (r < 0) + goto error; + } + + size += toadd; + state = STATE_COMMA; + } + else if (state == STATE_COMMA) { + if (json_is_value(var)) + goto error; + + if (var->value.integer != JSON_COMMA) + goto error; + + key = NULL; + value = NULL; + + state = arr ? STATE_VALUE : STATE_KEY; + } + } + +error: + json_raw_unref(items, size); + return -EBADMSG; + +out: + scope->size = size; + scope->objects = items; + + return scope->type; +} + +static int json_parse_tokens(JsonVariant **tokens, size_t ntokens, JsonVariant **rv) { + size_t it = 0; + int r; + JsonVariant *e; + _cleanup_json_variant_unref_ JsonVariant *p = NULL; + + assert(tokens); + assert(ntokens); + + e = tokens[it++]; + r = json_variant_new(&p, JSON_VARIANT_OBJECT); + if (r < 0) + return r; + + if (e->type != JSON_VARIANT_CONTROL && e->value.integer != JSON_OBJECT_OPEN) + return -EBADMSG; + + r = json_scoped_parse(tokens, &it, ntokens, p); + if (r < 0) + return r; + + *rv = p; + p = NULL; + + return 0; +} + +static int json_tokens(const char *string, size_t size, JsonVariant ***tokens, size_t *n) { + _cleanup_free_ char *buf = NULL; + _cleanup_(json_variant_array_unrefp) JsonVariant **items = NULL; + union json_value v = {}; + void *json_state = NULL; + const char *p; + int t, r; + size_t allocated = 0, s = 0; + + assert(string); + assert(n); + + if (size <= 0) + return -EBADMSG; + + buf = strndup(string, size); + if (!buf) + return -ENOMEM; + + p = buf; + for (;;) { + _cleanup_json_variant_unref_ JsonVariant *var = NULL; + _cleanup_free_ char *rstr = NULL; + + t = json_tokenize(&p, &rstr, &v, &json_state, NULL); + + if (t < 0) + return t; + else if (t == JSON_END) + break; + + if (t <= JSON_ARRAY_CLOSE) { + r = json_variant_new(&var, JSON_VARIANT_CONTROL); + if (r < 0) + return r; + var->value.integer = t; + } else { + switch (t) { + case JSON_STRING: + r = json_variant_new(&var, JSON_VARIANT_STRING); + if (r < 0) + return r; + var->size = strlen(rstr); + var->string = strdup(rstr); + if (!var->string) { + return -ENOMEM; + } + break; + case JSON_INTEGER: + r = json_variant_new(&var, JSON_VARIANT_INTEGER); + if (r < 0) + return r; + var->value = v; + break; + case JSON_REAL: + r = json_variant_new(&var, JSON_VARIANT_REAL); + if (r < 0) + return r; + var->value = v; + break; + case JSON_BOOLEAN: + r = json_variant_new(&var, JSON_VARIANT_BOOLEAN); + if (r < 0) + return r; + var->value = v; + break; + case JSON_NULL: + r = json_variant_new(&var, JSON_VARIANT_NULL); + if (r < 0) + return r; + break; + } + } + + if (!GREEDY_REALLOC(items, allocated, s+2)) + return -ENOMEM; + + items[s++] = var; + items[s] = NULL; + var = NULL; + } + + *n = s; + *tokens = items; + items = NULL; + + return 0; +} + +int json_parse(const char *string, JsonVariant **rv) { + _cleanup_(json_variant_array_unrefp) JsonVariant **s = NULL; + JsonVariant *v = NULL; + size_t n = 0; + int r; + + assert(string); + assert(rv); + + r = json_tokens(string, strlen(string), &s, &n); + if (r < 0) + return r; + + r = json_parse_tokens(s, n, &v); + if (r < 0) + return r; + + *rv = v; + return 0; +} diff --git a/src/shared/json.h b/src/shared/json.h index 55976d513b..e0b4d810b5 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -22,6 +22,7 @@ ***/ #include <stdbool.h> +#include "util.h" enum { JSON_END, @@ -38,12 +39,50 @@ enum { JSON_NULL, }; +typedef enum { + JSON_VARIANT_CONTROL, + JSON_VARIANT_STRING, + JSON_VARIANT_INTEGER, + JSON_VARIANT_BOOLEAN, + JSON_VARIANT_REAL, + JSON_VARIANT_ARRAY, + JSON_VARIANT_OBJECT, + JSON_VARIANT_NULL +} JsonVariantType; + union json_value { bool boolean; double real; intmax_t integer; }; +typedef struct JsonVariant { + JsonVariantType type; + size_t size; + union { + char *string; + struct JsonVariant *objects; + union json_value value; + }; +} JsonVariant; + +int json_variant_new(JsonVariant **ret, JsonVariantType type); +JsonVariant *json_variant_unref(JsonVariant *v); + +DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant *, json_variant_unref); +#define _cleanup_json_variant_unref_ _cleanup_(json_variant_unrefp) + +char *json_variant_string(JsonVariant *v); +bool json_variant_bool(JsonVariant *v); +intmax_t json_variant_integer(JsonVariant *v); +double json_variant_real(JsonVariant *v); + +JsonVariant *json_variant_element(JsonVariant *v, unsigned index); +JsonVariant *json_variant_value(JsonVariant *v, const char *key); + #define JSON_VALUE_NULL ((union json_value) {}) int json_tokenize(const char **p, char **ret_string, union json_value *ret_value, void **state, unsigned *line); + +int json_parse(const char *string, JsonVariant **rv); +int json_parse_measure(const char *string, size_t *size); diff --git a/src/shared/log.c b/src/shared/log.c index 6168a2955d..b96afc4de4 100644 --- a/src/shared/log.c +++ b/src/shared/log.c @@ -38,6 +38,7 @@ #include "formats-util.h" #include "process-util.h" #include "terminal-util.h" +#include "signal-util.h" #define SNDBUF_SIZE (8*1024*1024) diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index 9920d150ab..d27931cb4a 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -30,6 +30,7 @@ #include "mkdir.h" #include "btrfs-util.h" #include "path-util.h" +#include "signal-util.h" #include "machine-pool.h" #define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL) @@ -198,7 +199,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) { return 0; } - if (path_is_mount_point("/var/lib/machines", true) > 0 || + if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0 || dir_is_empty("/var/lib/machines") == 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems."); diff --git a/src/shared/missing.h b/src/shared/missing.h index 8ca6f8edb6..9194009491 100644 --- a/src/shared/missing.h +++ b/src/shared/missing.h @@ -713,7 +713,7 @@ static inline int setns(int fd, int nstype) { #define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1) #endif -#if !HAVE_DECL_IFLA_VXLAN_LOCAL6 +#if !HAVE_DECL_IFLA_VXLAN_REMCSUM_NOPARTIAL #define IFLA_VXLAN_UNSPEC 0 #define IFLA_VXLAN_ID 1 #define IFLA_VXLAN_GROUP 2 @@ -732,7 +732,14 @@ static inline int setns(int fd, int nstype) { #define IFLA_VXLAN_PORT 15 #define IFLA_VXLAN_GROUP6 16 #define IFLA_VXLAN_LOCAL6 17 -#define __IFLA_VXLAN_MAX 18 +#define IFLA_VXLAN_UDP_CSUM 18 +#define IFLA_VXLAN_UDP_ZERO_CSUM6_TX 19 +#define IFLA_VXLAN_UDP_ZERO_CSUM6_RX 20 +#define IFLA_VXLAN_REMCSUM_TX 21 +#define IFLA_VXLAN_REMCSUM_RX 22 +#define IFLA_VXLAN_GBP 23 +#define IFLA_VXLAN_REMCSUM_NOPARTIAL 24 +#define __IFLA_VXLAN_MAX 25 #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) #endif diff --git a/src/shared/path-util.c b/src/shared/path-util.c index 7090989fcb..be50a1865d 100644 --- a/src/shared/path-util.c +++ b/src/shared/path-util.c @@ -509,7 +509,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id return safe_atoi(p, mnt_id); } -int fd_is_mount_point(int fd) { +int fd_is_mount_point(int fd, const char *filename, int flags) { union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; int mount_id = -1, mount_id_parent = -1; bool nosupp = false, check_st_dev = true; @@ -517,6 +517,7 @@ int fd_is_mount_point(int fd) { int r; assert(fd >= 0); + assert(filename); /* First we will try the name_to_handle_at() syscall, which * tells us the mount id and an opaque file "handle". It is @@ -541,7 +542,7 @@ int fd_is_mount_point(int fd) { * subvolumes have different st_dev, even though they aren't * real mounts of their own. */ - r = name_to_handle_at(fd, "", &h.handle, &mount_id, AT_EMPTY_PATH); + r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); if (r < 0) { if (errno == ENOSYS) /* This kernel does not support name_to_handle_at() @@ -558,7 +559,7 @@ int fd_is_mount_point(int fd) { return -errno; } - r = name_to_handle_at(fd, "..", &h_parent.handle, &mount_id_parent, 0); + r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); if (r < 0) { if (errno == EOPNOTSUPP) { if (nosupp) @@ -593,13 +594,13 @@ int fd_is_mount_point(int fd) { return mount_id != mount_id_parent; fallback_fdinfo: - r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id); + r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); if (r == -EOPNOTSUPP) goto fallback_fstat; if (r < 0) return r; - r = fd_fdinfo_mnt_id(fd, "..", 0, &mount_id_parent); + r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); if (r < 0) return r; @@ -615,10 +616,16 @@ fallback_fdinfo: check_st_dev = false; fallback_fstat: - if (fstatat(fd, "", &a, AT_EMPTY_PATH) < 0) + /* yay for fstatat() taking a different set of flags than the other + * _at() above */ + if (flags & AT_SYMLINK_FOLLOW) + flags &= ~AT_SYMLINK_FOLLOW; + else + flags |= AT_SYMLINK_NOFOLLOW; + if (fstatat(fd, filename, &a, flags) < 0) return -errno; - if (fstatat(fd, "..", &b, 0) < 0) + if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) return -errno; /* A directory with same device and inode as its parent? Must @@ -630,19 +637,26 @@ fallback_fstat: return check_st_dev && (a.st_dev != b.st_dev); } -int path_is_mount_point(const char *t, bool allow_symlink) { +/* flags can be AT_SYMLINK_FOLLOW or 0 */ +int path_is_mount_point(const char *t, int flags) { _cleanup_close_ int fd = -1; + _cleanup_free_ char *parent = NULL; + int r; assert(t); if (path_equal(t, "/")) return 1; - fd = openat(AT_FDCWD, t, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|(allow_symlink ? 0 : O_PATH)); + r = path_get_parent(t, &parent); + if (r < 0) + return r; + + fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); if (fd < 0) return -errno; - return fd_is_mount_point(fd); + return fd_is_mount_point(fd, basename(t), flags); } int path_is_read_only_fs(const char *path) { diff --git a/src/shared/path-util.h b/src/shared/path-util.h index 4f45cfd2b7..1eac89c51b 100644 --- a/src/shared/path-util.h +++ b/src/shared/path-util.h @@ -53,8 +53,8 @@ char** path_strv_make_absolute_cwd(char **l); char** path_strv_resolve(char **l, const char *prefix); char** path_strv_resolve_uniq(char **l, const char *prefix); -int fd_is_mount_point(int fd); -int path_is_mount_point(const char *path, bool allow_symlink); +int fd_is_mount_point(int fd, const char *filename, int flags); +int path_is_mount_point(const char *path, int flags); int path_is_read_only_fs(const char *path); int path_is_os_tree(const char *path); diff --git a/src/shared/process-util.c b/src/shared/process-util.c index 92a69f50e7..cfc876567d 100644 --- a/src/shared/process-util.c +++ b/src/shared/process-util.c @@ -28,10 +28,11 @@ #include <signal.h> #include <ctype.h> -#include "process-util.h" #include "fileio.h" #include "util.h" #include "log.h" +#include "signal-util.h" +#include "process-util.h" int get_process_state(pid_t pid) { const char *p; diff --git a/src/shared/pty.c b/src/shared/pty.c index 0f80f4863b..119d66e9a2 100644 --- a/src/shared/pty.c +++ b/src/shared/pty.c @@ -57,9 +57,10 @@ #include "barrier.h" #include "macro.h" -#include "pty.h" #include "ring.h" #include "util.h" +#include "signal-util.h" +#include "pty.h" #define PTY_BUFSIZE 4096 diff --git a/src/shared/random-util.c b/src/shared/random-util.c index 88f5182508..b230044f50 100644 --- a/src/shared/random-util.c +++ b/src/shared/random-util.c @@ -23,7 +23,9 @@ #include <sys/stat.h> #include <fcntl.h> #include <time.h> +#ifdef HAVE_SYS_AUXV_H #include <sys/auxv.h> +#endif #include <linux/random.h> #include "random-util.h" diff --git a/src/shared/rm-rf.c b/src/shared/rm-rf.c index a89e8afc2a..bafd483be2 100644 --- a/src/shared/rm-rf.c +++ b/src/shared/rm-rf.c @@ -103,7 +103,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { } /* Stop at mount points */ - r = fd_is_mount_point(subdir_fd); + r = fd_is_mount_point(fd, de->d_name, 0); if (r < 0) { if (ret == 0 && r != -ENOENT) ret = r; diff --git a/src/shared/signal-util.c b/src/shared/signal-util.c new file mode 100644 index 0000000000..9a2973b6fd --- /dev/null +++ b/src/shared/signal-util.c @@ -0,0 +1,228 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 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 "util.h" +#include "signal-util.h" + +int reset_all_signal_handlers(void) { + int sig, r = 0; + + for (sig = 1; sig < _NSIG; sig++) { + static const struct sigaction sa = { + .sa_handler = SIG_DFL, + .sa_flags = SA_RESTART, + }; + + /* These two cannot be caught... */ + if (sig == SIGKILL || sig == SIGSTOP) + continue; + + /* On Linux the first two RT signals are reserved by + * glibc, and sigaction() will return EINVAL for them. */ + if ((sigaction(sig, &sa, NULL) < 0)) + if (errno != EINVAL && r == 0) + r = -errno; + } + + return r; +} + +int reset_signal_mask(void) { + sigset_t ss; + + if (sigemptyset(&ss) < 0) + return -errno; + + if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) + return -errno; + + return 0; +} + +int sigaction_many(const struct sigaction *sa, ...) { + va_list ap; + int r = 0, sig; + + va_start(ap, sa); + while ((sig = va_arg(ap, int)) > 0) + if (sigaction(sig, sa, NULL) < 0) + r = -errno; + va_end(ap); + + return r; +} + +int ignore_signals(int sig, ...) { + static const struct sigaction sa = { + .sa_handler = SIG_IGN, + .sa_flags = SA_RESTART, + }; + va_list ap; + int r = 0; + + if (sigaction(sig, &sa, NULL) < 0) + r = -errno; + + va_start(ap, sig); + while ((sig = va_arg(ap, int)) > 0) + if (sigaction(sig, &sa, NULL) < 0) + r = -errno; + va_end(ap); + + return r; +} + +int default_signals(int sig, ...) { + static const struct sigaction sa = { + .sa_handler = SIG_DFL, + .sa_flags = SA_RESTART, + }; + va_list ap; + int r = 0; + + if (sigaction(sig, &sa, NULL) < 0) + r = -errno; + + va_start(ap, sig); + while ((sig = va_arg(ap, int)) > 0) + if (sigaction(sig, &sa, NULL) < 0) + r = -errno; + va_end(ap); + + return r; +} + +void sigset_add_many(sigset_t *ss, ...) { + va_list ap; + int sig; + + assert(ss); + + va_start(ap, ss); + while ((sig = va_arg(ap, int)) > 0) + assert_se(sigaddset(ss, sig) == 0); + va_end(ap); +} + +int sigprocmask_many(int how, ...) { + va_list ap; + sigset_t ss; + int sig; + + assert_se(sigemptyset(&ss) == 0); + + va_start(ap, how); + while ((sig = va_arg(ap, int)) > 0) + assert_se(sigaddset(&ss, sig) == 0); + va_end(ap); + + if (sigprocmask(how, &ss, NULL) < 0) + return -errno; + + return 0; +} + +static const char *const __signal_table[] = { + [SIGHUP] = "HUP", + [SIGINT] = "INT", + [SIGQUIT] = "QUIT", + [SIGILL] = "ILL", + [SIGTRAP] = "TRAP", + [SIGABRT] = "ABRT", + [SIGBUS] = "BUS", + [SIGFPE] = "FPE", + [SIGKILL] = "KILL", + [SIGUSR1] = "USR1", + [SIGSEGV] = "SEGV", + [SIGUSR2] = "USR2", + [SIGPIPE] = "PIPE", + [SIGALRM] = "ALRM", + [SIGTERM] = "TERM", +#ifdef SIGSTKFLT + [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */ +#endif + [SIGCHLD] = "CHLD", + [SIGCONT] = "CONT", + [SIGSTOP] = "STOP", + [SIGTSTP] = "TSTP", + [SIGTTIN] = "TTIN", + [SIGTTOU] = "TTOU", + [SIGURG] = "URG", + [SIGXCPU] = "XCPU", + [SIGXFSZ] = "XFSZ", + [SIGVTALRM] = "VTALRM", + [SIGPROF] = "PROF", + [SIGWINCH] = "WINCH", + [SIGIO] = "IO", + [SIGPWR] = "PWR", + [SIGSYS] = "SYS" +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); + +const char *signal_to_string(int signo) { + static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; + const char *name; + + name = __signal_to_string(signo); + if (name) + return name; + + if (signo >= SIGRTMIN && signo <= SIGRTMAX) + snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN); + else + snprintf(buf, sizeof(buf), "%d", signo); + + return buf; +} + +int signal_from_string(const char *s) { + int signo; + int offset = 0; + unsigned u; + + signo = __signal_from_string(s); + if (signo > 0) + return signo; + + if (startswith(s, "RTMIN+")) { + s += 6; + offset = SIGRTMIN; + } + if (safe_atou(s, &u) >= 0) { + signo = (int) u + offset; + if (signo > 0 && signo < _NSIG) + return signo; + } + return -EINVAL; +} + +int signal_from_string_try_harder(const char *s) { + int signo; + assert(s); + + signo = signal_from_string(s); + if (signo <= 0) + if (startswith(s, "SIG")) + return signal_from_string(s+3); + + return signo; +} diff --git a/src/shared/signal-util.h b/src/shared/signal-util.h new file mode 100644 index 0000000000..ddf64cda76 --- /dev/null +++ b/src/shared/signal-util.h @@ -0,0 +1,41 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2015 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 <signal.h> + +#include "macro.h" + +int reset_all_signal_handlers(void); +int reset_signal_mask(void); + +int ignore_signals(int sig, ...); +int default_signals(int sig, ...); +int sigaction_many(const struct sigaction *sa, ...); + +void sigset_add_many(sigset_t *ss, ...); +int sigprocmask_many(int how, ...); + +const char *signal_to_string(int i) _const_; +int signal_from_string(const char *s) _pure_; + +int signal_from_string_try_harder(const char *s); diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index ae3839de16..b12189cd10 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -105,7 +105,7 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, * to look like. They might even boot, if they are RO and * don't have the FS layout. Just ignore the error and * switch_root() nevertheless. */ - (void) base_filesystem_create(new_root); + (void) base_filesystem_create(new_root, UID_INVALID, GID_INVALID); if (chdir(new_root) < 0) return log_error_errno(errno, "Failed to change directory to %s: %m", new_root); diff --git a/src/shared/unit-name.c b/src/shared/unit-name.c index b23e47a2e6..bf52463d81 100644 --- a/src/shared/unit-name.c +++ b/src/shared/unit-name.c @@ -812,6 +812,8 @@ static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_PART_OF] = "PartOf", [UNIT_REQUIRED_BY] = "RequiredBy", [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable", + [UNIT_REQUISITE_OF] = "RequisiteOf", + [UNIT_REQUISITE_OF_OVERRIDABLE] = "RequisiteOfOverridable", [UNIT_WANTED_BY] = "WantedBy", [UNIT_BOUND_BY] = "BoundBy", [UNIT_CONSISTS_OF] = "ConsistsOf", diff --git a/src/shared/unit-name.h b/src/shared/unit-name.h index c2f31e3f90..b2043d0870 100644 --- a/src/shared/unit-name.h +++ b/src/shared/unit-name.h @@ -71,8 +71,10 @@ enum UnitDependency { UNIT_PART_OF, /* Inverse of the above */ - UNIT_REQUIRED_BY, /* inverse of 'requires' and 'requisite' is 'required_by' */ - UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' and 'requisite_overridable' is 'soft_required_by' */ + UNIT_REQUIRED_BY, /* inverse of 'requires' is 'required_by' */ + UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' is 'required_by_overridable' */ + UNIT_REQUISITE_OF, /* inverse of 'requisite' is 'requisite_of' */ + UNIT_REQUISITE_OF_OVERRIDABLE,/* inverse of 'requisite_overridable' is 'requisite_of_overridable' */ UNIT_WANTED_BY, /* inverse of 'wants' */ UNIT_BOUND_BY, /* inverse of 'binds_to' */ UNIT_CONSISTS_OF, /* inverse of 'part_of' */ diff --git a/src/shared/util.c b/src/shared/util.c index da6343f4c4..8a6107969a 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -93,6 +93,7 @@ #include "random-util.h" #include "terminal-util.h" #include "hostname-util.h" +#include "signal-util.h" /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); @@ -148,6 +149,27 @@ char* endswith(const char *s, const char *postfix) { return (char*) s + sl - pl; } +char* endswith_no_case(const char *s, const char *postfix) { + size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (char*) s + sl; + + if (sl < pl) + return NULL; + + if (strcasecmp(s + sl - pl, postfix) != 0) + return NULL; + + return (char*) s + sl - pl; +} + char* first_word(const char *s, const char *word) { size_t sl, wl; const char *p; @@ -750,41 +772,6 @@ int readlink_and_canonicalize(const char *p, char **r) { return 0; } -int reset_all_signal_handlers(void) { - int sig, r = 0; - - for (sig = 1; sig < _NSIG; sig++) { - struct sigaction sa = { - .sa_handler = SIG_DFL, - .sa_flags = SA_RESTART, - }; - - /* These two cannot be caught... */ - if (sig == SIGKILL || sig == SIGSTOP) - continue; - - /* On Linux the first two RT signals are reserved by - * glibc, and sigaction() will return EINVAL for them. */ - if ((sigaction(sig, &sa, NULL) < 0)) - if (errno != EINVAL && r == 0) - r = -errno; - } - - return r; -} - -int reset_signal_mask(void) { - sigset_t ss; - - if (sigemptyset(&ss) < 0) - return -errno; - - if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) - return -errno; - - return 0; -} - char *strstrip(char *s) { char *e; @@ -1540,59 +1527,6 @@ int flush_fd(int fd) { } } -int sigaction_many(const struct sigaction *sa, ...) { - va_list ap; - int r = 0, sig; - - va_start(ap, sa); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - -int ignore_signals(int sig, ...) { - struct sigaction sa = { - .sa_handler = SIG_IGN, - .sa_flags = SA_RESTART, - }; - va_list ap; - int r = 0; - - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - - va_start(ap, sig); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - -int default_signals(int sig, ...) { - struct sigaction sa = { - .sa_handler = SIG_DFL, - .sa_flags = SA_RESTART, - }; - va_list ap; - int r = 0; - - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - - va_start(ap, sig); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - void safe_close_pair(int p[]) { assert(p); @@ -1697,7 +1631,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { int parse_size(const char *t, off_t base, off_t *size) { - /* Soo, sometimes we want to parse IEC binary suffxies, and + /* Soo, sometimes we want to parse IEC binary suffixes, and * sometimes SI decimal suffixes. This function can parse * both. Which one is the right way depends on the * context. Wikipedia suggests that SI is customary for @@ -1906,35 +1840,6 @@ void rename_process(const char name[8]) { } } -void sigset_add_many(sigset_t *ss, ...) { - va_list ap; - int sig; - - assert(ss); - - va_start(ap, ss); - while ((sig = va_arg(ap, int)) > 0) - assert_se(sigaddset(ss, sig) == 0); - va_end(ap); -} - -int sigprocmask_many(int how, ...) { - va_list ap; - sigset_t ss; - int sig; - - assert_se(sigemptyset(&ss) == 0); - - va_start(ap, how); - while ((sig = va_arg(ap, int)) > 0) - assert_se(sigaddset(&ss, sig) == 0); - va_end(ap); - - if (sigprocmask(how, &ss, NULL) < 0) - return -errno; - - return 0; -} char *lookup_uid(uid_t uid) { long bufsize; char *name; @@ -2323,18 +2228,6 @@ DIR *xopendirat(int fd, const char *name, int flags) { return d; } -int signal_from_string_try_harder(const char *s) { - int signo; - assert(s); - - signo = signal_from_string(s); - if (signo <= 0) - if (startswith(s, "SIG")) - return signal_from_string(s+3); - - return signo; -} - static char *tag_to_udev_node(const char *tagvalue, const char *by) { _cleanup_free_ char *t = NULL, *u = NULL; size_t enc_len; @@ -3291,81 +3184,6 @@ static const char* const ip_tos_table[] = { DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); -static const char *const __signal_table[] = { - [SIGHUP] = "HUP", - [SIGINT] = "INT", - [SIGQUIT] = "QUIT", - [SIGILL] = "ILL", - [SIGTRAP] = "TRAP", - [SIGABRT] = "ABRT", - [SIGBUS] = "BUS", - [SIGFPE] = "FPE", - [SIGKILL] = "KILL", - [SIGUSR1] = "USR1", - [SIGSEGV] = "SEGV", - [SIGUSR2] = "USR2", - [SIGPIPE] = "PIPE", - [SIGALRM] = "ALRM", - [SIGTERM] = "TERM", -#ifdef SIGSTKFLT - [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */ -#endif - [SIGCHLD] = "CHLD", - [SIGCONT] = "CONT", - [SIGSTOP] = "STOP", - [SIGTSTP] = "TSTP", - [SIGTTIN] = "TTIN", - [SIGTTOU] = "TTOU", - [SIGURG] = "URG", - [SIGXCPU] = "XCPU", - [SIGXFSZ] = "XFSZ", - [SIGVTALRM] = "VTALRM", - [SIGPROF] = "PROF", - [SIGWINCH] = "WINCH", - [SIGIO] = "IO", - [SIGPWR] = "PWR", - [SIGSYS] = "SYS" -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); - -const char *signal_to_string(int signo) { - static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; - const char *name; - - name = __signal_to_string(signo); - if (name) - return name; - - if (signo >= SIGRTMIN && signo <= SIGRTMAX) - snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN); - else - snprintf(buf, sizeof(buf), "%d", signo); - - return buf; -} - -int signal_from_string(const char *s) { - int signo; - int offset = 0; - unsigned u; - - signo = __signal_from_string(s); - if (signo > 0) - return signo; - - if (startswith(s, "RTMIN+")) { - s += 6; - offset = SIGRTMIN; - } - if (safe_atou(s, &u) >= 0) { - signo = (int) u + offset; - if (signo > 0 && signo < _NSIG) - return signo; - } - return -EINVAL; -} - bool kexec_loaded(void) { bool loaded = false; char *s; @@ -4665,16 +4483,7 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) { return -errno; } - if (setresgid(0, 0, 0) < 0) - return -errno; - - if (setgroups(0, NULL) < 0) - return -errno; - - if (setresuid(0, 0, 0) < 0) - return -errno; - - return 0; + return reset_uid_gid(); } int getpeercred(int fd, struct ucred *ucred) { @@ -4825,10 +4634,7 @@ unsigned long personality_from_string(const char *p) { return PER_LINUX; #endif - /* personality(7) documents that 0xffffffffUL is used for - * querying the current personality, hence let's use that here - * as error indicator. */ - return 0xffffffffUL; + return PERSONALITY_INVALID; } const char* personality_to_string(unsigned long p) { @@ -5878,7 +5684,7 @@ int same_fd(int a, int b) { /* The fds refer to the same inode on disk, let's also check * if they have the same fd flags. This is useful to - * distuingish the read and write side of a pipe created with + * distinguish the read and write side of a pipe created with * pipe(). */ fa = fcntl(a, F_GETFL); if (fa < 0) @@ -6208,3 +6014,35 @@ int parse_mode(const char *s, mode_t *ret) { *ret = (mode_t) l; return 0; } + +int mount_move_root(const char *path) { + assert(path); + + if (chdir(path) < 0) + return -errno; + + if (mount(path, "/", NULL, MS_MOVE, NULL) < 0) + return -errno; + + if (chroot(".") < 0) + return -errno; + + if (chdir("/") < 0) + return -errno; + + return 0; +} + +int reset_uid_gid(void) { + + if (setgroups(0, NULL) < 0) + return -errno; + + if (setresgid(0, 0, 0) < 0) + return -errno; + + if (setresuid(0, 0, 0) < 0) + return -errno; + + return 0; +} diff --git a/src/shared/util.h b/src/shared/util.h index a2b1ec5030..467ae234a0 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -29,7 +29,6 @@ #include <stdbool.h> #include <stdlib.h> #include <stdio.h> -#include <signal.h> #include <sched.h> #include <limits.h> #include <sys/types.h> @@ -134,6 +133,7 @@ static inline char *startswith_no_case(const char *s, const char *prefix) { } char *endswith(const char *s, const char *postfix) _pure_; +char *endswith_no_case(const char *s, const char *postfix) _pure_; char *first_word(const char *s, const char *word) _pure_; @@ -226,9 +226,6 @@ int readlink_value(const char *p, char **ret); int readlink_and_make_absolute(const char *p, char **r); int readlink_and_canonicalize(const char *p, char **r); -int reset_all_signal_handlers(void); -int reset_signal_mask(void); - char *strstrip(char *s); char *delete_chars(char *s, const char *bad); char *truncate_nl(char *s); @@ -333,10 +330,6 @@ bool fstype_is_network(const char *fstype); int flush_fd(int fd); -int ignore_signals(int sig, ...); -int default_signals(int sig, ...); -int sigaction_many(const struct sigaction *sa, ...); - int fopen_temporary(const char *path, FILE **_f, char **_temp_path); ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); @@ -348,9 +341,6 @@ bool is_device_path(const char *path); int dir_is_empty(const char *path); char* dirname_malloc(const char *path); -void sigset_add_many(sigset_t *ss, ...); -int sigprocmask_many(int how, ...); - char* lookup_uid(uid_t uid); char* getlogname_malloc(void); char* getusername_malloc(void); @@ -464,11 +454,6 @@ int rlimit_from_string(const char *s) _pure_; int ip_tos_to_string_alloc(int i, char **s); int ip_tos_from_string(const char *s); -const char *signal_to_string(int i) _const_; -int signal_from_string(const char *s) _pure_; - -int signal_from_string_try_harder(const char *s); - extern int saved_argc; extern char **saved_argv; @@ -774,7 +759,7 @@ int shall_restore_state(void); * that only if nmemb > 0. */ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) { - if (nmemb <= 0) + if (nmemb <= 1) return; assert(base); @@ -815,6 +800,13 @@ int open_tmpfile(const char *path, int flags); int fd_warn_permissions(const char *path, int fd); +#ifndef PERSONALITY_INVALID +/* personality(7) documents that 0xffffffffUL is used for querying the + * current personality, hence let's use that here as error + * indicator. */ +#define PERSONALITY_INVALID 0xffffffffLU +#endif + unsigned long personality_from_string(const char *p); const char *personality_to_string(unsigned long); @@ -905,3 +897,7 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char char *shell_maybe_quote(const char *s); int parse_mode(const char *s, mode_t *ret); + +int mount_move_root(const char *path); + +int reset_uid_gid(void); |