mirror of
https://github.com/systemd/systemd.git
synced 2024-12-05 08:13:48 +08:00
Merge pull request #16604 from poettering/tmpfiles-image
add --image= switch to tmpfiles, sysusers, journalctl
This commit is contained in:
commit
992aa67231
9
TODO
9
TODO
@ -120,9 +120,9 @@ Features:
|
||||
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
|
||||
operate on disk images directly. Specifically: bootctl, tmpfiles, sysusers,
|
||||
systemctl, repart, journalctl, coredumpctl. (Already done: systemd-nspawn,
|
||||
systemd-firstboot)
|
||||
operate on disk images directly. Specifically: bootctl, systemctl,
|
||||
coredumpctl. (Already done: systemd-nspawn, 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
|
||||
|
||||
@ -337,9 +337,6 @@ Features:
|
||||
right) become genuine first class citizens, and we gain automatic, sane JSON
|
||||
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
|
||||
that are linked to these places instead of copied. After all they are
|
||||
constant vendor data.
|
||||
|
@ -756,16 +756,29 @@
|
||||
<varlistentry>
|
||||
<term><option>--root=<replaceable>ROOT</replaceable></option></term>
|
||||
|
||||
<listitem><para>Takes a directory path as an argument. If
|
||||
specified, journalctl will operate on journal directories and catalog file hierarchy
|
||||
underneath the specified directory instead of the root
|
||||
directory (e.g. <option>--update-catalog</option> will create
|
||||
<filename><replaceable>ROOT</replaceable>/var/lib/systemd/catalog/database</filename>,
|
||||
and journal files under <filename><replaceable>ROOT</replaceable>/run/journal/</filename>
|
||||
or <filename><replaceable>ROOT</replaceable>/var/log/journal/</filename> will be displayed).
|
||||
<listitem><para>Takes a directory path as an argument. If specified, <command>journalctl</command>
|
||||
will operate on journal directories and catalog file hierarchy underneath the specified directory
|
||||
instead of the root directory (e.g. <option>--update-catalog</option> will create
|
||||
<filename><replaceable>ROOT</replaceable>/var/lib/systemd/catalog/database</filename>, and journal
|
||||
files under <filename><replaceable>ROOT</replaceable>/run/journal/</filename> or
|
||||
<filename><replaceable>ROOT</replaceable>/var/log/journal/</filename> will be displayed).
|
||||
</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,
|
||||
<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>
|
||||
<term><option>--namespace=<replaceable>NAMESPACE</replaceable></option></term>
|
||||
|
||||
|
@ -68,6 +68,19 @@
|
||||
paths. </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></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--replace=<replaceable>PATH</replaceable></option></term>
|
||||
<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
|
||||
times.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--exclude-prefix=<replaceable>path</replaceable></option></term>
|
||||
<listitem><para>Ignore rules with paths that start with the
|
||||
@ -156,6 +157,16 @@
|
||||
times.</para></listitem>
|
||||
</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>
|
||||
<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
|
||||
@ -164,7 +175,26 @@
|
||||
<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>
|
||||
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>
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "kbd-util.h"
|
||||
#include "libcrypt-util.h"
|
||||
#include "locale-util.h"
|
||||
#include "loop-util.h"
|
||||
#include "main-func.h"
|
||||
#include "memory-util.h"
|
||||
#include "mkdir.h"
|
||||
@ -907,75 +906,6 @@ static int process_kernel_cmdline(void) {
|
||||
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) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
@ -1353,9 +1283,22 @@ static int run(int argc, char *argv[]) {
|
||||
return 0; /* disabled */
|
||||
}
|
||||
|
||||
r = setup_image(&unlink_dir, &loop_device, &decrypted_image);
|
||||
if (r < 0)
|
||||
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();
|
||||
}
|
||||
|
||||
r = process_locale();
|
||||
if (r < 0)
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "chattr-util.h"
|
||||
#include "def.h"
|
||||
#include "device-private.h"
|
||||
#include "dissect-image.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
@ -51,6 +52,7 @@
|
||||
#include "logs-show.h"
|
||||
#include "memory-util.h"
|
||||
#include "mkdir.h"
|
||||
#include "mount-util.h"
|
||||
#include "mountpoint-util.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "pager.h"
|
||||
@ -121,6 +123,7 @@ static bool arg_reverse = false;
|
||||
static int arg_journal_type = 0;
|
||||
static int arg_namespace_flags = 0;
|
||||
static char *arg_root = NULL;
|
||||
static char *arg_image = NULL;
|
||||
static const char *arg_machine = NULL;
|
||||
static const char *arg_namespace = NULL;
|
||||
static uint64_t arg_vacuum_size = 0;
|
||||
@ -375,6 +378,7 @@ static int help(void) {
|
||||
" -D --directory=PATH Show journal files from directory\n"
|
||||
" --file=PATH Show journal file\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"
|
||||
" --interval=TIME Time interval for changing the FSS sealing 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_SYSTEM,
|
||||
ARG_ROOT,
|
||||
ARG_IMAGE,
|
||||
ARG_HEADER,
|
||||
ARG_FACILITY,
|
||||
ARG_SETUP_KEYS,
|
||||
@ -478,6 +483,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "directory", required_argument, NULL, 'D' },
|
||||
{ "file", required_argument, NULL, ARG_FILE },
|
||||
{ "root", required_argument, NULL, ARG_ROOT },
|
||||
{ "image", required_argument, NULL, ARG_IMAGE },
|
||||
{ "header", no_argument, NULL, ARG_HEADER },
|
||||
{ "identifier", required_argument, NULL, 't' },
|
||||
{ "priority", required_argument, NULL, 'p' },
|
||||
@ -713,7 +719,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
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)
|
||||
return r;
|
||||
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)
|
||||
arg_lines = 10;
|
||||
|
||||
if (!!arg_directory + !!arg_file + !!arg_machine + !!arg_root > 1) {
|
||||
log_error("Please specify at most one of -D/--directory=, --file=, -M/--machine=, --root.");
|
||||
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=, --image=.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -2084,6 +2096,9 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
|
||||
}
|
||||
|
||||
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 use_cursor = false, after_cursor = false;
|
||||
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
||||
@ -2101,6 +2116,24 @@ int main(int argc, char *argv[]) {
|
||||
if (r <= 0)
|
||||
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);
|
||||
sigbus_install();
|
||||
|
||||
|
@ -33,8 +33,10 @@
|
||||
#include "hexdecoct.h"
|
||||
#include "hostname-util.h"
|
||||
#include "id128-util.h"
|
||||
#include "mkdir.h"
|
||||
#include "mount-util.h"
|
||||
#include "mountpoint-util.h"
|
||||
#include "namespace-util.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "os-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)
|
||||
if (partition_number == m->partition_number && !isempty(m->options))
|
||||
return m->options;
|
||||
|
||||
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[] = {
|
||||
[PARTITION_ROOT] = "root",
|
||||
[PARTITION_ROOT_SECONDARY] = "root-secondary",
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "list.h"
|
||||
#include "loop-util.h"
|
||||
#include "macro.h"
|
||||
|
||||
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);
|
||||
bool dissected_image_can_do_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);
|
||||
|
@ -7,17 +7,19 @@
|
||||
#include "conf-files.h"
|
||||
#include "copy.h"
|
||||
#include "def.h"
|
||||
#include "dissect-image.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "hashmap.h"
|
||||
#include "main-func.h"
|
||||
#include "mount-util.h"
|
||||
#include "pager.h"
|
||||
#include "path-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "set.h"
|
||||
#include "selinux-util.h"
|
||||
#include "set.h"
|
||||
#include "smack-util.h"
|
||||
#include "specifier.h"
|
||||
#include "string-util.h"
|
||||
@ -63,6 +65,7 @@ typedef struct Item {
|
||||
} Item;
|
||||
|
||||
static char *arg_root = NULL;
|
||||
static char *arg_image = NULL;
|
||||
static bool arg_cat_config = false;
|
||||
static const char *arg_replace = NULL;
|
||||
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(uid_range, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
|
||||
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
|
||||
@ -1739,6 +1743,7 @@ static int help(void) {
|
||||
" --version Show package version\n"
|
||||
" --cat-config Show configuration files\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"
|
||||
" --inline Treat arguments as configuration lines\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_CAT_CONFIG,
|
||||
ARG_ROOT,
|
||||
ARG_IMAGE,
|
||||
ARG_REPLACE,
|
||||
ARG_INLINE,
|
||||
ARG_NO_PAGER,
|
||||
@ -1766,6 +1772,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "version", no_argument, NULL, ARG_VERSION },
|
||||
{ "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
|
||||
{ "root", required_argument, NULL, ARG_ROOT },
|
||||
{ "image", required_argument, NULL, ARG_IMAGE },
|
||||
{ "replace", required_argument, NULL, ARG_REPLACE },
|
||||
{ "inline", no_argument, NULL, ARG_INLINE },
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||
@ -1797,6 +1804,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return r;
|
||||
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:
|
||||
if (!path_is_absolute(optarg) ||
|
||||
!endswith(optarg, ".conf"))
|
||||
@ -1829,6 +1842,9 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"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;
|
||||
}
|
||||
|
||||
@ -1880,6 +1896,9 @@ static int read_config_files(char **args) {
|
||||
}
|
||||
|
||||
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;
|
||||
Iterator iterator;
|
||||
Item *i;
|
||||
@ -1900,6 +1919,23 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
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
|
||||
* configuration files and insert the positional arguments at the specified
|
||||
* place. Otherwise, if command line arguments are specified, execute just
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "copy.h"
|
||||
#include "def.h"
|
||||
#include "dirent-util.h"
|
||||
#include "dissect-image.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@ -38,6 +39,7 @@
|
||||
#include "macro.h"
|
||||
#include "main-func.h"
|
||||
#include "mkdir.h"
|
||||
#include "mount-util.h"
|
||||
#include "mountpoint-util.h"
|
||||
#include "offline-passwd.h"
|
||||
#include "pager.h"
|
||||
@ -164,6 +166,7 @@ static PagerFlags arg_pager_flags = 0;
|
||||
static char **arg_include_prefixes = NULL;
|
||||
static char **arg_exclude_prefixes = NULL;
|
||||
static char *arg_root = NULL;
|
||||
static char *arg_image = NULL;
|
||||
static char *arg_replace = NULL;
|
||||
|
||||
#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_exclude_prefixes, 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_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);
|
||||
}
|
||||
|
||||
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) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
int r;
|
||||
@ -2904,7 +2929,9 @@ static int help(void) {
|
||||
" --boot Execute actions only safe at boot\n"
|
||||
" --prefix=PATH Only apply 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"
|
||||
" --image=PATH Operate on disk image as filesystem root\n"
|
||||
" --replace=PATH Treat arguments as replacement for PATH\n"
|
||||
" --no-pager Do not pipe output into a pager\n"
|
||||
"\nSee the %s for details.\n"
|
||||
@ -2928,6 +2955,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_PREFIX,
|
||||
ARG_EXCLUDE_PREFIX,
|
||||
ARG_ROOT,
|
||||
ARG_IMAGE,
|
||||
ARG_REPLACE,
|
||||
ARG_NO_PAGER,
|
||||
};
|
||||
@ -2944,6 +2972,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "prefix", required_argument, NULL, ARG_PREFIX },
|
||||
{ "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
|
||||
{ "root", required_argument, NULL, ARG_ROOT },
|
||||
{ "image", required_argument, NULL, ARG_IMAGE },
|
||||
{ "replace", required_argument, NULL, ARG_REPLACE },
|
||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||
{}
|
||||
@ -2954,7 +2983,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
|
||||
while ((c = getopt_long(argc, argv, "hE", options, NULL)) >= 0)
|
||||
|
||||
switch (c) {
|
||||
|
||||
@ -3004,6 +3033,21 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return r;
|
||||
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:
|
||||
if (!path_is_absolute(optarg) ||
|
||||
!endswith(optarg, ".conf"))
|
||||
@ -3036,6 +3080,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"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;
|
||||
}
|
||||
|
||||
@ -3211,6 +3262,9 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_array_hash_ops, char, string_
|
||||
ItemArray, item_array_free);
|
||||
|
||||
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;
|
||||
bool invalid_config = false;
|
||||
Iterator iterator;
|
||||
@ -3243,10 +3297,20 @@ static int run(int argc, char *argv[]) {
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
char **i;
|
||||
|
||||
t = strv_join(config_dirs, "\n\t");
|
||||
if (t)
|
||||
log_debug("Looking for configuration files in (higher priority first):\n\t%s", t);
|
||||
STRV_FOREACH(i, config_dirs) {
|
||||
_cleanup_free_ char *j = NULL;
|
||||
|
||||
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) {
|
||||
@ -3261,6 +3325,23 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
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);
|
||||
globs = ordered_hashmap_new(&item_array_hash_ops);
|
||||
if (!items || !globs)
|
||||
|
Loading…
Reference in New Issue
Block a user