]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #25327 from keszybz/mkosi-less-work
authorFrantisek Sumsal <frantisek@sumsal.cz>
Mon, 14 Nov 2022 11:44:16 +0000 (11:44 +0000)
committerGitHub <noreply@github.com>
Mon, 14 Nov 2022 11:44:16 +0000 (11:44 +0000)
Skip mkosi runs on docs-only changes and some small cleanups

118 files changed:
README
TODO
docs/ENVIRONMENT.md
man/systemd-dissect.xml
man/systemd-measure.xml
meson.build
mkosi.build
po/fi.po
src/analyze/analyze-calendar.c
src/analyze/analyze-cat-config.c
src/analyze/analyze-filesystems.c
src/analyze/analyze-inspect-elf.c
src/analyze/analyze-security.c
src/analyze/analyze-syscall-filter.c
src/analyze/analyze-timespan.c
src/analyze/analyze-timestamp.c
src/basic/chase-symlinks.c
src/basic/chase-symlinks.h
src/basic/conf-files.c
src/basic/fileio.c
src/basic/filesystems.c
src/basic/fs-util.c
src/basic/locale-util.c
src/basic/nulstr-util.c
src/basic/nulstr-util.h
src/basic/path-lookup.c
src/basic/path-util.c
src/basic/path-util.h
src/basic/process-util.c
src/basic/stat-util.c
src/basic/stat-util.h
src/basic/strv.c
src/basic/strv.h
src/basic/tmpfile-util.c
src/boot/bootctl.c
src/boot/efi/boot.c
src/boot/efi/drivers.c
src/core/bpf-devices.c
src/core/bpf-lsm.c
src/core/load-fragment.c
src/core/namespace.c
src/cryptsetup/cryptsetup.c
src/delta/delta.c
src/dissect/dissect.c
src/home/homework-fscrypt.c
src/home/homework.c
src/hostname/hostnamectl.c
src/import/pull-tar.c
src/journal-remote/microhttpd-util.h
src/journal/journalctl.c
src/libsystemd/sd-bus/bus-creds.c
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-device/device-private.c
src/libsystemd/sd-device/test-sd-device.c
src/libsystemd/sd-hwdb/sd-hwdb.c
src/libsystemd/sd-journal/sd-journal.c
src/libsystemd/sd-path/sd-path.c
src/locale/localectl.c
src/locale/localed-util.c
src/machine/machine-dbus.c
src/machine/machinectl.c
src/nspawn/nspawn.c
src/partition/repart.c
src/resolve/resolvectl.c
src/resolve/resolved-dns-question.h
src/resolve/resolved-dns-server.h
src/resolve/resolved-dns-trust-anchor.c
src/resolve/resolved-link-bus.c
src/resolve/resolved-link.c
src/resolve/resolved-link.h
src/shared/ask-password-api.c
src/shared/base-filesystem.c
src/shared/bootspec.c
src/shared/cgroup-show.c
src/shared/condition.c
src/shared/conf-parser.c
src/shared/copy.c
src/shared/copy.h
src/shared/dev-setup.c
src/shared/discover-image.c
src/shared/dissect-image.c
src/shared/dissect-image.h
src/shared/format-table.c
src/shared/format-table.h
src/shared/fstab-util.c
src/shared/gpt.c
src/shared/gpt.h
src/shared/hwdb-util.c
src/shared/import-util.c
src/shared/install.h
src/shared/json.c
src/shared/json.h
src/shared/kbd-util.c
src/shared/libfido2-util.c
src/shared/module-util.c
src/shared/resolve-util.h
src/shared/rm-rf.h
src/shared/seccomp-util.c
src/shared/udev-util.c
src/systemctl/fuzz-systemctl-parse-argv.c
src/systemctl/systemctl-show.c
src/test/meson.build
src/test/test-compress-benchmark.c
src/test/test-condition.c
src/test/test-copy.c
src/test/test-format-table.c
src/test/test-fs-util.c
src/test/test-hashmap-plain.c
src/test/test-nulstr-util.c [new file with mode: 0644]
src/test/test-sd-hwdb.c
src/test/test-seccomp.c
src/test/test-strbuf.c
src/test/test-strv.c
src/timedate/timedatectl.c
src/tmpfiles/tmpfiles.c
src/udev/udev-rules.c
test/units/testsuite-58.sh
test/units/testsuite-75.sh

diff --git a/README b/README
index 92e3ca0f48644975ee35ed66cca0ef62d6170fc5..d8c279f9fa287d6a133b4df1aa23d808d24f9c79 100644 (file)
--- a/README
+++ b/README
@@ -17,7 +17,7 @@ BUG REPORTS:
         https://github.com/systemd/systemd/issues
 
 OLDER DOCUMENTATION:
-        http://0pointer.de/blog/projects/systemd.html
+        https://0pointer.de/blog/projects/systemd.html
         https://www.freedesktop.org/wiki/Software/systemd
 
 AUTHOR:
@@ -128,6 +128,11 @@ REQUIREMENTS:
 
         Required for signed Verity images support:
           CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG
+        Required to verify signed Verity images using keys enrolled in the MoK
+        (Machine-Owner Key) keyring:
+          CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING
+          CONFIG_IMA_ARCH_POLICY
+          CONFIG_INTEGRITY_MACHINE_KEYRING
 
         Required for RestrictFileSystems= in service units:
           CONFIG_BPF
diff --git a/TODO b/TODO
index 88b4ed34d7a1e0763dbd1f2838e0e47e1685beb2..0b9f4da7f0842bc49ba3ed9a957810c04feb000e 100644 (file)
--- a/TODO
+++ b/TODO
@@ -117,6 +117,19 @@ Deprecations and removals:
 
 Features:
 
+* sd-boot: add a new PE section .bls or so that carries a cpio with additional
+  boot loader entries (both type1 and type2). Then when initializing, find this
+  section, iterate through it and populate menu with it. cpio is simple enough
+  to make a parser for this reasonably robust. use same path structures as in
+  the ESP. Similar add one for signature key drop-ins.
+
+* add a new EFI tool "sd-fetch" or so. It looks in a PE section ".url" for an
+  URL, then downloads the file from it using UEFI HTTP APIs, and executes it.
+  Usecase: provide a minimal ESP with sd-boot and a couple of these sd-fetch
+  binaries in place of UKIs, and download them on-the-fly.
+
+* bootctl: warn if ESP is mounted world-readable (and in particular the seed)
+
 * maybe: systemd-loop-generator that sets up loopback devices if requested via kernel
   cmdline. usecase: include encrypted/verity root fs in UKI.
 
index ab3add6031aef7e6138b936e3eb1f25cbb0f93bd..61ad07508545cb00b0ea6837c9dbb6ed57178366 100644 (file)
@@ -85,6 +85,12 @@ All tools:
 * `$SYSTEMD_MEMPOOL=0` — if set, the internal memory caching logic employed by
   hash tables is turned off, and libc `malloc()` is used for all allocations.
 
+* `$SYSTEMD_UTF8=` — takes a boolean value, and overrides whether to generate
+  non-ASCII special glyphs at various places (i.e. "→" instead of
+  "->"). Usually this is deterined automatically, based on $LC_CTYPE, but in
+  scenarios where locale definitions are not installed it might make sense to
+  override this check explicitly.
+
 * `$SYSTEMD_EMOJI=0` — if set, tools such as `systemd-analyze security` will
   not output graphical smiley emojis, but ASCII alternatives instead. Note that
   this only controls use of Unicode emoji glyphs, and has no effect on other
index 0b6bf793cea4a58b3ce2731c326df93876cf1911..b9404082671bc11b26b9f6f8a9f4f03d0ad706c7 100644 (file)
@@ -52,7 +52,7 @@
     <title>Description</title>
 
     <para><command>systemd-dissect</command> is a tool for introspecting and interacting with file system OS
-    disk images, specifically Discoverable Disk Images (DDIs). It supports five different operations:</para>
+    disk images, specifically Discoverable Disk Images (DDIs). It supports four different operations:</para>
 
     <orderedlist>
       <listitem><para>Show general OS image information, including the image's
index 46fc9796549c065e7b56578c0743cb72ec290121..f3b2834b2ec23274c7f7ce5df91c1d2bc7727453 100644 (file)
     --add-section .initrd=initrd.cpio --change-section-vma .initrd=0x3000000 \
     --add-section .splash=splash.bmp --change-section-vma .splash=0x100000 \
     --add-section .dtb=devicetree.dtb --change-section-vma .dtb=0x40000 \
-    --add-section .pcrsig=tpm2-pcr-signature.json --change-section-vma .splash=0x80000 \
-    --add-section .pcrpkey=tpm2-pcr-public.pem --change-section-vma .splash=0x90000 \
+    --add-section .pcrsig=tpm2-pcr-signature.json --change-section-vma .pcrsig=0x80000 \
+    --add-section .pcrpkey=tpm2-pcr-public.pem --change-section-vma .pcrpkey=0x90000 \
     /usr/lib/systemd/boot/efi/linuxx64.efi.stub \
     foo.efi</programlisting>
 
index 00daeac1b6cd8572eada8cb8ebf39ff7f55957de..2d41ff8799d0fa9d6d2a79ecc349868dad99caaf 100644 (file)
@@ -3444,15 +3444,14 @@ public_programs += executable(
         install : true,
         install_dir : rootlibexecdir)
 
-executable(
+public_programs += executable(
         'systemd-ac-power',
         'src/ac-power/ac-power.c',
         include_directories : includes,
         link_with : [libshared],
         dependencies : [versiondep],
         install_rpath : rootpkglibdir,
-        install : true,
-        install_dir : rootlibexecdir)
+        install : true)
 
 public_programs += executable(
         'systemd-detect-virt',
index dbfd5e383049bebe811a20b30a93802dc29fea56..5f6208dd887473f0be2234adcd9107594dfb0646 100755 (executable)
@@ -307,6 +307,10 @@ if [ -d mkosi.kernel/ ]; then
                 --enable MEMCG \
                 --enable MEMCG_SWAP \
                 --enable MEMCG_KMEM \
+                --enable IMA_ARCH_POLICY \
+                --enable DM_VERITY_VERIFY_ROOTHASH_SIG \
+                --enable DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING \
+                --enable INTEGRITY_MACHINE_KEYRING \
                 --enable NETFILTER_ADVANCED \
                 --enable NF_CONNTRACK_MARK
 
index c1472e66fb5d82fa0151f7d9b6bee51acbb102f4..4cf9c48c2e0e259ec82699edeb23fdbb2b9aeda2 100644 (file)
--- a/po/fi.po
+++ b/po/fi.po
@@ -2,12 +2,13 @@
 #
 # Finnish translation of systemd.
 # Jan Kuparinen <copper_fin@hotmail.com>, 2021, 2022.
+# Ricky Tigg <ricky.tigg@gmail.com>, 2022.
 msgid ""
 msgstr ""
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-10-20 10:35+0200\n"
-"PO-Revision-Date: 2022-10-22 17:19+0000\n"
-"Last-Translator: Jan Kuparinen <copper_fin@hotmail.com>\n"
+"PO-Revision-Date: 2022-11-10 19:19+0000\n"
+"Last-Translator: Ricky Tigg <ricky.tigg@gmail.com>\n"
 "Language-Team: Finnish <https://translate.fedoraproject.org/projects/systemd/"
 "master/fi/>\n"
 "Language: fi\n"
@@ -15,7 +16,7 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.14.1\n"
+"X-Generator: Weblate 4.14.2\n"
 
 #: src/core/org.freedesktop.systemd1.policy.in:22
 msgid "Send passphrase back to system"
@@ -119,7 +120,7 @@ msgstr "Todennus vaaditaan käyttäjän kotialueen salasanan vaihtamiseksi."
 
 #: src/hostname/org.freedesktop.hostname1.policy:20
 msgid "Set hostname"
-msgstr "Määritä isäntänimi"
+msgstr "Määritä konenimi"
 
 #: src/hostname/org.freedesktop.hostname1.policy:21
 msgid "Authentication is required to set the local hostname."
index 952fe95c2cfdc939123ce7365de0642f3faeed0d..6daab0844367ce814c0c38073328993954288186 100644 (file)
@@ -24,21 +24,15 @@ static int test_calendar_one(usec_t n, const char *p) {
         if (r < 0)
                 return log_error_errno(r, "Failed to format calendar specification '%s': %m", p);
 
-        table = table_new("name", "value");
+        table = table_new_vertical();
         if (!table)
                 return log_oom();
 
-        table_set_header(table, false);
-
         assert_se(cell = table_get_cell(table, 0, 0));
         r = table_set_ellipsize_percent(table, cell, 100);
         if (r < 0)
                 return r;
 
-        r = table_set_align_percent(table, cell, 100);
-        if (r < 0)
-                return r;
-
         assert_se(cell = table_get_cell(table, 0, 1));
         r = table_set_ellipsize_percent(table, cell, 100);
         if (r < 0)
@@ -46,14 +40,14 @@ static int test_calendar_one(usec_t n, const char *p) {
 
         if (!streq(t, p)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Original form:",
+                                   TABLE_FIELD, "Original form",
                                    TABLE_STRING, p);
                 if (r < 0)
                         return table_log_add_error(r);
         }
 
         r = table_add_many(table,
-                           TABLE_STRING, "Normalized form:",
+                           TABLE_FIELD, "Normalized form",
                            TABLE_STRING, t);
         if (r < 0)
                 return table_log_add_error(r);
@@ -65,7 +59,7 @@ static int test_calendar_one(usec_t n, const char *p) {
                 if (r == -ENOENT) {
                         if (i == 0) {
                                 r = table_add_many(table,
-                                                   TABLE_STRING, "Next elapse:",
+                                                   TABLE_FIELD, "Next elapse",
                                                    TABLE_STRING, "never",
                                                    TABLE_SET_COLOR, ansi_highlight_yellow());
                                 if (r < 0)
@@ -78,7 +72,7 @@ static int test_calendar_one(usec_t n, const char *p) {
 
                 if (i == 0) {
                         r = table_add_many(table,
-                                           TABLE_STRING, "Next elapse:",
+                                           TABLE_FIELD, "Next elapse",
                                            TABLE_TIMESTAMP, next,
                                            TABLE_SET_COLOR, ansi_highlight_blue());
                         if (r < 0)
@@ -91,7 +85,7 @@ static int test_calendar_one(usec_t n, const char *p) {
                         else
                                 k = 0;
 
-                        r = table_add_cell_stringf(table, NULL, "Iter. #%u:", i+1);
+                        r = table_add_cell_stringf_full(table, NULL, TABLE_FIELD, "Iteration #%u", i+1);
                         if (r < 0)
                                 return table_log_add_error(r);
 
@@ -104,14 +98,14 @@ static int test_calendar_one(usec_t n, const char *p) {
 
                 if (!in_utc_timezone()) {
                         r = table_add_many(table,
-                                           TABLE_STRING, "(in UTC):",
+                                           TABLE_FIELD, "(in UTC)",
                                            TABLE_TIMESTAMP_UTC, next);
                         if (r < 0)
                                 return table_log_add_error(r);
                 }
 
                 r = table_add_many(table,
-                                   TABLE_STRING, "From now:",
+                                   TABLE_FIELD, "From now",
                                    TABLE_TIMESTAMP_RELATIVE, next);
                 if (r < 0)
                         return table_log_add_error(r);
index a30662b49f70c7b83ed79ac8265849f53e6569ed..08184cedfe2fc8f8ff57efae451d94fbae246499 100644 (file)
@@ -23,8 +23,6 @@ int verb_cat_config(int argc, char *argv[], void *userdata) {
                         print_separator();
 
                 if (path_is_absolute(*arg)) {
-                        const char *dir;
-
                         NULSTR_FOREACH(dir, CONF_PATHS_NULSTR("")) {
                                 t = path_startswith(*arg, dir);
                                 if (t)
index e30b3a6ac6d7b8a0aa13a3fbfc08ab251dcf0c18..582e04eac9132866368b806df11ca05bbbd5041c 100644 (file)
@@ -50,8 +50,6 @@ static int load_available_kernel_filesystems(Set **ret) {
 }
 
 static void filesystem_set_remove(Set *s, const FilesystemSet *set) {
-        const char *filesystem;
-
         NULSTR_FOREACH(filesystem, set->value) {
                 if (filesystem[0] == '@')
                         continue;
@@ -61,7 +59,6 @@ static void filesystem_set_remove(Set *s, const FilesystemSet *set) {
 }
 
 static void dump_filesystem_set(const FilesystemSet *set) {
-        const char *filesystem;
         int r;
 
         if (!set)
@@ -119,7 +116,6 @@ int verb_filesystems(int argc, char *argv[], void *userdata) {
 
         if (strv_isempty(strv_skip(argv, 1))) {
                 _cleanup_set_free_ Set *kernel = NULL, *known = NULL;
-                const char *fs;
                 int k;
 
                 NULSTR_FOREACH(fs, filesystem_sets[FILESYSTEM_SET_KNOWN].value)
index 155c611c7176abcff29b025e94683a1bef433f6f..da2c64565a68b3d782ff5be9bd42acd3b25fa917 100644 (file)
@@ -34,7 +34,7 @@ static int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
                 if (r < 0)
                         return log_error_errno(r, "Parsing \"%s\" as ELF object failed: %m", abspath);
 
-                t = table_new("", "");
+                t = table_new_vertical();
                 if (!t)
                         return log_oom();
 
@@ -44,7 +44,7 @@ static int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
 
                 r = table_add_many(
                                 t,
-                                TABLE_STRING, "path:",
+                                TABLE_FIELD, "path",
                                 TABLE_STRING, abspath);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -62,15 +62,9 @@ static int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
                                  * metadata is parsed recursively in core files, so there might be
                                  * multiple modules. */
                                 if (STR_IN_SET(module_name, "elfType", "elfArchitecture")) {
-                                        _cleanup_free_ char *suffixed = NULL;
-
-                                        suffixed = strjoin(module_name, ":");
-                                        if (!suffixed)
-                                                return log_oom();
-
                                         r = table_add_many(
                                                         t,
-                                                        TABLE_STRING, suffixed,
+                                                        TABLE_FIELD, module_name,
                                                         TABLE_STRING, json_variant_string(module_json));
                                         if (r < 0)
                                                 return table_log_add_error(r);
@@ -91,7 +85,7 @@ static int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
                                 if (!streq(abspath, module_name)) {
                                         r = table_add_many(
                                                         t,
-                                                        TABLE_STRING, "module name:",
+                                                        TABLE_FIELD, "module name",
                                                         TABLE_STRING, module_name);
                                         if (r < 0)
                                                 return table_log_add_error(r);
@@ -99,15 +93,9 @@ static int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
 
                                 JSON_VARIANT_OBJECT_FOREACH(field_name, field, module_json)
                                         if (json_variant_is_string(field)) {
-                                                _cleanup_free_ char *suffixed = NULL;
-
-                                                suffixed = strjoin(field_name, ":");
-                                                if (!suffixed)
-                                                        return log_oom();
-
                                                 r = table_add_many(
                                                                 t,
-                                                                TABLE_STRING, suffixed,
+                                                                TABLE_FIELD, field_name,
                                                                 TABLE_STRING, json_variant_string(field));
                                                 if (r < 0)
                                                         return table_log_add_error(r);
@@ -115,8 +103,6 @@ static int analyze_elf(char **filenames, JsonFormatFlags json_flags) {
                         }
                 }
                 if (json_flags & JSON_FORMAT_OFF) {
-                        (void) table_set_header(t, true);
-
                         r = table_print(t, NULL);
                         if (r < 0)
                                 return table_log_print_error(r);
index 69eab91bdb6719cca1e589c77ca1d858d68076a7..585dd01f689fffdd2ff806005b00a89bf4c44aff 100644 (file)
@@ -567,8 +567,6 @@ static int assess_system_call_architectures(
 }
 
 static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilterSet *f, const char **ret_offending_syscall) {
-        const char *syscall;
-
         NULSTR_FOREACH(syscall, f->value) {
                 if (syscall[0] == '@') {
                         const SyscallFilterSet *g;
index 308b1724e5d56d7c20393b5192e8101684448b07..50662da0627095abec1e141798d28991f52d00c3 100644 (file)
@@ -59,8 +59,6 @@ static int load_kernel_syscalls(Set **ret) {
 }
 
 static void syscall_set_remove(Set *s, const SyscallFilterSet *set) {
-        const char *syscall;
-
         if (!set)
                 return;
 
@@ -73,8 +71,6 @@ static void syscall_set_remove(Set *s, const SyscallFilterSet *set) {
 }
 
 static void dump_syscall_filter(const SyscallFilterSet *set) {
-        const char *syscall;
-
         printf("%s%s%s\n"
                "    # %s\n",
                ansi_highlight(),
@@ -93,7 +89,6 @@ int verb_syscall_filters(int argc, char *argv[], void *userdata) {
 
         if (strv_isempty(strv_skip(argv, 1))) {
                 _cleanup_set_free_ Set *kernel = NULL, *known = NULL;
-                const char *sys;
                 int k = 0;  /* explicit initialization to appease gcc */
 
                 NULSTR_FOREACH(sys, syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].value)
index f244ace04ac0af596cbcac900ef12e5a2a303cc6..3fdf0f964c14cece4ff7078348cdb06a76852074 100644 (file)
@@ -22,39 +22,33 @@ int verb_timespan(int argc, char *argv[], void *userdata) {
                         return r;
                 }
 
-                table = table_new("name", "value");
+                table = table_new_vertical();
                 if (!table)
                         return log_oom();
 
-                table_set_header(table, false);
-
                 assert_se(cell = table_get_cell(table, 0, 0));
                 r = table_set_ellipsize_percent(table, cell, 100);
                 if (r < 0)
                         return r;
 
-                r = table_set_align_percent(table, cell, 100);
-                if (r < 0)
-                        return r;
-
                 assert_se(cell = table_get_cell(table, 0, 1));
                 r = table_set_ellipsize_percent(table, cell, 100);
                 if (r < 0)
                         return r;
 
                 r = table_add_many(table,
-                                   TABLE_STRING, "Original:",
+                                   TABLE_FIELD, "Original",
                                    TABLE_STRING, *input_timespan);
                 if (r < 0)
                         return table_log_add_error(r);
 
-                r = table_add_cell_stringf(table, NULL, "%ss:", special_glyph(SPECIAL_GLYPH_MU));
+                r = table_add_cell_stringf_full(table, NULL, TABLE_FIELD, "%ss", special_glyph(SPECIAL_GLYPH_MU));
                 if (r < 0)
                         return table_log_add_error(r);
 
                 r = table_add_many(table,
                                    TABLE_UINT64, output_usecs,
-                                   TABLE_STRING, "Human:",
+                                   TABLE_FIELD, "Human",
                                    TABLE_TIMESPAN, output_usecs,
                                    TABLE_SET_COLOR, ansi_highlight());
                 if (r < 0)
index 79764e014e57d1da16231ee8e44e1e02c6483c36..97de4387aba650882799ed0066b3d2e5641fd5bd 100644 (file)
@@ -18,30 +18,24 @@ static int test_timestamp_one(const char *p) {
                 return r;
         }
 
-        table = table_new("name", "value");
+        table = table_new_vertical();
         if (!table)
                 return log_oom();
 
-        table_set_header(table, false);
-
         assert_se(cell = table_get_cell(table, 0, 0));
         r = table_set_ellipsize_percent(table, cell, 100);
         if (r < 0)
                 return r;
 
-        r = table_set_align_percent(table, cell, 100);
-        if (r < 0)
-                return r;
-
         assert_se(cell = table_get_cell(table, 0, 1));
         r = table_set_ellipsize_percent(table, cell, 100);
         if (r < 0)
                 return r;
 
         r = table_add_many(table,
-                           TABLE_STRING, "Original form:",
+                           TABLE_FIELD, "Original form",
                            TABLE_STRING, p,
-                           TABLE_STRING, "Normalized form:",
+                           TABLE_FIELD, "Normalized form",
                            TABLE_TIMESTAMP, usec,
                            TABLE_SET_COLOR, ansi_highlight_blue());
         if (r < 0)
@@ -49,13 +43,13 @@ static int test_timestamp_one(const char *p) {
 
         if (!in_utc_timezone()) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "(in UTC):",
+                                   TABLE_FIELD, "(in UTC)",
                                    TABLE_TIMESTAMP_UTC, usec);
                 if (r < 0)
                         return table_log_add_error(r);
         }
 
-        r = table_add_cell(table, NULL, TABLE_STRING, "UNIX seconds:");
+        r = table_add_cell(table, NULL, TABLE_FIELD, "UNIX seconds");
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -70,7 +64,7 @@ static int test_timestamp_one(const char *p) {
                 return r;
 
         r = table_add_many(table,
-                           TABLE_STRING, "From now:",
+                           TABLE_FIELD, "From now",
                            TABLE_TIMESTAMP_RELATIVE, usec);
         if (r < 0)
                 return table_log_add_error(r);
index a0d29427d33a8333c450664cb683c3a008793bad..0bb07000bad8922b10e83a4793cb6bd059997df0 100644 (file)
@@ -57,6 +57,21 @@ static int log_autofs_mount_point(int fd, const char *path, ChaseSymlinksFlags f
                                  strna(n1), path);
 }
 
+static int log_prohibited_symlink(int fd, ChaseSymlinksFlags flags) {
+        _cleanup_free_ char *n1 = NULL;
+
+        assert(fd >= 0);
+
+        if (!FLAGS_SET(flags, CHASE_WARN))
+                return -EREMCHG;
+
+        (void) fd_get_path(fd, &n1);
+
+        return log_warning_errno(SYNTHETIC_ERRNO(EREMCHG),
+                                 "Detected symlink where not symlink is allowed at %s, refusing.",
+                                 strna(n1));
+}
+
 int chase_symlinks_at(
                 int dir_fd,
                 const char *path,
@@ -291,6 +306,9 @@ int chase_symlinks_at(
                 if (S_ISLNK(st.st_mode) && !((flags & CHASE_NOFOLLOW) && isempty(todo))) {
                         _cleanup_free_ char *destination = NULL;
 
+                        if (flags & CHASE_PROHIBIT_SYMLINKS)
+                                return log_prohibited_symlink(child, flags);
+
                         /* This is a symlink, in this case read the destination. But let's make sure we
                          * don't follow symlinks without bounds. */
                         if (--max_follow <= 0)
@@ -442,9 +460,7 @@ int chase_symlinks(
                                               SYNTHETIC_ERRNO(ECHRNG),
                                               "Specified path '%s' is outside of specified root directory '%s', refusing to resolve.",
                                               absolute, root);
-        }
 
-        if (root) {
                 fd = open(root, O_CLOEXEC|O_DIRECTORY|O_PATH);
                 if (fd < 0)
                         return -errno;
index 6ea0b178759f30b0a436fe1669f3463b75ee434a..af0fcf155a26973c3adedc59ce4faee975cb1f83 100644 (file)
@@ -19,6 +19,7 @@ typedef enum ChaseSymlinksFlags {
                                             * Note: this may do an NSS lookup, hence this flag cannot be used in PID 1. */
         CHASE_AT_RESOLVE_IN_ROOT = 1 << 8, /* Same as openat2()'s RESOLVE_IN_ROOT flag, symlinks are resolved
                                             * relative to the given directory fd instead of root. */
+        CHASE_PROHIBIT_SYMLINKS  = 1 << 9, /* Refuse all symlinks */
 } ChaseSymlinksFlags;
 
 bool unsafe_transition(const struct stat *a, const struct stat *b);
index 348f7dcc7018a87dd6befe427d19a8ebda1ec154..3fbb2cda0010957de24fc4a5c7fab65bd36084c2 100644 (file)
@@ -13,6 +13,7 @@
 #include "hashmap.h"
 #include "log.h"
 #include "macro.h"
+#include "nulstr-util.h"
 #include "path-util.h"
 #include "set.h"
 #include "sort-util.h"
index a5c44f184a9cae5c901a5d018d684217e877bdac..5078cae2df1ec4f3b7fec0a766965d629ccae49c 100644 (file)
@@ -21,6 +21,7 @@
 #include "log.h"
 #include "macro.h"
 #include "mkdir.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "socket-util.h"
index b11cbb9d65a1c417be269878d3a4e423e269547a..7d34e4e9ad0489cfaeca8a25f444e0bcab7a5124 100644 (file)
@@ -28,7 +28,6 @@ int fs_type_from_string(const char *name, const statfs_f_type_t **ret) {
 }
 
 bool fs_in_group(const struct statfs *s, FilesystemGroups fs_group) {
-        const char *fs;
         int r;
 
         NULSTR_FOREACH(fs, filesystem_sets[fs_group].value) {
index c70926c12cab0cccd1b7edf5acb6737f22c4d2f0..4d24cd59de96a7ffccb21ba30e0bc9746d5b8a24 100644 (file)
@@ -197,6 +197,8 @@ int readlink_and_make_absolute(const char *p, char **r) {
 int chmod_and_chown_at(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid) {
         _cleanup_close_ int fd = -1;
 
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+
         if (path) {
                 /* Let's acquire an O_PATH fd, as precaution to change mode/owner on the same file */
                 fd = openat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOFOLLOW);
index 2f486a4d92ca0f2fb33d2509b881fe69410be373..40c6e46ab888e2760d9bc21c20df281b0f28c8f0 100644 (file)
@@ -286,8 +286,9 @@ void init_gettext(void) {
 }
 
 bool is_locale_utf8(void) {
-        const char *set;
         static int cached_answer = -1;
+        const char *set;
+        int r;
 
         /* Note that we default to 'true' here, since today UTF8 is
          * pretty much supported everywhere. */
@@ -295,6 +296,13 @@ bool is_locale_utf8(void) {
         if (cached_answer >= 0)
                 goto out;
 
+        r = getenv_bool_secure("SYSTEMD_UTF8");
+        if (r >= 0) {
+                cached_answer = r;
+                goto out;
+        } else if (r != -ENXIO)
+                log_debug_errno(r, "Failed to parse $SYSTEMD_UTF8, ignoring: %m");
+
         if (!setlocale(LC_ALL, "")) {
                 cached_answer = true;
                 goto out;
index dbafc8c4c94544fc0f1f553d20eba71dac6ca777..44b88ca75353f9b043ff043f34884e03ebd66c20 100644 (file)
 
 #include "nulstr-util.h"
 #include "string-util.h"
+#include "strv.h"
 
-const char* nulstr_get(const char *nulstr, const char *needle) {
-        const char *i;
+char** strv_parse_nulstr(const char *s, size_t l) {
+        /* l is the length of the input data, which will be split at NULs into elements of the resulting
+         * strv. Hence, the number of items in the resulting strv will be equal to one plus the number of NUL
+         * bytes in the l bytes starting at s, unless s[l-1] is NUL, in which case the final empty string is
+         * not stored in the resulting strv, and length is equal to the number of NUL bytes.
+         *
+         * Note that contrary to a normal nulstr which cannot contain empty strings, because the input data
+         * is terminated by any two consequent NUL bytes, this parser accepts empty strings in s. */
+
+        _cleanup_strv_free_ char **v = NULL;
+        size_t c = 0, i = 0;
+
+        assert(s || l <= 0);
+
+        if (l <= 0)
+                return new0(char*, 1);
+
+        for (const char *p = s; p < s + l; p++)
+                if (*p == 0)
+                        c++;
+
+        if (s[l-1] != 0)
+                c++;
+
+        v = new0(char*, c+1);
+        if (!v)
+                return NULL;
+
+        for (const char *p = s; p < s + l; ) {
+                const char *e;
+
+                e = memchr(p, 0, s + l - p);
+
+                v[i] = memdup_suffix0(p, e ? e - p : s + l - p);
+                if (!v[i])
+                        return NULL;
+
+                i++;
+
+                if (!e)
+                        break;
+
+                p = e + 1;
+        }
+
+        assert(i == c);
+
+        return TAKE_PTR(v);
+}
+
+char** strv_split_nulstr(const char *s) {
+        _cleanup_strv_free_ char **l = NULL;
 
+        /* This parses a nulstr, without specification of size, and stops at an empty string. This cannot
+         * parse nulstrs with embedded empty strings hence, as an empty string is an end marker. Use
+         * strv_parse_nulstr() above to parse a nulstr with embedded empty strings (which however requires a
+         * size to be specified) */
+
+        NULSTR_FOREACH(i, s)
+                if (strv_extend(&l, i) < 0)
+                        return NULL;
+
+        return l ? TAKE_PTR(l) : strv_new(NULL);
+}
+
+int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
+        /* Builds a nulstr and returns it together with the size. An extra NUL byte will be appended (⚠️ but
+         * not included in the size! ⚠️). This is done so that the nulstr can be used both in
+         * strv_parse_nulstr() and in NULSTR_FOREACH()/strv_split_nulstr() contexts, i.e. with and without a
+         * size parameter. In the former case we can include empty strings, in the latter case we cannot (as
+         * that is the end marker).
+         *
+         * When NULSTR_FOREACH()/strv_split_nulstr() is used it is often assumed that the nulstr ends in two
+         * NUL bytes (which it will, if not empty). To ensure that this assumption *always* holds, we'll
+         * return a buffer with two NUL bytes in that case, but return a size of zero. */
+
+        _cleanup_free_ char *m = NULL;
+        size_t n = 0;
+
+        assert(ret);
+        assert(ret_size);
+
+        STRV_FOREACH(i, l) {
+                size_t z;
+
+                z = strlen(*i);
+
+                if (!GREEDY_REALLOC(m, n + z + 2))
+                        return -ENOMEM;
+
+                memcpy(m + n, *i, z + 1);
+                n += z + 1;
+        }
+
+        if (!m) {
+                /* return a buffer with an extra NUL, so that the assumption that we always have two trailing NULs holds */
+                m = new0(char, 2);
+                if (!m)
+                        return -ENOMEM;
+
+                n = 0;
+        } else
+                /* Make sure there is a second extra NUL at the end of resulting nulstr (not counted in return size) */
+                m[n] = '\0';
+
+        *ret = TAKE_PTR(m);
+        *ret_size = n;
+
+        return 0;
+}
+
+const char* nulstr_get(const char *nulstr, const char *needle) {
         if (!nulstr)
                 return NULL;
 
index 1d1fbc19c04284d9b64327f327b5ab280e2f9f42..19f4edd3846de365642b998a6baec702625b470b 100644 (file)
@@ -1,17 +1,36 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <errno.h>
+#include <macro.h>
 #include <stdbool.h>
 #include <string.h>
 
 #define NULSTR_FOREACH(i, l)                                    \
-        for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
+        for (typeof(*(l)) *(i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
 
 #define NULSTR_FOREACH_PAIR(i, j, l)                             \
-        for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
+        for (typeof(*(l)) *(i) = (l), *(j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
 
 const char* nulstr_get(const char *nulstr, const char *needle);
 
 static inline bool nulstr_contains(const char *nulstr, const char *needle) {
         return nulstr_get(nulstr, needle);
 }
+
+char** strv_parse_nulstr(const char *s, size_t l);
+char** strv_split_nulstr(const char *s);
+int strv_make_nulstr(char * const *l, char **p, size_t *n);
+
+static inline int strv_from_nulstr(char ***ret, const char *nulstr) {
+        char **t;
+
+        assert(ret);
+
+        t = strv_split_nulstr(nulstr);
+        if (!t)
+                return -ENOMEM;
+
+        *ret = t;
+        return 0;
+}
index 36f386254b72e7432f73584fafc2efd89ec202be..c99e9d8786cb1d7b1f21ae1a0cab82b9ee4960ad 100644 (file)
@@ -880,7 +880,7 @@ char **env_generator_binary_paths(bool is_system) {
 }
 
 int find_portable_profile(const char *name, const char *unit, char **ret_path) {
-        const char *p, *dot;
+        const char *dot;
 
         assert(name);
         assert(ret_path);
index f6c2d662b277f4734d2b25b3c19aa900647016c8..bf93990fde1db8422f37ca8bfdf46b3a0083bff1 100644 (file)
@@ -221,33 +221,6 @@ int path_make_relative_parent(const char *from_child, const char *to, char **ret
         return path_make_relative(from, to, ret);
 }
 
-int path_make_relative_cwd(const char *p, char **ret) {
-        char *c;
-        int r;
-
-        assert(p);
-        assert(ret);
-
-        if (path_is_absolute(p)) {
-                _cleanup_free_ char *cwd = NULL;
-
-                r = safe_getcwd(&cwd);
-                if (r < 0)
-                        return r;
-
-                r = path_make_relative(cwd, p, &c);
-                if (r < 0)
-                        return r;
-        } else {
-                c = strdup(p);
-                if (!c)
-                        return -ENOMEM;
-        }
-
-        *ret = TAKE_PTR(c);
-        return 0;
-}
-
 char* path_startswith_strv(const char *p, char **set) {
         STRV_FOREACH(s, set) {
                 char *t;
index f93455df3b1347c809d4f73ba5918ecc216ccec5..22d3632e6ef2c4f24959bd6ab0bd1e23f6e5a87c 100644 (file)
@@ -62,7 +62,6 @@ int safe_getcwd(char **ret);
 int path_make_absolute_cwd(const char *p, char **ret);
 int path_make_relative(const char *from, const char *to, char **ret);
 int path_make_relative_parent(const char *from_child, const char *to, char **ret);
-int path_make_relative_cwd(const char *from, char **ret);
 char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_;
 static inline char* path_startswith(const char *path, const char *prefix) {
         return path_startswith_full(path, prefix, true);
index dd913bc3238e6a9fe90a6aee57d22bc11124d83c..183ff8b84eb4f7b408047f82028b3bc909ffccf5 100644 (file)
@@ -37,6 +37,7 @@
 #include "missing_sched.h"
 #include "missing_syscall.h"
 #include "namespace-util.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
index 51adaca9d070ce10d0838a3801d460586bc83fd5..97dbcaac66a3348bd7a1b87985f0a532c7c683c2 100644 (file)
@@ -15,6 +15,7 @@
 #include "fileio.h"
 #include "filesystems.h"
 #include "fs-util.h"
+#include "hash-funcs.h"
 #include "macro.h"
 #include "missing_fs.h"
 #include "missing_magic.h"
@@ -441,3 +442,20 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
 
         return 0;
 }
+
+void inode_hash_func(const struct stat *q, struct siphash *state) {
+        siphash24_compress(&q->st_dev, sizeof(q->st_dev), state);
+        siphash24_compress(&q->st_ino, sizeof(q->st_ino), state);
+}
+
+int inode_compare_func(const struct stat *a, const struct stat *b) {
+        int r;
+
+        r = CMP(a->st_dev, b->st_dev);
+        if (r != 0)
+                return r;
+
+        return CMP(a->st_ino, b->st_ino);
+}
+
+DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops, struct stat, inode_hash_func, inode_compare_func, free);
index f9519d8cbde3591cb142d059238a641e5751f449..de11c0cf7c2b9503fdb8a68f2fccb324e13530b1 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "macro.h"
 #include "missing_stat.h"
+#include "siphash24.h"
 
 int is_symlink(const char *path);
 int is_dir_full(int atfd, const char *fname, bool follow);
@@ -96,3 +97,7 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s
                 struct new_statx nsx;           \
         } var
 #endif
+
+void inode_hash_func(const struct stat *q, struct siphash *state);
+int inode_compare_func(const struct stat *a, const struct stat *b);
+extern const struct hash_ops inode_hash_ops;
index eea34ca68d9a98f6317b190b5927f3536c40e7e6..74e87046cca9dac00e30a8361a6021acb33f184d 100644 (file)
@@ -623,121 +623,6 @@ char** strv_remove(char **l, const char *s) {
         return l;
 }
 
-char** strv_parse_nulstr(const char *s, size_t l) {
-        /* l is the length of the input data, which will be split at NULs into
-         * elements of the resulting strv. Hence, the number of items in the resulting strv
-         * will be equal to one plus the number of NUL bytes in the l bytes starting at s,
-         * unless s[l-1] is NUL, in which case the final empty string is not stored in
-         * the resulting strv, and length is equal to the number of NUL bytes.
-         *
-         * Note that contrary to a normal nulstr which cannot contain empty strings, because
-         * the input data is terminated by any two consequent NUL bytes, this parser accepts
-         * empty strings in s.
-         */
-
-        size_t c = 0, i = 0;
-        char **v;
-
-        assert(s || l <= 0);
-
-        if (l <= 0)
-                return new0(char*, 1);
-
-        for (const char *p = s; p < s + l; p++)
-                if (*p == 0)
-                        c++;
-
-        if (s[l-1] != 0)
-                c++;
-
-        v = new0(char*, c+1);
-        if (!v)
-                return NULL;
-
-        for (const char *p = s; p < s + l; ) {
-                const char *e;
-
-                e = memchr(p, 0, s + l - p);
-
-                v[i] = strndup(p, e ? e - p : s + l - p);
-                if (!v[i]) {
-                        strv_free(v);
-                        return NULL;
-                }
-
-                i++;
-
-                if (!e)
-                        break;
-
-                p = e + 1;
-        }
-
-        assert(i == c);
-
-        return v;
-}
-
-char** strv_split_nulstr(const char *s) {
-        const char *i;
-        char **r = NULL;
-
-        NULSTR_FOREACH(i, s)
-                if (strv_extend(&r, i) < 0) {
-                        strv_free(r);
-                        return NULL;
-                }
-
-        if (!r)
-                return strv_new(NULL);
-
-        return r;
-}
-
-int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
-        /* A valid nulstr with two NULs at the end will be created, but
-         * q will be the length without the two trailing NULs. Thus the output
-         * string is a valid nulstr and can be iterated over using NULSTR_FOREACH,
-         * and can also be parsed by strv_parse_nulstr as long as the length
-         * is provided separately.
-         */
-
-        _cleanup_free_ char *m = NULL;
-        size_t n = 0;
-
-        assert(ret);
-        assert(ret_size);
-
-        STRV_FOREACH(i, l) {
-                size_t z;
-
-                z = strlen(*i);
-
-                if (!GREEDY_REALLOC(m, n + z + 2))
-                        return -ENOMEM;
-
-                memcpy(m + n, *i, z + 1);
-                n += z + 1;
-        }
-
-        if (!m) {
-                m = new0(char, 1);
-                if (!m)
-                        return -ENOMEM;
-                n = 1;
-        } else
-                /* make sure there is a second extra NUL at the end of resulting nulstr */
-                m[n] = '\0';
-
-        assert(n > 0);
-        *ret = m;
-        *ret_size = n - 1;
-
-        m = NULL;
-
-        return 0;
-}
-
 bool strv_overlap(char * const *a, char * const *b) {
         STRV_FOREACH(i, a)
                 if (strv_contains(b, *i))
index d6f5ac6ba581958471b9499c356020b59ba061b1..87a7038a54744ab18b9cf4b89a00ed86db4e5a78 100644 (file)
@@ -124,20 +124,6 @@ static inline char *strv_join(char * const *l, const char *separator) {
         return strv_join_full(l, separator, NULL, false);
 }
 
-char** strv_parse_nulstr(const char *s, size_t l);
-char** strv_split_nulstr(const char *s);
-int strv_make_nulstr(char * const *l, char **p, size_t *n);
-
-static inline int strv_from_nulstr(char ***a, const char *nulstr) {
-        char **t;
-
-        t = strv_split_nulstr(nulstr);
-        if (!t)
-                return -ENOMEM;
-        *a = t;
-        return 0;
-}
-
 bool strv_overlap(char * const *a, char * const *b) _pure_;
 
 #define _STRV_FOREACH_BACKWARDS(s, l, h, i)                             \
index e0e58472d37314b0e763ee51f6357c9f68b23e10..909057429d4ce23bcf778a46bbc5c82ae155327b 100644 (file)
@@ -25,6 +25,8 @@ int fopen_temporary_at(int dir_fd, const char *path, FILE **ret_file, char **ret
         _cleanup_close_ int fd = -1;
         int r;
 
+        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
+
         if (path) {
                 r = tempfn_random(path, NULL, &t);
                 if (r < 0)
index 79b26765373c6d5d4ef5d879d3e6feb40c6d8d72..430887fe676e0e9ac8766417716a4a2990526014 100644 (file)
@@ -484,7 +484,7 @@ static int enumerate_binaries(
         assert(previous);
         assert(is_first);
 
-        r = chase_symlinks_and_opendir(path, esp_path, CHASE_PREFIX_ROOT, &p, &d);
+        r = chase_symlinks_and_opendir(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
         if (r == -ENOENT)
                 return 0;
         if (r < 0)
@@ -586,11 +586,11 @@ static int print_efi_option(uint16_t id, int *n_printed, bool in_order) {
 
         r = efi_get_boot_option(id, &title, &partition, &path, &active);
         if (r < 0)
-                return log_error_errno(r, "Failed to read boot option %u: %m", id);
+                return log_debug_errno(r, "Failed to read boot option 0x%04X: %m", id);
 
         /* print only configured entries with partition information */
         if (!path || sd_id128_is_null(partition)) {
-                log_debug("Ignoring boot entry %u without partition information.", id);
+                log_debug("Ignoring boot entry 0x%04X without partition information.", id);
                 return 0;
         }
 
@@ -913,10 +913,10 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
         if (!p)
                 return log_oom();
 
-        r = chase_symlinks(p, root, CHASE_PREFIX_ROOT, &source_path, NULL);
+        r = chase_symlinks(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &source_path, NULL);
         /* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
         if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
-                r = chase_symlinks(p, NULL, CHASE_PREFIX_ROOT, &source_path, NULL);
+                r = chase_symlinks(p, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &source_path, NULL);
         if (r < 0)
                 return log_error_errno(r,
                                        "Failed to resolve path %s%s%s: %m",
@@ -928,7 +928,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
         if (!q)
                 return log_oom();
 
-        r = chase_symlinks(q, esp_path, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &dest_path, NULL);
+        r = chase_symlinks(q, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT, &dest_path, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", q, esp_path);
 
@@ -945,7 +945,7 @@ static int copy_one_file(const char *esp_path, const char *name, bool force) {
                 v = strjoina("/EFI/BOOT/BOOT", e);
                 ascii_strupper(strrchr(v, '/') + 1);
 
-                r = chase_symlinks(v, esp_path, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &default_dest_path, NULL);
+                r = chase_symlinks(v, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_NONEXISTENT, &default_dest_path, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to resolve path %s under directory %s: %m", v, esp_path);
 
@@ -963,10 +963,10 @@ static int install_binaries(const char *esp_path, const char *arch, bool force)
         _cleanup_free_ char *path = NULL;
         int r;
 
-        r = chase_symlinks_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT, &path, &d);
+        r = chase_symlinks_and_opendir(BOOTLIBDIR, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &path, &d);
         /* If we had a root directory to try, we didn't find it and we are in auto mode, retry on the host */
         if (r == -ENOENT && root && arg_install_source == ARG_INSTALL_SOURCE_AUTO)
-                r = chase_symlinks_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT, &path, &d);
+                r = chase_symlinks_and_opendir(BOOTLIBDIR, NULL, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &path, &d);
         if (r < 0)
                 return log_error_errno(r, "Failed to open boot loader directory %s%s: %m", strempty(root), BOOTLIBDIR);
 
@@ -1136,7 +1136,7 @@ static int install_variables(
                 return 0;
         }
 
-        r = chase_symlinks_and_access(path, esp_path, CHASE_PREFIX_ROOT, F_OK, NULL, NULL);
+        r = chase_symlinks_and_access(path, esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL, NULL);
         if (r == -ENOENT)
                 return 0;
         if (r < 0)
@@ -1167,7 +1167,7 @@ static int remove_boot_efi(const char *esp_path) {
         _cleanup_free_ char *p = NULL;
         int r, c = 0;
 
-        r = chase_symlinks_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT, &p, &d);
+        r = chase_symlinks_and_opendir("/EFI/BOOT", esp_path, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &p, &d);
         if (r == -ENOENT)
                 return 0;
         if (r < 0)
index 4150b16ecf9bbd3b1f04d7c867f2205c21377cf4..84f4cc11a35c2ec443bdc1d4abf7063d879fd2af 100644 (file)
@@ -2678,7 +2678,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
 
         err = device_path_to_str(loaded_image->FilePath, &loaded_image_path);
         if (err != EFI_SUCCESS)
-                return log_error_status_stall(err, L"Error getting loaded image path: %m");
+                return log_error_status_stall(err, L"Error getting loaded image path: %r", err);
 
         export_variables(loaded_image, loaded_image_path, init_usec);
 
index 39b65e74a6f413d11d21df8c0c06d3006bbe4a99..7f2057f5a15e89a3bacd78a855d12e21228bb8d7 100644 (file)
@@ -51,25 +51,23 @@ static EFI_STATUS load_one_driver(
 }
 
 EFI_STATUS reconnect_all_drivers(void) {
-          _cleanup_free_ EFI_HANDLE *handles = NULL;
-          UINTN n_handles = 0;
-          EFI_STATUS err;
+        _cleanup_free_ EFI_HANDLE *handles = NULL;
+        size_t n_handles = 0;
+        EFI_STATUS err;
 
-          /* Reconnects all handles, so that any loaded drivers can take effect. */
+        /* Reconnects all handles, so that any loaded drivers can take effect. */
 
-          err = BS->LocateHandleBuffer(AllHandles, NULL, NULL, &n_handles, &handles);
-          if (err != EFI_SUCCESS)
-                  return log_error_status_stall(err, L"Failed to get list of handles: %r", err);
+        err = BS->LocateHandleBuffer(AllHandles, NULL, NULL, &n_handles, &handles);
+        if (err != EFI_SUCCESS)
+                return log_error_status_stall(err, L"Failed to get list of handles: %r", err);
 
-          for (UINTN i = 0; i < n_handles; i++) {
-                  err = BS->ConnectController(handles[i], NULL, NULL, true);
-                  if (err == EFI_NOT_FOUND) /* No drivers for this handle */
-                          continue;
-                  if (err != EFI_SUCCESS)
-                          log_error_status_stall(err, L"Failed to reconnect handle %" PRIuN L", ignoring: %r", i, err);
-          }
+        for (size_t i = 0; i < n_handles; i++)
+                /* Some firmware gives us some bogus handles (or they might become bad due to
+                 * reconnecting everything). Security policy may also prevent us from doing so too.
+                 * There is nothing we can realistically do on errors anyways, so just ignore them. */
+                (void) BS->ConnectController(handles[i], NULL, NULL, true);
 
-          return EFI_SUCCESS;
+        return EFI_SUCCESS;
 }
 
 EFI_STATUS load_drivers(
index 3af9e78a1e32f5e9f2987d115da3002cb0b77d92..c79cda5b76d9cacfc06339f827aaa6961b3a13d8 100644 (file)
@@ -515,7 +515,6 @@ int bpf_devices_allow_list_static(
                 "/run/systemd/inaccessible/blk\0" "rwm\0";
         int r = 0, k;
 
-        const char *node, *acc;
         NULSTR_FOREACH_PAIR(node, acc, auto_devices) {
                 k = bpf_devices_allow_list_device(prog, path, node, acc);
                 if (r >= 0 && k < 0)
index 173221b9f178eb1c0e981d5658fe74f422cc9373..de601c48d751ffce39a7ba12a6c5e0254edaf451 100644 (file)
@@ -326,7 +326,6 @@ int lsm_bpf_parse_filesystem(
 
         if (name[0] == '@') {
                 const FilesystemSet *set;
-                const char *i;
 
                 set = filesystem_set_find(name);
                 if (!set) {
index 1a5895346d96633561d2a624068b91871e193386..49d3c0359141c880993fda3f5e4b009d6f8ba59f 100644 (file)
@@ -6226,7 +6226,6 @@ void unit_dump_config_items(FILE *f) {
         };
 
         const char *prev = NULL;
-        const char *i;
 
         assert(f);
 
index 852be3bdde82880e43a931841865ff06e7356491..7752e48fb0bfbb8f0e8cc0a4033f60722e556f58 100644 (file)
@@ -916,7 +916,7 @@ static int mount_private_dev(MountEntry *m) {
                 "/dev/tty\0";
 
         char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
-        const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
+        const char *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
         bool can_mknod = true;
         int r;
 
index 7aa36b4b032f54b1139719db78d0b8a68e771eb3..90b5ab21a991d5df63f691eca77a85aa189c56fc 100644 (file)
@@ -494,7 +494,7 @@ static char* disk_description(const char *path) {
                 "ID_MODEL\0";
 
         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
-        const char *i, *name;
+        const char *name;
         struct stat st;
 
         assert(path);
index da648bc837dbfb40ee21cf301e9f3d208e12a5c5..db6e957fc9d51ee9a083a641629033a29e0197ed 100644 (file)
@@ -371,7 +371,6 @@ static int enumerate_dir(
 static int should_skip_path(const char *prefix, const char *suffix) {
 #if HAVE_SPLIT_USR
         _cleanup_free_ char *target = NULL, *dirname = NULL;
-        const char *p;
 
         dirname = path_join(prefix, suffix);
         if (!dirname)
@@ -400,7 +399,6 @@ static int should_skip_path(const char *prefix, const char *suffix) {
 }
 
 static int process_suffix(const char *suffix, const char *onlyprefix) {
-        const char *p;
         char *f, *key;
         OrderedHashmap *top, *bottom, *drops, *h;
         int r = 0, k, n_found = 0;
@@ -477,7 +475,6 @@ finish:
 }
 
 static int process_suffixes(const char *onlyprefix) {
-        const char *n;
         int n_found = 0, r;
 
         NULSTR_FOREACH(n, suffixes) {
@@ -492,8 +489,6 @@ static int process_suffixes(const char *onlyprefix) {
 }
 
 static int process_suffix_chop(const char *arg) {
-        const char *p;
-
         assert(arg);
 
         if (!path_is_absolute(arg))
index 81764690e9975c53fe3f476e8f4c2a5c61bc8ccd..4ff86ba1dedc0aadaff0493f3a252f687dfac531 100644 (file)
@@ -568,7 +568,7 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
                 pager_open(arg_pager_flags);
 
         if (arg_json_format_flags & JSON_FORMAT_OFF)
-                printf("      Name: %s\n", bn);
+                printf("      Name: %s%s%s\n", ansi_highlight(), bn, ansi_normal());
 
         if (ioctl(d->fd, BLKGETSIZE64, &size) < 0)
                 log_debug_errno(errno, "Failed to query size of loopback device: %m");
@@ -594,6 +594,9 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
         else if (arg_json_format_flags & JSON_FORMAT_OFF) {
                 _cleanup_strv_free_ char **sysext_scopes = NULL;
 
+                if (!sd_id128_is_null(m->image_uuid))
+                        printf("Image UUID: %s\n", SD_ID128_TO_UUID_STRING(m->image_uuid));
+
                 if (m->hostname)
                         printf("  Hostname: %s\n", m->hostname);
 
@@ -673,6 +676,7 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) {
 
                 r = json_build(&v, JSON_BUILD_OBJECT(
                                                JSON_BUILD_PAIR("name", JSON_BUILD_STRING(bn)),
+                                               JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(m->image_uuid), "imageUuid", JSON_BUILD_UUID(m->image_uuid)),
                                                JSON_BUILD_PAIR("size", JSON_BUILD_INTEGER(size)),
                                                JSON_BUILD_PAIR_CONDITION(m->hostname, "hostname", JSON_BUILD_STRING(m->hostname)),
                                                JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(m->machine_id), "machineId", JSON_BUILD_ID128(m->machine_id)),
@@ -1122,9 +1126,9 @@ static int action_list_or_mtree_or_copy(DissectedImage *m, LoopDevice *d) {
                                 if (errno != ENOENT)
                                         return log_error_errno(errno, "Failed to open destination '%s': %m", arg_target);
 
-                                r = copy_tree_at(source_fd, ".", dfd, bn, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
+                                r = copy_tree_at(source_fd, ".", dfd, bn, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL);
                         } else
-                                r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS);
+                                r = copy_tree_at(source_fd, ".", target_fd, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, NULL);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to copy '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image);
 
index 5106961f38bdef6ec55b3967699f166c9b99dca7..f29c55c8952b05dc5859efbc777f7f0f3f13e43a 100644 (file)
@@ -216,7 +216,6 @@ static int fscrypt_setup(
                 size_t *ret_volume_key_size) {
 
         _cleanup_free_ char *xattr_buf = NULL;
-        const char *xa;
         int r;
 
         assert(setup);
@@ -646,7 +645,6 @@ int home_passwd_fscrypt(
         _cleanup_free_ char *xattr_buf = NULL;
         size_t volume_key_size = 0;
         uint32_t slot = 0;
-        const char *xa;
         int r;
 
         assert(h);
index c41866cd41b182959d9ffb141b630635471ba9c0..bc38437f2cf6cee030bfd6b57abd7e74142dd3e9 100644 (file)
@@ -1036,7 +1036,7 @@ static int copy_skel(int root_fd, const char *skel) {
 
         assert(root_fd >= 0);
 
-        r = copy_tree_at(AT_FDCWD, skel, root_fd, ".", UID_INVALID, GID_INVALID, COPY_MERGE|COPY_REPLACE);
+        r = copy_tree_at(AT_FDCWD, skel, root_fd, ".", UID_INVALID, GID_INVALID, COPY_MERGE|COPY_REPLACE, NULL);
         if (r == -ENOENT) {
                 log_info("Skeleton directory %s missing, ignoring.", skel);
                 return 0;
index 826826d70b9437989034f2170bfd6d5d7b58d208..52606d2f4046094ba374147c14cc4be4c3283067 100644 (file)
@@ -82,20 +82,17 @@ static int print_status_info(StatusInfo *i) {
 
         assert(i);
 
-        table = table_new("key", "value");
+        table = table_new_vertical();
         if (!table)
                 return log_oom();
 
         assert_se(cell = table_get_cell(table, 0, 0));
         (void) table_set_ellipsize_percent(table, cell, 100);
-        (void) table_set_align_percent(table, cell, 100);
-
-        table_set_header(table, false);
 
         table_set_ersatz_string(table, TABLE_ERSATZ_UNSET);
 
         r = table_add_many(table,
-                           TABLE_STRING, "Static hostname:",
+                           TABLE_FIELD, "Static hostname",
                            TABLE_STRING, i->static_hostname);
         if (r < 0)
                 return table_log_add_error(r);
@@ -103,7 +100,7 @@ static int print_status_info(StatusInfo *i) {
         if (!isempty(i->pretty_hostname) &&
             !streq_ptr(i->pretty_hostname, i->static_hostname)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Pretty hostname:",
+                                   TABLE_FIELD, "Pretty hostname",
                                    TABLE_STRING, i->pretty_hostname);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -112,7 +109,7 @@ static int print_status_info(StatusInfo *i) {
         if (!isempty(i->hostname) &&
             !streq_ptr(i->hostname, i->static_hostname)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Transient hostname:",
+                                   TABLE_FIELD, "Transient hostname",
                                    TABLE_STRING, i->hostname);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -120,7 +117,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->icon_name)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Icon name:",
+                                   TABLE_FIELD, "Icon name",
                                    TABLE_STRING, i->icon_name);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -134,7 +131,7 @@ static int print_status_info(StatusInfo *i) {
                         v = strjoina(i->chassis, " ", v);
 
                 r = table_add_many(table,
-                                   TABLE_STRING, "Chassis:",
+                                   TABLE_FIELD, "Chassis",
                                    TABLE_STRING, v ?: i->chassis);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -142,7 +139,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->deployment)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Deployment:",
+                                   TABLE_FIELD, "Deployment",
                                    TABLE_STRING, i->deployment);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -150,7 +147,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->location)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Location:",
+                                   TABLE_FIELD, "Location",
                                    TABLE_STRING, i->location);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -159,7 +156,7 @@ static int print_status_info(StatusInfo *i) {
         r = sd_id128_get_machine(&mid);
         if (r >= 0) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Machine ID:",
+                                   TABLE_FIELD, "Machine ID",
                                    TABLE_ID128, mid);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -168,7 +165,7 @@ static int print_status_info(StatusInfo *i) {
         r = sd_id128_get_boot(&bid);
         if (r >= 0) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Boot ID:",
+                                   TABLE_FIELD, "Boot ID",
                                    TABLE_ID128, bid);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -176,7 +173,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->virtualization)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Virtualization:",
+                                   TABLE_FIELD, "Virtualization",
                                    TABLE_STRING, i->virtualization);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -184,7 +181,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->os_pretty_name)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Operating System:",
+                                   TABLE_FIELD, "Operating System",
                                    TABLE_STRING, i->os_pretty_name,
                                    TABLE_SET_URL, i->home_url);
                 if (r < 0)
@@ -193,7 +190,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->os_cpe_name)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "CPE OS Name:",
+                                   TABLE_FIELD, "CPE OS Name",
                                    TABLE_STRING, i->os_cpe_name);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -204,7 +201,7 @@ static int print_status_info(StatusInfo *i) {
 
                 v = strjoina(i->kernel_name, " ", i->kernel_release);
                 r = table_add_many(table,
-                                   TABLE_STRING, "Kernel:",
+                                   TABLE_FIELD, "Kernel",
                                    TABLE_STRING, v);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -212,7 +209,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->architecture)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Architecture:",
+                                   TABLE_FIELD, "Architecture",
                                    TABLE_STRING, i->architecture);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -220,7 +217,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->hardware_vendor)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Hardware Vendor:",
+                                   TABLE_FIELD, "Hardware Vendor",
                                    TABLE_STRING, i->hardware_vendor);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -228,7 +225,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->hardware_model)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Hardware Model:",
+                                   TABLE_FIELD, "Hardware Model",
                                    TABLE_STRING, i->hardware_model);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -236,7 +233,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->firmware_version)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Firmware Version:",
+                                   TABLE_FIELD, "Firmware Version",
                                    TABLE_STRING, i->firmware_version);
                 if (r < 0)
                         return table_log_add_error(r);
index cf18461db30e070c8b58122eae5c8a0c6337705f..d3a1179ebc7616eb803cdd05b3f72ad785d4246f 100644 (file)
@@ -245,7 +245,7 @@ static int tar_pull_make_local_copy(TarPull *i) {
                                 BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
                                 BTRFS_SNAPSHOT_RECURSIVE);
         else
-                r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS);
+                r = copy_tree(i->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to create local image: %m");
 
index 7e7d1b56b1b3127641c077e80779f613b4577e5a..df183354694117d1bf4a533539424469bed5093c 100644 (file)
@@ -64,11 +64,11 @@ void microhttpd_logger(void *arg, const char *fmt, va_list ap) _printf_(2, 0);
 
 int mhd_respondf(struct MHD_Connection *connection,
                  int error,
-                 unsigned code,
+                 enum MHD_RequestTerminationCode code,
                  const char *format, ...) _printf_(4,5);
 
 int mhd_respond(struct MHD_Connection *connection,
-                unsigned code,
+                enum MHD_RequestTerminationCode code,
                 const char *message);
 
 int mhd_respond_oom(struct MHD_Connection *connection);
index eb8106cbb41fadb28a11ef69d1de862ac1d5a0d9..ba5636af141d38ccda6453e86c5391e033f87d5c 100644 (file)
@@ -1512,7 +1512,6 @@ static int get_possible_units(
                 Set **units) {
 
         _cleanup_set_free_free_ Set *found = NULL;
-        const char *field;
         int r;
 
         found = set_new(&string_hash_ops);
index 45e7473c29f2eaea39d03f782d80bfb543a058ff..6e53e942dff232b95939da8462a47f9b96a41786 100644 (file)
@@ -15,6 +15,7 @@
 #include "fileio.h"
 #include "format-util.h"
 #include "hexdecoct.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "process-util.h"
 #include "string-util.h"
index 7e72245e8dca2c48d706b22440a44f5348321f2a..ba5ef7de006f61740a1c375e8cd4c7081095501a 100644 (file)
@@ -3529,7 +3529,7 @@ static int bus_add_match_full(
                                                                  s);
 
                                 if (r < 0)
-                                        return r;
+                                        goto finish;
 
                                 /* Make the slot of the match call floating now. We need the reference, but we don't
                                  * want that this match pins the bus object, hence we first create it non-floating, but
index bc7a838608996b81df0497e15d9a6c0006d99813..7cda48c4cafb8ef0bcaf9e655d4344782eb86213 100644 (file)
@@ -559,7 +559,6 @@ static int device_update_properties_bufs(sd_device *device) {
                 return -ENOMEM;
 
         size_t i = 0;
-        char *p;
         NULSTR_FOREACH(p, buf_nulstr)
                 buf_strv[i++] = p;
         assert(i == num);
index 4ab8b3894ae3737498c2557bcc924d92ed490254..32ee6707013f4c691ebd01015b7fc320f2871efa 100644 (file)
@@ -534,7 +534,7 @@ TEST(sd_device_new_from_nulstr) {
 
         _cleanup_(sd_device_unrefp) sd_device *device = NULL, *from_nulstr = NULL;
         _cleanup_free_ char *nulstr_copy = NULL;
-        const char *devlink, *nulstr;
+        const char *nulstr;
         size_t len;
 
         assert_se(sd_device_new_from_syspath(&device, "/sys/class/net/lo") >= 0);
index 51be54b1e14ceff3e7166bd57438d3ad0b09f527..f163314f7c3ac1153b534eb601fc94f29eaf96db 100644 (file)
@@ -300,13 +300,15 @@ static int hwdb_new(const char *path, sd_hwdb **ret) {
                 if (!hwdb->f)
                         return log_debug_errno(errno, "Failed to open %s: %m", path);
         } else {
-                NULSTR_FOREACH(path, hwdb_bin_paths) {
-                        log_debug("Trying to open \"%s\"...", path);
-                        hwdb->f = fopen(path, "re");
-                        if (hwdb->f)
+                NULSTR_FOREACH(p, hwdb_bin_paths) {
+                        log_debug("Trying to open \"%s\"...", p);
+                        hwdb->f = fopen(p, "re");
+                        if (hwdb->f) {
+                                path = p;
                                 break;
+                        }
                         if (errno != ENOENT)
-                                return log_debug_errno(errno, "Failed to open %s: %m", path);
+                                return log_debug_errno(errno, "Failed to open %s: %m", p);
                 }
 
                 if (!hwdb->f)
index 53c0b2a01e93f6b2baf86afca650f6c4d6825f0e..aa90d873a5741a10aefb2c2bd3d6ed2112b7cb59 100644 (file)
@@ -1828,7 +1828,6 @@ static int add_search_paths(sd_journal *j) {
         static const char search_paths[] =
                 "/run/log/journal\0"
                 "/var/log/journal\0";
-        const char *p;
 
         assert(j);
 
index 601f61bf639f2bae1a451044a5a92c7c1613d93a..ded64a66efad22e7b367b752a616047f6c084b3f 100644 (file)
@@ -7,6 +7,7 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
+#include "nulstr-util.h"
 #include "path-lookup.h"
 #include "path-util.h"
 #include "string-util.h"
index e44e287282774874ccfd0bdbceb67913fae0464e..9a4e4fb59b5540fcdc05274e15f0d2b5ed5dfca2 100644 (file)
@@ -72,15 +72,12 @@ static int print_status_info(StatusInfo *i) {
                         return log_error_errno(r, "Failed to build locale settings from kernel command line: %m");
         }
 
-        table = table_new("key", "value");
+        table = table_new_vertical();
         if (!table)
                 return log_oom();
 
         assert_se(cell = table_get_cell(table, 0, 0));
         (void) table_set_ellipsize_percent(table, cell, 100);
-        (void) table_set_align_percent(table, cell, 100);
-
-        table_set_header(table, false);
 
         table_set_ersatz_string(table, TABLE_ERSATZ_UNSET);
 
@@ -96,30 +93,30 @@ static int print_status_info(StatusInfo *i) {
         }
 
         r = table_add_many(table,
-                           TABLE_STRING, "System Locale:",
+                           TABLE_FIELD, "System Locale",
                            TABLE_STRV, i->locale,
-                           TABLE_STRING, "VC Keymap:",
+                           TABLE_FIELD, "VC Keymap",
                            TABLE_STRING, i->vconsole_keymap);
         if (r < 0)
                 return table_log_add_error(r);
 
         if (!isempty(i->vconsole_keymap_toggle)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "VC Toggle Keymap:",
+                                   TABLE_FIELD, "VC Toggle Keymap",
                                    TABLE_STRING, i->vconsole_keymap_toggle);
                 if (r < 0)
                         return table_log_add_error(r);
         }
 
         r = table_add_many(table,
-                           TABLE_STRING, "X11 Layout:",
+                           TABLE_FIELD, "X11 Layout",
                            TABLE_STRING, i->x11_layout);
         if (r < 0)
                 return table_log_add_error(r);
 
         if (!isempty(i->x11_model)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "X11 Model:",
+                                   TABLE_FIELD, "X11 Model",
                                    TABLE_STRING, i->x11_model);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -127,7 +124,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->x11_variant)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "X11 Variant:",
+                                   TABLE_FIELD, "X11 Variant",
                                    TABLE_STRING, i->x11_variant);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -135,7 +132,7 @@ static int print_status_info(StatusInfo *i) {
 
         if (!isempty(i->x11_options)) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "X11 Options:",
+                                   TABLE_FIELD, "X11 Options",
                                    TABLE_STRING, i->x11_options);
                 if (r < 0)
                         return table_log_add_error(r);
index dd2bbf5bfb80a58e1d2256c2bced26854b498fcc..880d0d209c5c35e020e45db27540aa8cb6ce517d 100644 (file)
@@ -432,7 +432,6 @@ int vconsole_convert_to_x11(Context *c) {
 }
 
 int find_converted_keymap(const char *x11_layout, const char *x11_variant, char **new_keymap) {
-        const char *dir;
         _cleanup_free_ char *n = NULL;
 
         if (x11_variant)
index 0a245247ec766672c15bf5c09f4e0a590d0ed443..75f397dd6bac8ee27f9d9c6389b7a6968fc1eb54 100644 (file)
@@ -1014,9 +1014,9 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
                  * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
                  * the UID/GIDs as they are. */
                 if (copy_from)
-                        r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags);
+                        r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, uid_shift == 0 ? UID_INVALID : 0, uid_shift == 0 ? GID_INVALID : 0, copy_flags, NULL);
                 else
-                        r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags);
+                        r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, uid_shift == 0 ? UID_INVALID : uid_shift, uid_shift == 0 ? GID_INVALID : uid_shift, copy_flags, NULL);
 
                 hostfd = safe_close(hostfd);
                 containerfd = safe_close(containerfd);
index af0f5d861206a9837eb84f2d1288e4f1aeac2680..93761a1da9bdff993b5a7a25f8c347025246d7c2 100644 (file)
@@ -98,7 +98,7 @@ static OutputFlags get_output_flags(void) {
 static int call_get_os_release(sd_bus *bus, const char *method, const char *name, const char *query, ...) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        const char *k, *v, *iter, **query_res = NULL;
+        const char *k, *v, **query_res = NULL;
         size_t count = 0, awaited_args = 0;
         va_list ap;
         int r;
index fb9fbed12cbed749e108df2fde5f6349b46c4766..ef5825ef7573c2ea80d2882058ea3bc56c8287ec 100644 (file)
@@ -2219,7 +2219,6 @@ static int copy_devnodes(const char *dest) {
                 "tty\0"
                 "net/tun\0";
 
-        const char *d;
         int r = 0;
 
         assert(dest);
index a037d7be1d22b0acf3dfccf34a33ec6bf045f517..8a1a8411cfe2c2053b9993c1f27806500a07f887 100644 (file)
@@ -51,6 +51,7 @@
 #include "mkfs-util.h"
 #include "mount-util.h"
 #include "mountpoint-util.h"
+#include "nulstr-util.h"
 #include "openssl-util.h"
 #include "parse-argument.h"
 #include "parse-helpers.h"
@@ -3227,7 +3228,7 @@ static int context_copy_blocks(Context *context) {
         return 0;
 }
 
-static int do_copy_files(Partition *p, const char *root) {
+static int do_copy_files(Partition *p, const char *root, const Set *denylist) {
         int r;
 
         assert(p);
@@ -3273,13 +3274,15 @@ static int do_copy_files(Partition *p, const char *root) {
                                                 sfd, ".",
                                                 pfd, fn,
                                                 UID_INVALID, GID_INVALID,
-                                                COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS);
+                                                COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS,
+                                                denylist);
                         } else
                                 r = copy_tree_at(
                                                 sfd, ".",
                                                 tfd, ".",
                                                 UID_INVALID, GID_INVALID,
-                                                COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS);
+                                                COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS,
+                                                denylist);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", *source, strempty(arg_root), *target);
                 } else {
@@ -3339,7 +3342,7 @@ static int do_make_directories(Partition *p, const char *root) {
         return 0;
 }
 
-static int partition_populate_directory(Partition *p, char **ret_root, char **ret_tmp_root) {
+static int partition_populate_directory(Partition *p, const Set *denylist, char **ret_root, char **ret_tmp_root) {
         _cleanup_(rm_rf_physical_and_freep) char *root = NULL;
         int r;
 
@@ -3362,7 +3365,8 @@ static int partition_populate_directory(Partition *p, char **ret_root, char **re
          * allocate a temporary directory, it's stored in "ret_tmp_root" to indicate it should be removed.
          * Otherwise, we return the directory to use in "root" to indicate it should not be removed. */
 
-        if (strv_length(p->copy_files) == 2 && strv_length(p->make_directories) == 0 && streq(p->copy_files[1], "/")) {
+        if (strv_length(p->copy_files) == 2 && strv_length(p->make_directories) == 0 &&
+                streq(p->copy_files[1], "/") && set_isempty(denylist)) {
                 _cleanup_free_ char *s = NULL;
 
                 r = chase_symlinks(p->copy_files[0], arg_root, CHASE_PREFIX_ROOT, &s, NULL);
@@ -3378,7 +3382,7 @@ static int partition_populate_directory(Partition *p, char **ret_root, char **re
         if (r < 0)
                 return log_error_errno(r, "Failed to create temporary directory: %m");
 
-        r = do_copy_files(p, root);
+        r = do_copy_files(p, root, denylist);
         if (r < 0)
                 return r;
 
@@ -3391,7 +3395,7 @@ static int partition_populate_directory(Partition *p, char **ret_root, char **re
         return 0;
 }
 
-static int partition_populate_filesystem(Partition *p, const char *node) {
+static int partition_populate_filesystem(Partition *p, const char *node, const Set *denylist) {
         int r;
 
         assert(p);
@@ -3425,7 +3429,7 @@ static int partition_populate_filesystem(Partition *p, const char *node) {
                 if (mount_nofollow_verbose(LOG_ERR, node, fs, p->format, MS_NOATIME|MS_NODEV|MS_NOEXEC|MS_NOSUID, NULL) < 0)
                         _exit(EXIT_FAILURE);
 
-                if (do_copy_files(p, fs) < 0)
+                if (do_copy_files(p, fs, denylist) < 0)
                         _exit(EXIT_FAILURE);
 
                 if (do_make_directories(p, fs) < 0)
@@ -3444,13 +3448,58 @@ static int partition_populate_filesystem(Partition *p, const char *node) {
         return 0;
 }
 
+static int make_copy_files_denylist(Context *context, Set **ret) {
+        _cleanup_set_free_ Set *denylist = NULL;
+        int r;
+
+        assert(context);
+        assert(ret);
+
+        LIST_FOREACH(partitions, p, context->partitions) {
+                const char *sources = gpt_partition_type_mountpoint_nulstr(p->type_uuid);
+                if (!sources)
+                        continue;
+
+                NULSTR_FOREACH(s, sources) {
+                        _cleanup_free_ char *d = NULL;
+                        struct stat st;
+
+                        r = chase_symlinks_and_stat(s, arg_root, CHASE_PREFIX_ROOT, NULL, &st, NULL);
+                        if (r == -ENOENT)
+                                continue;
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to stat source file '%s%s': %m",
+                                                       strempty(arg_root), s);
+
+                        if (set_contains(denylist, &st))
+                                continue;
+
+                        d = memdup(&st, sizeof(st));
+                        if (!d)
+                                return log_oom();
+                        if (set_ensure_put(&denylist, &inode_hash_ops, d) < 0)
+                                return log_oom();
+
+                        TAKE_PTR(d);
+                }
+        }
+
+        *ret = TAKE_PTR(denylist);
+        return 0;
+}
+
 static int context_mkfs(Context *context) {
+        _cleanup_set_free_ Set *denylist = NULL;
         int fd = -1, r;
 
         assert(context);
 
         /* Make a file system */
 
+        r = make_copy_files_denylist(context, &denylist);
+        if (r < 0)
+                return r;
+
         LIST_FOREACH(partitions, p, context->partitions) {
                 _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
                 _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
@@ -3507,7 +3556,7 @@ static int context_mkfs(Context *context) {
                  * using read-only filesystems such as squashfs, we can't populate after creating the
                  * filesystem because it's read-only, so instead we create a temporary root to use as the
                  * source tree when generating the read-only filesystem. */
-                r = partition_populate_directory(p, &root, &tmp_root);
+                r = partition_populate_directory(p, denylist, &root, &tmp_root);
                 if (r < 0)
                         return r;
 
@@ -3526,7 +3575,7 @@ static int context_mkfs(Context *context) {
                                 return log_error_errno(errno, "Failed to unlock LUKS device: %m");
 
                 /* Now, we can populate all the other filesystems that aren't read-only. */
-                r = partition_populate_filesystem(p, fsdev);
+                r = partition_populate_filesystem(p, fsdev, denylist);
                 if (r < 0) {
                         encrypted_dev_fd = safe_close(encrypted_dev_fd);
                         (void) deactivate_luks(cd, encrypted);
index dd0a8e121e256e39125c186d4f6c8928be21a340..ff645fc0d704315e422067b110a6bfa46505702a 100644 (file)
@@ -33,6 +33,7 @@
 #include "pretty-print.h"
 #include "process-util.h"
 #include "resolvconf-compat.h"
+#include "resolve-util.h"
 #include "resolvectl.h"
 #include "resolved-def.h"
 #include "resolved-dns-packet.h"
@@ -1114,49 +1115,49 @@ static int show_statistics(int argc, char **argv, void *userdata) {
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        table = table_new("key", "value");
+        table = table_new_vertical();
         if (!table)
                 return log_oom();
 
-        table_set_header(table, false);
-
         r = table_add_many(table,
                            TABLE_STRING, "Transactions",
                            TABLE_SET_COLOR, ansi_highlight(),
+                           TABLE_SET_ALIGN_PERCENT, 0,
                            TABLE_EMPTY,
-                           TABLE_STRING, "Current Transactions:",
+                           TABLE_FIELD, "Current Transactions",
                            TABLE_SET_ALIGN_PERCENT, 100,
                            TABLE_UINT64, n_current_transactions,
-                           TABLE_STRING, "Total Transactions:",
+                           TABLE_SET_ALIGN_PERCENT, 100,
+                           TABLE_FIELD, "Total Transactions",
                            TABLE_UINT64, n_total_transactions,
                            TABLE_EMPTY, TABLE_EMPTY,
                            TABLE_STRING, "Cache",
                            TABLE_SET_COLOR, ansi_highlight(),
                            TABLE_SET_ALIGN_PERCENT, 0,
                            TABLE_EMPTY,
-                           TABLE_STRING, "Current Cache Size:",
+                           TABLE_FIELD, "Current Cache Size",
                            TABLE_SET_ALIGN_PERCENT, 100,
                            TABLE_UINT64, cache_size,
-                           TABLE_STRING, "Cache Hits:",
+                           TABLE_FIELD, "Cache Hits",
                            TABLE_UINT64, n_cache_hit,
-                           TABLE_STRING, "Cache Misses:",
+                           TABLE_FIELD, "Cache Misses",
                            TABLE_UINT64, n_cache_miss,
                            TABLE_EMPTY, TABLE_EMPTY,
                            TABLE_STRING, "DNSSEC Verdicts",
                            TABLE_SET_COLOR, ansi_highlight(),
                            TABLE_SET_ALIGN_PERCENT, 0,
                            TABLE_EMPTY,
-                           TABLE_STRING, "Secure:",
+                           TABLE_FIELD, "Secure",
                            TABLE_SET_ALIGN_PERCENT, 100,
                            TABLE_UINT64, n_dnssec_secure,
-                           TABLE_STRING, "Insecure:",
+                           TABLE_FIELD, "Insecure",
                            TABLE_UINT64, n_dnssec_insecure,
-                           TABLE_STRING, "Bogus:",
+                           TABLE_FIELD, "Bogus",
                            TABLE_UINT64, n_dnssec_bogus,
-                           TABLE_STRING, "Indeterminate:",
+                           TABLE_FIELD, "Indeterminate:",
                            TABLE_UINT64, n_dnssec_indeterminate);
         if (r < 0)
-                table_log_add_error(r);
+                return table_log_add_error(r);
 
         r = table_print(table, NULL);
         if (r < 0)
@@ -1476,14 +1477,14 @@ static void global_info_clear(GlobalInfo *p) {
         strv_free(p->ntas);
 }
 
-static int dump_list(Table *table, const char *prefix, char * const *l) {
+static int dump_list(Table *table, const char *field, char * const *l) {
         int r;
 
         if (strv_isempty(l))
                 return 0;
 
         r = table_add_many(table,
-                           TABLE_STRING, prefix,
+                           TABLE_FIELD, field,
                            TABLE_STRV_WRAPPED, l);
         if (r < 0)
                 return table_log_add_error(r);
@@ -1655,15 +1656,13 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
         printf("%sLink %i (%s)%s\n",
                ansi_highlight(), ifindex, name, ansi_normal());
 
-        table = table_new("key", "value");
+        table = table_new_vertical();
         if (!table)
                 return log_oom();
 
-        table_set_header(table, false);
-
         r = table_add_many(table,
-                           TABLE_STRING, "Current Scopes:",
-                           TABLE_SET_ALIGN_PERCENT, 100);
+                           TABLE_FIELD, "Current Scopes",
+                           TABLE_SET_MINIMUM_WIDTH, 19);
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -1695,24 +1694,24 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode
                 return log_oom();
 
         r = table_add_many(table,
-                           TABLE_STRING,       "Protocols:",
+                           TABLE_FIELD,       "Protocols",
                            TABLE_STRV_WRAPPED, pstatus);
         if (r < 0)
                 return table_log_add_error(r);
 
         if (link_info.current_dns) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Current DNS Server:",
+                                   TABLE_FIELD, "Current DNS Server",
                                    TABLE_STRING, link_info.current_dns_ex ?: link_info.current_dns);
                 if (r < 0)
                         return table_log_add_error(r);
         }
 
-        r = dump_list(table, "DNS Servers:", link_info.dns_ex ?: link_info.dns);
+        r = dump_list(table, "DNS Servers", link_info.dns_ex ?: link_info.dns);
         if (r < 0)
                 return r;
 
-        r = dump_list(table, "DNS Domain:", link_info.domains);
+        r = dump_list(table, "DNS Domain", link_info.domains);
         if (r < 0)
                 return r;
 
@@ -1901,26 +1900,24 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
 
         printf("%sGlobal%s\n", ansi_highlight(), ansi_normal());
 
-        table = table_new("key", "value");
+        table = table_new_vertical();
         if (!table)
                 return log_oom();
 
-        table_set_header(table, false);
-
         _cleanup_strv_free_ char **pstatus = global_protocol_status(&global_info);
         if (!pstatus)
                 return log_oom();
 
         r = table_add_many(table,
-                           TABLE_STRING,            "Protocols:",
-                           TABLE_SET_ALIGN_PERCENT, 100,
+                           TABLE_FIELD,            "Protocols",
+                           TABLE_SET_MINIMUM_WIDTH, 19,
                            TABLE_STRV_WRAPPED,      pstatus);
         if (r < 0)
                 return table_log_add_error(r);
 
         if (global_info.resolv_conf_mode) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "resolv.conf mode:",
+                                   TABLE_FIELD, "resolv.conf mode",
                                    TABLE_STRING, global_info.resolv_conf_mode);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -1928,7 +1925,7 @@ static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
 
         if (global_info.current_dns) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Current DNS Server:",
+                                   TABLE_FIELD, "Current DNS Server",
                                    TABLE_STRING, global_info.current_dns_ex ?: global_info.current_dns);
                 if (r < 0)
                         return table_log_add_error(r);
@@ -2277,6 +2274,8 @@ static int verb_default_route(int argc, char **argv, void *userdata) {
 
 static int verb_llmnr(int argc, char **argv, void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *global_llmnr_support_str = NULL;
+        ResolveSupport global_llmnr_support, llmnr_support;
         sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
@@ -2292,6 +2291,22 @@ static int verb_llmnr(int argc, char **argv, void *userdata) {
         if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_LLMNR, NULL);
 
+        llmnr_support = resolve_support_from_string(argv[2]);
+        if (llmnr_support < 0)
+                return log_error_errno(llmnr_support, "Invalid LLMNR setting: %s", argv[2]);
+
+        r = bus_get_property_string(bus, bus_resolve_mgr, "LLMNR", &error, &global_llmnr_support_str);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get the global LLMNR support state: %s", bus_error_message(&error, r));
+
+        global_llmnr_support = resolve_support_from_string(global_llmnr_support_str);
+        if (global_llmnr_support < 0)
+                return log_error_errno(global_llmnr_support, "Received invalid global LLMNR setting: %s", global_llmnr_support_str);
+
+        if (global_llmnr_support < llmnr_support)
+                log_warning("Setting LLMNR support level \"%s\" for \"%s\", but the global support level is \"%s\".",
+                            argv[2], arg_ifname, global_llmnr_support_str);
+
         r = bus_call_method(bus, bus_resolve_mgr, "SetLinkLLMNR", &error, NULL, "is", arg_ifindex, argv[2]);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
@@ -2311,6 +2326,8 @@ static int verb_llmnr(int argc, char **argv, void *userdata) {
 
 static int verb_mdns(int argc, char **argv, void *userdata) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *global_mdns_support_str = NULL;
+        ResolveSupport global_mdns_support, mdns_support;
         sd_bus *bus = ASSERT_PTR(userdata);
         int r;
 
@@ -2326,6 +2343,22 @@ static int verb_mdns(int argc, char **argv, void *userdata) {
         if (argc < 3)
                 return status_ifindex(bus, arg_ifindex, NULL, STATUS_MDNS, NULL);
 
+        mdns_support = resolve_support_from_string(argv[2]);
+        if (mdns_support < 0)
+                return log_error_errno(mdns_support, "Invalid mDNS setting: %s", argv[2]);
+
+        r = bus_get_property_string(bus, bus_resolve_mgr, "MulticastDNS", &error, &global_mdns_support_str);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get the global mDNS support state: %s", bus_error_message(&error, r));
+
+        global_mdns_support = resolve_support_from_string(global_mdns_support_str);
+        if (global_mdns_support < 0)
+                return log_error_errno(global_mdns_support, "Received invalid global mDNS setting: %s", global_mdns_support_str);
+
+        if (global_mdns_support < mdns_support)
+                log_warning("Setting mDNS support level \"%s\" for \"%s\", but the global support level is \"%s\".",
+                            argv[2], arg_ifname, global_mdns_support_str);
+
         r = bus_call_method(bus, bus_resolve_mgr, "SetLinkMulticastDNS", &error, NULL, "is", arg_ifindex, argv[2]);
         if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
                 sd_bus_error_free(&error);
index 91bbeaed5bfce1504a25e78d61759ea88a574bcd..b7dc60c9c8b66369bc946920a482769b976f95b6 100644 (file)
@@ -21,7 +21,7 @@ struct DnsQuestionItem {
 struct DnsQuestion {
         unsigned n_ref;
         size_t n_keys, n_allocated;
-        DnsQuestionItem items[0];
+        DnsQuestionItem items[];
 };
 
 DnsQuestion *dns_question_new(size_t n);
index be9efb0a79a592eb4573fe5953c826e11e766bd5..f939b534c3fd98d384718ef40f18a0a301cd5b14 100644 (file)
@@ -44,8 +44,8 @@ typedef enum DnsServerFeatureLevel {
 #define DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(x) ((x) >= DNS_SERVER_FEATURE_LEVEL_DO)
 #define DNS_SERVER_FEATURE_LEVEL_IS_UDP(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_UDP, DNS_SERVER_FEATURE_LEVEL_EDNS0, DNS_SERVER_FEATURE_LEVEL_DO)
 
-const char* dns_server_feature_level_to_string(int i) _const_;
-int dns_server_feature_level_from_string(const char *s) _pure_;
+const char* dns_server_feature_level_to_string(DnsServerFeatureLevel i) _const_;
+DnsServerFeatureLevel dns_server_feature_level_from_string(const char *s) _pure_;
 
 struct DnsServer {
         Manager *manager;
index 828045f68fb878e728839b4848d9e8dc8bde6982..ca670b30f1e63d8ec787aebd0819570ad40169f8 100644 (file)
@@ -165,7 +165,6 @@ static int dns_trust_anchor_add_builtin_negative(DnsTrustAnchor *d) {
                 /* Defined by RFC 8375. The most official choice. */
                 "home.arpa\0";
 
-        const char *name;
         int r;
 
         assert(d);
index 5b1096daf6dad5381a0d1eb175ce244dbc5bb90e..9b6d14f20cc92d197566d48cfcfa386e62fedb00 100644 (file)
@@ -22,6 +22,8 @@
 
 static BUS_DEFINE_PROPERTY_GET(property_get_dnssec_supported, "b", Link, link_dnssec_supported);
 static BUS_DEFINE_PROPERTY_GET2(property_get_dnssec_mode, "s", Link, link_get_dnssec_mode, dnssec_mode_to_string);
+static BUS_DEFINE_PROPERTY_GET2(property_get_llmnr_support, "s", Link, link_get_llmnr_support, resolve_support_to_string);
+static BUS_DEFINE_PROPERTY_GET2(property_get_mdns_support, "s", Link, link_get_mdns_support, resolve_support_to_string);
 
 static int property_get_dns_over_tls_mode(
                 sd_bus *bus,
@@ -864,8 +866,8 @@ static const sd_bus_vtable link_vtable[] = {
         SD_BUS_PROPERTY("CurrentDNSServerEx", "(iayqs)", property_get_current_dns_server_ex, offsetof(Link, current_dns_server), 0),
         SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
         SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route, 0, 0),
-        SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0),
-        SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Link, mdns_support), 0),
+        SD_BUS_PROPERTY("LLMNR", "s", property_get_llmnr_support, 0, 0),
+        SD_BUS_PROPERTY("MulticastDNS", "s", property_get_mdns_support, 0, 0),
         SD_BUS_PROPERTY("DNSOverTLS", "s", property_get_dns_over_tls_mode, 0, 0),
         SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
         SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
index 5b34677cbefea230565c789f24e15c01d8444921..d41f6f3e5477585982540441dd46d0bb50fd4160 100644 (file)
@@ -140,8 +140,7 @@ void link_allocate_scopes(Link *l) {
                 l->unicast_scope = dns_scope_free(l->unicast_scope);
 
         if (link_relevant(l, AF_INET, true) &&
-            l->llmnr_support != RESOLVE_SUPPORT_NO &&
-            l->manager->llmnr_support != RESOLVE_SUPPORT_NO) {
+            link_get_llmnr_support(l) != RESOLVE_SUPPORT_NO) {
                 if (!l->llmnr_ipv4_scope) {
                         r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
                         if (r < 0)
@@ -151,9 +150,7 @@ void link_allocate_scopes(Link *l) {
                 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
 
         if (link_relevant(l, AF_INET6, true) &&
-            l->llmnr_support != RESOLVE_SUPPORT_NO &&
-            l->manager->llmnr_support != RESOLVE_SUPPORT_NO &&
-            socket_ipv6_is_supported()) {
+            link_get_llmnr_support(l) != RESOLVE_SUPPORT_NO) {
                 if (!l->llmnr_ipv6_scope) {
                         r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
                         if (r < 0)
@@ -163,8 +160,7 @@ void link_allocate_scopes(Link *l) {
                 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
 
         if (link_relevant(l, AF_INET, true) &&
-            l->mdns_support != RESOLVE_SUPPORT_NO &&
-            l->manager->mdns_support != RESOLVE_SUPPORT_NO) {
+            link_get_mdns_support(l) != RESOLVE_SUPPORT_NO) {
                 if (!l->mdns_ipv4_scope) {
                         r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET);
                         if (r < 0)
@@ -174,8 +170,7 @@ void link_allocate_scopes(Link *l) {
                 l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope);
 
         if (link_relevant(l, AF_INET6, true) &&
-            l->mdns_support != RESOLVE_SUPPORT_NO &&
-            l->manager->mdns_support != RESOLVE_SUPPORT_NO) {
+            link_get_mdns_support(l) != RESOLVE_SUPPORT_NO) {
                 if (!l->mdns_ipv6_scope) {
                         r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6);
                         if (r < 0)
@@ -192,8 +187,7 @@ void link_add_rrs(Link *l, bool force_remove) {
                 link_address_add_rrs(a, force_remove);
 
         if (!force_remove &&
-            l->mdns_support == RESOLVE_SUPPORT_YES &&
-            l->manager->mdns_support == RESOLVE_SUPPORT_YES) {
+            link_get_mdns_support(l) == RESOLVE_SUPPORT_YES) {
 
                 if (l->mdns_ipv4_scope) {
                         r = dns_scope_add_dnssd_services(l->mdns_ipv4_scope);
@@ -652,13 +646,13 @@ int link_update(Link *l) {
         if (r < 0)
                 return r;
 
-        if (l->llmnr_support != RESOLVE_SUPPORT_NO) {
+        if (link_get_llmnr_support(l) != RESOLVE_SUPPORT_NO) {
                 r = manager_llmnr_start(l->manager);
                 if (r < 0)
                         return r;
         }
 
-        if (l->mdns_support != RESOLVE_SUPPORT_NO) {
+        if (link_get_mdns_support(l) != RESOLVE_SUPPORT_NO) {
                 r = manager_mdns_start(l->manager);
                 if (r < 0)
                         return r;
@@ -803,6 +797,24 @@ bool link_dnssec_supported(Link *l) {
         return true;
 }
 
+ResolveSupport link_get_llmnr_support(Link *link) {
+        assert(link);
+        assert(link->manager);
+
+        /* This provides the effective LLMNR support level for the link, instead of the 'internal' per-link setting. */
+
+        return MIN(link->llmnr_support, link->manager->llmnr_support);
+}
+
+ResolveSupport link_get_mdns_support(Link *link) {
+        assert(link);
+        assert(link->manager);
+
+        /* This provides the effective mDNS support level for the link, instead of the 'internal' per-link setting. */
+
+        return MIN(link->mdns_support, link->manager->mdns_support);
+}
+
 int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
         LinkAddress *a;
 
@@ -886,8 +898,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
                 if (!force_remove &&
                     link_address_relevant(a, true) &&
                     a->link->llmnr_ipv4_scope &&
-                    a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
-                    a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
+                    link_get_llmnr_support(a->link) == RESOLVE_SUPPORT_YES) {
 
                         if (!a->link->manager->llmnr_host_ipv4_key) {
                                 a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
@@ -940,8 +951,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
                 if (!force_remove &&
                     link_address_relevant(a, true) &&
                     a->link->mdns_ipv4_scope &&
-                    a->link->mdns_support == RESOLVE_SUPPORT_YES &&
-                    a->link->manager->mdns_support == RESOLVE_SUPPORT_YES) {
+                    link_get_mdns_support(a->link) == RESOLVE_SUPPORT_YES) {
                         if (!a->link->manager->mdns_host_ipv4_key) {
                                 a->link->manager->mdns_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->mdns_hostname);
                                 if (!a->link->manager->mdns_host_ipv4_key) {
@@ -996,8 +1006,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
                 if (!force_remove &&
                     link_address_relevant(a, true) &&
                     a->link->llmnr_ipv6_scope &&
-                    a->link->llmnr_support == RESOLVE_SUPPORT_YES &&
-                    a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) {
+                    link_get_llmnr_support(a->link) == RESOLVE_SUPPORT_YES) {
 
                         if (!a->link->manager->llmnr_host_ipv6_key) {
                                 a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
@@ -1050,8 +1059,7 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) {
                 if (!force_remove &&
                     link_address_relevant(a, true) &&
                     a->link->mdns_ipv6_scope &&
-                    a->link->mdns_support == RESOLVE_SUPPORT_YES &&
-                    a->link->manager->mdns_support == RESOLVE_SUPPORT_YES) {
+                    link_get_mdns_support(a->link) == RESOLVE_SUPPORT_YES) {
 
                         if (!a->link->manager->mdns_host_ipv6_key) {
                                 a->link->manager->mdns_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->mdns_hostname);
index b5299e0b5b87ae5577e88cf26b644c7675451ace..d2043a10008050b0f84d423760d9257b3de911cc 100644 (file)
@@ -104,6 +104,9 @@ bool link_dnssec_supported(Link *l);
 
 DnsOverTlsMode link_get_dns_over_tls_mode(Link *l);
 
+ResolveSupport link_get_llmnr_support(Link *link);
+ResolveSupport link_get_mdns_support(Link *link);
+
 int link_save_user(Link *l);
 int link_load_user(Link *l);
 void link_remove_user(Link *l);
index 84d7b31bad7db78d33e03b7fb0cd050566780ed0..e7db23c2017bef81ae881d71c99e7dbaf4c92ca1 100644 (file)
@@ -34,6 +34,7 @@
 #include "memory-util.h"
 #include "missing_syscall.h"
 #include "mkdir-label.h"
+#include "nulstr-util.h"
 #include "process-util.h"
 #include "random-util.h"
 #include "signal-util.h"
@@ -112,6 +113,10 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa
         if (r < 0)
                 return r;
 
+        /* chop off the final NUL byte. We do this because we want to use the separator NUL bytes only if we
+         * have multiple passwords. */
+        n = LESS_BY(n, (size_t) 1);
+
         serial = add_key("user", keyname, p, n, KEY_SPEC_USER_KEYRING);
         if (serial == -1)
                 return -errno;
index 5b4f674ec2b01b3516f861e356d9b5fdf1765356..c2902d35082e40b9d26a69269a64e634885ae518 100644 (file)
@@ -135,7 +135,7 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
                         continue;
 
                 if (table[i].target) {
-                        const char *target = NULL, *s;
+                        const char *target = NULL;
 
                         /* check if one of the targets exists */
                         NULSTR_FOREACH(s, table[i].target) {
index 6a34b10c044c3c403e9295d5fcaf962cacde7399..0afc41d200bd03d23f5afbe10cd1cffbdefb0d0a 100644 (file)
@@ -19,6 +19,7 @@
 #include "pretty-print.h"
 #include "recurse-dir.h"
 #include "sort-util.h"
+#include "stat-util.h"
 #include "string-table.h"
 #include "strv.h"
 #include "terminal-util.h"
@@ -507,7 +508,7 @@ static int boot_loader_read_conf_path(BootConfig *config, const char *root, cons
         assert(config);
         assert(path);
 
-        r = chase_symlinks_and_fopen_unlocked(path, root, CHASE_PREFIX_ROOT, "re", &full, &f);
+        r = chase_symlinks_and_fopen_unlocked(path, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, "re", &full, &f);
         if (r == -ENOENT)
                 return 0;
         if (r < 0)
@@ -543,23 +544,6 @@ static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
         return -strverscmp_improved(a->id, b->id);
 }
 
-static void inode_hash_func(const struct stat *q, struct siphash *state) {
-        siphash24_compress(&q->st_dev, sizeof(q->st_dev), state);
-        siphash24_compress(&q->st_ino, sizeof(q->st_ino), state);
-}
-
-static int inode_compare_func(const struct stat *a, const struct stat *b) {
-        int r;
-
-        r = CMP(a->st_dev, b->st_dev);
-        if (r != 0)
-                return r;
-
-        return CMP(a->st_ino, b->st_ino);
-}
-
-DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops, struct stat, inode_hash_func, inode_compare_func, free);
-
 static int config_check_inode_relevant_and_unseen(BootConfig *config, int fd, const char *fname) {
         _cleanup_free_ char *d = NULL;
         struct stat st;
@@ -609,7 +593,7 @@ static int boot_entries_find_type1(
         assert(root);
         assert(dir);
 
-        dir_fd = chase_symlinks_and_open(dir, root, CHASE_PREFIX_ROOT, O_DIRECTORY|O_CLOEXEC, &full);
+        dir_fd = chase_symlinks_and_open(dir, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, O_DIRECTORY|O_CLOEXEC, &full);
         if (dir_fd == -ENOENT)
                 return 0;
         if (dir_fd < 0)
@@ -869,7 +853,7 @@ static int boot_entries_find_unified(
         assert(config);
         assert(dir);
 
-        r = chase_symlinks_and_opendir(dir, root, CHASE_PREFIX_ROOT, &full, &d);
+        r = chase_symlinks_and_opendir(dir, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, &full, &d);
         if (r == -ENOENT)
                 return 0;
         if (r < 0)
@@ -1276,7 +1260,7 @@ static void boot_entry_file_list(
         assert(p);
         assert(ret_status);
 
-        int status = chase_symlinks_and_access(p, root, CHASE_PREFIX_ROOT, F_OK, NULL, NULL);
+        int status = chase_symlinks_and_access(p, root, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, F_OK, NULL, NULL);
 
         printf("%13s%s ", strempty(field), field ? ":" : " ");
         if (status < 0) {
index e34a68ef8696ae1dc112029aabd6d3b506f9958f..e6f67fc714920e5a61a868202157b3f0b670a27b 100644 (file)
@@ -211,7 +211,6 @@ static int show_cgroup_name(
 
         if (FLAGS_SET(flags, OUTPUT_CGROUP_XATTRS) && fd >= 0) {
                 _cleanup_free_ char *nl = NULL;
-                char *xa;
 
                 r = flistxattr_malloc(fd, &nl);
                 if (r < 0)
index f404d99878b023ba6b07e838ff619789ecef7249..d5fdbbf9e07d5c57916112ed21b79388a0059245 100644 (file)
 #include "fs-util.h"
 #include "glob-util.h"
 #include "hostname-util.h"
-#include "initrd-util.h"
 #include "ima-util.h"
+#include "initrd-util.h"
 #include "limits-util.h"
 #include "list.h"
 #include "macro.h"
 #include "mountpoint-util.h"
+#include "nulstr-util.h"
 #include "os-util.h"
 #include "parse-util.h"
 #include "path-util.h"
index 69932865ba59fc33ceddd8e30012e8847288228c..29051ca0e34b11af116945c3f35e05998c7f3a6d 100644 (file)
@@ -211,7 +211,6 @@ static int parse_line(
 
                 if (sections && !nulstr_contains(sections, n)) {
                         bool ignore;
-                        const char *t;
 
                         ignore = (flags & CONFIG_PARSE_RELAXED) || startswith(n, "X-");
 
index 182544a206b755666014d88a983d91dc1596e242..2b492c38a5af63a2fba1453a2b86b84dd260f7fa 100644 (file)
@@ -687,6 +687,7 @@ static int fd_copy_tree_generic(
                 uid_t override_uid,
                 gid_t override_gid,
                 CopyFlags copy_flags,
+                const Set *denylist,
                 HardlinkContext *hardlink_context,
                 const char *display_path,
                 copy_progress_path_t progress_path,
@@ -877,6 +878,7 @@ static int fd_copy_directory(
                 uid_t override_uid,
                 gid_t override_gid,
                 CopyFlags copy_flags,
+                const Set *denylist,
                 HardlinkContext *hardlink_context,
                 const char *display_path,
                 copy_progress_path_t progress_path,
@@ -979,6 +981,11 @@ static int fd_copy_directory(
                                 return r;
                 }
 
+                if (set_contains(denylist, &buf)) {
+                        log_debug("%s/%s is in the denylist, skipping", from, de->d_name);
+                        continue;
+                }
+
                 if (S_ISDIR(buf.st_mode)) {
                         /*
                          * Don't descend into directories on other file systems, if this is requested. We do a simple
@@ -1011,7 +1018,10 @@ static int fd_copy_directory(
                         }
                 }
 
-                q = fd_copy_tree_generic(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags, hardlink_context, child_display_path, progress_path, progress_bytes, userdata);
+                q = fd_copy_tree_generic(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device,
+                                         depth_left-1, override_uid, override_gid, copy_flags, denylist,
+                                         hardlink_context, child_display_path, progress_path, progress_bytes,
+                                         userdata);
 
                 if (q == -EINTR) /* Propagate SIGINT/SIGTERM up instantly */
                         return q;
@@ -1082,6 +1092,7 @@ static int fd_copy_tree_generic(
                 uid_t override_uid,
                 gid_t override_gid,
                 CopyFlags copy_flags,
+                const Set *denylist,
                 HardlinkContext *hardlink_context,
                 const char *display_path,
                 copy_progress_path_t progress_path,
@@ -1090,7 +1101,9 @@ static int fd_copy_tree_generic(
         int r;
 
         if (S_ISDIR(st->st_mode))
-                return fd_copy_directory(df, from, st, dt, to, original_device, depth_left-1, override_uid, override_gid, copy_flags, hardlink_context, display_path, progress_path, progress_bytes, userdata);
+                return fd_copy_directory(df, from, st, dt, to, original_device, depth_left-1, override_uid,
+                                         override_gid, copy_flags, denylist, hardlink_context, display_path,
+                                         progress_path, progress_bytes, userdata);
 
         r = fd_copy_leaf(df, from, st, dt, to, override_uid, override_gid, copy_flags, hardlink_context, display_path, progress_bytes, userdata);
         /* We just tried to copy a leaf node of the tree. If it failed because the node already exists *and* the COPY_REPLACE flag has been provided, we should unlink the node and re-copy. */
@@ -1113,6 +1126,7 @@ int copy_tree_at_full(
                 uid_t override_uid,
                 gid_t override_gid,
                 CopyFlags copy_flags,
+                const Set *denylist,
                 copy_progress_path_t progress_path,
                 copy_progress_bytes_t progress_bytes,
                 void *userdata) {
@@ -1126,7 +1140,9 @@ int copy_tree_at_full(
         if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0)
                 return -errno;
 
-        r = fd_copy_tree_generic(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata);
+        r = fd_copy_tree_generic(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid,
+                                 override_gid, copy_flags, denylist, NULL, NULL, progress_path,
+                                 progress_bytes, userdata);
         if (r < 0)
                 return r;
 
@@ -1188,7 +1204,7 @@ int copy_directory_fd_full(
                         COPY_DEPTH_MAX,
                         UID_INVALID, GID_INVALID,
                         copy_flags,
-                        NULL, NULL,
+                        NULL, NULL, NULL,
                         progress_path,
                         progress_bytes,
                         userdata);
@@ -1231,7 +1247,7 @@ int copy_directory_full(
                         COPY_DEPTH_MAX,
                         UID_INVALID, GID_INVALID,
                         copy_flags,
-                        NULL, NULL,
+                        NULL, NULL, NULL,
                         progress_path,
                         progress_bytes,
                         userdata);
@@ -1539,7 +1555,6 @@ int copy_rights_with_fallback(int fdf, int fdt, const char *patht) {
 int copy_xattr(int fdf, int fdt, CopyFlags copy_flags) {
         _cleanup_free_ char *names = NULL;
         int ret = 0, r;
-        const char *p;
 
         r = flistxattr_malloc(fdf, &names);
         if (r < 0)
index d755916bd98dea3a89f419010e8721165bdbc1bb..d19361c9a29352ae5cc4517cc7ed9d38ce06324b 100644 (file)
@@ -9,6 +9,8 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include "set.h"
+
 typedef enum CopyFlags {
         COPY_REFLINK     = 1 << 0,  /* Try to reflink */
         COPY_MERGE       = 1 << 1,  /* Merge existing trees with our new one to copy */
@@ -45,12 +47,12 @@ static inline int copy_file_atomic(const char *from, const char *to, mode_t mode
         return copy_file_atomic_full(from, to, mode, chattr_flags, chattr_mask, copy_flags, NULL, NULL);
 }
 
-int copy_tree_at_full(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
-static inline int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
-        return copy_tree_at_full(fdf, from, fdt, to, override_uid, override_gid, copy_flags, NULL, NULL, NULL);
+int copy_tree_at_full(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, const Set *denylist, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
+static inline int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, const Set *denylist) {
+        return copy_tree_at_full(fdf, from, fdt, to, override_uid, override_gid, copy_flags, denylist, NULL, NULL, NULL);
 }
-static inline int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) {
-        return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, NULL, NULL, NULL);
+static inline int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, const Set *denylist) {
+        return copy_tree_at_full(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags, denylist, NULL, NULL, NULL);
 }
 
 int copy_directory_fd_full(int dirfd, const char *to, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
index a34052451034dfacc697d6aa053142a902afb06f..e0db777c96effafc3e2c40c333ecb0050c0f5852 100644 (file)
@@ -22,7 +22,6 @@ int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
                 "/proc/self/fd/1\0"  "/dev/stdout\0"
                 "/proc/self/fd/2\0"  "/dev/stderr\0";
 
-        const char *j, *k;
         int r;
 
         NULSTR_FOREACH_PAIR(j, k, symlinks) {
index fad95f7f435ccf5032c4dcc82d6950201a34a32d..073e5e84338d50f0881bc4ad992e0774720c234d 100644 (file)
@@ -429,7 +429,6 @@ int image_find(ImageClass class,
                const char *root,
                Image **ret) {
 
-        const char *path;
         int r;
 
         assert(class >= 0);
@@ -533,7 +532,6 @@ int image_discover(
                 const char *root,
                 Hashmap *h) {
 
-        const char *path;
         int r;
 
         assert(class >= 0);
@@ -1262,8 +1260,6 @@ bool image_in_search_path(
                 const char *root,
                 const char *image) {
 
-        const char *path;
-
         assert(image);
 
         NULSTR_FOREACH(path, image_search_path[class]) {
index 2f1903121636aca5b88fd68e43b5055a38e5ab96..8418ed6dc372e534071de9413f23520bcca07af4 100644 (file)
@@ -349,7 +349,7 @@ static int dissect_image(
         _cleanup_(blkid_free_probep) blkid_probe b = NULL;
         _cleanup_free_ char *generic_node = NULL;
         sd_id128_t generic_uuid = SD_ID128_NULL;
-        const char *pttype = NULL;
+        const char *pttype = NULL, *sptuuid = NULL;
         blkid_partlist pl;
         int r, generic_nr = -1, n_partitions;
 
@@ -410,7 +410,7 @@ static int dissect_image(
         if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) {
                 /* Look for file system superblocks, unless we only shall look for GPT partition tables */
                 blkid_probe_enable_superblocks(b, 1);
-                blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE);
+                blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE|BLKID_SUBLKS_UUID);
         }
 
         blkid_probe_enable_partitions(b, 1);
@@ -433,8 +433,9 @@ static int dissect_image(
                 (void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
                 if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
                         _cleanup_free_ char *t = NULL, *n = NULL, *o = NULL;
-                        const char *fstype = NULL, *options = NULL;
+                        const char *fstype = NULL, *options = NULL, *suuid = NULL;
                         _cleanup_close_ int mount_node_fd = -1;
+                        sd_id128_t uuid = SD_ID128_NULL;
 
                         if (FLAGS_SET(flags, DISSECT_IMAGE_OPEN_PARTITION_DEVICES)) {
                                 mount_node_fd = open_partition(devname, /* is_partition = */ false, m->loop);
@@ -444,6 +445,7 @@ static int dissect_image(
 
                         /* OK, we have found a file system, that's our root partition then. */
                         (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
+                        (void) blkid_probe_lookup_value(b, "UUID", &suuid, NULL);
 
                         if (fstype) {
                                 t = strdup(fstype);
@@ -451,6 +453,15 @@ static int dissect_image(
                                         return -ENOMEM;
                         }
 
+                        if (suuid) {
+                                /* blkid will return FAT's serial number as UUID, hence it is quite possible
+                                 * that parsing this will fail. We'll ignore the ID, since it's just too
+                                 * short to be useful as tru identifier. */
+                                r = sd_id128_from_string(suuid, &uuid);
+                                if (r < 0)
+                                        log_debug_errno(r, "Failed to parse file system UUID '%s', ignoring: %m", suuid);
+                        }
+
                         n = strdup(devname);
                         if (!n)
                                 return -ENOMEM;
@@ -467,6 +478,8 @@ static int dissect_image(
                         m->verity_sig_ready = m->verity_ready &&
                                 verity->root_hash_sig;
 
+                        m->image_uuid = uuid;
+
                         options = mount_options_from_designator(mount_options, PARTITION_ROOT);
                         if (options) {
                                 o = strdup(options);
@@ -515,6 +528,13 @@ static int dissect_image(
                         return -EPROTONOSUPPORT;
         }
 
+        (void) blkid_probe_lookup_value(b, "PTUUID", &sptuuid, NULL);
+        if (sptuuid) {
+                r = sd_id128_from_string(sptuuid, &m->image_uuid);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to parse partition table UUID '%s', ignoring: %m", sptuuid);
+        }
+
         errno = 0;
         pl = blkid_probe_get_partitions(b);
         if (!pl)
@@ -668,7 +688,7 @@ static int dissect_image(
                                         continue;
 
                                 assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0);
-                                designator = PARTITION_ROOT_OF_ARCH(architecture);
+                                designator = partition_root_of_arch(architecture);
                                 rw = !(pflags & SD_GPT_FLAG_READ_ONLY);
                                 growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS);
 
@@ -693,7 +713,7 @@ static int dissect_image(
                                         continue;
 
                                 assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0);
-                                designator = PARTITION_VERITY_OF(PARTITION_ROOT_OF_ARCH(architecture));
+                                designator = partition_verity_of(partition_root_of_arch(architecture));
                                 fstype = "DM_verity_hash";
                                 rw = false;
 
@@ -713,7 +733,7 @@ static int dissect_image(
                                         continue;
 
                                 assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0);
-                                designator = PARTITION_VERITY_SIG_OF(PARTITION_ROOT_OF_ARCH(architecture));
+                                designator = partition_verity_sig_of(partition_root_of_arch(architecture));
                                 fstype = "verity_hash_signature";
                                 rw = false;
 
@@ -730,7 +750,7 @@ static int dissect_image(
                                         continue;
 
                                 assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0);
-                                designator = PARTITION_USR_OF_ARCH(architecture);
+                                designator = partition_usr_of_arch(architecture);
                                 rw = !(pflags & SD_GPT_FLAG_READ_ONLY);
                                 growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS);
 
@@ -754,7 +774,7 @@ static int dissect_image(
                                         continue;
 
                                 assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0);
-                                designator = PARTITION_VERITY_OF(PARTITION_USR_OF_ARCH(architecture));
+                                designator = partition_verity_of(partition_usr_of_arch(architecture));
                                 fstype = "DM_verity_hash";
                                 rw = false;
 
@@ -774,7 +794,7 @@ static int dissect_image(
                                         continue;
 
                                 assert_se((architecture = gpt_partition_type_uuid_to_arch(type_id)) >= 0);
-                                designator = PARTITION_VERITY_SIG_OF(PARTITION_USR_OF_ARCH(architecture));
+                                designator = partition_verity_sig_of(partition_usr_of_arch(architecture));
                                 fstype = "verity_hash_signature";
                                 rw = false;
 
@@ -864,7 +884,7 @@ static int dissect_image(
                                          * let the newest version win. This permits a simple A/B versioning
                                          * scheme in OS images. */
 
-                                        if (!PARTITION_DESIGNATOR_VERSIONED(designator) ||
+                                        if (!partition_designator_is_versioned(designator) ||
                                             strverscmp_improved(m->partitions[designator].label, label) >= 0)
                                                 continue;
 
@@ -1010,19 +1030,13 @@ static int dissect_image(
                 log_debug("No root partition found of the native architecture, falling back to a root "
                           "partition of the secondary architecture.");
 
-                m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_SECONDARY];
-                zero(m->partitions[PARTITION_ROOT_SECONDARY]);
-                m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY];
-                zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
-                m->partitions[PARTITION_ROOT_VERITY_SIG] = m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG];
-                zero(m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG]);
+                m->partitions[PARTITION_ROOT] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_SECONDARY]);
+                m->partitions[PARTITION_ROOT_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_SECONDARY_VERITY]);
+                m->partitions[PARTITION_ROOT_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_SECONDARY_VERITY_SIG]);
 
-                m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_SECONDARY];
-                zero(m->partitions[PARTITION_USR_SECONDARY]);
-                m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_SECONDARY_VERITY];
-                zero(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
-                m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG];
-                zero(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
+                m->partitions[PARTITION_USR] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY]);
+                m->partitions[PARTITION_USR_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
+                m->partitions[PARTITION_USR_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
 
                 m->partitions[PARTITION_ROOT_OTHER].found = false;
                 m->partitions[PARTITION_ROOT_OTHER_VERITY].found = false;
@@ -1044,19 +1058,13 @@ static int dissect_image(
                           "falling back to a root partition of a non-native architecture (%s).",
                           architecture_to_string(m->partitions[PARTITION_ROOT_OTHER].architecture));
 
-                m->partitions[PARTITION_ROOT] = m->partitions[PARTITION_ROOT_OTHER];
-                zero(m->partitions[PARTITION_ROOT_OTHER]);
-                m->partitions[PARTITION_ROOT_VERITY] = m->partitions[PARTITION_ROOT_OTHER_VERITY];
-                zero(m->partitions[PARTITION_ROOT_OTHER_VERITY]);
-                m->partitions[PARTITION_ROOT_VERITY_SIG] = m->partitions[PARTITION_ROOT_OTHER_VERITY_SIG];
-                zero(m->partitions[PARTITION_ROOT_OTHER_VERITY_SIG]);
-
-                m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_OTHER];
-                zero(m->partitions[PARTITION_USR_OTHER]);
-                m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_OTHER_VERITY];
-                zero(m->partitions[PARTITION_USR_OTHER_VERITY]);
-                m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_OTHER_VERITY_SIG];
-                zero(m->partitions[PARTITION_USR_OTHER_VERITY_SIG]);
+                m->partitions[PARTITION_ROOT] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_OTHER]);
+                m->partitions[PARTITION_ROOT_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_OTHER_VERITY]);
+                m->partitions[PARTITION_ROOT_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_ROOT_OTHER_VERITY_SIG]);
+
+                m->partitions[PARTITION_USR] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER]);
+                m->partitions[PARTITION_USR_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER_VERITY]);
+                m->partitions[PARTITION_USR_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER_VERITY_SIG]);
         }
 
         /* Hmm, we found a signature partition but no Verity data? Something is off. */
@@ -1083,12 +1091,9 @@ static int dissect_image(
                           "partition of the secondary architecture.");
 
                 /* Upgrade secondary arch to primary */
-                m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_SECONDARY];
-                zero(m->partitions[PARTITION_USR_SECONDARY]);
-                m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_SECONDARY_VERITY];
-                zero(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
-                m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG];
-                zero(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
+                m->partitions[PARTITION_USR] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY]);
+                m->partitions[PARTITION_USR_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY_VERITY]);
+                m->partitions[PARTITION_USR_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_USR_SECONDARY_VERITY_SIG]);
 
                 m->partitions[PARTITION_USR_OTHER].found = false;
                 m->partitions[PARTITION_USR_OTHER_VERITY].found = false;
@@ -1105,12 +1110,9 @@ static int dissect_image(
                           architecture_to_string(m->partitions[PARTITION_ROOT_OTHER].architecture));
 
                 /* Upgrade other arch to primary */
-                m->partitions[PARTITION_USR] = m->partitions[PARTITION_USR_OTHER];
-                zero(m->partitions[PARTITION_USR_OTHER]);
-                m->partitions[PARTITION_USR_VERITY] = m->partitions[PARTITION_USR_OTHER_VERITY];
-                zero(m->partitions[PARTITION_USR_OTHER_VERITY]);
-                m->partitions[PARTITION_USR_VERITY_SIG] = m->partitions[PARTITION_USR_OTHER_VERITY_SIG];
-                zero(m->partitions[PARTITION_USR_OTHER_VERITY_SIG]);
+                m->partitions[PARTITION_USR] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER]);
+                m->partitions[PARTITION_USR_VERITY] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER_VERITY]);
+                m->partitions[PARTITION_USR_VERITY_SIG] = TAKE_PARTITION(m->partitions[PARTITION_USR_OTHER_VERITY_SIG]);
         }
 
         /* Hmm, we found a signature partition but no Verity data? Something is off. */
@@ -2349,7 +2351,7 @@ int dissected_image_decrypt(
                 if (r < 0)
                         return r;
 
-                k = PARTITION_VERITY_OF(i);
+                k = partition_verity_of(i);
                 if (k >= 0) {
                         r = verity_partition(i, p, m->partitions + k, verity, flags | DISSECT_IMAGE_VERITY_SHARE, d);
                         if (r < 0)
@@ -2691,7 +2693,7 @@ int dissected_image_load_verity_sig_partition(
         if (r == 0)
                 return 0;
 
-        d = PARTITION_VERITY_SIG_OF(verity->designator < 0 ? PARTITION_ROOT : verity->designator);
+        d = partition_verity_sig_of(verity->designator < 0 ? PARTITION_ROOT : verity->designator);
         assert(d >= 0);
 
         p = m->partitions + d;
@@ -2849,7 +2851,6 @@ int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_
 
                 for (unsigned k = 0; k < _META_MAX; k++) {
                         _cleanup_close_ int fd = -ENOENT;
-                        const char *p;
 
                         if (!paths[k])
                                 continue;
@@ -3150,7 +3151,7 @@ bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesi
         if (image->single_file_system)
                 return partition_designator == PARTITION_ROOT && image->has_verity;
 
-        return PARTITION_VERITY_OF(partition_designator) >= 0;
+        return partition_verity_of(partition_designator) >= 0;
 }
 
 bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignator partition_designator) {
@@ -3167,7 +3168,7 @@ bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignat
         if (image->single_file_system)
                 return partition_designator == PARTITION_ROOT;
 
-        k = PARTITION_VERITY_OF(partition_designator);
+        k = partition_verity_of(partition_designator);
         return k >= 0 && image->partitions[k].found;
 }
 
@@ -3184,7 +3185,7 @@ bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesi
         if (image->single_file_system)
                 return partition_designator == PARTITION_ROOT;
 
-        k = PARTITION_VERITY_SIG_OF(partition_designator);
+        k = partition_verity_sig_of(partition_designator);
         return k >= 0 && image->partitions[k].found;
 }
 
@@ -3286,34 +3287,6 @@ int mount_image_privately_interactively(
         return 0;
 }
 
-static const char *const partition_designator_table[] = {
-        [PARTITION_ROOT]                      = "root",
-        [PARTITION_ROOT_SECONDARY]            = "root-secondary",
-        [PARTITION_ROOT_OTHER]                = "root-other",
-        [PARTITION_USR]                       = "usr",
-        [PARTITION_USR_SECONDARY]             = "usr-secondary",
-        [PARTITION_USR_OTHER]                 = "usr-other",
-        [PARTITION_HOME]                      = "home",
-        [PARTITION_SRV]                       = "srv",
-        [PARTITION_ESP]                       = "esp",
-        [PARTITION_XBOOTLDR]                  = "xbootldr",
-        [PARTITION_SWAP]                      = "swap",
-        [PARTITION_ROOT_VERITY]               = "root-verity",
-        [PARTITION_ROOT_SECONDARY_VERITY]     = "root-secondary-verity",
-        [PARTITION_ROOT_OTHER_VERITY]         = "root-other-verity",
-        [PARTITION_USR_VERITY]                = "usr-verity",
-        [PARTITION_USR_SECONDARY_VERITY]      = "usr-secondary-verity",
-        [PARTITION_USR_OTHER_VERITY]          = "usr-other-verity",
-        [PARTITION_ROOT_VERITY_SIG]           = "root-verity-sig",
-        [PARTITION_ROOT_SECONDARY_VERITY_SIG] = "root-secondary-verity-sig",
-        [PARTITION_ROOT_OTHER_VERITY_SIG]     = "root-other-verity-sig",
-        [PARTITION_USR_VERITY_SIG]            = "usr-verity-sig",
-        [PARTITION_USR_SECONDARY_VERITY_SIG]  = "usr-secondary-verity-sig",
-        [PARTITION_USR_OTHER_VERITY_SIG]      = "usr-other-verity-sig",
-        [PARTITION_TMP]                       = "tmp",
-        [PARTITION_VAR]                       = "var",
-};
-
 static bool mount_options_relax_extension_release_checks(const MountOptions *options) {
         if (!options)
                 return false;
@@ -3441,5 +3414,3 @@ int verity_dissect_and_mount(
 
         return 0;
 }
-
-DEFINE_STRING_TABLE_LOOKUP(partition_designator, PartitionDesignator);
index 46675d22ab3a981f47ee810241560d4b095700b6..1a398010b53b9d9210c9fb8e4ea8336d12daa22f 100644 (file)
@@ -6,6 +6,7 @@
 #include "sd-id128.h"
 
 #include "architecture.h"
+#include "gpt.h"
 #include "list.h"
 #include "loop-util.h"
 #include "macro.h"
@@ -40,147 +41,12 @@ struct DissectedPartition {
                 .architecture = _ARCHITECTURE_INVALID,                  \
                 .mount_node_fd = -1,                                    \
         })
-
-typedef enum PartitionDesignator {
-        PARTITION_ROOT,
-        PARTITION_ROOT_SECONDARY,  /* Secondary architecture */
-        PARTITION_ROOT_OTHER,
-        PARTITION_USR,
-        PARTITION_USR_SECONDARY,
-        PARTITION_USR_OTHER,
-        PARTITION_HOME,
-        PARTITION_SRV,
-        PARTITION_ESP,
-        PARTITION_XBOOTLDR,
-        PARTITION_SWAP,
-        PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */
-        PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
-        PARTITION_ROOT_OTHER_VERITY,
-        PARTITION_USR_VERITY,
-        PARTITION_USR_SECONDARY_VERITY,
-        PARTITION_USR_OTHER_VERITY,
-        PARTITION_ROOT_VERITY_SIG, /* PKCS#7 signature for root hash for the PARTITION_ROOT partition */
-        PARTITION_ROOT_SECONDARY_VERITY_SIG, /* ditto for the PARTITION_ROOT_SECONDARY partition */
-        PARTITION_ROOT_OTHER_VERITY_SIG,
-        PARTITION_USR_VERITY_SIG,
-        PARTITION_USR_SECONDARY_VERITY_SIG,
-        PARTITION_USR_OTHER_VERITY_SIG,
-        PARTITION_TMP,
-        PARTITION_VAR,
-        _PARTITION_DESIGNATOR_MAX,
-        _PARTITION_DESIGNATOR_INVALID = -EINVAL,
-} PartitionDesignator;
-
-static inline bool PARTITION_DESIGNATOR_VERSIONED(PartitionDesignator d) {
-        /* Returns true for all designators where we want to support a concept of "versioning", i.e. which
-         * likely contain software binaries (or hashes thereof) that make sense to be versioned as a
-         * whole. We use this check to automatically pick the newest version of these partitions, by version
-         * comparing the partition labels. */
-
-        return IN_SET(d,
-                      PARTITION_ROOT,
-                      PARTITION_ROOT_SECONDARY,
-                      PARTITION_ROOT_OTHER,
-                      PARTITION_USR,
-                      PARTITION_USR_SECONDARY,
-                      PARTITION_USR_OTHER,
-                      PARTITION_ROOT_VERITY,
-                      PARTITION_ROOT_SECONDARY_VERITY,
-                      PARTITION_ROOT_OTHER_VERITY,
-                      PARTITION_USR_VERITY,
-                      PARTITION_USR_SECONDARY_VERITY,
-                      PARTITION_USR_OTHER_VERITY,
-                      PARTITION_ROOT_VERITY_SIG,
-                      PARTITION_ROOT_SECONDARY_VERITY_SIG,
-                      PARTITION_ROOT_OTHER_VERITY_SIG,
-                      PARTITION_USR_VERITY_SIG,
-                      PARTITION_USR_SECONDARY_VERITY_SIG,
-                      PARTITION_USR_OTHER_VERITY_SIG);
-}
-
-static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) {
-        switch (p) {
-
-        case PARTITION_ROOT:
-                return PARTITION_ROOT_VERITY;
-
-        case PARTITION_ROOT_SECONDARY:
-                return PARTITION_ROOT_SECONDARY_VERITY;
-
-        case PARTITION_ROOT_OTHER:
-                return PARTITION_ROOT_OTHER_VERITY;
-
-        case PARTITION_USR:
-                return PARTITION_USR_VERITY;
-
-        case PARTITION_USR_SECONDARY:
-                return PARTITION_USR_SECONDARY_VERITY;
-
-        case PARTITION_USR_OTHER:
-                return PARTITION_USR_OTHER_VERITY;
-
-        default:
-                return _PARTITION_DESIGNATOR_INVALID;
-        }
-}
-
-static inline PartitionDesignator PARTITION_VERITY_SIG_OF(PartitionDesignator p) {
-        switch (p) {
-
-        case PARTITION_ROOT:
-                return PARTITION_ROOT_VERITY_SIG;
-
-        case PARTITION_ROOT_SECONDARY:
-                return PARTITION_ROOT_SECONDARY_VERITY_SIG;
-
-        case PARTITION_ROOT_OTHER:
-                return PARTITION_ROOT_OTHER_VERITY_SIG;
-
-        case PARTITION_USR:
-                return PARTITION_USR_VERITY_SIG;
-
-        case PARTITION_USR_SECONDARY:
-                return PARTITION_USR_SECONDARY_VERITY_SIG;
-
-        case PARTITION_USR_OTHER:
-                return PARTITION_USR_OTHER_VERITY_SIG;
-
-        default:
-                return _PARTITION_DESIGNATOR_INVALID;
-        }
-}
-
-static inline PartitionDesignator PARTITION_ROOT_OF_ARCH(Architecture arch) {
-        switch (arch) {
-
-        case native_architecture():
-                return PARTITION_ROOT;
-
-#ifdef ARCHITECTURE_SECONDARY
-        case ARCHITECTURE_SECONDARY:
-                return PARTITION_ROOT_SECONDARY;
-#endif
-
-        default:
-                return PARTITION_ROOT_OTHER;
-        }
-}
-
-static inline PartitionDesignator PARTITION_USR_OF_ARCH(Architecture arch) {
-        switch (arch) {
-
-        case native_architecture():
-                return PARTITION_USR;
-
-#ifdef ARCHITECTURE_SECONDARY
-        case ARCHITECTURE_SECONDARY:
-                return PARTITION_USR_SECONDARY;
-#endif
-
-        default:
-                return PARTITION_USR_OTHER;
-        }
-}
+#define TAKE_PARTITION(p)                                       \
+        ({                                                      \
+                DissectedPartition *_pp = &(p), _p = *_pp;      \
+                *_pp = DISSECTED_PARTITION_NULL;                \
+                _p;                                             \
+        })
 
 typedef enum DissectImageFlags {
         DISSECT_IMAGE_DEVICE_READ_ONLY         = 1 << 0,  /* Make device read-only */
@@ -229,6 +95,7 @@ struct DissectedImage {
 
         /* Meta information extracted from /etc/os-release and similar */
         char *image_name;
+        sd_id128_t image_uuid;
         char *hostname;
         sd_id128_t machine_id;
         char **machine_info;
@@ -297,9 +164,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DecryptedImage*, decrypted_image_unref);
 
 int dissected_image_relinquish(DissectedImage *m);
 
-const char* partition_designator_to_string(PartitionDesignator d) _const_;
-PartitionDesignator partition_designator_from_string(const char *name) _pure_;
-
 int verity_settings_load(VeritySettings *verity, const char *image, const char *root_hash_path, const char *root_hash_sig_path);
 void verity_settings_done(VeritySettings *verity);
 
index 0549c9f12ef1153693954af5eecd71cbcfcdbbf8..1c1db2f43a97bcbea4be85d4624ddeaee8dd6375 100644 (file)
@@ -132,6 +132,8 @@ struct Table {
         size_t n_cells;
 
         bool header;   /* Whether to show the header row? */
+        bool vertical; /* Whether to field names are on the left rather than the first line */
+
         TableErsatz ersatz; /* What to show when we have an empty cell or an invalid value that cannot be rendered. */
 
         size_t width;  /* If == 0 format this as wide as necessary. If SIZE_MAX format this to console
@@ -197,14 +199,7 @@ Table *table_new_internal(const char *first_header, ...) {
         for (const char *h = first_header; h; h = va_arg(ap, const char*)) {
                 TableCell *cell;
 
-                r = table_add_cell(t, &cell, TABLE_STRING, h);
-                if (r < 0) {
-                        va_end(ap);
-                        return NULL;
-                }
-
-                /* Make the table header uppercase */
-                r = table_set_uppercase(t, cell, true);
+                r = table_add_cell(t, &cell, TABLE_HEADER, h);
                 if (r < 0) {
                         va_end(ap);
                         return NULL;
@@ -216,6 +211,32 @@ Table *table_new_internal(const char *first_header, ...) {
         return TAKE_PTR(t);
 }
 
+Table *table_new_vertical(void) {
+        _cleanup_(table_unrefp) Table *t = NULL;
+        TableCell *cell;
+
+        t = table_new_raw(2);
+        if (!t)
+                return NULL;
+
+        t->vertical = true;
+        t->header = false;
+
+        if (table_add_cell(t, &cell, TABLE_HEADER, "key") < 0)
+                return NULL;
+
+        if (table_set_align_percent(t, cell, 100) < 0)
+                return NULL;
+
+        if (table_add_cell(t, &cell, TABLE_HEADER, "value") < 0)
+                return NULL;
+
+        if (table_set_align_percent(t, cell, 0) < 0)
+                return NULL;
+
+        return TAKE_PTR(t);
+}
+
 static TableData *table_data_free(TableData *d) {
         assert(d);
 
@@ -260,6 +281,8 @@ static size_t table_data_size(TableDataType type, const void *data) {
 
         case TABLE_STRING:
         case TABLE_PATH:
+        case TABLE_FIELD:
+        case TABLE_HEADER:
                 return strlen(data) + 1;
 
         case TABLE_STRV:
@@ -336,7 +359,8 @@ static bool table_data_matches(
                 size_t maximum_width,
                 unsigned weight,
                 unsigned align_percent,
-                unsigned ellipsize_percent) {
+                unsigned ellipsize_percent,
+                bool uppercase) {
 
         size_t k, l;
         assert(d);
@@ -359,13 +383,14 @@ static bool table_data_matches(
         if (d->ellipsize_percent != ellipsize_percent)
                 return false;
 
-        /* If a color/url/uppercase flag is set, refuse to merge */
+        if (d->uppercase != uppercase)
+                return false;
+
+        /* If a color/url is set, refuse to merge */
         if (d->color || d->rgap_color)
                 return false;
         if (d->url)
                 return false;
-        if (d->uppercase)
-                return false;
 
         k = table_data_size(type, data);
         l = table_data_size(d->type, d->data);
@@ -382,7 +407,8 @@ static TableData *table_data_new(
                 size_t maximum_width,
                 unsigned weight,
                 unsigned align_percent,
-                unsigned ellipsize_percent) {
+                unsigned ellipsize_percent,
+                bool uppercase) {
 
         _cleanup_free_ TableData *d = NULL;
         size_t data_size;
@@ -400,6 +426,7 @@ static TableData *table_data_new(
         d->weight = weight;
         d->align_percent = align_percent;
         d->ellipsize_percent = ellipsize_percent;
+        d->uppercase = uppercase;
 
         if (IN_SET(type, TABLE_STRV, TABLE_STRV_WRAPPED)) {
                 d->strv = strv_copy(data);
@@ -423,6 +450,7 @@ int table_add_cell_full(
                 unsigned ellipsize_percent) {
 
         _cleanup_(table_data_unrefp) TableData *d = NULL;
+        bool uppercase;
         TableData *p;
 
         assert(t);
@@ -455,13 +483,15 @@ int table_add_cell_full(
         assert(align_percent <= 100);
         assert(ellipsize_percent <= 100);
 
+        uppercase = type == TABLE_HEADER;
+
         /* Small optimization: Pretty often adjacent cells in two subsequent lines have the same data and
          * formatting. Let's see if we can reuse the cell data and ref it once more. */
 
-        if (p && table_data_matches(p, type, data, minimum_width, maximum_width, weight, align_percent, ellipsize_percent))
+        if (p && table_data_matches(p, type, data, minimum_width, maximum_width, weight, align_percent, ellipsize_percent, uppercase))
                 d = table_data_ref(p);
         else {
-                d = table_data_new(type, data, minimum_width, maximum_width, weight, align_percent, ellipsize_percent);
+                d = table_data_new(type, data, minimum_width, maximum_width, weight, align_percent, ellipsize_percent, uppercase);
                 if (!d)
                         return -ENOMEM;
         }
@@ -477,18 +507,21 @@ int table_add_cell_full(
         return 0;
 }
 
-int table_add_cell_stringf(Table *t, TableCell **ret_cell, const char *format, ...) {
+int table_add_cell_stringf_full(Table *t, TableCell **ret_cell, TableDataType dt, const char *format, ...) {
         _cleanup_free_ char *buffer = NULL;
         va_list ap;
         int r;
 
+        assert(t);
+        assert(IN_SET(dt, TABLE_STRING, TABLE_PATH, TABLE_FIELD, TABLE_HEADER));
+
         va_start(ap, format);
         r = vasprintf(&buffer, format, ap);
         va_end(ap);
         if (r < 0)
                 return -ENOMEM;
 
-        return table_add_cell(t, ret_cell, TABLE_STRING, buffer);
+        return table_add_cell(t, ret_cell, dt, buffer);
 }
 
 int table_fill_empty(Table *t, size_t until_column) {
@@ -563,14 +596,14 @@ static int table_dedup_cell(Table *t, TableCell *cell) {
                         od->maximum_width,
                         od->weight,
                         od->align_percent,
-                        od->ellipsize_percent);
+                        od->ellipsize_percent,
+                        od->uppercase);
         if (!nd)
                 return -ENOMEM;
 
         nd->color = od->color;
         nd->rgap_color = od->rgap_color;
         nd->url = TAKE_PTR(curl);
-        nd->uppercase = od->uppercase;
 
         table_data_unref(od);
         t->data[i] = nd;
@@ -780,14 +813,14 @@ int table_update(Table *t, TableCell *cell, TableDataType type, const void *data
                         od->maximum_width,
                         od->weight,
                         od->align_percent,
-                        od->ellipsize_percent);
+                        od->ellipsize_percent,
+                        od->uppercase);
         if (!nd)
                 return -ENOMEM;
 
         nd->color = od->color;
         nd->rgap_color = od->rgap_color;
         nd->url = TAKE_PTR(curl);
-        nd->uppercase = od->uppercase;
 
         table_data_unref(od);
         t->data[i] = nd;
@@ -840,6 +873,8 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
 
                 case TABLE_STRING:
                 case TABLE_PATH:
+                case TABLE_FIELD:
+                case TABLE_HEADER:
                         data = va_arg(ap, const char *);
                         break;
 
@@ -1241,6 +1276,8 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t
                 switch (a->type) {
 
                 case TABLE_STRING:
+                case TABLE_FIELD:
+                case TABLE_HEADER:
                         return strcmp(a->string, b->string);
 
                 case TABLE_PATH:
@@ -1416,15 +1453,26 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
 
         case TABLE_STRING:
         case TABLE_PATH:
+        case TABLE_FIELD:
+        case TABLE_HEADER:
                 if (d->uppercase && !avoid_uppercasing) {
-                        d->formatted = new(char, strlen(d->string) + 1);
+                        d->formatted = new(char, strlen(d->string) + (d->type == TABLE_FIELD) + 1);
                         if (!d->formatted)
                                 return NULL;
 
                         char *q = d->formatted;
-                        for (char *p = d->string; *p; p++, q++)
-                                *q = (char) toupper((unsigned char) *p);
+                        for (char *p = d->string; *p; p++)
+                                *(q++) = (char) toupper((unsigned char) *p);
+
+                        if (d->type == TABLE_FIELD)
+                                *(q++) = ':';
+
                         *q = 0;
+                        return d->formatted;
+                } else if (d->type == TABLE_FIELD) {
+                        d->formatted = strjoin(d->string, ":");
+                        if (!d->formatted)
+                                return NULL;
 
                         return d->formatted;
                 }
@@ -1982,6 +2030,11 @@ static const char* table_data_color(TableData *d) {
         if (table_data_isempty(d))
                 return ansi_grey();
 
+        if (d->type == TABLE_FIELD)
+                return ansi_bright_blue();
+        if (d->type == TABLE_HEADER)
+                return ansi_underline();
+
         return NULL;
 }
 
@@ -1991,6 +2044,9 @@ static const char* table_data_rgap_color(TableData *d) {
         if (d->rgap_color)
                 return d->rgap_color;
 
+        if (d->type == TABLE_HEADER)
+                return ansi_underline();
+
         return NULL;
 }
 
@@ -2335,7 +2391,7 @@ int table_print(Table *t, FILE *f) {
 
                                                 /* Drop trailing white spaces of last column when no cosmetics is set. */
                                                 if (j == display_columns - 1 &&
-                                                    (!colors_enabled() || (!table_data_color(d) && row != t->data)) &&
+                                                    (!colors_enabled() || !table_data_color(d)) &&
                                                     (!urlify_enabled() || !d->url))
                                                         delete_trailing_chars(aligned, NULL);
 
@@ -2355,12 +2411,8 @@ int table_print(Table *t, FILE *f) {
                                         field = buffer;
                                 }
 
-                                if (colors_enabled()) {
-                                        if (gap_color)
-                                                fputs(gap_color, f);
-                                        else if (row == t->data) /* underline header line fully, including the column separator */
-                                                fputs(ansi_underline(), f);
-                                }
+                                if (colors_enabled() && gap_color)
+                                        fputs(gap_color, f);
 
                                 if (j > 0)
                                         fputc(' ', f); /* column separator left of cell */
@@ -2369,18 +2421,16 @@ int table_print(Table *t, FILE *f) {
                                         color = table_data_color(d);
 
                                         /* Undo gap color */
-                                        if (gap_color || (color && row == t->data))
+                                        if (gap_color)
                                                 fputs(ANSI_NORMAL, f);
 
                                         if (color)
                                                 fputs(color, f);
-                                        else if (gap_color && row == t->data) /* underline header line cell */
-                                                fputs(ansi_underline(), f);
                                 }
 
                                 fputs(field, f);
 
-                                if (colors_enabled() && (color || row == t->data))
+                                if (colors_enabled() && color)
                                         fputs(ANSI_NORMAL, f);
 
                                 gap_color = table_data_rgap_color(d);
@@ -2494,6 +2544,8 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
 
         case TABLE_STRING:
         case TABLE_PATH:
+        case TABLE_FIELD:
+        case TABLE_HEADER:
                 return json_variant_new_string(ret, d->string);
 
         case TABLE_STRV:
@@ -2573,10 +2625,10 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
                 return json_variant_new_array_bytes(ret, &d->address, FAMILY_ADDRESS_SIZE(AF_INET6));
 
         case TABLE_ID128:
-                return json_variant_new_string(ret, SD_ID128_TO_STRING(d->id128));
+                return json_variant_new_id128(ret, d->id128);
 
         case TABLE_UUID:
-                return json_variant_new_string(ret, SD_ID128_TO_UUID_STRING(d->id128));
+                return json_variant_new_uuid(ret, d->id128);
 
         case TABLE_UID:
                 if (!uid_is_valid(d->uid))
@@ -2629,21 +2681,47 @@ static char* string_to_json_field_name(const char *f) {
         return c;
 }
 
-static const char *table_get_json_field_name(Table *t, size_t column) {
+static int table_make_json_field_name(Table *t, TableData *d, char **ret) {
+        _cleanup_free_ char *mangled = NULL;
+        const char *n;
+
         assert(t);
+        assert(d);
+        assert(ret);
 
-        return column < t->n_json_fields ? t->json_fields[column] : NULL;
+        if (IN_SET(d->type, TABLE_HEADER, TABLE_FIELD))
+                n = d->string;
+        else {
+                n = table_data_format(t, d, /* avoid_uppercasing= */ true, SIZE_MAX, NULL);
+                if (!n)
+                        return -ENOMEM;
+        }
+
+        mangled = string_to_json_field_name(n);
+        if (!mangled)
+                return -ENOMEM;
+
+        *ret = TAKE_PTR(mangled);
+        return 0;
 }
 
-int table_to_json(Table *t, JsonVariant **ret) {
+static const char *table_get_json_field_name(Table *t, size_t idx) {
+        assert(t);
+
+        return idx < t->n_json_fields ? t->json_fields[idx] : NULL;
+}
+
+static int table_to_json_regular(Table *t, JsonVariant **ret) {
         JsonVariant **rows = NULL, **elements = NULL;
         _cleanup_free_ size_t *sorted = NULL;
         size_t n_rows, display_columns;
         int r;
 
         assert(t);
+        assert(!t->vertical);
 
         /* Ensure we have no incomplete rows */
+        assert(t->n_columns > 0);
         assert(t->n_cells % t->n_columns == 0);
 
         n_rows = t->n_cells / t->n_columns;
@@ -2686,24 +2764,10 @@ int table_to_json(Table *t, JsonVariant **ret) {
                 /* Use explicitly set JSON field name, if we have one. Otherwise mangle the column field value. */
                 n = table_get_json_field_name(t, c);
                 if (!n) {
-                        const char *formatted;
-                        TableData *d;
-
-                        assert_se(d = t->data[c]);
-
-                        /* Field names must be strings, hence format whatever we got here as a string first */
-                        formatted = table_data_format(t, d, true, SIZE_MAX, NULL);
-                        if (!formatted) {
-                                r = -ENOMEM;
+                        r = table_make_json_field_name(t, ASSERT_PTR(t->data[c]), &mangled);
+                        if (r < 0)
                                 goto finish;
-                        }
 
-                        /* Arbitrary strings suck as field names, try to mangle them into something more suitable hence */
-                        mangled = string_to_json_field_name(formatted);
-                        if (!mangled) {
-                                r = -ENOMEM;
-                                goto finish;
-                        }
                         n = mangled;
                 }
 
@@ -2761,6 +2825,70 @@ finish:
         return r;
 }
 
+static int table_to_json_vertical(Table *t, JsonVariant **ret) {
+        JsonVariant **elements = NULL;
+        size_t n_elements = 0;
+        int r;
+
+        assert(t);
+        assert(t->vertical);
+
+        if (t->n_columns != 2)
+                return -EINVAL;
+
+        /* Ensure we have no incomplete rows */
+        assert(t->n_cells % t->n_columns == 0);
+
+        elements = new0(JsonVariant *, t->n_cells);
+        if (!elements) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        for (size_t i = t->n_columns; i < t->n_cells; i++) {
+
+                if (i % t->n_columns == 0) {
+                        _cleanup_free_ char *mangled = NULL;
+                        const char *n;
+
+                        n = table_get_json_field_name(t, i / t->n_columns - 1);
+                        if (!n) {
+                                r = table_make_json_field_name(t, ASSERT_PTR(t->data[i]), &mangled);
+                                if (r < 0)
+                                        goto finish;
+
+                                n = mangled;
+                        }
+
+                        r = json_variant_new_string(elements + n_elements, n);
+                } else
+                        r = table_data_to_json(t->data[i], elements + n_elements);
+                if (r < 0)
+                        goto finish;
+
+                n_elements++;
+        }
+
+        r = json_variant_new_object(ret, elements, n_elements);
+
+finish:
+        if (elements) {
+                json_variant_unref_many(elements, n_elements);
+                free(elements);
+        }
+
+        return r;
+}
+
+int table_to_json(Table *t, JsonVariant **ret) {
+        assert(t);
+
+        if (t->vertical)
+                return table_to_json_vertical(t, ret);
+
+        return table_to_json_regular(t, ret);
+}
+
 int table_print_json(Table *t, FILE *f, JsonFormatFlags flags) {
         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
         int r;
@@ -2809,7 +2937,7 @@ int table_print_with_pager(
         return 0;
 }
 
-int table_set_json_field_name(Table *t, size_t column, const char *name) {
+int table_set_json_field_name(Table *t, size_t idx, const char *name) {
         int r;
 
         assert(t);
@@ -2817,21 +2945,21 @@ int table_set_json_field_name(Table *t, size_t column, const char *name) {
         if (name) {
                 size_t m;
 
-                m = MAX(column + 1, t->n_json_fields);
+                m = MAX(idx + 1, t->n_json_fields);
                 if (!GREEDY_REALLOC0(t->json_fields, m))
                         return -ENOMEM;
 
-                r = free_and_strdup(t->json_fields + column, name);
+                r = free_and_strdup(t->json_fields + idx, name);
                 if (r < 0)
                         return r;
 
                 t->n_json_fields = m;
                 return r;
         } else {
-                if (column >= t->n_json_fields)
+                if (idx >= t->n_json_fields)
                         return 0;
 
-                t->json_fields[column] = mfree(t->json_fields[column]);
+                t->json_fields[idx] = mfree(t->json_fields[idx]);
                 return 1;
         }
 }
index c88a060dbea0ac0e18b07cafd0f73be21678c9d2..e835692c6fdb9db19ac1fcae46c460f869ebf011 100644 (file)
@@ -12,6 +12,8 @@
 typedef enum TableDataType {
         TABLE_EMPTY,
         TABLE_STRING,
+        TABLE_HEADER,              /* in regular mode: the cells in the first row, that carry the column names */
+        TABLE_FIELD,               /* in vertical mode: the cells in the first column, that carry the field names */
         TABLE_STRV,
         TABLE_STRV_WRAPPED,
         TABLE_PATH,
@@ -78,6 +80,7 @@ typedef struct TableCell TableCell;
 Table *table_new_internal(const char *first_header, ...) _sentinel_;
 #define table_new(...) table_new_internal(__VA_ARGS__, NULL)
 Table *table_new_raw(size_t n_columns);
+Table *table_new_vertical(void);
 Table *table_unref(Table *t);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Table*, table_unref);
@@ -86,7 +89,8 @@ int table_add_cell_full(Table *t, TableCell **ret_cell, TableDataType type, cons
 static inline int table_add_cell(Table *t, TableCell **ret_cell, TableDataType type, const void *data) {
         return table_add_cell_full(t, ret_cell, type, data, SIZE_MAX, SIZE_MAX, UINT_MAX, UINT_MAX, UINT_MAX);
 }
-int table_add_cell_stringf(Table *t, TableCell **ret_cell, const char *format, ...) _printf_(3, 4);
+int table_add_cell_stringf_full(Table *t, TableCell **ret_cell, TableDataType type, const char *format, ...) _printf_(4, 5);
+#define table_add_cell_stringf(t, ret_cell, format, ...) table_add_cell_stringf_full(t, ret_cell, TABLE_STRING, format, __VA_ARGS__)
 
 int table_fill_empty(Table *t, size_t until_column);
 
@@ -139,7 +143,7 @@ int table_print_json(Table *t, FILE *f, JsonFormatFlags json_flags);
 
 int table_print_with_pager(Table *t, JsonFormatFlags json_format_flags, PagerFlags pager_flags, bool show_header);
 
-int table_set_json_field_name(Table *t, size_t column, const char *name);
+int table_set_json_field_name(Table *t, size_t idx, const char *name);
 
 #define table_log_add_error(r) \
         log_error_errno(r, "Failed to add cells to table: %m")
index 3cbc6be248b3bab2f83cae32dd130820107dd4cc..164e71a150d0d9f1d2c139168987093a233714f9 100644 (file)
@@ -88,7 +88,7 @@ int fstab_filter_options(
                 char ***ret_values,
                 char **ret_filtered) {
 
-        const char *name, *namefound = NULL, *x;
+        const char *namefound = NULL, *x;
         _cleanup_strv_free_ char **stor = NULL, **values = NULL;
         _cleanup_free_ char *value = NULL, **filtered = NULL;
         int r;
@@ -127,17 +127,17 @@ int fstab_filter_options(
                                 if (!x)
                                         continue;
                                 /* Match name, but when ret_values, only when followed by assignment. */
-                                if (*x == '=' || (!ret_values && *x == '\0'))
+                                if (*x == '=' || (!ret_values && *x == '\0')) {
+                                        /* Keep the last occurrence found */
+                                        namefound = name;
                                         goto found;
+                                }
                         }
 
                         *t = *s;
                         t++;
                         continue;
                 found:
-                        /* Keep the last occurrence found */
-                        namefound = name;
-
                         if (ret_value || ret_values) {
                                 assert(IN_SET(*x, '=', '\0'));
 
index a15833b21dbf44ff7db1359b731d37efc1b03837..af969ff9d5782f35876f10046028f5f074bfe91f 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include "gpt.h"
+#include "string-table.h"
 #include "string-util.h"
 #include "utf8.h"
 
 #pragma message "Please define GPT partition types for your architecture."
 #endif
 
+bool partition_designator_is_versioned(PartitionDesignator d) {
+        /* Returns true for all designators where we want to support a concept of "versioning", i.e. which
+         * likely contain software binaries (or hashes thereof) that make sense to be versioned as a
+         * whole. We use this check to automatically pick the newest version of these partitions, by version
+         * comparing the partition labels. */
+
+        return IN_SET(d,
+                      PARTITION_ROOT,
+                      PARTITION_ROOT_SECONDARY,
+                      PARTITION_ROOT_OTHER,
+                      PARTITION_USR,
+                      PARTITION_USR_SECONDARY,
+                      PARTITION_USR_OTHER,
+                      PARTITION_ROOT_VERITY,
+                      PARTITION_ROOT_SECONDARY_VERITY,
+                      PARTITION_ROOT_OTHER_VERITY,
+                      PARTITION_USR_VERITY,
+                      PARTITION_USR_SECONDARY_VERITY,
+                      PARTITION_USR_OTHER_VERITY,
+                      PARTITION_ROOT_VERITY_SIG,
+                      PARTITION_ROOT_SECONDARY_VERITY_SIG,
+                      PARTITION_ROOT_OTHER_VERITY_SIG,
+                      PARTITION_USR_VERITY_SIG,
+                      PARTITION_USR_SECONDARY_VERITY_SIG,
+                      PARTITION_USR_OTHER_VERITY_SIG);
+}
+
+PartitionDesignator partition_verity_of(PartitionDesignator p) {
+        switch (p) {
+
+        case PARTITION_ROOT:
+                return PARTITION_ROOT_VERITY;
+
+        case PARTITION_ROOT_SECONDARY:
+                return PARTITION_ROOT_SECONDARY_VERITY;
+
+        case PARTITION_ROOT_OTHER:
+                return PARTITION_ROOT_OTHER_VERITY;
+
+        case PARTITION_USR:
+                return PARTITION_USR_VERITY;
+
+        case PARTITION_USR_SECONDARY:
+                return PARTITION_USR_SECONDARY_VERITY;
+
+        case PARTITION_USR_OTHER:
+                return PARTITION_USR_OTHER_VERITY;
+
+        default:
+                return _PARTITION_DESIGNATOR_INVALID;
+        }
+}
+
+PartitionDesignator partition_verity_sig_of(PartitionDesignator p) {
+        switch (p) {
+
+        case PARTITION_ROOT:
+                return PARTITION_ROOT_VERITY_SIG;
+
+        case PARTITION_ROOT_SECONDARY:
+                return PARTITION_ROOT_SECONDARY_VERITY_SIG;
+
+        case PARTITION_ROOT_OTHER:
+                return PARTITION_ROOT_OTHER_VERITY_SIG;
+
+        case PARTITION_USR:
+                return PARTITION_USR_VERITY_SIG;
+
+        case PARTITION_USR_SECONDARY:
+                return PARTITION_USR_SECONDARY_VERITY_SIG;
+
+        case PARTITION_USR_OTHER:
+                return PARTITION_USR_OTHER_VERITY_SIG;
+
+        default:
+                return _PARTITION_DESIGNATOR_INVALID;
+        }
+}
+
+PartitionDesignator partition_root_of_arch(Architecture arch) {
+        switch (arch) {
+
+        case native_architecture():
+                return PARTITION_ROOT;
+
+#ifdef ARCHITECTURE_SECONDARY
+        case ARCHITECTURE_SECONDARY:
+                return PARTITION_ROOT_SECONDARY;
+#endif
+
+        default:
+                return PARTITION_ROOT_OTHER;
+        }
+}
+
+PartitionDesignator partition_usr_of_arch(Architecture arch) {
+        switch (arch) {
+
+        case native_architecture():
+                return PARTITION_USR;
+
+#ifdef ARCHITECTURE_SECONDARY
+        case ARCHITECTURE_SECONDARY:
+                return PARTITION_USR_SECONDARY;
+#endif
+
+        default:
+                return PARTITION_USR_OTHER;
+        }
+}
+
+static const char *const partition_designator_table[] = {
+        [PARTITION_ROOT]                      = "root",
+        [PARTITION_ROOT_SECONDARY]            = "root-secondary",
+        [PARTITION_ROOT_OTHER]                = "root-other",
+        [PARTITION_USR]                       = "usr",
+        [PARTITION_USR_SECONDARY]             = "usr-secondary",
+        [PARTITION_USR_OTHER]                 = "usr-other",
+        [PARTITION_HOME]                      = "home",
+        [PARTITION_SRV]                       = "srv",
+        [PARTITION_ESP]                       = "esp",
+        [PARTITION_XBOOTLDR]                  = "xbootldr",
+        [PARTITION_SWAP]                      = "swap",
+        [PARTITION_ROOT_VERITY]               = "root-verity",
+        [PARTITION_ROOT_SECONDARY_VERITY]     = "root-secondary-verity",
+        [PARTITION_ROOT_OTHER_VERITY]         = "root-other-verity",
+        [PARTITION_USR_VERITY]                = "usr-verity",
+        [PARTITION_USR_SECONDARY_VERITY]      = "usr-secondary-verity",
+        [PARTITION_USR_OTHER_VERITY]          = "usr-other-verity",
+        [PARTITION_ROOT_VERITY_SIG]           = "root-verity-sig",
+        [PARTITION_ROOT_SECONDARY_VERITY_SIG] = "root-secondary-verity-sig",
+        [PARTITION_ROOT_OTHER_VERITY_SIG]     = "root-other-verity-sig",
+        [PARTITION_USR_VERITY_SIG]            = "usr-verity-sig",
+        [PARTITION_USR_SECONDARY_VERITY_SIG]  = "usr-secondary-verity-sig",
+        [PARTITION_USR_OTHER_VERITY_SIG]      = "usr-other-verity-sig",
+        [PARTITION_TMP]                       = "tmp",
+        [PARTITION_VAR]                       = "var",
+        [PARTITION_USER_HOME]                 = "user-home",
+        [PARTITION_LINUX_GENERIC]             = "linux-generic",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(partition_designator, PartitionDesignator);
+
+static const char *const partition_mountpoint_table[] = {
+        [PARTITION_ROOT]                      = "/\0",
+        [PARTITION_ROOT_SECONDARY]            = "/\0",
+        [PARTITION_ROOT_OTHER]                = "/\0",
+        [PARTITION_USR]                       = "/usr\0",
+        [PARTITION_USR_SECONDARY]             = "/usr\0",
+        [PARTITION_USR_OTHER]                 = "/usr\0",
+        [PARTITION_HOME]                      = "/home\0",
+        [PARTITION_SRV]                       = "/srv\0",
+        [PARTITION_ESP]                       = "/efi\0/boot\0",
+        [PARTITION_XBOOTLDR]                  = "/boot\0",
+        [PARTITION_TMP]                       = "/var/tmp\0",
+        [PARTITION_VAR]                       = "/var\0",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(partition_mountpoint, PartitionDesignator);
+
 #define _GPT_ARCH_SEXTET(arch, name)                                   \
-        { SD_GPT_ROOT_##arch,              "root-" name,               ARCHITECTURE_##arch, .is_root = true            },  \
-        { SD_GPT_ROOT_##arch##_VERITY,     "root-" name "-verity",     ARCHITECTURE_##arch, .is_root_verity = true     },  \
-        { SD_GPT_ROOT_##arch##_VERITY_SIG, "root-" name "-verity-sig", ARCHITECTURE_##arch, .is_root_verity_sig = true },  \
-        { SD_GPT_USR_##arch,               "usr-" name,                ARCHITECTURE_##arch, .is_usr = true             },  \
-        { SD_GPT_USR_##arch##_VERITY,      "usr-" name "-verity",      ARCHITECTURE_##arch, .is_usr_verity = true      },  \
-        { SD_GPT_USR_##arch##_VERITY_SIG,  "usr-" name "-verity-sig",  ARCHITECTURE_##arch, .is_usr_verity_sig = true  }
+        { SD_GPT_ROOT_##arch,              "root-" name,               ARCHITECTURE_##arch, .designator = PARTITION_ROOT_OTHER            },  \
+        { SD_GPT_ROOT_##arch##_VERITY,     "root-" name "-verity",     ARCHITECTURE_##arch, .designator = PARTITION_ROOT_OTHER_VERITY     },  \
+        { SD_GPT_ROOT_##arch##_VERITY_SIG, "root-" name "-verity-sig", ARCHITECTURE_##arch, .designator = PARTITION_ROOT_OTHER_VERITY_SIG },  \
+        { SD_GPT_USR_##arch,               "usr-" name,                ARCHITECTURE_##arch, .designator = PARTITION_USR_OTHER             },  \
+        { SD_GPT_USR_##arch##_VERITY,      "usr-" name "-verity",      ARCHITECTURE_##arch, .designator = PARTITION_USR_OTHER_VERITY      },  \
+        { SD_GPT_USR_##arch##_VERITY_SIG,  "usr-" name "-verity-sig",  ARCHITECTURE_##arch, .designator = PARTITION_USR_OTHER_VERITY_SIG  }
 
 const GptPartitionType gpt_partition_type_table[] = {
         _GPT_ARCH_SEXTET(ALPHA,       "alpha"),
@@ -43,26 +204,31 @@ const GptPartitionType gpt_partition_type_table[] = {
         _GPT_ARCH_SEXTET(X86,         "x86"),
         _GPT_ARCH_SEXTET(X86_64,      "x86-64"),
 #ifdef SD_GPT_ROOT_NATIVE
-        { SD_GPT_ROOT_NATIVE,            "root",            native_architecture(), .is_root = true            },
-        { SD_GPT_ROOT_NATIVE_VERITY,     "root-verity",     native_architecture(), .is_root_verity = true     },
-        { SD_GPT_ROOT_NATIVE_VERITY_SIG, "root-verity-sig", native_architecture(), .is_root_verity_sig = true },
-        { SD_GPT_USR_NATIVE,             "usr",             native_architecture(), .is_usr = true             },
-        { SD_GPT_USR_NATIVE_VERITY,      "usr-verity",      native_architecture(), .is_usr_verity = true      },
-        { SD_GPT_USR_NATIVE_VERITY_SIG,  "usr-verity-sig",  native_architecture(), .is_usr_verity_sig = true  },
+        { SD_GPT_ROOT_NATIVE,            "root",            native_architecture(), .designator = PARTITION_ROOT            },
+        { SD_GPT_ROOT_NATIVE_VERITY,     "root-verity",     native_architecture(), .designator = PARTITION_ROOT_VERITY     },
+        { SD_GPT_ROOT_NATIVE_VERITY_SIG, "root-verity-sig", native_architecture(), .designator = PARTITION_ROOT_VERITY_SIG },
+        { SD_GPT_USR_NATIVE,             "usr",             native_architecture(), .designator = PARTITION_USR             },
+        { SD_GPT_USR_NATIVE_VERITY,      "usr-verity",      native_architecture(), .designator = PARTITION_USR_VERITY      },
+        { SD_GPT_USR_NATIVE_VERITY_SIG,  "usr-verity-sig",  native_architecture(), .designator = PARTITION_USR_VERITY_SIG  },
 #endif
 #ifdef SD_GPT_ROOT_SECONDARY
-        _GPT_ARCH_SEXTET(SECONDARY,   "secondary"),
+        { SD_GPT_ROOT_NATIVE,            "root-secondary",            native_architecture(), .designator = PARTITION_ROOT_SECONDARY            },
+        { SD_GPT_ROOT_NATIVE_VERITY,     "root-secondary-verity",     native_architecture(), .designator = PARTITION_ROOT_SECONDARY_VERITY     },
+        { SD_GPT_ROOT_NATIVE_VERITY_SIG, "root-secondary-verity-sig", native_architecture(), .designator = PARTITION_ROOT_SECONDARY_VERITY_SIG },
+        { SD_GPT_USR_NATIVE,             "usr-secondary",             native_architecture(), .designator = PARTITION_USR_SECONDARY             },
+        { SD_GPT_USR_NATIVE_VERITY,      "usr-secondary-verity",      native_architecture(), .designator = PARTITION_USR_SECONDARY_VERITY      },
+        { SD_GPT_USR_NATIVE_VERITY_SIG,  "usr-secondary-verity-sig",  native_architecture(), .designator = PARTITION_USR_SECONDARY_VERITY_SIG  },
 #endif
 
-        { SD_GPT_ESP,                    "esp",           _ARCHITECTURE_INVALID },
-        { SD_GPT_XBOOTLDR,               "xbootldr",      _ARCHITECTURE_INVALID },
-        { SD_GPT_SWAP,                   "swap",          _ARCHITECTURE_INVALID },
-        { SD_GPT_HOME,                   "home",          _ARCHITECTURE_INVALID },
-        { SD_GPT_SRV,                    "srv",           _ARCHITECTURE_INVALID },
-        { SD_GPT_VAR,                    "var",           _ARCHITECTURE_INVALID },
-        { SD_GPT_TMP,                    "tmp",           _ARCHITECTURE_INVALID },
-        { SD_GPT_USER_HOME,              "user-home",     _ARCHITECTURE_INVALID },
-        { SD_GPT_LINUX_GENERIC,          "linux-generic", _ARCHITECTURE_INVALID },
+        { SD_GPT_ESP,                    "esp",           _ARCHITECTURE_INVALID, .designator = PARTITION_ESP },
+        { SD_GPT_XBOOTLDR,               "xbootldr",      _ARCHITECTURE_INVALID, .designator = PARTITION_XBOOTLDR },
+        { SD_GPT_SWAP,                   "swap",          _ARCHITECTURE_INVALID, .designator = PARTITION_SWAP },
+        { SD_GPT_HOME,                   "home",          _ARCHITECTURE_INVALID, .designator = PARTITION_HOME },
+        { SD_GPT_SRV,                    "srv",           _ARCHITECTURE_INVALID, .designator = PARTITION_SRV },
+        { SD_GPT_VAR,                    "var",           _ARCHITECTURE_INVALID, .designator = PARTITION_VAR },
+        { SD_GPT_TMP,                    "tmp",           _ARCHITECTURE_INVALID, .designator = PARTITION_TMP },
+        { SD_GPT_USER_HOME,              "user-home",     _ARCHITECTURE_INVALID, .designator = PARTITION_USER_HOME },
+        { SD_GPT_LINUX_GENERIC,          "linux-generic", _ARCHITECTURE_INVALID, .designator = PARTITION_LINUX_GENERIC },
         {}
 };
 
@@ -140,55 +306,86 @@ static GptPartitionType gpt_partition_type_from_uuid(sd_id128_t id) {
         if (pt)
                 return *pt;
 
-        return (GptPartitionType) { .uuid = id, .arch = _ARCHITECTURE_INVALID };
+        return (GptPartitionType) {
+                .uuid = id,
+                .arch = _ARCHITECTURE_INVALID,
+                .designator = _PARTITION_DESIGNATOR_INVALID,
+        };
 }
 
 bool gpt_partition_type_is_root(sd_id128_t id) {
-        return gpt_partition_type_from_uuid(id).is_root;
+        return IN_SET(gpt_partition_type_from_uuid(id).designator,
+                      PARTITION_ROOT,
+                      PARTITION_ROOT_SECONDARY,
+                      PARTITION_ROOT_OTHER);
 }
 
 bool gpt_partition_type_is_root_verity(sd_id128_t id) {
-        return gpt_partition_type_from_uuid(id).is_root_verity;
+        return IN_SET(gpt_partition_type_from_uuid(id).designator,
+                      PARTITION_ROOT_VERITY,
+                      PARTITION_ROOT_SECONDARY_VERITY,
+                      PARTITION_ROOT_OTHER_VERITY);
 }
 
 bool gpt_partition_type_is_root_verity_sig(sd_id128_t id) {
-        return gpt_partition_type_from_uuid(id).is_root_verity_sig;
+        return IN_SET(gpt_partition_type_from_uuid(id).designator,
+                      PARTITION_ROOT_VERITY_SIG,
+                      PARTITION_ROOT_SECONDARY_VERITY_SIG,
+                      PARTITION_ROOT_OTHER_VERITY_SIG);
 }
 
 bool gpt_partition_type_is_usr(sd_id128_t id) {
-        return gpt_partition_type_from_uuid(id).is_usr;
+        return IN_SET(gpt_partition_type_from_uuid(id).designator,
+                      PARTITION_USR,
+                      PARTITION_USR_SECONDARY,
+                      PARTITION_USR_OTHER);
 }
 
 bool gpt_partition_type_is_usr_verity(sd_id128_t id) {
-        return gpt_partition_type_from_uuid(id).is_usr_verity;
+        return IN_SET(gpt_partition_type_from_uuid(id).designator,
+                      PARTITION_USR_VERITY,
+                      PARTITION_USR_SECONDARY_VERITY,
+                      PARTITION_USR_OTHER_VERITY);
 }
 
 bool gpt_partition_type_is_usr_verity_sig(sd_id128_t id) {
-        return gpt_partition_type_from_uuid(id).is_usr_verity_sig;
+        return IN_SET(gpt_partition_type_from_uuid(id).designator,
+                      PARTITION_USR_VERITY_SIG,
+                      PARTITION_USR_SECONDARY_VERITY_SIG,
+                      PARTITION_USR_OTHER_VERITY_SIG);
+}
+
+const char *gpt_partition_type_mountpoint_nulstr(sd_id128_t id) {
+        PartitionDesignator d = gpt_partition_type_from_uuid(id).designator;
+        if (d < 0)
+                return NULL;
+
+        return partition_mountpoint_to_string(d);
 }
 
 bool gpt_partition_type_knows_read_only(sd_id128_t id) {
         return gpt_partition_type_is_root(id) ||
                 gpt_partition_type_is_usr(id) ||
-                sd_id128_in_set(id,
-                                SD_GPT_HOME,
-                                SD_GPT_SRV,
-                                SD_GPT_VAR,
-                                SD_GPT_TMP,
-                                SD_GPT_XBOOTLDR) ||
-                gpt_partition_type_is_root_verity(id) || /* pretty much implied, but let's set the bit to make things really clear */
-                gpt_partition_type_is_usr_verity(id);    /* ditto */
+                /* pretty much implied, but let's set the bit to make things really clear */
+                gpt_partition_type_is_root_verity(id) ||
+                gpt_partition_type_is_usr_verity(id) ||
+                IN_SET(gpt_partition_type_from_uuid(id).designator,
+                       PARTITION_HOME,
+                       PARTITION_SRV,
+                       PARTITION_VAR,
+                       PARTITION_TMP,
+                       PARTITION_XBOOTLDR);
 }
 
 bool gpt_partition_type_knows_growfs(sd_id128_t id) {
         return gpt_partition_type_is_root(id) ||
                 gpt_partition_type_is_usr(id) ||
-                sd_id128_in_set(id,
-                                SD_GPT_HOME,
-                                SD_GPT_SRV,
-                                SD_GPT_VAR,
-                                SD_GPT_TMP,
-                                SD_GPT_XBOOTLDR);
+                IN_SET(gpt_partition_type_from_uuid(id).designator,
+                       PARTITION_HOME,
+                       PARTITION_SRV,
+                       PARTITION_VAR,
+                       PARTITION_TMP,
+                       PARTITION_XBOOTLDR);
 }
 
 bool gpt_partition_type_knows_no_auto(sd_id128_t id) {
@@ -196,11 +393,11 @@ bool gpt_partition_type_knows_no_auto(sd_id128_t id) {
                 gpt_partition_type_is_root_verity(id) ||
                 gpt_partition_type_is_usr(id) ||
                 gpt_partition_type_is_usr_verity(id) ||
-                sd_id128_in_set(id,
-                                SD_GPT_HOME,
-                                SD_GPT_SRV,
-                                SD_GPT_VAR,
-                                SD_GPT_TMP,
-                                SD_GPT_XBOOTLDR,
-                                SD_GPT_SWAP);
+                IN_SET(gpt_partition_type_from_uuid(id).designator,
+                       PARTITION_HOME,
+                       PARTITION_SRV,
+                       PARTITION_VAR,
+                       PARTITION_TMP,
+                       PARTITION_XBOOTLDR,
+                       PARTITION_SWAP);
 }
index f673194d4af9f9df5cfdcf7c2c53d0791afd0f1f..e0ab44a6427a85d441e962425ee377ffaad32a65 100644 (file)
 /* maximum length of gpt label */
 #define GPT_LABEL_MAX 36
 
+typedef enum PartitionDesignator {
+        PARTITION_ROOT, /* Primary architecture */
+        PARTITION_ROOT_SECONDARY, /* Secondary architecture */
+        PARTITION_ROOT_OTHER, /* Any architecture not covered by the primary or secondary architecture. */
+        PARTITION_USR,
+        PARTITION_USR_SECONDARY,
+        PARTITION_USR_OTHER,
+        PARTITION_HOME,
+        PARTITION_SRV,
+        PARTITION_ESP,
+        PARTITION_XBOOTLDR,
+        PARTITION_SWAP,
+        PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */
+        PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
+        PARTITION_ROOT_OTHER_VERITY,
+        PARTITION_USR_VERITY,
+        PARTITION_USR_SECONDARY_VERITY,
+        PARTITION_USR_OTHER_VERITY,
+        PARTITION_ROOT_VERITY_SIG, /* PKCS#7 signature for root hash for the PARTITION_ROOT partition */
+        PARTITION_ROOT_SECONDARY_VERITY_SIG, /* ditto for the PARTITION_ROOT_SECONDARY partition */
+        PARTITION_ROOT_OTHER_VERITY_SIG,
+        PARTITION_USR_VERITY_SIG,
+        PARTITION_USR_SECONDARY_VERITY_SIG,
+        PARTITION_USR_OTHER_VERITY_SIG,
+        PARTITION_TMP,
+        PARTITION_VAR,
+        PARTITION_USER_HOME,
+        PARTITION_LINUX_GENERIC,
+        _PARTITION_DESIGNATOR_MAX,
+        _PARTITION_DESIGNATOR_INVALID = -EINVAL,
+} PartitionDesignator;
+
+bool partition_designator_is_versioned(PartitionDesignator d);
+
+PartitionDesignator partition_verity_of(PartitionDesignator p);
+PartitionDesignator partition_verity_sig_of(PartitionDesignator p);
+PartitionDesignator partition_root_of_arch(Architecture arch);
+PartitionDesignator partition_usr_of_arch(Architecture arch);
+
+const char* partition_designator_to_string(PartitionDesignator d) _const_;
+PartitionDesignator partition_designator_from_string(const char *name) _pure_;
+
 const char *gpt_partition_type_uuid_to_string(sd_id128_t id);
 const char *gpt_partition_type_uuid_to_string_harder(
                 sd_id128_t id,
@@ -25,13 +67,7 @@ typedef struct GptPartitionType {
         sd_id128_t uuid;
         const char *name;
         Architecture arch;
-
-        bool is_root:1;
-        bool is_root_verity:1;
-        bool is_root_verity_sig:1;
-        bool is_usr:1;
-        bool is_usr_verity:1;
-        bool is_usr_verity_sig:1;
+        PartitionDesignator designator;
 } GptPartitionType;
 
 extern const GptPartitionType gpt_partition_type_table[];
@@ -45,6 +81,8 @@ bool gpt_partition_type_is_usr(sd_id128_t id);
 bool gpt_partition_type_is_usr_verity(sd_id128_t id);
 bool gpt_partition_type_is_usr_verity_sig(sd_id128_t id);
 
+const char *gpt_partition_type_mountpoint_nulstr(sd_id128_t id);
+
 bool gpt_partition_type_knows_read_only(sd_id128_t id);
 bool gpt_partition_type_knows_growfs(sd_id128_t id);
 bool gpt_partition_type_knows_no_auto(sd_id128_t id);
index 6a680fb3be1b7747a5a86ee577a8134f10439e68..0ff686d24b65a478f00bcb37d1d33e8e33e3536e 100644 (file)
@@ -652,7 +652,7 @@ int hwdb_update(const char *root, const char *hwdb_bin_dir, bool strict, bool co
 
 int hwdb_query(const char *modalias, const char *root) {
         _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
-        const char *key, *value, *p;
+        const char *key, *value;
         int r;
 
         assert(modalias);
@@ -682,7 +682,6 @@ int hwdb_query(const char *modalias, const char *root) {
 
 bool hwdb_should_reload(sd_hwdb *hwdb) {
         bool found = false;
-        const char* p;
         struct stat st;
 
         if (!hwdb)
index 97d39ee04777bc6dcf1760895ecfeba039e2b573..ec8906450611491777ff81ca6175c35152746bdd 100644 (file)
@@ -179,7 +179,6 @@ int raw_strip_suffixes(const char *p, char **ret) {
                 return -ENOMEM;
 
         for (;;) {
-                const char *sfx;
                 bool changed = false;
 
                 NULSTR_FOREACH(sfx, suffixes) {
index 9bb412ba06842031377d903d6bde981c92416f2f..0abc73897e8b7233b3bba43a2bdc3c15f963cb73 100644 (file)
@@ -197,7 +197,7 @@ int unit_file_exists(LookupScope scope, const LookupPaths *paths, const char *na
 int unit_file_get_list(LookupScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns);
 Hashmap* unit_file_list_free(Hashmap *h);
 
-InstallChangeType install_changes_add(InstallChange **changes, size_t *n_changes, int type, const char *path, const char *source);
+InstallChangeType install_changes_add(InstallChange **changes, size_t *n_changes, InstallChangeType type, const char *path, const char *source);
 void install_changes_free(InstallChange *changes, size_t n_changes);
 void install_changes_dump(int r, const char *verb, const InstallChange *changes, size_t n_changes, bool quiet);
 
@@ -224,7 +224,7 @@ UnitFileState unit_file_state_from_string(const char *s) _pure_;
 /* from_string conversion is unreliable because of the overlap between -EPERM and -1 for error. */
 
 const char *install_change_type_to_string(InstallChangeType t) _const_;
-int install_change_type_from_string(const char *s) _pure_;
+InstallChangeType install_change_type_from_string(const char *s) _pure_;
 
 const char *unit_file_preset_mode_to_string(UnitFilePresetMode m) _const_;
 UnitFilePresetMode unit_file_preset_mode_from_string(const char *s) _pure_;
index eda7bb19563e560b074fe138b54fb7b70bcb83fd..94d7b3155705cf29e22b5f7921b879a14697b1e8 100644 (file)
@@ -481,6 +481,10 @@ int json_variant_new_id128(JsonVariant **ret, sd_id128_t id) {
         return json_variant_new_string(ret, SD_ID128_TO_STRING(id));
 }
 
+int json_variant_new_uuid(JsonVariant **ret, sd_id128_t id) {
+        return json_variant_new_string(ret, SD_ID128_TO_UUID_STRING(id));
+}
+
 static void json_variant_set(JsonVariant *a, JsonVariant *b) {
         assert(a);
 
@@ -3609,7 +3613,8 @@ int json_buildv(JsonVariant **ret, va_list ap) {
                         break;
                 }
 
-                case _JSON_BUILD_ID128: {
+                case _JSON_BUILD_ID128:
+                case _JSON_BUILD_UUID: {
                         const sd_id128_t *id;
 
                         if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) {
@@ -3620,7 +3625,9 @@ int json_buildv(JsonVariant **ret, va_list ap) {
                         assert_se(id = va_arg(ap, sd_id128_t*));
 
                         if (current->n_suppress == 0) {
-                                r = json_variant_new_id128(&add, *id);
+                                r = command == _JSON_BUILD_ID128 ?
+                                        json_variant_new_id128(&add, *id) :
+                                        json_variant_new_uuid(&add, *id);
                                 if (r < 0)
                                         goto finish;
                         }
index 5993e05299c6e8c03961647c99d01ccce8f56154..c5f052a9d569bbcafc83c3afca3a61c619611ae7 100644 (file)
@@ -75,6 +75,7 @@ int json_variant_new_array_strv(JsonVariant **ret, char **l);
 int json_variant_new_object(JsonVariant **ret, JsonVariant **array, size_t n);
 int json_variant_new_null(JsonVariant **ret);
 int json_variant_new_id128(JsonVariant **ret, sd_id128_t id);
+int json_variant_new_uuid(JsonVariant **ret, sd_id128_t id);
 
 static inline int json_variant_new_string(JsonVariant **ret, const char *s) {
         return json_variant_new_stringn(ret, s, SIZE_MAX);
@@ -251,6 +252,7 @@ enum {
         _JSON_BUILD_HEX,
         _JSON_BUILD_OCTESCAPE,
         _JSON_BUILD_ID128,
+        _JSON_BUILD_UUID,
         _JSON_BUILD_BYTE_ARRAY,
         _JSON_BUILD_HW_ADDR,
         _JSON_BUILD_PAIR_UNSIGNED_NON_ZERO,
@@ -288,6 +290,7 @@ enum {
 #define JSON_BUILD_HEX(p, n) _JSON_BUILD_HEX, (const void*) { p }, (size_t) { n }
 #define JSON_BUILD_OCTESCAPE(p, n) _JSON_BUILD_OCTESCAPE, (const void*) { p }, (size_t) { n }
 #define JSON_BUILD_ID128(id) _JSON_BUILD_ID128, (const sd_id128_t*) { &(id) }
+#define JSON_BUILD_UUID(id) _JSON_BUILD_UUID, (const sd_id128_t*) { &(id) }
 #define JSON_BUILD_BYTE_ARRAY(v, n) _JSON_BUILD_BYTE_ARRAY, (const void*) { v }, (size_t) { n }
 #define JSON_BUILD_CONST_STRING(s) _JSON_BUILD_VARIANT, JSON_VARIANT_STRING_CONST(s)
 #define JSON_BUILD_IN4_ADDR(v) JSON_BUILD_BYTE_ARRAY((const struct in_addr*) { v }, sizeof(struct in_addr))
@@ -313,6 +316,7 @@ enum {
 #define JSON_BUILD_PAIR_BASE64(name, p, n) JSON_BUILD_PAIR(name, JSON_BUILD_BASE64(p, n))
 #define JSON_BUILD_PAIR_HEX(name, p, n) JSON_BUILD_PAIR(name, JSON_BUILD_HEX(p, n))
 #define JSON_BUILD_PAIR_ID128(name, id) JSON_BUILD_PAIR(name, JSON_BUILD_ID128(id))
+#define JSON_BUILD_PAIR_UUID(name, id) JSON_BUILD_PAIR(name, JSON_BUILD_UUID(id))
 #define JSON_BUILD_PAIR_BYTE_ARRAY(name, v, n) JSON_BUILD_PAIR(name, JSON_BUILD_BYTE_ARRAY(v, n))
 #define JSON_BUILD_PAIR_IN4_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_IN4_ADDR(v))
 #define JSON_BUILD_PAIR_IN6_ADDR(name, v) JSON_BUILD_PAIR(name, JSON_BUILD_IN6_ADDR(v))
index 842ff3066b4151a2fa89c2d3bae51e0ded9ff6c3..6222ef4fc81c4d50864833e4ec76e7dfc72e0227 100644 (file)
@@ -71,7 +71,6 @@ int get_keymaps(char ***ret) {
         if (!keymaps)
                 return -ENOMEM;
 
-        const char *dir;
         NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
                 r = recurse_dir_at(
                                 AT_FDCWD,
@@ -135,7 +134,6 @@ int keymap_exists(const char *name) {
         if (!keymap_is_valid(name))
                 return -EINVAL;
 
-        const char *dir;
         NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
                 r = recurse_dir_at(
                                 AT_FDCWD,
index 525849ee19e77f4e6057644d75c2c3de79e0eccd..a2bf14ec487299fc450491422fb3b2277f13b94b 100644 (file)
@@ -194,6 +194,157 @@ static int verify_features(
         return 0;
 }
 
+static int fido2_assert_set_basic_properties(
+                fido_assert_t *a,
+                const char *rp_id,
+                const void *cid,
+                size_t cid_size) {
+        int r;
+
+        assert(a);
+        assert(rp_id);
+        assert(cid);
+        assert(cid_size > 0);
+
+        r = sym_fido_assert_set_rp(a, rp_id);
+        if (r != FIDO_OK)
+                return log_error_errno(SYNTHETIC_ERRNO(EIO),
+                                       "Failed to set FIDO2 assertion ID: %s", sym_fido_strerr(r));
+
+        r = sym_fido_assert_set_clientdata_hash(a, (const unsigned char[32]) {}, 32);
+        if (r != FIDO_OK)
+                return log_error_errno(SYNTHETIC_ERRNO(EIO),
+                                       "Failed to set FIDO2 assertion client data hash: %s", sym_fido_strerr(r));
+
+        r = sym_fido_assert_allow_cred(a, cid, cid_size);
+        if (r != FIDO_OK)
+                return log_error_errno(SYNTHETIC_ERRNO(EIO),
+                                       "Failed to add FIDO2 assertion credential ID: %s", sym_fido_strerr(r));
+
+        return 0;
+}
+
+static int fido2_common_assert_error_handle(int r) {
+        switch (r) {
+        case FIDO_OK:
+                return 0;
+        case FIDO_ERR_NO_CREDENTIALS:
+                return log_error_errno(SYNTHETIC_ERRNO(EBADSLT),
+                                       "Wrong security token; needed credentials not present on token.");
+        case FIDO_ERR_PIN_REQUIRED:
+                return log_error_errno(SYNTHETIC_ERRNO(ENOANO),
+                                       "Security token requires PIN.");
+        case FIDO_ERR_PIN_AUTH_BLOCKED:
+                return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD),
+                                       "PIN of security token is blocked, please remove/reinsert token.");
+#ifdef FIDO_ERR_UV_BLOCKED
+        case FIDO_ERR_UV_BLOCKED:
+                return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD),
+                                       "Verification of security token is blocked, please remove/reinsert token.");
+#endif
+        case FIDO_ERR_PIN_INVALID:
+                return log_error_errno(SYNTHETIC_ERRNO(ENOLCK),
+                                       "PIN of security token incorrect.");
+        case FIDO_ERR_UP_REQUIRED:
+                return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE),
+                                       "User presence required.");
+        case FIDO_ERR_ACTION_TIMEOUT:
+                return log_error_errno(SYNTHETIC_ERRNO(ENOSTR),
+                                       "Token action timeout. (User didn't interact with token quickly enough.)");
+        default:
+                return log_error_errno(SYNTHETIC_ERRNO(EIO),
+                                       "Failed to ask token for assertion: %s", sym_fido_strerr(r));
+        }
+}
+
+static int fido2_is_cred_in_specific_token(
+                const char *path,
+                const char *rp_id,
+                const void *cid,
+                size_t cid_size,
+                char **pins,
+                Fido2EnrollFlags flags) {
+
+        assert(path);
+        assert(rp_id);
+        assert(cid);
+        assert(cid_size);
+
+        _cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL;
+        _cleanup_(fido_assert_free_wrapper) fido_assert_t *a = NULL;
+        bool has_up = false, has_uv = false;
+        int r;
+
+        d = sym_fido_dev_new();
+        if (!d)
+                return log_oom();
+
+        r = sym_fido_dev_open(d, path);
+        if (r != FIDO_OK)
+                return log_error_errno(SYNTHETIC_ERRNO(EIO),
+                                       "Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r));
+
+        r = verify_features(d, path, LOG_ERR, NULL, NULL, &has_up, &has_uv);
+        if (r < 0)
+                return r;
+
+        a = sym_fido_assert_new();
+        if (!a)
+                return log_oom();
+
+        r = fido2_assert_set_basic_properties(a, rp_id, cid, cid_size);
+        if (r < 0)
+                return r;
+
+        /* According to CTAP 2.1 specification, to do pre-flight we need to set up option to false
+         * with optionally pinUvAuthParam in assertion[1]. But for authenticator that doesn't support
+         * user presence, once up option is present, the authenticator may return CTAP2_ERR_UNSUPPORTED_OPTION[2].
+         * So we simplely omit the option in that case.
+         * Reference:
+         * 1: https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#pre-flight
+         * 2: https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#authenticatorGetAssertion (in step 5)
+         */
+        if (has_up)
+                r = sym_fido_assert_set_up(a, FIDO_OPT_FALSE);
+        else
+                r = sym_fido_assert_set_up(a, FIDO_OPT_OMIT);
+        if (r != FIDO_OK)
+                return log_error_errno(SYNTHETIC_ERRNO(EIO),
+                                       "Failed to set assertion user presence: %s", sym_fido_strerr(r));
+
+
+        /* According to CTAP 2.1 specification, if the credential is marked as userVerificationRequired,
+         * we may pass pinUvAuthParam parameter or set uv option to true in order to check whether the
+         * credential is in the token. Here we choose to use PIN (pinUvAuthParam) to achieve this.
+         * If we don't do that, the authenticator will remove the credential from the applicable
+         * credentials list, hence CTAP2_ERR_NO_CREDENTIALS error will be returned.
+         * Please see
+         * https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#sctn-getAssert-authnr-alg
+         * step 7.4 for detailed information.
+         */
+        if (FLAGS_SET(flags, FIDO2ENROLL_UV) && has_uv) {
+                if (strv_isempty(pins))
+                        r = FIDO_ERR_PIN_REQUIRED;
+                else
+                        STRV_FOREACH(i, pins) {
+                                r = sym_fido_dev_get_assert(d, a, *i);
+                                if (r != FIDO_ERR_PIN_INVALID)
+                                        break;
+                        }
+
+        } else
+                r = sym_fido_dev_get_assert(d, a, NULL);
+
+        switch (r) {
+                case FIDO_OK:
+                        return true;
+                case FIDO_ERR_NO_CREDENTIALS:
+                        return false;
+                default:
+                        return fido2_common_assert_error_handle(r);
+        }
+}
+
 static int fido2_use_hmac_hash_specific_token(
                 const char *path,
                 const char *rp_id,
@@ -263,20 +414,9 @@ static int fido2_use_hmac_hash_specific_token(
                 return log_error_errno(SYNTHETIC_ERRNO(EIO),
                                        "Failed to set salt on FIDO2 assertion: %s", sym_fido_strerr(r));
 
-        r = sym_fido_assert_set_rp(a, rp_id);
-        if (r != FIDO_OK)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO),
-                                       "Failed to set FIDO2 assertion ID: %s", sym_fido_strerr(r));
-
-        r = sym_fido_assert_set_clientdata_hash(a, (const unsigned char[32]) {}, 32);
-        if (r != FIDO_OK)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO),
-                                       "Failed to set FIDO2 assertion client data hash: %s", sym_fido_strerr(r));
-
-        r = sym_fido_assert_allow_cred(a, cid, cid_size);
-        if (r != FIDO_OK)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO),
-                                       "Failed to add FIDO2 assertion credential ID: %s", sym_fido_strerr(r));
+        r = fido2_assert_set_basic_properties(a, rp_id, cid, cid_size);
+        if (r < 0)
+                return r;
 
         log_info("Asking FIDO2 token for authentication.");
 
@@ -403,36 +543,9 @@ static int fido2_use_hmac_hash_specific_token(
                         required |= FIDO2ENROLL_PIN;
         }
 
-        switch (r) {
-        case FIDO_OK:
-                break;
-        case FIDO_ERR_NO_CREDENTIALS:
-                return log_error_errno(SYNTHETIC_ERRNO(EBADSLT),
-                                       "Wrong security token; needed credentials not present on token.");
-        case FIDO_ERR_PIN_REQUIRED:
-                return log_error_errno(SYNTHETIC_ERRNO(ENOANO),
-                                       "Security token requires PIN.");
-        case FIDO_ERR_PIN_AUTH_BLOCKED:
-                return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD),
-                                       "PIN of security token is blocked, please remove/reinsert token.");
-#ifdef FIDO_ERR_UV_BLOCKED
-        case FIDO_ERR_UV_BLOCKED:
-                return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD),
-                                       "Verification of security token is blocked, please remove/reinsert token.");
-#endif
-        case FIDO_ERR_PIN_INVALID:
-                return log_error_errno(SYNTHETIC_ERRNO(ENOLCK),
-                                       "PIN of security token incorrect.");
-        case FIDO_ERR_UP_REQUIRED:
-                return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE),
-                                       "User presence required.");
-        case FIDO_ERR_ACTION_TIMEOUT:
-                return log_error_errno(SYNTHETIC_ERRNO(ENOSTR),
-                                       "Token action timeout. (User didn't interact with token quickly enough.)");
-        default:
-                return log_error_errno(SYNTHETIC_ERRNO(EIO),
-                                       "Failed to ask token for assertion: %s", sym_fido_strerr(r));
-        }
+        r = fido2_common_assert_error_handle(r);
+        if (r < 0)
+                return r;
 
         hmac = sym_fido_assert_hmac_secret_ptr(a, 0);
         if (!hmac)
@@ -519,6 +632,30 @@ int fido2_use_hmac_hash(
                         goto finish;
                 }
 
+                r = fido2_is_cred_in_specific_token(path, rp_id, cid, cid_size, pins, required);
+                /* We handle PIN related errors here since we have used PIN in the check.
+                 * If PIN error happens, we can avoid pin retries decreased the second time. */
+                if (IN_SET(r, -ENOANO,        /* → pin required */
+                              -ENOLCK,        /* → pin incorrect */
+                              -EOWNERDEAD)) { /* → uv blocked */
+                        /* If it's not the last device, try next one */
+                        if (i < found - 1)
+                                continue;
+
+                        /* -EOWNERDEAD is returned when uv is blocked. Map it to EAGAIN so users can reinsert
+                         * the token and try again. */
+                        if (r == -EOWNERDEAD)
+                                r = -EAGAIN;
+                        goto finish;
+                } else if (r == -ENODEV) /* not a FIDO2 device or lacking HMAC-SECRET extension */
+                        continue;
+                else if (r < 0)
+                        log_error_errno(r, "Failed to determine whether the credential is in the token, trying anyway: %m");
+                else if (r == 0) {
+                        log_debug("The credential is not in the token %s, skipping.", path);
+                        continue;
+                }
+
                 r = fido2_use_hmac_hash_specific_token(path, rp_id, salt, salt_size, cid, cid_size, pins, required, ret_hmac, ret_hmac_size);
                 if (!IN_SET(r,
                             -EBADSLT, /* device doesn't understand our credential hash */
@@ -762,20 +899,9 @@ int fido2_generate_hmac_hash(
                 return log_error_errno(SYNTHETIC_ERRNO(EIO),
                                        "Failed to set salt on FIDO2 assertion: %s", sym_fido_strerr(r));
 
-        r = sym_fido_assert_set_rp(a, rp_id);
-        if (r != FIDO_OK)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO),
-                                       "Failed to set FIDO2 assertion ID: %s", sym_fido_strerr(r));
-
-        r = sym_fido_assert_set_clientdata_hash(a, (const unsigned char[32]) {}, 32);
-        if (r != FIDO_OK)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO),
-                                       "Failed to set FIDO2 assertion client data hash: %s", sym_fido_strerr(r));
-
-        r = sym_fido_assert_allow_cred(a, cid, cid_size);
-        if (r != FIDO_OK)
-                return log_error_errno(SYNTHETIC_ERRNO(EIO),
-                                       "Failed to add FIDO2 assertion credential ID: %s", sym_fido_strerr(r));
+        r = fido2_assert_set_basic_properties(a, rp_id, cid, cid_size);
+        if (r < 0)
+                return r;
 
         log_info("Generating secret key on FIDO2 security token.");
 
index 1526f59b0aa028fc1ea8b6e51d7e610a699dbc56..951701d497ef40320d634c238873bdc22f328563 100644 (file)
@@ -3,11 +3,47 @@
 #include <errno.h>
 
 #include "module-util.h"
+#include "proc-cmdline.h"
+#include "strv.h"
+
+static int denylist_modules(const char *p, char ***denylist) {
+        _cleanup_strv_free_ char **k = NULL;
+
+        assert(p);
+        assert(denylist);
+
+        k = strv_split(p, ",");
+        if (!k)
+                return -ENOMEM;
+
+        if (strv_extend_strv(denylist, k, true) < 0)
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
+        int r;
+
+        if (proc_cmdline_key_streq(key, "module_blacklist")) {
+
+                if (proc_cmdline_value_missing(key, value))
+                        return 0;
+
+                r = denylist_modules(value, data);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
 
 int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose) {
         const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST;
         struct kmod_list *itr;
         _cleanup_(kmod_module_unref_listp) struct kmod_list *modlist = NULL;
+        _cleanup_strv_free_ char **denylist = NULL;
+        bool denylist_parsed = false;
         int r;
 
         /* verbose==true means we should log at non-debug level if we
@@ -50,10 +86,27 @@ int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose)
                                          "Inserted module '%s'", kmod_module_get_name(mod));
                         else if (err == KMOD_PROBE_APPLY_BLACKLIST)
                                 log_full(verbose ? LOG_INFO : LOG_DEBUG,
-                                         "Module '%s' is deny-listed", kmod_module_get_name(mod));
+                                         "Module '%s' is deny-listed (by kmod)", kmod_module_get_name(mod));
                         else {
                                 assert(err < 0);
 
+                                if (err == -EPERM) {
+                                        if (!denylist_parsed) {
+                                                r = proc_cmdline_parse(parse_proc_cmdline_item, &denylist, 0);
+                                                if (r < 0)
+                                                        log_full_errno(!verbose ? LOG_DEBUG : LOG_WARNING,
+                                                                       r,
+                                                                       "Failed to parse kernel command line, ignoring: %m");
+
+                                                denylist_parsed = true;
+                                        }
+                                        if (strv_contains(denylist, kmod_module_get_name(mod))) {
+                                                log_full(verbose ? LOG_INFO : LOG_DEBUG,
+                                                         "Module '%s' is deny-listed (by kernel)", kmod_module_get_name(mod));
+                                                continue;
+                                        }
+                                }
+
                                 log_full_errno(!verbose ? LOG_DEBUG :
                                                err == -ENODEV ? LOG_NOTICE :
                                                err == -ENOENT ? LOG_WARNING :
index d9ab387301d1ca5f704e52ec6d8d840e60f8b370..e58173d864dad8976d2b4d4e66b6f6fded29b381 100644 (file)
@@ -25,10 +25,11 @@ typedef enum ResolveSupport ResolveSupport;
 typedef enum DnssecMode DnssecMode;
 typedef enum DnsOverTlsMode DnsOverTlsMode;
 
+/* Do not change the order, see link_get_llmnr_support() or link_get_mdns_support(). */
 enum ResolveSupport {
         RESOLVE_SUPPORT_NO,
-        RESOLVE_SUPPORT_YES,
         RESOLVE_SUPPORT_RESOLVE,
+        RESOLVE_SUPPORT_YES,
         _RESOLVE_SUPPORT_MAX,
         _RESOLVE_SUPPORT_INVALID = -EINVAL,
 };
index 86d3e57b0e543cbaf5a078a120f69c25272f8be5..24fd9a2aa2d2650984ac81cde2f4be13604ba658 100644 (file)
@@ -5,7 +5,6 @@
 
 #include "alloc-util.h"
 #include "errno-util.h"
-#include "fd-util.h"
 
 typedef enum RemoveFlags {
         REMOVE_ONLY_DIRECTORIES = 1 << 0, /* Only remove empty directories, no files */
@@ -52,19 +51,3 @@ static inline char *rm_rf_subvolume_and_free(char *p) {
         return mfree(p);
 }
 DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_subvolume_and_free);
-
-static inline int rm_rf_physical_and_close(int fd) {
-        _cleanup_free_ char *p = NULL;
-
-        if (fd < 0)
-                return -1;
-
-        if (fd_get_path(fd, &p) < 0)
-                return safe_close(fd);
-
-        safe_close(fd);
-        (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_MISSING_OK|REMOVE_CHMOD);
-
-        return -1;
-}
-DEFINE_TRIVIAL_CLEANUP_FUNC(int, rm_rf_physical_and_close);
index dfac4da7cc364c057be18c882dc7c9ebaac5198d..8ece7f163f1be53370957aff2e2cfc61bce90814 100644 (file)
@@ -1039,7 +1039,6 @@ static int add_syscall_filter_set(
                 bool log_missing,
                 char ***added) {
 
-        const char *sys;
         int r;
 
         /* Any syscalls that are handled are added to the *added strv. It needs to be initialized. */
@@ -1169,7 +1168,6 @@ int seccomp_parse_syscall_filter(
 
         if (name[0] == '@') {
                 const SyscallFilterSet *set;
-                const char *i;
 
                 set = syscall_filter_set_find(name);
                 if (!set) {
@@ -1909,7 +1907,6 @@ int parse_syscall_archs(char **l, Set **ret_archs) {
 }
 
 int seccomp_filter_set_add(Hashmap *filter, bool add, const SyscallFilterSet *set) {
-        const char *i;
         int r;
 
         assert(set);
@@ -2308,7 +2305,6 @@ int seccomp_suppress_sync(void) {
 
         SECCOMP_FOREACH_LOCAL_ARCH(arch) {
                 _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
-                const char *c;
 
                 r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
                 if (r < 0)
index aac02cd61bcaed4eebb0f92b46058e69e33867e9..7d953534520b9b7e04e9b96aa927d948f1252355 100644 (file)
@@ -642,9 +642,46 @@ static int device_is_power_sink(sd_device *device) {
         return found_sink || !found_source;
 }
 
+static bool battery_is_discharging(sd_device *d) {
+        const char *val;
+        int r;
+
+        assert(d);
+
+        r = sd_device_get_sysattr_value(d, "scope", &val);
+        if (r < 0) {
+                if (r != -ENOENT)
+                        log_device_debug_errno(d, r, "Failed to read 'scope' sysfs attribute, ignoring: %m");
+        } else if (streq(val, "Device")) {
+                log_device_debug(d, "The power supply is a device battery, ignoring device.");
+                return false;
+        }
+
+        r = device_get_sysattr_bool(d, "present");
+        if (r < 0)
+                log_device_debug_errno(d, r, "Failed to read 'present' sysfs attribute, assuming the battery is present: %m");
+        else if (r == 0) {
+                log_device_debug(d, "The battery is not present, ignoring the power supply.");
+                return false;
+        }
+
+        /* Possible values: "Unknown", "Charging", "Discharging", "Not charging", "Full" */
+        r = sd_device_get_sysattr_value(d, "status", &val);
+        if (r < 0) {
+                log_device_debug_errno(d, r, "Failed to read 'status' sysfs attribute, assuming the battery is discharging: %m");
+                return true;
+        }
+        if (!streq(val, "Discharging")) {
+                log_device_debug(d, "The battery status is '%s', assuming the battery is not used as a power source of this machine.", val);
+                return false;
+        }
+
+        return true;
+}
+
 int on_ac_power(void) {
         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
-        bool found_ac_online = false, found_battery = false;
+        bool found_ac_online = false, found_discharging_battery = false;
         sd_device *d;
         int r;
 
@@ -686,17 +723,10 @@ int on_ac_power(void) {
                 }
 
                 if (streq(val, "Battery")) {
-                        r = sd_device_get_sysattr_value(d, "scope", &val);
-                        if (r < 0) {
-                                if (r != -ENOENT)
-                                        log_device_debug_errno(d, r, "Failed to read 'scope' sysfs attribute, ignoring: %m");
-                        } else if (streq(val, "Device")) {
-                                log_device_debug(d, "The power supply is a device battery, ignoring device.");
-                                continue;
+                        if (battery_is_discharging(d)) {
+                                found_discharging_battery = true;
+                                log_device_debug(d, "The power supply is a battery and currently discharging.");
                         }
-
-                        found_battery = true;
-                        log_device_debug(d, "The power supply is battery.");
                         continue;
                 }
 
@@ -713,11 +743,11 @@ int on_ac_power(void) {
         if (found_ac_online) {
                 log_debug("Found at least one online non-battery power supply, system is running on AC.");
                 return true;
-        } else if (found_battery) {
-                log_debug("Found battery and no online power sources, assuming system is running from battery.");
+        } else if (found_discharging_battery) {
+                log_debug("Found at least one discharging battery and no online power sources, assuming system is running from battery.");
                 return false;
         } else {
-                log_debug("No power supply reported online and no battery, assuming system is running on AC.");
+                log_debug("No power supply reported online and no discharging battery found, assuming system is running on AC.");
                 return true;
         }
 }
index 588c8b56c5cebc518e0e45a229e94452d92a694d..92f6ecaa8d044145b87ae87f91ec71c66e48f7d8 100644 (file)
@@ -6,6 +6,7 @@
 #include "env-util.h"
 #include "fd-util.h"
 #include "fuzz.h"
+#include "nulstr-util.h"
 #include "selinux-util.h"
 #include "static-destruct.h"
 #include "stdio-util.h"
index 8d3db98c0a5966e4659f0f77b86597b0d22d4acb..24c7d564b8bba62a2c680cdde5ce084f7c682e82 100644 (file)
@@ -2207,9 +2207,10 @@ int verb_show(int argc, char *argv[], void *userdata) {
 
                 if (!arg_states && !arg_types) {
                         if (show_mode == SYSTEMCTL_SHOW_PROPERTIES)
-                                r = show_one(bus, "/org/freedesktop/systemd1", NULL, show_mode, &new_line, &ellipsized);
-                        else
-                                r = show_system_status(bus);
+                                /* systemctl show --all → show properties of the manager */
+                                return show_one(bus, "/org/freedesktop/systemd1", NULL, show_mode, &new_line, &ellipsized);
+
+                        r = show_system_status(bus);
                         if (r < 0)
                                 return r;
 
index 9d193651edb88c9dd6cfc4a29e9eb2dc55c100f8..4f72e00f57da25a3e64810cf0e3ed4d0acdce04a 100644 (file)
@@ -557,6 +557,8 @@ tests += [
 
         [files('test-strv.c')],
 
+        [files('test-nulstr-util.c')],
+
         [files('test-path-util.c')],
 
         [files('test-rm-rf.c')],
index 3f8225cbcc1a48832e081d91adc15eee4dd6ea08..da0f5e137a75ea669301101d080ae27fc9985ad1 100644 (file)
@@ -158,7 +158,6 @@ int main(int argc, char *argv[]) {
         else
                 arg_start = getpid_cached();
 
-        const char *i;
         NULSTR_FOREACH(i, "zeros\0simple\0random\0") {
 #if HAVE_XZ
                 test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz);
index 4cd23d8e2135bba4ec65f986a66894bd5aa9f9ab..5144eb4687298a55433ef60ae202120e84edd955 100644 (file)
@@ -800,7 +800,6 @@ TEST(print_securities) {
 
 TEST(condition_test_virtualization) {
         Condition *condition;
-        const char *virt;
         int r;
 
         condition = condition_new(CONDITION_VIRTUALIZATION, "garbage oifdsjfoidsjoj", false, false);
index 00a38b18f6a690d53fe012e1f09541f90f3bb428..8177f6e33b87e50dca66e806b4db73b69ac80d5b 100644 (file)
@@ -67,21 +67,22 @@ TEST(copy_tree_replace_file) {
 
         /* The file exists- now overwrite original contents, and test the COPY_REPLACE flag. */
 
-        assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK) == -EEXIST);
+        assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK, NULL) == -EEXIST);
 
         assert_se(read_file_at_and_streq(AT_FDCWD, dst, "foo foo foo\n"));
 
-        assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE) == 0);
+        assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE, NULL) == 0);
 
         assert_se(read_file_at_and_streq(AT_FDCWD, dst, "bar bar\n"));
 }
 
 TEST(copy_tree_replace_dirs) {
-        _cleanup_(rm_rf_physical_and_closep) int src = -1, dst = -1;
+        _cleanup_(rm_rf_physical_and_freep) char *srcp = NULL, *dstp = NULL;
+        _cleanup_close_ int src = -1, dst = -1;
 
         /* Create the random source/destination directories */
-        assert_se((src = mkdtemp_open(NULL, 0, NULL)) >= 0);
-        assert_se((dst = mkdtemp_open(NULL, 0, NULL)) >= 0);
+        assert_se((src = mkdtemp_open(NULL, 0, &srcp)) >= 0);
+        assert_se((dst = mkdtemp_open(NULL, 0, &dstp)) >= 0);
 
         /* Populate some data to differentiate the files. */
         assert_se(write_string_file_at(src, "foo", "src file 1", WRITE_STRING_FILE_CREATE) >= 0);
@@ -91,14 +92,14 @@ TEST(copy_tree_replace_dirs) {
         assert_se(write_string_file_at(dst, "bar", "dest file 2", WRITE_STRING_FILE_CREATE) == 0);
 
         /* Copying without COPY_REPLACE should fail because the destination file already exists. */
-        assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK) == -EEXIST);
+        assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK, NULL) == -EEXIST);
 
         assert_se(read_file_at_and_streq(src, "foo", "src file 1\n"));
         assert_se(read_file_at_and_streq(src, "bar", "src file 2\n"));
         assert_se(read_file_at_and_streq(dst, "foo", "dest file 1\n"));
         assert_se(read_file_at_and_streq(dst, "bar", "dest file 2\n"));
 
-        assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE) == 0);
+        assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE, NULL) == 0);
 
         assert_se(read_file_at_and_streq(src, "foo", "src file 1\n"));
         assert_se(read_file_at_and_streq(src, "bar", "src file 2\n"));
@@ -131,6 +132,8 @@ TEST(copy_file_fd) {
 }
 
 TEST(copy_tree) {
+        _cleanup_set_free_ Set *denylist = NULL;
+        _cleanup_free_ char *cp = NULL;
         char original_dir[] = "/tmp/test-copy_tree/";
         char copy_dir[] = "/tmp/test-copy_tree-copy/";
         char **files = STRV_MAKE("file", "dir1/file", "dir1/dir2/file", "dir1/dir2/dir3/dir4/dir5/file");
@@ -138,7 +141,7 @@ TEST(copy_tree) {
                                     "link2", "dir1/file");
         char **hardlinks = STRV_MAKE("hlink", "file",
                                      "hlink2", "dir1/file");
-        const char *unixsockp;
+        const char *unixsockp, *ignorep;
         struct stat st;
         int xattr_worked = -1; /* xattr support is optional in temporary directories, hence use it if we can,
                                 * but don't fail if we can't */
@@ -184,7 +187,14 @@ TEST(copy_tree) {
         unixsockp = strjoina(original_dir, "unixsock");
         assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0);
 
-        assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS) == 0);
+        ignorep = strjoina(original_dir, "ignore/file");
+        assert_se(write_string_file(ignorep, "ignore", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755) == 0);
+        assert_se(RET_NERRNO(stat(ignorep, &st)) >= 0);
+        assert_se(cp = memdup(&st, sizeof(st)));
+        assert_se(set_ensure_put(&denylist, &inode_hash_ops, cp) >= 0);
+        TAKE_PTR(cp);
+
+        assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS, denylist) == 0);
 
         STRV_FOREACH(p, files) {
                 _cleanup_free_ char *buf, *f, *c = NULL;
@@ -236,8 +246,11 @@ TEST(copy_tree) {
         assert_se(stat(unixsockp, &st) >= 0);
         assert_se(S_ISSOCK(st.st_mode));
 
-        assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK) < 0);
-        assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK) < 0);
+        assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK, denylist) < 0);
+        assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK, denylist) < 0);
+
+        ignorep = strjoina(copy_dir, "ignore/file");
+        assert_se(RET_NERRNO(access(ignorep, F_OK)) == -ENOENT);
 
         (void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
         (void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
index 60d5fee71fc2b452c2917ca79809ca3ff8d344ea..14341b97b4ea3960f43692efa2132863303025d8 100644 (file)
@@ -534,6 +534,37 @@ TEST(table) {
                                 "5min              5min              \n"));
 }
 
+TEST(vertical) {
+        _cleanup_(table_unrefp) Table *t = NULL;
+        _cleanup_free_ char *formatted = NULL;
+
+        assert_se(t = table_new_vertical());
+
+        assert_se(table_add_many(t,
+                                 TABLE_FIELD, "pfft aa", TABLE_STRING, "foo",
+                                 TABLE_FIELD, "uuu o", TABLE_SIZE, UINT64_C(1024),
+                                 TABLE_FIELD, "lllllllllllo", TABLE_STRING, "jjjjjjjjjjjjjjjjj") >= 0);
+
+        assert_se(table_set_json_field_name(t, 1, "dimpfelmoser") >= 0);
+
+        assert_se(table_format(t, &formatted) >= 0);
+
+        assert_se(streq(formatted,
+                        "     pfft aa: foo\n"
+                        "       uuu o: 1.0K\n"
+                        "lllllllllllo: jjjjjjjjjjjjjjjjj\n"));
+
+        _cleanup_(json_variant_unrefp) JsonVariant *a = NULL, *b = NULL;
+        assert_se(table_to_json(t, &a) >= 0);
+
+        assert_se(json_build(&b, JSON_BUILD_OBJECT(
+                                             JSON_BUILD_PAIR("pfft_aa", JSON_BUILD_STRING("foo")),
+                                             JSON_BUILD_PAIR("dimpfelmoser", JSON_BUILD_UNSIGNED(1024)),
+                                             JSON_BUILD_PAIR("lllllllllllo", JSON_BUILD_STRING("jjjjjjjjjjjjjjjjj")))) >= 0);
+
+        assert_se(json_variant_equal(a, b));
+}
+
 static int intro(void) {
         assert_se(setenv("SYSTEMD_COLORS", "0", 1) >= 0);
         assert_se(setenv("COLUMNS", "40", 1) >= 0);
index d0259843b6723a43d57e4380be5299855b83c028..4bf0a5daf8765c85d4fcf8b9389addf166cf8a8a 100644 (file)
@@ -386,6 +386,15 @@ TEST(chase_symlinks) {
         assert_se(path_equal(path_startswith(result, p), "usr"));
         result = mfree(result);
 
+        /* Test CHASE_PROHIBIT_SYMLINKS */
+
+        assert_se(chase_symlinks("top/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG);
+        assert_se(chase_symlinks("top/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG);
+        assert_se(chase_symlinks("top/dotdot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG);
+        assert_se(chase_symlinks("top/dotdot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG);
+        assert_se(chase_symlinks("top/dot/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG);
+        assert_se(chase_symlinks("top/dot/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG);
+
  cleanup:
         assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
 }
index 36a775012b3c742971e2d56628ba997f3937bbda..fea20d82a6783245155b94252aadfd57361438ca 100644 (file)
@@ -452,8 +452,8 @@ TEST(hashmap_foreach_key) {
 
         m = hashmap_new(&string_hash_ops);
 
-        NULSTR_FOREACH(key, key_table)
-                hashmap_put(m, key, (void*) (const char*) "my dummy val");
+        NULSTR_FOREACH(k, key_table)
+                hashmap_put(m, k, (void*) (const char*) "my dummy val");
 
         HASHMAP_FOREACH_KEY(s, key, m) {
                 assert_se(s);
diff --git a/src/test/test-nulstr-util.c b/src/test/test-nulstr-util.c
new file mode 100644 (file)
index 0000000..a068e5f
--- /dev/null
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "nulstr-util.h"
+#include "strv.h"
+#include "tests.h"
+
+TEST(strv_split_nulstr) {
+        _cleanup_strv_free_ char **l = NULL;
+        const char nulstr[] = "str0\0str1\0str2\0str3\0";
+
+        l = strv_split_nulstr(nulstr);
+        assert_se(l);
+
+        assert_se(streq(l[0], "str0"));
+        assert_se(streq(l[1], "str1"));
+        assert_se(streq(l[2], "str2"));
+        assert_se(streq(l[3], "str3"));
+}
+
+TEST(strv_parse_nulstr) {
+        _cleanup_strv_free_ char **l = NULL;
+        const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx";
+
+        l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
+        assert_se(l);
+        puts("Parse nulstr:");
+        strv_print(l);
+
+        assert_se(streq(l[0], "hoge"));
+        assert_se(streq(l[1], "hoge2"));
+        assert_se(streq(l[2], "hoge3"));
+        assert_se(streq(l[3], ""));
+        assert_se(streq(l[4], "hoge5"));
+        assert_se(streq(l[5], ""));
+        assert_se(streq(l[6], "xxx"));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[0]) {}, 0);
+        assert_se(l);
+        assert_se(strv_isempty(l));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[1]) { 0 }, 1);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[1]) { 'x' }, 1);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("x")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[2]) { 0, 0 }, 2);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("", "")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[2]) { 'x', 0 }, 2);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("x")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[3]) { 0, 0, 0 }, 3);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("", "", "")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[3]) { 'x', 0, 0 }, 3);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("x", "")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[3]) { 0, 'x', 0 }, 3);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("", "x")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[3]) { 0, 0, 'x' }, 3);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("", "", "x")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[3]) { 'x', 'x', 0 }, 3);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("xx")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[3]) { 0, 'x', 'x' }, 3);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("", "xx")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[3]) { 'x', 0, 'x' }, 3);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("x", "x")));
+        strv_free(l);
+
+        l = strv_parse_nulstr((const char[3]) { 'x', 'x', 'x' }, 3);
+        assert_se(l);
+        assert_se(strv_equal(l, STRV_MAKE("xxx")));
+}
+
+static void test_strv_make_nulstr_one(char **l) {
+        _cleanup_free_ char *b = NULL, *c = NULL;
+        _cleanup_strv_free_ char **q = NULL;
+        size_t n, m;
+        unsigned i = 0;
+
+        log_info("/* %s */", __func__);
+
+        assert_se(strv_make_nulstr(l, &b, &n) >= 0);
+        assert_se(q = strv_parse_nulstr(b, n));
+        assert_se(strv_equal(l, q));
+
+        assert_se(strv_make_nulstr(q, &c, &m) >= 0);
+        assert_se(memcmp_nn(b, n, c, m) == 0);
+
+        NULSTR_FOREACH(s, b)
+                assert_se(streq(s, l[i++]));
+        assert_se(i == strv_length(l));
+}
+
+TEST(strv_make_nulstr) {
+        test_strv_make_nulstr_one(NULL);
+        test_strv_make_nulstr_one(STRV_MAKE(NULL));
+        test_strv_make_nulstr_one(STRV_MAKE("foo"));
+        test_strv_make_nulstr_one(STRV_MAKE("foo", "bar"));
+        test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux"));
+}
+
+static void test_strv_make_nulstr_binary_one(char **l, const char *b, size_t n) {
+        _cleanup_strv_free_ char **z = NULL;
+        _cleanup_free_ char *a = NULL;
+        size_t m;
+
+        assert_se(strv_make_nulstr(l, &a, &m) >= 0);
+        assert_se(memcmp_nn(a, m, b, n) == 0);
+        assert_se(z = strv_parse_nulstr(a, m));
+        assert_se(strv_equal(l, z));
+}
+
+TEST(strv_make_nulstr_binary) {
+        test_strv_make_nulstr_binary_one(NULL, (const char[0]) {}, 0);
+        test_strv_make_nulstr_binary_one(STRV_MAKE(NULL), (const char[0]) {}, 0);
+        test_strv_make_nulstr_binary_one(STRV_MAKE(""), (const char[1]) { 0 }, 1);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("", ""), (const char[2]) { 0, 0 }, 2);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("x", ""), (const char[3]) { 'x', 0, 0 }, 3);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("", "x"), (const char[3]) { 0, 'x', 0 }, 3);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("", "", ""), (const char[3]) { 0, 0, 0 }, 3);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("x", "", ""), (const char[4]) { 'x', 0, 0, 0 }, 4);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("", "x", ""), (const char[4]) { 0, 'x', 0, 0 }, 4);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("", "", "x"), (const char[4]) { 0, 0, 'x', 0 }, 4);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("x", "x", ""), (const char[5]) { 'x', 0, 'x', 0, 0 }, 5);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("", "x", "x"), (const char[5]) { 0, 'x', 0, 'x', 0 }, 5);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("x", "", "x"), (const char[5]) { 'x', 0, 0, 'x', 0 }, 5);
+        test_strv_make_nulstr_binary_one(STRV_MAKE("x", "x", "x"), (const char[6]) { 'x', 0, 'x', 0, 'x', 0 }, 6);
+}
+
+DEFINE_TEST_MAIN(LOG_INFO);
index f18634cc34e32fc2251f2f2cd7db7f4d406056ba..ecb6118bcaf678f5531972b628bb734fb559731f 100644 (file)
@@ -56,7 +56,6 @@ TEST(basic_enumerate) {
 
 TEST(sd_hwdb_new_from_path) {
         _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
-        const char *hwdb_bin_path = NULL;
         int r;
 
         assert_se(sd_hwdb_new_from_path(NULL, &hwdb) == -EINVAL);
index 4c704badbd71ca0320b392f3e0b409a5459ab261..ae311c56868295d88aa44799008e7bae63ff5963 100644 (file)
@@ -117,7 +117,7 @@ TEST(seccomp_arch_to_string) {
 }
 
 TEST(architecture_table) {
-        const char *n, *n2;
+        const char *n2;
 
         NULSTR_FOREACH(n,
                        "native\0"
@@ -234,7 +234,7 @@ TEST(filter_sets_ordered) {
         assert_se(streq(syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].name, "@known"));
 
         for (size_t i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
-                const char *k, *p = NULL;
+                const char *p = NULL;
 
                 /* Make sure each group has a description */
                 assert_se(!isempty(syscall_filter_sets[0].help));
index 5c12a0597ad29321793e734761356371b315a813..f69e80ca5a84911b65342722c408b589c24fb0e3 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <stdlib.h>
 
+#include "nulstr-util.h"
 #include "strbuf.h"
 #include "string-util.h"
 #include "strv.h"
index b892396f05bf8c92a75802d0a964fa4952570b31..9208faafa47d22c482090a71d0be038a97e01955 100644 (file)
@@ -2,7 +2,6 @@
 
 #include "alloc-util.h"
 #include "escape.h"
-#include "nulstr-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tests.h"
@@ -487,37 +486,6 @@ TEST(strv_split_newlines_full) {
         assert_se(strv_equal(l, (char**) input_table_retain_escape));
 }
 
-TEST(strv_split_nulstr) {
-        _cleanup_strv_free_ char **l = NULL;
-        const char nulstr[] = "str0\0str1\0str2\0str3\0";
-
-        l = strv_split_nulstr (nulstr);
-        assert_se(l);
-
-        assert_se(streq(l[0], "str0"));
-        assert_se(streq(l[1], "str1"));
-        assert_se(streq(l[2], "str2"));
-        assert_se(streq(l[3], "str3"));
-}
-
-TEST(strv_parse_nulstr) {
-        _cleanup_strv_free_ char **l = NULL;
-        const char nulstr[] = "hoge\0hoge2\0hoge3\0\0hoge5\0\0xxx";
-
-        l = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
-        assert_se(l);
-        puts("Parse nulstr:");
-        strv_print(l);
-
-        assert_se(streq(l[0], "hoge"));
-        assert_se(streq(l[1], "hoge2"));
-        assert_se(streq(l[2], "hoge3"));
-        assert_se(streq(l[3], ""));
-        assert_se(streq(l[4], "hoge5"));
-        assert_se(streq(l[5], ""));
-        assert_se(streq(l[6], "xxx"));
-}
-
 TEST(strv_overlap) {
         const char * const input_table[] = {
                 "one",
@@ -945,36 +913,6 @@ TEST(strv_extend_n) {
         assert_se(v[1] == NULL);
 }
 
-static void test_strv_make_nulstr_one(char **l) {
-        _cleanup_free_ char *b = NULL, *c = NULL;
-        _cleanup_strv_free_ char **q = NULL;
-        const char *s = NULL;
-        size_t n, m;
-        unsigned i = 0;
-
-        log_info("/* %s */", __func__);
-
-        assert_se(strv_make_nulstr(l, &b, &n) >= 0);
-        assert_se(q = strv_parse_nulstr(b, n));
-        assert_se(strv_equal(l, q));
-
-        assert_se(strv_make_nulstr(q, &c, &m) >= 0);
-        assert_se(m == n);
-        assert_se(memcmp(b, c, m) == 0);
-
-        NULSTR_FOREACH(s, b)
-                assert_se(streq(s, l[i++]));
-        assert_se(i == strv_length(l));
-}
-
-TEST(strv_make_nulstr) {
-        test_strv_make_nulstr_one(NULL);
-        test_strv_make_nulstr_one(STRV_MAKE(NULL));
-        test_strv_make_nulstr_one(STRV_MAKE("foo"));
-        test_strv_make_nulstr_one(STRV_MAKE("foo", "bar"));
-        test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux"));
-}
-
 TEST(foreach_string) {
         const char * const t[] = {
                 "foo",
index e3c722610a2ca9081ed9f831bf2b9c5463d2daa4..5d1be1150940a1cc4dee7589e781cab13154bf47 100644 (file)
@@ -61,15 +61,12 @@ static int print_status_info(const StatusInfo *i) {
 
         assert(i);
 
-        table = table_new("key", "value");
+        table = table_new_vertical();
         if (!table)
                 return log_oom();
 
-        table_set_header(table, false);
-
         assert_se(cell = table_get_cell(table, 0, 0));
         (void) table_set_ellipsize_percent(table, cell, 100);
-        (void) table_set_align_percent(table, cell, 100);
 
         assert_se(cell = table_get_cell(table, 0, 1));
         (void) table_set_ellipsize_percent(table, cell, 100);
@@ -97,14 +94,14 @@ static int print_status_info(const StatusInfo *i) {
 
         n = have_time ? strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) : 0;
         r = table_add_many(table,
-                           TABLE_STRING, "Local time:",
+                           TABLE_FIELD, "Local time",
                            TABLE_STRING, n > 0 ? a : "n/a");
         if (r < 0)
                 return table_log_add_error(r);
 
         n = have_time ? strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)) : 0;
         r = table_add_many(table,
-                           TABLE_STRING, "Universal time:",
+                           TABLE_FIELD, "Universal time",
                            TABLE_STRING, n > 0 ? a : "n/a");
         if (r < 0)
                 return table_log_add_error(r);
@@ -117,12 +114,12 @@ static int print_status_info(const StatusInfo *i) {
         } else
                 n = 0;
         r = table_add_many(table,
-                           TABLE_STRING, "RTC time:",
+                           TABLE_FIELD, "RTC time",
                            TABLE_STRING, n > 0 ? a : "n/a");
         if (r < 0)
                 return table_log_add_error(r);
 
-        r = table_add_cell(table, NULL, TABLE_STRING, "Time zone:");
+        r = table_add_cell(table, NULL, TABLE_FIELD, "Time zone");
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -139,11 +136,11 @@ static int print_status_info(const StatusInfo *i) {
                 tzset();
 
         r = table_add_many(table,
-                           TABLE_STRING, "System clock synchronized:",
+                           TABLE_FIELD, "System clock synchronized",
                            TABLE_BOOLEAN, i->ntp_synced,
-                           TABLE_STRING, "NTP service:",
+                           TABLE_FIELD, "NTP service",
                            TABLE_STRING, i->ntp_capable ? (i->ntp_active ? "active" : "inactive") : "n/a",
-                           TABLE_STRING, "RTC in local TZ:",
+                           TABLE_FIELD, "RTC in local TZ",
                            TABLE_BOOLEAN, i->rtc_local);
         if (r < 0)
                 return table_log_add_error(r);
@@ -363,15 +360,12 @@ static int print_ntp_status_info(NTPStatusInfo *i) {
 
         assert(i);
 
-        table = table_new("key", "value");
+        table = table_new_vertical();
         if (!table)
                 return log_oom();
 
-        table_set_header(table, false);
-
         assert_se(cell = table_get_cell(table, 0, 0));
         (void) table_set_ellipsize_percent(table, cell, 100);
-        (void) table_set_align_percent(table, cell, 100);
 
         assert_se(cell = table_get_cell(table, 0, 1));
         (void) table_set_ellipsize_percent(table, cell, 100);
@@ -388,7 +382,7 @@ static int print_ntp_status_info(NTPStatusInfo *i) {
          *  d = (T4 - T1) - (T3 - T2)     t = ((T2 - T1) + (T3 - T4)) / 2"
          */
 
-        r = table_add_cell(table, NULL, TABLE_STRING, "Server:");
+        r = table_add_cell(table, NULL, TABLE_FIELD, "Server");
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -396,7 +390,7 @@ static int print_ntp_status_info(NTPStatusInfo *i) {
         if (r < 0)
                 return table_log_add_error(r);
 
-        r = table_add_cell(table, NULL, TABLE_STRING, "Poll interval:");
+        r = table_add_cell(table, NULL, TABLE_FIELD, "Poll interval");
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -409,7 +403,7 @@ static int print_ntp_status_info(NTPStatusInfo *i) {
 
         if (i->packet_count == 0) {
                 r = table_add_many(table,
-                                   TABLE_STRING, "Packet count:",
+                                   TABLE_FIELD, "Packet count",
                                    TABLE_STRING, "0");
                 if (r < 0)
                         return table_log_add_error(r);
@@ -440,13 +434,13 @@ static int print_ntp_status_info(NTPStatusInfo *i) {
         root_distance = i->root_delay / 2 + i->root_dispersion;
 
         r = table_add_many(table,
-                           TABLE_STRING, "Leap:",
+                           TABLE_FIELD, "Leap",
                            TABLE_STRING, ntp_leap_to_string(i->leap),
-                           TABLE_STRING, "Version:",
+                           TABLE_FIELD, "Version",
                            TABLE_UINT32, i->version,
-                           TABLE_STRING, "Stratum:",
+                           TABLE_FIELD, "Stratum",
                            TABLE_UINT32, i->stratum,
-                           TABLE_STRING, "Reference:");
+                           TABLE_FIELD, "Reference");
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -457,7 +451,7 @@ static int print_ntp_status_info(NTPStatusInfo *i) {
         if (r < 0)
                 return table_log_add_error(r);
 
-        r = table_add_cell(table, NULL, TABLE_STRING, "Precision:");
+        r = table_add_cell(table, NULL, TABLE_FIELD, "Precision");
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -467,7 +461,7 @@ static int print_ntp_status_info(NTPStatusInfo *i) {
         if (r < 0)
                 return table_log_add_error(r);
 
-        r = table_add_cell(table, NULL, TABLE_STRING, "Root distance:");
+        r = table_add_cell(table, NULL, TABLE_FIELD, "Root distance");
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -477,7 +471,7 @@ static int print_ntp_status_info(NTPStatusInfo *i) {
         if (r < 0)
                 return table_log_add_error(r);
 
-        r = table_add_cell(table, NULL, TABLE_STRING, "Offset:");
+        r = table_add_cell(table, NULL, TABLE_FIELD, "Offset");
         if (r < 0)
                 return table_log_add_error(r);
 
@@ -488,17 +482,17 @@ static int print_ntp_status_info(NTPStatusInfo *i) {
                 return table_log_add_error(r);
 
         r = table_add_many(table,
-                           TABLE_STRING, "Delay:",
+                           TABLE_FIELD, "Delay",
                            TABLE_STRING, FORMAT_TIMESPAN(delay, 0),
-                           TABLE_STRING, "Jitter:",
+                           TABLE_FIELD, "Jitter",
                            TABLE_STRING, FORMAT_TIMESPAN(i->jitter, 0),
-                           TABLE_STRING, "Packet count:",
+                           TABLE_FIELD, "Packet count",
                            TABLE_UINT64, i->packet_count);
         if (r < 0)
                 return table_log_add_error(r);
 
         if (!i->spike) {
-                r = table_add_cell(table, NULL, TABLE_STRING, "Frequency:");
+                r = table_add_cell(table, NULL, TABLE_FIELD, "Frequency");
                 if (r < 0)
                         return table_log_add_error(r);
 
index 1fec6d48319fcf4d69c14fe135f32cfa1e5bbf75..bf5192c56fecc716a21585c06f4158dc6455402f 100644 (file)
@@ -50,6 +50,7 @@
 #include "mkdir-label.h"
 #include "mount-util.h"
 #include "mountpoint-util.h"
+#include "nulstr-util.h"
 #include "offline-passwd.h"
 #include "pager.h"
 #include "parse-argument.h"
@@ -962,22 +963,34 @@ shortcut:
         return label_fix_full(fd, /* inode_path= */ NULL, /* label_path= */ path, 0);
 }
 
-static int path_open_parent_safe(const char *path) {
+static int path_open_parent_safe(const char *path, bool allow_failure) {
         _cleanup_free_ char *dn = NULL;
         int r, fd;
 
         if (!path_is_normalized(path))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to open parent of '%s': path not normalized.", path);
+                return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
+                                      SYNTHETIC_ERRNO(EINVAL),
+                                      "Failed to open parent of '%s': path not normalized%s.",
+                                      path,
+                                      allow_failure ? ", ignoring" : "");
 
         r = path_extract_directory(path, &dn);
         if (r < 0)
-                return log_error_errno(r, "Unable to determine parent directory of '%s': %m", path);
+                return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
+                                      r,
+                                      "Unable to determine parent directory of '%s'%s: %m",
+                                      path,
+                                      allow_failure ? ", ignoring" : "");
 
-        r = chase_symlinks(dn, arg_root, CHASE_SAFE|CHASE_WARN, NULL, &fd);
+        r = chase_symlinks(dn, arg_root, allow_failure ? CHASE_SAFE : CHASE_SAFE|CHASE_WARN, NULL, &fd);
         if (r == -ENOLINK) /* Unsafe symlink: already covered by CHASE_WARN */
                 return r;
         if (r < 0)
-                return log_error_errno(r, "Failed to open path '%s': %m", dn);
+                return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
+                                      r,
+                                      "Failed to open path '%s'%s: %m",
+                                      dn,
+                                      allow_failure ? ", ignoring" : "");
 
         return fd;
 }
@@ -1432,7 +1445,7 @@ static int write_one_file(Item *i, const char *path, CreationMode creation) {
 
         /* Validate the path and keep the fd on the directory for opening the file so we're sure that it
          * can't be changed behind our back. */
-        dir_fd = path_open_parent_safe(path);
+        dir_fd = path_open_parent_safe(path, i->allow_failure);
         if (dir_fd < 0)
                 return dir_fd;
 
@@ -1482,7 +1495,7 @@ static int create_file(Item *i, const char *path) {
 
         /* Validate the path and keep the fd on the directory for opening the file so we're sure that it
          * can't be changed behind our back. */
-        dir_fd = path_open_parent_safe(path);
+        dir_fd = path_open_parent_safe(path, i->allow_failure);
         if (dir_fd < 0)
                 return dir_fd;
 
@@ -1550,7 +1563,7 @@ static int truncate_file(Item *i, const char *path) {
 
         /* Validate the path and keep the fd on the directory for opening the file so we're sure that it
          * can't be changed behind our back. */
-        dir_fd = path_open_parent_safe(path);
+        dir_fd = path_open_parent_safe(path, i->allow_failure);
         if (dir_fd < 0)
                 return dir_fd;
 
@@ -1629,7 +1642,7 @@ static int copy_files(Item *i) {
 
         /* Validate the path and use the returned directory fd for copying the target so we're sure that the
          * path can't be changed behind our back. */
-        dfd = path_open_parent_safe(i->path);
+        dfd = path_open_parent_safe(i->path, i->allow_failure);
         if (dfd < 0)
                 return dfd;
 
@@ -1637,7 +1650,8 @@ static int copy_files(Item *i) {
                          dfd, bn,
                          i->uid_set ? i->uid : UID_INVALID,
                          i->gid_set ? i->gid : GID_INVALID,
-                         COPY_REFLINK | COPY_MERGE_EMPTY | COPY_MAC_CREATE | COPY_HARDLINKS);
+                         COPY_REFLINK | COPY_MERGE_EMPTY | COPY_MAC_CREATE | COPY_HARDLINKS,
+                         NULL);
 
         fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH);
         if (fd < 0) {
@@ -1665,6 +1679,7 @@ static int create_directory_or_subvolume(
                 const char *path,
                 mode_t mode,
                 bool subvol,
+                bool allow_failure,
                 struct stat *ret_st,
                 CreationMode *ret_creation) {
 
@@ -1680,7 +1695,7 @@ static int create_directory_or_subvolume(
         if (r < 0)
                 return log_error_errno(r, "Failed to extract filename from path '%s': %m", path);
 
-        pfd = path_open_parent_safe(path);
+        pfd = path_open_parent_safe(path, allow_failure);
         if (pfd < 0)
                 return pfd;
 
@@ -1721,7 +1736,11 @@ static int create_directory_or_subvolume(
 
                 /* Then look at the original error */
                 if (r < 0)
-                        return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", path);
+                        return log_full_errno(allow_failure ? LOG_INFO : LOG_ERR,
+                                              r,
+                                              "Failed to create directory or subvolume \"%s\"%s: %m",
+                                              path,
+                                              allow_failure ? ", ignoring" : "");
 
                 return log_error_errno(errno, "Failed to open directory/subvolume we just created '%s': %m", path);
         }
@@ -1749,7 +1768,7 @@ static int create_directory(Item *i, const char *path) {
         assert(i);
         assert(IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY));
 
-        fd = create_directory_or_subvolume(path, i->mode, /* subvol= */ false, &st, &creation);
+        fd = create_directory_or_subvolume(path, i->mode, /* subvol= */ false, i->allow_failure, &st, &creation);
         if (fd == -EEXIST)
                 return 0;
         if (fd < 0)
@@ -1767,7 +1786,7 @@ static int create_subvolume(Item *i, const char *path) {
         assert(i);
         assert(IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA));
 
-        fd = create_directory_or_subvolume(path, i->mode, /* subvol = */ true, &st, &creation);
+        fd = create_directory_or_subvolume(path, i->mode, /* subvol = */ true, i->allow_failure, &st, &creation);
         if (fd == -EEXIST)
                 return 0;
         if (fd < 0)
@@ -1846,7 +1865,7 @@ static int create_device(Item *i, mode_t file_type) {
 
         /* Validate the path and use the returned directory fd for copying the target so we're sure that the
          * path can't be changed behind our back. */
-        dfd = path_open_parent_safe(i->path);
+        dfd = path_open_parent_safe(i->path, i->allow_failure);
         if (dfd < 0)
                 return dfd;
 
@@ -1948,7 +1967,7 @@ static int create_fifo(Item *i) {
         if (r == O_DIRECTORY)
                 return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Cannot open path '%s' for creating FIFO, is a directory.", i->path);
 
-        pfd = path_open_parent_safe(i->path);
+        pfd = path_open_parent_safe(i->path, i->allow_failure);
         if (pfd < 0)
                 return pfd;
 
@@ -2033,7 +2052,7 @@ static int create_symlink(Item *i) {
         if (r == O_DIRECTORY)
                 return log_error_errno(SYNTHETIC_ERRNO(EISDIR), "Cannot open path '%s' for creating FIFO, is a directory.", i->path);
 
-        pfd = path_open_parent_safe(i->path);
+        pfd = path_open_parent_safe(i->path, i->allow_failure);
         if (pfd < 0)
                 return pfd;
 
index 5f837f4c31e649c7bd023a84dcb55022bb231135..3b0cdda74e0bfdc106faed9a0b37f15722360e73 100644 (file)
@@ -1341,7 +1341,7 @@ bool udev_rules_should_reload(UdevRules *rules) {
 }
 
 static bool token_match_string(UdevRuleToken *token, const char *str) {
-        const char *i, *value;
+        const char *value;
         bool match = false;
 
         assert(token);
index f41069ee04f5b552900d5a18f02e727ce526dde7..640b8440dc1c2e91648c1282abbba99be66b86be 100755 (executable)
@@ -14,6 +14,9 @@ fi
 export SYSTEMD_LOG_LEVEL=debug
 export PAGER=cat
 
+# Disable use of special glyphs such as →
+export SYSTEMD_UTF8=0
+
 seed=750b6cd5c4ae4012a15e7be3c29e6a47
 
 if ! systemd-detect-virt --quiet --container; then
@@ -327,7 +330,7 @@ EOF
 
     output=$(systemd-repart --definitions="$defs" --empty=create --size=100M --json=pretty "$imgs/zzz")
 
-    diff <(echo "$output") - <<EOF
+    diff -u <(echo "$output") - <<EOF
 [
        {
                "type" : "swap",
@@ -338,10 +341,10 @@ EOF
                "offset" : 1048576,
                "old_size" : 0,
                "raw_size" : 33554432,
-               "size" : " 32.0M",
+               "size" : "-> 32.0M",
                "old_padding" : 0,
                "raw_padding" : 0,
-               "padding" : " 0B",
+               "padding" : "-> 0B",
                "activity" : "create",
                "drop-in_files" : [
                        "$defs/root.conf.d/override1.conf",
@@ -382,7 +385,7 @@ EOF
 
     output=$(systemd-repart --definitions="$defs/1" --definitions="$defs/2" --empty=create --size=100M --json=pretty "$imgs/zzz")
 
-    diff <(echo "$output") - <<EOF
+    diff -u <(echo "$output") - <<EOF
 [
        {
                "type" : "swap",
@@ -393,10 +396,10 @@ EOF
                "offset" : 1048576,
                "old_size" : 0,
                "raw_size" : 33554432,
-               "size" : " 32.0M",
+               "size" : "-> 32.0M",
                "old_padding" : 0,
                "raw_padding" : 0,
-               "padding" : " 0B",
+               "padding" : "-> 0B",
                "activity" : "create"
        },
        {
@@ -408,10 +411,10 @@ EOF
                "offset" : 34603008,
                "old_size" : 0,
                "raw_size" : 33554432,
-               "size" : " 32.0M",
+               "size" : "-> 32.0M",
                "old_padding" : 0,
                "raw_padding" : 0,
-               "padding" : " 0B",
+               "padding" : "-> 0B",
                "activity" : "create"
        }
 ]
@@ -766,13 +769,68 @@ EOF
 
     roothash=$(jq -r ".[] | select(.type == \"root-${architecture}-verity\") | .roothash" <<< "$output")
 
-    # Check that we can dissect, mount and unmount a repart verity image.
+    # Check that we can dissect, mount and unmount a repart verity image. (and that the image UUID is deterministic)
 
     systemd-dissect "$imgs/verity" --root-hash "$roothash"
+    systemd-dissect "$imgs/verity" --root-hash "$roothash" --json=short | grep -q '"imageUuid":"1d2ce291-7cce-4f7d-bc83-fdb49ad74ebd"'
     systemd-dissect "$imgs/verity" --root-hash "$roothash" -M "$imgs/mnt"
     systemd-dissect -U "$imgs/mnt"
 }
 
+test_issue_24786() {
+    local defs imgs root output
+
+    if systemd-detect-virt --quiet --container; then
+        echo "Skipping verity test in container."
+        return
+    fi
+
+    defs="$(mktemp --directory "/tmp/test-repart.XXXXXXXXXX")"
+    imgs="$(mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+    root="$(mktemp --directory "/var/tmp/test-repart.XXXXXXXXXX")"
+    # shellcheck disable=SC2064
+    trap "rm -rf '$defs' '$imgs' '$root'" RETURN
+
+    touch "$root/abc"
+    mkdir "$root/usr"
+    touch "$root/usr/def"
+
+    cat >"$defs/00-root.conf" <<EOF
+[Partition]
+Type=root-${architecture}
+CopyFiles=/
+EOF
+
+    cat >"$defs/10-usr.conf" <<EOF
+[Partition]
+Type=usr-${architecture}
+CopyFiles=/usr:/
+EOF
+
+    output=$(systemd-repart --definitions="$defs" \
+                            --seed="$seed" \
+                            --dry-run=no \
+                            --empty=create \
+                            --size=auto \
+                            --json=pretty \
+                            --root="$root" \
+                            "$imgs/zzz")
+
+    loop=$(losetup -P --show -f "$imgs/zzz")
+    udevadm wait --timeout 60 --settle "${loop:?}"
+
+    mkdir "$imgs/mnt"
+    mount -t ext4 "${loop}p1" "$imgs/mnt"
+    assert_rc 0 ls "$imgs/mnt/abc"
+    assert_rc 2 ls "$imgs/mnt/usr"
+    mkdir "$imgs/mnt/usr"
+    mount -t ext4 "${loop}p2" "$imgs/mnt/usr"
+    assert_rc 0 ls "$imgs/mnt/usr/def"
+
+    umount -R "$imgs/mnt"
+    losetup -d "$loop"
+}
+
 test_sector() {
     local defs imgs output loop
     local start size ratio
@@ -841,6 +899,7 @@ test_issue_21817
 test_issue_24553
 test_zero_uuid
 test_verity
+test_issue_24786
 
 # Valid block sizes on the Linux block layer are >= 512 and <= PAGE_SIZE, and
 # must be powers of 2. Which leaves exactly four different ones to test on
index 04a8b6e9cc8378a18d3da5f5e33aad0545482f57..1a656fcdc1a09eb9455db4b0b1e7e52321939a04 100755 (executable)
@@ -55,6 +55,79 @@ echo nameserver 10.0.3.1 10.0.3.2 | "$RESOLVCONF" -a hoge.inet.ipsec.192.168.35
 echo nameserver 10.0.3.3 10.0.3.4 | "$RESOLVCONF" -a hoge.foo.dhcp
 assert_in '10.0.3.1 10.0.3.2' "$(resolvectl dns hoge)"
 assert_in '10.0.3.3 10.0.3.4' "$(resolvectl dns hoge.foo)"
+
+# Tests for mDNS and LLMNR settings
+mkdir -p /run/systemd/resolved.conf.d
+{
+    echo "[Resolve]"
+    echo "MulticastDNS=yes"
+    echo "LLMNR=yes"
+} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
+systemctl restart systemd-resolved.service
+systemctl service-log-level systemd-resolved.service debug
+# make sure networkd is not running.
+systemctl stop systemd-networkd.service
+# defaults to yes (both the global and per-link settings are yes)
+assert_in 'yes' "$(resolvectl mdns hoge)"
+assert_in 'yes' "$(resolvectl llmnr hoge)"
+# set per-link setting
+resolvectl mdns hoge yes
+resolvectl llmnr hoge yes
+assert_in 'yes' "$(resolvectl mdns hoge)"
+assert_in 'yes' "$(resolvectl llmnr hoge)"
+resolvectl mdns hoge resolve
+resolvectl llmnr hoge resolve
+assert_in 'resolve' "$(resolvectl mdns hoge)"
+assert_in 'resolve' "$(resolvectl llmnr hoge)"
+resolvectl mdns hoge no
+resolvectl llmnr hoge no
+assert_in 'no' "$(resolvectl mdns hoge)"
+assert_in 'no' "$(resolvectl llmnr hoge)"
+# downgrade global setting to resolve
+{
+    echo "[Resolve]"
+    echo "MulticastDNS=resolve"
+    echo "LLMNR=resolve"
+} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
+systemctl restart systemd-resolved.service
+systemctl service-log-level systemd-resolved.service debug
+# set per-link setting
+resolvectl mdns hoge yes
+resolvectl llmnr hoge yes
+assert_in 'resolve' "$(resolvectl mdns hoge)"
+assert_in 'resolve' "$(resolvectl llmnr hoge)"
+resolvectl mdns hoge resolve
+resolvectl llmnr hoge resolve
+assert_in 'resolve' "$(resolvectl mdns hoge)"
+assert_in 'resolve' "$(resolvectl llmnr hoge)"
+resolvectl mdns hoge no
+resolvectl llmnr hoge no
+assert_in 'no' "$(resolvectl mdns hoge)"
+assert_in 'no' "$(resolvectl llmnr hoge)"
+# downgrade global setting to no
+{
+    echo "[Resolve]"
+    echo "MulticastDNS=no"
+    echo "LLMNR=no"
+} >/run/systemd/resolved.conf.d/mdns-llmnr.conf
+systemctl restart systemd-resolved.service
+systemctl service-log-level systemd-resolved.service debug
+# set per-link setting
+resolvectl mdns hoge yes
+resolvectl llmnr hoge yes
+assert_in 'no' "$(resolvectl mdns hoge)"
+assert_in 'no' "$(resolvectl llmnr hoge)"
+resolvectl mdns hoge resolve
+resolvectl llmnr hoge resolve
+assert_in 'no' "$(resolvectl mdns hoge)"
+assert_in 'no' "$(resolvectl llmnr hoge)"
+resolvectl mdns hoge no
+resolvectl llmnr hoge no
+assert_in 'no' "$(resolvectl mdns hoge)"
+assert_in 'no' "$(resolvectl llmnr hoge)"
+
+# Cleanup
+rm -f /run/systemd/resolved.conf.d/mdns-llmnr.conf
 ip link del hoge
 ip link del hoge.foo
 
@@ -79,11 +152,13 @@ DNSSEC=allow-downgrade
 DNS=10.0.0.1
 EOF
 
+mkdir -p /run/systemd/resolved.conf.d
 {
+    echo "[Resolve]"
     echo "FallbackDNS="
     echo "DNSSEC=allow-downgrade"
     echo "DNSOverTLS=opportunistic"
-} >>/etc/systemd/resolved.conf
+} >/run/systemd/resolved.conf.d/test.conf
 ln -svf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
 # Override the default NTA list, which turns off DNSSEC validation for (among
 # others) the test. domain