mirror of
https://github.com/systemd/systemd.git
synced 2024-11-23 02:03:37 +08:00
import: add generator that synthesizes download jobs from kernel cmdline
This commit is contained in:
parent
f596658811
commit
5f87b035fa
@ -953,6 +953,7 @@ manpages = [
|
||||
['systemd-hostnamed.service', '8', ['systemd-hostnamed'], 'ENABLE_HOSTNAMED'],
|
||||
['systemd-hwdb', '8', [], 'ENABLE_HWDB'],
|
||||
['systemd-id128', '1', [], ''],
|
||||
['systemd-import-generator', '8', [], ''],
|
||||
['systemd-importd.service', '8', ['systemd-importd'], 'ENABLE_IMPORTD'],
|
||||
['systemd-inhibit', '1', [], ''],
|
||||
['systemd-initctl.service',
|
||||
|
194
man/systemd-import-generator.xml
Normal file
194
man/systemd-import-generator.xml
Normal file
@ -0,0 +1,194 @@
|
||||
<?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" [
|
||||
<!ENTITY % entities SYSTEM "custom-entities.ent" >
|
||||
%entities;
|
||||
]>
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
<refentry id="systemd-import-generator"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-import-generator</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-import-generator</refentrytitle>
|
||||
<manvolnum>8</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-import-generator</refname>
|
||||
<refpurpose>Generator for automatically downloading disk images at boot</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>/usr/lib/systemd/system-generators/systemd-import-generator</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-import-generator</command> may be used to automatically download disk images
|
||||
(tarballs or DDIs) via
|
||||
<citerefentry><refentrytitle>systemd-importd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
at boot, based on parameters on the kernel command line or via system credentials. This is useful for
|
||||
automatically deploying an
|
||||
<citerefentry><refentrytitle>systemd-confext</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>/
|
||||
<citerefentry><refentrytitle>systemd-vmspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> or
|
||||
<citerefentry><refentrytitle>systemd-portabled.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
image at boot. This provides functionality equivalent to
|
||||
<citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, but
|
||||
accessible via the kernel command line and system credentials.</para>
|
||||
|
||||
<para><filename>systemd-import-generator</filename> implements
|
||||
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Kernel Command Line</title>
|
||||
|
||||
<para><filename>systemd-import-generator</filename> understands the following
|
||||
<citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
parameters:</para>
|
||||
|
||||
<variablelist class='kernel-commandline-options'>
|
||||
<varlistentry>
|
||||
<term><varname>systemd.pull=</varname></term>
|
||||
|
||||
<listitem><para>This option takes a colon separate triplet of option string, local target image name
|
||||
and remote URL. The local target image name can be specified as an empty string, in which case the
|
||||
name is derived from the specified remote URL. The remote URL must using the
|
||||
<literal>http://</literal>, <literal>https://</literal>, <literal>file://</literal> schemes. The
|
||||
option string itself is a comma separated list of options:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>rw</term>
|
||||
<term>ro</term>
|
||||
|
||||
<listitem><para>Controls whether to mark the local image as read-only. If not
|
||||
specified read-only defaults to off.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>verify=</term>
|
||||
|
||||
<listitem><para>Controls whether to cryptographically validate the download before installing it
|
||||
in place. Takes one of <literal>no</literal>, <literal>checksum</literal> or
|
||||
<literal>signature</literal> (the latter being the default if not specified). For details see the
|
||||
<option>--verify=</option> of
|
||||
<citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>sysext</term>
|
||||
<term>confext</term>
|
||||
<term>machine</term>
|
||||
<term>portable</term>
|
||||
|
||||
<listitem><para>Controls the image class to download, and thus ultimately the target directory
|
||||
for the image, depending on this choice the target directory
|
||||
<filename>/var/lib/extensions/</filename>, <filename>/var/lib/confexts/</filename>,
|
||||
<filename>/var/lib/machines/</filename> or <filename>/var/lib/portables/</filename> is
|
||||
selected.</para>
|
||||
|
||||
<para>Specification of exactly one of these options is mandatory.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>tar</term>
|
||||
<term>raw</term>
|
||||
|
||||
<listitem><para>Controls the type of resource to download, i.e. a (possibly compressed) tarball
|
||||
that needs to be unpacked into a file system tree, or (possibly compressed) raw disk image (DDI).</para>
|
||||
|
||||
<para>Specification of exactly one of these options is mandatory.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>systemd.pull.success_action=</varname></term>
|
||||
<term><varname>systemd.pull.failure_action=</varname></term>
|
||||
|
||||
<listitem><para>Controls whether to execute an action such as reboot, power-off and similar after
|
||||
completing the download successfully, or unsuccessfully. See
|
||||
<varname>SuccessAction=</varname>/<varname>FailureAction=</varname> on
|
||||
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details about the available actions. If not specified no action is taken, and the system will
|
||||
continue to boot normally.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Credentials</title>
|
||||
|
||||
<para><command>systemd-import-generator</command> supports the system credentials logic. The following
|
||||
credentials are used when passed in:</para>
|
||||
|
||||
<variablelist class='system-credentials'>
|
||||
<varlistentry>
|
||||
<term><varname>import.pull</varname></term>
|
||||
|
||||
<listitem><para>This credential should be a text file, with each line referencing one download
|
||||
operation. Each line should follow the same format as the value of the
|
||||
<varname>systemd.pull=</varname> kernel command line option described above.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
|
||||
<example>
|
||||
<title>Download Configuration Extension</title>
|
||||
|
||||
<programlisting>systemd.pull=raw,confext::https://example.com/myconfext.raw.gz</programlisting>
|
||||
|
||||
<para>With a kernel command line option like the above a configuration extension DDI is downloaded
|
||||
automatically at boot from the specified URL, validated cryptographically, uncompressed and installed.</para>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Download System Extension (Without Validation)</title>
|
||||
|
||||
<programlisting>systemd.pull=tar,sysext,verify=no::https://example.com/mysysext.tar.gz</programlisting>
|
||||
|
||||
<para>With a kernel command line option like the above a system extension tarball is downloaded
|
||||
automatically at boot from the specified URL, uncompressed and installed – without any cryptographic
|
||||
validation. This is useful for development purposes in virtual machines and containers. Warning: do not
|
||||
deploy a system with validation disabled like this!</para>
|
||||
</example>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-importd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd.system-credentials</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
</refentry>
|
@ -415,6 +415,16 @@
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>import.pull</varname></term>
|
||||
<listitem>
|
||||
<para>Specified disk images (tarballs and DDIs) to automatically download and install at boot. For details see
|
||||
<citerefentry><refentrytitle>systemd-import-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
288
src/import/import-generator.c
Normal file
288
src/import/import-generator.c
Normal file
@ -0,0 +1,288 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "creds-util.h"
|
||||
#include "discover-image.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "generator.h"
|
||||
#include "import-util.h"
|
||||
#include "json-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "specifier.h"
|
||||
#include "web-util.h"
|
||||
|
||||
static const char *arg_dest = NULL;
|
||||
static char *arg_success_action = NULL;
|
||||
static char *arg_failure_action = NULL;
|
||||
static sd_json_variant **arg_transfers = NULL;
|
||||
static size_t arg_n_transfers = 0;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_success_action, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_failure_action, freep);
|
||||
STATIC_ARRAY_DESTRUCTOR_REGISTER(arg_transfers, arg_n_transfers, sd_json_variant_unref_many);
|
||||
|
||||
static int parse_pull_expression(const char *v) {
|
||||
const char *p = v;
|
||||
int r;
|
||||
|
||||
assert(v);
|
||||
|
||||
_cleanup_free_ char *options = NULL;
|
||||
r = extract_first_word(&p, &options, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract option string from pull expression '%s': %m", v);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No option string in pull expression '%s': %m", v);
|
||||
|
||||
_cleanup_free_ char *local = NULL;
|
||||
r = extract_first_word(&p, &local, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract local name from pull expression '%s': %m", v);
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No local string in pull expression '%s': %m", v);
|
||||
|
||||
if (!http_url_is_valid(p) && !file_url_is_valid(p))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid URL, refusing: %s", p);
|
||||
_cleanup_free_ char *remote = strdup(p);
|
||||
if (!remote)
|
||||
return log_oom();
|
||||
|
||||
if (isempty(local))
|
||||
local = mfree(local);
|
||||
else if (!image_name_is_valid(local))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid image name, refusing: %s", local);
|
||||
|
||||
ImportType type = _IMPORT_TYPE_INVALID;
|
||||
ImageClass class = _IMAGE_CLASS_INVALID;
|
||||
ImportVerify verify = IMPORT_VERIFY_SIGNATURE;
|
||||
bool ro = false;
|
||||
|
||||
const char *o = options;
|
||||
for (;;) {
|
||||
_cleanup_free_ char *opt = NULL;
|
||||
|
||||
r = extract_first_word(&o, &opt, ",", EXTRACT_DONT_COALESCE_SEPARATORS);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to extract option from pull option expression '%s': %m", options);
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
const char *suffix;
|
||||
|
||||
if (streq(opt, "ro"))
|
||||
ro = true;
|
||||
else if (streq(opt, "rw"))
|
||||
ro = false;
|
||||
else if ((suffix = startswith(opt, "verify="))) {
|
||||
|
||||
ImportVerify w = import_verify_from_string(suffix);
|
||||
|
||||
if (w < 0)
|
||||
log_warning_errno(w, "Unknown verification mode, ignoring: %s", suffix);
|
||||
else
|
||||
verify = w;
|
||||
} else {
|
||||
ImageClass c;
|
||||
|
||||
c = image_class_from_string(opt);
|
||||
if (c < 0) {
|
||||
ImportType t;
|
||||
|
||||
t = import_type_from_string(opt);
|
||||
if (t < 0)
|
||||
log_warning_errno(c, "Unknown pull option, ignoring: %s", opt);
|
||||
else
|
||||
type = t;
|
||||
} else
|
||||
class = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (type < 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No image type (raw, tar) specified in pull expression, refusing: %s", v);
|
||||
if (class < 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No image class (machine, portable, sysext, confext) specified in pull expression, refusing: %s", v);
|
||||
|
||||
if (!GREEDY_REALLOC(arg_transfers, arg_n_transfers + 1))
|
||||
return log_oom();
|
||||
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
|
||||
|
||||
r = sd_json_buildo(
|
||||
&j,
|
||||
SD_JSON_BUILD_PAIR("remote", SD_JSON_BUILD_STRING(remote)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!!local, "local", SD_JSON_BUILD_STRING(local)),
|
||||
SD_JSON_BUILD_PAIR("class", JSON_BUILD_STRING_UNDERSCORIFY(image_class_to_string(class))),
|
||||
SD_JSON_BUILD_PAIR("type", JSON_BUILD_STRING_UNDERSCORIFY(import_type_to_string(type))),
|
||||
SD_JSON_BUILD_PAIR("readOnly", SD_JSON_BUILD_BOOLEAN(ro)),
|
||||
SD_JSON_BUILD_PAIR("verify", JSON_BUILD_STRING_UNDERSCORIFY(import_verify_to_string(verify))));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build import JSON object: %m");
|
||||
|
||||
arg_transfers[arg_n_transfers++] = TAKE_PTR(j);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
|
||||
int r;
|
||||
|
||||
if (proc_cmdline_key_streq(key, "systemd.pull")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
r = parse_pull_expression(value);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse %s expression, ignoring: %s", key, value);
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.pull.success_action")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
return free_and_strdup_warn(&arg_success_action, value);
|
||||
|
||||
} else if (proc_cmdline_key_streq(key, "systemd.pull.failure_action")) {
|
||||
|
||||
if (proc_cmdline_value_missing(key, value))
|
||||
return 0;
|
||||
|
||||
return free_and_strdup_warn(&arg_failure_action, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_credentials(void) {
|
||||
_cleanup_free_ char *b = NULL;
|
||||
size_t sz = 0;
|
||||
int r;
|
||||
|
||||
r = read_credential_with_decryption("import.pull", (void**) &b, &sz);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
f = fmemopen_unlocked(b, sz, "r");
|
||||
if (!f)
|
||||
return log_oom();
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *item = NULL;
|
||||
|
||||
r = read_stripped_line(f, LINE_MAX, &item);
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to parse credential 'ssh.listen': %m");
|
||||
break;
|
||||
}
|
||||
|
||||
if (startswith(item, "#"))
|
||||
continue;
|
||||
|
||||
r = parse_pull_expression(item);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse expression, ignoring: %s", item);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int transfer_generate(sd_json_variant *v, size_t c) {
|
||||
int r;
|
||||
|
||||
assert(v);
|
||||
|
||||
_cleanup_free_ char *service = NULL;
|
||||
if (asprintf(&service, "import%zu.service", c) < 0)
|
||||
return log_oom();
|
||||
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
r = generator_open_unit_file(arg_dest, /* source = */ NULL, service, &f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
const char *remote = sd_json_variant_string(sd_json_variant_by_key(v, "remote"));
|
||||
|
||||
fprintf(f,
|
||||
"[Unit]\n"
|
||||
"Description=Download of %s\n"
|
||||
"Documentation=man:systemd-import-generator(8)\n"
|
||||
"SourcePath=/proc/cmdline\n"
|
||||
"Requires=systemd-importd.socket\n"
|
||||
"After=systemd-importd.socket\n"
|
||||
"Conflicts=shutdown.target\n"
|
||||
"Before=shutdown.target\n"
|
||||
"DefaultDependencies=no\n",
|
||||
remote);
|
||||
|
||||
if (arg_success_action)
|
||||
fprintf(f, "SuccessAction=%s\n",
|
||||
arg_success_action);
|
||||
|
||||
if (arg_failure_action)
|
||||
fprintf(f, "FailureAction=%s\n",
|
||||
arg_failure_action);
|
||||
|
||||
const char *class = sd_json_variant_string(sd_json_variant_by_key(v, "class"));
|
||||
if (streq_ptr(class, "sysext"))
|
||||
fputs("Before=systemd-sysext.service\n", f);
|
||||
else if (streq_ptr(class, "confext"))
|
||||
fputs("Before=systemd-confext.service\n", f);
|
||||
|
||||
/* Assume network resource unless URL is file:// */
|
||||
if (!file_url_is_valid(remote))
|
||||
fputs("Wants=network-online.target\n"
|
||||
"After=network-online.target\n", f);
|
||||
|
||||
fputs("\n"
|
||||
"[Service]\n"
|
||||
"Type=oneshot\n", f);
|
||||
|
||||
_cleanup_free_ char *formatted = NULL;
|
||||
r = sd_json_variant_format(v, /* flags= */ 0, &formatted);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format import JSON data: %m");
|
||||
|
||||
_cleanup_free_ char *escaped = specifier_escape(formatted);
|
||||
if (!escaped)
|
||||
return log_oom();
|
||||
|
||||
fprintf(f, "ExecStart=:varlinkctl call -q --more /run/systemd/io.systemd.Import io.systemd.Import.Pull '%s'\n",
|
||||
escaped);
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write unit %s: %m", service);
|
||||
|
||||
return generator_add_symlink(arg_dest, "multi-user.target", "wants", service);
|
||||
}
|
||||
|
||||
static int generate(void) {
|
||||
size_t c = 0;
|
||||
int r = 0;
|
||||
|
||||
FOREACH_ARRAY(i, arg_transfers, arg_n_transfers)
|
||||
RET_GATHER(r, transfer_generate(*i, c++));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
||||
int r;
|
||||
|
||||
assert_se(arg_dest = dest);
|
||||
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_RD_STRICT|PROC_CMDLINE_STRIP_RD_PREFIX);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
(void) parse_credentials();
|
||||
|
||||
return generate();
|
||||
}
|
||||
|
||||
DEFINE_MAIN_GENERATOR_FUNCTION(run);
|
@ -110,6 +110,11 @@ executables += [
|
||||
'conditions' : ['ENABLE_IMPORTD'],
|
||||
'sources' : files('importctl.c'),
|
||||
},
|
||||
generator_template + {
|
||||
'name' : 'systemd-import-generator',
|
||||
'sources' : files('import-generator.c'),
|
||||
'conditions' : ['ENABLE_IMPORTD'],
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files(
|
||||
'test-qcow2.c',
|
||||
|
Loading…
Reference in New Issue
Block a user