timedatectl.c revision 546158bc6f46f8004cc11e81d19d223e0da56730
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen This file is part of systemd.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Copyright 2012 Lennart Poettering
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen systemd is free software; you can redistribute it and/or modify it
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen under the terms of the GNU Lesser General Public License as published by
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen (at your option) any later version.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen systemd is distributed in the hope that it will be useful, but
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen Lesser General Public License for more details.
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen You should have received a copy of the GNU Lesser General Public License
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringstatic bool arg_adjust_system_clock = false;
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringstatic bool arg_no_pager = false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic bool arg_ask_password = true;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic void pager_open_if_enabled(void) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic void polkit_agent_open_if_enabled(void) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Open the polkit agent as a child process if necessary */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersentypedef struct StatusInfo {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic bool ntp_synced(void) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return false;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic const char *jump_str(int delta_minutes, char *s, size_t size) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return "one hour forward";
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return "one hour backwards";
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen snprintf(s, size, "%i minutes backwards", -delta_minutes);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen snprintf(s, size, "%i minutes forward", delta_minutes);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* enforce the values of /etc/localtime */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen fprintf(stderr, "Warning: ignoring the TZ variable, reading the system's timezone setting only.\n\n");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) > 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)) > 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (r >= 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Calculcate the week-day */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S", &tm) > 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_se(strftime(a, sizeof(a), "%Z, %z", localtime_r(&sec, &tm)) > 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " NTP enabled: %s\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen "NTP synchronized: %s\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " RTC in local TZ: %s\n",
08232a020bd2571088d3ee06dda07732c5e963d1Tom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0);
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering assert_se(strftime(b, sizeof(b), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm)) > 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_se(strftime(b, sizeof(b), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm)) > 0);
52d629010db73a9466c359201916494bd55186d1Tom Gundersen printf(" Next DST change: DST %s (the clock jumps %s) at\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen is_dstn ? "begins" : "ends", jump_str(dn, s, sizeof(s)), a, b);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen "Warning: The RTC is configured to maintain time in the local time zone. This\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " mode is not fully supported and will create various problems with time\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " zone changes and daylight saving adjustments. If at all possible use\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " RTC in UTC, by calling 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int status_property(const char *name, DBusMessageIter *iter, StatusInfo *i) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen switch (dbus_message_iter_get_arg_type(iter)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen const char *s;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int show_status(DBusConnection *bus, char **args, unsigned n) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen "org.freedesktop.DBus.Properties",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
a9ec9f29420623133c419ddc8864921a824751fbKay Sieversstatic int set_time(DBusConnection *bus, char **args, unsigned n) {
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
a9ec9f29420623133c419ddc8864921a824751fbKay Sievers dbus_bool_t relative = false, interactive = arg_ask_password;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_error("Failed to parse time specification: %s", args[1]);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int set_timezone(DBusConnection *bus, char **args, unsigned n) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen "SetTimezone",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int set_local_rtc(DBusConnection *bus, char **args, unsigned n) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dbus_bool_t interactive = arg_ask_password, b, q;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_error("Failed to parse local RTC setting: %s", args[1]);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen "SetLocalRTC",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int set_ntp(DBusConnection *bus, char **args, unsigned n) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen dbus_bool_t interactive = arg_ask_password, b;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_error("Failed to parse NTP setting: %s", args[1]);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int list_timezones(DBusConnection *bus, char **args, unsigned n) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen f = fopen("/usr/share/zoneinfo/zone.tab", "re");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_error("Failed to open timezone database: %m");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen char l[LINE_MAX], *p, **z, *w;
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen if (!fgets(l, sizeof(l), f)) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_error("Failed to read timezone database: %m");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Skip over country code */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Skip over coordinates */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Found timezone name */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen z = realloc(zones, sizeof(char*) * (n_zones + 2));
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int help(void) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen "Query or change system time and date settings.\n\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " -h --help Show this help\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " --version Show package version\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " --adjust-system-clock\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " Adjust system clock when changing local RTC mode\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " --no-pager Do not pipe output into a pager\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " -P --privileged Acquire privileges before execution\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " --no-ask-password Do not prompt for password\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " -H --host=[USER@]HOST Operate on remote host\n\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen "Commands:\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " status Show current time settings\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " set-time TIME Set system time\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " set-timezone ZONE Set system timezone\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " list-timezones Show known timezones\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " set-local-rtc BOOL Control whether RTC is in local time\n"
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen " set-ntp BOOL Control whether NTP is enabled\n",
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int parse_argv(int argc, char *argv[]) {
2a2137401b3aef20618308d2b2694e21b0124f89Tom Gundersen { "version", no_argument, NULL, ARG_VERSION },
bba061662b0f759abb43bad60c9733305c191045Tom Gundersen { "no-pager", no_argument, NULL, ARG_NO_PAGER },
e53fc357a9bb9d0a5362ccc4246d598cb0febd5eLennart Poettering { "host", required_argument, NULL, 'H' },
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen { "adjust-system-clock", no_argument, NULL, ARG_ADJUST_SYSTEM_CLOCK },
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen while ((c = getopt_long(argc, argv, "hH:P", options, NULL)) >= 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersenstatic int timedatectl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen static const struct {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen int (* const dispatch)(DBusConnection *bus, char **args, unsigned n);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen { "list-timezones", EQUAL, 1, list_timezones },
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen /* Special rule: no arguments means "status" */
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_error("Unknown operation %s", argv[optind]);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_not_reached("Unknown comparison operator.");
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen log_error("Failed to get D-Bus connection: %s", error->message);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen return verbs[i].dispatch(bus, argv + optind, left);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen else if (r == 0) {
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen bus_connect_system_ssh(NULL, arg_host, &bus, &error);
57fa1d094cd2c5ac68970526ad0a0754c548e75dTom Gundersen assert_not_reached("Uh, invalid transport...");