From 2ff40c758ed6f5bf802748ffd71487d912a961e8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Wed, 19 Mar 2025 17:05:20 +0100 Subject: [PATCH] update-done: add --root= arg MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The idea is to use this when building an image to mark the image as not needing updates after the reboot. In general it is impossible to say if any of the early boot update services can be safely skipped, except when the creator of the image knows all the contents there and has made sure that all the updates have been processed. (This is in fact what happens in a typical package-based installation: the packages have scriptlets which implement the changes during or after the installation process.) With this patch, the image build process can do 'systemd-update-done --root=…' at the appropriate point to avoid triggering of ldconfig.service, systemd-hwdb-update.service, etc. I didn't write --image=, because it doesn't seem immediately useful. The approach with --root is most useful when we're building the image "offline", which means that we have a directory we're working on. --- man/systemd-update-done.service.xml | 9 +++++ src/update-done/update-done.c | 54 +++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/man/systemd-update-done.service.xml b/man/systemd-update-done.service.xml index 2db2e407b6f..d9d78262a14 100644 --- a/man/systemd-update-done.service.xml +++ b/man/systemd-update-done.service.xml @@ -69,6 +69,15 @@ The following options are understood: + + + Takes a directory path as an argument. The program + will operate on paths below the specified root directory. + + + + + diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index f9c8ec4f429..b30bb2dbf0b 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -6,15 +6,23 @@ #include #include "alloc-util.h" +#include "chase.h" +#include "fd-util.h" #include "fileio.h" #include "main-func.h" +#include "parse-argument.h" #include "path-util.h" #include "pretty-print.h" #include "selinux-util.h" #include "time-util.h" +static char *arg_root = NULL; + +STATIC_DESTRUCTOR_REGISTER(arg_root, freep); + static int save_timestamp(const char *dir, struct timespec *ts) { - _cleanup_free_ char *message = NULL, *path = NULL; + _cleanup_free_ char *message = NULL, *dirpath = NULL; + _cleanup_close_ int fd = -EBADF; int r; /* @@ -22,9 +30,12 @@ static int save_timestamp(const char *dir, struct timespec *ts) { * to support filesystems which cannot store nanosecond-precision timestamps. */ - path = path_join(dir, ".updated"); - if (!path) - return log_oom(); + fd = chase_and_open(dir, arg_root, + CHASE_PREFIX_ROOT | CHASE_WARN | CHASE_MUST_BE_DIRECTORY, + O_DIRECTORY | O_CLOEXEC, + &dirpath); + if (fd < 0) + return log_error_errno(fd, "Failed to open %s%s: %m", strempty(arg_root), dir); if (asprintf(&message, "# This file was created by systemd-update-done. The timestamp below is the\n" @@ -35,11 +46,16 @@ static int save_timestamp(const char *dir, struct timespec *ts) { timespec_load_nsec(ts)) < 0) return log_oom(); - r = write_string_file_full(AT_FDCWD, path, message, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL, ts, NULL); - if (r == -EROFS) - log_debug_errno(r, "Cannot create \"%s\", file system is read-only.", path); + r = write_string_file_full(fd, ".updated", message, + WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL, + ts, NULL); + if (r == -EROFS && !arg_root) + log_debug_errno(r, "Cannot create \"%s/.updated\", file system is read-only.", dirpath); else if (r < 0) - return log_error_errno(r, "Failed to write \"%s\": %m", path); + return log_error_errno(r, "Failed to write \"%s/.updated\": %m", dirpath); + else + log_debug("%s/.updated updated to TIMESTAMP_NSEC="NSEC_FMT, dirpath, timespec_load_nsec(ts)); + return 0; } @@ -55,6 +71,7 @@ static int help(void) { "%5$sMark /etc/ and /var/ as fully updated.%6$s\n" "\n%3$sOptions:%4$s\n" " -h --help Show this help\n" + " --root=PATH Operate on root directory PATH\n" "\nSee the %2$s for details.\n", program_invocation_short_name, link, @@ -67,12 +84,17 @@ static int help(void) { } static int parse_argv(int argc, char *argv[]) { + enum { + ARG_ROOT = 0x100, + }; + static const struct option options[] = { { "help", no_argument, NULL, 'h' }, + { "root", required_argument, NULL, ARG_ROOT }, {}, }; - int c; + int r, c; assert(argc >= 0); assert(argv); @@ -84,6 +106,12 @@ static int parse_argv(int argc, char *argv[]) { case 'h': return help(); + case ARG_ROOT: + r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_root); + if (r < 0) + return r; + break; + case '?': return -EINVAL; @@ -108,8 +136,12 @@ static int run(int argc, char *argv[]) { log_setup(); - if (stat("/usr", &st) < 0) - return log_error_errno(errno, "Failed to stat /usr: %m"); + r = chase_and_stat("/usr", arg_root, + CHASE_PREFIX_ROOT | CHASE_WARN | CHASE_MUST_BE_DIRECTORY, + /* ret_path = */ NULL, + &st); + if (r < 0) + return log_error_errno(r, "Failed to stat %s/usr/: %m", strempty(arg_root)); r = mac_init(); if (r < 0) -- 2.47.3