diff options
Diffstat (limited to 'src')
61 files changed, 1654 insertions, 617 deletions
diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c index d559be1bbb..bf9d8d4d7c 100644 --- a/src/basic/bitmap.c +++ b/src/basic/bitmap.c @@ -24,7 +24,7 @@ #include "bitmap.h" struct Bitmap { - long long unsigned *bitmaps; + uint64_t *bitmaps; size_t n_bitmaps; size_t bitmaps_allocated; }; @@ -37,9 +37,9 @@ struct Bitmap { /* This indicates that we reached the end of the bitmap */ #define BITMAP_END ((unsigned) -1) -#define BITMAP_NUM_TO_OFFSET(n) ((n) / (sizeof(long long unsigned) * 8)) -#define BITMAP_NUM_TO_REM(n) ((n) % (sizeof(long long unsigned) * 8)) -#define BITMAP_OFFSET_TO_NUM(offset, rem) ((offset) * sizeof(long long unsigned) * 8 + (rem)) +#define BITMAP_NUM_TO_OFFSET(n) ((n) / (sizeof(uint64_t) * 8)) +#define BITMAP_NUM_TO_REM(n) ((n) % (sizeof(uint64_t) * 8)) +#define BITMAP_OFFSET_TO_NUM(offset, rem) ((offset) * sizeof(uint64_t) * 8 + (rem)) Bitmap *bitmap_new(void) { return new0(Bitmap, 1); @@ -56,6 +56,8 @@ void bitmap_free(Bitmap *b) { int bitmap_ensure_allocated(Bitmap **b) { Bitmap *a; + assert(b); + if (*b) return 0; @@ -69,7 +71,7 @@ int bitmap_ensure_allocated(Bitmap **b) { } int bitmap_set(Bitmap *b, unsigned n) { - long long bitmask; + uint64_t bitmask; unsigned offset; assert(b); @@ -87,7 +89,7 @@ int bitmap_set(Bitmap *b, unsigned n) { b->n_bitmaps = offset + 1; } - bitmask = 1 << BITMAP_NUM_TO_REM(n); + bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n); b->bitmaps[offset] |= bitmask; @@ -95,26 +97,27 @@ int bitmap_set(Bitmap *b, unsigned n) { } void bitmap_unset(Bitmap *b, unsigned n) { - long long bitmask; + uint64_t bitmask; unsigned offset; - assert(b); + if (!b) + return; offset = BITMAP_NUM_TO_OFFSET(n); if (offset >= b->n_bitmaps) return; - bitmask = 1 << BITMAP_NUM_TO_REM(n); + bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n); b->bitmaps[offset] &= ~bitmask; } bool bitmap_isset(Bitmap *b, unsigned n) { - long long bitmask; + uint64_t bitmask; unsigned offset; - if (!b || !b->bitmaps) + if (!b) return false; offset = BITMAP_NUM_TO_OFFSET(n); @@ -122,7 +125,7 @@ bool bitmap_isset(Bitmap *b, unsigned n) { if (offset >= b->n_bitmaps) return false; - bitmask = 1 << BITMAP_NUM_TO_REM(n); + bitmask = UINT64_C(1) << BITMAP_NUM_TO_REM(n); return !!(b->bitmaps[offset] & bitmask); } @@ -133,31 +136,31 @@ bool bitmap_isclear(Bitmap *b) { assert(b); for (i = 0; i < b->n_bitmaps; i++) - if (b->bitmaps[i]) + if (b->bitmaps[i] != 0) return false; return true; } void bitmap_clear(Bitmap *b) { - unsigned i; - assert(b); - for (i = 0; i < b->n_bitmaps; i++) - b->bitmaps[i] = 0; + b->n_bitmaps = 0; } bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n) { - long long bitmask; + uint64_t bitmask; unsigned offset, rem; - if (!b && i->idx == BITMAP_END) + assert(i); + assert(n); + + if (!b || i->idx == BITMAP_END) return false; offset = BITMAP_NUM_TO_OFFSET(i->idx); rem = BITMAP_NUM_TO_REM(i->idx); - bitmask = 1 << rem; + bitmask = UINT64_C(1) << rem; for (; offset < b->n_bitmaps; offset ++) { if (b->bitmaps[offset]) { @@ -181,7 +184,6 @@ bool bitmap_iterate(Bitmap *b, Iterator *i, unsigned *n) { } bool bitmap_equal(Bitmap *a, Bitmap *b) { - unsigned i; if (!a ^ !b) return false; @@ -192,9 +194,5 @@ bool bitmap_equal(Bitmap *a, Bitmap *b) { if (a->n_bitmaps != b->n_bitmaps) return false; - for (i = 0; i < a->n_bitmaps; i++) - if (a->bitmaps[i] != b->bitmaps[i]) - return false; - - return true; + return memcmp(a->bitmaps, b->bitmaps, sizeof(uint64_t) * a->n_bitmaps) == 0; } diff --git a/src/basic/copy.c b/src/basic/copy.c index 230e7e4d3f..e2d356d676 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -24,6 +24,7 @@ #include "util.h" #include "btrfs-util.h" +#include "strv.h" #include "copy.h" #define COPY_BUFFER_SIZE (16*1024) @@ -262,10 +263,13 @@ static int fd_copy_directory( (void) copy_xattr(dirfd(d), fdt); } - FOREACH_DIRENT(de, d, return -errno) { + FOREACH_DIRENT_ALL(de, d, return -errno) { struct stat buf; int q; + if (STR_IN_SET(de->d_name, ".", "..")) + continue; + if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) { r = -errno; continue; diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c index 5ab36825c0..fcff753ada 100644 --- a/src/basic/exit-status.c +++ b/src/basic/exit-status.c @@ -151,6 +151,9 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { case EXIT_BUS_ENDPOINT: return "BUS_ENDPOINT"; + + case EXIT_SMACK_PROCESS_LABEL: + return "SMACK_PROCESS_LABEL"; } } diff --git a/src/basic/fileio.c b/src/basic/fileio.c index d592bf5ac9..2216853777 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -786,7 +786,7 @@ int executable_is_script(const char *path, char **interpreter) { */ int get_status_field(const char *filename, const char *pattern, char **field) { _cleanup_free_ char *status = NULL; - char *t; + char *t, *f; size_t len; int r; @@ -820,9 +820,10 @@ int get_status_field(const char *filename, const char *pattern, char **field) { len = strcspn(t, WHITESPACE); - *field = strndup(t, len); - if (!*field) + f = strndup(t, len); + if (!f) return -ENOMEM; + *field = f; return 0; } diff --git a/src/basic/macro.h b/src/basic/macro.h index 5fa17ed208..627d768b76 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -26,6 +26,7 @@ #include <sys/types.h> #include <sys/uio.h> #include <inttypes.h> +#include <stdbool.h> #define _printf_(a,b) __attribute__ ((format (printf, a, b))) #define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) @@ -406,12 +407,12 @@ do { \ #define IN_SET(x, y, ...) \ ({ \ - const typeof(y) _y = (y); \ - const typeof(_y) _x = (x); \ + static const typeof(y) _array[] = { (y), __VA_ARGS__ }; \ + const typeof(y) _x = (x); \ unsigned _i; \ bool _found = false; \ - for (_i = 0; _i < 1 + sizeof((const typeof(_x)[]) { __VA_ARGS__ })/sizeof(const typeof(_x)); _i++) \ - if (((const typeof(_x)[]) { _y, __VA_ARGS__ })[_i] == _x) { \ + for (_i = 0; _i < ELEMENTSOF(_array); _i++) \ + if (_array[_i] == _x) { \ _found = true; \ break; \ } \ @@ -461,6 +462,18 @@ do { \ #define GID_INVALID ((gid_t) -1) #define MODE_INVALID ((mode_t) -1) +static inline bool UID_IS_INVALID(uid_t uid) { + /* We consider both the old 16bit -1 user and the newer 32bit + * -1 user invalid, since they are or used to be incompatible + * with syscalls such as setresuid() or chown(). */ + + return uid == (uid_t) ((uint32_t) -1) || uid == (uid_t) ((uint16_t) -1); +} + +static inline bool GID_IS_INVALID(gid_t gid) { + return gid == (gid_t) ((uint32_t) -1) || gid == (gid_t) ((uint16_t) -1); +} + #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ static inline void func##p(type *p) { \ if (*p) \ diff --git a/src/basic/missing.h b/src/basic/missing.h index be7f6186fc..ed6cd80c75 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -772,7 +772,7 @@ static inline int setns(int fd, int nstype) { #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) #endif -#if !HAVE_DECL_IFLA_IPTUN_6RD_RELAY_PREFIXLEN +#if !HAVE_DECL_IFLA_IPTUN_ENCAP_DPORT #define IFLA_IPTUN_UNSPEC 0 #define IFLA_IPTUN_LINK 1 #define IFLA_IPTUN_LOCAL 2 @@ -788,11 +788,41 @@ static inline int setns(int fd, int nstype) { #define IFLA_IPTUN_6RD_RELAY_PREFIX 12 #define IFLA_IPTUN_6RD_PREFIXLEN 13 #define IFLA_IPTUN_6RD_RELAY_PREFIXLEN 14 -#define __IFLA_IPTUN_MAX 15 +#define IFLA_IPTUN_ENCAP_TYPE 15 +#define IFLA_IPTUN_ENCAP_FLAGS 16 +#define IFLA_IPTUN_ENCAP_SPORT 17 +#define IFLA_IPTUN_ENCAP_DPORT 18 + +#define __IFLA_IPTUN_MAX 19 #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) #endif +#if !HAVE_DECL_IFLA_GRE_ENCAP_DPORT +#define IFLA_GRE_UNSPEC 0 +#define IFLA_GRE_LINK 1 +#define IFLA_GRE_IFLAGS 2 +#define IFLA_GRE_OFLAGS 3 +#define IFLA_GRE_IKEY 4 +#define IFLA_GRE_OKEY 5 +#define IFLA_GRE_LOCAL 6 +#define IFLA_GRE_REMOTE 7 +#define IFLA_GRE_TTL 8 +#define IFLA_GRE_TOS 9 +#define IFLA_GRE_PMTUDISC 10 +#define IFLA_GRE_ENCAP_LIMIT 11 +#define IFLA_GRE_FLOWINFO 12 +#define IFLA_GRE_FLAGS 13 +#define IFLA_GRE_ENCAP_TYPE 14 +#define IFLA_GRE_ENCAP_FLAGS 15 +#define IFLA_GRE_ENCAP_SPORT 16 +#define IFLA_GRE_ENCAP_DPORT 17 + +#define __IFLA_GRE_MAX 18 + +#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1) +#endif + #if !HAVE_DECL_IFLA_BRIDGE_VLAN_INFO #define IFLA_BRIDGE_FLAGS 0 #define IFLA_BRIDGE_MODE 1 @@ -802,7 +832,7 @@ static inline int setns(int fd, int nstype) { #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) #endif -#if !HAVE_DECL_IFLA_BRPORT_UNICAST_FLOOD +#if !HAVE_DECL_IFLA_BRPORT_LEARNING_SYNC #define IFLA_BRPORT_UNSPEC 0 #define IFLA_BRPORT_STATE 1 #define IFLA_BRPORT_PRIORITY 2 @@ -813,7 +843,9 @@ static inline int setns(int fd, int nstype) { #define IFLA_BRPORT_FAST_LEAVE 7 #define IFLA_BRPORT_LEARNING 8 #define IFLA_BRPORT_UNICAST_FLOOD 9 -#define __IFLA_BRPORT_MAX 10 +#define IFLA_BRPORT_PROXYARP 10 +#define IFLA_BRPORT_LEARNING_SYNC 11 +#define __IFLA_BRPORT_MAX 12 #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) #endif diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 2c05f2fee4..61f188467f 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -43,7 +43,10 @@ int get_process_state(pid_t pid) { assert(pid >= 0); p = procfs_file_alloca(pid, "stat"); + r = read_one_line_file(p, &line); + if (r == -ENOENT) + return -ESRCH; if (r < 0) return r; @@ -87,8 +90,11 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * p = procfs_file_alloca(pid, "cmdline"); f = fopen(p, "re"); - if (!f) + if (!f) { + if (errno == ENOENT) + return -ESRCH; return -errno; + } if (max_length == 0) { size_t len = 0, allocated = 0; @@ -182,8 +188,11 @@ int is_kernel_thread(pid_t pid) { p = procfs_file_alloca(pid, "cmdline"); f = fopen(p, "re"); - if (!f) + if (!f) { + if (errno == ENOENT) + return -ESRCH; return -errno; + } count = fread(&c, 1, 1, f); eof = feof(f); @@ -199,13 +208,18 @@ int is_kernel_thread(pid_t pid) { int get_process_capeff(pid_t pid, char **capeff) { const char *p; + int r; assert(capeff); assert(pid >= 0); p = procfs_file_alloca(pid, "status"); - return get_status_field(p, "\nCapEff:", capeff); + r = get_status_field(p, "\nCapEff:", capeff); + if (r == -ENOENT) + return -ESRCH; + + return r; } static int get_process_link_contents(const char *proc_file, char **name) { @@ -215,8 +229,10 @@ static int get_process_link_contents(const char *proc_file, char **name) { assert(name); r = readlink_malloc(proc_file, name); + if (r == -ENOENT) + return -ESRCH; if (r < 0) - return r == -ENOENT ? -ESRCH : r; + return r; return 0; } @@ -253,8 +269,11 @@ static int get_process_id(pid_t pid, const char *field, uid_t *uid) { p = procfs_file_alloca(pid, "status"); f = fopen(p, "re"); - if (!f) + if (!f) { + if (errno == ENOENT) + return -ESRCH; return -errno; + } FOREACH_LINE(line, f, return -errno) { char *l; @@ -316,8 +335,11 @@ int get_process_environ(pid_t pid, char **env) { p = procfs_file_alloca(pid, "environ"); f = fopen(p, "re"); - if (!f) + if (!f) { + if (errno == ENOENT) + return -ESRCH; return -errno; + } while ((c = fgetc(f)) != EOF) { if (!GREEDY_REALLOC(outcome, allocated, sz + 5)) @@ -329,10 +351,13 @@ int get_process_environ(pid_t pid, char **env) { sz += cescape_char(c, outcome + sz); } - if (sz == 0) - return -ENOENT; + if (!outcome) { + outcome = strdup(""); + if (!outcome) + return -ENOMEM; + } else + outcome[sz] = '\0'; - outcome[sz] = '\0'; *env = outcome; outcome = NULL; @@ -355,6 +380,8 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) { p = procfs_file_alloca(pid, "stat"); r = read_one_line_file(p, &line); + if (r == -ENOENT) + return -ESRCH; if (r < 0) return r; @@ -475,8 +502,11 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { path = procfs_file_alloca(pid, "environ"); f = fopen(path, "re"); - if (!f) + if (!f) { + if (errno == ENOENT) + return -ESRCH; return -errno; + } l = strlen(field); r = 0; @@ -535,7 +565,7 @@ bool pid_is_alive(pid_t pid) { return false; r = get_process_state(pid); - if (r == -ENOENT || r == 'Z') + if (r == -ESRCH || r == 'Z') return false; return true; diff --git a/src/basic/virt.c b/src/basic/virt.c index 1299a75ed5..a8d26716a1 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -188,7 +188,7 @@ int detect_vm(const char **id) { _cleanup_free_ char *domcap = NULL, *cpuinfo_contents = NULL; static thread_local int cached_found = -1; static thread_local const char *cached_id = NULL; - const char *_id = NULL; + const char *_id = NULL, *_id_cpuid = NULL; int r; if (_likely_(cached_found >= 0)) { @@ -234,10 +234,26 @@ int detect_vm(const char **id) { /* this will set _id to "other" and return 0 for unknown hypervisors */ r = detect_vm_cpuid(&_id); - if (r != 0) + + /* finish when found a known hypervisor other than kvm */ + if (r < 0 || (r > 0 && !streq(_id, "kvm"))) goto finish; + _id_cpuid = _id; + r = detect_vm_dmi(&_id); + + /* kvm with and without Virtualbox */ + if (streq_ptr(_id_cpuid, "kvm")) { + if (r > 0 && streq(_id, "oracle")) + goto finish; + + _id = _id_cpuid; + r = 1; + goto finish; + } + + /* information from dmi */ if (r != 0) goto finish; diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c index 3360bc85be..1625d51fa8 100644 --- a/src/bootchart/bootchart.c +++ b/src/bootchart/bootchart.c @@ -387,9 +387,6 @@ int main(int argc, char *argv[]) { for (samples = 0; !exiting && samples < arg_samples_len; samples++) { int res; double sample_stop; - struct timespec req; - time_t newint_s; - long newint_ns; double elapsed; double timeleft; @@ -427,18 +424,17 @@ int main(int argc, char *argv[]) { elapsed = (sample_stop - sampledata->sampletime) * 1000000000.0; timeleft = interval - elapsed; - newint_s = (time_t)(timeleft / 1000000000.0); - newint_ns = (long)(timeleft - (newint_s * 1000000000.0)); - /* * check if we have not consumed our entire timeslice. If we * do, don't sleep and take a new sample right away. * we'll lose all the missed samples and overrun our total * time */ - if (newint_ns > 0 || newint_s > 0) { - req.tv_sec = newint_s; - req.tv_nsec = newint_ns; + if (timeleft > 0) { + struct timespec req; + + req.tv_sec = (time_t)(timeleft / 1000000000.0); + req.tv_nsec = (long)(timeleft - (req.tv_sec * 1000000000.0)); res = nanosleep(&req, NULL); if (res) { @@ -452,7 +448,7 @@ int main(int argc, char *argv[]) { } else { overrun++; /* calculate how many samples we lost and scrap them */ - arg_samples_len -= (int)(newint_ns / interval); + arg_samples_len -= (int)(-timeleft / interval); } LIST_PREPEND(link, head, sampledata); } diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index 46a444340a..b8d1d2ccaf 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -197,19 +197,19 @@ int main(int argc, char *argv[]) { if (arg_machine) { char *m; const char *cgroup; - _cleanup_free_ char *scope = NULL; + _cleanup_free_ char *unit = NULL; _cleanup_free_ char *path = NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; m = strjoina("/run/systemd/machines/", arg_machine); - r = parse_env_file(m, NEWLINE, "SCOPE", &scope, NULL); + r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL); if (r < 0) { log_error_errno(r, "Failed to get machine path: %m"); goto finish; } - path = unit_dbus_path_from_name(scope); + path = unit_dbus_path_from_name(unit); if (!path) { log_oom(); goto finish; @@ -219,7 +219,7 @@ int main(int argc, char *argv[]) { bus, "org.freedesktop.systemd1", path, - "org.freedesktop.systemd1.Scope", + endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service", "ControlGroup", &error, &reply, diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index d630e35882..f953c9e624 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -27,6 +27,7 @@ #include <unistd.h> #include <alloca.h> #include <getopt.h> +#include <signal.h> #include "path-util.h" #include "terminal-util.h" diff --git a/src/core/automount.c b/src/core/automount.c index d847dc1629..342dd8f0a9 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -672,7 +672,7 @@ static int automount_start_expire(Automount *a) { assert(a); - timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/10, USEC_PER_SEC); + timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/3, USEC_PER_SEC); if (a->expire_event_source) { r = sd_event_source_set_time(a->expire_event_source, timeout); @@ -1066,7 +1066,6 @@ const UnitVTable automount_vtable = { .finished_start_job = { [JOB_DONE] = "Set up automount %s.", [JOB_FAILED] = "Failed to set up automount %s.", - [JOB_DEPENDENCY] = "Dependency failed for %s.", }, .finished_stop_job = { [JOB_DONE] = "Unset automount %s.", diff --git a/src/core/busname.c b/src/core/busname.c index 2085721546..9530a87311 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -1065,13 +1065,10 @@ const UnitVTable busname_vtable = { .finished_start_job = { [JOB_DONE] = "Listening on %s.", [JOB_FAILED] = "Failed to listen on %s.", - [JOB_DEPENDENCY] = "Dependency failed for %s.", - [JOB_TIMEOUT] = "Timed out starting %s.", }, .finished_stop_job = { [JOB_DONE] = "Closed %s.", [JOB_FAILED] = "Failed stopping %s.", - [JOB_TIMEOUT] = "Timed out stopping %s.", }, }, }; diff --git a/src/core/job.c b/src/core/job.c index 1448e5b69a..15f5cc0cc9 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -495,10 +495,48 @@ static void job_change_type(Job *j, JobType newtype) { j->type = newtype; } +static int job_perform_on_unit(Job **j) { + /* While we execute this operation the job might go away (for + * example: because it finishes immediately or is replaced by a new, + * conflicting job.) To make sure we don't access a freed job later on + * we store the id here, so that we can verify the job is still + * valid. */ + Manager *m = (*j)->manager; + Unit *u = (*j)->unit; + JobType t = (*j)->type; + uint32_t id = (*j)->id; + int r; + + switch (t) { + case JOB_START: + r = unit_start(u); + break; + + case JOB_RESTART: + t = JOB_STOP; + case JOB_STOP: + r = unit_stop(u); + break; + + case JOB_RELOAD: + r = unit_reload(u); + break; + + default: + assert_not_reached("Invalid job type"); + } + + /* Log if the job still exists and the start/stop/reload function + * actually did something. */ + *j = manager_get_job(m, id); + if (*j && r > 0) + unit_status_emit_starting_stopping_reloading(u, t); + + return r; +} + int job_run_and_invalidate(Job *j) { int r; - uint32_t id; - Manager *m = j->manager; assert(j); assert(j->installed); @@ -517,23 +555,9 @@ int job_run_and_invalidate(Job *j) { job_set_state(j, JOB_RUNNING); job_add_to_dbus_queue(j); - /* While we execute this operation the job might go away (for - * example: because it is replaced by a new, conflicting - * job.) To make sure we don't access a freed job later on we - * store the id here, so that we can verify the job is still - * valid. */ - id = j->id; switch (j->type) { - case JOB_START: - r = unit_start(j->unit); - - /* If this unit cannot be started, then simply wait */ - if (r == -EBADR) - r = 0; - break; - case JOB_VERIFY_ACTIVE: { UnitActiveState t = unit_active_state(j->unit); if (UNIT_IS_ACTIVE_OR_RELOADING(t)) @@ -545,17 +569,19 @@ int job_run_and_invalidate(Job *j) { break; } + case JOB_START: case JOB_STOP: case JOB_RESTART: - r = unit_stop(j->unit); + r = job_perform_on_unit(&j); - /* If this unit cannot stopped, then simply wait. */ + /* If the unit type does not support starting/stopping, + * then simply wait. */ if (r == -EBADR) r = 0; break; case JOB_RELOAD: - r = unit_reload(j->unit); + r = job_perform_on_unit(&j); break; case JOB_NOP: @@ -566,7 +592,6 @@ int job_run_and_invalidate(Job *j) { assert_not_reached("Unknown job type"); } - j = manager_get_job(m, id); if (j) { if (r == -EALREADY) r = job_finish_and_invalidate(j, JOB_DONE, true); @@ -588,161 +613,110 @@ int job_run_and_invalidate(Job *j) { } _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) { + const char *format; const UnitStatusMessageFormats *format_table; + static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = { + [JOB_DONE] = "Started %s.", + [JOB_TIMEOUT] = "Timed out starting %s.", + [JOB_FAILED] = "Failed to start %s.", + [JOB_DEPENDENCY] = "Dependency failed for %s.", + [JOB_ASSERT] = "Assertion failed for %s.", + [JOB_UNSUPPORTED] = "Starting of %s not supported.", + }; + static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = { + [JOB_DONE] = "Stopped %s.", + [JOB_FAILED] = "Stopped (with error) %s.", + [JOB_TIMEOUT] = "Timed out stoppping %s.", + }; + static const char *const generic_finished_reload_job[_JOB_RESULT_MAX] = { + [JOB_DONE] = "Reloaded %s.", + [JOB_FAILED] = "Reload failed for %s.", + [JOB_TIMEOUT] = "Timed out reloading %s.", + }; + /* When verify-active detects the unit is inactive, report it. + * Most likely a DEPEND warning from a requisiting unit will + * occur next and it's nice to see what was requisited. */ + static const char *const generic_finished_verify_active_job[_JOB_RESULT_MAX] = { + [JOB_SKIPPED] = "%s is not active.", + }; assert(u); assert(t >= 0); assert(t < _JOB_TYPE_MAX); - format_table = &UNIT_VTABLE(u)->status_message_formats; - if (!format_table) - return NULL; + if (t == JOB_START || t == JOB_STOP || t == JOB_RESTART) { + format_table = &UNIT_VTABLE(u)->status_message_formats; + if (format_table) { + format = t == JOB_START ? format_table->finished_start_job[result] : + format_table->finished_stop_job[result]; + if (format) + return format; + } + } + /* Return generic strings */ if (t == JOB_START) - return format_table->finished_start_job[result]; + return generic_finished_start_job[result]; else if (t == JOB_STOP || t == JOB_RESTART) - return format_table->finished_stop_job[result]; + return generic_finished_stop_job[result]; + else if (t == JOB_RELOAD) + return generic_finished_reload_job[result]; + else if (t == JOB_VERIFY_ACTIVE) + return generic_finished_verify_active_job[result]; return NULL; } -_pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) { +static void job_print_status_message(Unit *u, JobType t, JobResult result) { const char *format; + static const char* const job_result_status_table[_JOB_RESULT_MAX] = { + [JOB_DONE] = ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, + [JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, + [JOB_FAILED] = ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, + [JOB_DEPENDENCY] = ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, + [JOB_SKIPPED] = ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, + [JOB_ASSERT] = ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF, + [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW_ON "UNSUPP" ANSI_HIGHLIGHT_OFF, + }; assert(u); assert(t >= 0); assert(t < _JOB_TYPE_MAX); format = job_get_status_message_format(u, t, result); - if (format) - return format; - - /* Return generic strings */ - if (t == JOB_START) { - if (result == JOB_DONE) - return "Started %s."; - else if (result == JOB_TIMEOUT) - return "Timed out starting %s."; - else if (result == JOB_FAILED) - return "Failed to start %s."; - else if (result == JOB_DEPENDENCY) - return "Dependency failed for %s."; - else if (result == JOB_ASSERT) - return "Assertion failed for %s."; - else if (result == JOB_UNSUPPORTED) - return "Starting of %s not supported."; - } else if (t == JOB_STOP || t == JOB_RESTART) { - if (result == JOB_DONE) - return "Stopped %s."; - else if (result == JOB_FAILED) - return "Stopped (with error) %s."; - else if (result == JOB_TIMEOUT) - return "Timed out stoppping %s."; - } else if (t == JOB_RELOAD) { - if (result == JOB_DONE) - return "Reloaded %s."; - else if (result == JOB_FAILED) - return "Reload failed for %s."; - else if (result == JOB_TIMEOUT) - return "Timed out reloading %s."; - } - - return NULL; -} + if (!format) + return; -static void job_print_status_message(Unit *u, JobType t, JobResult result) { - const char *format; - - assert(u); - assert(t >= 0); - assert(t < _JOB_TYPE_MAX); + if (result != JOB_DONE) + manager_flip_auto_status(u->manager, true); DISABLE_WARNING_FORMAT_NONLITERAL; + unit_status_printf(u, job_result_status_table[result], format); + REENABLE_WARNING; - if (t == JOB_START) { - format = job_get_status_message_format(u, t, result); - if (!format) - return; - - switch (result) { - - case JOB_DONE: - if (u->condition_result) - unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format); - break; - - case JOB_TIMEOUT: - manager_flip_auto_status(u->manager, true); - unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format); - break; - - case JOB_FAILED: { - _cleanup_free_ char *quoted = NULL; - - quoted = shell_maybe_quote(u->id); - - manager_flip_auto_status(u->manager, true); - unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format); - manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted)); - break; - } - - case JOB_DEPENDENCY: - manager_flip_auto_status(u->manager, true); - unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format); - break; - - case JOB_ASSERT: - manager_flip_auto_status(u->manager, true); - unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF, format); - break; - - case JOB_UNSUPPORTED: - manager_flip_auto_status(u->manager, true); - unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "UNSUPP" ANSI_HIGHLIGHT_OFF, format); - break; - - default: - ; - } - - } else if (t == JOB_STOP || t == JOB_RESTART) { - - format = job_get_status_message_format(u, t, result); - if (!format) - return; - - switch (result) { - - case JOB_TIMEOUT: - manager_flip_auto_status(u->manager, true); - unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format); - break; - - case JOB_DONE: - case JOB_FAILED: - unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format); - break; - - default: - ; - } - - } else if (t == JOB_VERIFY_ACTIVE) { + if (t == JOB_START && result == JOB_FAILED) { + _cleanup_free_ char *quoted = shell_maybe_quote(u->id); - /* When verify-active detects the unit is inactive, report it. - * Most likely a DEPEND warning from a requisiting unit will - * occur next and it's nice to see what was requisited. */ - if (result == JOB_SKIPPED) - unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active."); + manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, + "See 'systemctl status %s' for details.", strna(quoted)); } - - REENABLE_WARNING; } static void job_log_status_message(Unit *u, JobType t, JobResult result) { const char *format; char buf[LINE_MAX]; + sd_id128_t mid; + static const int job_result_log_level[_JOB_RESULT_MAX] = { + [JOB_DONE] = LOG_INFO, + [JOB_CANCELED] = LOG_INFO, + [JOB_TIMEOUT] = LOG_ERR, + [JOB_FAILED] = LOG_ERR, + [JOB_DEPENDENCY] = LOG_WARNING, + [JOB_SKIPPED] = LOG_NOTICE, + [JOB_INVALID] = LOG_INFO, + [JOB_ASSERT] = LOG_WARNING, + [JOB_UNSUPPORTED] = LOG_WARNING, + }; assert(u); assert(t >= 0); @@ -754,7 +728,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) { if (log_on_console()) return; - format = job_get_status_message_format_try_harder(u, t, result); + format = job_get_status_message_format(u, t, result); if (!format) return; @@ -762,32 +736,40 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) { snprintf(buf, sizeof(buf), format, unit_description(u)); REENABLE_WARNING; - if (t == JOB_START) { - sd_id128_t mid; - + if (t == JOB_START) mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED; - log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR, - LOG_MESSAGE_ID(mid), + else if (t == JOB_STOP || t == JOB_RESTART) + mid = SD_MESSAGE_UNIT_STOPPED; + else if (t == JOB_RELOAD) + mid = SD_MESSAGE_UNIT_RELOADED; + else { + log_struct(job_result_log_level[result], LOG_UNIT_ID(u), LOG_MESSAGE("%s", buf), "RESULT=%s", job_result_to_string(result), NULL); + return; + } - } else if (t == JOB_STOP) - log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR, - LOG_MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED), - LOG_UNIT_ID(u), - LOG_MESSAGE("%s", buf), - "RESULT=%s", job_result_to_string(result), - NULL); + log_struct(job_result_log_level[result], + LOG_MESSAGE_ID(mid), + LOG_UNIT_ID(u), + LOG_MESSAGE("%s", buf), + "RESULT=%s", job_result_to_string(result), + NULL); +} - else if (t == JOB_RELOAD) - log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR, - LOG_MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED), - LOG_UNIT_ID(u), - LOG_MESSAGE("%s", buf), - "RESULT=%s", job_result_to_string(result), - NULL); +static void job_emit_status_message(Unit *u, JobType t, JobResult result) { + + /* No message if the job did not actually do anything due to failed condition. */ + if (t == JOB_START && result == JOB_DONE && !u->condition_result) + return; + + job_log_status_message(u, t, result); + + /* Reload status messages have traditionally not been printed to console. */ + if (t != JOB_RELOAD) + job_print_status_message(u, t, result); } static void job_fail_dependencies(Unit *u, UnitDependency d) { @@ -825,8 +807,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { log_unit_debug(u, "Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result)); - job_print_status_message(u, t, result); - job_log_status_message(u, t, result); + job_emit_status_message(u, t, result); job_add_to_dbus_queue(j); diff --git a/src/core/mount.c b/src/core/mount.c index 851b41351e..bf8e52bf0e 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1025,7 +1025,7 @@ static int mount_reload(Unit *u) { assert(m->state == MOUNT_MOUNTED); mount_enter_remounting(m); - return 0; + return 1; } static int mount_serialize(Unit *u, FILE *f, FDSet *fds) { @@ -1897,7 +1897,6 @@ const UnitVTable mount_vtable = { .finished_start_job = { [JOB_DONE] = "Mounted %s.", [JOB_FAILED] = "Failed to mount %s.", - [JOB_DEPENDENCY] = "Dependency failed for %s.", [JOB_TIMEOUT] = "Timed out mounting %s.", }, .finished_stop_job = { diff --git a/src/core/service.c b/src/core/service.c index d72ff54daa..b790ec98be 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -401,7 +401,6 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) { r = service_add_fd_store(s, fd); if (r < 0) return log_unit_error_errno(UNIT(s), r, "Couldn't add fd to fd store: %m"); - if (r > 0) { log_unit_debug(UNIT(s), "Added fd to fd store."); fd = -1; @@ -576,8 +575,10 @@ static int service_add_extras(Service *s) { return r; r = unit_watch_bus_name(UNIT(s), s->bus_name); + if (r == -EEXIST) + return log_unit_error_errno(UNIT(s), r, "Two services allocated for the same bus name %s, refusing operation.", s->bus_name); if (r < 0) - return r; + return log_unit_error_errno(UNIT(s), r, "Cannot watch bus name %s: %m", s->bus_name); } if (UNIT(s)->default_dependencies) { @@ -1974,7 +1975,7 @@ static int service_reload(Unit *u) { assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED); service_enter_reload(s); - return 0; + return 1; } _pure_ static bool service_can_reload(Unit *u) { @@ -3229,13 +3230,10 @@ const UnitVTable service_vtable = { .finished_start_job = { [JOB_DONE] = "Started %s.", [JOB_FAILED] = "Failed to start %s.", - [JOB_DEPENDENCY] = "Dependency failed for %s.", - [JOB_TIMEOUT] = "Timed out starting %s.", }, .finished_stop_job = { [JOB_DONE] = "Stopped %s.", [JOB_FAILED] = "Stopped (with error) %s.", - [JOB_TIMEOUT] = "Timed out stopping %s.", }, }, }; diff --git a/src/core/slice.c b/src/core/slice.c index e52bf71515..064eb5d933 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -297,7 +297,6 @@ const UnitVTable slice_vtable = { .status_message_formats = { .finished_start_job = { [JOB_DONE] = "Created slice %s.", - [JOB_DEPENDENCY] = "Dependency failed for %s.", }, .finished_stop_job = { [JOB_DONE] = "Removed slice %s.", diff --git a/src/core/socket.c b/src/core/socket.c index 693cbc6080..87631f8753 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2722,7 +2722,6 @@ const UnitVTable socket_vtable = { .finished_start_job = { [JOB_DONE] = "Listening on %s.", [JOB_FAILED] = "Failed to listen on %s.", - [JOB_DEPENDENCY] = "Dependency failed for %s.", [JOB_TIMEOUT] = "Timed out starting %s.", }, .finished_stop_job = { diff --git a/src/core/swap.c b/src/core/swap.c index 193c8c3767..0bc3827ff0 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1505,7 +1505,6 @@ const UnitVTable swap_vtable = { .finished_start_job = { [JOB_DONE] = "Activated swap %s.", [JOB_FAILED] = "Failed to activate swap %s.", - [JOB_DEPENDENCY] = "Dependency failed for %s.", [JOB_TIMEOUT] = "Timed out activating swap %s.", }, .finished_stop_job = { diff --git a/src/core/target.c b/src/core/target.c index 8817ef21c4..b492a7c4c7 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -227,7 +227,6 @@ const UnitVTable target_vtable = { .status_message_formats = { .finished_start_job = { [JOB_DONE] = "Reached target %s.", - [JOB_DEPENDENCY] = "Dependency failed for %s.", }, .finished_stop_job = { [JOB_DONE] = "Stopped target %s.", diff --git a/src/core/unit.c b/src/core/unit.c index fac017c57d..dd5e801285 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1318,42 +1318,28 @@ static bool unit_assert_test(Unit *u) { } _pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) { - const UnitStatusMessageFormats *format_table; - - assert(u); - assert(t >= 0); - assert(t < _JOB_TYPE_MAX); - - if (t != JOB_START && t != JOB_STOP) - return NULL; - - format_table = &UNIT_VTABLE(u)->status_message_formats; - if (!format_table) - return NULL; - - return format_table->starting_stopping[t == JOB_STOP]; -} - -_pure_ static const char *unit_get_status_message_format_try_harder(Unit *u, JobType t) { const char *format; + const UnitStatusMessageFormats *format_table; assert(u); - assert(t >= 0); - assert(t < _JOB_TYPE_MAX); + assert(t == JOB_START || t == JOB_STOP || t == JOB_RELOAD); - format = unit_get_status_message_format(u, t); - if (format) - return format; + if (t != JOB_RELOAD) { + format_table = &UNIT_VTABLE(u)->status_message_formats; + if (format_table) { + format = format_table->starting_stopping[t == JOB_STOP]; + if (format) + return format; + } + } /* Return generic strings */ if (t == JOB_START) return "Starting %s."; else if (t == JOB_STOP) return "Stopping %s."; - else if (t == JOB_RELOAD) + else return "Reloading %s."; - - return NULL; } static void unit_status_print_starting_stopping(Unit *u, JobType t) { @@ -1361,12 +1347,7 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) { assert(u); - /* We only print status messages for selected units on - * selected operations. */ - format = unit_get_status_message_format(u, t); - if (!format) - return; DISABLE_WARNING_FORMAT_NONLITERAL; unit_status_printf(u, "", format); @@ -1388,9 +1369,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { /* We log status messages for all units and all operations. */ - format = unit_get_status_message_format_try_harder(u, t); - if (!format) - return; + format = unit_get_status_message_format(u, t); DISABLE_WARNING_FORMAT_NONLITERAL; snprintf(buf, sizeof(buf), format, unit_description(u)); @@ -1413,6 +1392,15 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { NULL); } +void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) { + + unit_status_log_starting_stopping_reloading(u, t); + + /* Reload status messages have traditionally not been printed to console. */ + if (t != JOB_RELOAD) + unit_status_print_starting_stopping(u, t); +} + /* Errors: * -EBADR: This unit type does not support starting. * -EALREADY: Unit is already started. @@ -1423,7 +1411,6 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { int unit_start(Unit *u) { UnitActiveState state; Unit *following; - int r; assert(u); @@ -1477,14 +1464,7 @@ int unit_start(Unit *u) { unit_add_to_dbus_queue(u); - r = UNIT_VTABLE(u)->start(u); - if (r <= 0) - return r; - - /* Log if the start function actually did something */ - unit_status_log_starting_stopping_reloading(u, JOB_START); - unit_status_print_starting_stopping(u, JOB_START); - return r; + return UNIT_VTABLE(u)->start(u); } bool unit_can_start(Unit *u) { @@ -1508,7 +1488,6 @@ bool unit_can_isolate(Unit *u) { int unit_stop(Unit *u) { UnitActiveState state; Unit *following; - int r; assert(u); @@ -1527,13 +1506,7 @@ int unit_stop(Unit *u) { unit_add_to_dbus_queue(u); - r = UNIT_VTABLE(u)->stop(u); - if (r <= 0) - return r; - - unit_status_log_starting_stopping_reloading(u, JOB_STOP); - unit_status_print_starting_stopping(u, JOB_STOP); - return r; + return UNIT_VTABLE(u)->stop(u); } /* Errors: @@ -1544,7 +1517,6 @@ int unit_stop(Unit *u) { int unit_reload(Unit *u) { UnitActiveState state; Unit *following; - int r; assert(u); @@ -1571,12 +1543,7 @@ int unit_reload(Unit *u) { unit_add_to_dbus_queue(u); - r = UNIT_VTABLE(u)->reload(u); - if (r <= 0) - return r; - - unit_status_log_starting_stopping_reloading(u, JOB_RELOAD); - return r; + return UNIT_VTABLE(u)->reload(u); } bool unit_can_reload(Unit *u) { diff --git a/src/core/unit.h b/src/core/unit.h index 9491ef64f9..e60168267f 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -544,6 +544,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants); int unit_coldplug(Unit *u); void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0); +void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t); bool unit_need_daemon_reload(Unit *u); diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index be6a5522fa..f7815b2796 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -656,13 +656,16 @@ static int journal_file_setup_field_hash_table(JournalFile *f) { return 0; } -static int journal_file_map_data_hash_table(JournalFile *f) { +int journal_file_map_data_hash_table(JournalFile *f) { uint64_t s, p; void *t; int r; assert(f); + if (f->data_hash_table) + return 0; + p = le64toh(f->header->data_hash_table_offset); s = le64toh(f->header->data_hash_table_size); @@ -678,13 +681,16 @@ static int journal_file_map_data_hash_table(JournalFile *f) { return 0; } -static int journal_file_map_field_hash_table(JournalFile *f) { +int journal_file_map_field_hash_table(JournalFile *f) { uint64_t s, p; void *t; int r; assert(f); + if (f->field_hash_table) + return 0; + p = le64toh(f->header->field_hash_table_offset); s = le64toh(f->header->field_hash_table_size); @@ -803,10 +809,18 @@ int journal_file_find_field_object_with_hash( assert(f); assert(field && size > 0); + /* If the field hash table is empty, we can't find anything */ + if (le64toh(f->header->field_hash_table_size) <= 0) + return 0; + + /* Map the field hash table, if it isn't mapped yet. */ + r = journal_file_map_field_hash_table(f); + if (r < 0) + return r; + osize = offsetof(Object, field.payload) + size; m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem); - if (m <= 0) return -EBADMSG; @@ -866,6 +880,15 @@ int journal_file_find_data_object_with_hash( assert(f); assert(data || size == 0); + /* If there's no data hash table, then there's no entry. */ + if (le64toh(f->header->data_hash_table_size) <= 0) + return 0; + + /* Map the data hash table, if it isn't mapped yet. */ + r = journal_file_map_data_hash_table(f); + if (r < 0) + return r; + osize = offsetof(Object, data.payload) + size; m = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); @@ -2731,14 +2754,6 @@ int journal_file_open( #endif } - r = journal_file_map_field_hash_table(f); - if (r < 0) - goto fail; - - r = journal_file_map_data_hash_table(f); - if (r < 0) - goto fail; - if (mmap_cache_got_sigbus(f->mmap, f->fd)) { r = -EIO; goto fail; diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index 403c8f760c..e92b75eabe 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -229,3 +229,6 @@ int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t * int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to); bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec); + +int journal_file_map_data_hash_table(JournalFile *f); +int journal_file_map_field_hash_table(JournalFile *f); diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index ce734d8df7..eaf006db7a 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -69,6 +69,16 @@ static void draw_progress(uint64_t p, usec_t *last_usec) { fflush(stdout); } +static uint64_t scale_progress(uint64_t scale, uint64_t p, uint64_t m) { + + /* Calculates scale * p / m, but handles m == 0 safely, and saturates */ + + if (p >= m || m == 0) + return scale; + + return scale * p / m; +} + static void flush_progress(void) { unsigned n, i; @@ -113,8 +123,10 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o * other objects. */ if ((o->object.flags & OBJECT_COMPRESSED_XZ) && - o->object.type != OBJECT_DATA) + o->object.type != OBJECT_DATA) { + error(offset, "Found compressed object that isn't of type DATA, which is not allowed."); return -EBADMSG; + } switch (o->object.type) { @@ -123,15 +135,15 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o int compression, r; if (le64toh(o->data.entry_offset) == 0) - warning(offset, "unused data (entry_offset==0)"); + warning(offset, "Unused data (entry_offset==0)"); if ((le64toh(o->data.entry_offset) == 0) ^ (le64toh(o->data.n_entries) == 0)) { - error(offset, "bad n_entries: %"PRIu64, o->data.n_entries); + error(offset, "Bad n_entries: %"PRIu64, o->data.n_entries); return -EBADMSG; } if (le64toh(o->object.size) - offsetof(DataObject, payload) <= 0) { - error(offset, "bad object size (<= %zu): %"PRIu64, + error(offset, "Bad object size (<= %zu): %"PRIu64, offsetof(DataObject, payload), le64toh(o->object.size)); return -EBADMSG; @@ -159,7 +171,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o h2 = hash64(o->data.payload, le64toh(o->object.size) - offsetof(Object, data.payload)); if (h1 != h2) { - error(offset, "invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2); + error(offset, "Invalid hash (%08"PRIx64" vs. %08"PRIx64, h1, h2); return -EBADMSG; } @@ -167,7 +179,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o !VALID64(o->data.next_field_offset) || !VALID64(o->data.entry_offset) || !VALID64(o->data.entry_array_offset)) { - error(offset, "invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt, + error(offset, "Invalid offset (next_hash_offset="OFSfmt", next_field_offset="OFSfmt", entry_offset="OFSfmt", entry_array_offset="OFSfmt, o->data.next_hash_offset, o->data.next_field_offset, o->data.entry_offset, @@ -181,7 +193,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o case OBJECT_FIELD: if (le64toh(o->object.size) - offsetof(FieldObject, payload) <= 0) { error(offset, - "bad field size (<= %zu): %"PRIu64, + "Bad field size (<= %zu): %"PRIu64, offsetof(FieldObject, payload), le64toh(o->object.size)); return -EBADMSG; @@ -190,7 +202,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o if (!VALID64(o->field.next_hash_offset) || !VALID64(o->field.head_data_offset)) { error(offset, - "invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt, + "Invalid offset (next_hash_offset="OFSfmt", head_data_offset="OFSfmt, o->field.next_hash_offset, o->field.head_data_offset); return -EBADMSG; @@ -200,7 +212,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o case OBJECT_ENTRY: if ((le64toh(o->object.size) - offsetof(EntryObject, items)) % sizeof(EntryItem) != 0) { error(offset, - "bad entry size (<= %zu): %"PRIu64, + "Bad entry size (<= %zu): %"PRIu64, offsetof(EntryObject, items), le64toh(o->object.size)); return -EBADMSG; @@ -208,28 +220,28 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o if ((le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem) <= 0) { error(offset, - "invalid number items in entry: %"PRIu64, + "Invalid number items in entry: %"PRIu64, (le64toh(o->object.size) - offsetof(EntryObject, items)) / sizeof(EntryItem)); return -EBADMSG; } if (le64toh(o->entry.seqnum) <= 0) { error(offset, - "invalid entry seqnum: %"PRIx64, + "Invalid entry seqnum: %"PRIx64, le64toh(o->entry.seqnum)); return -EBADMSG; } if (!VALID_REALTIME(le64toh(o->entry.realtime))) { error(offset, - "invalid entry realtime timestamp: %"PRIu64, + "Invalid entry realtime timestamp: %"PRIu64, le64toh(o->entry.realtime)); return -EBADMSG; } if (!VALID_MONOTONIC(le64toh(o->entry.monotonic))) { error(offset, - "invalid entry monotonic timestamp: %"PRIu64, + "Invalid entry monotonic timestamp: %"PRIu64, le64toh(o->entry.monotonic)); return -EBADMSG; } @@ -238,7 +250,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o if (o->entry.items[i].object_offset == 0 || !VALID64(o->entry.items[i].object_offset)) { error(offset, - "invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt, + "Invalid entry item (%"PRIu64"/%"PRIu64" offset: "OFSfmt, i, journal_file_entry_n_items(o), o->entry.items[i].object_offset); return -EBADMSG; @@ -252,7 +264,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o if ((le64toh(o->object.size) - offsetof(HashTableObject, items)) % sizeof(HashItem) != 0 || (le64toh(o->object.size) - offsetof(HashTableObject, items)) / sizeof(HashItem) <= 0) { error(offset, - "invalid %s hash table size: %"PRIu64, + "Invalid %s hash table size: %"PRIu64, o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", le64toh(o->object.size)); return -EBADMSG; @@ -262,7 +274,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o if (o->hash_table.items[i].head_hash_offset != 0 && !VALID64(le64toh(o->hash_table.items[i].head_hash_offset))) { error(offset, - "invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt, + "Invalid %s hash table item (%"PRIu64"/%"PRIu64") head_hash_offset: "OFSfmt, o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", i, journal_file_hash_table_n_items(o), le64toh(o->hash_table.items[i].head_hash_offset)); @@ -271,7 +283,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o if (o->hash_table.items[i].tail_hash_offset != 0 && !VALID64(le64toh(o->hash_table.items[i].tail_hash_offset))) { error(offset, - "invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt, + "Invalid %s hash table item (%"PRIu64"/%"PRIu64") tail_hash_offset: "OFSfmt, o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", i, journal_file_hash_table_n_items(o), le64toh(o->hash_table.items[i].tail_hash_offset)); @@ -281,7 +293,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o if ((o->hash_table.items[i].head_hash_offset != 0) != (o->hash_table.items[i].tail_hash_offset != 0)) { error(offset, - "invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt, + "Invalid %s hash table item (%"PRIu64"/%"PRIu64"): head_hash_offset="OFSfmt" tail_hash_offset="OFSfmt, o->object.type == OBJECT_DATA_HASH_TABLE ? "data" : "field", i, journal_file_hash_table_n_items(o), le64toh(o->hash_table.items[i].head_hash_offset), @@ -296,14 +308,14 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o if ((le64toh(o->object.size) - offsetof(EntryArrayObject, items)) % sizeof(le64_t) != 0 || (le64toh(o->object.size) - offsetof(EntryArrayObject, items)) / sizeof(le64_t) <= 0) { error(offset, - "invalid object entry array size: %"PRIu64, + "Invalid object entry array size: %"PRIu64, le64toh(o->object.size)); return -EBADMSG; } if (!VALID64(o->entry_array.next_entry_array_offset)) { error(offset, - "invalid object entry array next_entry_array_offset: "OFSfmt, + "Invalid object entry array next_entry_array_offset: "OFSfmt, o->entry_array.next_entry_array_offset); return -EBADMSG; } @@ -312,7 +324,7 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o if (le64toh(o->entry_array.items[i]) != 0 && !VALID64(le64toh(o->entry_array.items[i]))) { error(offset, - "invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt, + "Invalid object entry array item (%"PRIu64"/%"PRIu64"): "OFSfmt, i, journal_file_entry_array_n_items(o), le64toh(o->entry_array.items[i])); return -EBADMSG; @@ -323,14 +335,14 @@ static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o case OBJECT_TAG: if (le64toh(o->object.size) != sizeof(TagObject)) { error(offset, - "invalid object tag size: %"PRIu64, + "Invalid object tag size: %"PRIu64, le64toh(o->object.size)); return -EBADMSG; } if (!VALID_EPOCH(o->tag.epoch)) { error(offset, - "invalid object tag epoch: %"PRIu64, + "Invalid object tag epoch: %"PRIu64, o->tag.epoch); return -EBADMSG; } @@ -403,8 +415,7 @@ static int entry_points_to_data( assert(entry_fd >= 0); if (!contains_uint64(f->mmap, entry_fd, n_entries, entry_p)) { - error(data_p, - "data object references invalid entry at "OFSfmt, entry_p); + error(data_p, "Data object references invalid entry at "OFSfmt, entry_p); return -EBADMSG; } @@ -420,8 +431,7 @@ static int entry_points_to_data( } if (!found) { - error(entry_p, - "data object at "OFSfmt" not referenced by linked entry", data_p); + error(entry_p, "Data object at "OFSfmt" not referenced by linked entry", data_p); return -EBADMSG; } @@ -464,7 +474,7 @@ static int entry_points_to_data( x = z; } - error(entry_p, "entry object doesn't exist in main entry array"); + error(entry_p, "Entry object doesn't exist in main entry array"); return -EBADMSG; } @@ -494,9 +504,7 @@ static int verify_data( /* Entry array means at least two objects */ if (a && n < 2) { - error(p, - "entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")", - a, n); + error(p, "Entry array present (entry_array_offset="OFSfmt", but n_entries=%"PRIu64")", a, n); return -EBADMSG; } @@ -516,12 +524,12 @@ static int verify_data( uint64_t next, m, j; if (a == 0) { - error(p, "array chain too short"); + error(p, "Array chain too short"); return -EBADMSG; } if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) { - error(p, "invalid array offset "OFSfmt, a); + error(p, "Invalid array offset "OFSfmt, a); return -EBADMSG; } @@ -531,8 +539,7 @@ static int verify_data( next = le64toh(o->entry_array.next_entry_array_offset); if (next != 0 && next <= a) { - error(p, "array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")", - a, next); + error(p, "Array chain has cycle (jumps back from "OFSfmt" to "OFSfmt")", a, next); return -EBADMSG; } @@ -541,7 +548,7 @@ static int verify_data( q = le64toh(o->entry_array.items[j]); if (q <= last) { - error(p, "data object's entry array not sorted"); + error(p, "Data object's entry array not sorted"); return -EBADMSG; } last = q; @@ -580,11 +587,18 @@ static int verify_hash_table( assert(last_usec); n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); + if (n <= 0) + return 0; + + r = journal_file_map_data_hash_table(f); + if (r < 0) + return log_error_errno(r, "Failed to map data hash table: %m"); + for (i = 0; i < n; i++) { uint64_t last = 0, p; if (show_progress) - draw_progress(0xC000 + (0x3FFF * i / n), last_usec); + draw_progress(0xC000 + scale_progress(0x3FFF, i, n), last_usec); p = le64toh(f->data_hash_table[i].head_hash_offset); while (p != 0) { @@ -592,8 +606,7 @@ static int verify_hash_table( uint64_t next; if (!contains_uint64(f->mmap, data_fd, n_data, p)) { - error(p, "invalid data object at hash entry %"PRIu64" of %"PRIu64, - i, n); + error(p, "Invalid data object at hash entry %"PRIu64" of %"PRIu64, i, n); return -EBADMSG; } @@ -603,14 +616,12 @@ static int verify_hash_table( next = le64toh(o->data.next_hash_offset); if (next != 0 && next <= p) { - error(p, "hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, - i, n); + error(p, "Hash chain has a cycle in hash entry %"PRIu64" of %"PRIu64, i, n); return -EBADMSG; } if (le64toh(o->data.hash) % n != i) { - error(p, "hash value mismatch in hash entry %"PRIu64" of %"PRIu64, - i, n); + error(p, "Hash value mismatch in hash entry %"PRIu64" of %"PRIu64, i, n); return -EBADMSG; } @@ -623,7 +634,7 @@ static int verify_hash_table( } if (last != le64toh(f->data_hash_table[i].tail_hash_offset)) { - error(p, "tail hash pointer mismatch in hash table"); + error(p, "Tail hash pointer mismatch in hash table"); return -EBADMSG; } } @@ -637,6 +648,13 @@ static int data_object_in_hash_table(JournalFile *f, uint64_t hash, uint64_t p) assert(f); n = le64toh(f->header->data_hash_table_size) / sizeof(HashItem); + if (n <= 0) + return 0; + + r = journal_file_map_data_hash_table(f); + if (r < 0) + return log_error_errno(r, "Failed to map data hash table: %m"); + h = hash % n; q = le64toh(f->data_hash_table[h].head_hash_offset); @@ -677,16 +695,16 @@ static int verify_entry( h = le64toh(o->entry.items[i].hash); if (!contains_uint64(f->mmap, data_fd, n_data, q)) { - error(p, "invalid data object of entry"); - return -EBADMSG; - } + error(p, "Invalid data object of entry"); + return -EBADMSG; + } r = journal_file_move_to_object(f, OBJECT_DATA, q, &u); if (r < 0) return r; if (le64toh(u->data.hash) != h) { - error(p, "hash mismatch for data object of entry"); + error(p, "Hash mismatch for data object of entry"); return -EBADMSG; } @@ -694,7 +712,7 @@ static int verify_entry( if (r < 0) return r; if (r == 0) { - error(p, "data object missing from hash table"); + error(p, "Data object missing from hash table"); return -EBADMSG; } } @@ -726,15 +744,15 @@ static int verify_entry_array( Object *o; if (show_progress) - draw_progress(0x8000 + (0x3FFF * i / n), last_usec); + draw_progress(0x8000 + scale_progress(0x3FFF, i, n), last_usec); if (a == 0) { - error(a, "array chain too short at %"PRIu64" of %"PRIu64, i, n); + error(a, "Array chain too short at %"PRIu64" of %"PRIu64, i, n); return -EBADMSG; } if (!contains_uint64(f->mmap, entry_array_fd, n_entry_arrays, a)) { - error(a, "invalid array %"PRIu64" of %"PRIu64, i, n); + error(a, "Invalid array %"PRIu64" of %"PRIu64, i, n); return -EBADMSG; } @@ -744,9 +762,7 @@ static int verify_entry_array( next = le64toh(o->entry_array.next_entry_array_offset); if (next != 0 && next <= a) { - error(a, - "array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")", - i, n, next); + error(a, "Array chain has cycle at %"PRIu64" of %"PRIu64" (jumps back from to "OFSfmt")", i, n, next); return -EBADMSG; } @@ -756,15 +772,13 @@ static int verify_entry_array( p = le64toh(o->entry_array.items[j]); if (p <= last) { - error(a, "entry array not sorted at %"PRIu64" of %"PRIu64, - i, n); + error(a, "Entry array not sorted at %"PRIu64" of %"PRIu64, i, n); return -EBADMSG; } last = p; if (!contains_uint64(f->mmap, entry_fd, n_entries, p)) { - error(a, "invalid array entry at %"PRIu64" of %"PRIu64, - i, n); + error(a, "Invalid array entry at %"PRIu64" of %"PRIu64, i, n); return -EBADMSG; } @@ -852,7 +866,7 @@ int journal_file_verify( for (i = 0; i < sizeof(f->header->reserved); i++) if (f->header->reserved[i] != 0) { - error(offsetof(Header, reserved[i]), "reserved field is non-zero"); + error(offsetof(Header, reserved[i]), "Reserved field is non-zero"); r = -EBADMSG; goto fail; } @@ -861,36 +875,37 @@ int journal_file_verify( * superficial structure, headers, hashes. */ p = le64toh(f->header->header_size); - while (p != 0) { + for (;;) { + /* Early exit if there are no objects in the file, at all */ + if (le64toh(f->header->tail_object_offset) == 0) + break; + if (show_progress) - draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec); + draw_progress(scale_progress(0x7FFF, p, le64toh(f->header->tail_object_offset)), &last_usec); r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); if (r < 0) { - error(p, "invalid object"); + error(p, "Invalid object"); goto fail; } if (p > le64toh(f->header->tail_object_offset)) { - error(offsetof(Header, tail_object_offset), "invalid tail object pointer"); + error(offsetof(Header, tail_object_offset), "Invalid tail object pointer"); r = -EBADMSG; goto fail; } - if (p == le64toh(f->header->tail_object_offset)) - found_last = true; - n_objects ++; r = journal_file_object_verify(f, p, o); if (r < 0) { - error(p, "invalid object contents: %s", strerror(-r)); + error(p, "Envalid object contents: %s", strerror(-r)); goto fail; } if ((o->object.flags & OBJECT_COMPRESSED_XZ) && (o->object.flags & OBJECT_COMPRESSED_LZ4)) { - error(p, "objected with double compression"); + error(p, "Objected with double compression"); r = -EINVAL; goto fail; } @@ -923,7 +938,7 @@ int journal_file_verify( case OBJECT_ENTRY: if (JOURNAL_HEADER_SEALED(f->header) && n_tags <= 0) { - error(p, "first entry before first tag"); + error(p, "First entry before first tag"); r = -EBADMSG; goto fail; } @@ -933,21 +948,21 @@ int journal_file_verify( goto fail; if (le64toh(o->entry.realtime) < last_tag_realtime) { - error(p, "older entry after newer tag"); + error(p, "Older entry after newer tag"); r = -EBADMSG; goto fail; } if (!entry_seqnum_set && le64toh(o->entry.seqnum) != le64toh(f->header->head_entry_seqnum)) { - error(p, "head entry sequence number incorrect"); + error(p, "Head entry sequence number incorrect"); r = -EBADMSG; goto fail; } if (entry_seqnum_set && entry_seqnum >= le64toh(o->entry.seqnum)) { - error(p, "entry sequence number out of synchronization"); + error(p, "Entry sequence number out of synchronization"); r = -EBADMSG; goto fail; } @@ -958,7 +973,7 @@ int journal_file_verify( if (entry_monotonic_set && sd_id128_equal(entry_boot_id, o->entry.boot_id) && entry_monotonic > le64toh(o->entry.monotonic)) { - error(p, "entry timestamp out of synchronization"); + error(p, "Entry timestamp out of synchronization"); r = -EBADMSG; goto fail; } @@ -969,7 +984,7 @@ int journal_file_verify( if (!entry_realtime_set && le64toh(o->entry.realtime) != le64toh(f->header->head_entry_realtime)) { - error(p, "head entry realtime timestamp incorrect"); + error(p, "Head entry realtime timestamp incorrect"); r = -EBADMSG; goto fail; } @@ -982,7 +997,7 @@ int journal_file_verify( case OBJECT_DATA_HASH_TABLE: if (n_data_hash_tables > 1) { - error(p, "more than one data hash table"); + error(p, "More than one data hash table"); r = -EBADMSG; goto fail; } @@ -999,14 +1014,14 @@ int journal_file_verify( case OBJECT_FIELD_HASH_TABLE: if (n_field_hash_tables > 1) { - error(p, "more than one field hash table"); + error(p, "More than one field hash table"); r = -EBADMSG; goto fail; } if (le64toh(f->header->field_hash_table_offset) != p + offsetof(HashTableObject, items) || le64toh(f->header->field_hash_table_size) != le64toh(o->object.size) - offsetof(HashTableObject, items)) { - error(p, "header fields for field hash table invalid"); + error(p, "Header fields for field hash table invalid"); r = -EBADMSG; goto fail; } @@ -1021,7 +1036,7 @@ int journal_file_verify( if (p == le64toh(f->header->entry_array_offset)) { if (found_main_entry_array) { - error(p, "more than one main entry array"); + error(p, "More than one main entry array"); r = -EBADMSG; goto fail; } @@ -1034,19 +1049,19 @@ int journal_file_verify( case OBJECT_TAG: if (!JOURNAL_HEADER_SEALED(f->header)) { - error(p, "tag object in file without sealing"); + error(p, "Tag object in file without sealing"); r = -EBADMSG; goto fail; } if (le64toh(o->tag.seqnum) != n_tags + 1) { - error(p, "tag sequence number out of synchronization"); + error(p, "Tag sequence number out of synchronization"); r = -EBADMSG; goto fail; } if (le64toh(o->tag.epoch) < last_epoch) { - error(p, "epoch sequence out of synchronization"); + error(p, "Epoch sequence out of synchronization"); r = -EBADMSG; goto fail; } @@ -1055,7 +1070,7 @@ int journal_file_verify( if (f->seal) { uint64_t q, rt; - debug(p, "checking tag %"PRIu64"...", le64toh(o->tag.seqnum)); + debug(p, "Checking tag %"PRIu64"...", le64toh(o->tag.seqnum)); rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec; if (entry_realtime_set && entry_realtime >= rt + f->fss_interval_usec) { @@ -1102,7 +1117,7 @@ int journal_file_verify( goto fail; if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) { - error(p, "tag failed verification"); + error(p, "Tag failed verification"); r = -EBADMSG; goto fail; } @@ -1124,79 +1139,69 @@ int journal_file_verify( n_weird ++; } - if (p == le64toh(f->header->tail_object_offset)) - p = 0; - else - p = p + ALIGN64(le64toh(o->object.size)); - } + if (p == le64toh(f->header->tail_object_offset)) { + found_last = true; + break; + } - if (!found_last) { - error(le64toh(f->header->tail_object_offset), "tail object pointer dead"); + p = p + ALIGN64(le64toh(o->object.size)); + }; + + if (!found_last && le64toh(f->header->tail_object_offset) != 0) { + error(le64toh(f->header->tail_object_offset), "Tail object pointer dead"); r = -EBADMSG; goto fail; } if (n_objects != le64toh(f->header->n_objects)) { - error(offsetof(Header, n_objects), "object number mismatch"); + error(offsetof(Header, n_objects), "Object number mismatch"); r = -EBADMSG; goto fail; } if (n_entries != le64toh(f->header->n_entries)) { - error(offsetof(Header, n_entries), "entry number mismatch"); + error(offsetof(Header, n_entries), "Entry number mismatch"); r = -EBADMSG; goto fail; } if (JOURNAL_HEADER_CONTAINS(f->header, n_data) && n_data != le64toh(f->header->n_data)) { - error(offsetof(Header, n_data), "data number mismatch"); + error(offsetof(Header, n_data), "Data number mismatch"); r = -EBADMSG; goto fail; } if (JOURNAL_HEADER_CONTAINS(f->header, n_fields) && n_fields != le64toh(f->header->n_fields)) { - error(offsetof(Header, n_fields), "field number mismatch"); + error(offsetof(Header, n_fields), "Field number mismatch"); r = -EBADMSG; goto fail; } if (JOURNAL_HEADER_CONTAINS(f->header, n_tags) && n_tags != le64toh(f->header->n_tags)) { - error(offsetof(Header, n_tags), "tag number mismatch"); + error(offsetof(Header, n_tags), "Tag number mismatch"); r = -EBADMSG; goto fail; } if (JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays) && n_entry_arrays != le64toh(f->header->n_entry_arrays)) { - error(offsetof(Header, n_entry_arrays), "entry array number mismatch"); - r = -EBADMSG; - goto fail; - } - - if (n_data_hash_tables != 1) { - error(0, "missing data hash table"); - r = -EBADMSG; - goto fail; - } - - if (n_field_hash_tables != 1) { - error(0, "missing field hash table"); + error(offsetof(Header, n_entry_arrays), "Entry array number mismatch"); r = -EBADMSG; goto fail; } - if (!found_main_entry_array) { - error(0, "missing entry array"); + if (!found_main_entry_array && le64toh(f->header->entry_array_offset) != 0) { + error(0, "Missing entry array"); r = -EBADMSG; goto fail; } if (entry_seqnum_set && entry_seqnum != le64toh(f->header->tail_entry_seqnum)) { - error(offsetof(Header, tail_entry_seqnum), "invalid tail seqnum"); + error(offsetof(Header, tail_entry_seqnum), "Invalid tail seqnum"); r = -EBADMSG; goto fail; } @@ -1204,13 +1209,13 @@ int journal_file_verify( if (entry_monotonic_set && (!sd_id128_equal(entry_boot_id, f->header->boot_id) || entry_monotonic != le64toh(f->header->tail_entry_monotonic))) { - error(0, "invalid tail monotonic timestamp"); + error(0, "Invalid tail monotonic timestamp"); r = -EBADMSG; goto fail; } if (entry_realtime_set && entry_realtime != le64toh(f->header->tail_entry_realtime)) { - error(0, "invalid tail realtime timestamp"); + error(0, "Invalid tail realtime timestamp"); r = -EBADMSG; goto fail; } diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 2d6ecfb750..073cc77711 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2066,6 +2066,10 @@ int main(int argc, char *argv[]) { log_error_errno(r, "Failed to iterate through journal: %m"); goto finish; } + if (r == 0) { + printf("-- No entries --\n"); + goto finish; + } if (!arg_follow) pager_open_if_enabled(); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 46358e1c1a..28b1472ac8 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -175,9 +175,11 @@ static uint64_t available_space(Server *s, bool verbose) { fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX]; server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE, - "%s journal is using %s (max allowed %s, " - "trying to leave %s free of %s available → current limit %s).", - s->system_journal ? "Permanent" : "Runtime", + "%s is currently using %s.\n" + "Maximum allowed usage is set to %s.\n" + "Leaving at least %s free (of currently available %s of space).\n" + "Enforced usage limit is thus %s.", + s->system_journal ? "Permanent journal (/var/log/journal/)" : "Runtime journal (/run/log/journal/)", format_bytes(fb1, sizeof(fb1), sum), format_bytes(fb2, sizeof(fb2), m->max_use), format_bytes(fb3, sizeof(fb3), m->keep_free), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index 0dbfbddcf6..f2092795f4 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -46,6 +46,8 @@ #define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID" #define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists" #define BUS_ERROR_NO_PRIVATE_NETWORKING "org.freedesktop.machine1.NoPrivateNetworking" +#define BUS_ERROR_NO_SUCH_USER_MAPPING "org.freedesktop.machine1.NoSuchUserMapping" +#define BUS_ERROR_NO_SUCH_GROUP_MAPPING "org.freedesktop.machine1.NoSuchGroupMapping" #define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession" #define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID" diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index 99115d5e49..c53666ddd0 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -1131,7 +1131,7 @@ static int add_name_change_match(sd_bus *bus, /* If the old name is unset or empty, then * this can match against added names */ - if (!old_owner || old_owner[0] == 0) { + if (isempty(old_owner)) { item->type = KDBUS_ITEM_NAME_ADD; r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); @@ -1141,7 +1141,7 @@ static int add_name_change_match(sd_bus *bus, /* If the new name is unset or empty, then * this can match against removed names */ - if (!new_owner || new_owner[0] == 0) { + if (isempty(new_owner)) { item->type = KDBUS_ITEM_NAME_REMOVE; r = ioctl(bus->input_fd, KDBUS_CMD_MATCH_ADD, m); @@ -1185,7 +1185,7 @@ static int add_name_change_match(sd_bus *bus, /* If the old name is unset or empty, then this can * match against added ids */ - if (!old_owner || old_owner[0] == 0) { + if (isempty(old_owner)) { item->type = KDBUS_ITEM_ID_ADD; if (!isempty(new_owner)) item->id_change.id = new_owner_id; @@ -1197,7 +1197,7 @@ static int add_name_change_match(sd_bus *bus, /* If thew new name is unset or empty, then this can * match against removed ids */ - if (!new_owner || new_owner[0] == 0) { + if (isempty(new_owner)) { item->type = KDBUS_ITEM_ID_REMOVE; if (!isempty(old_owner)) item->id_change.id = old_owner_id; diff --git a/src/libsystemd/sd-bus/test-bus-proxy.c b/src/libsystemd/sd-bus/test-bus-proxy.c new file mode 100644 index 0000000000..369c2f331c --- /dev/null +++ b/src/libsystemd/sd-bus/test-bus-proxy.c @@ -0,0 +1,109 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 David Herrmann <dh.herrmann@gmail.com> + + 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 <errno.h> +#include <fcntl.h> +#include <stdlib.h> + +#include "util.h" +#include "log.h" + +#include "sd-bus.h" +#include "bus-kernel.h" +#include "bus-util.h" +#include "bus-dump.h" + +typedef struct { + const char *sender; + int matched_acquired; +} TestProxyMatch; + +static int test_proxy_acquired(sd_bus_message *m, void *userdata, sd_bus_error *error) { + TestProxyMatch *match = userdata; + const char *name; + int r; + + r = sd_bus_message_read(m, "s", &name); + assert_se(r >= 0); + + if (!streq_ptr(match->sender, name)) + return 0; + + ++match->matched_acquired; + return 1; +} + +static void test_proxy_matched(void) { + _cleanup_bus_flush_close_unref_ sd_bus *a = NULL; + TestProxyMatch match = {}; + int r; + + /* open bus 'a' */ + + r = sd_bus_new(&a); + assert_se(r >= 0); + + r = sd_bus_set_address(a, "unix:path=/var/run/dbus/system_bus_socket"); + assert_se(r >= 0); + + r = sd_bus_set_bus_client(a, true); + assert_se(r >= 0); + + r = sd_bus_start(a); + assert_se(r >= 0); + + r = sd_bus_add_match(a, NULL, + "type='signal'," + "member='NameAcquired'", + test_proxy_acquired, &match); + assert_se(r >= 0); + + r = sd_bus_get_unique_name(a, &match.sender); + assert_se(r >= 0); + + /* barrier to guarantee proxy/dbus-daemon handled the previous data */ + r = sd_bus_call_method(a, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetId", + NULL, NULL, NULL); + assert_se(r >= 0); + + /* now we can be sure the Name* signals were sent */ + do { + r = sd_bus_process(a, NULL); + } while (r > 0); + assert_se(r == 0); + + assert_se(match.matched_acquired == 1); +} + +int main(int argc, char **argv) { + if (access("/var/run/dbus/system_bus_socket", F_OK) < 0) + return EXIT_TEST_SKIP; + + log_parse_environment(); + + test_proxy_matched(); + + return EXIT_SUCCESS; +} diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 74ac2ab344..ff1b8a260f 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -196,19 +196,29 @@ static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = { [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NETLINK_TYPE_U32 }, [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NETLINK_TYPE_U16 }, [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NETLINK_TYPE_U16 }, + [IFLA_IPTUN_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16}, + [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16}, + [IFLA_IPTUN_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16}, + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16}, }; static const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = { - [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 }, - [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, - [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 }, - [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_IKEY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_OKEY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_GRE_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, + [IFLA_GRE_TTL] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_TOS] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_PMTUDISC] = { .type = NETLINK_TYPE_U8 }, + [IFLA_GRE_FLOWINFO] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GRE_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_ENCAP_FLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_ENCAP_SPORT] = { .type = NETLINK_TYPE_U16 }, + [IFLA_GRE_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 }, }; static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = { @@ -319,8 +329,11 @@ static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] [IFLA_BRPORT_MODE] = { .type = NETLINK_TYPE_U8 }, [IFLA_BRPORT_GUARD] = { .type = NETLINK_TYPE_U8 }, [IFLA_BRPORT_PROTECT] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_FAST_LEAVE] = { .type = NETLINK_TYPE_U8 }, [IFLA_BRPORT_LEARNING] = { .type = NETLINK_TYPE_U8 }, [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_PROXYARP] = { .type = NETLINK_TYPE_U8 }, + [IFLA_BRPORT_LEARNING_SYNC] = { .type = NETLINK_TYPE_U8 }, }; static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = { diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 049e33e2a6..e6371ff04d 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1774,7 +1774,7 @@ static int nologin_timeout_handler( log_info("Creating /run/nologin, blocking further logins..."); - r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_ATOMIC); + r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); if (r < 0) log_error_errno(r, "Failed to create /run/nologin: %m"); else diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index 9d5287ad35..495ec50be0 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -486,7 +486,7 @@ void seat_evict_position(Seat *s, Session *session) { * position (eg., during gdm->session transition), so let's look * for it and set it on the free slot. */ LIST_FOREACH(sessions_by_seat, iter, s->sessions) { - if (iter->position == pos) { + if (iter->position == pos && session_get_state(iter) != SESSION_CLOSING) { s->positions[pos] = iter; break; } @@ -505,7 +505,7 @@ void seat_claim_position(Seat *s, Session *session, unsigned int pos) { seat_evict_position(s, session); session->position = pos; - if (pos > 0 && !s->positions[pos]) + if (pos > 0) s->positions[pos] = session; } diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 0e971a6789..3637815fc9 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -31,12 +31,13 @@ #include "bus-common-errors.h" #include "cgroup-util.h" #include "btrfs-util.h" +#include "formats-util.h" +#include "process-util.h" #include "machine-image.h" #include "machine-pool.h" #include "image-dbus.h" #include "machined.h" #include "machine-dbus.h" -#include "formats-util.h" static int property_get_pool_path( sd_bus *bus, @@ -840,6 +841,230 @@ static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bu return bus_image_method_set_limit(message, i, error); } +static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_fclose_ FILE *f = NULL; + Manager *m = userdata; + const char *name, *p; + Machine *machine; + uint32_t uid; + int r; + + r = sd_bus_message_read(message, "su", &name, &uid); + if (r < 0) + return r; + + if (UID_IS_INVALID(uid)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid); + + machine = hashmap_get(m->machines, name); + if (!machine) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name); + + p = procfs_file_alloca(machine->leader, "uid_map"); + f = fopen(p, "re"); + if (!f) + return -errno; + + for (;;) { + uid_t uid_base, uid_shift, uid_range, converted; + int k; + + errno = 0; + k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range); + if (k < 0 && feof(f)) + break; + if (k != 3) { + if (ferror(f) && errno != 0) + return -errno; + + return -EIO; + } + + if (uid < uid_base || uid >= uid_base + uid_range) + continue; + + converted = uid - uid_base + uid_shift; + if (UID_IS_INVALID(converted)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid); + + return sd_bus_reply_method_return(message, "u", (uint32_t) converted); + } + + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name); +} + +static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + Machine *machine; + uid_t uid; + Iterator i; + int r; + + r = sd_bus_message_read(message, "u", &uid); + if (r < 0) + return r; + if (UID_IS_INVALID(uid)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid); + if (uid < 0x10000) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid); + + HASHMAP_FOREACH(machine, m->machines, i) { + _cleanup_fclose_ FILE *f = NULL; + char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1]; + + xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader); + f = fopen(p, "re"); + if (!f) { + log_warning_errno(errno, "Failed top open %s, ignoring,", p); + continue; + } + + for (;;) { + _cleanup_free_ char *o = NULL; + uid_t uid_base, uid_shift, uid_range, converted; + int k; + + errno = 0; + k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range); + if (k < 0 && feof(f)) + break; + if (k != 3) { + if (ferror(f) && errno != 0) + return -errno; + + return -EIO; + } + + if (uid < uid_shift || uid >= uid_shift + uid_range) + continue; + + converted = (uid - uid_shift + uid_base); + if (UID_IS_INVALID(converted)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid); + + o = machine_bus_path(machine); + if (!o) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted); + } + } + + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid); +} + +static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) { + _cleanup_fclose_ FILE *f = NULL; + Manager *m = groupdata; + const char *name, *p; + Machine *machine; + uint32_t gid; + int r; + + r = sd_bus_message_read(message, "su", &name, &gid); + if (r < 0) + return r; + + if (GID_IS_INVALID(gid)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid); + + machine = hashmap_get(m->machines, name); + if (!machine) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name); + + p = procfs_file_alloca(machine->leader, "gid_map"); + f = fopen(p, "re"); + if (!f) + return -errno; + + for (;;) { + gid_t gid_base, gid_shift, gid_range, converted; + int k; + + errno = 0; + k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range); + if (k < 0 && feof(f)) + break; + if (k != 3) { + if (ferror(f) && errno != 0) + return -errno; + + return -EIO; + } + + if (gid < gid_base || gid >= gid_base + gid_range) + continue; + + converted = gid - gid_base + gid_shift; + if (GID_IS_INVALID(converted)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid); + + return sd_bus_reply_method_return(message, "u", (uint32_t) converted); + } + + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name); +} + +static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) { + Manager *m = groupdata; + Machine *machine; + gid_t gid; + Iterator i; + int r; + + r = sd_bus_message_read(message, "u", &gid); + if (r < 0) + return r; + if (GID_IS_INVALID(gid)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid); + if (gid < 0x10000) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid); + + HASHMAP_FOREACH(machine, m->machines, i) { + _cleanup_fclose_ FILE *f = NULL; + char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1]; + + xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader); + f = fopen(p, "re"); + if (!f) { + log_warning_errno(errno, "Failed top open %s, ignoring,", p); + continue; + } + + for (;;) { + _cleanup_free_ char *o = NULL; + gid_t gid_base, gid_shift, gid_range, converted; + int k; + + errno = 0; + k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range); + if (k < 0 && feof(f)) + break; + if (k != 3) { + if (ferror(f) && errno != 0) + return -errno; + + return -EIO; + } + + if (gid < gid_shift || gid >= gid_shift + gid_range) + continue; + + converted = (gid - gid_shift + gid_base); + if (GID_IS_INVALID(converted)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid); + + o = machine_bus_path(machine); + if (!o) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted); + } + } + + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid); +} + const sd_bus_vtable manager_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0), @@ -869,6 +1094,10 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_SIGNAL("MachineNew", "so", 0), SD_BUS_SIGNAL("MachineRemoved", "so", 0), SD_BUS_VTABLE_END diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf index 93aaf6a377..d58f01507b 100644 --- a/src/machine/org.freedesktop.machine1.conf +++ b/src/machine/org.freedesktop.machine1.conf @@ -113,6 +113,22 @@ send_member="SetImageLimit"/> <allow send_destination="org.freedesktop.machine1" + send_interface="org.freedesktop.machine1.Manager" + send_member="MapFromMachineUser"/> + + <allow send_destination="org.freedesktop.machine1" + send_interface="org.freedesktop.machine1.Manager" + send_member="MapToMachineUser"/> + + <allow send_destination="org.freedesktop.machine1" + send_interface="org.freedesktop.machine1.Manager" + send_member="MapFromMachineGroup"/> + + <allow send_destination="org.freedesktop.machine1" + send_interface="org.freedesktop.machine1.Manager" + send_member="MapToMachineGroup"/> + + <allow send_destination="org.freedesktop.machine1" send_interface="org.freedesktop.machine1.Machine" send_member="GetAddresses"/> diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index d446bfa8b3..4aa301b112 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -270,12 +270,18 @@ static int dhcp_lease_lost(Link *link) { if (link->network->dhcp_hostname) { const char *hostname = NULL; - r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); - if (r >= 0 && hostname) { - r = link_set_hostname(link, ""); + if (!link->network->hostname) + r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); + else + hostname = link->network->hostname; + + if (r >= 0 || hostname) { + r = link_set_hostname(link, hostname); if (r < 0) - log_link_error(link, - "Failed to reset transient hostname"); + log_link_error_errno(link, r, + "Failed to set transient hostname to '%s': %m", + hostname); + } } @@ -464,8 +470,12 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { if (link->network->dhcp_hostname) { const char *hostname; - r = sd_dhcp_lease_get_hostname(lease, &hostname); - if (r >= 0) { + if (!link->network->hostname) + r = sd_dhcp_lease_get_hostname(lease, &hostname); + else + hostname = link->network->hostname; + + if (r >= 0 || hostname) { r = link_set_hostname(link, hostname); if (r < 0) log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname); @@ -616,14 +626,19 @@ int dhcp4_configure(Link *link) { if (link->network->dhcp_sendhost) { _cleanup_free_ char *hostname = NULL; + const char *hn = NULL; + + if (!link->network->hostname) { + hostname = gethostname_malloc(); + if (!hostname) + return -ENOMEM; - hostname = gethostname_malloc(); - if (!hostname) - return -ENOMEM; + hn = hostname; + } else + hn = link->network->hostname; - if (!is_localhost(hostname)) { - r = sd_dhcp_client_set_hostname(link->dhcp_client, - hostname); + if (!is_localhost(hn)) { + r = sd_dhcp_client_set_hostname(link->dhcp_client, hn); if (r < 0) return r; } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 9550e89a15..55510b46e9 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -846,9 +846,6 @@ static int link_set_bridge(Link *link) { assert(link); assert(link->network); - if(link->network->cost == 0) - return 0; - r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex); if (r < 0) return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); @@ -861,6 +858,26 @@ static int link_set_bridge(Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m"); + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, link->network->bpdu_guard); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_GUARD attribute: %m"); + + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MODE, link->network->hairpin); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MODE attribute: %m"); + + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_FAST_LEAVE, link->network->fast_leave); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_FAST_LEAVE attribute: %m"); + + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, link->network->root_block); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m"); + + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m"); + if(link->network->cost != 0) { r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost); if (r < 0) diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index 010c106610..bdc43e87f6 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -36,6 +36,8 @@ Tunnel.TOS, config_parse_unsigned, 0, Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl) Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc) Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode) +Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel) +Tunnel.DiffServiceCodePoint, config_parse_bool, 0, offsetof(Tunnel, dscp) Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer) Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer) VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id) diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index 5533fb5c7b..1af234aba3 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -33,6 +33,7 @@ #include "conf-parser.h" #define DEFAULT_TNL_HOP_LIMIT 64 +#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF) static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = { [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6", @@ -184,6 +185,16 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m"); + if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) { + r = sd_netlink_message_append_u32(m, IFLA_GRE_FLOWINFO, t->ipv6_flowlabel); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLOWINFO attribute: %m"); + } + + r = sd_netlink_message_append_u32(m, IFLA_GRE_FLAGS, t->flags); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLAGS attribute: %m"); + return r; } @@ -264,6 +275,19 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m"); + if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) { + r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLOWINFO, t->ipv6_flowlabel); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m"); + } + + if (t->dscp) + t->flags |= IP6_TNL_F_RCV_DSCP_COPY; + + r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m"); + switch (t->ip6tnl_mode) { case NETDEV_IP6_TNL_MODE_IP6IP6: proto = IPPROTO_IPV6; @@ -380,6 +404,52 @@ int config_parse_tunnel_address(const char *unit, return 0; } +static const char* const ipv6_flowlabel_table[_NETDEV_IPV6_FLOWLABEL_MAX] = { + [NETDEV_IPV6_FLOWLABEL_INHERIT] = "inherit", +}; + +DEFINE_STRING_TABLE_LOOKUP(ipv6_flowlabel, IPv6FlowLabel); + +int config_parse_ipv6_flowlabel(const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + IPv6FlowLabel *ipv6_flowlabel = data; + Tunnel *t = userdata; + IPv6FlowLabel s; + int k = 0; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(ipv6_flowlabel); + + s = ipv6_flowlabel_from_string(rvalue); + if (s != _NETDEV_IPV6_FLOWLABEL_INVALID) { + *ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL; + t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL; + } else { + r = config_parse_unsigned(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata); + if (r >= 0) { + if (k > 0xFFFFF) + log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue); + else { + *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL; + t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; + } + } + } + + return 0; +} + static void ipip_init(NetDev *n) { Tunnel *t = IPIP(n); @@ -452,6 +522,7 @@ static void ip6tnl_init(NetDev *n) { t->ttl = DEFAULT_TNL_HOP_LIMIT; t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID; + t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID; } const NetDevVTable ipip_vtable = { diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index 88f57ac105..e08e2891e7 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -33,6 +33,12 @@ typedef enum Ip6TnlMode { _NETDEV_IP6_TNL_MODE_INVALID = -1, } Ip6TnlMode; +typedef enum IPv6FlowLabel { + NETDEV_IPV6_FLOWLABEL_INHERIT = 0xFFFFF + 1, + _NETDEV_IPV6_FLOWLABEL_MAX, + _NETDEV_IPV6_FLOWLABEL_INVALID = -1, +} IPv6FlowLabel; + struct Tunnel { NetDev meta; @@ -48,8 +54,10 @@ struct Tunnel { union in_addr_union remote; Ip6TnlMode ip6tnl_mode; + IPv6FlowLabel ipv6_flowlabel; bool pmtudisc; + bool dscp; }; extern const NetDevVTable ipip_vtable; @@ -70,3 +78,23 @@ int config_parse_ip6tnl_mode(const char *unit, const char *filename, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +int config_parse_tunnel_address(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata); + +const char *ipv6_flowlabel_to_string(IPv6FlowLabel d) _const_; +IPv6FlowLabel ipv6_flowlabel_from_string(const char *d) _pure_; + +int config_parse_ipv6_flowlabel(const char *unit, const char *filename, + unsigned line, const char *section, + unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, + void *userdata); diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h index fe5254e91f..e7d1306f13 100644 --- a/src/network/networkd-netdev-vxlan.h +++ b/src/network/networkd-netdev-vxlan.h @@ -53,3 +53,14 @@ struct VxLan { }; extern const NetDevVTable vxlan_vtable; + +int config_parse_vxlan_group_address(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 787fc2ff5b..720f6b9d0b 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -67,11 +67,17 @@ DHCP.UseHostname, config_parse_bool, 0 DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains) DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes) DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost) +DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, hostname) DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) +Bridge.BPDUGuard, config_parse_bool, 0, offsetof(Network, bpdu_guard) +Bridge.HairPin, config_parse_bool, 0, offsetof(Network, hairpin) +Bridge.FastLeave, config_parse_bool, 0, offsetof(Network, fast_leave) +Bridge.RootBlock, config_parse_bool, 0, offsetof(Network, root_block) +Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood) BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0 BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0 /* backwards compatibility: do not add new entries to this section */ diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index a8e9ef909c..55e735e6bf 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -207,6 +207,7 @@ void network_free(Network *network) { free(network->description); free(network->dhcp_vendor_class_identifier); + free(network->hostname); free(network->mac); @@ -809,3 +810,38 @@ int config_parse_ipv6_privacy_extensions( return 0; } + +int config_parse_hostname(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + char **hostname = data; + char *hn = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = config_parse_string(unit, filename, line, section, section_line, + lvalue, ltype, rvalue, &hn, userdata); + if (r < 0) + return r; + + if (!hostname_is_valid(hn)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, "hostname is not valid, ignoring assignment: %s", rvalue); + + free(hn); + return 0; + } + + *hostname = hn; + + return 0; +} diff --git a/src/network/networkd.h b/src/network/networkd.h index f98c640822..6418c0a536 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -133,6 +133,7 @@ struct Network { AddressFamilyBoolean dhcp; DCHPClientIdentifier dhcp_client_identifier; char *dhcp_vendor_class_identifier; + char *hostname; bool dhcp_dns; bool dhcp_ntp; bool dhcp_mtu; @@ -149,6 +150,11 @@ struct Network { bool dhcp_server; + bool bpdu_guard; + bool hairpin; + bool fast_leave; + bool root_block; + bool unicast_flood; unsigned cost; AddressFamilyBoolean ip_forward; @@ -319,28 +325,6 @@ int config_parse_tunnel(const char *unit, void *data, void *userdata); -int config_parse_tunnel_address(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata); - -int config_parse_vxlan_group_address(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata); - extern const sd_bus_vtable network_vtable[]; int network_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); @@ -473,3 +457,7 @@ const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_; IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; int config_parse_ipv6_privacy_extensions(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + + +/* Hostname */ +int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 3428109da4..65b9a5071b 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1785,15 +1785,13 @@ static int setup_pts(const char *dest) { #ifdef HAVE_SELINUX if (arg_selinux_apifs_context) (void) asprintf(&options, - "newinstance,ptmxmode=0666,mode=620,uid=" UID_FMT ",gid=" GID_FMT ",context=\"%s\"", - arg_uid_shift, + "newinstance,ptmxmode=0666,mode=620,gid=" GID_FMT ",context=\"%s\"", arg_uid_shift + TTY_GID, arg_selinux_apifs_context); else #endif (void) asprintf(&options, - "newinstance,ptmxmode=0666,mode=620,uid=" UID_FMT ",gid=" GID_FMT, - arg_uid_shift, + "newinstance,ptmxmode=0666,mode=620,gid=" GID_FMT, arg_uid_shift + TTY_GID); if (!options) diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index f712033e6c..cdec83d074 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -28,9 +28,12 @@ #include "util.h" #include "nss-util.h" #include "bus-util.h" +#include "bus-common-errors.h" #include "in-addr-util.h" NSS_GETHOSTBYNAME_PROTOTYPES(mymachines); +NSS_GETPW_PROTOTYPES(mymachines); +NSS_GETGR_PROTOTYPES(mymachines); static int count_addresses(sd_bus_message *m, int af, unsigned *ret) { unsigned c = 0; @@ -380,4 +383,319 @@ fail: return NSS_STATUS_UNAVAIL; } -NSS_GETHOSTBYNAME_FALLBACKS(mymachines) +NSS_GETHOSTBYNAME_FALLBACKS(mymachines); + +enum nss_status _nss_mymachines_getpwnam_r( + const char *name, + struct passwd *pwd, + char *buffer, size_t buflen, + int *errnop) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + const char *p, *e, *machine; + uint32_t mapped; + uid_t uid; + size_t l; + int r; + + assert(name); + assert(pwd); + + p = startswith(name, "vu-"); + if (!p) + goto not_found; + + e = strrchr(p, '-'); + if (!e || e == p) + goto not_found; + + r = parse_uid(e + 1, &uid); + if (r < 0) + goto not_found; + + machine = strndupa(p, e - p); + if (!machine_name_is_valid(machine)) + goto not_found; + + r = sd_bus_open_system(&bus); + if (r < 0) + goto fail; + + r = sd_bus_call_method(bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "MapFromMachineUser", + &error, + &reply, + "su", + machine, (uint32_t) uid); + if (r < 0) { + if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING)) + goto not_found; + + goto fail; + } + + r = sd_bus_message_read(reply, "u", &mapped); + if (r < 0) + goto fail; + + l = strlen(name); + if (buflen < l+1) { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + memcpy(buffer, name, l+1); + + pwd->pw_name = buffer; + pwd->pw_uid = mapped; + pwd->pw_gid = 65534; /* nobody */ + pwd->pw_gecos = buffer; + pwd->pw_passwd = (char*) "*"; /* locked */ + pwd->pw_dir = (char*) "/"; + pwd->pw_shell = (char*) "/sbin/nologin"; + + *errnop = 0; + return NSS_STATUS_SUCCESS; + +not_found: + *errnop = 0; + return NSS_STATUS_NOTFOUND; + +fail: + *errnop = -r; + return NSS_STATUS_UNAVAIL; +} + +enum nss_status _nss_mymachines_getpwuid_r( + uid_t uid, + struct passwd *pwd, + char *buffer, size_t buflen, + int *errnop) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + const char *machine, *object; + uint32_t mapped; + int r; + + if (UID_IS_INVALID(uid)) { + r = -EINVAL; + goto fail; + } + + /* We consider all uids < 65536 host uids */ + if (uid < 0x10000) + goto not_found; + + r = sd_bus_open_system(&bus); + if (r < 0) + goto fail; + + r = sd_bus_call_method(bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "MapToMachineUser", + &error, + &reply, + "u", + (uint32_t) uid); + if (r < 0) { + if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_USER_MAPPING)) + goto not_found; + + goto fail; + } + + r = sd_bus_message_read(reply, "sou", &machine, &object, &mapped); + if (r < 0) + goto fail; + + if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + pwd->pw_name = buffer; + pwd->pw_uid = uid; + pwd->pw_gid = 65534; /* nobody */ + pwd->pw_gecos = buffer; + pwd->pw_passwd = (char*) "*"; /* locked */ + pwd->pw_dir = (char*) "/"; + pwd->pw_shell = (char*) "/sbin/nologin"; + + *errnop = 0; + return NSS_STATUS_SUCCESS; + +not_found: + *errnop = 0; + return NSS_STATUS_NOTFOUND; + +fail: + *errnop = -r; + return NSS_STATUS_UNAVAIL; +} + +enum nss_status _nss_mymachines_getgrnam_r( + const char *name, + struct group *gr, + char *buffer, size_t buflen, + int *errnop) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + const char *p, *e, *machine; + uint32_t mapped; + uid_t gid; + size_t l; + int r; + + assert(name); + assert(gr); + + p = startswith(name, "vg-"); + if (!p) + goto not_found; + + e = strrchr(p, '-'); + if (!e || e == p) + goto not_found; + + r = parse_gid(e + 1, &gid); + if (r < 0) + goto not_found; + + machine = strndupa(p, e - p); + if (!machine_name_is_valid(machine)) + goto not_found; + + r = sd_bus_open_system(&bus); + if (r < 0) + goto fail; + + r = sd_bus_call_method(bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "MapFromMachineGroup", + &error, + &reply, + "su", + machine, (uint32_t) gid); + if (r < 0) { + if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING)) + goto not_found; + + goto fail; + } + + r = sd_bus_message_read(reply, "u", &mapped); + if (r < 0) + goto fail; + + l = sizeof(char*) + strlen(name) + 1; + if (buflen < l) { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + memzero(buffer, sizeof(char*)); + strcpy(buffer + sizeof(char*), name); + + gr->gr_name = buffer + sizeof(char*); + gr->gr_gid = gid; + gr->gr_passwd = (char*) "*"; /* locked */ + gr->gr_mem = (char**) buffer; + + *errnop = 0; + return NSS_STATUS_SUCCESS; + +not_found: + *errnop = 0; + return NSS_STATUS_NOTFOUND; + +fail: + *errnop = -r; + return NSS_STATUS_UNAVAIL; +} + +enum nss_status _nss_mymachines_getgrgid_r( + gid_t gid, + struct group *gr, + char *buffer, size_t buflen, + int *errnop) { + + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + const char *machine, *object; + uint32_t mapped; + int r; + + if (GID_IS_INVALID(gid)) { + r = -EINVAL; + goto fail; + } + + /* We consider all gids < 65536 host gids */ + if (gid < 0x10000) + goto not_found; + + r = sd_bus_open_system(&bus); + if (r < 0) + goto fail; + + r = sd_bus_call_method(bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "MapToMachineGroup", + &error, + &reply, + "u", + (uint32_t) gid); + if (r < 0) { + if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_GROUP_MAPPING)) + goto not_found; + + goto fail; + } + + r = sd_bus_message_read(reply, "sou", &machine, &object, &mapped); + if (r < 0) + goto fail; + + if (buflen < sizeof(char*) + 1) { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + memzero(buffer, sizeof(char*)); + if (snprintf(buffer + sizeof(char*), buflen - sizeof(char*), "vg-%s-" GID_FMT, machine, (gid_t) mapped) >= (int) buflen) { + *errnop = ENOMEM; + return NSS_STATUS_TRYAGAIN; + } + + gr->gr_name = buffer + sizeof(char*); + gr->gr_gid = gid; + gr->gr_passwd = (char*) "*"; /* locked */ + gr->gr_mem = (char**) buffer; + + *errnop = 0; + return NSS_STATUS_SUCCESS; + +not_found: + *errnop = 0; + return NSS_STATUS_NOTFOUND; + +fail: + *errnop = -r; + return NSS_STATUS_UNAVAIL; +} diff --git a/src/nss-mymachines/nss-mymachines.sym b/src/nss-mymachines/nss-mymachines.sym index f80b51c1aa..0728ac3ba7 100644 --- a/src/nss-mymachines/nss-mymachines.sym +++ b/src/nss-mymachines/nss-mymachines.sym @@ -13,5 +13,9 @@ global: _nss_mymachines_gethostbyname2_r; _nss_mymachines_gethostbyname3_r; _nss_mymachines_gethostbyname4_r; + _nss_mymachines_getpwnam_r; + _nss_mymachines_getpwuid_r; + _nss_mymachines_getgrnam_r; + _nss_mymachines_getgrgid_r; local: *; }; diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c index a3e740896f..e1087b3219 100644 --- a/src/resolve/dns-type.c +++ b/src/resolve/dns-type.c @@ -43,3 +43,8 @@ int dns_type_from_string(const char *s) { return sc->id; } + +/* XXX: find an authorotative list of all pseudo types? */ +bool dns_type_is_pseudo(int n) { + return IN_SET(n, DNS_TYPE_ANY, DNS_TYPE_AXFR, DNS_TYPE_IXFR, DNS_TYPE_OPT); +} diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index 86951d233a..950af36ee3 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -25,6 +25,7 @@ const char *dns_type_to_string(int type); int dns_type_from_string(const char *s); +bool dns_type_is_pseudo(int n); /* DNS record types, taken from * http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml. diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index b1cde4ab35..649e8b74e1 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -275,7 +275,7 @@ static void dns_packet_truncate(DnsPacket *p, size_t sz) { if (p->size <= sz) return; - HASHMAP_FOREACH_KEY(s, n, p->names, i) { + HASHMAP_FOREACH_KEY(n, s, p->names, i) { if (PTR_TO_SIZE(n) < sz) continue; @@ -509,22 +509,22 @@ static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t l assert(p); assert(types); - if (length == 0) - return 0; - saved_size = p->size; - r = dns_packet_append_uint8(p, window, NULL); - if (r < 0) - goto fail; + if (length != 0) { - r = dns_packet_append_uint8(p, length, NULL); - if (r < 0) - goto fail; + r = dns_packet_append_uint8(p, window, NULL); + if (r < 0) + goto fail; - r = dns_packet_append_blob(p, types, length, NULL); - if (r < 0) - goto fail; + r = dns_packet_append_uint8(p, length, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_blob(p, types, length, NULL); + if (r < 0) + goto fail; + } if (start) *start = saved_size; @@ -761,7 +761,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (r < 0) goto fail; - r = dns_packet_append_blob(p, rr->sshfp.key, rr->sshfp.key_size, NULL); + r = dns_packet_append_blob(p, rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, NULL); break; case DNS_TYPE_DNSKEY: @@ -933,6 +933,42 @@ int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) { return 0; } +static int dns_packet_read_memdup( + DnsPacket *p, size_t size, + void **ret, size_t *ret_size, + size_t *ret_start) { + + const void *src; + size_t start; + int r; + + assert(p); + assert(ret); + + r = dns_packet_read(p, size, &src, &start); + if (r < 0) + return r; + + if (size <= 0) + *ret = NULL; + else { + void *copy; + + copy = memdup(src, size); + if (!copy) + return -ENOMEM; + + *ret = copy; + } + + if (ret_size) + *ret_size = size; + if (ret_start) + *ret_start = start; + + return 0; +} + int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) { const void *d; int r; @@ -1172,9 +1208,12 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta if (bitmap[i] & bitmask) { uint16_t n; - /* XXX: ignore pseudo-types? see RFC4034 section 4.1.2 */ n = (uint16_t) window << 8 | (uint16_t) bit; + /* Ignore pseudo-types. see RFC4034 section 4.1.2 */ + if (dns_type_is_pseudo(n)) + continue; + r = bitmap_set(*types, n); if (r < 0) goto fail; @@ -1197,6 +1236,38 @@ fail: return r; } +static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t size, size_t *start) { + size_t saved_rindex; + int r; + + saved_rindex = p->rindex; + + while (p->rindex < saved_rindex + size) { + r = dns_packet_read_type_window(p, types, NULL); + if (r < 0) + goto fail; + + /* don't read past end of current RR */ + if (p->rindex > saved_rindex + size) { + r = -EBADMSG; + goto fail; + } + } + + if (p->rindex != saved_rindex + size) { + r = -EBADMSG; + goto fail; + } + + if (start) + *start = saved_rindex; + + return 0; +fail: + dns_packet_rewind(p, saved_rindex); + return r; +} + int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) { _cleanup_free_ char *name = NULL; uint16_t class, type; @@ -1239,26 +1310,6 @@ fail: return r; } -static int dns_packet_read_public_key(DnsPacket *p, size_t length, - void **dp, size_t *lengthp, - size_t *start) { - int r; - const void *d; - void *d2; - - r = dns_packet_read(p, length, &d, NULL); - if (r < 0) - return r; - - d2 = memdup(d, length); - if (!d2) - return -ENOMEM; - - *dp = d2; - *lengthp = length; - return 0; -} - static bool loc_size_ok(uint8_t size) { uint8_t m = size >> 4, e = size & 0xF; @@ -1281,7 +1332,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; size_t saved_rindex, offset; uint16_t rdlength; - const void *d; int r; assert(p); @@ -1492,12 +1542,19 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; - r = dns_packet_read_public_key(p, rdlength - 4, - &rr->ds.digest, &rr->ds.digest_size, - NULL); + r = dns_packet_read_memdup(p, rdlength - 4, + &rr->ds.digest, &rr->ds.digest_size, + NULL); if (r < 0) goto fail; + if (rr->ds.digest_size <= 0) { + /* the accepted size depends on the algorithm, but for now + just ensure that the value is greater than zero */ + r = -EBADMSG; + goto fail; + } + break; case DNS_TYPE_SSHFP: r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL); @@ -1508,9 +1565,17 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; - r = dns_packet_read_public_key(p, rdlength - 2, - &rr->sshfp.key, &rr->sshfp.key_size, - NULL); + r = dns_packet_read_memdup(p, rdlength - 2, + &rr->sshfp.fingerprint, &rr->sshfp.fingerprint_size, + NULL); + + if (rr->sshfp.fingerprint_size <= 0) { + /* the accepted size depends on the algorithm, but for now + just ensure that the value is greater than zero */ + r = -EBADMSG; + goto fail; + } + break; case DNS_TYPE_DNSKEY: { @@ -1539,9 +1604,17 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; - r = dns_packet_read_public_key(p, rdlength - 4, - &rr->dnskey.key, &rr->dnskey.key_size, - NULL); + r = dns_packet_read_memdup(p, rdlength - 4, + &rr->dnskey.key, &rr->dnskey.key_size, + NULL); + + if (rr->dnskey.key_size <= 0) { + /* the accepted size depends on the algorithm, but for now + just ensure that the value is greater than zero */ + r = -EBADMSG; + goto fail; + } + break; } @@ -1578,9 +1651,17 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; - r = dns_packet_read_public_key(p, offset + rdlength - p->rindex, - &rr->rrsig.signature, &rr->rrsig.signature_size, - NULL); + r = dns_packet_read_memdup(p, offset + rdlength - p->rindex, + &rr->rrsig.signature, &rr->rrsig.signature_size, + NULL); + + if (rr->rrsig.signature_size <= 0) { + /* the accepted size depends on the algorithm, but for now + just ensure that the value is greater than zero */ + r = -EBADMSG; + goto fail; + } + break; case DNS_TYPE_NSEC: @@ -1588,11 +1669,12 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; - while (p->rindex != offset + rdlength) { - r = dns_packet_read_type_window(p, &rr->nsec.types, NULL); - if (r < 0) - goto fail; - } + r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL); + if (r < 0) + goto fail; + + /* NSEC RRs with empty bitmpas makes no sense, but the RFC does not explicitly forbid them + so we allow it */ break; @@ -1611,57 +1693,41 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; + /* this may be zero */ r = dns_packet_read_uint8(p, &size, NULL); if (r < 0) goto fail; - rr->nsec3.salt_size = size; - - r = dns_packet_read_blob(p, &d, rr->nsec3.salt_size, NULL); + r = dns_packet_read_memdup(p, size, &rr->nsec3.salt, &rr->nsec3.salt_size, NULL); if (r < 0) goto fail; - rr->nsec3.salt = memdup(d, rr->nsec3.salt_size); - if (!rr->nsec3.salt) { - r = -ENOMEM; - goto fail; - } - r = dns_packet_read_uint8(p, &size, NULL); if (r < 0) goto fail; - rr->nsec3.next_hashed_name_size = size; - - r = dns_packet_read(p, rr->nsec3.next_hashed_name_size, &d, NULL); - if (r < 0) + if (size <= 0) { + r = -EBADMSG; goto fail; + } - rr->nsec3.next_hashed_name = memdup(d, rr->nsec3.next_hashed_name_size); - if (!rr->nsec3.next_hashed_name) { - r = -ENOMEM; + r = dns_packet_read_memdup(p, size, &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, NULL); + if (r < 0) goto fail; - } - r = dns_packet_append_types(p, rr->nsec3.types, NULL); + r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL); if (r < 0) goto fail; + /* empty non-terminals can have NSEC3 records, so empty bitmaps are allowed */ + break; } default: unparseable: - r = dns_packet_read(p, rdlength, &d, NULL); + r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.size, NULL); if (r < 0) goto fail; - - rr->generic.data = memdup(d, rdlength); - if (!rr->generic.data) { - r = -ENOMEM; - goto fail; - } - - rr->generic.size = rdlength; break; } if (r < 0) diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 859b3f7339..2bc9f2b520 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -276,7 +276,7 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) { break; case DNS_TYPE_SSHFP: - free(rr->sshfp.key); + free(rr->sshfp.fingerprint); break; case DNS_TYPE_DNSKEY: @@ -434,8 +434,8 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor case DNS_TYPE_SSHFP: return a->sshfp.algorithm == b->sshfp.algorithm && a->sshfp.fptype == b->sshfp.fptype && - a->sshfp.key_size == b->sshfp.key_size && - memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0; + a->sshfp.fingerprint_size == b->sshfp.fingerprint_size && + memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0; case DNS_TYPE_DNSKEY: return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag && @@ -533,7 +533,7 @@ static char *format_types(Bitmap *types) { BITMAP_FOREACH(type, types, i) { if (dns_type_to_string(type)) { - r = strv_extend(&strv, strdup(dns_type_to_string(type))); + r = strv_extend(&strv, dns_type_to_string(type)); if (r < 0) return NULL; } else { @@ -543,7 +543,7 @@ static char *format_types(Bitmap *types) { if (r < 0) return NULL; - r = strv_extend(&strv, t); + r = strv_consume(&strv, t); if (r < 0) return NULL; } @@ -687,7 +687,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { break; case DNS_TYPE_SSHFP: - t = hexmem(rr->sshfp.key, rr->sshfp.key_size); + t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size); if (!t) return -ENOMEM; @@ -776,7 +776,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { case DNS_TYPE_NSEC3: { _cleanup_free_ char *salt = NULL, *hash = NULL; - if (rr->nsec3.salt_size) { + if (rr->nsec3.salt_size > 0) { salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size); if (!salt) return -ENOMEM; @@ -795,7 +795,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { rr->nsec3.algorithm, rr->nsec3.flags, rr->nsec3.iterations, - rr->nsec3.salt_size ? salt : "-", + rr->nsec3.salt_size > 0 ? salt : "-", hash, t); if (r < 0) @@ -809,7 +809,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { if (!t) return -ENOMEM; - r = asprintf(&s, "%s \\# %"PRIu8" %s", k, rr->generic.size, t); + r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t); if (r < 0) return -ENOMEM; break; diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index bdd5a5c824..0f40f3ceef 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -53,7 +53,7 @@ struct DnsResourceRecord { union { struct { void *data; - uint16_t size; + size_t size; } generic; struct { @@ -117,11 +117,12 @@ struct DnsResourceRecord { size_t digest_size; } ds; + /* https://tools.ietf.org/html/rfc4255#section-3.1 */ struct { uint8_t algorithm; uint8_t fptype; - void *key; - size_t key_size; + void *fingerprint; + size_t fingerprint_size; } sshfp; /* http://tools.ietf.org/html/rfc4034#section-2.1 */ diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 7b72c090c2..0aab1e35d3 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -420,19 +420,6 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) { return 0; } -int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address) { - assert(s); - assert(address); - - if (s->protocol != DNS_PROTOCOL_DNS) - return 1; - - if (s->link) - return !!link_find_dns_server(s->link, family, address); - else - return !!manager_find_dns_server(s->manager, family, address); -} - static int dns_scope_make_reply_packet( DnsScope *s, uint16_t id, diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 5c5ccc71c5..21a160ea39 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -70,7 +70,6 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain); int dns_scope_good_key(DnsScope *s, DnsResourceKey *key); -int dns_scope_good_dns_server(DnsScope *s, int family, const union in_addr_union *address); DnsServer *dns_scope_get_dns_server(DnsScope *s); void dns_scope_next_dns_server(DnsScope *s); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index e468f245f7..3d46c99df8 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -417,8 +417,10 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { /* Only consider responses with equivalent query section to the request */ if (!dns_question_is_superset(p->question, t->question) || - !dns_question_is_superset(t->question, p->question)) + !dns_question_is_superset(t->question, p->question)) { dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); + return; + } /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */ dns_cache_put(&t->scope->cache, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender); diff --git a/src/shared/nss-util.h b/src/shared/nss-util.h index 230a986040..3657aa5d9c 100644 --- a/src/shared/nss-util.h +++ b/src/shared/nss-util.h @@ -24,6 +24,9 @@ #include <nss.h> #include <netdb.h> #include <resolv.h> +#include <pwd.h> +#include <grp.h> + #define NSS_GETHOSTBYNAME_PROTOTYPES(module) \ enum nss_status _nss_##module##_gethostbyname4_r( \ @@ -109,7 +112,8 @@ enum nss_status _nss_##module##_gethostbyname_r( \ NULL, \ NULL); \ return ret; \ -} +} \ +struct __useless_struct_to_allow_trailing_semicolon__ #define NSS_GETHOSTBYADDR_FALLBACKS(module) \ enum nss_status _nss_##module##_gethostbyaddr_r( \ @@ -125,4 +129,29 @@ enum nss_status _nss_##module##_gethostbyaddr_r( \ buffer, buflen, \ errnop, h_errnop, \ NULL); \ -} +} \ +struct __useless_struct_to_allow_trailing_semicolon__ + +#define NSS_GETPW_PROTOTYPES(module) \ +enum nss_status _nss_##module##_getpwnam_r( \ + const char *name, \ + struct passwd *pwd, \ + char *buffer, size_t buflen, \ + int *errnop) _public_; \ +enum nss_status _nss_mymachines_getpwuid_r( \ + uid_t uid, \ + struct passwd *pwd, \ + char *buffer, size_t buflen, \ + int *errnop) _public_ + +#define NSS_GETGR_PROTOTYPES(module) \ +enum nss_status _nss_##module##_getgrnam_r( \ + const char *name, \ + struct group *gr, \ + char *buffer, size_t buflen, \ + int *errnop) _public_; \ +enum nss_status _nss_##module##_getgrgid_r( \ + gid_t gid, \ + struct group *gr, \ + char *buffer, size_t buflen, \ + int *errnop) _public_ diff --git a/src/test/test-bitmap.c b/src/test/test-bitmap.c index 77db784a94..96deeded7e 100644 --- a/src/test/test-bitmap.c +++ b/src/test/test-bitmap.c @@ -58,6 +58,14 @@ int main(int argc, const char *argv[]) { assert_se(bitmap_isset(b, 256) == false); assert_se(bitmap_isclear(b) == true); + assert_se(bitmap_set(b, 32) == 0); + bitmap_unset(b, 0); + assert_se(bitmap_isset(b, 32) == true); + bitmap_unset(b, 32); + + BITMAP_FOREACH(n, NULL, it) + assert_not_reached("NULL bitmap"); + assert_se(bitmap_set(b, 0) == 0); assert_se(bitmap_set(b, 1) == 0); assert_se(bitmap_set(b, 256) == 0); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 42f757c4b7..271984b5a8 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -955,9 +955,10 @@ static int path_set_attribute(Item *item, const char *path) { r = chattr_fd(fd, f, item->attribute_mask); if (r < 0) - return log_error_errno(r, - "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m", - path, item->attribute_value, item->attribute_mask); + log_full_errno(r == -ENOTTY ? LOG_DEBUG : LOG_WARNING, + r, + "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x: %m", + path, item->attribute_value, item->attribute_mask); return 0; } diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c index 7ba0b7fc8f..a59d4c6d50 100644 --- a/src/udev/ata_id/ata_id.c +++ b/src/udev/ata_id/ata_id.c @@ -638,10 +638,20 @@ int main(int argc, char *argv[]) * All other values are reserved. */ word = identify.wyde[108]; - if ((word & 0xf000) == 0x5000) + if ((word & 0xf000) == 0x5000) { + uint64_t wwwn; + + wwwn = identify.wyde[108]; + wwwn <<= 16; + wwwn |= identify.wyde[109]; + wwwn <<= 16; + wwwn |= identify.wyde[110]; + wwwn <<= 16; + wwwn |= identify.wyde[111]; printf("ID_WWN=0x%1$" PRIx64 "\n" "ID_WWN_WITH_EXTENSION=0x%1$" PRIx64 "\n", - identify.octa[108/4]); + wwwn); + } /* from Linux's include/linux/ata.h */ if (identify.wyde[0] == 0x848a || diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 0661f7be00..d0b8bad48e 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1358,6 +1358,7 @@ static int listen_fds(int *rctrl, int *rnetlink) { * udev.event-timeout=<number of seconds> seconds to wait before terminating an event */ static int parse_proc_cmdline_item(const char *key, const char *value) { + const char *full_key = key; int r; assert(key); @@ -1377,26 +1378,29 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { int prio; prio = util_log_priority(value); + if (prio < 0) + goto invalid; log_set_max_level(prio); } else if (streq(key, "children-max")) { r = safe_atou(value, &arg_children_max); if (r < 0) - log_warning("invalid udev.children-max ignored: %s", value); + goto invalid; } else if (streq(key, "exec-delay")) { r = safe_atoi(value, &arg_exec_delay); if (r < 0) - log_warning("invalid udev.exec-delay ignored: %s", value); + goto invalid; } else if (streq(key, "event-timeout")) { r = safe_atou64(value, &arg_event_timeout_usec); if (r < 0) - log_warning("invalid udev.event-timeout ignored: %s", value); - else { - arg_event_timeout_usec *= USEC_PER_SEC; - arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; - } + goto invalid; + arg_event_timeout_usec *= USEC_PER_SEC; + arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1; } return 0; +invalid: + log_warning("invalid %s ignored: %s", full_key, value); + return 0; } static void help(void) { @@ -1432,7 +1436,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "c:de:DtN:hV", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "c:de:Dt:N:hV", options, NULL)) >= 0) { int r; switch (c) { diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index ddeb310c3c..e80a7771de 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -65,7 +65,7 @@ int main(int argc, char*argv[]) { } else if (streq(argv[1], "stop")) { int r; - r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_ATOMIC); + r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); if (r < 0) { log_error_errno(r, "Failed to create /run/nologin: %m"); return EXIT_FAILURE; |