mirror of
https://git.proxmox.com/git/systemd
synced 2025-08-05 18:20:27 +00:00
New upstream version 252.4
This commit is contained in:
parent
9fe6880f6c
commit
a68108222d
7
.github/workflows/mkosi.yml
vendored
7
.github/workflows/mkosi.yml
vendored
@ -54,6 +54,13 @@ jobs:
|
||||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
|
||||
- uses: systemd/mkosi@792cbc60eb2dc4a58d66bb3c212bf92f8d50f6ea
|
||||
|
||||
# FIXME: temporary workaround for a file conflict between systemd (C9S) and
|
||||
# systemd-boot (EPEL9). Drop this once systemd in C9S is updated to v252
|
||||
# (should be done by the end of 2022).
|
||||
- name: Fix C9S/EPEL9
|
||||
if: ${{ matrix.release == '9-stream' }}
|
||||
run: sudo sed -i '/add_packages/s/systemd-boot/systemd/g' /usr/local/lib/python3.10/dist-packages/mkosi/__init__.py
|
||||
|
||||
- name: Install
|
||||
run: sudo apt-get update && sudo apt-get install --no-install-recommends python3-pexpect python3-jinja2
|
||||
|
||||
|
19
.packit.yml
19
.packit.yml
@ -4,8 +4,8 @@
|
||||
# Docs: https://packit.dev/docs/
|
||||
|
||||
specfile_path: .packit_rpm/systemd.spec
|
||||
synced_files:
|
||||
- .packit.yaml
|
||||
files_to_sync:
|
||||
- .packit.yml
|
||||
- src: .packit_rpm/systemd.spec
|
||||
dest: systemd.spec
|
||||
upstream_package_name: systemd
|
||||
@ -32,14 +32,15 @@ actions:
|
||||
# [0] https://github.com/mesonbuild/meson/issues/7360
|
||||
# [1] https://github.com/systemd/systemd/pull/18908#issuecomment-792250110
|
||||
- 'sed -i "/^CONFIGURE_OPTS=(/a--werror" .packit_rpm/systemd.spec'
|
||||
# Ignore unpackages standalone binaries
|
||||
- "sed -i 's/assert False,.*/pass/' .packit_rpm/split-files.py"
|
||||
|
||||
jobs:
|
||||
- job: copr_build
|
||||
trigger: pull_request
|
||||
metadata:
|
||||
targets:
|
||||
- fedora-rawhide-aarch64
|
||||
- fedora-rawhide-i386
|
||||
- fedora-rawhide-ppc64le
|
||||
- fedora-rawhide-s390x
|
||||
- fedora-rawhide-x86_64
|
||||
targets:
|
||||
- fedora-rawhide-aarch64
|
||||
- fedora-rawhide-i386
|
||||
- fedora-rawhide-ppc64le
|
||||
- fedora-rawhide-s390x
|
||||
- fedora-rawhide-x86_64
|
||||
|
@ -268,6 +268,13 @@ All tools:
|
||||
it is either set to `system` or `user` depending on whether the NSS/PAM
|
||||
module is called by systemd in `--system` or `--user` mode.
|
||||
|
||||
* `$SYSTEMD_DEFAULT_MOUNT_RATE_LIMIT_BURST` — can be set to override the mount
|
||||
units burst rate limit for parsing `/proc/self/mountinfo`. On a system with
|
||||
few resources but many mounts the rate limit may be hit, which will cause the
|
||||
processing of mount units to stall. The burst limit may be adjusted when the
|
||||
default is not appropriate for a given system. Defaults to `5`, accepts
|
||||
positive integers.
|
||||
|
||||
`systemd-remount-fs`:
|
||||
|
||||
* `$SYSTEMD_REMOUNT_ROOT_RW=1` — if set and no entry for the root directory
|
||||
|
@ -13,7 +13,7 @@ Packages=
|
||||
fdisk
|
||||
iproute2
|
||||
isc-dhcp-server
|
||||
libbpf0
|
||||
libbpf1
|
||||
libfido2-1
|
||||
libglib2.0-0
|
||||
libgnutls30
|
||||
|
@ -3,23 +3,28 @@
|
||||
ACTION=="remove", GOTO="evdev_end"
|
||||
KERNEL!="event*", GOTO="evdev_end"
|
||||
|
||||
# skip later rules when we find something for this input device
|
||||
IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=evdev:", \
|
||||
IMPORT{builtin}="keyboard", GOTO="evdev_end"
|
||||
# Execute the match patterns below, from least-to-most specific.
|
||||
|
||||
# Device matching the modalias string (bustype, vendor, product, version, other properties)
|
||||
IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=evdev:",
|
||||
ENV{.HAVE_HWDB_PROPERTIES}="1"
|
||||
|
||||
# AT keyboard matching by the machine's DMI data
|
||||
DRIVERS=="atkbd", \
|
||||
IMPORT{builtin}="hwdb 'evdev:atkbd:$attr{[dmi/id]modalias}'", \
|
||||
IMPORT{builtin}="keyboard", GOTO="evdev_end"
|
||||
ENV{.HAVE_HWDB_PROPERTIES}="1"
|
||||
|
||||
# device matching the input device name + properties + the machine's DMI data
|
||||
KERNELS=="input*", \
|
||||
IMPORT{builtin}="hwdb 'evdev:name:$attr{name}:phys:$attr{phys}:ev:$attr{capabilities/ev}:$attr{[dmi/id]modalias}'", \
|
||||
IMPORT{builtin}="keyboard", GOTO="evdev_end"
|
||||
|
||||
# device matching the input device name and the machine's DMI data
|
||||
# Device matching the input device name and the machine's DMI data
|
||||
KERNELS=="input*", \
|
||||
IMPORT{builtin}="hwdb 'evdev:name:$attr{name}:$attr{[dmi/id]modalias}'", \
|
||||
IMPORT{builtin}="keyboard", GOTO="evdev_end"
|
||||
ENV{.HAVE_HWDB_PROPERTIES}="1"
|
||||
|
||||
# Device matching the input device name + properties + the machine's DMI data
|
||||
KERNELS=="input*", \
|
||||
IMPORT{builtin}="hwdb 'evdev:name:$attr{name}:phys:$attr{phys}:ev:$attr{capabilities/ev}:$attr{[dmi/id]modalias}'", \
|
||||
ENV{.HAVE_HWDB_PROPERTIES}="1"
|
||||
|
||||
ENV{.HAVE_HWDB_PROPERTIES}=="1", \
|
||||
IMPORT{builtin}="keyboard"
|
||||
|
||||
LABEL="evdev_end"
|
||||
|
@ -9,15 +9,15 @@ bool emoji_enabled(void) {
|
||||
static int cached_emoji_enabled = -1;
|
||||
|
||||
if (cached_emoji_enabled < 0) {
|
||||
int val;
|
||||
int val = getenv_bool("SYSTEMD_EMOJI");
|
||||
if (val >= 0)
|
||||
return (cached_emoji_enabled = val);
|
||||
|
||||
val = getenv_bool("SYSTEMD_EMOJI");
|
||||
if (val < 0)
|
||||
cached_emoji_enabled =
|
||||
is_locale_utf8() &&
|
||||
!STRPTR_IN_SET(getenv("TERM"), "dumb", "linux");
|
||||
else
|
||||
cached_emoji_enabled = val;
|
||||
const char *term = getenv("TERM");
|
||||
if (!term || STR_IN_SET(term, "dumb", "linux"))
|
||||
return (cached_emoji_enabled = false);
|
||||
|
||||
cached_emoji_enabled = is_locale_utf8();
|
||||
}
|
||||
|
||||
return cached_emoji_enabled;
|
||||
|
@ -91,7 +91,16 @@ struct iovec_wrapper *iovw_new(void);
|
||||
struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw);
|
||||
struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw);
|
||||
void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors);
|
||||
|
||||
int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len);
|
||||
static inline int iovw_consume(struct iovec_wrapper *iovw, void *data, size_t len) {
|
||||
/* Move data into iovw or free on error */
|
||||
int r = iovw_put(iovw, data, len);
|
||||
if (r < 0)
|
||||
free(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value);
|
||||
int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value);
|
||||
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new);
|
||||
|
@ -179,7 +179,7 @@ static int load_etc_machine_id(void) {
|
||||
int r;
|
||||
|
||||
r = sd_id128_get_machine(&arg_machine_id);
|
||||
if (IN_SET(r, -ENOENT, -ENOMEDIUM)) /* Not set or empty */
|
||||
if (IN_SET(r, -ENOENT, -ENOMEDIUM, -ENOPKG)) /* Not set or empty */
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get machine-id: %m");
|
||||
|
@ -4158,7 +4158,7 @@ int compare_job_priority(const void *a, const void *b) {
|
||||
int unit_cgroup_freezer_action(Unit *u, FreezerAction action) {
|
||||
_cleanup_free_ char *path = NULL;
|
||||
FreezerState target, kernel = _FREEZER_STATE_INVALID;
|
||||
int r;
|
||||
int r, ret;
|
||||
|
||||
assert(u);
|
||||
assert(IN_SET(action, FREEZER_FREEZE, FREEZER_THAW));
|
||||
@ -4166,9 +4166,23 @@ int unit_cgroup_freezer_action(Unit *u, FreezerAction action) {
|
||||
if (!cg_freezer_supported())
|
||||
return 0;
|
||||
|
||||
/* Ignore all requests to thaw init.scope or -.slice and reject all requests to freeze them */
|
||||
if (unit_has_name(u, SPECIAL_ROOT_SLICE) || unit_has_name(u, SPECIAL_INIT_SCOPE))
|
||||
return action == FREEZER_FREEZE ? -EPERM : 0;
|
||||
|
||||
if (!u->cgroup_realized)
|
||||
return -EBUSY;
|
||||
|
||||
if (action == FREEZER_THAW) {
|
||||
Unit *slice = UNIT_GET_SLICE(u);
|
||||
|
||||
if (slice) {
|
||||
r = unit_cgroup_freezer_action(slice, FREEZER_THAW);
|
||||
if (r < 0)
|
||||
return log_unit_error_errno(u, r, "Failed to thaw slice %s of unit: %m", slice->id);
|
||||
}
|
||||
}
|
||||
|
||||
target = action == FREEZER_FREEZE ? FREEZER_FROZEN : FREEZER_RUNNING;
|
||||
|
||||
r = unit_freezer_state_kernel(u, &kernel);
|
||||
@ -4177,8 +4191,11 @@ int unit_cgroup_freezer_action(Unit *u, FreezerAction action) {
|
||||
|
||||
if (target == kernel) {
|
||||
u->freezer_state = target;
|
||||
return 0;
|
||||
}
|
||||
if (action == FREEZER_FREEZE)
|
||||
return 0;
|
||||
ret = 0;
|
||||
} else
|
||||
ret = 1;
|
||||
|
||||
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.freeze", &path);
|
||||
if (r < 0)
|
||||
@ -4186,16 +4203,18 @@ int unit_cgroup_freezer_action(Unit *u, FreezerAction action) {
|
||||
|
||||
log_unit_debug(u, "%s unit.", action == FREEZER_FREEZE ? "Freezing" : "Thawing");
|
||||
|
||||
if (action == FREEZER_FREEZE)
|
||||
u->freezer_state = FREEZER_FREEZING;
|
||||
else
|
||||
u->freezer_state = FREEZER_THAWING;
|
||||
if (target != kernel) {
|
||||
if (action == FREEZER_FREEZE)
|
||||
u->freezer_state = FREEZER_FREEZING;
|
||||
else
|
||||
u->freezer_state = FREEZER_THAWING;
|
||||
}
|
||||
|
||||
r = write_string_file(path, one_zero(action == FREEZER_FREEZE), WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) {
|
||||
|
@ -782,14 +782,15 @@ static int bus_unit_method_freezer_generic(sd_bus_message *message, void *userda
|
||||
if (r == 0)
|
||||
reply_no_delay = true;
|
||||
|
||||
assert(!u->pending_freezer_message);
|
||||
if (u->pending_freezer_message) {
|
||||
bus_unit_send_pending_freezer_message(u, true);
|
||||
assert(!u->pending_freezer_message);
|
||||
}
|
||||
|
||||
r = sd_bus_message_new_method_return(message, &u->pending_freezer_message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
u->pending_freezer_message = sd_bus_message_ref(message);
|
||||
|
||||
if (reply_no_delay) {
|
||||
r = bus_unit_send_pending_freezer_message(u);
|
||||
r = bus_unit_send_pending_freezer_message(u, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -1661,7 +1662,8 @@ void bus_unit_send_pending_change_signal(Unit *u, bool including_new) {
|
||||
bus_unit_send_change_signal(u);
|
||||
}
|
||||
|
||||
int bus_unit_send_pending_freezer_message(Unit *u) {
|
||||
int bus_unit_send_pending_freezer_message(Unit *u, bool cancelled) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
@ -1669,7 +1671,18 @@ int bus_unit_send_pending_freezer_message(Unit *u) {
|
||||
if (!u->pending_freezer_message)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_send(NULL, u->pending_freezer_message, NULL);
|
||||
if (cancelled)
|
||||
r = sd_bus_message_new_method_error(
|
||||
u->pending_freezer_message,
|
||||
&reply,
|
||||
&SD_BUS_ERROR_MAKE_CONST(
|
||||
BUS_ERROR_FREEZE_CANCELLED, "Freeze operation aborted"));
|
||||
else
|
||||
r = sd_bus_message_new_method_return(u->pending_freezer_message, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_send(NULL, reply, NULL);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to send queued message, ignoring: %m");
|
||||
|
||||
|
@ -10,7 +10,7 @@ extern const sd_bus_vtable bus_unit_cgroup_vtable[];
|
||||
|
||||
void bus_unit_send_change_signal(Unit *u);
|
||||
void bus_unit_send_pending_change_signal(Unit *u, bool including_new);
|
||||
int bus_unit_send_pending_freezer_message(Unit *u);
|
||||
int bus_unit_send_pending_freezer_message(Unit *u, bool cancelled);
|
||||
void bus_unit_send_removed_signal(Unit *u);
|
||||
|
||||
int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
|
||||
|
@ -2662,6 +2662,7 @@ static int load_credential(
|
||||
assert(id);
|
||||
assert(path);
|
||||
assert(unit);
|
||||
assert(read_dfd >= 0 || read_dfd == AT_FDCWD);
|
||||
assert(write_dfd >= 0);
|
||||
assert(left);
|
||||
|
||||
@ -2888,7 +2889,7 @@ static int acquire_credentials(
|
||||
lc->path,
|
||||
lc->encrypted,
|
||||
unit,
|
||||
-1,
|
||||
AT_FDCWD,
|
||||
dfd,
|
||||
uid,
|
||||
ownership_ok,
|
||||
|
@ -1908,6 +1908,7 @@ static void mount_enumerate(Manager *m) {
|
||||
mnt_init_debug(0);
|
||||
|
||||
if (!m->mount_monitor) {
|
||||
unsigned mount_rate_limit_burst = 5;
|
||||
int fd;
|
||||
|
||||
m->mount_monitor = mnt_new_monitor();
|
||||
@ -1947,7 +1948,15 @@ static void mount_enumerate(Manager *m) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = sd_event_source_set_ratelimit(m->mount_event_source, 1 * USEC_PER_SEC, 5);
|
||||
/* Let users override the default (5 in 1s), as it stalls the boot sequence on busy systems. */
|
||||
const char *e = secure_getenv("SYSTEMD_DEFAULT_MOUNT_RATE_LIMIT_BURST");
|
||||
if (e) {
|
||||
r = safe_atou(e, &mount_rate_limit_burst);
|
||||
if (r < 0)
|
||||
log_debug("Invalid value in $SYSTEMD_DEFAULT_MOUNT_RATE_LIMIT_BURST, ignoring: %s", e);
|
||||
}
|
||||
|
||||
r = sd_event_source_set_ratelimit(m->mount_event_source, 1 * USEC_PER_SEC, mount_rate_limit_burst);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to enable rate limit for mount events: %m");
|
||||
goto fail;
|
||||
|
129
src/core/unit.c
129
src/core/unit.c
@ -937,29 +937,17 @@ static int unit_reserve_dependencies(Unit *u, Unit *other) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unit_maybe_warn_about_dependency(
|
||||
Unit *u,
|
||||
const char *other_id,
|
||||
UnitDependency dependency) {
|
||||
|
||||
assert(u);
|
||||
|
||||
static bool unit_should_warn_about_dependency(UnitDependency dependency) {
|
||||
/* Only warn about some unit types */
|
||||
if (!IN_SET(dependency,
|
||||
UNIT_CONFLICTS,
|
||||
UNIT_CONFLICTED_BY,
|
||||
UNIT_BEFORE,
|
||||
UNIT_AFTER,
|
||||
UNIT_ON_SUCCESS,
|
||||
UNIT_ON_FAILURE,
|
||||
UNIT_TRIGGERS,
|
||||
UNIT_TRIGGERED_BY))
|
||||
return;
|
||||
|
||||
if (streq_ptr(u->id, other_id))
|
||||
log_unit_warning(u, "Dependency %s=%s dropped", unit_dependency_to_string(dependency), u->id);
|
||||
else
|
||||
log_unit_warning(u, "Dependency %s=%s dropped, merged into %s", unit_dependency_to_string(dependency), strna(other_id), u->id);
|
||||
return IN_SET(dependency,
|
||||
UNIT_CONFLICTS,
|
||||
UNIT_CONFLICTED_BY,
|
||||
UNIT_BEFORE,
|
||||
UNIT_AFTER,
|
||||
UNIT_ON_SUCCESS,
|
||||
UNIT_ON_FAILURE,
|
||||
UNIT_TRIGGERS,
|
||||
UNIT_TRIGGERED_BY);
|
||||
}
|
||||
|
||||
static int unit_per_dependency_type_hashmap_update(
|
||||
@ -1044,11 +1032,10 @@ static int unit_add_dependency_hashmap(
|
||||
return unit_per_dependency_type_hashmap_update(per_type, other, origin_mask, destination_mask);
|
||||
}
|
||||
|
||||
static void unit_merge_dependencies(
|
||||
Unit *u,
|
||||
Unit *other) {
|
||||
|
||||
int r;
|
||||
static void unit_merge_dependencies(Unit *u, Unit *other) {
|
||||
Hashmap *deps;
|
||||
void *dt; /* Actually of type UnitDependency, except that we don't bother casting it here,
|
||||
* since the hashmaps all want it as void pointer. */
|
||||
|
||||
assert(u);
|
||||
assert(other);
|
||||
@ -1056,18 +1043,29 @@ static void unit_merge_dependencies(
|
||||
if (u == other)
|
||||
return;
|
||||
|
||||
/* First, remove dependency to other. */
|
||||
HASHMAP_FOREACH_KEY(deps, dt, u->dependencies) {
|
||||
if (hashmap_remove(deps, other) && unit_should_warn_about_dependency(UNIT_DEPENDENCY_FROM_PTR(dt)))
|
||||
log_unit_warning(u, "Dependency %s=%s is dropped, as %s is merged into %s.",
|
||||
unit_dependency_to_string(UNIT_DEPENDENCY_FROM_PTR(dt)),
|
||||
other->id, other->id, u->id);
|
||||
|
||||
if (hashmap_isempty(deps))
|
||||
hashmap_free(hashmap_remove(u->dependencies, dt));
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
_cleanup_(hashmap_freep) Hashmap *other_deps = NULL;
|
||||
UnitDependencyInfo di_back;
|
||||
Unit *back;
|
||||
void *dt; /* Actually of type UnitDependency, except that we don't bother casting it here,
|
||||
* since the hashmaps all want it as void pointer. */
|
||||
|
||||
/* Let's focus on one dependency type at a time, that 'other' has defined. */
|
||||
other_deps = hashmap_steal_first_key_and_value(other->dependencies, &dt);
|
||||
if (!other_deps)
|
||||
break; /* done! */
|
||||
|
||||
deps = hashmap_get(u->dependencies, dt);
|
||||
|
||||
/* Now iterate through all dependencies of this dependency type, of 'other'. We refer to the
|
||||
* referenced units as 'back'. */
|
||||
HASHMAP_FOREACH_KEY(di_back.data, back, other_deps) {
|
||||
@ -1077,7 +1075,12 @@ static void unit_merge_dependencies(
|
||||
if (back == u) {
|
||||
/* This is a dependency pointing back to the unit we want to merge with?
|
||||
* Suppress it (but warn) */
|
||||
unit_maybe_warn_about_dependency(u, other->id, UNIT_DEPENDENCY_FROM_PTR(dt));
|
||||
if (unit_should_warn_about_dependency(UNIT_DEPENDENCY_FROM_PTR(dt)))
|
||||
log_unit_warning(u, "Dependency %s=%s in %s is dropped, as %s is merged into %s.",
|
||||
unit_dependency_to_string(UNIT_DEPENDENCY_FROM_PTR(dt)),
|
||||
u->id, other->id, other->id, u->id);
|
||||
|
||||
hashmap_remove(other_deps, back);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1096,41 +1099,21 @@ static void unit_merge_dependencies(
|
||||
di_move.origin_mask,
|
||||
di_move.destination_mask) >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now all references towards 'other' of the current type 'dt' are corrected to point to
|
||||
* 'u'. Lets's now move the deps of type 'dt' from 'other' to 'u'. First, let's try to move
|
||||
* them per type wholesale. */
|
||||
r = hashmap_put(u->dependencies, dt, other_deps);
|
||||
if (r == -EEXIST) {
|
||||
Hashmap *deps;
|
||||
|
||||
/* The target unit already has dependencies of this type, let's then merge this individually. */
|
||||
|
||||
assert_se(deps = hashmap_get(u->dependencies, dt));
|
||||
|
||||
for (;;) {
|
||||
UnitDependencyInfo di_move;
|
||||
|
||||
/* Get first dep */
|
||||
di_move.data = hashmap_steal_first_key_and_value(other_deps, (void**) &back);
|
||||
if (!di_move.data)
|
||||
break; /* done */
|
||||
if (back == u) {
|
||||
/* Would point back to us, ignore */
|
||||
unit_maybe_warn_about_dependency(u, other->id, UNIT_DEPENDENCY_FROM_PTR(dt));
|
||||
continue;
|
||||
}
|
||||
|
||||
assert_se(unit_per_dependency_type_hashmap_update(deps, back, di_move.origin_mask, di_move.destination_mask) >= 0);
|
||||
}
|
||||
} else {
|
||||
assert_se(r >= 0);
|
||||
TAKE_PTR(other_deps);
|
||||
|
||||
if (hashmap_remove(other_deps, u))
|
||||
unit_maybe_warn_about_dependency(u, other->id, UNIT_DEPENDENCY_FROM_PTR(dt));
|
||||
if (deps)
|
||||
assert_se(unit_per_dependency_type_hashmap_update(
|
||||
deps,
|
||||
back,
|
||||
di_back.origin_mask,
|
||||
di_back.destination_mask) >= 0);
|
||||
}
|
||||
|
||||
/* Now all references towards 'other' of the current type 'dt' are corrected to point to 'u'.
|
||||
* Lets's now move the deps of type 'dt' from 'other' to 'u'. If the unit does not have
|
||||
* dependencies of this type, let's move them per type wholesale. */
|
||||
if (!deps)
|
||||
assert_se(hashmap_put(u->dependencies, dt, TAKE_PTR(other_deps)) >= 0);
|
||||
}
|
||||
|
||||
other->dependencies = hashmap_free(other->dependencies);
|
||||
@ -1176,11 +1159,6 @@ int unit_merge(Unit *u, Unit *other) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Merge names */
|
||||
r = unit_merge_names(u, other);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Redirect all references */
|
||||
while (other->refs_by_target)
|
||||
unit_ref_set(other->refs_by_target, other->refs_by_target->source, u);
|
||||
@ -1188,6 +1166,11 @@ int unit_merge(Unit *u, Unit *other) {
|
||||
/* Merge dependencies */
|
||||
unit_merge_dependencies(u, other);
|
||||
|
||||
/* Merge names. It is better to do that after merging deps, otherwise the log message contains n/a. */
|
||||
r = unit_merge_names(u, other);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
other->load_state = UNIT_MERGED;
|
||||
other->merged_into = u;
|
||||
|
||||
@ -3066,7 +3049,6 @@ int unit_add_dependency(
|
||||
[UNIT_IN_SLICE] = UNIT_SLICE_OF,
|
||||
[UNIT_SLICE_OF] = UNIT_IN_SLICE,
|
||||
};
|
||||
Unit *original_u = u, *original_other = other;
|
||||
UnitDependencyAtom a;
|
||||
int r;
|
||||
|
||||
@ -3085,7 +3067,9 @@ int unit_add_dependency(
|
||||
|
||||
/* We won't allow dependencies on ourselves. We will not consider them an error however. */
|
||||
if (u == other) {
|
||||
unit_maybe_warn_about_dependency(original_u, original_other->id, d);
|
||||
if (unit_should_warn_about_dependency(d))
|
||||
log_unit_warning(u, "Dependency %s=%s is dropped.",
|
||||
unit_dependency_to_string(d), u->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -5811,7 +5795,7 @@ void unit_frozen(Unit *u) {
|
||||
|
||||
u->freezer_state = FREEZER_FROZEN;
|
||||
|
||||
bus_unit_send_pending_freezer_message(u);
|
||||
bus_unit_send_pending_freezer_message(u, false);
|
||||
}
|
||||
|
||||
void unit_thawed(Unit *u) {
|
||||
@ -5819,7 +5803,7 @@ void unit_thawed(Unit *u) {
|
||||
|
||||
u->freezer_state = FREEZER_RUNNING;
|
||||
|
||||
bus_unit_send_pending_freezer_message(u);
|
||||
bus_unit_send_pending_freezer_message(u, false);
|
||||
}
|
||||
|
||||
static int unit_freezer_action(Unit *u, FreezerAction action) {
|
||||
@ -5844,7 +5828,8 @@ static int unit_freezer_action(Unit *u, FreezerAction action) {
|
||||
if (s != UNIT_ACTIVE)
|
||||
return -EHOSTDOWN;
|
||||
|
||||
if (IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_THAWING))
|
||||
if ((IN_SET(u->freezer_state, FREEZER_FREEZING, FREEZER_THAWING) && action == FREEZER_FREEZE) ||
|
||||
(u->freezer_state == FREEZER_THAWING && action == FREEZER_THAW))
|
||||
return -EALREADY;
|
||||
|
||||
r = method(u);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -106,24 +107,27 @@ enum {
|
||||
|
||||
META_EXE = _META_MANDATORY_MAX,
|
||||
META_UNIT,
|
||||
META_PROC_AUXV,
|
||||
_META_MAX
|
||||
};
|
||||
|
||||
static const char * const meta_field_names[_META_MAX] = {
|
||||
[META_ARGV_PID] = "COREDUMP_PID=",
|
||||
[META_ARGV_UID] = "COREDUMP_UID=",
|
||||
[META_ARGV_GID] = "COREDUMP_GID=",
|
||||
[META_ARGV_SIGNAL] = "COREDUMP_SIGNAL=",
|
||||
[META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
|
||||
[META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
|
||||
[META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
|
||||
[META_COMM] = "COREDUMP_COMM=",
|
||||
[META_EXE] = "COREDUMP_EXE=",
|
||||
[META_UNIT] = "COREDUMP_UNIT=",
|
||||
[META_ARGV_PID] = "COREDUMP_PID=",
|
||||
[META_ARGV_UID] = "COREDUMP_UID=",
|
||||
[META_ARGV_GID] = "COREDUMP_GID=",
|
||||
[META_ARGV_SIGNAL] = "COREDUMP_SIGNAL=",
|
||||
[META_ARGV_TIMESTAMP] = "COREDUMP_TIMESTAMP=",
|
||||
[META_ARGV_RLIMIT] = "COREDUMP_RLIMIT=",
|
||||
[META_ARGV_HOSTNAME] = "COREDUMP_HOSTNAME=",
|
||||
[META_COMM] = "COREDUMP_COMM=",
|
||||
[META_EXE] = "COREDUMP_EXE=",
|
||||
[META_UNIT] = "COREDUMP_UNIT=",
|
||||
[META_PROC_AUXV] = "COREDUMP_PROC_AUXV=",
|
||||
};
|
||||
|
||||
typedef struct Context {
|
||||
const char *meta[_META_MAX];
|
||||
size_t meta_size[_META_MAX];
|
||||
pid_t pid;
|
||||
bool is_pid1;
|
||||
bool is_journald;
|
||||
@ -138,9 +142,9 @@ typedef enum CoredumpStorage {
|
||||
} CoredumpStorage;
|
||||
|
||||
static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
|
||||
[COREDUMP_STORAGE_NONE] = "none",
|
||||
[COREDUMP_STORAGE_NONE] = "none",
|
||||
[COREDUMP_STORAGE_EXTERNAL] = "external",
|
||||
[COREDUMP_STORAGE_JOURNAL] = "journal",
|
||||
[COREDUMP_STORAGE_JOURNAL] = "journal",
|
||||
};
|
||||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
|
||||
@ -156,13 +160,13 @@ static uint64_t arg_max_use = UINT64_MAX;
|
||||
|
||||
static int parse_config(void) {
|
||||
static const ConfigTableItem items[] = {
|
||||
{ "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
|
||||
{ "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
|
||||
{ "Coredump", "ProcessSizeMax", config_parse_iec_uint64, 0, &arg_process_size_max },
|
||||
{ "Coredump", "ExternalSizeMax", config_parse_iec_uint64_infinity, 0, &arg_external_size_max },
|
||||
{ "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
|
||||
{ "Coredump", "KeepFree", config_parse_iec_uint64, 0, &arg_keep_free },
|
||||
{ "Coredump", "MaxUse", config_parse_iec_uint64, 0, &arg_max_use },
|
||||
{ "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
|
||||
{ "Coredump", "Compress", config_parse_bool, 0, &arg_compress },
|
||||
{ "Coredump", "ProcessSizeMax", config_parse_iec_uint64, 0, &arg_process_size_max },
|
||||
{ "Coredump", "ExternalSizeMax", config_parse_iec_uint64_infinity, 0, &arg_external_size_max },
|
||||
{ "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
|
||||
{ "Coredump", "KeepFree", config_parse_iec_uint64, 0, &arg_keep_free },
|
||||
{ "Coredump", "MaxUse", config_parse_iec_uint64, 0, &arg_max_use },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -185,13 +189,16 @@ static uint64_t storage_size_max(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fix_acl(int fd, uid_t uid) {
|
||||
static int fix_acl(int fd, uid_t uid, bool allow_user) {
|
||||
assert(fd >= 0);
|
||||
assert(uid_is_valid(uid));
|
||||
|
||||
#if HAVE_ACL
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(uid_is_valid(uid));
|
||||
/* We don't allow users to read coredumps if the uid or capabilities were changed. */
|
||||
if (!allow_user)
|
||||
return 0;
|
||||
|
||||
if (uid_is_system(uid) || uid_is_dynamic(uid) || uid == UID_NOBODY)
|
||||
return 0;
|
||||
@ -208,15 +215,15 @@ static int fix_acl(int fd, uid_t uid) {
|
||||
static int fix_xattr(int fd, const Context *context) {
|
||||
|
||||
static const char * const xattrs[_META_MAX] = {
|
||||
[META_ARGV_PID] = "user.coredump.pid",
|
||||
[META_ARGV_UID] = "user.coredump.uid",
|
||||
[META_ARGV_GID] = "user.coredump.gid",
|
||||
[META_ARGV_SIGNAL] = "user.coredump.signal",
|
||||
[META_ARGV_TIMESTAMP] = "user.coredump.timestamp",
|
||||
[META_ARGV_RLIMIT] = "user.coredump.rlimit",
|
||||
[META_ARGV_HOSTNAME] = "user.coredump.hostname",
|
||||
[META_COMM] = "user.coredump.comm",
|
||||
[META_EXE] = "user.coredump.exe",
|
||||
[META_ARGV_PID] = "user.coredump.pid",
|
||||
[META_ARGV_UID] = "user.coredump.uid",
|
||||
[META_ARGV_GID] = "user.coredump.gid",
|
||||
[META_ARGV_SIGNAL] = "user.coredump.signal",
|
||||
[META_ARGV_TIMESTAMP] = "user.coredump.timestamp",
|
||||
[META_ARGV_RLIMIT] = "user.coredump.rlimit",
|
||||
[META_ARGV_HOSTNAME] = "user.coredump.hostname",
|
||||
[META_COMM] = "user.coredump.comm",
|
||||
[META_EXE] = "user.coredump.exe",
|
||||
};
|
||||
|
||||
int r = 0;
|
||||
@ -251,7 +258,8 @@ static int fix_permissions(
|
||||
const char *filename,
|
||||
const char *target,
|
||||
const Context *context,
|
||||
uid_t uid) {
|
||||
uid_t uid,
|
||||
bool allow_user) {
|
||||
|
||||
int r;
|
||||
|
||||
@ -261,7 +269,7 @@ static int fix_permissions(
|
||||
|
||||
/* Ignore errors on these */
|
||||
(void) fchmod(fd, 0640);
|
||||
(void) fix_acl(fd, uid);
|
||||
(void) fix_acl(fd, uid, allow_user);
|
||||
(void) fix_xattr(fd, context);
|
||||
|
||||
r = fsync_full(fd);
|
||||
@ -331,6 +339,153 @@ static int make_filename(const Context *context, char **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_auxv64(
|
||||
const uint64_t *auxv,
|
||||
size_t size_bytes,
|
||||
int *at_secure,
|
||||
uid_t *uid,
|
||||
uid_t *euid,
|
||||
gid_t *gid,
|
||||
gid_t *egid) {
|
||||
|
||||
assert(auxv || size_bytes == 0);
|
||||
|
||||
if (size_bytes % (2 * sizeof(uint64_t)) != 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EIO), "Incomplete auxv structure (%zu bytes).", size_bytes);
|
||||
|
||||
size_t words = size_bytes / sizeof(uint64_t);
|
||||
|
||||
/* Note that we set output variables even on error. */
|
||||
|
||||
for (size_t i = 0; i + 1 < words; i += 2)
|
||||
switch (auxv[i]) {
|
||||
case AT_SECURE:
|
||||
*at_secure = auxv[i + 1] != 0;
|
||||
break;
|
||||
case AT_UID:
|
||||
*uid = auxv[i + 1];
|
||||
break;
|
||||
case AT_EUID:
|
||||
*euid = auxv[i + 1];
|
||||
break;
|
||||
case AT_GID:
|
||||
*gid = auxv[i + 1];
|
||||
break;
|
||||
case AT_EGID:
|
||||
*egid = auxv[i + 1];
|
||||
break;
|
||||
case AT_NULL:
|
||||
if (auxv[i + 1] != 0)
|
||||
goto error;
|
||||
return 0;
|
||||
}
|
||||
error:
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(ENODATA),
|
||||
"AT_NULL terminator not found, cannot parse auxv structure.");
|
||||
}
|
||||
|
||||
static int parse_auxv32(
|
||||
const uint32_t *auxv,
|
||||
size_t size_bytes,
|
||||
int *at_secure,
|
||||
uid_t *uid,
|
||||
uid_t *euid,
|
||||
gid_t *gid,
|
||||
gid_t *egid) {
|
||||
|
||||
assert(auxv || size_bytes == 0);
|
||||
|
||||
size_t words = size_bytes / sizeof(uint32_t);
|
||||
|
||||
if (size_bytes % (2 * sizeof(uint32_t)) != 0)
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(EIO), "Incomplete auxv structure (%zu bytes).", size_bytes);
|
||||
|
||||
/* Note that we set output variables even on error. */
|
||||
|
||||
for (size_t i = 0; i + 1 < words; i += 2)
|
||||
switch (auxv[i]) {
|
||||
case AT_SECURE:
|
||||
*at_secure = auxv[i + 1] != 0;
|
||||
break;
|
||||
case AT_UID:
|
||||
*uid = auxv[i + 1];
|
||||
break;
|
||||
case AT_EUID:
|
||||
*euid = auxv[i + 1];
|
||||
break;
|
||||
case AT_GID:
|
||||
*gid = auxv[i + 1];
|
||||
break;
|
||||
case AT_EGID:
|
||||
*egid = auxv[i + 1];
|
||||
break;
|
||||
case AT_NULL:
|
||||
if (auxv[i + 1] != 0)
|
||||
goto error;
|
||||
return 0;
|
||||
}
|
||||
error:
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(ENODATA),
|
||||
"AT_NULL terminator not found, cannot parse auxv structure.");
|
||||
}
|
||||
|
||||
static int grant_user_access(int core_fd, const Context *context) {
|
||||
int at_secure = -1;
|
||||
uid_t uid = UID_INVALID, euid = UID_INVALID;
|
||||
uid_t gid = GID_INVALID, egid = GID_INVALID;
|
||||
int r;
|
||||
|
||||
assert(core_fd >= 0);
|
||||
assert(context);
|
||||
|
||||
if (!context->meta[META_PROC_AUXV])
|
||||
return log_warning_errno(SYNTHETIC_ERRNO(ENODATA), "No auxv data, not adjusting permissions.");
|
||||
|
||||
uint8_t elf[EI_NIDENT];
|
||||
errno = 0;
|
||||
if (pread(core_fd, &elf, sizeof(elf), 0) != sizeof(elf))
|
||||
return log_warning_errno(errno_or_else(EIO),
|
||||
"Failed to pread from coredump fd: %s", STRERROR_OR_EOF(errno));
|
||||
|
||||
if (elf[EI_MAG0] != ELFMAG0 ||
|
||||
elf[EI_MAG1] != ELFMAG1 ||
|
||||
elf[EI_MAG2] != ELFMAG2 ||
|
||||
elf[EI_MAG3] != ELFMAG3 ||
|
||||
elf[EI_VERSION] != EV_CURRENT)
|
||||
return log_info_errno(SYNTHETIC_ERRNO(EUCLEAN),
|
||||
"Core file does not have ELF header, not adjusting permissions.");
|
||||
if (!IN_SET(elf[EI_CLASS], ELFCLASS32, ELFCLASS64) ||
|
||||
!IN_SET(elf[EI_DATA], ELFDATA2LSB, ELFDATA2MSB))
|
||||
return log_info_errno(SYNTHETIC_ERRNO(EUCLEAN),
|
||||
"Core file has strange ELF class, not adjusting permissions.");
|
||||
|
||||
if ((elf[EI_DATA] == ELFDATA2LSB) != (__BYTE_ORDER == __LITTLE_ENDIAN))
|
||||
return log_info_errno(SYNTHETIC_ERRNO(EUCLEAN),
|
||||
"Core file has non-native endianness, not adjusting permissions.");
|
||||
|
||||
if (elf[EI_CLASS] == ELFCLASS64)
|
||||
r = parse_auxv64((const uint64_t*) context->meta[META_PROC_AUXV],
|
||||
context->meta_size[META_PROC_AUXV],
|
||||
&at_secure, &uid, &euid, &gid, &egid);
|
||||
else
|
||||
r = parse_auxv32((const uint32_t*) context->meta[META_PROC_AUXV],
|
||||
context->meta_size[META_PROC_AUXV],
|
||||
&at_secure, &uid, &euid, &gid, &egid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* We allow access if we got all the data and at_secure is not set and
|
||||
* the uid/gid matches euid/egid. */
|
||||
bool ret =
|
||||
at_secure == 0 &&
|
||||
uid != UID_INVALID && euid != UID_INVALID && uid == euid &&
|
||||
gid != GID_INVALID && egid != GID_INVALID && gid == egid;
|
||||
log_debug("Will %s access (uid="UID_FMT " euid="UID_FMT " gid="GID_FMT " egid="GID_FMT " at_secure=%s)",
|
||||
ret ? "permit" : "restrict",
|
||||
uid, euid, gid, egid, yes_no(at_secure));
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int save_external_coredump(
|
||||
const Context *context,
|
||||
int input_fd,
|
||||
@ -453,6 +608,8 @@ static int save_external_coredump(
|
||||
context->meta[META_ARGV_PID], context->meta[META_COMM]);
|
||||
truncated = r == 1;
|
||||
|
||||
bool allow_user = grant_user_access(fd, context) > 0;
|
||||
|
||||
#if HAVE_COMPRESSION
|
||||
if (arg_compress) {
|
||||
_cleanup_(unlink_and_freep) char *tmp_compressed = NULL;
|
||||
@ -490,7 +647,7 @@ static int save_external_coredump(
|
||||
uncompressed_size += partial_uncompressed_size;
|
||||
}
|
||||
|
||||
r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid);
|
||||
r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid, allow_user);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -517,7 +674,7 @@ static int save_external_coredump(
|
||||
"SIZE_LIMIT=%"PRIu64, max_size,
|
||||
"MESSAGE_ID=" SD_MESSAGE_TRUNCATED_CORE_STR);
|
||||
|
||||
r = fix_permissions(fd, tmp, fn, context, uid);
|
||||
r = fix_permissions(fd, tmp, fn, context, uid, allow_user);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to fix permissions and finalize coredump %s into %s: %m", coredump_tmpfile_name(tmp), fn);
|
||||
|
||||
@ -765,7 +922,7 @@ static int change_uid_gid(const Context *context) {
|
||||
}
|
||||
|
||||
static int submit_coredump(
|
||||
Context *context,
|
||||
const Context *context,
|
||||
struct iovec_wrapper *iovw,
|
||||
int input_fd) {
|
||||
|
||||
@ -944,16 +1101,15 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) {
|
||||
struct iovec *iovec = iovw->iovec + n;
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(meta_field_names); i++) {
|
||||
char *p;
|
||||
|
||||
/* Note that these strings are NUL terminated, because we made sure that a
|
||||
* trailing NUL byte is in the buffer, though not included in the iov_len
|
||||
* count (see process_socket() and gather_pid_metadata_*()) */
|
||||
assert(((char*) iovec->iov_base)[iovec->iov_len] == 0);
|
||||
|
||||
p = startswith(iovec->iov_base, meta_field_names[i]);
|
||||
const char *p = startswith(iovec->iov_base, meta_field_names[i]);
|
||||
if (p) {
|
||||
context->meta[i] = p;
|
||||
context->meta_size[i] = iovec->iov_len - strlen(meta_field_names[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1190,6 +1346,7 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
|
||||
uid_t owner_uid;
|
||||
pid_t pid;
|
||||
char *t;
|
||||
size_t size;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
@ -1254,13 +1411,26 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) {
|
||||
(void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_LIMITS=", t);
|
||||
|
||||
p = procfs_file_alloca(pid, "cgroup");
|
||||
if (read_full_virtual_file(p, &t, NULL) >=0)
|
||||
if (read_full_virtual_file(p, &t, NULL) >= 0)
|
||||
(void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_CGROUP=", t);
|
||||
|
||||
p = procfs_file_alloca(pid, "mountinfo");
|
||||
if (read_full_virtual_file(p, &t, NULL) >=0)
|
||||
if (read_full_virtual_file(p, &t, NULL) >= 0)
|
||||
(void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_MOUNTINFO=", t);
|
||||
|
||||
/* We attach /proc/auxv here. ELF coredumps also contain a note for this (NT_AUXV), see elf(5). */
|
||||
p = procfs_file_alloca(pid, "auxv");
|
||||
if (read_full_virtual_file(p, &t, &size) >= 0) {
|
||||
char *buf = malloc(strlen("COREDUMP_PROC_AUXV=") + size + 1);
|
||||
if (buf) {
|
||||
/* Add a dummy terminator to make save_context() happy. */
|
||||
*((uint8_t*) mempcpy(stpcpy(buf, "COREDUMP_PROC_AUXV="), t, size)) = '\0';
|
||||
(void) iovw_consume(iovw, buf, size + strlen("COREDUMP_PROC_AUXV="));
|
||||
}
|
||||
|
||||
free(t);
|
||||
}
|
||||
|
||||
if (get_process_cwd(pid, &t) >= 0)
|
||||
(void) iovw_put_string_field_free(iovw, "COREDUMP_CWD=", t);
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "compress.h"
|
||||
#include "def.h"
|
||||
#include "dissect-image.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-table.h"
|
||||
#include "fs-util.h"
|
||||
@ -790,9 +791,10 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
|
||||
r = json_parse(pkgmeta_json, 0, &v, NULL, NULL);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "json_parse on %s failed, ignoring: %m", pkgmeta_json);
|
||||
else {
|
||||
if (r < 0) {
|
||||
_cleanup_free_ char *esc = cescape(pkgmeta_json);
|
||||
log_warning_errno(r, "json_parse on \"%s\" failed, ignoring: %m", strnull(esc));
|
||||
} else {
|
||||
const char *module_name;
|
||||
JsonVariant *module_json;
|
||||
|
||||
|
@ -110,6 +110,10 @@ static inline bool ascii_isdigit(sd_char a) {
|
||||
return a >= '0' && a <= '9';
|
||||
}
|
||||
|
||||
static inline bool ascii_ishex(sd_char a) {
|
||||
return ascii_isdigit(a) || (a >= 'a' && a <= 'f') || (a >= 'A' && a <= 'F');
|
||||
}
|
||||
|
||||
static inline bool ascii_isalpha(sd_char a) {
|
||||
/* A pure ASCII, locale independent version of isalpha() */
|
||||
return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
|
||||
|
@ -31,6 +31,7 @@
|
||||
#define BUS_ERROR_NOTHING_TO_CLEAN "org.freedesktop.systemd1.NothingToClean"
|
||||
#define BUS_ERROR_UNIT_BUSY "org.freedesktop.systemd1.UnitBusy"
|
||||
#define BUS_ERROR_UNIT_INACTIVE "org.freedesktop.systemd1.UnitInactive"
|
||||
#define BUS_ERROR_FREEZE_CANCELLED "org.freedesktop.systemd1.FreezeCancelled"
|
||||
|
||||
#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine"
|
||||
#define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage"
|
||||
|
@ -2333,9 +2333,14 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr,
|
||||
sysattr, value, ret_value ? "" : ", ignoring");
|
||||
if (ret_value)
|
||||
return r;
|
||||
} else if (ret_value)
|
||||
*ret_value = TAKE_PTR(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ret_value)
|
||||
*ret_value = value;
|
||||
|
||||
TAKE_PTR(value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -13,59 +13,48 @@
|
||||
#include "sync-util.h"
|
||||
|
||||
bool id128_is_valid(const char *s) {
|
||||
size_t i, l;
|
||||
size_t l;
|
||||
|
||||
assert(s);
|
||||
|
||||
l = strlen(s);
|
||||
if (l == 32) {
|
||||
|
||||
if (l == SD_ID128_STRING_MAX - 1)
|
||||
/* Plain formatted 128bit hex string */
|
||||
return in_charset(s, HEXDIGITS);
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
char c = s[i];
|
||||
|
||||
if (!ascii_isdigit(c) &&
|
||||
!(c >= 'a' && c <= 'f') &&
|
||||
!(c >= 'A' && c <= 'F'))
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (l == 36) {
|
||||
|
||||
if (l == SD_ID128_UUID_STRING_MAX - 1) {
|
||||
/* Formatted UUID */
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
for (size_t i = 0; i < l; i++) {
|
||||
char c = s[i];
|
||||
|
||||
if (IN_SET(i, 8, 13, 18, 23)) {
|
||||
if (c != '-')
|
||||
return false;
|
||||
} else {
|
||||
if (!ascii_isdigit(c) &&
|
||||
!(c >= 'a' && c <= 'f') &&
|
||||
!(c >= 'A' && c <= 'F'))
|
||||
return false;
|
||||
}
|
||||
} else if (!ascii_ishex(c))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
|
||||
char buffer[36 + 2];
|
||||
int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret) {
|
||||
char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
|
||||
ssize_t l;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(f < _ID128_FORMAT_MAX);
|
||||
|
||||
/* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
|
||||
* optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
|
||||
* aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
|
||||
* accept". */
|
||||
* accept".
|
||||
*
|
||||
* This returns the following:
|
||||
* -ENOMEDIUM: an empty string,
|
||||
* -ENOPKG: "uninitialized" or "uninitialized\n",
|
||||
* -EINVAL: other invalid strings. */
|
||||
|
||||
l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
|
||||
if (l < 0)
|
||||
@ -75,33 +64,32 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
|
||||
|
||||
switch (l) {
|
||||
|
||||
case 13:
|
||||
case 14:
|
||||
/* Treat an "uninitialized" id file like an empty one */
|
||||
return f == ID128_PLAIN_OR_UNINIT && strneq(buffer, "uninitialized\n", l) ? -ENOMEDIUM : -EINVAL;
|
||||
case STRLEN("uninitialized"):
|
||||
case STRLEN("uninitialized\n"):
|
||||
return strneq(buffer, "uninitialized\n", l) ? -ENOPKG : -EINVAL;
|
||||
|
||||
case 33: /* plain UUID with trailing newline */
|
||||
if (buffer[32] != '\n')
|
||||
case SD_ID128_STRING_MAX: /* plain UUID with trailing newline */
|
||||
if (buffer[SD_ID128_STRING_MAX-1] != '\n')
|
||||
return -EINVAL;
|
||||
|
||||
_fallthrough_;
|
||||
case 32: /* plain UUID without trailing newline */
|
||||
if (f == ID128_UUID)
|
||||
case SD_ID128_STRING_MAX-1: /* plain UUID without trailing newline */
|
||||
if (!FLAGS_SET(f, ID128_FORMAT_PLAIN))
|
||||
return -EINVAL;
|
||||
|
||||
buffer[32] = 0;
|
||||
buffer[SD_ID128_STRING_MAX-1] = 0;
|
||||
break;
|
||||
|
||||
case 37: /* RFC UUID with trailing newline */
|
||||
if (buffer[36] != '\n')
|
||||
case SD_ID128_UUID_STRING_MAX: /* RFC UUID with trailing newline */
|
||||
if (buffer[SD_ID128_UUID_STRING_MAX-1] != '\n')
|
||||
return -EINVAL;
|
||||
|
||||
_fallthrough_;
|
||||
case 36: /* RFC UUID without trailing newline */
|
||||
if (IN_SET(f, ID128_PLAIN, ID128_PLAIN_OR_UNINIT))
|
||||
case SD_ID128_UUID_STRING_MAX-1: /* RFC UUID without trailing newline */
|
||||
if (!FLAGS_SET(f, ID128_FORMAT_UUID))
|
||||
return -EINVAL;
|
||||
|
||||
buffer[36] = 0;
|
||||
buffer[SD_ID128_UUID_STRING_MAX-1] = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -111,7 +99,7 @@ int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
|
||||
return sd_id128_from_string(buffer, ret);
|
||||
}
|
||||
|
||||
int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
|
||||
int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
@ -121,24 +109,23 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
|
||||
return id128_read_fd(fd, f, ret);
|
||||
}
|
||||
|
||||
int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
|
||||
char buffer[36 + 2];
|
||||
int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id, bool do_sync) {
|
||||
char buffer[SD_ID128_UUID_STRING_MAX + 1]; /* +1 is for trailing newline */
|
||||
size_t sz;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(f < _ID128_FORMAT_MAX);
|
||||
assert(IN_SET((f & ID128_FORMAT_ANY), ID128_FORMAT_PLAIN, ID128_FORMAT_UUID));
|
||||
|
||||
if (f != ID128_UUID) {
|
||||
if (FLAGS_SET(f, ID128_FORMAT_PLAIN)) {
|
||||
assert_se(sd_id128_to_string(id, buffer));
|
||||
buffer[SD_ID128_STRING_MAX - 1] = '\n';
|
||||
sz = SD_ID128_STRING_MAX;
|
||||
} else {
|
||||
assert_se(sd_id128_to_uuid_string(id, buffer));
|
||||
buffer[SD_ID128_UUID_STRING_MAX - 1] = '\n';
|
||||
sz = SD_ID128_UUID_STRING_MAX;
|
||||
}
|
||||
|
||||
buffer[sz - 1] = '\n';
|
||||
r = loop_write(fd, buffer, sz, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -152,7 +139,7 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
|
||||
int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id, bool do_sync) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444);
|
||||
@ -194,9 +181,9 @@ int id128_get_product(sd_id128_t *ret) {
|
||||
/* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
|
||||
* particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
|
||||
|
||||
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &uuid);
|
||||
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_FORMAT_UUID, &uuid);
|
||||
if (r == -ENOENT)
|
||||
r = id128_read("/proc/device-tree/vm,uuid", ID128_UUID, &uuid);
|
||||
r = id128_read("/proc/device-tree/vm,uuid", ID128_FORMAT_UUID, &uuid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -10,22 +10,17 @@
|
||||
|
||||
bool id128_is_valid(const char *s) _pure_;
|
||||
|
||||
typedef enum Id128Format {
|
||||
ID128_ANY,
|
||||
ID128_PLAIN, /* formatted as 32 hex chars as-is */
|
||||
ID128_PLAIN_OR_UNINIT, /* formatted as 32 hex chars as-is; allow special "uninitialized"
|
||||
* value when reading from file (id128_read() and id128_read_fd()).
|
||||
*
|
||||
* This format should be used when reading a machine-id file. */
|
||||
ID128_UUID, /* formatted as 36 character uuid string */
|
||||
_ID128_FORMAT_MAX,
|
||||
} Id128Format;
|
||||
typedef enum Id128FormatFlag {
|
||||
ID128_FORMAT_PLAIN = 1 << 0, /* formatted as 32 hex chars as-is */
|
||||
ID128_FORMAT_UUID = 1 << 1, /* formatted as 36 character uuid string */
|
||||
ID128_FORMAT_ANY = ID128_FORMAT_PLAIN | ID128_FORMAT_UUID,
|
||||
} Id128FormatFlag;
|
||||
|
||||
int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret);
|
||||
int id128_read(const char *p, Id128Format f, sd_id128_t *ret);
|
||||
int id128_read_fd(int fd, Id128FormatFlag f, sd_id128_t *ret);
|
||||
int id128_read(const char *p, Id128FormatFlag f, sd_id128_t *ret);
|
||||
|
||||
int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync);
|
||||
int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync);
|
||||
int id128_write_fd(int fd, Id128FormatFlag f, sd_id128_t id, bool do_sync);
|
||||
int id128_write(const char *p, Id128FormatFlag f, sd_id128_t id, bool do_sync);
|
||||
|
||||
void id128_hash_func(const sd_id128_t *p, struct siphash *state);
|
||||
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_;
|
||||
|
@ -19,14 +19,17 @@
|
||||
#include "util.h"
|
||||
|
||||
_public_ char *sd_id128_to_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD_ID128_STRING_MAX]) {
|
||||
size_t k = 0;
|
||||
|
||||
assert_return(s, NULL);
|
||||
|
||||
for (size_t n = 0; n < 16; n++) {
|
||||
s[n*2] = hexchar(id.bytes[n] >> 4);
|
||||
s[n*2+1] = hexchar(id.bytes[n] & 0xF);
|
||||
for (size_t n = 0; n < sizeof(sd_id128_t); n++) {
|
||||
s[k++] = hexchar(id.bytes[n] >> 4);
|
||||
s[k++] = hexchar(id.bytes[n] & 0xF);
|
||||
}
|
||||
|
||||
s[SD_ID128_STRING_MAX-1] = 0;
|
||||
assert(k == SD_ID128_STRING_MAX - 1);
|
||||
s[k] = 0;
|
||||
|
||||
return s;
|
||||
}
|
||||
@ -38,7 +41,7 @@ _public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD
|
||||
|
||||
/* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
|
||||
|
||||
for (size_t n = 0; n < 16; n++) {
|
||||
for (size_t n = 0; n < sizeof(sd_id128_t); n++) {
|
||||
|
||||
if (IN_SET(n, 4, 6, 8, 10))
|
||||
s[k++] = '-';
|
||||
@ -53,14 +56,14 @@ _public_ char *sd_id128_to_uuid_string(sd_id128_t id, char s[_SD_ARRAY_STATIC SD
|
||||
return s;
|
||||
}
|
||||
|
||||
_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
|
||||
unsigned n, i;
|
||||
_public_ int sd_id128_from_string(const char *s, sd_id128_t *ret) {
|
||||
size_t n, i;
|
||||
sd_id128_t t;
|
||||
bool is_guid = false;
|
||||
|
||||
assert_return(s, -EINVAL);
|
||||
|
||||
for (n = 0, i = 0; n < 16;) {
|
||||
for (n = 0, i = 0; n < sizeof(sd_id128_t);) {
|
||||
int a, b;
|
||||
|
||||
if (s[i] == '-') {
|
||||
@ -90,7 +93,7 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) {
|
||||
t.bytes[n++] = (a << 4) | b;
|
||||
}
|
||||
|
||||
if (i != (is_guid ? 36 : 32))
|
||||
if (i != (is_guid ? SD_ID128_UUID_STRING_MAX : SD_ID128_STRING_MAX) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (s[i] != 0)
|
||||
@ -124,7 +127,7 @@ _public_ int sd_id128_get_machine(sd_id128_t *ret) {
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (sd_id128_is_null(saved_machine_id)) {
|
||||
r = id128_read("/etc/machine-id", ID128_PLAIN, &saved_machine_id);
|
||||
r = id128_read("/etc/machine-id", ID128_FORMAT_PLAIN, &saved_machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -143,7 +146,7 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (sd_id128_is_null(saved_boot_id)) {
|
||||
r = id128_read("/proc/sys/kernel/random/boot_id", ID128_UUID, &saved_boot_id);
|
||||
r = id128_read("/proc/sys/kernel/random/boot_id", ID128_FORMAT_UUID, &saved_boot_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
@ -370,7 +370,7 @@ static int journal_file_refresh_header(JournalFile *f) {
|
||||
assert(f->header);
|
||||
|
||||
r = sd_id128_get_machine(&f->header->machine_id);
|
||||
if (IN_SET(r, -ENOENT, -ENOMEDIUM))
|
||||
if (IN_SET(r, -ENOENT, -ENOMEDIUM, -ENOPKG))
|
||||
/* We don't have a machine-id, let's continue without */
|
||||
zero(f->header->machine_id);
|
||||
else if (r < 0)
|
||||
|
@ -164,7 +164,7 @@ static int run(int argc, char *argv[]) {
|
||||
return r;
|
||||
|
||||
etc_machine_id = prefix_roota(arg_root, "/etc/machine-id");
|
||||
r = id128_read(etc_machine_id, ID128_PLAIN, &id);
|
||||
r = id128_read(etc_machine_id, ID128_FORMAT_PLAIN, &id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read machine ID back: %m");
|
||||
} else {
|
||||
|
@ -2195,7 +2195,7 @@ static int setup_boot_id(void) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate random boot id: %m");
|
||||
|
||||
r = id128_write(path, ID128_UUID, rnd, false);
|
||||
r = id128_write(path, ID128_FORMAT_UUID, rnd, false);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write boot id: %m");
|
||||
|
||||
@ -2821,9 +2821,9 @@ static int setup_machine_id(const char *directory) {
|
||||
|
||||
etc_machine_id = prefix_roota(directory, "/etc/machine-id");
|
||||
|
||||
r = id128_read(etc_machine_id, ID128_PLAIN_OR_UNINIT, &id);
|
||||
r = id128_read(etc_machine_id, ID128_FORMAT_PLAIN, &id);
|
||||
if (r < 0) {
|
||||
if (!IN_SET(r, -ENOENT, -ENOMEDIUM)) /* If the file is missing or empty, we don't mind */
|
||||
if (!IN_SET(r, -ENOENT, -ENOMEDIUM, -ENOPKG)) /* If the file is missing, empty, or uninitialized, we don't mind */
|
||||
return log_error_errno(r, "Failed to read machine ID from container image: %m");
|
||||
|
||||
if (sd_id128_is_null(arg_uuid)) {
|
||||
|
@ -4473,8 +4473,8 @@ static int context_read_seed(Context *context, const char *root) {
|
||||
else if (fd < 0)
|
||||
return log_error_errno(fd, "Failed to determine machine ID of image: %m");
|
||||
else {
|
||||
r = id128_read_fd(fd, ID128_PLAIN_OR_UNINIT, &context->seed);
|
||||
if (r == -ENOMEDIUM)
|
||||
r = id128_read_fd(fd, ID128_FORMAT_PLAIN, &context->seed);
|
||||
if (IN_SET(r, -ENOMEDIUM, -ENOPKG))
|
||||
log_info("No machine ID set, using randomized partition UUIDs.");
|
||||
else if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse machine ID of image: %m");
|
||||
|
@ -1768,36 +1768,30 @@ int dns_resource_record_get_cname_target(DnsResourceKey *key, DnsResourceRecord
|
||||
return 0;
|
||||
}
|
||||
|
||||
DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
|
||||
DnsTxtItem *n;
|
||||
DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *first) {
|
||||
LIST_FOREACH(items, i, first)
|
||||
free(i);
|
||||
|
||||
if (!i)
|
||||
return NULL;
|
||||
|
||||
n = i->items_next;
|
||||
|
||||
free(i);
|
||||
return dns_txt_item_free_all(n);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
|
||||
DnsTxtItem *bb = b;
|
||||
|
||||
if (a == b)
|
||||
return true;
|
||||
|
||||
if (!a != !b)
|
||||
return false;
|
||||
LIST_FOREACH(items, aa, a) {
|
||||
if (!bb)
|
||||
return false;
|
||||
|
||||
if (!a)
|
||||
return true;
|
||||
if (memcmp_nn(aa->data, aa->length, bb->data, bb->length) != 0)
|
||||
return false;
|
||||
|
||||
if (a->length != b->length)
|
||||
return false;
|
||||
bb = bb->items_next;
|
||||
}
|
||||
|
||||
if (memcmp(a->data, b->data, a->length) != 0)
|
||||
return false;
|
||||
|
||||
return dns_txt_item_equal(a->items_next, b->items_next);
|
||||
return !bb;
|
||||
}
|
||||
|
||||
DnsTxtItem *dns_txt_item_copy(DnsTxtItem *first) {
|
||||
|
@ -1153,7 +1153,7 @@ int image_read_metadata(Image *i) {
|
||||
if (fd < 0)
|
||||
log_debug_errno(errno, "Failed to open %s: %m", path);
|
||||
else {
|
||||
r = id128_read_fd(fd, ID128_PLAIN, &machine_id);
|
||||
r = id128_read_fd(fd, ID128_FORMAT_PLAIN, &machine_id);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Image %s contains invalid machine ID.", i->name);
|
||||
}
|
||||
|
@ -74,9 +74,15 @@
|
||||
/* how many times to wait for the device nodes to appear */
|
||||
#define N_DEVICE_NODE_LIST_ATTEMPTS 10
|
||||
|
||||
int probe_filesystem_full(int fd, const char *path, char **ret_fstype) {
|
||||
int probe_filesystem_full(
|
||||
int fd,
|
||||
const char *path,
|
||||
uint64_t offset,
|
||||
uint64_t size,
|
||||
char **ret_fstype) {
|
||||
|
||||
/* Try to find device content type and return it in *ret_fstype. If nothing is found,
|
||||
* 0/NULL will be returned. -EUCLEAN will be returned for ambiguous results, and an
|
||||
* 0/NULL will be returned. -EUCLEAN will be returned for ambiguous results, and a
|
||||
* different error otherwise. */
|
||||
|
||||
#if HAVE_BLKID
|
||||
@ -105,12 +111,19 @@ int probe_filesystem_full(int fd, const char *path, char **ret_fstype) {
|
||||
path = path_by_fd;
|
||||
}
|
||||
|
||||
if (size == 0) /* empty size? nothing found! */
|
||||
goto not_found;
|
||||
|
||||
b = blkid_new_probe();
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_set_device(b, fd, 0, 0);
|
||||
r = blkid_probe_set_device(
|
||||
b,
|
||||
fd,
|
||||
offset,
|
||||
size == UINT64_MAX ? 0 : size); /* when blkid sees size=0 it understands "everything". We prefer using UINT64_MAX for that */
|
||||
if (r != 0)
|
||||
return errno_or_else(ENOMEM);
|
||||
|
||||
@ -152,7 +165,7 @@ not_found:
|
||||
}
|
||||
|
||||
#if HAVE_BLKID
|
||||
static int dissected_image_probe_filesystem(DissectedImage *m) {
|
||||
static int dissected_image_probe_filesystems(DissectedImage *m, int fd) {
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@ -165,9 +178,14 @@ static int dissected_image_probe_filesystem(DissectedImage *m) {
|
||||
if (!p->found)
|
||||
continue;
|
||||
|
||||
if (!p->fstype && p->mount_node_fd >= 0 && !p->decrypted_node) {
|
||||
r = probe_filesystem_full(p->mount_node_fd, p->node, &p->fstype);
|
||||
if (r < 0 && r != -EUCLEAN)
|
||||
if (!p->fstype) {
|
||||
/* If we have an fd referring to the partition block device, use that. Otherwise go
|
||||
* via the whole block device or backing regular file, and read via offset. */
|
||||
if (p->mount_node_fd >= 0)
|
||||
r = probe_filesystem_full(p->mount_node_fd, p->node, 0, UINT64_MAX, &p->fstype);
|
||||
else
|
||||
r = probe_filesystem_full(fd, p->node, p->offset, p->size, &p->fstype);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -1217,6 +1235,10 @@ static int dissect_image(
|
||||
}
|
||||
}
|
||||
|
||||
r = dissected_image_probe_filesystems(m, fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@ -2339,7 +2361,7 @@ int dissected_image_decrypt(
|
||||
}
|
||||
|
||||
if (!p->decrypted_fstype && p->mount_node_fd >= 0 && p->decrypted_node) {
|
||||
r = probe_filesystem_full(p->mount_node_fd, p->decrypted_node, &p->decrypted_fstype);
|
||||
r = probe_filesystem_full(p->mount_node_fd, p->decrypted_node, 0, UINT64_MAX, &p->decrypted_fstype);
|
||||
if (r < 0 && r != -EUCLEAN)
|
||||
return r;
|
||||
}
|
||||
@ -3041,10 +3063,6 @@ int dissect_loop_device(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dissected_image_probe_filesystem(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(m);
|
||||
return 0;
|
||||
#else
|
||||
|
@ -271,9 +271,9 @@ MountOptions* mount_options_free_all(MountOptions *options);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
|
||||
const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator);
|
||||
|
||||
int probe_filesystem_full(int fd, const char *path, char **ret_fstype);
|
||||
int probe_filesystem_full(int fd, const char *path, uint64_t offset, uint64_t size, char **ret_fstype);
|
||||
static inline int probe_filesystem(const char *path, char **ret_fstype) {
|
||||
return probe_filesystem_full(-1, path, ret_fstype);
|
||||
return probe_filesystem_full(-1, path, 0, UINT64_MAX, ret_fstype);
|
||||
}
|
||||
int dissect_image_file(
|
||||
const char *path,
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "dlfcn-util.h"
|
||||
#include "elf-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "fileio.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
@ -397,8 +398,10 @@ static int parse_package_metadata(const char *name, JsonVariant *id_json, Elf *e
|
||||
}
|
||||
|
||||
r = json_parse(payload, 0, &v, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "json_parse on %s failed: %m", payload);
|
||||
if (r < 0) {
|
||||
_cleanup_free_ char *esc = cescape(payload);
|
||||
return log_error_errno(r, "json_parse on \"%s\" failed: %m", strnull(esc));
|
||||
}
|
||||
|
||||
/* If we have a build-id, merge it in the same JSON object so that it appears all
|
||||
* nicely together in the logs/metadata. */
|
||||
|
@ -38,7 +38,7 @@ static int generate_machine_id(const char *root, sd_id128_t *ret) {
|
||||
dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id");
|
||||
fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
|
||||
if (fd >= 0) {
|
||||
if (id128_read_fd(fd, ID128_PLAIN, ret) >= 0) {
|
||||
if (id128_read_fd(fd, ID128_FORMAT_PLAIN, ret) >= 0) {
|
||||
log_info("Initializing machine ID from D-Bus machine ID.");
|
||||
return 0;
|
||||
}
|
||||
@ -123,7 +123,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
|
||||
if (sd_id128_is_null(machine_id)) {
|
||||
|
||||
/* Try to read any existing machine ID */
|
||||
if (id128_read_fd(fd, ID128_PLAIN, ret) >= 0)
|
||||
if (id128_read_fd(fd, ID128_FORMAT_PLAIN, ret) >= 0)
|
||||
return 0;
|
||||
|
||||
/* Hmm, so, the id currently stored is not useful, then let's generate one */
|
||||
@ -152,7 +152,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to sync %s: %m", etc_machine_id);
|
||||
} else {
|
||||
r = id128_write_fd(fd, ID128_PLAIN, machine_id, true);
|
||||
r = id128_write_fd(fd, ID128_FORMAT_PLAIN, machine_id, true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write %s: %m", etc_machine_id);
|
||||
else
|
||||
@ -168,7 +168,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_
|
||||
run_machine_id = prefix_roota(root, "/run/machine-id");
|
||||
|
||||
RUN_WITH_UMASK(0022)
|
||||
r = id128_write(run_machine_id, ID128_PLAIN, machine_id, false);
|
||||
r = id128_write(run_machine_id, ID128_FORMAT_PLAIN, machine_id, false);
|
||||
if (r < 0) {
|
||||
(void) unlink(run_machine_id);
|
||||
return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
|
||||
@ -240,7 +240,7 @@ int machine_id_commit(const char *root) {
|
||||
"%s is not on a temporary file system.",
|
||||
etc_machine_id);
|
||||
|
||||
r = id128_read_fd(fd, ID128_PLAIN, &id);
|
||||
r = id128_read_fd(fd, ID128_FORMAT_PLAIN, &id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "We didn't find a valid machine ID in %s: %m", etc_machine_id);
|
||||
|
||||
@ -261,7 +261,7 @@ int machine_id_commit(const char *root) {
|
||||
return r;
|
||||
|
||||
/* Update a persistent version of etc_machine_id */
|
||||
r = id128_write(etc_machine_id, ID128_PLAIN, id, true);
|
||||
r = id128_write(etc_machine_id, ID128_FORMAT_PLAIN, id, true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Cannot write %s. This is mandatory to get a persistent machine ID: %m", etc_machine_id);
|
||||
|
||||
|
@ -195,7 +195,7 @@ int specifier_machine_id(char specifier, const void *data, const char *root, con
|
||||
/* Translate error for missing os-release file to EUNATCH. */
|
||||
return fd == -ENOENT ? -EUNATCH : fd;
|
||||
|
||||
r = id128_read_fd(fd, ID128_PLAIN, &id);
|
||||
r = id128_read_fd(fd, ID128_FORMAT_PLAIN, &id);
|
||||
} else
|
||||
r = sd_id128_get_machine(&id);
|
||||
if (r < 0)
|
||||
|
@ -374,7 +374,7 @@ static int freeze_thaw_user_slice(const char **method) {
|
||||
}
|
||||
|
||||
static int execute_s2h(const SleepConfig *sleep_config) {
|
||||
_unused_ _cleanup_(freeze_thaw_user_slice) const char *auto_method_thaw = NULL;
|
||||
_unused_ _cleanup_(freeze_thaw_user_slice) const char *auto_method_thaw = "ThawUnit";
|
||||
int r, k;
|
||||
|
||||
assert(sleep_config);
|
||||
@ -382,8 +382,6 @@ static int execute_s2h(const SleepConfig *sleep_config) {
|
||||
r = freeze_thaw_user_slice(&(const char*) { "FreezeUnit" });
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to freeze unit user.slice, ignoring: %m");
|
||||
else
|
||||
auto_method_thaw = "ThawUnit"; /* from now on we want automatic thawing */;
|
||||
|
||||
r = check_wakeup_type();
|
||||
if (r < 0)
|
||||
|
@ -250,7 +250,7 @@ TEST(condition_test_host) {
|
||||
int r;
|
||||
|
||||
r = sd_id128_get_machine(&id);
|
||||
if (IN_SET(r, -ENOENT, -ENOMEDIUM))
|
||||
if (IN_SET(r, -ENOENT, -ENOMEDIUM, -ENOPKG))
|
||||
return (void) log_tests_skipped("/etc/machine-id missing");
|
||||
assert_se(r >= 0);
|
||||
|
||||
|
@ -326,7 +326,7 @@ TEST(chase_symlinks) {
|
||||
assert_se(fd >= 0);
|
||||
safe_close(pfd);
|
||||
|
||||
assert_se(id128_read_fd(fd, ID128_PLAIN, &a) >= 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &a) >= 0);
|
||||
assert_se(sd_id128_get_machine(&b) >= 0);
|
||||
assert_se(sd_id128_equal(a, b));
|
||||
}
|
||||
|
@ -86,17 +86,17 @@ TEST(id128) {
|
||||
|
||||
/* First, write as UUID */
|
||||
assert_se(sd_id128_randomize(&id) >= 0);
|
||||
assert_se(id128_write_fd(fd, ID128_UUID, id, false) >= 0);
|
||||
assert_se(id128_write_fd(fd, ID128_FORMAT_UUID, id, false) >= 0);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) == -EINVAL);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) >= 0);
|
||||
assert_se(sd_id128_equal(id, id2));
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_ANY, &id2) >= 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, &id2) >= 0);
|
||||
assert_se(sd_id128_equal(id, id2));
|
||||
|
||||
/* Second, write as plain */
|
||||
@ -104,17 +104,17 @@ TEST(id128) {
|
||||
assert_se(ftruncate(fd, 0) >= 0);
|
||||
|
||||
assert_se(sd_id128_randomize(&id) >= 0);
|
||||
assert_se(id128_write_fd(fd, ID128_PLAIN, id, false) >= 0);
|
||||
assert_se(id128_write_fd(fd, ID128_FORMAT_PLAIN, id, false) >= 0);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_UUID, &id2) == -EINVAL);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) == -EINVAL);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) >= 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) >= 0);
|
||||
assert_se(sd_id128_equal(id, id2));
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_ANY, &id2) >= 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, &id2) >= 0);
|
||||
assert_se(sd_id128_equal(id, id2));
|
||||
|
||||
/* Third, write plain without trailing newline */
|
||||
@ -125,13 +125,13 @@ TEST(id128) {
|
||||
assert_se(write(fd, sd_id128_to_string(id, t), 32) == 32);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_UUID, &id2) == -EINVAL);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) == -EINVAL);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) >= 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) >= 0);
|
||||
assert_se(sd_id128_equal(id, id2));
|
||||
|
||||
/* Third, write UUID without trailing newline */
|
||||
/* Fourth, write UUID without trailing newline */
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(ftruncate(fd, 0) >= 0);
|
||||
|
||||
@ -139,12 +139,37 @@ TEST(id128) {
|
||||
assert_se(write(fd, sd_id128_to_uuid_string(id, q), 36) == 36);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_PLAIN, &id2) == -EINVAL);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_UUID, &id2) >= 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_UUID, &id2) >= 0);
|
||||
assert_se(sd_id128_equal(id, id2));
|
||||
|
||||
/* Fifth, tests for "uninitialized" */
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(ftruncate(fd, 0) >= 0);
|
||||
assert_se(write(fd, "uninitialized", STRLEN("uninitialized")) == STRLEN("uninitialized"));
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -ENOPKG);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(ftruncate(fd, 0) >= 0);
|
||||
assert_se(write(fd, "uninitialized\n", STRLEN("uninitialized\n")) == STRLEN("uninitialized\n"));
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -ENOPKG);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(ftruncate(fd, 0) >= 0);
|
||||
assert_se(write(fd, "uninitialized\nfoo", STRLEN("uninitialized\nfoo")) == STRLEN("uninitialized\nfoo"));
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -EINVAL);
|
||||
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(ftruncate(fd, 0) >= 0);
|
||||
assert_se(write(fd, "uninit", STRLEN("uninit")) == STRLEN("uninit"));
|
||||
assert_se(lseek(fd, 0, SEEK_SET) == 0);
|
||||
assert_se(id128_read_fd(fd, ID128_FORMAT_ANY, NULL) == -EINVAL);
|
||||
|
||||
if (sd_booted() > 0 && access("/etc/machine-id", F_OK) >= 0) {
|
||||
assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id) >= 0);
|
||||
assert_se(sd_id128_get_machine_app_specific(SD_ID128_MAKE(f0,3d,aa,eb,1c,33,4b,43,a7,32,17,29,44,bf,77,2e), &id2) >= 0);
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <linux/loop.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "capability-util.h"
|
||||
@ -44,6 +46,15 @@ static void verify_dissected_image(DissectedImage *dissected) {
|
||||
assert_se(dissected->partitions[PARTITION_HOME].node);
|
||||
}
|
||||
|
||||
static void verify_dissected_image_harder(DissectedImage *dissected) {
|
||||
verify_dissected_image(dissected);
|
||||
|
||||
assert_se(streq(dissected->partitions[PARTITION_ESP].fstype, "vfat"));
|
||||
assert_se(streq(dissected->partitions[PARTITION_XBOOTLDR].fstype, "vfat"));
|
||||
assert_se(streq(dissected->partitions[PARTITION_ROOT].fstype, "ext4"));
|
||||
assert_se(streq(dissected->partitions[PARTITION_HOME].fstype, "ext4"));
|
||||
}
|
||||
|
||||
static void* thread_func(void *ptr) {
|
||||
int fd = PTR_TO_FD(ptr);
|
||||
int r;
|
||||
@ -246,8 +257,23 @@ static int run(int argc, char *argv[]) {
|
||||
assert_se(make_filesystem(dissected->partitions[PARTITION_HOME].node, "ext4", "home", NULL, id, true) >= 0);
|
||||
|
||||
dissected = dissected_image_unref(dissected);
|
||||
|
||||
/* We created the file systems now via the per-partition block devices. But the dissection code might
|
||||
* probe them via the whole block device. These block devices have separate buffer caches though,
|
||||
* hence what was written via the partition device might not appear on the whole block device
|
||||
* yet. Let's hence explicitly flush the whole block device, so that the read-back definitely
|
||||
* works. */
|
||||
assert_se(ioctl(loop->fd, BLKFLSBUF, 0) >= 0);
|
||||
|
||||
/* Try to read once, without pinning or adding partitions, i.e. by only accessing the whole block
|
||||
* device. */
|
||||
assert_se(dissect_loop_device(loop, NULL, NULL, 0, &dissected) >= 0);
|
||||
verify_dissected_image_harder(dissected);
|
||||
dissected = dissected_image_unref(dissected);
|
||||
|
||||
/* Now go via the loopback device after all, but this time add/pin, because now we want to mount it. */
|
||||
assert_se(dissect_loop_device(loop, NULL, NULL, DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected) >= 0);
|
||||
verify_dissected_image(dissected);
|
||||
verify_dissected_image_harder(dissected);
|
||||
|
||||
assert_se(mkdtemp_malloc(NULL, &mounted) >= 0);
|
||||
|
||||
|
@ -119,8 +119,10 @@ static int manager_send_request(Manager *m) {
|
||||
m->event_timeout = sd_event_source_unref(m->event_timeout);
|
||||
|
||||
r = manager_listen_setup(m);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to set up connection socket: %m");
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to set up connection socket: %m");
|
||||
return manager_connect(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set transmit timestamp, remember it; the server will send that back
|
||||
@ -752,7 +754,7 @@ static int manager_resolve_handler(sd_resolve_query *q, int ret, const struct ad
|
||||
assert(ai->ai_addrlen >= offsetof(struct sockaddr, sa_data));
|
||||
|
||||
if (!IN_SET(ai->ai_addr->sa_family, AF_INET, AF_INET6)) {
|
||||
log_warning("Unsuitable address protocol for %s", m->current_server_name->string);
|
||||
log_debug("Ignoring unsuitable address protocol for %s.", m->current_server_name->string);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -806,11 +808,6 @@ int manager_connect(Manager *m) {
|
||||
if (m->current_server_address && m->current_server_address->addresses_next)
|
||||
manager_set_server_address(m, m->current_server_address->addresses_next);
|
||||
else {
|
||||
static const struct addrinfo hints = {
|
||||
.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG,
|
||||
.ai_socktype = SOCK_DGRAM,
|
||||
};
|
||||
|
||||
/* Hmm, we are through all addresses, let's look for the next host instead */
|
||||
if (m->current_server_name && m->current_server_name->names_next)
|
||||
manager_set_server_name(m, m->current_server_name->names_next);
|
||||
@ -878,6 +875,12 @@ int manager_connect(Manager *m) {
|
||||
|
||||
log_debug("Resolving %s...", m->current_server_name->string);
|
||||
|
||||
struct addrinfo hints = {
|
||||
.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG,
|
||||
.ai_socktype = SOCK_DGRAM,
|
||||
.ai_family = socket_ipv6_is_supported() ? AF_UNSPEC : AF_INET,
|
||||
};
|
||||
|
||||
r = resolve_getaddrinfo(m->resolve, &m->resolve_query, m->current_server_name->string, "123", &hints, manager_resolve_handler, NULL, m);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create resolver: %m");
|
||||
|
@ -1328,7 +1328,7 @@ create_empty_image() {
|
||||
fi
|
||||
|
||||
# Partition sizes are in MiBs
|
||||
local root_size=500
|
||||
local root_size=1000
|
||||
local data_size=50
|
||||
if ! get_bool "$NO_BUILD"; then
|
||||
if meson configure "${BUILD_DIR:?}" | grep 'static-lib\|standalone-binaries' | awk '{ print $2 }' | grep -q 'true'; then
|
||||
|
@ -3,10 +3,18 @@
|
||||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
# shellcheck source=test/units/assert.sh
|
||||
. "$(dirname "$0")"/assert.sh
|
||||
|
||||
: >/failed
|
||||
|
||||
at_exit() {
|
||||
if [[ -v UNIT_NAME && -e "/usr/lib/systemd/system/$UNIT_NAME" ]]; then
|
||||
rm -fv "/usr/lib/systemd/system/$UNIT_NAME"
|
||||
fi
|
||||
|
||||
rm -f /etc/init.d/issue-24990
|
||||
return 0
|
||||
}
|
||||
|
||||
trap at_exit EXIT
|
||||
@ -284,6 +292,110 @@ systemctl unset-environment IMPORT_THIS IMPORT_THIS_TOO
|
||||
(! systemctl show-environment | grep "^IMPORT_THIS=")
|
||||
(! systemctl show-environment | grep "^IMPORT_THIS_TOO=")
|
||||
|
||||
echo OK >/testok
|
||||
# test for sysv-generator (issue #24990)
|
||||
if [[ -x /usr/lib/systemd/system-generators/systemd-sysv-generator ]]; then
|
||||
|
||||
exit 0
|
||||
# invalid dependency
|
||||
cat >/etc/init.d/issue-24990 <<\EOF
|
||||
#!/bin/bash
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides:test1 test2
|
||||
# Required-Start:test1 $remote_fs $network
|
||||
# Required-Stop:test1 $remote_fs $network
|
||||
# Description:Test
|
||||
# Short-Description: Test
|
||||
### END INIT INFO
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting issue-24990.service"
|
||||
sleep 1000 &
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping issue-24990.service"
|
||||
sleep 10 &
|
||||
;;
|
||||
*)
|
||||
echo "Usage: service test {start|stop|restart|status}"
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
|
||||
chmod +x /etc/init.d/issue-24990
|
||||
systemctl daemon-reload
|
||||
[[ -L /run/systemd/generator.late/test1.service ]]
|
||||
[[ -L /run/systemd/generator.late/test2.service ]]
|
||||
assert_eq "$(readlink -f /run/systemd/generator.late/test1.service)" "/run/systemd/generator.late/issue-24990.service"
|
||||
assert_eq "$(readlink -f /run/systemd/generator.late/test2.service)" "/run/systemd/generator.late/issue-24990.service"
|
||||
output=$(systemctl cat issue-24990)
|
||||
assert_in "SourcePath=/etc/init.d/issue-24990" "$output"
|
||||
assert_in "Description=LSB: Test" "$output"
|
||||
assert_in "After=test1.service" "$output"
|
||||
assert_in "After=remote-fs.target" "$output"
|
||||
assert_in "After=network-online.target" "$output"
|
||||
assert_in "Wants=network-online.target" "$output"
|
||||
assert_in "ExecStart=/etc/init.d/issue-24990 start" "$output"
|
||||
assert_in "ExecStop=/etc/init.d/issue-24990 stop" "$output"
|
||||
systemctl status issue-24990 || :
|
||||
systemctl show issue-24990
|
||||
assert_not_in "issue-24990.service" "$(systemctl show --property=After --value)"
|
||||
assert_not_in "issue-24990.service" "$(systemctl show --property=Before --value)"
|
||||
|
||||
if ! systemctl is-active network-online.target; then
|
||||
systemctl start network-online.target
|
||||
fi
|
||||
|
||||
systemctl restart issue-24990
|
||||
systemctl stop issue-24990
|
||||
|
||||
# valid dependency
|
||||
cat >/etc/init.d/issue-24990 <<\EOF
|
||||
#!/bin/bash
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides:test1 test2
|
||||
# Required-Start:$remote_fs
|
||||
# Required-Stop:$remote_fs
|
||||
# Description:Test
|
||||
# Short-Description: Test
|
||||
### END INIT INFO
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting issue-24990.service"
|
||||
sleep 1000 &
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping issue-24990.service"
|
||||
sleep 10 &
|
||||
;;
|
||||
*)
|
||||
echo "Usage: service test {start|stop|restart|status}"
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
|
||||
chmod +x /etc/init.d/issue-24990
|
||||
systemctl daemon-reload
|
||||
[[ -L /run/systemd/generator.late/test1.service ]]
|
||||
[[ -L /run/systemd/generator.late/test2.service ]]
|
||||
assert_eq "$(readlink -f /run/systemd/generator.late/test1.service)" "/run/systemd/generator.late/issue-24990.service"
|
||||
assert_eq "$(readlink -f /run/systemd/generator.late/test2.service)" "/run/systemd/generator.late/issue-24990.service"
|
||||
output=$(systemctl cat issue-24990)
|
||||
assert_in "SourcePath=/etc/init.d/issue-24990" "$output"
|
||||
assert_in "Description=LSB: Test" "$output"
|
||||
assert_in "After=remote-fs.target" "$output"
|
||||
assert_in "ExecStart=/etc/init.d/issue-24990 start" "$output"
|
||||
assert_in "ExecStop=/etc/init.d/issue-24990 stop" "$output"
|
||||
systemctl status issue-24990 || :
|
||||
systemctl show issue-24990
|
||||
assert_not_in "issue-24990.service" "$(systemctl show --property=After --value)"
|
||||
assert_not_in "issue-24990.service" "$(systemctl show --property=Before --value)"
|
||||
|
||||
systemctl restart issue-24990
|
||||
systemctl stop issue-24990
|
||||
fi
|
||||
|
||||
touch /testok
|
||||
rm /failed
|
||||
|
Loading…
Reference in New Issue
Block a user