]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #28976 from yuwata/network-ndisc-drop-on-zero-lifetime
authorLuca Boccassi <bluca@debian.org>
Sun, 3 Sep 2023 13:04:58 +0000 (14:04 +0100)
committerGitHub <noreply@github.com>
Sun, 3 Sep 2023 13:04:58 +0000 (14:04 +0100)
network/ndisc: also drop configurations with infinite lifetime on RA …

28 files changed:
.github/workflows/build_test.yml
.github/workflows/cifuzz.yml
.github/workflows/codeql.yml
.github/workflows/coverity.yml
.github/workflows/development_freeze.yml
.github/workflows/differential-shellcheck.yml
.github/workflows/gather-pr-metadata.yml
.github/workflows/issue_labeler.yml
.github/workflows/linter.yml
.github/workflows/mkosi.yml
.github/workflows/requirements.txt
.github/workflows/scorecards.yml
.github/workflows/unit_tests.yml
NEWS
TODO
hwdb.d/60-sensor.hwdb
src/basic/string-util.h
src/core/dbus-manager.c
src/core/main.c
src/journal/journald-server.c
src/libsystemd/sd-journal/journal-file.c
src/login/loginctl.c
src/shared/format-table.c
src/shared/switch-root.c
src/shared/switch-root.h
src/shutdown/shutdown.c
src/systemctl/systemctl-switch-root.c
src/test/test-string-util.c

index 93b7f2c2d1ea801a60cf0c77eccf92d7620ec442..16dcd30c082a76947bd12b223eca0055c29d8d80 100644 (file)
@@ -33,6 +33,6 @@ jobs:
     env: ${{ matrix.env }}
     steps:
       - name: Repository checkout
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
       - name: ${{ format('Build check ({0}-{1}-{2}-{3})', env.COMPILER, env.COMPILER_VERSION, env.LINKER, env.CRYPTOLIB) }}
         run: sudo -E .github/workflows/build_test.sh
index ca1ccf7fea5ad033c452bf1762701c27a4180938..a7e4d2b84202ef1ffda6a3c54c690ffbb14b9103 100644 (file)
@@ -67,7 +67,7 @@ jobs:
           path: ./out/artifacts
       - name: Upload Sarif
         if: always() && steps.build.outcome == 'success'
-        uses: github/codeql-action/upload-sarif@0ba4244466797eb048eb91a6cd43d5c03ca8bd05
+        uses: github/codeql-action/upload-sarif@00e563ead9f72a8461b24876bee2d0c2e8bd2ee8
         with:
           # Path to SARIF file relative to the root of the repository
           sarif_file: cifuzz-sarif/results.sarif
index 82c64db687716abc005fd3d45fef8f2ea427aa1d..d66dcdc7e89127ebf1cec6a7bada0725de6dd8f0 100644 (file)
@@ -42,10 +42,10 @@ jobs:
 
     steps:
     - name: Checkout repository
-      uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+      uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
 
     - name: Initialize CodeQL
-      uses: github/codeql-action/init@0ba4244466797eb048eb91a6cd43d5c03ca8bd05
+      uses: github/codeql-action/init@00e563ead9f72a8461b24876bee2d0c2e8bd2ee8
       with:
         languages: ${{ matrix.language }}
         config-file: ./.github/codeql-config.yml
@@ -53,7 +53,7 @@ jobs:
     - run: sudo -E .github/workflows/unit_tests.sh SETUP
 
     - name: Autobuild
-      uses: github/codeql-action/autobuild@0ba4244466797eb048eb91a6cd43d5c03ca8bd05
+      uses: github/codeql-action/autobuild@00e563ead9f72a8461b24876bee2d0c2e8bd2ee8
 
     - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@0ba4244466797eb048eb91a6cd43d5c03ca8bd05
+      uses: github/codeql-action/analyze@00e563ead9f72a8461b24876bee2d0c2e8bd2ee8
index e9ba8d8b8697d01f3819be38f7fa586b33c1b5c8..05bf751924d54a8a85404eb8b8efa93b24ed6048 100644 (file)
@@ -22,7 +22,7 @@ jobs:
       COVERITY_SCAN_NOTIFICATION_EMAIL: "${{ secrets.COVERITY_SCAN_NOTIFICATION_EMAIL }}"
     steps:
       - name: Repository checkout
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
       # Reuse the setup phase of the unit test script to avoid code duplication
       - name: Install build dependencies
         run: sudo -E .github/workflows/unit_tests.sh SETUP
index 7566e4dabda2f21c36d3648aab28d27af93525cd..17065b24d27534f48a86c2002f64d9559f834f4e 100644 (file)
@@ -63,7 +63,7 @@ jobs:
             core.exportVariable('pr_number', pr_number);
 
       - name: Repository checkout
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
         with:
           fetch-depth: 0
 
index 4b40d397a35853a6406a8f9a1766d8e0859aa880..1a3615360591cdda265cf1f2371b5ac386d55ad3 100644 (file)
@@ -23,7 +23,7 @@ jobs:
 
     steps:
       - name: Repository checkout
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
         with:
           fetch-depth: 0
 
index 7ec5a8ec0bd7cea4f76c44027f4354ea3054f164..c85795cbb5f1b7d2b659056acb9ca47e9cc11d6d 100644 (file)
@@ -20,7 +20,7 @@ jobs:
 
     steps:
       - name: Repository checkout
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
         with:
           fetch-depth: 0
 
index 1530e019843e0f08c0abd257090f62388111e503..e57ac70bcdbd0d161c775d63a20db7d354f371b7 100644 (file)
@@ -20,7 +20,7 @@ jobs:
         template: [ bug_report.yml, feature_request.yml ]
 
     steps:
-      - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
 
       - name: Parse issue form
         uses: stefanbuck/github-issue-parser@c1a559d78bfb8dd05216dab9ffd2b91082ff5324
index bf1ba59b4c70d8f6cccaf088faedf5f9d461bd62..d1b363824e5fdadd147871012e264761a676b83a 100644 (file)
@@ -23,7 +23,7 @@ jobs:
 
     steps:
       - name: Repo checkout
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
         with:
           # We need a full repo clone
           fetch-depth: 0
index d5f587f4ad7e5bc00b7157ea109c26be3b45edf7..5d8b3c01176f027862e56469c72ba092a2667da1 100644 (file)
@@ -75,7 +75,7 @@ jobs:
       SYSTEMD_LOG_LEVEL: debug
 
     steps:
-    - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+    - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
     - uses: systemd/mkosi@0af3f8a35c3be0e54b20234be7ab478d25bcc740
 
     - name: Configure
index 15ee81d4cb2c6fd4fd4823b64b7ea8388a43e92c..d320b794882bc996c367a8fac7729e0b70806ee4 100644 (file)
@@ -1,6 +1,6 @@
-meson==1.2.0 \
-    --hash=sha256:10c0364edc67a1b3146f405800b300f0535f42b8736e79c744a8029a855b7c6b \
-    --hash=sha256:1c0b634fe6b6a7072e398647f1bf392048577068a5c92ae44d04085dab0ded6f
+meson==1.2.1 \
+    --hash=sha256:08f83fc17513e99cd6e82c7554c1f58af70425211887f8f9c7363b2a90209462 \
+    --hash=sha256:b1db3a153087549497ee52b1c938d2134e0338214fe14f7efd16fecd57b639f5
 ninja==1.11.1 \
     --hash=sha256:1c474326e11fba3f8c2582715d79216292e327d3335367c0e87e9647a002cc4a \
     --hash=sha256:3329b4b7c1694730772522a3ba0ba40fd15c012476ed3e1c9f0fd9e76190394e \
index b668d92368cdeab94fb4ac05b5aa08ce61b12b95..062a95af2faa99107cc943204cfde134f4e98306 100644 (file)
@@ -29,7 +29,7 @@ jobs:
 
     steps:
       - name: Checkout code
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
+        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
         with:
           persist-credentials: false
 
index 98747663eab7f04cf09965badd4ddb79d4cd4a27..051e8ec3bf66a469bbbe218af5375322ca52a814 100644 (file)
@@ -30,7 +30,7 @@ jobs:
             cryptolib: gcrypt
     steps:
       - name: Repository checkout
-        uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
+        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744
       - name: Install build dependencies
         run: |
           # Drop XDG_* stuff from /etc/environment, so we don't get the user
diff --git a/NEWS b/NEWS
index 3acbafc44af6a7dc50dbecee648c637553915de8..8ba35e5b3151bcaad39972a89a1576000af9ac62 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,10 @@ CHANGES WITH 255 in spe:
           by default when combined with --scope, will be changed in a future
           release to be enabled by default.
 
+        * "systemctl switch-root" is now restricted to initrd transtions only.
+          Transitions between real systems should be done with "systemctl soft-reboot"
+          instead.
+
         Device Management:
 
         * udev will now create symlinks to loopback block devices in the
diff --git a/TODO b/TODO
index eda525dc443dc8626386c312cff0292bf361b98e..20d81c4ba7f4e566c554ff59a83bb027881d9377 100644 (file)
--- a/TODO
+++ b/TODO
@@ -274,11 +274,6 @@ Features:
   idea, and specifically works around the fact the autofs ignores busy by mount
   namespaces)
 
-* refuse using the switch-root operation without /etc/initrd-release. Now
-  that we have a concept of userspace reboot, we can clearly say: switch-root
-  is for transitioning from initrd to host (or initrd to next initrd), while
-  userspace reboot is for switching host to next version of the host.
-
 * mount most file systems with a restrictive uidmap. e.g. mount /usr/ with a
   uidmap that blocks out anything outside 0…1000 (i.e. system users) and similar.
 
index 6bcf2cba4a543a8726d5bc24f450f0a8fdb01bae..c757f83f19cf914cae057889465681d354c96905 100644 (file)
@@ -926,6 +926,12 @@ sensor:modalias:acpi:SMO8500*:dmi:*:svnProwise:pnPT301:*
 sensor:modalias:acpi:SMO8500*:dmi:*:rvnReeder:rnA8iW-Rev.A:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
+#########################################
+# RCA
+#########################################
+sensor:modalias:acpi:KIOX000A*:dmi:*:svnRCA:pnW101SA23T1:*
+ ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
+
 #########################################
 # Schneider
 #########################################
index 73d586d4c54c849687bb4f0cff489b68b5c30135..72f791f6ccb92c2905570e6b73684173275b6c10 100644 (file)
@@ -196,6 +196,17 @@ int strextendf_with_separator(char **x, const char *separator, const char *forma
 
 char *strrep(const char *s, unsigned n);
 
+#define strrepa(s, n)                                           \
+        ({                                                      \
+                char *_d_, *_p_;                                \
+                size_t _len_ = strlen(s) * n;                   \
+                _p_ = _d_ = newa(char, _len_ + 1);              \
+                for (unsigned _i_ = 0; _i_ < n; _i_++)          \
+                        _p_ = stpcpy(_p_, s);                   \
+                *_p_ = 0;                                       \
+                _d_;                                            \
+        })
+
 int split_pair(const char *s, const char *sep, char **l, char **r);
 
 int free_and_strdup(char **p, const char *s);
index 245c5f14f1fbd4d4bd4ebcb7604889a1ccc8486b..3d1a38b21ed80b1c2f8752ab07bdef499f6874f9 100644 (file)
@@ -26,6 +26,7 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
+#include "initrd-util.h"
 #include "install.h"
 #include "log.h"
 #include "manager-dump.h"
@@ -1864,26 +1865,37 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
                 if (!path_is_valid(root))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
                                                  "New root directory must be a valid path.");
+
                 if (!path_is_absolute(root))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
                                                  "New root path '%s' is not absolute.", root);
-                if (path_equal(root, "/"))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
-                                                 "New root directory cannot be the old root directory.");
-        }
 
-        /* Safety check */
-        if (isempty(init)) {
-                r = path_is_os_tree(root);
+                r = path_is_root(root);
                 if (r < 0)
                         return sd_bus_error_set_errnof(error, r,
-                                                       "Failed to determine whether root path '%s' contains an OS tree: %m",
+                                                       "Failed to check if new root directory '%s' is the same as old root: %m",
                                                        root);
-                if (r == 0)
+                if (r > 0)
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
-                                                 "Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.",
-                                                 root);
-        } else {
+                                                 "New root directory cannot be the old root directory.");
+        }
+
+        /* Safety check */
+        if (!in_initrd())
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Not in initrd, refusing switch-root operation.");
+
+        r = path_is_os_tree(root);
+        if (r < 0)
+                return sd_bus_error_set_errnof(error, r,
+                                               "Failed to determine whether root path '%s' contains an OS tree: %m",
+                                               root);
+        if (r == 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.",
+                                         root);
+
+        if (!isempty(init)) {
                 if (!path_is_valid(init))
                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
                                                  "Path to init binary '%s' is not a valid path.", init);
index c54558f23b9ba0e0757f887be559e33ec64c0a02..f8b0c69f5aa5d0759f98881b70fd48aeeeb23741 100644 (file)
@@ -1891,7 +1891,7 @@ static int do_reexecute(
                 r = switch_root(/* new_root= */ switch_root_dir,
                                 /* old_root_after= */ NULL,
                                 /* flags= */ (objective == MANAGER_SWITCH_ROOT ? SWITCH_ROOT_DESTROY_OLD_ROOT : 0) |
-                                             (objective == MANAGER_SOFT_REBOOT ? SWITCH_ROOT_SKIP_RECURSIVE_RUN : 0));
+                                             (objective == MANAGER_SOFT_REBOOT ? 0 : SWITCH_ROOT_RECURSIVE_RUN));
                 if (r < 0)
                         log_error_errno(r, "Failed to switch root, trying to continue: %m");
         }
index 2932a190ff7e4bfc66a9f4a46753abaca4983c26..897e2abd3a2f540b0115f2e99e4af51c8c48f16e 100644 (file)
@@ -871,12 +871,12 @@ static bool shall_try_append_again(JournalFile *f, int r) {
                 log_ratelimit_info_errno(r, JOURNAL_LOG_RATELIMIT, "%s: Realtime clock jumped backwards relative to last journal entry, rotating.", f->path);
                 return true;
 
-        case -EREMOTE:         /* Boot ID different from the one of the last entry */
-                log_ratelimit_info_errno(r, JOURNAL_LOG_RATELIMIT, "%s: Boot ID changed since last record, rotating.", f->path);
-                return true;
-
-        case -ENOTNAM:         /* Monotonic time (CLOCK_MONOTONIC) jumped backwards relative to last journal entry */
-                log_ratelimit_info_errno(r, JOURNAL_LOG_RATELIMIT, "%s: Monotonic clock jumped backwards relative to last journal entry, rotating.", f->path);
+        case -ENOTNAM: /* Monotonic time (CLOCK_MONOTONIC) jumped backwards relative to last journal entry with the same boot ID */
+                log_ratelimit_info_errno(
+                                r,
+                                JOURNAL_LOG_RATELIMIT,
+                                "%s: Monotonic clock jumped backwards relative to last journal entry with the same boot ID, rotating.",
+                                f->path);
                 return true;
 
         case -EILSEQ:          /* seqnum ID last used in the file doesn't match the one we'd passed when writing an entry to it */
index 06ffa137d41f1c59c390971aeb53313f72af8e99..95cf25bff00264672e1d626657bbf57bd0d428ba 100644 (file)
@@ -572,6 +572,10 @@ static int journal_file_verify_header(JournalFile *f) {
         if (journal_file_writable(f) && header_size != sizeof(Header))
                 return -EPROTONOSUPPORT;
 
+        /* Don't write to journal files without the new boot ID update behavior guarantee. */
+        if (journal_file_writable(f) && !JOURNAL_HEADER_TAIL_ENTRY_BOOT_ID(f->header))
+                return -EPROTONOSUPPORT;
+
         if (JOURNAL_HEADER_SEALED(f->header) && !JOURNAL_HEADER_CONTAINS(f->header, n_entry_arrays))
                 return -EBADMSG;
 
@@ -2283,18 +2287,15 @@ static int journal_file_append_entry_internal(
                                                "timestamp %" PRIu64 ", refusing entry.",
                                                ts->realtime, le64toh(f->header->tail_entry_realtime));
 
-                if (!sd_id128_is_null(f->header->tail_entry_boot_id) && boot_id) {
-
-                        if (!sd_id128_equal(f->header->tail_entry_boot_id, *boot_id))
-                                return log_debug_errno(SYNTHETIC_ERRNO(EREMOTE),
-                                                       "Boot ID to write is different from previous boot id, refusing entry.");
-
-                        if (ts->monotonic < le64toh(f->header->tail_entry_monotonic))
-                                return log_debug_errno(SYNTHETIC_ERRNO(ENOTNAM),
-                                                       "Monotonic timestamp %" PRIu64 " smaller than previous monotonic "
-                                                       "timestamp %" PRIu64 ", refusing entry.",
-                                                       ts->monotonic, le64toh(f->header->tail_entry_monotonic));
-                }
+                if ((!boot_id || sd_id128_equal(*boot_id, f->header->tail_entry_boot_id)) &&
+                    ts->monotonic < le64toh(f->header->tail_entry_monotonic))
+                        return log_debug_errno(
+                                        SYNTHETIC_ERRNO(ENOTNAM),
+                                        "Monotonic timestamp %" PRIu64
+                                        " smaller than previous monotonic timestamp %" PRIu64
+                                        " while having the same boot ID, refusing entry.",
+                                        ts->monotonic,
+                                        le64toh(f->header->tail_entry_monotonic));
         }
 
         if (seqnum_id) {
index cc72d6ca8f057e791946a621d177a030859431bb..8704f44dfd7989a5b9564be6c455211068a9ff00 100644 (file)
@@ -113,32 +113,6 @@ static OutputFlags get_output_flags(void) {
                 colors_enabled() * OUTPUT_COLOR;
 }
 
-static int get_session_path(sd_bus *bus, const char *session_id, sd_bus_error *error, char **path) {
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        char *ans;
-        int r;
-
-        assert(bus);
-        assert(session_id);
-        assert(error);
-        assert(path);
-
-        r = bus_call_method(bus, bus_login_mgr, "GetSession", error, &reply, "s", session_id);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_message_read(reply, "o", &ans);
-        if (r < 0)
-                return r;
-
-        ans = strdup(ans);
-        if (!ans)
-                return -ENOMEM;
-
-        *path = ans;
-        return 0;
-}
-
 static int show_table(Table *table, const char *word) {
         int r;
 
@@ -375,14 +349,20 @@ static int list_seats(int argc, char *argv[], void *userdata) {
         return show_table(table, "seats");
 }
 
-static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
-        _cleanup_free_ char *cgroup = NULL;
+static int show_unit_cgroup(
+                sd_bus *bus,
+                const char *unit,
+                pid_t leader,
+                const char *prefix) {
+
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *cgroup = NULL;
         unsigned c;
         int r;
 
         assert(bus);
         assert(unit);
+        assert(prefix);
 
         r = show_cgroup_get_unit_path_and_warn(bus, unit, &cgroup);
         if (r < 0)
@@ -394,12 +374,9 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
         c = columns();
         if (c > 18)
                 c -= 18;
-        else
-                c = 0;
 
-        r = unit_show_processes(bus, unit, cgroup, "\t\t  ", c, get_output_flags(), &error);
+        r = unit_show_processes(bus, unit, cgroup, prefix, c, get_output_flags(), &error);
         if (r == -EBADR) {
-
                 if (arg_transport == BUS_TRANSPORT_REMOTE)
                         return 0;
 
@@ -408,7 +385,7 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
                 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
                         return 0;
 
-                show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, &leader, leader > 0, get_output_flags());
+                show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, prefix, c, &leader, leader > 0, get_output_flags());
         } else if (r < 0)
                 return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
 
@@ -467,7 +444,25 @@ static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_messag
         return sd_bus_message_exit_container(m);
 }
 
-static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
+static int mark_session(char **sessions, const char *target_session) {
+        assert(sessions);
+        assert(target_session);
+
+        STRV_FOREACH(i, sessions)
+                if (streq(*i, target_session)) {
+                        _cleanup_free_ char *marked = NULL;
+
+                        marked = strjoin("*", target_session);
+                        if (!marked)
+                                return log_oom();
+
+                        return free_and_replace(*i, marked);
+                }
+
+        return 0;
+}
+
+static int print_session_status_info(sd_bus *bus, const char *path) {
 
         static const struct bus_properties_map map[] = {
                 { "Id",                     "s",    NULL,                     offsetof(SessionStatusInfo,  id)                            },
@@ -497,6 +492,7 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
 
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        _cleanup_(table_unrefp) Table *table = NULL;
         SessionStatusInfo i = {};
         int r;
 
@@ -504,95 +500,148 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
         if (r < 0)
                 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
 
-        if (*new_line)
-                printf("\n");
-
-        *new_line = true;
+        table = table_new_vertical();
+        if (!table)
+                return log_oom();
 
-        printf("%s - ", strna(i.id));
+        if (dual_timestamp_is_set(&i.timestamp)) {
+                r = table_add_cell(table, NULL, TABLE_FIELD, "Since");
+                if (r < 0)
+                        return table_log_add_error(r);
 
-        if (i.name)
-                printf("%s (" UID_FMT ")\n", i.name, i.uid);
-        else
-                printf(UID_FMT "\n", i.uid);
+                r = table_add_cell_stringf(table, NULL, "%s; %s",
+                                           FORMAT_TIMESTAMP(i.timestamp.realtime),
+                                           FORMAT_TIMESTAMP_RELATIVE_MONOTONIC(i.timestamp.monotonic));
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
 
-        if (dual_timestamp_is_set(&i.timestamp))
-                printf("\t   Since: %s; %s\n",
-                       FORMAT_TIMESTAMP(i.timestamp.realtime),
-                       FORMAT_TIMESTAMP_RELATIVE_MONOTONIC(i.timestamp.monotonic));
+        r = table_add_many(table,
+                           TABLE_FIELD, "State",
+                           TABLE_STRING, i.state);
+        if (r < 0)
+                return table_log_add_error(r);
 
         if (i.leader > 0) {
-                _cleanup_free_ char *t = NULL;
+                _cleanup_free_ char *name = NULL;
 
-                printf("\t  Leader: " PID_FMT, i.leader);
+                (void) get_process_comm(i.leader, &name);
 
-                (void) get_process_comm(i.leader, &t);
-                if (t)
-                        printf(" (%s)", t);
+                r = table_add_cell(table, NULL, TABLE_FIELD, "Leader");
+                if (r < 0)
+                        return table_log_add_error(r);
 
-                printf("\n");
+                r = table_add_cell_stringf(table, NULL, PID_FMT "%s%s%s",
+                                           i.leader,
+                                           !isempty(name) ? " (" : "",
+                                           strempty(name),
+                                           !isempty(name) ? ")" : "");
+                if (r < 0)
+                        return table_log_add_error(r);
         }
 
-        if (!isempty(i.seat)) {
-                printf("\t    Seat: %s", i.seat);
-
-                if (i.vtnr > 0)
-                        printf("; vc%u", i.vtnr);
+        r = table_add_cell(table, NULL, TABLE_FIELD, "Seat");
+        if (r < 0)
+                return table_log_add_error(r);
 
-                printf("\n");
-        }
+        if (i.vtnr > 0)
+                r = table_add_cell_stringf(table, NULL, "%s; vc%u", i.seat, i.vtnr);
+        else
+                r = table_add_cell(table, NULL, TABLE_STRING, i.seat);
+        if (r < 0)
+                return table_log_add_error(r);
 
         if (i.tty)
-                printf("\t     TTY: %s\n", i.tty);
+                r = table_add_many(table,
+                                   TABLE_FIELD, "TTY",
+                                   TABLE_STRING, i.tty);
         else if (i.display)
-                printf("\t Display: %s\n", i.display);
+                r = table_add_many(table,
+                                   TABLE_FIELD, "Display",
+                                   TABLE_STRING, i.display);
+        else
+                r = 0;
+        if (r < 0)
+                return table_log_add_error(r);
+
+        r = table_add_cell(table, NULL, TABLE_FIELD, "Remote");
+        if (r < 0)
+                return table_log_add_error(r);
 
         if (i.remote_host && i.remote_user)
-                printf("\t  Remote: %s@%s\n", i.remote_user, i.remote_host);
+                r = table_add_cell_stringf(table, NULL, "%s@%s", i.remote_user, i.remote_host);
         else if (i.remote_host)
-                printf("\t  Remote: %s\n", i.remote_host);
+                r = table_add_cell(table, NULL, TABLE_STRING, i.remote_host);
         else if (i.remote_user)
-                printf("\t  Remote: user %s\n", i.remote_user);
-        else if (i.remote)
-                printf("\t  Remote: Yes\n");
+                r = table_add_cell_stringf(table, NULL, "user %s", i.remote_user);
+        else
+                r = table_add_cell(table, NULL, TABLE_BOOLEAN, &i.remote);
+        if (r < 0)
+                return table_log_add_error(r);
 
         if (i.service) {
-                printf("\t Service: %s", i.service);
+                r = table_add_many(table,
+                                   TABLE_FIELD, "Service",
+                                   TABLE_STRING, i.service);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
 
-                if (i.type)
-                        printf("; type %s", i.type);
+        if (i.type) {
+                r = table_add_many(table,
+                                   TABLE_FIELD, "Type",
+                                   TABLE_STRING, i.type);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
 
-                if (i.class)
-                        printf("; class %s", i.class);
+        if (i.class) {
+                r = table_add_many(table,
+                                   TABLE_FIELD, "Class",
+                                   TABLE_STRING, i.class);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
 
-                printf("\n");
-        } else if (i.type) {
-                printf("\t    Type: %s", i.type);
+        if (!isempty(i.desktop)) {
+                r = table_add_many(table,
+                                   TABLE_FIELD, "Desktop",
+                                   TABLE_STRING, i.desktop);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
 
-                if (i.class)
-                        printf("; class %s", i.class);
+        r = table_add_cell(table, NULL, TABLE_FIELD, "Idle");
+        if (r < 0)
+                return table_log_add_error(r);
 
-                printf("\n");
-        } else if (i.class)
-                printf("\t   Class: %s\n", i.class);
+        if (i.idle_hint && dual_timestamp_is_set(&i.idle_hint_timestamp))
+                r = table_add_cell_stringf(table, NULL, "%s since %s (%s)",
+                                           yes_no(i.idle_hint),
+                                           FORMAT_TIMESTAMP(i.idle_hint_timestamp.realtime),
+                                           FORMAT_TIMESTAMP_RELATIVE_MONOTONIC(i.idle_hint_timestamp.monotonic));
+        else
+                r = table_add_cell(table, NULL, TABLE_BOOLEAN, &i.idle_hint);
+        if (r < 0)
+                return table_log_add_error(r);
 
-        if (!isempty(i.desktop))
-                printf("\t Desktop: %s\n", i.desktop);
+        if (i.scope) {
+                r = table_add_many(table,
+                                   TABLE_FIELD, "Unit",
+                                   TABLE_STRING, i.scope);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
 
-        if (i.state)
-                printf("\t   State: %s\n", i.state);
+        /* We don't use the table to show the header, in order to make the width of the column stable. */
+        printf("%s%s - %s (" UID_FMT ")%s\n", ansi_highlight(), i.id, i.name, i.uid, ansi_normal());
 
-        if (i.idle_hint && dual_timestamp_is_set(&i.idle_hint_timestamp))
-                printf("\t    Idle: %s since %s (%s)\n",
-                       yes_no(i.idle_hint),
-                       FORMAT_TIMESTAMP(i.idle_hint_timestamp.realtime),
-                       FORMAT_TIMESTAMP_RELATIVE_MONOTONIC(i.idle_hint_timestamp.monotonic));
-        else
-                printf("\t    Idle: %s\n", yes_no(i.idle_hint));
+        r = table_print(table, NULL);
+        if (r < 0)
+                return table_log_print_error(r);
 
         if (i.scope) {
-                printf("\t    Unit: %s\n", i.scope);
-                show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
+                show_unit_cgroup(bus, i.scope, i.leader, /* prefix = */ strrepa(" ", STRLEN("Display: ")));
 
                 if (arg_transport == BUS_TRANSPORT_LOCAL)
                         show_journal_by_unit(
@@ -613,7 +662,7 @@ static int print_session_status_info(sd_bus *bus, const char *path, bool *new_li
         return 0;
 }
 
-static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
+static int print_user_status_info(sd_bus *bus, const char *path) {
 
         static const struct bus_properties_map map[] = {
                 { "Name",               "s",     NULL,                     offsetof(UserStatusInfo, name)                },
@@ -631,66 +680,92 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_(user_status_info_done) UserStatusInfo i = {};
+        _cleanup_(table_unrefp) Table *table = NULL;
         int r;
 
         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, BUS_MAP_BOOLEAN_AS_BOOL, &error, &m, &i);
         if (r < 0)
                 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
 
-        if (*new_line)
-                printf("\n");
-
-        *new_line = true;
+        table = table_new_vertical();
+        if (!table)
+                return log_oom();
 
-        if (i.name)
-                printf("%s (%"PRIu32")\n", i.name, i.uid);
-        else
-                printf("%"PRIu32"\n", i.uid);
+        if (dual_timestamp_is_set(&i.timestamp)) {
+                r = table_add_cell(table, NULL, TABLE_FIELD, "Since");
+                if (r < 0)
+                        return table_log_add_error(r);
 
-        if (dual_timestamp_is_set(&i.timestamp))
-                printf("\t   Since: %s; %s\n",
-                       FORMAT_TIMESTAMP(i.timestamp.realtime),
-                       FORMAT_TIMESTAMP_RELATIVE_MONOTONIC(i.timestamp.monotonic));
+                r = table_add_cell_stringf(table, NULL, "%s; %s",
+                                           FORMAT_TIMESTAMP(i.timestamp.realtime),
+                                           FORMAT_TIMESTAMP_RELATIVE_MONOTONIC(i.timestamp.monotonic));
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
 
-        if (!isempty(i.state))
-                printf("\t   State: %s\n", i.state);
+        r = table_add_many(table,
+                           TABLE_FIELD, "State",
+                           TABLE_STRING, i.state);
+        if (r < 0)
+                return table_log_add_error(r);
 
         if (!strv_isempty(i.sessions)) {
-                printf("\tSessions:");
+                _cleanup_strv_free_ char **sessions = TAKE_PTR(i.sessions);
 
-                STRV_FOREACH(l, i.sessions)
-                        printf(" %s%s",
-                               streq_ptr(*l, i.display) ? "*" : "",
-                               *l);
+                r = mark_session(sessions, i.display);
+                if (r < 0)
+                        return r;
 
-                printf("\n");
+                r = table_add_many(table,
+                                   TABLE_FIELD, "Sessions",
+                                   TABLE_STRV_WRAPPED, sessions);
+                if (r < 0)
+                        return table_log_add_error(r);
         }
 
-        printf("\t  Linger: %s\n", yes_no(i.linger));
+        r = table_add_many(table,
+                           TABLE_FIELD, "Linger",
+                           TABLE_BOOLEAN, i.linger);
+        if (r < 0)
+                return table_log_add_error(r);
 
         if (i.slice) {
-                printf("\t    Unit: %s\n", i.slice);
-                show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
-
-                show_journal_by_unit(
-                                stdout,
-                                i.slice,
-                                NULL,
-                                arg_output,
-                                0,
-                                i.timestamp.monotonic,
-                                arg_lines,
-                                0,
-                                get_output_flags() | OUTPUT_BEGIN_NEWLINE,
-                                SD_JOURNAL_LOCAL_ONLY,
-                                true,
-                                NULL);
+                r = table_add_many(table,
+                                   TABLE_FIELD, "Unit",
+                                   TABLE_STRING, i.slice);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
+
+        printf("%s%s (" UID_FMT ")%s\n", ansi_highlight(), i.name, i.uid, ansi_normal());
+
+        r = table_print(table, NULL);
+        if (r < 0)
+                return table_log_print_error(r);
+
+        if (i.slice) {
+                show_unit_cgroup(bus, i.slice, /* leader = */ 0, /* prefix = */ strrepa(" ", STRLEN("Sessions: ")));
+
+                if (arg_transport == BUS_TRANSPORT_LOCAL)
+                        show_journal_by_unit(
+                                        stdout,
+                                        i.slice,
+                                        NULL,
+                                        arg_output,
+                                        0,
+                                        i.timestamp.monotonic,
+                                        arg_lines,
+                                        0,
+                                        get_output_flags() | OUTPUT_BEGIN_NEWLINE,
+                                        SD_JOURNAL_LOCAL_ONLY,
+                                        true,
+                                        NULL);
         }
 
         return 0;
 }
 
-static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
+static int print_seat_status_info(sd_bus *bus, const char *path) {
 
         static const struct bus_properties_map map[] = {
                 { "Id",            "s",     NULL,                     offsetof(SeatStatusInfo, id)             },
@@ -702,44 +777,51 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line)
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_(seat_status_info_done) SeatStatusInfo i = {};
+        _cleanup_(table_unrefp) Table *table = NULL;
         int r;
 
         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, 0, &error, &m, &i);
         if (r < 0)
                 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
 
-        if (*new_line)
-                printf("\n");
-
-        *new_line = true;
-
-        printf("%s\n", strna(i.id));
+        table = table_new_vertical();
+        if (!table)
+                return log_oom();
 
         if (!strv_isempty(i.sessions)) {
-                printf("\tSessions:");
+                _cleanup_strv_free_ char **sessions = TAKE_PTR(i.sessions);
 
-                STRV_FOREACH(l, i.sessions) {
-                        if (streq_ptr(*l, i.active_session))
-                                printf(" *%s", *l);
-                        else
-                                printf(" %s", *l);
-                }
+                r = mark_session(sessions, i.active_session);
+                if (r < 0)
+                        return r;
 
-                printf("\n");
+                r = table_add_many(table,
+                                   TABLE_FIELD, "Sessions",
+                                   TABLE_STRV_WRAPPED, sessions);
+                if (r < 0)
+                        return table_log_add_error(r);
         }
 
         if (arg_transport == BUS_TRANSPORT_LOCAL) {
-                unsigned c;
+                r = table_add_many(table,
+                                   TABLE_FIELD, "Devices",
+                                   TABLE_EMPTY);
+                if (r < 0)
+                        return table_log_add_error(r);
+        }
+
+        printf("%s%s%s\n", ansi_highlight(), i.id, ansi_normal());
+
+        r = table_print(table, NULL);
+        if (r < 0)
+                return table_log_print_error(r);
 
-                c = columns();
+        if (arg_transport == BUS_TRANSPORT_LOCAL) {
+                unsigned c = columns();
                 if (c > 21)
                         c -= 21;
-                else
-                        c = 0;
 
-                printf("\t Devices:\n");
-
-                show_sysfs(i.id, "\t\t  ", c, get_output_flags());
+                show_sysfs(i.id, strrepa(" ", STRLEN("Sessions:")), c, get_output_flags());
         }
 
         return 0;
@@ -825,17 +907,11 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
         return 0;
 }
 
-static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
+static int show_properties(sd_bus *bus, const char *path) {
         int r;
 
         assert(bus);
         assert(path);
-        assert(new_line);
-
-        if (*new_line)
-                printf("\n");
-
-        *new_line = true;
 
         r = bus_print_all_properties(
                         bus,
@@ -851,12 +927,46 @@ static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
         return 0;
 }
 
+static int get_bus_path_by_id(
+                sd_bus *bus,
+                const char *type,
+                const char *method,
+                const char *id,
+                char **ret) {
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_free_ char *p = NULL;
+        const char *path;
+        int r;
+
+        assert(bus);
+        assert(type);
+        assert(STR_IN_SET(type, "session", "seat"));
+        assert(method);
+        assert(id);
+        assert(ret);
+
+        r = bus_call_method(bus, bus_login_mgr, method, &error, &reply, "s", id);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get path for %s '%s': %s", type, id, bus_error_message(&error, r));
+
+        r = sd_bus_message_read(reply, "o", &path);
+        if (r < 0)
+                return bus_log_parse_error(r);
+
+        p = strdup(path);
+        if (!p)
+                return log_oom();
+
+        *ret = TAKE_PTR(p);
+        return 0;
+}
+
 static int show_session(int argc, char *argv[], void *userdata) {
-        bool properties, new_line = false;
         sd_bus *bus = ASSERT_PTR(userdata);
+        bool properties;
         int r;
-        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        _cleanup_free_ char *path = NULL;
 
         assert(argv);
 
@@ -867,21 +977,25 @@ static int show_session(int argc, char *argv[], void *userdata) {
         if (argc <= 1) {
                 /* If no argument is specified inspect the manager itself */
                 if (properties)
-                        return show_properties(bus, "/org/freedesktop/login1", &new_line);
+                        return show_properties(bus, "/org/freedesktop/login1");
 
-                return print_session_status_info(bus, "/org/freedesktop/login1/session/auto", &new_line);
+                return print_session_status_info(bus, "/org/freedesktop/login1/session/auto");
         }
 
-        for (int i = 1; i < argc; i++) {
-                r = get_session_path(bus, argv[i], &error, &path);
+        for (int i = 1, first = true; i < argc; i++, first = false) {
+                _cleanup_free_ char *path = NULL;
+
+                r = get_bus_path_by_id(bus, "session", "GetSession", argv[i], &path);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to get session path: %s", bus_error_message(&error, r));
+                        return r;
+
+                if (!first)
+                        putchar('\n');
 
                 if (properties)
-                        r = show_properties(bus, path, &new_line);
+                        r = show_properties(bus, path);
                 else
-                        r = print_session_status_info(bus, path, &new_line);
-
+                        r = print_session_status_info(bus, path);
                 if (r < 0)
                         return r;
         }
@@ -890,8 +1004,8 @@ static int show_session(int argc, char *argv[], void *userdata) {
 }
 
 static int show_user(int argc, char *argv[], void *userdata) {
-        bool properties, new_line = false;
         sd_bus *bus = ASSERT_PTR(userdata);
+        bool properties;
         int r;
 
         assert(argv);
@@ -903,15 +1017,15 @@ static int show_user(int argc, char *argv[], void *userdata) {
         if (argc <= 1) {
                 /* If no argument is specified inspect the manager itself */
                 if (properties)
-                        return show_properties(bus, "/org/freedesktop/login1", &new_line);
+                        return show_properties(bus, "/org/freedesktop/login1");
 
-                return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
+                return print_user_status_info(bus, "/org/freedesktop/login1/user/self");
         }
 
-        for (int i = 1; i < argc; i++) {
+        for (int i = 1, first = true; i < argc; i++, first = false) {
                 _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 *path = NULL;
+                _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+                const char *path;
                 uid_t uid;
 
                 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
@@ -926,11 +1040,13 @@ static int show_user(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return bus_log_parse_error(r);
 
+                if (!first)
+                        putchar('\n');
+
                 if (properties)
-                        r = show_properties(bus, path, &new_line);
+                        r = show_properties(bus, path);
                 else
-                        r = print_user_status_info(bus, path, &new_line);
-
+                        r = print_user_status_info(bus, path);
                 if (r < 0)
                         return r;
         }
@@ -939,8 +1055,8 @@ static int show_user(int argc, char *argv[], void *userdata) {
 }
 
 static int show_seat(int argc, char *argv[], void *userdata) {
-        bool properties, new_line = false;
         sd_bus *bus = ASSERT_PTR(userdata);
+        bool properties;
         int r;
 
         assert(argv);
@@ -952,29 +1068,25 @@ static int show_seat(int argc, char *argv[], void *userdata) {
         if (argc <= 1) {
                 /* If no argument is specified inspect the manager itself */
                 if (properties)
-                        return show_properties(bus, "/org/freedesktop/login1", &new_line);
+                        return show_properties(bus, "/org/freedesktop/login1");
 
-                return print_seat_status_info(bus, "/org/freedesktop/login1/seat/auto", &new_line);
+                return print_seat_status_info(bus, "/org/freedesktop/login1/seat/auto");
         }
 
-        for (int i = 1; i < argc; i++) {
-                _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 *path = NULL;
+        for (int i = 1, first = true; i < argc; i++, first = false) {
+                _cleanup_free_ char *path = NULL;
 
-                r = bus_call_method(bus, bus_login_mgr, "GetSeat", &error, &reply, "s", argv[i]);
+                r = get_bus_path_by_id(bus, "seat", "GetSeat", argv[i], &path);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to get seat: %s", bus_error_message(&error, r));
+                        return r;
 
-                r = sd_bus_message_read(reply, "o", &path);
-                if (r < 0)
-                        return bus_log_parse_error(r);
+                if (!first)
+                        putchar('\n');
 
                 if (properties)
-                        r = show_properties(bus, path, &new_line);
+                        r = show_properties(bus, path);
                 else
-                        r = print_seat_status_info(bus, path, &new_line);
-
+                        r = print_seat_status_info(bus, path);
                 if (r < 0)
                         return r;
         }
index 679e835db5b15342304da74c07579bca20595bdc..20e1675d0decabc606e20ca5724c7ac15062fa7f 100644 (file)
@@ -1586,9 +1586,7 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas
                 else if (d->type == TABLE_TIMESTAMP_DATE)
                         ret = format_timestamp_style(p, FORMAT_TIMESTAMP_MAX, d->timestamp, TIMESTAMP_DATE);
                 else if (d->type == TABLE_TIMESTAMP_RELATIVE_MONOTONIC)
-                        ret = format_timestamp_relative_full(p, FORMAT_TIMESTAMP_RELATIVE_MAX,
-                                                             d->timestamp, CLOCK_MONOTONIC,
-                                                             /* implicit_left = */ false);
+                        ret = format_timestamp_relative_monotonic(p, FORMAT_TIMESTAMP_RELATIVE_MAX, d->timestamp);
                 else
                         ret = format_timestamp_relative_full(p, FORMAT_TIMESTAMP_RELATIVE_MAX,
                                                              d->timestamp, CLOCK_REALTIME,
index 9fb9a3e3768ef426745e2ab733c8ea8444b42a08..b620156c75be0558ad3062b44f810e8e0edee8aa 100644 (file)
@@ -30,23 +30,22 @@ int switch_root(const char *new_root,
                 const char *old_root_after,   /* path below the new root, where to place the old root after the transition; may be NULL to unmount it */
                 SwitchRootFlags flags) {
 
-        /* Stuff mounted below /run we don't save on soft reboot, as it might have lost its relevance, i.e.
-         * credentials, removable media and such, we rather want that the new boot mounts this fresh.
-         * But on the switch from initrd we do use MS_REC, as it is expected that mounts set up in /run
-         * are maintained. */
-        unsigned long run_mount_flags = MS_BIND|(!FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_RUN) ? MS_REC : 0);
-        struct {
+        /* Stuff mounted below /run/ we don't save on soft reboot, as it might have lost its relevance, i.e.
+         * credentials, removable media and such, we rather want that the new boot mounts this fresh.  But on
+         * the switch from initrd we do use MS_REC, as it is expected that mounts set up in /run/ are
+         * maintained. */
+        static const struct {
                 const char *path;
-                unsigned long mount_flags;
-                bool skip_if_run_is_rec; /* For child mounts of /run, if it's moved recursively no need to handle */
+                unsigned long mount_flags;                 /* Flags to apply if SWITCH_ROOT_RECURSIVE_RUN is unset */
+                unsigned long mount_flags_recursive_run;   /* Flags to apply if SWITCH_ROOT_RECURSIVE_RUN is set (0 if shall be skipped) */
         } transfer_table[] = {
-                { "/dev",                                 MS_BIND|MS_REC,  false }, /* Recursive, because we want to save the original /dev/shm + /dev/pts and similar */
-                { "/sys",                                 MS_BIND|MS_REC,  false }, /* Similar, we want to retain various API VFS, or the cgroupv1 /sys/fs/cgroup/ tree */
-                { "/proc",                                MS_BIND|MS_REC,  false }, /* Similar */
-                { "/run",                                 run_mount_flags, false }, /* Recursive except on soft reboot, see above */
-                { SYSTEM_CREDENTIALS_DIRECTORY,           MS_BIND,         true },  /* Credentials passed into the system should survive */
-                { ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND,         true },  /* Similar */
-                { "/run/host",                            MS_BIND|MS_REC,  true },  /* Host supplied hierarchy should also survive */
+                { "/dev",                                 MS_BIND|MS_REC,  MS_BIND|MS_REC }, /* Recursive, because we want to save the original /dev/shm/ + /dev/pts/ and similar */
+                { "/sys",                                 MS_BIND|MS_REC,  MS_BIND|MS_REC }, /* Similar, we want to retain various API VFS, or the cgroupv1 /sys/fs/cgroup/ tree */
+                { "/proc",                                MS_BIND|MS_REC,  MS_BIND|MS_REC }, /* Similar */
+                { "/run",                                 MS_BIND,         MS_BIND|MS_REC }, /* Recursive except on soft reboot, see above */
+                { SYSTEM_CREDENTIALS_DIRECTORY,           MS_BIND,         0 /* skip! */  }, /* Credentials passed into the system should survive */
+                { ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY, MS_BIND,         0 /* skip! */  },  /* Similar */
+                { "/run/host",                            MS_BIND|MS_REC,  0 /* skip! */  },  /* Host supplied hierarchy should also survive */
         };
 
         _cleanup_close_ int old_root_fd = -EBADF, new_root_fd = -EBADF;
@@ -129,8 +128,10 @@ int switch_root(const char *new_root,
 
         FOREACH_ARRAY(transfer, transfer_table, ELEMENTSOF(transfer_table)) {
                 _cleanup_free_ char *chased = NULL;
+                unsigned long mount_flags;
 
-                if (transfer->skip_if_run_is_rec && !FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_RUN))
+                mount_flags = FLAGS_SET(flags, SWITCH_ROOT_RECURSIVE_RUN) ? transfer->mount_flags_recursive_run : transfer->mount_flags;
+                if (mount_flags == 0) /* skip if zero */
                         continue;
 
                 if (access(transfer->path, F_OK) < 0) {
@@ -149,7 +150,7 @@ int switch_root(const char *new_root,
                 if (r > 0) /* If it is already mounted, then do nothing */
                         continue;
 
-                r = mount_nofollow_verbose(LOG_ERR, transfer->path, chased, NULL, transfer->mount_flags, NULL);
+                r = mount_nofollow_verbose(LOG_ERR, transfer->path, chased, NULL, mount_flags, NULL);
                 if (r < 0)
                         return r;
         }
@@ -172,14 +173,19 @@ int switch_root(const char *new_root,
         if (r < 0) {
                 log_debug_errno(r, "Pivoting root file system failed, moving mounts instead: %m");
 
+                if (resolved_old_root_after) {
+                        r = mount_nofollow_verbose(LOG_ERR, "/", resolved_old_root_after, NULL, MS_BIND|MS_REC, NULL);
+                        if (r < 0)
+                                return r;
+                }
+
                 /* If we have to use MS_MOVE let's first try to get rid of *all* mounts we can, with the
                  * exception of the path we want to switch to, plus everything leading to it and within
                  * it. This is necessary because unlike pivot_root() just moving the mount to the root via
                  * MS_MOVE won't magically unmount anything below it. Once the chroot() succeeds the mounts
                  * below would still be around but invisible to us, because not accessible via
                  * /proc/self/mountinfo. Hence, let's clean everything up first, as long as we still can. */
-                if (!FLAGS_SET(flags, SWITCH_ROOT_SKIP_RECURSIVE_UMOUNT))
-                        (void) umount_recursive_full(NULL, MNT_DETACH, STRV_MAKE(new_root));
+                (void) umount_recursive_full(NULL, MNT_DETACH, STRV_MAKE(new_root));
 
                 if (mount(".", "/", NULL, MS_MOVE, NULL) < 0)
                         return log_error_errno(errno, "Failed to move %s to /: %m", new_root);
index 20561fcee8bdd9b4c61757de952b1b49f5cb7c0b..ba0d280eba4ec9f28e926a7e04f0038ba5d29e37 100644 (file)
@@ -7,8 +7,7 @@ typedef enum SwitchRootFlags {
         SWITCH_ROOT_DESTROY_OLD_ROOT      = 1 << 0, /* rm -rf old root when switching – under the condition
                                                      * that it is backed by non-persistent tmpfs/ramfs/… */
         SWITCH_ROOT_DONT_SYNC             = 1 << 1, /* don't call sync() immediately before switching root */
-        SWITCH_ROOT_SKIP_RECURSIVE_RUN    = 1 << 2, /* move /run without MS_REC */
-        SWITCH_ROOT_SKIP_RECURSIVE_UMOUNT = 1 << 3, /* do not umount recursively on move */
+        SWITCH_ROOT_RECURSIVE_RUN         = 1 << 2, /* move /run/ with MS_REC from old to new root */
 } SwitchRootFlags;
 
 int switch_root(const char *new_root, const char *old_root_after, SwitchRootFlags flags);
index 263c444ac20d6698008eae35a274401744e7b931..b976b7d8cf60d299cc96d4a8192dddfc62003f34 100644 (file)
@@ -169,13 +169,11 @@ static int switch_root_initramfs(void) {
          * Disable sync() during switch-root, we after all sync'ed here plenty, and a dumb sync (as opposed
          * to the "smart" sync() we did here that looks at progress parameters) would defeat much of our
          * efforts here. As the new root will be /run/initramfs/, it is not necessary to mount /run/
-         * recursively. Also, do not umount filesystems before MS_MOVE, as that should be done by ourself. */
+         * recursively. */
         return switch_root(
                         /* new_root= */ "/run/initramfs",
                         /* old_root_after= */ "/oldroot",
-                        /* flags= */ SWITCH_ROOT_DONT_SYNC |
-                                     SWITCH_ROOT_SKIP_RECURSIVE_RUN |
-                                     SWITCH_ROOT_SKIP_RECURSIVE_UMOUNT);
+                        /* flags= */ SWITCH_ROOT_DONT_SYNC);
 }
 
 /* Read the following fields from /proc/meminfo:
index b59ea701c91cfbe6a9451d7a4546de5bf15651f8..ae4a1a72c2b56dd5e29beda3f0053723298e21bb 100644 (file)
@@ -4,6 +4,8 @@
 #include "bus-error.h"
 #include "bus-locator.h"
 #include "chase.h"
+#include "fd-util.h"
+#include "initrd-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
@@ -47,15 +49,24 @@ int verb_switch_root(int argc, char *argv[], void *userdata) {
 
         if (argc >= 2) {
                 root = argv[1];
+
                 if (!path_is_valid(root))
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid root path: %s", root);
+
                 if (!path_is_absolute(root))
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Root path is not absolute: %s", root);
-                if (path_equal(root, "/"))
+
+                r = path_is_root(root);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to check if switch-root directory '%s' is current root: %m", root);
+                if (r > 0)
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot switch to current root directory: %s", root);
         } else
                 root = "/sysroot";
 
+        if (!in_initrd())
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not in initrd, refusing switch-root operation.");
+
         if (argc >= 3)
                 init = argv[2];
         else {
index b5f0008d76bef481b49198af55205965f2c8ec46..a8fd45df733e77aed6d42e46a971e725c11fb53c 100644 (file)
@@ -260,6 +260,8 @@ TEST(strextend_with_separator) {
 
 TEST(strrep) {
         _cleanup_free_ char *one = NULL, *three = NULL, *zero = NULL;
+        char *onea, *threea;
+
         one = strrep("waldo", 1);
         three = strrep("waldo", 3);
         zero = strrep("waldo", 0);
@@ -267,6 +269,12 @@ TEST(strrep) {
         assert_se(streq(one, "waldo"));
         assert_se(streq(three, "waldowaldowaldo"));
         assert_se(streq(zero, ""));
+
+        onea = strrepa("waldo", 1);
+        threea = strrepa("waldo", 3);
+
+        assert_se(streq(onea, "waldo"));
+        assert_se(streq(threea, "waldowaldowaldo"));
 }
 
 TEST(string_has_cc) {