Compare commits

..

19 Commits

Author SHA1 Message Date
Christian Göttsche c0f765cac8 core: move bus-util include out of selinux-access header 2020-02-04 19:26:38 +01:00
Christian Göttsche f156e60c66 core: unit_label_path(): take const unit 2020-02-04 18:36:19 +01:00
Zbigniew Jędrzejewski-Szmek 2979f04b99
Merge pull request #14717 from yuwata/network-radv-dns-link-local
network: make DNS= in [IPv6PrefixDelegation] section take special value '_link_local'
2020-02-04 17:47:17 +01:00
Zbigniew Jędrzejewski-Szmek dc9fd22d3d Merge pull request #14398 from poettering/mount-prep 2020-02-04 16:28:51 +01:00
Ansgar Burchardt eb1322744d NEWS: correct indenting for two entries 2020-02-04 23:57:20 +09:00
Zbigniew Jędrzejewski-Szmek ce4121c6ff meson: update efi path detection to gnu-efi-3.0.11
Fixes systemd build in Fedora rawhide.

The old ldsdir option is not useful, because both the directory and the
file name changed. Let's remove the option and try to autodetect the file
name. If this turns out to be not enough, a new option to simply specify
the full path to the file can be added.

F31:
         efi arch:                          x86_64
         EFI machine type:                  x64
         EFI CC                             ccache cc
         EFI lds:                           /usr/lib64/gnuefi/elf_x64_efi.lds
         EFI crt0:                          /usr/lib64/gnuefi/crt0-efi-x64.o
         EFI include directory:             /usr/include/efi
F32:
         efi arch:                          x86_64
         EFI machine type:                  x64
         EFI CC                             ccache cc
         EFI lds:                           /usr/lib/gnuefi/x64/efi.lds
         EFI crt0:                          /usr/lib/gnuefi/x64/crt0.o
         EFI include directory:             /usr/include/efi
2020-02-04 23:43:21 +09:00
Yu Watanabe 41fd8fe716 test-network: add a test case for IPv6PrefixDelegation.DNS=linklocal 2020-02-04 13:57:12 +09:00
Yu Watanabe fd3ef936ed network,radv: make DNS= in [IPv6PrefixDelegation] section take special value 'linklocal'
Closes #13639.
2020-02-04 13:56:30 +09:00
Lennart Poettering 68bda079fd man: document blockdev@.target 2020-01-21 20:23:47 +01:00
Lennart Poettering 44b0d1fd59 core: add implicit ordering dep on blockdev@.target from all mount units
This way we shuld be able to order mounts properly against their backing
services in case complex storage is used (i.e. LUKS), even if the device
path used for mounting the devices is different from the expected device
node of the backing service.

Specifically, if we have a LUKS device /dev/mapper/foo that is mounted
by this name all is trivial as the relationship can be established a
priori easily. But if it is mounted via a /dev/disk/by-uuid/ symlink or
similar we only can relate the device node generated to the one mounted
at the moment the device is actually established. That's because the
UUID of the fs is stored inside the encrypted volume and thus not
knowable until the volume is set up. This patch tries to improve on this
situation: a implicit After=blockdev@.target dependency is generated for
all mounts, based on the data from /proc/self/mountinfo, which should be
the actual device node, with all symlinks resolved. This means that as
soon as the mount is established the ordering via blockdev@.target will
work, and that means during shutdown it is honoured, which is what we
are looking for.

Note that specifying /etc/fstab entries via UUID= for LUKS devices still
sucks and shouldn't be done, because it means we cannot know which LUKS
device to activate to make an fs appear, and that means unless the
volume is set up at boot anyway we can't really handle things
automatically when putting together transactions that need the mount.
2020-01-21 20:23:44 +01:00
Lennart Poettering e3e6f99689 core: downgrade swap → device dep to Requires=
This catches up with 9d06297e26 and adapts
the change made to swap units. We generally don't want to react
a-posteriori to swap devices disappearing, bad things will happen
anyway.
2020-01-21 20:23:40 +01:00
Lennart Poettering 61f9cf4e4c swap: generate automatic dependencies also for /proc/swaps devices
This catches up with the logic we do for mounts: we create deps based on
/proc/swaps now too, with the right flags set.
2020-01-21 20:23:37 +01:00
Lennart Poettering 5de0acf40d core: let's be defensive, /dev/nfs is also a special mount source, filter it out 2020-01-21 20:23:34 +01:00
Lennart Poettering 219f3cd941 core: drop _pure_ from static functions
For static functions the compiler should figure this out on its own.
2020-01-21 20:23:30 +01:00
Lennart Poettering a7e8855879 units: introduce blockdev@.target for properly ordering mounts/swaps against cryptsetup
Let's hook it into both cryptsetup-generator and gpt-auto-generator with
a shared implementation in generator.c

Fixes: #8472
2020-01-21 20:23:13 +01:00
Lennart Poettering 6bbd539e5e cryptsetup-generator: order after cryptsetup-pre.target unconditionally 2020-01-21 20:23:10 +01:00
Lennart Poettering 49685fb314 cryptsetup-generator: break overly long line 2020-01-21 20:23:06 +01:00
Lennart Poettering 33a4c98342 fstab-generator: line break a bit more systematically 2020-01-21 20:23:03 +01:00
Lennart Poettering 56a061f508 update TODO 2020-01-21 20:22:38 +01:00
27 changed files with 419 additions and 172 deletions

3
TODO
View File

@ -44,6 +44,9 @@ Features:
* cryptsetup: allow encoding key directly in /etc/crypttab, maybe with a
"base64:" prefix. Useful in particular for pkcs11 mode.
* cryptsetup: reimplement the mkswap/mke2fs in cryptsetup-generator to use
systemd-makefs.service instead.
* socket units: allow creating a udev monitor socket with ListenDevices= or so,
with matches, then actviate app thorugh that passing socket oveer

View File

@ -1926,15 +1926,14 @@
<term><varname>EmitDNS=</varname></term>
<term><varname>DNS=</varname></term>
<listitem><para><varname>DNS=</varname> specifies a list of recursive
DNS server IPv6 addresses that distributed via Router Advertisement
messages when <varname>EmitDNS=</varname> is true. If <varname>DNS=
</varname> is empty, DNS servers are read from the
<literal>[Network]</literal> section. If the
<literal>[Network]</literal> section does not contain any DNS servers
either, DNS servers from the uplink with the highest priority default
route are used. When <varname>EmitDNS=</varname> is false, no DNS server
information is sent in Router Advertisement messages.
<listitem><para><varname>DNS=</varname> specifies a list of recursive DNS server IPv6 addresses
that are distributed via Router Advertisement messages when <varname>EmitDNS=</varname> is
true. <varname>DNS=</varname> also takes special value <literal>_link_local</literal>; in that
case the IPv6 link local address is distributed. If <varname>DNS=</varname> is empty, DNS
servers are read from the <literal>[Network]</literal> section. If the
<literal>[Network]</literal> section does not contain any DNS servers either, DNS servers from
the uplink with the highest priority default route are used. When <varname>EmitDNS=</varname>
is false, no DNS server information is sent in Router Advertisement messages.
<varname>EmitDNS=</varname> defaults to true.
</para></listitem>
</varlistentry>

View File

@ -26,6 +26,7 @@
<filename>cryptsetup-pre.target</filename>,
<filename>cryptsetup.target</filename>,
<filename>ctrl-alt-del.target</filename>,
<filename>blockdev@.target</filename>,
<filename>boot-complete.target</filename>,
<filename>default.target</filename>,
<filename>emergency.target</filename>,
@ -845,6 +846,23 @@
not useful as only unit within a transaction.</para>
<variablelist>
<varlistentry>
<term><filename>blockdev@.target</filename></term>
<listitem><para>This template unit may be used to order mount units and other consumers of block
devices against services that synthesize these block devices. This is intended to be used to order
storage services (such as
<citerefentry><refentrytitle>systemd-cryptsetup@.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>)
that allocate and manage a virtual block device against mount units and other consumers of
it. Specifically, the storage services are supposed to be orderd before an instance of
<filename>blockdev@.target</filename>, and the mount unit (or other consuming unit, such as a swap
unit) after it. The ordering is particular relevant during shutdown, as it ensures that the mount
is deactivated first and the service backing the mount only deactivated after that completed. The
<filename>blockdev@.target</filename> instance should be pulled in via a <option>Wants=</option>
dependency of the storage daemon and thus generally not be part of any transaction unless a storage
daemon is used. The instance name for instances of this template unit is supposed to be the
properly escaped bock device node path, e.g. <filename>blockdev@dev-mapper-foobar.target</filename>
for a storage device <filename>/dev/mapper/foobar</filename>.</para></listitem>
</varlistentry>
<varlistentry>
<term><filename>cryptsetup-pre.target</filename></term>
<listitem>

View File

@ -3369,8 +3369,8 @@ if conf.get('ENABLE_EFI') == 1
status += [
'EFI machine type: @0@'.format(EFI_MACHINE_TYPE_NAME),
'EFI CC @0@'.format(' '.join(efi_cc)),
'EFI lib directory: @0@'.format(efi_libdir),
'EFI lds directory: @0@'.format(efi_ldsdir),
'EFI lds: @0@'.format(efi_lds),
'EFI crt0: @0@'.format(efi_crt0),
'EFI include directory: @0@'.format(efi_incdir)]
endif
endif

View File

@ -323,8 +323,6 @@ option('efi-ld', type : 'string',
description : 'the linker to use for EFI modules')
option('efi-libdir', type : 'string',
description : 'path to the EFI lib directory')
option('efi-ldsdir', type : 'string',
description : 'path to the EFI lds directory')
option('efi-includedir', type : 'string', value : '/usr/include/efi',
description : 'path to the EFI header directory')
option('tpm-pcrindex', type : 'integer', value : 8,

View File

@ -64,12 +64,19 @@ if conf.get('ENABLE_EFI') == 1 and get_option('gnu-efi') != 'false'
efi_libdir = get_option('efi-libdir')
if efi_libdir == ''
ret = run_command(efi_cc + ['-print-multi-os-directory'])
if ret.returncode() == 0
path = join_paths('/usr/lib', ret.stdout().strip())
ret = run_command('realpath', '-e', path)
if ret.returncode() == 0
efi_libdir = ret.stdout().strip()
# New location first introduced with gnu-efi 3.0.11
efi_libdir = join_paths('/usr/lib/gnuefi', EFI_MACHINE_TYPE_NAME)
cmd = run_command('test', '-e', efi_libdir)
if cmd.returncode() != 0
# Fall back to the old approach
cmd = run_command(efi_cc + ['-print-multi-os-directory'])
if cmd.returncode() == 0
path = join_paths('/usr/lib', cmd.stdout().strip())
cmd = run_command('realpath', '-e', path)
if cmd.returncode() == 0
efi_libdir = cmd.stdout().strip()
endif
endif
endif
endif
@ -95,20 +102,35 @@ if have_gnu_efi
objcopy = find_program('objcopy')
efi_ldsdir = get_option('efi-ldsdir')
arch_lds = 'elf_@0@_efi.lds'.format(gnu_efi_path_arch)
if efi_ldsdir == ''
efi_ldsdir = join_paths(efi_libdir, 'gnuefi')
cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds))
if cmd.returncode() != 0
efi_ldsdir = efi_libdir
cmd = run_command('test', '-f', join_paths(efi_ldsdir, arch_lds))
if cmd.returncode() != 0
error('Cannot find @0@'.format(arch_lds))
efi_location_map = [
# New locations first introduced with gnu-efi 3.0.11
[join_paths(efi_libdir, 'efi.lds'),
join_paths(efi_libdir, 'crt0.o')],
# Older locations...
[join_paths(efi_libdir, 'gnuefi', 'elf_@0@_efi.lds'.format(gnu_efi_path_arch)),
join_paths(efi_libdir, 'gnuefi', 'crt0-efi-@0@.o'.format(gnu_efi_path_arch))],
[join_paths(efi_libdir, 'elf_@0@_efi.lds'.format(gnu_efi_path_arch)),
join_paths(efi_libdir, 'crt0-efi-@0@.o'.format(gnu_efi_path_arch))]]
efi_lds = ''
foreach location : efi_location_map
if efi_lds == ''
cmd = run_command('test', '-f', location[0])
if cmd.returncode() == 0
efi_lds = location[0]
efi_crt0 = location[1]
endif
endif
endforeach
if efi_lds == ''
if get_option('gnu-efi') == 'true'
error('gnu-efi support requested, but cannot find efi.lds')
else
have_gnu_efi = false
endif
endif
endif
if have_gnu_efi
compile_args = ['-Wall',
'-Wextra',
'-std=gnu90',
@ -145,14 +167,13 @@ if have_gnu_efi
compile_args += ['-O2']
endif
efi_ldflags = ['-T',
join_paths(efi_ldsdir, arch_lds),
efi_ldflags = ['-T', efi_lds,
'-shared',
'-Bsymbolic',
'-nostdlib',
'-znocombreloc',
'-L', efi_libdir,
join_paths(efi_ldsdir, 'crt0-efi-@0@.o'.format(gnu_efi_path_arch))]
efi_crt0]
if efi_arch == 'aarch64' or efi_arch == 'arm'
# Aarch64 and ARM32 don't have an EFI capable objcopy. Use 'binary'
# instead, and add required symbols manually.
@ -219,11 +240,9 @@ if have_gnu_efi
set_variable(tuple[0].underscorify(), so)
set_variable(tuple[0].underscorify() + '_stub', stub)
endforeach
endif
############################################################
if have_gnu_efi
test_efi_disk_img = custom_target(
'test-efi-disk.img',
input : [systemd_boot_so, stub_so_stub],

View File

@ -3,6 +3,7 @@
#include "sd-bus.h"
#include "alloc-util.h"
#include "bus-util.h"
#include "dbus-job.h"
#include "dbus-unit.h"
#include "dbus.h"

View File

@ -9,6 +9,7 @@
#include "architecture.h"
#include "build.h"
#include "bus-common-errors.h"
#include "bus-util.h"
#include "dbus-cgroup.h"
#include "dbus-execute.h"
#include "dbus-job.h"

View File

@ -6,6 +6,7 @@
#include "bpf-firewall.h"
#include "bus-common-errors.h"
#include "bus-polkit.h"
#include "bus-util.h"
#include "cgroup-util.h"
#include "condition.h"
#include "dbus-job.h"

View File

@ -11,6 +11,7 @@
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-polkit.h"
#include "bus-util.h"
#include "dbus-automount.h"
#include "dbus-cgroup.h"
#include "dbus-device.h"

View File

@ -217,7 +217,7 @@ static void mount_done(Unit *u) {
m->timer_event_source = sd_event_source_unref(m->timer_event_source);
}
_pure_ static MountParameters* get_mount_parameters_fragment(Mount *m) {
static MountParameters* get_mount_parameters_fragment(Mount *m) {
assert(m);
if (m->from_fragment)
@ -226,7 +226,7 @@ _pure_ static MountParameters* get_mount_parameters_fragment(Mount *m) {
return NULL;
}
_pure_ static MountParameters* get_mount_parameters(Mount *m) {
static MountParameters* get_mount_parameters(Mount *m) {
assert(m);
if (m->from_proc_self_mountinfo)
@ -342,20 +342,18 @@ static int mount_add_device_dependencies(Mount *m) {
if (!is_device_path(p->what))
return 0;
/* /dev/root is a really weird thing, it's not a real device,
* but just a path the kernel exports for the root file system
* specified on the kernel command line. Ignore it here. */
if (path_equal(p->what, "/dev/root"))
/* /dev/root is a really weird thing, it's not a real device, but just a path the kernel exports for
* the root file system specified on the kernel command line. Ignore it here. */
if (PATH_IN_SET(p->what, "/dev/root", "/dev/nfs"))
return 0;
if (path_equal(m->where, "/"))
return 0;
/* Mount units from /proc/self/mountinfo are not bound to devices
* by default since they're subject to races when devices are
* unplugged. But the user can still force this dep with an
* appropriate option (or udev property) so the mount units are
* automatically stopped when the device disappears suddenly. */
/* Mount units from /proc/self/mountinfo are not bound to devices by default since they're subject to
* races when devices are unplugged. But the user can still force this dep with an appropriate option
* (or udev property) so the mount units are automatically stopped when the device disappears
* suddenly. */
dep = mount_is_bound_to_device(m) ? UNIT_BINDS_TO : UNIT_REQUIRES;
/* We always use 'what' from /proc/self/mountinfo if mounted */
@ -365,7 +363,7 @@ static int mount_add_device_dependencies(Mount *m) {
if (r < 0)
return r;
return 0;
return unit_add_blockdev_dependency(UNIT(m), p->what, mask);
}
static int mount_add_quota_dependencies(Mount *m) {

View File

@ -3,7 +3,6 @@
#include "sd-bus.h"
#include "bus-util.h"
#include "manager.h"
int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error);

View File

@ -184,21 +184,45 @@ static int swap_arm_timer(Swap *s, usec_t usec) {
return 0;
}
static SwapParameters* swap_get_parameters(Swap *s) {
assert(s);
if (s->from_proc_swaps)
return &s->parameters_proc_swaps;
if (s->from_fragment)
return &s->parameters_fragment;
return NULL;
}
static int swap_add_device_dependencies(Swap *s) {
UnitDependencyMask mask;
SwapParameters *p;
int r;
assert(s);
if (!s->what)
return 0;
if (!s->from_fragment)
p = swap_get_parameters(s);
if (!p)
return 0;
if (is_device_path(s->what))
return unit_add_node_dependency(UNIT(s), s->what, UNIT_BINDS_TO, UNIT_DEPENDENCY_FILE);
mask = s->from_proc_swaps ? UNIT_DEPENDENCY_PROC_SWAP : UNIT_DEPENDENCY_FILE;
/* File based swap devices need to be ordered after systemd-remount-fs.service,
* since they might need a writable file system. */
return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, true, UNIT_DEPENDENCY_FILE);
if (is_device_path(p->what)) {
r = unit_add_node_dependency(UNIT(s), p->what, UNIT_REQUIRES, mask);
if (r < 0)
return r;
return unit_add_blockdev_dependency(UNIT(s), p->what, mask);
}
/* File based swap devices need to be ordered after systemd-remount-fs.service, since they might need
* a writable file system. */
return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, true, mask);
}
static int swap_add_default_dependencies(Swap *s) {

View File

@ -3866,8 +3866,8 @@ int unit_deserialize_skip(FILE *f) {
}
int unit_add_node_dependency(Unit *u, const char *what, UnitDependency dep, UnitDependencyMask mask) {
Unit *device;
_cleanup_free_ char *e = NULL;
Unit *device;
int r;
assert(u);
@ -3879,8 +3879,7 @@ int unit_add_node_dependency(Unit *u, const char *what, UnitDependency dep, Unit
if (!is_device_path(what))
return 0;
/* When device units aren't supported (such as in a
* container), don't create dependencies on them. */
/* When device units aren't supported (such as in a container), don't create dependencies on them. */
if (!unit_type_supported(UNIT_DEVICE))
return 0;
@ -3900,6 +3899,33 @@ int unit_add_node_dependency(Unit *u, const char *what, UnitDependency dep, Unit
device, true, mask);
}
int unit_add_blockdev_dependency(Unit *u, const char *what, UnitDependencyMask mask) {
_cleanup_free_ char *escaped = NULL, *target = NULL;
int r;
assert(u);
if (isempty(what))
return 0;
if (!path_startswith(what, "/dev/"))
return 0;
/* If we don't support devices, then also don't bother with blockdev@.target */
if (!unit_type_supported(UNIT_DEVICE))
return 0;
r = unit_name_path_escape(what, &escaped);
if (r < 0)
return r;
r = unit_name_build("blockdev", escaped, ".target", &target);
if (r < 0)
return r;
return unit_add_dependency_by_name(u, UNIT_AFTER, target, true, mask);
}
int unit_coldplug(Unit *u) {
int r = 0, q;
char **i;
@ -5777,9 +5803,11 @@ bool unit_needs_console(Unit *u) {
return exec_context_may_touch_console(ec);
}
const char *unit_label_path(Unit *u) {
const char *unit_label_path(const Unit *u) {
const char *p;
assert(u);
/* Returns the file system path to use for MAC access decisions, i.e. the file to read the SELinux label off
* when validating access checks. */

View File

@ -743,6 +743,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
int unit_deserialize_skip(FILE *f);
int unit_add_node_dependency(Unit *u, const char *what, UnitDependency d, UnitDependencyMask mask);
int unit_add_blockdev_dependency(Unit *u, const char *what, UnitDependencyMask mask);
int unit_coldplug(Unit *u);
void unit_catchup(Unit *u);
@ -841,7 +842,7 @@ int unit_warn_leftover_processes(Unit *u);
bool unit_needs_console(Unit *u);
const char *unit_label_path(Unit *u);
const char *unit_label_path(const Unit *u);
int unit_pid_attachable(Unit *unit, pid_t pid, sd_bus_error *error);

View File

@ -99,7 +99,14 @@ static int split_keyspec(const char *keyspec, char **ret_keyfile, char **ret_key
return 0;
}
static int generate_keydev_mount(const char *name, const char *keydev, const char *keydev_timeout, bool canfail, char **unit, char **mount) {
static int generate_keydev_mount(
const char *name,
const char *keydev,
const char *keydev_timeout,
bool canfail,
char **unit,
char **mount) {
_cleanup_free_ char *u = NULL, *where = NULL, *name_escaped = NULL, *device_unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
@ -223,8 +230,8 @@ static int create_disk(
const char *options) {
_cleanup_free_ char *n = NULL, *d = NULL, *u = NULL, *e = NULL,
*keydev_mount = NULL, *keyfile_timeout_value = NULL, *password_escaped = NULL,
*filtered = NULL, *u_escaped = NULL, *filtered_escaped = NULL, *name_escaped = NULL, *header_path = NULL;
*keydev_mount = NULL, *keyfile_timeout_value = NULL,
*filtered = NULL, *u_escaped = NULL, *name_escaped = NULL, *header_path = NULL, *password_buffer = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *dmname;
bool noauto, nofail, tmp, swap, netdev, attach_in_initrd;
@ -285,39 +292,29 @@ static int create_disk(
if (r < 0)
return r;
fprintf(f,
"[Unit]\n"
"Description=Cryptography Setup for %%I\n"
"Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
"SourcePath=%s\n"
"DefaultDependencies=no\n"
"IgnoreOnIsolate=true\n"
"After=%s\n",
arg_crypttab,
netdev ? "remote-fs-pre.target" : "cryptsetup-pre.target");
r = generator_write_cryptsetup_unit_section(f, arg_crypttab);
if (r < 0)
return r;
if (netdev)
fprintf(f, "After=remote-fs-pre.target\n");
/* If initrd takes care of attaching the disk then it should also detach it during shutdown. */
if (!attach_in_initrd)
fprintf(f, "Conflicts=umount.target\n");
if (password) {
password_escaped = specifier_escape(password);
if (!password_escaped)
return log_oom();
}
if (keydev) {
_cleanup_free_ char *unit = NULL, *p = NULL;
_cleanup_free_ char *unit = NULL;
r = generate_keydev_mount(name, keydev, keyfile_timeout_value, keyfile_can_timeout > 0, &unit, &keydev_mount);
if (r < 0)
return log_error_errno(r, "Failed to generate keydev mount unit: %m");
p = path_join(keydev_mount, password_escaped);
if (!p)
password_buffer = path_join(keydev_mount, password);
if (!password_buffer)
return log_oom();
free_and_replace(password_escaped, p);
password = password_buffer;
fprintf(f, "After=%s\n", unit);
if (keyfile_can_timeout > 0)
@ -344,17 +341,13 @@ static int create_disk(
return r;
}
if (path_startswith(u, "/dev/")) {
if (path_startswith(u, "/dev/"))
fprintf(f,
"BindsTo=%s\n"
"After=%s\n"
"Before=umount.target\n",
d, d);
if (swap)
fputs("Before=dev-mapper-%i.swap\n",
f);
} else
else
/* For loopback devices, add systemd-tmpfiles-setup-dev.service
dependency to ensure that loopback support is available in
the kernel (/dev/loop-control needs to exist) */
@ -368,23 +361,9 @@ static int create_disk(
if (r < 0)
log_warning_errno(r, "Failed to write device timeout drop-in: %m");
if (filtered) {
filtered_escaped = specifier_escape(filtered);
if (!filtered_escaped)
return log_oom();
}
fprintf(f,
"\n[Service]\n"
"Type=oneshot\n"
"RemainAfterExit=yes\n"
"TimeoutSec=0\n" /* the binary handles timeouts anyway */
"KeyringMode=shared\n" /* make sure we can share cached keys among instances */
"OOMScoreAdjust=500\n" /* unlocking can allocate a lot of memory if Argon2 is used */
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
name_escaped, u_escaped, strempty(password_escaped), strempty(filtered_escaped),
name_escaped);
r = generator_write_cryptsetup_service_section(f, name, u, password, filtered);
if (r < 0)
return r;
if (tmp)
fprintf(f,

View File

@ -118,11 +118,18 @@ static int add_swap(
fprintf(f,
"[Unit]\n"
"SourcePath=%s\n"
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
"[Swap]\n",
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
"SourcePath=%s\n",
fstab_path());
r = generator_write_blockdev_dependency(f, what);
if (r < 0)
return r;
fprintf(f,
"\n"
"[Swap]\n");
r = write_what(f, what);
if (r < 0)
return r;
@ -174,8 +181,13 @@ static bool mount_in_initrd(struct mntent *me) {
streq(me->mnt_dir, "/usr");
}
static int write_timeout(FILE *f, const char *where, const char *opts,
const char *filter, const char *variable) {
static int write_timeout(
FILE *f,
const char *where,
const char *opts,
const char *filter,
const char *variable) {
_cleanup_free_ char *timeout = NULL;
char timespan[FORMAT_TIMESPAN_MAX];
usec_t u;
@ -208,8 +220,12 @@ static int write_mount_timeout(FILE *f, const char *where, const char *opts) {
"x-systemd.mount-timeout\0", "TimeoutSec");
}
static int write_dependency(FILE *f, const char *opts,
const char *filter, const char *format) {
static int write_dependency(
FILE *f,
const char *opts,
const char *filter,
const char *format) {
_cleanup_strv_free_ char **names = NULL, **units = NULL;
_cleanup_free_ char *res = NULL;
char **s;
@ -230,6 +246,7 @@ static int write_dependency(FILE *f, const char *opts,
r = unit_name_mangle_with_suffix(*s, "as dependency", 0, ".mount", &x);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
r = strv_consume(&units, x);
if (r < 0)
return log_oom();
@ -249,7 +266,8 @@ static int write_dependency(FILE *f, const char *opts,
}
static int write_after(FILE *f, const char *opts) {
return write_dependency(f, opts, "x-systemd.after", "After=%1$s\n");
return write_dependency(f, opts,
"x-systemd.after", "After=%1$s\n");
}
static int write_requires_after(FILE *f, const char *opts) {
@ -363,8 +381,8 @@ static int add_mount(
fprintf(f,
"[Unit]\n"
"SourcePath=%s\n"
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
"SourcePath=%s\n",
source);
/* All mounts under /sysroot need to happen later, at initrd-fs.target time. IOW, it's not
@ -411,7 +429,14 @@ static int add_mount(
return r;
}
fprintf(f, "\n[Mount]\n");
r = generator_write_blockdev_dependency(f, what);
if (r < 0)
return r;
fprintf(f,
"\n"
"[Mount]\n");
if (original_where)
fprintf(f, "# Canonicalized from %s\n", original_where);

View File

@ -105,9 +105,8 @@ static int open_parent_block_device(dev_t devnum, int *ret_fd) {
}
static int add_cryptsetup(const char *id, const char *what, bool rw, bool require, char **device) {
_cleanup_free_ char *e = NULL, *n = NULL, *d = NULL, *id_escaped = NULL, *what_escaped = NULL;
_cleanup_free_ char *e = NULL, *n = NULL, *d = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *p;
int r;
assert(id);
@ -125,44 +124,28 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, bool requir
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
id_escaped = specifier_escape(id);
if (!id_escaped)
return log_oom();
r = generator_open_unit_file(arg_dest, NULL, n, &f);
if (r < 0)
return r;
what_escaped = specifier_escape(what);
if (!what_escaped)
return log_oom();
p = prefix_roota(arg_dest, n);
f = fopen(p, "wxe");
if (!f)
return log_error_errno(errno, "Failed to create unit file %s: %m", p);
r = generator_write_cryptsetup_unit_section(f, NULL);
if (r < 0)
return r;
fprintf(f,
"# Automatically generated by systemd-gpt-auto-generator\n\n"
"[Unit]\n"
"Description=Cryptography Setup for %%I\n"
"Documentation=man:systemd-gpt-auto-generator(8) man:systemd-cryptsetup@.service(8)\n"
"DefaultDependencies=no\n"
"Conflicts=umount.target\n"
"BindsTo=dev-mapper-%%i.device %s\n"
"Before=umount.target cryptsetup.target\n"
"After=%s\n"
"IgnoreOnIsolate=true\n"
"[Service]\n"
"Type=oneshot\n"
"RemainAfterExit=yes\n"
"TimeoutSec=0\n" /* the binary handles timeouts anyway */
"KeyringMode=shared\n" /* make sure we can share cached keys among instances */
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '' '%s'\n"
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
d, d,
id_escaped, what_escaped, rw ? "" : "read-only",
id_escaped);
"Conflicts=umount.target\n"
"BindsTo=%s\n"
"After=%s\n",
d, d);
r = generator_write_cryptsetup_service_section(f, id, what, NULL, rw ? NULL : "read-only");
if (r < 0)
return r;
r = fflush_and_check(f);
if (r < 0)
return log_error_errno(r, "Failed to write file %s: %m", p);
return log_error_errno(r, "Failed to write file %s: %m", n);
r = generator_add_symlink(arg_dest, d, "wants", n);
if (r < 0)
@ -227,7 +210,6 @@ static int add_mount(
log_debug("Adding %s: %s fstype=%s", where, what, fstype ?: "(any)");
if (streq_ptr(fstype, "crypto_LUKS")) {
r = add_cryptsetup(id, what, rw, true, &crypto_what);
if (r < 0)
return r;
@ -262,6 +244,10 @@ static int add_mount(
if (r < 0)
return r;
r = generator_write_blockdev_dependency(f, what);
if (r < 0)
return r;
fprintf(f,
"\n"
"[Mount]\n"
@ -370,7 +356,14 @@ static int add_swap(const char *path) {
"# Automatically generated by systemd-gpt-auto-generator\n\n"
"[Unit]\n"
"Description=Swap Partition\n"
"Documentation=man:systemd-gpt-auto-generator(8)\n\n"
"Documentation=man:systemd-gpt-auto-generator(8)\n");
r = generator_write_blockdev_dependency(f, path);
if (r < 0)
return r;
fprintf(f,
"\n"
"[Swap]\n"
"What=%s\n",
path);

View File

@ -1514,6 +1514,10 @@ static int link_acquire_ipv6_conf(Link *link) {
log_link_debug(link, "Starting IPv6 Router Advertisements");
r = radv_emit_dns(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to configure DNS or Domains in IPv6 Router Advertisement: %m");
r = sd_radv_start(link->radv);
if (r < 0 && r != -EBUSY)
return log_link_warning_errno(link, r, "Could not start IPv6 Router Advertisement: %m");

View File

@ -443,20 +443,29 @@ static int radv_get_ip6dns(Network *network, struct in6_addr **dns,
static int radv_set_dns(Link *link, Link *uplink) {
_cleanup_free_ struct in6_addr *dns = NULL;
size_t n_dns;
usec_t lifetime_usec;
size_t n_dns;
int r;
if (!link->network->router_emit_dns)
return 0;
if (link->network->router_dns) {
dns = newdup(struct in6_addr, link->network->router_dns,
link->network->n_router_dns);
struct in6_addr *p;
dns = new(struct in6_addr, link->network->n_router_dns);
if (!dns)
return -ENOMEM;
n_dns = link->network->n_router_dns;
p = dns;
for (size_t i = 0; i < link->network->n_router_dns; i++)
if (IN6_IS_ADDR_UNSPECIFIED(&link->network->router_dns[i])) {
if (!IN6_IS_ADDR_UNSPECIFIED(&link->ipv6ll_address))
*(p++) = link->ipv6ll_address;
} else
*(p++) = link->network->router_dns[i];
n_dns = p - dns;
lifetime_usec = link->network->router_dns_lifetime_usec;
goto set_dns;
@ -620,7 +629,7 @@ int radv_configure(Link *link) {
}
return radv_emit_dns(link);
return 0;
}
int config_parse_radv_dns(
@ -658,19 +667,30 @@ int config_parse_radv_dns(
if (r == 0)
break;
if (in_addr_from_string(AF_INET6, w, &a) >= 0) {
struct in6_addr *m;
if (streq(w, "_link_local"))
a = IN_ADDR_NULL;
else {
r = in_addr_from_string(AF_INET6, w, &a);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to parse DNS server address, ignoring: %s", w);
continue;
}
if (in_addr_is_null(AF_INET6, &a)) {
log_syntax(unit, LOG_ERR, filename, line, 0,
"DNS server address is null, ignoring: %s", w);
continue;
}
}
struct in6_addr *m;
m = reallocarray(n->router_dns, n->n_router_dns + 1, sizeof(struct in6_addr));
if (!m)
return log_oom();
m[n->n_router_dns++] = a.in6;
n->router_dns = m;
} else
log_syntax(unit, LOG_ERR, filename, line, 0,
"Failed to parse DNS server address, ignoring: %s", w);
}
return 0;

View File

@ -519,6 +519,103 @@ int generator_enable_remount_fs_service(const char *dir) {
SYSTEM_DATA_UNIT_PATH "/" SPECIAL_REMOUNT_FS_SERVICE);
}
int generator_write_blockdev_dependency(
FILE *f,
const char *what) {
_cleanup_free_ char *escaped = NULL;
int r;
assert(f);
assert(what);
if (!path_startswith(what, "/dev/"))
return 0;
r = unit_name_path_escape(what, &escaped);
if (r < 0)
return log_error_errno(r, "Failed to escape device node path %s: %m", what);
fprintf(f,
"After=blockdev@%s.target\n",
escaped);
return 0;
}
int generator_write_cryptsetup_unit_section(
FILE *f,
const char *source) {
assert(f);
fprintf(f,
"[Unit]\n"
"Description=Cryptography Setup for %%I\n"
"Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n");
if (source)
fprintf(f, "SourcePath=%s\n", source);
fprintf(f,
"DefaultDependencies=no\n"
"IgnoreOnIsolate=true\n"
"After=cryptsetup-pre.target\n"
"Before=blockdev@dev-mapper-%%i.target\n"
"Wants=blockdev@dev-mapper-%%i.target\n");
return 0;
}
int generator_write_cryptsetup_service_section(
FILE *f,
const char *name,
const char *what,
const char *password,
const char *options) {
_cleanup_free_ char *name_escaped = NULL, *what_escaped = NULL, *password_escaped = NULL, *options_escaped = NULL;
assert(f);
assert(name);
assert(what);
name_escaped = specifier_escape(name);
if (!name_escaped)
return log_oom();
what_escaped = specifier_escape(what);
if (!what_escaped)
return log_oom();
if (password) {
password_escaped = specifier_escape(password);
if (!password_escaped)
return log_oom();
}
if (options) {
options_escaped = specifier_escape(options);
if (!options_escaped)
return log_oom();
}
fprintf(f,
"\n"
"[Service]\n"
"Type=oneshot\n"
"RemainAfterExit=yes\n"
"TimeoutSec=0\n" /* The binary handles timeouts on its own */
"KeyringMode=shared\n" /* Make sure we can share cached keys among instances */
"OOMScoreAdjust=500\n" /* Unlocking can allocate a lot of memory if Argon2 is used */
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
name_escaped, what_escaped, strempty(password_escaped), strempty(options_escaped),
name_escaped);
return 0;
}
void log_setup_generator(void) {
log_set_prohibit_ipc(true);
log_setup_service();

View File

@ -27,6 +27,21 @@ int generator_write_timeouts(
const char *opts,
char **filtered);
int generator_write_blockdev_dependency(
FILE *f,
const char *what);
int generator_write_cryptsetup_unit_section(
FILE *f,
const char *source);
int generator_write_cryptsetup_service_section(
FILE *f,
const char *name,
const char *what,
const char *password,
const char *options);
int generator_write_device_deps(
const char *dir,
const char *what,

View File

@ -4,6 +4,10 @@ Name=veth-peer
[Network]
IPv6PrefixDelegation=yes
[IPv6PrefixDelegation]
DNS=_link_local 2002:da8:1:0::1
DNSLifetimeSec=1min
[IPv6Prefix]
Prefix=2002:da8:1:0::/64
PreferredLifetimeSec=1000s

View File

@ -2646,6 +2646,11 @@ class NetworkdRATests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['veth99:routable', 'veth-peer:degraded'])
output = check_output(*resolvectl_cmd, 'dns', 'veth99', env=env)
print(output)
self.assertRegex(output, 'fe80::')
self.assertRegex(output, '2002:da8:1::1')
output = check_output(*networkctl_cmd, '-n', '0', 'status', 'veth99', env=env)
print(output)
self.assertRegex(output, '2002:da8:1:0')

13
units/blockdev@.target Normal file
View File

@ -0,0 +1,13 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Block Device Preparation for %f
Documentation=man:systemd.special(7)
StopWhenUnneeded=yes

View File

@ -2,6 +2,7 @@
units = [
['basic.target', ''],
['blockdev@.target', ''],
['bluetooth.target', ''],
['boot-complete.target', ''],
['cryptsetup-pre.target', 'HAVE_LIBCRYPTSETUP'],