]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/update-done/update-done.c
Fixes for vscode/intellisense parsing (#38040)
[thirdparty/systemd.git] / src / update-done / update-done.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
8ea48dfc 2
20f7f0a8 3#include <getopt.h>
ca78ad1d 4#include <sys/stat.h>
ca78ad1d 5
5a1d6763 6#include "alloc-util.h"
2ff40c75 7#include "chase.h"
fda65211 8#include "errno-util.h"
2ff40c75 9#include "fd-util.h"
8eeb8709 10#include "fileio.h"
8857aa74 11#include "label-util.h"
93a1f792 12#include "log.h"
bca9a6e2 13#include "main-func.h"
2ff40c75 14#include "parse-argument.h"
20f7f0a8 15#include "pretty-print.h"
8857aa74 16#include "string-util.h"
ca78ad1d 17#include "time-util.h"
8ea48dfc 18
2ff40c75
ZJS
19static char *arg_root = NULL;
20
21STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
22
04db1a6a 23static int save_timestamp(const char *dir, struct timespec *ts) {
2ff40c75
ZJS
24 _cleanup_free_ char *message = NULL, *dirpath = NULL;
25 _cleanup_close_ int fd = -EBADF;
fb8b0869 26 int r;
8ea48dfc 27
fb8b0869
IS
28 /*
29 * We store the timestamp both as mtime of the file and in the file itself,
30 * to support filesystems which cannot store nanosecond-precision timestamps.
fb8b0869 31 */
8ea48dfc 32
2ff40c75
ZJS
33 fd = chase_and_open(dir, arg_root,
34 CHASE_PREFIX_ROOT | CHASE_WARN | CHASE_MUST_BE_DIRECTORY,
ace814f0 35 O_DIRECTORY | O_CLOEXEC | O_CREAT,
2ff40c75
ZJS
36 &dirpath);
37 if (fd < 0)
38 return log_error_errno(fd, "Failed to open %s%s: %m", strempty(arg_root), dir);
04db1a6a 39
872c4039 40 if (asprintf(&message,
04db1a6a
ZJS
41 "# This file was created by systemd-update-done. The timestamp below is the\n"
42 "# modification time of /usr/ for which the most recent updates of %s have\n"
43 "# been applied. See man:systemd-update-done.service(8) for details.\n"
872c4039 44 "TIMESTAMP_NSEC=" NSEC_FMT "\n",
04db1a6a 45 dir,
872c4039
ZJS
46 timespec_load_nsec(ts)) < 0)
47 return log_oom();
8ea48dfc 48
2ff40c75
ZJS
49 r = write_string_file_full(fd, ".updated", message,
50 WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC|WRITE_STRING_FILE_LABEL,
51 ts, NULL);
52 if (r == -EROFS && !arg_root)
53 log_debug_errno(r, "Cannot create \"%s/.updated\", file system is read-only.", dirpath);
1eee15c3 54 else if (r < 0)
2ff40c75
ZJS
55 return log_error_errno(r, "Failed to write \"%s/.updated\": %m", dirpath);
56 else
57 log_debug("%s/.updated updated to TIMESTAMP_NSEC="NSEC_FMT, dirpath, timespec_load_nsec(ts));
58
8ea48dfc
LP
59 return 0;
60}
61
20f7f0a8
ZJS
62static int help(void) {
63 _cleanup_free_ char *link = NULL;
64 int r;
65
66 r = terminal_urlify_man("systemd-update-done", "8", &link);
67 if (r < 0)
68 return log_oom();
69
70 printf("%1$s [OPTIONS...]\n\n"
71 "%5$sMark /etc/ and /var/ as fully updated.%6$s\n"
72 "\n%3$sOptions:%4$s\n"
73 " -h --help Show this help\n"
2ff40c75 74 " --root=PATH Operate on root directory PATH\n"
20f7f0a8
ZJS
75 "\nSee the %2$s for details.\n",
76 program_invocation_short_name,
77 link,
78 ansi_underline(),
79 ansi_normal(),
80 ansi_highlight(),
81 ansi_normal());
82
83 return 0;
84}
85
86static int parse_argv(int argc, char *argv[]) {
2ff40c75
ZJS
87 enum {
88 ARG_ROOT = 0x100,
89 };
90
20f7f0a8
ZJS
91 static const struct option options[] = {
92 { "help", no_argument, NULL, 'h' },
2ff40c75 93 { "root", required_argument, NULL, ARG_ROOT },
20f7f0a8
ZJS
94 {},
95 };
96
2ff40c75 97 int r, c;
20f7f0a8
ZJS
98
99 assert(argc >= 0);
100 assert(argv);
101
102 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
103
104 switch (c) {
105
106 case 'h':
107 return help();
108
2ff40c75
ZJS
109 case ARG_ROOT:
110 r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_root);
111 if (r < 0)
112 return r;
113 break;
114
20f7f0a8
ZJS
115 case '?':
116 return -EINVAL;
117
118 default:
119 assert_not_reached();
120 }
121
122 if (optind < argc)
123 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program takes no arguments.");
124
125 return 1;
126}
127
128
bca9a6e2 129static int run(int argc, char *argv[]) {
8ea48dfc 130 struct stat st;
bca9a6e2 131 int r;
8ea48dfc 132
20f7f0a8
ZJS
133 r = parse_argv(argc, argv);
134 if (r <= 0)
135 return r;
136
d2acb93d 137 log_setup();
8ea48dfc 138
2ff40c75
ZJS
139 r = chase_and_stat("/usr", arg_root,
140 CHASE_PREFIX_ROOT | CHASE_WARN | CHASE_MUST_BE_DIRECTORY,
141 /* ret_path = */ NULL,
142 &st);
143 if (r < 0)
144 return log_error_errno(r, "Failed to stat %s/usr/: %m", strempty(arg_root));
8ea48dfc 145
a452c807 146 r = mac_init();
a9ba0e32 147 if (r < 0)
bca9a6e2 148 return r;
8ea48dfc 149
bca9a6e2
ZJS
150 r = 0;
151 RET_GATHER(r, save_timestamp("/etc/", &st.st_mtim));
152 RET_GATHER(r, save_timestamp("/var/", &st.st_mtim));
153 return r;
8ea48dfc 154}
bca9a6e2
ZJS
155
156DEFINE_MAIN_FUNCTION(run);