]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/timedate/timedatectl.c
core: dont't remount /sys/fs/cgroup for relabel if not needed (#8595)
[thirdparty/systemd.git] / src / timedate / timedatectl.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
6d0274f1
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2012 Lennart Poettering
2f6a5907 6 Copyright 2013 Kay Sievers
6d0274f1
LP
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
6d0274f1 22#include <getopt.h>
a9cdc94f 23#include <locale.h>
3f6fd1ba
LP
24#include <stdbool.h>
25#include <stdlib.h>
6d0274f1 26
a281d9c7 27#include "sd-bus.h"
3f6fd1ba 28
a281d9c7 29#include "bus-error.h"
3f6fd1ba
LP
30#include "bus-util.h"
31#include "pager.h"
6bedfcbb 32#include "parse-util.h"
6d0274f1 33#include "spawn-polkit-agent.h"
6d0274f1 34#include "strv.h"
288a74cc 35#include "terminal-util.h"
3f6fd1ba 36#include "util.h"
be90a886 37#include "verbs.h"
6d0274f1 38
6d0274f1 39static bool arg_no_pager = false;
6d0274f1 40static bool arg_ask_password = true;
e1636421 41static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
7085053a 42static char *arg_host = NULL;
e1636421 43static bool arg_adjust_system_clock = false;
6d0274f1 44
6d0274f1 45typedef struct StatusInfo {
2f6a5907 46 usec_t time;
f37f8a61 47 const char *timezone;
2f6a5907
KS
48
49 usec_t rtc_time;
f37f8a61 50 bool rtc_local;
2f6a5907 51
f37f8a61
YW
52 bool ntp_enabled;
53 bool ntp_capable;
54 bool ntp_synced;
6d0274f1
LP
55} StatusInfo;
56
ffc06c35 57static void print_status_info(const StatusInfo *i) {
14ce0c25 58 char a[LINE_MAX];
6d0274f1
LP
59 struct tm tm;
60 time_t sec;
9ff09bcb 61 bool have_time = false;
d95a74ed 62 const char *old_tz = NULL, *tz;
6d0274f1 63 int r;
14ce0c25 64 size_t n;
6d0274f1 65
59965986
LP
66 assert(i);
67
d95a74ed
LP
68 /* Save the old $TZ */
69 tz = getenv("TZ");
70 if (tz)
71 old_tz = strdupa(tz);
2311eb2f 72
d95a74ed 73 /* Set the new $TZ */
bdeb9e60 74 if (setenv("TZ", isempty(i->timezone) ? "UTC" : i->timezone, true) < 0)
d95a74ed
LP
75 log_warning_errno(errno, "Failed to set TZ environment variable, ignoring: %m");
76 else
77 tzset();
3e5e74d5 78
9ff09bcb
SL
79 if (i->time != 0) {
80 sec = (time_t) (i->time / USEC_PER_SEC);
81 have_time = true;
d95a74ed 82 } else if (IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE)) {
9ff09bcb
SL
83 sec = time(NULL);
84 have_time = true;
85 } else
d95a74ed 86 log_warning("Could not get time from timedated and not operating locally, ignoring.");
6d0274f1 87
9ff09bcb 88 if (have_time) {
14ce0c25
ZJS
89 n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm));
90 printf(" Local time: %s\n", n > 0 ? a : "n/a");
5ffa8c81 91
14ce0c25
ZJS
92 n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm));
93 printf(" Universal time: %s\n", n > 0 ? a : "n/a");
9ff09bcb 94 } else {
3ec530a1
ZJS
95 printf(" Local time: %s\n", "n/a");
96 printf(" Universal time: %s\n", "n/a");
9ff09bcb 97 }
6d0274f1 98
2f6a5907
KS
99 if (i->rtc_time > 0) {
100 time_t rtc_sec;
6d0274f1 101
d95a74ed 102 rtc_sec = (time_t) (i->rtc_time / USEC_PER_SEC);
14ce0c25
ZJS
103 n = strftime(a, sizeof a, "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm));
104 printf(" RTC time: %s\n", n > 0 ? a : "n/a");
2f6a5907 105 } else
3ec530a1 106 printf(" RTC time: %s\n", "n/a");
6d0274f1 107
5ffa8c81 108 if (have_time)
14ce0c25 109 n = strftime(a, sizeof a, "%Z, %z", localtime_r(&sec, &tm));
2667cc25 110
d95a74ed
LP
111 /* Restore the $TZ */
112 if (old_tz)
113 r = setenv("TZ", old_tz, true);
114 else
115 r = unsetenv("TZ");
116 if (r < 0)
117 log_warning_errno(errno, "Failed to set TZ environment variable, ignoring: %m");
118 else
119 tzset();
120
14ce0c25 121 printf(" Time zone: %s (%s)\n"
3ec530a1
ZJS
122 " System clock synchronized: %s\n"
123 "systemd-timesyncd.service active: %s\n"
124 " RTC in local TZ: %s\n",
14ce0c25 125 strna(i->timezone), have_time && n > 0 ? a : "n/a",
2f6a5907 126 yes_no(i->ntp_synced),
a5198615 127 i->ntp_capable ? yes_no(i->ntp_enabled) : "n/a",
2f6a5907 128 yes_no(i->rtc_local));
6d0274f1 129
2f6a5907 130 if (i->rtc_local)
54f8c958
LP
131 printf("\n%s"
132 "Warning: The system is configured to read the RTC time in the local time zone.\n"
87ac8d99 133 " This mode cannot be fully supported. It will create various problems\n"
54f8c958
LP
134 " with time zone changes and daylight saving time adjustments. The RTC\n"
135 " time is never updated, it relies on external facilities to maintain it.\n"
136 " If at all possible, use RTC in UTC by calling\n"
137 " 'timedatectl set-local-rtc 0'.%s\n", ansi_highlight(), ansi_normal());
6d0274f1
LP
138}
139
be90a886 140static int show_status(int argc, char **argv, void *userdata) {
f37f8a61 141 StatusInfo info = {};
9f6eb1cd
KS
142 static const struct bus_properties_map map[] = {
143 { "Timezone", "s", NULL, offsetof(StatusInfo, timezone) },
144 { "LocalRTC", "b", NULL, offsetof(StatusInfo, rtc_local) },
145 { "NTP", "b", NULL, offsetof(StatusInfo, ntp_enabled) },
146 { "CanNTP", "b", NULL, offsetof(StatusInfo, ntp_capable) },
147 { "NTPSynchronized", "b", NULL, offsetof(StatusInfo, ntp_synced) },
148 { "TimeUSec", "t", NULL, offsetof(StatusInfo, time) },
149 { "RTCTimeUSec", "t", NULL, offsetof(StatusInfo, rtc_time) },
ffc06c35
KS
150 {}
151 };
f9e0eefc
LP
152
153 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f37f8a61 154 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
be90a886 155 sd_bus *bus = userdata;
ffc06c35 156 int r;
6d0274f1 157
a281d9c7 158 assert(bus);
6d0274f1 159
ffc06c35
KS
160 r = bus_map_all_properties(bus,
161 "org.freedesktop.timedate1",
162 "/org/freedesktop/timedate1",
9f6eb1cd 163 map,
f9e0eefc 164 &error,
f37f8a61 165 &m,
9f6eb1cd 166 &info);
e7e55dbd 167 if (r < 0)
f9e0eefc 168 return log_error_errno(r, "Failed to query server: %s", bus_error_message(&error, r));
6d0274f1
LP
169
170 print_status_info(&info);
ffc06c35 171
ffc06c35 172 return r;
6d0274f1
LP
173}
174
be90a886 175static int set_time(int argc, char **argv, void *userdata) {
4afd3348 176 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
a281d9c7 177 bool relative = false, interactive = arg_ask_password;
be90a886 178 sd_bus *bus = userdata;
6d0274f1 179 usec_t t;
6d0274f1
LP
180 int r;
181
8a4b13c5 182 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
6d0274f1 183
be90a886
YW
184 r = parse_timestamp(argv[1], &t);
185 if (r < 0)
186 return log_error_errno(r, "Failed to parse time specification '%s': %m", argv[1]);
6d0274f1 187
a281d9c7
TA
188 r = sd_bus_call_method(bus,
189 "org.freedesktop.timedate1",
190 "/org/freedesktop/timedate1",
191 "org.freedesktop.timedate1",
192 "SetTime",
193 &error,
194 NULL,
be90a886 195 "xbb", (int64_t) t, relative, interactive);
a281d9c7 196 if (r < 0)
be90a886 197 log_error("Failed to set time: %s", bus_error_message(&error, r));
a281d9c7
TA
198
199 return r;
6d0274f1
LP
200}
201
be90a886 202static int set_timezone(int argc, char **argv, void *userdata) {
4afd3348 203 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
be90a886 204 sd_bus *bus = userdata;
a281d9c7 205 int r;
6d0274f1 206
8a4b13c5 207 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
6d0274f1 208
a281d9c7
TA
209 r = sd_bus_call_method(bus,
210 "org.freedesktop.timedate1",
211 "/org/freedesktop/timedate1",
212 "org.freedesktop.timedate1",
213 "SetTimezone",
214 &error,
215 NULL,
be90a886 216 "sb", argv[1], arg_ask_password);
a281d9c7 217 if (r < 0)
be90a886 218 log_error("Failed to set time zone: %s", bus_error_message(&error, r));
a281d9c7
TA
219
220 return r;
6d0274f1
LP
221}
222
be90a886 223static int set_local_rtc(int argc, char **argv, void *userdata) {
4afd3348 224 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
be90a886 225 sd_bus *bus = userdata;
e5609878 226 int r, b;
6d0274f1 227
8a4b13c5 228 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
6d0274f1 229
be90a886
YW
230 b = parse_boolean(argv[1]);
231 if (b < 0)
232 return log_error_errno(b, "Failed to parse local RTC setting '%s': %m", argv[1]);
6d0274f1 233
a281d9c7
TA
234 r = sd_bus_call_method(bus,
235 "org.freedesktop.timedate1",
236 "/org/freedesktop/timedate1",
237 "org.freedesktop.timedate1",
238 "SetLocalRTC",
239 &error,
240 NULL,
e5609878 241 "bbb", b, arg_adjust_system_clock, arg_ask_password);
a281d9c7 242 if (r < 0)
be90a886 243 log_error("Failed to set local RTC: %s", bus_error_message(&error, r));
a281d9c7
TA
244
245 return r;
6d0274f1
LP
246}
247
be90a886 248static int set_ntp(int argc, char **argv, void *userdata) {
4afd3348 249 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
be90a886 250 sd_bus *bus = userdata;
e5609878 251 int b, r;
6d0274f1 252
8a4b13c5 253 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
6d0274f1 254
be90a886
YW
255 b = parse_boolean(argv[1]);
256 if (b < 0)
257 return log_error_errno(b, "Failed to parse NTP setting '%s': %m", argv[1]);
6d0274f1 258
a281d9c7
TA
259 r = sd_bus_call_method(bus,
260 "org.freedesktop.timedate1",
261 "/org/freedesktop/timedate1",
262 "org.freedesktop.timedate1",
263 "SetNTP",
264 &error,
265 NULL,
e5609878 266 "bb", b, arg_ask_password);
a281d9c7 267 if (r < 0)
be90a886 268 log_error("Failed to set ntp: %s", bus_error_message(&error, r));
a281d9c7
TA
269
270 return r;
6d0274f1
LP
271}
272
be90a886 273static int list_timezones(int argc, char **argv, void *userdata) {
6d0274f1 274 _cleanup_strv_free_ char **zones = NULL;
75683450 275 int r;
6d0274f1 276
75683450 277 r = get_timezones(&zones);
f647962d
MS
278 if (r < 0)
279 return log_error_errno(r, "Failed to read list of time zones: %m");
6d0274f1 280
ee5324aa 281 (void) pager_open(arg_no_pager, false);
7c2d8094 282 strv_print(zones);
6d0274f1
LP
283
284 return 0;
285}
286
be90a886 287static int help(void) {
7591abd4
LP
288 printf("%s [OPTIONS...] COMMAND ...\n\n"
289 "Query or change system time and date settings.\n\n"
07a062a7 290 " -h --help Show this help message\n"
4f8f66cb
ZJS
291 " --version Show package version\n"
292 " --no-pager Do not pipe output into a pager\n"
293 " --no-ask-password Do not prompt for password\n"
294 " -H --host=[USER@]HOST Operate on remote host\n"
295 " -M --machine=CONTAINER Operate on local container\n"
296 " --adjust-system-clock Adjust system clock when changing local RTC mode\n\n"
6d0274f1 297 "Commands:\n"
4f8f66cb
ZJS
298 " status Show current time settings\n"
299 " set-time TIME Set system time\n"
07a062a7
JSJ
300 " set-timezone ZONE Set system time zone\n"
301 " list-timezones Show known time zones\n"
4f8f66cb 302 " set-local-rtc BOOL Control whether RTC is in local time\n"
3906ab4a 303 " set-ntp BOOL Enable or disable network time synchronization\n",
6d0274f1 304 program_invocation_short_name);
be90a886
YW
305
306 return 0;
307}
308
309static int verb_help(int argc, char **argv, void *userdata) {
310 return help();
6d0274f1
LP
311}
312
313static int parse_argv(int argc, char *argv[]) {
314
315 enum {
316 ARG_VERSION = 0x100,
317 ARG_NO_PAGER,
c9783430 318 ARG_ADJUST_SYSTEM_CLOCK,
6d0274f1
LP
319 ARG_NO_ASK_PASSWORD
320 };
321
322 static const struct option options[] = {
c9783430
LP
323 { "help", no_argument, NULL, 'h' },
324 { "version", no_argument, NULL, ARG_VERSION },
325 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
326 { "host", required_argument, NULL, 'H' },
a281d9c7 327 { "machine", required_argument, NULL, 'M' },
c9783430
LP
328 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
329 { "adjust-system-clock", no_argument, NULL, ARG_ADJUST_SYSTEM_CLOCK },
eb9da376 330 {}
6d0274f1
LP
331 };
332
333 int c;
334
335 assert(argc >= 0);
336 assert(argv);
337
601185b4 338 while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
6d0274f1
LP
339
340 switch (c) {
341
342 case 'h':
be90a886 343 return help();
6d0274f1
LP
344
345 case ARG_VERSION:
3f6fd1ba 346 return version();
6d0274f1 347
a281d9c7
TA
348 case 'H':
349 arg_transport = BUS_TRANSPORT_REMOTE;
350 arg_host = optarg;
6d0274f1
LP
351 break;
352
a281d9c7 353 case 'M':
de33fc62 354 arg_transport = BUS_TRANSPORT_MACHINE;
a281d9c7 355 arg_host = optarg;
6d0274f1
LP
356 break;
357
546158bc
JJ
358 case ARG_NO_ASK_PASSWORD:
359 arg_ask_password = false;
360 break;
361
c9783430
LP
362 case ARG_ADJUST_SYSTEM_CLOCK:
363 arg_adjust_system_clock = true;
6d0274f1
LP
364 break;
365
366 case ARG_NO_PAGER:
367 arg_no_pager = true;
368 break;
369
370 case '?':
371 return -EINVAL;
372
373 default:
eb9da376 374 assert_not_reached("Unhandled option");
6d0274f1 375 }
6d0274f1
LP
376
377 return 1;
378}
379
a281d9c7 380static int timedatectl_main(sd_bus *bus, int argc, char *argv[]) {
6d0274f1 381
be90a886
YW
382 static const Verb verbs[] = {
383 { "status", VERB_ANY, 1, VERB_DEFAULT, show_status },
384 { "set-time", 2, 2, 0, set_time },
385 { "set-timezone", 2, 2, 0, set_timezone },
386 { "list-timezones", VERB_ANY, 1, 0, list_timezones },
387 { "set-local-rtc", 2, 2, 0, set_local_rtc },
388 { "set-ntp", 2, 2, 0, set_ntp },
389 { "help", VERB_ANY, VERB_ANY, 0, verb_help }, /* Not documented, but supported since it is created. */
390 {}
6d0274f1
LP
391 };
392
be90a886 393 return dispatch_verb(argc, argv, verbs, bus);
6d0274f1
LP
394}
395
396int main(int argc, char *argv[]) {
a3c56345 397 sd_bus *bus = NULL;
84f6181c 398 int r;
6d0274f1 399
a9cdc94f 400 setlocale(LC_ALL, "");
6d0274f1
LP
401 log_parse_environment();
402 log_open();
403
404 r = parse_argv(argc, argv);
84f6181c 405 if (r <= 0)
6d0274f1 406 goto finish;
6d0274f1 407
266f3e26 408 r = bus_connect_transport(arg_transport, arg_host, false, &bus);
a281d9c7 409 if (r < 0) {
da927ba9 410 log_error_errno(r, "Failed to create bus connection: %m");
a281d9c7 411 goto finish;
6d0274f1
LP
412 }
413
a281d9c7 414 r = timedatectl_main(bus, argc, argv);
6d0274f1 415
a281d9c7 416finish:
0a84daa5
FB
417 /* make sure we terminate the bus connection first, and then close the
418 * pager, see issue #3543 for the details. */
a3c56345 419 sd_bus_flush_close_unref(bus);
6d0274f1
LP
420 pager_close();
421
84f6181c 422 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
6d0274f1 423}