mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-08 21:17:47 +03:00
Merge pull request #4879 from poettering/systemd
This commit is contained in:
commit
6b3d378331
3
.gitignore
vendored
3
.gitignore
vendored
@ -126,6 +126,9 @@
|
||||
/systemd-update-utmp
|
||||
/systemd-user-sessions
|
||||
/systemd-vconsole-setup
|
||||
/systemd-veritysetup
|
||||
/systemd-veritysetup-generator
|
||||
/systemd-volatile-root
|
||||
/tags
|
||||
/test-acd
|
||||
/test-acl-util
|
||||
|
1
.mkosi/Makefile
Symbolic link
1
.mkosi/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../src/Makefile
|
@ -64,7 +64,6 @@ BuildPackages=
|
||||
libxslt
|
||||
lz4-devel
|
||||
make
|
||||
diffutils
|
||||
pam-devel
|
||||
pkgconfig
|
||||
python3-devel
|
||||
|
@ -21,6 +21,11 @@ All tools:
|
||||
* `$SD_EVENT_PROFILE_DELAYS=1` — if set, the sd-event event loop implementation
|
||||
will print latency information at runtime.
|
||||
|
||||
* `$SYSTEMD_PROC_CMDLINE` — if set, may contain a string that is used as kernel
|
||||
command line instead of the actual one readable from /proc/cmdline. This is
|
||||
useful for debugging, in order to test generators and other code against
|
||||
specific kernel command lines.
|
||||
|
||||
systemctl:
|
||||
|
||||
* `$SYSTEMCTL_FORCE_BUS=1` — if set, do not connect to PID1's private D-Bus
|
||||
|
@ -142,6 +142,7 @@ MANPAGES += \
|
||||
man/systemd-tty-ask-password-agent.1 \
|
||||
man/systemd-udevd.service.8 \
|
||||
man/systemd-update-done.service.8 \
|
||||
man/systemd-volatile-root.service.8 \
|
||||
man/systemd.1 \
|
||||
man/systemd.automount.5 \
|
||||
man/systemd.device.5 \
|
||||
@ -482,6 +483,7 @@ MANPAGES_ALIAS += \
|
||||
man/systemd-udevd.8 \
|
||||
man/systemd-update-done.8 \
|
||||
man/systemd-user.conf.5 \
|
||||
man/systemd-volatile-root.8 \
|
||||
man/udev_device_get_action.3 \
|
||||
man/udev_device_get_devlinks_list_entry.3 \
|
||||
man/udev_device_get_devnode.3 \
|
||||
@ -837,6 +839,7 @@ man/systemd-udevd-kernel.socket.8: man/systemd-udevd.service.8
|
||||
man/systemd-udevd.8: man/systemd-udevd.service.8
|
||||
man/systemd-update-done.8: man/systemd-update-done.service.8
|
||||
man/systemd-user.conf.5: man/systemd-system.conf.5
|
||||
man/systemd-volatile-root.8: man/systemd-volatile-root.service.8
|
||||
man/udev_device_get_action.3: man/udev_device_get_syspath.3
|
||||
man/udev_device_get_devlinks_list_entry.3: man/udev_device_has_tag.3
|
||||
man/udev_device_get_devnode.3: man/udev_device_get_syspath.3
|
||||
@ -1790,6 +1793,9 @@ man/systemd-update-done.html: man/systemd-update-done.service.html
|
||||
man/systemd-user.conf.html: man/systemd-system.conf.html
|
||||
$(html-alias)
|
||||
|
||||
man/systemd-volatile-root.html: man/systemd-volatile-root.service.html
|
||||
$(html-alias)
|
||||
|
||||
man/udev_device_get_action.html: man/udev_device_get_syspath.html
|
||||
$(html-alias)
|
||||
|
||||
@ -2270,13 +2276,20 @@ if HAVE_LIBCRYPTSETUP
|
||||
MANPAGES += \
|
||||
man/crypttab.5 \
|
||||
man/systemd-cryptsetup-generator.8 \
|
||||
man/systemd-cryptsetup@.service.8
|
||||
man/systemd-cryptsetup@.service.8 \
|
||||
man/systemd-veritysetup-generator.8 \
|
||||
man/systemd-veritysetup@.service.8
|
||||
MANPAGES_ALIAS += \
|
||||
man/systemd-cryptsetup.8
|
||||
man/systemd-cryptsetup.8 \
|
||||
man/systemd-veritysetup.8
|
||||
man/systemd-cryptsetup.8: man/systemd-cryptsetup@.service.8
|
||||
man/systemd-veritysetup.8: man/systemd-veritysetup@.service.8
|
||||
man/systemd-cryptsetup.html: man/systemd-cryptsetup@.service.html
|
||||
$(html-alias)
|
||||
|
||||
man/systemd-veritysetup.html: man/systemd-veritysetup@.service.html
|
||||
$(html-alias)
|
||||
|
||||
endif
|
||||
|
||||
if HAVE_MICROHTTPD
|
||||
@ -2804,6 +2817,9 @@ EXTRA_DIST += \
|
||||
man/systemd-update-utmp.service.xml \
|
||||
man/systemd-user-sessions.service.xml \
|
||||
man/systemd-vconsole-setup.service.xml \
|
||||
man/systemd-veritysetup-generator.xml \
|
||||
man/systemd-veritysetup@.service.xml \
|
||||
man/systemd-volatile-root.service.xml \
|
||||
man/systemd.automount.xml \
|
||||
man/systemd.device.xml \
|
||||
man/systemd.exec.xml \
|
||||
|
37
Makefile.am
37
Makefile.am
@ -397,6 +397,7 @@ rootlibexec_PROGRAMS = \
|
||||
systemd-initctl \
|
||||
systemd-shutdown \
|
||||
systemd-remount-fs \
|
||||
systemd-volatile-root \
|
||||
systemd-reply-password \
|
||||
systemd-fsck \
|
||||
systemd-ac-power \
|
||||
@ -538,6 +539,7 @@ nodist_systemunit_DATA = \
|
||||
units/system-update-cleanup.service \
|
||||
units/systemd-initctl.service \
|
||||
units/systemd-remount-fs.service \
|
||||
units/systemd-volatile-root.service \
|
||||
units/systemd-ask-password-wall.service \
|
||||
units/systemd-ask-password-console.service \
|
||||
units/systemd-sysctl.service \
|
||||
@ -602,6 +604,7 @@ EXTRA_DIST += \
|
||||
units/system-update-cleanup.service.in \
|
||||
units/systemd-initctl.service.in \
|
||||
units/systemd-remount-fs.service.in \
|
||||
units/systemd-volatile-root.service.in \
|
||||
units/systemd-update-utmp.service.in \
|
||||
units/systemd-update-utmp-runlevel.service.in \
|
||||
units/systemd-ask-password-wall.service.in \
|
||||
@ -1065,7 +1068,9 @@ libshared_la_SOURCES = \
|
||||
src/shared/nsflags.h \
|
||||
src/shared/nsflags.c \
|
||||
src/shared/dissect-image.c \
|
||||
src/shared/dissect-image.h
|
||||
src/shared/dissect-image.h \
|
||||
src/shared/volatile-util.c \
|
||||
src/shared/volatile-util.h
|
||||
|
||||
if HAVE_UTMP
|
||||
libshared_la_SOURCES += \
|
||||
@ -3065,6 +3070,13 @@ systemd_remount_fs_SOURCES = \
|
||||
systemd_remount_fs_LDADD = \
|
||||
libsystemd-shared.la
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
systemd_volatile_root_SOURCES = \
|
||||
src/volatile-root/volatile-root.c
|
||||
|
||||
systemd_volatile_root_LDADD = \
|
||||
libsystemd-shared.la
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
systemd_cgroups_agent_SOURCES = \
|
||||
src/cgroups-agent/cgroups-agent.c
|
||||
@ -4821,10 +4833,12 @@ EXTRA_DIST += \
|
||||
# ------------------------------------------------------------------------------
|
||||
if HAVE_LIBCRYPTSETUP
|
||||
rootlibexec_PROGRAMS += \
|
||||
systemd-cryptsetup
|
||||
systemd-cryptsetup \
|
||||
systemd-veritysetup
|
||||
|
||||
systemgenerator_PROGRAMS += \
|
||||
systemd-cryptsetup-generator
|
||||
systemd-cryptsetup-generator \
|
||||
systemd-veritysetup-generator
|
||||
|
||||
dist_systemunit_DATA += \
|
||||
units/cryptsetup.target \
|
||||
@ -4847,6 +4861,23 @@ systemd_cryptsetup_generator_SOURCES = \
|
||||
systemd_cryptsetup_generator_LDADD = \
|
||||
libsystemd-shared.la
|
||||
|
||||
systemd_veritysetup_SOURCES = \
|
||||
src/veritysetup/veritysetup.c
|
||||
|
||||
systemd_veritysetup_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
$(LIBCRYPTSETUP_CFLAGS)
|
||||
|
||||
systemd_veritysetup_LDADD = \
|
||||
libsystemd-shared.la \
|
||||
$(LIBCRYPTSETUP_LIBS)
|
||||
|
||||
systemd_veritysetup_generator_SOURCES = \
|
||||
src/veritysetup/veritysetup-generator.c
|
||||
|
||||
systemd_veritysetup_generator_LDADD = \
|
||||
libsystemd-shared.la
|
||||
|
||||
SYSINIT_TARGET_WANTS += \
|
||||
cryptsetup.target
|
||||
|
||||
|
5
NEWS
5
NEWS
@ -6,6 +6,11 @@ CHANGES WITH 233 in spe
|
||||
sure your system has dbus >= 1.9.18 running before upgrading to this
|
||||
version, or override the install path with --with-dbuspolicydir= .
|
||||
|
||||
* The shell invoked by debug-shell.service now defaults to /bin/sh in
|
||||
all cases. If distributions want to use a different shell for this
|
||||
purpose (for example Fedora's /sbin/sushell) they need to specify
|
||||
this explicitly at configure time using --with-debug-shell=.
|
||||
|
||||
* The confirmation spawn prompt has been reworked to offer the
|
||||
following choices:
|
||||
|
||||
|
17
TODO
17
TODO
@ -24,6 +24,19 @@ Janitorial Clean-ups:
|
||||
|
||||
Features:
|
||||
|
||||
* Maybe add a small tool invoked early at boot, that adds in or resizes
|
||||
partitions automatically, to be used when the media used is actually larger
|
||||
than the image written onto it is.
|
||||
|
||||
* change the dependency Set* objects in Unit structures to become Hashmap*, and
|
||||
then store a bit mask who created a specific dependency: the source unit via
|
||||
fragment configuration, the destination unit via fragment configuration, or
|
||||
the source unit via udev rules (in case of .device units), or any combination
|
||||
thereof. This information can then be used to flush out old udev-created
|
||||
dependencies when the udev properties change, and eventually to implement a
|
||||
"systemctl refresh" operation for reloading the configuration of individual
|
||||
units without reloading the whole set.
|
||||
|
||||
* Add ExecMonitor= setting. May be used multiple times. Forks off a process in
|
||||
the service cgroup, which is supposed to monitor the service, and when it
|
||||
exits the service is considered failed by its monitor.
|
||||
@ -55,8 +68,6 @@ Features:
|
||||
partition, that is mounted to / and is writable, and where the actual root's
|
||||
/usr is mounted into.
|
||||
|
||||
* add dm-verity boots, and in nspawn (libcryptsetup knows this, should be relatively straight-forward)
|
||||
|
||||
* machined: add apis to query /etc/machine-info data of a container
|
||||
|
||||
* .mount and .swap units: add Format=yes|no option that formats the partition before mounting/enabling it, implicitly
|
||||
@ -295,7 +306,6 @@ Features:
|
||||
|
||||
* support empty /etc boots nicely:
|
||||
- nspawn/gpt-generator: introduce new gpt partition type for /usr
|
||||
- fstab-generator: support systemd.volatile=yes|no|state on the kernel cmdline, too, similar to nspawn's --volatile=
|
||||
|
||||
* generator that automatically discovers btrfs subvolumes, identifies their purpose based on some xattr on them.
|
||||
|
||||
@ -311,7 +321,6 @@ Features:
|
||||
* add bus api to query unit file's X fields.
|
||||
|
||||
* gpt-auto-generator:
|
||||
- Support LUKS for root devices
|
||||
- Define new partition type for encrypted swap? Support probed LUKS for encrypted swap?
|
||||
- Make /home automount rather than mount?
|
||||
|
||||
|
@ -554,8 +554,8 @@ AS_IF([test "x$enable_wheel_group" != "xno"], [
|
||||
AC_ARG_WITH(debug-shell,
|
||||
AS_HELP_STRING([--with-debug-shell=PATH],
|
||||
[path to debug shell binary]),
|
||||
[SUSHELL="$withval"],[
|
||||
AS_IF([test "x${have_selinux}" != "xno"], [SUSHELL="/sbin/sushell"] , [SUSHELL="/bin/sh"])])
|
||||
[SUSHELL="$withval"],
|
||||
[SUSHELL="/bin/sh"])
|
||||
|
||||
AC_SUBST(SUSHELL)
|
||||
|
||||
|
@ -102,7 +102,7 @@
|
||||
<varlistentry>
|
||||
<term><varname>systemd.mask=</varname></term>
|
||||
<term><varname>systemd.wants=</varname></term>
|
||||
<term><varname>systemd.debug-shell</varname></term>
|
||||
<term><varname>systemd.debug_shell</varname></term>
|
||||
<listitem>
|
||||
<para>Additional parameters understood by
|
||||
<citerefentry><refentrytitle>systemd-debug-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
@ -124,6 +124,28 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.volatile=</varname></term>
|
||||
<listitem>
|
||||
<para>This parameter controls whether the system shall boot up in volatile mode. Takes a boolean argument, or
|
||||
the special value <literal>state</literal>. If false (the default), normal boot mode is selected, the root
|
||||
directory and <filename>/var</filename> are mounted as specified on the kernel command line or
|
||||
<filename>/etc/fstab</filename>, or otherwise configured. If true, full state-less boot mode is selected. In
|
||||
this case the root directory is mounted as volatile memory file system (<literal>tmpfs</literal>), and only
|
||||
<filename>/usr</filename> is mounted from the file system configured as root device, in read-only mode. This
|
||||
enables fully state-less boots were the vendor-supplied OS is used as shipped, with only default
|
||||
configuration and no stored state in effect, as <filename>/etc</filename> and <filename>/var</filename> (as
|
||||
well as all other resources shipped in the root file system) are reset at boot and lost on shutdown. If this
|
||||
setting is set to <literal>state</literal> the root file system is mounted as usual, however
|
||||
<filename>/var</filename> is mounted as a volatile memory file system (<literal>tmpfs</literal>), so that the
|
||||
system boots up with the normal configuration applied, but all state reset at boot and lost at shutdown. For details,
|
||||
see
|
||||
<citerefentry><refentrytitle>systemd-volatile-root.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
and
|
||||
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>quiet</varname></term>
|
||||
<listitem>
|
||||
@ -236,14 +258,14 @@
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>udev.log-priority=</varname></term>
|
||||
<term><varname>rd.udev.log-priority=</varname></term>
|
||||
<term><varname>udev.children-max=</varname></term>
|
||||
<term><varname>rd.udev.children-max=</varname></term>
|
||||
<term><varname>udev.exec-delay=</varname></term>
|
||||
<term><varname>rd.udev.exec-delay=</varname></term>
|
||||
<term><varname>udev.event-timeout=</varname></term>
|
||||
<term><varname>rd.udev.event-timeout=</varname></term>
|
||||
<term><varname>udev.log_priority=</varname></term>
|
||||
<term><varname>rd.udev.log_priority=</varname></term>
|
||||
<term><varname>udev.children_max=</varname></term>
|
||||
<term><varname>rd.udev.children_max=</varname></term>
|
||||
<term><varname>udev.exec_delay=</varname></term>
|
||||
<term><varname>rd.udev.exec_delay=</varname></term>
|
||||
<term><varname>udev.event_timeout=</varname></term>
|
||||
<term><varname>rd.udev.event_timeout=</varname></term>
|
||||
<term><varname>net.ifnames=</varname></term>
|
||||
|
||||
<listitem>
|
||||
@ -311,6 +333,19 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>roothash=</varname></term>
|
||||
<term><varname>systemd.verity=</varname></term>
|
||||
<term><varname>rd.systemd.verity=</varname></term>
|
||||
<term><varname>systemd.verity_root_data=</varname></term>
|
||||
<term><varname>systemd.verity_root_hash=</varname></term>
|
||||
<listitem>
|
||||
<para>Configures the integrity protection root hash for the root file system, and other related
|
||||
parameters. For details, see
|
||||
<citerefentry><refentrytitle>systemd-veritysetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.gpt_auto=</varname></term>
|
||||
<term><varname>rd.systemd.gpt_auto=</varname></term>
|
||||
@ -332,8 +367,8 @@
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>modules-load=</varname></term>
|
||||
<term><varname>rd.modules-load=</varname></term>
|
||||
<term><varname>modules_load=</varname></term>
|
||||
<term><varname>rd.modules_load=</varname></term>
|
||||
|
||||
<listitem>
|
||||
<para>Load a specific kernel module early at boot. For
|
||||
@ -353,6 +388,15 @@
|
||||
<citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.firstboot=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument, defaults to on. If off,
|
||||
<citerefentry><refentrytitle>systemd-firstboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
will not query the user for basic system settings, even if the system boots up for the first time and the
|
||||
relevant settings are not initialized yet.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
@ -371,12 +415,15 @@
|
||||
<citerefentry><refentrytitle>systemd-udevd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry project='die-net'><refentrytitle>plymouth</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-veritysetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-volatile-root.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-modules-load.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-backlight@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-rfkill.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-firstboot.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -66,9 +66,8 @@
|
||||
password using the right mechanism at boot and during
|
||||
runtime.</para>
|
||||
|
||||
<para>At early boot and when the system manager configuration is
|
||||
reloaded this <filename>/etc/crypttab</filename> is translated
|
||||
into <filename>systemd-cryptsetup@.service</filename> units by
|
||||
<para>At early boot and when the system manager configuration is reloaded, <filename>/etc/crypttab</filename> is
|
||||
translated into <filename>systemd-cryptsetup@.service</filename> units by
|
||||
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -70,7 +70,7 @@
|
||||
the initial transaction. This is useful to start one or more
|
||||
additional units at boot. May be specified more than once.</para>
|
||||
|
||||
<para>If the <option>systemd.debug-shell</option> option is
|
||||
<para>If the <option>systemd.debug_shell</option> option is
|
||||
specified, the debug shell service
|
||||
<literal>debug-shell.service</literal> is pulled into the boot
|
||||
transaction. It will spawn a debug shell on tty9 during early
|
||||
|
@ -240,6 +240,20 @@
|
||||
otherwise.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Kernel Command Line</title>
|
||||
|
||||
<variablelist class='kernel-commandline-options'>
|
||||
<varlistentry>
|
||||
<term><varname>systemd.firstboot=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument, defaults to on. If off, <filename>systemd-firstboot.service</filename>
|
||||
won't interactively query the user for basic settings at first boot, even if those settings are not
|
||||
initialized yet.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
|
@ -89,12 +89,13 @@
|
||||
|
||||
<listitem><para>Takes a boolean argument. Defaults to
|
||||
<literal>yes</literal>. If <literal>no</literal>, causes the
|
||||
generator to ignore any mounts or swaps configured in
|
||||
generator to ignore any mounts or swap devices configured in
|
||||
<filename>/etc/fstab</filename>. <varname>rd.fstab=</varname>
|
||||
is honored only by initial RAM disk (initrd) while
|
||||
is honored only by the initial RAM disk (initrd) while
|
||||
<varname>fstab=</varname> is honored by both the main system
|
||||
and the initrd.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>root=</varname></term>
|
||||
|
||||
@ -102,6 +103,7 @@
|
||||
initrd. <varname>root=</varname> is honored by the
|
||||
initrd.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>rootfstype=</varname></term>
|
||||
|
||||
@ -109,6 +111,7 @@
|
||||
passed to the mount command. <varname>rootfstype=</varname> is
|
||||
honored by the initrd.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>rootflags=</varname></term>
|
||||
|
||||
@ -116,6 +119,7 @@
|
||||
use. <varname>rootflags=</varname> is honored by the
|
||||
initrd.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>mount.usr=</varname></term>
|
||||
|
||||
@ -133,6 +137,7 @@
|
||||
<para><varname>mount.usr=</varname> is honored by the initrd.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>mount.usrfstype=</varname></term>
|
||||
|
||||
@ -150,6 +155,7 @@
|
||||
<para><varname>mount.usrfstype=</varname> is honored by the
|
||||
initrd.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>mount.usrflags=</varname></term>
|
||||
|
||||
@ -166,6 +172,39 @@
|
||||
<para><varname>mount.usrflags=</varname> is honored by the
|
||||
initrd.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.volatile=</varname></term>
|
||||
|
||||
<listitem><para>Controls whether the system shall boot up in volatile mode. Takes a boolean argument or the
|
||||
special value <option>state</option>.</para>
|
||||
|
||||
<para>If false (the default), this generator makes no changes to the mount tree and the system is booted up in
|
||||
normal mode.</para>
|
||||
|
||||
<para>If true the generator ensures
|
||||
<citerefentry><refentrytitle>systemd-volatile-root.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
is run as part of the initial RAM disk ("initrd"). This service changes the mount table before transitioning to
|
||||
the host system, so that a volatile memory file system (<literal>tmpfs</literal>) is used as root directory,
|
||||
with only <filename>/usr</filename> mounted into it from the configured root file system, in read-only
|
||||
mode. This way the system operates in fully stateless mode, with all configuration and state reset at boot and
|
||||
lost at shutdown, as <filename>/etc</filename> and <filename>/var</filename> will be served from the (initially
|
||||
unpopulated) volatile memory file system.</para>
|
||||
|
||||
<para>If set to <option>state</option> the generator will leave the root
|
||||
directory mount point unaltered, however will mount a <literal>tmpfs</literal> file system to
|
||||
<filename>/var</filename>. In this mode the normal system configuration (i.e the contents of
|
||||
<literal>/etc</literal>) is in effect (and may be modified during system runtime), however the system state
|
||||
(i.e. the contents of <literal>/var</literal>) is reset at boot and lost at shutdown.</para>
|
||||
|
||||
<para>Note that in none of these modes the root directory, <filename>/etc</filename>, <filename>/var</filename>
|
||||
or any other resources stored in the root file system are physically removed. It's thus safe to boot a system
|
||||
that is normally operated in non-volatile mode temporarily into volatile mode, without losing data.</para>
|
||||
|
||||
<para>Note that enabling this setting will only work correctly on operating systems that can boot up with only
|
||||
<filename>/usr</filename> mounted, and are able to automatically populate <filename>/etc</filename>, and also
|
||||
<filename>/var</filename> in case of <literal>systemd.volatile=yes</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
@ -176,7 +215,8 @@
|
||||
<citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd.swap</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -73,8 +73,8 @@
|
||||
<variablelist class='kernel-commandline-options'>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>modules-load=</varname></term>
|
||||
<term><varname>rd.modules-load=</varname></term>
|
||||
<term><varname>modules_load=</varname></term>
|
||||
<term><varname>rd.modules_load=</varname></term>
|
||||
|
||||
<listitem><para>Takes a comma-separated list of kernel modules
|
||||
to statically load during early boot. The option prefixed with
|
||||
|
@ -939,12 +939,15 @@
|
||||
<option>no</option> (the default), the whole OS tree is made
|
||||
available writable.</para>
|
||||
|
||||
<para>Note that setting this to <option>yes</option> or
|
||||
<option>state</option> will only work correctly with
|
||||
operating systems in the container that can boot up with only
|
||||
<filename>/usr</filename> mounted, and are able to populate
|
||||
<filename>/var</filename> automatically, as
|
||||
needed.</para></listitem>
|
||||
<para>This option provides similar functionality for containers as the <literal>systemd.volatile=</literal>
|
||||
kernel command line switch provides for host systems. See
|
||||
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
|
||||
details.</para>
|
||||
|
||||
<para>Note that enabling this setting will only work correctly with operating systems in the container that can
|
||||
boot up with only <filename>/usr</filename> mounted, and are able to automatically populate
|
||||
<filename>/var</filename>, and also <filename>/etc</filename> in case of
|
||||
<literal>--volatile=yes</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -97,12 +97,10 @@
|
||||
<term><varname>DefaultStandardOutput=journal</varname></term>
|
||||
<term><varname>DefaultStandardError=inherit</varname></term>
|
||||
|
||||
<listitem><para>Configures various parameters of basic manager
|
||||
operation. These options may be overridden by the respective
|
||||
command line arguments. See
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
for details about these command line
|
||||
arguments.</para></listitem>
|
||||
<listitem><para>Configures various parameters of basic manager operation. These options may be overridden by
|
||||
the respective process and kernel command line arguments. See
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> for
|
||||
details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -133,22 +133,22 @@
|
||||
<para>Parameters starting with "rd." will be read when
|
||||
<command>systemd-udevd</command> is used in an initrd.</para>
|
||||
<varlistentry>
|
||||
<term><varname>udev.log-priority=</varname></term>
|
||||
<term><varname>rd.udev.log-priority=</varname></term>
|
||||
<term><varname>udev.log_priority=</varname></term>
|
||||
<term><varname>rd.udev.log_priority=</varname></term>
|
||||
<listitem>
|
||||
<para>Set the log level.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>udev.children-max=</varname></term>
|
||||
<term><varname>rd.udev.children-max=</varname></term>
|
||||
<term><varname>udev.children_max=</varname></term>
|
||||
<term><varname>rd.udev.children_max=</varname></term>
|
||||
<listitem>
|
||||
<para>Limit the number of events executed in parallel.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>udev.exec-delay=</varname></term>
|
||||
<term><varname>rd.udev.exec-delay=</varname></term>
|
||||
<term><varname>udev.exec_delay=</varname></term>
|
||||
<term><varname>rd.udev.exec_delay=</varname></term>
|
||||
<listitem>
|
||||
<para>Delay the execution of <varname>RUN</varname> instructions by the given
|
||||
number of seconds. This option might be useful when
|
||||
@ -157,8 +157,8 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>udev.event-timeout=</varname></term>
|
||||
<term><varname>rd.udev.event-timeout=</varname></term>
|
||||
<term><varname>udev.event_timeout=</varname></term>
|
||||
<term><varname>rd.udev.event_timeout=</varname></term>
|
||||
<listitem>
|
||||
<para>Wait for events to finish up to the given number
|
||||
of seconds. This option might be useful if events are
|
||||
|
122
man/systemd-veritysetup-generator.xml
Normal file
122
man/systemd-veritysetup-generator.xml
Normal file
@ -0,0 +1,122 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Lennart Poettering
|
||||
|
||||
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.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<refentry id="systemd-veritysetup-generator" conditional='HAVE_LIBCRYPTSETUP'>
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-veritysetup-generator</title>
|
||||
<productname>systemd</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Lennart</firstname>
|
||||
<surname>Poettering</surname>
|
||||
<email>lennart@poettering.net</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-veritysetup-generator</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-veritysetup-generator</refname>
|
||||
<refpurpose>Unit generator for integrity protected block devices</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>/usr/lib/systemd/system-generators/systemd-veritysetup-generator</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-veritysetup-generator</filename> is a generator that translates kernel command line options
|
||||
configuring integrity protected block devices (verity) into native systemd units early at boot and when
|
||||
configuration of the system manager is reloaded. This will create
|
||||
<citerefentry><refentrytitle>systemd-veritysetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
units as necessary.</para>
|
||||
|
||||
<para>Currently, only a single verity device may be se up with this generator, backing the root file system of the
|
||||
OS.</para>
|
||||
|
||||
<para><filename>systemd-veritysetup-generator</filename> implements
|
||||
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Kernel Command Line</title>
|
||||
|
||||
<para><filename>systemd-veritysetup-generator</filename>
|
||||
understands the following kernel command line parameters:</para>
|
||||
|
||||
<variablelist class='kernel-commandline-options'>
|
||||
<varlistentry>
|
||||
<term><varname>systemd.verity=</varname></term>
|
||||
<term><varname>rd.systemd.verity=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. Defaults to <literal>yes</literal>. If <literal>no</literal>,
|
||||
disables the generator entirely. <varname>rd.systemd.verity=</varname> is honored only by the initial RAM disk
|
||||
(initrd) while <varname>systemd.verity=</varname> is honored by both the host system and the
|
||||
initrd. </para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>roothash=</varname></term>
|
||||
|
||||
<listitem><para>Takes a root hash value for the root file system. Expects a hash value formatted in hexadecimal
|
||||
characters, of the appropriate length (i.e. most likely 256 bit/64 characters, or longer). If not specified via
|
||||
<varname>systemd.verity_root_data=</varname> and <varname>systemd.verity_root_hash=</varname>, the hash and
|
||||
data devices to use are automatically derived from the specified hash value. Specifically, the data partition
|
||||
device is looked for under a GPT partition UUID derived from the first 128bit of the root hash, the hash
|
||||
partition device is looked for under a GPT partition UUID derived from the last 128bit of the root hash. Hence
|
||||
it is usually sufficient to specify the root hash to boot from an integrity protected root file system, as
|
||||
device paths are automatically determined from it — as long as the partition table is properly set up.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.verity_root_data=</varname></term>
|
||||
<term><varname>systemd.verity_root_hash=</varname></term>
|
||||
|
||||
<listitem><para>These two settings take block device paths as arguments, and may be use to explicitly configure
|
||||
the data partition and hash partition to use for setting up the integrity protection for the root file
|
||||
system. If not specified, these paths are automatically derived from the <varname>roothash=</varname> argument
|
||||
(see above).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-veritysetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry project='die-net'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
75
man/systemd-veritysetup@.service.xml
Normal file
75
man/systemd-veritysetup@.service.xml
Normal file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Lennart Poettering
|
||||
|
||||
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.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<refentry id="systemd-veritysetup@.service" conditional='HAVE_LIBCRYPTSETUP'>
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-veritysetup@.service</title>
|
||||
<productname>systemd</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Lennart</firstname>
|
||||
<surname>Poettering</surname>
|
||||
<email>lennart@poettering.net</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-veritysetup@.service</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-veritysetup@.service</refname>
|
||||
<refname>systemd-veritysetup</refname>
|
||||
<refpurpose>Disk integrity protection logic</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>systemd-veritysetup@.service</filename></para>
|
||||
<para><filename>/usr/lib/systemd/systemd-veritysetup</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-veritysetup@.service</filename> is a service responsible for setting up integrity
|
||||
protection (verity) block devices. It should be instantiated for each device that requires integrity
|
||||
protection.</para>
|
||||
|
||||
<para>At early boot and when the system manager configuration is reloaded kernel command line configuration for
|
||||
integrity protected block devices is translated into <filename>systemd-veritysetup@.service</filename> units by
|
||||
<citerefentry><refentrytitle>systemd-veritysetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-veritysetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry project='die-net'><refentrytitle>veritysetup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
79
man/systemd-volatile-root.service.xml
Normal file
79
man/systemd-volatile-root.service.xml
Normal file
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Lennart Poettering
|
||||
|
||||
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.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<refentry id="systemd-volatile-root.service">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-volatile-root.service</title>
|
||||
<productname>systemd</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Lennart</firstname>
|
||||
<surname>Poettering</surname>
|
||||
<email>lennart@poettering.net</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-volatile-root.service</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-volatile-root.service</refname>
|
||||
<refname>systemd-volatile-root</refname>
|
||||
<refpurpose>Make the root file system volatile</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>systemd-volatile-root.service</filename></para>
|
||||
<para><filename>/usr/lib/systemd/systemd-volatile-root</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><filename>systemd-volatile-root.service</filename> is a service that replaces the root directory with a
|
||||
volatile memory file system (<literal>tmpfs</literal>), mounting the original (non-volatile)
|
||||
<filename>/usr</filename> inside it read-only. This way, vendor data from <filename>/usr</filename> is available as
|
||||
usual, but all configuration data in <filename>/etc</filename>, all state data in <filename>/var</filename> and all
|
||||
other resources stored directly under the root directory are reset on boot and lost at shutdown, enabling fully
|
||||
stateless systems.</para>
|
||||
|
||||
<para>This service is only enabled if full volatile mode is selected, for example by specifying
|
||||
<literal>systemd.volatile=yes</literal> on the kernel command line. This service runs only in the initial RAM disk
|
||||
("initrd"), before the system transitions to the host's root directory. Note that this service is not used if
|
||||
<literal>systemd.volatile=state</literal> is used, as in that mode the root directory is non-volatile.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
@ -284,7 +284,9 @@
|
||||
providing multiple command lines in the same directive, or alternatively, this directive may be specified more
|
||||
than once with the same effect. If the empty string is assigned to this option, the list of commands to start
|
||||
is reset, prior assignments of this option will have no effect. If no <varname>ExecStart=</varname> is
|
||||
specified, then the service must have <varname>RemainAfterExit=yes</varname> set.</para>
|
||||
specified, then the service must have <varname>RemainAfterExit=yes</varname> and at least one
|
||||
<varname>ExecStop=</varname> line set. (Services lacking both <varname>ExecStart=</varname> and
|
||||
<varname>ExecStop=</varname> are not valid.)</para>
|
||||
|
||||
<para>For each of the specified commands, the first argument must be an absolute path to an
|
||||
executable. Optionally, if this file name is prefixed with <literal>@</literal>, the second token will be
|
||||
|
@ -183,10 +183,14 @@
|
||||
<varlistentry>
|
||||
<term><option>--show-status=</option></term>
|
||||
|
||||
<listitem><para>Show terse service status information while
|
||||
booting. This switch has no effect when run as user instance.
|
||||
Takes a boolean argument which may be omitted which is
|
||||
interpreted as <option>true</option>.</para></listitem>
|
||||
<listitem><para>Takes a boolean argument or the special value <constant>auto</constant>. If on, terse unit
|
||||
status information is shown on the console during boot-up and shutdown. If off, no such status information is
|
||||
shown. If set to <constant>auto</constant> behavior is similar to off, except that it is automatically switched
|
||||
to on, as soon as the first unit failure or significant boot delay is encountered. This switch has no effect
|
||||
when invoked as user instance. If specified, overrides both the kernel command line setting
|
||||
<varname>systemd.show_status=</varname> (see below) and the configuration file option
|
||||
<option>ShowStatus=</option>, see
|
||||
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--log-target=</option></term>
|
||||
@ -953,15 +957,15 @@
|
||||
<varlistentry>
|
||||
<term><varname>systemd.show_status=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument or the constant
|
||||
<constant>auto</constant>. If <option>yes</option>, the
|
||||
systemd manager (PID 1) shows terse service status updates on
|
||||
the console during bootup. <constant>auto</constant> behaves
|
||||
like <option>false</option> until a service fails or there is
|
||||
a significant delay in boot. Defaults to
|
||||
<option>yes</option>, unless <option>quiet</option> is passed
|
||||
as kernel command line option, in which case it defaults to
|
||||
<constant>auto</constant>.</para></listitem>
|
||||
<listitem><para>Takes a boolean argument or the constant <constant>auto</constant>. If <option>yes</option>,
|
||||
the systemd manager (PID 1) shows terse service status updates on the console during bootup.
|
||||
<constant>auto</constant> behaves like <option>false</option> until a unit fails or there is a significant
|
||||
delay in boot. Defaults to <option>yes</option>, unless <option>quiet</option> is passed as kernel command
|
||||
line option, in which case it defaults to <constant>auto</constant>. If specified overrides the system manager
|
||||
configuration file option <option>ShowStatus=</option>, see
|
||||
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>. However,
|
||||
the process command line option <option>--show-status=</option> takes precedence over both this kernel command
|
||||
line option and the configuration file option.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -88,7 +88,4 @@ ENV{DEVTYPE}=="partition", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-i
|
||||
ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}"
|
||||
ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/by-partlabel/$env{ID_PART_ENTRY_NAME}"
|
||||
|
||||
# add symlink to GPT root disk
|
||||
ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_GPT_AUTO_ROOT}=="1", SYMLINK+="gpt-auto-root"
|
||||
|
||||
LABEL="persistent_storage_end"
|
||||
|
@ -17,6 +17,11 @@ SUBSYSTEM=="block", ACTION=="add", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", E
|
||||
# we are probably still calling mke2fs or mkswap on it.
|
||||
SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"
|
||||
|
||||
# add symlink to GPT root disk
|
||||
SUBSYSTEM=="block", ENV{ID_PART_GPT_AUTO_ROOT}=="1", ENV{ID_FS_TYPE}!="crypto_LUKS", SYMLINK+="gpt-auto-root"
|
||||
SUBSYSTEM=="block", ENV{ID_PART_GPT_AUTO_ROOT}=="1", ENV{ID_FS_TYPE}=="crypto_LUKS", SYMLINK+="gpt-auto-root-luks"
|
||||
SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{DM_NAME}=="root", SYMLINK+="gpt-auto-root"
|
||||
|
||||
# Ignore raid devices that are not yet assembled and started
|
||||
SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", TEST!="md/array_state", ENV{SYSTEMD_READY}="0"
|
||||
SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", ATTR{md/array_state}=="|clear|inactive", ENV{SYSTEMD_READY}="0"
|
||||
|
@ -2361,6 +2361,7 @@ int cg_enable_everywhere(CGroupMask supported, CGroupMask mask, const char *p) {
|
||||
bool cg_is_unified_wanted(void) {
|
||||
static thread_local int wanted = -1;
|
||||
int r, unified;
|
||||
bool b;
|
||||
|
||||
/* If the hierarchy is already mounted, then follow whatever
|
||||
* was chosen for it. */
|
||||
@ -2374,20 +2375,11 @@ bool cg_is_unified_wanted(void) {
|
||||
if (wanted >= 0)
|
||||
return wanted;
|
||||
|
||||
r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy", NULL);
|
||||
if (r > 0)
|
||||
return (wanted = true);
|
||||
else {
|
||||
_cleanup_free_ char *value = NULL;
|
||||
r = proc_cmdline_get_bool("systemd.unified_cgroup_hierarchy", &b);
|
||||
if (r < 0)
|
||||
return false;
|
||||
|
||||
r = get_proc_cmdline_key("systemd.unified_cgroup_hierarchy=", &value);
|
||||
if (r < 0)
|
||||
return false;
|
||||
if (r == 0)
|
||||
return (wanted = false);
|
||||
|
||||
return (wanted = parse_boolean(value) > 0);
|
||||
}
|
||||
return (wanted = r > 0 ? b : false);
|
||||
}
|
||||
|
||||
bool cg_is_legacy_wanted(void) {
|
||||
@ -2397,6 +2389,7 @@ bool cg_is_legacy_wanted(void) {
|
||||
bool cg_is_unified_systemd_controller_wanted(void) {
|
||||
static thread_local int wanted = -1;
|
||||
int r, unified;
|
||||
bool b;
|
||||
|
||||
/* If the unified hierarchy is requested in full, no need to
|
||||
* bother with this. */
|
||||
@ -2415,23 +2408,11 @@ bool cg_is_unified_systemd_controller_wanted(void) {
|
||||
if (wanted >= 0)
|
||||
return wanted;
|
||||
|
||||
r = get_proc_cmdline_key("systemd.legacy_systemd_cgroup_controller", NULL);
|
||||
if (r > 0)
|
||||
wanted = false;
|
||||
else {
|
||||
_cleanup_free_ char *value = NULL;
|
||||
r = proc_cmdline_get_bool("systemd.legacy_systemd_cgroup_controller", &b);
|
||||
if (r < 0)
|
||||
return false;
|
||||
|
||||
r = get_proc_cmdline_key("systemd.legacy_systemd_cgroup_controller=", &value);
|
||||
if (r < 0)
|
||||
return false;
|
||||
|
||||
if (r == 0)
|
||||
wanted = false;
|
||||
else
|
||||
wanted = parse_boolean(value) <= 0;
|
||||
}
|
||||
|
||||
return wanted;
|
||||
return (wanted = r > 0 ? b : false);
|
||||
}
|
||||
|
||||
bool cg_is_legacy_systemd_controller_wanted(void) {
|
||||
|
@ -799,8 +799,10 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*ret = done;
|
||||
done = NULL;
|
||||
if (ret) {
|
||||
*ret = done;
|
||||
done = NULL;
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
@ -97,6 +97,9 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
|
||||
assert(len);
|
||||
assert(p);
|
||||
|
||||
if (l % 2 != 0)
|
||||
return -EINVAL;
|
||||
|
||||
z = r = malloc((l + 1) / 2 + 1);
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
@ -107,12 +110,10 @@ int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
|
||||
a = unhexchar(x[0]);
|
||||
if (a < 0)
|
||||
return a;
|
||||
else if (x+1 < p + l) {
|
||||
b = unhexchar(x[1]);
|
||||
if (b < 0)
|
||||
return b;
|
||||
} else
|
||||
b = 0;
|
||||
|
||||
b = unhexchar(x[1]);
|
||||
if (b < 0)
|
||||
return b;
|
||||
|
||||
*(z++) = (uint8_t) a << 4 | (uint8_t) b;
|
||||
}
|
||||
|
@ -981,24 +981,30 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
if (streq(key, "debug") && !value)
|
||||
log_set_max_level(LOG_DEBUG);
|
||||
|
||||
else if (streq(key, "systemd.log_target") && value) {
|
||||
else if (proc_cmdline_key_streq(key, "systemd.log_target")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (log_set_target_from_string(value) < 0)
|
||||
log_warning("Failed to parse log target '%s'. Ignoring.", value);
|
||||
|
||||
} else if (streq(key, "systemd.log_level") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (log_set_max_level_from_string(value) < 0)
|
||||
log_warning("Failed to parse log level '%s'. Ignoring.", value);
|
||||
|
||||
} else if (streq(key, "systemd.log_color") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
|
||||
|
||||
if (log_show_color_from_string(value) < 0)
|
||||
if (log_show_color_from_string(value ?: "1") < 0)
|
||||
log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
|
||||
|
||||
} else if (streq(key, "systemd.log_location") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
|
||||
|
||||
if (log_show_location_from_string(value) < 0)
|
||||
if (log_show_location_from_string(value ?: "1") < 0)
|
||||
log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
|
||||
}
|
||||
|
||||
@ -1009,10 +1015,9 @@ void log_parse_environment(void) {
|
||||
const char *e;
|
||||
|
||||
if (get_ctty_devnr(0, NULL) < 0)
|
||||
/* Only try to read the command line in daemons.
|
||||
We assume that anything that has a controlling
|
||||
tty is user stuff. */
|
||||
(void) parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
|
||||
/* Only try to read the command line in daemons. We assume that anything that has a controlling tty is
|
||||
user stuff. */
|
||||
(void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||
|
||||
e = secure_getenv("SYSTEMD_LOG_TARGET");
|
||||
if (e && log_set_target_from_string(e) < 0)
|
||||
|
@ -673,6 +673,9 @@ int mount_verbose(
|
||||
else if ((flags & MS_BIND) && !type)
|
||||
log_debug("Bind-mounting %s on %s (%s \"%s\")...",
|
||||
what, where, strnull(fl), strempty(options));
|
||||
else if (flags & MS_MOVE)
|
||||
log_debug("Moving mount %s → %s (%s \"%s\")...",
|
||||
what, where, strnull(fl), strempty(options));
|
||||
else
|
||||
log_debug("Mounting %s on %s (%s \"%s\")...",
|
||||
strna(type), where, strnull(fl), strempty(options));
|
||||
|
@ -34,17 +34,30 @@
|
||||
#include "virt.h"
|
||||
|
||||
int proc_cmdline(char **ret) {
|
||||
const char *e;
|
||||
assert(ret);
|
||||
|
||||
/* For testing purposes it is sometimes useful to be able to override what we consider /proc/cmdline to be */
|
||||
e = secure_getenv("SYSTEMD_PROC_CMDLINE");
|
||||
if (e) {
|
||||
char *m;
|
||||
|
||||
m = strdup(e);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (detect_container() > 0)
|
||||
return get_process_cmdline(1, 0, false, ret);
|
||||
else
|
||||
return read_one_line_file("/proc/cmdline", ret);
|
||||
}
|
||||
|
||||
int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, void *data),
|
||||
void *data,
|
||||
bool strip_prefix) {
|
||||
int proc_cmdline_parse(proc_cmdline_parse_t parse_item, void *data, unsigned flags) {
|
||||
|
||||
_cleanup_free_ char *line = NULL;
|
||||
const char *p;
|
||||
int r;
|
||||
@ -58,7 +71,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, voi
|
||||
p = line;
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
char *value = NULL, *unprefixed;
|
||||
char *value, *key, *q;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
|
||||
if (r < 0)
|
||||
@ -66,17 +79,23 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, voi
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
/* Filter out arguments that are intended only for the
|
||||
* initrd */
|
||||
unprefixed = startswith(word, "rd.");
|
||||
if (unprefixed && !in_initrd())
|
||||
continue;
|
||||
key = word;
|
||||
|
||||
value = strchr(word, '=');
|
||||
/* Filter out arguments that are intended only for the initrd */
|
||||
q = startswith(word, "rd.");
|
||||
if (q) {
|
||||
if (!in_initrd())
|
||||
continue;
|
||||
|
||||
if (flags & PROC_CMDLINE_STRIP_RD_PREFIX)
|
||||
key = q;
|
||||
}
|
||||
|
||||
value = strchr(key, '=');
|
||||
if (value)
|
||||
*(value++) = 0;
|
||||
|
||||
r = parse_item(strip_prefix && unprefixed ? unprefixed : word, value, data);
|
||||
r = parse_item(key, value, data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -84,13 +103,64 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, voi
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_proc_cmdline_key(const char *key, char **value) {
|
||||
static bool relaxed_equal_char(char a, char b) {
|
||||
|
||||
return a == b ||
|
||||
(a == '_' && b == '-') ||
|
||||
(a == '-' && b == '_');
|
||||
}
|
||||
|
||||
char *proc_cmdline_key_startswith(const char *s, const char *prefix) {
|
||||
|
||||
assert(s);
|
||||
assert(prefix);
|
||||
|
||||
/* Much like startswith(), but considers "-" and "_" the same */
|
||||
|
||||
for (; *prefix != 0; s++, prefix++)
|
||||
if (!relaxed_equal_char(*s, *prefix))
|
||||
return NULL;
|
||||
|
||||
return (char*) s;
|
||||
}
|
||||
|
||||
bool proc_cmdline_key_streq(const char *x, const char *y) {
|
||||
assert(x);
|
||||
assert(y);
|
||||
|
||||
/* Much like streq(), but considers "-" and "_" the same */
|
||||
|
||||
for (; *x != 0 || *y != 0; x++, y++)
|
||||
if (!relaxed_equal_char(*x, *y))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int proc_cmdline_get_key(const char *key, unsigned flags, char **value) {
|
||||
_cleanup_free_ char *line = NULL, *ret = NULL;
|
||||
bool found = false;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
/* Looks for a specific key on the kernel command line. Supports two modes:
|
||||
*
|
||||
* a) The "value" parameter is used. In this case a parameter beginning with the "key" string followed by "="
|
||||
* is searched, and the value following this is returned in "value".
|
||||
*
|
||||
* b) as above, but the PROC_CMDLINE_VALUE_OPTIONAL flag is set. In this case if the the key is found as a
|
||||
* separate word (i.e. not followed by "=" but instead by whitespace or the end of the command line), then
|
||||
* this is also accepted, and "value" is returned as NULL.
|
||||
*
|
||||
* c) The "value" parameter is NULL. In this case a search for the exact "key" parameter is performed.
|
||||
*
|
||||
* In all three cases, > 0 is returned if the key is found, 0 if not.*/
|
||||
|
||||
if (isempty(key))
|
||||
return -EINVAL;
|
||||
|
||||
if ((flags & PROC_CMDLINE_VALUE_OPTIONAL) && !value)
|
||||
return -EINVAL;
|
||||
|
||||
r = proc_cmdline(&line);
|
||||
if (r < 0)
|
||||
@ -107,21 +177,26 @@ int get_proc_cmdline_key(const char *key, char **value) {
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
/* Filter out arguments that are intended only for the
|
||||
* initrd */
|
||||
/* Automatically filter out arguments that are intended only for the initrd, if we are not in the
|
||||
* initrd. */
|
||||
if (!in_initrd() && startswith(word, "rd."))
|
||||
continue;
|
||||
|
||||
if (value) {
|
||||
e = startswith(word, key);
|
||||
e = proc_cmdline_key_startswith(word, key);
|
||||
if (!e)
|
||||
continue;
|
||||
|
||||
r = free_and_strdup(&ret, e);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (*e == '=') {
|
||||
r = free_and_strdup(&ret, e+1);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
found = true;
|
||||
|
||||
} else if (*e == 0 && (flags & PROC_CMDLINE_VALUE_OPTIONAL))
|
||||
found = true;
|
||||
|
||||
found = true;
|
||||
} else {
|
||||
if (streq(word, key))
|
||||
found = true;
|
||||
@ -134,20 +209,42 @@ int get_proc_cmdline_key(const char *key, char **value) {
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
int proc_cmdline_get_bool(const char *key, bool *ret) {
|
||||
_cleanup_free_ char *v = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
*ret = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v) { /* parameter passed */
|
||||
r = parse_boolean(v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
*ret = r;
|
||||
} else /* no parameter passed */
|
||||
*ret = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int shall_restore_state(void) {
|
||||
_cleanup_free_ char *value = NULL;
|
||||
bool ret;
|
||||
int r;
|
||||
|
||||
r = get_proc_cmdline_key("systemd.restore_state=", &value);
|
||||
r = proc_cmdline_get_bool("systemd.restore_state", &ret);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return true;
|
||||
|
||||
return parse_boolean(value);
|
||||
return r > 0 ? ret : true;
|
||||
}
|
||||
|
||||
static const char * const rlmap[] = {
|
||||
|
@ -19,11 +19,36 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
enum {
|
||||
PROC_CMDLINE_STRIP_RD_PREFIX = 1,
|
||||
PROC_CMDLINE_VALUE_OPTIONAL = 2,
|
||||
};
|
||||
|
||||
typedef int (*proc_cmdline_parse_t)(const char *key, const char *value, void *data);
|
||||
|
||||
int proc_cmdline(char **ret);
|
||||
int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value, void *data),
|
||||
void *data,
|
||||
bool strip_prefix);
|
||||
int get_proc_cmdline_key(const char *parameter, char **value);
|
||||
|
||||
int proc_cmdline_parse(const proc_cmdline_parse_t parse, void *userdata, unsigned flags);
|
||||
|
||||
int proc_cmdline_get_key(const char *parameter, unsigned flags, char **value);
|
||||
int proc_cmdline_get_bool(const char *key, bool *ret);
|
||||
|
||||
char *proc_cmdline_key_startswith(const char *s, const char *prefix);
|
||||
bool proc_cmdline_key_streq(const char *x, const char *y);
|
||||
|
||||
int shall_restore_state(void);
|
||||
const char* runlevel_to_target(const char *rl);
|
||||
|
||||
/* A little helper call, to be used in proc_cmdline_parse_t callbacks */
|
||||
static inline bool proc_cmdline_value_missing(const char *key, const char *value) {
|
||||
if (!value) {
|
||||
log_warning("Missing argument for %s= kernel command line switch, ignoring.", key);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include "dirent-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "macro.h"
|
||||
#include "missing.h"
|
||||
#include "stat-util.h"
|
||||
@ -143,22 +144,29 @@ int path_is_read_only_fs(const char *path) {
|
||||
}
|
||||
|
||||
int path_is_os_tree(const char *path) {
|
||||
char *p;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
/* Does the path exist at all? If not, generate an error immediately. This is useful so that a missing root dir
|
||||
* always results in -ENOENT, and we can properly distuingish the case where the whole root doesn't exist from
|
||||
* the case where just the os-release file is missing. */
|
||||
if (laccess(path, F_OK) < 0)
|
||||
return -errno;
|
||||
|
||||
/* We use /usr/lib/os-release as flag file if something is an OS */
|
||||
p = strjoina(path, "/usr/lib/os-release");
|
||||
r = access(p, F_OK);
|
||||
if (r >= 0)
|
||||
return 1;
|
||||
r = chase_symlinks("/usr/lib/os-release", path, CHASE_PREFIX_ROOT, NULL);
|
||||
if (r == -ENOENT) {
|
||||
|
||||
/* Also check for the old location in /etc, just in case. */
|
||||
p = strjoina(path, "/etc/os-release");
|
||||
r = access(p, F_OK);
|
||||
/* Also check for the old location in /etc, just in case. */
|
||||
r = chase_symlinks("/etc/os-release", path, CHASE_PREFIX_ROOT, NULL);
|
||||
if (r == -ENOENT)
|
||||
return 0; /* We got nothing */
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return r >= 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int files_same(const char *filea, const char *fileb) {
|
||||
@ -196,7 +204,7 @@ int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
|
||||
int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
@ -216,3 +224,13 @@ int fd_is_temporary_fs(int fd) {
|
||||
|
||||
return is_temporary_fs(&s);
|
||||
}
|
||||
|
||||
int path_is_temporary_fs(const char *path) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
|
||||
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
return fd_is_temporary_fs(fd);
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ int path_check_fstype(const char *path, statfs_f_type_t magic_value);
|
||||
|
||||
bool is_temporary_fs(const struct statfs *s) _pure_;
|
||||
int fd_is_temporary_fs(int fd);
|
||||
int path_is_temporary_fs(const char *path);
|
||||
|
||||
/* Because statfs.t_type can be int on some architectures, we have to cast
|
||||
* the const magic to the type, otherwise the compiler warns about
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "install.h"
|
||||
#include "log.h"
|
||||
#include "path-util.h"
|
||||
@ -1484,25 +1485,36 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (path_equal(root, "/") || !path_is_absolute(root))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid switch root path %s", root);
|
||||
if (isempty(root))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root directory may not be the empty string.");
|
||||
if (!path_is_absolute(root))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root path '%s' is not absolute.", root);
|
||||
if (path_equal(root, "/"))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root directory cannot be the old root directory.");
|
||||
|
||||
/* Safety check */
|
||||
if (isempty(init)) {
|
||||
if (!path_is_os_tree(root))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path %s does not seem to be an OS tree. os-release file is missing.", root);
|
||||
r = path_is_os_tree(root);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to determine whether root path '%s' contains an OS tree: %m", root);
|
||||
if (r == 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.", root);
|
||||
} else {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
_cleanup_free_ char *chased = NULL;
|
||||
|
||||
if (!path_is_absolute(init))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid init path %s", init);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path to init binary '%s' not absolute.", init);
|
||||
|
||||
p = strappend(root, init);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
r = chase_symlinks(init, root, CHASE_PREFIX_ROOT, &chased);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Could not resolve init executable %s: %m", init);
|
||||
|
||||
if (access(p, X_OK) < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified init binary %s does not exist.", p);
|
||||
if (laccess(chased, X_OK) < 0) {
|
||||
if (errno == EACCES)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Init binary %s is not executable.", init);
|
||||
|
||||
return sd_bus_error_set_errnof(error, r, "Could not check whether init binary %s is executable: %m", init);
|
||||
}
|
||||
}
|
||||
|
||||
rt = strdup(root);
|
||||
|
@ -645,7 +645,7 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
|
||||
[JOB_DEPENDENCY] = "Dependency failed for %s.",
|
||||
[JOB_ASSERT] = "Assertion failed for %s.",
|
||||
[JOB_UNSUPPORTED] = "Starting of %s not supported.",
|
||||
[JOB_COLLECTED] = "Unecessary job for %s was removed.",
|
||||
[JOB_COLLECTED] = "Unnecessary job for %s was removed.",
|
||||
};
|
||||
static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = {
|
||||
[JOB_DONE] = "Stopped %s.",
|
||||
|
125
src/core/main.c
125
src/core/main.c
@ -49,6 +49,7 @@
|
||||
#include "cpu-set-util.h"
|
||||
#include "dbus-manager.h"
|
||||
#include "def.h"
|
||||
#include "emergency-action.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fdset.h"
|
||||
@ -90,7 +91,6 @@
|
||||
#include "user-util.h"
|
||||
#include "virt.h"
|
||||
#include "watchdog.h"
|
||||
#include "emergency-action.h"
|
||||
|
||||
static enum {
|
||||
ACTION_RUN,
|
||||
@ -337,60 +337,73 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
|
||||
assert(key);
|
||||
|
||||
if (streq(key, "systemd.unit") && value) {
|
||||
if (STR_IN_SET(key, "systemd.unit", "rd.systemd.unit")) {
|
||||
|
||||
if (!in_initrd())
|
||||
return free_and_strdup(&arg_default_unit, value);
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
} else if (streq(key, "rd.systemd.unit") && value) {
|
||||
if (!unit_name_is_valid(value, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
|
||||
log_warning("Unit name specified on %s= is not valid, ignoring: %s", key, value);
|
||||
else if (in_initrd() == !!startswith(key, "rd.")) {
|
||||
if (free_and_strdup(&arg_default_unit, value) < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (in_initrd())
|
||||
return free_and_strdup(&arg_default_unit, value);
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.dump_core")) {
|
||||
|
||||
} else if (streq(key, "systemd.dump_core") && value) {
|
||||
|
||||
r = parse_boolean(value);
|
||||
r = value ? parse_boolean(value) : true;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse dump core switch %s. Ignoring.", value);
|
||||
else
|
||||
arg_dump_core = r;
|
||||
|
||||
} else if (streq(key, "systemd.crash_chvt") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.crash_chvt")) {
|
||||
|
||||
if (parse_crash_chvt(value) < 0)
|
||||
if (!value)
|
||||
arg_crash_chvt = 0; /* turn on */
|
||||
else if (parse_crash_chvt(value) < 0)
|
||||
log_warning("Failed to parse crash chvt switch %s. Ignoring.", value);
|
||||
|
||||
} else if (streq(key, "systemd.crash_shell") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.crash_shell")) {
|
||||
|
||||
r = parse_boolean(value);
|
||||
r = value ? parse_boolean(value) : true;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse crash shell switch %s. Ignoring.", value);
|
||||
else
|
||||
arg_crash_shell = r;
|
||||
|
||||
} else if (streq(key, "systemd.crash_reboot") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.crash_reboot")) {
|
||||
|
||||
r = parse_boolean(value);
|
||||
r = value ? parse_boolean(value) : true;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse crash reboot switch %s. Ignoring.", value);
|
||||
else
|
||||
arg_crash_reboot = r;
|
||||
|
||||
} else if (streq(key, "systemd.confirm_spawn") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.confirm_spawn")) {
|
||||
char *s;
|
||||
|
||||
arg_confirm_spawn = mfree(arg_confirm_spawn);
|
||||
|
||||
r = parse_confirm_spawn(value, &arg_confirm_spawn);
|
||||
r = parse_confirm_spawn(value, &s);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse confirm_spawn switch %s. Ignoring.", value);
|
||||
else {
|
||||
free(arg_confirm_spawn);
|
||||
arg_confirm_spawn = s;
|
||||
}
|
||||
|
||||
} else if (streq(key, "systemd.show_status") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.show_status")) {
|
||||
|
||||
r = parse_show_status(value, &arg_show_status);
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse show status switch %s. Ignoring.", value);
|
||||
if (value) {
|
||||
r = parse_show_status(value, &arg_show_status);
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse show status switch %s. Ignoring.", value);
|
||||
} else
|
||||
arg_show_status = SHOW_STATUS_YES;
|
||||
|
||||
} else if (streq(key, "systemd.default_standard_output") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.default_standard_output")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = exec_output_from_string(value);
|
||||
if (r < 0)
|
||||
@ -398,7 +411,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
else
|
||||
arg_default_std_output = r;
|
||||
|
||||
} else if (streq(key, "systemd.default_standard_error") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.default_standard_error")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = exec_output_from_string(value);
|
||||
if (r < 0)
|
||||
@ -406,24 +422,42 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
else
|
||||
arg_default_std_error = r;
|
||||
|
||||
} else if (streq(key, "systemd.setenv") && value) {
|
||||
} else if (streq(key, "systemd.setenv")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (env_assignment_is_valid(value)) {
|
||||
char **env;
|
||||
|
||||
env = strv_env_set(arg_default_environment, value);
|
||||
if (env)
|
||||
arg_default_environment = env;
|
||||
else
|
||||
log_warning_errno(ENOMEM, "Setting environment variable '%s' failed, ignoring: %m", value);
|
||||
if (!env)
|
||||
return log_oom();
|
||||
|
||||
arg_default_environment = env;
|
||||
} else
|
||||
log_warning("Environment variable name '%s' is not valid. Ignoring.", value);
|
||||
|
||||
} else if (streq(key, "systemd.machine_id") && value) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.machine_id")) {
|
||||
|
||||
r = set_machine_id(value);
|
||||
if (r < 0)
|
||||
log_warning("MachineID '%s' is not valid. Ignoring.", value);
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = set_machine_id(value);
|
||||
if (r < 0)
|
||||
log_warning("MachineID '%s' is not valid. Ignoring.", value);
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.default_timeout_start_sec")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = parse_sec(value, &arg_default_timeout_start_usec);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse default start timeout: %s, ignoring.", value);
|
||||
|
||||
if (arg_default_timeout_start_usec <= 0)
|
||||
arg_default_timeout_start_usec = USEC_INFINITY;
|
||||
|
||||
} else if (streq(key, "quiet") && !value) {
|
||||
|
||||
@ -445,15 +479,6 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
target = runlevel_to_target(key);
|
||||
if (target)
|
||||
return free_and_strdup(&arg_default_unit, target);
|
||||
|
||||
} else if (streq(key, "systemd.default_timeout_start_sec") && value) {
|
||||
|
||||
r = parse_sec(value, &arg_default_timeout_start_usec);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse default start timeout: %s, ignoring.", value);
|
||||
|
||||
if (arg_default_timeout_start_usec <= 0)
|
||||
arg_default_timeout_start_usec = USEC_INFINITY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -1341,10 +1366,9 @@ static int fixup_environment(void) {
|
||||
* However if TERM was configured through the kernel
|
||||
* command line then leave it alone. */
|
||||
|
||||
r = get_proc_cmdline_key("TERM=", &term);
|
||||
r = proc_cmdline_get_key("TERM", 0, &term);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (r == 0) {
|
||||
term = strdup(default_term_for_tty("/dev/console"));
|
||||
if (!term)
|
||||
@ -1411,7 +1435,7 @@ int main(int argc, char *argv[]) {
|
||||
called 'systemd'. That is confusing, hence let's call us
|
||||
systemd right-away. */
|
||||
program_invocation_short_name = systemd;
|
||||
prctl(PR_SET_NAME, systemd);
|
||||
(void) prctl(PR_SET_NAME, systemd);
|
||||
|
||||
saved_argv = argv;
|
||||
saved_argc = argc;
|
||||
@ -1435,9 +1459,10 @@ int main(int argc, char *argv[]) {
|
||||
if (!skip_setup) {
|
||||
r = mount_setup_early();
|
||||
if (r < 0) {
|
||||
error_message = "Failed to early mount API filesystems";
|
||||
error_message = "Failed to mount early API filesystems";
|
||||
goto finish;
|
||||
}
|
||||
|
||||
dual_timestamp_get(&security_start_timestamp);
|
||||
if (mac_selinux_setup(&loaded_policy) < 0) {
|
||||
error_message = "Failed to load SELinux policy";
|
||||
@ -1513,7 +1538,7 @@ int main(int argc, char *argv[]) {
|
||||
log_close_console(); /* force reopen of /dev/console */
|
||||
log_open();
|
||||
|
||||
/* For the later on, see above... */
|
||||
/* For later on, see above... */
|
||||
log_set_target(LOG_TARGET_JOURNAL);
|
||||
|
||||
/* clear the kernel timestamp,
|
||||
@ -1590,7 +1615,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
if (arg_system) {
|
||||
r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
}
|
||||
|
@ -360,7 +360,6 @@ int mount_setup(bool loaded_policy) {
|
||||
int r = 0;
|
||||
|
||||
r = mount_points_setup(ELEMENTSOF(mount_table), loaded_policy);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -391,25 +390,24 @@ int mount_setup(bool loaded_policy) {
|
||||
* udevd. */
|
||||
dev_setup(NULL, UID_INVALID, GID_INVALID);
|
||||
|
||||
/* Mark the root directory as shared in regards to mount
|
||||
* propagation. The kernel defaults to "private", but we think
|
||||
* it makes more sense to have a default of "shared" so that
|
||||
* nspawn and the container tools work out of the box. If
|
||||
* specific setups need other settings they can reset the
|
||||
* propagation mode to private if needed. */
|
||||
/* Mark the root directory as shared in regards to mount propagation. The kernel defaults to "private", but we
|
||||
* think it makes more sense to have a default of "shared" so that nspawn and the container tools work out of
|
||||
* the box. If specific setups need other settings they can reset the propagation mode to private if
|
||||
* needed. Note that we set this only when we are invoked directly by the kernel. If we are invoked by a
|
||||
* container manager we assume the container manager knows what it is doing (for example, because it set up
|
||||
* some directories with different propagation modes). */
|
||||
if (detect_container() <= 0)
|
||||
if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
|
||||
log_warning_errno(errno, "Failed to set up the root directory for shared mount propagation: %m");
|
||||
|
||||
/* Create a few directories we always want around, Note that
|
||||
* sd_booted() checks for /run/systemd/system, so this mkdir
|
||||
* really needs to stay for good, otherwise software that
|
||||
* copied sd-daemon.c into their sources will misdetect
|
||||
* systemd. */
|
||||
/* Create a few directories we always want around, Note that sd_booted() checks for /run/systemd/system, so
|
||||
* this mkdir really needs to stay for good, otherwise software that copied sd-daemon.c into their sources will
|
||||
* misdetect systemd. */
|
||||
(void) mkdir_label("/run/systemd", 0755);
|
||||
(void) mkdir_label("/run/systemd/system", 0755);
|
||||
(void) mkdir_label("/run/systemd/inaccessible", 0000);
|
||||
|
||||
/* Set up inaccessible items */
|
||||
(void) mkdir_label("/run/systemd/inaccessible", 0000);
|
||||
(void) mknod("/run/systemd/inaccessible/reg", S_IFREG | 0000, 0);
|
||||
(void) mkdir_label("/run/systemd/inaccessible/dir", 0000);
|
||||
(void) mknod("/run/systemd/inaccessible/chr", S_IFCHR | 0000, makedev(0, 0));
|
||||
|
@ -102,18 +102,17 @@ static int create_disk(
|
||||
if (!f)
|
||||
return log_error_errno(errno, "Failed to create unit file %s: %m", p);
|
||||
|
||||
fputs(
|
||||
"# Automatically generated by systemd-cryptsetup-generator\n\n"
|
||||
"[Unit]\n"
|
||||
"Description=Cryptography Setup for %I\n"
|
||||
"Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
|
||||
"SourcePath=/etc/crypttab\n"
|
||||
"DefaultDependencies=no\n"
|
||||
"Conflicts=umount.target\n"
|
||||
"BindsTo=dev-mapper-%i.device\n"
|
||||
"IgnoreOnIsolate=true\n"
|
||||
"After=cryptsetup-pre.target\n",
|
||||
f);
|
||||
fputs("# Automatically generated by systemd-cryptsetup-generator\n\n"
|
||||
"[Unit]\n"
|
||||
"Description=Cryptography Setup for %I\n"
|
||||
"Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
|
||||
"SourcePath=/etc/crypttab\n"
|
||||
"DefaultDependencies=no\n"
|
||||
"Conflicts=umount.target\n"
|
||||
"BindsTo=dev-mapper-%i.device\n"
|
||||
"IgnoreOnIsolate=true\n"
|
||||
"After=cryptsetup-pre.target\n",
|
||||
f);
|
||||
|
||||
if (!nofail)
|
||||
fprintf(f,
|
||||
@ -278,27 +277,30 @@ static crypto_device *get_crypto_device(const char *uuid) {
|
||||
}
|
||||
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
int r;
|
||||
crypto_device *d;
|
||||
_cleanup_free_ char *uuid = NULL, *uuid_value = NULL;
|
||||
crypto_device *d;
|
||||
int r;
|
||||
|
||||
if (streq(key, "luks") && value) {
|
||||
if (streq(key, "luks")) {
|
||||
|
||||
r = parse_boolean(value);
|
||||
r = value ? parse_boolean(value) : 1;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse luks switch %s. Ignoring.", value);
|
||||
log_warning("Failed to parse luks= kernel command line switch %s. Ignoring.", value);
|
||||
else
|
||||
arg_enabled = r;
|
||||
|
||||
} else if (streq(key, "luks.crypttab") && value) {
|
||||
} else if (streq(key, "luks.crypttab")) {
|
||||
|
||||
r = parse_boolean(value);
|
||||
r = value ? parse_boolean(value) : 1;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse luks crypttab switch %s. Ignoring.", value);
|
||||
log_warning("Failed to parse luks.crypttab= kernel command line switch %s. Ignoring.", value);
|
||||
else
|
||||
arg_read_crypttab = r;
|
||||
|
||||
} else if (streq(key, "luks.uuid") && value) {
|
||||
} else if (streq(key, "luks.uuid")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
d = get_crypto_device(startswith(value, "luks-") ? value+5 : value);
|
||||
if (!d)
|
||||
@ -306,7 +308,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
|
||||
d->create = arg_whitelist = true;
|
||||
|
||||
} else if (streq(key, "luks.options") && value) {
|
||||
} else if (streq(key, "luks.options")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
|
||||
if (r == 2) {
|
||||
@ -314,13 +319,14 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
if (!d)
|
||||
return log_oom();
|
||||
|
||||
free(d->options);
|
||||
d->options = uuid_value;
|
||||
uuid_value = NULL;
|
||||
free_and_replace(d->options, uuid_value);
|
||||
} else if (free_and_strdup(&arg_default_options, value) < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "luks.key") && value) {
|
||||
} else if (streq(key, "luks.key")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
|
||||
if (r == 2) {
|
||||
@ -328,13 +334,14 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
if (!d)
|
||||
return log_oom();
|
||||
|
||||
free(d->keyfile);
|
||||
d->keyfile = uuid_value;
|
||||
uuid_value = NULL;
|
||||
free_and_replace(d->keyfile, uuid_value);
|
||||
} else if (free_and_strdup(&arg_default_keyfile, value) < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "luks.name") && value) {
|
||||
} else if (streq(key, "luks.name")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value);
|
||||
if (r == 2) {
|
||||
@ -349,7 +356,6 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
uuid_value = NULL;
|
||||
} else
|
||||
log_warning("Failed to parse luks name switch %s. Ignoring.", value);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -458,7 +464,7 @@ static int add_proc_cmdline_devices(void) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r = EXIT_FAILURE;
|
||||
int r;
|
||||
|
||||
if (argc > 1 && argc != 4) {
|
||||
log_error("This program takes three or no arguments.");
|
||||
@ -475,32 +481,36 @@ int main(int argc, char *argv[]) {
|
||||
umask(0022);
|
||||
|
||||
arg_disks = hashmap_new(&string_hash_ops);
|
||||
if (!arg_disks)
|
||||
goto cleanup;
|
||||
if (!arg_disks) {
|
||||
r = log_oom();
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
r = EXIT_FAILURE;
|
||||
log_warning_errno(r, "Failed to parse kernel command line: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!arg_enabled) {
|
||||
r = EXIT_SUCCESS;
|
||||
goto cleanup;
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (add_crypttab_devices() < 0)
|
||||
goto cleanup;
|
||||
r = add_crypttab_devices();
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (add_proc_cmdline_devices() < 0)
|
||||
goto cleanup;
|
||||
r = add_proc_cmdline_devices();
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = EXIT_SUCCESS;
|
||||
r = 0;
|
||||
|
||||
cleanup:
|
||||
finish:
|
||||
free_arg_disks();
|
||||
free(arg_default_options);
|
||||
free(arg_default_keyfile);
|
||||
|
||||
return r;
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ static char *disk_mount_point(const char *label) {
|
||||
if (asprintf(&device, "/dev/mapper/%s", label) < 0)
|
||||
return NULL;
|
||||
|
||||
f = setmntent("/etc/fstab", "r");
|
||||
f = setmntent("/etc/fstab", "re");
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
@ -593,17 +593,18 @@ static int help(void) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r = EXIT_FAILURE;
|
||||
struct crypt_device *cd = NULL;
|
||||
int r;
|
||||
|
||||
if (argc <= 1) {
|
||||
help();
|
||||
return EXIT_SUCCESS;
|
||||
r = help();
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (argc < 3) {
|
||||
log_error("This program requires at least two arguments.");
|
||||
return EXIT_FAILURE;
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
log_set_target(LOG_TARGET_AUTO);
|
||||
@ -614,7 +615,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (streq(argv[1], "attach")) {
|
||||
uint32_t flags = 0;
|
||||
int k;
|
||||
unsigned tries;
|
||||
usec_t until;
|
||||
crypt_status_info status;
|
||||
@ -648,11 +648,11 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (arg_header) {
|
||||
log_debug("LUKS header: %s", arg_header);
|
||||
k = crypt_init(&cd, arg_header);
|
||||
r = crypt_init(&cd, arg_header);
|
||||
} else
|
||||
k = crypt_init(&cd, argv[3]);
|
||||
if (k != 0) {
|
||||
log_error_errno(k, "crypt_init() failed: %m");
|
||||
r = crypt_init(&cd, argv[3]);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "crypt_init() failed: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
@ -661,7 +661,7 @@ int main(int argc, char *argv[]) {
|
||||
status = crypt_status(cd, argv[2]);
|
||||
if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
|
||||
log_info("Volume %s already active.", argv[2]);
|
||||
r = EXIT_SUCCESS;
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
@ -691,29 +691,30 @@ int main(int argc, char *argv[]) {
|
||||
_cleanup_strv_free_erase_ char **passwords = NULL;
|
||||
|
||||
if (!key_file) {
|
||||
k = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
|
||||
if (k == -EAGAIN)
|
||||
r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
|
||||
if (r == -EAGAIN)
|
||||
continue;
|
||||
else if (k < 0)
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (streq_ptr(arg_type, CRYPT_TCRYPT))
|
||||
k = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
|
||||
r = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
|
||||
else
|
||||
k = attach_luks_or_plain(cd,
|
||||
r = attach_luks_or_plain(cd,
|
||||
argv[2],
|
||||
key_file,
|
||||
arg_header ? argv[3] : NULL,
|
||||
passwords,
|
||||
flags);
|
||||
if (k >= 0)
|
||||
if (r >= 0)
|
||||
break;
|
||||
else if (k == -EAGAIN) {
|
||||
if (r == -EAGAIN) {
|
||||
key_file = NULL;
|
||||
continue;
|
||||
} else if (k != -EPERM) {
|
||||
log_error_errno(k, "Failed to activate: %m");
|
||||
}
|
||||
if (r != -EPERM) {
|
||||
log_error_errno(r, "Failed to activate: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
@ -722,28 +723,28 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (arg_tries != 0 && tries >= arg_tries) {
|
||||
log_error("Too many attempts; giving up.");
|
||||
r = EXIT_FAILURE;
|
||||
r = -EPERM;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
} else if (streq(argv[1], "detach")) {
|
||||
int k;
|
||||
|
||||
k = crypt_init_by_name(&cd, argv[2]);
|
||||
if (k == -ENODEV) {
|
||||
r = crypt_init_by_name(&cd, argv[2]);
|
||||
if (r == -ENODEV) {
|
||||
log_info("Volume %s already inactive.", argv[2]);
|
||||
r = EXIT_SUCCESS;
|
||||
r = 0;
|
||||
goto finish;
|
||||
} else if (k) {
|
||||
log_error_errno(k, "crypt_init_by_name() failed: %m");
|
||||
}
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "crypt_init_by_name() failed: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
crypt_set_log_callback(cd, log_glue, NULL);
|
||||
|
||||
k = crypt_deactivate(cd, argv[2]);
|
||||
if (k < 0) {
|
||||
log_error_errno(k, "Failed to deactivate: %m");
|
||||
r = crypt_deactivate(cd, argv[2]);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to deactivate: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
@ -752,10 +753,9 @@ int main(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = EXIT_SUCCESS;
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
|
||||
if (cd)
|
||||
crypt_free(cd);
|
||||
|
||||
@ -764,5 +764,5 @@ finish:
|
||||
free(arg_header);
|
||||
strv_free(arg_tcrypt_keyfiles);
|
||||
|
||||
return r;
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -39,56 +39,53 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
assert(key);
|
||||
|
||||
if (streq(key, "systemd.mask")) {
|
||||
char *n;
|
||||
|
||||
if (!value)
|
||||
log_error("Missing argument for systemd.mask= kernel command line parameter.");
|
||||
else {
|
||||
char *n;
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to glob unit name: %m");
|
||||
r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to glob unit name: %m");
|
||||
|
||||
r = strv_consume(&arg_mask, n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
r = strv_consume(&arg_mask, n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "systemd.wants")) {
|
||||
char *n;
|
||||
|
||||
if (!value)
|
||||
log_error("Missing argument for systemd.want= kernel command line parameter.");
|
||||
else {
|
||||
char *n;
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to glob unit name: %m");
|
||||
r = unit_name_mangle(value, UNIT_NAME_NOGLOB, &n);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to glob unit name: %m");
|
||||
|
||||
r = strv_consume(&arg_wants, n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
r = strv_consume(&arg_wants, n);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "systemd.debug-shell")) {
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.debug_shell")) {
|
||||
|
||||
if (value) {
|
||||
r = parse_boolean(value);
|
||||
if (r < 0)
|
||||
log_error("Failed to parse systemd.debug-shell= argument '%s', ignoring.", value);
|
||||
log_error("Failed to parse systemd.debug_shell= argument '%s', ignoring.", value);
|
||||
else
|
||||
arg_debug_shell = r;
|
||||
} else
|
||||
arg_debug_shell = true;
|
||||
|
||||
} else if (streq(key, "systemd.unit")) {
|
||||
|
||||
if (!value)
|
||||
log_error("Missing argument for systemd.unit= kernel command line parameter.");
|
||||
else {
|
||||
r = free_and_strdup(&arg_default_unit, value);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set default unit %s: %m", value);
|
||||
}
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = free_and_strdup(&arg_default_unit, value);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set default unit %s: %m", value);
|
||||
|
||||
} else if (!value) {
|
||||
const char *target;
|
||||
|
||||
@ -173,7 +170,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
|
@ -35,7 +35,7 @@ static enum {
|
||||
} arg_action = ACTION_DISSECT;
|
||||
static const char *arg_image = NULL;
|
||||
static const char *arg_path = NULL;
|
||||
static DissectImageFlags arg_flags = DISSECT_IMAGE_DISCARD_ON_LOOP;
|
||||
static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP;
|
||||
static void *arg_root_hash = NULL;
|
||||
static size_t arg_root_hash_size = 0;
|
||||
|
||||
@ -191,7 +191,7 @@ int main(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = dissect_image(d->fd, arg_root_hash, arg_root_hash_size, &m);
|
||||
r = dissect_image(d->fd, arg_root_hash, arg_root_hash_size, arg_flags, &m);
|
||||
if (r == -ENOPKG) {
|
||||
log_error_errno(r, "Couldn't identify a suitable partition table or file system in %s.", arg_image);
|
||||
goto finish;
|
||||
@ -221,6 +221,9 @@ int main(int argc, char *argv[]) {
|
||||
p->rw ? "writable" : "read-only",
|
||||
partition_designator_to_string(i));
|
||||
|
||||
if (!sd_id128_is_null(p->uuid))
|
||||
printf(" (UUID " SD_ID128_FORMAT_STR ")", SD_ID128_FORMAT_VAL(p->uuid));
|
||||
|
||||
if (p->fstype)
|
||||
printf(" of type %s", p->fstype);
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "mkdir.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "random-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
@ -825,6 +826,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
bool enabled;
|
||||
int r;
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
@ -837,6 +839,16 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = proc_cmdline_get_bool("systemd.firstboot", &enabled);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to parse systemd.firstboot= kernel command line argument, ignoring.");
|
||||
goto finish;
|
||||
}
|
||||
if (r > 0 && !enabled) {
|
||||
r = 0; /* disabled */
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = process_locale();
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
@ -99,7 +99,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
|
||||
assert(key);
|
||||
|
||||
if (streq(key, "fsck.mode") && value) {
|
||||
if (streq(key, "fsck.mode")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (streq(value, "auto"))
|
||||
arg_force = arg_skip = false;
|
||||
@ -110,7 +113,10 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
else
|
||||
log_warning("Invalid fsck.mode= parameter '%s'. Ignoring.", value);
|
||||
|
||||
} else if (streq(key, "fsck.repair") && value) {
|
||||
} else if (streq(key, "fsck.repair")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (streq(value, "preen"))
|
||||
arg_repair = "-a";
|
||||
@ -293,7 +299,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
|
@ -42,16 +42,20 @@
|
||||
#include "unit-name.h"
|
||||
#include "util.h"
|
||||
#include "virt.h"
|
||||
#include "volatile-util.h"
|
||||
|
||||
static const char *arg_dest = "/tmp";
|
||||
static const char *arg_dest_late = "/tmp";
|
||||
static bool arg_fstab_enabled = true;
|
||||
static char *arg_root_what = NULL;
|
||||
static char *arg_root_fstype = NULL;
|
||||
static char *arg_root_options = NULL;
|
||||
static char *arg_root_hash = NULL;
|
||||
static int arg_root_rw = -1;
|
||||
static char *arg_usr_what = NULL;
|
||||
static char *arg_usr_fstype = NULL;
|
||||
static char *arg_usr_options = NULL;
|
||||
static VolatileMode arg_volatile_mode = _VOLATILE_MODE_INVALID;
|
||||
|
||||
static int add_swap(
|
||||
const char *what,
|
||||
@ -235,6 +239,7 @@ static int write_requires_mounts_for(FILE *f, const char *opts) {
|
||||
}
|
||||
|
||||
static int add_mount(
|
||||
const char *dest,
|
||||
const char *what,
|
||||
const char *where,
|
||||
const char *fstype,
|
||||
@ -286,7 +291,7 @@ static int add_mount(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate unit name: %m");
|
||||
|
||||
unit = strjoin(arg_dest, "/", name);
|
||||
unit = strjoin(dest, "/", name);
|
||||
if (!unit)
|
||||
return log_oom();
|
||||
|
||||
@ -318,7 +323,7 @@ static int add_mount(
|
||||
}
|
||||
|
||||
if (passno != 0) {
|
||||
r = generator_write_fsck_deps(f, arg_dest, what, where, fstype);
|
||||
r = generator_write_fsck_deps(f, dest, what, where, fstype);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -334,7 +339,7 @@ static int add_mount(
|
||||
if (!isempty(fstype) && !streq(fstype, "auto"))
|
||||
fprintf(f, "Type=%s\n", fstype);
|
||||
|
||||
r = generator_write_timeouts(arg_dest, what, where, opts, &filtered);
|
||||
r = generator_write_timeouts(dest, what, where, opts, &filtered);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -350,7 +355,7 @@ static int add_mount(
|
||||
return log_error_errno(r, "Failed to write unit file %s: %m", unit);
|
||||
|
||||
if (!noauto && !automount) {
|
||||
lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", name);
|
||||
lnk = strjoin(dest, "/", post, nofail ? ".wants/" : ".requires/", name);
|
||||
if (!lnk)
|
||||
return log_oom();
|
||||
|
||||
@ -364,7 +369,7 @@ static int add_mount(
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate unit name: %m");
|
||||
|
||||
automount_unit = strjoin(arg_dest, "/", automount_name);
|
||||
automount_unit = strjoin(dest, "/", automount_name);
|
||||
if (!automount_unit)
|
||||
return log_oom();
|
||||
|
||||
@ -406,7 +411,7 @@ static int add_mount(
|
||||
return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit);
|
||||
|
||||
free(lnk);
|
||||
lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name);
|
||||
lnk = strjoin(dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name);
|
||||
if (!lnk)
|
||||
return log_oom();
|
||||
|
||||
@ -479,7 +484,8 @@ static int parse_fstab(bool initrd) {
|
||||
else
|
||||
post = SPECIAL_LOCAL_FS_TARGET;
|
||||
|
||||
k = add_mount(what,
|
||||
k = add_mount(arg_dest,
|
||||
what,
|
||||
where,
|
||||
me->mnt_type,
|
||||
me->mnt_opts,
|
||||
@ -540,7 +546,8 @@ static int add_sysroot_mount(void) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return add_mount(what,
|
||||
return add_mount(arg_dest,
|
||||
what,
|
||||
"/sysroot",
|
||||
arg_root_fstype,
|
||||
opts,
|
||||
@ -593,7 +600,8 @@ static int add_sysroot_usr_mount(void) {
|
||||
opts = arg_usr_options;
|
||||
|
||||
log_debug("Found entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
|
||||
return add_mount(what,
|
||||
return add_mount(arg_dest,
|
||||
what,
|
||||
"/sysroot/usr",
|
||||
arg_usr_fstype,
|
||||
opts,
|
||||
@ -605,6 +613,46 @@ static int add_sysroot_usr_mount(void) {
|
||||
"/proc/cmdline");
|
||||
}
|
||||
|
||||
static int add_volatile_root(void) {
|
||||
const char *from, *to;
|
||||
|
||||
if (arg_volatile_mode != VOLATILE_YES)
|
||||
return 0;
|
||||
|
||||
/* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
|
||||
* requested, leaving only /usr from the root mount inside. */
|
||||
|
||||
from = strjoina(SYSTEM_DATA_UNIT_PATH "/systemd-volatile-root.service");
|
||||
to = strjoina(arg_dest, "/" SPECIAL_INITRD_ROOT_FS_TARGET, ".requires/systemd-volatile-root.service");
|
||||
|
||||
(void) mkdir_parents(to, 0755);
|
||||
|
||||
if (symlink(from, to) < 0)
|
||||
return log_error_errno(errno, "Failed to hook in volatile remount service: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_volatile_var(void) {
|
||||
|
||||
if (arg_volatile_mode != VOLATILE_STATE)
|
||||
return 0;
|
||||
|
||||
/* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
|
||||
|
||||
return add_mount(arg_dest_late,
|
||||
"tmpfs",
|
||||
"/var",
|
||||
"tmpfs",
|
||||
"mode=0755",
|
||||
0,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
SPECIAL_LOCAL_FS_TARGET,
|
||||
"/proc/cmdline");
|
||||
}
|
||||
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
int r;
|
||||
|
||||
@ -612,27 +660,36 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
* instance should take precedence. In the case of multiple rootflags=
|
||||
* or usrflags= the arguments should be concatenated */
|
||||
|
||||
if (STR_IN_SET(key, "fstab", "rd.fstab") && value) {
|
||||
if (STR_IN_SET(key, "fstab", "rd.fstab")) {
|
||||
|
||||
r = parse_boolean(value);
|
||||
r = value ? parse_boolean(value) : 1;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse fstab switch %s. Ignoring.", value);
|
||||
else
|
||||
arg_fstab_enabled = r;
|
||||
|
||||
} else if (streq(key, "root") && value) {
|
||||
} else if (streq(key, "root")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (free_and_strdup(&arg_root_what, value) < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "rootfstype") && value) {
|
||||
} else if (streq(key, "rootfstype")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (free_and_strdup(&arg_root_fstype, value) < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "rootflags") && value) {
|
||||
} else if (streq(key, "rootflags")) {
|
||||
char *o;
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
o = arg_root_options ?
|
||||
strjoin(arg_root_options, ",", value) :
|
||||
strdup(value);
|
||||
@ -641,20 +698,36 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
|
||||
free(arg_root_options);
|
||||
arg_root_options = o;
|
||||
} else if (streq(key, "roothash")) {
|
||||
|
||||
} else if (streq(key, "mount.usr") && value) {
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (free_and_strdup(&arg_root_hash, value) < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "mount.usr")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (free_and_strdup(&arg_usr_what, value) < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "mount.usrfstype") && value) {
|
||||
} else if (streq(key, "mount.usrfstype")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (free_and_strdup(&arg_usr_fstype, value) < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "mount.usrflags") && value) {
|
||||
} else if (streq(key, "mount.usrflags")) {
|
||||
char *o;
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
o = arg_usr_options ?
|
||||
strjoin(arg_usr_options, ",", value) :
|
||||
strdup(value);
|
||||
@ -668,10 +741,40 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
arg_root_rw = true;
|
||||
else if (streq(key, "ro") && !value)
|
||||
arg_root_rw = false;
|
||||
else if (streq(key, "systemd.volatile")) {
|
||||
VolatileMode m;
|
||||
|
||||
if (value) {
|
||||
m = volatile_mode_from_string(value);
|
||||
if (m < 0)
|
||||
log_warning("Failed to parse systemd.volatile= argument: %s", value);
|
||||
else
|
||||
arg_volatile_mode = m;
|
||||
} else
|
||||
arg_volatile_mode = VOLATILE_YES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int determine_root(void) {
|
||||
/* If we have a root hash but no root device then Verity is used, and we use the "root" DM device as root. */
|
||||
|
||||
if (arg_root_what)
|
||||
return 0;
|
||||
|
||||
if (!arg_root_hash)
|
||||
return 0;
|
||||
|
||||
arg_root_what = strdup("/dev/mapper/root");
|
||||
if (!arg_root_what)
|
||||
return log_oom();
|
||||
|
||||
log_info("Using verity root device %s.", arg_root_what);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r = 0;
|
||||
|
||||
@ -682,6 +785,8 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc > 1)
|
||||
arg_dest = argv[1];
|
||||
if (argc > 3)
|
||||
arg_dest_late = argv[3];
|
||||
|
||||
log_set_target(LOG_TARGET_SAFE);
|
||||
log_parse_environment();
|
||||
@ -689,10 +794,12 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
(void) determine_root();
|
||||
|
||||
/* Always honour root= and usr= in the kernel command line if we are in an initrd */
|
||||
if (in_initrd()) {
|
||||
int k;
|
||||
@ -702,8 +809,12 @@ int main(int argc, char *argv[]) {
|
||||
k = add_sysroot_usr_mount();
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
k = add_volatile_root();
|
||||
if (k < 0)
|
||||
r = k;
|
||||
} else
|
||||
r = 0;
|
||||
r = add_volatile_var();
|
||||
|
||||
/* Honour /etc/fstab only when that's enabled */
|
||||
if (arg_fstab_enabled) {
|
||||
@ -729,6 +840,7 @@ int main(int argc, char *argv[]) {
|
||||
free(arg_root_what);
|
||||
free(arg_root_fstype);
|
||||
free(arg_root_options);
|
||||
free(arg_root_hash);
|
||||
|
||||
free(arg_usr_what);
|
||||
free(arg_usr_fstype);
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "blkid-util.h"
|
||||
#include "btrfs-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "dissect-image.h"
|
||||
#include "efivars.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@ -54,7 +55,7 @@ static bool arg_enabled = true;
|
||||
static bool arg_root_enabled = true;
|
||||
static bool arg_root_rw = false;
|
||||
|
||||
static int add_cryptsetup(const char *id, const char *what, bool rw, char **device) {
|
||||
static int add_cryptsetup(const char *id, const char *what, bool rw, bool require, char **device) {
|
||||
_cleanup_free_ char *e = NULL, *n = NULL, *p = NULL, *d = NULL, *to = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
char *from, *ret;
|
||||
@ -62,7 +63,6 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
|
||||
|
||||
assert(id);
|
||||
assert(what);
|
||||
assert(device);
|
||||
|
||||
r = unit_name_from_path(what, ".device", &d);
|
||||
if (r < 0)
|
||||
@ -119,23 +119,26 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
|
||||
if (symlink(from, to) < 0)
|
||||
return log_error_errno(errno, "Failed to create symlink %s: %m", to);
|
||||
|
||||
free(to);
|
||||
to = strjoin(arg_dest, "/cryptsetup.target.requires/", n);
|
||||
if (!to)
|
||||
return log_oom();
|
||||
if (require) {
|
||||
free(to);
|
||||
|
||||
mkdir_parents_label(to, 0755);
|
||||
if (symlink(from, to) < 0)
|
||||
return log_error_errno(errno, "Failed to create symlink %s: %m", to);
|
||||
to = strjoin(arg_dest, "/cryptsetup.target.requires/", n);
|
||||
if (!to)
|
||||
return log_oom();
|
||||
|
||||
free(to);
|
||||
to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n);
|
||||
if (!to)
|
||||
return log_oom();
|
||||
mkdir_parents_label(to, 0755);
|
||||
if (symlink(from, to) < 0)
|
||||
return log_error_errno(errno, "Failed to create symlink %s: %m", to);
|
||||
|
||||
mkdir_parents_label(to, 0755);
|
||||
if (symlink(from, to) < 0)
|
||||
return log_error_errno(errno, "Failed to create symlink %s: %m", to);
|
||||
free(to);
|
||||
to = strjoin(arg_dest, "/dev-mapper-", e, ".device.requires/", n);
|
||||
if (!to)
|
||||
return log_oom();
|
||||
|
||||
mkdir_parents_label(to, 0755);
|
||||
if (symlink(from, to) < 0)
|
||||
return log_error_errno(errno, "Failed to create symlink %s: %m", to);
|
||||
}
|
||||
|
||||
free(p);
|
||||
p = strjoin(arg_dest, "/dev-mapper-", e, ".device.d/50-job-timeout-sec-0.conf");
|
||||
@ -155,7 +158,8 @@ static int add_cryptsetup(const char *id, const char *what, bool rw, char **devi
|
||||
if (!ret)
|
||||
return log_oom();
|
||||
|
||||
*device = ret;
|
||||
if (device)
|
||||
*device = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -182,7 +186,7 @@ static int add_mount(
|
||||
|
||||
if (streq_ptr(fstype, "crypto_LUKS")) {
|
||||
|
||||
r = add_cryptsetup(id, what, rw, &crypto_what);
|
||||
r = add_cryptsetup(id, what, rw, true, &crypto_what);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -270,61 +274,28 @@ static bool path_is_busy(const char *where) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static int probe_and_add_mount(
|
||||
static int add_partition_mount(
|
||||
DissectedPartition *p,
|
||||
const char *id,
|
||||
const char *what,
|
||||
const char *where,
|
||||
bool rw,
|
||||
const char *description,
|
||||
const char *post) {
|
||||
const char *description) {
|
||||
|
||||
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
|
||||
const char *fstype = NULL;
|
||||
int r;
|
||||
|
||||
assert(id);
|
||||
assert(what);
|
||||
assert(where);
|
||||
assert(description);
|
||||
assert(p);
|
||||
|
||||
if (path_is_busy(where)) {
|
||||
log_debug("%s already populated, ignoring.", where);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Let's check the partition type here, so that we know
|
||||
* whether to do LUKS magic. */
|
||||
|
||||
errno = 0;
|
||||
b = blkid_new_probe_from_filename(what);
|
||||
if (!b) {
|
||||
if (errno == 0)
|
||||
return log_oom();
|
||||
return log_error_errno(errno, "Failed to allocate prober: %m");
|
||||
}
|
||||
|
||||
blkid_probe_enable_superblocks(b, 1);
|
||||
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
if (r == -2 || r == 1) /* no result or uncertain */
|
||||
return 0;
|
||||
else if (r != 0)
|
||||
return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
|
||||
|
||||
/* add_mount is OK with fstype being NULL. */
|
||||
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
|
||||
|
||||
return add_mount(
|
||||
id,
|
||||
what,
|
||||
p->node,
|
||||
where,
|
||||
fstype,
|
||||
rw,
|
||||
p->fstype,
|
||||
p->rw,
|
||||
NULL,
|
||||
description,
|
||||
post);
|
||||
SPECIAL_LOCAL_FS_TARGET);
|
||||
}
|
||||
|
||||
static int add_swap(const char *path) {
|
||||
@ -449,22 +420,17 @@ static int add_automount(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_boot(const char *what) {
|
||||
static int add_esp(DissectedPartition *p) {
|
||||
const char *esp;
|
||||
int r;
|
||||
|
||||
assert(what);
|
||||
assert(p);
|
||||
|
||||
if (in_initrd()) {
|
||||
log_debug("In initrd, ignoring the ESP.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (detect_container() > 0) {
|
||||
log_debug("In a container, ignoring the ESP.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice */
|
||||
esp = access("/efi/", F_OK) >= 0 ? "/efi" : "/boot";
|
||||
|
||||
@ -480,9 +446,7 @@ static int add_boot(const char *what) {
|
||||
}
|
||||
|
||||
if (is_efi_boot()) {
|
||||
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
|
||||
const char *fstype = NULL, *uuid_string = NULL;
|
||||
sd_id128_t loader_uuid, part_uuid;
|
||||
sd_id128_t loader_uuid;
|
||||
|
||||
/* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
|
||||
|
||||
@ -494,43 +458,7 @@ static int add_boot(const char *what) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read ESP partition UUID: %m");
|
||||
|
||||
errno = 0;
|
||||
b = blkid_new_probe_from_filename(what);
|
||||
if (!b) {
|
||||
if (errno == 0)
|
||||
return log_oom();
|
||||
return log_error_errno(errno, "Failed to allocate prober: %m");
|
||||
}
|
||||
|
||||
blkid_probe_enable_partitions(b, 1);
|
||||
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
if (r == -2 || r == 1) /* no result or uncertain */
|
||||
return 0;
|
||||
else if (r != 0)
|
||||
return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
|
||||
|
||||
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
|
||||
if (!streq_ptr(fstype, "vfat")) {
|
||||
log_debug("Partition for %s is not a FAT filesystem, ignoring.", esp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid_string, NULL);
|
||||
if (r != 0) {
|
||||
log_debug_errno(errno, "Partition for %s does not have a UUID, ignoring.", esp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sd_id128_from_string(uuid_string, &part_uuid) < 0) {
|
||||
log_debug("Partition for %s does not have a valid UUID, ignoring.", esp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_id128_equal(part_uuid, loader_uuid)) {
|
||||
if (!sd_id128_equal(p->uuid, loader_uuid)) {
|
||||
log_debug("Partition for %s does not appear to be the partition we are booted from.", esp);
|
||||
return 0;
|
||||
}
|
||||
@ -538,35 +466,29 @@ static int add_boot(const char *what) {
|
||||
log_debug("Not an EFI boot, skipping ESP check.");
|
||||
|
||||
return add_automount("boot",
|
||||
what,
|
||||
esp,
|
||||
"vfat",
|
||||
true,
|
||||
"umask=0077",
|
||||
"EFI System Partition Automount",
|
||||
120 * USEC_PER_SEC);
|
||||
p->node,
|
||||
esp,
|
||||
p->fstype,
|
||||
true,
|
||||
"umask=0077",
|
||||
"EFI System Partition Automount",
|
||||
120 * USEC_PER_SEC);
|
||||
}
|
||||
#else
|
||||
static int add_boot(const char *what) {
|
||||
static int add_esp(const char *what) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int enumerate_partitions(dev_t devnum) {
|
||||
|
||||
_cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
|
||||
static int open_parent(dev_t devnum, int *ret) {
|
||||
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
|
||||
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
|
||||
_cleanup_udev_unref_ struct udev *udev = NULL;
|
||||
_cleanup_free_ char *boot = NULL, *home = NULL, *srv = NULL;
|
||||
struct udev_list_entry *first, *item;
|
||||
struct udev_device *parent = NULL;
|
||||
const char *name, *node, *pttype, *devtype;
|
||||
int boot_nr = -1, home_nr = -1, srv_nr = -1;
|
||||
bool home_rw = true, srv_rw = true;
|
||||
blkid_partlist pl;
|
||||
int r, k;
|
||||
const char *name, *devtype, *node;
|
||||
struct udev_device *parent;
|
||||
dev_t pn;
|
||||
int fd;
|
||||
|
||||
assert(ret);
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev)
|
||||
@ -580,228 +502,94 @@ static int enumerate_partitions(dev_t devnum) {
|
||||
if (!name)
|
||||
name = udev_device_get_syspath(d);
|
||||
if (!name) {
|
||||
log_debug("Device %u:%u does not have a name, ignoring.",
|
||||
major(devnum), minor(devnum));
|
||||
return 0;
|
||||
log_debug("Device %u:%u does not have a name, ignoring.", major(devnum), minor(devnum));
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
parent = udev_device_get_parent(d);
|
||||
if (!parent) {
|
||||
log_debug("%s: not a partitioned device, ignoring.", name);
|
||||
return 0;
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
/* Does it have a devtype? */
|
||||
devtype = udev_device_get_devtype(parent);
|
||||
if (!devtype) {
|
||||
log_debug("%s: parent doesn't have a device type, ignoring.", name);
|
||||
return 0;
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
/* Is this a disk or a partition? We only care for disks... */
|
||||
if (!streq(devtype, "disk")) {
|
||||
log_debug("%s: parent isn't a raw disk, ignoring.", name);
|
||||
return 0;
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
/* Does it have a device node? */
|
||||
node = udev_device_get_devnode(parent);
|
||||
if (!node) {
|
||||
log_debug("%s: parent device does not have device node, ignoring.", name);
|
||||
return 0;
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
log_debug("%s: root device %s.", name, node);
|
||||
|
||||
pn = udev_device_get_devnum(parent);
|
||||
if (major(pn) == 0)
|
||||
return 0;
|
||||
|
||||
errno = 0;
|
||||
b = blkid_new_probe_from_filename(node);
|
||||
if (!b) {
|
||||
if (errno == 0)
|
||||
return log_oom();
|
||||
|
||||
return log_error_errno(errno, "%s: failed to allocate prober: %m", node);
|
||||
if (major(pn) == 0) {
|
||||
log_debug("%s: parent device is not a proper block device, ignoring.", name);
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
blkid_probe_enable_partitions(b, 1);
|
||||
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
fd = open(node, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open %s: %m", node);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
if (r == 1)
|
||||
return 0; /* no results */
|
||||
else if (r == -2) {
|
||||
log_warning("%s: probe gave ambiguous results, ignoring.", node);
|
||||
return 0;
|
||||
} else if (r != 0)
|
||||
return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node);
|
||||
*ret = fd;
|
||||
return 1;
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
|
||||
if (r != 0) {
|
||||
if (errno == 0)
|
||||
return 0; /* No partition table found. */
|
||||
not_found:
|
||||
*ret = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return log_error_errno(errno, "%s: failed to determine partition table type: %m", node);
|
||||
}
|
||||
static int enumerate_partitions(dev_t devnum) {
|
||||
|
||||
/* We only do this all for GPT... */
|
||||
if (!streq_ptr(pttype, "gpt")) {
|
||||
log_debug("%s: not a GPT partition table, ignoring.", node);
|
||||
_cleanup_close_ int fd = -1;
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
|
||||
int r, k;
|
||||
|
||||
r = open_parent(devnum, &fd);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = dissect_image(fd, NULL, 0, DISSECT_IMAGE_GPT_ONLY, &m);
|
||||
if (r == -ENOPKG) {
|
||||
log_debug_errno(r, "No suitable partition table found, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
pl = blkid_probe_get_partitions(b);
|
||||
if (!pl) {
|
||||
if (errno == 0)
|
||||
return log_oom();
|
||||
|
||||
return log_error_errno(errno, "%s: failed to list partitions: %m", node);
|
||||
}
|
||||
|
||||
e = udev_enumerate_new(udev);
|
||||
if (!e)
|
||||
return log_oom();
|
||||
|
||||
r = udev_enumerate_add_match_parent(e, parent);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
return log_error_errno(r, "Failed to dissect: %m");
|
||||
|
||||
r = udev_enumerate_add_match_subsystem(e, "block");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = udev_enumerate_scan_devices(e);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "%s: failed to enumerate partitions: %m", node);
|
||||
|
||||
first = udev_enumerate_get_list_entry(e);
|
||||
udev_list_entry_foreach(item, first) {
|
||||
_cleanup_udev_device_unref_ struct udev_device *q;
|
||||
unsigned long long flags;
|
||||
const char *stype, *subnode;
|
||||
sd_id128_t type_id;
|
||||
blkid_partition pp;
|
||||
dev_t qn;
|
||||
int nr;
|
||||
|
||||
q = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
|
||||
if (!q)
|
||||
continue;
|
||||
|
||||
qn = udev_device_get_devnum(q);
|
||||
if (major(qn) == 0)
|
||||
continue;
|
||||
|
||||
if (qn == devnum)
|
||||
continue;
|
||||
|
||||
if (qn == pn)
|
||||
continue;
|
||||
|
||||
subnode = udev_device_get_devnode(q);
|
||||
if (!subnode)
|
||||
continue;
|
||||
|
||||
pp = blkid_partlist_devno_to_partition(pl, qn);
|
||||
if (!pp)
|
||||
continue;
|
||||
|
||||
nr = blkid_partition_get_partno(pp);
|
||||
if (nr < 0)
|
||||
continue;
|
||||
|
||||
stype = blkid_partition_get_type_string(pp);
|
||||
if (!stype)
|
||||
continue;
|
||||
|
||||
if (sd_id128_from_string(stype, &type_id) < 0)
|
||||
continue;
|
||||
|
||||
flags = blkid_partition_get_flags(pp);
|
||||
|
||||
if (sd_id128_equal(type_id, GPT_SWAP)) {
|
||||
|
||||
if (flags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
if (flags & GPT_FLAG_READ_ONLY) {
|
||||
log_debug("%s marked as read-only swap partition, which is bogus. Ignoring.", subnode);
|
||||
continue;
|
||||
}
|
||||
|
||||
k = add_swap(subnode);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_ESP)) {
|
||||
|
||||
/* We only care for the first /boot partition */
|
||||
if (boot && nr >= boot_nr)
|
||||
continue;
|
||||
|
||||
/* Note that we do not honour the "no-auto"
|
||||
* flag for the ESP, as it is often unset, to
|
||||
* hide it from Windows. */
|
||||
|
||||
boot_nr = nr;
|
||||
|
||||
r = free_and_strdup(&boot, subnode);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_HOME)) {
|
||||
|
||||
if (flags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
/* We only care for the first /home partition */
|
||||
if (home && nr >= home_nr)
|
||||
continue;
|
||||
|
||||
home_nr = nr;
|
||||
home_rw = !(flags & GPT_FLAG_READ_ONLY),
|
||||
|
||||
r = free_and_strdup(&home, subnode);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (sd_id128_equal(type_id, GPT_SRV)) {
|
||||
|
||||
if (flags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
/* We only care for the first /srv partition */
|
||||
if (srv && nr >= srv_nr)
|
||||
continue;
|
||||
|
||||
srv_nr = nr;
|
||||
srv_rw = !(flags & GPT_FLAG_READ_ONLY),
|
||||
|
||||
r = free_and_strdup(&srv, subnode);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
if (boot) {
|
||||
k = add_boot(boot);
|
||||
if (m->partitions[PARTITION_SWAP].found) {
|
||||
k = add_swap(m->partitions[PARTITION_SWAP].node);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
if (home) {
|
||||
k = probe_and_add_mount("home", home, "/home", home_rw, "Home Partition", SPECIAL_LOCAL_FS_TARGET);
|
||||
if (m->partitions[PARTITION_ESP].found) {
|
||||
k = add_esp(m->partitions + PARTITION_ESP);
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
if (srv) {
|
||||
k = probe_and_add_mount("srv", srv, "/srv", srv_rw, "Server Data Partition", SPECIAL_LOCAL_FS_TARGET);
|
||||
if (m->partitions[PARTITION_HOME].found) {
|
||||
k = add_partition_mount(m->partitions + PARTITION_HOME, "home", "/home", "Home Partition");
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
|
||||
if (m->partitions[PARTITION_SRV].found) {
|
||||
k = add_partition_mount(m->partitions + PARTITION_SRV, "srv", "/srv", "Server Data Partition");
|
||||
if (k < 0)
|
||||
r = k;
|
||||
}
|
||||
@ -876,8 +664,40 @@ static int get_block_device_harder(const char *path, dev_t *dev) {
|
||||
if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
|
||||
continue;
|
||||
|
||||
if (found) /* Don't try to support multiple backing block devices */
|
||||
goto fallback;
|
||||
if (found) {
|
||||
_cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL;
|
||||
|
||||
/* We found a device backed by multiple other devices. We don't really support automatic
|
||||
* discovery on such setups, with the exception of dm-verity partitions. In this case there are
|
||||
* two backing devices: the data partition and the hash partition. We are fine with such
|
||||
* setups, however, only if both partitions are on the same physical device. Hence, let's
|
||||
* verify this. */
|
||||
|
||||
u = strjoin(p, "/", de->d_name, "/../dev");
|
||||
if (!u)
|
||||
return -ENOMEM;
|
||||
|
||||
v = strjoin(p, "/", found->d_name, "/../dev");
|
||||
if (!v)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_one_line_file(u, &a);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to read %s: %m", u);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
r = read_one_line_file(v, &b);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to read %s: %m", v);
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
/* Check if the parent device is the same. If not, then the two backing devices are on
|
||||
* different physical devices, and we don't support that. */
|
||||
if (!streq(a, b))
|
||||
goto fallback;
|
||||
}
|
||||
|
||||
found = de;
|
||||
}
|
||||
@ -912,21 +732,33 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
|
||||
assert(key);
|
||||
|
||||
if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto") && value) {
|
||||
if (STR_IN_SET(key, "systemd.gpt_auto", "rd.systemd.gpt_auto")) {
|
||||
|
||||
r = parse_boolean(value);
|
||||
r = value ? parse_boolean(value) : 1;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse gpt-auto switch \"%s\". Ignoring.", value);
|
||||
else
|
||||
arg_enabled = r;
|
||||
|
||||
} else if (streq(key, "root") && value) {
|
||||
} else if (streq(key, "root")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
/* Disable root disk logic if there's a root= value
|
||||
* specified (unless it happens to be "gpt-auto") */
|
||||
|
||||
arg_root_enabled = streq(value, "gpt-auto");
|
||||
|
||||
} else if (streq(key, "roothash")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
/* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
|
||||
|
||||
arg_root_enabled = false;
|
||||
|
||||
} else if (streq(key, "rw") && !value)
|
||||
arg_root_rw = true;
|
||||
else if (streq(key, "ro") && !value)
|
||||
@ -935,6 +767,16 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_EFI
|
||||
static int add_root_cryptsetup(void) {
|
||||
|
||||
/* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
|
||||
* sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
|
||||
|
||||
return add_cryptsetup("root", "/dev/gpt-auto-root-luks", true, false, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int add_root_mount(void) {
|
||||
|
||||
#ifdef ENABLE_EFI
|
||||
@ -960,6 +802,10 @@ static int add_root_mount(void) {
|
||||
r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
r = add_root_cryptsetup();
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return add_mount(
|
||||
@ -983,11 +829,11 @@ static int add_mounts(void) {
|
||||
r = get_block_device_harder("/", &devno);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine block device of root file system: %m");
|
||||
else if (r == 0) {
|
||||
if (r == 0) {
|
||||
r = get_block_device_harder("/usr", &devno);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
|
||||
else if (r == 0) {
|
||||
if (r == 0) {
|
||||
log_debug("Neither root nor /usr file system are on a (single) block device.");
|
||||
return 0;
|
||||
}
|
||||
@ -997,7 +843,7 @@ static int add_mounts(void) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r = 0;
|
||||
int r = 0, k;
|
||||
|
||||
if (argc > 1 && argc != 4) {
|
||||
log_error("This program takes three or no arguments.");
|
||||
@ -1018,7 +864,7 @@ int main(int argc, char *argv[]) {
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
@ -1031,8 +877,6 @@ int main(int argc, char *argv[]) {
|
||||
r = add_root_mount();
|
||||
|
||||
if (!in_initrd()) {
|
||||
int k;
|
||||
|
||||
k = add_mounts();
|
||||
if (k < 0)
|
||||
r = k;
|
||||
|
@ -31,15 +31,22 @@
|
||||
#include "util.h"
|
||||
|
||||
static const char *arg_dest = "/tmp";
|
||||
static char *arg_resume_dev = NULL;
|
||||
static char *arg_resume_device = NULL;
|
||||
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
|
||||
if (streq(key, "resume") && value) {
|
||||
free(arg_resume_dev);
|
||||
arg_resume_dev = fstab_node_to_udev_node(value);
|
||||
if (!arg_resume_dev)
|
||||
if (streq(key, "resume")) {
|
||||
char *s;
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
s = fstab_node_to_udev_node(value);
|
||||
if (!s)
|
||||
return log_oom();
|
||||
|
||||
free(arg_resume_device);
|
||||
arg_resume_device = s;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -49,10 +56,10 @@ static int process_resume(void) {
|
||||
_cleanup_free_ char *name = NULL, *lnk = NULL;
|
||||
int r;
|
||||
|
||||
if (!arg_resume_dev)
|
||||
if (!arg_resume_device)
|
||||
return 0;
|
||||
|
||||
r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_dev, ".service", &name);
|
||||
r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_device, ".service", &name);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate unit name: %m");
|
||||
|
||||
@ -88,12 +95,12 @@ int main(int argc, char *argv[]) {
|
||||
if (!in_initrd())
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
r = process_resume();
|
||||
free(arg_resume_dev);
|
||||
free(arg_resume_device);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -218,37 +218,40 @@ int pull_make_path(const char *url, const char *etag, const char *image_root, co
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pull_make_settings_job(
|
||||
int pull_make_auxiliary_job(
|
||||
PullJob **ret,
|
||||
const char *url,
|
||||
int (*strip_suffixes)(const char *name, char **ret),
|
||||
const char *suffix,
|
||||
CurlGlue *glue,
|
||||
PullJobFinished on_finished,
|
||||
void *userdata) {
|
||||
|
||||
_cleanup_free_ char *last_component = NULL, *ll = NULL, *settings_url = NULL;
|
||||
_cleanup_free_ char *last_component = NULL, *ll = NULL, *auxiliary_url = NULL;
|
||||
_cleanup_(pull_job_unrefp) PullJob *job = NULL;
|
||||
const char *q;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(url);
|
||||
assert(strip_suffixes);
|
||||
assert(glue);
|
||||
|
||||
r = import_url_last_component(url, &last_component);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = tar_strip_suffixes(last_component, &ll);
|
||||
r = strip_suffixes(last_component, &ll);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
q = strjoina(ll, ".nspawn");
|
||||
q = strjoina(ll, suffix);
|
||||
|
||||
r = import_url_change_last_component(url, q, &settings_url);
|
||||
r = import_url_change_last_component(url, q, &auxiliary_url);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pull_job_new(&job, settings_url, glue, userdata);
|
||||
r = pull_job_new(&job, auxiliary_url, glue, userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -320,7 +323,56 @@ int pull_make_verification_jobs(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_one(PullJob *checksum_job, PullJob *job) {
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
const char *line, *p;
|
||||
int r;
|
||||
|
||||
assert(checksum_job);
|
||||
|
||||
if (!job)
|
||||
return 0;
|
||||
|
||||
assert(IN_SET(job->state, PULL_JOB_DONE, PULL_JOB_FAILED));
|
||||
|
||||
/* Don't verify the checksum if we didn't actually successfully download something new */
|
||||
if (job->state != PULL_JOB_DONE)
|
||||
return 0;
|
||||
if (job->error != 0)
|
||||
return 0;
|
||||
if (job->etag_exists)
|
||||
return 0;
|
||||
|
||||
assert(job->calc_checksum);
|
||||
assert(job->checksum);
|
||||
|
||||
r = import_url_last_component(job->url, &fn);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
if (!filename_is_valid(fn)) {
|
||||
log_error("Cannot verify checksum, could not determine server-side file name.");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
line = strjoina(job->checksum, " *", fn, "\n");
|
||||
|
||||
p = memmem(checksum_job->payload,
|
||||
checksum_job->payload_size,
|
||||
line,
|
||||
strlen(line));
|
||||
|
||||
if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) {
|
||||
log_error("DOWNLOAD INVALID: Checksum of %s file did not checkout, file has been tampered with.", fn);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
log_info("SHA256 checksum of %s is valid.", job->url);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pull_verify(PullJob *main_job,
|
||||
PullJob *roothash_job,
|
||||
PullJob *settings_job,
|
||||
PullJob *checksum_job,
|
||||
PullJob *signature_job) {
|
||||
@ -328,7 +380,6 @@ int pull_verify(PullJob *main_job,
|
||||
_cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 };
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
_cleanup_close_ int sig_file = -1;
|
||||
const char *p, *line;
|
||||
char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
|
||||
_cleanup_(sigkill_waitp) pid_t pid = 0;
|
||||
bool gpg_home_created = false;
|
||||
@ -342,6 +393,7 @@ int pull_verify(PullJob *main_job,
|
||||
|
||||
assert(main_job->calc_checksum);
|
||||
assert(main_job->checksum);
|
||||
|
||||
assert(checksum_job->state == PULL_JOB_DONE);
|
||||
|
||||
if (!checksum_job->payload || checksum_job->payload_size <= 0) {
|
||||
@ -349,64 +401,17 @@ int pull_verify(PullJob *main_job,
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
r = import_url_last_component(main_job->url, &fn);
|
||||
r = verify_one(checksum_job, main_job);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
return r;
|
||||
|
||||
if (!filename_is_valid(fn)) {
|
||||
log_error("Cannot verify checksum, could not determine valid server-side file name.");
|
||||
return -EBADMSG;
|
||||
}
|
||||
r = verify_one(checksum_job, roothash_job);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
line = strjoina(main_job->checksum, " *", fn, "\n");
|
||||
|
||||
p = memmem(checksum_job->payload,
|
||||
checksum_job->payload_size,
|
||||
line,
|
||||
strlen(line));
|
||||
|
||||
if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) {
|
||||
log_error("DOWNLOAD INVALID: Checksum did not check out, payload has been tampered with.");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
log_info("SHA256 checksum of %s is valid.", main_job->url);
|
||||
|
||||
assert(!settings_job || IN_SET(settings_job->state, PULL_JOB_DONE, PULL_JOB_FAILED));
|
||||
|
||||
if (settings_job &&
|
||||
settings_job->state == PULL_JOB_DONE &&
|
||||
settings_job->error == 0 &&
|
||||
!settings_job->etag_exists) {
|
||||
|
||||
_cleanup_free_ char *settings_fn = NULL;
|
||||
|
||||
assert(settings_job->calc_checksum);
|
||||
assert(settings_job->checksum);
|
||||
|
||||
r = import_url_last_component(settings_job->url, &settings_fn);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
if (!filename_is_valid(settings_fn)) {
|
||||
log_error("Cannot verify checksum, could not determine server-side settings file name.");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
line = strjoina(settings_job->checksum, " *", settings_fn, "\n");
|
||||
|
||||
p = memmem(checksum_job->payload,
|
||||
checksum_job->payload_size,
|
||||
line,
|
||||
strlen(line));
|
||||
|
||||
if (!p || (p != (char*) checksum_job->payload && p[-1] != '\n')) {
|
||||
log_error("DOWNLOAD INVALID: Checksum of settings file did not checkout, settings file has been tampered with.");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
log_info("SHA256 checksum of %s is valid.", settings_job->url);
|
||||
}
|
||||
r = verify_one(checksum_job, settings_job);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!signature_job)
|
||||
return 0;
|
||||
|
@ -30,7 +30,7 @@ int pull_find_old_etags(const char *url, const char *root, int dt, const char *p
|
||||
|
||||
int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret);
|
||||
|
||||
int pull_make_settings_job(PullJob **ret, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
|
||||
int pull_make_auxiliary_job(PullJob **ret, const char *url, int (*strip_suffixes)(const char *name, char **ret), const char *suffix, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
|
||||
int pull_make_verification_jobs(PullJob **ret_checksum_job, PullJob **ret_signature_job, ImportVerify verify, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata);
|
||||
|
||||
int pull_verify(PullJob *main_job, PullJob *settings_job, PullJob *checksum_job, PullJob *signature_job);
|
||||
int pull_verify(PullJob *main_job, PullJob *roothash_job, PullJob *settings_job, PullJob *checksum_job, PullJob *signature_job);
|
||||
|
@ -63,6 +63,7 @@ struct RawPull {
|
||||
char *image_root;
|
||||
|
||||
PullJob *raw_job;
|
||||
PullJob *roothash_job;
|
||||
PullJob *settings_job;
|
||||
PullJob *checksum_job;
|
||||
PullJob *signature_job;
|
||||
@ -74,6 +75,7 @@ struct RawPull {
|
||||
bool force_local;
|
||||
bool grow_machine_directory;
|
||||
bool settings;
|
||||
bool roothash;
|
||||
|
||||
char *final_path;
|
||||
char *temp_path;
|
||||
@ -81,6 +83,9 @@ struct RawPull {
|
||||
char *settings_path;
|
||||
char *settings_temp_path;
|
||||
|
||||
char *roothash_path;
|
||||
char *roothash_temp_path;
|
||||
|
||||
ImportVerify verify;
|
||||
};
|
||||
|
||||
@ -90,6 +95,7 @@ RawPull* raw_pull_unref(RawPull *i) {
|
||||
|
||||
pull_job_unref(i->raw_job);
|
||||
pull_job_unref(i->settings_job);
|
||||
pull_job_unref(i->roothash_job);
|
||||
pull_job_unref(i->checksum_job);
|
||||
pull_job_unref(i->signature_job);
|
||||
|
||||
@ -101,12 +107,18 @@ RawPull* raw_pull_unref(RawPull *i) {
|
||||
free(i->temp_path);
|
||||
}
|
||||
|
||||
if (i->roothash_temp_path) {
|
||||
(void) unlink(i->roothash_temp_path);
|
||||
free(i->roothash_temp_path);
|
||||
}
|
||||
|
||||
if (i->settings_temp_path) {
|
||||
(void) unlink(i->settings_temp_path);
|
||||
free(i->settings_temp_path);
|
||||
}
|
||||
|
||||
free(i->final_path);
|
||||
free(i->roothash_path);
|
||||
free(i->settings_path);
|
||||
free(i->image_root);
|
||||
free(i->local);
|
||||
@ -176,6 +188,11 @@ static void raw_pull_report_progress(RawPull *i, RawProgress p) {
|
||||
remain -= 5;
|
||||
}
|
||||
|
||||
if (i->roothash_job) {
|
||||
percent += i->roothash_job->progress_percent * 5 / 100;
|
||||
remain -= 5;
|
||||
}
|
||||
|
||||
if (i->checksum_job) {
|
||||
percent += i->checksum_job->progress_percent * 5 / 100;
|
||||
remain -= 5;
|
||||
@ -262,6 +279,55 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int raw_pull_determine_path(RawPull *i, const char *suffix, char **field) {
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
assert(field);
|
||||
|
||||
if (*field)
|
||||
return 0;
|
||||
|
||||
assert(i->raw_job);
|
||||
|
||||
r = pull_make_path(i->raw_job->url, i->raw_job->etag, i->image_root, ".raw-", suffix, field);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int raw_pull_copy_auxiliary_file(
|
||||
RawPull *i,
|
||||
const char *suffix,
|
||||
char **path) {
|
||||
|
||||
const char *local;
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
assert(suffix);
|
||||
assert(path);
|
||||
|
||||
r = raw_pull_determine_path(i, suffix, path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
local = strjoina(i->image_root, "/", i->local, suffix);
|
||||
|
||||
r = copy_file_atomic(*path, local, 0644, i->force_local, 0);
|
||||
if (r == -EEXIST)
|
||||
log_warning_errno(r, "File %s already exists, not replacing.", local);
|
||||
else if (r == -ENOENT)
|
||||
log_debug_errno(r, "Skipping creation of auxiliary file, since none was found.");
|
||||
else if (r < 0)
|
||||
log_warning_errno(r, "Failed to copy file %s, ignoring: %m", local);
|
||||
else
|
||||
log_info("Created new file %s.", local);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_pull_make_local_copy(RawPull *i) {
|
||||
_cleanup_free_ char *tp = NULL;
|
||||
_cleanup_close_ int dfd = -1;
|
||||
@ -274,12 +340,6 @@ static int raw_pull_make_local_copy(RawPull *i) {
|
||||
if (!i->local)
|
||||
return 0;
|
||||
|
||||
if (!i->final_path) {
|
||||
r = pull_make_path(i->raw_job->url, i->raw_job->etag, i->image_root, ".raw-", ".raw", &i->final_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (i->raw_job->etag_exists) {
|
||||
/* We have downloaded this one previously, reopen it */
|
||||
|
||||
@ -338,27 +398,16 @@ static int raw_pull_make_local_copy(RawPull *i) {
|
||||
|
||||
log_info("Created new local image '%s'.", i->local);
|
||||
|
||||
if (i->roothash) {
|
||||
r = raw_pull_copy_auxiliary_file(i, ".roothash", &i->roothash_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (i->settings) {
|
||||
const char *local_settings;
|
||||
assert(i->settings_job);
|
||||
|
||||
if (!i->settings_path) {
|
||||
r = pull_make_path(i->settings_job->url, i->settings_job->etag, i->image_root, ".settings-", NULL, &i->settings_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
local_settings = strjoina(i->image_root, "/", i->local, ".nspawn");
|
||||
|
||||
r = copy_file_atomic(i->settings_path, local_settings, 0644, i->force_local, 0);
|
||||
if (r == -EEXIST)
|
||||
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
|
||||
else if (r == -ENOENT)
|
||||
log_debug_errno(r, "Skipping creation of settings file, since none was found.");
|
||||
else if (r < 0)
|
||||
log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
|
||||
else
|
||||
log_info("Created new settings file %s.", local_settings);
|
||||
r = raw_pull_copy_auxiliary_file(i, ".nspawn", &i->settings_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -370,6 +419,8 @@ static bool raw_pull_is_done(RawPull *i) {
|
||||
|
||||
if (!PULL_JOB_IS_COMPLETE(i->raw_job))
|
||||
return false;
|
||||
if (i->roothash_job && !PULL_JOB_IS_COMPLETE(i->roothash_job))
|
||||
return false;
|
||||
if (i->settings_job && !PULL_JOB_IS_COMPLETE(i->settings_job))
|
||||
return false;
|
||||
if (i->checksum_job && !PULL_JOB_IS_COMPLETE(i->checksum_job))
|
||||
@ -380,6 +431,39 @@ static bool raw_pull_is_done(RawPull *i) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int raw_pull_rename_auxiliary_file(
|
||||
RawPull *i,
|
||||
const char *suffix,
|
||||
char **temp_path,
|
||||
char **path) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
assert(temp_path);
|
||||
assert(suffix);
|
||||
assert(path);
|
||||
|
||||
/* Regenerate final name for this auxiliary file, we might know the etag of the raw file now, and we shoud
|
||||
* incorporate it in the file name if we can */
|
||||
*path = mfree(*path);
|
||||
r = raw_pull_determine_path(i, suffix, path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = import_make_read_only(*temp_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = rename_noreplace(AT_FDCWD, *temp_path, AT_FDCWD, *path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to rename file %s to %s: %m", *temp_path, *path);
|
||||
|
||||
*temp_path = mfree(*temp_path);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void raw_pull_job_on_finished(PullJob *j) {
|
||||
RawPull *i;
|
||||
int r;
|
||||
@ -388,7 +472,10 @@ static void raw_pull_job_on_finished(PullJob *j) {
|
||||
assert(j->userdata);
|
||||
|
||||
i = j->userdata;
|
||||
if (j == i->settings_job) {
|
||||
if (j == i->roothash_job) {
|
||||
if (j->error != 0)
|
||||
log_info_errno(j->error, "Root hash file could not be retrieved, proceeding without.");
|
||||
} else if (j == i->settings_job) {
|
||||
if (j->error != 0)
|
||||
log_info_errno(j->error, "Settings file could not be retrieved, proceeding without.");
|
||||
} else if (j->error != 0) {
|
||||
@ -413,16 +500,22 @@ static void raw_pull_job_on_finished(PullJob *j) {
|
||||
if (!raw_pull_is_done(i))
|
||||
return;
|
||||
|
||||
if (i->roothash_job)
|
||||
i->roothash_job->disk_fd = safe_close(i->roothash_job->disk_fd);
|
||||
if (i->settings_job)
|
||||
i->settings_job->disk_fd = safe_close(i->settings_job->disk_fd);
|
||||
|
||||
r = raw_pull_determine_path(i, ".raw", &i->final_path);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (!i->raw_job->etag_exists) {
|
||||
/* This is a new download, verify it, and move it into place */
|
||||
assert(i->raw_job->disk_fd >= 0);
|
||||
|
||||
raw_pull_report_progress(i, RAW_VERIFYING);
|
||||
|
||||
r = pull_verify(i->raw_job, i->settings_job, i->checksum_job, i->signature_job);
|
||||
r = pull_verify(i->raw_job, i->roothash_job, i->settings_job, i->checksum_job, i->signature_job);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
@ -446,24 +539,18 @@ static void raw_pull_job_on_finished(PullJob *j) {
|
||||
|
||||
i->temp_path = mfree(i->temp_path);
|
||||
|
||||
if (i->settings_job &&
|
||||
i->settings_job->error == 0 &&
|
||||
!i->settings_job->etag_exists) {
|
||||
|
||||
assert(i->settings_temp_path);
|
||||
assert(i->settings_path);
|
||||
|
||||
r = import_make_read_only(i->settings_temp_path);
|
||||
if (i->roothash_job &&
|
||||
i->roothash_job->error == 0) {
|
||||
r = raw_pull_rename_auxiliary_file(i, ".roothash", &i->roothash_temp_path, &i->roothash_path);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = rename_noreplace(AT_FDCWD, i->settings_temp_path, AT_FDCWD, i->settings_path);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to rename settings file: %m");
|
||||
if (i->settings_job &&
|
||||
i->settings_job->error == 0) {
|
||||
r = raw_pull_rename_auxiliary_file(i, ".nspawn", &i->settings_temp_path, &i->settings_path);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
i->settings_temp_path = mfree(i->settings_temp_path);
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,6 +569,35 @@ finish:
|
||||
sd_event_exit(i->event, r);
|
||||
}
|
||||
|
||||
static int raw_pull_job_on_open_disk_generic(
|
||||
RawPull *i,
|
||||
PullJob *j,
|
||||
const char *extra,
|
||||
char **temp_path) {
|
||||
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
assert(j);
|
||||
assert(extra);
|
||||
assert(temp_path);
|
||||
|
||||
if (!*temp_path) {
|
||||
r = tempfn_random_child(i->image_root, extra, temp_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
(void) mkdir_parents_label(*temp_path, 0700);
|
||||
|
||||
j->disk_fd = open(*temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
|
||||
if (j->disk_fd < 0)
|
||||
return log_error_errno(errno, "Failed to create %s: %m", *temp_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_pull_job_on_open_disk_raw(PullJob *j) {
|
||||
RawPull *i;
|
||||
int r;
|
||||
@ -491,57 +607,40 @@ static int raw_pull_job_on_open_disk_raw(PullJob *j) {
|
||||
|
||||
i = j->userdata;
|
||||
assert(i->raw_job == j);
|
||||
assert(!i->final_path);
|
||||
assert(!i->temp_path);
|
||||
|
||||
r = pull_make_path(j->url, j->etag, i->image_root, ".raw-", ".raw", &i->final_path);
|
||||
r = raw_pull_job_on_open_disk_generic(i, j, "raw", &i->temp_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = tempfn_random(i->final_path, NULL, &i->temp_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
(void) mkdir_parents_label(i->temp_path, 0700);
|
||||
|
||||
j->disk_fd = open(i->temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
|
||||
if (j->disk_fd < 0)
|
||||
return log_error_errno(errno, "Failed to create %s: %m", i->temp_path);
|
||||
return r;
|
||||
|
||||
r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path);
|
||||
log_warning_errno(r, "Failed to set file attributes on %s, ignoring: %m", i->temp_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_pull_job_on_open_disk_roothash(PullJob *j) {
|
||||
RawPull *i;
|
||||
|
||||
assert(j);
|
||||
assert(j->userdata);
|
||||
|
||||
i = j->userdata;
|
||||
assert(i->roothash_job == j);
|
||||
|
||||
return raw_pull_job_on_open_disk_generic(i, j, "roothash", &i->roothash_temp_path);
|
||||
}
|
||||
|
||||
static int raw_pull_job_on_open_disk_settings(PullJob *j) {
|
||||
RawPull *i;
|
||||
int r;
|
||||
|
||||
assert(j);
|
||||
assert(j->userdata);
|
||||
|
||||
i = j->userdata;
|
||||
assert(i->settings_job == j);
|
||||
assert(!i->settings_path);
|
||||
assert(!i->settings_temp_path);
|
||||
|
||||
r = pull_make_path(j->url, j->etag, i->image_root, ".settings-", NULL, &i->settings_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = tempfn_random(i->settings_path, NULL, &i->settings_temp_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
mkdir_parents_label(i->settings_temp_path, 0700);
|
||||
|
||||
j->disk_fd = open(i->settings_temp_path, O_RDWR|O_CREAT|O_EXCL|O_NOCTTY|O_CLOEXEC, 0664);
|
||||
if (j->disk_fd < 0)
|
||||
return log_error_errno(errno, "Failed to create %s: %m", i->settings_temp_path);
|
||||
|
||||
return 0;
|
||||
return raw_pull_job_on_open_disk_generic(i, j, "settings", &i->settings_temp_path);
|
||||
}
|
||||
|
||||
static void raw_pull_job_on_progress(PullJob *j) {
|
||||
@ -561,7 +660,8 @@ int raw_pull_start(
|
||||
const char *local,
|
||||
bool force_local,
|
||||
ImportVerify verify,
|
||||
bool settings) {
|
||||
bool settings,
|
||||
bool roothash) {
|
||||
|
||||
int r;
|
||||
|
||||
@ -585,6 +685,7 @@ int raw_pull_start(
|
||||
i->force_local = force_local;
|
||||
i->verify = verify;
|
||||
i->settings = settings;
|
||||
i->roothash = roothash;
|
||||
|
||||
/* Queue job for the image itself */
|
||||
r = pull_job_new(&i->raw_job, url, i->glue, i);
|
||||
@ -601,18 +702,24 @@ int raw_pull_start(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (roothash) {
|
||||
r = pull_make_auxiliary_job(&i->roothash_job, url, raw_strip_suffixes, ".roothash", i->glue, raw_pull_job_on_finished, i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
i->roothash_job->on_open_disk = raw_pull_job_on_open_disk_roothash;
|
||||
i->roothash_job->on_progress = raw_pull_job_on_progress;
|
||||
i->roothash_job->calc_checksum = verify != IMPORT_VERIFY_NO;
|
||||
}
|
||||
|
||||
if (settings) {
|
||||
r = pull_make_settings_job(&i->settings_job, url, i->glue, raw_pull_job_on_finished, i);
|
||||
r = pull_make_auxiliary_job(&i->settings_job, url, raw_strip_suffixes, ".nspawn", i->glue, raw_pull_job_on_finished, i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
i->settings_job->on_open_disk = raw_pull_job_on_open_disk_settings;
|
||||
i->settings_job->on_progress = raw_pull_job_on_progress;
|
||||
i->settings_job->calc_checksum = verify != IMPORT_VERIFY_NO;
|
||||
|
||||
r = pull_find_old_etags(i->settings_job->url, i->image_root, DT_REG, ".settings-", NULL, &i->settings_job->old_etags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, raw_pull_job_on_finished, i);
|
||||
@ -623,6 +730,12 @@ int raw_pull_start(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (i->roothash_job) {
|
||||
r = pull_job_begin(i->roothash_job);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (i->settings_job) {
|
||||
r = pull_job_begin(i->settings_job);
|
||||
if (r < 0)
|
||||
|
@ -33,4 +33,4 @@ RawPull* raw_pull_unref(RawPull *pull);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(RawPull*, raw_pull_unref);
|
||||
|
||||
int raw_pull_start(RawPull *pull, const char *url, const char *local, bool force_local, ImportVerify verify, bool settings);
|
||||
int raw_pull_start(RawPull *pull, const char *url, const char *local, bool force_local, ImportVerify verify, bool settings, bool roothash);
|
||||
|
@ -215,6 +215,24 @@ static void tar_pull_report_progress(TarPull *i, TarProgress p) {
|
||||
log_debug("Combined progress %u%%", percent);
|
||||
}
|
||||
|
||||
static int tar_pull_determine_path(TarPull *i, const char *suffix, char **field) {
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
assert(field);
|
||||
|
||||
if (*field)
|
||||
return 0;
|
||||
|
||||
assert(i->tar_job);
|
||||
|
||||
r = pull_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", suffix, field);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tar_pull_make_local_copy(TarPull *i) {
|
||||
int r;
|
||||
|
||||
@ -224,12 +242,6 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
||||
if (!i->local)
|
||||
return 0;
|
||||
|
||||
if (!i->final_path) {
|
||||
r = pull_make_path(i->tar_job->url, i->tar_job->etag, i->image_root, ".tar-", NULL, &i->final_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = pull_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -238,11 +250,9 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
||||
const char *local_settings;
|
||||
assert(i->settings_job);
|
||||
|
||||
if (!i->settings_path) {
|
||||
r = pull_make_path(i->settings_job->url, i->settings_job->etag, i->image_root, ".settings-", NULL, &i->settings_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
r = tar_pull_determine_path(i, ".nspawn", &i->settings_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
local_settings = strjoina(i->image_root, "/", i->local, ".nspawn");
|
||||
|
||||
@ -311,6 +321,10 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
||||
if (i->settings_job)
|
||||
i->settings_job->disk_fd = safe_close(i->settings_job->disk_fd);
|
||||
|
||||
r = tar_pull_determine_path(i, NULL, &i->final_path);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (i->tar_pid > 0) {
|
||||
r = wait_for_terminate_and_warn("tar", i->tar_pid, true);
|
||||
i->tar_pid = 0;
|
||||
@ -327,7 +341,7 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
||||
|
||||
tar_pull_report_progress(i, TAR_VERIFYING);
|
||||
|
||||
r = pull_verify(i->tar_job, i->settings_job, i->checksum_job, i->signature_job);
|
||||
r = pull_verify(i->tar_job, NULL, i->settings_job, i->checksum_job, i->signature_job);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
@ -346,16 +360,18 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
||||
i->temp_path = mfree(i->temp_path);
|
||||
|
||||
if (i->settings_job &&
|
||||
i->settings_job->error == 0 &&
|
||||
!i->settings_job->etag_exists) {
|
||||
i->settings_job->error == 0) {
|
||||
|
||||
assert(i->settings_temp_path);
|
||||
assert(i->settings_path);
|
||||
|
||||
/* Also move the settings file into place, if
|
||||
* it exist. Note that we do so only if we
|
||||
* also moved the tar file in place, to keep
|
||||
* things strictly in sync. */
|
||||
/* Also move the settings file into place, if it exist. Note that we do so only if we also
|
||||
* moved the tar file in place, to keep things strictly in sync. */
|
||||
|
||||
i->settings_path = mfree(i->settings_path);
|
||||
r = tar_pull_determine_path(i, ".nspawn", &i->settings_path);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = import_make_read_only(i->settings_temp_path);
|
||||
if (r < 0)
|
||||
@ -395,17 +411,13 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
|
||||
|
||||
i = j->userdata;
|
||||
assert(i->tar_job == j);
|
||||
assert(!i->final_path);
|
||||
assert(!i->temp_path);
|
||||
assert(i->tar_pid <= 0);
|
||||
|
||||
r = pull_make_path(j->url, j->etag, i->image_root, ".tar-", NULL, &i->final_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = tempfn_random(i->final_path, NULL, &i->temp_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (!i->temp_path) {
|
||||
r = tempfn_random_child(i->image_root, "tar", &i->temp_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
mkdir_parents_label(i->temp_path, 0700);
|
||||
|
||||
@ -434,16 +446,12 @@ static int tar_pull_job_on_open_disk_settings(PullJob *j) {
|
||||
|
||||
i = j->userdata;
|
||||
assert(i->settings_job == j);
|
||||
assert(!i->settings_path);
|
||||
assert(!i->settings_temp_path);
|
||||
|
||||
r = pull_make_path(j->url, j->etag, i->image_root, ".settings-", NULL, &i->settings_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = tempfn_random(i->settings_path, NULL, &i->settings_temp_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
if (!i->settings_temp_path) {
|
||||
r = tempfn_random_child(i->image_root, "settings", &i->settings_temp_path);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
mkdir_parents_label(i->settings_temp_path, 0700);
|
||||
|
||||
@ -513,17 +521,13 @@ int tar_pull_start(
|
||||
|
||||
/* Set up download job for the settings file (.nspawn) */
|
||||
if (settings) {
|
||||
r = pull_make_settings_job(&i->settings_job, url, i->glue, tar_pull_job_on_finished, i);
|
||||
r = pull_make_auxiliary_job(&i->settings_job, url, tar_strip_suffixes, ".nspawn", i->glue, tar_pull_job_on_finished, i);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
i->settings_job->on_open_disk = tar_pull_job_on_open_disk_settings;
|
||||
i->settings_job->on_progress = tar_pull_job_on_progress;
|
||||
i->settings_job->calc_checksum = verify != IMPORT_VERIFY_NO;
|
||||
|
||||
r = pull_find_old_etags(i->settings_job->url, i->image_root, DT_REG, ".settings-", NULL, &i->settings_job->old_etags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Set up download of checksum/signature files */
|
||||
|
@ -37,6 +37,7 @@ static bool arg_force = false;
|
||||
static const char *arg_image_root = "/var/lib/machines";
|
||||
static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
|
||||
static bool arg_settings = true;
|
||||
static bool arg_roothash = true;
|
||||
|
||||
static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||
log_notice("Transfer aborted.");
|
||||
@ -204,7 +205,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate puller: %m");
|
||||
|
||||
r = raw_pull_start(pull, url, local, arg_force, arg_verify, arg_settings);
|
||||
r = raw_pull_start(pull, url, local, arg_force, arg_verify, arg_settings, arg_roothash);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to pull image: %m");
|
||||
|
||||
@ -226,6 +227,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" --verify=MODE Verify downloaded image, one of: 'no',\n"
|
||||
" 'checksum', 'signature'\n"
|
||||
" --settings=BOOL Download settings file with image\n"
|
||||
" --roothash=BOOL Download root hash file with image\n"
|
||||
" --image-root=PATH Image root directory\n\n"
|
||||
"Commands:\n"
|
||||
" tar URL [NAME] Download a TAR image\n"
|
||||
@ -243,6 +245,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_IMAGE_ROOT,
|
||||
ARG_VERIFY,
|
||||
ARG_SETTINGS,
|
||||
ARG_ROOTHASH,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -252,6 +255,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "image-root", required_argument, NULL, ARG_IMAGE_ROOT },
|
||||
{ "verify", required_argument, NULL, ARG_VERIFY },
|
||||
{ "settings", required_argument, NULL, ARG_SETTINGS },
|
||||
{ "roothash", required_argument, NULL, ARG_ROOTHASH },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -295,6 +299,14 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_settings = r;
|
||||
break;
|
||||
|
||||
case ARG_ROOTHASH:
|
||||
r = parse_boolean(optarg);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse --roothash= parameter '%s'", optarg);
|
||||
|
||||
arg_roothash = r;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -283,17 +283,16 @@ static int open_journal(
|
||||
}
|
||||
|
||||
static bool flushed_flag_is_set(void) {
|
||||
return (access("/run/systemd/journal/flushed", F_OK) >= 0);
|
||||
return access("/run/systemd/journal/flushed", F_OK) >= 0;
|
||||
}
|
||||
|
||||
static int system_journal_open(Server *s, bool flush_requested) {
|
||||
bool flushed = false;
|
||||
const char *fn;
|
||||
int r = 0;
|
||||
|
||||
if (!s->system_journal &&
|
||||
(s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) &&
|
||||
(flush_requested || (flushed = flushed_flag_is_set()))) {
|
||||
IN_SET(s->storage, STORAGE_PERSISTENT, STORAGE_AUTO) &&
|
||||
(flush_requested || flushed_flag_is_set())) {
|
||||
|
||||
/* If in auto mode: first try to create the machine
|
||||
* path, but not the prefix.
|
||||
@ -326,8 +325,8 @@ static int system_journal_open(Server *s, bool flush_requested) {
|
||||
* Perform an implicit flush to var, leaving the runtime
|
||||
* journal closed, now that the system journal is back.
|
||||
*/
|
||||
if (s->runtime_journal && flushed)
|
||||
(void) server_flush_to_var(s);
|
||||
if (!flush_requested)
|
||||
(void) server_flush_to_var(s, true);
|
||||
}
|
||||
|
||||
if (!s->runtime_journal &&
|
||||
@ -1183,7 +1182,7 @@ finish:
|
||||
dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, priority, object_pid);
|
||||
}
|
||||
|
||||
int server_flush_to_var(Server *s) {
|
||||
int server_flush_to_var(Server *s, bool require_flag_file) {
|
||||
sd_id128_t machine;
|
||||
sd_journal *j = NULL;
|
||||
char ts[FORMAT_TIMESPAN_MAX];
|
||||
@ -1193,13 +1192,15 @@ int server_flush_to_var(Server *s) {
|
||||
|
||||
assert(s);
|
||||
|
||||
if (s->storage != STORAGE_AUTO &&
|
||||
s->storage != STORAGE_PERSISTENT)
|
||||
if (!IN_SET(s->storage, STORAGE_AUTO, STORAGE_PERSISTENT))
|
||||
return 0;
|
||||
|
||||
if (!s->runtime_journal)
|
||||
return 0;
|
||||
|
||||
if (require_flag_file && !flushed_flag_is_set())
|
||||
return 0;
|
||||
|
||||
(void) system_journal_open(s, true);
|
||||
|
||||
if (!s->system_journal)
|
||||
@ -1411,7 +1412,7 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *
|
||||
|
||||
log_info("Received request to flush runtime journal from PID " PID_FMT, si->ssi_pid);
|
||||
|
||||
(void) server_flush_to_var(s);
|
||||
(void) server_flush_to_var(s, false);
|
||||
server_sync(s);
|
||||
server_vacuum(s, false);
|
||||
|
||||
@ -1532,60 +1533,93 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
|
||||
assert(s);
|
||||
|
||||
if (streq(key, "systemd.journald.forward_to_syslog")) {
|
||||
if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_syslog")) {
|
||||
|
||||
r = value ? parse_boolean(value) : true;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse forward to syslog switch \"%s\". Ignoring.", value);
|
||||
else
|
||||
s->forward_to_syslog = r;
|
||||
} else if (streq(key, "systemd.journald.forward_to_kmsg")) {
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_kmsg")) {
|
||||
|
||||
r = value ? parse_boolean(value) : true;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse forward to kmsg switch \"%s\". Ignoring.", value);
|
||||
else
|
||||
s->forward_to_kmsg = r;
|
||||
} else if (streq(key, "systemd.journald.forward_to_console")) {
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_console")) {
|
||||
|
||||
r = value ? parse_boolean(value) : true;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse forward to console switch \"%s\". Ignoring.", value);
|
||||
else
|
||||
s->forward_to_console = r;
|
||||
} else if (streq(key, "systemd.journald.forward_to_wall")) {
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.journald.forward_to_wall")) {
|
||||
|
||||
r = value ? parse_boolean(value) : true;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse forward to wall switch \"%s\". Ignoring.", value);
|
||||
else
|
||||
s->forward_to_wall = r;
|
||||
} else if (streq(key, "systemd.journald.max_level_console") && value) {
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_console")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = log_level_from_string(value);
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse max level console value \"%s\". Ignoring.", value);
|
||||
else
|
||||
s->max_level_console = r;
|
||||
} else if (streq(key, "systemd.journald.max_level_store") && value) {
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_store")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = log_level_from_string(value);
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse max level store value \"%s\". Ignoring.", value);
|
||||
else
|
||||
s->max_level_store = r;
|
||||
} else if (streq(key, "systemd.journald.max_level_syslog") && value) {
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_syslog")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = log_level_from_string(value);
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse max level syslog value \"%s\". Ignoring.", value);
|
||||
else
|
||||
s->max_level_syslog = r;
|
||||
} else if (streq(key, "systemd.journald.max_level_kmsg") && value) {
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_kmsg")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = log_level_from_string(value);
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse max level kmsg value \"%s\". Ignoring.", value);
|
||||
else
|
||||
s->max_level_kmsg = r;
|
||||
} else if (streq(key, "systemd.journald.max_level_wall") && value) {
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.journald.max_level_wall")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = log_level_from_string(value);
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse max level wall value \"%s\". Ignoring.", value);
|
||||
else
|
||||
s->max_level_wall = r;
|
||||
|
||||
} else if (startswith(key, "systemd.journald"))
|
||||
log_warning("Unknown journald kernel command line option \"%s\". Ignoring.", key);
|
||||
|
||||
@ -1898,7 +1932,10 @@ int server_init(Server *s) {
|
||||
journal_reset_metrics(&s->runtime_storage.metrics);
|
||||
|
||||
server_parse_config_file(s);
|
||||
parse_proc_cmdline(parse_proc_cmdline_item, s, true);
|
||||
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, s, PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
if (!!s->rate_limit_interval ^ !!s->rate_limit_burst) {
|
||||
log_debug("Setting both rate limit interval and burst from "USEC_FMT",%u to 0,0",
|
||||
|
@ -197,7 +197,7 @@ void server_sync(Server *s);
|
||||
int server_vacuum(Server *s, bool verbose);
|
||||
void server_rotate(Server *s);
|
||||
int server_schedule_sync(Server *s, int priority);
|
||||
int server_flush_to_var(Server *s);
|
||||
int server_flush_to_var(Server *s, bool require_flag_file);
|
||||
void server_maybe_append_tags(Server *s);
|
||||
int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata);
|
||||
void server_space_usage_message(Server *s, JournalStorage *storage);
|
||||
|
@ -52,7 +52,7 @@ int main(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
|
||||
server_vacuum(&server, false);
|
||||
server_flush_to_var(&server);
|
||||
server_flush_to_var(&server, true);
|
||||
server_flush_dev_kmsg(&server);
|
||||
|
||||
log_debug("systemd-journald running as pid "PID_FMT, getpid());
|
||||
|
@ -335,7 +335,7 @@ static int raw_image_get_os_release(Image *image, char ***ret, sd_bus_error *err
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to set up loop block device for %s: %m", image->path);
|
||||
|
||||
r = dissect_image(d->fd, NULL, 0, &m);
|
||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
|
||||
if (r == -ENOPKG)
|
||||
return sd_bus_error_set_errnof(error, r, "Disk image %s not understood: %m", image->path);
|
||||
if (r < 0)
|
||||
|
@ -2666,9 +2666,9 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" -o --output=STRING Change journal output mode (short,\n"
|
||||
" short-monotonic, verbose, export, json,\n"
|
||||
" json-pretty, json-sse, cat)\n"
|
||||
" --verify=MODE Verification mode for downloaded images (no,\n"
|
||||
" --verify=MODE Verification mode for downloaded images (no,\n"
|
||||
" checksum, signature)\n"
|
||||
" --force Download image even if already exists\n\n"
|
||||
" --force Download image even if already exists\n\n"
|
||||
"Machine Commands:\n"
|
||||
" list List running VMs and containers\n"
|
||||
" status NAME... Show VM/container details\n"
|
||||
|
@ -62,7 +62,11 @@ static int add_modules(const char *p) {
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
int r;
|
||||
|
||||
if (streq(key, "modules-load") && value) {
|
||||
if (proc_cmdline_key_streq(key, "modules_load")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = add_modules(value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -226,7 +230,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
|
@ -1349,21 +1349,3 @@ fail:
|
||||
(void) rmdir(template);
|
||||
return r;
|
||||
}
|
||||
|
||||
VolatileMode volatile_mode_from_string(const char *s) {
|
||||
int b;
|
||||
|
||||
if (isempty(s))
|
||||
return _VOLATILE_MODE_INVALID;
|
||||
|
||||
b = parse_boolean(s);
|
||||
if (b > 0)
|
||||
return VOLATILE_YES;
|
||||
if (b == 0)
|
||||
return VOLATILE_NO;
|
||||
|
||||
if (streq(s, "state"))
|
||||
return VOLATILE_STATE;
|
||||
|
||||
return _VOLATILE_MODE_INVALID;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "cgroup-util.h"
|
||||
#include "volatile-util.h"
|
||||
|
||||
typedef enum MountSettingsMask {
|
||||
MOUNT_FATAL = 1 << 0, /* if set, a mount error is considered fatal */
|
||||
@ -32,14 +33,6 @@ typedef enum MountSettingsMask {
|
||||
Works only if MOUNT_APPLY_APIVFS_RO is also set. */
|
||||
} MountSettingsMask;
|
||||
|
||||
typedef enum VolatileMode {
|
||||
VOLATILE_NO,
|
||||
VOLATILE_YES,
|
||||
VOLATILE_STATE,
|
||||
_VOLATILE_MODE_MAX,
|
||||
_VOLATILE_MODE_INVALID = -1
|
||||
} VolatileMode;
|
||||
|
||||
typedef enum CustomMountType {
|
||||
CUSTOM_MOUNT_BIND,
|
||||
CUSTOM_MOUNT_TMPFS,
|
||||
@ -77,5 +70,3 @@ int mount_custom(const char *dest, CustomMount *mounts, unsigned n, bool userns,
|
||||
|
||||
int setup_volatile(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
|
||||
int setup_volatile_state(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
|
||||
|
||||
VolatileMode volatile_mode_from_string(const char *s);
|
||||
|
@ -1288,15 +1288,18 @@ static int setup_timezone(const char *dest) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = unlink(where);
|
||||
if (r < 0 && errno != ENOENT) {
|
||||
log_error_errno(errno, "Failed to remove existing timezone info %s in container: %m", where);
|
||||
if (unlink(where) < 0 && errno != ENOENT) {
|
||||
log_full_errno(IN_SET(errno, EROFS, EACCES, EPERM) ? LOG_DEBUG : LOG_WARNING, /* Don't complain on read-only images */
|
||||
errno,
|
||||
"Failed to remove existing timezone info %s in container, ignoring: %m", where);
|
||||
return 0;
|
||||
}
|
||||
|
||||
what = strjoina("../usr/share/zoneinfo/", z);
|
||||
if (symlink(what, where) < 0) {
|
||||
log_error_errno(errno, "Failed to correct timezone of container: %m");
|
||||
log_full_errno(IN_SET(errno, EROFS, EACCES, EPERM) ? LOG_DEBUG : LOG_WARNING,
|
||||
errno,
|
||||
"Failed to correct timezone of container, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1308,31 +1311,43 @@ static int setup_timezone(const char *dest) {
|
||||
}
|
||||
|
||||
static int setup_resolv_conf(const char *dest) {
|
||||
const char *where = NULL;
|
||||
int r;
|
||||
_cleanup_free_ char *resolved = NULL, *etc = NULL;
|
||||
const char *where;
|
||||
int r, found;
|
||||
|
||||
assert(dest);
|
||||
|
||||
if (arg_private_network)
|
||||
return 0;
|
||||
|
||||
/* Fix resolv.conf, if possible */
|
||||
where = prefix_roota(dest, "/etc/resolv.conf");
|
||||
r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to resolve /etc path in container, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
where = strjoina(etc, "/resolv.conf");
|
||||
found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved);
|
||||
if (found < 0) {
|
||||
log_warning_errno(found, "Failed to resolve /etc/resolv.conf path in container, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (access("/run/systemd/resolve/resolv.conf", F_OK) >= 0 &&
|
||||
access("/usr/lib/systemd/resolv.conf", F_OK) >= 0) {
|
||||
access("/usr/lib/systemd/resolv.conf", F_OK) >= 0) {
|
||||
|
||||
/* resolved is enabled on the host. In this, case bind mount its static resolv.conf file into the
|
||||
* container, so that the container can use the host's resolver. Given that network namespacing is
|
||||
* disabled it's only natural of the container also uses the host's resolver. It also has the big
|
||||
* advantage that the container will be able to follow the host's DNS server configuration changes
|
||||
* transparently. */
|
||||
|
||||
(void) touch(where);
|
||||
if (found == 0) /* missing? */
|
||||
(void) touch(resolved);
|
||||
|
||||
r = mount_verbose(LOG_WARNING, "/usr/lib/systemd/resolv.conf", where, NULL, MS_BIND, NULL);
|
||||
r = mount_verbose(LOG_DEBUG, "/usr/lib/systemd/resolv.conf", resolved, NULL, MS_BIND, NULL);
|
||||
if (r >= 0)
|
||||
return mount_verbose(LOG_ERR, NULL, where, NULL,
|
||||
MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NODEV, NULL);
|
||||
return mount_verbose(LOG_ERR, NULL, resolved, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NOSUID|MS_NODEV, NULL);
|
||||
}
|
||||
|
||||
/* If that didn't work, let's copy the file */
|
||||
@ -1343,7 +1358,7 @@ static int setup_resolv_conf(const char *dest) {
|
||||
*
|
||||
* If the disk image is read-only, there's also no point in complaining.
|
||||
*/
|
||||
log_full_errno(IN_SET(r, -ELOOP, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
log_full_errno(IN_SET(r, -ELOOP, -EROFS, -EACCES, -EPERM) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Failed to copy /etc/resolv.conf to %s, ignoring: %m", where);
|
||||
return 0;
|
||||
}
|
||||
@ -2467,20 +2482,6 @@ static int outer_child(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Mark everything as shared so our mounts get propagated down. This is
|
||||
* required to make new bind mounts available in systemd services
|
||||
* inside the containter that create a new mount namespace.
|
||||
* See https://github.com/systemd/systemd/issues/3860
|
||||
* Further submounts (such as /dev) done after this will inherit the
|
||||
* shared propagation mode.*/
|
||||
r = mount_verbose(LOG_ERR, NULL, directory, NULL, MS_SHARED|MS_REC, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = recursive_chown(directory, arg_uid_shift, arg_uid_range);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = setup_volatile(
|
||||
directory,
|
||||
arg_volatile_mode,
|
||||
@ -2501,6 +2502,20 @@ static int outer_child(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Mark everything as shared so our mounts get propagated down. This is
|
||||
* required to make new bind mounts available in systemd services
|
||||
* inside the containter that create a new mount namespace.
|
||||
* See https://github.com/systemd/systemd/issues/3860
|
||||
* Further submounts (such as /dev) done after this will inherit the
|
||||
* shared propagation mode.*/
|
||||
r = mount_verbose(LOG_ERR, NULL, directory, NULL, MS_SHARED|MS_REC, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = recursive_chown(directory, arg_uid_shift, arg_uid_range);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = base_filesystem_create(directory, arg_uid_shift, (gid_t) arg_uid_shift);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -3740,7 +3755,11 @@ int main(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = dissect_image(loop->fd, arg_root_hash, arg_root_hash_size, &dissected_image);
|
||||
r = dissect_image(
|
||||
loop->fd,
|
||||
arg_root_hash, arg_root_hash_size,
|
||||
DISSECT_IMAGE_REQUIRE_ROOT,
|
||||
&dissected_image);
|
||||
if (r == -ENOPKG) {
|
||||
log_error_errno(r, "Could not find a suitable file system or partition table in image: %s", arg_image);
|
||||
|
||||
|
@ -34,7 +34,10 @@ static bool arg_force = false;
|
||||
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
|
||||
if (streq(key, "quotacheck.mode") && value) {
|
||||
if (streq(key, "quotacheck.mode")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
if (streq(value, "auto"))
|
||||
arg_force = arg_skip = false;
|
||||
@ -88,7 +91,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, false);
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
@ -104,9 +107,10 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
log_error_errno(errno, "fork(): %m");
|
||||
return EXIT_FAILURE;
|
||||
} else if (pid == 0) {
|
||||
r = log_error_errno(errno, "fork(): %m");
|
||||
goto finish;
|
||||
}
|
||||
if (pid == 0) {
|
||||
|
||||
/* Child */
|
||||
|
||||
@ -120,5 +124,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
r = wait_for_terminate_and_warn("quotacheck", pid, true);
|
||||
|
||||
finish:
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
umask(0022);
|
||||
|
||||
f = setmntent("/etc/fstab", "r");
|
||||
f = setmntent("/etc/fstab", "re");
|
||||
if (!f) {
|
||||
if (errno == ENOENT) {
|
||||
r = 0;
|
||||
|
@ -101,7 +101,7 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
|
||||
if (r < 0 && errno != EEXIST)
|
||||
return log_error_errno(errno, "Failed to create symlink at %s/%s: %m", root, table[i].dir);
|
||||
|
||||
if (uid != UID_INVALID || gid != UID_INVALID) {
|
||||
if (uid_is_valid(uid) || gid_is_valid(gid)) {
|
||||
if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
|
||||
return log_error_errno(errno, "Failed to chown symlink at %s/%s: %m", root, table[i].dir);
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ not_found:
|
||||
#endif
|
||||
}
|
||||
|
||||
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectedImage **ret) {
|
||||
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret) {
|
||||
|
||||
#ifdef HAVE_BLKID
|
||||
sd_id128_t root_uuid = SD_ID128_NULL, verity_uuid = SD_ID128_NULL;
|
||||
@ -95,7 +95,8 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
|
||||
_cleanup_udev_unref_ struct udev *udev = NULL;
|
||||
_cleanup_free_ char *generic_node = NULL;
|
||||
const char *pttype = NULL, *usage = NULL;
|
||||
sd_id128_t generic_uuid = SD_ID128_NULL;
|
||||
const char *pttype = NULL;
|
||||
struct udev_list_entry *first, *item;
|
||||
blkid_partlist pl;
|
||||
int r, generic_nr;
|
||||
@ -147,8 +148,12 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
return -errno;
|
||||
}
|
||||
|
||||
blkid_probe_enable_superblocks(b, 1);
|
||||
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE);
|
||||
if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) {
|
||||
/* Look for file system superblocks, unless we only shall look for GPT partition tables */
|
||||
blkid_probe_enable_superblocks(b, 1);
|
||||
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE);
|
||||
}
|
||||
|
||||
blkid_probe_enable_partitions(b, 1);
|
||||
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
@ -169,40 +174,45 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
(void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
|
||||
if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
|
||||
_cleanup_free_ char *t = NULL, *n = NULL;
|
||||
const char *fstype = NULL;
|
||||
if (!(flags & DISSECT_IMAGE_GPT_ONLY) &&
|
||||
(flags & DISSECT_IMAGE_REQUIRE_ROOT)) {
|
||||
const char *usage = NULL;
|
||||
|
||||
/* OK, we have found a file system, that's our root partition then. */
|
||||
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
|
||||
(void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
|
||||
if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
|
||||
_cleanup_free_ char *t = NULL, *n = NULL;
|
||||
const char *fstype = NULL;
|
||||
|
||||
if (fstype) {
|
||||
t = strdup(fstype);
|
||||
if (!t)
|
||||
/* OK, we have found a file system, that's our root partition then. */
|
||||
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
|
||||
|
||||
if (fstype) {
|
||||
t = strdup(fstype);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (asprintf(&n, "/dev/block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
m->partitions[PARTITION_ROOT] = (DissectedPartition) {
|
||||
.found = true,
|
||||
.rw = true,
|
||||
.partno = -1,
|
||||
.architecture = _ARCHITECTURE_INVALID,
|
||||
.fstype = t,
|
||||
.node = n,
|
||||
};
|
||||
|
||||
t = n = NULL;
|
||||
|
||||
m->encrypted = streq(fstype, "crypto_LUKS");
|
||||
|
||||
*ret = m;
|
||||
m = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (asprintf(&n, "/dev/block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
m->partitions[PARTITION_ROOT] = (DissectedPartition) {
|
||||
.found = true,
|
||||
.rw = true,
|
||||
.partno = -1,
|
||||
.architecture = _ARCHITECTURE_INVALID,
|
||||
.fstype = t,
|
||||
.node = n,
|
||||
};
|
||||
|
||||
t = n = NULL;
|
||||
|
||||
m->encrypted = streq(fstype, "crypto_LUKS");
|
||||
|
||||
*ret = m;
|
||||
m = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
|
||||
@ -212,7 +222,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
is_gpt = streq_ptr(pttype, "gpt");
|
||||
is_mbr = streq_ptr(pttype, "dos");
|
||||
|
||||
if (!is_gpt && !is_mbr)
|
||||
if (!is_gpt && ((flags & DISSECT_IMAGE_GPT_ONLY) || !is_mbr))
|
||||
return -ENOPKG;
|
||||
|
||||
errno = 0;
|
||||
@ -300,7 +310,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
first = udev_enumerate_get_list_entry(e);
|
||||
udev_list_entry_foreach(item, first) {
|
||||
_cleanup_udev_device_unref_ struct udev_device *q;
|
||||
unsigned long long flags;
|
||||
unsigned long long pflags;
|
||||
blkid_partition pp;
|
||||
const char *node;
|
||||
dev_t qn;
|
||||
@ -325,7 +335,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
if (!pp)
|
||||
continue;
|
||||
|
||||
flags = blkid_partition_get_flags(pp);
|
||||
pflags = blkid_partition_get_flags(pp);
|
||||
|
||||
nr = blkid_partition_get_partno(pp);
|
||||
if (nr < 0)
|
||||
@ -337,7 +347,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
sd_id128_t type_id, id;
|
||||
bool rw = true;
|
||||
|
||||
if (flags & GPT_FLAG_NO_AUTO)
|
||||
if (pflags & GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
sid = blkid_partition_get_uuid(pp);
|
||||
@ -354,10 +364,10 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
|
||||
if (sd_id128_equal(type_id, GPT_HOME)) {
|
||||
designator = PARTITION_HOME;
|
||||
rw = !(flags & GPT_FLAG_READ_ONLY);
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
} else if (sd_id128_equal(type_id, GPT_SRV)) {
|
||||
designator = PARTITION_SRV;
|
||||
rw = !(flags & GPT_FLAG_READ_ONLY);
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
} else if (sd_id128_equal(type_id, GPT_ESP)) {
|
||||
designator = PARTITION_ESP;
|
||||
fstype = "vfat";
|
||||
@ -371,7 +381,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
|
||||
designator = PARTITION_ROOT;
|
||||
architecture = native_architecture();
|
||||
rw = !(flags & GPT_FLAG_READ_ONLY);
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
} else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE_VERITY)) {
|
||||
|
||||
m->can_verity = true;
|
||||
@ -395,9 +405,8 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
|
||||
designator = PARTITION_ROOT_SECONDARY;
|
||||
architecture = SECONDARY_ARCHITECTURE;
|
||||
rw = !(flags & GPT_FLAG_READ_ONLY);
|
||||
rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
} else if (sd_id128_equal(type_id, GPT_ROOT_SECONDARY_VERITY)) {
|
||||
|
||||
m->can_verity = true;
|
||||
|
||||
/* Ignore verity unless root has is specified */
|
||||
@ -419,7 +428,8 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
multiple_generic = true;
|
||||
else {
|
||||
generic_nr = nr;
|
||||
generic_rw = !(flags & GPT_FLAG_READ_ONLY);
|
||||
generic_rw = !(pflags & GPT_FLAG_READ_ONLY);
|
||||
generic_uuid = id;
|
||||
generic_node = strdup(node);
|
||||
if (!generic_node)
|
||||
return -ENOMEM;
|
||||
@ -450,6 +460,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
.architecture = architecture,
|
||||
.node = n,
|
||||
.fstype = t,
|
||||
.uuid = id,
|
||||
};
|
||||
|
||||
n = t = NULL;
|
||||
@ -457,7 +468,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
|
||||
} else if (is_mbr) {
|
||||
|
||||
if (flags != 0x80) /* Bootable flag */
|
||||
if (pflags != 0x80) /* Bootable flag */
|
||||
continue;
|
||||
|
||||
if (blkid_partition_get_type(pp) != 0x83) /* Linux partition */
|
||||
@ -480,7 +491,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
* either, then check if there's a single generic one, and use that. */
|
||||
|
||||
if (m->partitions[PARTITION_ROOT_VERITY].found)
|
||||
return -ENXIO;
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
if (m->partitions[PARTITION_ROOT_SECONDARY].found) {
|
||||
m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY];
|
||||
@ -489,8 +500,19 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY];
|
||||
zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
|
||||
|
||||
} else if (generic_node && !root_hash) {
|
||||
} else if (flags & DISSECT_IMAGE_REQUIRE_ROOT) {
|
||||
|
||||
/* If the root has was set, then we won't fallback to a generic node, because the root hash
|
||||
* decides */
|
||||
if (root_hash)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
/* If we didn't find a generic node, then we can't fix this up either */
|
||||
if (!generic_node)
|
||||
return -ENXIO;
|
||||
|
||||
/* If we didn't find a properly marked root partition, but we did find a single suitable
|
||||
* generic Linux partition, then use this as root partition, if the caller asked for it. */
|
||||
if (multiple_generic)
|
||||
return -ENOTUNIQ;
|
||||
|
||||
@ -500,17 +522,15 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, Dissecte
|
||||
.partno = generic_nr,
|
||||
.architecture = _ARCHITECTURE_INVALID,
|
||||
.node = generic_node,
|
||||
.uuid = generic_uuid,
|
||||
};
|
||||
|
||||
generic_node = NULL;
|
||||
} else
|
||||
return -ENXIO;
|
||||
}
|
||||
}
|
||||
|
||||
assert(m->partitions[PARTITION_ROOT].found);
|
||||
|
||||
if (root_hash) {
|
||||
if (!m->partitions[PARTITION_ROOT_VERITY].found)
|
||||
if (!m->partitions[PARTITION_ROOT_VERITY].found || !m->partitions[PARTITION_ROOT].found)
|
||||
return -EADDRNOTAVAIL;
|
||||
|
||||
/* If we found the primary root with the hash, then we definitely want to suppress any secondary root
|
||||
|
@ -32,6 +32,7 @@ struct DissectedPartition {
|
||||
bool rw:1;
|
||||
int partno; /* -1 if there was no partition and the images contains a file system directly */
|
||||
int architecture; /* Intended architecture: either native, secondary or unset (-1). */
|
||||
sd_id128_t uuid; /* Partition entry UUID as reported by the GPT */
|
||||
char *fstype;
|
||||
char *node;
|
||||
char *decrypted_node;
|
||||
@ -67,6 +68,8 @@ typedef enum DissectImageFlags {
|
||||
DISSECT_IMAGE_DISCARD_ANY = DISSECT_IMAGE_DISCARD_ON_LOOP |
|
||||
DISSECT_IMAGE_DISCARD |
|
||||
DISSECT_IMAGE_DISCARD_ON_CRYPTO,
|
||||
DISSECT_IMAGE_GPT_ONLY = 16, /* Only recognize images with GPT partition tables */
|
||||
DISSECT_IMAGE_REQUIRE_ROOT = 32, /* Don't accept disks without root partition */
|
||||
} DissectImageFlags;
|
||||
|
||||
struct DissectedImage {
|
||||
@ -76,7 +79,7 @@ struct DissectedImage {
|
||||
DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
|
||||
};
|
||||
|
||||
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectedImage **ret);
|
||||
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret);
|
||||
|
||||
DissectedImage* dissected_image_unref(DissectedImage *m);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
|
||||
|
@ -38,7 +38,7 @@ bool fstab_is_mount_point(const char *mount) {
|
||||
_cleanup_endmntent_ FILE *f = NULL;
|
||||
struct mntent *m;
|
||||
|
||||
f = setmntent("/etc/fstab", "r");
|
||||
f = setmntent("/etc/fstab", "re");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
|
@ -99,6 +99,16 @@ static char **image_settings_path(Image *image) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *image_roothash_path(Image *image) {
|
||||
const char *fn;
|
||||
|
||||
assert(image);
|
||||
|
||||
fn = strjoina(image->name, ".roothash");
|
||||
|
||||
return file_in_same_dir(image->path, fn);
|
||||
}
|
||||
|
||||
static int image_new(
|
||||
ImageType t,
|
||||
const char *pretty,
|
||||
@ -397,6 +407,7 @@ void image_hashmap_free(Hashmap *map) {
|
||||
int image_remove(Image *i) {
|
||||
_cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
|
||||
_cleanup_strv_free_ char **settings = NULL;
|
||||
_cleanup_free_ char *roothash = NULL;
|
||||
char **j;
|
||||
int r;
|
||||
|
||||
@ -409,6 +420,10 @@ int image_remove(Image *i) {
|
||||
if (!settings)
|
||||
return -ENOMEM;
|
||||
|
||||
roothash = image_roothash_path(i);
|
||||
if (!roothash)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Make sure we don't interfere with a running nspawn */
|
||||
r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
|
||||
if (r < 0)
|
||||
@ -445,14 +460,17 @@ int image_remove(Image *i) {
|
||||
log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", *j);
|
||||
}
|
||||
|
||||
if (unlink(roothash) < 0 && errno != ENOENT)
|
||||
log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", roothash);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rename_settings_file(const char *path, const char *new_name) {
|
||||
static int rename_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
|
||||
_cleanup_free_ char *rs = NULL;
|
||||
const char *fn;
|
||||
|
||||
fn = strjoina(new_name, ".nspawn");
|
||||
fn = strjoina(new_name, suffix);
|
||||
|
||||
rs = file_in_same_dir(path, fn);
|
||||
if (!rs)
|
||||
@ -463,7 +481,7 @@ static int rename_settings_file(const char *path, const char *new_name) {
|
||||
|
||||
int image_rename(Image *i, const char *new_name) {
|
||||
_cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
|
||||
_cleanup_free_ char *new_path = NULL, *nn = NULL;
|
||||
_cleanup_free_ char *new_path = NULL, *nn = NULL, *roothash = NULL;
|
||||
_cleanup_strv_free_ char **settings = NULL;
|
||||
unsigned file_attr = 0;
|
||||
char **j;
|
||||
@ -481,6 +499,10 @@ int image_rename(Image *i, const char *new_name) {
|
||||
if (!settings)
|
||||
return -ENOMEM;
|
||||
|
||||
roothash = image_roothash_path(i);
|
||||
if (!roothash)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Make sure we don't interfere with a running nspawn */
|
||||
r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
|
||||
if (r < 0)
|
||||
@ -550,19 +572,23 @@ int image_rename(Image *i, const char *new_name) {
|
||||
nn = NULL;
|
||||
|
||||
STRV_FOREACH(j, settings) {
|
||||
r = rename_settings_file(*j, new_name);
|
||||
r = rename_auxiliary_file(*j, new_name, ".nspawn");
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to rename settings file %s, ignoring: %m", *j);
|
||||
}
|
||||
|
||||
r = rename_auxiliary_file(roothash, new_name, ".roothash");
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to rename roothash file %s, ignoring: %m", roothash);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clone_settings_file(const char *path, const char *new_name) {
|
||||
static int clone_auxiliary_file(const char *path, const char *new_name, const char *suffix) {
|
||||
_cleanup_free_ char *rs = NULL;
|
||||
const char *fn;
|
||||
|
||||
fn = strjoina(new_name, ".nspawn");
|
||||
fn = strjoina(new_name, suffix);
|
||||
|
||||
rs = file_in_same_dir(path, fn);
|
||||
if (!rs)
|
||||
@ -574,6 +600,7 @@ static int clone_settings_file(const char *path, const char *new_name) {
|
||||
int image_clone(Image *i, const char *new_name, bool read_only) {
|
||||
_cleanup_release_lock_file_ LockFile name_lock = LOCK_FILE_INIT;
|
||||
_cleanup_strv_free_ char **settings = NULL;
|
||||
_cleanup_free_ char *roothash = NULL;
|
||||
const char *new_path;
|
||||
char **j;
|
||||
int r;
|
||||
@ -587,6 +614,10 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
|
||||
if (!settings)
|
||||
return -ENOMEM;
|
||||
|
||||
roothash = image_roothash_path(i);
|
||||
if (!roothash)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Make sure nobody takes the new name, between the time we
|
||||
* checked it is currently unused in all search paths, and the
|
||||
* time we take possession of it */
|
||||
@ -636,11 +667,15 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(j, settings) {
|
||||
r = clone_settings_file(*j, new_name);
|
||||
r = clone_auxiliary_file(*j, new_name, ".nspawn");
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to clone settings %s, ignoring: %m", *j);
|
||||
}
|
||||
|
||||
r = clone_auxiliary_file(roothash, new_name, ".roothash");
|
||||
if (r < 0 && r != -ENOENT)
|
||||
log_debug_errno(r, "Failed to clone root hash file %s, ignoring: %m", roothash);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -28,123 +28,102 @@
|
||||
|
||||
#include "base-filesystem.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "log.h"
|
||||
#include "missing.h"
|
||||
#include "mkdir.h"
|
||||
#include "mount-util.h"
|
||||
#include "path-util.h"
|
||||
#include "rm-rf.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "switch-root.h"
|
||||
#include "user-util.h"
|
||||
#include "util.h"
|
||||
|
||||
int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags) {
|
||||
|
||||
/* Don't try to unmount/move the old "/", there's no way to do it. */
|
||||
static const char move_mounts[] =
|
||||
"/dev\0"
|
||||
"/proc\0"
|
||||
"/sys\0"
|
||||
"/run\0";
|
||||
int switch_root(const char *new_root,
|
||||
const char *old_root_after, /* path below the new root, where to place the old root after the transition */
|
||||
bool unmount_old_root,
|
||||
unsigned long mount_flags) { /* MS_MOVE or MS_BIND */
|
||||
|
||||
_cleanup_free_ char *resolved_old_root_after = NULL;
|
||||
_cleanup_close_ int old_root_fd = -1;
|
||||
struct stat new_root_stat;
|
||||
bool old_root_remove;
|
||||
const char *i, *temporary_old_root;
|
||||
const char *i;
|
||||
int r;
|
||||
|
||||
assert(new_root);
|
||||
assert(old_root_after);
|
||||
|
||||
if (path_equal(new_root, "/"))
|
||||
return 0;
|
||||
|
||||
temporary_old_root = strjoina(new_root, oldroot);
|
||||
mkdir_p_label(temporary_old_root, 0755);
|
||||
|
||||
/* Check if we shall remove the contents of the old root */
|
||||
old_root_remove = in_initrd();
|
||||
if (old_root_remove) {
|
||||
old_root_fd = open("/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
|
||||
if (old_root_fd < 0)
|
||||
return log_error_errno(errno, "Failed to open root directory: %m");
|
||||
}
|
||||
|
||||
if (stat(new_root, &new_root_stat) < 0)
|
||||
return log_error_errno(errno, "Failed to stat directory %s: %m", new_root);
|
||||
/* Determine where we shall place the old root after the transition */
|
||||
r = chase_symlinks(old_root_after, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved_old_root_after);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to resolve %s/%s: %m", new_root, old_root_after);
|
||||
if (r == 0) /* Doesn't exist yet. Let's create it */
|
||||
(void) mkdir_p_label(resolved_old_root_after, 0755);
|
||||
|
||||
/* Work-around for kernel design: the kernel refuses switching
|
||||
* root if any file systems are mounted MS_SHARED. Hence
|
||||
/* Work-around for kernel design: the kernel refuses MS_MOVE if any file systems are mounted MS_SHARED. Hence
|
||||
* remount them MS_PRIVATE here as a work-around.
|
||||
*
|
||||
* https://bugzilla.redhat.com/show_bug.cgi?id=847418 */
|
||||
if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
|
||||
log_warning_errno(errno, "Failed to make \"/\" private mount: %m");
|
||||
return log_error_errno(errno, "Failed to set \"/\" mount propagation to private: %m");
|
||||
|
||||
NULSTR_FOREACH(i, move_mounts) {
|
||||
char new_mount[PATH_MAX];
|
||||
struct stat sb;
|
||||
size_t n;
|
||||
FOREACH_STRING(i, "/sys", "/dev", "/run", "/proc") {
|
||||
_cleanup_free_ char *chased = NULL;
|
||||
|
||||
n = snprintf(new_mount, sizeof new_mount, "%s%s", new_root, i);
|
||||
if (n >= sizeof new_mount) {
|
||||
bool move = mountflags & MS_MOVE;
|
||||
r = chase_symlinks(i, new_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &chased);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to resolve %s/%s: %m", new_root, i);
|
||||
if (r > 0) {
|
||||
/* Already exists. Let's see if it is a mount point already. */
|
||||
r = path_is_mount_point(chased, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", chased);
|
||||
if (r > 0) /* If it is already mounted, then do nothing */
|
||||
continue;
|
||||
} else
|
||||
/* Doesn't exist yet? */
|
||||
(void) mkdir_p_label(chased, 0755);
|
||||
|
||||
log_warning("New path is too long, %s: %s%s",
|
||||
move ? "forcing unmount instead" : "ignoring",
|
||||
new_root, i);
|
||||
|
||||
if (move)
|
||||
if (umount2(i, MNT_FORCE) < 0)
|
||||
log_warning_errno(errno, "Failed to unmount %s: %m", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
mkdir_p_label(new_mount, 0755);
|
||||
|
||||
if (stat(new_mount, &sb) < 0 ||
|
||||
sb.st_dev != new_root_stat.st_dev) {
|
||||
|
||||
/* Mount point seems to be mounted already or
|
||||
* stat failed. Unmount the old mount point. */
|
||||
if (umount2(i, MNT_DETACH) < 0)
|
||||
log_warning_errno(errno, "Failed to unmount %s: %m", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mount(i, new_mount, NULL, mountflags, NULL) < 0) {
|
||||
if (mountflags & MS_MOVE) {
|
||||
log_error_errno(errno, "Failed to move mount %s to %s, forcing unmount: %m", i, new_mount);
|
||||
|
||||
if (umount2(i, MNT_FORCE) < 0)
|
||||
log_warning_errno(errno, "Failed to unmount %s: %m", i);
|
||||
|
||||
} else if (mountflags & MS_BIND)
|
||||
log_error_errno(errno, "Failed to bind mount %s to %s: %m", i, new_mount);
|
||||
}
|
||||
if (mount(i, chased, NULL, mount_flags, NULL) < 0)
|
||||
return log_error_errno(r, "Failed to mount %s to %s: %m", i, chased);
|
||||
}
|
||||
|
||||
/* Do not fail, if base_filesystem_create() fails. Not all
|
||||
* switch roots are like base_filesystem_create() wants them
|
||||
* to look like. They might even boot, if they are RO and
|
||||
* don't have the FS layout. Just ignore the error and
|
||||
* switch_root() nevertheless. */
|
||||
/* Do not fail if base_filesystem_create() fails. Not all switch roots are like base_filesystem_create() wants
|
||||
* them to look like. They might even boot, if they are RO and don't have the FS layout. Just ignore the error
|
||||
* and switch_root() nevertheless. */
|
||||
(void) base_filesystem_create(new_root, UID_INVALID, GID_INVALID);
|
||||
|
||||
if (chdir(new_root) < 0)
|
||||
return log_error_errno(errno, "Failed to change directory to %s: %m", new_root);
|
||||
|
||||
if (old_root_remove) {
|
||||
old_root_fd = open("/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
|
||||
if (old_root_fd < 0)
|
||||
log_warning_errno(errno, "Failed to open root directory: %m");
|
||||
}
|
||||
|
||||
/* We first try a pivot_root() so that we can umount the old
|
||||
* root dir. In many cases (i.e. where rootfs is /), that's
|
||||
* not possible however, and hence we simply overmount root */
|
||||
if (pivot_root(new_root, temporary_old_root) >= 0) {
|
||||
/* We first try a pivot_root() so that we can umount the old root dir. In many cases (i.e. where rootfs is /),
|
||||
* that's not possible however, and hence we simply overmount root */
|
||||
if (pivot_root(new_root, resolved_old_root_after) >= 0) {
|
||||
|
||||
/* Immediately get rid of the old root, if detach_oldroot is set.
|
||||
* Since we are running off it we need to do this lazily. */
|
||||
if (detach_oldroot && umount2(oldroot, MNT_DETACH) < 0)
|
||||
log_error_errno(errno, "Failed to lazily umount old root dir %s, %s: %m",
|
||||
oldroot,
|
||||
errno == ENOENT ? "ignoring" : "leaving it around");
|
||||
if (unmount_old_root) {
|
||||
r = umount_recursive(old_root_after, MNT_DETACH);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to unmount old root directory tree, ignoring: %m");
|
||||
}
|
||||
|
||||
} else if (mount(new_root, "/", NULL, MS_MOVE, NULL) < 0)
|
||||
return log_error_errno(errno, "Failed to mount moving %s to /: %m", new_root);
|
||||
return log_error_errno(errno, "Failed to move %s to /: %m", new_root);
|
||||
|
||||
if (chroot(".") < 0)
|
||||
return log_error_errno(errno, "Failed to change root: %m");
|
||||
|
68
src/shared/volatile-util.c
Normal file
68
src/shared/volatile-util.c
Normal file
@ -0,0 +1,68 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2015 Lennart Poettering
|
||||
|
||||
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.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "string-util.h"
|
||||
#include "volatile-util.h"
|
||||
|
||||
VolatileMode volatile_mode_from_string(const char *s) {
|
||||
int b;
|
||||
|
||||
if (isempty(s))
|
||||
return _VOLATILE_MODE_INVALID;
|
||||
|
||||
b = parse_boolean(s);
|
||||
if (b > 0)
|
||||
return VOLATILE_YES;
|
||||
if (b == 0)
|
||||
return VOLATILE_NO;
|
||||
|
||||
if (streq(s, "state"))
|
||||
return VOLATILE_STATE;
|
||||
|
||||
return _VOLATILE_MODE_INVALID;
|
||||
}
|
||||
|
||||
int query_volatile_mode(VolatileMode *ret) {
|
||||
_cleanup_free_ char *mode = NULL;
|
||||
VolatileMode m = VOLATILE_NO;
|
||||
int r;
|
||||
|
||||
r = proc_cmdline_get_key("systemd.volatile", PROC_CMDLINE_VALUE_OPTIONAL, &mode);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
goto finish;
|
||||
|
||||
if (mode) {
|
||||
m = volatile_mode_from_string(mode);
|
||||
if (m < 0)
|
||||
return -EINVAL;
|
||||
} else
|
||||
m = VOLATILE_YES;
|
||||
|
||||
r = 1;
|
||||
|
||||
finish:
|
||||
*ret = m;
|
||||
return r;
|
||||
}
|
32
src/shared/volatile-util.h
Normal file
32
src/shared/volatile-util.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Lennart Poettering
|
||||
|
||||
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.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
typedef enum VolatileMode {
|
||||
VOLATILE_NO,
|
||||
VOLATILE_YES,
|
||||
VOLATILE_STATE,
|
||||
_VOLATILE_MODE_MAX,
|
||||
_VOLATILE_MODE_INVALID = -1
|
||||
} VolatileMode;
|
||||
|
||||
VolatileMode volatile_mode_from_string(const char *s);
|
||||
|
||||
int query_volatile_mode(VolatileMode *ret);
|
@ -43,7 +43,7 @@ int main(int argc, char *argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
r = dissect_image(d->fd, NULL, 0, &m);
|
||||
r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to dissect image: %m");
|
||||
return EXIT_FAILURE;
|
||||
|
@ -33,6 +33,7 @@
|
||||
#ifdef HAVE_SECCOMP
|
||||
#include "seccomp-util.h"
|
||||
#endif
|
||||
#include "stat-util.h"
|
||||
#include "test-helper.h"
|
||||
#include "unit.h"
|
||||
#include "util.h"
|
||||
@ -188,15 +189,27 @@ static void test_exec_protectkernelmodules(Manager *m) {
|
||||
}
|
||||
|
||||
static void test_exec_readonlypaths(Manager *m) {
|
||||
|
||||
if (path_is_read_only_fs("/var") > 0)
|
||||
return;
|
||||
|
||||
test(m, "exec-readonlypaths.service", 0, CLD_EXITED);
|
||||
test(m, "exec-readonlypaths-mount-propagation.service", 0, CLD_EXITED);
|
||||
}
|
||||
|
||||
static void test_exec_readwritepaths(Manager *m) {
|
||||
|
||||
if (path_is_read_only_fs("/") > 0)
|
||||
return;
|
||||
|
||||
test(m, "exec-readwritepaths-mount-propagation.service", 0, CLD_EXITED);
|
||||
}
|
||||
|
||||
static void test_exec_inaccessiblepaths(Manager *m) {
|
||||
|
||||
if (path_is_read_only_fs("/") > 0)
|
||||
return;
|
||||
|
||||
test(m, "exec-inaccessiblepaths-mount-propagation.service", 0, CLD_EXITED);
|
||||
}
|
||||
|
||||
|
@ -87,27 +87,19 @@ static void test_undecchar(void) {
|
||||
}
|
||||
|
||||
static void test_unhexmem(void) {
|
||||
const char *hex = "efa214921";
|
||||
const char *hex = "efa2149213";
|
||||
const char *hex_invalid = "efa214921o";
|
||||
_cleanup_free_ char *hex2 = NULL;
|
||||
_cleanup_free_ void *mem = NULL;
|
||||
size_t len;
|
||||
|
||||
assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0);
|
||||
assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL);
|
||||
assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL);
|
||||
assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL);
|
||||
assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == -EINVAL);
|
||||
assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0);
|
||||
|
||||
assert_se((hex2 = hexmem(mem, len)));
|
||||
|
||||
free(mem);
|
||||
|
||||
assert_se(memcmp(hex, hex2, strlen(hex)) == 0);
|
||||
|
||||
free(hex2);
|
||||
|
||||
assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0);
|
||||
assert_se((hex2 = hexmem(mem, len)));
|
||||
assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0);
|
||||
assert_se(streq(hex, hex2));
|
||||
}
|
||||
|
||||
/* https://tools.ietf.org/html/rfc4648#section-10 */
|
||||
|
@ -35,8 +35,8 @@ static int parse_item(const char *key, const char *value, void *data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_parse_proc_cmdline(void) {
|
||||
assert_se(parse_proc_cmdline(parse_item, &obj, true) >= 0);
|
||||
static void test_proc_cmdline_parse(void) {
|
||||
assert_se(proc_cmdline_parse(parse_item, &obj, true) >= 0);
|
||||
}
|
||||
|
||||
static void test_runlevel_to_target(void) {
|
||||
@ -55,11 +55,101 @@ static void test_runlevel_to_target(void) {
|
||||
assert_se(streq_ptr(runlevel_to_target("rd.rescue"), SPECIAL_RESCUE_TARGET));
|
||||
}
|
||||
|
||||
static void test_proc_cmdline_get_key(void) {
|
||||
_cleanup_free_ char *value = NULL;
|
||||
|
||||
putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm");
|
||||
|
||||
assert_se(proc_cmdline_get_key("", 0, &value) == -EINVAL);
|
||||
assert_se(proc_cmdline_get_key("abc", 0, NULL) == 0);
|
||||
assert_se(proc_cmdline_get_key("abc", 0, &value) == 0 && value == NULL);
|
||||
assert_se(proc_cmdline_get_key("abc", PROC_CMDLINE_VALUE_OPTIONAL, &value) == 0 && value == NULL);
|
||||
|
||||
assert_se(proc_cmdline_get_key("foo_bar", 0, &value) > 0 && streq_ptr(value, "quux"));
|
||||
value = mfree(value);
|
||||
assert_se(proc_cmdline_get_key("foo_bar", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && streq_ptr(value, "quux"));
|
||||
value = mfree(value);
|
||||
assert_se(proc_cmdline_get_key("foo-bar", 0, &value) > 0 && streq_ptr(value, "quux"));
|
||||
value = mfree(value);
|
||||
assert_se(proc_cmdline_get_key("foo-bar", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && streq_ptr(value, "quux"));
|
||||
value = mfree(value);
|
||||
assert_se(proc_cmdline_get_key("foo-bar", 0, NULL) == 0);
|
||||
assert_se(proc_cmdline_get_key("foo-bar", PROC_CMDLINE_VALUE_OPTIONAL, NULL) == -EINVAL);
|
||||
|
||||
assert_se(proc_cmdline_get_key("wuff-piep", 0, &value) > 0 && streq_ptr(value, "tuet"));
|
||||
value = mfree(value);
|
||||
assert_se(proc_cmdline_get_key("wuff-piep", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && streq_ptr(value, "tuet"));
|
||||
value = mfree(value);
|
||||
assert_se(proc_cmdline_get_key("wuff_piep", 0, &value) > 0 && streq_ptr(value, "tuet"));
|
||||
value = mfree(value);
|
||||
assert_se(proc_cmdline_get_key("wuff_piep", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && streq_ptr(value, "tuet"));
|
||||
value = mfree(value);
|
||||
assert_se(proc_cmdline_get_key("wuff_piep", 0, NULL) == 0);
|
||||
assert_se(proc_cmdline_get_key("wuff_piep", PROC_CMDLINE_VALUE_OPTIONAL, NULL) == -EINVAL);
|
||||
|
||||
assert_se(proc_cmdline_get_key("zumm", 0, &value) == 0 && value == NULL);
|
||||
assert_se(proc_cmdline_get_key("zumm", PROC_CMDLINE_VALUE_OPTIONAL, &value) > 0 && value == NULL);
|
||||
assert_se(proc_cmdline_get_key("zumm", 0, NULL) > 0);
|
||||
}
|
||||
|
||||
static void test_proc_cmdline_get_bool(void) {
|
||||
bool value = false;
|
||||
|
||||
putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar bar-waldo=1 x_y-z=0 quux=miep");
|
||||
|
||||
assert_se(proc_cmdline_get_bool("", &value) == -EINVAL);
|
||||
assert_se(proc_cmdline_get_bool("abc", &value) == 0 && value == false);
|
||||
assert_se(proc_cmdline_get_bool("foo_bar", &value) > 0 && value == true);
|
||||
assert_se(proc_cmdline_get_bool("foo-bar", &value) > 0 && value == true);
|
||||
assert_se(proc_cmdline_get_bool("bar-waldo", &value) > 0 && value == true);
|
||||
assert_se(proc_cmdline_get_bool("bar_waldo", &value) > 0 && value == true);
|
||||
assert_se(proc_cmdline_get_bool("x_y-z", &value) > 0 && value == false);
|
||||
assert_se(proc_cmdline_get_bool("x-y-z", &value) > 0 && value == false);
|
||||
assert_se(proc_cmdline_get_bool("x-y_z", &value) > 0 && value == false);
|
||||
assert_se(proc_cmdline_get_bool("x_y_z", &value) > 0 && value == false);
|
||||
assert_se(proc_cmdline_get_bool("quux", &value) == -EINVAL && value == false);
|
||||
}
|
||||
|
||||
static void test_proc_cmdline_key_streq(void) {
|
||||
|
||||
assert_se(proc_cmdline_key_streq("", ""));
|
||||
assert_se(proc_cmdline_key_streq("a", "a"));
|
||||
assert_se(!proc_cmdline_key_streq("", "a"));
|
||||
assert_se(!proc_cmdline_key_streq("a", ""));
|
||||
assert_se(proc_cmdline_key_streq("a", "a"));
|
||||
assert_se(!proc_cmdline_key_streq("a", "b"));
|
||||
assert_se(proc_cmdline_key_streq("x-y-z", "x-y-z"));
|
||||
assert_se(proc_cmdline_key_streq("x-y-z", "x_y_z"));
|
||||
assert_se(proc_cmdline_key_streq("x-y-z", "x-y_z"));
|
||||
assert_se(proc_cmdline_key_streq("x-y-z", "x_y-z"));
|
||||
assert_se(proc_cmdline_key_streq("x_y-z", "x-y_z"));
|
||||
assert_se(!proc_cmdline_key_streq("x_y-z", "x-z_z"));
|
||||
}
|
||||
|
||||
static void test_proc_cmdline_key_startswith(void) {
|
||||
|
||||
assert_se(proc_cmdline_key_startswith("", ""));
|
||||
assert_se(proc_cmdline_key_startswith("x", ""));
|
||||
assert_se(!proc_cmdline_key_startswith("", "x"));
|
||||
assert_se(proc_cmdline_key_startswith("x", "x"));
|
||||
assert_se(!proc_cmdline_key_startswith("x", "y"));
|
||||
assert_se(!proc_cmdline_key_startswith("foo-bar", "quux"));
|
||||
assert_se(proc_cmdline_key_startswith("foo-bar", "foo"));
|
||||
assert_se(proc_cmdline_key_startswith("foo-bar", "foo-bar"));
|
||||
assert_se(proc_cmdline_key_startswith("foo-bar", "foo_bar"));
|
||||
assert_se(proc_cmdline_key_startswith("foo-bar", "foo_"));
|
||||
assert_se(!proc_cmdline_key_startswith("foo-bar", "foo_xx"));
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
test_parse_proc_cmdline();
|
||||
test_proc_cmdline_parse();
|
||||
test_proc_cmdline_key_streq();
|
||||
test_proc_cmdline_key_startswith();
|
||||
test_proc_cmdline_get_key();
|
||||
test_proc_cmdline_get_bool();
|
||||
test_runlevel_to_target();
|
||||
|
||||
return 0;
|
||||
|
@ -18,12 +18,14 @@
|
||||
***/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/magic.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "macro.h"
|
||||
#include "missing.h"
|
||||
#include "stat-util.h"
|
||||
|
||||
static void test_files_same(void) {
|
||||
@ -60,9 +62,33 @@ static void test_is_symlink(void) {
|
||||
unlink(name_link);
|
||||
}
|
||||
|
||||
static void test_path_is_os_tree(void) {
|
||||
assert_se(path_is_os_tree("/") > 0);
|
||||
assert_se(path_is_os_tree("/etc") == 0);
|
||||
assert_se(path_is_os_tree("/idontexist") == -ENOENT);
|
||||
}
|
||||
|
||||
static void test_path_check_fstype(void) {
|
||||
assert_se(path_check_fstype("/run", TMPFS_MAGIC) > 0);
|
||||
assert_se(path_check_fstype("/run", BTRFS_SUPER_MAGIC) == 0);
|
||||
assert_se(path_check_fstype("/proc", PROC_SUPER_MAGIC) > 0);
|
||||
assert_se(path_check_fstype("/proc", BTRFS_SUPER_MAGIC) == 0);
|
||||
assert_se(path_check_fstype("/proc", BTRFS_SUPER_MAGIC) == 0);
|
||||
assert_se(path_check_fstype("/i-dont-exist", BTRFS_SUPER_MAGIC) == -ENOENT);
|
||||
}
|
||||
|
||||
static void test_path_is_temporary_fs(void) {
|
||||
assert_se(path_is_temporary_fs("/run") > 0);
|
||||
assert_se(path_is_temporary_fs("/proc") == 0);
|
||||
assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_files_same();
|
||||
test_is_symlink();
|
||||
test_path_is_os_tree();
|
||||
test_path_check_fstype();
|
||||
test_path_is_temporary_fs();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -192,14 +192,9 @@ static int load_link(link_config_ctx *ctx, const char *filename) {
|
||||
}
|
||||
|
||||
static bool enable_name_policy(void) {
|
||||
_cleanup_free_ char *value = NULL;
|
||||
int r;
|
||||
bool b;
|
||||
|
||||
r = get_proc_cmdline_key("net.ifnames=", &value);
|
||||
if (r > 0 && streq(value, "0"))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
|
||||
}
|
||||
|
||||
int link_config_load(link_config_ctx *ctx) {
|
||||
|
@ -1357,10 +1357,10 @@ static int listen_fds(int *rctrl, int *rnetlink) {
|
||||
|
||||
/*
|
||||
* read the kernel command line, in case we need to get into debug mode
|
||||
* udev.log-priority=<level> syslog priority
|
||||
* udev.children-max=<number of workers> events are fully serialized if set to 1
|
||||
* udev.exec-delay=<number of seconds> delay execution of every executed program
|
||||
* udev.event-timeout=<number of seconds> seconds to wait before terminating an event
|
||||
* udev.log_priority=<level> syslog priority
|
||||
* udev.children_max=<number of workers> events are fully serialized if set to 1
|
||||
* udev.exec_delay=<number of seconds> delay execution of every executed program
|
||||
* udev.event_timeout=<number of seconds> seconds to wait before terminating an event
|
||||
*/
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
int r = 0;
|
||||
@ -1370,25 +1370,46 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
if (!value)
|
||||
return 0;
|
||||
|
||||
if (streq(key, "udev.log-priority") && value) {
|
||||
if (proc_cmdline_key_streq(key, "udev.log_priority")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = util_log_priority(value);
|
||||
if (r >= 0)
|
||||
log_set_max_level(r);
|
||||
} else if (streq(key, "udev.event-timeout") && value) {
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "udev.event_timeout")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = safe_atou64(value, &arg_event_timeout_usec);
|
||||
if (r >= 0) {
|
||||
arg_event_timeout_usec *= USEC_PER_SEC;
|
||||
arg_event_timeout_warn_usec = (arg_event_timeout_usec / 3) ? : 1;
|
||||
}
|
||||
} else if (streq(key, "udev.children-max") && value)
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "udev.children_max")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = safe_atou(value, &arg_children_max);
|
||||
else if (streq(key, "udev.exec-delay") && value)
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "udev.exec_delay")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = safe_atoi(value, &arg_exec_delay);
|
||||
else if (startswith(key, "udev."))
|
||||
|
||||
} else if (startswith(key, "udev."))
|
||||
log_warning("Unknown udev kernel command line option \"%s\"", key);
|
||||
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse \"%s=%s\", ignoring: %m", key, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1649,7 +1670,7 @@ int main(int argc, char *argv[]) {
|
||||
if (r <= 0)
|
||||
goto exit;
|
||||
|
||||
r = parse_proc_cmdline(parse_proc_cmdline_item, NULL, true);
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
|
1
src/veritysetup/Makefile
Symbolic link
1
src/veritysetup/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../Makefile
|
253
src/veritysetup/veritysetup-generator.c
Normal file
253
src/veritysetup/veritysetup-generator.c
Normal file
@ -0,0 +1,253 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Lennart Poettering
|
||||
|
||||
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.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fstab-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "id128-util.h"
|
||||
#include "mkdir.h"
|
||||
#include "parse-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "string-util.h"
|
||||
#include "unit-name.h"
|
||||
|
||||
static char *arg_dest = NULL;
|
||||
static bool arg_enabled = true;
|
||||
static char *arg_root_hash = NULL;
|
||||
static char *arg_data_what = NULL;
|
||||
static char *arg_hash_what = NULL;
|
||||
|
||||
static int create_device(void) {
|
||||
_cleanup_free_ char *u = NULL, *v = NULL, *d = NULL, *e = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
const char *p, *to;
|
||||
int r;
|
||||
|
||||
/* If all three pieces of information are missing, then verity is turned off */
|
||||
if (!arg_root_hash && !arg_data_what && !arg_hash_what)
|
||||
return 0;
|
||||
|
||||
/* if one of them is missing however, the data is simply incomplete and this is an error */
|
||||
if (!arg_root_hash)
|
||||
log_error("Verity information incomplete, root hash unspecified.");
|
||||
if (!arg_data_what)
|
||||
log_error("Verity information incomplete, root data device unspecified.");
|
||||
if (!arg_hash_what)
|
||||
log_error("Verity information incomplete, root hash device unspecified.");
|
||||
|
||||
if (!arg_root_hash || !arg_data_what || !arg_hash_what)
|
||||
return -EINVAL;
|
||||
|
||||
log_debug("Using root verity data device %s,\n"
|
||||
" hash device %s,\n"
|
||||
" and root hash %s.", arg_data_what, arg_hash_what, arg_root_hash);
|
||||
|
||||
p = strjoina(arg_dest, "/systemd-veritysetup@root.service");
|
||||
|
||||
u = fstab_node_to_udev_node(arg_data_what);
|
||||
if (!u)
|
||||
return log_oom();
|
||||
v = fstab_node_to_udev_node(arg_hash_what);
|
||||
if (!v)
|
||||
return log_oom();
|
||||
|
||||
r = unit_name_from_path(u, ".device", &d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to to generate unit name: %m");
|
||||
r = unit_name_from_path(v, ".device", &e);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to to generate unit name: %m");
|
||||
|
||||
f = fopen(p, "wxe");
|
||||
if (!f)
|
||||
return log_error_errno(errno, "Failed to create unit file %s: %m", p);
|
||||
|
||||
fprintf(f,
|
||||
"# Automatically generated by systemd-veritysetup-generator\n\n"
|
||||
"[Unit]\n"
|
||||
"Description=Integrity Protection Setup for %%I\n"
|
||||
"Documentation=man:systemd-veritysetup-generator(8) man:systemd-veritysetup@.service(8)\n"
|
||||
"SourcePath=/proc/cmdline\n"
|
||||
"DefaultDependencies=no\n"
|
||||
"Conflicts=umount.target\n"
|
||||
"BindsTo=%s %s\n"
|
||||
"IgnoreOnIsolate=true\n"
|
||||
"After=cryptsetup-pre.target %s %s\n"
|
||||
"Before=cryptsetup.target umount.target\n"
|
||||
"\n[Service]\n"
|
||||
"Type=oneshot\n"
|
||||
"RemainAfterExit=yes\n"
|
||||
"ExecStart=" ROOTLIBEXECDIR "/systemd-veritysetup attach root '%s' '%s' '%s'\n"
|
||||
"ExecStop=" ROOTLIBEXECDIR "/systemd-veritysetup detach root\n",
|
||||
d, e,
|
||||
d, e,
|
||||
u, v, arg_root_hash);
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write file %s: %m", p);
|
||||
|
||||
to = strjoina(arg_dest, "/cryptsetup.target.requires/systemd-veritysetup@root.service");
|
||||
|
||||
(void) mkdir_parents(to, 0755);
|
||||
if (symlink("../systemd-veritysetup@root.service", to) < 0)
|
||||
return log_error_errno(errno, "Failed to create symlink %s: %m", to);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
int r;
|
||||
|
||||
if (streq(key, "systemd.verity")) {
|
||||
|
||||
r = value ? parse_boolean(value) : 1;
|
||||
if (r < 0)
|
||||
log_warning("Failed to parse verity= kernel command line switch %s. Ignoring.", value);
|
||||
else
|
||||
arg_enabled = r;
|
||||
|
||||
} else if (streq(key, "roothash")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = free_and_strdup(&arg_root_hash, value);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "systemd.verity_root_data")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = free_and_strdup(&arg_data_what, value);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
} else if (streq(key, "systemd.verity_root_hash")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = free_and_strdup(&arg_hash_what, value);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int determine_devices(void) {
|
||||
_cleanup_free_ void *m = NULL;
|
||||
sd_id128_t root_uuid, verity_uuid;
|
||||
char ids[37];
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
/* Try to automatically derive the root data and hash device paths from the root hash */
|
||||
|
||||
if (!arg_root_hash)
|
||||
return 0;
|
||||
|
||||
if (arg_data_what && arg_hash_what)
|
||||
return 0;
|
||||
|
||||
r = unhexmem(arg_root_hash, strlen(arg_root_hash), &m, &l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse root hash: %s", arg_root_hash);
|
||||
if (l < sizeof(sd_id128_t)) {
|
||||
log_debug("Root hash is shorter than 128 bits (32 characters), ignoring for discovering verity partition.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!arg_data_what) {
|
||||
memcpy(&root_uuid, m, sizeof(root_uuid));
|
||||
|
||||
arg_data_what = strjoin("/dev/disk/by-partuuid/", id128_to_uuid_string(root_uuid, ids));
|
||||
if (!arg_data_what)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (!arg_hash_what) {
|
||||
memcpy(&verity_uuid, (uint8_t*) m + l - sizeof(verity_uuid), sizeof(verity_uuid));
|
||||
|
||||
arg_hash_what = strjoin("/dev/disk/by-partuuid/", id128_to_uuid_string(verity_uuid, ids));
|
||||
if (!arg_hash_what)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r;
|
||||
|
||||
if (argc > 1 && argc != 4) {
|
||||
log_error("This program takes three or no arguments.");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
arg_dest = argv[1];
|
||||
|
||||
log_set_target(LOG_TARGET_SAFE);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
umask(0022);
|
||||
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to parse kernel command line: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* For now we only support the root device on verity. Later on we might want to add support for /etc/veritytab
|
||||
* or similar to define additional mappings */
|
||||
|
||||
if (!arg_enabled) {
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = determine_devices();
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = create_device();
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
free(arg_root_hash);
|
||||
free(arg_data_what);
|
||||
free(arg_hash_what);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
154
src/veritysetup/veritysetup.c
Normal file
154
src/veritysetup/veritysetup.c
Normal file
@ -0,0 +1,154 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Lennart Poettering
|
||||
|
||||
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.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <libcryptsetup.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "string-util.h"
|
||||
#include "alloc-util.h"
|
||||
|
||||
static char *arg_root_hash = NULL;
|
||||
static char *arg_data_what = NULL;
|
||||
static char *arg_hash_what = NULL;
|
||||
|
||||
static int help(void) {
|
||||
printf("%s attach VOLUME DATADEVICE HASHDEVICE ROOTHASH\n"
|
||||
"%s detach VOLUME\n\n"
|
||||
"Attaches or detaches an integrity protected block device.\n",
|
||||
program_invocation_short_name,
|
||||
program_invocation_short_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void log_glue(int level, const char *msg, void *usrptr) {
|
||||
log_debug("%s", msg);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct crypt_device *cd = NULL;
|
||||
int r;
|
||||
|
||||
if (argc <= 1) {
|
||||
r = help();
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (argc < 3) {
|
||||
log_error("This program requires at least two arguments.");
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
log_set_target(LOG_TARGET_AUTO);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
umask(0022);
|
||||
|
||||
if (streq(argv[1], "attach")) {
|
||||
_cleanup_free_ void *m = NULL;
|
||||
crypt_status_info status;
|
||||
size_t l;
|
||||
|
||||
if (argc < 6) {
|
||||
log_error("attach requires at least two arguments.");
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = unhexmem(argv[5], strlen(argv[5]), &m, &l);
|
||||
if (r < 0) {
|
||||
log_error("Failed to parse root hash.");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = crypt_init(&cd, argv[4]);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to open verity device %s: %m", argv[4]);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
crypt_set_log_callback(cd, log_glue, NULL);
|
||||
|
||||
status = crypt_status(cd, argv[2]);
|
||||
if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
|
||||
log_info("Volume %s already active.", argv[2]);
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = crypt_load(cd, CRYPT_VERITY, NULL);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to load verity superblock: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = crypt_set_data_device(cd, argv[3]);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to configure data device: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = crypt_activate_by_volume_key(cd, argv[2], m, l, CRYPT_ACTIVATE_READONLY);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to set up verity device: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
} else if (streq(argv[1], "detach")) {
|
||||
|
||||
r = crypt_init_by_name(&cd, argv[2]);
|
||||
if (r == -ENODEV) {
|
||||
log_info("Volume %s already inactive.", argv[2]);
|
||||
goto finish;
|
||||
} else if (r < 0) {
|
||||
log_error_errno(r, "crypt_init_by_name() failed: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
crypt_set_log_callback(cd, log_glue, NULL);
|
||||
|
||||
r = crypt_deactivate(cd, argv[2]);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to deactivate: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
} else {
|
||||
log_error("Unknown verb %s.", argv[1]);
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
||||
finish:
|
||||
if (cd)
|
||||
crypt_free(cd);
|
||||
|
||||
free(arg_root_hash);
|
||||
free(arg_data_what);
|
||||
free(arg_hash_what);
|
||||
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
1
src/volatile-root/Makefile
Symbolic link
1
src/volatile-root/Makefile
Symbolic link
@ -0,0 +1 @@
|
||||
../Makefile
|
157
src/volatile-root/volatile-root.c
Normal file
157
src/volatile-root/volatile-root.c
Normal file
@ -0,0 +1,157 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2016 Lennart Poettering
|
||||
|
||||
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.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "mkdir.h"
|
||||
#include "mount-util.h"
|
||||
#include "stat-util.h"
|
||||
#include "volatile-util.h"
|
||||
#include "string-util.h"
|
||||
#include "path-util.h"
|
||||
|
||||
static int make_volatile(const char *path) {
|
||||
_cleanup_free_ char *old_usr = NULL;
|
||||
int r;
|
||||
|
||||
r = path_is_mount_point(path, NULL, AT_SYMLINK_FOLLOW);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Couldn't determine whether %s is a mount point: %m", path);
|
||||
if (r == 0) {
|
||||
log_error("%s is not a mount point.", path);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = path_is_temporary_fs(path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Couldn't determine whether %s is a temporary file system: %m", path);
|
||||
if (r > 0) {
|
||||
log_info("%s already is a temporary file system.", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = chase_symlinks("/usr", path, CHASE_PREFIX_ROOT, &old_usr);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "/usr not available in old root: %m");
|
||||
|
||||
r = mkdir_p("/run/systemd/volatile-sysroot", 0700);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Couldn't generate volatile sysroot directory: %m");
|
||||
|
||||
r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/volatile-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
|
||||
if (r < 0)
|
||||
goto finish_rmdir;
|
||||
|
||||
if (mkdir("/run/systemd/volatile-sysroot/usr", 0755) < 0) {
|
||||
r = -errno;
|
||||
goto finish_umount;
|
||||
}
|
||||
|
||||
r = mount_verbose(LOG_ERR, old_usr, "/run/systemd/volatile-sysroot/usr", NULL, MS_BIND|MS_REC, NULL);
|
||||
if (r < 0)
|
||||
goto finish_umount;
|
||||
|
||||
r = bind_remount_recursive("/run/systemd/volatile-sysroot/usr", true, NULL);
|
||||
if (r < 0)
|
||||
goto finish_umount;
|
||||
|
||||
r = umount_recursive(path, 0);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to unmount %s: %m", path);
|
||||
goto finish_umount;
|
||||
}
|
||||
|
||||
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
|
||||
log_warning_errno(errno, "Failed to remount %s MS_SLAVE|MS_REC: %m", path);
|
||||
|
||||
r = mount_verbose(LOG_ERR, "/run/systemd/volatile-sysroot", path, NULL, MS_MOVE, NULL);
|
||||
|
||||
finish_umount:
|
||||
(void) umount_recursive("/run/systemd/volatile-sysroot", 0);
|
||||
|
||||
finish_rmdir:
|
||||
(void) rmdir("/run/systemd/volatile-sysroot");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
VolatileMode m = _VOLATILE_MODE_INVALID;
|
||||
const char *path;
|
||||
int r;
|
||||
|
||||
log_set_target(LOG_TARGET_AUTO);
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
if (argc > 3) {
|
||||
log_error("Too many arguments. Expected directory and mode.");
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = query_volatile_mode(&m);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to determine volatile mode from kernel command line.");
|
||||
goto finish;
|
||||
}
|
||||
if (r == 0 && argc >= 2) {
|
||||
/* The kernel command line always wins. However if nothing was set there, the argument passed here wins instead. */
|
||||
m = volatile_mode_from_string(argv[1]);
|
||||
if (m < 0) {
|
||||
log_error("Couldn't parse volatile mode: %s", argv[1]);
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 3)
|
||||
path = "/sysroot";
|
||||
else {
|
||||
path = argv[2];
|
||||
|
||||
if (isempty(path)) {
|
||||
log_error("Directory name cannot be empty.");
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
if (!path_is_absolute(path)) {
|
||||
log_error("Directory must be specified as absolute path.");
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
if (path_equal(path, "/")) {
|
||||
log_error("Directory cannot be the root directory.");
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (m != VOLATILE_YES) {
|
||||
r = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = make_volatile(path);
|
||||
|
||||
finish:
|
||||
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
1
units/.gitignore
vendored
1
units/.gitignore
vendored
@ -75,5 +75,6 @@
|
||||
/systemd-update-utmp.service
|
||||
/systemd-user-sessions.service
|
||||
/systemd-vconsole-setup.service
|
||||
/systemd-volatile-root.service
|
||||
/tmp.mount
|
||||
/user@.service
|
||||
|
@ -15,6 +15,5 @@ AllowIsolate=yes
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
# we have to use "--force" here, otherwise systemd would umount /run
|
||||
ExecStart=@rootbindir@/systemctl --no-block --force switch-root /sysroot
|
||||
ExecStart=@rootbindir@/systemctl --no-block switch-root /sysroot
|
||||
KillMode=none
|
||||
|
21
units/systemd-volatile-root.service.in
Normal file
21
units/systemd-volatile-root.service.in
Normal file
@ -0,0 +1,21 @@
|
||||
# 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=Enforce Volatile Root File Systems
|
||||
Documentation=man:systemd-volatile-root.service(8)
|
||||
DefaultDependencies=no
|
||||
Conflicts=shutdown.target
|
||||
After=sysroot.mount
|
||||
Before=initrd-root-fs.target shutdown.target
|
||||
Conflicts=shutdown.target
|
||||
AssertPathExists=/etc/initrd-release
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=@rootlibexecdir@/systemd-volatile-root yes /sysroot
|
Loading…
Reference in New Issue
Block a user