diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in index e30d9a8..a3d399b 100644 --- a/rules/99-systemd.rules.in +++ b/rules/99-systemd.rules.in @@ -14,10 +14,6 @@ KERNEL=="vport*", TAG+="systemd" SUBSYSTEM=="block", KERNEL!="ram*", TAG+="systemd" SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" -# Ignore encrypted devices with no identified superblock on it, since -# we are probably still calling mke2fs or mkswap on it. -SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0" - # Ignore raid devices that are not yet assembled and started SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", TEST!="md/array_state", ENV{SYSTEMD_READY}="0" SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", ATTR{md/array_state}=="|clear|inactive", ENV{SYSTEMD_READY}="0" diff --git a/src/core/job.c b/src/core/job.c index eaa4bb1..db44fee 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -352,6 +352,9 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) { return b == UNIT_ACTIVATING; + case JOB_NOP: + return true; + default: assert_not_reached("Invalid job type"); } diff --git a/src/core/job.h b/src/core/job.h index 1e7c61b..ee8e54a 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -49,9 +49,11 @@ enum JobType { _JOB_TYPE_MAX_MERGING, /* JOB_NOP can enter into a transaction, but as it won't pull in - * any dependencies, it won't have to merge with anything. - * job_install() avoids the problem of merging JOB_NOP too (it's - * special-cased, only merges with other JOB_NOPs). */ + * any dependencies and it uses the special 'nop_job' slot in Unit, + * it won't have to merge with anything (except possibly into another + * JOB_NOP, previously installed). JOB_NOP is special-cased in + * job_type_is_*() functions so that the transaction can be + * activated. */ JOB_NOP = _JOB_TYPE_MAX_MERGING, /* do nothing */ _JOB_TYPE_MAX_IN_TRANSACTION, @@ -190,11 +192,15 @@ _pure_ static inline bool job_type_is_mergeable(JobType a, JobType b) { } _pure_ static inline bool job_type_is_conflicting(JobType a, JobType b) { - return !job_type_is_mergeable(a, b); + return a != JOB_NOP && b != JOB_NOP && !job_type_is_mergeable(a, b); } _pure_ static inline bool job_type_is_superset(JobType a, JobType b) { /* Checks whether operation a is a "superset" of b in its actions */ + if (b == JOB_NOP) + return true; + if (a == JOB_NOP) + return false; return a == job_type_lookup_merge(a, b); } diff --git a/src/core/manager.c b/src/core/manager.c index d427d88..256d6f7 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -662,9 +662,11 @@ static int manager_setup_notify(Manager *m) { return -errno; } - if (m->running_as == SYSTEMD_SYSTEM) + if (m->running_as == SYSTEMD_SYSTEM) { m->notify_socket = strdup("/run/systemd/notify"); - else { + if (!m->notify_socket) + return log_oom(); + } else { const char *e; e = getenv("XDG_RUNTIME_DIR"); @@ -674,9 +676,11 @@ static int manager_setup_notify(Manager *m) { } m->notify_socket = strappend(e, "/systemd/notify"); + if (!m->notify_socket) + return log_oom(); + + mkdir_parents_label(m->notify_socket, 0755); } - if (!m->notify_socket) - return log_oom(); strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1); r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 20cf526..03cfddc 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -75,7 +75,9 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 1); assert(argv); - while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) + /* "-" prevents getopt from permuting argv[] and moving the verb away + * from argv[1]. Our interface to initrd promises it'll be there. */ + while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0) switch (c) { case ARG_LOG_LEVEL: @@ -113,6 +115,13 @@ static int parse_argv(int argc, char *argv[]) { break; + case '\001': + if (!arg_verb) + arg_verb = optarg; + else + log_error("Excess arguments, ignoring"); + break; + case '?': return -EINVAL; @@ -120,15 +129,11 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option code."); } - if (optind >= argc) { + if (!arg_verb) { log_error("Verb argument missing."); return -EINVAL; } - arg_verb = argv[optind]; - - if (optind + 1 < argc) - log_error("Excess arguments, ignoring"); return 0; } diff --git a/src/core/snapshot.c b/src/core/snapshot.c index 5eed615..c2678cb 100644 --- a/src/core/snapshot.c +++ b/src/core/snapshot.c @@ -208,7 +208,7 @@ int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name); if (manager_get_unit(m, name)) - sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name); + return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name); } else { diff --git a/src/core/systemd.pc.in b/src/core/systemd.pc.in index d5b86bf..9c66e7b 100644 --- a/src/core/systemd.pc.in +++ b/src/core/systemd.pc.in @@ -14,8 +14,8 @@ systemduserunitdir=@userunitdir@ systemduserpresetdir=@userpresetdir@ systemdsystemconfdir=@pkgsysconfdir@/system systemduserconfdir=@pkgsysconfdir@/user -systemdsystemunitpath=${systemdsystemconfdir}:/etc/systemd/system:/run/systemd/system:/usr/local/lib/systemd/system:${systemdsystemunitdir}:/usr/lib/systemd/system:/lib/systemd/system -systemduserunitpath=${systemduserconfdir}:/etc/systemd/user:/run/systemd/user:/usr/local/lib/systemd/user:/usr/local/share/systemd/user:${systemduserunitdir}:/usr/lib/systemd/user:/usr/share/systemd/user +systemdsystemunitpath=${systemdsystemconfdir}:/etc/systemd/system:/etc/systemd-mutable/system:/nix/var/nix/profiles/default/lib/systemd/user:/run/systemd/system:${systemdsystemunitdir} +systemduserunitpath=${systemduserconfdir}:/etc/systemd/user:/etc/systemd-mutable/user:/nix/var/nix/profiles/default/lib/systemd/system:/run/systemd/user:${systemduserunitdir} systemdsystemgeneratordir=@systemgeneratordir@ systemdusergeneratordir=@usergeneratordir@ systemdsleepdir=@systemsleepdir@ diff --git a/src/core/timer.c b/src/core/timer.c index a3713e2..5c4e9f9 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -521,6 +521,7 @@ fail: static int timer_start(Unit *u) { Timer *t = TIMER(u); + TimerValue *v; assert(t); assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED); @@ -530,6 +531,11 @@ static int timer_start(Unit *u) { t->last_trigger = DUAL_TIMESTAMP_NULL; + /* Reenable all timers that depend on unit activation time */ + LIST_FOREACH(value, v, t->values) + if (v->base == TIMER_ACTIVE) + v->disabled = false; + if (t->stamp_path) { struct stat st; diff --git a/src/core/umount.c b/src/core/umount.c index cffa453..4d1a9ff 100644 --- a/src/core/umount.c +++ b/src/core/umount.c @@ -385,6 +385,8 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e * anyway, since we are running from it. They have * already been remounted ro. */ if (path_equal(m->path, "/") + || path_equal(m->path, "/nix") + || path_equal(m->path, "/nix/store") #ifndef HAVE_SPLIT_USR || path_equal(m->path, "/usr") #endif diff --git a/src/delta/delta.c b/src/delta/delta.c index 25c4a0b..e1f2d6d 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -487,7 +487,7 @@ static int parse_flags(const char *flag_str, int flags) { const char *word, *state; size_t l; - FOREACH_WORD(word, l, flag_str, state) { + FOREACH_WORD_SEPARATOR(word, l, flag_str, ",", state) { if (strneq("masked", word, l)) flags |= SHOW_MASKED; else if (strneq ("equivalent", word, l)) diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index 70a5918..a5661e8 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -315,8 +315,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - cmdline[i++] = "/sbin/fsck"; - cmdline[i++] = arg_repair; + cmdline[i++] = "/run/current-system/sw/bin/fsck"; cmdline[i++] = "-T"; /* diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index e257c12..1e04553 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -485,7 +485,7 @@ static int add_usr_mount(void) { return log_oom(); } - if (!arg_usr_what || !arg_usr_options) + if (!arg_usr_what) return 0; what = fstab_node_to_udev_node(arg_usr_what); @@ -494,7 +494,13 @@ static int add_usr_mount(void) { return -1; } - opts = arg_usr_options; + if (!arg_usr_options) + opts = arg_root_rw > 0 ? "rw" : "ro"; + else if (!mount_test_option(arg_usr_options, "ro") && + !mount_test_option(arg_usr_options, "rw")) + opts = strappenda(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro"); + else + opts = arg_usr_options; log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype)); return add_mount(what, diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index e487369..ff4e9c9 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -536,5 +536,5 @@ int main(int argc, char *argv[]) { r = hostnamectl_main(bus, argc, argv); finish: - return r < 0 ? EXIT_FAILURE : r; + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c index 7dd8878..70a9a13 100644 --- a/src/journal-remote/journal-remote-parse.c +++ b/src/journal-remote/journal-remote-parse.c @@ -344,22 +344,25 @@ int process_data(RemoteSource *source) { LLLLLLLL0011223344...\n */ sep = memchr(line, '=', n); - if (sep) + if (sep) { /* chomp newline */ n--; - else + + r = iovw_put(&source->iovw, line, n); + if (r < 0) + return r; + } else { /* replace \n with = */ line[n-1] = '='; - log_trace("Received: %.*s", (int) n, line); - r = iovw_put(&source->iovw, line, n); - if (r < 0) { - log_error("Failed to put line in iovect"); - return r; + source->field_len = n; + source->state = STATE_DATA_START; + + /* we cannot put the field in iovec until we have all data */ } - if (!sep) - source->state = STATE_DATA_START; + log_trace("Received: %.*s (%s)", (int) n, line, sep ? "text" : "binary"); + return 0; /* continue */ } @@ -382,6 +385,7 @@ int process_data(RemoteSource *source) { case STATE_DATA: { void *data; + char *field; assert(source->data_size > 0); @@ -396,11 +400,12 @@ int process_data(RemoteSource *source) { assert(data); - r = iovw_put(&source->iovw, data, source->data_size); - if (r < 0) { - log_error("failed to put binary buffer in iovect"); + field = (char*) data - sizeof(uint64_t) - source->field_len; + memmove(field + sizeof(uint64_t), field, source->field_len); + + r = iovw_put(&source->iovw, field + sizeof(uint64_t), source->field_len + source->data_size); + if (r < 0) return r; - } source->state = STATE_DATA_FINISH; diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h index 8499f4e..22db550 100644 --- a/src/journal-remote/journal-remote-parse.h +++ b/src/journal-remote/journal-remote-parse.h @@ -42,7 +42,9 @@ typedef struct RemoteSource { size_t offset; /* offset to the beginning of live data in the buffer */ size_t scanned; /* number of bytes since the beginning of data without a newline */ size_t filled; /* total number of bytes in the buffer */ - size_t data_size; /* size of the binary data chunk being processed */ + + size_t field_len; /* used for binary fields: the field name length */ + size_t data_size; /* and the size of the binary data chunk being processed */ struct iovec_wrapper iovw; diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index 5ab1982..1f980ee 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -229,7 +229,7 @@ int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) { return 0; } -int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p) { +int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p) { int r; assert(f); @@ -246,7 +246,7 @@ int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p if (r < 0) return r; } else { - if (type >= 0 && o->object.type != type) + if (type > OBJECT_UNUSED && o->object.type != type) return -EBADMSG; } diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h index 0aaf836..565fe84 100644 --- a/src/journal/journal-authenticate.h +++ b/src/journal/journal-authenticate.h @@ -33,7 +33,7 @@ int journal_file_append_first_tag(JournalFile *f); int journal_file_hmac_setup(JournalFile *f); int journal_file_hmac_start(JournalFile *f); int journal_file_hmac_put_header(JournalFile *f); -int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p); +int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p); int journal_file_fss_load(JournalFile *f); int journal_file_parse_verification_key(JournalFile *f, const char *key); diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h index e55fa19..ab089cb 100644 --- a/src/journal/journal-def.h +++ b/src/journal/journal-def.h @@ -52,8 +52,8 @@ typedef struct HashItem HashItem; typedef struct FSSHeader FSSHeader; /* Object types */ -enum { - OBJECT_UNUSED, +typedef enum ObjectType { + OBJECT_UNUSED, /* also serves as "any type" or "additional context" */ OBJECT_DATA, OBJECT_FIELD, OBJECT_ENTRY, @@ -62,7 +62,7 @@ enum { OBJECT_ENTRY_ARRAY, OBJECT_TAG, _OBJECT_TYPE_MAX -}; +} ObjectType; /* Object flags */ enum { diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 8a2c0fc..c55a4dc 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -374,7 +374,13 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) return 0; } -static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) { +static unsigned type_to_context(ObjectType type) { + /* One context for each type, plus one catch-all for the rest */ + assert_cc(_OBJECT_TYPE_MAX <= MMAP_CACHE_MAX_CONTEXTS); + return type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX ? type : 0; +} + +static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_always, uint64_t offset, uint64_t size, void **ret) { assert(f); assert(ret); @@ -391,7 +397,7 @@ static int journal_file_move_to(JournalFile *f, int context, bool keep_always, u return -EADDRNOTAVAIL; } - return mmap_cache_get(f->mmap, f->fd, f->prot, context, keep_always, offset, size, &f->last_stat, ret, NULL); + return mmap_cache_get(f->mmap, f->fd, f->prot, type_to_context(type), keep_always, offset, size, &f->last_stat, ret); } static uint64_t minimum_header_size(Object *o) { @@ -412,7 +418,7 @@ static uint64_t minimum_header_size(Object *o) { return table[o->object.type]; } -int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret) { +int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret) { int r; void *t; Object *o; @@ -425,7 +431,7 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec if (!VALID64(offset)) return -EFAULT; - r = journal_file_move_to(f, type_to_context(type), false, offset, sizeof(ObjectHeader), &t); + r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t); if (r < 0) return r; @@ -441,11 +447,11 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec if (s < minimum_header_size(o)) return -EBADMSG; - if (type > 0 && o->object.type != type) + if (type > OBJECT_UNUSED && o->object.type != type) return -EBADMSG; if (s > sizeof(ObjectHeader)) { - r = journal_file_move_to(f, o->object.type, false, offset, s, &t); + r = journal_file_move_to(f, type, false, offset, s, &t); if (r < 0) return r; @@ -482,14 +488,14 @@ static uint64_t journal_file_entry_seqnum(JournalFile *f, uint64_t *seqnum) { return r; } -int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset) { +int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, Object **ret, uint64_t *offset) { int r; uint64_t p; Object *tail, *o; void *t; assert(f); - assert(type > 0 && type < _OBJECT_TYPE_MAX); + assert(type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX); assert(size >= sizeof(ObjectHeader)); assert(offset); assert(ret); @@ -502,7 +508,7 @@ int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object * if (p == 0) p = le64toh(f->header->header_size); else { - r = journal_file_move_to_object(f, -1, p, &tail); + r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &tail); if (r < 0) return r; @@ -1657,7 +1663,7 @@ static int generic_array_bisect( } } - if (k > n) { + if (k >= n) { if (direction == DIRECTION_UP) { i = n; subtract_one = true; @@ -1793,23 +1799,6 @@ _pure_ static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle return TEST_RIGHT; } -int journal_file_move_to_entry_by_offset( - JournalFile *f, - uint64_t p, - direction_t direction, - Object **ret, - uint64_t *offset) { - - return generic_array_bisect(f, - le64toh(f->header->entry_array_offset), - le64toh(f->header->n_entries), - p, - test_object_offset, - direction, - ret, offset, NULL); -} - - static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) { Object *o; int r; @@ -1939,9 +1928,81 @@ int journal_file_move_to_entry_by_monotonic( ret, offset, NULL); } +void journal_file_reset_location(JournalFile *f) { + f->location_type = LOCATION_HEAD; + f->current_offset = 0; + f->current_seqnum = 0; + f->current_realtime = 0; + f->current_monotonic = 0; + zero(f->current_boot_id); + f->current_xor_hash = 0; +} + +void journal_file_save_location(JournalFile *f, Object *o, uint64_t offset) { + f->location_type = LOCATION_SEEK; + f->current_offset = offset; + f->current_seqnum = le64toh(o->entry.seqnum); + f->current_realtime = le64toh(o->entry.realtime); + f->current_monotonic = le64toh(o->entry.monotonic); + f->current_boot_id = o->entry.boot_id; + f->current_xor_hash = le64toh(o->entry.xor_hash); +} + +int journal_file_compare_locations(JournalFile *af, JournalFile *bf) { + assert(af); + assert(bf); + assert(af->location_type == LOCATION_SEEK); + assert(bf->location_type == LOCATION_SEEK); + + /* If contents and timestamps match, these entries are + * identical, even if the seqnum does not match */ + if (sd_id128_equal(af->current_boot_id, bf->current_boot_id) && + af->current_monotonic == bf->current_monotonic && + af->current_realtime == bf->current_realtime && + af->current_xor_hash == bf->current_xor_hash) + return 0; + + if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) { + + /* If this is from the same seqnum source, compare + * seqnums */ + if (af->current_seqnum < bf->current_seqnum) + return -1; + if (af->current_seqnum > bf->current_seqnum) + return 1; + + /* Wow! This is weird, different data but the same + * seqnums? Something is borked, but let's make the + * best of it and compare by time. */ + } + + if (sd_id128_equal(af->current_boot_id, bf->current_boot_id)) { + + /* If the boot id matches, compare monotonic time */ + if (af->current_monotonic < bf->current_monotonic) + return -1; + if (af->current_monotonic > bf->current_monotonic) + return 1; + } + + /* Otherwise, compare UTC time */ + if (af->current_realtime < bf->current_realtime) + return -1; + if (af->current_realtime > bf->current_realtime) + return 1; + + /* Finally, compare by contents */ + if (af->current_xor_hash < bf->current_xor_hash) + return -1; + if (af->current_xor_hash > bf->current_xor_hash) + return 1; + + return 0; +} + int journal_file_next_entry( JournalFile *f, - Object *o, uint64_t p, + uint64_t p, direction_t direction, Object **ret, uint64_t *offset) { @@ -1949,18 +2010,14 @@ int journal_file_next_entry( int r; assert(f); - assert(p > 0 || !o); n = le64toh(f->header->n_entries); if (n <= 0) return 0; - if (!o) + if (p == 0) i = direction == DIRECTION_DOWN ? 0 : n - 1; else { - if (o->object.type != OBJECT_ENTRY) - return -EINVAL; - r = generic_array_bisect(f, le64toh(f->header->entry_array_offset), le64toh(f->header->n_entries), @@ -2006,55 +2063,6 @@ int journal_file_next_entry( return 1; } -int journal_file_skip_entry( - JournalFile *f, - Object *o, uint64_t p, - int64_t skip, - Object **ret, uint64_t *offset) { - - uint64_t i, n; - int r; - - assert(f); - assert(o); - assert(p > 0); - - if (o->object.type != OBJECT_ENTRY) - return -EINVAL; - - r = generic_array_bisect(f, - le64toh(f->header->entry_array_offset), - le64toh(f->header->n_entries), - p, - test_object_offset, - DIRECTION_DOWN, - NULL, NULL, - &i); - if (r <= 0) - return r; - - /* Calculate new index */ - if (skip < 0) { - if ((uint64_t) -skip >= i) - i = 0; - else - i = i - (uint64_t) -skip; - } else - i += (uint64_t) skip; - - n = le64toh(f->header->n_entries); - if (n <= 0) - return -EBADMSG; - - if (i >= n) - i = n-1; - - return generic_array_get(f, - le64toh(f->header->entry_array_offset), - i, - ret, offset); -} - int journal_file_next_entry_for_data( JournalFile *f, Object *o, uint64_t p, @@ -2289,7 +2297,7 @@ void journal_file_dump(JournalFile *f) { p = le64toh(f->header->header_size); while (p != 0) { - r = journal_file_move_to_object(f, -1, p, &o); + r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); if (r < 0) goto fail; diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index 211e121..ca17c97 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -48,6 +48,20 @@ typedef enum direction { DIRECTION_DOWN } direction_t; +typedef enum LocationType { + /* The first and last entries, resp. */ + LOCATION_HEAD, + LOCATION_TAIL, + + /* We already read the entry we currently point to, and the + * next one to read should probably not be this one again. */ + LOCATION_DISCRETE, + + /* We should seek to the precise location specified, and + * return it, as we haven't read it yet. */ + LOCATION_SEEK +} LocationType; + typedef struct JournalFile { int fd; @@ -63,6 +77,8 @@ typedef struct JournalFile { bool tail_entry_monotonic_valid:1; direction_t last_direction; + LocationType location_type; + uint64_t last_n_entries; char *path; struct stat last_stat; @@ -72,6 +88,11 @@ typedef struct JournalFile { HashItem *field_hash_table; uint64_t current_offset; + uint64_t current_seqnum; + uint64_t current_realtime; + uint64_t current_monotonic; + sd_id128_t current_boot_id; + uint64_t current_xor_hash; JournalMetrics metrics; MMapCache *mmap; @@ -160,13 +181,13 @@ static inline bool VALID_EPOCH(uint64_t u) { #define JOURNAL_HEADER_COMPRESSED_LZ4(h) \ (!!(le32toh((h)->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED_LZ4)) -int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret); +int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret); uint64_t journal_file_entry_n_items(Object *o) _pure_; uint64_t journal_file_entry_array_n_items(Object *o) _pure_; uint64_t journal_file_hash_table_n_items(Object *o) _pure_; -int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset); +int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, Object **ret, uint64_t *offset); int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const struct iovec iovec[], unsigned n_iovec, uint64_t *seqno, Object **ret, uint64_t *offset); int journal_file_find_data_object(JournalFile *f, const void *data, uint64_t size, Object **ret, uint64_t *offset); @@ -175,12 +196,13 @@ int journal_file_find_data_object_with_hash(JournalFile *f, const void *data, ui int journal_file_find_field_object(JournalFile *f, const void *field, uint64_t size, Object **ret, uint64_t *offset); int journal_file_find_field_object_with_hash(JournalFile *f, const void *field, uint64_t size, uint64_t hash, Object **ret, uint64_t *offset); -int journal_file_next_entry(JournalFile *f, Object *o, uint64_t p, direction_t direction, Object **ret, uint64_t *offset); -int journal_file_skip_entry(JournalFile *f, Object *o, uint64_t p, int64_t skip, Object **ret, uint64_t *offset); +void journal_file_reset_location(JournalFile *f); +void journal_file_save_location(JournalFile *f, Object *o, uint64_t offset); +int journal_file_compare_locations(JournalFile *af, JournalFile *bf); +int journal_file_next_entry(JournalFile *f, uint64_t p, direction_t direction, Object **ret, uint64_t *offset); int journal_file_next_entry_for_data(JournalFile *f, Object *o, uint64_t p, uint64_t data_offset, direction_t direction, Object **ret, uint64_t *offset); -int journal_file_move_to_entry_by_offset(JournalFile *f, uint64_t seqnum, direction_t direction, Object **ret, uint64_t *offset); int journal_file_move_to_entry_by_seqnum(JournalFile *f, uint64_t seqnum, direction_t direction, Object **ret, uint64_t *offset); int journal_file_move_to_entry_by_realtime(JournalFile *f, uint64_t realtime, direction_t direction, Object **ret, uint64_t *offset); int journal_file_move_to_entry_by_monotonic(JournalFile *f, sd_id128_t boot_id, uint64_t monotonic, direction_t direction, Object **ret, uint64_t *offset); @@ -205,21 +227,3 @@ 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); - - -static unsigned type_to_context(int type) { - /* One context for each type, plus one catch-all for the rest */ - return type > 0 && type < _OBJECT_TYPE_MAX ? type : 0; -} - -static inline int journal_file_object_keep(JournalFile *f, Object *o, uint64_t offset, void **release_cookie) { - unsigned context = type_to_context(o->object.type); - uint64_t s = le64toh(o->object.size); - - return mmap_cache_get(f->mmap, f->fd, f->prot, context, true, - offset, s, &f->last_stat, NULL, release_cookie); -} - -static inline int journal_file_object_release(JournalFile *f, void *release_cookie) { - return mmap_cache_release(f->mmap, f->fd, release_cookie); -} diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h index 70847db..e99050c 100644 --- a/src/journal/journal-internal.h +++ b/src/journal/journal-internal.h @@ -57,20 +57,6 @@ struct Match { LIST_HEAD(Match, matches); }; -typedef enum LocationType { - /* The first and last entries, resp. */ - LOCATION_HEAD, - LOCATION_TAIL, - - /* We already read the entry we currently point to, and the - * next one to read should probably not be this one again. */ - LOCATION_DISCRETE, - - /* We should seek to the precise location specified, and - * return it, as we haven't read it yet. */ - LOCATION_SEEK -} LocationType; - struct Location { LocationType type; diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index f74adcb..5baa22d 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -368,7 +368,7 @@ static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) { c = (a + b) / 2; - r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL); + r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z); if (r < 0) return r; @@ -865,7 +865,7 @@ int journal_file_verify( if (show_progress) draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec); - r = journal_file_move_to_object(f, -1, p, &o); + r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); if (r < 0) { error(p, "invalid object"); goto fail; @@ -1085,11 +1085,11 @@ int journal_file_verify( q = last_tag; while (q <= p) { - r = journal_file_move_to_object(f, -1, q, &o); + r = journal_file_move_to_object(f, OBJECT_UNUSED, q, &o); if (r < 0) goto fail; - r = journal_file_hmac_put_object(f, -1, o, q); + r = journal_file_hmac_put_object(f, OBJECT_UNUSED, o, q); if (r < 0) goto fail; @@ -1097,7 +1097,7 @@ int journal_file_verify( } /* Position might have changed, let's reposition things */ - r = journal_file_move_to_object(f, -1, p, &o); + r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); if (r < 0) goto fail; diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index f50faf4..03579fd 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -682,7 +682,7 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } - if (arg_follow && !arg_no_tail && arg_lines == ARG_LINES_DEFAULT) + if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT) arg_lines = 10; if (!!arg_directory + !!arg_file + !!arg_machine > 1) { diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index a635202..655e2dd 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -132,8 +132,8 @@ void server_process_native_message( /* A property follows */ - /* n received properties, +1 for _TRANSPORT */ - if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS + !!object_pid * N_IOVEC_OBJECT_FIELDS)) { + /* n existing properties, 1 new, +1 for _TRANSPORT */ + if (!GREEDY_REALLOC(iovec, m, n + 2 + N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS)) { log_oom(); break; } diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 12735c4..08b143b 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1655,6 +1655,7 @@ void server_done(Server *s) { free(s->buffer); free(s->tty_path); free(s->cgroup_root); + free(s->hostname_field); if (s->mmap) mmap_cache_unref(s->mmap); diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c index b7db6f1..f6f669d 100644 --- a/src/journal/mmap-cache.c +++ b/src/journal/mmap-cache.c @@ -38,7 +38,7 @@ typedef struct FileDescriptor FileDescriptor; struct Window { MMapCache *cache; - unsigned keep_always; + bool keep_always; bool in_unused; int prot; @@ -76,7 +76,7 @@ struct MMapCache { Hashmap *fds; - Hashmap *contexts; + Context *contexts[MMAP_CACHE_MAX_CONTEXTS]; LIST_HEAD(Window, unused); Window *last_unused; @@ -185,7 +185,7 @@ static void context_detach_window(Context *c) { c->window = NULL; LIST_REMOVE(by_window, w->contexts, c); - if (!w->contexts && w->keep_always == 0) { + if (!w->contexts && !w->keep_always) { /* Not used anymore? */ LIST_PREPEND(unused, c->cache->unused, w); if (!c->cache->last_unused) @@ -219,18 +219,13 @@ static void context_attach_window(Context *c, Window *w) { static Context *context_add(MMapCache *m, unsigned id) { Context *c; - int r; assert(m); - c = hashmap_get(m->contexts, UINT_TO_PTR(id + 1)); + c = m->contexts[id]; if (c) return c; - r = hashmap_ensure_allocated(&m->contexts, NULL); - if (r < 0) - return NULL; - c = new0(Context, 1); if (!c) return NULL; @@ -238,11 +233,8 @@ static Context *context_add(MMapCache *m, unsigned id) { c->cache = m; c->id = id; - r = hashmap_put(m->contexts, UINT_TO_PTR(id + 1), c); - if (r < 0) { - free(c); - return NULL; - } + assert(!m->contexts[id]); + m->contexts[id] = c; return c; } @@ -252,8 +244,10 @@ static void context_free(Context *c) { context_detach_window(c); - if (c->cache) - assert_se(hashmap_remove(c->cache->contexts, UINT_TO_PTR(c->id + 1))); + if (c->cache) { + assert(c->cache->contexts[c->id] == c); + c->cache->contexts[c->id] = NULL; + } free(c); } @@ -302,15 +296,14 @@ static FileDescriptor* fd_add(MMapCache *m, int fd) { } static void mmap_cache_free(MMapCache *m) { - Context *c; FileDescriptor *f; + int i; assert(m); - while ((c = hashmap_first(m->contexts))) - context_free(c); - - hashmap_free(m->contexts); + for (i = 0; i < MMAP_CACHE_MAX_CONTEXTS; i++) + if (m->contexts[i]) + context_free(m->contexts[i]); while ((f = hashmap_first(m->fds))) fd_free(f); @@ -352,8 +345,7 @@ static int try_context( bool keep_always, uint64_t offset, size_t size, - void **ret, - void **release_cookie) { + void **ret) { Context *c; @@ -361,8 +353,9 @@ static int try_context( assert(m->n_ref > 0); assert(fd >= 0); assert(size > 0); + assert(ret); - c = hashmap_get(m->contexts, UINT_TO_PTR(context+1)); + c = m->contexts[context]; if (!c) return 0; @@ -378,12 +371,9 @@ static int try_context( return 0; } - c->window->keep_always += keep_always; + c->window->keep_always |= keep_always; - if (ret) - *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset); - if (keep_always && release_cookie) - *release_cookie = c->window; + *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset); return 1; } @@ -395,8 +385,7 @@ static int find_mmap( bool keep_always, uint64_t offset, size_t size, - void **ret, - void **release_cookie) { + void **ret) { FileDescriptor *f; Window *w; @@ -427,10 +416,7 @@ static int find_mmap( context_attach_window(c, w); w->keep_always += keep_always; - if (ret) - *ret = (uint8_t*) w->ptr + (offset - w->offset); - if (keep_always && release_cookie) - *release_cookie = c->window; + *ret = (uint8_t*) w->ptr + (offset - w->offset); return 1; } @@ -443,8 +429,7 @@ static int add_mmap( uint64_t offset, size_t size, struct stat *st, - void **ret, - void **release_cookie) { + void **ret) { uint64_t woffset, wsize; Context *c; @@ -457,6 +442,7 @@ static int add_mmap( assert(m->n_ref > 0); assert(fd >= 0); assert(size > 0); + assert(ret); woffset = offset & ~((uint64_t) page_size() - 1ULL); wsize = size + (offset - woffset); @@ -526,10 +512,7 @@ static int add_mmap( c->window = w; LIST_PREPEND(by_window, w->contexts, c); - if (ret) - *ret = (uint8_t*) w->ptr + (offset - w->offset); - if (keep_always && release_cookie) - *release_cookie = c->window; + *ret = (uint8_t*) w->ptr + (offset - w->offset); return 1; outofmem: @@ -546,8 +529,7 @@ int mmap_cache_get( uint64_t offset, size_t size, struct stat *st, - void **ret, - void **release_cookie) { + void **ret) { int r; @@ -555,16 +537,18 @@ int mmap_cache_get( assert(m->n_ref > 0); assert(fd >= 0); assert(size > 0); + assert(ret); + assert(context < MMAP_CACHE_MAX_CONTEXTS); /* Check whether the current context is the right one already */ - r = try_context(m, fd, prot, context, keep_always, offset, size, ret, release_cookie); + r = try_context(m, fd, prot, context, keep_always, offset, size, ret); if (r != 0) { m->n_hit ++; return r; } /* Search for a matching mmap */ - r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret, release_cookie); + r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret); if (r != 0) { m->n_hit ++; return r; @@ -573,39 +557,7 @@ int mmap_cache_get( m->n_missed++; /* Create a new mmap */ - return add_mmap(m, fd, prot, context, keep_always, offset, size, st, ret, release_cookie); -} - -int mmap_cache_release( - MMapCache *m, - int fd, - void *release_cookie) { - - FileDescriptor *f; - Window *w; - - assert(m); - assert(m->n_ref > 0); - assert(fd >= 0); - - f = hashmap_get(m->fds, INT_TO_PTR(fd + 1)); - if (!f) - return -EBADF; - - assert(f->fd == fd); - - LIST_FOREACH(by_fd, w, f->windows) - if (w == release_cookie) - break; - - if (!w) - return -ENOENT; - - if (w->keep_always == 0) - return -ENOLCK; - - w->keep_always -= 1; - return 0; + return add_mmap(m, fd, prot, context, keep_always, offset, size, st, ret); } void mmap_cache_close_fd(MMapCache *m, int fd) { @@ -621,18 +573,6 @@ void mmap_cache_close_fd(MMapCache *m, int fd) { fd_free(f); } -void mmap_cache_close_context(MMapCache *m, unsigned context) { - Context *c; - - assert(m); - - c = hashmap_get(m->contexts, UINT_TO_PTR(context + 1)); - if (!c) - return; - - context_free(c); -} - unsigned mmap_cache_get_hit(MMapCache *m) { assert(m); diff --git a/src/journal/mmap-cache.h b/src/journal/mmap-cache.h index 76e5316..fe2c83d 100644 --- a/src/journal/mmap-cache.h +++ b/src/journal/mmap-cache.h @@ -25,6 +25,8 @@ #include #include +#define MMAP_CACHE_MAX_CONTEXTS 8 + typedef struct MMapCache MMapCache; MMapCache* mmap_cache_new(void); @@ -40,14 +42,8 @@ int mmap_cache_get( uint64_t offset, size_t size, struct stat *st, - void **ret, - void **release_cookie); -int mmap_cache_release( - MMapCache *m, - int fd, - void *release_cookie); + void **ret); void mmap_cache_close_fd(MMapCache *m, int fd); -void mmap_cache_close_context(MMapCache *m, unsigned context); unsigned mmap_cache_get_hit(MMapCache *m); unsigned mmap_cache_get_missed(MMapCache *m); diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index cf21c4d..cb7fc32 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -87,7 +87,7 @@ static void detach_location(sd_journal *j) { j->current_field = 0; ORDERED_HASHMAP_FOREACH(f, j->files, i) - f->current_offset = 0; + journal_file_reset_location(f); } static void reset_location(sd_journal *j) { @@ -114,20 +114,19 @@ static void init_location(Location *l, LocationType type, JournalFile *f, Object l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true; } -static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o, - direction_t direction, uint64_t offset) { +static void set_location(sd_journal *j, JournalFile *f, Object *o) { assert(j); - assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK); assert(f); assert(o); - init_location(&j->current_location, type, f, o); + init_location(&j->current_location, LOCATION_DISCRETE, f, o); j->current_file = f; j->current_field = 0; - f->last_direction = direction; - f->current_offset = offset; + /* Let f know its candidate entry was picked. */ + assert(f->location_type == LOCATION_SEEK); + f->location_type = LOCATION_DISCRETE; } static int match_is_valid(const void *data, size_t size) { @@ -413,144 +412,51 @@ _public_ void sd_journal_flush_matches(sd_journal *j) { detach_location(j); } -static int compare_entry_order(JournalFile *af, Object *_ao, - JournalFile *bf, uint64_t bp) { - - uint64_t a, b; - Object *ao, *bo; - int r; - - assert(af); - assert(bf); - assert(_ao); - - /* The mmap cache might invalidate the object from the first - * file if we look at the one from the second file. Hence - * temporarily copy the header of the first one, and look at - * that only. */ - ao = alloca(offsetof(EntryObject, items)); - memcpy(ao, _ao, offsetof(EntryObject, items)); - - r = journal_file_move_to_object(bf, OBJECT_ENTRY, bp, &bo); - if (r < 0) - return strcmp(af->path, bf->path); - - /* We operate on two different files here, hence we can access - * two objects at the same time, which we normally can't. - * - * If contents and timestamps match, these entries are - * identical, even if the seqnum does not match */ - - if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id) && - ao->entry.monotonic == bo->entry.monotonic && - ao->entry.realtime == bo->entry.realtime && - ao->entry.xor_hash == bo->entry.xor_hash) - return 0; - - if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) { - - /* If this is from the same seqnum source, compare - * seqnums */ - a = le64toh(ao->entry.seqnum); - b = le64toh(bo->entry.seqnum); - - if (a < b) - return -1; - if (a > b) - return 1; - - /* Wow! This is weird, different data but the same - * seqnums? Something is borked, but let's make the - * best of it and compare by time. */ - } - - if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) { - - /* If the boot id matches, compare monotonic time */ - a = le64toh(ao->entry.monotonic); - b = le64toh(bo->entry.monotonic); - - if (a < b) - return -1; - if (a > b) - return 1; - } - - /* Otherwise, compare UTC time */ - a = le64toh(ao->entry.realtime); - b = le64toh(bo->entry.realtime); - - if (a < b) - return -1; - if (a > b) - return 1; - - /* Finally, compare by contents */ - a = le64toh(ao->entry.xor_hash); - b = le64toh(bo->entry.xor_hash); - - if (a < b) - return -1; - if (a > b) - return 1; - - return 0; -} - -_pure_ static int compare_with_location(JournalFile *af, Object *ao, Location *l) { - uint64_t a; - - assert(af); - assert(ao); +_pure_ static int compare_with_location(JournalFile *f, Location *l) { + assert(f); assert(l); + assert(f->location_type == LOCATION_SEEK); assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK); if (l->monotonic_set && - sd_id128_equal(ao->entry.boot_id, l->boot_id) && + sd_id128_equal(f->current_boot_id, l->boot_id) && l->realtime_set && - le64toh(ao->entry.realtime) == l->realtime && + f->current_realtime == l->realtime && l->xor_hash_set && - le64toh(ao->entry.xor_hash) == l->xor_hash) + f->current_xor_hash == l->xor_hash) return 0; if (l->seqnum_set && - sd_id128_equal(af->header->seqnum_id, l->seqnum_id)) { - - a = le64toh(ao->entry.seqnum); + sd_id128_equal(f->header->seqnum_id, l->seqnum_id)) { - if (a < l->seqnum) + if (f->current_seqnum < l->seqnum) return -1; - if (a > l->seqnum) + if (f->current_seqnum > l->seqnum) return 1; } if (l->monotonic_set && - sd_id128_equal(ao->entry.boot_id, l->boot_id)) { + sd_id128_equal(f->current_boot_id, l->boot_id)) { - a = le64toh(ao->entry.monotonic); - - if (a < l->monotonic) + if (f->current_monotonic < l->monotonic) return -1; - if (a > l->monotonic) + if (f->current_monotonic > l->monotonic) return 1; } if (l->realtime_set) { - a = le64toh(ao->entry.realtime); - - if (a < l->realtime) + if (f->current_realtime < l->realtime) return -1; - if (a > l->realtime) + if (f->current_realtime > l->realtime) return 1; } if (l->xor_hash_set) { - a = le64toh(ao->entry.xor_hash); - if (a < l->xor_hash) + if (f->current_xor_hash < l->xor_hash) return -1; - if (a > l->xor_hash) + if (f->current_xor_hash > l->xor_hash) return 1; } @@ -766,9 +672,9 @@ static int find_location_with_matches( /* No matches is simple */ if (j->current_location.type == LOCATION_HEAD) - return journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, ret, offset); + return journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset); if (j->current_location.type == LOCATION_TAIL) - return journal_file_next_entry(f, NULL, 0, DIRECTION_UP, ret, offset); + return journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset); if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id)) return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset); if (j->current_location.monotonic_set) { @@ -779,7 +685,7 @@ static int find_location_with_matches( if (j->current_location.realtime_set) return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset); - return journal_file_next_entry(f, NULL, 0, direction, ret, offset); + return journal_file_next_entry(f, 0, direction, ret, offset); } else return find_location_for_match(j, j->level0, f, direction, ret, offset); } @@ -791,49 +697,61 @@ static int next_with_matches( Object **ret, uint64_t *offset) { - Object *c; - uint64_t cp; - assert(j); assert(f); assert(ret); assert(offset); - c = *ret; - cp = *offset; - /* No matches is easy. We simple advance the file * pointer by one. */ if (!j->level0) - return journal_file_next_entry(f, c, cp, direction, ret, offset); + return journal_file_next_entry(f, f->current_offset, direction, ret, offset); /* If we have a match then we look for the next matching entry * with an offset at least one step larger */ - return next_for_match(j, j->level0, f, direction == DIRECTION_DOWN ? cp+1 : cp-1, direction, ret, offset); + return next_for_match(j, j->level0, f, + direction == DIRECTION_DOWN ? f->current_offset + 1 + : f->current_offset - 1, + direction, ret, offset); } -static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) { +static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction) { Object *c; - uint64_t cp; + uint64_t cp, n_entries; int r; assert(j); assert(f); - if (f->last_direction == direction && f->current_offset > 0) { - cp = f->current_offset; + n_entries = le64toh(f->header->n_entries); - r = journal_file_move_to_object(f, OBJECT_ENTRY, cp, &c); - if (r < 0) - return r; + /* If we hit EOF before, we don't need to look into this file again + * unless direction changed or new entries appeared. */ + if (f->last_direction == direction && f->location_type == LOCATION_TAIL && + n_entries == f->last_n_entries) + return 0; - r = next_with_matches(j, f, direction, &c, &cp); - if (r <= 0) - return r; + f->last_n_entries = n_entries; + + if (f->last_direction == direction && f->current_offset > 0) { + /* LOCATION_SEEK here means we did the work in a previous + * iteration and the current location already points to a + * candidate entry. */ + if (f->location_type != LOCATION_SEEK) { + r = next_with_matches(j, f, direction, &c, &cp); + if (r <= 0) + return r; + + journal_file_save_location(f, c, cp); + } } else { + f->last_direction = direction; + r = find_location_with_matches(j, f, direction, &c, &cp); if (r <= 0) return r; + + journal_file_save_location(f, c, cp); } /* OK, we found the spot, now let's advance until an entry @@ -848,30 +766,25 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc if (j->current_location.type == LOCATION_DISCRETE) { int k; - k = compare_with_location(f, c, &j->current_location); + k = compare_with_location(f, &j->current_location); found = direction == DIRECTION_DOWN ? k > 0 : k < 0; } else found = true; - if (found) { - if (ret) - *ret = c; - if (offset) - *offset = cp; + if (found) return 1; - } r = next_with_matches(j, f, direction, &c, &cp); if (r <= 0) return r; + + journal_file_save_location(f, c, cp); } } static int real_journal_next(sd_journal *j, direction_t direction) { JournalFile *f, *new_file = NULL; - uint64_t new_offset = 0; - uint64_t p = 0; Iterator i; Object *o; int r; @@ -882,38 +795,38 @@ static int real_journal_next(sd_journal *j, direction_t direction) { ORDERED_HASHMAP_FOREACH(f, j->files, i) { bool found; - r = next_beyond_location(j, f, direction, &o, &p); + r = next_beyond_location(j, f, direction); if (r < 0) { log_debug("Can't iterate through %s, ignoring: %s", f->path, strerror(-r)); remove_file_real(j, f); continue; - } else if (r == 0) + } else if (r == 0) { + f->location_type = LOCATION_TAIL; continue; + } if (!new_file) found = true; else { int k; - k = compare_entry_order(f, o, new_file, new_offset); + k = journal_file_compare_locations(f, new_file); found = direction == DIRECTION_DOWN ? k < 0 : k > 0; } - if (found) { + if (found) new_file = f; - new_offset = p; - } } if (!new_file) return 0; - r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_offset, &o); + r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_file->current_offset, &o); if (r < 0) return r; - set_location(j, LOCATION_DISCRETE, new_file, o, direction, new_offset); + set_location(j, new_file, o); return 1; } @@ -2526,7 +2439,6 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ size_t ol; bool found; int r; - void *release_cookie; /* Proceed to next data object in the field's linked list */ if (j->unique_offset == 0) { @@ -2552,10 +2464,10 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ continue; } - /* We do not use the type context here, but 0 instead, - * so that we can look at this data object at the same + /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED + * instead, so that we can look at this data object at the same * time as one on another file */ - r = journal_file_move_to_object(j->unique_file, 0, j->unique_offset, &o); + r = journal_file_move_to_object(j->unique_file, OBJECT_UNUSED, j->unique_offset, &o); if (r < 0) return r; @@ -2567,10 +2479,6 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ return -EBADMSG; } - r = journal_file_object_keep(j->unique_file, o, j->unique_offset, &release_cookie); - if (r < 0) - return r; - r = return_data(j, j->unique_file, o, &odata, &ol); if (r < 0) return r; @@ -2615,10 +2523,6 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ found = true; } - r = journal_file_object_release(j->unique_file, release_cookie); - if (r < 0) - return r; - if (found) continue; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 372f3ed..d56ee51 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -392,10 +392,12 @@ void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *route fprintf(f, "%s=", key); - for (i = 0; i < size; i++) - fprintf(f, "%s/%" PRIu8 ",%s%s", inet_ntoa(routes[i].dst_addr), - routes[i].dst_prefixlen, inet_ntoa(routes[i].gw_addr), + for (i = 0; i < size; i++) { + fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr), + routes[i].dst_prefixlen); + fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr), (i < (size - 1)) ? " ": ""); + } fputs("\n", f); } diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 0eba4c3..9986b52 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -68,7 +68,6 @@ struct sd_dhcp_client { uint32_t mtu; uint32_t xid; usec_t start_time; - uint16_t secs; unsigned int attempt; usec_t request_sent; sd_event_source *timeout_t1; @@ -321,10 +320,12 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, _cleanup_free_ DHCPPacket *packet; size_t optlen, optoffset, size; be16_t max_size; + usec_t time_now; + uint16_t secs; int r; assert(client); - assert(client->secs); + assert(client->start_time); assert(ret); assert(_optlen); assert(_optoffset); @@ -344,7 +345,15 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers refuse to issue an DHCP lease if 'secs' is set to zero */ - packet->dhcp.secs = htobe16(client->secs); + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + return r; + assert(time_now >= client->start_time); + + /* seconds between sending first and last DISCOVER + * must always be strictly positive to deal with broken servers */ + secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; + packet->dhcp.secs = htobe16(secs); /* RFC2132 section 4.1 A client that cannot receive unicast IP datagrams until its protocol @@ -441,24 +450,12 @@ static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet, static int client_send_discover(sd_dhcp_client *client) { _cleanup_free_ DHCPPacket *discover = NULL; size_t optoffset, optlen; - usec_t time_now; int r; assert(client); assert(client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_SELECTING); - /* See RFC2131 section 4.4.1 */ - - r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - return r; - assert(time_now >= client->start_time); - - /* seconds between sending first and last DISCOVER - * must always be strictly positive to deal with broken servers */ - client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; - r = client_message_init(client, &discover, DHCP_DISCOVER, &optlen, &optoffset); if (r < 0) @@ -875,10 +872,8 @@ static int client_start(sd_dhcp_client *client) { } client->fd = r; - if (client->state == DHCP_STATE_INIT) { + if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT) client->start_time = now(clock_boottime_or_monotonic()); - client->secs = 0; - } return client_initialize_events(client, client_receive_message_raw); } @@ -1269,6 +1264,9 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, if (r >= 0) { client->timeout_resend = sd_event_source_unref(client->timeout_resend); + client->receive_message = + sd_event_source_unref(client->receive_message); + client->fd = asynchronous_close(client->fd); if (IN_SET(client->state, DHCP_STATE_REQUESTING, DHCP_STATE_REBOOTING)) diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 4fb01c0..b7c9a07 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -50,7 +50,7 @@ int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) { assert_return(lease, -EINVAL); - assert_return(lease, -EINVAL); + assert_return(lifetime, -EINVAL); *lifetime = lease->lifetime; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index fa4f9b5..dbec1a2 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -200,19 +200,19 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du switch (type) { case DHCP6_DUID_LLT: - if (duid_len <= sizeof(client->duid.llt)) + if (duid_len <= sizeof(client->duid.llt) - 2) return -EINVAL; break; case DHCP6_DUID_EN: - if (duid_len != sizeof(client->duid.en)) + if (duid_len != sizeof(client->duid.en) - 2) return -EINVAL; break; case DHCP6_DUID_LL: - if (duid_len <= sizeof(client->duid.ll)) + if (duid_len <= sizeof(client->duid.ll) - 2) return -EINVAL; break; case DHCP6_DUID_UUID: - if (duid_len != sizeof(client->duid.uuid)) + if (duid_len != sizeof(client->duid.uuid) - 2) return -EINVAL; break; default: @@ -222,7 +222,7 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du client->duid.raw.type = htobe16(type); memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len; + client->duid_len = duid_len + 2; /* +2 for sizeof(type) */ return 0; } diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index 18afe0f..5658c61 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -537,7 +537,7 @@ static int bus_match_find_compare_value( else if (BUS_MATCH_CAN_HASH(t)) n = hashmap_get(c->compare.children, value_str); else { - for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next) + for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next) ; } diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 0ab1119..6c3230a 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -617,6 +617,9 @@ static int property_get_set_callbacks_run( return r; } else { + const char *signature = NULL; + char type = 0; + if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Property '%s' is not writable.", c->member); @@ -628,6 +631,13 @@ static int property_get_set_callbacks_run( c->last_iteration = bus->iteration_counter; + r = sd_bus_message_peek_type(m, &type, &signature); + if (r < 0) + return r; + + if (type != 'v' || !streq(strempty(signature), strempty(c->vtable->x.property.signature))) + return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_INVALID_ARGS, "Incorrect parameters for property '%s', expected '%s', got '%s'.", c->member, strempty(c->vtable->x.property.signature), strempty(signature)); + r = sd_bus_message_enter_container(m, 'v', c->vtable->x.property.signature); if (r < 0) return r; diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c index b501a52..740133a 100644 --- a/src/libsystemd/sd-rtnl/rtnl-message.c +++ b/src/libsystemd/sd-rtnl/rtnl-message.c @@ -36,6 +36,8 @@ #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL) #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; +#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK) + static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret) { sd_rtnl_message *m; @@ -566,8 +568,8 @@ int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const size = (size_t)r; if (size) { - length = strnlen(data, size); - if (length >= size) + length = strnlen(data, size+1); + if (length > size) return -EINVAL; } else length = strlen(data); @@ -1066,7 +1068,7 @@ int rtnl_message_parse(sd_rtnl_message *m, *rta_tb_size = max + 1; for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) { - type = rta->rta_type; + type = RTA_TYPE(rta); /* if the kernel is newer than the headers we used when building, we ignore out-of-range attributes @@ -1222,7 +1224,7 @@ int socket_read_message(sd_rtnl *rtnl) { } } - for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) { + for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) { _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; const NLType *nl_type; @@ -1237,7 +1239,8 @@ int socket_read_message(sd_rtnl *rtnl) { if (new_msg->nlmsg_type == NLMSG_DONE) { /* finished reading multi-part message */ done = true; - break; + + continue; } /* check that we support this message type */ diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c index 2699374..e2afcb8 100644 --- a/src/libudev/libudev-device.c +++ b/src/libudev/libudev-device.c @@ -730,8 +730,13 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con return NULL; } else { /* everything else just needs to be a directory */ - if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) + if (stat(path, &statbuf) != 0) return NULL; + + if (!S_ISDIR(statbuf.st_mode)) { + errno = EISDIR; + return NULL; + } } udev_device = udev_device_new(udev); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index b6d9bc6..759794f 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -758,7 +758,7 @@ static int mount_binds(const char *dest, char **l, bool ro) { * and char devices. */ if (S_ISDIR(source_st.st_mode)) { r = mkdir_label(where, 0755); - if (r < 0) { + if (r < 0 && errno != EEXIST) { log_error("Failed to create mount point %s: %s", where, strerror(-r)); return r; @@ -818,7 +818,7 @@ static int mount_tmpfs(const char *dest) { return log_oom(); r = mkdir_label(where, 0755); - if (r < 0) { + if (r < 0 && errno != EEXIST) { log_error("creating mount point for tmpfs %s failed: %s", where, strerror(-r)); return r; @@ -3073,6 +3073,7 @@ int main(int argc, char *argv[]) { goto finish; } } else { +#if 0 const char *p; p = strappenda(arg_directory, @@ -3082,6 +3083,7 @@ int main(int argc, char *argv[]) { goto finish; } +#endif } } else { char template[] = "/tmp/nspawn-root-XXXXXX"; diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 7375f77..ec8efcc 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -866,7 +866,7 @@ fail: int dns_packet_read_name(DnsPacket *p, char **_ret, bool allow_compression, size_t *start) { - size_t saved_rindex, after_rindex = 0; + size_t saved_rindex, after_rindex = 0, jump_barrier; _cleanup_free_ char *ret = NULL; size_t n = 0, allocated = 0; bool first = true; @@ -876,6 +876,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, assert(_ret); saved_rindex = p->rindex; + jump_barrier = p->rindex; for (;;) { uint8_t c, d; @@ -922,7 +923,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, goto fail; ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d; - if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) { + if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) { r = -EBADMSG; goto fail; } @@ -930,9 +931,13 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, if (after_rindex == 0) after_rindex = p->rindex; + /* Jumps are limited to a "prior occurence" (RFC-1035 4.1.4) */ + jump_barrier = ptr; p->rindex = ptr; - } else + } else { + r = -EBADMSG; goto fail; + } } if (!GREEDY_REALLOC(ret, allocated, n + 1)) { diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index 7d258c9..6dd4cad 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -108,7 +108,7 @@ int main(int argc, char *argv[]) { finish: sd_notify(false, - "STOPPIN=1\n" + "STOPPING=1\n" "STATUS=Shutting down..."); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/run/run.c b/src/run/run.c index e3b6293..dcefb5c 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -573,9 +573,12 @@ int main(int argc, char* argv[]) { if (r <= 0) goto finish; - r = find_binary(argv[optind], &command); + r = find_binary(argv[optind], arg_transport == BUS_TRANSPORT_LOCAL, &command); if (r < 0) { - log_error("Failed to find executable %s: %s", argv[optind], strerror(-r)); + log_error("Failed to find executable %s%s: %s", + argv[optind], + arg_transport == BUS_TRANSPORT_LOCAL ? "" : " on local system", + strerror(-r)); goto finish; } argv[optind] = command; diff --git a/src/shared/install.c b/src/shared/install.c index 035b44c..cab93e8 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1620,12 +1620,10 @@ int unit_file_enable( STRV_FOREACH(i, files) { UnitFileState state; + /* We only want to know if this unit is masked, so we ignore + * errors from unit_file_get_state, deferring other checks. + * This allows templated units to be enabled on the fly. */ state = unit_file_get_state(scope, root_dir, *i); - if (state < 0) { - log_error("Failed to get unit file state for %s: %s", *i, strerror(-state)); - return state; - } - if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) { log_error("Failed to enable unit: Unit %s is masked", *i); return -ENOTSUP; diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 8f75a8e..c800e01 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -86,17 +86,14 @@ static char** user_dirs( const char * const config_unit_paths[] = { USER_CONFIG_UNIT_PATH, "/etc/systemd/user", + "/etc/systemd-mutable/user", NULL }; const char * const runtime_unit_path = "/run/systemd/user"; const char * const data_unit_paths[] = { - "/usr/local/lib/systemd/user", - "/usr/local/share/systemd/user", USER_DATA_UNIT_PATH, - "/usr/lib/systemd/user", - "/usr/share/systemd/user", NULL }; @@ -260,13 +257,11 @@ int lookup_paths_init( STRV_IFNOTNULL(generator_early), USER_CONFIG_UNIT_PATH, "/etc/systemd/user", + "/etc/systemd-mutable/user", + "/nix/var/nix/profiles/default/lib/systemd/user", "/run/systemd/user", STRV_IFNOTNULL(generator), - "/usr/local/lib/systemd/user", - "/usr/local/share/systemd/user", USER_DATA_UNIT_PATH, - "/usr/lib/systemd/user", - "/usr/share/systemd/user", STRV_IFNOTNULL(generator_late), NULL); } else @@ -276,14 +271,11 @@ int lookup_paths_init( STRV_IFNOTNULL(generator_early), SYSTEM_CONFIG_UNIT_PATH, "/etc/systemd/system", + "/etc/systemd-mutable/system", + "/nix/var/nix/profiles/default/lib/systemd/system", "/run/systemd/system", STRV_IFNOTNULL(generator), - "/usr/local/lib/systemd/system", SYSTEM_DATA_UNIT_PATH, - "/usr/lib/systemd/system", -#ifdef HAVE_SPLIT_USR - "/lib/systemd/system", -#endif STRV_IFNOTNULL(generator_late), NULL); diff --git a/src/shared/path-util.c b/src/shared/path-util.c index 67566bc..be03695 100644 --- a/src/shared/path-util.c +++ b/src/shared/path-util.c @@ -563,11 +563,11 @@ int path_is_os_tree(const char *path) { return r >= 0; } -int find_binary(const char *name, char **filename) { +int find_binary(const char *name, bool local, char **filename) { assert(name); if (is_path(name)) { - if (access(name, X_OK) < 0) + if (local && access(name, X_OK) < 0) return -errno; if (filename) { @@ -657,7 +657,7 @@ int fsck_exists(const char *fstype) { checker = strappenda("fsck.", fstype); - r = find_binary(checker, &p); + r = find_binary(checker, true, &p); if (r < 0) return r; diff --git a/src/shared/path-util.h b/src/shared/path-util.h index 8d171a5..bd0d324 100644 --- a/src/shared/path-util.h +++ b/src/shared/path-util.h @@ -55,7 +55,7 @@ int path_is_mount_point(const char *path, bool allow_symlink); int path_is_read_only_fs(const char *path); int path_is_os_tree(const char *path); -int find_binary(const char *name, char **filename); +int find_binary(const char *name, bool local, char **filename); bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); diff --git a/src/shared/virt.c b/src/shared/virt.c index f9c4e67..f10baab 100644 --- a/src/shared/virt.c +++ b/src/shared/virt.c @@ -293,8 +293,26 @@ int detect_container(const char **id) { r = read_one_line_file("/run/systemd/container", &m); if (r == -ENOENT) { - r = 0; - goto finish; + + /* Fallback for cases where PID 1 was not + * systemd (for example, cases where + * init=/bin/sh is used. */ + + r = getenv_for_pid(1, "container", &m); + if (r <= 0) { + + /* If that didn't work, give up, + * assume no container manager. + * + * Note: This means we still cannot + * detect containers if init=/bin/sh + * is passed but privileges dropped, + * as /proc/1/environ is only readable + * with privileges. */ + + r = 0; + goto finish; + } } if (r < 0) return r; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 28eaa6a..3866308 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -2651,7 +2651,7 @@ static int start_unit_one( log_debug("Adding %s to the set", p); r = set_consume(s, p); - if (r < 0) + if (r < 0 && r != -EEXIST) return log_oom(); } @@ -6917,8 +6917,13 @@ done: static int halt_now(enum action a) { -/* Make sure C-A-D is handled by the kernel from this - * point on... */ + /* The kernel will automaticall flush ATA disks and suchlike + * on reboot(), but the file systems need to be synce'd + * explicitly in advance. */ + sync(); + + /* Make sure C-A-D is handled by the kernel from this point + * on... */ reboot(RB_ENABLE_CAD); switch (a) { diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index eb24372..00237a2 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -138,13 +138,15 @@ int sd_journal_reliable_fd(sd_journal *j); int sd_journal_get_catalog(sd_journal *j, char **text); int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **text); +/* the inverse condition avoids ambiguity of danling 'else' after the macro */ #define SD_JOURNAL_FOREACH(j) \ - if (sd_journal_seek_head(j) >= 0) \ - while (sd_journal_next(j) > 0) + if (sd_journal_seek_head(j) < 0) { } \ + else while (sd_journal_next(j) > 0) +/* the inverse condition avoids ambiguity of danling 'else' after the macro */ #define SD_JOURNAL_FOREACH_BACKWARDS(j) \ - if (sd_journal_seek_tail(j) >= 0) \ - while (sd_journal_previous(j) > 0) + if (sd_journal_seek_tail(j) < 0) { } \ + else while (sd_journal_previous(j) > 0) #define SD_JOURNAL_FOREACH_DATA(j, data, l) \ for (sd_journal_restart_data(j); sd_journal_enumerate_data((j), &(data), &(l)) > 0; ) diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 63d64b2..57264de 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -85,29 +85,30 @@ static void test_path(void) { } } -static void test_find_binary(const char *self) { +static void test_find_binary(const char *self, bool local) { char *p; - assert_se(find_binary("/bin/sh", &p) == 0); + assert_se(find_binary("/bin/sh", local, &p) == 0); puts(p); assert_se(streq(p, "/bin/sh")); free(p); - assert_se(find_binary(self, &p) == 0); + assert_se(find_binary(self, local, &p) == 0); puts(p); assert_se(endswith(p, "/test-path-util")); assert_se(path_is_absolute(p)); free(p); - assert_se(find_binary("sh", &p) == 0); + assert_se(find_binary("sh", local, &p) == 0); puts(p); assert_se(endswith(p, "/sh")); assert_se(path_is_absolute(p)); free(p); - assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT); + assert_se(find_binary("xxxx-xxxx", local, &p) == -ENOENT); - assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT); + assert_se(find_binary("/some/dir/xxxx-xxxx", local, &p) == + (local ? -ENOENT : 0)); } static void test_prefixes(void) { @@ -244,7 +245,8 @@ static void test_strv_resolve(void) { int main(int argc, char **argv) { test_path(); - test_find_binary(argv[0]); + test_find_binary(argv[0], true); + test_find_binary(argv[0], false); test_prefixes(); test_path_join(); test_fsck_exists(); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 2e6c713..193702c 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -994,9 +994,9 @@ static void kernel_cmdline_options(struct udev *udev) { if (r < 0) log_warning("Invalid udev.exec-delay ignored: %s", opt + 16); } else if (startswith(opt, "udev.event-timeout=")) { - r = safe_atou64(opt + 16, &arg_event_timeout_usec); + r = safe_atou64(opt + 19, &arg_event_timeout_usec); if (r < 0) { - log_warning("Invalid udev.event-timeout ignored: %s", opt + 16); + log_warning("Invalid udev.event-timeout ignored: %s", opt + 19); break; } arg_event_timeout_usec *= USEC_PER_SEC; diff --git a/units/console-getty.service.m4.in b/units/console-getty.service.m4.in index 8ac51a4..cae9fb5 100644 --- a/units/console-getty.service.m4.in +++ b/units/console-getty.service.m4.in @@ -15,7 +15,6 @@ After=rc-local.service Before=getty.target [Service] -ExecStart=-/sbin/agetty --noclear --keep-baud console 115200,38400,9600 $TERM Type=idle Restart=always RestartSec=0 diff --git a/units/container-getty@.service.m4.in b/units/container-getty@.service.m4.in index 4f7794b..6dfc2e9 100644 --- a/units/container-getty@.service.m4.in +++ b/units/container-getty@.service.m4.in @@ -14,9 +14,9 @@ After=rc-local.service )m4_dnl Before=getty.target IgnoreOnIsolate=yes +ConditionPathExists=/dev/pts/%I [Service] -ExecStart=-/sbin/agetty --noclear --keep-baud pts/%I 115200,38400,9600 $TERM Type=idle Restart=always RestartSec=0 diff --git a/units/emergency.service.in b/units/emergency.service.in index 18973e7..3a99660 100644 --- a/units/emergency.service.in +++ b/units/emergency.service.in @@ -16,7 +16,6 @@ Before=shutdown.target [Service] Environment=HOME=/root WorkingDirectory=/root -ExecStartPre=-/bin/plymouth quit ExecStartPre=-/bin/echo -e 'Welcome to emergency mode! After logging in, type "journalctl -xb" to view\\nsystem logs, "systemctl reboot" to reboot, "systemctl default" or ^D to\\ntry again to boot into default mode.' ExecStart=-/bin/sh -c "/sbin/sulogin; @SYSTEMCTL@ --fail --no-block default" Type=idle diff --git a/units/getty@.service.m4 b/units/getty@.service.m4 index 46164ab..f194a31 100644 --- a/units/getty@.service.m4 +++ b/units/getty@.service.m4 @@ -23,11 +23,12 @@ IgnoreOnIsolate=yes # On systems without virtual consoles, don't start any getty. Note # that serial gettys are covered by serial-getty@.service, not this # unit. -ConditionPathExists=/dev/tty0 +ConditionPathExists=|/dev/tty0 +ConditionVirtualization=|lxc +ConditionVirtualization=|lxc-libvirt [Service] # the VT is cleared by TTYVTDisallocate -ExecStart=-/sbin/agetty --noclear %I $TERM Type=idle Restart=always RestartSec=0 diff --git a/units/kmod-static-nodes.service.in b/units/kmod-static-nodes.service.in index 0934a87..7e30c9e 100644 --- a/units/kmod-static-nodes.service.in +++ b/units/kmod-static-nodes.service.in @@ -10,7 +10,6 @@ Description=Create list of required static device nodes for the current kernel DefaultDependencies=no Before=sysinit.target systemd-tmpfiles-setup-dev.service ConditionCapability=CAP_SYS_MODULE -ConditionPathExists=/lib/modules/%v/modules.devname [Service] Type=oneshot diff --git a/units/local-fs.target b/units/local-fs.target index d2e5429..d26984b 100644 --- a/units/local-fs.target +++ b/units/local-fs.target @@ -13,3 +13,5 @@ Conflicts=shutdown.target After=local-fs-pre.target OnFailure=emergency.target OnFailureJobMode=replace-irreversibly + +X-StopOnReconfiguration=yes diff --git a/units/remote-fs.target b/units/remote-fs.target index 43ffa5c..156a681 100644 --- a/units/remote-fs.target +++ b/units/remote-fs.target @@ -12,5 +12,7 @@ After=remote-fs-pre.target DefaultDependencies=no Conflicts=shutdown.target +X-StopOnReconfiguration=yes + [Install] WantedBy=multi-user.target diff --git a/units/rescue.service.in b/units/rescue.service.in index fc93f1e..3c87cf8 100644 --- a/units/rescue.service.in +++ b/units/rescue.service.in @@ -16,7 +16,6 @@ Before=shutdown.target [Service] Environment=HOME=/root WorkingDirectory=/root -ExecStartPre=-/bin/plymouth quit ExecStartPre=-/bin/echo -e 'Welcome to emergency mode! After logging in, type "journalctl -xb" to view\\nsystem logs, "systemctl reboot" to reboot, "systemctl default" or ^D to\\nboot into default mode.' ExecStart=-/bin/sh -c "/sbin/sulogin; @SYSTEMCTL@ --fail --no-block default" Type=idle diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4 index 4522d0d..96daa5c 100644 --- a/units/serial-getty@.service.m4 +++ b/units/serial-getty@.service.m4 @@ -22,7 +22,6 @@ Before=getty.target IgnoreOnIsolate=yes [Service] -ExecStart=-/sbin/agetty --keep-baud 115200,38400,9600 %I $TERM Type=idle Restart=always UtmpIdentifier=%I diff --git a/units/sysinit.target b/units/sysinit.target index ec33503..4ac47b9 100644 --- a/units/sysinit.target +++ b/units/sysinit.target @@ -9,5 +9,4 @@ Description=System Initialization Documentation=man:systemd.special(7) Conflicts=emergency.service emergency.target -Wants=local-fs.target swap.target -After=local-fs.target swap.target emergency.service emergency.target +After=emergency.service emergency.target diff --git a/units/systemd-backlight@.service.in b/units/systemd-backlight@.service.in index ecf3de4..7e83446 100644 --- a/units/systemd-backlight@.service.in +++ b/units/systemd-backlight@.service.in @@ -19,3 +19,4 @@ Type=oneshot RemainAfterExit=yes ExecStart=@rootlibexecdir@/systemd-backlight load %i ExecStop=@rootlibexecdir@/systemd-backlight save %i +X-RestartIfChanged=false diff --git a/units/systemd-journal-flush.service.in b/units/systemd-journal-flush.service.in index 699670b..ba22c6d 100644 --- a/units/systemd-journal-flush.service.in +++ b/units/systemd-journal-flush.service.in @@ -10,8 +10,10 @@ Description=Trigger Flushing of Journal to Persistent Storage Documentation=man:systemd-journald.service(8) man:journald.conf(5) DefaultDependencies=no Requires=systemd-journald.service -After=systemd-journald.service local-fs.target remote-fs.target +After=systemd-journald.service +After=systemd-remount-fs.service Before=systemd-user-sessions.service systemd-tmpfiles-setup.service +RequiresMountsFor=/var/log/journal [Service] ExecStart=@rootbindir@/journalctl --flush diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in index 4de38fa..2f23c13 100644 --- a/units/systemd-journald.service.in +++ b/units/systemd-journald.service.in @@ -14,6 +14,7 @@ After=systemd-journald.socket systemd-journald-dev-log.socket syslog.socket Before=sysinit.target [Service] +Type=notify Sockets=systemd-journald.socket systemd-journald-dev-log.socket ExecStart=@rootlibexecdir@/systemd-journald Restart=always @@ -26,3 +27,8 @@ WatchdogSec=1min # Increase the default a bit in order to allow many simultaneous # services being run since we keep one fd open per service. LimitNOFILE=16384 + +# Don't restart journald, since that causes services connected to +# journald to stop logging (see +# https://bugs.freedesktop.org/show_bug.cgi?id=56043). +X-RestartIfChanged=no diff --git a/units/systemd-random-seed.service.in b/units/systemd-random-seed.service.in index b55844b..3ef9fc6 100644 --- a/units/systemd-random-seed.service.in +++ b/units/systemd-random-seed.service.in @@ -19,3 +19,4 @@ Type=oneshot RemainAfterExit=yes ExecStart=@rootlibexecdir@/systemd-random-seed load ExecStop=@rootlibexecdir@/systemd-random-seed save +X-RestartIfChanged=false diff --git a/units/systemd-rfkill@.service.in b/units/systemd-rfkill@.service.in index 0e9851b..9f8fa0d 100644 --- a/units/systemd-rfkill@.service.in +++ b/units/systemd-rfkill@.service.in @@ -19,3 +19,4 @@ Type=oneshot RemainAfterExit=yes ExecStart=@rootlibexecdir@/systemd-rfkill load %I ExecStop=@rootlibexecdir@/systemd-rfkill save %I +X-RestartIfChanged=false diff --git a/units/systemd-tmpfiles-setup.service.in b/units/systemd-tmpfiles-setup.service.in index e895cda..194146f 100644 --- a/units/systemd-tmpfiles-setup.service.in +++ b/units/systemd-tmpfiles-setup.service.in @@ -11,7 +11,7 @@ Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8) DefaultDependencies=no Conflicts=shutdown.target After=local-fs.target systemd-sysusers.service -Before=sysinit.target shutdown.target +Before=shutdown.target RefuseManualStop=yes [Service] diff --git a/units/systemd-update-utmp.service.in b/units/systemd-update-utmp.service.in index 163eccd..7357c12 100644 --- a/units/systemd-update-utmp.service.in +++ b/units/systemd-update-utmp.service.in @@ -11,7 +11,7 @@ Documentation=man:systemd-update-utmp.service(8) man:utmp(5) DefaultDependencies=no RequiresMountsFor=/var/log/wtmp Conflicts=shutdown.target -After=systemd-remount-fs.service systemd-tmpfiles-setup.service auditd.service +After=systemd-remount-fs.service auditd.service Before=sysinit.target shutdown.target [Service] @@ -19,3 +19,4 @@ Type=oneshot RemainAfterExit=yes ExecStart=@rootlibexecdir@/systemd-update-utmp reboot ExecStop=@rootlibexecdir@/systemd-update-utmp shutdown +X-RestartIfChanged=false diff --git a/units/systemd-user-sessions.service.in b/units/systemd-user-sessions.service.in index 0869e73..b6ed958 100644 --- a/units/systemd-user-sessions.service.in +++ b/units/systemd-user-sessions.service.in @@ -15,3 +15,6 @@ Type=oneshot RemainAfterExit=yes ExecStart=@rootlibexecdir@/systemd-user-sessions start ExecStop=@rootlibexecdir@/systemd-user-sessions stop + +# Restart kills all active sessions. +X-RestartIfChanged=no