mirror of
https://github.com/systemd/systemd
synced 2024-10-15 04:24:19 +00:00
Merge pull request #31507 from poettering/import-modernize
importd: various modernizations
This commit is contained in:
commit
0068131bf5
12
TODO
12
TODO
|
@ -133,6 +133,12 @@ Features:
|
|||
* add a new specifier to unit files that figures out the DDI the unit file is
|
||||
from, tracing through overlayfs, DM, loopback block device.
|
||||
|
||||
* importd/importctl
|
||||
- import generator
|
||||
- port tar handling to libarchive
|
||||
- add varlink interface
|
||||
- download images into .v/ dirs
|
||||
|
||||
* in os-release define a field that can be initialized at build time from
|
||||
SOURCE_DATE_EPOCH (maybe even under that name?). Would then be used to
|
||||
initialize the timestamp logic of ConditionNeedsUpdate=.
|
||||
|
@ -153,10 +159,6 @@ Features:
|
|||
pidfd, so that we can reasonably robustly do this. Would only cover the
|
||||
execution environment like namespaces, but not the privilege settings.
|
||||
|
||||
* add a generic client to importd called importctl, then make machinectl just
|
||||
chain-exec() it. Make sure importd/importctl can be used for sysext images,
|
||||
portable images too.
|
||||
|
||||
* varlink: extend varlink IDL macros to include documentation strings
|
||||
|
||||
* Introduce a CGroupRef structure, inspired by PidRef. Should contain cgroup
|
||||
|
@ -1541,8 +1543,6 @@ Features:
|
|||
that our log messages could contain clickable links for example for unit
|
||||
files and suchlike we operate on.
|
||||
|
||||
* importd: add ability download images for portabled + sysext
|
||||
|
||||
* add support for "portablectl attach http://foobar.com/waaa.raw (i.e. importd integration)
|
||||
|
||||
* sync dynamic uids/gids between host+portable srvice (i.e. if DynamicUser=1 is set for a service, make sure that the
|
||||
|
|
442
man/importctl.xml
Normal file
442
man/importctl.xml
Normal file
|
@ -0,0 +1,442 @@
|
|||
<?xml version='1.0'?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!ENTITY % entities SYSTEM "custom-entities.ent" >
|
||||
%entities;
|
||||
]>
|
||||
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
|
||||
|
||||
<refentry id="importctl" conditional='ENABLE_MACHINED'
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
|
||||
<refentryinfo>
|
||||
<title>importctl</title>
|
||||
<productname>systemd</productname>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>importctl</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>importctl</refname>
|
||||
<refpurpose>Download, import or export disk images</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>importctl</command>
|
||||
<arg choice="opt" rep="repeat">OPTIONS</arg>
|
||||
<arg choice="req">COMMAND</arg>
|
||||
<arg choice="opt" rep="repeat">NAME</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>importctl</command> may be used to download, import export disk images via
|
||||
<citerefentry><refentrytitle>systemd-importd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para><command>importctl</command> operates both on block-level disk images (such as DDIs) as well as
|
||||
file-system-level images (tarballs). It supports disk images are one of the four following
|
||||
classes:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem><para>VM images or full OS container images, that may be run via
|
||||
<citerefentry><refentrytitle>systemd-vmspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> or
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>, and
|
||||
managed via
|
||||
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
|
||||
|
||||
<listitem><para>Portable service images, that may be attached an managed via
|
||||
<citerefentry><refentrytitle>portablectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
|
||||
|
||||
<listitem><para>System extension (sysext) images, that may be activated via
|
||||
<citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para></listitem>
|
||||
|
||||
<listitem><para>Configuration extension (confext) images, that may be activated via
|
||||
<citerefentry><refentrytitle>systemd-confext</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>When images are downloaded or imported they are placed in the following directories, depending on
|
||||
the <option>--class=</option> parameter:</para>
|
||||
|
||||
<table>
|
||||
<title>Classes and Directories</title>
|
||||
<tgroup cols='2'>
|
||||
<colspec colname='class' />
|
||||
<colspec colname='directory' />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Class</entry>
|
||||
<entry>Directory</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><literal>machine</literal></entry>
|
||||
<entry><filename>/var/lib/machines/</filename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>portable</literal></entry>
|
||||
<entry><filename>/var/lib/portables/</filename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>sysext</literal></entry>
|
||||
<entry><filename>/var/lib/extensions/</filename></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><literal>confext</literal></entry>
|
||||
<entry><filename>/var/lib/confexts/</filename></entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Commands</title>
|
||||
|
||||
<para>The following commands are understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><command>pull-tar</command> <replaceable>URL</replaceable> [<replaceable>NAME</replaceable>]</term>
|
||||
|
||||
<listitem><para>Downloads a <filename>.tar</filename> image from the specified URL, and makes it
|
||||
available under the specified local name in the image directory for the selected
|
||||
<option>--class=</option>. The URL must be of type <literal>http://</literal> or
|
||||
<literal>https://</literal>, and must refer to a <filename>.tar</filename>,
|
||||
<filename>.tar.gz</filename>, <filename>.tar.xz</filename> or <filename>.tar.bz2</filename> archive
|
||||
file. If the local image name is omitted, it is automatically derived from the last component of the
|
||||
URL, with its suffix removed.</para>
|
||||
|
||||
<para>The image is verified before it is made available, unless <option>--verify=no</option> is
|
||||
specified. Verification is done either via an inline signed file with the name of the image and the
|
||||
suffix <filename>.sha256</filename> or via separate <filename>SHA256SUMS</filename> and
|
||||
<filename>SHA256SUMS.gpg</filename> files. The signature files need to be made available on the same
|
||||
web server, under the same URL as the <filename>.tar</filename> file. With
|
||||
<option>--verify=checksum</option>, only the SHA256 checksum for the file is verified, based on the
|
||||
<filename>.sha256</filename> suffixed file or the <filename>SHA256SUMS</filename> file. With
|
||||
<option>--verify=signature</option>, the sha checksum file is first verified with the inline
|
||||
signature in the <filename>.sha256</filename> file or the detached GPG signature file
|
||||
<filename>SHA256SUMS.gpg</filename>. The public key for this verification step needs to be available
|
||||
in <filename>/usr/lib/systemd/import-pubring.gpg</filename> or
|
||||
<filename>/etc/systemd/import-pubring.gpg</filename>.</para>
|
||||
|
||||
<para>If <option>-keep-download=yes</option> is specified the image will be downloaded and stored in
|
||||
a read-only subvolume/directory in the image directory that is named after the specified URL and its
|
||||
HTTP etag. A writable snapshot is then taken from this subvolume, and named after the specified local
|
||||
name. This behavior ensures that creating multiple instances of the same URL is efficient, as
|
||||
multiple downloads are not necessary. In order to create only the read-only image, and avoid creating
|
||||
its writable snapshot, specify <literal>-</literal> as local name.</para>
|
||||
|
||||
<para>Note that pressing C-c during execution of this command will not abort the download. Use
|
||||
<command>cancel-transfer</command>, described below.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>pull-raw</command> <replaceable>URL</replaceable> [<replaceable>NAME</replaceable>]</term>
|
||||
|
||||
<listitem><para>Downloads a <filename>.raw</filename> disk image from the specified URL, and makes it
|
||||
available under the specified local name in the image directory for the selected
|
||||
<option>--class=</option>. The URL must be of type <literal>http://</literal> or
|
||||
<literal>https://</literal>. The image must either be a <filename>.qcow2</filename> or raw disk
|
||||
image, optionally compressed as <filename>.gz</filename>, <filename>.xz</filename>, or
|
||||
<filename>.bz2</filename>. If the local name is omitted, it is automatically derived from the last
|
||||
component of the URL, with its suffix removed.</para>
|
||||
|
||||
<para>Image verification is identical for raw and tar images (see above).</para>
|
||||
|
||||
<para>If the downloaded image is in <filename>.qcow2</filename> format it is converted into a raw
|
||||
image file before it is made available.</para>
|
||||
|
||||
<para>If <option>-keep-download=yes</option> is specified the image will be downloaded and stored in
|
||||
a read-only file in the image directory that is named after the specified URL and its HTTP etag. A
|
||||
writable copy is then made from this file, and named after the specified local name. This behavior
|
||||
ensures that creating multiple instances of the same URL is efficient, as multiple downloads are not
|
||||
necessary. In order to create only the read-only image, and avoid creating its writable copy,
|
||||
specify <literal>-</literal> as local name.</para>
|
||||
|
||||
<para>Note that pressing C-c during execution of this command will not abort the download. Use
|
||||
<command>cancel-transfer</command>, described below.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>import-tar</command> <replaceable>FILE</replaceable> [<replaceable>NAME</replaceable>]</term>
|
||||
<term><command>import-raw</command> <replaceable>FILE</replaceable> [<replaceable>NAME</replaceable>]</term>
|
||||
|
||||
<listitem><para>Imports a TAR or RAW image, and places it under the specified name in the image
|
||||
directory for the image class selected via <option>--class=</option>. When
|
||||
<command>import-tar</command> is used, the file specified as the first argument should be a tar
|
||||
archive, possibly compressed with xz, gzip or bzip2. It will then be unpacked into its own
|
||||
subvolume/directory. When <command>import-raw</command> is used, the file should be a qcow2 or raw
|
||||
disk image, possibly compressed with xz, gzip or bzip2. If the second argument (the resulting image
|
||||
name) is not specified, it is automatically derived from the file name. If the filename is passed as
|
||||
<literal>-</literal>, the image is read from standard input, in which case the second argument is
|
||||
mandatory.</para>
|
||||
|
||||
<para>No cryptographic validation is done when importing the images.</para>
|
||||
|
||||
<para>Much like image downloads, ongoing imports may be listed with <command>list</command>
|
||||
and aborted with <command>cancel-transfer</command>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>import-fs</command> <replaceable>DIRECTORY</replaceable> [<replaceable>NAME</replaceable>]</term>
|
||||
|
||||
<listitem><para>Imports an image stored in a local directory into the image directory for the image
|
||||
class selected via <option>--class=</option> and operates similarly to <command>import-tar</command>
|
||||
or <command>import-raw</command>, but the first argument is the source directory. If supported, this
|
||||
command will create a btrfs snapshot or subvolume for the new image.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>export-tar</command> <replaceable>NAME</replaceable> [<replaceable>FILE</replaceable>]</term>
|
||||
<term><command>export-raw</command> <replaceable>NAME</replaceable> [<replaceable>FILE</replaceable>]</term>
|
||||
|
||||
<listitem><para>Exports a TAR or RAW image and stores it in the specified file. The first parameter
|
||||
should be an image name. The second parameter should be a file path the TAR or RAW
|
||||
image is written to. If the path ends in <literal>.gz</literal>, the file is compressed with gzip, if
|
||||
it ends in <literal>.xz</literal>, with xz, and if it ends in <literal>.bz2</literal>, with bzip2. If
|
||||
the path ends in neither, the file is left uncompressed. If the second argument is missing, the image
|
||||
is written to standard output. The compression may also be explicitly selected with the
|
||||
<option>--format=</option> switch. This is in particular useful if the second parameter is left
|
||||
unspecified.</para>
|
||||
|
||||
<para>Much like image downloads and imports, ongoing exports may be listed with
|
||||
<command>list</command> and aborted with <command>cancel-transfer</command>.</para>
|
||||
|
||||
<para>Note that, currently, only directory and subvolume images may be exported as TAR images, and
|
||||
only raw disk images as RAW images.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>list-transfer</command></term>
|
||||
|
||||
<listitem><para>Shows a list of image downloads, imports and exports that are currently in
|
||||
progress.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>cancel-transfer</command> <replaceable>ID</replaceable>…</term>
|
||||
|
||||
<listitem><para>Aborts a download, import or export of the image with the specified ID. To list
|
||||
ongoing transfers and their IDs, use <command>list</command>. </para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>list-images</command></term>
|
||||
|
||||
<listitem><para>Shows a list of already downloaded/imported images.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
|
||||
<para>The following options are understood:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--read-only</option></term>
|
||||
|
||||
<listitem>
|
||||
<para>When used with <command>pull-raw</command>, <command>pull-tar</command>,
|
||||
<command>import-raw</command>, <command>import-tar</command> or <command>import-fs</command> a
|
||||
read-only image is created.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--verify=</option></term>
|
||||
|
||||
<listitem><para>When downloading an image, specify whether the image shall be verified before it is
|
||||
made available. Takes one of <literal>no</literal>, <literal>checksum</literal> and
|
||||
<literal>signature</literal>. If <literal>no</literal>, no verification is done. If
|
||||
<literal>checksum</literal> is specified, the download is checked for integrity after the transfer is
|
||||
complete, but no signatures are verified. If <literal>signature</literal> is specified, the checksum
|
||||
is verified and the image's signature is checked against a local keyring of trustable vendors. It is
|
||||
strongly recommended to set this option to <literal>signature</literal> if the server and protocol
|
||||
support this. Defaults to <literal>signature</literal>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--force</option></term>
|
||||
|
||||
<listitem><para>When downloading an image, and a local copy by the specified local name already
|
||||
exists, delete it first and replace it by the newly downloaded image.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--format=</option></term>
|
||||
|
||||
<listitem><para>When used with the <option>export-tar</option> or <option>export-raw</option>
|
||||
commands, specifies the compression format to use for the resulting file. Takes one of
|
||||
<literal>uncompressed</literal>, <literal>xz</literal>, <literal>gzip</literal>,
|
||||
<literal>bzip2</literal>. By default, the format is determined automatically from the output image
|
||||
file name passed.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-q</option></term>
|
||||
<term><option>--quiet</option></term>
|
||||
|
||||
<listitem><para>Suppresses additional informational output while running.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="user-system-options.xml" xpointer="host" />
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-M</option></term>
|
||||
<term><option>--machine=</option></term>
|
||||
|
||||
<listitem><para>Connect to
|
||||
<citerefentry><refentrytitle>systemd-import.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
running in a local container, to perform the specified operation within the container.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--class=</option></term>
|
||||
<term><option>-m</option></term>
|
||||
<term><option>-P</option></term>
|
||||
<term><option>-S</option></term>
|
||||
<term><option>-C</option></term>
|
||||
|
||||
<listitem><para>Selects the image class for the downloaded images. This primarily selects the
|
||||
directory to download into. The <option>--class=</option> switch takes <literal>machine</literal>,
|
||||
<literal>portable</literal>, <literal>sysext</literal> or <literal>confext</literal> as argument. The
|
||||
short options <option>-m</option>, <option>-P</option>, <option>-S</option>, <option>-C</option> are
|
||||
shortcuts for <option>--class=machine</option>, <option>--class=portable</option>,
|
||||
<option>--class=sysext</option>, <option>--class=confext</option>.</para>
|
||||
|
||||
<para>Note that <option>--keep-download=</option> defaults to true for
|
||||
<option>--class=machine</option> and false otherwise, see below.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--keep-download=</option></term>
|
||||
<term><option>-N</option></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. When specified with <command>pull-raw</command> or
|
||||
<command>pull-tar</command>, selects whether to download directly into the specified local image
|
||||
name, or whether to download into a read-only copy first of which to make a writable copy after the
|
||||
download is completed. Defaults to true for <option>--class=machine</option>, false otherwise.</para>
|
||||
|
||||
<para>The <option>-N</option> switch is a shortcut for <option>--keep-download=no</option>.</para>
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="json" />
|
||||
<xi:include href="standard-options.xml" xpointer="j" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-pager" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-legend" />
|
||||
<xi:include href="standard-options.xml" xpointer="no-ask-password" />
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<example id="example-import-tar">
|
||||
<title>Download an Ubuntu TAR image and open a shell in it</title>
|
||||
|
||||
<programlisting># importctl pull-tar -mN https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64-root.tar.xz
|
||||
# systemd-nspawn -M jammy-server-cloudimg-amd64-root</programlisting>
|
||||
|
||||
<para>This downloads and verifies the specified <filename>.tar</filename> image, and then uses
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> to
|
||||
open a shell in it.</para>
|
||||
</example>
|
||||
|
||||
<example id="example-import-raw">
|
||||
<title>Download an Ubuntu RAW image, set a root password in it, start
|
||||
it as a service</title>
|
||||
|
||||
<programlisting># importctl pull-raw -mN \
|
||||
https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64-disk-kvm.img \
|
||||
jammy
|
||||
# systemd-firstboot --image=/var/lib/machines/jammy.raw --prompt-root-password --force
|
||||
# machinectl start jammy
|
||||
# machinectl login jammy</programlisting>
|
||||
|
||||
<para>This downloads the specified <filename>.raw</filename> image and makes it available under the
|
||||
local name <literal>jammy</literal>. Then, a root password is set with
|
||||
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>. Afterwards
|
||||
the machine is started as system service. With the last command a login prompt into the container is
|
||||
requested.</para>
|
||||
</example>
|
||||
|
||||
<example id="example-export-tar">
|
||||
<title>Exports a container image as tar file</title>
|
||||
|
||||
<programlisting># importctl export-tar -m fedora myfedora.tar.xz</programlisting>
|
||||
|
||||
<para>Exports the container <literal>fedora</literal> as an xz-compressed tar file
|
||||
<filename>myfedora.tar.xz</filename> into the current directory.</para>
|
||||
</example>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit status</title>
|
||||
|
||||
<para>On success, 0 is returned, a non-zero failure code
|
||||
otherwise.</para>
|
||||
</refsect1>
|
||||
|
||||
<xi:include href="common-variables.xml" />
|
||||
|
||||
<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>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-vmspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>portablectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-confext</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='die-net'><refentrytitle>tar</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='die-net'><refentrytitle>xz</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='die-net'><refentrytitle>gzip</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='die-net'><refentrytitle>bzip2</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
|
@ -80,6 +80,9 @@
|
|||
<listitem><para>The file system tree of the host OS itself.</para></listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Images may be downloaded, imported and exported via the
|
||||
<citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
tool.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -87,8 +90,9 @@
|
|||
|
||||
<para>The following commands are understood:</para>
|
||||
|
||||
<refsect2><title>Machine Commands</title><variablelist>
|
||||
<refsect2><title>Machine Commands</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><command>list</command></term>
|
||||
|
||||
|
@ -361,8 +365,9 @@
|
|||
</varlistentry>
|
||||
</variablelist></refsect2>
|
||||
|
||||
<refsect2><title>Image Commands</title><variablelist>
|
||||
<refsect2><title>Image Commands</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><command>list-images</command></term>
|
||||
|
||||
|
@ -515,7 +520,7 @@
|
|||
<para>When combined with the <option>--all</option> switch removes all images, not just hidden ones. This
|
||||
command effectively empties <filename>/var/lib/machines/</filename>.</para>
|
||||
|
||||
<para>Note that commands such as <command>machinectl pull-tar</command> or <command>machinectl
|
||||
<para>Note that commands such as <command>importctl pull-tar</command> or <command>importctl
|
||||
pull-raw</command> usually create hidden, read-only, unmodified machine images from the downloaded image first,
|
||||
before cloning a writable working copy of it, in order to avoid duplicate downloads in case of images that are
|
||||
reused multiple times. Use <command>machinectl clean</command> to remove old, hidden images created this
|
||||
|
@ -525,197 +530,6 @@
|
|||
</varlistentry>
|
||||
|
||||
</variablelist></refsect2>
|
||||
|
||||
<refsect2><title>Image Transfer Commands</title><variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>pull-tar</command> <replaceable>URL</replaceable> [<replaceable>NAME</replaceable>]</term>
|
||||
|
||||
<listitem><para>Downloads a <filename>.tar</filename>
|
||||
container image from the specified URL, and makes it available
|
||||
under the specified local machine name. The URL must be of
|
||||
type <literal>http://</literal> or
|
||||
<literal>https://</literal>, and must refer to a
|
||||
<filename>.tar</filename>, <filename>.tar.gz</filename>,
|
||||
<filename>.tar.xz</filename> or <filename>.tar.bz2</filename>
|
||||
archive file. If the local machine name is omitted, it
|
||||
is automatically derived from the last component of the URL,
|
||||
with its suffix removed.</para>
|
||||
|
||||
<para>The image is verified before it is made available, unless
|
||||
<option>--verify=no</option> is specified.
|
||||
Verification is done either via an inline signed file with the name
|
||||
of the image and the suffix <filename>.sha256</filename> or via
|
||||
separate <filename>SHA256SUMS</filename> and
|
||||
<filename>SHA256SUMS.gpg</filename> files.
|
||||
The signature files need to be made available on the same web
|
||||
server, under the same URL as the <filename>.tar</filename> file.
|
||||
With <option>--verify=checksum</option>, only the SHA256 checksum
|
||||
for the file is verified, based on the <filename>.sha256</filename>
|
||||
suffixed file or the <filename>SHA256SUMS</filename> file.
|
||||
With <option>--verify=signature</option>, the sha checksum file is
|
||||
first verified with the inline signature in the
|
||||
<filename>.sha256</filename> file or the detached GPG signature file
|
||||
<filename>SHA256SUMS.gpg</filename>.
|
||||
The public key for this verification step needs to be available in
|
||||
<filename>/usr/lib/systemd/import-pubring.gpg</filename> or
|
||||
<filename>/etc/systemd/import-pubring.gpg</filename>.</para>
|
||||
|
||||
<para>The container image will be downloaded and stored in a
|
||||
read-only subvolume in
|
||||
<filename>/var/lib/machines/</filename> that is named after
|
||||
the specified URL and its HTTP etag. A writable snapshot is
|
||||
then taken from this subvolume, and named after the specified
|
||||
local name. This behavior ensures that creating multiple
|
||||
container instances of the same URL is efficient, as multiple
|
||||
downloads are not necessary. In order to create only the
|
||||
read-only image, and avoid creating its writable snapshot,
|
||||
specify <literal>-</literal> as local machine name.</para>
|
||||
|
||||
<para>Note that the read-only subvolume is prefixed with
|
||||
<filename>.tar-</filename>, and is thus not shown by
|
||||
<command>list-images</command>, unless <option>--all</option>
|
||||
is passed.</para>
|
||||
|
||||
<para>Note that pressing C-c during execution of this command
|
||||
will not abort the download. Use
|
||||
<command>cancel-transfer</command>, described
|
||||
below.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v219"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>pull-raw</command> <replaceable>URL</replaceable> [<replaceable>NAME</replaceable>]</term>
|
||||
|
||||
<listitem><para>Downloads a <filename>.raw</filename>
|
||||
container or VM disk image from the specified URL, and makes
|
||||
it available under the specified local machine name. The URL
|
||||
must be of type <literal>http://</literal> or
|
||||
<literal>https://</literal>. The container image must either
|
||||
be a <filename>.qcow2</filename> or raw disk image, optionally
|
||||
compressed as <filename>.gz</filename>,
|
||||
<filename>.xz</filename>, or <filename>.bz2</filename>. If the
|
||||
local machine name is omitted, it is automatically
|
||||
derived from the last component of the URL, with its suffix
|
||||
removed.</para>
|
||||
|
||||
<para>Image verification is identical for raw and tar images
|
||||
(see above).</para>
|
||||
|
||||
<para>If the downloaded image is in
|
||||
<filename>.qcow2</filename> format it is converted into a raw
|
||||
image file before it is made available.</para>
|
||||
|
||||
<para>Downloaded images of this type will be placed as
|
||||
read-only <filename>.raw</filename> file in
|
||||
<filename>/var/lib/machines/</filename>. A local, writable
|
||||
(reflinked) copy is then made under the specified local
|
||||
machine name. To omit creation of the local, writable copy
|
||||
pass <literal>-</literal> as local machine name.</para>
|
||||
|
||||
<para>Similarly to the behavior of <command>pull-tar</command>, the read-only image is prefixed with
|
||||
<filename>.raw-</filename>, and thus not shown by <command>list-images</command>, unless
|
||||
<option>--all</option> is passed.</para>
|
||||
|
||||
<para>Note that pressing C-c during execution of this command
|
||||
will not abort the download. Use
|
||||
<command>cancel-transfer</command>, described
|
||||
below.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v219"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>import-tar</command> <replaceable>FILE</replaceable> [<replaceable>NAME</replaceable>]</term>
|
||||
<term><command>import-raw</command> <replaceable>FILE</replaceable> [<replaceable>NAME</replaceable>]</term>
|
||||
<listitem><para>Imports a TAR or RAW container or VM image,
|
||||
and places it under the specified name in
|
||||
<filename>/var/lib/machines/</filename>. When
|
||||
<command>import-tar</command> is used, the file specified as
|
||||
the first argument should be a tar archive, possibly compressed
|
||||
with xz, gzip or bzip2. It will then be unpacked into its own
|
||||
subvolume in <filename>/var/lib/machines/</filename>. When
|
||||
<command>import-raw</command> is used, the file should be a
|
||||
qcow2 or raw disk image, possibly compressed with xz, gzip or
|
||||
bzip2. If the second argument (the resulting image name) is
|
||||
not specified, it is automatically derived from the file
|
||||
name. If the filename is passed as <literal>-</literal>, the
|
||||
image is read from standard input, in which case the second
|
||||
argument is mandatory.</para>
|
||||
|
||||
<para>Optionally, the <option>--read-only</option> switch may be used to create a read-only container or VM
|
||||
image. No cryptographic validation is done when importing the images.</para>
|
||||
|
||||
<para>Much like image downloads, ongoing imports may be listed
|
||||
with <command>list-transfers</command> and aborted with
|
||||
<command>cancel-transfer</command>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v220"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>import-fs</command> <replaceable>DIRECTORY</replaceable> [<replaceable>NAME</replaceable>]</term>
|
||||
|
||||
<listitem><para>Imports a container image stored in a local directory into
|
||||
<filename>/var/lib/machines/</filename>, operates similarly to <command>import-tar</command> or
|
||||
<command>import-raw</command>, but the first argument is the source directory. If supported, this
|
||||
command will create a btrfs snapshot or subvolume for the new image.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v240"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>export-tar</command> <replaceable>NAME</replaceable> [<replaceable>FILE</replaceable>]</term>
|
||||
<term><command>export-raw</command> <replaceable>NAME</replaceable> [<replaceable>FILE</replaceable>]</term>
|
||||
<listitem><para>Exports a TAR or RAW container or VM image and
|
||||
stores it in the specified file. The first parameter should be
|
||||
a VM or container image name. The second parameter should be a
|
||||
file path the TAR or RAW image is written to. If the path ends
|
||||
in <literal>.gz</literal>, the file is compressed with gzip, if
|
||||
it ends in <literal>.xz</literal>, with xz, and if it ends in
|
||||
<literal>.bz2</literal>, with bzip2. If the path ends in
|
||||
neither, the file is left uncompressed. If the second argument
|
||||
is missing, the image is written to standard output. The
|
||||
compression may also be explicitly selected with the
|
||||
<option>--format=</option> switch. This is in particular
|
||||
useful if the second parameter is left unspecified.</para>
|
||||
|
||||
<para>Much like image downloads and imports, ongoing exports
|
||||
may be listed with <command>list-transfers</command> and
|
||||
aborted with
|
||||
<command>cancel-transfer</command>.</para>
|
||||
|
||||
<para>Note that, currently, only directory and subvolume images
|
||||
may be exported as TAR images, and only raw disk images as RAW
|
||||
images.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v220"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>list-transfers</command></term>
|
||||
|
||||
<listitem><para>Shows a list of container or VM image
|
||||
downloads, imports and exports that are currently in
|
||||
progress.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v219"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>cancel-transfer</command> <replaceable>ID</replaceable>…</term>
|
||||
|
||||
<listitem><para>Aborts a download, import or export of the
|
||||
container or VM image with the specified ID. To list ongoing
|
||||
transfers and their IDs, use
|
||||
<command>list-transfers</command>. </para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v219"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist></refsect2>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -834,8 +648,7 @@
|
|||
|
||||
<listitem><para>When used with <command>bind</command>, creates a read-only bind mount.</para>
|
||||
|
||||
<para>When used with <command>clone</command>, <command>import-raw</command> or <command>import-tar</command> a
|
||||
read-only container or VM image is created.</para>
|
||||
<para>When used with <command>clone</command> a read-only container or VM image is created.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v219"/></listitem>
|
||||
</varlistentry>
|
||||
|
@ -866,27 +679,6 @@
|
|||
<xi:include href="version-info.xml" xpointer="v219"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--verify=</option></term>
|
||||
|
||||
<listitem><para>When downloading a container or VM image,
|
||||
specify whether the image shall be verified before it is made
|
||||
available. Takes one of <literal>no</literal>,
|
||||
<literal>checksum</literal> and <literal>signature</literal>.
|
||||
If <literal>no</literal>, no verification is done. If
|
||||
<literal>checksum</literal> is specified, the download is
|
||||
checked for integrity after the transfer is complete, but no
|
||||
signatures are verified. If <literal>signature</literal> is
|
||||
specified, the checksum is verified and the image's signature
|
||||
is checked against a local keyring of trustable vendors. It is
|
||||
strongly recommended to set this option to
|
||||
<literal>signature</literal> if the server and protocol
|
||||
support this. Defaults to
|
||||
<literal>signature</literal>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v219"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--runner=</option><option>nspawn</option>|<option>vmspawn</option></term>
|
||||
|
||||
|
@ -926,28 +718,11 @@
|
|||
<varlistentry>
|
||||
<term><option>--force</option></term>
|
||||
|
||||
<listitem><para>When downloading a container or VM image, and
|
||||
a local copy by the specified local machine name already
|
||||
exists, delete it first and replace it by the newly downloaded
|
||||
image.</para>
|
||||
<listitem><para>Replace target file when copying files.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v219"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--format=</option></term>
|
||||
|
||||
<listitem><para>When used with the <option>export-tar</option>
|
||||
or <option>export-raw</option> commands, specifies the
|
||||
compression format to use for the resulting file. Takes one of
|
||||
<literal>uncompressed</literal>, <literal>xz</literal>,
|
||||
<literal>gzip</literal>, <literal>bzip2</literal>. By default,
|
||||
the format is determined automatically from the image file
|
||||
name passed.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v220"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--max-addresses=</option></term>
|
||||
|
||||
|
@ -1069,58 +844,8 @@
|
|||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<example>
|
||||
<title>Download a Ubuntu image and open a shell in it</title>
|
||||
|
||||
<programlisting># machinectl pull-tar https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-amd64-root.tar.gz
|
||||
# systemd-nspawn -M trusty-server-cloudimg-amd64-root</programlisting>
|
||||
|
||||
<para>This downloads and verifies the specified
|
||||
<filename>.tar</filename> image, and then uses
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
to open a shell in it.</para>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Download a Fedora image, set a root password in it, start
|
||||
it as a service</title>
|
||||
|
||||
<programlisting># machinectl pull-raw --verify=no \
|
||||
https://download.fedoraproject.org/pub/fedora/linux/releases/&fedora_latest_version;/Cloud/x86_64/images/Fedora-Cloud-Base-&fedora_latest_version;-&fedora_cloud_release;.x86_64.raw.xz \
|
||||
Fedora-Cloud-Base-&fedora_latest_version;-&fedora_cloud_release;.x86-64
|
||||
# systemd-nspawn -M Fedora-Cloud-Base-&fedora_latest_version;-&fedora_cloud_release;.x86-64
|
||||
# passwd
|
||||
# exit
|
||||
# machinectl start Fedora-Cloud-Base-&fedora_latest_version;-&fedora_cloud_release;.x86-64
|
||||
# machinectl login Fedora-Cloud-Base-&fedora_latest_version;-&fedora_cloud_release;.x86-64</programlisting>
|
||||
|
||||
<para>This downloads the specified <filename>.raw</filename>
|
||||
image with verification disabled. Then, a shell is opened in it
|
||||
and a root password is set. Afterwards the shell is left, and
|
||||
the machine started as system service. With the last command a
|
||||
login prompt into the container is requested.</para>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Exports a container image as tar file</title>
|
||||
|
||||
<programlisting># machinectl export-tar fedora myfedora.tar.xz</programlisting>
|
||||
|
||||
<para>Exports the container <literal>fedora</literal> as an
|
||||
xz-compressed tar file <filename>myfedora.tar.xz</filename> into the
|
||||
current directory.</para>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Create a new shell session</title>
|
||||
|
||||
<programlisting># machinectl shell --uid=lennart</programlisting>
|
||||
|
||||
<para>This creates a new shell session on the local host for
|
||||
the user ID <literal>lennart</literal>, in a <citerefentry
|
||||
project='die-net'><refentrytitle>su</refentrytitle><manvolnum>1</manvolnum></citerefentry>-like
|
||||
fashion.</para>
|
||||
</example>
|
||||
<xi:include href="importctl.xml" xpointer="example-import-raw" />
|
||||
|
||||
</refsect1>
|
||||
|
||||
|
@ -1140,6 +865,7 @@
|
|||
<member><citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='die-net'><refentrytitle>tar</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='die-net'><refentrytitle>xz</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='die-net'><refentrytitle>gzip</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
|
|
|
@ -25,11 +25,11 @@
|
|||
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd-importd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
is a system service which may be used to import, export and download additional system images. These
|
||||
images can be used by tools such as
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
to run local containers. The service is used as the backend for <command>machinectl pull-raw</command>,
|
||||
<command>machinectl pull-tar</command> and related commands. This page describes the D-Bus interface.
|
||||
is a system service which may be used to import, export and download disk images. These images can be
|
||||
used by tools such as
|
||||
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> to run
|
||||
local containers. The service is used as the backend for <command>importctl pull-raw</command>,
|
||||
<command>importctl pull-tar</command> and related commands. This page describes the D-Bus interface.
|
||||
</para>
|
||||
|
||||
<para>Note that
|
||||
|
@ -56,42 +56,94 @@ node /org/freedesktop/import1 {
|
|||
in b read_only,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
ImportTarEx(in h fd,
|
||||
in s local_name,
|
||||
in s class,
|
||||
in t flags,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
ImportRaw(in h fd,
|
||||
in s local_name,
|
||||
in b force,
|
||||
in b read_only,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
ImportRawEx(in h fd,
|
||||
in s local_name,
|
||||
in s class,
|
||||
in t flags,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
ImportFileSystem(in h fd,
|
||||
in s local_name,
|
||||
in b force,
|
||||
in b read_only,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
ImportFileSystemEx(in h fd,
|
||||
in s local_name,
|
||||
in s class,
|
||||
in t flags,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
ExportTar(in s local_name,
|
||||
in h fd,
|
||||
in s format,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
ExportTarEx(in s local_name,
|
||||
in s class,
|
||||
in h fd,
|
||||
in s format,
|
||||
in t flags,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
ExportRaw(in s local_name,
|
||||
in h fd,
|
||||
in s format,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
ExportRawEx(in s local_name,
|
||||
in s class,
|
||||
in h fd,
|
||||
in s format,
|
||||
in t flags,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
PullTar(in s url,
|
||||
in s local_name,
|
||||
in s verify_mode,
|
||||
in b force,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
PullTarEx(in s url,
|
||||
in s local_name,
|
||||
in s class,
|
||||
in s verify_mode,
|
||||
in t flags,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
PullRaw(in s url,
|
||||
in s local_name,
|
||||
in s verify_mode,
|
||||
in b force,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
PullRawEx(in s url,
|
||||
in s local_name,
|
||||
in s class,
|
||||
in s verify_mode,
|
||||
in t flags,
|
||||
out u transfer_id,
|
||||
out o transfer_path);
|
||||
ListTransfers(out a(usssdo) transfers);
|
||||
ListTransfersEx(in s class,
|
||||
in t flags,
|
||||
out a(ussssdo) transfers);
|
||||
CancelTransfer(in u transfer_id);
|
||||
ListImages(in s class,
|
||||
in t flags,
|
||||
out a(ssssbtttttt) images);
|
||||
signals:
|
||||
TransferNew(u transfer_id,
|
||||
o transfer_path);
|
||||
|
@ -105,8 +157,6 @@ node /org/freedesktop/import1 {
|
|||
};
|
||||
</programlisting>
|
||||
|
||||
<!--method ImportFileSystem is not documented!-->
|
||||
|
||||
<!--Autogenerated cross-references for systemd.directives, do not edit-->
|
||||
|
||||
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.import1.Manager"/>
|
||||
|
@ -115,22 +165,40 @@ node /org/freedesktop/import1 {
|
|||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ImportTar()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ImportTarEx()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ImportRaw()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ImportRawEx()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ImportFileSystem()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ImportFileSystemEx()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ExportTar()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ExportTarEx()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ExportRaw()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ExportRawEx()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="PullTar()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="PullTarEx()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="PullRaw()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="PullRawEx()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ListTransfers()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ListTransfersEx()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="CancelTransfer()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="ListImages()"/>
|
||||
|
||||
<variablelist class="dbus-signal" generated="True" extra-ref="TransferNew()"/>
|
||||
|
||||
<variablelist class="dbus-signal" generated="True" extra-ref="TransferRemoved()"/>
|
||||
|
@ -140,81 +208,114 @@ node /org/freedesktop/import1 {
|
|||
<refsect2>
|
||||
<title>Methods</title>
|
||||
|
||||
<para><function>ImportTar()</function> and <function>ImportRaw()</function> import a system image and
|
||||
place it into <filename>/var/lib/machines/</filename>. The first argument should be a file descriptor
|
||||
(opened for reading) referring to the tar or raw file to import. It should reference a file on disk,
|
||||
a pipe or a socket. When <function>ImportTar()</function> is used the file descriptor should
|
||||
refer to a tar file, optionally compressed with
|
||||
<citerefentry project="die-net"><refentrytitle>gzip</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry project="die-net"><refentrytitle>bzip2</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
or
|
||||
<para><function>ImportTar()</function>/<function>ImportTarEx()</function> and
|
||||
<function>ImportRaw()</function>/<function>ImportRawEx()</function> import a disk image and place it
|
||||
into the image directory. The first argument should be a file descriptor (opened for reading) referring
|
||||
to the tar or raw file to import. It should reference a file on disk, a pipe or a socket. When
|
||||
<function>ImportTar()</function>/<function>ImportTarEx()</function> is used the file descriptor should
|
||||
refer to a tar file, optionally compressed with <citerefentry project="die-net"><refentrytitle>gzip</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry project="die-net"><refentrytitle>bzip2</refentrytitle><manvolnum>1</manvolnum></citerefentry>, or
|
||||
<citerefentry project="die-net"><refentrytitle>xz</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
|
||||
<command>systemd-importd</command> will detect the used compression scheme (if any) automatically. When
|
||||
<function>ImportRaw()</function> is used the file descriptor should refer to a raw or qcow2 disk image
|
||||
containing an MBR or GPT disk label, also optionally compressed with gzip, bzip2 or xz. In either case,
|
||||
if the file is specified as a file descriptor on disk, progress information is generated for the import
|
||||
operation (as in that case we know the total size on disk). If a socket or pipe is specified, progress information is not
|
||||
available. The file descriptor argument is followed by a local name for the image. This should be a
|
||||
name suitable as a hostname and will be used to name the imported image below
|
||||
<filename>/var/lib/machines/</filename>. A tar import is placed as a directory tree or a
|
||||
<citerefentry project="url"><refentrytitle url="https://btrfs.readthedocs.io/en/latest/btrfs.html">btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
subvolume below <filename>/var/lib/machines/</filename> under the specified name with no suffix
|
||||
appended. A raw import is placed as a file in <filename>/var/lib/machines/</filename> with the
|
||||
<filename>.raw</filename> suffix appended. If the <option>force</option> argument is true, any
|
||||
pre-existing image with the same name is removed before starting the operation. Otherwise, the
|
||||
operation fails if an image with the same name already exists. Finally, the
|
||||
<option>read_only</option> argument controls
|
||||
whether to create a writable or read-only image. Both methods return immediately after starting the import,
|
||||
with the import transfer ongoing. They return a pair of transfer identifier and object path, which may
|
||||
be used to retrieve progress information about the transfer or to cancel it. The transfer identifier is a
|
||||
simple numeric identifier, the object path references an
|
||||
<function>ImportRaw()</function>/<function>ImportRawEx()</function> is used the file descriptor should
|
||||
refer to a raw or qcow2 disk image containing an MBR or GPT disk label, also optionally compressed with
|
||||
gzip, bzip2 or xz. In either case, if the file is specified as a file descriptor on disk, progress
|
||||
information is generated for the import operation (as in that case we know the total size on disk). If
|
||||
a socket or pipe is specified, progress information is not available. The file descriptor argument is
|
||||
followed by a local name for the image. This should be a name suitable as a hostname and will be used
|
||||
to name the imported image below <filename>/var/lib/machines/</filename>. A tar import is placed as a
|
||||
directory tree or a <citerefentry project="url"><refentrytitle url="https://btrfs.readthedocs.io/en/latest/btrfs.html">btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
subvolume below the image directory under the specified name with no suffix appended. A raw import is
|
||||
placed as a file in the image directory with the <filename>.raw</filename> suffix appended. In case of
|
||||
<function>ImportTar()</function>/<function>ImportRaw()</function>, if the <option>force</option>
|
||||
argument is true, any pre-existing image with the same name is removed before starting the
|
||||
operation. Otherwise, the operation fails if an image with the same name already exists. The
|
||||
<option>read_only</option> argument controls whether to create a writable or read-only image. In case
|
||||
of <function>ImportTarEx()</function>/<function>ImportRawEx()</function> these boolean flags are
|
||||
provided via a 64bit flags parameter instead, with bit 0 mapping to the <option>force</option>
|
||||
parameter, and bit 1 mapping to <option>read_only</option>. The <option>class</option> parameter
|
||||
specifies the image class, and takes one of <literal>machine</literal>, <literal>portable</literal>,
|
||||
<literal>sysext</literal>, <literal>confext</literal>. All four methods return immediately after
|
||||
starting the import, with the import transfer ongoing. They return a pair of transfer identifier and
|
||||
object path, which may be used to retrieve progress information about the transfer or to cancel it. The
|
||||
transfer identifier is a simple numeric identifier, the object path references an
|
||||
<interfacename>org.freedesktop.import1.Transfer</interfacename> object, see below. Listen for a
|
||||
<function>TransferRemoved()</function> signal for the transfer ID in order to detect when a transfer is
|
||||
complete. The returned transfer object is useful to determine the current progress or log output of the
|
||||
ongoing import operation.</para>
|
||||
|
||||
<para><function>ExportTar()</function> and <function>ExportRaw()</function> implement the reverse
|
||||
operation, and may be used to export a system image in order to place it in a tar or raw image. They
|
||||
take the machine name to export as their first parameter, followed by a file descriptor (opened for writing)
|
||||
where the tar or raw file will be written. It may either reference a file on disk or a pipe/socket. The
|
||||
third argument specifies in which compression format to write the image. It takes one of
|
||||
<para><function>ExportTar()</function>/<function>ExportTarEx()</function> and
|
||||
<function>ExportRaw()</function>/<function>ExportRaw()</function> implement the reverse operation, and
|
||||
may be used to export a system image in order to place it in a tar or raw image. They take the machine
|
||||
name to export as their first parameter, followed by a file descriptor (opened for writing) where the
|
||||
tar or raw file will be written. It may either reference a file on disk or a pipe/socket. The third
|
||||
argument specifies in which compression format to write the image. It takes one of
|
||||
<literal>uncompressed</literal>, <literal>xz</literal>, <literal>bzip2</literal> or
|
||||
<literal>gzip</literal>, depending on which compression scheme is required. The image written to the
|
||||
specified file descriptor will be a tar file in case of <function>ExportTar()</function> or a raw disk
|
||||
image in case of <function>ExportRaw()</function>. Note that currently raw disk images may not be
|
||||
exported as tar files, and vice versa. This restriction might be lifted eventually. The method
|
||||
returns a transfer identifier and object path for cancelling or tracking the export operation, similarly
|
||||
to <function>ImportTar()</function> or <function>ImportRaw()</function> as described above.</para>
|
||||
specified file descriptor will be a tar file in case of
|
||||
<function>ExportTar()</function>/<function>ExportTarEx()</function> or a raw disk image in case of
|
||||
<function>ExportRaw()</function>/<function>ExportRawEx()</function>. Note that currently raw disk
|
||||
images may not be exported as tar files, and vice versa. This restriction might be lifted
|
||||
eventually. The method returns a transfer identifier and object path for cancelling or tracking the
|
||||
export operation, similarly to <function>ImportTar()</function>/<function>ImportTarEx()</function> or
|
||||
<function>ImportRaw()</function>/<function>ImportRawEx()</function> as described
|
||||
above. <function>ExportTarEx()</function>/<function>ExportRawEx()</function> expect the image class as
|
||||
additional parameter, as well as a 64bit flags parameter that currently must be specified as
|
||||
zero.</para>
|
||||
|
||||
<para><function>PullTar()</function> and <function>PullRaw()</function> may be used to download, verify
|
||||
and import a system image from a URL. They take a URL argument which should point to a tar or
|
||||
raw file on the <literal>http://</literal> or <literal>https://</literal> protocols, possibly
|
||||
compressed with xz, bzip2 or gzip. The second argument is a local name for the image. It should be
|
||||
suitable as a hostname, similarly to the matching argument of the <function>ImportTar()</function> and
|
||||
<function>ImportRaw()</function> methods above. The third argument indicates the verification mode for
|
||||
the image. It may be one of <literal>no</literal>, <literal>checksum</literal>,
|
||||
<literal>signature</literal>. <literal>no</literal> turns off any kind of verification of the image;
|
||||
<literal>checksum</literal> looks for a <filename>SHA256SUM</filename> file next to the downloaded
|
||||
image and verifies any SHA256 hash value in that file against the image; <literal>signature</literal>
|
||||
does the same but also tries to authenticate the <filename>SHA256SUM</filename> file via
|
||||
<citerefentry project="man-pages"><refentrytitle>gpg</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
first. The last argument indicates whether to replace a possibly pre-existing image with the same local
|
||||
name (if <literal>true</literal>), or whether to fail (if <literal>false</literal>). Like the import
|
||||
and export calls above, these calls return a pair of transfer identifier and object path for the ongoing
|
||||
<para><function>PullTar()</function>/<function>PullTarEx()</function> and
|
||||
<function>PullRaw()</function>/<function>PullRawEx()</function> may be used to download, verify and
|
||||
import a system image from a URL. They take a URL argument which should point to a tar or raw file on
|
||||
the <literal>http://</literal> or <literal>https://</literal> protocols, possibly compressed with xz,
|
||||
bzip2 or gzip. The second argument is a local name for the image. It should be suitable as a hostname,
|
||||
similarly to the matching argument of the
|
||||
<function>ImportTar()</function>/<function>ImportTarEx()</function> and
|
||||
<function>ImportRaw()</function>/<function>ImportRawEx()</function> methods above. The third argument
|
||||
indicates the verification mode for the image. It may be one of <literal>no</literal>,
|
||||
<literal>checksum</literal>, <literal>signature</literal>. <literal>no</literal> turns off any kind of
|
||||
verification of the image; <literal>checksum</literal> looks for a <filename>SHA256SUM</filename> file
|
||||
next to the downloaded image and verifies any SHA256 hash value in that file against the image;
|
||||
<literal>signature</literal> does the same but also tries to authenticate the
|
||||
<filename>SHA256SUM</filename> file via <citerefentry project="man-pages"><refentrytitle>gpg</refentrytitle><manvolnum>8</manvolnum></citerefentry> first. In
|
||||
case of <function>PullTar()</function>/<function>PullRaw()</function> the last argument indicates
|
||||
whether to replace a possibly pre-existing image with the same local name (if <literal>true</literal>),
|
||||
or whether to fail (if <literal>false</literal>). In case of
|
||||
<function>PullTarEx()</function>/<function>PullRawEx()</function> the last argument is a 64bit flags
|
||||
parameter, where bit 0 controls the <literal>force</literal> flag, bit 1 is a
|
||||
<literal>read_only</literal> flag that controls whether the created image shall be marked read-only,
|
||||
and bit 2 is a <literal>keep_download</literal> flag that indicates whether a pristine, read-only copy
|
||||
of the downloaded image shell be kept, in addition for the local copy of the image. The
|
||||
<function>…_Ex()</function> variants also expect an image class string (as above). Like the import and
|
||||
export calls above, these calls return a pair of transfer identifier and object path for the ongoing
|
||||
download.</para>
|
||||
|
||||
<para><function>ListTransfers()</function> returns a list of ongoing import, export or download
|
||||
operations as created with the six calls described above. It returns an array of structures which
|
||||
consist of the numeric transfer identifier, a string indicating the operation (one of
|
||||
<literal>import-tar</literal>, <literal>import-raw</literal>, <literal>export-tar</literal>,
|
||||
<literal>export-raw</literal>, <literal>pull-tar</literal> or <literal>pull-raw</literal>), a string
|
||||
describing the remote file (in case of download operations this is the source URL, in case of
|
||||
import/export operations this is a short string describing the file descriptor passed in), a string
|
||||
with the local machine image name, a progress value between 0.0 (for 0%) and 1.0 (for 100%), as well as
|
||||
the transfer object path.</para>
|
||||
<para><function>ImportFileSystem()</function>/<function>ImportFileSystemEx()</function> are similar to
|
||||
<function>ImportTar()</function>/<function>ImportTarEx()</function> but import a directory tree. The
|
||||
first argument must refer to a directory file descriptor for the source hierarchy to import.</para>
|
||||
|
||||
<para><function>ListTransfers()</function>/<function>ListTransfersEx()</function> return a list of
|
||||
ongoing import, export or download operations as created with the six calls described above. They
|
||||
return an array of structures which consist of the numeric transfer identifier, a string indicating the
|
||||
operation (one of <literal>import-tar</literal>, <literal>import-raw</literal>,
|
||||
<literal>export-tar</literal>, <literal>export-raw</literal>, <literal>pull-tar</literal> or
|
||||
<literal>pull-raw</literal>), a string describing the remote file (in case of download operations this
|
||||
is the source URL, in case of import/export operations this is a short string describing the file
|
||||
descriptor passed in), a string with the local machine image name, the image class (only in case of
|
||||
<function>ListTransfersEx()</function>; one of <literal>machine</literal>, <literal>portable</literal>,
|
||||
<literal>sysext</literal>, <literal>confext</literal>), a progress value between 0.0 (for 0%) and 1.0
|
||||
(for 100%), as well as the transfer object path.</para>
|
||||
|
||||
<para><function>CancelTransfer()</function> may be used to cancel an ongoing import, export or download
|
||||
operation. Simply specify the transfer identifier to cancel the ongoing operation.</para>
|
||||
|
||||
<para><function>ListImages()</function> returns a list of currently installed images. It takes a image
|
||||
class string and a flags parameter. The image class is either the empty string or specifies one of the
|
||||
four image classes, by which it will then filter. The flags parameter must be zero at this time. It
|
||||
returns an array of items, each describing one image. The item fields are in order: the image class,
|
||||
the local image name, the image type, the image path, the read-only flag, the creation and modification
|
||||
times (in microseconds since the UNIX epoch), as well as the current disk usage in bytes (both overall,
|
||||
and exclusive), as well as any size limit in bytes set on the image (both overall and
|
||||
exclusive).</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
|
@ -242,6 +343,7 @@ node /org/freedesktop/import1/transfer/_1 {
|
|||
signals:
|
||||
LogMessage(u priority,
|
||||
s line);
|
||||
ProgressUpdate(d progress);
|
||||
properties:
|
||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||
readonly u Id = ...;
|
||||
|
@ -262,8 +364,6 @@ node /org/freedesktop/import1/transfer/_1 {
|
|||
};
|
||||
</programlisting>
|
||||
|
||||
<!--signal LogMessage is not documented!-->
|
||||
|
||||
<!--Autogenerated cross-references for systemd.directives, do not edit-->
|
||||
|
||||
<variablelist class="dbus-interface" generated="True" extra-ref="org.freedesktop.import1.Transfer"/>
|
||||
|
@ -274,6 +374,8 @@ node /org/freedesktop/import1/transfer/_1 {
|
|||
|
||||
<variablelist class="dbus-signal" generated="True" extra-ref="LogMessage()"/>
|
||||
|
||||
<variablelist class="dbus-signal" generated="True" extra-ref="ProgressUpdate()"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Id"/>
|
||||
|
||||
<variablelist class="dbus-property" generated="True" extra-ref="Local"/>
|
||||
|
@ -315,6 +417,17 @@ node /org/freedesktop/import1/transfer/_1 {
|
|||
between 0.0 and 1.0. To show a progress bar on screen we recommend to query this value in regular
|
||||
intervals, for example every 500 ms or so.</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Signals</title>
|
||||
|
||||
<para>The <function>LogMessage()</function> signal is emitted for log messages generated by a transfer. It
|
||||
carries a pair of syslog log level integer and log string.</para>
|
||||
|
||||
<para>The <function>ProgressUpdate()</function> signal is emitted in regular intervals when new
|
||||
download progress information is available for a transfer. It carries a double precision floating
|
||||
pointer number between 0.0 and 1.0 indicating the transfer progress.</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -340,4 +453,20 @@ node /org/freedesktop/import1/transfer/_1 {
|
|||
</refsect1>
|
||||
|
||||
<xi:include href="org.freedesktop.locale1.xml" xpointer="versioning"/>
|
||||
<refsect1>
|
||||
<title>History</title>
|
||||
<refsect2>
|
||||
<title>The Manager Object</title>
|
||||
<para><function>ImportTarEx()</function>, <function>ImportRawEx()</function>,
|
||||
<function>ImportFileSystemEx()</function>, <function>ExportTarEx()</function>,
|
||||
<function>ExportRawEx()</function>, <function>PullTarEx()</function>, <function>PullRawEx()</function>,
|
||||
<function>ListTransfersEx()</function>, <function>ListImages()</function> were added in version
|
||||
256.</para>
|
||||
</refsect2>
|
||||
<refsect2>
|
||||
<title>Transfer Objects</title>
|
||||
<para><function>ProgressUpdate()</function> was added in version 256.</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
|
|
@ -511,6 +511,7 @@
|
|||
<member><citerefentry><refentrytitle>systemd-sysext</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>org.freedesktop.portable1</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-portabled.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ manpages = [
|
|||
['hostname', '5', [], ''],
|
||||
['hostnamectl', '1', [], 'ENABLE_HOSTNAMED'],
|
||||
['hwdb', '7', [], 'ENABLE_HWDB'],
|
||||
['importctl', '1', [], 'ENABLE_MACHINED'],
|
||||
['integritytab', '5', [], 'HAVE_LIBCRYPTSETUP'],
|
||||
['iocost.conf', '5', [], ''],
|
||||
['journal-remote.conf', '5', ['journal-remote.conf.d'], 'HAVE_MICROHTTPD'],
|
||||
|
|
|
@ -65,9 +65,11 @@
|
|||
the exit code stored in the event loop object is updated, but
|
||||
otherwise no further operation is executed.</para>
|
||||
|
||||
<para><function>sd_event_get_exit_code()</function> may be used to
|
||||
query the exit code passed into
|
||||
<function>sd_event_exit()</function> earlier.</para>
|
||||
<para><function>sd_event_get_exit_code()</function> may be used to query the exit code passed to an
|
||||
earlier call of <function>sd_event_exit()</function>. The return parameter <parameter>code</parameter>
|
||||
may be set to <constant>NULL</constant>, in order to simply check if <function>sd_event_exit()</function>
|
||||
has been called before (as <function>sd_event_get_exit_code()</function> fails with
|
||||
<constant>-ENODATA</constant> if that's not the case, see below).</para>
|
||||
|
||||
<para>While the full positive and negative integer ranges may be used
|
||||
for the exit code, care should be taken not pick exit codes that
|
||||
|
@ -122,7 +124,8 @@
|
|||
<varlistentry>
|
||||
<term><constant>-ENODATA</constant></term>
|
||||
|
||||
<listitem><para>The event loop has not been requested to exit yet.</para></listitem>
|
||||
<listitem><para>Returned by <function>sd_event_get_exit_code()</function> in case the event loop has not
|
||||
been requested to exit yet.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
|
|
@ -29,12 +29,12 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-importd</command> is a system service that allows importing, exporting and downloading of
|
||||
system images suitable for running as VM or containers. It is a companion service for
|
||||
<citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, and provides the implementation for
|
||||
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
||||
<para><command>systemd-importd</command> is a system service that allows importing, exporting and
|
||||
downloading of disk images. It provides the implementation for
|
||||
<citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
||||
<command>pull-raw</command>, <command>pull-tar</command>, <command>import-raw</command>,
|
||||
<command>import-tar</command>, <command>import-fs</command>, <command>export-raw</command>, and <command>export-tar</command> commands.</para>
|
||||
<command>import-tar</command>, <command>import-fs</command>, <command>export-raw</command>, and
|
||||
<command>export-tar</command> commands.</para>
|
||||
|
||||
<para>See
|
||||
<citerefentry><refentrytitle>org.freedesktop.import1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
|
@ -47,7 +47,7 @@
|
|||
<title>See Also</title>
|
||||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
|
|
|
@ -1800,19 +1800,7 @@ After=sys-subsystem-net-devices-ens1.device</programlisting>
|
|||
<refsect1>
|
||||
<title>Examples</title>
|
||||
|
||||
<example>
|
||||
<title>Download a
|
||||
<ulink url="https://getfedora.org">Fedora</ulink> image and start a shell in it</title>
|
||||
|
||||
<programlisting># machinectl pull-raw --verify=no \
|
||||
https://download.fedoraproject.org/pub/fedora/linux/releases/&fedora_latest_version;/Cloud/x86_64/images/Fedora-Cloud-Base-&fedora_latest_version;-&fedora_cloud_release;.x86_64.raw.xz \
|
||||
Fedora-Cloud-Base-&fedora_latest_version;-&fedora_cloud_release;.x86-64
|
||||
# systemd-nspawn -M Fedora-Cloud-Base-&fedora_latest_version;-&fedora_cloud_release;.x86-64</programlisting>
|
||||
|
||||
<para>This downloads an image using
|
||||
<citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
and opens a shell in it.</para>
|
||||
</example>
|
||||
<xi:include href="importctl.xml" xpointer="example-import-tar" />
|
||||
|
||||
<example>
|
||||
<title>Build and boot a minimal Fedora distribution in a container</title>
|
||||
|
@ -1921,6 +1909,7 @@ After=sys-subsystem-net-devices-ens1.device</programlisting>
|
|||
<member><citerefentry project='mankier'><refentrytitle>zypper</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='url'><refentrytitle url='https://btrfs.readthedocs.io/en/latest/btrfs.html'>btrfs</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
|
|
@ -449,6 +449,7 @@
|
|||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>systemd-stub</refentrytitle><manvolnum>7</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
||||
|
|
|
@ -485,6 +485,8 @@ $ systemd-vmspawn --image=image.raw
|
|||
<para><simplelist type="inline">
|
||||
<member><citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>mkosi</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>importctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
|
|
@ -926,6 +926,8 @@ int fd_verify_safe_flags(int fd) {
|
|||
*
|
||||
* RAW_O_LARGEFILE: glibc secretly sets this and neglects to hide it from us if we call fcntl.
|
||||
* See comment in missing_fcntl.h for more details about this.
|
||||
*
|
||||
* O_DIRECTORY: this is set for directories, which are totally fine
|
||||
*/
|
||||
|
||||
assert(fd >= 0);
|
||||
|
@ -934,7 +936,7 @@ int fd_verify_safe_flags(int fd) {
|
|||
if (flags < 0)
|
||||
return -errno;
|
||||
|
||||
unexpected_flags = flags & ~(O_ACCMODE|O_NOFOLLOW|RAW_O_LARGEFILE);
|
||||
unexpected_flags = flags & ~(O_ACCMODE|O_NOFOLLOW|RAW_O_LARGEFILE|O_DIRECTORY);
|
||||
if (unexpected_flags != 0)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EREMOTEIO),
|
||||
"Unexpected flags set for extrinsic fd: 0%o",
|
||||
|
|
|
@ -41,6 +41,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
|
|||
[SPECIAL_GLYPH_TREE_SPACE] = " ",
|
||||
[SPECIAL_GLYPH_TREE_TOP] = ",-",
|
||||
[SPECIAL_GLYPH_VERTICAL_DOTTED] = ":",
|
||||
[SPECIAL_GLYPH_HORIZONTAL_DOTTED] = "-",
|
||||
[SPECIAL_GLYPH_HORIZONTAL_FAT] = "=",
|
||||
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">",
|
||||
[SPECIAL_GLYPH_BLACK_CIRCLE] = "*",
|
||||
[SPECIAL_GLYPH_WHITE_CIRCLE] = "*",
|
||||
|
@ -91,6 +93,8 @@ const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
|
|||
|
||||
/* Single glyphs in both cases */
|
||||
[SPECIAL_GLYPH_VERTICAL_DOTTED] = u8"┆",
|
||||
[SPECIAL_GLYPH_HORIZONTAL_DOTTED] = u8"┄",
|
||||
[SPECIAL_GLYPH_HORIZONTAL_FAT] = u8"━",
|
||||
[SPECIAL_GLYPH_TRIANGULAR_BULLET] = u8"‣",
|
||||
[SPECIAL_GLYPH_BLACK_CIRCLE] = u8"●",
|
||||
[SPECIAL_GLYPH_WHITE_CIRCLE] = u8"○",
|
||||
|
|
|
@ -13,6 +13,8 @@ typedef enum SpecialGlyph {
|
|||
SPECIAL_GLYPH_TREE_SPACE,
|
||||
SPECIAL_GLYPH_TREE_TOP,
|
||||
SPECIAL_GLYPH_VERTICAL_DOTTED,
|
||||
SPECIAL_GLYPH_HORIZONTAL_DOTTED,
|
||||
SPECIAL_GLYPH_HORIZONTAL_FAT,
|
||||
SPECIAL_GLYPH_TRIANGULAR_BULLET,
|
||||
SPECIAL_GLYPH_BLACK_CIRCLE,
|
||||
SPECIAL_GLYPH_WHITE_CIRCLE,
|
||||
|
|
|
@ -10,20 +10,28 @@
|
|||
#include "version.h"
|
||||
|
||||
static void curl_glue_check_finished(CurlGlue *g) {
|
||||
CURLMsg *msg;
|
||||
int k = 0;
|
||||
int r;
|
||||
|
||||
assert(g);
|
||||
|
||||
/* sd_event_get_exit_code() returns -ENODATA if no exit was scheduled yet */
|
||||
r = sd_event_get_exit_code(g->event, /* ret_code= */ NULL);
|
||||
if (r >= 0)
|
||||
return; /* exit scheduled? Then don't process this anymore */
|
||||
if (r != -ENODATA)
|
||||
log_debug_errno(r, "Unexpected error while checking for event loop exit code, ignoring: %m");
|
||||
|
||||
CURLMsg *msg;
|
||||
int k = 0;
|
||||
msg = curl_multi_info_read(g->curl, &k);
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
if (msg->msg != CURLMSG_DONE)
|
||||
return;
|
||||
|
||||
if (g->on_finished)
|
||||
if (msg->msg == CURLMSG_DONE && g->on_finished)
|
||||
g->on_finished(g, msg->easy_handle, msg->data.result);
|
||||
|
||||
/* This is a queue, process another item soon, but do so in a later event loop iteration. */
|
||||
(void) sd_event_source_set_enabled(g->defer, SD_EVENT_ONESHOT);
|
||||
}
|
||||
|
||||
static int curl_glue_on_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
|
@ -153,6 +161,15 @@ static int curl_glue_timer_callback(CURLM *curl, long timeout_ms, void *userdata
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int curl_glue_on_defer(sd_event_source *s, void *userdata) {
|
||||
CurlGlue *g = ASSERT_PTR(userdata);
|
||||
|
||||
assert(s);
|
||||
|
||||
curl_glue_check_finished(g);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CurlGlue *curl_glue_unref(CurlGlue *g) {
|
||||
sd_event_source *io;
|
||||
|
||||
|
@ -167,7 +184,8 @@ CurlGlue *curl_glue_unref(CurlGlue *g) {
|
|||
|
||||
hashmap_free(g->ios);
|
||||
|
||||
sd_event_source_unref(g->timer);
|
||||
sd_event_source_disable_unref(g->timer);
|
||||
sd_event_source_disable_unref(g->defer);
|
||||
sd_event_unref(g->event);
|
||||
return mfree(g);
|
||||
}
|
||||
|
@ -211,6 +229,12 @@ int curl_glue_new(CurlGlue **glue, sd_event *event) {
|
|||
if (curl_multi_setopt(g->curl, CURLMOPT_TIMERFUNCTION, curl_glue_timer_callback) != CURLM_OK)
|
||||
return -EINVAL;
|
||||
|
||||
r = sd_event_add_defer(g->event, &g->defer, curl_glue_on_defer, g);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) sd_event_source_set_description(g->defer, "curl-defer");
|
||||
|
||||
*glue = TAKE_PTR(g);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -16,6 +16,7 @@ struct CurlGlue {
|
|||
CURLM *curl;
|
||||
sd_event_source *timer;
|
||||
Hashmap *ios;
|
||||
sd_event_source *defer;
|
||||
|
||||
void (*on_finished)(CurlGlue *g, CURL *curl, CURLcode code);
|
||||
void *userdata;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "import-common.h"
|
||||
#include "import-util.h"
|
||||
#include "main-func.h"
|
||||
#include "signal-util.h"
|
||||
|
@ -22,6 +23,7 @@
|
|||
#include "verbs.h"
|
||||
|
||||
static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
|
||||
static ImageClass arg_class = IMAGE_MACHINE;
|
||||
|
||||
static void determine_compression_from_filename(const char *p) {
|
||||
|
||||
|
@ -43,12 +45,6 @@ static void determine_compression_from_filename(const char *p) {
|
|||
arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
|
||||
}
|
||||
|
||||
static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||
log_notice("Transfer aborted.");
|
||||
sd_event_exit(sd_event_source_get_event(s), EINTR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void on_tar_finished(TarExport *export, int error, void *userdata) {
|
||||
sd_event *event = userdata;
|
||||
assert(export);
|
||||
|
@ -67,12 +63,13 @@ static int export_tar(int argc, char *argv[], void *userdata) {
|
|||
_cleanup_close_ int open_fd = -EBADF;
|
||||
int r, fd;
|
||||
|
||||
if (hostname_is_valid(argv[1], 0)) {
|
||||
r = image_find(IMAGE_MACHINE, argv[1], NULL, &image);
|
||||
local = argv[1];
|
||||
if (image_name_is_valid(local)) {
|
||||
r = image_find(arg_class, local, NULL, &image);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(r, "Machine image %s not found.", argv[1]);
|
||||
return log_error_errno(r, "Image %s not found.", local);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to look for machine %s: %m", argv[1]);
|
||||
return log_error_errno(r, "Failed to look for image %s: %m", local);
|
||||
|
||||
local = image->path;
|
||||
} else
|
||||
|
@ -101,13 +98,9 @@ static int export_tar(int argc, char *argv[], void *userdata) {
|
|||
log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
|
||||
}
|
||||
|
||||
r = sd_event_default(&event);
|
||||
r = import_allocate_event_with_signals(&event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate event loop: %m");
|
||||
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
|
||||
(void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
|
||||
(void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
|
||||
return r;
|
||||
|
||||
r = tar_export_new(&export, event, on_tar_finished, event);
|
||||
if (r < 0)
|
||||
|
@ -143,12 +136,13 @@ static int export_raw(int argc, char *argv[], void *userdata) {
|
|||
_cleanup_close_ int open_fd = -EBADF;
|
||||
int r, fd;
|
||||
|
||||
if (hostname_is_valid(argv[1], 0)) {
|
||||
r = image_find(IMAGE_MACHINE, argv[1], NULL, &image);
|
||||
local = argv[1];
|
||||
if (image_name_is_valid(local)) {
|
||||
r = image_find(arg_class, local, NULL, &image);
|
||||
if (r == -ENOENT)
|
||||
return log_error_errno(r, "Machine image %s not found.", argv[1]);
|
||||
return log_error_errno(r, "Image %s not found.", local);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to look for machine %s: %m", argv[1]);
|
||||
return log_error_errno(r, "Failed to look for image %s: %m", local);
|
||||
|
||||
local = image->path;
|
||||
} else
|
||||
|
@ -177,13 +171,9 @@ static int export_raw(int argc, char *argv[], void *userdata) {
|
|||
log_info("Exporting '%s', saving to '%s' with compression '%s'.", local, strna(pretty), import_compress_type_to_string(arg_compress));
|
||||
}
|
||||
|
||||
r = sd_event_default(&event);
|
||||
r = import_allocate_event_with_signals(&event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate event loop: %m");
|
||||
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
|
||||
(void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
|
||||
(void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
|
||||
return r;
|
||||
|
||||
r = raw_export_new(&export, event, on_raw_finished, event);
|
||||
if (r < 0)
|
||||
|
@ -203,14 +193,16 @@ static int export_raw(int argc, char *argv[], void *userdata) {
|
|||
|
||||
static int help(int argc, char *argv[], void *userdata) {
|
||||
printf("%1$s [OPTIONS...] {COMMAND} ...\n"
|
||||
"\n%4$sExport container or virtual machine images.%5$s\n"
|
||||
"\n%4$sExport disk images.%5$s\n"
|
||||
"\n%2$sCommands:%3$s\n"
|
||||
" tar NAME [FILE] Export a TAR image\n"
|
||||
" raw NAME [FILE] Export a RAW image\n"
|
||||
"\n%2$sOptions:%3$s\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --format=FORMAT Select format\n\n",
|
||||
" --format=FORMAT Select format\n"
|
||||
" --class=CLASS Select image class (machine, sysext, confext,\n"
|
||||
" portable)\n",
|
||||
program_invocation_short_name,
|
||||
ansi_underline(),
|
||||
ansi_normal(),
|
||||
|
@ -225,12 +217,14 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_FORMAT,
|
||||
ARG_CLASS,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "format", required_argument, NULL, ARG_FORMAT },
|
||||
{ "class", required_argument, NULL, ARG_CLASS },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -263,6 +257,13 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
"Unknown format: %s", optarg);
|
||||
break;
|
||||
|
||||
case ARG_CLASS:
|
||||
arg_class = image_class_from_string(optarg);
|
||||
if (arg_class < 0)
|
||||
return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg);
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -288,8 +289,7 @@ static int run(int argc, char *argv[]) {
|
|||
int r;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
log_setup();
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
|
|
|
@ -276,7 +276,7 @@ bool import_validate_local(const char *name, ImportFlags flags) {
|
|||
if (FLAGS_SET(flags, IMPORT_DIRECT))
|
||||
return path_is_valid(name);
|
||||
|
||||
return hostname_is_valid(name, 0);
|
||||
return image_name_is_valid(name);
|
||||
}
|
||||
|
||||
static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||
|
@ -295,9 +295,8 @@ int import_allocate_event_with_signals(sd_event **ret) {
|
|||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate event loop: %m");
|
||||
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
|
||||
(void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL);
|
||||
(void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);
|
||||
(void) sd_event_add_signal(event, NULL, SIGTERM|SD_EVENT_SIGNAL_PROCMASK, interrupt_signal_handler, NULL);
|
||||
(void) sd_event_add_signal(event, NULL, SIGINT|SD_EVENT_SIGNAL_PROCMASK, interrupt_signal_handler, NULL);
|
||||
|
||||
*ret = TAKE_PTR(event);
|
||||
return 0;
|
||||
|
|
|
@ -6,16 +6,33 @@
|
|||
#include "sd-event.h"
|
||||
|
||||
typedef enum ImportFlags {
|
||||
/* Public Flags (i.e. accessible via D-Bus, must stay stable! */
|
||||
IMPORT_FORCE = 1 << 0, /* replace existing image */
|
||||
IMPORT_READ_ONLY = 1 << 1, /* make generated image read-only */
|
||||
IMPORT_BTRFS_SUBVOL = 1 << 2, /* tar: preferably create images as btrfs subvols */
|
||||
IMPORT_BTRFS_QUOTA = 1 << 3, /* tar: set up btrfs quota for new subvolume as child of parent subvolume */
|
||||
IMPORT_CONVERT_QCOW2 = 1 << 4, /* raw: if we detect a qcow2 image, unpack it */
|
||||
IMPORT_DIRECT = 1 << 5, /* import without rename games */
|
||||
IMPORT_SYNC = 1 << 6, /* fsync() right before we are done */
|
||||
IMPORT_PULL_KEEP_DOWNLOAD = 1 << 2, /* keep a pristine copy of the downloaded file around */
|
||||
|
||||
/* Private flags */
|
||||
IMPORT_BTRFS_SUBVOL = 1 << 3, /* tar: preferably create images as btrfs subvols */
|
||||
IMPORT_BTRFS_QUOTA = 1 << 4, /* tar: set up btrfs quota for new subvolume as child of parent subvolume */
|
||||
IMPORT_CONVERT_QCOW2 = 1 << 5, /* raw: if we detect a qcow2 image, unpack it */
|
||||
IMPORT_DIRECT = 1 << 6, /* import without rename games */
|
||||
IMPORT_SYNC = 1 << 7, /* fsync() right before we are done */
|
||||
|
||||
/* When pulling these flags are defined too */
|
||||
IMPORT_PULL_SETTINGS = 1 << 8, /* download .nspawn settings file */
|
||||
IMPORT_PULL_ROOTHASH = 1 << 9, /* only for raw: download .roothash file for verity */
|
||||
IMPORT_PULL_ROOTHASH_SIGNATURE = 1 << 10, /* only for raw: download .roothash.p7s file for verity */
|
||||
IMPORT_PULL_VERITY = 1 << 11, /* only for raw: download .verity file for verity */
|
||||
|
||||
/* The supported flags for the tar and the raw importing */
|
||||
IMPORT_FLAGS_MASK_TAR = IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_BTRFS_SUBVOL|IMPORT_BTRFS_QUOTA|IMPORT_DIRECT|IMPORT_SYNC,
|
||||
IMPORT_FLAGS_MASK_RAW = IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_CONVERT_QCOW2|IMPORT_DIRECT|IMPORT_SYNC,
|
||||
|
||||
/* The supported flags for the tar and the raw pulling */
|
||||
IMPORT_PULL_FLAGS_MASK_TAR = IMPORT_FLAGS_MASK_TAR|IMPORT_PULL_KEEP_DOWNLOAD|IMPORT_PULL_SETTINGS,
|
||||
IMPORT_PULL_FLAGS_MASK_RAW = IMPORT_FLAGS_MASK_RAW|IMPORT_PULL_KEEP_DOWNLOAD|IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY,
|
||||
|
||||
_IMPORT_FLAGS_INVALID = -EINVAL,
|
||||
} ImportFlags;
|
||||
|
||||
int import_fork_tar_c(const char *path, pid_t *ret);
|
||||
|
|
|
@ -31,7 +31,8 @@ static bool arg_btrfs_subvol = true;
|
|||
static bool arg_btrfs_quota = true;
|
||||
static bool arg_sync = true;
|
||||
static bool arg_direct = false;
|
||||
static const char *arg_image_root = "/var/lib/machines";
|
||||
static const char *arg_image_root = NULL;
|
||||
static ImageClass arg_class = IMAGE_MACHINE;
|
||||
|
||||
typedef struct ProgressInfo {
|
||||
RateLimit limit;
|
||||
|
@ -132,7 +133,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
|
|||
"Local path name '%s' is not valid.", final_path);
|
||||
} else {
|
||||
if (local) {
|
||||
if (!hostname_is_valid(local, 0))
|
||||
if (!image_name_is_valid(local))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Local image name '%s' is not valid.", local);
|
||||
} else
|
||||
|
@ -143,7 +144,7 @@ static int import_fs(int argc, char *argv[], void *userdata) {
|
|||
return log_oom();
|
||||
|
||||
if (!arg_force) {
|
||||
r = image_find(IMAGE_MACHINE, local, NULL, NULL);
|
||||
r = image_find(arg_class, local, NULL, NULL);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
|
||||
|
@ -170,6 +171,8 @@ static int import_fs(int argc, char *argv[], void *userdata) {
|
|||
log_info("Importing '%s', saving as '%s'.", strempty(pretty), local);
|
||||
}
|
||||
|
||||
log_info("Operating on image directory '%s'.", arg_image_root);
|
||||
|
||||
if (!arg_sync)
|
||||
log_info("File system synchronization on completion is off.");
|
||||
|
||||
|
@ -266,7 +269,9 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" instead of a directory\n"
|
||||
" --btrfs-quota=BOOL Controls whether to set up quota for btrfs\n"
|
||||
" subvolume\n"
|
||||
" --sync=BOOL Controls whether to sync() before completing\n",
|
||||
" --sync=BOOL Controls whether to sync() before completing\n"
|
||||
" --class=CLASS Select image class (machine, sysext, confext,\n"
|
||||
" portable)\n",
|
||||
program_invocation_short_name,
|
||||
ansi_underline(),
|
||||
ansi_normal(),
|
||||
|
@ -287,6 +292,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
ARG_BTRFS_SUBVOL,
|
||||
ARG_BTRFS_QUOTA,
|
||||
ARG_SYNC,
|
||||
ARG_CLASS,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
|
@ -299,6 +305,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
{ "btrfs-subvol", required_argument, NULL, ARG_BTRFS_SUBVOL },
|
||||
{ "btrfs-quota", required_argument, NULL, ARG_BTRFS_QUOTA },
|
||||
{ "sync", required_argument, NULL, ARG_SYNC },
|
||||
{ "class", required_argument, NULL, ARG_CLASS },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -354,6 +361,13 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
|
||||
break;
|
||||
|
||||
case ARG_CLASS:
|
||||
arg_class = image_class_from_string(optarg);
|
||||
if (arg_class < 0)
|
||||
return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg);
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -361,6 +375,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (!arg_image_root)
|
||||
arg_image_root = image_root_to_string(arg_class);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -379,8 +396,7 @@ static int run(int argc, char *argv[]) {
|
|||
int r;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
log_setup();
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
|
|
|
@ -95,8 +95,9 @@ int raw_import_new(
|
|||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(image_root);
|
||||
|
||||
root = strdup(image_root ?: "/var/lib/machines");
|
||||
root = strdup(image_root);
|
||||
if (!root)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -97,8 +97,9 @@ int tar_import_new(
|
|||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(image_root);
|
||||
|
||||
root = strdup(image_root ?: "/var/lib/machines");
|
||||
root = strdup(image_root);
|
||||
if (!root)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
@ -25,9 +25,10 @@
|
|||
#include "terminal-util.h"
|
||||
#include "verbs.h"
|
||||
|
||||
static const char *arg_image_root = "/var/lib/machines";
|
||||
static const char *arg_image_root = NULL;
|
||||
static ImportFlags arg_import_flags = IMPORT_BTRFS_SUBVOL | IMPORT_BTRFS_QUOTA | IMPORT_CONVERT_QCOW2 | IMPORT_SYNC;
|
||||
static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX;
|
||||
static ImageClass arg_class = IMAGE_MACHINE;
|
||||
|
||||
static int normalize_local(const char *local, char **ret) {
|
||||
_cleanup_free_ char *ll = NULL;
|
||||
|
@ -53,7 +54,7 @@ static int normalize_local(const char *local, char **ret) {
|
|||
"Local path name '%s' is not valid.", local);
|
||||
} else {
|
||||
if (local) {
|
||||
if (!hostname_is_valid(local, 0))
|
||||
if (!image_name_is_valid(local))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Local image name '%s' is not valid.",
|
||||
local);
|
||||
|
@ -61,7 +62,7 @@ static int normalize_local(const char *local, char **ret) {
|
|||
local = "imported";
|
||||
|
||||
if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) {
|
||||
r = image_find(IMAGE_MACHINE, local, NULL, NULL);
|
||||
r = image_find(arg_class, local, NULL, NULL);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
|
||||
|
@ -113,6 +114,12 @@ static int open_source(const char *path, const char *local, int *ret_open_fd) {
|
|||
log_info("Importing '%s', saving as '%s'.", strempty(pretty), local);
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
|
||||
log_info("Operating on image directory '%s'.", arg_image_root);
|
||||
|
||||
if (!FLAGS_SET(arg_import_flags, IMPORT_SYNC))
|
||||
log_info("File system synchronization on completion is off.");
|
||||
|
||||
*ret_open_fd = TAKE_FD(open_fd);
|
||||
return retval;
|
||||
}
|
||||
|
@ -160,15 +167,12 @@ static int import_tar(int argc, char *argv[], void *userdata) {
|
|||
|
||||
fd = open_source(path, normalized, &open_fd);
|
||||
if (fd < 0)
|
||||
return r;
|
||||
return fd;
|
||||
|
||||
r = import_allocate_event_with_signals(&event);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!FLAGS_SET(arg_import_flags, IMPORT_SYNC))
|
||||
log_info("File system synchronization on completion is off.");
|
||||
|
||||
r = tar_import_new(&import, event, arg_image_root, on_tar_finished, event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate importer: %m");
|
||||
|
@ -238,9 +242,6 @@ static int import_raw(int argc, char *argv[], void *userdata) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!FLAGS_SET(arg_import_flags, IMPORT_SYNC))
|
||||
log_info("File system synchronization on completion is off.");
|
||||
|
||||
r = raw_import_new(&import, event, arg_image_root, on_raw_finished, event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate importer: %m");
|
||||
|
@ -266,7 +267,7 @@ static int import_raw(int argc, char *argv[], void *userdata) {
|
|||
static int help(int argc, char *argv[], void *userdata) {
|
||||
|
||||
printf("%1$s [OPTIONS...] {COMMAND} ...\n"
|
||||
"\n%4$sImport container or virtual machine images.%5$s\n"
|
||||
"\n%4$sImport disk images.%5$s\n"
|
||||
"\n%2$sCommands:%3$s\n"
|
||||
" tar FILE [NAME] Import a TAR image\n"
|
||||
" raw FILE [NAME] Import a RAW image\n"
|
||||
|
@ -285,7 +286,9 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" regular disk images\n"
|
||||
" --sync=BOOL Controls whether to sync() before completing\n"
|
||||
" --offset=BYTES Offset to seek to in destination\n"
|
||||
" --size-max=BYTES Maximum number of bytes to write to destination\n",
|
||||
" --size-max=BYTES Maximum number of bytes to write to destination\n"
|
||||
" --class=CLASS Select image class (machine, sysext, confext,\n"
|
||||
" portable)\n",
|
||||
program_invocation_short_name,
|
||||
ansi_underline(),
|
||||
ansi_normal(),
|
||||
|
@ -309,6 +312,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
ARG_SYNC,
|
||||
ARG_OFFSET,
|
||||
ARG_SIZE_MAX,
|
||||
ARG_CLASS,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
|
@ -324,6 +328,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
{ "sync", required_argument, NULL, ARG_SYNC },
|
||||
{ "offset", required_argument, NULL, ARG_OFFSET },
|
||||
{ "size-max", required_argument, NULL, ARG_SIZE_MAX },
|
||||
{ "class", required_argument, NULL, ARG_CLASS },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -416,6 +421,13 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
break;
|
||||
}
|
||||
|
||||
case ARG_CLASS:
|
||||
arg_class = image_class_from_string(optarg);
|
||||
if (arg_class < 0)
|
||||
return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg);
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -432,6 +444,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (arg_offset != UINT64_MAX && !FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File offset only supported in --direct mode.");
|
||||
|
||||
if (!arg_image_root)
|
||||
arg_image_root = image_root_to_string(arg_class);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -475,8 +490,7 @@ static int run(int argc, char *argv[]) {
|
|||
int r;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
log_setup();
|
||||
|
||||
parse_env();
|
||||
|
||||
|
|
1245
src/import/importctl.c
Normal file
1245
src/import/importctl.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -14,15 +14,19 @@
|
|||
#include "common-signal.h"
|
||||
#include "constants.h"
|
||||
#include "daemon-util.h"
|
||||
#include "discover-image.h"
|
||||
#include "env-util.h"
|
||||
#include "event-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "float.h"
|
||||
#include "hostname-util.h"
|
||||
#include "import-common.h"
|
||||
#include "import-util.h"
|
||||
#include "machine-pool.h"
|
||||
#include "main-func.h"
|
||||
#include "missing_capability.h"
|
||||
#include "mkdir-label.h"
|
||||
#include "os-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "percent-util.h"
|
||||
|
@ -63,12 +67,11 @@ struct Transfer {
|
|||
|
||||
char *remote;
|
||||
char *local;
|
||||
bool force_local;
|
||||
bool read_only;
|
||||
|
||||
ImageClass class;
|
||||
ImportFlags flags;
|
||||
char *format;
|
||||
|
||||
pid_t pid;
|
||||
PidRef pidref;
|
||||
|
||||
int log_fd;
|
||||
|
||||
|
@ -80,6 +83,7 @@ struct Transfer {
|
|||
|
||||
unsigned n_canceled;
|
||||
unsigned progress_percent;
|
||||
unsigned progress_percent_sent;
|
||||
|
||||
int stdin_fd;
|
||||
int stdout_fd;
|
||||
|
@ -131,8 +135,7 @@ static Transfer *transfer_unref(Transfer *t) {
|
|||
free(t->format);
|
||||
free(t->object_path);
|
||||
|
||||
if (t->pid > 1)
|
||||
sigkill_wait(t->pid);
|
||||
pidref_done_sigkill_wait(&t->pidref);
|
||||
|
||||
safe_close(t->log_fd);
|
||||
safe_close(t->stdin_fd);
|
||||
|
@ -165,6 +168,7 @@ static int transfer_new(Manager *m, Transfer **ret) {
|
|||
.stdout_fd = -EBADF,
|
||||
.verify = _IMPORT_VERIFY_INVALID,
|
||||
.progress_percent = UINT_MAX,
|
||||
.progress_percent_sent = UINT_MAX,
|
||||
};
|
||||
|
||||
id = m->current_transfer_id + 1;
|
||||
|
@ -217,6 +221,27 @@ static void transfer_send_log_line(Transfer *t, const char *line) {
|
|||
log_warning_errno(r, "Cannot emit log message signal, ignoring: %m");
|
||||
}
|
||||
|
||||
static void transfer_send_progress_update(Transfer *t) {
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
|
||||
if (t->progress_percent_sent == t->progress_percent)
|
||||
return;
|
||||
|
||||
r = sd_bus_emit_signal(
|
||||
t->manager->bus,
|
||||
t->object_path,
|
||||
"org.freedesktop.import1.Transfer",
|
||||
"ProgressUpdate",
|
||||
"d",
|
||||
transfer_percent_as_double(t));
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Cannot emit progress update signal, ignoring: %m");
|
||||
|
||||
t->progress_percent_sent = t->progress_percent;
|
||||
}
|
||||
|
||||
static void transfer_send_logs(Transfer *t, bool flush) {
|
||||
assert(t);
|
||||
|
||||
|
@ -302,7 +327,7 @@ static int transfer_cancel(Transfer *t) {
|
|||
|
||||
assert(t);
|
||||
|
||||
r = kill_and_sigcont(t->pid, t->n_canceled < 3 ? SIGTERM : SIGKILL);
|
||||
r = pidref_kill_and_sigcont(&t->pidref, t->n_canceled < 3 ? SIGTERM : SIGKILL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -329,7 +354,7 @@ static int transfer_on_pid(sd_event_source *s, const siginfo_t *si, void *userda
|
|||
else
|
||||
log_error("Transfer process failed due to unknown reason.");
|
||||
|
||||
t->pid = 0;
|
||||
pidref_done(&t->pidref);
|
||||
|
||||
return transfer_finalize(t, success);
|
||||
}
|
||||
|
@ -363,15 +388,17 @@ static int transfer_start(Transfer *t) {
|
|||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(t->pid <= 0);
|
||||
assert(!pidref_is_set(&t->pidref));
|
||||
|
||||
if (pipe2(pipefd, O_CLOEXEC) < 0)
|
||||
return -errno;
|
||||
|
||||
r = safe_fork_full("(sd-transfer)",
|
||||
r = pidref_safe_fork_full(
|
||||
"(sd-transfer)",
|
||||
(int[]) { t->stdin_fd, t->stdout_fd < 0 ? pipefd[1] : t->stdout_fd, pipefd[1] },
|
||||
NULL, 0,
|
||||
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO, &t->pid);
|
||||
/* except_fds= */ NULL, /* n_except_fds= */ 0,
|
||||
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG,
|
||||
&t->pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
|
@ -380,6 +407,9 @@ static int transfer_start(Transfer *t) {
|
|||
NULL, /* tar, raw */
|
||||
NULL, /* --verify= */
|
||||
NULL, /* verify argument */
|
||||
NULL, /* --class= */
|
||||
NULL, /* class argument */
|
||||
NULL, /* --keep-download= */
|
||||
NULL, /* maybe --force */
|
||||
NULL, /* maybe --read-only */
|
||||
NULL, /* if so: the actual URL */
|
||||
|
@ -389,7 +419,7 @@ static int transfer_start(Transfer *t) {
|
|||
NULL, /* local */
|
||||
NULL
|
||||
};
|
||||
unsigned k = 0;
|
||||
size_t k = 0;
|
||||
|
||||
/* Child */
|
||||
|
||||
|
@ -399,6 +429,10 @@ static int transfer_start(Transfer *t) {
|
|||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
r = setenv_systemd_log_level();
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to update $SYSTEMD_LOG_LEVEL, ignoring: %m");
|
||||
|
||||
r = setenv_systemd_exec_pid(true);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to update $SYSTEMD_EXEC_PID, ignoring: %m");
|
||||
|
@ -455,9 +489,18 @@ static int transfer_start(Transfer *t) {
|
|||
cmd[k++] = import_verify_to_string(t->verify);
|
||||
}
|
||||
|
||||
if (t->force_local)
|
||||
if (t->class != IMAGE_MACHINE) {
|
||||
cmd[k++] = "--class";
|
||||
cmd[k++] = image_class_to_string(t->class);
|
||||
}
|
||||
|
||||
if (IN_SET(t->type, TRANSFER_PULL_TAR, TRANSFER_PULL_RAW))
|
||||
cmd[k++] = FLAGS_SET(t->flags, IMPORT_PULL_KEEP_DOWNLOAD) ?
|
||||
"--keep-download=yes" : "--keep-download=no";
|
||||
|
||||
if (FLAGS_SET(t->flags, IMPORT_FORCE))
|
||||
cmd[k++] = "--force";
|
||||
if (t->read_only)
|
||||
if (FLAGS_SET(t->flags, IMPORT_READ_ONLY))
|
||||
cmd[k++] = "--read-only";
|
||||
|
||||
if (t->format) {
|
||||
|
@ -478,6 +521,11 @@ static int transfer_start(Transfer *t) {
|
|||
|
||||
assert(k < ELEMENTSOF(cmd));
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *joined = strv_join((char**) cmd, " ");
|
||||
log_debug("Calling: %s", strnull(joined));
|
||||
}
|
||||
|
||||
r = invoke_callout_binary(cmd[0], (char * const *) cmd);
|
||||
log_error_errno(r, "Failed to execute %s tool: %m", cmd[0]);
|
||||
_exit(EXIT_FAILURE);
|
||||
|
@ -488,8 +536,13 @@ static int transfer_start(Transfer *t) {
|
|||
|
||||
t->stdin_fd = safe_close(t->stdin_fd);
|
||||
|
||||
r = sd_event_add_child(t->manager->event, &t->pid_event_source,
|
||||
t->pid, WEXITED, transfer_on_pid, t);
|
||||
r = event_add_child_pidref(
|
||||
t->manager->event,
|
||||
&t->pid_event_source,
|
||||
&t->pidref,
|
||||
WEXITED,
|
||||
transfer_on_pid,
|
||||
t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -584,7 +637,7 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
|
|||
}
|
||||
|
||||
HASHMAP_FOREACH(t, m->transfers)
|
||||
if (ucred->pid == t->pid)
|
||||
if (ucred->pid == t->pidref.pid)
|
||||
break;
|
||||
|
||||
if (!t) {
|
||||
|
@ -609,6 +662,8 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
|
|||
t->progress_percent = (unsigned) r;
|
||||
|
||||
log_debug("Got percentage from client: %u%%", t->progress_percent);
|
||||
|
||||
transfer_send_progress_update(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -635,17 +690,11 @@ static int manager_new(Manager **ret) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(void) sd_event_set_watchdog(m->event, true);
|
||||
|
||||
r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
|
||||
r = sd_event_set_signal_exit(m->event, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_event_add_signal(m->event, NULL, SIGRTMIN+18, sigrtmin18_handler, NULL);
|
||||
r = sd_event_add_signal(m->event, NULL, (SIGRTMIN+18)|SD_EVENT_SIGNAL_PROCMASK, sigrtmin18_handler, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -653,6 +702,10 @@ static int manager_new(Manager **ret) {
|
|||
if (r < 0)
|
||||
log_debug_errno(r, "Failed allocate memory pressure event source, ignoring: %m");
|
||||
|
||||
r = sd_event_set_watchdog(m->event, true);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to enable watchdog logic, ignoring: %m");
|
||||
|
||||
r = sd_bus_default_system(&m->bus);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -697,12 +750,13 @@ static Transfer *manager_find(Manager *m, TransferType type, const char *remote)
|
|||
|
||||
static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(transfer_unrefp) Transfer *t = NULL;
|
||||
int fd, force, read_only, r;
|
||||
const char *local, *object;
|
||||
ImageClass class = _IMAGE_CLASS_INVALID;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
const char *local;
|
||||
TransferType type;
|
||||
struct stat st;
|
||||
uint32_t id;
|
||||
uint64_t flags;
|
||||
int fd, r;
|
||||
|
||||
assert(msg);
|
||||
|
||||
|
@ -717,25 +771,56 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
|
|||
if (r == 0)
|
||||
return 1; /* Will call us back */
|
||||
|
||||
if (endswith(sd_bus_message_get_member(msg), "Ex")) {
|
||||
const char *sclass;
|
||||
|
||||
r = sd_bus_message_read(msg, "hsst", &fd, &local, &sclass, &flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
class = image_class_from_string(sclass);
|
||||
if (class < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Image class '%s' not known", sclass);
|
||||
|
||||
if (flags & ~(IMPORT_READ_ONLY|IMPORT_FORCE))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Flags 0x%" PRIx64 " invalid", flags);
|
||||
} else {
|
||||
int force, read_only;
|
||||
|
||||
r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
class = IMAGE_MACHINE;
|
||||
|
||||
flags = 0;
|
||||
SET_FLAG(flags, IMPORT_FORCE, force);
|
||||
SET_FLAG(flags, IMPORT_READ_ONLY, read_only);
|
||||
}
|
||||
|
||||
r = fd_verify_safe_flags(fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
||||
if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
|
||||
return -EINVAL;
|
||||
|
||||
if (!hostname_is_valid(local, 0))
|
||||
if (!image_name_is_valid(local))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Local name %s is invalid", local);
|
||||
"Local image name %s is invalid", local);
|
||||
|
||||
if (class == IMAGE_MACHINE) {
|
||||
r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
type = streq_ptr(sd_bus_message_get_member(msg), "ImportTar") ?
|
||||
type = startswith(sd_bus_message_get_member(msg), "ImportTar") ?
|
||||
TRANSFER_IMPORT_TAR : TRANSFER_IMPORT_RAW;
|
||||
|
||||
r = transfer_new(m, &t);
|
||||
|
@ -743,8 +828,8 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
|
|||
return r;
|
||||
|
||||
t->type = type;
|
||||
t->force_local = force;
|
||||
t->read_only = read_only;
|
||||
t->class = class;
|
||||
t->flags = flags;
|
||||
|
||||
t->local = strdup(local);
|
||||
if (!t->local)
|
||||
|
@ -758,19 +843,21 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
object = t->object_path;
|
||||
id = t->id;
|
||||
t = NULL;
|
||||
r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(msg, "uo", id, object);
|
||||
TAKE_PTR(t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(transfer_unrefp) Transfer *t = NULL;
|
||||
int fd, force, read_only, r;
|
||||
const char *local, *object;
|
||||
ImageClass class = _IMAGE_CLASS_INVALID;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
uint32_t id;
|
||||
const char *local;
|
||||
uint64_t flags;
|
||||
int fd, r;
|
||||
|
||||
assert(msg);
|
||||
|
||||
|
@ -785,29 +872,60 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e
|
|||
if (r == 0)
|
||||
return 1; /* Will call us back */
|
||||
|
||||
if (endswith(sd_bus_message_get_member(msg), "Ex")) {
|
||||
const char *sclass;
|
||||
|
||||
r = sd_bus_message_read(msg, "hsst", &fd, &local, &sclass, &flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
class = image_class_from_string(sclass);
|
||||
if (class < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Image class '%s' not known", sclass);
|
||||
|
||||
if (flags & ~(IMPORT_READ_ONLY|IMPORT_FORCE))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Flags 0x%" PRIx64 " invalid", flags);
|
||||
} else {
|
||||
int force, read_only;
|
||||
|
||||
r = sd_bus_message_read(msg, "hsbb", &fd, &local, &force, &read_only);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
class = IMAGE_MACHINE;
|
||||
|
||||
flags = 0;
|
||||
SET_FLAG(flags, IMPORT_FORCE, force);
|
||||
SET_FLAG(flags, IMPORT_READ_ONLY, read_only);
|
||||
}
|
||||
|
||||
r = fd_verify_safe_flags(fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = fd_verify_directory(fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!hostname_is_valid(local, 0))
|
||||
if (!image_name_is_valid(local))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Local name %s is invalid", local);
|
||||
"Local image name %s is invalid", local);
|
||||
|
||||
if (class == IMAGE_MACHINE) {
|
||||
r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = transfer_new(m, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t->type = TRANSFER_IMPORT_FS;
|
||||
t->force_local = force;
|
||||
t->read_only = read_only;
|
||||
t->class = class;
|
||||
t->flags = flags;
|
||||
|
||||
t->local = strdup(local);
|
||||
if (!t->local)
|
||||
|
@ -821,21 +939,23 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
object = t->object_path;
|
||||
id = t->id;
|
||||
t = NULL;
|
||||
r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(msg, "uo", id, object);
|
||||
TAKE_PTR(t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(transfer_unrefp) Transfer *t = NULL;
|
||||
int fd, r;
|
||||
const char *local, *object, *format;
|
||||
ImageClass class = _IMAGE_CLASS_INVALID;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
const char *local, *format;
|
||||
TransferType type;
|
||||
uint64_t flags;
|
||||
struct stat st;
|
||||
uint32_t id;
|
||||
int fd, r;
|
||||
|
||||
assert(msg);
|
||||
|
||||
|
@ -850,13 +970,37 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
|
|||
if (r == 0)
|
||||
return 1; /* Will call us back */
|
||||
|
||||
if (endswith(sd_bus_message_get_member(msg), "Ex")) {
|
||||
const char *sclass;
|
||||
|
||||
r = sd_bus_message_read(msg, "sshst", &local, &sclass, &fd, &format, &flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
class = image_class_from_string(sclass);
|
||||
if (class < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Image class '%s' not known", sclass);
|
||||
|
||||
if (flags != 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Flags 0x%" PRIx64 " invalid", flags);
|
||||
} else {
|
||||
r = sd_bus_message_read(msg, "shs", &local, &fd, &format);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!hostname_is_valid(local, 0))
|
||||
class = IMAGE_MACHINE;
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
if (!image_name_is_valid(local))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Local name %s is invalid", local);
|
||||
"Local image name %s is invalid", local);
|
||||
|
||||
r = fd_verify_safe_flags(fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (fstat(fd, &st) < 0)
|
||||
return -errno;
|
||||
|
@ -864,7 +1008,7 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
|
|||
if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode))
|
||||
return -EINVAL;
|
||||
|
||||
type = streq_ptr(sd_bus_message_get_member(msg), "ExportTar") ?
|
||||
type = startswith(sd_bus_message_get_member(msg), "ExportTar") ?
|
||||
TRANSFER_EXPORT_TAR : TRANSFER_EXPORT_RAW;
|
||||
|
||||
r = transfer_new(m, &t);
|
||||
|
@ -872,6 +1016,8 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
|
|||
return r;
|
||||
|
||||
t->type = type;
|
||||
t->class = class;
|
||||
t->flags = flags;
|
||||
|
||||
if (!isempty(format)) {
|
||||
t->format = strdup(format);
|
||||
|
@ -891,21 +1037,23 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
object = t->object_path;
|
||||
id = t->id;
|
||||
t = NULL;
|
||||
r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(msg, "uo", id, object);
|
||||
TAKE_PTR(t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(transfer_unrefp) Transfer *t = NULL;
|
||||
const char *remote, *local, *verify, *object;
|
||||
ImageClass class = _IMAGE_CLASS_INVALID;
|
||||
const char *remote, *local, *verify;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
ImportVerify v;
|
||||
TransferType type;
|
||||
int force, r;
|
||||
uint32_t id;
|
||||
uint64_t flags;
|
||||
ImportVerify v;
|
||||
int r;
|
||||
|
||||
assert(msg);
|
||||
|
||||
|
@ -920,19 +1068,43 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
|
|||
if (r == 0)
|
||||
return 1; /* Will call us back */
|
||||
|
||||
if (endswith(sd_bus_message_get_member(msg), "Ex")) {
|
||||
const char *sclass;
|
||||
|
||||
r = sd_bus_message_read(msg, "sssst", &remote, &local, &sclass, &verify, &flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
class = image_class_from_string(sclass);
|
||||
if (class < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Image class '%s' not known", sclass);
|
||||
|
||||
if (flags & ~(IMPORT_FORCE|IMPORT_READ_ONLY|IMPORT_PULL_KEEP_DOWNLOAD))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Flags 0x%" PRIx64 " invalid", flags);
|
||||
} else {
|
||||
int force;
|
||||
|
||||
r = sd_bus_message_read(msg, "sssb", &remote, &local, &verify, &force);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
class = IMAGE_MACHINE;
|
||||
|
||||
flags = 0;
|
||||
SET_FLAG(flags, IMPORT_FORCE, force);
|
||||
}
|
||||
|
||||
if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"URL %s is invalid", remote);
|
||||
|
||||
if (isempty(local))
|
||||
local = NULL;
|
||||
else if (!hostname_is_valid(local, 0))
|
||||
else if (!image_name_is_valid(local))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Local name %s is invalid", local);
|
||||
"Local image name %s is invalid", local);
|
||||
|
||||
if (isempty(verify))
|
||||
v = IMPORT_VERIFY_SIGNATURE;
|
||||
|
@ -942,11 +1114,13 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
|
|||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Unknown verification mode %s", verify);
|
||||
|
||||
if (class == IMAGE_MACHINE) {
|
||||
r = setup_machine_directory(error, m->use_btrfs_subvol, m->use_btrfs_quota);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ?
|
||||
type = startswith(sd_bus_message_get_member(msg), "PullTar") ?
|
||||
TRANSFER_PULL_TAR : TRANSFER_PULL_RAW;
|
||||
|
||||
if (manager_find(m, type, remote))
|
||||
|
@ -959,7 +1133,8 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
|
|||
|
||||
t->type = type;
|
||||
t->verify = v;
|
||||
t->force_local = force;
|
||||
t->flags = flags;
|
||||
t->class = class;
|
||||
|
||||
t->remote = strdup(remote);
|
||||
if (!t->remote)
|
||||
|
@ -975,31 +1150,72 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
object = t->object_path;
|
||||
id = t->id;
|
||||
t = NULL;
|
||||
r = sd_bus_reply_method_return(msg, "uo", t->id, t->object_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_reply_method_return(msg, "uo", id, object);
|
||||
TAKE_PTR(t);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
ImageClass class = _IMAGE_CLASS_INVALID;
|
||||
Transfer *t;
|
||||
int r;
|
||||
|
||||
assert(msg);
|
||||
|
||||
bool ex = endswith(sd_bus_message_get_member(msg), "Ex");
|
||||
if (ex) {
|
||||
const char *sclass;
|
||||
uint64_t flags;
|
||||
|
||||
r = sd_bus_message_read(msg, "st", &sclass, &flags);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
if (!isempty(sclass)) {
|
||||
class = image_class_from_string(sclass);
|
||||
if (class < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Image class '%s' not known", sclass);
|
||||
}
|
||||
|
||||
if (flags != 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Flags 0x%" PRIx64 " invalid", flags);
|
||||
}
|
||||
|
||||
r = sd_bus_message_new_method_return(msg, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ex)
|
||||
r = sd_bus_message_open_container(reply, 'a', "(ussssdo)");
|
||||
else
|
||||
r = sd_bus_message_open_container(reply, 'a', "(usssdo)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
HASHMAP_FOREACH(t, m->transfers) {
|
||||
|
||||
if (class >= 0 && class != t->class)
|
||||
continue;
|
||||
|
||||
if (ex)
|
||||
r = sd_bus_message_append(
|
||||
reply,
|
||||
"(ussssdo)",
|
||||
t->id,
|
||||
transfer_type_to_string(t->type),
|
||||
t->remote,
|
||||
t->local,
|
||||
image_class_to_string(t->class),
|
||||
transfer_percent_as_double(t),
|
||||
t->object_path);
|
||||
else
|
||||
r = sd_bus_message_append(
|
||||
reply,
|
||||
"(usssdo)",
|
||||
|
@ -1054,7 +1270,7 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er
|
|||
|
||||
r = bus_verify_polkit_async(
|
||||
msg,
|
||||
"org.freedesktop.import1.pull",
|
||||
"org.freedesktop.import1.cancel",
|
||||
/* details= */ NULL,
|
||||
&m->polkit_registry,
|
||||
error);
|
||||
|
@ -1080,6 +1296,86 @@ static int method_cancel_transfer(sd_bus_message *msg, void *userdata, sd_bus_er
|
|||
return sd_bus_reply_method_return(msg, NULL);
|
||||
}
|
||||
|
||||
static int method_list_images(sd_bus_message *msg, void *userdata, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
ImageClass class = _IMAGE_CLASS_INVALID;
|
||||
int r;
|
||||
|
||||
assert(msg);
|
||||
|
||||
const char *sclass;
|
||||
uint64_t flags;
|
||||
|
||||
r = sd_bus_message_read(msg, "st", &sclass, &flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!isempty(sclass)) {
|
||||
class = image_class_from_string(sclass);
|
||||
if (class < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Image class '%s' not known", sclass);
|
||||
}
|
||||
|
||||
if (flags != 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Flags 0x%" PRIx64 " invalid", flags);
|
||||
|
||||
r = sd_bus_message_new_method_return(msg, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_open_container(reply, 'a', "(ssssbtttttt)");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (ImageClass c = class < 0 ? 0 : class;
|
||||
class < 0 ? (c < _IMAGE_CLASS_MAX) : (c == class);
|
||||
c++) {
|
||||
|
||||
_cleanup_(hashmap_freep) Hashmap *h = NULL;
|
||||
|
||||
h = hashmap_new(&image_hash_ops);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
r = image_discover(c, /* root= */ NULL, h);
|
||||
if (r < 0) {
|
||||
if (class >= 0)
|
||||
return r;
|
||||
|
||||
log_warning_errno(r, "Failed to discover images of type %s: %m", image_class_to_string(c));
|
||||
continue;
|
||||
}
|
||||
|
||||
Image *i;
|
||||
HASHMAP_FOREACH(i, h) {
|
||||
r = sd_bus_message_append(
|
||||
reply,
|
||||
"(ssssbtttttt)",
|
||||
image_class_to_string(i->class),
|
||||
i->name,
|
||||
image_type_to_string(i->type),
|
||||
i->path,
|
||||
i->read_only,
|
||||
i->crtime,
|
||||
i->mtime,
|
||||
i->usage,
|
||||
i->usage_exclusive,
|
||||
i->limit,
|
||||
i->limit_exclusive);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return sd_bus_send(NULL, reply, NULL);
|
||||
}
|
||||
|
||||
static int property_get_progress(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
|
@ -1182,6 +1478,10 @@ static const sd_bus_vtable transfer_vtable[] = {
|
|||
SD_BUS_PARAM(priority)
|
||||
SD_BUS_PARAM(line),
|
||||
0),
|
||||
SD_BUS_SIGNAL_WITH_NAMES("ProgressUpdate",
|
||||
"d",
|
||||
SD_BUS_PARAM(progress),
|
||||
0),
|
||||
|
||||
SD_BUS_VTABLE_END,
|
||||
};
|
||||
|
@ -1207,6 +1507,17 @@ static const sd_bus_vtable manager_vtable[] = {
|
|||
SD_BUS_PARAM(transfer_path),
|
||||
method_import_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ImportTarEx",
|
||||
"hsst",
|
||||
SD_BUS_PARAM(fd)
|
||||
SD_BUS_PARAM(local_name)
|
||||
SD_BUS_PARAM(class)
|
||||
SD_BUS_PARAM(flags),
|
||||
"uo",
|
||||
SD_BUS_PARAM(transfer_id)
|
||||
SD_BUS_PARAM(transfer_path),
|
||||
method_import_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ImportRaw",
|
||||
"hsbb",
|
||||
SD_BUS_PARAM(fd)
|
||||
|
@ -1218,6 +1529,17 @@ static const sd_bus_vtable manager_vtable[] = {
|
|||
SD_BUS_PARAM(transfer_path),
|
||||
method_import_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ImportRawEx",
|
||||
"hsst",
|
||||
SD_BUS_PARAM(fd)
|
||||
SD_BUS_PARAM(local_name)
|
||||
SD_BUS_PARAM(class)
|
||||
SD_BUS_PARAM(flags),
|
||||
"uo",
|
||||
SD_BUS_PARAM(transfer_id)
|
||||
SD_BUS_PARAM(transfer_path),
|
||||
method_import_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ImportFileSystem",
|
||||
"hsbb",
|
||||
SD_BUS_PARAM(fd)
|
||||
|
@ -1229,6 +1551,17 @@ static const sd_bus_vtable manager_vtable[] = {
|
|||
SD_BUS_PARAM(transfer_path),
|
||||
method_import_fs,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ImportFileSystemEx",
|
||||
"hsst",
|
||||
SD_BUS_PARAM(fd)
|
||||
SD_BUS_PARAM(local_name)
|
||||
SD_BUS_PARAM(class)
|
||||
SD_BUS_PARAM(flags),
|
||||
"uo",
|
||||
SD_BUS_PARAM(transfer_id)
|
||||
SD_BUS_PARAM(transfer_path),
|
||||
method_import_fs,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ExportTar",
|
||||
"shs",
|
||||
SD_BUS_PARAM(local_name)
|
||||
|
@ -1239,6 +1572,18 @@ static const sd_bus_vtable manager_vtable[] = {
|
|||
SD_BUS_PARAM(transfer_path),
|
||||
method_export_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ExportTarEx",
|
||||
"sshst",
|
||||
SD_BUS_PARAM(local_name)
|
||||
SD_BUS_PARAM(class)
|
||||
SD_BUS_PARAM(fd)
|
||||
SD_BUS_PARAM(format)
|
||||
SD_BUS_PARAM(flags),
|
||||
"uo",
|
||||
SD_BUS_PARAM(transfer_id)
|
||||
SD_BUS_PARAM(transfer_path),
|
||||
method_export_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ExportRaw",
|
||||
"shs",
|
||||
SD_BUS_PARAM(local_name)
|
||||
|
@ -1249,6 +1594,18 @@ static const sd_bus_vtable manager_vtable[] = {
|
|||
SD_BUS_PARAM(transfer_path),
|
||||
method_export_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ExportRawEx",
|
||||
"sshst",
|
||||
SD_BUS_PARAM(local_name)
|
||||
SD_BUS_PARAM(class)
|
||||
SD_BUS_PARAM(fd)
|
||||
SD_BUS_PARAM(format)
|
||||
SD_BUS_PARAM(flags),
|
||||
"uo",
|
||||
SD_BUS_PARAM(transfer_id)
|
||||
SD_BUS_PARAM(transfer_path),
|
||||
method_export_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("PullTar",
|
||||
"sssb",
|
||||
SD_BUS_PARAM(url)
|
||||
|
@ -1260,6 +1617,18 @@ static const sd_bus_vtable manager_vtable[] = {
|
|||
SD_BUS_PARAM(transfer_path),
|
||||
method_pull_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("PullTarEx",
|
||||
"sssst",
|
||||
SD_BUS_PARAM(url)
|
||||
SD_BUS_PARAM(local_name)
|
||||
SD_BUS_PARAM(class)
|
||||
SD_BUS_PARAM(verify_mode)
|
||||
SD_BUS_PARAM(flags),
|
||||
"uo",
|
||||
SD_BUS_PARAM(transfer_id)
|
||||
SD_BUS_PARAM(transfer_path),
|
||||
method_pull_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("PullRaw",
|
||||
"sssb",
|
||||
SD_BUS_PARAM(url)
|
||||
|
@ -1271,18 +1640,46 @@ static const sd_bus_vtable manager_vtable[] = {
|
|||
SD_BUS_PARAM(transfer_path),
|
||||
method_pull_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("PullRawEx",
|
||||
"sssst",
|
||||
SD_BUS_PARAM(url)
|
||||
SD_BUS_PARAM(local_name)
|
||||
SD_BUS_PARAM(class)
|
||||
SD_BUS_PARAM(verify_mode)
|
||||
SD_BUS_PARAM(flags),
|
||||
"uo",
|
||||
SD_BUS_PARAM(transfer_id)
|
||||
SD_BUS_PARAM(transfer_path),
|
||||
method_pull_tar_or_raw,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ListTransfers",
|
||||
NULL,,
|
||||
"a(usssdo)",
|
||||
SD_BUS_PARAM(transfers),
|
||||
method_list_transfers,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ListTransfersEx",
|
||||
"st",
|
||||
SD_BUS_PARAM(class)
|
||||
SD_BUS_PARAM(flags),
|
||||
"a(ussssdo)",
|
||||
SD_BUS_PARAM(transfers),
|
||||
method_list_transfers,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("CancelTransfer",
|
||||
"u",
|
||||
SD_BUS_PARAM(transfer_id),
|
||||
NULL,,
|
||||
method_cancel_transfer,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD_WITH_NAMES("ListImages",
|
||||
"st",
|
||||
SD_BUS_PARAM(class)
|
||||
SD_BUS_PARAM(flags),
|
||||
"a(ssssbtttttt)",
|
||||
SD_BUS_PARAM(images),
|
||||
method_list_images,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_SIGNAL_WITH_NAMES("TransferNew",
|
||||
"uo",
|
||||
|
@ -1374,7 +1771,7 @@ static int run(int argc, char *argv[]) {
|
|||
|
||||
umask(0022);
|
||||
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, SIGRTMIN+18) >= 0);
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
|
||||
|
||||
r = manager_new(&m);
|
||||
if (r < 0)
|
||||
|
|
|
@ -100,6 +100,12 @@ executables += [
|
|||
'link_with' : common_libs,
|
||||
'dependencies' : common_deps,
|
||||
},
|
||||
executable_template + {
|
||||
'name' : 'importctl',
|
||||
'public' : true,
|
||||
'conditions' : ['ENABLE_IMPORTD'],
|
||||
'sources' : files('importctl.c'),
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files(
|
||||
'test-qcow2.c',
|
||||
|
|
|
@ -42,6 +42,10 @@
|
|||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ListTransfers"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ListTransfersEx"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="CancelTransfer"/>
|
||||
|
@ -50,34 +54,66 @@
|
|||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ImportTar"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ImportTarEx"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ImportRaw"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ImportRawEx"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ImportFileSystem"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ImportFileSystemEx"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ExportTar"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ExportTarEx"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ExportRaw"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="ExportRawEx"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="PullTar"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="PullTarEx"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="PullRaw"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Manager"
|
||||
send_member="PullRawEx"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Transfer"
|
||||
send_member="Cancel"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.import1"
|
||||
send_interface="org.freedesktop.import1.Transfer"
|
||||
send_member="ListImages"/>
|
||||
|
||||
<allow receive_sender="org.freedesktop.import1"/>
|
||||
</policy>
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
<vendor_url>https://systemd.io</vendor_url>
|
||||
|
||||
<action id="org.freedesktop.import1.import">
|
||||
<description gettext-domain="systemd">Import a VM or container image</description>
|
||||
<message gettext-domain="systemd">Authentication is required to import a VM or container image</message>
|
||||
<description gettext-domain="systemd">Import a disk image</description>
|
||||
<message gettext-domain="systemd">Authentication is required to import an image</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
|
@ -29,8 +29,8 @@
|
|||
</action>
|
||||
|
||||
<action id="org.freedesktop.import1.export">
|
||||
<description gettext-domain="systemd">Export a VM or container image</description>
|
||||
<message gettext-domain="systemd">Authentication is required to export a VM or container image</message>
|
||||
<description gettext-domain="systemd">Export a disk image</description>
|
||||
<message gettext-domain="systemd">Authentication is required to export disk image</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
|
@ -39,8 +39,18 @@
|
|||
</action>
|
||||
|
||||
<action id="org.freedesktop.import1.pull">
|
||||
<description gettext-domain="systemd">Download a VM or container image</description>
|
||||
<message gettext-domain="systemd">Authentication is required to download a VM or container image</message>
|
||||
<description gettext-domain="systemd">Download a disk image</description>
|
||||
<message gettext-domain="systemd">Authentication is required to download a disk image</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
<action id="org.freedesktop.import1.cancel">
|
||||
<description gettext-domain="systemd">Cancel transfer of a disk image</description>
|
||||
<message gettext-domain="systemd">Authentication is required to cancel the ongoing transfer of a disk image</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin</allow_any>
|
||||
<allow_inactive>auth_admin</allow_inactive>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "capability-util.h"
|
||||
#include "copy.h"
|
||||
#include "dirent-util.h"
|
||||
#include "discover-image.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "hostname-util.h"
|
||||
|
@ -37,11 +38,9 @@ int pull_find_old_etags(
|
|||
int r;
|
||||
|
||||
assert(url);
|
||||
assert(image_root);
|
||||
assert(etags);
|
||||
|
||||
if (!image_root)
|
||||
image_root = "/var/lib/machines";
|
||||
|
||||
_cleanup_free_ char *escaped_url = xescape(url, FILENAME_ESCAPE);
|
||||
if (!escaped_url)
|
||||
return -ENOMEM;
|
||||
|
@ -128,11 +127,9 @@ int pull_make_path(const char *url, const char *etag, const char *image_root, co
|
|||
char *path;
|
||||
|
||||
assert(url);
|
||||
assert(image_root);
|
||||
assert(ret);
|
||||
|
||||
if (!image_root)
|
||||
image_root = "/var/lib/machines";
|
||||
|
||||
escaped_url = xescape(url, FILENAME_ESCAPE);
|
||||
if (!escaped_url)
|
||||
return -ENOMEM;
|
||||
|
@ -643,12 +640,12 @@ int pull_job_restart_with_sha256sum(PullJob *j, char **ret) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
bool pull_validate_local(const char *name, PullFlags flags) {
|
||||
bool pull_validate_local(const char *name, ImportFlags flags) {
|
||||
|
||||
if (FLAGS_SET(flags, PULL_DIRECT))
|
||||
if (FLAGS_SET(flags, IMPORT_DIRECT))
|
||||
return path_is_valid(name);
|
||||
|
||||
return hostname_is_valid(name, 0);
|
||||
return image_name_is_valid(name);
|
||||
}
|
||||
|
||||
int pull_url_needs_checksum(const char *url) {
|
||||
|
|
|
@ -3,27 +3,10 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "import-common.h"
|
||||
#include "import-util.h"
|
||||
#include "pull-job.h"
|
||||
|
||||
typedef enum PullFlags {
|
||||
PULL_FORCE = 1 << 0, /* replace existing image */
|
||||
PULL_READ_ONLY = 1 << 1, /* make generated image read-only */
|
||||
PULL_SETTINGS = 1 << 2, /* download .nspawn settings file */
|
||||
PULL_ROOTHASH = 1 << 3, /* only for raw: download .roothash file for verity */
|
||||
PULL_ROOTHASH_SIGNATURE = 1 << 4, /* only for raw: download .roothash.p7s file for verity */
|
||||
PULL_VERITY = 1 << 5, /* only for raw: download .verity file for verity */
|
||||
PULL_BTRFS_SUBVOL = 1 << 6, /* tar: preferably create images as btrfs subvols */
|
||||
PULL_BTRFS_QUOTA = 1 << 7, /* tar: set up btrfs quota for new subvolume as child of parent subvolume */
|
||||
PULL_CONVERT_QCOW2 = 1 << 8, /* raw: if we detect a qcow2 image, unpack it */
|
||||
PULL_DIRECT = 1 << 9, /* download without rename games */
|
||||
PULL_SYNC = 1 << 10, /* fsync() right before we are done */
|
||||
|
||||
/* The supported flags for the tar and the raw pulling */
|
||||
PULL_FLAGS_MASK_TAR = PULL_FORCE|PULL_READ_ONLY|PULL_SETTINGS|PULL_BTRFS_SUBVOL|PULL_BTRFS_QUOTA|PULL_DIRECT|PULL_SYNC,
|
||||
PULL_FLAGS_MASK_RAW = PULL_FORCE|PULL_READ_ONLY|PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY|PULL_CONVERT_QCOW2|PULL_DIRECT|PULL_SYNC,
|
||||
} PullFlags;
|
||||
|
||||
int pull_find_old_etags(const char *url, const char *root, int dt, const char *prefix, const char *suffix, char ***etags);
|
||||
|
||||
int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret);
|
||||
|
@ -44,6 +27,6 @@ int verification_style_from_url(const char *url, VerificationStyle *style);
|
|||
|
||||
int pull_job_restart_with_sha256sum(PullJob *job, char **ret);
|
||||
|
||||
bool pull_validate_local(const char *name, PullFlags flags);
|
||||
bool pull_validate_local(const char *name, ImportFlags flags);
|
||||
|
||||
int pull_url_needs_checksum(const char *url);
|
||||
|
|
|
@ -187,7 +187,7 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) {
|
|||
}
|
||||
}
|
||||
|
||||
r = log_error_errno(
|
||||
r = log_notice_errno(
|
||||
status == 404 ? SYNTHETIC_ERRNO(ENOMEDIUM) : SYNTHETIC_ERRNO(EIO), /* Make the most common error recognizable */
|
||||
"HTTP request to %s failed with code %li.", j->url, status);
|
||||
goto finish;
|
||||
|
|
|
@ -42,7 +42,7 @@ struct RawPull {
|
|||
sd_event *event;
|
||||
CurlGlue *glue;
|
||||
|
||||
PullFlags flags;
|
||||
ImportFlags flags;
|
||||
ImportVerify verify;
|
||||
char *image_root;
|
||||
|
||||
|
@ -60,7 +60,7 @@ struct RawPull {
|
|||
void *userdata;
|
||||
|
||||
char *local; /* In PULL_DIRECT mode the path we are supposed to place things in, otherwise the
|
||||
* machine name of the final copy we make */
|
||||
* image name of the final copy we make */
|
||||
|
||||
char *final_path;
|
||||
char *temp_path;
|
||||
|
@ -127,8 +127,9 @@ int raw_pull_new(
|
|||
int r;
|
||||
|
||||
assert(ret);
|
||||
assert(image_root);
|
||||
|
||||
root = strdup(image_root ?: "/var/lib/machines");
|
||||
root = strdup(image_root);
|
||||
if (!root)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -244,9 +245,9 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) {
|
|||
|
||||
assert(i);
|
||||
assert(i->raw_job);
|
||||
assert(!FLAGS_SET(i->flags, PULL_DIRECT));
|
||||
assert(!FLAGS_SET(i->flags, IMPORT_DIRECT));
|
||||
|
||||
if (!FLAGS_SET(i->flags, PULL_CONVERT_QCOW2))
|
||||
if (!FLAGS_SET(i->flags, IMPORT_CONVERT_QCOW2))
|
||||
return 0;
|
||||
|
||||
assert(i->final_path);
|
||||
|
@ -310,7 +311,7 @@ static int raw_pull_copy_auxiliary_file(
|
|||
const char *suffix,
|
||||
char **path /* input + output (!) */) {
|
||||
|
||||
const char *local;
|
||||
_cleanup_free_ char *local = NULL;
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
|
@ -321,21 +322,29 @@ static int raw_pull_copy_auxiliary_file(
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
local = strjoina(i->image_root, "/", i->local, suffix);
|
||||
local = strjoin(i->image_root, "/", i->local, suffix);
|
||||
if (!local)
|
||||
return log_oom();
|
||||
|
||||
if (FLAGS_SET(i->flags, IMPORT_PULL_KEEP_DOWNLOAD))
|
||||
r = copy_file_atomic(
|
||||
*path,
|
||||
local,
|
||||
0644,
|
||||
COPY_REFLINK |
|
||||
(FLAGS_SET(i->flags, PULL_FORCE) ? COPY_REPLACE : 0) |
|
||||
(FLAGS_SET(i->flags, PULL_SYNC) ? COPY_FSYNC_FULL : 0));
|
||||
(FLAGS_SET(i->flags, IMPORT_FORCE) ? COPY_REPLACE : 0) |
|
||||
(FLAGS_SET(i->flags, IMPORT_SYNC) ? COPY_FSYNC_FULL : 0));
|
||||
else
|
||||
r = install_file(AT_FDCWD, *path,
|
||||
AT_FDCWD, local,
|
||||
(i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
|
||||
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
|
||||
if (r == -EEXIST)
|
||||
log_warning_errno(r, "File %s already exists, not replacing.", local);
|
||||
else if (r == -ENOENT)
|
||||
log_debug_errno(r, "Skipping creation of auxiliary file, since none was found.");
|
||||
else if (r < 0)
|
||||
log_warning_errno(r, "Failed to copy file %s, ignoring: %m", local);
|
||||
log_warning_errno(r, "Failed to install file %s, ignoring: %m", local);
|
||||
else
|
||||
log_info("Created new file %s.", local);
|
||||
|
||||
|
@ -344,14 +353,12 @@ static int raw_pull_copy_auxiliary_file(
|
|||
|
||||
static int raw_pull_make_local_copy(RawPull *i) {
|
||||
_cleanup_(unlink_and_freep) char *tp = NULL;
|
||||
_cleanup_free_ char *f = NULL;
|
||||
_cleanup_close_ int dfd = -EBADF;
|
||||
const char *p;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
assert(i->raw_job);
|
||||
assert(!FLAGS_SET(i->flags, PULL_DIRECT));
|
||||
assert(!FLAGS_SET(i->flags, IMPORT_DIRECT));
|
||||
|
||||
if (!i->local)
|
||||
return 0;
|
||||
|
@ -374,7 +381,14 @@ static int raw_pull_make_local_copy(RawPull *i) {
|
|||
return log_error_errno(errno, "Failed to seek to beginning of vendor image: %m");
|
||||
}
|
||||
|
||||
p = strjoina(i->image_root, "/", i->local, ".raw");
|
||||
p = strjoin(i->image_root, "/", i->local, ".raw");
|
||||
if (!p)
|
||||
return log_oom();
|
||||
|
||||
const char *source;
|
||||
if (FLAGS_SET(i->flags, IMPORT_PULL_KEEP_DOWNLOAD)) {
|
||||
_cleanup_close_ int dfd = -EBADF;
|
||||
_cleanup_free_ char *f = NULL;
|
||||
|
||||
r = tempfn_random(p, NULL, &f);
|
||||
if (r < 0)
|
||||
|
@ -399,37 +413,41 @@ static int raw_pull_make_local_copy(RawPull *i) {
|
|||
|
||||
dfd = safe_close(dfd);
|
||||
|
||||
r = install_file(AT_FDCWD, tp,
|
||||
source = tp;
|
||||
} else
|
||||
source = i->final_path;
|
||||
|
||||
r = install_file(AT_FDCWD, source,
|
||||
AT_FDCWD, p,
|
||||
(i->flags & PULL_FORCE ? INSTALL_REPLACE : 0) |
|
||||
(i->flags & PULL_READ_ONLY ? INSTALL_READ_ONLY : 0) |
|
||||
(i->flags & PULL_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||
(i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
|
||||
(i->flags & IMPORT_READ_ONLY ? INSTALL_READ_ONLY : 0) |
|
||||
(i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||
if (r < 0)
|
||||
return log_error_errno(errno, "Failed to move local image into place '%s': %m", p);
|
||||
return log_error_errno(r, "Failed to move local image into place '%s': %m", p);
|
||||
|
||||
tp = mfree(tp);
|
||||
|
||||
log_info("Created new local image '%s'.", i->local);
|
||||
|
||||
if (FLAGS_SET(i->flags, PULL_SETTINGS)) {
|
||||
if (FLAGS_SET(i->flags, IMPORT_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 (FLAGS_SET(i->flags, IMPORT_PULL_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)) {
|
||||
if (FLAGS_SET(i->flags, IMPORT_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)) {
|
||||
if (FLAGS_SET(i->flags, IMPORT_PULL_VERITY)) {
|
||||
r = raw_pull_copy_auxiliary_file(i, ".verity", &i->verity_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -485,7 +503,7 @@ static int raw_pull_rename_auxiliary_file(
|
|||
AT_FDCWD, *temp_path,
|
||||
AT_FDCWD, *path,
|
||||
INSTALL_READ_ONLY|
|
||||
(i->flags & PULL_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||
(i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to move '%s' into place: %m", *path);
|
||||
|
||||
|
@ -588,7 +606,7 @@ static void raw_pull_job_on_finished(PullJob *j) {
|
|||
goto finish;
|
||||
}
|
||||
|
||||
if (i->flags & PULL_DIRECT) {
|
||||
if (i->flags & IMPORT_DIRECT) {
|
||||
assert(!i->settings_job);
|
||||
assert(!i->roothash_job);
|
||||
assert(!i->roothash_signature_job);
|
||||
|
@ -599,8 +617,8 @@ static void raw_pull_job_on_finished(PullJob *j) {
|
|||
if (i->local) {
|
||||
r = install_file(AT_FDCWD, i->local,
|
||||
AT_FDCWD, NULL,
|
||||
((i->flags & PULL_READ_ONLY) && i->offset == UINT64_MAX ? INSTALL_READ_ONLY : 0) |
|
||||
(i->flags & PULL_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||
((i->flags & IMPORT_READ_ONLY) && i->offset == UINT64_MAX ? INSTALL_READ_ONLY : 0) |
|
||||
(i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to finalize raw file to '%s': %m", i->local);
|
||||
goto finish;
|
||||
|
@ -627,8 +645,8 @@ static void raw_pull_job_on_finished(PullJob *j) {
|
|||
|
||||
r = install_file(AT_FDCWD, i->temp_path,
|
||||
AT_FDCWD, i->final_path,
|
||||
INSTALL_READ_ONLY|
|
||||
(i->flags & PULL_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||
(i->flags & IMPORT_PULL_KEEP_DOWNLOAD ? INSTALL_READ_ONLY : 0) |
|
||||
(i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to move raw file to '%s': %m", i->final_path);
|
||||
goto finish;
|
||||
|
@ -694,7 +712,7 @@ static int raw_pull_job_on_open_disk_generic(
|
|||
assert(extra);
|
||||
assert(temp_path);
|
||||
|
||||
assert(!FLAGS_SET(i->flags, PULL_DIRECT));
|
||||
assert(!FLAGS_SET(i->flags, IMPORT_DIRECT));
|
||||
|
||||
if (!*temp_path) {
|
||||
r = tempfn_random_child(i->image_root, extra, temp_path);
|
||||
|
@ -722,7 +740,7 @@ static int raw_pull_job_on_open_disk_raw(PullJob *j) {
|
|||
assert(i->raw_job == j);
|
||||
assert(j->disk_fd < 0);
|
||||
|
||||
if (i->flags & PULL_DIRECT) {
|
||||
if (i->flags & IMPORT_DIRECT) {
|
||||
|
||||
if (!i->local) { /* If no local name specified, the pull job will write its data to stdout */
|
||||
j->disk_fd = STDOUT_FILENO;
|
||||
|
@ -816,7 +834,7 @@ int raw_pull_start(
|
|||
const char *local,
|
||||
uint64_t offset,
|
||||
uint64_t size_max,
|
||||
PullFlags flags,
|
||||
ImportFlags flags,
|
||||
ImportVerify verify,
|
||||
const char *checksum) {
|
||||
|
||||
|
@ -827,10 +845,10 @@ int raw_pull_start(
|
|||
assert(verify == _IMPORT_VERIFY_INVALID || verify < _IMPORT_VERIFY_MAX);
|
||||
assert(verify == _IMPORT_VERIFY_INVALID || verify >= 0);
|
||||
assert((verify < 0) || !checksum);
|
||||
assert(!(flags & ~PULL_FLAGS_MASK_RAW));
|
||||
assert(offset == UINT64_MAX || FLAGS_SET(flags, PULL_DIRECT));
|
||||
assert(!(flags & (PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY)) || !(flags & PULL_DIRECT));
|
||||
assert(!(flags & (PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY)) || !checksum);
|
||||
assert(!(flags & ~IMPORT_PULL_FLAGS_MASK_RAW));
|
||||
assert(offset == UINT64_MAX || FLAGS_SET(flags, IMPORT_DIRECT));
|
||||
assert(!(flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) || !(flags & IMPORT_DIRECT));
|
||||
assert(!(flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) || !checksum);
|
||||
|
||||
if (!http_url_is_valid(url) && !file_url_is_valid(url))
|
||||
return -EINVAL;
|
||||
|
@ -880,7 +898,7 @@ int raw_pull_start(
|
|||
if (offset != UINT64_MAX)
|
||||
i->raw_job->offset = i->offset = offset;
|
||||
|
||||
if (!FLAGS_SET(flags, PULL_DIRECT)) {
|
||||
if (!FLAGS_SET(flags, IMPORT_DIRECT)) {
|
||||
r = pull_find_old_etags(url, i->image_root, DT_REG, ".raw-", ".raw", &i->raw_job->old_etags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -898,7 +916,7 @@ int raw_pull_start(
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (FLAGS_SET(flags, PULL_SETTINGS)) {
|
||||
if (FLAGS_SET(flags, IMPORT_PULL_SETTINGS)) {
|
||||
r = pull_make_auxiliary_job(
|
||||
&i->settings_job,
|
||||
url,
|
||||
|
@ -913,7 +931,7 @@ int raw_pull_start(
|
|||
return r;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(flags, PULL_ROOTHASH)) {
|
||||
if (FLAGS_SET(flags, IMPORT_PULL_ROOTHASH)) {
|
||||
r = pull_make_auxiliary_job(
|
||||
&i->roothash_job,
|
||||
url,
|
||||
|
@ -928,7 +946,7 @@ int raw_pull_start(
|
|||
return r;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(flags, PULL_ROOTHASH_SIGNATURE)) {
|
||||
if (FLAGS_SET(flags, IMPORT_PULL_ROOTHASH_SIGNATURE)) {
|
||||
r = pull_make_auxiliary_job(
|
||||
&i->roothash_signature_job,
|
||||
url,
|
||||
|
@ -943,7 +961,7 @@ int raw_pull_start(
|
|||
return r;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(flags, PULL_VERITY)) {
|
||||
if (FLAGS_SET(flags, IMPORT_PULL_VERITY)) {
|
||||
r = pull_make_auxiliary_job(
|
||||
&i->verity_job,
|
||||
url,
|
||||
|
@ -972,7 +990,7 @@ int raw_pull_start(
|
|||
continue;
|
||||
|
||||
j->on_progress = raw_pull_job_on_progress;
|
||||
j->sync = FLAGS_SET(flags, PULL_SYNC);
|
||||
j->sync = FLAGS_SET(flags, IMPORT_SYNC);
|
||||
|
||||
r = pull_job_begin(j);
|
||||
if (r < 0)
|
||||
|
|
|
@ -16,4 +16,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, uint64_t offset, uint64_t size_max, PullFlags flags, ImportVerify verify, const char *checksum);
|
||||
int raw_pull_start(RawPull *pull, const char *url, const char *local, uint64_t offset, uint64_t size_max, ImportFlags flags, ImportVerify verify, const char *checksum);
|
||||
|
|
|
@ -41,7 +41,7 @@ struct TarPull {
|
|||
sd_event *event;
|
||||
CurlGlue *glue;
|
||||
|
||||
PullFlags flags;
|
||||
ImportFlags flags;
|
||||
ImportVerify verify;
|
||||
char *image_root;
|
||||
|
||||
|
@ -106,9 +106,10 @@ int tar_pull_new(
|
|||
_cleanup_free_ char *root = NULL;
|
||||
int r;
|
||||
|
||||
assert(image_root);
|
||||
assert(ret);
|
||||
|
||||
root = strdup(image_root ?: "/var/lib/machines");
|
||||
root = strdup(image_root);
|
||||
if (!root)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -219,7 +220,8 @@ static int tar_pull_determine_path(
|
|||
|
||||
static int tar_pull_make_local_copy(TarPull *i) {
|
||||
_cleanup_(rm_rf_subvolume_and_freep) char *t = NULL;
|
||||
const char *p;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
const char *source;
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
|
@ -230,17 +232,20 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
|||
|
||||
assert(i->final_path);
|
||||
|
||||
p = prefix_roota(i->image_root, i->local);
|
||||
p = path_join(i->image_root, i->local);
|
||||
if (!p)
|
||||
return log_oom();
|
||||
|
||||
if (FLAGS_SET(i->flags, IMPORT_PULL_KEEP_DOWNLOAD)) {
|
||||
r = tempfn_random(p, NULL, &t);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate temporary filename for %s: %m", p);
|
||||
|
||||
if (i->flags & PULL_BTRFS_SUBVOL)
|
||||
if (i->flags & IMPORT_BTRFS_SUBVOL)
|
||||
r = btrfs_subvol_snapshot_at(
|
||||
AT_FDCWD, i->final_path,
|
||||
AT_FDCWD, t,
|
||||
(i->flags & PULL_BTRFS_QUOTA ? BTRFS_SNAPSHOT_QUOTA : 0)|
|
||||
(i->flags & IMPORT_BTRFS_QUOTA ? BTRFS_SNAPSHOT_QUOTA : 0)|
|
||||
BTRFS_SNAPSHOT_FALLBACK_COPY|
|
||||
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
|
||||
BTRFS_SNAPSHOT_RECURSIVE);
|
||||
|
@ -249,11 +254,15 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
|||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create local image: %m");
|
||||
|
||||
r = install_file(AT_FDCWD, t,
|
||||
source = t;
|
||||
} else
|
||||
source = i->final_path;
|
||||
|
||||
r = install_file(AT_FDCWD, source,
|
||||
AT_FDCWD, p,
|
||||
(i->flags & PULL_FORCE ? INSTALL_REPLACE : 0) |
|
||||
(i->flags & PULL_READ_ONLY ? INSTALL_READ_ONLY : 0) |
|
||||
(i->flags & PULL_SYNC ? INSTALL_SYNCFS : 0));
|
||||
(i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
|
||||
(i->flags & IMPORT_READ_ONLY ? INSTALL_READ_ONLY : 0) |
|
||||
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to install local image '%s': %m", p);
|
||||
|
||||
|
@ -261,29 +270,37 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
|||
|
||||
log_info("Created new local image '%s'.", i->local);
|
||||
|
||||
if (FLAGS_SET(i->flags, PULL_SETTINGS)) {
|
||||
const char *local_settings;
|
||||
if (FLAGS_SET(i->flags, IMPORT_PULL_SETTINGS)) {
|
||||
_cleanup_free_ char *local_settings = NULL;
|
||||
assert(i->settings_job);
|
||||
|
||||
r = tar_pull_determine_path(i, ".nspawn", &i->settings_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
local_settings = strjoina(i->image_root, "/", i->local, ".nspawn");
|
||||
local_settings = strjoin(i->image_root, "/", i->local, ".nspawn");
|
||||
if (!local_settings)
|
||||
return log_oom();
|
||||
|
||||
if (FLAGS_SET(i->flags, IMPORT_PULL_KEEP_DOWNLOAD))
|
||||
r = copy_file_atomic(
|
||||
i->settings_path,
|
||||
local_settings,
|
||||
0664,
|
||||
COPY_REFLINK |
|
||||
(FLAGS_SET(i->flags, PULL_FORCE) ? COPY_REPLACE : 0) |
|
||||
(FLAGS_SET(i->flags, PULL_SYNC) ? COPY_FSYNC_FULL : 0));
|
||||
(FLAGS_SET(i->flags, IMPORT_FORCE) ? COPY_REPLACE : 0) |
|
||||
(FLAGS_SET(i->flags, IMPORT_SYNC) ? COPY_FSYNC_FULL : 0));
|
||||
else
|
||||
r = install_file(AT_FDCWD, i->settings_path,
|
||||
AT_FDCWD, local_settings,
|
||||
(i->flags & IMPORT_FORCE ? INSTALL_REPLACE : 0) |
|
||||
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
|
||||
if (r == -EEXIST)
|
||||
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
|
||||
else if (r == -ENOENT)
|
||||
log_debug_errno(r, "Skipping creation of settings file, since none was found.");
|
||||
else if (r < 0)
|
||||
log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
|
||||
log_warning_errno(r, "Failed to install settings files %s, ignoring: %m", local_settings);
|
||||
else
|
||||
log_info("Created new settings file %s.", local_settings);
|
||||
}
|
||||
|
@ -392,7 +409,7 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
|||
goto finish;
|
||||
}
|
||||
|
||||
if (i->flags & PULL_DIRECT) {
|
||||
if (i->flags & IMPORT_DIRECT) {
|
||||
assert(!i->settings_job);
|
||||
assert(i->local);
|
||||
assert(!i->temp_path);
|
||||
|
@ -406,8 +423,8 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
|||
r = install_file(
|
||||
AT_FDCWD, i->local,
|
||||
AT_FDCWD, NULL,
|
||||
(i->flags & PULL_READ_ONLY) ? INSTALL_READ_ONLY : 0 |
|
||||
(i->flags & PULL_SYNC ? INSTALL_SYNCFS : 0));
|
||||
(i->flags & IMPORT_READ_ONLY) ? INSTALL_READ_ONLY : 0 |
|
||||
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to finalize '%s': %m", i->local);
|
||||
goto finish;
|
||||
|
@ -432,8 +449,8 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
|||
r = install_file(
|
||||
AT_FDCWD, i->temp_path,
|
||||
AT_FDCWD, i->final_path,
|
||||
INSTALL_READ_ONLY|
|
||||
(i->flags & PULL_SYNC ? INSTALL_SYNCFS : 0));
|
||||
(i->flags & IMPORT_PULL_KEEP_DOWNLOAD ? INSTALL_READ_ONLY : 0) |
|
||||
(i->flags & IMPORT_SYNC ? INSTALL_SYNCFS : 0));
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to rename to final image name to %s: %m", i->final_path);
|
||||
goto finish;
|
||||
|
@ -460,7 +477,7 @@ static void tar_pull_job_on_finished(PullJob *j) {
|
|||
AT_FDCWD, i->settings_temp_path,
|
||||
AT_FDCWD, i->settings_path,
|
||||
INSTALL_READ_ONLY|
|
||||
(i->flags & PULL_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||
(i->flags & IMPORT_SYNC ? INSTALL_FSYNC_FULL : 0));
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to rename settings file to %s: %m", i->settings_path);
|
||||
goto finish;
|
||||
|
@ -498,7 +515,7 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
|
|||
assert(i->tar_job == j);
|
||||
assert(i->tar_pid <= 0);
|
||||
|
||||
if (i->flags & PULL_DIRECT)
|
||||
if (i->flags & IMPORT_DIRECT)
|
||||
where = i->local;
|
||||
else {
|
||||
if (!i->temp_path) {
|
||||
|
@ -512,20 +529,20 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
|
|||
|
||||
(void) mkdir_parents_label(where, 0700);
|
||||
|
||||
if (FLAGS_SET(i->flags, PULL_DIRECT|PULL_FORCE))
|
||||
if (FLAGS_SET(i->flags, IMPORT_DIRECT|IMPORT_FORCE))
|
||||
(void) rm_rf(where, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
|
||||
|
||||
if (i->flags & PULL_BTRFS_SUBVOL)
|
||||
if (i->flags & IMPORT_BTRFS_SUBVOL)
|
||||
r = btrfs_subvol_make_fallback(AT_FDCWD, where, 0755);
|
||||
else
|
||||
r = RET_NERRNO(mkdir(where, 0755));
|
||||
if (r == -EEXIST && (i->flags & PULL_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
|
||||
if (r == -EEXIST && (i->flags & IMPORT_DIRECT)) /* EEXIST is OK if in direct mode, but not otherwise,
|
||||
* because in that case our temporary path collided */
|
||||
r = 0;
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create directory/subvolume %s: %m", where);
|
||||
if (r > 0 && (i->flags & PULL_BTRFS_QUOTA)) { /* actually btrfs subvol */
|
||||
if (!(i->flags & PULL_DIRECT))
|
||||
if (r > 0 && (i->flags & IMPORT_BTRFS_QUOTA)) { /* actually btrfs subvol */
|
||||
if (!(i->flags & IMPORT_DIRECT))
|
||||
(void) import_assign_pool_quota_and_warn(i->image_root);
|
||||
(void) import_assign_pool_quota_and_warn(where);
|
||||
}
|
||||
|
@ -577,7 +594,7 @@ int tar_pull_start(
|
|||
TarPull *i,
|
||||
const char *url,
|
||||
const char *local,
|
||||
PullFlags flags,
|
||||
ImportFlags flags,
|
||||
ImportVerify verify,
|
||||
const char *checksum) {
|
||||
|
||||
|
@ -587,9 +604,9 @@ int tar_pull_start(
|
|||
assert(verify == _IMPORT_VERIFY_INVALID || verify < _IMPORT_VERIFY_MAX);
|
||||
assert(verify == _IMPORT_VERIFY_INVALID || verify >= 0);
|
||||
assert((verify < 0) || !checksum);
|
||||
assert(!(flags & ~PULL_FLAGS_MASK_TAR));
|
||||
assert(!(flags & PULL_SETTINGS) || !(flags & PULL_DIRECT));
|
||||
assert(!(flags & PULL_SETTINGS) || !checksum);
|
||||
assert(!(flags & ~IMPORT_PULL_FLAGS_MASK_TAR));
|
||||
assert(!(flags & IMPORT_PULL_SETTINGS) || !(flags & IMPORT_DIRECT));
|
||||
assert(!(flags & IMPORT_PULL_SETTINGS) || !checksum);
|
||||
|
||||
if (!http_url_is_valid(url) && !file_url_is_valid(url))
|
||||
return -EINVAL;
|
||||
|
@ -620,7 +637,7 @@ int tar_pull_start(
|
|||
i->tar_job->on_open_disk = tar_pull_job_on_open_disk_tar;
|
||||
i->tar_job->calc_checksum = checksum || IN_SET(verify, IMPORT_VERIFY_CHECKSUM, IMPORT_VERIFY_SIGNATURE);
|
||||
|
||||
if (!FLAGS_SET(flags, PULL_DIRECT)) {
|
||||
if (!FLAGS_SET(flags, IMPORT_DIRECT)) {
|
||||
r = pull_find_old_etags(url, i->image_root, DT_DIR, ".tar-", NULL, &i->tar_job->old_etags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -640,7 +657,7 @@ int tar_pull_start(
|
|||
return r;
|
||||
|
||||
/* Set up download job for the settings file (.nspawn) */
|
||||
if (FLAGS_SET(flags, PULL_SETTINGS)) {
|
||||
if (FLAGS_SET(flags, IMPORT_PULL_SETTINGS)) {
|
||||
r = pull_make_auxiliary_job(
|
||||
&i->settings_job,
|
||||
url,
|
||||
|
@ -666,7 +683,7 @@ int tar_pull_start(
|
|||
continue;
|
||||
|
||||
j->on_progress = tar_pull_job_on_progress;
|
||||
j->sync = FLAGS_SET(flags, PULL_SYNC);
|
||||
j->sync = FLAGS_SET(flags, IMPORT_SYNC);
|
||||
|
||||
r = pull_job_begin(j);
|
||||
if (r < 0)
|
||||
|
|
|
@ -16,4 +16,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, const char *checksum);
|
||||
int tar_pull_start(TarPull *pull, const char *url, const char *local, ImportFlags flags, ImportVerify verify, const char *checksum);
|
||||
|
|
|
@ -26,11 +26,12 @@
|
|||
#include "verbs.h"
|
||||
#include "web-util.h"
|
||||
|
||||
static const char *arg_image_root = "/var/lib/machines";
|
||||
static const char *arg_image_root = NULL;
|
||||
static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
|
||||
static PullFlags arg_pull_flags = PULL_SETTINGS | PULL_ROOTHASH | PULL_ROOTHASH_SIGNATURE | PULL_VERITY | PULL_BTRFS_SUBVOL | PULL_BTRFS_QUOTA | PULL_CONVERT_QCOW2 | PULL_SYNC;
|
||||
static ImportFlags arg_import_flags = IMPORT_PULL_SETTINGS | IMPORT_PULL_ROOTHASH | IMPORT_PULL_ROOTHASH_SIGNATURE | IMPORT_PULL_VERITY | IMPORT_BTRFS_SUBVOL | IMPORT_BTRFS_QUOTA | IMPORT_CONVERT_QCOW2 | IMPORT_SYNC;
|
||||
static uint64_t arg_offset = UINT64_MAX, arg_size_max = UINT64_MAX;
|
||||
static char *arg_checksum = NULL;
|
||||
static ImageClass arg_class = IMAGE_MACHINE;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_checksum, freep);
|
||||
|
||||
|
@ -38,7 +39,7 @@ static int normalize_local(const char *local, const char *url, char **ret) {
|
|||
_cleanup_free_ char *ll = NULL;
|
||||
int r;
|
||||
|
||||
if (arg_pull_flags & PULL_DIRECT) {
|
||||
if (arg_import_flags & IMPORT_DIRECT) {
|
||||
|
||||
if (!local)
|
||||
log_debug("Writing downloaded data to STDOUT.");
|
||||
|
@ -58,13 +59,13 @@ static int normalize_local(const char *local, const char *url, char **ret) {
|
|||
|
||||
} else if (local) {
|
||||
|
||||
if (!hostname_is_valid(local, 0))
|
||||
if (!image_name_is_valid(local))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"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 (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) {
|
||||
r = image_find(arg_class, local, NULL, NULL);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
|
||||
|
@ -89,6 +90,12 @@ static int normalize_local(const char *local, const char *url, char **ret) {
|
|||
} else
|
||||
log_info("Pulling '%s'.", url);
|
||||
|
||||
if (!FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
|
||||
log_info("Operating on image directory '%s'.", arg_image_root);
|
||||
|
||||
if (!FLAGS_SET(arg_import_flags, IMPORT_SYNC))
|
||||
log_info("File system synchronization on completion is off.");
|
||||
|
||||
*ret = TAKE_PTR(ll);
|
||||
return 0;
|
||||
}
|
||||
|
@ -130,7 +137,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
|
|||
local = ll;
|
||||
}
|
||||
|
||||
if (!local && FLAGS_SET(arg_pull_flags, PULL_DIRECT))
|
||||
if (!local && FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Pulling tar images to STDOUT is not supported.");
|
||||
|
||||
r = normalize_local(local, url, &normalized);
|
||||
|
@ -141,9 +148,6 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!FLAGS_SET(arg_pull_flags, PULL_SYNC))
|
||||
log_info("File system synchronization on completion is off.");
|
||||
|
||||
r = tar_pull_new(&pull, event, arg_image_root, on_tar_finished, event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate puller: %m");
|
||||
|
@ -152,7 +156,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
|
|||
pull,
|
||||
url,
|
||||
normalized,
|
||||
arg_pull_flags & PULL_FLAGS_MASK_TAR,
|
||||
arg_import_flags & IMPORT_PULL_FLAGS_MASK_TAR,
|
||||
arg_verify,
|
||||
arg_checksum);
|
||||
if (r < 0)
|
||||
|
@ -211,8 +215,6 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!FLAGS_SET(arg_pull_flags, PULL_SYNC))
|
||||
log_info("File system synchronization on completion is off.");
|
||||
r = raw_pull_new(&pull, event, arg_image_root, on_raw_finished, event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to allocate puller: %m");
|
||||
|
@ -223,7 +225,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
|
|||
normalized,
|
||||
arg_offset,
|
||||
arg_size_max,
|
||||
arg_pull_flags & PULL_FLAGS_MASK_RAW,
|
||||
arg_import_flags & IMPORT_PULL_FLAGS_MASK_RAW,
|
||||
arg_verify,
|
||||
arg_checksum);
|
||||
if (r < 0)
|
||||
|
@ -240,7 +242,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
|
|||
static int help(int argc, char *argv[], void *userdata) {
|
||||
|
||||
printf("%1$s [OPTIONS...] {COMMAND} ...\n"
|
||||
"\n%4$sDownload container or virtual machine images.%5$s\n"
|
||||
"\n%4$sDownload disk images.%5$s\n"
|
||||
"\n%2$sCommands:%3$s\n"
|
||||
" tar URL [NAME] Download a TAR image\n"
|
||||
" raw URL [NAME] Download a RAW image\n"
|
||||
|
@ -255,7 +257,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" --roothash-signature=BOOL\n"
|
||||
" Download root hash signature file with image\n"
|
||||
" --verity=BOOL Download verity file with image\n"
|
||||
" --image-root=PATH Image root directory\n\n"
|
||||
" --image-root=PATH Image root directory\n"
|
||||
" --read-only Create a read-only image\n"
|
||||
" --direct Download directly to specified file\n"
|
||||
" --btrfs-subvol=BOOL Controls whether to create a btrfs subvolume\n"
|
||||
|
@ -266,7 +268,11 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" regular disk images\n"
|
||||
" --sync=BOOL Controls whether to sync() before completing\n"
|
||||
" --offset=BYTES Offset to seek to in destination\n"
|
||||
" --size-max=BYTES Maximum number of bytes to write to destination\n",
|
||||
" --size-max=BYTES Maximum number of bytes to write to destination\n"
|
||||
" --class=CLASS Select image class (machine, sysext, confext,\n"
|
||||
" portable)\n"
|
||||
" --keep-download=BOOL Keep a copy pristine copy of the downloaded file\n"
|
||||
" around\n",
|
||||
program_invocation_short_name,
|
||||
ansi_underline(),
|
||||
ansi_normal(),
|
||||
|
@ -295,6 +301,8 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
ARG_SYNC,
|
||||
ARG_OFFSET,
|
||||
ARG_SIZE_MAX,
|
||||
ARG_CLASS,
|
||||
ARG_KEEP_DOWNLOAD,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
|
@ -315,10 +323,13 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
{ "sync", required_argument, NULL, ARG_SYNC },
|
||||
{ "offset", required_argument, NULL, ARG_OFFSET },
|
||||
{ "size-max", required_argument, NULL, ARG_SIZE_MAX },
|
||||
{ "class", required_argument, NULL, ARG_CLASS },
|
||||
{ "keep-download", required_argument, NULL, ARG_KEEP_DOWNLOAD },
|
||||
{}
|
||||
};
|
||||
|
||||
int c, r;
|
||||
bool auto_settings = true, auto_keep_download = true;
|
||||
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
@ -334,7 +345,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
return version();
|
||||
|
||||
case ARG_FORCE:
|
||||
arg_pull_flags |= PULL_FORCE;
|
||||
arg_import_flags |= IMPORT_FORCE;
|
||||
break;
|
||||
|
||||
case ARG_IMAGE_ROOT:
|
||||
|
@ -366,7 +377,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
return log_oom();
|
||||
|
||||
free_and_replace(arg_checksum, hh);
|
||||
arg_pull_flags &= ~(PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY);
|
||||
arg_import_flags &= ~(IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY);
|
||||
arg_verify = _IMPORT_VERIFY_INVALID;
|
||||
} else
|
||||
arg_verify = v;
|
||||
|
@ -379,7 +390,8 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FLAG(arg_pull_flags, PULL_SETTINGS, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_PULL_SETTINGS, r);
|
||||
auto_settings = false;
|
||||
break;
|
||||
|
||||
case ARG_ROOTHASH:
|
||||
|
@ -387,11 +399,11 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FLAG(arg_pull_flags, PULL_ROOTHASH, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_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);
|
||||
SET_FLAG(arg_import_flags, IMPORT_PULL_ROOTHASH_SIGNATURE, false);
|
||||
break;
|
||||
|
||||
case ARG_ROOTHASH_SIGNATURE:
|
||||
|
@ -399,7 +411,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FLAG(arg_pull_flags, PULL_ROOTHASH_SIGNATURE, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_PULL_ROOTHASH_SIGNATURE, r);
|
||||
break;
|
||||
|
||||
case ARG_VERITY:
|
||||
|
@ -407,16 +419,16 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FLAG(arg_pull_flags, PULL_VERITY, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_PULL_VERITY, r);
|
||||
break;
|
||||
|
||||
case ARG_READ_ONLY:
|
||||
arg_pull_flags |= PULL_READ_ONLY;
|
||||
arg_import_flags |= IMPORT_READ_ONLY;
|
||||
break;
|
||||
|
||||
case ARG_DIRECT:
|
||||
arg_pull_flags |= PULL_DIRECT;
|
||||
arg_pull_flags &= ~(PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY);
|
||||
arg_import_flags |= IMPORT_DIRECT;
|
||||
arg_import_flags &= ~(IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY);
|
||||
break;
|
||||
|
||||
case ARG_BTRFS_SUBVOL:
|
||||
|
@ -424,7 +436,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FLAG(arg_pull_flags, PULL_BTRFS_SUBVOL, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_BTRFS_SUBVOL, r);
|
||||
break;
|
||||
|
||||
case ARG_BTRFS_QUOTA:
|
||||
|
@ -432,7 +444,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FLAG(arg_pull_flags, PULL_BTRFS_QUOTA, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_BTRFS_QUOTA, r);
|
||||
break;
|
||||
|
||||
case ARG_CONVERT_QCOW2:
|
||||
|
@ -440,7 +452,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FLAG(arg_pull_flags, PULL_CONVERT_QCOW2, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_CONVERT_QCOW2, r);
|
||||
break;
|
||||
|
||||
case ARG_SYNC:
|
||||
|
@ -448,7 +460,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
SET_FLAG(arg_pull_flags, PULL_SYNC, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_SYNC, r);
|
||||
break;
|
||||
|
||||
case ARG_OFFSET: {
|
||||
|
@ -477,6 +489,22 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
break;
|
||||
}
|
||||
|
||||
case ARG_CLASS:
|
||||
arg_class = image_class_from_string(optarg);
|
||||
if (arg_class < 0)
|
||||
return log_error_errno(arg_class, "Failed to parse --class= argument: %s", optarg);
|
||||
|
||||
break;
|
||||
|
||||
case ARG_KEEP_DOWNLOAD:
|
||||
r = parse_boolean(optarg);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse --keep-download= argument: %s", optarg);
|
||||
|
||||
SET_FLAG(arg_import_flags, IMPORT_PULL_KEEP_DOWNLOAD, r);
|
||||
auto_keep_download = false;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -490,12 +518,24 @@ static int parse_argv(int argc, char *argv[]) {
|
|||
!FILE_SIZE_VALID(arg_offset + arg_size_max)))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File offset und maximum size out of range.");
|
||||
|
||||
if (arg_offset != UINT64_MAX && !FLAGS_SET(arg_pull_flags, PULL_DIRECT))
|
||||
if (arg_offset != UINT64_MAX && !FLAGS_SET(arg_import_flags, IMPORT_DIRECT))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File offset only supported in --direct mode.");
|
||||
|
||||
if (arg_checksum && (arg_pull_flags & (PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY)) != 0)
|
||||
if (arg_checksum && (arg_import_flags & (IMPORT_PULL_SETTINGS|IMPORT_PULL_ROOTHASH|IMPORT_PULL_ROOTHASH_SIGNATURE|IMPORT_PULL_VERITY)) != 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Literal checksum verification only supported if no associated files are downloaded.");
|
||||
|
||||
if (!arg_image_root)
|
||||
arg_image_root = image_root_to_string(arg_class);
|
||||
|
||||
/* .nspawn settings files only really make sense for machine images, not for sysext/confext/portable */
|
||||
if (auto_settings && arg_class != IMAGE_MACHINE)
|
||||
arg_import_flags &= ~IMPORT_PULL_SETTINGS;
|
||||
|
||||
/* Keep the original pristine downloaded file as a copy only when dealing with machine images,
|
||||
* because unlike sysext/confext/portable they are typically modified during runtime. */
|
||||
if (auto_keep_download)
|
||||
SET_FLAG(arg_import_flags, IMPORT_PULL_KEEP_DOWNLOAD, arg_class == IMAGE_MACHINE);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -507,19 +547,19 @@ static void parse_env(void) {
|
|||
|
||||
r = getenv_bool("SYSTEMD_IMPORT_BTRFS_SUBVOL");
|
||||
if (r >= 0)
|
||||
SET_FLAG(arg_pull_flags, PULL_BTRFS_SUBVOL, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_BTRFS_SUBVOL, r);
|
||||
else if (r != -ENXIO)
|
||||
log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_SUBVOL: %m");
|
||||
|
||||
r = getenv_bool("SYSTEMD_IMPORT_BTRFS_QUOTA");
|
||||
if (r >= 0)
|
||||
SET_FLAG(arg_pull_flags, PULL_BTRFS_QUOTA, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_BTRFS_QUOTA, r);
|
||||
else if (r != -ENXIO)
|
||||
log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_BTRFS_QUOTA: %m");
|
||||
|
||||
r = getenv_bool("SYSTEMD_IMPORT_SYNC");
|
||||
if (r >= 0)
|
||||
SET_FLAG(arg_pull_flags, PULL_SYNC, r);
|
||||
SET_FLAG(arg_import_flags, IMPORT_SYNC, r);
|
||||
else if (r != -ENXIO)
|
||||
log_warning_errno(r, "Failed to parse $SYSTEMD_IMPORT_SYNC: %m");
|
||||
}
|
||||
|
@ -539,8 +579,7 @@ static int run(int argc, char *argv[]) {
|
|||
int r;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
log_setup();
|
||||
|
||||
parse_env();
|
||||
|
||||
|
|
|
@ -4915,12 +4915,12 @@ _public_ int sd_event_get_state(sd_event *e) {
|
|||
_public_ int sd_event_get_exit_code(sd_event *e, int *code) {
|
||||
assert_return(e, -EINVAL);
|
||||
assert_return(e = event_resolve(e), -ENOPKG);
|
||||
assert_return(code, -EINVAL);
|
||||
assert_return(!event_origin_changed(e), -ECHILD);
|
||||
|
||||
if (!e->exit_requested)
|
||||
return -ENODATA;
|
||||
|
||||
if (code)
|
||||
*code = e->exit_code;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "alloc-util.h"
|
||||
#include "build.h"
|
||||
#include "build-path.h"
|
||||
#include "bus-common-errors.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-locator.h"
|
||||
|
@ -1874,633 +1875,6 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int match_log_message(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
const char **our_path = userdata, *line;
|
||||
unsigned priority;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(our_path);
|
||||
|
||||
r = sd_bus_message_read(m, "us", &priority, &line);
|
||||
if (r < 0) {
|
||||
bus_log_parse_error(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!streq_ptr(*our_path, sd_bus_message_get_path(m)))
|
||||
return 0;
|
||||
|
||||
if (arg_quiet && LOG_PRI(priority) >= LOG_INFO)
|
||||
return 0;
|
||||
|
||||
log_full(priority, "%s", line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_transfer_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
const char **our_path = userdata, *path, *result;
|
||||
uint32_t id;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(our_path);
|
||||
|
||||
r = sd_bus_message_read(m, "uos", &id, &path, &result);
|
||||
if (r < 0) {
|
||||
bus_log_parse_error(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!streq_ptr(*our_path, path))
|
||||
return 0;
|
||||
|
||||
sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), !streq_ptr(result, "done"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int transfer_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
|
||||
assert(s);
|
||||
assert(si);
|
||||
|
||||
if (!arg_quiet)
|
||||
log_info("Continuing download in the background. Use \"machinectl cancel-transfer %" PRIu32 "\" to abort transfer.", PTR_TO_UINT32(userdata));
|
||||
|
||||
sd_event_exit(sd_event_source_get_event(s), EINTR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
|
||||
_cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(sd_event_unrefp) sd_event* event = NULL;
|
||||
const char *path = NULL;
|
||||
uint32_t id;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(m);
|
||||
|
||||
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
||||
|
||||
r = sd_event_default(&event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get event loop: %m");
|
||||
|
||||
r = sd_bus_attach_event(bus, event, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
||||
|
||||
r = bus_match_signal_async(
|
||||
bus,
|
||||
&slot_job_removed,
|
||||
bus_import_mgr,
|
||||
"TransferRemoved",
|
||||
match_transfer_removed, NULL, &path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to request match: %m");
|
||||
|
||||
r = sd_bus_match_signal_async(
|
||||
bus,
|
||||
&slot_log_message,
|
||||
"org.freedesktop.import1",
|
||||
NULL,
|
||||
"org.freedesktop.import1.Transfer",
|
||||
"LogMessage",
|
||||
match_log_message, NULL, &path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to request match: %m");
|
||||
|
||||
r = sd_bus_call(bus, m, 0, &error, &reply);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to transfer image: %s", bus_error_message(&error, r));
|
||||
|
||||
r = sd_bus_message_read(reply, "uo", &id, &path);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT) >= 0);
|
||||
|
||||
if (!arg_quiet)
|
||||
log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id);
|
||||
|
||||
(void) sd_event_add_signal(event, NULL, SIGINT, transfer_signal_handler, UINT32_TO_PTR(id));
|
||||
(void) sd_event_add_signal(event, NULL, SIGTERM, transfer_signal_handler, UINT32_TO_PTR(id));
|
||||
|
||||
r = sd_event_loop(event);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to run event loop: %m");
|
||||
|
||||
return -r;
|
||||
}
|
||||
|
||||
static int import_tar(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
_cleanup_free_ char *ll = NULL, *fn = NULL;
|
||||
const char *local = NULL, *path = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
sd_bus *bus = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
if (argc >= 2)
|
||||
path = empty_or_dash_to_null(argv[1]);
|
||||
|
||||
if (argc >= 3)
|
||||
local = empty_or_dash_to_null(argv[2]);
|
||||
else if (path) {
|
||||
r = path_extract_filename(path, &fn);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Cannot extract container name from filename: %m");
|
||||
if (r == O_DIRECTORY)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EISDIR),
|
||||
"Path '%s' refers to directory, but we need a regular file: %m", path);
|
||||
|
||||
local = fn;
|
||||
}
|
||||
if (!local)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Need either path or local name.");
|
||||
|
||||
r = tar_strip_suffixes(local, &ll);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
local = ll;
|
||||
|
||||
if (!hostname_is_valid(local, 0))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Local name %s is not a suitable machine name.",
|
||||
local);
|
||||
|
||||
if (path) {
|
||||
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open %s: %m", path);
|
||||
}
|
||||
|
||||
r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportTar");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(
|
||||
m,
|
||||
"hsbb",
|
||||
fd >= 0 ? fd : STDIN_FILENO,
|
||||
local,
|
||||
arg_force,
|
||||
arg_read_only);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return transfer_image_common(bus, m);
|
||||
}
|
||||
|
||||
static int import_raw(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
_cleanup_free_ char *ll = NULL, *fn = NULL;
|
||||
const char *local = NULL, *path = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
sd_bus *bus = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
if (argc >= 2)
|
||||
path = empty_or_dash_to_null(argv[1]);
|
||||
|
||||
if (argc >= 3)
|
||||
local = empty_or_dash_to_null(argv[2]);
|
||||
else if (path) {
|
||||
r = path_extract_filename(path, &fn);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Cannot extract container name from filename: %m");
|
||||
if (r == O_DIRECTORY)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EISDIR),
|
||||
"Path '%s' refers to directory, but we need a regular file: %m", path);
|
||||
|
||||
local = fn;
|
||||
}
|
||||
if (!local)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Need either path or local name.");
|
||||
|
||||
r = raw_strip_suffixes(local, &ll);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
local = ll;
|
||||
|
||||
if (!hostname_is_valid(local, 0))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Local name %s is not a suitable machine name.",
|
||||
local);
|
||||
|
||||
if (path) {
|
||||
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open %s: %m", path);
|
||||
}
|
||||
|
||||
r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportRaw");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(
|
||||
m,
|
||||
"hsbb",
|
||||
fd >= 0 ? fd : STDIN_FILENO,
|
||||
local,
|
||||
arg_force,
|
||||
arg_read_only);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return transfer_image_common(bus, m);
|
||||
}
|
||||
|
||||
static int import_fs(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
const char *local = NULL, *path = NULL;
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
sd_bus *bus = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
if (argc >= 2)
|
||||
path = empty_or_dash_to_null(argv[1]);
|
||||
|
||||
if (argc >= 3)
|
||||
local = empty_or_dash_to_null(argv[2]);
|
||||
else if (path) {
|
||||
r = path_extract_filename(path, &fn);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Cannot extract container name from filename: %m");
|
||||
|
||||
local = fn;
|
||||
}
|
||||
if (!local)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Need either path or local name.");
|
||||
|
||||
if (!hostname_is_valid(local, 0))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Local name %s is not a suitable machine name.",
|
||||
local);
|
||||
|
||||
if (path) {
|
||||
fd = open(path, O_DIRECTORY|O_RDONLY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open directory '%s': %m", path);
|
||||
}
|
||||
|
||||
r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ImportFileSystem");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(
|
||||
m,
|
||||
"hsbb",
|
||||
fd >= 0 ? fd : STDIN_FILENO,
|
||||
local,
|
||||
arg_force,
|
||||
arg_read_only);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return transfer_image_common(bus, m);
|
||||
}
|
||||
|
||||
static void determine_compression_from_filename(const char *p) {
|
||||
if (arg_format)
|
||||
return;
|
||||
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
if (endswith(p, ".xz"))
|
||||
arg_format = "xz";
|
||||
else if (endswith(p, ".gz"))
|
||||
arg_format = "gzip";
|
||||
else if (endswith(p, ".bz2"))
|
||||
arg_format = "bzip2";
|
||||
}
|
||||
|
||||
static int export_tar(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
const char *local = NULL, *path = NULL;
|
||||
sd_bus *bus = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
local = argv[1];
|
||||
if (!hostname_is_valid(local, 0))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Machine name %s is not valid.", local);
|
||||
|
||||
if (argc >= 3)
|
||||
path = argv[2];
|
||||
path = empty_or_dash_to_null(path);
|
||||
|
||||
if (path) {
|
||||
determine_compression_from_filename(path);
|
||||
|
||||
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open %s: %m", path);
|
||||
}
|
||||
|
||||
r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ExportTar");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(
|
||||
m,
|
||||
"shs",
|
||||
local,
|
||||
fd >= 0 ? fd : STDOUT_FILENO,
|
||||
arg_format);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return transfer_image_common(bus, m);
|
||||
}
|
||||
|
||||
static int export_raw(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
const char *local = NULL, *path = NULL;
|
||||
sd_bus *bus = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
local = argv[1];
|
||||
if (!hostname_is_valid(local, 0))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Machine name %s is not valid.", local);
|
||||
|
||||
if (argc >= 3)
|
||||
path = argv[2];
|
||||
path = empty_or_dash_to_null(path);
|
||||
|
||||
if (path) {
|
||||
determine_compression_from_filename(path);
|
||||
|
||||
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open %s: %m", path);
|
||||
}
|
||||
|
||||
r = bus_message_new_method_call(bus, &m, bus_import_mgr, "ExportRaw");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(
|
||||
m,
|
||||
"shs",
|
||||
local,
|
||||
fd >= 0 ? fd : STDOUT_FILENO,
|
||||
arg_format);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return transfer_image_common(bus, m);
|
||||
}
|
||||
|
||||
static int pull_tar(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
_cleanup_free_ char *l = NULL, *ll = NULL;
|
||||
const char *local, *remote;
|
||||
sd_bus *bus = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
remote = argv[1];
|
||||
if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"URL '%s' is not valid.", remote);
|
||||
|
||||
if (argc >= 3)
|
||||
local = argv[2];
|
||||
else {
|
||||
r = import_url_last_component(remote, &l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get final component of URL: %m");
|
||||
|
||||
local = l;
|
||||
}
|
||||
|
||||
local = empty_or_dash_to_null(local);
|
||||
|
||||
if (local) {
|
||||
r = tar_strip_suffixes(local, &ll);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
local = ll;
|
||||
|
||||
if (!hostname_is_valid(local, 0))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Local name %s is not a suitable machine name.",
|
||||
local);
|
||||
}
|
||||
|
||||
r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullTar");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(
|
||||
m,
|
||||
"sssb",
|
||||
remote,
|
||||
local,
|
||||
import_verify_to_string(arg_verify),
|
||||
arg_force);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return transfer_image_common(bus, m);
|
||||
}
|
||||
|
||||
static int pull_raw(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
||||
_cleanup_free_ char *l = NULL, *ll = NULL;
|
||||
const char *local, *remote;
|
||||
sd_bus *bus = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
remote = argv[1];
|
||||
if (!http_url_is_valid(remote) && !file_url_is_valid(remote))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"URL '%s' is not valid.", remote);
|
||||
|
||||
if (argc >= 3)
|
||||
local = argv[2];
|
||||
else {
|
||||
r = import_url_last_component(remote, &l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get final component of URL: %m");
|
||||
|
||||
local = l;
|
||||
}
|
||||
|
||||
local = empty_or_dash_to_null(local);
|
||||
|
||||
if (local) {
|
||||
r = raw_strip_suffixes(local, &ll);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
local = ll;
|
||||
|
||||
if (!hostname_is_valid(local, 0))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Local name %s is not a suitable machine name.",
|
||||
local);
|
||||
}
|
||||
|
||||
r = bus_message_new_method_call(bus, &m, bus_import_mgr, "PullRaw");
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
r = sd_bus_message_append(
|
||||
m,
|
||||
"sssb",
|
||||
remote,
|
||||
local,
|
||||
import_verify_to_string(arg_verify),
|
||||
arg_force);
|
||||
if (r < 0)
|
||||
return bus_log_create_error(r);
|
||||
|
||||
return transfer_image_common(bus, m);
|
||||
}
|
||||
|
||||
typedef struct TransferInfo {
|
||||
uint32_t id;
|
||||
const char *type;
|
||||
const char *remote;
|
||||
const char *local;
|
||||
double progress;
|
||||
} TransferInfo;
|
||||
|
||||
static int compare_transfer_info(const TransferInfo *a, const TransferInfo *b) {
|
||||
return strcmp(a->local, b->local);
|
||||
}
|
||||
|
||||
static int list_transfers(int argc, char *argv[], void *userdata) {
|
||||
size_t max_type = STRLEN("TYPE"), max_local = STRLEN("LOCAL"), max_remote = STRLEN("REMOTE");
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
_cleanup_free_ TransferInfo *transfers = NULL;
|
||||
const char *type, *remote, *local;
|
||||
sd_bus *bus = userdata;
|
||||
uint32_t id, max_id = 0;
|
||||
size_t n_transfers = 0;
|
||||
double progress;
|
||||
int r;
|
||||
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
r = bus_call_method(bus, bus_import_mgr, "ListTransfers", &error, &reply, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not get transfers: %s", bus_error_message(&error, r));
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "(usssdo)");
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
while ((r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, NULL)) > 0) {
|
||||
size_t l;
|
||||
|
||||
if (!GREEDY_REALLOC(transfers, n_transfers + 1))
|
||||
return log_oom();
|
||||
|
||||
transfers[n_transfers].id = id;
|
||||
transfers[n_transfers].type = type;
|
||||
transfers[n_transfers].remote = remote;
|
||||
transfers[n_transfers].local = local;
|
||||
transfers[n_transfers].progress = progress;
|
||||
|
||||
l = strlen(type);
|
||||
if (l > max_type)
|
||||
max_type = l;
|
||||
|
||||
l = strlen(remote);
|
||||
if (l > max_remote)
|
||||
max_remote = l;
|
||||
|
||||
l = strlen(local);
|
||||
if (l > max_local)
|
||||
max_local = l;
|
||||
|
||||
if (id > max_id)
|
||||
max_id = id;
|
||||
|
||||
n_transfers++;
|
||||
}
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
typesafe_qsort(transfers, n_transfers, compare_transfer_info);
|
||||
|
||||
if (arg_legend && n_transfers > 0)
|
||||
printf("%-*s %-*s %-*s %-*s %-*s\n",
|
||||
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID",
|
||||
(int) 7, "PERCENT",
|
||||
(int) max_type, "TYPE",
|
||||
(int) max_local, "LOCAL",
|
||||
(int) max_remote, "REMOTE");
|
||||
|
||||
for (size_t j = 0; j < n_transfers; j++)
|
||||
|
||||
if (transfers[j].progress < 0)
|
||||
printf("%*" PRIu32 " %*s %-*s %-*s %-*s\n",
|
||||
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
|
||||
(int) 7, "n/a",
|
||||
(int) max_type, transfers[j].type,
|
||||
(int) max_local, transfers[j].local,
|
||||
(int) max_remote, transfers[j].remote);
|
||||
else
|
||||
printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
|
||||
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
|
||||
(int) 6, (unsigned) (transfers[j].progress * 100),
|
||||
(int) max_type, transfers[j].type,
|
||||
(int) max_local, transfers[j].local,
|
||||
(int) max_remote, transfers[j].remote);
|
||||
|
||||
if (arg_legend) {
|
||||
if (n_transfers > 0)
|
||||
printf("\n%zu transfers listed.\n", n_transfers);
|
||||
else
|
||||
printf("No transfers.\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cancel_transfer(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus *bus = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
uint32_t id;
|
||||
|
||||
r = safe_atou32(argv[i], &id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
|
||||
|
||||
r = bus_call_method(bus, bus_import_mgr, "CancelTransfer", &error, NULL, "u", id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not cancel transfer: %s", bus_error_message(&error, r));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_limit(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
sd_bus *bus = userdata;
|
||||
|
@ -2585,6 +1959,52 @@ static int clean_images(int argc, char *argv[], void *userdata) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int chainload_importctl(int argc, char *argv[]) {
|
||||
int r;
|
||||
|
||||
log_notice("The 'machinectl %1$s' command has been replaced by 'importctl -m %1$s'. Redirecting invocation.", argv[optind]);
|
||||
|
||||
_cleanup_strv_free_ char **c =
|
||||
strv_new("importctl", "--class=machine");
|
||||
if (!c)
|
||||
return log_oom();
|
||||
|
||||
if (FLAGS_SET(arg_pager_flags, PAGER_DISABLE))
|
||||
if (strv_extend(&c, "--no-pager") < 0)
|
||||
return log_oom();
|
||||
if (!arg_legend)
|
||||
if (strv_extend(&c, "--no-legend") < 0)
|
||||
return log_oom();
|
||||
if (arg_read_only)
|
||||
if (strv_extend(&c, "--read-only") < 0)
|
||||
return log_oom();
|
||||
if (arg_force)
|
||||
if (strv_extend(&c, "--force") < 0)
|
||||
return log_oom();
|
||||
if (arg_quiet)
|
||||
if (strv_extend(&c, "--quiet") < 0)
|
||||
return log_oom();
|
||||
if (!arg_ask_password)
|
||||
if (strv_extend(&c, "--no-ask-password") < 0)
|
||||
return log_oom();
|
||||
if (strv_extend_many(&c, "--verify", import_verify_to_string(arg_verify)) < 0)
|
||||
return log_oom();
|
||||
if (arg_format)
|
||||
if (strv_extend_many(&c, "--format", arg_format) < 0)
|
||||
return log_oom();
|
||||
|
||||
if (strv_extend_strv(&c, argv + optind, /* filter_duplicates= */ false) < 0)
|
||||
return log_oom();
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *joined = strv_join(c, " ");
|
||||
log_debug("Chainloading: %s", joined);
|
||||
}
|
||||
|
||||
r = invoke_callout_binary(BINDIR "/importctl", c);
|
||||
return log_error_errno(r, "Failed to invoke 'importctl': %m");
|
||||
}
|
||||
|
||||
static int help(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
|
@ -2629,16 +2049,6 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" remove NAME... Remove an image\n"
|
||||
" set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n"
|
||||
" clean Remove hidden (or all) images\n"
|
||||
"\n%3$sImage Transfer Commands:%4$s\n"
|
||||
" pull-tar URL [NAME] Download a TAR container image\n"
|
||||
" pull-raw URL [NAME] Download a RAW container or VM image\n"
|
||||
" import-tar FILE [NAME] Import a local TAR container image\n"
|
||||
" import-raw FILE [NAME] Import a local RAW container or VM image\n"
|
||||
" import-fs DIRECTORY [NAME] Import a local directory container image\n"
|
||||
" export-tar NAME [FILE] Export a TAR container image locally\n"
|
||||
" export-raw NAME [FILE] Export a RAW container or VM image locally\n"
|
||||
" list-transfers Show list of downloads in progress\n"
|
||||
" cancel-transfer Cancel a download\n"
|
||||
"\n%3$sOptions:%4$s\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
|
@ -2656,7 +2066,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" -s --signal=SIGNAL Which signal to send\n"
|
||||
" --uid=USER Specify user ID to invoke shell as\n"
|
||||
" -E --setenv=VAR[=VALUE] Add an environment variable for shell\n"
|
||||
" --read-only Create read-only bind mount\n"
|
||||
" --read-only Create read-only bind mount or clone\n"
|
||||
" --mkdir Create directory before bind mounting, if missing\n"
|
||||
" -n --lines=INTEGER Number of journal entries to show\n"
|
||||
" --max-addresses=INTEGER Number of internet addresses to show at most\n"
|
||||
|
@ -2665,9 +2075,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
|||
" short-monotonic, short-unix, short-delta,\n"
|
||||
" json, json-pretty, json-sse, json-seq, cat,\n"
|
||||
" verbose, export, with-unit)\n"
|
||||
" --verify=MODE Verification mode for downloaded images (no,\n"
|
||||
" checksum, signature)\n"
|
||||
" --force Download image even if already exists\n"
|
||||
" --force Replace target file when copying, if necessary\n"
|
||||
" --now Start or power off container after enabling or\n"
|
||||
" disabling it\n"
|
||||
" --runner=RUNNER Select between nspawn and vmspawn as the runner\n"
|
||||
|
@ -3007,15 +2415,6 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
|
|||
{ "start", 2, VERB_ANY, 0, start_machine },
|
||||
{ "enable", 2, VERB_ANY, 0, enable_machine },
|
||||
{ "disable", 2, VERB_ANY, 0, enable_machine },
|
||||
{ "import-tar", 2, 3, 0, import_tar },
|
||||
{ "import-raw", 2, 3, 0, import_raw },
|
||||
{ "import-fs", 2, 3, 0, import_fs },
|
||||
{ "export-tar", 2, 3, 0, export_tar },
|
||||
{ "export-raw", 2, 3, 0, export_raw },
|
||||
{ "pull-tar", 2, 3, 0, pull_tar },
|
||||
{ "pull-raw", 2, 3, 0, pull_raw },
|
||||
{ "list-transfers", VERB_ANY, 1, 0, list_transfers },
|
||||
{ "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
|
||||
{ "set-limit", 2, 3, 0, set_limit },
|
||||
{ "clean", VERB_ANY, 1, 0, clean_images },
|
||||
{}
|
||||
|
@ -3033,13 +2432,19 @@ static int run(int argc, char *argv[]) {
|
|||
|
||||
/* The journal merging logic potentially needs a lot of fds. */
|
||||
(void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
|
||||
|
||||
sigbus_install();
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
if (STRPTR_IN_SET(argv[optind],
|
||||
"import-tar", "import-raw", "import-fs",
|
||||
"export-tar", "export-raw",
|
||||
"pull-tar", "pull-raw",
|
||||
"list-transfers", "cancel-transfer"))
|
||||
return chainload_importctl(argc, argv);
|
||||
|
||||
r = bus_connect_transport(arg_transport, arg_host, RUNTIME_SCOPE_SYSTEM, &bus);
|
||||
if (r < 0)
|
||||
return bus_log_connect_error(r, arg_transport);
|
||||
|
|
|
@ -99,6 +99,15 @@ static const char* image_class_suffix_table[_IMAGE_CLASS_MAX] = {
|
|||
|
||||
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(image_class_suffix, ImageClass);
|
||||
|
||||
static const char *const image_root_table[_IMAGE_CLASS_MAX] = {
|
||||
[IMAGE_MACHINE] = "/var/lib/machines",
|
||||
[IMAGE_PORTABLE] = "/var/lib/portables",
|
||||
[IMAGE_SYSEXT] = "/var/lib/extensions",
|
||||
[IMAGE_CONFEXT] = "/var/lib/confexts",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(image_root, ImageClass);
|
||||
|
||||
static Image *image_free(Image *i) {
|
||||
assert(i);
|
||||
|
||||
|
|
|
@ -119,4 +119,6 @@ static inline bool IMAGE_IS_HOST(const struct Image *i) {
|
|||
|
||||
int image_to_json(const struct Image *i, JsonVariant **ret);
|
||||
|
||||
const char *image_root_to_string(ImageClass c) _const_;
|
||||
|
||||
extern const struct hash_ops image_hash_ops;
|
||||
|
|
|
@ -462,3 +462,75 @@ int terminal_tint_color(double hue, char **ret) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void draw_progress_bar(const char *prefix, double percentage) {
|
||||
|
||||
fputs("\r", stderr);
|
||||
if (prefix)
|
||||
fputs(prefix, stderr);
|
||||
|
||||
if (!terminal_is_dumb()) {
|
||||
size_t cols = columns();
|
||||
size_t prefix_length = strlen_ptr(prefix);
|
||||
size_t length = cols > prefix_length + 6 ? cols - prefix_length - 6 : 0;
|
||||
|
||||
fputs(ansi_highlight_green(), stderr);
|
||||
|
||||
if (length > 5 && percentage >= 0.0 && percentage <= 100.0) {
|
||||
size_t p = (size_t) (length * percentage / 100.0);
|
||||
bool separator_done = false;
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
|
||||
if (i <= p) {
|
||||
if (get_color_mode() == COLOR_24BIT) {
|
||||
uint8_t r8, g8, b8;
|
||||
double z = i == 0 ? 0 : (((double) i / p) * 100);
|
||||
hsv_to_rgb(145 /* green */, z, 33 + z*2/3, &r8, &g8, &b8);
|
||||
fprintf(stderr, "\x1B[38;2;%u;%u;%um", r8, g8, b8);
|
||||
}
|
||||
|
||||
fputs(special_glyph(SPECIAL_GLYPH_HORIZONTAL_FAT), stderr);
|
||||
} else if (i+1 < length && !separator_done) {
|
||||
fputs(ansi_normal(), stderr);
|
||||
fputc(' ', stderr);
|
||||
separator_done = true;
|
||||
fputs(ansi_grey(), stderr);
|
||||
} else
|
||||
fputs(special_glyph(SPECIAL_GLYPH_HORIZONTAL_DOTTED), stderr);
|
||||
}
|
||||
|
||||
fputs(ansi_normal(), stderr);
|
||||
fputc(' ', stderr);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"%s%3.0f%%%s",
|
||||
ansi_highlight(),
|
||||
percentage,
|
||||
ansi_normal());
|
||||
|
||||
if (!terminal_is_dumb())
|
||||
fputs(ANSI_ERASE_TO_END_OF_LINE, stderr);
|
||||
|
||||
fputc('\r', stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
void clear_progress_bar(const char *prefix) {
|
||||
|
||||
fputc('\r', stderr);
|
||||
|
||||
if (terminal_is_dumb()) {
|
||||
size_t l = strlen_ptr(prefix);
|
||||
for (size_t i = 0; i < l; i ++)
|
||||
fputc(' ', stderr);
|
||||
|
||||
fputs(" ", stderr);
|
||||
} else
|
||||
fputs(ANSI_ERASE_TO_END_OF_LINE, stderr);
|
||||
|
||||
fputc('\r', stderr);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
|
|
@ -49,3 +49,6 @@ static inline const char *green_check_mark_internal(char buffer[static GREEN_CHE
|
|||
#define COLOR_MARK_BOOL(b) ((b) ? GREEN_CHECK_MARK() : RED_CROSS_MARK())
|
||||
|
||||
int terminal_tint_color(double hue, char **ret);
|
||||
|
||||
void draw_progress_bar(const char *prefix, double percentage);
|
||||
void clear_progress_bar(const char *prefix);
|
||||
|
|
|
@ -380,6 +380,10 @@ executables += [
|
|||
'sources' : files('test-process-util.c'),
|
||||
'dependencies' : threads,
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-progress-bar.c'),
|
||||
'type' : 'manual',
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-qrcode-util.c'),
|
||||
'dependencies' : libdl,
|
||||
|
|
|
@ -92,6 +92,8 @@ TEST(dump_special_glyphs) {
|
|||
dump_glyph(SPECIAL_GLYPH_TREE_SPACE);
|
||||
dump_glyph(SPECIAL_GLYPH_TREE_TOP);
|
||||
dump_glyph(SPECIAL_GLYPH_VERTICAL_DOTTED);
|
||||
dump_glyph(SPECIAL_GLYPH_HORIZONTAL_DOTTED);
|
||||
dump_glyph(SPECIAL_GLYPH_HORIZONTAL_FAT);
|
||||
dump_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET);
|
||||
dump_glyph(SPECIAL_GLYPH_BLACK_CIRCLE);
|
||||
dump_glyph(SPECIAL_GLYPH_WHITE_CIRCLE);
|
||||
|
|
34
src/test/test-progress-bar.c
Normal file
34
src/test/test-progress-bar.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "pretty-print.h"
|
||||
#include "random-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
#define PROGRESS_PREFIX "test: "
|
||||
|
||||
TEST(progress_bar) {
|
||||
|
||||
draw_progress_bar(PROGRESS_PREFIX, 0);
|
||||
|
||||
bool paused = false;
|
||||
|
||||
for (double d = 0; d <= 100; d += 0.5) {
|
||||
usleep_safe(random_u64_range(20 * USEC_PER_MSEC));
|
||||
draw_progress_bar(PROGRESS_PREFIX, d);
|
||||
|
||||
if (!paused && d >= 50) {
|
||||
clear_progress_bar(PROGRESS_PREFIX);
|
||||
fputs("Sleeping for 1s...", stdout);
|
||||
fflush(stdout);
|
||||
usleep_safe(USEC_PER_SEC);
|
||||
paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
draw_progress_bar(PROGRESS_PREFIX, 100);
|
||||
usleep_safe(300 * MSEC_PER_SEC);
|
||||
clear_progress_bar(PROGRESS_PREFIX);
|
||||
fputs("Done.\n", stdout);
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
66
test/units/testsuite-13.importctl.sh
Executable file
66
test/units/testsuite-13.importctl.sh
Executable file
|
@ -0,0 +1,66 @@
|
|||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# shellcheck disable=SC2016
|
||||
set -eux
|
||||
set -o pipefail
|
||||
|
||||
# shellcheck source=test/units/util.sh
|
||||
. "$(dirname "$0")"/util.sh
|
||||
|
||||
export PAGER=
|
||||
|
||||
at_exit() {
|
||||
set +e
|
||||
umount -l -R /var/lib/confexts
|
||||
rm -f /var/tmp/importtest /var/tmp/importtest2 /var/tmp/importtest.tar.gz /var/tmp/importtest2.tar.gz
|
||||
}
|
||||
|
||||
trap at_exit EXIT
|
||||
|
||||
systemctl service-log-level systemd-importd debug
|
||||
|
||||
# Mount tmpfs over /var/lib/confexts to not pollute the image
|
||||
mkdir -p /var/lib/confexts
|
||||
mount -t tmpfs tmpfs /var/lib/confexts -o mode=755
|
||||
|
||||
importctl
|
||||
importctl --no-pager --help
|
||||
importctl --version
|
||||
importctl list-transfers
|
||||
importctl list-transfers --no-legend --no-ask-password
|
||||
importctl list-transfers -j
|
||||
importctl list-images
|
||||
importctl list-images --no-legend --no-ask-password
|
||||
importctl list-images -j
|
||||
|
||||
(! importctl cancel-transfer 4711)
|
||||
|
||||
dd if=/dev/urandom of=/var/tmp/importtest bs=4096 count=10
|
||||
|
||||
importctl import-raw --class=confext /var/tmp/importtest
|
||||
cmp /var/tmp/importtest /var/lib/confexts/importtest.raw
|
||||
importctl export-raw --class=confext importtest /var/tmp/importtest2
|
||||
cmp /var/tmp/importtest /var/tmp/importtest2
|
||||
|
||||
(! importctl pull-raw --class=confext file:///var/tmp/importtest)
|
||||
importctl pull-raw --verify=no --class=confext file:///var/tmp/importtest importtest3
|
||||
cmp /var/tmp/importtest /var/lib/confexts/importtest3.raw
|
||||
|
||||
tar czf /var/tmp/importtest.tar.gz -C /var/tmp importtest
|
||||
|
||||
importctl import-tar --class=confext /var/tmp/importtest.tar.gz importtest4
|
||||
cmp /var/tmp/importtest /var/lib/confexts/importtest4/importtest
|
||||
|
||||
importctl export-tar --class=confext importtest4 /var/tmp/importtest2.tar.gz
|
||||
importctl import-tar --class=confext /var/tmp/importtest2.tar.gz importtest5
|
||||
cmp /var/tmp/importtest /var/lib/confexts/importtest5/importtest
|
||||
|
||||
importctl import-fs --class=confext /var/lib/confexts/importtest5 importtest6
|
||||
cmp /var/tmp/importtest /var/lib/confexts/importtest6/importtest
|
||||
|
||||
(! importctl pull-tar --class=confext file:///var/tmp/importtest.tar.gz importtest7)
|
||||
importctl pull-tar --class=confext --verify=no file:///var/tmp/importtest.tar.gz importtest7
|
||||
cmp /var/tmp/importtest /var/lib/confexts/importtest7/importtest
|
||||
|
||||
importctl list-images
|
||||
importctl list-images -j
|
|
@ -20,6 +20,9 @@ at_exit() {
|
|||
|
||||
trap at_exit EXIT
|
||||
|
||||
systemctl service-log-level systemd-machined debug
|
||||
systemctl service-log-level systemd-importd debug
|
||||
|
||||
# Mount tmpfs over /var/lib/machines to not pollute the image
|
||||
mkdir -p /var/lib/machines
|
||||
mount -t tmpfs tmpfs /var/lib/machines
|
||||
|
|
Loading…
Reference in a new issue