389e654e03
This is a backport of systemd/systemd@e32886e. As noted by @ts468 in #9876, systemd-detect-virt will report KVM if we're running inside VirtualBox 5.x. Instead of just disabling the check, this essentially fixes systemd to be able to detect VirtualBox again. Tested this against nixos/tests/simple.nix (just to make sure systemd is still working) and nixos/tests/virtualbox.nix (all tests succeed). Thanks a lot to @ts468 for catching this and also to @domenkozar for testing various things concerning that bug. Fixes #9876. Signed-off-by: aszlig <aszlig@redmoonstudios.org>
2569 lines
98 KiB
Diff
2569 lines
98 KiB
Diff
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 <stdbool.h>
|
|
#include <sys/stat.h>
|
|
|
|
+#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..f3104d5 100644
|
|
--- a/src/shared/virt.c
|
|
+++ b/src/shared/virt.c
|
|
@@ -151,7 +151,7 @@ int detect_vm(const char **id) {
|
|
_cleanup_free_ char *domcap = NULL, *cpuinfo_contents = NULL;
|
|
static thread_local int cached_found = -1;
|
|
static thread_local const char *cached_id = NULL;
|
|
- const char *_id = NULL;
|
|
+ const char *_id = NULL, *_id_cpuid = NULL;
|
|
int r;
|
|
|
|
if (_likely_(cached_found >= 0)) {
|
|
@@ -197,10 +197,26 @@ int detect_vm(const char **id) {
|
|
|
|
/* this will set _id to "other" and return 0 for unknown hypervisors */
|
|
r = detect_vm_cpuid(&_id);
|
|
- if (r != 0)
|
|
+
|
|
+ /* finish when found a known hypervisor other than kvm */
|
|
+ if (r < 0 || (r > 0 && !streq(_id, "kvm")))
|
|
goto finish;
|
|
|
|
+ _id_cpuid = _id;
|
|
+
|
|
r = detect_vm_dmi(&_id);
|
|
+
|
|
+ /* kvm with and without Virtualbox */
|
|
+ if (streq_ptr(_id_cpuid, "kvm")) {
|
|
+ if (r > 0 && streq(_id, "oracle"))
|
|
+ goto finish;
|
|
+
|
|
+ _id = _id_cpuid;
|
|
+ r = 1;
|
|
+ goto finish;
|
|
+ }
|
|
+
|
|
+ /* information from dmi */
|
|
if (r != 0)
|
|
goto finish;
|
|
|
|
@@ -293,8 +309,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
|