timedatectl.c revision 2f6a59070559786428d9eaf199ae3d61772b2225
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen This file is part of systemd.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Copyright 2012 Lennart Poettering
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Copyright 2013 Kay Sievers
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen systemd is free software; you can redistribute it and/or modify it
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen under the terms of the GNU Lesser General Public License as published by
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen (at your option) any later version.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen systemd is distributed in the hope that it will be useful, but
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen Lesser General Public License for more details.
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen You should have received a copy of the GNU Lesser General Public License
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersenstatic bool arg_adjust_system_clock = false;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenstatic bool arg_no_pager = false;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersenstatic bool arg_ask_password = true;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersenstatic void pager_open_if_enabled(void) {
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersenstatic void polkit_agent_open_if_enabled(void) {
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersen /* Open the polkit agent as a child process if necessary */
20af7091de0cdf92bf299addfc3f96c3ef805bd8Tom Gundersentypedef struct StatusInfo {
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersenstatic const char *jump_str(int delta_minutes, char *s, size_t size) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return "one hour forward";
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen return "one hour backwards";
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen snprintf(s, size, "%i minutes backwards", -delta_minutes);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen snprintf(s, size, "%i minutes forward", delta_minutes);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen /* Enforce the values of /etc/localtime */
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen fprintf(stderr, "Warning: ignoring the TZ variable, reading the system's timezone setting only.\n\n");
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) > 0);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)) > 0);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering rtc_sec = (time_t)(i->rtc_time / USEC_PER_SEC);
3bdace9bf779ce051f00c14914b35c3a26164aa9Lennart Poettering assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", gmtime_r(&rtc_sec, &tm)) > 0);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert_se(strftime(a, sizeof(a), "%Z, %z", localtime_r(&sec, &tm)) > 0);
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen " NTP enabled: %s\n"
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen "NTP synchronized: %s\n"
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen " RTC in local TZ: %s\n",
3a864fe4a894745ac61f1ecabd7cadf04139a284Tom Gundersen i->ntp_capable ? yes_no(i->ntp_enabled) : "n/a",
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert_se(strftime(b, sizeof(b), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm)) > 0);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen assert_se(strftime(b, sizeof(b), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm)) > 0);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen printf(" Next DST change: DST %s (the clock jumps %s) at\n"
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen is_dstn ? "begins" : "ends", jump_str(dn, s, sizeof(s)), a, b);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen "Warning: The RTC is configured to maintain time in the local timezone. This\n"
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen " mode is not fully supported and will create various problems with time\n"
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen " zone changes and daylight saving adjustments. If at all possible use\n"
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersen " RTC in UTC, by calling 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout);
b44cd8821087f2afebf85fec5b588f5720a9415cTom Gundersenstatic int get_timedate_property_bool(sd_bus *bus, const char *name, bool *target) {
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
ff734080aa02cd70b13bc0fdeec4a5886166163aTom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to get property: %s %s", name, bus_error_message(&error, -r));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int get_timedate_property_usec(sd_bus *bus, const char *name, usec_t *target) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to get property: %s %s", name, bus_error_message(&error, -r));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int show_status(sd_bus *bus, char **args, unsigned n) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to get property: Timezone %s", bus_error_message(&error, -r));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = sd_bus_message_read(reply, "s", &info.timezone);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = get_timedate_property_bool(bus, "LocalRTC", &info.rtc_local);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = get_timedate_property_bool(bus, "NTP", &info.ntp_enabled);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = get_timedate_property_bool(bus, "CanNTP", &info.ntp_capable);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = get_timedate_property_bool(bus, "NTPSynchronized", &info.ntp_synced);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = get_timedate_property_usec(bus, "TimeUSec", &info.time);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen r = get_timedate_property_usec(bus, "RTCTimeUSec", &info.rtc_time);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int set_time(sd_bus *bus, char **args, unsigned n) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen bool relative = false, interactive = arg_ask_password;
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to parse time specification: %s", args[1]);
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen log_error("Failed to set time: %s", bus_error_message(&error, -r));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int set_timezone(sd_bus *bus, char **args, unsigned n) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen "SetTimezone",
d6bd972d061af306ede2affd2c9340a1660f7996Tom Gundersen log_error("Failed to set timezone: %s", bus_error_message(&error, -r));
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersenstatic int set_local_rtc(sd_bus *bus, char **args, unsigned n) {
969b009d9416806911b9b52e7e7bc619c0c1a931Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen log_error("Failed to parse local RTC setting: %s", args[1]);
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen "SetLocalRTC",
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_error("Failed to set local RTC: %s", bus_error_message(&error, -r));
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersenstatic int set_ntp(sd_bus *bus, char **args, unsigned n) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_error("Failed to parse NTP setting: %s", args[1]);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen log_error("Failed to set ntp: %s", bus_error_message(&error, -r));
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersenstatic int list_timezones(sd_bus *bus, char **args, unsigned n) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen f = fopen("/usr/share/zoneinfo/zone.tab", "re");
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen log_error("Failed to open timezone database: %m");
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen char l[LINE_MAX], *p, **z, *w;
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen if (!fgets(l, sizeof(l), f)) {
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen log_error("Failed to read timezone database: %m");
bd57b45029ff25067704c9538e79f31e71c10045Tom Gundersen /* Skip over country code */
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* Skip over coordinates */
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen /* Found timezone name */
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen z = realloc(zones, sizeof(char*) * (n_zones + 2));
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersenstatic int help(void) {
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen "Query or change system time and date settings.\n\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " -h --help Show this help\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " --version Show package version\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " --adjust-system-clock\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " Adjust system clock when changing local RTC mode\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " --no-pager Do not pipe output into a pager\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " --no-ask-password Do not prompt for password\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " -H --host=[USER@]HOST Operate on remote host\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " -M --machine=CONTAINER Operate on local container\n\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen "Commands:\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " status Show current time settings\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " set-time TIME Set system time\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " set-timezone ZONE Set system timezone\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " list-timezones Show known timezones\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " set-local-rtc BOOL Control whether RTC is in local time\n"
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen " set-ntp BOOL Control whether NTP is enabled\n",
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersenstatic int parse_argv(int argc, char *argv[]) {
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen { "version", no_argument, NULL, ARG_VERSION },
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen { "no-pager", no_argument, NULL, ARG_NO_PAGER },
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen { "adjust-system-clock", no_argument, NULL, ARG_ADJUST_SYSTEM_CLOCK },
816e2e7af96886e4a43194042ef61ba9fec2c77dTom Gundersen while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersenstatic int timedatectl_main(sd_bus *bus, int argc, char *argv[]) {
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen static const struct {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
87322b3aee0dc649ff1ae7a403dcc9d7305baba2Tom Gundersen { "list-timezones", EQUAL, 1, list_timezones },
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen /* Special rule: no arguments means "status" */
4dc355680460fdc8e0d590d8572dff1b6a257d88Tom Gundersen log_error("Unknown operation %s", argv[optind]);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen assert_not_reached("Unknown comparison operator.");
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen return verbs[i].dispatch(bus, argv + optind, left);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen else if (r == 0) {
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen r = bus_open_transport(arg_transport, arg_host, false, &bus);
2dead8129f7b6fe644e17e1dc1739bebacfe1364Tom Gundersen log_error("Failed to create bus connection: %s", strerror(-r));