Compare commits
12 Commits
fdc6c4f49c
...
992aa67231
Author | SHA1 | Date |
---|---|---|
Zbigniew Jędrzejewski-Szmek | 992aa67231 | |
Lennart Poettering | e3eec1fd10 | |
Lennart Poettering | bbac7da2b3 | |
Lennart Poettering | 612d3a68d6 | |
Lennart Poettering | 71b1d2ded1 | |
Lennart Poettering | cc171228d4 | |
Lennart Poettering | 0c3ee12737 | |
Lennart Poettering | 63d3d0a50b | |
Lennart Poettering | 6aa05ebdd8 | |
Lennart Poettering | b8e35011f7 | |
Lennart Poettering | b63aacaa1a | |
Lennart Poettering | dd04fb3268 |
9
TODO
9
TODO
|
@ -120,9 +120,9 @@ Features:
|
||||||
this, it's useful to have one that can dump contents of them, too.
|
this, it's useful to have one that can dump contents of them, too.
|
||||||
|
|
||||||
* All tools that support --root= should also learn --image= so that they can
|
* All tools that support --root= should also learn --image= so that they can
|
||||||
operate on disk images directly. Specifically: bootctl, tmpfiles, sysusers,
|
operate on disk images directly. Specifically: bootctl, systemctl,
|
||||||
systemctl, repart, journalctl, coredumpctl. (Already done: systemd-nspawn,
|
coredumpctl. (Already done: systemd-nspawn, systemd-firstboot,
|
||||||
systemd-firstboot)
|
systemd-repart, systemd-tmpfiles, systemd-sysusers, journalctl)
|
||||||
|
|
||||||
* seccomp: by default mask x32 ABI system wide on x86-64. it's on its way out
|
* seccomp: by default mask x32 ABI system wide on x86-64. it's on its way out
|
||||||
|
|
||||||
|
@ -337,9 +337,6 @@ Features:
|
||||||
right) become genuine first class citizens, and we gain automatic, sane JSON
|
right) become genuine first class citizens, and we gain automatic, sane JSON
|
||||||
output for them.
|
output for them.
|
||||||
|
|
||||||
* systemd-firstboot: teach it dissector magic, so that you can point it to some
|
|
||||||
disk image and it will just set everything in it all behind the scenes.
|
|
||||||
|
|
||||||
* We should probably replace /var/log/README, /etc/rc.d/README with symlinks
|
* We should probably replace /var/log/README, /etc/rc.d/README with symlinks
|
||||||
that are linked to these places instead of copied. After all they are
|
that are linked to these places instead of copied. After all they are
|
||||||
constant vendor data.
|
constant vendor data.
|
||||||
|
|
|
@ -756,16 +756,29 @@
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--root=<replaceable>ROOT</replaceable></option></term>
|
<term><option>--root=<replaceable>ROOT</replaceable></option></term>
|
||||||
|
|
||||||
<listitem><para>Takes a directory path as an argument. If
|
<listitem><para>Takes a directory path as an argument. If specified, <command>journalctl</command>
|
||||||
specified, journalctl will operate on journal directories and catalog file hierarchy
|
will operate on journal directories and catalog file hierarchy underneath the specified directory
|
||||||
underneath the specified directory instead of the root
|
instead of the root directory (e.g. <option>--update-catalog</option> will create
|
||||||
directory (e.g. <option>--update-catalog</option> will create
|
<filename><replaceable>ROOT</replaceable>/var/lib/systemd/catalog/database</filename>, and journal
|
||||||
<filename><replaceable>ROOT</replaceable>/var/lib/systemd/catalog/database</filename>,
|
files under <filename><replaceable>ROOT</replaceable>/run/journal/</filename> or
|
||||||
and journal files under <filename><replaceable>ROOT</replaceable>/run/journal/</filename>
|
<filename><replaceable>ROOT</replaceable>/var/log/journal/</filename> will be displayed).
|
||||||
or <filename><replaceable>ROOT</replaceable>/var/log/journal/</filename> will be displayed).
|
|
||||||
</para></listitem>
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--image=<replaceable>IMAGE</replaceable></option></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes a path to a disk image file or block device node. If specified,
|
||||||
|
<command>journalctl</command> will operate on the file system in the indicated disk image. This is
|
||||||
|
similar to <option>--root=</option> but operates on file systems stored in disk images or block
|
||||||
|
devices, thus providing an easy way to extract log data from disk images. The disk image should
|
||||||
|
either contain just a file system or a set of file systems within a GPT partition table, following
|
||||||
|
the <ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions
|
||||||
|
Specification</ulink>. For further information on supported disk images, see
|
||||||
|
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
||||||
|
switch of the same name.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--namespace=<replaceable>NAMESPACE</replaceable></option></term>
|
<term><option>--namespace=<replaceable>NAMESPACE</replaceable></option></term>
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,19 @@
|
||||||
paths. </para></listitem>
|
paths. </para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--image=<replaceable>image</replaceable></option></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes a path to a disk image file or block device node. If specified all operations
|
||||||
|
are applied to file system in the indicated disk image. This is similar to <option>--root=</option>
|
||||||
|
but operates on file systems stored in disk images or block devices. The disk image should either
|
||||||
|
contain just a file system or a set of file systems within a GPT partition table, following the
|
||||||
|
<ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions
|
||||||
|
Specification</ulink>. For further information on supported disk images, see
|
||||||
|
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
||||||
|
switch of the same name.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--replace=<replaceable>PATH</replaceable></option></term>
|
<term><option>--replace=<replaceable>PATH</replaceable></option></term>
|
||||||
<listitem><para>When this option is given, one ore more positional arguments
|
<listitem><para>When this option is given, one ore more positional arguments
|
||||||
|
|
|
@ -149,6 +149,7 @@
|
||||||
the specified prefix. This option can be specified multiple
|
the specified prefix. This option can be specified multiple
|
||||||
times.</para></listitem>
|
times.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--exclude-prefix=<replaceable>path</replaceable></option></term>
|
<term><option>--exclude-prefix=<replaceable>path</replaceable></option></term>
|
||||||
<listitem><para>Ignore rules with paths that start with the
|
<listitem><para>Ignore rules with paths that start with the
|
||||||
|
@ -156,6 +157,16 @@
|
||||||
times.</para></listitem>
|
times.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-E</option></term>
|
||||||
|
<listitem><para>A shortcut for <literal>--exclude-prefix=/dev --exclude-prefix=/proc
|
||||||
|
--exclude-prefix=/run --exclude-prefix=/sys</literal>, i.e. exclude the hierarchies typically backed
|
||||||
|
by virtual or memory file systems. This is useful in combination with <option>--root=</option>, if
|
||||||
|
the specified directory tree contains an OS tree without these virtual/memory file systems mounted
|
||||||
|
in, as it is typically not desirable to create any files and directories below these subdirectories
|
||||||
|
if they are supposed to be overmounted during runtime.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--root=<replaceable>root</replaceable></option></term>
|
<term><option>--root=<replaceable>root</replaceable></option></term>
|
||||||
<listitem><para>Takes a directory path as an argument. All paths will be prefixed with the given alternate
|
<listitem><para>Takes a directory path as an argument. All paths will be prefixed with the given alternate
|
||||||
|
@ -164,7 +175,26 @@
|
||||||
<para>When this option is used, the libc Name Service Switch (NSS) is bypassed for resolving users
|
<para>When this option is used, the libc Name Service Switch (NSS) is bypassed for resolving users
|
||||||
and groups. Instead the files <filename>/etc/passwd</filename> and <filename>/etc/group</filename>
|
and groups. Instead the files <filename>/etc/passwd</filename> and <filename>/etc/group</filename>
|
||||||
inside the alternate root are read directly. This means that users/groups not listed in these files
|
inside the alternate root are read directly. This means that users/groups not listed in these files
|
||||||
will not be resolved, i.e. LDAP NIS and other complex databases are not considered.</para></listitem>
|
will not be resolved, i.e. LDAP NIS and other complex databases are not considered.</para>
|
||||||
|
|
||||||
|
<para>Consider combining this with <option>-E</option> to ensure the invocation does not create files
|
||||||
|
or directories below mount points in the OS image operated on that are typically overmounted during
|
||||||
|
runtime.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--image=<replaceable>image</replaceable></option></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes a path to a disk image file or block device node. If specified all operations
|
||||||
|
are applied to file system in the indicated disk image. This is similar to <option>--root=</option>
|
||||||
|
but operates on file systems stored in disk images or block devices. The disk image should either
|
||||||
|
contain just a file system or a set of file systems within a GPT partition table, following the
|
||||||
|
<ulink url="https://systemd.io/DISCOVERABLE_PARTITIONS">Discoverable Partitions
|
||||||
|
Specification</ulink>. For further information on supported disk images, see
|
||||||
|
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>'s
|
||||||
|
switch of the same name.</para>
|
||||||
|
|
||||||
|
<para>Implies <option>-E</option>.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "kbd-util.h"
|
#include "kbd-util.h"
|
||||||
#include "libcrypt-util.h"
|
#include "libcrypt-util.h"
|
||||||
#include "locale-util.h"
|
#include "locale-util.h"
|
||||||
#include "loop-util.h"
|
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
|
@ -907,75 +906,6 @@ static int process_kernel_cmdline(void) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setup_image(char **ret_mount_dir, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image) {
|
|
||||||
DissectImageFlags f = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK;
|
|
||||||
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
|
|
||||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
|
||||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
|
||||||
_cleanup_(rmdir_and_freep) char *mount_dir = NULL;
|
|
||||||
_cleanup_free_ char *temp = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
if (!arg_image) {
|
|
||||||
*ret_mount_dir = NULL;
|
|
||||||
*ret_decrypted_image = NULL;
|
|
||||||
*ret_loop_device = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(!arg_root);
|
|
||||||
|
|
||||||
r = tempfn_random_child(NULL, "firstboot", &temp);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to generate temporary mount directory: %m");
|
|
||||||
|
|
||||||
r = loop_device_make_by_path(arg_image, O_RDWR, LO_FLAGS_PARTSCAN, &d);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to set up loopback device: %m");
|
|
||||||
|
|
||||||
r = dissect_image_and_warn(d->fd, arg_image, NULL, 0, NULL, NULL, f, &dissected_image);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = dissected_image_decrypt_interactively(dissected_image, NULL, NULL, 0, NULL, NULL, NULL, 0, f, &decrypted_image);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = detach_mount_namespace();
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to detach mount namespace: %m");
|
|
||||||
|
|
||||||
mount_dir = strdup(temp);
|
|
||||||
if (!mount_dir)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
r = mkdir_p(mount_dir, 0700);
|
|
||||||
if (r < 0) {
|
|
||||||
mount_dir = mfree(mount_dir);
|
|
||||||
return log_error_errno(r, "Failed to create mount point: %m");
|
|
||||||
}
|
|
||||||
|
|
||||||
r = dissected_image_mount(dissected_image, mount_dir, UID_INVALID, f);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to mount image: %m");
|
|
||||||
|
|
||||||
if (decrypted_image) {
|
|
||||||
r = decrypted_image_relinquish(decrypted_image);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to relinquish DM devices: %m");
|
|
||||||
}
|
|
||||||
|
|
||||||
loop_device_relinquish(d);
|
|
||||||
|
|
||||||
arg_root = TAKE_PTR(temp);
|
|
||||||
|
|
||||||
*ret_mount_dir = TAKE_PTR(mount_dir);
|
|
||||||
*ret_decrypted_image = TAKE_PTR(decrypted_image);
|
|
||||||
*ret_loop_device = TAKE_PTR(d);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int help(void) {
|
static int help(void) {
|
||||||
_cleanup_free_ char *link = NULL;
|
_cleanup_free_ char *link = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
@ -1353,10 +1283,23 @@ static int run(int argc, char *argv[]) {
|
||||||
return 0; /* disabled */
|
return 0; /* disabled */
|
||||||
}
|
}
|
||||||
|
|
||||||
r = setup_image(&unlink_dir, &loop_device, &decrypted_image);
|
if (arg_image) {
|
||||||
|
assert(!arg_root);
|
||||||
|
|
||||||
|
r = mount_image_privately_interactively(
|
||||||
|
arg_image,
|
||||||
|
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
|
||||||
|
&unlink_dir,
|
||||||
|
&loop_device,
|
||||||
|
&decrypted_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
arg_root = strdup(unlink_dir);
|
||||||
|
if (!arg_root)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
r = process_locale();
|
r = process_locale();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "chattr-util.h"
|
#include "chattr-util.h"
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
#include "device-private.h"
|
#include "device-private.h"
|
||||||
|
#include "dissect-image.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
|
@ -51,6 +52,7 @@
|
||||||
#include "logs-show.h"
|
#include "logs-show.h"
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
|
#include "mount-util.h"
|
||||||
#include "mountpoint-util.h"
|
#include "mountpoint-util.h"
|
||||||
#include "nulstr-util.h"
|
#include "nulstr-util.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
|
@ -121,6 +123,7 @@ static bool arg_reverse = false;
|
||||||
static int arg_journal_type = 0;
|
static int arg_journal_type = 0;
|
||||||
static int arg_namespace_flags = 0;
|
static int arg_namespace_flags = 0;
|
||||||
static char *arg_root = NULL;
|
static char *arg_root = NULL;
|
||||||
|
static char *arg_image = NULL;
|
||||||
static const char *arg_machine = NULL;
|
static const char *arg_machine = NULL;
|
||||||
static const char *arg_namespace = NULL;
|
static const char *arg_namespace = NULL;
|
||||||
static uint64_t arg_vacuum_size = 0;
|
static uint64_t arg_vacuum_size = 0;
|
||||||
|
@ -375,6 +378,7 @@ static int help(void) {
|
||||||
" -D --directory=PATH Show journal files from directory\n"
|
" -D --directory=PATH Show journal files from directory\n"
|
||||||
" --file=PATH Show journal file\n"
|
" --file=PATH Show journal file\n"
|
||||||
" --root=ROOT Operate on files below a root directory\n"
|
" --root=ROOT Operate on files below a root directory\n"
|
||||||
|
" --image=IMAGE Operate on files in filesystem image\n"
|
||||||
" --namespace=NAMESPACE Show journal data from specified namespace\n"
|
" --namespace=NAMESPACE Show journal data from specified namespace\n"
|
||||||
" --interval=TIME Time interval for changing the FSS sealing key\n"
|
" --interval=TIME Time interval for changing the FSS sealing key\n"
|
||||||
" --verify-key=KEY Specify FSS verification key\n"
|
" --verify-key=KEY Specify FSS verification key\n"
|
||||||
|
@ -422,6 +426,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_USER,
|
ARG_USER,
|
||||||
ARG_SYSTEM,
|
ARG_SYSTEM,
|
||||||
ARG_ROOT,
|
ARG_ROOT,
|
||||||
|
ARG_IMAGE,
|
||||||
ARG_HEADER,
|
ARG_HEADER,
|
||||||
ARG_FACILITY,
|
ARG_FACILITY,
|
||||||
ARG_SETUP_KEYS,
|
ARG_SETUP_KEYS,
|
||||||
|
@ -478,6 +483,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "directory", required_argument, NULL, 'D' },
|
{ "directory", required_argument, NULL, 'D' },
|
||||||
{ "file", required_argument, NULL, ARG_FILE },
|
{ "file", required_argument, NULL, ARG_FILE },
|
||||||
{ "root", required_argument, NULL, ARG_ROOT },
|
{ "root", required_argument, NULL, ARG_ROOT },
|
||||||
|
{ "image", required_argument, NULL, ARG_IMAGE },
|
||||||
{ "header", no_argument, NULL, ARG_HEADER },
|
{ "header", no_argument, NULL, ARG_HEADER },
|
||||||
{ "identifier", required_argument, NULL, 't' },
|
{ "identifier", required_argument, NULL, 't' },
|
||||||
{ "priority", required_argument, NULL, 'p' },
|
{ "priority", required_argument, NULL, 'p' },
|
||||||
|
@ -713,7 +719,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ARG_ROOT:
|
case ARG_ROOT:
|
||||||
r = parse_path_argument_and_warn(optarg, true, &arg_root);
|
r = parse_path_argument_and_warn(optarg, /* suppress_root= */ true, &arg_root);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ARG_IMAGE:
|
||||||
|
r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
break;
|
break;
|
||||||
|
@ -1043,8 +1055,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT)
|
if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT)
|
||||||
arg_lines = 10;
|
arg_lines = 10;
|
||||||
|
|
||||||
if (!!arg_directory + !!arg_file + !!arg_machine + !!arg_root > 1) {
|
if (!!arg_directory + !!arg_file + !!arg_machine + !!arg_root + !!arg_image > 1) {
|
||||||
log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.");
|
log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root=, --image=.");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2084,6 +2096,9 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||||
|
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||||
|
_cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
|
||||||
bool previous_boot_id_valid = false, first_line = true, ellipsized = false, need_seek = false;
|
bool previous_boot_id_valid = false, first_line = true, ellipsized = false, need_seek = false;
|
||||||
bool use_cursor = false, after_cursor = false;
|
bool use_cursor = false, after_cursor = false;
|
||||||
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
||||||
|
@ -2101,6 +2116,24 @@ int main(int argc, char *argv[]) {
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
if (arg_image) {
|
||||||
|
assert(!arg_root);
|
||||||
|
|
||||||
|
r = mount_image_privately_interactively(
|
||||||
|
arg_image,
|
||||||
|
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|
|
||||||
|
(arg_action == ACTION_UPDATE_CATALOG ? DISSECT_IMAGE_FSCK : DISSECT_IMAGE_READ_ONLY),
|
||||||
|
&unlink_dir,
|
||||||
|
&loop_device,
|
||||||
|
&decrypted_image);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
arg_root = strdup(unlink_dir);
|
||||||
|
if (!arg_root)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
signal(SIGWINCH, columns_lines_cache_reset);
|
signal(SIGWINCH, columns_lines_cache_reset);
|
||||||
sigbus_install();
|
sigbus_install();
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,10 @@
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
#include "hostname-util.h"
|
#include "hostname-util.h"
|
||||||
#include "id128-util.h"
|
#include "id128-util.h"
|
||||||
|
#include "mkdir.h"
|
||||||
#include "mount-util.h"
|
#include "mount-util.h"
|
||||||
#include "mountpoint-util.h"
|
#include "mountpoint-util.h"
|
||||||
|
#include "namespace-util.h"
|
||||||
#include "nulstr-util.h"
|
#include "nulstr-util.h"
|
||||||
#include "os-util.h"
|
#include "os-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
|
@ -1940,9 +1942,84 @@ const char* mount_options_from_part(const MountOptions *options, unsigned int pa
|
||||||
LIST_FOREACH(mount_options, m, (MountOptions *)options)
|
LIST_FOREACH(mount_options, m, (MountOptions *)options)
|
||||||
if (partition_number == m->partition_number && !isempty(m->options))
|
if (partition_number == m->partition_number && !isempty(m->options))
|
||||||
return m->options;
|
return m->options;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mount_image_privately_interactively(
|
||||||
|
const char *image,
|
||||||
|
DissectImageFlags flags,
|
||||||
|
char **ret_directory,
|
||||||
|
LoopDevice **ret_loop_device,
|
||||||
|
DecryptedImage **ret_decrypted_image) {
|
||||||
|
|
||||||
|
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
|
||||||
|
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||||
|
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||||
|
_cleanup_(rmdir_and_freep) char *created_dir = NULL;
|
||||||
|
_cleanup_free_ char *temp = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* Mounts an OS image at a temporary place, inside a newly created mount namespace of our own. This
|
||||||
|
* is used by tools such as systemd-tmpfiles or systemd-firstboot to operate on some disk image
|
||||||
|
* easily. */
|
||||||
|
|
||||||
|
assert(image);
|
||||||
|
assert(ret_directory);
|
||||||
|
assert(ret_loop_device);
|
||||||
|
assert(ret_decrypted_image);
|
||||||
|
|
||||||
|
r = tempfn_random_child(NULL, program_invocation_short_name, &temp);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to generate temporary mount directory: %m");
|
||||||
|
|
||||||
|
r = loop_device_make_by_path(
|
||||||
|
image,
|
||||||
|
FLAGS_SET(flags, DISSECT_IMAGE_READ_ONLY) ? O_RDONLY : O_RDWR,
|
||||||
|
FLAGS_SET(flags, DISSECT_IMAGE_NO_PARTITION_TABLE) ? 0 : LO_FLAGS_PARTSCAN,
|
||||||
|
&d);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to set up loopback device: %m");
|
||||||
|
|
||||||
|
r = dissect_image_and_warn(d->fd, image, NULL, 0, NULL, NULL, flags, &dissected_image);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = dissected_image_decrypt_interactively(dissected_image, NULL, NULL, 0, NULL, NULL, NULL, 0, flags, &decrypted_image);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = detach_mount_namespace();
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to detach mount namespace: %m");
|
||||||
|
|
||||||
|
r = mkdir_p(temp, 0700);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create mount point: %m");
|
||||||
|
|
||||||
|
created_dir = TAKE_PTR(temp);
|
||||||
|
|
||||||
|
r = dissected_image_mount(dissected_image, created_dir, UID_INVALID, flags);
|
||||||
|
if (r == -EUCLEAN)
|
||||||
|
return log_error_errno(r, "File system check on image failed: %m");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to mount image: %m");
|
||||||
|
|
||||||
|
if (decrypted_image) {
|
||||||
|
r = decrypted_image_relinquish(decrypted_image);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to relinquish DM devices: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
loop_device_relinquish(d);
|
||||||
|
|
||||||
|
*ret_directory = TAKE_PTR(created_dir);
|
||||||
|
*ret_loop_device = TAKE_PTR(d);
|
||||||
|
*ret_decrypted_image = TAKE_PTR(decrypted_image);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const char *const partition_designator_table[] = {
|
static const char *const partition_designator_table[] = {
|
||||||
[PARTITION_ROOT] = "root",
|
[PARTITION_ROOT] = "root",
|
||||||
[PARTITION_ROOT_SECONDARY] = "root-secondary",
|
[PARTITION_ROOT_SECONDARY] = "root-secondary",
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "sd-id128.h"
|
#include "sd-id128.h"
|
||||||
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
#include "loop-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
|
||||||
typedef struct DissectedImage DissectedImage;
|
typedef struct DissectedImage DissectedImage;
|
||||||
|
@ -117,3 +118,5 @@ int partition_designator_from_string(const char *name) _pure_;
|
||||||
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data, char **ret_roothashsig);
|
int verity_metadata_load(const char *image, const char *root_hash_path, void **ret_roothash, size_t *ret_roothash_size, char **ret_verity_data, char **ret_roothashsig);
|
||||||
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
|
bool dissected_image_can_do_verity(const DissectedImage *image, unsigned partition_designator);
|
||||||
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
|
bool dissected_image_has_verity(const DissectedImage *image, unsigned partition_designator);
|
||||||
|
|
||||||
|
int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);
|
||||||
|
|
|
@ -168,8 +168,12 @@ typedef struct ParseFieldVec {
|
||||||
size_t *target_len;
|
size_t *target_len;
|
||||||
} ParseFieldVec;
|
} ParseFieldVec;
|
||||||
|
|
||||||
#define PARSE_FIELD_VEC_ENTRY(_field, _target, _target_len) \
|
#define PARSE_FIELD_VEC_ENTRY(_field, _target, _target_len) { \
|
||||||
{ .field = _field, .field_len = strlen(_field), .target = _target, .target_len = _target_len }
|
.field = _field, \
|
||||||
|
.field_len = strlen(_field), \
|
||||||
|
.target = _target, \
|
||||||
|
.target_len = _target_len \
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_fieldv(const void *data, size_t length, const ParseFieldVec *fields, unsigned n_fields) {
|
static int parse_fieldv(const void *data, size_t length, const ParseFieldVec *fields, unsigned n_fields) {
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
@ -1122,19 +1126,17 @@ static int output_cat_field(
|
||||||
FILE *f,
|
FILE *f,
|
||||||
sd_journal *j,
|
sd_journal *j,
|
||||||
OutputFlags flags,
|
OutputFlags flags,
|
||||||
|
int prio,
|
||||||
const char *field,
|
const char *field,
|
||||||
const size_t highlight[2]) {
|
const size_t highlight[2]) {
|
||||||
|
|
||||||
const char *highlight_on, *highlight_off;
|
const char *color_on = "", *color_off = "", *highlight_on = "";
|
||||||
const void *data;
|
const void *data;
|
||||||
size_t l, fl;
|
size_t l, fl;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (FLAGS_SET(flags, OUTPUT_COLOR)) {
|
if (FLAGS_SET(flags, OUTPUT_COLOR))
|
||||||
highlight_on = ANSI_HIGHLIGHT_RED;
|
get_log_colors(prio, &color_on, &color_off, &highlight_on);
|
||||||
highlight_off = ANSI_NORMAL;
|
|
||||||
} else
|
|
||||||
highlight_on = highlight_off = "";
|
|
||||||
|
|
||||||
r = sd_journal_get_data(j, field, &data, &l);
|
r = sd_journal_get_data(j, field, &data, &l);
|
||||||
if (r == -EBADMSG) {
|
if (r == -EBADMSG) {
|
||||||
|
@ -1153,15 +1155,23 @@ static int output_cat_field(
|
||||||
data = (const uint8_t*) data + fl + 1;
|
data = (const uint8_t*) data + fl + 1;
|
||||||
l -= fl + 1;
|
l -= fl + 1;
|
||||||
|
|
||||||
if (highlight && FLAGS_SET(flags, OUTPUT_COLOR)) {
|
if (FLAGS_SET(flags, OUTPUT_COLOR)) {
|
||||||
|
if (highlight) {
|
||||||
assert(highlight[0] <= highlight[1]);
|
assert(highlight[0] <= highlight[1]);
|
||||||
assert(highlight[1] <= l);
|
assert(highlight[1] <= l);
|
||||||
|
|
||||||
|
fputs(color_on, f);
|
||||||
fwrite((const char*) data, 1, highlight[0], f);
|
fwrite((const char*) data, 1, highlight[0], f);
|
||||||
fwrite(highlight_on, 1, strlen(highlight_on), f);
|
fputs(highlight_on, f);
|
||||||
fwrite((const char*) data + highlight[0], 1, highlight[1] - highlight[0], f);
|
fwrite((const char*) data + highlight[0], 1, highlight[1] - highlight[0], f);
|
||||||
fwrite(highlight_off, 1, strlen(highlight_off), f);
|
fputs(color_on, f);
|
||||||
fwrite((const char*) data + highlight[1], 1, l - highlight[1], f);
|
fwrite((const char*) data + highlight[1], 1, l - highlight[1], f);
|
||||||
|
fputs(color_off, f);
|
||||||
|
} else {
|
||||||
|
fputs(color_on, f);
|
||||||
|
fwrite((const char*) data, 1, l, f);
|
||||||
|
fputs(color_off, f);
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
fwrite((const char*) data, 1, l, f);
|
fwrite((const char*) data, 1, l, f);
|
||||||
|
|
||||||
|
@ -1178,20 +1188,44 @@ static int output_cat(
|
||||||
const Set *output_fields,
|
const Set *output_fields,
|
||||||
const size_t highlight[2]) {
|
const size_t highlight[2]) {
|
||||||
|
|
||||||
|
int r, prio = LOG_INFO;
|
||||||
const char *field;
|
const char *field;
|
||||||
Iterator iterator;
|
Iterator iterator;
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(j);
|
assert(j);
|
||||||
assert(f);
|
assert(f);
|
||||||
|
|
||||||
(void) sd_journal_set_data_threshold(j, 0);
|
(void) sd_journal_set_data_threshold(j, 0);
|
||||||
|
|
||||||
|
if (FLAGS_SET(flags, OUTPUT_COLOR)) {
|
||||||
|
const void *data;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
|
/* Determine priority of this entry, so that we can color it nicely */
|
||||||
|
|
||||||
|
r = sd_journal_get_data(j, "PRIORITY", &data, &l);
|
||||||
|
if (r == -EBADMSG) {
|
||||||
|
log_debug_errno(r, "Skipping message we can't read: %m");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (r < 0) {
|
||||||
|
if (r != -ENOENT)
|
||||||
|
return log_error_errno(r, "Failed to get data: %m");
|
||||||
|
|
||||||
|
/* An entry without PRIORITY */
|
||||||
|
} else if (l == 10 && memcmp(data, "PRIORITY=", 9) == 0) {
|
||||||
|
char c = ((char*) data)[9];
|
||||||
|
|
||||||
|
if (c >= '0' && c <= '7')
|
||||||
|
prio = c - '0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (set_isempty(output_fields))
|
if (set_isempty(output_fields))
|
||||||
return output_cat_field(f, j, flags, "MESSAGE", highlight);
|
return output_cat_field(f, j, flags, prio, "MESSAGE", highlight);
|
||||||
|
|
||||||
SET_FOREACH(field, output_fields, iterator) {
|
SET_FOREACH(field, output_fields, iterator) {
|
||||||
r = output_cat_field(f, j, flags, field, streq(field, "MESSAGE") ? highlight : NULL);
|
r = output_cat_field(f, j, flags, prio, field, streq(field, "MESSAGE") ? highlight : NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,19 @@
|
||||||
#include "conf-files.h"
|
#include "conf-files.h"
|
||||||
#include "copy.h"
|
#include "copy.h"
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
|
#include "dissect-image.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
|
#include "mount-util.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "set.h"
|
|
||||||
#include "selinux-util.h"
|
#include "selinux-util.h"
|
||||||
|
#include "set.h"
|
||||||
#include "smack-util.h"
|
#include "smack-util.h"
|
||||||
#include "specifier.h"
|
#include "specifier.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
@ -63,6 +65,7 @@ typedef struct Item {
|
||||||
} Item;
|
} Item;
|
||||||
|
|
||||||
static char *arg_root = NULL;
|
static char *arg_root = NULL;
|
||||||
|
static char *arg_image = NULL;
|
||||||
static bool arg_cat_config = false;
|
static bool arg_cat_config = false;
|
||||||
static const char *arg_replace = NULL;
|
static const char *arg_replace = NULL;
|
||||||
static bool arg_inline = false;
|
static bool arg_inline = false;
|
||||||
|
@ -93,6 +96,7 @@ STATIC_DESTRUCTOR_REGISTER(database_by_groupname, hashmap_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(database_groups, set_free_freep);
|
STATIC_DESTRUCTOR_REGISTER(database_groups, set_free_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(uid_range, freep);
|
STATIC_DESTRUCTOR_REGISTER(uid_range, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||||
|
|
||||||
static int errno_is_not_exists(int code) {
|
static int errno_is_not_exists(int code) {
|
||||||
/* See getpwnam(3) and getgrnam(3): those codes and others can be returned if the user or group are
|
/* See getpwnam(3) and getgrnam(3): those codes and others can be returned if the user or group are
|
||||||
|
@ -1739,6 +1743,7 @@ static int help(void) {
|
||||||
" --version Show package version\n"
|
" --version Show package version\n"
|
||||||
" --cat-config Show configuration files\n"
|
" --cat-config Show configuration files\n"
|
||||||
" --root=PATH Operate on an alternate filesystem root\n"
|
" --root=PATH Operate on an alternate filesystem root\n"
|
||||||
|
" --image=PATH Operate on disk image as filesystem root\n"
|
||||||
" --replace=PATH Treat arguments as replacement for PATH\n"
|
" --replace=PATH Treat arguments as replacement for PATH\n"
|
||||||
" --inline Treat arguments as configuration lines\n"
|
" --inline Treat arguments as configuration lines\n"
|
||||||
" --no-pager Do not pipe output into a pager\n"
|
" --no-pager Do not pipe output into a pager\n"
|
||||||
|
@ -1756,6 +1761,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_VERSION = 0x100,
|
ARG_VERSION = 0x100,
|
||||||
ARG_CAT_CONFIG,
|
ARG_CAT_CONFIG,
|
||||||
ARG_ROOT,
|
ARG_ROOT,
|
||||||
|
ARG_IMAGE,
|
||||||
ARG_REPLACE,
|
ARG_REPLACE,
|
||||||
ARG_INLINE,
|
ARG_INLINE,
|
||||||
ARG_NO_PAGER,
|
ARG_NO_PAGER,
|
||||||
|
@ -1766,6 +1772,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "version", no_argument, NULL, ARG_VERSION },
|
{ "version", no_argument, NULL, ARG_VERSION },
|
||||||
{ "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
|
{ "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
|
||||||
{ "root", required_argument, NULL, ARG_ROOT },
|
{ "root", required_argument, NULL, ARG_ROOT },
|
||||||
|
{ "image", required_argument, NULL, ARG_IMAGE },
|
||||||
{ "replace", required_argument, NULL, ARG_REPLACE },
|
{ "replace", required_argument, NULL, ARG_REPLACE },
|
||||||
{ "inline", no_argument, NULL, ARG_INLINE },
|
{ "inline", no_argument, NULL, ARG_INLINE },
|
||||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||||
|
@ -1797,6 +1804,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
return r;
|
return r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_IMAGE:
|
||||||
|
r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_image);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
break;
|
||||||
|
|
||||||
case ARG_REPLACE:
|
case ARG_REPLACE:
|
||||||
if (!path_is_absolute(optarg) ||
|
if (!path_is_absolute(optarg) ||
|
||||||
!endswith(optarg, ".conf"))
|
!endswith(optarg, ".conf"))
|
||||||
|
@ -1829,6 +1842,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"When --replace= is given, some configuration items must be specified");
|
"When --replace= is given, some configuration items must be specified");
|
||||||
|
|
||||||
|
if (arg_image && arg_root)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1880,6 +1896,9 @@ static int read_config_files(char **args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int run(int argc, char *argv[]) {
|
static int run(int argc, char *argv[]) {
|
||||||
|
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||||
|
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||||
|
_cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
|
||||||
_cleanup_close_ int lock = -1;
|
_cleanup_close_ int lock = -1;
|
||||||
Iterator iterator;
|
Iterator iterator;
|
||||||
Item *i;
|
Item *i;
|
||||||
|
@ -1900,6 +1919,23 @@ static int run(int argc, char *argv[]) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (arg_image) {
|
||||||
|
assert(!arg_root);
|
||||||
|
|
||||||
|
r = mount_image_privately_interactively(
|
||||||
|
arg_image,
|
||||||
|
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
|
||||||
|
&unlink_dir,
|
||||||
|
&loop_device,
|
||||||
|
&decrypted_image);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
arg_root = strdup(unlink_dir);
|
||||||
|
if (!arg_root)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
/* If command line arguments are specified along with --replace, read all
|
/* If command line arguments are specified along with --replace, read all
|
||||||
* configuration files and insert the positional arguments at the specified
|
* configuration files and insert the positional arguments at the specified
|
||||||
* place. Otherwise, if command line arguments are specified, execute just
|
* place. Otherwise, if command line arguments are specified, execute just
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "copy.h"
|
#include "copy.h"
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
#include "dirent-util.h"
|
#include "dirent-util.h"
|
||||||
|
#include "dissect-image.h"
|
||||||
#include "escape.h"
|
#include "escape.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
|
#include "mount-util.h"
|
||||||
#include "mountpoint-util.h"
|
#include "mountpoint-util.h"
|
||||||
#include "offline-passwd.h"
|
#include "offline-passwd.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
|
@ -164,6 +166,7 @@ static PagerFlags arg_pager_flags = 0;
|
||||||
static char **arg_include_prefixes = NULL;
|
static char **arg_include_prefixes = NULL;
|
||||||
static char **arg_exclude_prefixes = NULL;
|
static char **arg_exclude_prefixes = NULL;
|
||||||
static char *arg_root = NULL;
|
static char *arg_root = NULL;
|
||||||
|
static char *arg_image = NULL;
|
||||||
static char *arg_replace = NULL;
|
static char *arg_replace = NULL;
|
||||||
|
|
||||||
#define MAX_DEPTH 256
|
#define MAX_DEPTH 256
|
||||||
|
@ -177,6 +180,7 @@ STATIC_DESTRUCTOR_REGISTER(unix_sockets, set_free_freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_include_prefixes, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_include_prefixes, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_exclude_prefixes, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_exclude_prefixes, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||||
|
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||||
|
|
||||||
static int specifier_machine_id_safe(char specifier, const void *data, const void *userdata, char **ret);
|
static int specifier_machine_id_safe(char specifier, const void *data, const void *userdata, char **ret);
|
||||||
static int specifier_directory(char specifier, const void *data, const void *userdata, char **ret);
|
static int specifier_directory(char specifier, const void *data, const void *userdata, char **ret);
|
||||||
|
@ -2884,6 +2888,27 @@ static int cat_config(char **config_dirs, char **args) {
|
||||||
return cat_files(NULL, files, 0);
|
return cat_files(NULL, files, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int exclude_default_prefixes(void) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* Provide an easy way to exclude virtual/memory file systems from what we do here. Useful in
|
||||||
|
* combination with --root= where we probably don't want to apply stuff to these dirs as they are
|
||||||
|
* likely over-mounted if the root directory is actually used, and it wouldbe less than ideal to have
|
||||||
|
* all kinds of files created/adjusted underneath these mount points. */
|
||||||
|
|
||||||
|
r = strv_extend_strv(
|
||||||
|
&arg_exclude_prefixes,
|
||||||
|
STRV_MAKE("/dev",
|
||||||
|
"/proc",
|
||||||
|
"/run",
|
||||||
|
"/sys"),
|
||||||
|
true);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int help(void) {
|
static int help(void) {
|
||||||
_cleanup_free_ char *link = NULL;
|
_cleanup_free_ char *link = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
@ -2904,7 +2929,9 @@ static int help(void) {
|
||||||
" --boot Execute actions only safe at boot\n"
|
" --boot Execute actions only safe at boot\n"
|
||||||
" --prefix=PATH Only apply rules with the specified prefix\n"
|
" --prefix=PATH Only apply rules with the specified prefix\n"
|
||||||
" --exclude-prefix=PATH Ignore rules with the specified prefix\n"
|
" --exclude-prefix=PATH Ignore rules with the specified prefix\n"
|
||||||
|
" -E Ignore rules prefixed with /dev, /proc, /run, /sys\n"
|
||||||
" --root=PATH Operate on an alternate filesystem root\n"
|
" --root=PATH Operate on an alternate filesystem root\n"
|
||||||
|
" --image=PATH Operate on disk image as filesystem root\n"
|
||||||
" --replace=PATH Treat arguments as replacement for PATH\n"
|
" --replace=PATH Treat arguments as replacement for PATH\n"
|
||||||
" --no-pager Do not pipe output into a pager\n"
|
" --no-pager Do not pipe output into a pager\n"
|
||||||
"\nSee the %s for details.\n"
|
"\nSee the %s for details.\n"
|
||||||
|
@ -2928,6 +2955,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
ARG_PREFIX,
|
ARG_PREFIX,
|
||||||
ARG_EXCLUDE_PREFIX,
|
ARG_EXCLUDE_PREFIX,
|
||||||
ARG_ROOT,
|
ARG_ROOT,
|
||||||
|
ARG_IMAGE,
|
||||||
ARG_REPLACE,
|
ARG_REPLACE,
|
||||||
ARG_NO_PAGER,
|
ARG_NO_PAGER,
|
||||||
};
|
};
|
||||||
|
@ -2944,6 +2972,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
{ "prefix", required_argument, NULL, ARG_PREFIX },
|
{ "prefix", required_argument, NULL, ARG_PREFIX },
|
||||||
{ "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
|
{ "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
|
||||||
{ "root", required_argument, NULL, ARG_ROOT },
|
{ "root", required_argument, NULL, ARG_ROOT },
|
||||||
|
{ "image", required_argument, NULL, ARG_IMAGE },
|
||||||
{ "replace", required_argument, NULL, ARG_REPLACE },
|
{ "replace", required_argument, NULL, ARG_REPLACE },
|
||||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||||
{}
|
{}
|
||||||
|
@ -2954,7 +2983,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "hE", options, NULL)) >= 0)
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
||||||
|
@ -3004,6 +3033,21 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
return r;
|
return r;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARG_IMAGE:
|
||||||
|
r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_image);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Imply -E here since it makes little sense to create files persistently in the /run mointpoint of a disk image */
|
||||||
|
_fallthrough_;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
r = exclude_default_prefixes();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case ARG_REPLACE:
|
case ARG_REPLACE:
|
||||||
if (!path_is_absolute(optarg) ||
|
if (!path_is_absolute(optarg) ||
|
||||||
!endswith(optarg, ".conf"))
|
!endswith(optarg, ".conf"))
|
||||||
|
@ -3036,6 +3080,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"When --replace= is given, some configuration items must be specified");
|
"When --replace= is given, some configuration items must be specified");
|
||||||
|
|
||||||
|
if (arg_root && arg_user)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
|
"Combination of --user and --root= is not supported.");
|
||||||
|
|
||||||
|
if (arg_image && arg_root)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3211,6 +3262,9 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_array_hash_ops, char, string_
|
||||||
ItemArray, item_array_free);
|
ItemArray, item_array_free);
|
||||||
|
|
||||||
static int run(int argc, char *argv[]) {
|
static int run(int argc, char *argv[]) {
|
||||||
|
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||||
|
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||||
|
_cleanup_(umount_and_rmdir_and_freep) char *unlink_dir = NULL;
|
||||||
_cleanup_strv_free_ char **config_dirs = NULL;
|
_cleanup_strv_free_ char **config_dirs = NULL;
|
||||||
bool invalid_config = false;
|
bool invalid_config = false;
|
||||||
Iterator iterator;
|
Iterator iterator;
|
||||||
|
@ -3243,10 +3297,20 @@ static int run(int argc, char *argv[]) {
|
||||||
|
|
||||||
if (DEBUG_LOGGING) {
|
if (DEBUG_LOGGING) {
|
||||||
_cleanup_free_ char *t = NULL;
|
_cleanup_free_ char *t = NULL;
|
||||||
|
char **i;
|
||||||
|
|
||||||
t = strv_join(config_dirs, "\n\t");
|
STRV_FOREACH(i, config_dirs) {
|
||||||
if (t)
|
_cleanup_free_ char *j = NULL;
|
||||||
log_debug("Looking for configuration files in (higher priority first):\n\t%s", t);
|
|
||||||
|
j = path_join(arg_root, *i);
|
||||||
|
if (!j)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
if (!strextend(&t, "\n\t", j, NULL))
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("Looking for configuration files in (higher priority first):%s", t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg_cat_config) {
|
if (arg_cat_config) {
|
||||||
|
@ -3261,6 +3325,23 @@ static int run(int argc, char *argv[]) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
if (arg_image) {
|
||||||
|
assert(!arg_root);
|
||||||
|
|
||||||
|
r = mount_image_privately_interactively(
|
||||||
|
arg_image,
|
||||||
|
DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_VALIDATE_OS|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK,
|
||||||
|
&unlink_dir,
|
||||||
|
&loop_device,
|
||||||
|
&decrypted_image);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
arg_root = strdup(unlink_dir);
|
||||||
|
if (!arg_root)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
items = ordered_hashmap_new(&item_array_hash_ops);
|
items = ordered_hashmap_new(&item_array_hash_ops);
|
||||||
globs = ordered_hashmap_new(&item_array_hash_ops);
|
globs = ordered_hashmap_new(&item_array_hash_ops);
|
||||||
if (!items || !globs)
|
if (!items || !globs)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Permit User Sessions
|
Description=Permit User Sessions
|
||||||
Documentation=man:systemd-user-sessions.service(8)
|
Documentation=man:systemd-user-sessions.service(8)
|
||||||
After=remote-fs.target nss-user-lookup.target network.target
|
After=remote-fs.target nss-user-lookup.target network.target home.mount
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
|
|
Loading…
Reference in New Issue