Compare commits

..

12 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek 992aa67231
Merge pull request #16604 from poettering/tmpfiles-image
add --image= switch to tmpfiles, sysusers, journalctl
2020-08-07 10:08:42 +02:00
Lennart Poettering e3eec1fd10 journalctl: in "-o cat" mode show color
Let's provide a modicum of niceness, even in this barebones mode.

Fixes: #16232
2020-08-07 10:05:13 +02:00
Lennart Poettering bbac7da2b3 units: order systemd-user-sessions.service after home.mount
This should make /home as automount work reasonably well.

If /home is an automount this has little effect at boot, because if the
automount is not triggered it doesn't matter how the associated mount is
ordered.

It does matter at shutdown however, where home.mount is likely active
now. There the ordering means we'll end sessions first, and only then
deactivate home.mount.

Fixes: #16291
2020-08-07 10:02:05 +02:00
Lennart Poettering 612d3a68d6 update TODO 2020-08-05 20:34:58 +02:00
Lennart Poettering 71b1d2ded1 man: document the new --image= switches in journalctl/sysusers/tmpfiles 2020-08-05 20:34:58 +02:00
Lennart Poettering cc171228d4 journalctl: add --image= switch 2020-08-05 20:34:58 +02:00
Lennart Poettering 0c3ee12737 sysusers: add support for a --image= switch 2020-08-05 20:34:58 +02:00
Lennart Poettering 63d3d0a50b tmpfiles: support --image= similar to --root= 2020-08-05 20:34:58 +02:00
Lennart Poettering 6aa05ebdd8 firstboot: move --image= logic into common code
That way we can reuse it in tmpfiles/sysusers/journalctl and so on.
2020-08-05 20:34:58 +02:00
Lennart Poettering b8e35011f7 tmpfiles: properly prefix paths in debug outputs
This is otherwise very confusing...
2020-08-05 20:26:25 +02:00
Lennart Poettering b63aacaa1a tmpfiles: we don't support the combination of --root and --user, hence refuse it
--user only really works with certain env vars such as XDG_RUNTIME_DIR
set, but that's just weird if --root= is used.
2020-08-05 20:26:25 +02:00
Lennart Poettering dd04fb3268 tmpfiles: add new switch -E for quickly excluding /proc, /dev, /sys and /run 2020-08-05 20:26:25 +02:00
12 changed files with 375 additions and 115 deletions

9
TODO
View File

@ -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.

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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,9 +1283,22 @@ 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) {
if (r < 0) assert(!arg_root);
return r;
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();
}
r = process_locale(); r = process_locale();
if (r < 0) if (r < 0)

View File

@ -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();

View File

@ -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",

View File

@ -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);

View File

@ -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)) {
assert(highlight[0] <= highlight[1]); if (highlight) {
assert(highlight[1] <= l); assert(highlight[0] <= highlight[1]);
assert(highlight[1] <= l);
fwrite((const char*) data, 1, highlight[0], f); fputs(color_on, f);
fwrite(highlight_on, 1, strlen(highlight_on), f); fwrite((const char*) data, 1, highlight[0], f);
fwrite((const char*) data + highlight[0], 1, highlight[1] - highlight[0], f); fputs(highlight_on, f);
fwrite(highlight_off, 1, strlen(highlight_off), f); fwrite((const char*) data + highlight[0], 1, highlight[1] - highlight[0], f);
fwrite((const char*) data + highlight[1], 1, l - highlight[1], f); fputs(color_on, 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;
} }

View File

@ -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

View File

@ -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)

View File

@ -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