1
0
mirror of https://github.com/systemd/systemd synced 2025-09-28 16:24:45 +02:00

Compare commits

..

No commits in common. "a631cbfae3fab810db01238867ae93191dbfbeed" and "7b5ed18779992a62ac705952b4dc63b783be93b8" have entirely different histories.

51 changed files with 384 additions and 2215 deletions

7
TODO
View File

@ -45,13 +45,6 @@ Features:
in a graceful way, so that updated /usr trees automatically propagate into
updated boot loaders on reboot.
* sysext: optionally, if the merged trees allow it use bind mounts instead of
overlayfs
* nspawn: add support for sysext extensions, too. i.e. a new --extension=
switch that takes one or more arguments, and applies the extensions already
during startup.
* add "systemd-analyze debug" + AttachDebugger= in unit files: The former
specifies a command to execute; the latter specifies that an already running
"systemd-analyze debug" instance shall be contacted and execution paused

View File

@ -267,15 +267,3 @@ systemd-firstboot and localectl:
* `SYSTEMD_LIST_NON_UTF8_LOCALES=1` if set non-UTF-8 locales are listed among
the installed ones. By default non-UTF-8 locales are suppressed from the
selection, since we are living in the 21st century.
systemd-sysext:
* `SYSTEMD_SYSEXT_HIERARCHIES` if set to a colon-separated list of absolute
paths this variable may be used to override which hierarchies to manage with
`systemd-sysext`. By default only `/usr/` and `/opt/` are managed. With this
environment variable this list may be changed, in order to add or remove
directories from this list. This should only reference "real" file systems
and directories that only contain "real" file systems as submounts — do not
specify API file systems such as `/proc/` or `/sys/` here, or hierarchies
that have them as submounts. In particular, do not specify the root directory
`/` here.

View File

@ -70,14 +70,6 @@
is false. Defaults to yes.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>RouteTable=</varname></term>
<listitem><para>Specifies the route table name. Takes a route name and table number separated with a colon.
(<literal><replaceable>name</replaceable>:<replaceable>integer</replaceable></literal>. The route table number
must be an integer in the range 1..4294967295. This setting can be specified multiple times. If an empty string
is specified, then all options specified earlier are cleared. Defaults to unset.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -317,17 +317,6 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>SYSEXT_LEVEL=</varname></term>
<listitem><para>A lower-case string (mostly numeric, no spaces or other characters outside of 09,
az, ".", "_" and "-") identifying the operating system extensions support level, to indicate which
extension images are supported (See:
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>).
Example: <literal>SYSEXT_LEVEL=2</literal> or
<literal>SYSEXT_LEVEL=15.14</literal>.</para></listitem>
</varlistentry>
</variablelist>
<para>If you are reading this file from C code or a shell script

View File

@ -954,7 +954,6 @@ manpages = [
'systemd-suspend-then-hibernate.service'],
''],
['systemd-sysctl.service', '8', ['systemd-sysctl'], ''],
['systemd-sysext', '8', ['systemd-sysext.service'], ''],
['systemd-system-update-generator', '8', [], ''],
['systemd-system.conf',
'5',

View File

@ -1080,10 +1080,8 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
<para><command>systemd</command> supports an environment block that is passed to processes the manager
spawns. The names of the variables can contain ASCII letters, digits, and the underscore
character. Variable names cannot be empty or start with a digit. In variable values, most characters
are allowed, but the whole sequence must be valid UTF-8. (Note that control characters like newline
(<constant>NL</constant>), tab (<constant>TAB</constant>), or the escape character
(<constant>ESC</constant>), <emphasis>are</emphasis> valid ASCII and thus valid UTF-8). The total
length of the environment block is limited to <constant>_SC_ARG_MAX</constant> value defined by
are allowed, but non-printable characters are currently rejected. The total length of the environment
block is limited to <constant>_SC_ARG_MAX</constant> value defined by
<citerefentry project='man-pages'><refentrytitle>sysconf</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
</para>

View File

@ -1,239 +0,0 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="systemd-sysext"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>systemd-sysext</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>systemd-sysext</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>systemd-sysext</refname>
<refname>systemd-sysext.service</refname>
<refpurpose>Activates System Extension Images</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>systemd-sysext</command>
<arg choice="opt" rep="repeat">OPTIONS</arg>
</cmdsynopsis>
<para><literallayout><filename>systemd-sysext.service</filename></literallayout></para>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><command>systemd-sysext</command> activates/deactivates system extension images. System extension
images may dynamically at runtime — extend the <filename>/usr/</filename> and
<filename>/opt/</filename> directory hierarchies with additional files. This is particularly useful on
immutable system images where a <filename>/usr/</filename> and/or <filename>/opt/</filename> hierarchy
residing on a read-only file system shall be extended temporarily at runtime without making any
persistent modifications.</para>
<para>System extension images should contain files and directories similar in fashion to regular
operating system tree. When one or more system extension images are activated, their
<filename>/usr/</filename> and <filename>/opt/</filename> hierarchies are combined via
<literal>overlayfs</literal> with the same hierarchies of the host OS, and the host
<filename>/usr/</filename> and <filename>/opt</filename> overmounted with it ("merging"). When they are
deactivated, the mount point is disassembled — again revealing the unmodified original host version of
the hierarchy ("unmerging"). Merging thus makes the extension's resources suddenly appear below the
<filename>/usr/</filename> and <filename>/opt/</filename> hierarchies as if they were included in the
base OS image itself. Unmerging makes them disappear again, leaving in place only the files that were
shipped with the base OS image itself.</para>
<para>Files and directories contained in the extension images outside of the <filename>/usr/</filename>
and <filename>/opt/</filename> hierarchies are <emphasis>not</emphasis> merged, and hence have no effect
when included in a system extension image. In particular, files in the <filename>/etc/</filename> and
<filename>/var/</filename> included in a system extension image will <emphasis>not</emphasis> appear in
the respective hierarchies after activation.</para>
<para>System extension images are strictly read-only, and the host <filename>/usr/</filename> and
<filename>/opt/</filename> hierarchies become read-only too while they are activated.</para>
<para>System extensions are supposed to be purely additive, i.e. they are supposed to include only files
that do not exist in the underlying basic OS image. However, the underlying mechanism (overlayfs) also
allows removing files, but it is recommended not to make use of this.</para>
<para>System extension images may be provided in the following formats:</para>
<orderedlist>
<listitem><para>Plain directories or btrfs subvolumes containing the OS tree</para></listitem>
<listitem><para>Disk images with a GPT disk label, following the <ulink
url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partition Specification</ulink></para></listitem>
<listitem><para>Disk images lacking a partition table, with a naked Linux file system (e.g. squashfs or ext4)</para></listitem>
</orderedlist>
<para>These image formats are the same ones that
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
supports via it's <option>--directory=</option>/<option>--image=</option> switches and those that the
service manager supports via <option>RootDirectory=</option>/<option>RootImage=</option>. Similar to
them they may optionally carry Verity authentication information.</para>
<para>System extensions are automatically looked for in the directories
<filename>/etc/extensions/</filename>, <filename>/run/extensions/</filename>,
<filename>/var/lib/extensions/</filename>, <filename>/usr/lib/extensions/</filename> and
<filename>/usr/local/lib/extensions/</filename>. The first two listed directories are not suitable for
carrying large binary images, however are still useful for carrying symlinks to them. The primary place
for installing system extensions is <filename>/var/lib/extensions/</filename>. Any directories found in
these search directories are considered directory based extension images, any files with the
<filename>.raw</filename> suffix are considered disk image based extension images.</para>
<para>During boot OS extension images are activated automatically, if the
<filename>systemd-sysext.service</filename> is enabled. Note that this service runs only after the
underlying file systems where system extensions are searched are mounted. This means they are not
suitable for shipping resources that are processed by subsystems running in earliest boot. Specifically,
OS extension images are not suitable for shipping system services or
<citerefentry><refentrytitle>systemd-sysusers</refentrytitle><manvolnum>8</manvolnum></citerefentry>
definitions. See <ulink url="https://systemd.io/PORTABLE_SERVICES">Portable Services</ulink> for a simple
mechanism for shipping system services in disk images, in a similar fashion to OS extensions. Note the
different isolation on these two mechanisms: while system extension directly extend the underlying OS
image with additional files that appear in a way very similar to as if they were shipped in the OS image
itself and thus imply no security isolation, portable services imply service level sandboxing in one way
or another. The <filename>systemd-sysext.service</filename> service is guaranteed to finish start-up
before <filename>basic.target</filename> is reached; i.e. at the time regular services initialize (those
which do not use <varname>DefaultDependencies=no</varname>), the files and directories system extensions
provide are available in <filename>/usr/</filename> and <filename>/opt/</filename> and may be
accessed.</para>
<para>Note that there is no concept of enabling/disabling installed system extension images: all
installed extension images are automatically activated at boot.</para>
<para>A simple mechanism for version compatibility is enforced: a system extension image must carry a
<filename>/usr/lib/extension-release.d/extension-release.<replaceable>$name</replaceable></filename>
file, which must match its image name, that is compared with the host <filename>os-release</filename>
file: the contained <varname>ID=</varname> fields have to match, as well as the
<varname>SYSEXT_LEVEL=</varname> field (if defined). If the latter is not defined, the
<varname>VERSION_ID=</varname> field has to match instead. System extensions should not ship a
<filename>/usr/lib/os-release</filename> file (as that would be merged into the host
<filename>/usr/</filename> tree, overriding the host OS version data, which is not desirable). The
<filename>extension-release</filename> file follows the same format and semantics, and carries the same
content, as the <filename>os-release</filename> file of the OS, but it describes the resources carried
in the extension image.</para>
</refsect1>
<refsect1>
<title>Uses</title>
<para>The primary use case for system images are immutable environments where debugging and development
tools shall optionally be made available, but not included in the immutable base OS image itself
(e.g. <filename>strace</filename> and <filename>gdb</filename> shall be an optionally installable
addition in order to make debugging/development easier). System extension images should not be
misunderstood as a generic software packaging framework, as no dependency scheme is available: system
extensions should carry all files they need themselves, except for those already shipped in the
underlying host system image. Typically, system extension images are built at the same time as the base
OS image — within the same build system.</para>
<para>Another use case for the system extension concept is temporarily overriding OS supplied resources
with newer ones, for example to install a locally compiled development version of some low-level
component over the immutable OS image without doing a full OS rebuild or modifying the nominally
immutable image. (e.g. "install" a locally built package with <command>DESTDIR=/var/lib/extensions/mytest
make install &amp;&amp; systemd-sysext --refresh</command>, making it available in
<filename>/usr/</filename> as if it was installed in the OS image itself.) This case works regardless if
the underlying host <filename>/usr/</filename> is managed as immutable disk image or is a traditional
package manager controlled (i.e. writable) tree.</para>
</refsect1>
<refsect1>
<title>Commands</title>
<para>The following command switches are understood:</para>
<variablelist>
<varlistentry>
<term><option>--merge</option></term>
<term><option>-m</option></term>
<listitem><para>Merges all currently installed system extension images into
<filename>/usr/</filename> and <filename>/opt/</filename>, by overmounting these hierarchies with an
<literal>overlayfs</literal> file system combining the underlying hierarchies with those included in
the extension images. This command will fail if the hierarchies are already merged.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--unmerge</option></term>
<term><option>-u</option></term>
<listitem><para>Unmerges all currently installed system extension images from
<filename>/usr/</filename> and <filename>/opt/</filename>, by unmounting the
<literal>overlayfs</literal> file systems created by <option>--merge</option>
prior.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--refresh</option></term>
<term><option>-R</option></term>
<listitem><para>A combination of <option>--unmerge</option> and <option>--merge</option>: if already
mounted the existing <literal>overlayfs</literal> instance is unmounted temporarily, and then
replaced by a new version. This command is useful after installing/removing system extension images,
in order to update the <literal>overlayfs</literal> file system accordingly. If no system extensions
are installed when this command is executed, the equivalent of <option>--unmerge</option> is
executed, without establishing any new <literal>overlayfs</literal> instance. Note that currently
there's a brief moment where neither the old nor the new <literal>overlayfs</literal> file system is
mounted. This implies that all resources supplied by a system extension will briefly disappear — even
if it exists continuously during the refresh operation.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--list</option></term>
<term><option>-l</option></term>
<listitem><para>A brief list of installed extension images is shown.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
<para>When invoked without any command switches, the current merge status is shown, separately for both
<filename>/usr/</filename> and <filename>/opt/</filename>.</para>
</refsect1>
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term><option>--root=</option></term>
<listitem><para>Operate relative to the specified root directory, i.e. establish the
<literal>overlayfs</literal> mount not on the top-level host <filename>/usr/</filename> and
<filename>/opt/</filename> hierarchies, but below some specified root directory.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--json=</option></term>
<listitem><para>Generate JSON output, instead of human readable tabular output. Takes one of
<literal>short</literal>, <literal>pretty</literal> or <literal>off</literal> in order to control the
output style, or explicitly disabling JSON output.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="no-pager" />
</variablelist>
</refsect1>
<refsect1>
<title>Exit status</title>
<para>On success, 0 is returned.</para>
</refsect1>
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -1200,9 +1200,8 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
<varlistentry>
<term><varname>Table=</varname></term>
<listitem>
<para>Specifies the routing table identifier to lookup if the rule selector matches. Takes one of predefined names
<literal>default</literal>, <literal>main</literal>, and <literal>local</literal>, and names defined in <varname>RouteTable=</varname>
in <citerefentry><refentrytitle>networkd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<para>Specifies the routing table identifier to lookup if the rule selector matches. Takes
one of <literal>default</literal>, <literal>main</literal>, and <literal>local</literal>,
or a number between 1 and 4294967295. Defaults to <literal>main</literal>.</para>
</listitem>
</varlistentry>
@ -1410,11 +1409,11 @@ IPv6Token=prefixstable:2002:da8:1::</programlisting></para>
<varlistentry>
<term><varname>Table=</varname></term>
<listitem>
<para>The table identifier for the route. Takes one of predefined names <literal>default</literal>, <literal>main</literal>,
and <literal>local</literal>, and names defined in <varname>RouteTable=</varname> in <citerefentry><refentrytitle>networkd.conf</refentrytitle>
<manvolnum>5</manvolnum></citerefentry>, or a number between 1 and 4294967295. The table can be retrieved using
<command>ip route show table <replaceable>num</replaceable></command>. If unset and <varname>Type=</varname> is <literal>local</literal>,
<literal>broadcast</literal>, <literal>anycast</literal>, or <literal>nat</literal>, then <literal>local</literal> is used.
<para>The table identifier for the route. Takes <literal>default</literal>,
<literal>main</literal>, <literal>local</literal> or a number between 1 and 4294967295.
The table can be retrieved using <command>ip route show table <replaceable>num</replaceable></command>.
If unset and <varname>Type=</varname> is <literal>local</literal>, <literal>broadcast</literal>,
<literal>anycast</literal>, or <literal>nat</literal>, then <literal>local</literal> is used.
In other cases, defaults to <literal>main</literal>.
</para>
</listitem>

View File

@ -1502,7 +1502,6 @@ foreach term : ['analyze',
'nss-myhostname',
'nss-systemd',
'portabled',
'sysext',
'pstore',
'quotacheck',
'randomseed',
@ -1746,7 +1745,6 @@ subdir('src/portable')
subdir('src/pstore')
subdir('src/resolve')
subdir('src/shutdown')
subdir('src/sysext')
subdir('src/systemctl')
subdir('src/timedate')
subdir('src/timesync')
@ -2204,17 +2202,6 @@ if conf.get('ENABLE_PORTABLED') == 1
install_dir : rootbindir)
endif
if conf.get('ENABLE_SYSEXT') == 1
public_programs += executable(
'systemd-sysext',
systemd_sysext_sources,
include_directories : includes,
link_with : [libshared],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootlibexecdir)
endif
if conf.get('ENABLE_USERDB') == 1
executable(
'systemd-userwork',
@ -2403,7 +2390,8 @@ if conf.get('HAVE_LIBCRYPTSETUP') == 1
libopenssl,
libp11kit],
install_rpath : rootlibexecdir,
install : true)
install : true,
install_dir : bindir)
endif
if conf.get('HAVE_SYSV_COMPAT') == 1
@ -3747,7 +3735,6 @@ foreach tuple : [
['logind'],
['machined'],
['portabled'],
['sysext'],
['userdb'],
['homed'],
['importd'],

View File

@ -111,8 +111,6 @@ option('machined', type : 'boolean',
description : 'install the systemd-machined stack')
option('portabled', type : 'boolean',
description : 'install the systemd-portabled stack')
option('sysext', type : 'boolean',
description : 'install the systemd-sysext stack')
option('userdb', type : 'boolean',
description : 'install the systemd-userdbd stack')
option('homed', type : 'combo', choices : ['auto', 'true', 'false'],

View File

@ -57,13 +57,16 @@ bool env_value_is_valid(const char *e) {
if (!utf8_is_valid(e))
return false;
/* Note that variable *values* may contain control characters, in particular NL, TAB, BS, DEL, ESC…
* When printing those variables with show-environment, we'll escape them. Make sure to print
* environment variables carefully! */
/* bash allows tabs and newlines in environment variables, and so
* should we */
if (string_has_cc(e, "\t\n"))
return false;
/* POSIX says the overall size of the environment block cannot be > ARG_MAX, an individual assignment
* hence cannot be either. Discounting the shortest possible variable name of length 1, the equal
* sign and trailing NUL this hence leaves ARG_MAX-3 as longest possible variable value. */
/* POSIX says the overall size of the environment block cannot
* be > ARG_MAX, an individual assignment hence cannot be
* either. Discounting the shortest possible variable name of
* length 1, the equal sign and trailing NUL this hence leaves
* ARG_MAX-3 as longest possible variable value. */
if (strlen(e) > sc_arg_max() - 3)
return false;
@ -83,8 +86,10 @@ bool env_assignment_is_valid(const char *e) {
if (!env_value_is_valid(eq + 1))
return false;
/* POSIX says the overall size of the environment block cannot be > ARG_MAX, hence the individual
* variable assignments cannot be either, but let's leave room for one trailing NUL byte. */
/* POSIX says the overall size of the environment block cannot
* be > ARG_MAX, hence the individual variable assignments
* cannot be either, but let's leave room for one trailing NUL
* byte. */
if (strlen(e) > sc_arg_max() - 1)
return false;

View File

@ -100,25 +100,16 @@ int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chas
int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd);
/* Useful for usage with _cleanup_(), removes a directory and frees the pointer */
static inline char *rmdir_and_free(char *p) {
static inline void rmdir_and_free(char *p) {
PROTECT_ERRNO;
if (!p)
return NULL;
(void) rmdir(p);
free(p);
return NULL;
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rmdir_and_free);
static inline char* unlink_and_free(char *p) {
if (!p)
return NULL;
static inline void unlink_and_free(char *p) {
(void) unlink_noerrno(p);
free(p);
return NULL;
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free);

View File

@ -18,27 +18,17 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
int rm_rf(const char *path, RemoveFlags flags);
/* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */
static inline char *rm_rf_physical_and_free(char *p) {
static inline void rm_rf_physical_and_free(char *p) {
PROTECT_ERRNO;
if (!p)
return NULL;
(void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
free(p);
return NULL;
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_physical_and_free);
/* Similar as above, but also has magic btrfs subvolume powers */
static inline char *rm_rf_subvolume_and_free(char *p) {
static inline void rm_rf_subvolume_and_free(char *p) {
PROTECT_ERRNO;
if (!p)
return NULL;
(void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
free(p);
return NULL;
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_subvolume_and_free);

View File

@ -3183,9 +3183,7 @@ static int apply_mount_namespace(
if (context->mount_flags == MS_SHARED)
log_unit_debug(u, "shared mount propagation hidden by other fs namespacing unit settings: ignoring");
if (exec_context_has_credentials(context) &&
params->prefix[EXEC_DIRECTORY_RUNTIME] &&
FLAGS_SET(params->flags, EXEC_WRITE_CREDENTIALS)) {
if (exec_context_has_credentials(context) && params->prefix[EXEC_DIRECTORY_RUNTIME]) {
creds_path = path_join(params->prefix[EXEC_DIRECTORY_RUNTIME], "credentials", u->id);
if (!creds_path) {
r = -ENOMEM;

View File

@ -142,20 +142,6 @@ int identity_add_token_pin(JsonVariant **v, const char *pin) {
return 1;
}
static int acquire_pkcs11_certificate(
const char *uri,
const char *askpw_friendly_name,
const char *askpw_icon_name,
X509 **ret_cert,
char **ret_pin_used) {
#if HAVE_P11KIT
return pkcs11_acquire_certificate(uri, askpw_friendly_name, askpw_icon_name, ret_cert, ret_pin_used);
#else
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"PKCS#11 tokens not supported on this build.");
#endif
}
int identity_add_pkcs11_key_data(JsonVariant **v, const char *uri) {
_cleanup_(erase_and_freep) void *decrypted_key = NULL, *encrypted_key = NULL;
_cleanup_(erase_and_freep) char *pin = NULL;
@ -166,7 +152,7 @@ int identity_add_pkcs11_key_data(JsonVariant **v, const char *uri) {
assert(v);
r = acquire_pkcs11_certificate(uri, "home directory operation", "user-home", &cert, &pin);
r = pkcs11_acquire_certificate(uri, "home directory operation", "user-home", &cert, &pin);
if (r < 0)
return r;

View File

@ -231,8 +231,7 @@ int curl_glue_make(CURL **ret, const char *url, void *userdata) {
if (!c)
return -ENOMEM;
if (DEBUG_LOGGING)
(void) curl_easy_setopt(c, CURLOPT_VERBOSE, 1L);
/* curl_easy_setopt(c, CURLOPT_VERBOSE, 1L); */
if (curl_easy_setopt(c, CURLOPT_URL, url) != CURLE_OK)
return -EIO;

View File

@ -66,7 +66,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
int r, fd;
if (hostname_is_valid(argv[1], 0)) {
r = image_find(IMAGE_MACHINE, argv[1], NULL, &image);
r = image_find(IMAGE_MACHINE, argv[1], &image);
if (r == -ENOENT)
return log_error_errno(r, "Machine image %s not found.", argv[1]);
if (r < 0)
@ -142,7 +142,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
int r, fd;
if (hostname_is_valid(argv[1], 0)) {
r = image_find(IMAGE_MACHINE, argv[1], NULL, &image);
r = image_find(IMAGE_MACHINE, argv[1], &image);
if (r == -ENOENT)
return log_error_errno(r, "Machine image %s not found.", argv[1]);
if (r < 0)

View File

@ -132,7 +132,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
local);
if (!arg_force) {
r = image_find(IMAGE_MACHINE, local, NULL, NULL);
r = image_find(IMAGE_MACHINE, local, NULL);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);

View File

@ -70,7 +70,7 @@ static int import_tar(int argc, char *argv[], void *userdata) {
local);
if (!arg_force) {
r = image_find(IMAGE_MACHINE, local, NULL, NULL);
r = image_find(IMAGE_MACHINE, local, NULL);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
@ -165,7 +165,7 @@ static int import_raw(int argc, char *argv[], void *userdata) {
local);
if (!arg_force) {
r = image_find(IMAGE_MACHINE, local, NULL, NULL);
r = image_find(IMAGE_MACHINE, local, NULL);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);

View File

@ -110,7 +110,7 @@ int pull_find_old_etags(
return 0;
}
int pull_make_local_copy(const char *final, const char *image_root, const char *local, PullFlags flags) {
int pull_make_local_copy(const char *final, const char *image_root, const char *local, bool force_local) {
const char *p;
int r;
@ -122,7 +122,7 @@ int pull_make_local_copy(const char *final, const char *image_root, const char *
p = prefix_roota(image_root, local);
if (FLAGS_SET(flags, PULL_FORCE))
if (force_local)
(void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
r = btrfs_subvol_snapshot(final, p,
@ -255,6 +255,7 @@ int pull_make_verification_jobs(
_cleanup_(pull_job_unrefp) PullJob *checksum_job = NULL, *signature_job = NULL;
int r;
const char *chksums = NULL;
assert(ret_checksum_job);
assert(ret_signature_job);
@ -265,7 +266,6 @@ int pull_make_verification_jobs(
if (verify != IMPORT_VERIFY_NO) {
_cleanup_free_ char *checksum_url = NULL, *fn = NULL;
const char *chksums = NULL;
/* Queue jobs for the checksum file for the image. */
r = import_url_last_component(url, &fn);
@ -302,8 +302,10 @@ int pull_make_verification_jobs(
signature_job->uncompressed_max = signature_job->compressed_max = 1ULL * 1024ULL * 1024ULL;
}
*ret_checksum_job = TAKE_PTR(checksum_job);
*ret_signature_job = TAKE_PTR(signature_job);
*ret_checksum_job = checksum_job;
*ret_signature_job = signature_job;
checksum_job = signature_job = NULL;
return 0;
}
@ -363,35 +365,70 @@ static int verify_one(PullJob *checksum_job, PullJob *job) {
return 1;
}
static int verify_gpg(
const void *payload, size_t payload_size,
const void *signature, size_t signature_size) {
int pull_verify(PullJob *main_job,
PullJob *roothash_job,
PullJob *settings_job,
PullJob *checksum_job,
PullJob *signature_job) {
_cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 };
_cleanup_close_ int sig_file = -1;
char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
_cleanup_(sigkill_waitp) pid_t pid = 0;
bool gpg_home_created = false;
int r;
assert(payload || payload_size == 0);
assert(signature || signature_size == 0);
assert(main_job);
assert(main_job->state == PULL_JOB_DONE);
if (!checksum_job)
return 0;
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)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Checksum is empty, cannot verify.");
r = verify_one(checksum_job, main_job);
if (r < 0)
return r;
r = verify_one(checksum_job, roothash_job);
if (r < 0)
return r;
r = verify_one(checksum_job, settings_job);
if (r < 0)
return r;
if (!signature_job)
return 0;
if (checksum_job->style == VERIFICATION_PER_FILE)
signature_job = checksum_job;
assert(signature_job->state == PULL_JOB_DONE);
if (!signature_job->payload || signature_job->payload_size <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Signature is empty, cannot verify.");
r = pipe2(gpg_pipe, O_CLOEXEC);
if (r < 0)
return log_error_errno(errno, "Failed to create pipe for gpg: %m");
if (signature_size > 0) {
_cleanup_close_ int sig_file = -1;
sig_file = mkostemp(sig_file_path, O_RDWR);
if (sig_file < 0)
return log_error_errno(errno, "Failed to create temporary file: %m");
sig_file = mkostemp(sig_file_path, O_RDWR);
if (sig_file < 0)
return log_error_errno(errno, "Failed to create temporary file: %m");
r = loop_write(sig_file, signature, signature_size, false);
if (r < 0) {
log_error_errno(r, "Failed to write to temporary file: %m");
goto finish;
}
r = loop_write(sig_file, signature_job->payload, signature_job->payload_size, false);
if (r < 0) {
log_error_errno(r, "Failed to write to temporary file: %m");
goto finish;
}
if (!mkdtemp(gpg_home)) {
@ -420,7 +457,7 @@ static int verify_gpg(
NULL, /* dash */
NULL /* trailing NULL */
};
size_t k = ELEMENTSOF(cmd) - 6;
unsigned k = ELEMENTSOF(cmd) - 6;
/* Child */
@ -436,7 +473,8 @@ static int verify_gpg(
cmd[k++] = strjoina("--homedir=", gpg_home);
/* We add the user keyring only to the command line arguments, if it's around since gpg fails
/* We add the user keyring only to the command line
* arguments, if it's around since gpg fails
* otherwise. */
if (access(USER_KEYRING_PATH, F_OK) >= 0)
cmd[k++] = "--keyring=" USER_KEYRING_PATH;
@ -444,7 +482,7 @@ static int verify_gpg(
cmd[k++] = "--keyring=" VENDOR_KEYRING_PATH;
cmd[k++] = "--verify";
if (signature) {
if (checksum_job->style == VERIFICATION_PER_DIRECTORY) {
cmd[k++] = sig_file_path;
cmd[k++] = "-";
cmd[k++] = NULL;
@ -458,7 +496,7 @@ static int verify_gpg(
gpg_pipe[0] = safe_close(gpg_pipe[0]);
r = loop_write(gpg_pipe[1], payload, payload_size, false);
r = loop_write(gpg_pipe[1], checksum_job->payload, checksum_job->payload_size, false);
if (r < 0) {
log_error_errno(r, "Failed to write to pipe: %m");
goto finish;
@ -479,120 +517,10 @@ static int verify_gpg(
}
finish:
if (signature_size > 0)
(void) unlink(sig_file_path);
(void) unlink(sig_file_path);
if (gpg_home_created)
(void) rm_rf(gpg_home, REMOVE_ROOT|REMOVE_PHYSICAL);
return r;
}
int pull_verify(ImportVerify verify,
PullJob *main_job,
PullJob *roothash_job,
PullJob *settings_job,
PullJob *checksum_job,
PullJob *signature_job) {
VerificationStyle style;
int r;
assert(main_job);
assert(main_job->state == PULL_JOB_DONE);
if (verify == IMPORT_VERIFY_NO)
return 0;
assert(main_job->calc_checksum);
assert(main_job->checksum);
assert(checksum_job);
assert(checksum_job->state == PULL_JOB_DONE);
if (!checksum_job->payload || checksum_job->payload_size <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Checksum is empty, cannot verify.");
r = verify_one(checksum_job, main_job);
if (r < 0)
return r;
r = verify_one(checksum_job, roothash_job);
if (r < 0)
return r;
r = verify_one(checksum_job, settings_job);
if (r < 0)
return r;
if (verify == IMPORT_VERIFY_CHECKSUM)
return 0;
r = verification_style_from_url(checksum_job->url, &style);
if (r < 0)
return log_error_errno(r, "Failed to determine verification style from URL '%s': %m", checksum_job->url);
if (style == VERIFICATION_PER_DIRECTORY) {
assert(signature_job);
assert(signature_job->state == PULL_JOB_DONE);
if (!signature_job->payload || signature_job->payload_size <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
"Signature is empty, cannot verify.");
return verify_gpg(checksum_job->payload, checksum_job->payload_size, signature_job->payload, signature_job->payload_size);
} else
return verify_gpg(checksum_job->payload, checksum_job->payload_size, NULL, 0);
}
int verification_style_from_url(const char *url, VerificationStyle *ret) {
_cleanup_free_ char *last = NULL;
int r;
assert(url);
assert(ret);
/* Determines which kind of verification style is appropriate for this url */
r = import_url_last_component(url, &last);
if (r < 0)
return r;
if (streq(last, "SHA256SUMS")) {
*ret = VERIFICATION_PER_DIRECTORY;
return 0;
}
if (endswith(last, ".sha256")) {
*ret = VERIFICATION_PER_FILE;
return 0;
}
return -EINVAL;
}
int pull_job_restart_with_sha256sum(PullJob *j, char **ret) {
VerificationStyle style;
int r;
assert(j);
/* Generic implementation of a PullJobNotFound handler, that restarts the job requesting SHA256SUMS */
r = verification_style_from_url(j->url, &style);
if (r < 0)
return log_error_errno(r, "Failed to determine verification style of URL '%s': %m", j->url);
if (style == VERIFICATION_PER_DIRECTORY) /* Nothing to do anymore */
return 0;
assert(style == VERIFICATION_PER_FILE); /* This must have been .sha256 style URL before */
log_debug("Got 404 for %s, now trying to get SHA256SUMS instead.", j->url);
r = import_url_change_last_component(j->url, "SHA256SUMS", ret);
if (r < 0)
return log_error_errno(r, "Failed to replace SHA256SUMS suffix: %m");
return 1;
}

View File

@ -6,19 +6,7 @@
#include "import-util.h"
#include "pull-job.h"
typedef enum PullFlags {
PULL_FORCE = 1 << 0, /* replace existing image */
PULL_SETTINGS = 1 << 1, /* .nspawn settings file */
PULL_ROOTHASH = 1 << 2, /* only for raw: .roothash file for verity */
PULL_ROOTHASH_SIGNATURE = 1 << 3, /* only for raw: .roothash.p7s file for verity */
PULL_VERITY = 1 << 4, /* only for raw: .verity file for verity */
/* The supported flags for the tar and the raw pulling */
PULL_FLAGS_MASK_TAR = PULL_FORCE|PULL_SETTINGS,
PULL_FLAGS_MASK_RAW = PULL_FORCE|PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY,
} PullFlags;
int pull_make_local_copy(const char *final, const char *root, const char *local, PullFlags flags);
int pull_make_local_copy(const char *final, const char *root, const char *local, bool force_local);
int pull_find_old_etags(const char *url, const char *root, int dt, const char *prefix, const char *suffix, char ***etags);
@ -27,15 +15,4 @@ int pull_make_path(const char *url, const char *etag, const char *image_root, co
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(ImportVerify verify, PullJob *main_job, PullJob *roothash_job, PullJob *settings_job, PullJob *checksum_job, PullJob *signature_job);
typedef enum VerificationStyle {
VERIFICATION_PER_FILE, /* SuSE-style ".sha256" files with inline gpg signature */
VERIFICATION_PER_DIRECTORY, /* Ubuntu-style SHA256SUM files with detached SHA256SUM.gpg signatures */
_VERIFICATION_STYLE_MAX,
_VERIFICATION_STYLE_INVALID = -1,
} VerificationStyle;
int verification_style_from_url(const char *url, VerificationStyle *style);
int pull_job_restart_with_sha256sum(PullJob *job, char **ret);
int pull_verify(PullJob *main_job, PullJob *roothash_job, PullJob *settings_job, PullJob *checksum_job, PullJob *signature_job);

View File

@ -61,41 +61,22 @@ static void pull_job_finish(PullJob *j, int ret) {
j->on_finished(j);
}
static int pull_job_restart(PullJob *j, const char *new_url) {
static int pull_job_restart(PullJob *j) {
int r;
char *chksum_url = NULL;
assert(j);
assert(new_url);
r = free_and_strdup(&j->url, new_url);
r = import_url_change_last_component(j->url, "SHA256SUMS", &chksum_url);
if (r < 0)
return r;
free(j->url);
j->url = chksum_url;
j->state = PULL_JOB_INIT;
j->error = 0;
j->payload = mfree(j->payload);
j->payload_size = 0;
j->payload_allocated = 0;
j->written_compressed = 0;
j->written_uncompressed = 0;
j->content_length = UINT64_MAX;
j->etag = mfree(j->etag);
j->etag_exists = false;
j->mtime = 0;
j->checksum = mfree(j->checksum);
curl_glue_remove_and_free(j->glue, j->curl);
j->curl = NULL;
curl_slist_free_all(j->request_header);
j->request_header = NULL;
import_compress_free(&j->compress);
if (j->checksum_context) {
gcry_md_close(j->checksum_context);
j->checksum_context = NULL;
}
r = pull_job_begin(j);
if (r < 0)
@ -133,31 +114,23 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
r = 0;
goto finish;
} else if (status >= 300) {
if (status == 404 && j->style == VERIFICATION_PER_FILE) {
if (status == 404 && j->on_not_found) {
_cleanup_free_ char *new_url = NULL;
/* This resource wasn't found, but the implementor wants to maybe let us know a new URL, query for it. */
r = j->on_not_found(j, &new_url);
/* retry pull job with SHA256SUMS file */
r = pull_job_restart(j);
if (r < 0)
goto finish;
if (r > 0) { /* A new url to use */
assert(new_url);
code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status);
if (code != CURLE_OK) {
log_error("Failed to retrieve response code: %s", curl_easy_strerror(code));
r = -EIO;
goto finish;
}
r = pull_job_restart(j, new_url);
if (r < 0)
goto finish;
code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status);
if (code != CURLE_OK) {
log_error("Failed to retrieve response code: %s", curl_easy_strerror(code));
r = -EIO;
goto finish;
}
if (status == 0)
return;
if (status == 0) {
j->style = VERIFICATION_PER_DIRECTORY;
return;
}
}
@ -434,11 +407,10 @@ fail:
}
static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb, void *userdata) {
_cleanup_free_ char *length = NULL, *last_modified = NULL, *etag = NULL;
size_t sz = size * nmemb;
PullJob *j = userdata;
CURLcode code;
long status;
size_t sz = size * nmemb;
_cleanup_free_ char *length = NULL, *last_modified = NULL;
char *etag;
int r;
assert(contents);
@ -451,25 +423,14 @@ static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb
assert(j->state == PULL_JOB_ANALYZING);
code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status);
if (code != CURLE_OK) {
log_error("Failed to retrieve response code: %s", curl_easy_strerror(code));
r = -EIO;
goto fail;
}
if (status < 200 || status >= 300)
/* If this is not HTTP 2xx, let's skip these headers, they are probably for
* some redirect or so, and we are not interested in the headers of those. */
return sz;
r = curl_header_strdup(contents, sz, "ETag:", &etag);
if (r < 0) {
log_oom();
goto fail;
}
if (r > 0) {
free_and_replace(j->etag, etag);
free(j->etag);
j->etag = etag;
if (strv_contains(j->old_etags, j->etag)) {
log_info("Image already downloaded. Skipping download.");
@ -595,6 +556,7 @@ int pull_job_new(PullJob **ret, const char *url, CurlGlue *glue, void *userdata)
.start_usec = now(CLOCK_MONOTONIC),
.compressed_max = 64LLU * 1024LLU * 1024LLU * 1024LLU, /* 64GB safety limit */
.uncompressed_max = 64LLU * 1024LLU * 1024LLU * 1024LLU, /* 64GB safety limit */
.style = VERIFICATION_STYLE_UNSET,
.url = TAKE_PTR(u),
};

View File

@ -13,18 +13,23 @@ typedef void (*PullJobFinished)(PullJob *job);
typedef int (*PullJobOpenDisk)(PullJob *job);
typedef int (*PullJobHeader)(PullJob *job, const char *header, size_t sz);
typedef void (*PullJobProgress)(PullJob *job);
typedef int (*PullJobNotFound)(PullJob *job, char **ret_new_url);
typedef enum PullJobState {
PULL_JOB_INIT,
PULL_JOB_ANALYZING, /* Still reading into ->payload, to figure out what we have */
PULL_JOB_RUNNING, /* Writing to destination */
PULL_JOB_RUNNING, /* Writing to destination */
PULL_JOB_DONE,
PULL_JOB_FAILED,
_PULL_JOB_STATE_MAX,
_PULL_JOB_STATE_INVALID = -1,
} PullJobState;
typedef enum VerificationStyle {
VERIFICATION_STYLE_UNSET,
VERIFICATION_PER_FILE, /* SuSE-style ".sha256" files with inline signature */
VERIFICATION_PER_DIRECTORY, /* Ubuntu-style SHA256SUM files with detach SHA256SUM.gpg signatures */
} VerificationStyle;
#define PULL_JOB_IS_COMPLETE(j) (IN_SET((j)->state, PULL_JOB_DONE, PULL_JOB_FAILED))
struct PullJob {
@ -38,7 +43,6 @@ struct PullJob {
PullJobOpenDisk on_open_disk;
PullJobHeader on_header;
PullJobProgress on_progress;
PullJobNotFound on_not_found;
CurlGlue *glue;
CURL *curl;
@ -75,6 +79,8 @@ struct PullJob {
gcry_md_hd_t checksum_context;
char *checksum;
VerificationStyle style;
};
int pull_job_new(PullJob **job, const char *url, CurlGlue *glue, void *userdata);

View File

@ -42,22 +42,21 @@ struct RawPull {
sd_event *event;
CurlGlue *glue;
PullFlags flags;
ImportVerify verify;
char *image_root;
PullJob *raw_job;
PullJob *roothash_job;
PullJob *settings_job;
PullJob *checksum_job;
PullJob *signature_job;
PullJob *settings_job;
PullJob *roothash_job;
PullJob *roothash_signature_job;
PullJob *verity_job;
RawPullFinished on_finished;
void *userdata;
char *local;
bool force_local;
bool settings;
bool roothash;
char *final_path;
char *temp_path;
@ -68,11 +67,7 @@ struct RawPull {
char *roothash_path;
char *roothash_temp_path;
char *roothash_signature_path;
char *roothash_signature_temp_path;
char *verity_path;
char *verity_temp_path;
ImportVerify verify;
};
RawPull* raw_pull_unref(RawPull *i) {
@ -80,30 +75,34 @@ RawPull* raw_pull_unref(RawPull *i) {
return NULL;
pull_job_unref(i->raw_job);
pull_job_unref(i->checksum_job);
pull_job_unref(i->signature_job);
pull_job_unref(i->settings_job);
pull_job_unref(i->roothash_job);
pull_job_unref(i->roothash_signature_job);
pull_job_unref(i->verity_job);
pull_job_unref(i->checksum_job);
pull_job_unref(i->signature_job);
curl_glue_unref(i->glue);
sd_event_unref(i->event);
unlink_and_free(i->temp_path);
unlink_and_free(i->settings_temp_path);
unlink_and_free(i->roothash_temp_path);
unlink_and_free(i->roothash_signature_temp_path);
unlink_and_free(i->verity_temp_path);
if (i->temp_path) {
(void) unlink(i->temp_path);
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->settings_path);
free(i->roothash_path);
free(i->roothash_signature_path);
free(i->verity_path);
free(i->settings_path);
free(i->image_root);
free(i->local);
return mfree(i);
}
@ -170,16 +169,6 @@ static void raw_pull_report_progress(RawPull *i, RawProgress p) {
percent = 0;
if (i->checksum_job) {
percent += i->checksum_job->progress_percent * 5 / 100;
remain -= 5;
}
if (i->signature_job) {
percent += i->signature_job->progress_percent * 5 / 100;
remain -= 5;
}
if (i->settings_job) {
percent += i->settings_job->progress_percent * 5 / 100;
remain -= 5;
@ -190,14 +179,14 @@ static void raw_pull_report_progress(RawPull *i, RawProgress p) {
remain -= 5;
}
if (i->roothash_signature_job) {
percent += i->roothash_signature_job->progress_percent * 5 / 100;
if (i->checksum_job) {
percent += i->checksum_job->progress_percent * 5 / 100;
remain -= 5;
}
if (i->verity_job) {
percent += i->verity_job->progress_percent * 10 / 100;
remain -= 10;
if (i->signature_job) {
percent += i->signature_job->progress_percent * 5 / 100;
remain -= 5;
}
if (i->raw_job)
@ -305,7 +294,7 @@ static int raw_pull_copy_auxiliary_file(
local = strjoina(i->image_root, "/", i->local, suffix);
r = copy_file_atomic(*path, local, 0644, 0, 0, COPY_REFLINK | (FLAGS_SET(i->flags, PULL_FORCE) ? COPY_REPLACE : 0));
r = copy_file_atomic(*path, local, 0644, 0, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
if (r == -EEXIST)
log_warning_errno(r, "File %s already exists, not replacing.", local);
else if (r == -ENOENT)
@ -349,7 +338,7 @@ static int raw_pull_make_local_copy(RawPull *i) {
p = strjoina(i->image_root, "/", i->local, ".raw");
if (FLAGS_SET(i->flags, PULL_FORCE))
if (i->force_local)
(void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
r = tempfn_random(p, NULL, &tp);
@ -384,26 +373,14 @@ static int raw_pull_make_local_copy(RawPull *i) {
log_info("Created new local image '%s'.", i->local);
if (FLAGS_SET(i->flags, PULL_SETTINGS)) {
r = raw_pull_copy_auxiliary_file(i, ".nspawn", &i->settings_path);
if (r < 0)
return r;
}
if (FLAGS_SET(i->flags, PULL_ROOTHASH)) {
if (i->roothash) {
r = raw_pull_copy_auxiliary_file(i, ".roothash", &i->roothash_path);
if (r < 0)
return r;
}
if (FLAGS_SET(i->flags, PULL_ROOTHASH_SIGNATURE)) {
r = raw_pull_copy_auxiliary_file(i, ".roothash.p7s", &i->roothash_signature_path);
if (r < 0)
return r;
}
if (FLAGS_SET(i->flags, PULL_VERITY)) {
r = raw_pull_copy_auxiliary_file(i, ".verity", &i->verity_path);
if (i->settings) {
r = raw_pull_copy_auxiliary_file(i, ".nspawn", &i->settings_path);
if (r < 0)
return r;
}
@ -417,17 +394,13 @@ static bool raw_pull_is_done(RawPull *i) {
if (!PULL_JOB_IS_COMPLETE(i->raw_job))
return false;
if (i->checksum_job && !PULL_JOB_IS_COMPLETE(i->checksum_job))
return false;
if (i->signature_job && !PULL_JOB_IS_COMPLETE(i->signature_job))
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->roothash_job && !PULL_JOB_IS_COMPLETE(i->roothash_job))
if (i->checksum_job && !PULL_JOB_IS_COMPLETE(i->checksum_job))
return false;
if (i->roothash_signature_job && !PULL_JOB_IS_COMPLETE(i->roothash_signature_job))
return false;
if (i->verity_job && !PULL_JOB_IS_COMPLETE(i->verity_job))
if (i->signature_job && !PULL_JOB_IS_COMPLETE(i->signature_job))
return false;
return true;
@ -474,18 +447,12 @@ static void raw_pull_job_on_finished(PullJob *j) {
assert(j->userdata);
i = j->userdata;
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 == i->roothash_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->roothash_signature_job) {
} else if (j == i->settings_job) {
if (j->error != 0)
log_info_errno(j->error, "Root hash signature file could not be retrieved, proceeding without.");
} else if (j == i->verity_job) {
if (j->error != 0)
log_info_errno(j->error, "Verity integrity file could not be retrieved, proceeding without. %s", j->url);
log_info_errno(j->error, "Settings file could not be retrieved, proceeding without.");
} else if (j->error != 0 && j != i->signature_job) {
if (j == i->checksum_job)
log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)");
@ -496,41 +463,27 @@ static void raw_pull_job_on_finished(PullJob *j) {
goto finish;
}
/* This is invoked if either the download completed successfully, or the download was skipped because
* we already have the etag. In this case ->etag_exists is true.
/* This is invoked if either the download completed
* successfully, or the download was skipped because we
* already have the etag. In this case ->etag_exists is
* true.
*
* We only do something when we got all three files */
if (!raw_pull_is_done(i))
return;
if (i->signature_job && i->signature_job->error != 0) {
VerificationStyle style;
if (i->signature_job && i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) {
log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
r = verification_style_from_url(i->checksum_job->url, &style);
if (r < 0) {
log_error_errno(r, "Failed to determine verification style from checksum URL: %m");
goto finish;
}
if (style == VERIFICATION_PER_DIRECTORY) { /* A failed signature file download only matters
* in per-directory verification mode, since only
* then the signature is detached, and thus a file
* of its own. */
log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
r = i->signature_job->error;
goto finish;
}
r = i->signature_job->error;
goto finish;
}
if (i->settings_job)
i->settings_job->disk_fd = safe_close(i->settings_job->disk_fd);
if (i->roothash_job)
i->roothash_job->disk_fd = safe_close(i->roothash_job->disk_fd);
if (i->roothash_signature_job)
i->roothash_signature_job->disk_fd = safe_close(i->roothash_signature_job->disk_fd);
if (i->verity_job)
i->verity_job->disk_fd = safe_close(i->verity_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)
@ -542,7 +495,7 @@ static void raw_pull_job_on_finished(PullJob *j) {
raw_pull_report_progress(i, RAW_VERIFYING);
r = pull_verify(i->verify, i->raw_job, i->roothash_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;
@ -645,18 +598,6 @@ static int raw_pull_job_on_open_disk_raw(PullJob *j) {
return 0;
}
static int raw_pull_job_on_open_disk_settings(PullJob *j) {
RawPull *i;
assert(j);
assert(j->userdata);
i = j->userdata;
assert(i->settings_job == j);
return raw_pull_job_on_open_disk_generic(i, j, "settings", &i->settings_temp_path);
}
static int raw_pull_job_on_open_disk_roothash(PullJob *j) {
RawPull *i;
@ -669,28 +610,16 @@ static int raw_pull_job_on_open_disk_roothash(PullJob *j) {
return raw_pull_job_on_open_disk_generic(i, j, "roothash", &i->roothash_temp_path);
}
static int raw_pull_job_on_open_disk_roothash_signature(PullJob *j) {
static int raw_pull_job_on_open_disk_settings(PullJob *j) {
RawPull *i;
assert(j);
assert(j->userdata);
i = j->userdata;
assert(i->roothash_signature_job == j);
assert(i->settings_job == j);
return raw_pull_job_on_open_disk_generic(i, j, "roothash.p7s", &i->roothash_signature_temp_path);
}
static int raw_pull_job_on_open_disk_verity(PullJob *j) {
RawPull *i;
assert(j);
assert(j->userdata);
i = j->userdata;
assert(i->verity_job == j);
return raw_pull_job_on_open_disk_generic(i, j, "verity", &i->verity_temp_path);
return raw_pull_job_on_open_disk_generic(i, j, "settings", &i->settings_temp_path);
}
static void raw_pull_job_on_progress(PullJob *j) {
@ -708,15 +637,16 @@ int raw_pull_start(
RawPull *i,
const char *url,
const char *local,
PullFlags flags,
ImportVerify verify) {
bool force_local,
ImportVerify verify,
bool settings,
bool roothash) {
int r;
assert(i);
assert(verify < _IMPORT_VERIFY_MAX);
assert(verify >= 0);
assert(!(flags & ~PULL_FLAGS_MASK_RAW));
if (!http_url_is_valid(url))
return -EINVAL;
@ -731,8 +661,10 @@ int raw_pull_start(
if (r < 0)
return r;
i->flags = flags;
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);
@ -748,21 +680,7 @@ int raw_pull_start(
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);
if (r < 0)
return r;
if (FLAGS_SET(flags, PULL_SETTINGS)) {
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;
}
if (FLAGS_SET(flags, PULL_ROOTHASH)) {
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;
@ -772,33 +690,39 @@ int raw_pull_start(
i->roothash_job->calc_checksum = verify != IMPORT_VERIFY_NO;
}
if (FLAGS_SET(flags, PULL_ROOTHASH_SIGNATURE)) {
r = pull_make_auxiliary_job(&i->roothash_signature_job, url, raw_strip_suffixes, ".roothash.p7s", i->glue, raw_pull_job_on_finished, i);
if (settings) {
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->roothash_signature_job->on_open_disk = raw_pull_job_on_open_disk_roothash_signature;
i->roothash_signature_job->on_progress = raw_pull_job_on_progress;
i->roothash_signature_job->calc_checksum = verify != IMPORT_VERIFY_NO;
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;
}
if (FLAGS_SET(flags, PULL_VERITY)) {
r = pull_make_auxiliary_job(&i->verity_job, url, raw_strip_suffixes, ".verity", i->glue, raw_pull_job_on_finished, i);
if (r < 0)
return r;
i->verity_job->on_open_disk = raw_pull_job_on_open_disk_verity;
i->verity_job->on_progress = raw_pull_job_on_progress;
i->verity_job->calc_checksum = verify != IMPORT_VERIFY_NO;
}
r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, raw_pull_job_on_finished, i);
if (r < 0)
return r;
r = pull_job_begin(i->raw_job);
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)
return r;
}
if (i->checksum_job) {
i->checksum_job->on_progress = raw_pull_job_on_progress;
i->checksum_job->on_not_found = pull_job_restart_with_sha256sum;
i->checksum_job->style = VERIFICATION_PER_FILE;
r = pull_job_begin(i->checksum_job);
if (r < 0)
@ -813,29 +737,5 @@ int raw_pull_start(
return r;
}
if (i->settings_job) {
r = pull_job_begin(i->settings_job);
if (r < 0)
return r;
}
if (i->roothash_job) {
r = pull_job_begin(i->roothash_job);
if (r < 0)
return r;
}
if (i->roothash_signature_job) {
r = pull_job_begin(i->roothash_signature_job);
if (r < 0)
return r;
}
if (i->verity_job) {
r = pull_job_begin(i->verity_job);
if (r < 0)
return r;
}
return 0;
}

View File

@ -5,7 +5,6 @@
#include "import-util.h"
#include "macro.h"
#include "pull-common.h"
typedef struct RawPull RawPull;
@ -16,4 +15,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, PullFlags flags, ImportVerify verify);
int raw_pull_start(RawPull *pull, const char *url, const char *local, bool force_local, ImportVerify verify, bool settings, bool roothash);

View File

@ -40,19 +40,19 @@ struct TarPull {
sd_event *event;
CurlGlue *glue;
PullFlags flags;
ImportVerify verify;
char *image_root;
PullJob *tar_job;
PullJob *settings_job;
PullJob *checksum_job;
PullJob *signature_job;
PullJob *settings_job;
TarPullFinished on_finished;
void *userdata;
char *local;
bool force_local;
bool settings;
pid_t tar_pid;
@ -61,6 +61,8 @@ struct TarPull {
char *settings_path;
char *settings_temp_path;
ImportVerify verify;
};
TarPull* tar_pull_unref(TarPull *i) {
@ -73,15 +75,22 @@ TarPull* tar_pull_unref(TarPull *i) {
}
pull_job_unref(i->tar_job);
pull_job_unref(i->settings_job);
pull_job_unref(i->checksum_job);
pull_job_unref(i->signature_job);
pull_job_unref(i->settings_job);
curl_glue_unref(i->glue);
sd_event_unref(i->event);
rm_rf_subvolume_and_free(i->temp_path);
unlink_and_free(i->settings_temp_path);
if (i->temp_path) {
(void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
free(i->temp_path);
}
if (i->settings_temp_path) {
(void) unlink(i->settings_temp_path);
free(i->settings_temp_path);
}
free(i->final_path);
free(i->settings_path);
@ -154,6 +163,11 @@ static void tar_pull_report_progress(TarPull *i, TarProgress p) {
percent = 0;
if (i->settings_job) {
percent += i->settings_job->progress_percent * 5 / 100;
remain -= 5;
}
if (i->checksum_job) {
percent += i->checksum_job->progress_percent * 5 / 100;
remain -= 5;
@ -164,11 +178,6 @@ static void tar_pull_report_progress(TarPull *i, TarProgress p) {
remain -= 5;
}
if (i->settings_job) {
percent += i->settings_job->progress_percent * 5 / 100;
remain -= 5;
}
if (i->tar_job)
percent += i->tar_job->progress_percent * remain / 100;
break;
@ -221,11 +230,11 @@ static int tar_pull_make_local_copy(TarPull *i) {
if (!i->local)
return 0;
r = pull_make_local_copy(i->final_path, i->image_root, i->local, i->flags);
r = pull_make_local_copy(i->final_path, i->image_root, i->local, i->force_local);
if (r < 0)
return r;
if (FLAGS_SET(i->flags, PULL_SETTINGS)) {
if (i->settings) {
const char *local_settings;
assert(i->settings_job);
@ -235,7 +244,7 @@ static int tar_pull_make_local_copy(TarPull *i) {
local_settings = strjoina(i->image_root, "/", i->local, ".nspawn");
r = copy_file_atomic(i->settings_path, local_settings, 0664, 0, 0, COPY_REFLINK | (FLAGS_SET(i->flags, PULL_FORCE) ? COPY_REPLACE : 0));
r = copy_file_atomic(i->settings_path, local_settings, 0664, 0, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
else if (r == -ENOENT)
@ -255,12 +264,12 @@ static bool tar_pull_is_done(TarPull *i) {
if (!PULL_JOB_IS_COMPLETE(i->tar_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))
return false;
if (i->signature_job && !PULL_JOB_IS_COMPLETE(i->signature_job))
return false;
if (i->settings_job && !PULL_JOB_IS_COMPLETE(i->settings_job))
return false;
return true;
}
@ -293,23 +302,11 @@ static void tar_pull_job_on_finished(PullJob *j) {
if (!tar_pull_is_done(i))
return;
if (i->signature_job && i->signature_job->error != 0) {
VerificationStyle style;
if (i->signature_job && i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) {
log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
r = verification_style_from_url(i->checksum_job->url, &style);
if (r < 0) {
log_error_errno(r, "Failed to determine verification style from checksum URL: %m");
goto finish;
}
if (style == VERIFICATION_PER_DIRECTORY) { /* A failed signature file download only matters
* in per-directory verification mode, since only
* then the signature is detached, and thus a file
* of its own. */
log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)");
r = i->signature_job->error;
goto finish;
}
r = i->signature_job->error;
goto finish;
}
i->tar_job->disk_fd = safe_close(i->tar_job->disk_fd);
@ -336,7 +333,7 @@ static void tar_pull_job_on_finished(PullJob *j) {
tar_pull_report_progress(i, TAR_VERIFYING);
r = pull_verify(i->verify, i->tar_job, NULL, 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;
@ -474,15 +471,15 @@ int tar_pull_start(
TarPull *i,
const char *url,
const char *local,
PullFlags flags,
ImportVerify verify) {
bool force_local,
ImportVerify verify,
bool settings) {
int r;
assert(i);
assert(verify < _IMPORT_VERIFY_MAX);
assert(verify >= 0);
assert(!(flags & ~PULL_FLAGS_MASK_TAR));
if (!http_url_is_valid(url))
return -EINVAL;
@ -497,8 +494,9 @@ int tar_pull_start(
if (r < 0)
return r;
i->flags = flags;
i->force_local = force_local;
i->verify = verify;
i->settings = settings;
/* Set up download job for TAR file */
r = pull_job_new(&i->tar_job, url, i->glue, i);
@ -514,13 +512,8 @@ int tar_pull_start(
if (r < 0)
return r;
/* Set up download of checksum/signature files */
r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, tar_pull_job_on_finished, i);
if (r < 0)
return r;
/* Set up download job for the settings file (.nspawn) */
if (FLAGS_SET(flags, PULL_SETTINGS)) {
if (settings) {
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;
@ -530,13 +523,24 @@ int tar_pull_start(
i->settings_job->calc_checksum = verify != IMPORT_VERIFY_NO;
}
/* Set up download of checksum/signature files */
r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, tar_pull_job_on_finished, i);
if (r < 0)
return r;
r = pull_job_begin(i->tar_job);
if (r < 0)
return r;
if (i->settings_job) {
r = pull_job_begin(i->settings_job);
if (r < 0)
return r;
}
if (i->checksum_job) {
i->checksum_job->on_progress = tar_pull_job_on_progress;
i->checksum_job->on_not_found = pull_job_restart_with_sha256sum;
i->checksum_job->style = VERIFICATION_PER_FILE;
r = pull_job_begin(i->checksum_job);
if (r < 0)
@ -551,11 +555,5 @@ int tar_pull_start(
return r;
}
if (i->settings_job) {
r = pull_job_begin(i->settings_job);
if (r < 0)
return r;
}
return 0;
}

View File

@ -5,7 +5,6 @@
#include "import-util.h"
#include "macro.h"
#include "pull-common.h"
typedef struct TarPull TarPull;
@ -16,4 +15,4 @@ TarPull* tar_pull_unref(TarPull *pull);
DEFINE_TRIVIAL_CLEANUP_FUNC(TarPull*, tar_pull_unref);
int tar_pull_start(TarPull *pull, const char *url, const char *local, PullFlags flags, ImportVerify verify);
int tar_pull_start(TarPull *pull, const char *url, const char *local, bool force_local, ImportVerify verify, bool settings);

View File

@ -19,9 +19,11 @@
#include "verbs.h"
#include "web-util.h"
static bool arg_force = false;
static const char *arg_image_root = "/var/lib/machines";
static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
static PullFlags arg_pull_flags = PULL_SETTINGS | PULL_ROOTHASH | PULL_ROOTHASH_SIGNATURE | PULL_VERITY;
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.");
@ -75,8 +77,8 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
"Local image name '%s' is not valid.",
local);
if (!FLAGS_SET(arg_pull_flags, PULL_FORCE)) {
r = image_find(IMAGE_MACHINE, local, NULL, NULL);
if (!arg_force) {
r = image_find(IMAGE_MACHINE, local, NULL);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
@ -103,7 +105,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to allocate puller: %m");
r = tar_pull_start(pull, url, local, arg_pull_flags & PULL_FLAGS_MASK_TAR, arg_verify);
r = tar_pull_start(pull, url, local, arg_force, arg_verify, arg_settings);
if (r < 0)
return log_error_errno(r, "Failed to pull image: %m");
@ -161,8 +163,8 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
"Local image name '%s' is not valid.",
local);
if (!FLAGS_SET(arg_pull_flags, PULL_FORCE)) {
r = image_find(IMAGE_MACHINE, local, NULL, NULL);
if (!arg_force) {
r = image_find(IMAGE_MACHINE, local, NULL);
if (r < 0) {
if (r != -ENOENT)
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
@ -189,7 +191,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_pull_flags & PULL_FLAGS_MASK_RAW, arg_verify);
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");
@ -212,8 +214,6 @@ static int help(int argc, char *argv[], void *userdata) {
" 'checksum', 'signature'\n"
" --settings=BOOL Download settings file with image\n"
" --roothash=BOOL Download root hash file with image\n"
" --roothash-sigature=BOOL Download root hash signature file with image\n"
" --verity=BOOL Download verity file with image\n"
" --image-root=PATH Image root directory\n\n"
"Commands:\n"
" tar URL [NAME] Download a TAR image\n"
@ -232,20 +232,16 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERIFY,
ARG_SETTINGS,
ARG_ROOTHASH,
ARG_ROOTHASH_SIGNATURE,
ARG_VERITY,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "force", no_argument, NULL, ARG_FORCE },
{ "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 },
{ "roothash-signature", required_argument, NULL, ARG_ROOTHASH_SIGNATURE },
{ "verity", required_argument, NULL, ARG_VERITY },
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "force", no_argument, NULL, ARG_FORCE },
{ "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 },
{}
};
@ -265,7 +261,7 @@ static int parse_argv(int argc, char *argv[]) {
return version();
case ARG_FORCE:
arg_pull_flags |= PULL_FORCE;
arg_force = true;
break;
case ARG_IMAGE_ROOT:
@ -285,7 +281,7 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to parse --settings= parameter '%s': %m", optarg);
SET_FLAG(arg_pull_flags, PULL_SETTINGS, r);
arg_settings = r;
break;
case ARG_ROOTHASH:
@ -293,27 +289,7 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to parse --roothash= parameter '%s': %m", optarg);
SET_FLAG(arg_pull_flags, PULL_ROOTHASH, r);
/* If we were asked to turn off the root hash, implicitly also turn off the root hash signature */
if (!r)
SET_FLAG(arg_pull_flags, PULL_ROOTHASH_SIGNATURE, false);
break;
case ARG_ROOTHASH_SIGNATURE:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --roothash-signature= parameter '%s': %m", optarg);
SET_FLAG(arg_pull_flags, PULL_ROOTHASH_SIGNATURE, r);
break;
case ARG_VERITY:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --verity= parameter '%s': %m", optarg);
SET_FLAG(arg_pull_flags, PULL_VERITY, r);
arg_roothash = r;
break;
case '?':

View File

@ -408,7 +408,7 @@ static int image_object_find(sd_bus *bus, const char *path, const char *interfac
if (r < 0)
return r;
r = image_find(IMAGE_MACHINE, e, NULL, &image);
r = image_find(IMAGE_MACHINE, e, &image);
if (r == -ENOENT)
return 0;
if (r < 0)
@ -452,7 +452,7 @@ static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata,
if (!images)
return -ENOMEM;
r = image_discover(IMAGE_MACHINE, NULL, images);
r = image_discover(IMAGE_MACHINE, images);
if (r < 0)
return r;

View File

@ -124,7 +124,7 @@ static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_erro
if (r < 0)
return r;
r = image_find(IMAGE_MACHINE, name, NULL, NULL);
r = image_find(IMAGE_MACHINE, name, NULL);
if (r == -ENOENT)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
if (r < 0)
@ -480,7 +480,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er
if (!images)
return -ENOMEM;
r = image_discover(IMAGE_MACHINE, NULL, images);
r = image_discover(IMAGE_MACHINE, images);
if (r < 0)
return r;
@ -562,7 +562,7 @@ static int redirect_method_to_image(sd_bus_message *message, Manager *m, sd_bus_
if (!image_name_is_valid(name))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
r = image_find(IMAGE_MACHINE, name, NULL, &i);
r = image_find(IMAGE_MACHINE, name, &i);
if (r == -ENOENT)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
if (r < 0)
@ -755,7 +755,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
goto child_fail;
}
r = image_discover(IMAGE_MACHINE, NULL, images);
r = image_discover(IMAGE_MACHINE, images);
if (r < 0)
goto child_fail;

View File

@ -6,7 +6,6 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
#include "conf-parser.h"
#include "networkd-conf.h"
#include "networkd-manager.h"
#include "networkd-route.h"
%}
struct ConfigPerfItem;
%null_strings
@ -22,6 +21,5 @@ struct ConfigPerfItem;
Network.SpeedMeter, config_parse_bool, 0, offsetof(Manager, use_speed_meter)
Network.SpeedMeterIntervalSec, config_parse_sec, 0, offsetof(Manager, speed_meter_interval_usec)
Network.ManageForeignRoutes, config_parse_bool, 0, offsetof(Manager, manage_foreign_routes)
Network.RouteTable, config_parse_route_table_names, 0, offsetof(Manager, route_tables)
DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid)
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid)

View File

@ -875,8 +875,6 @@ void manager_free(Manager *m) {
ordered_set_free_free(m->address_pools);
m->route_tables = hashmap_free_free_key(m->route_tables);
/* routing_policy_rule_free() access m->rules and m->rules_foreign.
* So, it is necessary to set NULL after the sets are freed. */
m->rules = set_free(m->rules);

View File

@ -65,9 +65,6 @@ struct Manager {
Set *routes;
Set *routes_foreign;
/* Route table name */
Hashmap *route_tables;
/* For link speed meter*/
bool use_speed_meter;
sd_event_source *speed_meter_event_source;

View File

@ -87,7 +87,7 @@ static const char * const route_table_table[] = {
[RT_TABLE_LOCAL] = "local",
};
DEFINE_STRING_TABLE_LOOKUP(route_table, int);
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
#define ROUTE_TABLE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("default") + 1)
static const char *format_route_table(int table, char *buf, size_t size) {
@ -1868,28 +1868,6 @@ int config_parse_route_scope(
return 0;
}
int route_table_from_string_full(Manager *m, const char *s, uint32_t *ret) {
int r;
assert(s);
assert(m);
assert(ret);
r = route_table_from_string(s);
if (r >= 0) {
*ret = (uint32_t) r;
return 0;
}
uint32_t t = PTR_TO_UINT32(hashmap_get(m->route_tables, s));
if (t != 0) {
*ret = t;
return 0;
}
return safe_atou32(s, ret);
}
int config_parse_route_table(
const char *unit,
const char *filename,
@ -1921,11 +1899,16 @@ int config_parse_route_table(
return 0;
}
r = route_table_from_string_full(network->manager, rvalue, &n->table);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
return 0;
r = route_table_from_string(rvalue);
if (r >= 0)
n->table = r;
else {
r = safe_atou32(rvalue, &n->table);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
}
n->table_set = true;
@ -2373,77 +2356,6 @@ int config_parse_multipath_route(
return 0;
}
int config_parse_route_table_names(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_free_ char *name = NULL;
Hashmap **s = data;
uint32_t table;
const char *p;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
if (isempty(rvalue)) {
*s = hashmap_free_free_key(*s);
return 0;
}
p = rvalue;
r = extract_first_word(&p, &name, ":", 0);
if (r == -ENOMEM)
return log_oom();
if (r <= 0 || isempty(p)) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid RouteTable=, ignoring assignment: %s", rvalue);
return 0;
}
if (STR_IN_SET(name, "default", "main","local")) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Route table name %s already preconfigured. Ignoring assignment: %s", name, rvalue);
return 0;
}
r = safe_atou32(p, &table);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse RouteTable=, ignoring assignment: %s", p);
return 0;
}
if (table == 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid RouteTable=, ignoring assignment: %s", p);
return 0;
}
r = hashmap_ensure_put(s, &string_hash_ops, name, UINT32_TO_PTR(table));
if (r == -ENOMEM)
return log_oom();
if (r == -EEXIST) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Specified RouteTable= name and value pair conflicts with others, ignoring assignment: %s", rvalue);
return 0;
}
if (r > 0)
TAKE_PTR(name);
return 0;
}
static int route_section_verify(Route *route, Network *network) {
if (section_is_invalid(route->section))
return -EINVAL;

View File

@ -86,11 +86,6 @@ int network_add_ipv4ll_route(Network *network);
int network_add_default_route_on_device(Network *network);
void network_drop_invalid_routes(Network *network);
int route_table_from_string_full(Manager *m, const char *table, uint32_t *ret);
const char *route_table_to_string(int d) _const_;
int route_table_from_string(const char *d) _pure_;
CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);
CONFIG_PARSER_PROTOTYPE(config_parse_destination);
@ -105,4 +100,3 @@ CONFIG_PARSER_PROTOTYPE(config_parse_tcp_window);
CONFIG_PARSER_PROTOTYPE(config_parse_route_mtu);
CONFIG_PARSER_PROTOTYPE(config_parse_multipath_route);
CONFIG_PARSER_PROTOTYPE(config_parse_tcp_advmss);
CONFIG_PARSER_PROTOTYPE(config_parse_route_table_names);

View File

@ -8,7 +8,6 @@
#include "conf-parser.h"
#include "fileio.h"
#include "format-util.h"
#include "hashmap.h"
#include "ip-protocol-list.h"
#include "netlink-util.h"
#include "networkd-manager.h"
@ -1130,10 +1129,9 @@ int config_parse_routing_policy_rule_table(
if (r < 0)
return log_oom();
r = route_table_from_string_full(network->manager, rvalue, &n->table);
r = safe_atou32(rvalue, &n->table);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Could not parse RPDB rule route table number \"%s\", ignoring assignment: %m", rvalue);
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
return 0;
}

View File

@ -2940,7 +2940,7 @@ static int determine_names(void) {
if (arg_machine) {
_cleanup_(image_unrefp) Image *i = NULL;
r = image_find(IMAGE_MACHINE, arg_machine, NULL, &i);
r = image_find(IMAGE_MACHINE, arg_machine, &i);
if (r == -ENOENT)
return log_error_errno(r, "No image for machine '%s'.", arg_machine);
if (r < 0)

View File

@ -495,7 +495,7 @@ int portable_extract(
assert(name_or_path);
r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
r = image_find_harder(IMAGE_PORTABLE, name_or_path, &image);
if (r < 0)
return r;
@ -953,7 +953,7 @@ static int install_image_symlink(
/* If the image is outside of the image search also link it into it, so that it can be found with short image
* names and is listed among the images. */
if (image_in_search_path(IMAGE_PORTABLE, NULL, image_path))
if (image_in_search_path(IMAGE_PORTABLE, image_path))
return 0;
r = image_symlink(image_path, flags, &sl);
@ -987,7 +987,7 @@ int portable_attach(
assert(name_or_path);
r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image);
r = image_find_harder(IMAGE_PORTABLE, name_or_path, &image);
if (r < 0)
return r;
@ -1193,7 +1193,7 @@ int portable_detach(
return log_debug_errno(r, "Failed to add unit name '%s' to set: %m", de->d_name);
if (path_is_absolute(marker) &&
!image_in_search_path(IMAGE_PORTABLE, NULL, marker)) {
!image_in_search_path(IMAGE_PORTABLE, marker)) {
r = set_ensure_consume(&markers, &path_hash_ops_free, TAKE_PTR(marker));
if (r < 0)

View File

@ -606,7 +606,7 @@ int bus_image_acquire(
if (image_name_is_valid(name_or_path)) {
/* If it's a short name, let's search for it */
r = image_find(IMAGE_PORTABLE, name_or_path, NULL, &loaded);
r = image_find(IMAGE_PORTABLE, name_or_path, &loaded);
if (r == -ENOENT)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE, "No image '%s' found.", name_or_path);

View File

@ -92,7 +92,7 @@ int manager_image_cache_discover(Manager *m, Hashmap *images, sd_bus_error *erro
/* A wrapper around image_discover() (for finding images in search path) and portable_discover_attached() (for
* finding attached images). */
r = image_discover(IMAGE_PORTABLE, NULL, images);
r = image_discover(IMAGE_PORTABLE, images);
if (r < 0)
return r;

View File

@ -42,24 +42,18 @@
#include "xattr-util.h"
static const char* const image_search_path[_IMAGE_CLASS_MAX] = {
[IMAGE_MACHINE] = "/etc/machines\0" /* only place symlinks here */
"/run/machines\0" /* and here too */
"/var/lib/machines\0" /* the main place for images */
"/var/lib/container\0" /* legacy */
"/usr/local/lib/machines\0"
"/usr/lib/machines\0",
[IMAGE_MACHINE] = "/etc/machines\0" /* only place symlinks here */
"/run/machines\0" /* and here too */
"/var/lib/machines\0" /* the main place for images */
"/var/lib/container\0" /* legacy */
"/usr/local/lib/machines\0"
"/usr/lib/machines\0",
[IMAGE_PORTABLE] = "/etc/portables\0" /* only place symlinks here */
"/run/portables\0" /* and here too */
"/var/lib/portables\0" /* the main place for images */
"/usr/local/lib/portables\0"
"/usr/lib/portables\0",
[IMAGE_EXTENSION] = "/etc/extensions\0" /* only place symlinks here */
"/run/extensions\0" /* and here too */
"/var/lib/extensions\0" /* the main place for images */
"/usr/local/lib/extensions\0"
"/usr/lib/extensions\0",
[IMAGE_PORTABLE] = "/etc/portables\0" /* only place symlinks here */
"/run/portables\0" /* and here too */
"/var/lib/portables\0" /* the main place for images */
"/usr/local/lib/portables\0"
"/usr/lib/portables\0",
};
static Image *image_free(Image *i) {
@ -421,11 +415,7 @@ static int image_make(
return -EMEDIUMTYPE;
}
int image_find(ImageClass class,
const char *name,
const char *root,
Image **ret) {
int image_find(ImageClass class, const char *name, Image **ret) {
const char *path;
int r;
@ -438,22 +428,20 @@ int image_find(ImageClass class,
return -ENOENT;
NULSTR_FOREACH(path, image_search_path[class]) {
_cleanup_free_ char *resolved = NULL;
_cleanup_closedir_ DIR *d = NULL;
struct stat st;
int flags;
r = chase_symlinks_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d);
if (r == -ENOENT)
continue;
if (r < 0)
return r;
d = opendir(path);
if (!d) {
if (errno == ENOENT)
continue;
/* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people
* to symlink block devices into the search path. (For now, we disable that when operating
* relative to some root directory.) */
flags = root ? AT_SYMLINK_NOFOLLOW : 0;
if (fstatat(dirfd(d), name, &st, flags) < 0) {
return -errno;
}
/* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people to
* symlink block devices into the search path */
if (fstatat(dirfd(d), name, &st, 0) < 0) {
_cleanup_free_ char *raw = NULL;
if (errno != ENOENT)
@ -463,7 +451,8 @@ int image_find(ImageClass class,
if (!raw)
return -ENOMEM;
if (fstatat(dirfd(d), raw, &st, flags) < 0) {
if (fstatat(dirfd(d), raw, &st, 0) < 0) {
if (errno == ENOENT)
continue;
@ -473,13 +462,13 @@ int image_find(ImageClass class,
if (!S_ISREG(st.st_mode))
continue;
r = image_make(name, dirfd(d), resolved, raw, &st, ret);
r = image_make(name, dirfd(d), path, raw, &st, ret);
} else {
if (!S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode))
continue;
r = image_make(name, dirfd(d), resolved, name, &st, ret);
r = image_make(name, dirfd(d), path, name, &st, ret);
}
if (IN_SET(r, -ENOENT, -EMEDIUMTYPE))
continue;
@ -493,7 +482,7 @@ int image_find(ImageClass class,
}
if (class == IMAGE_MACHINE && streq(name, ".host")) {
r = image_make(".host", AT_FDCWD, NULL, empty_to_root(root), NULL, ret);
r = image_make(".host", AT_FDCWD, NULL, "/", NULL, ret);
if (r < 0)
return r;
@ -518,18 +507,14 @@ int image_from_path(const char *path, Image **ret) {
return image_make(NULL, AT_FDCWD, NULL, path, NULL, ret);
}
int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret) {
int image_find_harder(ImageClass class, const char *name_or_path, Image **ret) {
if (image_name_is_valid(name_or_path))
return image_find(class, name_or_path, root, ret);
return image_find(class, name_or_path, ret);
return image_from_path(name_or_path, ret);
}
int image_discover(
ImageClass class,
const char *root,
Hashmap *h) {
int image_discover(ImageClass class, Hashmap *h) {
const char *path;
int r;
@ -538,30 +523,29 @@ int image_discover(
assert(h);
NULSTR_FOREACH(path, image_search_path[class]) {
_cleanup_free_ char *resolved = NULL;
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
r = chase_symlinks_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d);
if (r == -ENOENT)
continue;
if (r < 0)
return r;
d = opendir(path);
if (!d) {
if (errno == ENOENT)
continue;
return -errno;
}
FOREACH_DIRENT_ALL(de, d, return -errno) {
_cleanup_(image_unrefp) Image *image = NULL;
_cleanup_free_ char *truncated = NULL;
const char *pretty;
struct stat st;
int flags;
if (dot_or_dot_dot(de->d_name))
continue;
/* As mentioned above, we follow symlinks on this fstatat(), because we want to
* permit people to symlink block devices into the search path. */
flags = root ? AT_SYMLINK_NOFOLLOW : 0;
if (fstatat(dirfd(d), de->d_name, &st, flags) < 0) {
/* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people
* to symlink block devices into the search path */
if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
if (errno == ENOENT)
continue;
@ -591,7 +575,7 @@ int image_discover(
if (hashmap_contains(h, pretty))
continue;
r = image_make(pretty, dirfd(d), resolved, de->d_name, &st, &image);
r = image_make(pretty, dirfd(d), path, de->d_name, &st, &image);
if (IN_SET(r, -ENOENT, -EMEDIUMTYPE))
continue;
if (r < 0)
@ -610,7 +594,7 @@ int image_discover(
if (class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) {
_cleanup_(image_unrefp) Image *image = NULL;
r = image_make(".host", AT_FDCWD, NULL, empty_to_root("/"), NULL, &image);
r = image_make(".host", AT_FDCWD, NULL, "/", NULL, &image);
if (r < 0)
return r;
@ -753,7 +737,7 @@ int image_rename(Image *i, const char *new_name) {
if (r < 0)
return r;
r = image_find(IMAGE_MACHINE, new_name, NULL, NULL);
r = image_find(IMAGE_MACHINE, new_name, NULL);
if (r >= 0)
return -EEXIST;
if (r != -ENOENT)
@ -866,7 +850,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
if (r < 0)
return r;
r = image_find(IMAGE_MACHINE, new_name, NULL, NULL);
r = image_find(IMAGE_MACHINE, new_name, NULL);
if (r >= 0)
return -EEXIST;
if (r != -ENOENT)
@ -1258,27 +1242,16 @@ bool image_name_is_valid(const char *s) {
return true;
}
bool image_in_search_path(
ImageClass class,
const char *root,
const char *image) {
bool image_in_search_path(ImageClass class, const char *image) {
const char *path;
assert(image);
NULSTR_FOREACH(path, image_search_path[class]) {
const char *p, *q;
const char *p;
size_t k;
if (!empty_or_root(root)) {
q = path_startswith(path, root);
if (!q)
continue;
} else
q = path;
p = path_startswith(q, path);
p = path_startswith(image, path);
if (!p)
continue;

View File

@ -16,7 +16,6 @@
typedef enum ImageClass {
IMAGE_MACHINE,
IMAGE_PORTABLE,
IMAGE_EXTENSION,
_IMAGE_CLASS_MAX,
_IMAGE_CLASS_INVALID = -1
} ImageClass;
@ -62,10 +61,10 @@ Image *image_ref(Image *i);
DEFINE_TRIVIAL_CLEANUP_FUNC(Image*, image_unref);
int image_find(ImageClass class, const char *root, const char *name, Image **ret);
int image_find(ImageClass class, const char *name, Image **ret);
int image_from_path(const char *path, Image **ret);
int image_find_harder(ImageClass class, const char *root, const char *name_or_path, Image **ret);
int image_discover(ImageClass class, const char *root, Hashmap *map);
int image_find_harder(ImageClass class, const char *name_or_path, Image **ret);
int image_discover(ImageClass class, Hashmap *map);
int image_remove(Image *i);
int image_rename(Image *i, const char *new_name);
@ -84,7 +83,7 @@ int image_set_limit(Image *i, uint64_t referenced_max);
int image_read_metadata(Image *i);
bool image_in_search_path(ImageClass class, const char *root, const char *image);
bool image_in_search_path(ImageClass class, const char *image);
static inline bool IMAGE_IS_HIDDEN(const struct Image *i) {
assert(i);

View File

@ -6,7 +6,6 @@
#include "fileio.h"
#include "fs-util.h"
#include "macro.h"
#include "machine-image.h"
#include "os-util.h"
#include "string-util.h"
#include "strv.h"
@ -32,31 +31,17 @@ int path_is_os_tree(const char *path) {
return 1;
}
int open_extension_release(const char *root, const char *extension, char **ret_path, int *ret_fd) {
int open_os_release(const char *root, char **ret_path, int *ret_fd) {
_cleanup_free_ char *q = NULL;
const char *p;
int r, fd;
if (extension) {
const char *extension_full_path;
if (!image_name_is_valid(extension))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
"The extension name %s is invalid.", extension);
extension_full_path = strjoina("/usr/lib/extension-release.d/extension-release.", extension);
r = chase_symlinks(extension_full_path, root, CHASE_PREFIX_ROOT,
ret_path ? &q : NULL,
ret_fd ? &fd : NULL);
} else {
const char *p;
FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") {
r = chase_symlinks(p, root, CHASE_PREFIX_ROOT,
ret_path ? &q : NULL,
ret_fd ? &fd : NULL);
if (r != -ENOENT)
break;
}
FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") {
r = chase_symlinks(p, root, CHASE_PREFIX_ROOT,
ret_path ? &q : NULL,
ret_fd ? &fd : NULL);
if (r != -ENOENT)
break;
}
if (r < 0)
return r;
@ -79,16 +64,16 @@ int open_extension_release(const char *root, const char *extension, char **ret_p
return 0;
}
int fopen_extension_release(const char *root, const char *extension, char **ret_path, FILE **ret_file) {
int fopen_os_release(const char *root, char **ret_path, FILE **ret_file) {
_cleanup_free_ char *p = NULL;
_cleanup_close_ int fd = -1;
FILE *f;
int r;
if (!ret_file)
return open_extension_release(root, extension, ret_path, NULL);
return open_os_release(root, ret_path, NULL);
r = open_extension_release(root, extension, ret_path ? &p : NULL, &fd);
r = open_os_release(root, ret_path ? &p : NULL, &fd);
if (r < 0)
return r;
@ -104,35 +89,18 @@ int fopen_extension_release(const char *root, const char *extension, char **ret_
return 0;
}
static int parse_release_internal(const char *root, const char *extension, va_list ap) {
int parse_os_release(const char *root, ...) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
va_list ap;
int r;
r = fopen_extension_release(root, extension, &p, &f);
r = fopen_os_release(root, &p, &f);
if (r < 0)
return r;
return parse_env_filev(f, p, ap);
}
int parse_extension_release(const char *root, const char *extension, ...) {
va_list ap;
int r;
va_start(ap, extension);
r = parse_release_internal(root, extension, ap);
va_end(ap);
return r;
}
int parse_os_release(const char *root, ...) {
va_list ap;
int r;
va_start(ap, root);
r = parse_release_internal(root, NULL, ap);
r = parse_env_filev(f, p, ap);
va_end(ap);
return r;

View File

@ -5,19 +5,9 @@
int path_is_os_tree(const char *path);
/* The *_extension_release flavours will look for /usr/lib/extension-release/extension-release.NAME
* in accordance with the OS extension specification, rather than for /usr/lib/ or /etc/os-release. */
int open_extension_release(const char *root, const char *extension, char **ret_path, int *ret_fd);
static inline int open_os_release(const char *root, char **ret_path, int *ret_fd) {
return open_extension_release(root, NULL, ret_path, ret_fd);
}
int open_os_release(const char *root, char **ret_path, int *ret_fd);
int fopen_os_release(const char *root, char **ret_path, FILE **ret_file);
int fopen_extension_release(const char *root, const char *extension, char **ret_path, FILE **ret_file);
static inline int fopen_os_release(const char *root, char **ret_path, FILE **ret_file) {
return fopen_extension_release(root, NULL, ret_path, ret_file);
}
int parse_extension_release(const char *root, const char *extension, ...) _sentinel_;
int parse_os_release(const char *root, ...) _sentinel_;
int load_os_release_pairs(const char *root, char ***ret);
int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret);

View File

@ -1,5 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
systemd_sysext_sources = files('''
sysext.c
'''.split())

File diff suppressed because it is too large Load Diff

View File

@ -127,12 +127,6 @@ int import_environment(int argc, char *argv[], void *userdata) {
strv_env_clean_with_callback(copy, invalid_callback, NULL);
char **e;
STRV_FOREACH(e, copy)
if (string_has_cc(*e, NULL))
log_notice("Environment variable $%.*s contains control characters, importing anyway.",
(int) strcspn(*e, "="), *e);
r = sd_bus_message_append_strv(m, copy);
} else {
@ -145,30 +139,21 @@ int import_environment(int argc, char *argv[], void *userdata) {
STRV_FOREACH(a, strv_skip(argv, 1)) {
if (!env_name_is_valid(*a))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Not a valid environment variable name: %s", *a);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid environment variable name: %s", *a);
bool found = false;
STRV_FOREACH(b, environ) {
const char *eq;
eq = startswith(*b, *a);
if (eq && *eq == '=') {
if (string_has_cc(eq + 1, NULL))
log_notice("Environment variable $%.*s contains control characters, importing anyway.",
(int) (eq - *b), *b);
r = sd_bus_message_append(m, "s", *b);
if (r < 0)
return bus_log_create_error(r);
found = true;
break;
}
}
if (!found)
log_notice("Environment variable $%s not set, ignoring.", *a);
}
r = sd_bus_message_close_container(m);

View File

@ -265,7 +265,6 @@ static void test_env_clean(void) {
"another=one",
"another=final one",
"CRLF=\r\n",
"LESS_TERMCAP_mb=\x1b[01;31m",
"BASH_FUNC_foo%%=() { echo foo\n}");
assert_se(e);
assert_se(!strv_env_is_valid(e));
@ -278,9 +277,7 @@ static void test_env_clean(void) {
assert_se(streq(e[3], "abcd=äöüß"));
assert_se(streq(e[4], "xyz=xyz\n"));
assert_se(streq(e[5], "another=final one"));
assert_se(streq(e[6], "CRLF=\r\n"));
assert_se(streq(e[7], "LESS_TERMCAP_mb=\x1b[01;31m"));
assert_se(e[8] == NULL);
assert_se(e[6] == NULL);
}
static void test_env_name_is_valid(void) {
@ -305,11 +302,8 @@ static void test_env_value_is_valid(void) {
assert_se(env_value_is_valid("printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\""));
assert_se(env_value_is_valid("tab\tcharacter"));
assert_se(env_value_is_valid("new\nline"));
assert_se(env_value_is_valid("Show this?\rNope. Show that!"));
assert_se(env_value_is_valid("new DOS\r\nline"));
assert_se(!env_value_is_valid("\xc5")); /* A truncated utf-8-encoded "ł".
* We currently disallow that. */
assert_se(!env_value_is_valid("Show this?\rNope. Show that!"));
assert_se(!env_value_is_valid("new DOS\r\nline"));
}
static void test_env_assignment_is_valid(void) {

View File

@ -933,7 +933,7 @@ install_execs() {
# some {rc,halt}.local scripts and programs are okay to not exist, the rest should
# also, plymouth is pulled in by rescue.service, but even there the exit code
# is ignored; as it's not present on some distros, don't fail if it doesn't exist
dinfo "Attempting to install $i (based on unit file reference)"
dinfo "Attempting to install $i"
inst $i || [ "${i%.local}" != "$i" ] || [ "${i%systemd-update-done}" != "$i" ] || [ "${i##*/}" == "plymouth" ]
done
)

View File

@ -211,7 +211,6 @@ in_units = [
['systemd-oomd.service', 'ENABLE_OOMD'],
['systemd-portabled.service', 'ENABLE_PORTABLED',
'dbus-org.freedesktop.portable1.service'],
['systemd-sysext.service', 'ENABLE_SYSEXT'],
['systemd-userdbd.service', 'ENABLE_USERDB'],
['systemd-homed.service', 'ENABLE_HOMED'],
['systemd-quotacheck.service', 'ENABLE_QUOTACHECK'],

View File

@ -1,31 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# 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=Merge System Extension Images into /usr/ and /opt/
Documentation=man:systemd-sysext.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
After=local-fs.target
Before=sysinit.target shutdown.target systemd-tmpfiles.service
ConditionCapability=CAP_SYS_ADMIN
ConditionDirectoryNotEmpty=|/etc/extensions
ConditionDirectoryNotEmpty=|/run/extensions
ConditionDirectoryNotEmpty=|/var/lib/extensions
ConditionDirectoryNotEmpty=|/usr/local/lib/extensions
ConditionDirectoryNotEmpty=|/usr/lib/extensions
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-sysext --merge
ExecStop=@rootlibexecdir@/systemd-sysext --unmerge
[Install]
WantedBy=sysinit.target