]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #16690 from poettering/userdb-group-desc
authorAnita Zhang <the.anitazha@gmail.com>
Tue, 11 Aug 2020 07:27:54 +0000 (00:27 -0700)
committerGitHub <noreply@github.com>
Tue, 11 Aug 2020 07:27:54 +0000 (00:27 -0700)
description field for group records

29 files changed:
TODO
docs/AUTOMATIC_BOOT_ASSESSMENT.md
hwdb.d/60-sensor.hwdb
man/journalctl.xml
man/org.freedesktop.systemd1.xml
man/systemd-sysusers.xml
man/systemd-tmpfiles.xml
src/basic/user-util.c
src/basic/user-util.h
src/boot/bless-boot.c
src/firstboot/firstboot.c
src/journal/journal-qrcode.c
src/journal/journalctl.c
src/network/networkd-address.c
src/network/networkd-link.c
src/network/networkd-link.h
src/shared/dissect-image.c
src/shared/dissect-image.h
src/shared/logs-show.c
src/shared/user-record-nss.c
src/shared/user-record.c
src/systemctl/systemctl.c
src/sysusers/sysusers.c
src/test/test-nss.c
src/test/test-seccomp.c
src/test/test-user-util.c
src/tmpfiles/tmpfiles.c
units/systemd-user-sessions.service.in
units/systemd-volatile-root.service.in

diff --git a/TODO b/TODO
index c038a0d115d77c92fd4902d03291c613853d8e9a..c0fbf8bc6ae9a5ad30678443c2cdddda6f2e09bc 100644 (file)
--- a/TODO
+++ b/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.
index 83ddf28fdd8770a87abc9b1445b46af12547b8bd..f6d63afcdf8eb783c9c5cb7d8966605e8be2a124 100644 (file)
@@ -10,12 +10,11 @@ systemd provides support for automatically reverting back to the previous
 version of the OS or kernel in case the system consistently fails to boot. This
 support is built into various of its components. When used together these
 components provide a complete solution on UEFI systems, built as add-on to the
-[Boot Loader
-Specification](https://systemd.io/BOOT_LOADER_SPECIFICATION). However, the
-different components may also be used independently, and in combination with
-other software, to implement similar schemes, for example with other boot
-loaders or for non-UEFI systems. Here's a brief overview of the complete set of
-components:
+[Boot Loader Specification](https://systemd.io/BOOT_LOADER_SPECIFICATION).
+However, the different components may also be used independently, and in
+combination with other software, to implement similar schemes, for example with
+other boot loaders or for non-UEFI systems. Here's a brief overview of the
+complete set of components:
 
 * The
   [`systemd-boot(7)`](https://www.freedesktop.org/software/systemd/man/systemd-boot.html)
@@ -45,11 +44,10 @@ components:
 
 * The `boot-complete.target` target unit (see
   [`systemd.special(7)`](https://www.freedesktop.org/software/systemd/man/systemd.special.html))
-  serves as a generic extension point both for units that shall be considered
-  necessary to consider a boot successful on one side (example:
-  `systemd-boot-check-no-failures.service` as described above), and units that
-  want to act only if the boot is successful on the other (example:
-  `systemd-bless-boot.service` as described above).
+  serves as a generic extension point both for units that are necessary to
+  consider a boot successful (example: `systemd-boot-check-no-failures.service`
+  as described above), and units that want to act only if the boot is
+  successful (example: `systemd-bless-boot.service` as described above).
 
 * The
   [`kernel-install(8)`](https://www.freedesktop.org/software/systemd/man/kernel-install.html)
index 092d356b64195972be065d7925695e1918410c42..36ff80fd15b818a3fc7634817609667f866d7784 100644 (file)
@@ -111,6 +111,7 @@ sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100CHI*
 sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:pnT300CHI*
  ACCEL_MOUNT_MATRIX=0, -1, 0; 1, 0, 0; 0, 0, 1
 
+sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnM80TA*
 sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:*pnT100TA*
 sensor:modalias:acpi:INVN6500*:dmi:*svnASUSTeK*:pnT200TA*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
index 07310d90a1a99214f92ecb2fa18674602e751703..a03493fc35b41b4e322b2b7078da3cfcc36e27fa 100644 (file)
       <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>
 
index 6b16ae16da917b1c15eff47d35bc70534de6089f..8a7990ff7d63c9d3c5b1e0962c1cfaa40456cd24 100644 (file)
@@ -8778,7 +8778,7 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
   <refsect1>
     <title>Scope Unit Objects</title>
 
-    <para>All slice unit objects implement the <interfacename>org.freedesktop.systemd1.Scope</interfacename>
+    <para>All scope unit objects implement the <interfacename>org.freedesktop.systemd1.Scope</interfacename>
     interface (described here) in addition to the generic
     <interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
 
index cc026256990257b73cacfcbe8b85959dd44894cc..1e5853a55b8e86469d8f0a5a2b6c3b8a4b9afd5a 100644 (file)
         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
index 998fd0911baa5ba35df16e3a64d81ca51d81b53b..4510fb120a74e0200f530d2598b2f0a67a37b9d3 100644 (file)
         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
         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
         <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>
index 8115065b5eca119a8515a776cb27428ee9d76b18..0e96a75797a95fdb9412ee7acada798e1ff8d7c0 100644 (file)
@@ -863,6 +863,37 @@ bool valid_gecos(const char *d) {
         return true;
 }
 
+char *mangle_gecos(const char *d) {
+        char *mangled;
+
+        /* Makes sure the provided string becomes valid as a GEGOS field, by dropping bad chars. glibc's
+         * putwent() only changes \n and : to spaces. We do more: replace all CC too, and remove invalid
+         * UTF-8 */
+
+        mangled = strdup(d);
+        if (!mangled)
+                return NULL;
+
+        for (char *i = mangled; *i; i++) {
+                int len;
+
+                if ((uint8_t) *i < (uint8_t) ' ' || *i == ':') {
+                        *i = ' ';
+                        continue;
+                }
+
+                len = utf8_encoded_valid_unichar(i, (size_t) -1);
+                if (len < 0) {
+                        *i = ' ';
+                        continue;
+                }
+
+                i += len - 1;
+        }
+
+        return mangled;
+}
+
 bool valid_home(const char *p) {
         /* Note that this function is also called by valid_shell(), any
          * changes must account for that. */
index 1f267d21a3f3f188af142b3f7e2925b9626fd450..7c142dd1e66e6521f91a2cf73eb247a755870257 100644 (file)
@@ -105,6 +105,7 @@ typedef enum ValidUserFlags {
 
 bool valid_user_group_name(const char *u, ValidUserFlags flags);
 bool valid_gecos(const char *d);
+char *mangle_gecos(const char *d);
 bool valid_home(const char *p);
 
 static inline bool valid_shell(const char *p) {
index b96e1f927fffab84d1e4f9d28d4dab6a11875c0e..0824266a809a89688961ae77870c8e9f5d5ce1ec 100644 (file)
@@ -34,6 +34,7 @@ static int help(int argc, char *argv[], void *userdata) {
         printf("%s [OPTIONS...] COMMAND\n"
                "\n%sMark the boot process as good or bad.%s\n"
                "\nCommands:\n"
+               "     status          Show status of current boot loader entry\n"
                "     good            Mark this boot as good\n"
                "     bad             Mark this boot as bad\n"
                "     indeterminate   Undo any marking as good or bad\n"
index 78abcbeff6ca4d4dd7ff29593cf2b5df6f8391c4..d56de0bb2593010248aa167c235239a6d9b316f5 100644 (file)
@@ -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)
index dddbd7b3813fa65e5e7967fa8e94e762bb295378..8c8360853ebf9848a2b3abe682cd9beadfc608c0 100644 (file)
@@ -46,7 +46,7 @@ int print_qr_code(
         _cleanup_(dlclosep) void *dl = NULL;
         _cleanup_free_ char *url = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        size_t url_size = 0, i;
+        size_t url_size = 0;
         unsigned x, y;
         QRcode* qr;
         int r;
@@ -79,7 +79,7 @@ int print_qr_code(
 
         fputs("fss://", f);
 
-        for (i = 0; i < seed_size; i++) {
+        for (size_t i = 0; i < seed_size; i++) {
                 if (i > 0 && i % 3 == 0)
                         fputc('-', f);
                 fprintf(f, "%02x", ((uint8_t*) seed)[i]);
index 79daa43494db41d73d0d4df7e98817015e4706c5..acdceea037284eb59291f28fe87a776cf1a96d33 100644 (file)
@@ -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;
         }
 
@@ -1778,7 +1790,7 @@ static int add_syslog_identifier(sd_journal *j) {
 
 static int setup_keys(void) {
 #if HAVE_GCRYPT
-        size_t mpk_size, seed_size, state_size, i;
+        size_t mpk_size, seed_size, state_size;
         _cleanup_(unlink_and_freep) char *k = NULL;
         _cleanup_free_ char *p = NULL;
         uint8_t *mpk, *seed, *state;
@@ -1890,52 +1902,49 @@ static int setup_keys(void) {
 
         k = mfree(k);
 
+        _cleanup_free_ char *hn = NULL;
+
         if (on_tty()) {
+                hn = gethostname_malloc();
+                if (hn)
+                        hostname_cleanup(hn);
+
+                char tsb[FORMAT_TIMESPAN_MAX];
                 fprintf(stderr,
+                        "\nNew keys have been generated for host %s%s" SD_ID128_FORMAT_STR ".\n"
                         "\n"
-                        "The new key pair has been generated. The %ssecret sealing key%s has been written to\n"
-                        "the following local file. This key file is automatically updated when the\n"
-                        "sealing key is advanced. It should not be used on multiple hosts.\n"
+                        "The %ssecret sealing key%s has been written to the following local file.\n"
+                        "This key file is automatically updated when the sealing key is advanced.\n"
+                        "It should not be used on multiple hosts.\n"
                         "\n"
                         "\t%s\n"
                         "\n"
+                        "The sealing key is automatically changed every %s.\n"
+                        "\n"
                         "Please write down the following %ssecret verification key%s. It should be stored\n"
-                        "at a safe location and should not be saved locally on disk.\n"
+                        "in a safe location and should not be saved locally on disk.\n"
                         "\n\t%s",
+                        hn ?: "", hn ? "/" : "", SD_ID128_FORMAT_VAL(machine),
                         ansi_highlight(), ansi_normal(),
                         p,
+                        format_timespan(tsb, sizeof(tsb), arg_interval, 0),
                         ansi_highlight(), ansi_normal(),
                         ansi_highlight_red());
                 fflush(stderr);
         }
-        for (i = 0; i < seed_size; i++) {
+
+        for (size_t i = 0; i < seed_size; i++) {
                 if (i > 0 && i % 3 == 0)
                         putchar('-');
                 printf("%02x", ((uint8_t*) seed)[i]);
         }
-
         printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
 
         if (on_tty()) {
-                _cleanup_free_ char *hn = NULL;
-                char tsb[FORMAT_TIMESPAN_MAX];
-
-                fprintf(stderr,
-                        "%s\n"
-                        "The sealing key is automatically changed every %s.\n",
-                        ansi_normal(),
-                        format_timespan(tsb, sizeof(tsb), arg_interval, 0));
-
-                hn = gethostname_malloc();
-                if (hn) {
-                        hostname_cleanup(hn);
-                        fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
-                } else
-                        fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
-
+                fprintf(stderr, "%s", ansi_normal());
 #if HAVE_QRENCODE
                 (void) print_qr_code(stderr,
-                                     "\nTo transfer the verification key to your phone please scan the QR code below:\n\n",
+                                     "\nTo transfer the verification key to your phone scan the QR code below:\n",
                                      seed, seed_size,
                                      n, arg_interval,
                                      hn, machine);
@@ -2084,6 +2093,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 +2113,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();
 
index b09d75e6158e7e6e39ba0ce891eaad5aa93ee1ad..0349ca6f93d6056fd1ccaf7cfe38e8d3f647b917 100644 (file)
@@ -487,7 +487,7 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
         r = sd_netlink_message_get_errno(m);
         if (r < 0 && r != -EADDRNOTAVAIL)
                 log_link_message_warning_errno(link, m, r, "Could not drop address");
-        else
+        else if (r >= 0)
                 (void) manager_rtnl_process_address(rtnl, m, link->manager);
 
         return 1;
index 0057d184f7658c88d61dfffd699dffb7d0e7aca2..c3bc3415a8bde40a54590b819a949543b7b07082 100644 (file)
@@ -1365,7 +1365,14 @@ static int link_request_set_addresses(Link *link) {
         assert(link->network);
         assert(link->state != _LINK_STATE_INVALID);
 
+        if (link->address_remove_messages != 0) {
+                log_link_debug(link, "Removing old addresses, new addresses will be configured later.");
+                link->request_static_addresses = true;
+                return 0;
+        }
+
         /* Reset all *_configured flags we are configuring. */
+        link->request_static_addresses = false;
         link->addresses_configured = false;
         link->addresses_ready = false;
         link->neighbors_configured = false;
@@ -2884,6 +2891,35 @@ static int link_drop_foreign_config(Link *link) {
         return 0;
 }
 
+static int remove_static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(m);
+        assert(link);
+        assert(link->ifname);
+        assert(link->address_remove_messages > 0);
+
+        link->address_remove_messages--;
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0 && r != -EADDRNOTAVAIL)
+                log_link_message_warning_errno(link, m, r, "Could not drop address");
+        else if (r >= 0)
+                (void) manager_rtnl_process_address(rtnl, m, link->manager);
+
+        if (link->address_remove_messages == 0 && link->request_static_addresses) {
+                link_set_state(link, LINK_STATE_CONFIGURING);
+                r = link_request_set_addresses(link);
+                if (r < 0)
+                        link_enter_failed(link);
+        }
+
+        return 1;
+}
+
 static int link_drop_config(Link *link) {
         Address *address, *pool_address;
         Neighbor *neighbor;
@@ -2896,18 +2932,19 @@ static int link_drop_config(Link *link) {
                 if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1 && link_ipv6ll_enabled(link))
                         continue;
 
-                r = address_remove(address, link, NULL);
+                r = address_remove(address, link, remove_static_address_handler);
                 if (r < 0)
                         return r;
 
+                link->address_remove_messages++;
+
                 /* If this address came from an address pool, clean up the pool */
-                LIST_FOREACH(addresses, pool_address, link->pool_addresses) {
+                LIST_FOREACH(addresses, pool_address, link->pool_addresses)
                         if (address_equal(address, pool_address)) {
                                 LIST_REMOVE(addresses, link->pool_addresses, pool_address);
                                 address_free(pool_address);
                                 break;
                         }
-                }
         }
 
         SET_FOREACH(neighbor, link->neighbors, i) {
index 7f99c0f47b2ac4932fbedf4a262da3c684f4b609..ab5c3fd26a09d89482b0d10b2cfd237a4abe0699 100644 (file)
@@ -75,6 +75,7 @@ typedef struct Link {
         LinkAddressState address_state;
 
         unsigned address_messages;
+        unsigned address_remove_messages;
         unsigned address_label_messages;
         unsigned neighbor_messages;
         unsigned route_messages;
@@ -111,6 +112,7 @@ typedef struct Link {
         sd_ipv4ll *ipv4ll;
         bool ipv4ll_address_configured:1;
 
+        bool request_static_addresses:1;
         bool addresses_configured:1;
         bool addresses_ready:1;
         bool neighbors_configured:1;
index e96658ca66933ab0ed23255ffa664cb6276a1436..c98c84993e2e3cb90fdd873a1a4dfbfde42f299a 100644 (file)
 #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",
index 52aa377a671a32616ce11a7162ae5c68c1b7912c..7f67c8745e858c4261d55883972ff3c0da489025 100644 (file)
@@ -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);
index 899e894ab7e9fad318710aef15bcdc893849acfb..780ac508ced3300a9a1c5199dfbe05d014e6d632 100644 (file)
@@ -168,8 +168,12 @@ typedef struct ParseFieldVec {
         size_t *target_len;
 } ParseFieldVec;
 
-#define PARSE_FIELD_VEC_ENTRY(_field, _target, _target_len) \
-        { .field = _field, .field_len = strlen(_field), .target = _target, .target_len = _target_len }
+#define PARSE_FIELD_VEC_ENTRY(_field, _target, _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) {
         unsigned i;
@@ -1122,19 +1126,17 @@ static int output_cat_field(
                 FILE *f,
                 sd_journal *j,
                 OutputFlags flags,
+                int prio,
                 const char *field,
                 const size_t highlight[2]) {
 
-        const char *highlight_on, *highlight_off;
+        const char *color_on = "", *color_off = "", *highlight_on = "";
         const void *data;
         size_t l, fl;
         int r;
 
-        if (FLAGS_SET(flags, OUTPUT_COLOR)) {
-                highlight_on = ANSI_HIGHLIGHT_RED;
-                highlight_off = ANSI_NORMAL;
-        } else
-                highlight_on = highlight_off = "";
+        if (FLAGS_SET(flags, OUTPUT_COLOR))
+                get_log_colors(prio, &color_on, &color_off, &highlight_on);
 
         r = sd_journal_get_data(j, field, &data, &l);
         if (r == -EBADMSG) {
@@ -1153,15 +1155,23 @@ static int output_cat_field(
         data = (const uint8_t*) data + fl + 1;
         l -= fl + 1;
 
-        if (highlight && FLAGS_SET(flags, OUTPUT_COLOR)) {
-                assert(highlight[0] <= highlight[1]);
-                assert(highlight[1] <= l);
-
-                fwrite((const char*) data, 1, highlight[0], f);
-                fwrite(highlight_on, 1, strlen(highlight_on), f);
-                fwrite((const char*) data + highlight[0], 1, highlight[1] - highlight[0], f);
-                fwrite(highlight_off, 1, strlen(highlight_off), f);
-                fwrite((const char*) data + highlight[1], 1, l - highlight[1], f);
+        if (FLAGS_SET(flags, OUTPUT_COLOR)) {
+                if (highlight) {
+                        assert(highlight[0] <= highlight[1]);
+                        assert(highlight[1] <= l);
+
+                        fputs(color_on, f);
+                        fwrite((const char*) data, 1, highlight[0], f);
+                        fputs(highlight_on, f);
+                        fwrite((const char*) data + highlight[0], 1, highlight[1] - highlight[0], 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
                 fwrite((const char*) data, 1, l, f);
 
@@ -1178,20 +1188,44 @@ static int output_cat(
                 const Set *output_fields,
                 const size_t highlight[2]) {
 
+        int r, prio = LOG_INFO;
         const char *field;
         Iterator iterator;
-        int r;
 
         assert(j);
         assert(f);
 
         (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))
-                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) {
-                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)
                         return r;
         }
index f265a2af9333e24457cd634b77cbb77ab0840090..b27a12c55d06bd15e2ad732c009eb066cb03e179 100644 (file)
@@ -5,6 +5,7 @@
 #include "libcrypt-util.h"
 #include "strv.h"
 #include "user-record-nss.h"
+#include "user-util.h"
 
 #define SET_IF(field, condition, value, fallback)  \
         field = (condition) ? (value) : (fallback)
@@ -34,10 +35,25 @@ int nss_passwd_to_user_record(
         if (r < 0)
                 return r;
 
-        r = free_and_strdup(&hr->real_name,
-                            streq_ptr(pwd->pw_gecos, hr->user_name) ? NULL : empty_to_null(pwd->pw_gecos));
-        if (r < 0)
-                return r;
+        /* Some bad NSS modules synthesize GECOS fields with embedded ":" or "\n" characters, which are not
+         * something we can output in /etc/passwd compatible format, since these are record separators
+         * there. We normally refuse that, but we need to maintain compatibility with arbitrary NSS modules,
+         * hence let's do what glibc does: mangle the data to fit the format. */
+        if (isempty(pwd->pw_gecos) || streq_ptr(pwd->pw_gecos, hr->user_name))
+                hr->real_name = mfree(hr->real_name);
+        else if (valid_gecos(pwd->pw_gecos)) {
+                r = free_and_strdup(&hr->real_name, pwd->pw_gecos);
+                if (r < 0)
+                        return r;
+        } else {
+                _cleanup_free_ char *mangled = NULL;
+
+                mangled = mangle_gecos(pwd->pw_gecos);
+                if (!mangled)
+                        return -ENOMEM;
+
+                free_and_replace(hr->real_name, mangled);
+        }
 
         r = free_and_strdup(&hr->home_directory, empty_to_null(pwd->pw_dir));
         if (r < 0)
index 801de197748ecfb1d316f741af6f52f1b364ce9c..678f04e53747ceec718d563164d4cf38fd746155 100644 (file)
@@ -206,7 +206,6 @@ int json_dispatch_realm(const char *name, JsonVariant *variant, JsonDispatchFlag
 int json_dispatch_gecos(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
         char **s = userdata;
         const char *n;
-        int r;
 
         if (json_variant_is_null(variant)) {
                 *s = mfree(*s);
@@ -217,12 +216,20 @@ int json_dispatch_gecos(const char *name, JsonVariant *variant, JsonDispatchFlag
                 return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
 
         n = json_variant_string(variant);
-        if (!valid_gecos(n))
-                return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid GECOS compatible real name.", strna(name));
+        if (valid_gecos(n)) {
+                if (free_and_strdup(s, n) < 0)
+                        return json_log_oom(variant, flags);
+        } else {
+                _cleanup_free_ char *m = NULL;
 
-        r = free_and_strdup(s, n);
-        if (r < 0)
-                return json_log(variant, flags, r, "Failed to allocate string: %m");
+                json_log(variant, flags|JSON_DEBUG, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid GECOS compatible string, mangling.", strna(name));
+
+                m = mangle_gecos(n);
+                if (!m)
+                        return json_log_oom(variant, flags);
+
+                free_and_replace(*s, m);
+        }
 
         return 0;
 }
index d55a89efabcfcd7684815d3cf1967248a6c9d8d3..6e6e1810a046b698ee4c625be9dad613a625f3eb 100644 (file)
@@ -7751,7 +7751,7 @@ static int systemctl_help(void) {
                "  -M --machine=CONTAINER Operate on a local container\n"
                "  -t --type=TYPE         List units of a particular type\n"
                "     --state=STATE       List units with particular LOAD or SUB or ACTIVE state\n"
-               "     --failed            Shorcut for --state=failed\n"
+               "     --failed            Shortcut for --state=failed\n"
                "  -p --property=NAME     Show only properties by this name\n"
                "  -P NAME                Equivalent to --value --property=NAME\n"
                "  -a --all               Show all properties/all units currently in memory,\n"
index b5e7e08eee969c34c4617b6599ff12e0ac921da2..383a62c598b4e535d8f396c1ffc9bf919405500d 100644 (file)
@@ -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
index 6ba0f6887e3854b7c96190b865d34acc5a078185..293d7a8468b2b342daafbae536a11bff6d7a0576 100644 (file)
@@ -54,7 +54,7 @@ static const char* af_to_string(int family, char *buf, size_t buf_len) {
         return buf;
 }
 
-static void* open_handle(const char* dir, const char* module, int flags) {
+static void* open_handle(const char *dir, const char *module, int flags) {
         const char *path = NULL;
         void *handle;
 
@@ -63,6 +63,7 @@ static void* open_handle(const char* dir, const char* module, int flags) {
         if (!path || access(path, F_OK) < 0)
                 path = strjoina("libnss_", module, ".so.2");
 
+        log_debug("Using %s", path);
         handle = dlopen(path, flags);
         if (!handle)
                 log_error("Failed to load module %s: %s", module, dlerror());
@@ -70,10 +71,9 @@ static void* open_handle(const char* dir, const char* module, int flags) {
 }
 
 static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) {
-        const struct gaih_addrtuple *it;
         int n = 0;
 
-        for (it = tuples; it; it = it->next) {
+        for (const struct gaih_addrtuple *it = tuples; it; it = it->next) {
                 _cleanup_free_ char *a = NULL;
                 union in_addr_union u;
                 int r;
@@ -147,7 +147,10 @@ static void test_gethostbyname4_r(void *handle, const char *module, const char *
         fname = strjoina("_nss_", module, "_gethostbyname4_r");
         f = dlsym(handle, fname);
         log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
-        assert_se(f);
+        if (!f) {
+                log_info("%s not defined", fname);
+                return;
+        }
 
         status = f(name, &pat, buffer, sizeof buffer, &errno1, &errno2, &ttl);
         if (status == NSS_STATUS_SUCCESS) {
@@ -197,7 +200,10 @@ static void test_gethostbyname3_r(void *handle, const char *module, const char *
         fname = strjoina("_nss_", module, "_gethostbyname3_r");
         f = dlsym(handle, fname);
         log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
-        assert_se(f);
+        if (!f) {
+                log_info("%s not defined", fname);
+                return;
+        }
 
         status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl, &canon);
         log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
@@ -223,7 +229,10 @@ static void test_gethostbyname2_r(void *handle, const char *module, const char *
         fname = strjoina("_nss_", module, "_gethostbyname2_r");
         f = dlsym(handle, fname);
         log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
-        assert_se(f);
+        if (!f) {
+                log_info("%s not defined", fname);
+                return;
+        }
 
         status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2);
         log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s",
@@ -247,7 +256,10 @@ static void test_gethostbyname_r(void *handle, const char *module, const char *n
         fname = strjoina("_nss_", module, "_gethostbyname_r");
         f = dlsym(handle, fname);
         log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
-        assert_se(f);
+        if (!f) {
+                log_info("%s not defined", fname);
+                return;
+        }
 
         status = f(name, &host, buffer, sizeof buffer, &errno1, &errno2);
         log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s",
@@ -279,8 +291,10 @@ static void test_gethostbyaddr2_r(void *handle,
 
         log_full_errno(f ? LOG_DEBUG : LOG_INFO,  errno,
                        "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f);
-        if (!f)
+        if (!f) {
+                log_info("%s not defined", fname);
                 return;
+        }
 
         assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0);
 
@@ -314,8 +328,10 @@ static void test_gethostbyaddr_r(void *handle,
 
         log_full_errno(f ? LOG_DEBUG : LOG_INFO,  errno,
                        "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f);
-        if (!f)
+        if (!f) {
+                log_info("%s not defined", fname);
                 return;
+        }
 
         assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0);
 
@@ -388,14 +404,13 @@ static int make_addresses(struct local_address **addresses) {
         return 0;
 }
 
-static int test_one_module(const chardir,
+static int test_one_module(const char *dir,
                            const char *module,
                            char **names,
                            struct local_address *addresses,
                            int n_addresses) {
         void *handle;
         char **name;
-        int i;
 
         log_info("======== %s ========", module);
 
@@ -406,7 +421,7 @@ static int test_one_module(const char* dir,
         STRV_FOREACH(name, names)
                 test_byname(handle, module, *name);
 
-        for (i = 0; i < n_addresses; i++)
+        for (int i = 0; i < n_addresses; i++)
                 test_byaddr(handle, module,
                             &addresses[i].address,
                             FAMILY_ADDRESS_SIZE(addresses[i].family),
index eec2779a9e2a69cec60f08365b0ab4a26213bdf1..cebf5a1080b6d7a5a02cac823c192da2baeb7c45 100644 (file)
@@ -98,9 +98,6 @@ static void test_syscall_filter_set_find(void) {
 }
 
 static void test_filter_sets(void) {
-        unsigned i;
-        int r;
-
         log_info("/* %s */", __func__);
 
         if (!is_seccomp_available()) {
@@ -112,7 +109,7 @@ static void test_filter_sets(void) {
                 return;
         }
 
-        for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
+        for (unsigned i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
                 pid_t pid;
 
                 log_info("Testing %s", syscall_filter_sets[i].name);
@@ -121,7 +118,7 @@ static void test_filter_sets(void) {
                 assert_se(pid >= 0);
 
                 if (pid == 0) { /* Child? */
-                        int fd;
+                        int fd, r;
 
                         /* If we look at the default set (or one that includes it), allow-list instead of deny-list */
                         if (IN_SET(i, SYSCALL_FILTER_SET_DEFAULT, SYSCALL_FILTER_SET_SYSTEM_SERVICE))
index c9bff941be17673ab4d327057026a201e83511ea..306d08a2824cb9640075a6ed385da9796da19610 100644 (file)
@@ -452,6 +452,25 @@ static void test_parse_uid_range(void) {
         assert_se(parse_uid_range(" 01", &a, &b) == -EINVAL && a == 4 && b == 5);
 }
 
+static void test_mangle_gecos_one(const char *input, const char *expected) {
+        _cleanup_free_ char *p = NULL;
+
+        assert_se(p = mangle_gecos(input));
+        assert_se(streq(p, expected));
+        assert_se(valid_gecos(p));
+}
+
+static void test_mangle_gecos(void) {
+        test_mangle_gecos_one("", "");
+        test_mangle_gecos_one("root", "root");
+        test_mangle_gecos_one("wuff\nwuff", "wuff wuff");
+        test_mangle_gecos_one("wuff:wuff", "wuff wuff");
+        test_mangle_gecos_one("wuff\r\n:wuff", "wuff   wuff");
+        test_mangle_gecos_one("\n--wüff-wäff-wöff::", " --wüff-wäff-wöff  ");
+        test_mangle_gecos_one("\xc3\x28", " (");
+        test_mangle_gecos_one("\xe2\x28\xa1", " ( ");
+}
+
 int main(int argc, char *argv[]) {
         test_uid_to_name_one(0, "root");
         test_uid_to_name_one(UID_NOBODY, NOBODY_USER_NAME);
@@ -482,6 +501,7 @@ int main(int argc, char *argv[]) {
         test_valid_user_group_name_or_numeric_relaxed();
         test_valid_user_group_name_or_numeric();
         test_valid_gecos();
+        test_mangle_gecos();
         test_valid_home();
 
         test_make_salt();
index 2404e36bf2984873eeb709721115d7ad91a560bc..616a54b3c31c20f392d4a8e19bdcc40a6f89cea8 100644 (file)
@@ -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;
+
+                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();
+                }
 
-                t = strv_join(config_dirs, "\n\t");
-                if (t)
-                        log_debug("Looking for configuration files in (higher priority first):\n\t%s", t);
+                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)
index 6d585eb0a15d48791c837ae82f89f913295e73cb..13de728b1dba361e2bea1475bfc46aec18b7d17a 100644 (file)
@@ -10,7 +10,7 @@
 [Unit]
 Description=Permit User Sessions
 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]
 Type=oneshot
index 8f228bce9fe74ced7e421a97615b938180c3ccc4..a39e9a4ec2d557034c2488b6ffa5b3b57d2e083b 100644 (file)
@@ -12,7 +12,7 @@ Description=Enforce Volatile Root File Systems
 Documentation=man:systemd-volatile-root.service(8)
 DefaultDependencies=no
 Conflicts=shutdown.target
-After=sysroot.mount
+After=sysroot.mount systemd-repart.service
 Before=initrd-root-fs.target shutdown.target
 AssertPathExists=/etc/initrd-release