at v206 100 kB view raw
1diff --git a/rules/99-systemd.rules.in b/rules/99-systemd.rules.in 2index e30d9a8..a3d399b 100644 3--- a/rules/99-systemd.rules.in 4+++ b/rules/99-systemd.rules.in 5@@ -14,10 +14,6 @@ KERNEL=="vport*", TAG+="systemd" 6 SUBSYSTEM=="block", KERNEL!="ram*", TAG+="systemd" 7 SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0" 8 9-# Ignore encrypted devices with no identified superblock on it, since 10-# we are probably still calling mke2fs or mkswap on it. 11-SUBSYSTEM=="block", KERNEL!="ram*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0" 12- 13 # Ignore raid devices that are not yet assembled and started 14 SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", TEST!="md/array_state", ENV{SYSTEMD_READY}="0" 15 SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", ATTR{md/array_state}=="|clear|inactive", ENV{SYSTEMD_READY}="0" 16diff --git a/src/core/job.c b/src/core/job.c 17index eaa4bb1..db44fee 100644 18--- a/src/core/job.c 19+++ b/src/core/job.c 20@@ -352,6 +352,9 @@ bool job_type_is_redundant(JobType a, UnitActiveState b) { 21 return 22 b == UNIT_ACTIVATING; 23 24+ case JOB_NOP: 25+ return true; 26+ 27 default: 28 assert_not_reached("Invalid job type"); 29 } 30diff --git a/src/core/job.h b/src/core/job.h 31index 1e7c61b..ee8e54a 100644 32--- a/src/core/job.h 33+++ b/src/core/job.h 34@@ -49,9 +49,11 @@ enum JobType { 35 _JOB_TYPE_MAX_MERGING, 36 37 /* JOB_NOP can enter into a transaction, but as it won't pull in 38- * any dependencies, it won't have to merge with anything. 39- * job_install() avoids the problem of merging JOB_NOP too (it's 40- * special-cased, only merges with other JOB_NOPs). */ 41+ * any dependencies and it uses the special 'nop_job' slot in Unit, 42+ * it won't have to merge with anything (except possibly into another 43+ * JOB_NOP, previously installed). JOB_NOP is special-cased in 44+ * job_type_is_*() functions so that the transaction can be 45+ * activated. */ 46 JOB_NOP = _JOB_TYPE_MAX_MERGING, /* do nothing */ 47 48 _JOB_TYPE_MAX_IN_TRANSACTION, 49@@ -190,11 +192,15 @@ _pure_ static inline bool job_type_is_mergeable(JobType a, JobType b) { 50 } 51 52 _pure_ static inline bool job_type_is_conflicting(JobType a, JobType b) { 53- return !job_type_is_mergeable(a, b); 54+ return a != JOB_NOP && b != JOB_NOP && !job_type_is_mergeable(a, b); 55 } 56 57 _pure_ static inline bool job_type_is_superset(JobType a, JobType b) { 58 /* Checks whether operation a is a "superset" of b in its actions */ 59+ if (b == JOB_NOP) 60+ return true; 61+ if (a == JOB_NOP) 62+ return false; 63 return a == job_type_lookup_merge(a, b); 64 } 65 66diff --git a/src/core/manager.c b/src/core/manager.c 67index d427d88..256d6f7 100644 68--- a/src/core/manager.c 69+++ b/src/core/manager.c 70@@ -662,9 +662,11 @@ static int manager_setup_notify(Manager *m) { 71 return -errno; 72 } 73 74- if (m->running_as == SYSTEMD_SYSTEM) 75+ if (m->running_as == SYSTEMD_SYSTEM) { 76 m->notify_socket = strdup("/run/systemd/notify"); 77- else { 78+ if (!m->notify_socket) 79+ return log_oom(); 80+ } else { 81 const char *e; 82 83 e = getenv("XDG_RUNTIME_DIR"); 84@@ -674,9 +676,11 @@ static int manager_setup_notify(Manager *m) { 85 } 86 87 m->notify_socket = strappend(e, "/systemd/notify"); 88+ if (!m->notify_socket) 89+ return log_oom(); 90+ 91+ mkdir_parents_label(m->notify_socket, 0755); 92 } 93- if (!m->notify_socket) 94- return log_oom(); 95 96 strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1); 97 r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); 98diff --git a/src/core/shutdown.c b/src/core/shutdown.c 99index 20cf526..03cfddc 100644 100--- a/src/core/shutdown.c 101+++ b/src/core/shutdown.c 102@@ -75,7 +75,9 @@ static int parse_argv(int argc, char *argv[]) { 103 assert(argc >= 1); 104 assert(argv); 105 106- while ((c = getopt_long(argc, argv, "", options, NULL)) >= 0) 107+ /* "-" prevents getopt from permuting argv[] and moving the verb away 108+ * from argv[1]. Our interface to initrd promises it'll be there. */ 109+ while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0) 110 switch (c) { 111 112 case ARG_LOG_LEVEL: 113@@ -113,6 +115,13 @@ static int parse_argv(int argc, char *argv[]) { 114 115 break; 116 117+ case '\001': 118+ if (!arg_verb) 119+ arg_verb = optarg; 120+ else 121+ log_error("Excess arguments, ignoring"); 122+ break; 123+ 124 case '?': 125 return -EINVAL; 126 127@@ -120,15 +129,11 @@ static int parse_argv(int argc, char *argv[]) { 128 assert_not_reached("Unhandled option code."); 129 } 130 131- if (optind >= argc) { 132+ if (!arg_verb) { 133 log_error("Verb argument missing."); 134 return -EINVAL; 135 } 136 137- arg_verb = argv[optind]; 138- 139- if (optind + 1 < argc) 140- log_error("Excess arguments, ignoring"); 141 return 0; 142 } 143 144diff --git a/src/core/snapshot.c b/src/core/snapshot.c 145index 5eed615..c2678cb 100644 146--- a/src/core/snapshot.c 147+++ b/src/core/snapshot.c 148@@ -208,7 +208,7 @@ int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, 149 return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name); 150 151 if (manager_get_unit(m, name)) 152- sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name); 153+ return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name); 154 155 } else { 156 157diff --git a/src/core/systemd.pc.in b/src/core/systemd.pc.in 158index d5b86bf..9c66e7b 100644 159--- a/src/core/systemd.pc.in 160+++ b/src/core/systemd.pc.in 161@@ -14,8 +14,8 @@ systemduserunitdir=@userunitdir@ 162 systemduserpresetdir=@userpresetdir@ 163 systemdsystemconfdir=@pkgsysconfdir@/system 164 systemduserconfdir=@pkgsysconfdir@/user 165-systemdsystemunitpath=${systemdsystemconfdir}:/etc/systemd/system:/run/systemd/system:/usr/local/lib/systemd/system:${systemdsystemunitdir}:/usr/lib/systemd/system:/lib/systemd/system 166-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 167+systemdsystemunitpath=${systemdsystemconfdir}:/etc/systemd/system:/etc/systemd-mutable/system:/nix/var/nix/profiles/default/lib/systemd/user:/run/systemd/system:${systemdsystemunitdir} 168+systemduserunitpath=${systemduserconfdir}:/etc/systemd/user:/etc/systemd-mutable/user:/nix/var/nix/profiles/default/lib/systemd/system:/run/systemd/user:${systemduserunitdir} 169 systemdsystemgeneratordir=@systemgeneratordir@ 170 systemdusergeneratordir=@usergeneratordir@ 171 systemdsleepdir=@systemsleepdir@ 172diff --git a/src/core/timer.c b/src/core/timer.c 173index a3713e2..5c4e9f9 100644 174--- a/src/core/timer.c 175+++ b/src/core/timer.c 176@@ -521,6 +521,7 @@ fail: 177 178 static int timer_start(Unit *u) { 179 Timer *t = TIMER(u); 180+ TimerValue *v; 181 182 assert(t); 183 assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED); 184@@ -530,6 +531,11 @@ static int timer_start(Unit *u) { 185 186 t->last_trigger = DUAL_TIMESTAMP_NULL; 187 188+ /* Reenable all timers that depend on unit activation time */ 189+ LIST_FOREACH(value, v, t->values) 190+ if (v->base == TIMER_ACTIVE) 191+ v->disabled = false; 192+ 193 if (t->stamp_path) { 194 struct stat st; 195 196diff --git a/src/core/umount.c b/src/core/umount.c 197index cffa453..4d1a9ff 100644 198--- a/src/core/umount.c 199+++ b/src/core/umount.c 200@@ -385,6 +385,8 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e 201 * anyway, since we are running from it. They have 202 * already been remounted ro. */ 203 if (path_equal(m->path, "/") 204+ || path_equal(m->path, "/nix") 205+ || path_equal(m->path, "/nix/store") 206 #ifndef HAVE_SPLIT_USR 207 || path_equal(m->path, "/usr") 208 #endif 209diff --git a/src/delta/delta.c b/src/delta/delta.c 210index 25c4a0b..e1f2d6d 100644 211--- a/src/delta/delta.c 212+++ b/src/delta/delta.c 213@@ -487,7 +487,7 @@ static int parse_flags(const char *flag_str, int flags) { 214 const char *word, *state; 215 size_t l; 216 217- FOREACH_WORD(word, l, flag_str, state) { 218+ FOREACH_WORD_SEPARATOR(word, l, flag_str, ",", state) { 219 if (strneq("masked", word, l)) 220 flags |= SHOW_MASKED; 221 else if (strneq ("equivalent", word, l)) 222diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c 223index 70a5918..a5661e8 100644 224--- a/src/fsck/fsck.c 225+++ b/src/fsck/fsck.c 226@@ -315,8 +315,7 @@ int main(int argc, char *argv[]) { 227 return EXIT_FAILURE; 228 } 229 230- cmdline[i++] = "/sbin/fsck"; 231- cmdline[i++] = arg_repair; 232+ cmdline[i++] = "/run/current-system/sw/bin/fsck"; 233 cmdline[i++] = "-T"; 234 235 /* 236diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c 237index e257c12..1e04553 100644 238--- a/src/fstab-generator/fstab-generator.c 239+++ b/src/fstab-generator/fstab-generator.c 240@@ -485,7 +485,7 @@ static int add_usr_mount(void) { 241 return log_oom(); 242 } 243 244- if (!arg_usr_what || !arg_usr_options) 245+ if (!arg_usr_what) 246 return 0; 247 248 what = fstab_node_to_udev_node(arg_usr_what); 249@@ -494,7 +494,13 @@ static int add_usr_mount(void) { 250 return -1; 251 } 252 253- opts = arg_usr_options; 254+ if (!arg_usr_options) 255+ opts = arg_root_rw > 0 ? "rw" : "ro"; 256+ else if (!mount_test_option(arg_usr_options, "ro") && 257+ !mount_test_option(arg_usr_options, "rw")) 258+ opts = strappenda(arg_usr_options, ",", arg_root_rw > 0 ? "rw" : "ro"); 259+ else 260+ opts = arg_usr_options; 261 262 log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype)); 263 return add_mount(what, 264diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c 265index e487369..ff4e9c9 100644 266--- a/src/hostname/hostnamectl.c 267+++ b/src/hostname/hostnamectl.c 268@@ -536,5 +536,5 @@ int main(int argc, char *argv[]) { 269 r = hostnamectl_main(bus, argc, argv); 270 271 finish: 272- return r < 0 ? EXIT_FAILURE : r; 273+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; 274 } 275diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c 276index 7dd8878..70a9a13 100644 277--- a/src/journal-remote/journal-remote-parse.c 278+++ b/src/journal-remote/journal-remote-parse.c 279@@ -344,22 +344,25 @@ int process_data(RemoteSource *source) { 280 LLLLLLLL0011223344...\n 281 */ 282 sep = memchr(line, '=', n); 283- if (sep) 284+ if (sep) { 285 /* chomp newline */ 286 n--; 287- else 288+ 289+ r = iovw_put(&source->iovw, line, n); 290+ if (r < 0) 291+ return r; 292+ } else { 293 /* replace \n with = */ 294 line[n-1] = '='; 295- log_trace("Received: %.*s", (int) n, line); 296 297- r = iovw_put(&source->iovw, line, n); 298- if (r < 0) { 299- log_error("Failed to put line in iovect"); 300- return r; 301+ source->field_len = n; 302+ source->state = STATE_DATA_START; 303+ 304+ /* we cannot put the field in iovec until we have all data */ 305 } 306 307- if (!sep) 308- source->state = STATE_DATA_START; 309+ log_trace("Received: %.*s (%s)", (int) n, line, sep ? "text" : "binary"); 310+ 311 return 0; /* continue */ 312 } 313 314@@ -382,6 +385,7 @@ int process_data(RemoteSource *source) { 315 316 case STATE_DATA: { 317 void *data; 318+ char *field; 319 320 assert(source->data_size > 0); 321 322@@ -396,11 +400,12 @@ int process_data(RemoteSource *source) { 323 324 assert(data); 325 326- r = iovw_put(&source->iovw, data, source->data_size); 327- if (r < 0) { 328- log_error("failed to put binary buffer in iovect"); 329+ field = (char*) data - sizeof(uint64_t) - source->field_len; 330+ memmove(field + sizeof(uint64_t), field, source->field_len); 331+ 332+ r = iovw_put(&source->iovw, field + sizeof(uint64_t), source->field_len + source->data_size); 333+ if (r < 0) 334 return r; 335- } 336 337 source->state = STATE_DATA_FINISH; 338 339diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h 340index 8499f4e..22db550 100644 341--- a/src/journal-remote/journal-remote-parse.h 342+++ b/src/journal-remote/journal-remote-parse.h 343@@ -42,7 +42,9 @@ typedef struct RemoteSource { 344 size_t offset; /* offset to the beginning of live data in the buffer */ 345 size_t scanned; /* number of bytes since the beginning of data without a newline */ 346 size_t filled; /* total number of bytes in the buffer */ 347- size_t data_size; /* size of the binary data chunk being processed */ 348+ 349+ size_t field_len; /* used for binary fields: the field name length */ 350+ size_t data_size; /* and the size of the binary data chunk being processed */ 351 352 struct iovec_wrapper iovw; 353 354diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c 355index 5ab1982..1f980ee 100644 356--- a/src/journal/journal-authenticate.c 357+++ b/src/journal/journal-authenticate.c 358@@ -229,7 +229,7 @@ int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) { 359 return 0; 360 } 361 362-int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p) { 363+int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p) { 364 int r; 365 366 assert(f); 367@@ -246,7 +246,7 @@ int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p 368 if (r < 0) 369 return r; 370 } else { 371- if (type >= 0 && o->object.type != type) 372+ if (type > OBJECT_UNUSED && o->object.type != type) 373 return -EBADMSG; 374 } 375 376diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h 377index 0aaf836..565fe84 100644 378--- a/src/journal/journal-authenticate.h 379+++ b/src/journal/journal-authenticate.h 380@@ -33,7 +33,7 @@ int journal_file_append_first_tag(JournalFile *f); 381 int journal_file_hmac_setup(JournalFile *f); 382 int journal_file_hmac_start(JournalFile *f); 383 int journal_file_hmac_put_header(JournalFile *f); 384-int journal_file_hmac_put_object(JournalFile *f, int type, Object *o, uint64_t p); 385+int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uint64_t p); 386 387 int journal_file_fss_load(JournalFile *f); 388 int journal_file_parse_verification_key(JournalFile *f, const char *key); 389diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h 390index e55fa19..ab089cb 100644 391--- a/src/journal/journal-def.h 392+++ b/src/journal/journal-def.h 393@@ -52,8 +52,8 @@ typedef struct HashItem HashItem; 394 typedef struct FSSHeader FSSHeader; 395 396 /* Object types */ 397-enum { 398- OBJECT_UNUSED, 399+typedef enum ObjectType { 400+ OBJECT_UNUSED, /* also serves as "any type" or "additional context" */ 401 OBJECT_DATA, 402 OBJECT_FIELD, 403 OBJECT_ENTRY, 404@@ -62,7 +62,7 @@ enum { 405 OBJECT_ENTRY_ARRAY, 406 OBJECT_TAG, 407 _OBJECT_TYPE_MAX 408-}; 409+} ObjectType; 410 411 /* Object flags */ 412 enum { 413diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c 414index 8a2c0fc..c55a4dc 100644 415--- a/src/journal/journal-file.c 416+++ b/src/journal/journal-file.c 417@@ -374,7 +374,13 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) 418 return 0; 419 } 420 421-static int journal_file_move_to(JournalFile *f, int context, bool keep_always, uint64_t offset, uint64_t size, void **ret) { 422+static unsigned type_to_context(ObjectType type) { 423+ /* One context for each type, plus one catch-all for the rest */ 424+ assert_cc(_OBJECT_TYPE_MAX <= MMAP_CACHE_MAX_CONTEXTS); 425+ return type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX ? type : 0; 426+} 427+ 428+static int journal_file_move_to(JournalFile *f, ObjectType type, bool keep_always, uint64_t offset, uint64_t size, void **ret) { 429 assert(f); 430 assert(ret); 431 432@@ -391,7 +397,7 @@ static int journal_file_move_to(JournalFile *f, int context, bool keep_always, u 433 return -EADDRNOTAVAIL; 434 } 435 436- return mmap_cache_get(f->mmap, f->fd, f->prot, context, keep_always, offset, size, &f->last_stat, ret, NULL); 437+ return mmap_cache_get(f->mmap, f->fd, f->prot, type_to_context(type), keep_always, offset, size, &f->last_stat, ret); 438 } 439 440 static uint64_t minimum_header_size(Object *o) { 441@@ -412,7 +418,7 @@ static uint64_t minimum_header_size(Object *o) { 442 return table[o->object.type]; 443 } 444 445-int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret) { 446+int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret) { 447 int r; 448 void *t; 449 Object *o; 450@@ -425,7 +431,7 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec 451 if (!VALID64(offset)) 452 return -EFAULT; 453 454- r = journal_file_move_to(f, type_to_context(type), false, offset, sizeof(ObjectHeader), &t); 455+ r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t); 456 if (r < 0) 457 return r; 458 459@@ -441,11 +447,11 @@ int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Objec 460 if (s < minimum_header_size(o)) 461 return -EBADMSG; 462 463- if (type > 0 && o->object.type != type) 464+ if (type > OBJECT_UNUSED && o->object.type != type) 465 return -EBADMSG; 466 467 if (s > sizeof(ObjectHeader)) { 468- r = journal_file_move_to(f, o->object.type, false, offset, s, &t); 469+ r = journal_file_move_to(f, type, false, offset, s, &t); 470 if (r < 0) 471 return r; 472 473@@ -482,14 +488,14 @@ static uint64_t journal_file_entry_seqnum(JournalFile *f, uint64_t *seqnum) { 474 return r; 475 } 476 477-int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset) { 478+int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, Object **ret, uint64_t *offset) { 479 int r; 480 uint64_t p; 481 Object *tail, *o; 482 void *t; 483 484 assert(f); 485- assert(type > 0 && type < _OBJECT_TYPE_MAX); 486+ assert(type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX); 487 assert(size >= sizeof(ObjectHeader)); 488 assert(offset); 489 assert(ret); 490@@ -502,7 +508,7 @@ int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object * 491 if (p == 0) 492 p = le64toh(f->header->header_size); 493 else { 494- r = journal_file_move_to_object(f, -1, p, &tail); 495+ r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &tail); 496 if (r < 0) 497 return r; 498 499@@ -1657,7 +1663,7 @@ static int generic_array_bisect( 500 } 501 } 502 503- if (k > n) { 504+ if (k >= n) { 505 if (direction == DIRECTION_UP) { 506 i = n; 507 subtract_one = true; 508@@ -1793,23 +1799,6 @@ _pure_ static int test_object_offset(JournalFile *f, uint64_t p, uint64_t needle 509 return TEST_RIGHT; 510 } 511 512-int journal_file_move_to_entry_by_offset( 513- JournalFile *f, 514- uint64_t p, 515- direction_t direction, 516- Object **ret, 517- uint64_t *offset) { 518- 519- return generic_array_bisect(f, 520- le64toh(f->header->entry_array_offset), 521- le64toh(f->header->n_entries), 522- p, 523- test_object_offset, 524- direction, 525- ret, offset, NULL); 526-} 527- 528- 529 static int test_object_seqnum(JournalFile *f, uint64_t p, uint64_t needle) { 530 Object *o; 531 int r; 532@@ -1939,9 +1928,81 @@ int journal_file_move_to_entry_by_monotonic( 533 ret, offset, NULL); 534 } 535 536+void journal_file_reset_location(JournalFile *f) { 537+ f->location_type = LOCATION_HEAD; 538+ f->current_offset = 0; 539+ f->current_seqnum = 0; 540+ f->current_realtime = 0; 541+ f->current_monotonic = 0; 542+ zero(f->current_boot_id); 543+ f->current_xor_hash = 0; 544+} 545+ 546+void journal_file_save_location(JournalFile *f, Object *o, uint64_t offset) { 547+ f->location_type = LOCATION_SEEK; 548+ f->current_offset = offset; 549+ f->current_seqnum = le64toh(o->entry.seqnum); 550+ f->current_realtime = le64toh(o->entry.realtime); 551+ f->current_monotonic = le64toh(o->entry.monotonic); 552+ f->current_boot_id = o->entry.boot_id; 553+ f->current_xor_hash = le64toh(o->entry.xor_hash); 554+} 555+ 556+int journal_file_compare_locations(JournalFile *af, JournalFile *bf) { 557+ assert(af); 558+ assert(bf); 559+ assert(af->location_type == LOCATION_SEEK); 560+ assert(bf->location_type == LOCATION_SEEK); 561+ 562+ /* If contents and timestamps match, these entries are 563+ * identical, even if the seqnum does not match */ 564+ if (sd_id128_equal(af->current_boot_id, bf->current_boot_id) && 565+ af->current_monotonic == bf->current_monotonic && 566+ af->current_realtime == bf->current_realtime && 567+ af->current_xor_hash == bf->current_xor_hash) 568+ return 0; 569+ 570+ if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) { 571+ 572+ /* If this is from the same seqnum source, compare 573+ * seqnums */ 574+ if (af->current_seqnum < bf->current_seqnum) 575+ return -1; 576+ if (af->current_seqnum > bf->current_seqnum) 577+ return 1; 578+ 579+ /* Wow! This is weird, different data but the same 580+ * seqnums? Something is borked, but let's make the 581+ * best of it and compare by time. */ 582+ } 583+ 584+ if (sd_id128_equal(af->current_boot_id, bf->current_boot_id)) { 585+ 586+ /* If the boot id matches, compare monotonic time */ 587+ if (af->current_monotonic < bf->current_monotonic) 588+ return -1; 589+ if (af->current_monotonic > bf->current_monotonic) 590+ return 1; 591+ } 592+ 593+ /* Otherwise, compare UTC time */ 594+ if (af->current_realtime < bf->current_realtime) 595+ return -1; 596+ if (af->current_realtime > bf->current_realtime) 597+ return 1; 598+ 599+ /* Finally, compare by contents */ 600+ if (af->current_xor_hash < bf->current_xor_hash) 601+ return -1; 602+ if (af->current_xor_hash > bf->current_xor_hash) 603+ return 1; 604+ 605+ return 0; 606+} 607+ 608 int journal_file_next_entry( 609 JournalFile *f, 610- Object *o, uint64_t p, 611+ uint64_t p, 612 direction_t direction, 613 Object **ret, uint64_t *offset) { 614 615@@ -1949,18 +2010,14 @@ int journal_file_next_entry( 616 int r; 617 618 assert(f); 619- assert(p > 0 || !o); 620 621 n = le64toh(f->header->n_entries); 622 if (n <= 0) 623 return 0; 624 625- if (!o) 626+ if (p == 0) 627 i = direction == DIRECTION_DOWN ? 0 : n - 1; 628 else { 629- if (o->object.type != OBJECT_ENTRY) 630- return -EINVAL; 631- 632 r = generic_array_bisect(f, 633 le64toh(f->header->entry_array_offset), 634 le64toh(f->header->n_entries), 635@@ -2006,55 +2063,6 @@ int journal_file_next_entry( 636 return 1; 637 } 638 639-int journal_file_skip_entry( 640- JournalFile *f, 641- Object *o, uint64_t p, 642- int64_t skip, 643- Object **ret, uint64_t *offset) { 644- 645- uint64_t i, n; 646- int r; 647- 648- assert(f); 649- assert(o); 650- assert(p > 0); 651- 652- if (o->object.type != OBJECT_ENTRY) 653- return -EINVAL; 654- 655- r = generic_array_bisect(f, 656- le64toh(f->header->entry_array_offset), 657- le64toh(f->header->n_entries), 658- p, 659- test_object_offset, 660- DIRECTION_DOWN, 661- NULL, NULL, 662- &i); 663- if (r <= 0) 664- return r; 665- 666- /* Calculate new index */ 667- if (skip < 0) { 668- if ((uint64_t) -skip >= i) 669- i = 0; 670- else 671- i = i - (uint64_t) -skip; 672- } else 673- i += (uint64_t) skip; 674- 675- n = le64toh(f->header->n_entries); 676- if (n <= 0) 677- return -EBADMSG; 678- 679- if (i >= n) 680- i = n-1; 681- 682- return generic_array_get(f, 683- le64toh(f->header->entry_array_offset), 684- i, 685- ret, offset); 686-} 687- 688 int journal_file_next_entry_for_data( 689 JournalFile *f, 690 Object *o, uint64_t p, 691@@ -2289,7 +2297,7 @@ void journal_file_dump(JournalFile *f) { 692 693 p = le64toh(f->header->header_size); 694 while (p != 0) { 695- r = journal_file_move_to_object(f, -1, p, &o); 696+ r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); 697 if (r < 0) 698 goto fail; 699 700diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h 701index 211e121..ca17c97 100644 702--- a/src/journal/journal-file.h 703+++ b/src/journal/journal-file.h 704@@ -48,6 +48,20 @@ typedef enum direction { 705 DIRECTION_DOWN 706 } direction_t; 707 708+typedef enum LocationType { 709+ /* The first and last entries, resp. */ 710+ LOCATION_HEAD, 711+ LOCATION_TAIL, 712+ 713+ /* We already read the entry we currently point to, and the 714+ * next one to read should probably not be this one again. */ 715+ LOCATION_DISCRETE, 716+ 717+ /* We should seek to the precise location specified, and 718+ * return it, as we haven't read it yet. */ 719+ LOCATION_SEEK 720+} LocationType; 721+ 722 typedef struct JournalFile { 723 int fd; 724 725@@ -63,6 +77,8 @@ typedef struct JournalFile { 726 bool tail_entry_monotonic_valid:1; 727 728 direction_t last_direction; 729+ LocationType location_type; 730+ uint64_t last_n_entries; 731 732 char *path; 733 struct stat last_stat; 734@@ -72,6 +88,11 @@ typedef struct JournalFile { 735 HashItem *field_hash_table; 736 737 uint64_t current_offset; 738+ uint64_t current_seqnum; 739+ uint64_t current_realtime; 740+ uint64_t current_monotonic; 741+ sd_id128_t current_boot_id; 742+ uint64_t current_xor_hash; 743 744 JournalMetrics metrics; 745 MMapCache *mmap; 746@@ -160,13 +181,13 @@ static inline bool VALID_EPOCH(uint64_t u) { 747 #define JOURNAL_HEADER_COMPRESSED_LZ4(h) \ 748 (!!(le32toh((h)->incompatible_flags) & HEADER_INCOMPATIBLE_COMPRESSED_LZ4)) 749 750-int journal_file_move_to_object(JournalFile *f, int type, uint64_t offset, Object **ret); 751+int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret); 752 753 uint64_t journal_file_entry_n_items(Object *o) _pure_; 754 uint64_t journal_file_entry_array_n_items(Object *o) _pure_; 755 uint64_t journal_file_hash_table_n_items(Object *o) _pure_; 756 757-int journal_file_append_object(JournalFile *f, int type, uint64_t size, Object **ret, uint64_t *offset); 758+int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, Object **ret, uint64_t *offset); 759 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); 760 761 int journal_file_find_data_object(JournalFile *f, const void *data, uint64_t size, Object **ret, uint64_t *offset); 762@@ -175,12 +196,13 @@ int journal_file_find_data_object_with_hash(JournalFile *f, const void *data, ui 763 int journal_file_find_field_object(JournalFile *f, const void *field, uint64_t size, Object **ret, uint64_t *offset); 764 int journal_file_find_field_object_with_hash(JournalFile *f, const void *field, uint64_t size, uint64_t hash, Object **ret, uint64_t *offset); 765 766-int journal_file_next_entry(JournalFile *f, Object *o, uint64_t p, direction_t direction, Object **ret, uint64_t *offset); 767-int journal_file_skip_entry(JournalFile *f, Object *o, uint64_t p, int64_t skip, Object **ret, uint64_t *offset); 768+void journal_file_reset_location(JournalFile *f); 769+void journal_file_save_location(JournalFile *f, Object *o, uint64_t offset); 770+int journal_file_compare_locations(JournalFile *af, JournalFile *bf); 771+int journal_file_next_entry(JournalFile *f, uint64_t p, direction_t direction, Object **ret, uint64_t *offset); 772 773 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); 774 775-int journal_file_move_to_entry_by_offset(JournalFile *f, uint64_t seqnum, direction_t direction, Object **ret, uint64_t *offset); 776 int journal_file_move_to_entry_by_seqnum(JournalFile *f, uint64_t seqnum, direction_t direction, Object **ret, uint64_t *offset); 777 int journal_file_move_to_entry_by_realtime(JournalFile *f, uint64_t realtime, direction_t direction, Object **ret, uint64_t *offset); 778 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); 779@@ -205,21 +227,3 @@ int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t * 780 int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot, usec_t *from, usec_t *to); 781 782 bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec); 783- 784- 785-static unsigned type_to_context(int type) { 786- /* One context for each type, plus one catch-all for the rest */ 787- return type > 0 && type < _OBJECT_TYPE_MAX ? type : 0; 788-} 789- 790-static inline int journal_file_object_keep(JournalFile *f, Object *o, uint64_t offset, void **release_cookie) { 791- unsigned context = type_to_context(o->object.type); 792- uint64_t s = le64toh(o->object.size); 793- 794- return mmap_cache_get(f->mmap, f->fd, f->prot, context, true, 795- offset, s, &f->last_stat, NULL, release_cookie); 796-} 797- 798-static inline int journal_file_object_release(JournalFile *f, void *release_cookie) { 799- return mmap_cache_release(f->mmap, f->fd, release_cookie); 800-} 801diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h 802index 70847db..e99050c 100644 803--- a/src/journal/journal-internal.h 804+++ b/src/journal/journal-internal.h 805@@ -57,20 +57,6 @@ struct Match { 806 LIST_HEAD(Match, matches); 807 }; 808 809-typedef enum LocationType { 810- /* The first and last entries, resp. */ 811- LOCATION_HEAD, 812- LOCATION_TAIL, 813- 814- /* We already read the entry we currently point to, and the 815- * next one to read should probably not be this one again. */ 816- LOCATION_DISCRETE, 817- 818- /* We should seek to the precise location specified, and 819- * return it, as we haven't read it yet. */ 820- LOCATION_SEEK 821-} LocationType; 822- 823 struct Location { 824 LocationType type; 825 826diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c 827index f74adcb..5baa22d 100644 828--- a/src/journal/journal-verify.c 829+++ b/src/journal/journal-verify.c 830@@ -368,7 +368,7 @@ static int contains_uint64(MMapCache *m, int fd, uint64_t n, uint64_t p) { 831 832 c = (a + b) / 2; 833 834- r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL); 835+ r = mmap_cache_get(m, fd, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z); 836 if (r < 0) 837 return r; 838 839@@ -865,7 +865,7 @@ int journal_file_verify( 840 if (show_progress) 841 draw_progress(0x7FFF * p / le64toh(f->header->tail_object_offset), &last_usec); 842 843- r = journal_file_move_to_object(f, -1, p, &o); 844+ r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); 845 if (r < 0) { 846 error(p, "invalid object"); 847 goto fail; 848@@ -1085,11 +1085,11 @@ int journal_file_verify( 849 q = last_tag; 850 851 while (q <= p) { 852- r = journal_file_move_to_object(f, -1, q, &o); 853+ r = journal_file_move_to_object(f, OBJECT_UNUSED, q, &o); 854 if (r < 0) 855 goto fail; 856 857- r = journal_file_hmac_put_object(f, -1, o, q); 858+ r = journal_file_hmac_put_object(f, OBJECT_UNUSED, o, q); 859 if (r < 0) 860 goto fail; 861 862@@ -1097,7 +1097,7 @@ int journal_file_verify( 863 } 864 865 /* Position might have changed, let's reposition things */ 866- r = journal_file_move_to_object(f, -1, p, &o); 867+ r = journal_file_move_to_object(f, OBJECT_UNUSED, p, &o); 868 if (r < 0) 869 goto fail; 870 871diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c 872index f50faf4..03579fd 100644 873--- a/src/journal/journalctl.c 874+++ b/src/journal/journalctl.c 875@@ -682,7 +682,7 @@ static int parse_argv(int argc, char *argv[]) { 876 assert_not_reached("Unhandled option"); 877 } 878 879- if (arg_follow && !arg_no_tail && arg_lines == ARG_LINES_DEFAULT) 880+ if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT) 881 arg_lines = 10; 882 883 if (!!arg_directory + !!arg_file + !!arg_machine > 1) { 884diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c 885index a635202..655e2dd 100644 886--- a/src/journal/journald-native.c 887+++ b/src/journal/journald-native.c 888@@ -132,8 +132,8 @@ void server_process_native_message( 889 890 /* A property follows */ 891 892- /* n received properties, +1 for _TRANSPORT */ 893- if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS + !!object_pid * N_IOVEC_OBJECT_FIELDS)) { 894+ /* n existing properties, 1 new, +1 for _TRANSPORT */ 895+ if (!GREEDY_REALLOC(iovec, m, n + 2 + N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS)) { 896 log_oom(); 897 break; 898 } 899diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c 900index 12735c4..08b143b 100644 901--- a/src/journal/journald-server.c 902+++ b/src/journal/journald-server.c 903@@ -1655,6 +1655,7 @@ void server_done(Server *s) { 904 free(s->buffer); 905 free(s->tty_path); 906 free(s->cgroup_root); 907+ free(s->hostname_field); 908 909 if (s->mmap) 910 mmap_cache_unref(s->mmap); 911diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c 912index b7db6f1..f6f669d 100644 913--- a/src/journal/mmap-cache.c 914+++ b/src/journal/mmap-cache.c 915@@ -38,7 +38,7 @@ typedef struct FileDescriptor FileDescriptor; 916 struct Window { 917 MMapCache *cache; 918 919- unsigned keep_always; 920+ bool keep_always; 921 bool in_unused; 922 923 int prot; 924@@ -76,7 +76,7 @@ struct MMapCache { 925 926 927 Hashmap *fds; 928- Hashmap *contexts; 929+ Context *contexts[MMAP_CACHE_MAX_CONTEXTS]; 930 931 LIST_HEAD(Window, unused); 932 Window *last_unused; 933@@ -185,7 +185,7 @@ static void context_detach_window(Context *c) { 934 c->window = NULL; 935 LIST_REMOVE(by_window, w->contexts, c); 936 937- if (!w->contexts && w->keep_always == 0) { 938+ if (!w->contexts && !w->keep_always) { 939 /* Not used anymore? */ 940 LIST_PREPEND(unused, c->cache->unused, w); 941 if (!c->cache->last_unused) 942@@ -219,18 +219,13 @@ static void context_attach_window(Context *c, Window *w) { 943 944 static Context *context_add(MMapCache *m, unsigned id) { 945 Context *c; 946- int r; 947 948 assert(m); 949 950- c = hashmap_get(m->contexts, UINT_TO_PTR(id + 1)); 951+ c = m->contexts[id]; 952 if (c) 953 return c; 954 955- r = hashmap_ensure_allocated(&m->contexts, NULL); 956- if (r < 0) 957- return NULL; 958- 959 c = new0(Context, 1); 960 if (!c) 961 return NULL; 962@@ -238,11 +233,8 @@ static Context *context_add(MMapCache *m, unsigned id) { 963 c->cache = m; 964 c->id = id; 965 966- r = hashmap_put(m->contexts, UINT_TO_PTR(id + 1), c); 967- if (r < 0) { 968- free(c); 969- return NULL; 970- } 971+ assert(!m->contexts[id]); 972+ m->contexts[id] = c; 973 974 return c; 975 } 976@@ -252,8 +244,10 @@ static void context_free(Context *c) { 977 978 context_detach_window(c); 979 980- if (c->cache) 981- assert_se(hashmap_remove(c->cache->contexts, UINT_TO_PTR(c->id + 1))); 982+ if (c->cache) { 983+ assert(c->cache->contexts[c->id] == c); 984+ c->cache->contexts[c->id] = NULL; 985+ } 986 987 free(c); 988 } 989@@ -302,15 +296,14 @@ static FileDescriptor* fd_add(MMapCache *m, int fd) { 990 } 991 992 static void mmap_cache_free(MMapCache *m) { 993- Context *c; 994 FileDescriptor *f; 995+ int i; 996 997 assert(m); 998 999- while ((c = hashmap_first(m->contexts))) 1000- context_free(c); 1001- 1002- hashmap_free(m->contexts); 1003+ for (i = 0; i < MMAP_CACHE_MAX_CONTEXTS; i++) 1004+ if (m->contexts[i]) 1005+ context_free(m->contexts[i]); 1006 1007 while ((f = hashmap_first(m->fds))) 1008 fd_free(f); 1009@@ -352,8 +345,7 @@ static int try_context( 1010 bool keep_always, 1011 uint64_t offset, 1012 size_t size, 1013- void **ret, 1014- void **release_cookie) { 1015+ void **ret) { 1016 1017 Context *c; 1018 1019@@ -361,8 +353,9 @@ static int try_context( 1020 assert(m->n_ref > 0); 1021 assert(fd >= 0); 1022 assert(size > 0); 1023+ assert(ret); 1024 1025- c = hashmap_get(m->contexts, UINT_TO_PTR(context+1)); 1026+ c = m->contexts[context]; 1027 if (!c) 1028 return 0; 1029 1030@@ -378,12 +371,9 @@ static int try_context( 1031 return 0; 1032 } 1033 1034- c->window->keep_always += keep_always; 1035+ c->window->keep_always |= keep_always; 1036 1037- if (ret) 1038- *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset); 1039- if (keep_always && release_cookie) 1040- *release_cookie = c->window; 1041+ *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset); 1042 return 1; 1043 } 1044 1045@@ -395,8 +385,7 @@ static int find_mmap( 1046 bool keep_always, 1047 uint64_t offset, 1048 size_t size, 1049- void **ret, 1050- void **release_cookie) { 1051+ void **ret) { 1052 1053 FileDescriptor *f; 1054 Window *w; 1055@@ -427,10 +416,7 @@ static int find_mmap( 1056 context_attach_window(c, w); 1057 w->keep_always += keep_always; 1058 1059- if (ret) 1060- *ret = (uint8_t*) w->ptr + (offset - w->offset); 1061- if (keep_always && release_cookie) 1062- *release_cookie = c->window; 1063+ *ret = (uint8_t*) w->ptr + (offset - w->offset); 1064 return 1; 1065 } 1066 1067@@ -443,8 +429,7 @@ static int add_mmap( 1068 uint64_t offset, 1069 size_t size, 1070 struct stat *st, 1071- void **ret, 1072- void **release_cookie) { 1073+ void **ret) { 1074 1075 uint64_t woffset, wsize; 1076 Context *c; 1077@@ -457,6 +442,7 @@ static int add_mmap( 1078 assert(m->n_ref > 0); 1079 assert(fd >= 0); 1080 assert(size > 0); 1081+ assert(ret); 1082 1083 woffset = offset & ~((uint64_t) page_size() - 1ULL); 1084 wsize = size + (offset - woffset); 1085@@ -526,10 +512,7 @@ static int add_mmap( 1086 c->window = w; 1087 LIST_PREPEND(by_window, w->contexts, c); 1088 1089- if (ret) 1090- *ret = (uint8_t*) w->ptr + (offset - w->offset); 1091- if (keep_always && release_cookie) 1092- *release_cookie = c->window; 1093+ *ret = (uint8_t*) w->ptr + (offset - w->offset); 1094 return 1; 1095 1096 outofmem: 1097@@ -546,8 +529,7 @@ int mmap_cache_get( 1098 uint64_t offset, 1099 size_t size, 1100 struct stat *st, 1101- void **ret, 1102- void **release_cookie) { 1103+ void **ret) { 1104 1105 int r; 1106 1107@@ -555,16 +537,18 @@ int mmap_cache_get( 1108 assert(m->n_ref > 0); 1109 assert(fd >= 0); 1110 assert(size > 0); 1111+ assert(ret); 1112+ assert(context < MMAP_CACHE_MAX_CONTEXTS); 1113 1114 /* Check whether the current context is the right one already */ 1115- r = try_context(m, fd, prot, context, keep_always, offset, size, ret, release_cookie); 1116+ r = try_context(m, fd, prot, context, keep_always, offset, size, ret); 1117 if (r != 0) { 1118 m->n_hit ++; 1119 return r; 1120 } 1121 1122 /* Search for a matching mmap */ 1123- r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret, release_cookie); 1124+ r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret); 1125 if (r != 0) { 1126 m->n_hit ++; 1127 return r; 1128@@ -573,39 +557,7 @@ int mmap_cache_get( 1129 m->n_missed++; 1130 1131 /* Create a new mmap */ 1132- return add_mmap(m, fd, prot, context, keep_always, offset, size, st, ret, release_cookie); 1133-} 1134- 1135-int mmap_cache_release( 1136- MMapCache *m, 1137- int fd, 1138- void *release_cookie) { 1139- 1140- FileDescriptor *f; 1141- Window *w; 1142- 1143- assert(m); 1144- assert(m->n_ref > 0); 1145- assert(fd >= 0); 1146- 1147- f = hashmap_get(m->fds, INT_TO_PTR(fd + 1)); 1148- if (!f) 1149- return -EBADF; 1150- 1151- assert(f->fd == fd); 1152- 1153- LIST_FOREACH(by_fd, w, f->windows) 1154- if (w == release_cookie) 1155- break; 1156- 1157- if (!w) 1158- return -ENOENT; 1159- 1160- if (w->keep_always == 0) 1161- return -ENOLCK; 1162- 1163- w->keep_always -= 1; 1164- return 0; 1165+ return add_mmap(m, fd, prot, context, keep_always, offset, size, st, ret); 1166 } 1167 1168 void mmap_cache_close_fd(MMapCache *m, int fd) { 1169@@ -621,18 +573,6 @@ void mmap_cache_close_fd(MMapCache *m, int fd) { 1170 fd_free(f); 1171 } 1172 1173-void mmap_cache_close_context(MMapCache *m, unsigned context) { 1174- Context *c; 1175- 1176- assert(m); 1177- 1178- c = hashmap_get(m->contexts, UINT_TO_PTR(context + 1)); 1179- if (!c) 1180- return; 1181- 1182- context_free(c); 1183-} 1184- 1185 unsigned mmap_cache_get_hit(MMapCache *m) { 1186 assert(m); 1187 1188diff --git a/src/journal/mmap-cache.h b/src/journal/mmap-cache.h 1189index 76e5316..fe2c83d 100644 1190--- a/src/journal/mmap-cache.h 1191+++ b/src/journal/mmap-cache.h 1192@@ -25,6 +25,8 @@ 1193 #include <stdbool.h> 1194 #include <sys/stat.h> 1195 1196+#define MMAP_CACHE_MAX_CONTEXTS 8 1197+ 1198 typedef struct MMapCache MMapCache; 1199 1200 MMapCache* mmap_cache_new(void); 1201@@ -40,14 +42,8 @@ int mmap_cache_get( 1202 uint64_t offset, 1203 size_t size, 1204 struct stat *st, 1205- void **ret, 1206- void **release_cookie); 1207-int mmap_cache_release( 1208- MMapCache *m, 1209- int fd, 1210- void *release_cookie); 1211+ void **ret); 1212 void mmap_cache_close_fd(MMapCache *m, int fd); 1213-void mmap_cache_close_context(MMapCache *m, unsigned context); 1214 1215 unsigned mmap_cache_get_hit(MMapCache *m); 1216 unsigned mmap_cache_get_missed(MMapCache *m); 1217diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c 1218index cf21c4d..cb7fc32 100644 1219--- a/src/journal/sd-journal.c 1220+++ b/src/journal/sd-journal.c 1221@@ -87,7 +87,7 @@ static void detach_location(sd_journal *j) { 1222 j->current_field = 0; 1223 1224 ORDERED_HASHMAP_FOREACH(f, j->files, i) 1225- f->current_offset = 0; 1226+ journal_file_reset_location(f); 1227 } 1228 1229 static void reset_location(sd_journal *j) { 1230@@ -114,20 +114,19 @@ static void init_location(Location *l, LocationType type, JournalFile *f, Object 1231 l->seqnum_set = l->realtime_set = l->monotonic_set = l->xor_hash_set = true; 1232 } 1233 1234-static void set_location(sd_journal *j, LocationType type, JournalFile *f, Object *o, 1235- direction_t direction, uint64_t offset) { 1236+static void set_location(sd_journal *j, JournalFile *f, Object *o) { 1237 assert(j); 1238- assert(type == LOCATION_DISCRETE || type == LOCATION_SEEK); 1239 assert(f); 1240 assert(o); 1241 1242- init_location(&j->current_location, type, f, o); 1243+ init_location(&j->current_location, LOCATION_DISCRETE, f, o); 1244 1245 j->current_file = f; 1246 j->current_field = 0; 1247 1248- f->last_direction = direction; 1249- f->current_offset = offset; 1250+ /* Let f know its candidate entry was picked. */ 1251+ assert(f->location_type == LOCATION_SEEK); 1252+ f->location_type = LOCATION_DISCRETE; 1253 } 1254 1255 static int match_is_valid(const void *data, size_t size) { 1256@@ -413,144 +412,51 @@ _public_ void sd_journal_flush_matches(sd_journal *j) { 1257 detach_location(j); 1258 } 1259 1260-static int compare_entry_order(JournalFile *af, Object *_ao, 1261- JournalFile *bf, uint64_t bp) { 1262- 1263- uint64_t a, b; 1264- Object *ao, *bo; 1265- int r; 1266- 1267- assert(af); 1268- assert(bf); 1269- assert(_ao); 1270- 1271- /* The mmap cache might invalidate the object from the first 1272- * file if we look at the one from the second file. Hence 1273- * temporarily copy the header of the first one, and look at 1274- * that only. */ 1275- ao = alloca(offsetof(EntryObject, items)); 1276- memcpy(ao, _ao, offsetof(EntryObject, items)); 1277- 1278- r = journal_file_move_to_object(bf, OBJECT_ENTRY, bp, &bo); 1279- if (r < 0) 1280- return strcmp(af->path, bf->path); 1281- 1282- /* We operate on two different files here, hence we can access 1283- * two objects at the same time, which we normally can't. 1284- * 1285- * If contents and timestamps match, these entries are 1286- * identical, even if the seqnum does not match */ 1287- 1288- if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id) && 1289- ao->entry.monotonic == bo->entry.monotonic && 1290- ao->entry.realtime == bo->entry.realtime && 1291- ao->entry.xor_hash == bo->entry.xor_hash) 1292- return 0; 1293- 1294- if (sd_id128_equal(af->header->seqnum_id, bf->header->seqnum_id)) { 1295- 1296- /* If this is from the same seqnum source, compare 1297- * seqnums */ 1298- a = le64toh(ao->entry.seqnum); 1299- b = le64toh(bo->entry.seqnum); 1300- 1301- if (a < b) 1302- return -1; 1303- if (a > b) 1304- return 1; 1305- 1306- /* Wow! This is weird, different data but the same 1307- * seqnums? Something is borked, but let's make the 1308- * best of it and compare by time. */ 1309- } 1310- 1311- if (sd_id128_equal(ao->entry.boot_id, bo->entry.boot_id)) { 1312- 1313- /* If the boot id matches, compare monotonic time */ 1314- a = le64toh(ao->entry.monotonic); 1315- b = le64toh(bo->entry.monotonic); 1316- 1317- if (a < b) 1318- return -1; 1319- if (a > b) 1320- return 1; 1321- } 1322- 1323- /* Otherwise, compare UTC time */ 1324- a = le64toh(ao->entry.realtime); 1325- b = le64toh(bo->entry.realtime); 1326- 1327- if (a < b) 1328- return -1; 1329- if (a > b) 1330- return 1; 1331- 1332- /* Finally, compare by contents */ 1333- a = le64toh(ao->entry.xor_hash); 1334- b = le64toh(bo->entry.xor_hash); 1335- 1336- if (a < b) 1337- return -1; 1338- if (a > b) 1339- return 1; 1340- 1341- return 0; 1342-} 1343- 1344-_pure_ static int compare_with_location(JournalFile *af, Object *ao, Location *l) { 1345- uint64_t a; 1346- 1347- assert(af); 1348- assert(ao); 1349+_pure_ static int compare_with_location(JournalFile *f, Location *l) { 1350+ assert(f); 1351 assert(l); 1352+ assert(f->location_type == LOCATION_SEEK); 1353 assert(l->type == LOCATION_DISCRETE || l->type == LOCATION_SEEK); 1354 1355 if (l->monotonic_set && 1356- sd_id128_equal(ao->entry.boot_id, l->boot_id) && 1357+ sd_id128_equal(f->current_boot_id, l->boot_id) && 1358 l->realtime_set && 1359- le64toh(ao->entry.realtime) == l->realtime && 1360+ f->current_realtime == l->realtime && 1361 l->xor_hash_set && 1362- le64toh(ao->entry.xor_hash) == l->xor_hash) 1363+ f->current_xor_hash == l->xor_hash) 1364 return 0; 1365 1366 if (l->seqnum_set && 1367- sd_id128_equal(af->header->seqnum_id, l->seqnum_id)) { 1368- 1369- a = le64toh(ao->entry.seqnum); 1370+ sd_id128_equal(f->header->seqnum_id, l->seqnum_id)) { 1371 1372- if (a < l->seqnum) 1373+ if (f->current_seqnum < l->seqnum) 1374 return -1; 1375- if (a > l->seqnum) 1376+ if (f->current_seqnum > l->seqnum) 1377 return 1; 1378 } 1379 1380 if (l->monotonic_set && 1381- sd_id128_equal(ao->entry.boot_id, l->boot_id)) { 1382+ sd_id128_equal(f->current_boot_id, l->boot_id)) { 1383 1384- a = le64toh(ao->entry.monotonic); 1385- 1386- if (a < l->monotonic) 1387+ if (f->current_monotonic < l->monotonic) 1388 return -1; 1389- if (a > l->monotonic) 1390+ if (f->current_monotonic > l->monotonic) 1391 return 1; 1392 } 1393 1394 if (l->realtime_set) { 1395 1396- a = le64toh(ao->entry.realtime); 1397- 1398- if (a < l->realtime) 1399+ if (f->current_realtime < l->realtime) 1400 return -1; 1401- if (a > l->realtime) 1402+ if (f->current_realtime > l->realtime) 1403 return 1; 1404 } 1405 1406 if (l->xor_hash_set) { 1407- a = le64toh(ao->entry.xor_hash); 1408 1409- if (a < l->xor_hash) 1410+ if (f->current_xor_hash < l->xor_hash) 1411 return -1; 1412- if (a > l->xor_hash) 1413+ if (f->current_xor_hash > l->xor_hash) 1414 return 1; 1415 } 1416 1417@@ -766,9 +672,9 @@ static int find_location_with_matches( 1418 /* No matches is simple */ 1419 1420 if (j->current_location.type == LOCATION_HEAD) 1421- return journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, ret, offset); 1422+ return journal_file_next_entry(f, 0, DIRECTION_DOWN, ret, offset); 1423 if (j->current_location.type == LOCATION_TAIL) 1424- return journal_file_next_entry(f, NULL, 0, DIRECTION_UP, ret, offset); 1425+ return journal_file_next_entry(f, 0, DIRECTION_UP, ret, offset); 1426 if (j->current_location.seqnum_set && sd_id128_equal(j->current_location.seqnum_id, f->header->seqnum_id)) 1427 return journal_file_move_to_entry_by_seqnum(f, j->current_location.seqnum, direction, ret, offset); 1428 if (j->current_location.monotonic_set) { 1429@@ -779,7 +685,7 @@ static int find_location_with_matches( 1430 if (j->current_location.realtime_set) 1431 return journal_file_move_to_entry_by_realtime(f, j->current_location.realtime, direction, ret, offset); 1432 1433- return journal_file_next_entry(f, NULL, 0, direction, ret, offset); 1434+ return journal_file_next_entry(f, 0, direction, ret, offset); 1435 } else 1436 return find_location_for_match(j, j->level0, f, direction, ret, offset); 1437 } 1438@@ -791,49 +697,61 @@ static int next_with_matches( 1439 Object **ret, 1440 uint64_t *offset) { 1441 1442- Object *c; 1443- uint64_t cp; 1444- 1445 assert(j); 1446 assert(f); 1447 assert(ret); 1448 assert(offset); 1449 1450- c = *ret; 1451- cp = *offset; 1452- 1453 /* No matches is easy. We simple advance the file 1454 * pointer by one. */ 1455 if (!j->level0) 1456- return journal_file_next_entry(f, c, cp, direction, ret, offset); 1457+ return journal_file_next_entry(f, f->current_offset, direction, ret, offset); 1458 1459 /* If we have a match then we look for the next matching entry 1460 * with an offset at least one step larger */ 1461- return next_for_match(j, j->level0, f, direction == DIRECTION_DOWN ? cp+1 : cp-1, direction, ret, offset); 1462+ return next_for_match(j, j->level0, f, 1463+ direction == DIRECTION_DOWN ? f->current_offset + 1 1464+ : f->current_offset - 1, 1465+ direction, ret, offset); 1466 } 1467 1468-static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction, Object **ret, uint64_t *offset) { 1469+static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direction) { 1470 Object *c; 1471- uint64_t cp; 1472+ uint64_t cp, n_entries; 1473 int r; 1474 1475 assert(j); 1476 assert(f); 1477 1478- if (f->last_direction == direction && f->current_offset > 0) { 1479- cp = f->current_offset; 1480+ n_entries = le64toh(f->header->n_entries); 1481 1482- r = journal_file_move_to_object(f, OBJECT_ENTRY, cp, &c); 1483- if (r < 0) 1484- return r; 1485+ /* If we hit EOF before, we don't need to look into this file again 1486+ * unless direction changed or new entries appeared. */ 1487+ if (f->last_direction == direction && f->location_type == LOCATION_TAIL && 1488+ n_entries == f->last_n_entries) 1489+ return 0; 1490 1491- r = next_with_matches(j, f, direction, &c, &cp); 1492- if (r <= 0) 1493- return r; 1494+ f->last_n_entries = n_entries; 1495+ 1496+ if (f->last_direction == direction && f->current_offset > 0) { 1497+ /* LOCATION_SEEK here means we did the work in a previous 1498+ * iteration and the current location already points to a 1499+ * candidate entry. */ 1500+ if (f->location_type != LOCATION_SEEK) { 1501+ r = next_with_matches(j, f, direction, &c, &cp); 1502+ if (r <= 0) 1503+ return r; 1504+ 1505+ journal_file_save_location(f, c, cp); 1506+ } 1507 } else { 1508+ f->last_direction = direction; 1509+ 1510 r = find_location_with_matches(j, f, direction, &c, &cp); 1511 if (r <= 0) 1512 return r; 1513+ 1514+ journal_file_save_location(f, c, cp); 1515 } 1516 1517 /* OK, we found the spot, now let's advance until an entry 1518@@ -848,30 +766,25 @@ static int next_beyond_location(sd_journal *j, JournalFile *f, direction_t direc 1519 if (j->current_location.type == LOCATION_DISCRETE) { 1520 int k; 1521 1522- k = compare_with_location(f, c, &j->current_location); 1523+ k = compare_with_location(f, &j->current_location); 1524 1525 found = direction == DIRECTION_DOWN ? k > 0 : k < 0; 1526 } else 1527 found = true; 1528 1529- if (found) { 1530- if (ret) 1531- *ret = c; 1532- if (offset) 1533- *offset = cp; 1534+ if (found) 1535 return 1; 1536- } 1537 1538 r = next_with_matches(j, f, direction, &c, &cp); 1539 if (r <= 0) 1540 return r; 1541+ 1542+ journal_file_save_location(f, c, cp); 1543 } 1544 } 1545 1546 static int real_journal_next(sd_journal *j, direction_t direction) { 1547 JournalFile *f, *new_file = NULL; 1548- uint64_t new_offset = 0; 1549- uint64_t p = 0; 1550 Iterator i; 1551 Object *o; 1552 int r; 1553@@ -882,38 +795,38 @@ static int real_journal_next(sd_journal *j, direction_t direction) { 1554 ORDERED_HASHMAP_FOREACH(f, j->files, i) { 1555 bool found; 1556 1557- r = next_beyond_location(j, f, direction, &o, &p); 1558+ r = next_beyond_location(j, f, direction); 1559 if (r < 0) { 1560 log_debug("Can't iterate through %s, ignoring: %s", f->path, strerror(-r)); 1561 remove_file_real(j, f); 1562 continue; 1563- } else if (r == 0) 1564+ } else if (r == 0) { 1565+ f->location_type = LOCATION_TAIL; 1566 continue; 1567+ } 1568 1569 if (!new_file) 1570 found = true; 1571 else { 1572 int k; 1573 1574- k = compare_entry_order(f, o, new_file, new_offset); 1575+ k = journal_file_compare_locations(f, new_file); 1576 1577 found = direction == DIRECTION_DOWN ? k < 0 : k > 0; 1578 } 1579 1580- if (found) { 1581+ if (found) 1582 new_file = f; 1583- new_offset = p; 1584- } 1585 } 1586 1587 if (!new_file) 1588 return 0; 1589 1590- r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_offset, &o); 1591+ r = journal_file_move_to_object(new_file, OBJECT_ENTRY, new_file->current_offset, &o); 1592 if (r < 0) 1593 return r; 1594 1595- set_location(j, LOCATION_DISCRETE, new_file, o, direction, new_offset); 1596+ set_location(j, new_file, o); 1597 1598 return 1; 1599 } 1600@@ -2526,7 +2439,6 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ 1601 size_t ol; 1602 bool found; 1603 int r; 1604- void *release_cookie; 1605 1606 /* Proceed to next data object in the field's linked list */ 1607 if (j->unique_offset == 0) { 1608@@ -2552,10 +2464,10 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ 1609 continue; 1610 } 1611 1612- /* We do not use the type context here, but 0 instead, 1613- * so that we can look at this data object at the same 1614+ /* We do not use OBJECT_DATA context here, but OBJECT_UNUSED 1615+ * instead, so that we can look at this data object at the same 1616 * time as one on another file */ 1617- r = journal_file_move_to_object(j->unique_file, 0, j->unique_offset, &o); 1618+ r = journal_file_move_to_object(j->unique_file, OBJECT_UNUSED, j->unique_offset, &o); 1619 if (r < 0) 1620 return r; 1621 1622@@ -2567,10 +2479,6 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ 1623 return -EBADMSG; 1624 } 1625 1626- r = journal_file_object_keep(j->unique_file, o, j->unique_offset, &release_cookie); 1627- if (r < 0) 1628- return r; 1629- 1630 r = return_data(j, j->unique_file, o, &odata, &ol); 1631 if (r < 0) 1632 return r; 1633@@ -2615,10 +2523,6 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ 1634 found = true; 1635 } 1636 1637- r = journal_file_object_release(j->unique_file, release_cookie); 1638- if (r < 0) 1639- return r; 1640- 1641 if (found) 1642 continue; 1643 1644diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c 1645index 372f3ed..d56ee51 100644 1646--- a/src/libsystemd-network/network-internal.c 1647+++ b/src/libsystemd-network/network-internal.c 1648@@ -392,10 +392,12 @@ void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *route 1649 1650 fprintf(f, "%s=", key); 1651 1652- for (i = 0; i < size; i++) 1653- fprintf(f, "%s/%" PRIu8 ",%s%s", inet_ntoa(routes[i].dst_addr), 1654- routes[i].dst_prefixlen, inet_ntoa(routes[i].gw_addr), 1655+ for (i = 0; i < size; i++) { 1656+ fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr), 1657+ routes[i].dst_prefixlen); 1658+ fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr), 1659 (i < (size - 1)) ? " ": ""); 1660+ } 1661 1662 fputs("\n", f); 1663 } 1664diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c 1665index 0eba4c3..9986b52 100644 1666--- a/src/libsystemd-network/sd-dhcp-client.c 1667+++ b/src/libsystemd-network/sd-dhcp-client.c 1668@@ -68,7 +68,6 @@ struct sd_dhcp_client { 1669 uint32_t mtu; 1670 uint32_t xid; 1671 usec_t start_time; 1672- uint16_t secs; 1673 unsigned int attempt; 1674 usec_t request_sent; 1675 sd_event_source *timeout_t1; 1676@@ -321,10 +320,12 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, 1677 _cleanup_free_ DHCPPacket *packet; 1678 size_t optlen, optoffset, size; 1679 be16_t max_size; 1680+ usec_t time_now; 1681+ uint16_t secs; 1682 int r; 1683 1684 assert(client); 1685- assert(client->secs); 1686+ assert(client->start_time); 1687 assert(ret); 1688 assert(_optlen); 1689 assert(_optoffset); 1690@@ -344,7 +345,15 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, 1691 1692 /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers 1693 refuse to issue an DHCP lease if 'secs' is set to zero */ 1694- packet->dhcp.secs = htobe16(client->secs); 1695+ r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); 1696+ if (r < 0) 1697+ return r; 1698+ assert(time_now >= client->start_time); 1699+ 1700+ /* seconds between sending first and last DISCOVER 1701+ * must always be strictly positive to deal with broken servers */ 1702+ secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; 1703+ packet->dhcp.secs = htobe16(secs); 1704 1705 /* RFC2132 section 4.1 1706 A client that cannot receive unicast IP datagrams until its protocol 1707@@ -441,24 +450,12 @@ static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet, 1708 static int client_send_discover(sd_dhcp_client *client) { 1709 _cleanup_free_ DHCPPacket *discover = NULL; 1710 size_t optoffset, optlen; 1711- usec_t time_now; 1712 int r; 1713 1714 assert(client); 1715 assert(client->state == DHCP_STATE_INIT || 1716 client->state == DHCP_STATE_SELECTING); 1717 1718- /* See RFC2131 section 4.4.1 */ 1719- 1720- r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); 1721- if (r < 0) 1722- return r; 1723- assert(time_now >= client->start_time); 1724- 1725- /* seconds between sending first and last DISCOVER 1726- * must always be strictly positive to deal with broken servers */ 1727- client->secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; 1728- 1729 r = client_message_init(client, &discover, DHCP_DISCOVER, 1730 &optlen, &optoffset); 1731 if (r < 0) 1732@@ -875,10 +872,8 @@ static int client_start(sd_dhcp_client *client) { 1733 } 1734 client->fd = r; 1735 1736- if (client->state == DHCP_STATE_INIT) { 1737+ if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT) 1738 client->start_time = now(clock_boottime_or_monotonic()); 1739- client->secs = 0; 1740- } 1741 1742 return client_initialize_events(client, client_receive_message_raw); 1743 } 1744@@ -1269,6 +1264,9 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, 1745 if (r >= 0) { 1746 client->timeout_resend = 1747 sd_event_source_unref(client->timeout_resend); 1748+ client->receive_message = 1749+ sd_event_source_unref(client->receive_message); 1750+ client->fd = asynchronous_close(client->fd); 1751 1752 if (IN_SET(client->state, DHCP_STATE_REQUESTING, 1753 DHCP_STATE_REBOOTING)) 1754diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c 1755index 4fb01c0..b7c9a07 100644 1756--- a/src/libsystemd-network/sd-dhcp-lease.c 1757+++ b/src/libsystemd-network/sd-dhcp-lease.c 1758@@ -50,7 +50,7 @@ int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { 1759 1760 int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) { 1761 assert_return(lease, -EINVAL); 1762- assert_return(lease, -EINVAL); 1763+ assert_return(lifetime, -EINVAL); 1764 1765 *lifetime = lease->lifetime; 1766 1767diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c 1768index fa4f9b5..dbec1a2 100644 1769--- a/src/libsystemd-network/sd-dhcp6-client.c 1770+++ b/src/libsystemd-network/sd-dhcp6-client.c 1771@@ -200,19 +200,19 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du 1772 1773 switch (type) { 1774 case DHCP6_DUID_LLT: 1775- if (duid_len <= sizeof(client->duid.llt)) 1776+ if (duid_len <= sizeof(client->duid.llt) - 2) 1777 return -EINVAL; 1778 break; 1779 case DHCP6_DUID_EN: 1780- if (duid_len != sizeof(client->duid.en)) 1781+ if (duid_len != sizeof(client->duid.en) - 2) 1782 return -EINVAL; 1783 break; 1784 case DHCP6_DUID_LL: 1785- if (duid_len <= sizeof(client->duid.ll)) 1786+ if (duid_len <= sizeof(client->duid.ll) - 2) 1787 return -EINVAL; 1788 break; 1789 case DHCP6_DUID_UUID: 1790- if (duid_len != sizeof(client->duid.uuid)) 1791+ if (duid_len != sizeof(client->duid.uuid) - 2) 1792 return -EINVAL; 1793 break; 1794 default: 1795@@ -222,7 +222,7 @@ int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *du 1796 1797 client->duid.raw.type = htobe16(type); 1798 memcpy(&client->duid.raw.data, duid, duid_len); 1799- client->duid_len = duid_len; 1800+ client->duid_len = duid_len + 2; /* +2 for sizeof(type) */ 1801 1802 return 0; 1803 } 1804diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c 1805index 18afe0f..5658c61 100644 1806--- a/src/libsystemd/sd-bus/bus-match.c 1807+++ b/src/libsystemd/sd-bus/bus-match.c 1808@@ -537,7 +537,7 @@ static int bus_match_find_compare_value( 1809 else if (BUS_MATCH_CAN_HASH(t)) 1810 n = hashmap_get(c->compare.children, value_str); 1811 else { 1812- for (n = c->child; !value_node_same(n, t, value_u8, value_str); n = n->next) 1813+ for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next) 1814 ; 1815 } 1816 1817diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c 1818index 0ab1119..6c3230a 100644 1819--- a/src/libsystemd/sd-bus/bus-objects.c 1820+++ b/src/libsystemd/sd-bus/bus-objects.c 1821@@ -617,6 +617,9 @@ static int property_get_set_callbacks_run( 1822 return r; 1823 1824 } else { 1825+ const char *signature = NULL; 1826+ char type = 0; 1827+ 1828 if (c->vtable->type != _SD_BUS_VTABLE_WRITABLE_PROPERTY) 1829 return sd_bus_reply_method_errorf(m, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Property '%s' is not writable.", c->member); 1830 1831@@ -628,6 +631,13 @@ static int property_get_set_callbacks_run( 1832 1833 c->last_iteration = bus->iteration_counter; 1834 1835+ r = sd_bus_message_peek_type(m, &type, &signature); 1836+ if (r < 0) 1837+ return r; 1838+ 1839+ if (type != 'v' || !streq(strempty(signature), strempty(c->vtable->x.property.signature))) 1840+ 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)); 1841+ 1842 r = sd_bus_message_enter_container(m, 'v', c->vtable->x.property.signature); 1843 if (r < 0) 1844 return r; 1845diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c 1846index b501a52..740133a 100644 1847--- a/src/libsystemd/sd-rtnl/rtnl-message.c 1848+++ b/src/libsystemd/sd-rtnl/rtnl-message.c 1849@@ -36,6 +36,8 @@ 1850 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL) 1851 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; 1852 1853+#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK) 1854+ 1855 static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret) { 1856 sd_rtnl_message *m; 1857 1858@@ -566,8 +568,8 @@ int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const 1859 size = (size_t)r; 1860 1861 if (size) { 1862- length = strnlen(data, size); 1863- if (length >= size) 1864+ length = strnlen(data, size+1); 1865+ if (length > size) 1866 return -EINVAL; 1867 } else 1868 length = strlen(data); 1869@@ -1066,7 +1068,7 @@ int rtnl_message_parse(sd_rtnl_message *m, 1870 *rta_tb_size = max + 1; 1871 1872 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) { 1873- type = rta->rta_type; 1874+ type = RTA_TYPE(rta); 1875 1876 /* if the kernel is newer than the headers we used 1877 when building, we ignore out-of-range attributes 1878@@ -1222,7 +1224,7 @@ int socket_read_message(sd_rtnl *rtnl) { 1879 } 1880 } 1881 1882- for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) { 1883+ for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) { 1884 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL; 1885 const NLType *nl_type; 1886 1887@@ -1237,7 +1239,8 @@ int socket_read_message(sd_rtnl *rtnl) { 1888 if (new_msg->nlmsg_type == NLMSG_DONE) { 1889 /* finished reading multi-part message */ 1890 done = true; 1891- break; 1892+ 1893+ continue; 1894 } 1895 1896 /* check that we support this message type */ 1897diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c 1898index 2699374..e2afcb8 100644 1899--- a/src/libudev/libudev-device.c 1900+++ b/src/libudev/libudev-device.c 1901@@ -730,8 +730,13 @@ _public_ struct udev_device *udev_device_new_from_syspath(struct udev *udev, con 1902 return NULL; 1903 } else { 1904 /* everything else just needs to be a directory */ 1905- if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) 1906+ if (stat(path, &statbuf) != 0) 1907 return NULL; 1908+ 1909+ if (!S_ISDIR(statbuf.st_mode)) { 1910+ errno = EISDIR; 1911+ return NULL; 1912+ } 1913 } 1914 1915 udev_device = udev_device_new(udev); 1916diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c 1917index b6d9bc6..759794f 100644 1918--- a/src/nspawn/nspawn.c 1919+++ b/src/nspawn/nspawn.c 1920@@ -758,7 +758,7 @@ static int mount_binds(const char *dest, char **l, bool ro) { 1921 * and char devices. */ 1922 if (S_ISDIR(source_st.st_mode)) { 1923 r = mkdir_label(where, 0755); 1924- if (r < 0) { 1925+ if (r < 0 && errno != EEXIST) { 1926 log_error("Failed to create mount point %s: %s", where, strerror(-r)); 1927 1928 return r; 1929@@ -818,7 +818,7 @@ static int mount_tmpfs(const char *dest) { 1930 return log_oom(); 1931 1932 r = mkdir_label(where, 0755); 1933- if (r < 0) { 1934+ if (r < 0 && errno != EEXIST) { 1935 log_error("creating mount point for tmpfs %s failed: %s", where, strerror(-r)); 1936 1937 return r; 1938@@ -3073,6 +3073,7 @@ int main(int argc, char *argv[]) { 1939 goto finish; 1940 } 1941 } else { 1942+#if 0 1943 const char *p; 1944 1945 p = strappenda(arg_directory, 1946@@ -3082,6 +3083,7 @@ int main(int argc, char *argv[]) { 1947 goto finish; 1948 1949 } 1950+#endif 1951 } 1952 } else { 1953 char template[] = "/tmp/nspawn-root-XXXXXX"; 1954diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c 1955index 7375f77..ec8efcc 100644 1956--- a/src/resolve/resolved-dns-packet.c 1957+++ b/src/resolve/resolved-dns-packet.c 1958@@ -866,7 +866,7 @@ fail: 1959 1960 int dns_packet_read_name(DnsPacket *p, char **_ret, 1961 bool allow_compression, size_t *start) { 1962- size_t saved_rindex, after_rindex = 0; 1963+ size_t saved_rindex, after_rindex = 0, jump_barrier; 1964 _cleanup_free_ char *ret = NULL; 1965 size_t n = 0, allocated = 0; 1966 bool first = true; 1967@@ -876,6 +876,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, 1968 assert(_ret); 1969 1970 saved_rindex = p->rindex; 1971+ jump_barrier = p->rindex; 1972 1973 for (;;) { 1974 uint8_t c, d; 1975@@ -922,7 +923,7 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, 1976 goto fail; 1977 1978 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d; 1979- if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) { 1980+ if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) { 1981 r = -EBADMSG; 1982 goto fail; 1983 } 1984@@ -930,9 +931,13 @@ int dns_packet_read_name(DnsPacket *p, char **_ret, 1985 if (after_rindex == 0) 1986 after_rindex = p->rindex; 1987 1988+ /* Jumps are limited to a "prior occurence" (RFC-1035 4.1.4) */ 1989+ jump_barrier = ptr; 1990 p->rindex = ptr; 1991- } else 1992+ } else { 1993+ r = -EBADMSG; 1994 goto fail; 1995+ } 1996 } 1997 1998 if (!GREEDY_REALLOC(ret, allocated, n + 1)) { 1999diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c 2000index 7d258c9..6dd4cad 100644 2001--- a/src/resolve/resolved.c 2002+++ b/src/resolve/resolved.c 2003@@ -108,7 +108,7 @@ int main(int argc, char *argv[]) { 2004 2005 finish: 2006 sd_notify(false, 2007- "STOPPIN=1\n" 2008+ "STOPPING=1\n" 2009 "STATUS=Shutting down..."); 2010 2011 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; 2012diff --git a/src/run/run.c b/src/run/run.c 2013index e3b6293..dcefb5c 100644 2014--- a/src/run/run.c 2015+++ b/src/run/run.c 2016@@ -573,9 +573,12 @@ int main(int argc, char* argv[]) { 2017 if (r <= 0) 2018 goto finish; 2019 2020- r = find_binary(argv[optind], &command); 2021+ r = find_binary(argv[optind], arg_transport == BUS_TRANSPORT_LOCAL, &command); 2022 if (r < 0) { 2023- log_error("Failed to find executable %s: %s", argv[optind], strerror(-r)); 2024+ log_error("Failed to find executable %s%s: %s", 2025+ argv[optind], 2026+ arg_transport == BUS_TRANSPORT_LOCAL ? "" : " on local system", 2027+ strerror(-r)); 2028 goto finish; 2029 } 2030 argv[optind] = command; 2031diff --git a/src/shared/install.c b/src/shared/install.c 2032index 035b44c..cab93e8 100644 2033--- a/src/shared/install.c 2034+++ b/src/shared/install.c 2035@@ -1620,12 +1620,10 @@ int unit_file_enable( 2036 STRV_FOREACH(i, files) { 2037 UnitFileState state; 2038 2039+ /* We only want to know if this unit is masked, so we ignore 2040+ * errors from unit_file_get_state, deferring other checks. 2041+ * This allows templated units to be enabled on the fly. */ 2042 state = unit_file_get_state(scope, root_dir, *i); 2043- if (state < 0) { 2044- log_error("Failed to get unit file state for %s: %s", *i, strerror(-state)); 2045- return state; 2046- } 2047- 2048 if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) { 2049 log_error("Failed to enable unit: Unit %s is masked", *i); 2050 return -ENOTSUP; 2051diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c 2052index 8f75a8e..c800e01 100644 2053--- a/src/shared/path-lookup.c 2054+++ b/src/shared/path-lookup.c 2055@@ -86,17 +86,14 @@ static char** user_dirs( 2056 const char * const config_unit_paths[] = { 2057 USER_CONFIG_UNIT_PATH, 2058 "/etc/systemd/user", 2059+ "/etc/systemd-mutable/user", 2060 NULL 2061 }; 2062 2063 const char * const runtime_unit_path = "/run/systemd/user"; 2064 2065 const char * const data_unit_paths[] = { 2066- "/usr/local/lib/systemd/user", 2067- "/usr/local/share/systemd/user", 2068 USER_DATA_UNIT_PATH, 2069- "/usr/lib/systemd/user", 2070- "/usr/share/systemd/user", 2071 NULL 2072 }; 2073 2074@@ -260,13 +257,11 @@ int lookup_paths_init( 2075 STRV_IFNOTNULL(generator_early), 2076 USER_CONFIG_UNIT_PATH, 2077 "/etc/systemd/user", 2078+ "/etc/systemd-mutable/user", 2079+ "/nix/var/nix/profiles/default/lib/systemd/user", 2080 "/run/systemd/user", 2081 STRV_IFNOTNULL(generator), 2082- "/usr/local/lib/systemd/user", 2083- "/usr/local/share/systemd/user", 2084 USER_DATA_UNIT_PATH, 2085- "/usr/lib/systemd/user", 2086- "/usr/share/systemd/user", 2087 STRV_IFNOTNULL(generator_late), 2088 NULL); 2089 } else 2090@@ -276,14 +271,11 @@ int lookup_paths_init( 2091 STRV_IFNOTNULL(generator_early), 2092 SYSTEM_CONFIG_UNIT_PATH, 2093 "/etc/systemd/system", 2094+ "/etc/systemd-mutable/system", 2095+ "/nix/var/nix/profiles/default/lib/systemd/system", 2096 "/run/systemd/system", 2097 STRV_IFNOTNULL(generator), 2098- "/usr/local/lib/systemd/system", 2099 SYSTEM_DATA_UNIT_PATH, 2100- "/usr/lib/systemd/system", 2101-#ifdef HAVE_SPLIT_USR 2102- "/lib/systemd/system", 2103-#endif 2104 STRV_IFNOTNULL(generator_late), 2105 NULL); 2106 2107diff --git a/src/shared/path-util.c b/src/shared/path-util.c 2108index 67566bc..be03695 100644 2109--- a/src/shared/path-util.c 2110+++ b/src/shared/path-util.c 2111@@ -563,11 +563,11 @@ int path_is_os_tree(const char *path) { 2112 return r >= 0; 2113 } 2114 2115-int find_binary(const char *name, char **filename) { 2116+int find_binary(const char *name, bool local, char **filename) { 2117 assert(name); 2118 2119 if (is_path(name)) { 2120- if (access(name, X_OK) < 0) 2121+ if (local && access(name, X_OK) < 0) 2122 return -errno; 2123 2124 if (filename) { 2125@@ -657,7 +657,7 @@ int fsck_exists(const char *fstype) { 2126 2127 checker = strappenda("fsck.", fstype); 2128 2129- r = find_binary(checker, &p); 2130+ r = find_binary(checker, true, &p); 2131 if (r < 0) 2132 return r; 2133 2134diff --git a/src/shared/path-util.h b/src/shared/path-util.h 2135index 8d171a5..bd0d324 100644 2136--- a/src/shared/path-util.h 2137+++ b/src/shared/path-util.h 2138@@ -55,7 +55,7 @@ int path_is_mount_point(const char *path, bool allow_symlink); 2139 int path_is_read_only_fs(const char *path); 2140 int path_is_os_tree(const char *path); 2141 2142-int find_binary(const char *name, char **filename); 2143+int find_binary(const char *name, bool local, char **filename); 2144 2145 bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); 2146 2147diff --git a/src/shared/virt.c b/src/shared/virt.c 2148index f9c4e67..f3104d5 100644 2149--- a/src/shared/virt.c 2150+++ b/src/shared/virt.c 2151@@ -151,7 +151,7 @@ int detect_vm(const char **id) { 2152 _cleanup_free_ char *domcap = NULL, *cpuinfo_contents = NULL; 2153 static thread_local int cached_found = -1; 2154 static thread_local const char *cached_id = NULL; 2155- const char *_id = NULL; 2156+ const char *_id = NULL, *_id_cpuid = NULL; 2157 int r; 2158 2159 if (_likely_(cached_found >= 0)) { 2160@@ -197,10 +197,26 @@ int detect_vm(const char **id) { 2161 2162 /* this will set _id to "other" and return 0 for unknown hypervisors */ 2163 r = detect_vm_cpuid(&_id); 2164- if (r != 0) 2165+ 2166+ /* finish when found a known hypervisor other than kvm */ 2167+ if (r < 0 || (r > 0 && !streq(_id, "kvm"))) 2168 goto finish; 2169 2170+ _id_cpuid = _id; 2171+ 2172 r = detect_vm_dmi(&_id); 2173+ 2174+ /* kvm with and without Virtualbox */ 2175+ if (streq_ptr(_id_cpuid, "kvm")) { 2176+ if (r > 0 && streq(_id, "oracle")) 2177+ goto finish; 2178+ 2179+ _id = _id_cpuid; 2180+ r = 1; 2181+ goto finish; 2182+ } 2183+ 2184+ /* information from dmi */ 2185 if (r != 0) 2186 goto finish; 2187 2188@@ -293,8 +309,26 @@ int detect_container(const char **id) { 2189 2190 r = read_one_line_file("/run/systemd/container", &m); 2191 if (r == -ENOENT) { 2192- r = 0; 2193- goto finish; 2194+ 2195+ /* Fallback for cases where PID 1 was not 2196+ * systemd (for example, cases where 2197+ * init=/bin/sh is used. */ 2198+ 2199+ r = getenv_for_pid(1, "container", &m); 2200+ if (r <= 0) { 2201+ 2202+ /* If that didn't work, give up, 2203+ * assume no container manager. 2204+ * 2205+ * Note: This means we still cannot 2206+ * detect containers if init=/bin/sh 2207+ * is passed but privileges dropped, 2208+ * as /proc/1/environ is only readable 2209+ * with privileges. */ 2210+ 2211+ r = 0; 2212+ goto finish; 2213+ } 2214 } 2215 if (r < 0) 2216 return r; 2217diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c 2218index 28eaa6a..3866308 100644 2219--- a/src/systemctl/systemctl.c 2220+++ b/src/systemctl/systemctl.c 2221@@ -2651,7 +2651,7 @@ static int start_unit_one( 2222 2223 log_debug("Adding %s to the set", p); 2224 r = set_consume(s, p); 2225- if (r < 0) 2226+ if (r < 0 && r != -EEXIST) 2227 return log_oom(); 2228 } 2229 2230@@ -6917,8 +6917,13 @@ done: 2231 2232 static int halt_now(enum action a) { 2233 2234-/* Make sure C-A-D is handled by the kernel from this 2235- * point on... */ 2236+ /* The kernel will automaticall flush ATA disks and suchlike 2237+ * on reboot(), but the file systems need to be synce'd 2238+ * explicitly in advance. */ 2239+ sync(); 2240+ 2241+ /* Make sure C-A-D is handled by the kernel from this point 2242+ * on... */ 2243 reboot(RB_ENABLE_CAD); 2244 2245 switch (a) { 2246diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h 2247index eb24372..00237a2 100644 2248--- a/src/systemd/sd-journal.h 2249+++ b/src/systemd/sd-journal.h 2250@@ -138,13 +138,15 @@ int sd_journal_reliable_fd(sd_journal *j); 2251 int sd_journal_get_catalog(sd_journal *j, char **text); 2252 int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **text); 2253 2254+/* the inverse condition avoids ambiguity of danling 'else' after the macro */ 2255 #define SD_JOURNAL_FOREACH(j) \ 2256- if (sd_journal_seek_head(j) >= 0) \ 2257- while (sd_journal_next(j) > 0) 2258+ if (sd_journal_seek_head(j) < 0) { } \ 2259+ else while (sd_journal_next(j) > 0) 2260 2261+/* the inverse condition avoids ambiguity of danling 'else' after the macro */ 2262 #define SD_JOURNAL_FOREACH_BACKWARDS(j) \ 2263- if (sd_journal_seek_tail(j) >= 0) \ 2264- while (sd_journal_previous(j) > 0) 2265+ if (sd_journal_seek_tail(j) < 0) { } \ 2266+ else while (sd_journal_previous(j) > 0) 2267 2268 #define SD_JOURNAL_FOREACH_DATA(j, data, l) \ 2269 for (sd_journal_restart_data(j); sd_journal_enumerate_data((j), &(data), &(l)) > 0; ) 2270diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c 2271index 63d64b2..57264de 100644 2272--- a/src/test/test-path-util.c 2273+++ b/src/test/test-path-util.c 2274@@ -85,29 +85,30 @@ static void test_path(void) { 2275 } 2276 } 2277 2278-static void test_find_binary(const char *self) { 2279+static void test_find_binary(const char *self, bool local) { 2280 char *p; 2281 2282- assert_se(find_binary("/bin/sh", &p) == 0); 2283+ assert_se(find_binary("/bin/sh", local, &p) == 0); 2284 puts(p); 2285 assert_se(streq(p, "/bin/sh")); 2286 free(p); 2287 2288- assert_se(find_binary(self, &p) == 0); 2289+ assert_se(find_binary(self, local, &p) == 0); 2290 puts(p); 2291 assert_se(endswith(p, "/test-path-util")); 2292 assert_se(path_is_absolute(p)); 2293 free(p); 2294 2295- assert_se(find_binary("sh", &p) == 0); 2296+ assert_se(find_binary("sh", local, &p) == 0); 2297 puts(p); 2298 assert_se(endswith(p, "/sh")); 2299 assert_se(path_is_absolute(p)); 2300 free(p); 2301 2302- assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT); 2303+ assert_se(find_binary("xxxx-xxxx", local, &p) == -ENOENT); 2304 2305- assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT); 2306+ assert_se(find_binary("/some/dir/xxxx-xxxx", local, &p) == 2307+ (local ? -ENOENT : 0)); 2308 } 2309 2310 static void test_prefixes(void) { 2311@@ -244,7 +245,8 @@ static void test_strv_resolve(void) { 2312 2313 int main(int argc, char **argv) { 2314 test_path(); 2315- test_find_binary(argv[0]); 2316+ test_find_binary(argv[0], true); 2317+ test_find_binary(argv[0], false); 2318 test_prefixes(); 2319 test_path_join(); 2320 test_fsck_exists(); 2321diff --git a/src/udev/udevd.c b/src/udev/udevd.c 2322index 2e6c713..193702c 100644 2323--- a/src/udev/udevd.c 2324+++ b/src/udev/udevd.c 2325@@ -994,9 +994,9 @@ static void kernel_cmdline_options(struct udev *udev) { 2326 if (r < 0) 2327 log_warning("Invalid udev.exec-delay ignored: %s", opt + 16); 2328 } else if (startswith(opt, "udev.event-timeout=")) { 2329- r = safe_atou64(opt + 16, &arg_event_timeout_usec); 2330+ r = safe_atou64(opt + 19, &arg_event_timeout_usec); 2331 if (r < 0) { 2332- log_warning("Invalid udev.event-timeout ignored: %s", opt + 16); 2333+ log_warning("Invalid udev.event-timeout ignored: %s", opt + 19); 2334 break; 2335 } 2336 arg_event_timeout_usec *= USEC_PER_SEC; 2337diff --git a/units/console-getty.service.m4.in b/units/console-getty.service.m4.in 2338index 8ac51a4..cae9fb5 100644 2339--- a/units/console-getty.service.m4.in 2340+++ b/units/console-getty.service.m4.in 2341@@ -15,7 +15,6 @@ After=rc-local.service 2342 Before=getty.target 2343 2344 [Service] 2345-ExecStart=-/sbin/agetty --noclear --keep-baud console 115200,38400,9600 $TERM 2346 Type=idle 2347 Restart=always 2348 RestartSec=0 2349diff --git a/units/container-getty@.service.m4.in b/units/container-getty@.service.m4.in 2350index 4f7794b..6dfc2e9 100644 2351--- a/units/container-getty@.service.m4.in 2352+++ b/units/container-getty@.service.m4.in 2353@@ -14,9 +14,9 @@ After=rc-local.service 2354 )m4_dnl 2355 Before=getty.target 2356 IgnoreOnIsolate=yes 2357+ConditionPathExists=/dev/pts/%I 2358 2359 [Service] 2360-ExecStart=-/sbin/agetty --noclear --keep-baud pts/%I 115200,38400,9600 $TERM 2361 Type=idle 2362 Restart=always 2363 RestartSec=0 2364diff --git a/units/emergency.service.in b/units/emergency.service.in 2365index 18973e7..3a99660 100644 2366--- a/units/emergency.service.in 2367+++ b/units/emergency.service.in 2368@@ -16,7 +16,6 @@ Before=shutdown.target 2369 [Service] 2370 Environment=HOME=/root 2371 WorkingDirectory=/root 2372-ExecStartPre=-/bin/plymouth quit 2373 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.' 2374 ExecStart=-/bin/sh -c "/sbin/sulogin; @SYSTEMCTL@ --fail --no-block default" 2375 Type=idle 2376diff --git a/units/getty@.service.m4 b/units/getty@.service.m4 2377index 46164ab..f194a31 100644 2378--- a/units/getty@.service.m4 2379+++ b/units/getty@.service.m4 2380@@ -23,11 +23,12 @@ IgnoreOnIsolate=yes 2381 # On systems without virtual consoles, don't start any getty. Note 2382 # that serial gettys are covered by serial-getty@.service, not this 2383 # unit. 2384-ConditionPathExists=/dev/tty0 2385+ConditionPathExists=|/dev/tty0 2386+ConditionVirtualization=|lxc 2387+ConditionVirtualization=|lxc-libvirt 2388 2389 [Service] 2390 # the VT is cleared by TTYVTDisallocate 2391-ExecStart=-/sbin/agetty --noclear %I $TERM 2392 Type=idle 2393 Restart=always 2394 RestartSec=0 2395diff --git a/units/kmod-static-nodes.service.in b/units/kmod-static-nodes.service.in 2396index 0934a87..7e30c9e 100644 2397--- a/units/kmod-static-nodes.service.in 2398+++ b/units/kmod-static-nodes.service.in 2399@@ -10,7 +10,6 @@ Description=Create list of required static device nodes for the current kernel 2400 DefaultDependencies=no 2401 Before=sysinit.target systemd-tmpfiles-setup-dev.service 2402 ConditionCapability=CAP_SYS_MODULE 2403-ConditionPathExists=/lib/modules/%v/modules.devname 2404 2405 [Service] 2406 Type=oneshot 2407diff --git a/units/local-fs.target b/units/local-fs.target 2408index d2e5429..d26984b 100644 2409--- a/units/local-fs.target 2410+++ b/units/local-fs.target 2411@@ -13,3 +13,5 @@ Conflicts=shutdown.target 2412 After=local-fs-pre.target 2413 OnFailure=emergency.target 2414 OnFailureJobMode=replace-irreversibly 2415+ 2416+X-StopOnReconfiguration=yes 2417diff --git a/units/remote-fs.target b/units/remote-fs.target 2418index 43ffa5c..156a681 100644 2419--- a/units/remote-fs.target 2420+++ b/units/remote-fs.target 2421@@ -12,5 +12,7 @@ After=remote-fs-pre.target 2422 DefaultDependencies=no 2423 Conflicts=shutdown.target 2424 2425+X-StopOnReconfiguration=yes 2426+ 2427 [Install] 2428 WantedBy=multi-user.target 2429diff --git a/units/rescue.service.in b/units/rescue.service.in 2430index fc93f1e..3c87cf8 100644 2431--- a/units/rescue.service.in 2432+++ b/units/rescue.service.in 2433@@ -16,7 +16,6 @@ Before=shutdown.target 2434 [Service] 2435 Environment=HOME=/root 2436 WorkingDirectory=/root 2437-ExecStartPre=-/bin/plymouth quit 2438 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.' 2439 ExecStart=-/bin/sh -c "/sbin/sulogin; @SYSTEMCTL@ --fail --no-block default" 2440 Type=idle 2441diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4 2442index 4522d0d..96daa5c 100644 2443--- a/units/serial-getty@.service.m4 2444+++ b/units/serial-getty@.service.m4 2445@@ -22,7 +22,6 @@ Before=getty.target 2446 IgnoreOnIsolate=yes 2447 2448 [Service] 2449-ExecStart=-/sbin/agetty --keep-baud 115200,38400,9600 %I $TERM 2450 Type=idle 2451 Restart=always 2452 UtmpIdentifier=%I 2453diff --git a/units/sysinit.target b/units/sysinit.target 2454index ec33503..4ac47b9 100644 2455--- a/units/sysinit.target 2456+++ b/units/sysinit.target 2457@@ -9,5 +9,4 @@ 2458 Description=System Initialization 2459 Documentation=man:systemd.special(7) 2460 Conflicts=emergency.service emergency.target 2461-Wants=local-fs.target swap.target 2462-After=local-fs.target swap.target emergency.service emergency.target 2463+After=emergency.service emergency.target 2464diff --git a/units/systemd-backlight@.service.in b/units/systemd-backlight@.service.in 2465index ecf3de4..7e83446 100644 2466--- a/units/systemd-backlight@.service.in 2467+++ b/units/systemd-backlight@.service.in 2468@@ -19,3 +19,4 @@ Type=oneshot 2469 RemainAfterExit=yes 2470 ExecStart=@rootlibexecdir@/systemd-backlight load %i 2471 ExecStop=@rootlibexecdir@/systemd-backlight save %i 2472+X-RestartIfChanged=false 2473diff --git a/units/systemd-journal-flush.service.in b/units/systemd-journal-flush.service.in 2474index 699670b..ba22c6d 100644 2475--- a/units/systemd-journal-flush.service.in 2476+++ b/units/systemd-journal-flush.service.in 2477@@ -10,8 +10,10 @@ Description=Trigger Flushing of Journal to Persistent Storage 2478 Documentation=man:systemd-journald.service(8) man:journald.conf(5) 2479 DefaultDependencies=no 2480 Requires=systemd-journald.service 2481-After=systemd-journald.service local-fs.target remote-fs.target 2482+After=systemd-journald.service 2483+After=systemd-remount-fs.service 2484 Before=systemd-user-sessions.service systemd-tmpfiles-setup.service 2485+RequiresMountsFor=/var/log/journal 2486 2487 [Service] 2488 ExecStart=@rootbindir@/journalctl --flush 2489diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in 2490index 4de38fa..2f23c13 100644 2491--- a/units/systemd-journald.service.in 2492+++ b/units/systemd-journald.service.in 2493@@ -14,6 +14,7 @@ After=systemd-journald.socket systemd-journald-dev-log.socket syslog.socket 2494 Before=sysinit.target 2495 2496 [Service] 2497+Type=notify 2498 Sockets=systemd-journald.socket systemd-journald-dev-log.socket 2499 ExecStart=@rootlibexecdir@/systemd-journald 2500 Restart=always 2501@@ -26,3 +27,8 @@ WatchdogSec=1min 2502 # Increase the default a bit in order to allow many simultaneous 2503 # services being run since we keep one fd open per service. 2504 LimitNOFILE=16384 2505+ 2506+# Don't restart journald, since that causes services connected to 2507+# journald to stop logging (see 2508+# https://bugs.freedesktop.org/show_bug.cgi?id=56043). 2509+X-RestartIfChanged=no 2510diff --git a/units/systemd-random-seed.service.in b/units/systemd-random-seed.service.in 2511index b55844b..3ef9fc6 100644 2512--- a/units/systemd-random-seed.service.in 2513+++ b/units/systemd-random-seed.service.in 2514@@ -19,3 +19,4 @@ Type=oneshot 2515 RemainAfterExit=yes 2516 ExecStart=@rootlibexecdir@/systemd-random-seed load 2517 ExecStop=@rootlibexecdir@/systemd-random-seed save 2518+X-RestartIfChanged=false 2519diff --git a/units/systemd-rfkill@.service.in b/units/systemd-rfkill@.service.in 2520index 0e9851b..9f8fa0d 100644 2521--- a/units/systemd-rfkill@.service.in 2522+++ b/units/systemd-rfkill@.service.in 2523@@ -19,3 +19,4 @@ Type=oneshot 2524 RemainAfterExit=yes 2525 ExecStart=@rootlibexecdir@/systemd-rfkill load %I 2526 ExecStop=@rootlibexecdir@/systemd-rfkill save %I 2527+X-RestartIfChanged=false 2528diff --git a/units/systemd-tmpfiles-setup.service.in b/units/systemd-tmpfiles-setup.service.in 2529index e895cda..194146f 100644 2530--- a/units/systemd-tmpfiles-setup.service.in 2531+++ b/units/systemd-tmpfiles-setup.service.in 2532@@ -11,7 +11,7 @@ Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8) 2533 DefaultDependencies=no 2534 Conflicts=shutdown.target 2535 After=local-fs.target systemd-sysusers.service 2536-Before=sysinit.target shutdown.target 2537+Before=shutdown.target 2538 RefuseManualStop=yes 2539 2540 [Service] 2541diff --git a/units/systemd-update-utmp.service.in b/units/systemd-update-utmp.service.in 2542index 163eccd..7357c12 100644 2543--- a/units/systemd-update-utmp.service.in 2544+++ b/units/systemd-update-utmp.service.in 2545@@ -11,7 +11,7 @@ Documentation=man:systemd-update-utmp.service(8) man:utmp(5) 2546 DefaultDependencies=no 2547 RequiresMountsFor=/var/log/wtmp 2548 Conflicts=shutdown.target 2549-After=systemd-remount-fs.service systemd-tmpfiles-setup.service auditd.service 2550+After=systemd-remount-fs.service auditd.service 2551 Before=sysinit.target shutdown.target 2552 2553 [Service] 2554@@ -19,3 +19,4 @@ Type=oneshot 2555 RemainAfterExit=yes 2556 ExecStart=@rootlibexecdir@/systemd-update-utmp reboot 2557 ExecStop=@rootlibexecdir@/systemd-update-utmp shutdown 2558+X-RestartIfChanged=false 2559diff --git a/units/systemd-user-sessions.service.in b/units/systemd-user-sessions.service.in 2560index 0869e73..b6ed958 100644 2561--- a/units/systemd-user-sessions.service.in 2562+++ b/units/systemd-user-sessions.service.in 2563@@ -15,3 +15,6 @@ Type=oneshot 2564 RemainAfterExit=yes 2565 ExecStart=@rootlibexecdir@/systemd-user-sessions start 2566 ExecStop=@rootlibexecdir@/systemd-user-sessions stop 2567+ 2568+# Restart kills all active sessions. 2569+X-RestartIfChanged=no