timedatectl.c revision 7568345034f2890af745747783c5abfbf6eccf0f
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen/***
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen This file is part of systemd.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen Copyright 2012 Lennart Poettering
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen Copyright 2013 Kay Sievers
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen systemd is free software; you can redistribute it and/or modify it
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen under the terms of the GNU Lesser General Public License as published by
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen (at your option) any later version.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen systemd is distributed in the hope that it will be useful, but
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen Lesser General Public License for more details.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen You should have received a copy of the GNU Lesser General Public License
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen***/
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include <stdlib.h>
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include <stdbool.h>
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include <unistd.h>
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include <getopt.h>
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include <locale.h>
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include <string.h>
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include <sys/timex.h>
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include "sd-bus.h"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include "bus-util.h"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include "bus-error.h"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include "util.h"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include "spawn-polkit-agent.h"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include "build.h"
920b52e4909d9dc812817fd8b82f83ca23a11c91Thomas Hindoe Paaboel Andersen#include "strv.h"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include "pager.h"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen#include "time-dst.h"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenstatic bool arg_no_pager = false;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenstatic bool arg_ask_password = true;
79008bddf679a5e0900369950eb346c9fa687107Lennart Poetteringstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenstatic char *arg_host = NULL;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenstatic bool arg_adjust_system_clock = false;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
79008bddf679a5e0900369950eb346c9fa687107Lennart Poetteringstatic void pager_open_if_enabled(void) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (arg_no_pager)
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen return;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen pager_open(false);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen}
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenstatic void polkit_agent_open_if_enabled(void) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen /* Open the polkit agent as a child process if necessary */
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (!arg_ask_password)
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen return;
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (arg_transport != BUS_TRANSPORT_LOCAL)
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen return;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen polkit_agent_open();
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen}
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersentypedef struct StatusInfo {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen usec_t time;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char *timezone;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen usec_t rtc_time;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen bool rtc_local;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen bool ntp_enabled;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen bool ntp_capable;
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen bool ntp_synced;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen} StatusInfo;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenstatic const char *jump_str(int delta_minutes, char *s, size_t size) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (delta_minutes == 60)
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen return "one hour forward";
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (delta_minutes == -60)
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen return "one hour backwards";
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (delta_minutes < 0) {
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering snprintf(s, size, "%i minutes backwards", -delta_minutes);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen return s;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen }
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (delta_minutes > 0) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen snprintf(s, size, "%i minutes forward", delta_minutes);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen return s;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen }
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen return "";
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen}
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenstatic void print_status_info(const StatusInfo *i) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char a[FORMAT_TIMESTAMP_MAX];
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen char b[FORMAT_TIMESTAMP_MAX];
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char s[32];
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen struct tm tm;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen time_t sec;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen bool have_time = false;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen _cleanup_free_ char *zc = NULL, *zn = NULL;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen time_t t, tc, tn;
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen int dn = 0;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen bool is_dstc = false, is_dstn = false;
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering int r;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
45af44d47da6933b260c734ad9ff721f63f80a4dTom Gundersen assert(i);
45af44d47da6933b260c734ad9ff721f63f80a4dTom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen /* Enforce the values of /etc/localtime */
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (getenv("TZ")) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen fprintf(stderr, "Warning: Ignoring the TZ variable. Reading the system's time zone setting only.\n\n");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen unsetenv("TZ");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen }
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (i->time != 0) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen sec = (time_t) (i->time / USEC_PER_SEC);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen have_time = true;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen } else if (arg_transport == BUS_TRANSPORT_LOCAL) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen sec = time(NULL);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen have_time = true;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen } else
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen fprintf(stderr, "Warning: Could not get time from timedated and not operating locally.\n\n");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (have_time) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen zero(tm);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm)) > 0);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char_array_0(a);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" Local time: %s\n", a);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen zero(tm);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm)) > 0);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char_array_0(a);
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering printf(" Universal time: %s\n", a);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen } else {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" Local time: %s\n", "n/a");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" Universal time: %s\n", "n/a");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen }
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (i->rtc_time > 0) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen time_t rtc_sec;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen rtc_sec = (time_t)(i->rtc_time / USEC_PER_SEC);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen zero(tm);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm)) > 0);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char_array_0(a);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" RTC time: %s\n", a);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen } else
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" RTC time: %s\n", "n/a");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (have_time) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen zero(tm);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen assert_se(strftime(a, sizeof(a), "%Z, %z", localtime_r(&sec, &tm)) > 0);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char_array_0(a);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen }
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" Time zone: %s (%s)\n"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen " NTP enabled: %s\n"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen "NTP synchronized: %s\n"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen " RTC in local TZ: %s\n",
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen strna(i->timezone), have_time ? a : "n/a",
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen i->ntp_capable ? yes_no(i->ntp_enabled) : "n/a",
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen yes_no(i->ntp_synced),
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen yes_no(i->rtc_local));
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (have_time) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = time_get_dst(sec, "/etc/localtime",
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen &tc, &zc, &is_dstc,
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen &tn, &dn, &zn, &is_dstn);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (r < 0)
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" DST active: %s\n", "n/a");
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen else {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" DST active: %s\n", yes_no(is_dstc));
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen t = tc - 1;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen zero(tm);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char_array_0(a);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen zero(tm);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen assert_se(strftime(b, sizeof(b), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm)) > 0);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char_array_0(b);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" Last DST change: DST %s at\n"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen " %s\n"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen " %s\n",
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen is_dstc ? "began" : "ended", a, b);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen t = tn - 1;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen zero(tm);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen assert_se(strftime(a, sizeof(a), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)) > 0);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char_array_0(a);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen zero(tm);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen assert_se(strftime(b, sizeof(b), "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm)) > 0);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen char_array_0(b);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" Next DST change: DST %s (the clock jumps %s) at\n"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen " %s\n"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen " %s\n",
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering is_dstn ? "begins" : "ends", jump_str(dn, s, sizeof(s)), a, b);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen }
79008bddf679a5e0900369950eb346c9fa687107Lennart Poettering } else
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen printf(" DST active: %s\n", yes_no(is_dstc));
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (i->rtc_local)
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen fputs("\n" ANSI_HIGHLIGHT_ON
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen "Warning: The RTC is configured to maintain time in the local time zone. This\n"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen " mode is not fully supported and will create various problems with time\n"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen " zone changes and daylight saving time adjustments. If at all possible, use\n"
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen " RTC in UTC by calling 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen}
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
e0ee46f29028e291eb67f435aff1b6202d75d9d6Lennart Poetteringstatic int show_status(sd_bus *bus, char **args, unsigned n) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen StatusInfo info = {};
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen static const struct bus_properties_map map[] = {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen { "Timezone", "s", NULL, offsetof(StatusInfo, timezone) },
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen { "LocalRTC", "b", NULL, offsetof(StatusInfo, rtc_local) },
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen { "NTP", "b", NULL, offsetof(StatusInfo, ntp_enabled) },
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen { "CanNTP", "b", NULL, offsetof(StatusInfo, ntp_capable) },
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen { "NTPSynchronized", "b", NULL, offsetof(StatusInfo, ntp_synced) },
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen { "TimeUSec", "t", NULL, offsetof(StatusInfo, time) },
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen { "RTCTimeUSec", "t", NULL, offsetof(StatusInfo, rtc_time) },
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen {}
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen };
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen int r;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen assert(bus);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen r = bus_map_all_properties(bus,
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen "org.freedesktop.timedate1",
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen "/org/freedesktop/timedate1",
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen map,
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen &info);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen if (r < 0) {
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen log_error("Failed to query server: %s", strerror(-r));
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen goto fail;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen }
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen print_status_info(&info);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersenfail:
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen free(info.timezone);
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen return r;
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen}
b22d8a00f48f3c5fc4510b4acd3e1a43e731e592Tom Gundersen
static int set_time(sd_bus *bus, char **args, unsigned n) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
bool relative = false, interactive = arg_ask_password;
usec_t t;
int r;
assert(args);
assert(n == 2);
polkit_agent_open_if_enabled();
r = parse_timestamp(args[1], &t);
if (r < 0) {
log_error("Failed to parse time specification: %s", args[1]);
return r;
}
r = sd_bus_call_method(bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetTime",
&error,
NULL,
"xbb", (int64_t)t, relative, interactive);
if (r < 0)
log_error("Failed to set time: %s", bus_error_message(&error, -r));
return r;
}
static int set_timezone(sd_bus *bus, char **args, unsigned n) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
assert(args);
assert(n == 2);
polkit_agent_open_if_enabled();
r = sd_bus_call_method(bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetTimezone",
&error,
NULL,
"sb", args[1], arg_ask_password);
if (r < 0)
log_error("Failed to set time zone: %s", bus_error_message(&error, -r));
return r;
}
static int set_local_rtc(sd_bus *bus, char **args, unsigned n) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r, b;
assert(args);
assert(n == 2);
polkit_agent_open_if_enabled();
b = parse_boolean(args[1]);
if (b < 0) {
log_error("Failed to parse local RTC setting: %s", args[1]);
return b;
}
r = sd_bus_call_method(bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetLocalRTC",
&error,
NULL,
"bbb", b, arg_adjust_system_clock, arg_ask_password);
if (r < 0)
log_error("Failed to set local RTC: %s", bus_error_message(&error, -r));
return r;
}
static int set_ntp(sd_bus *bus, char **args, unsigned n) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int b, r;
assert(args);
assert(n == 2);
polkit_agent_open_if_enabled();
b = parse_boolean(args[1]);
if (b < 0) {
log_error("Failed to parse NTP setting: %s", args[1]);
return b;
}
r = sd_bus_call_method(bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetNTP",
&error,
NULL,
"bb", b, arg_ask_password);
if (r < 0)
log_error("Failed to set ntp: %s", bus_error_message(&error, -r));
return r;
}
static int list_timezones(sd_bus *bus, char **args, unsigned n) {
_cleanup_strv_free_ char **zones = NULL;
int r;
assert(args);
assert(n == 1);
r = get_timezones(&zones);
if (r < 0) {
log_error("Failed to read list of time zones: %s", strerror(-r));
return r;
}
pager_open_if_enabled();
strv_print(zones);
return 0;
}
static int help(void) {
printf("%s [OPTIONS...] COMMAND ...\n\n"
"Query or change system time and date settings.\n\n"
" -h --help Show this help message\n"
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
" --no-ask-password Do not prompt for password\n"
" -H --host=[USER@]HOST Operate on remote host\n"
" -M --machine=CONTAINER Operate on local container\n"
" --adjust-system-clock Adjust system clock when changing local RTC mode\n\n"
"Commands:\n"
" status Show current time settings\n"
" set-time TIME Set system time\n"
" set-timezone ZONE Set system time zone\n"
" list-timezones Show known time zones\n"
" set-local-rtc BOOL Control whether RTC is in local time\n"
" set-ntp BOOL Control whether NTP is enabled\n",
program_invocation_short_name);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_ADJUST_SYSTEM_CLOCK,
ARG_NO_ASK_PASSWORD
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ "adjust-system-clock", no_argument, NULL, ARG_ADJUST_SYSTEM_CLOCK },
{}
};
int c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) {
switch (c) {
case 'h':
return help();
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
arg_host = optarg;
break;
case 'M':
arg_transport = BUS_TRANSPORT_CONTAINER;
arg_host = optarg;
break;
case ARG_NO_ASK_PASSWORD:
arg_ask_password = false;
break;
case ARG_ADJUST_SYSTEM_CLOCK:
arg_adjust_system_clock = true;
break;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
}
return 1;
}
static int timedatectl_main(sd_bus *bus, int argc, char *argv[]) {
static const struct {
const char* verb;
const enum {
MORE,
LESS,
EQUAL
} argc_cmp;
const int argc;
int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
} verbs[] = {
{ "status", LESS, 1, show_status },
{ "set-time", EQUAL, 2, set_time },
{ "set-timezone", EQUAL, 2, set_timezone },
{ "list-timezones", EQUAL, 1, list_timezones },
{ "set-local-rtc", EQUAL, 2, set_local_rtc },
{ "set-ntp", EQUAL, 2, set_ntp, },
};
int left;
unsigned i;
assert(argc >= 0);
assert(argv);
left = argc - optind;
if (left <= 0)
/* Special rule: no arguments means "status" */
i = 0;
else {
if (streq(argv[optind], "help")) {
help();
return 0;
}
for (i = 0; i < ELEMENTSOF(verbs); i++)
if (streq(argv[optind], verbs[i].verb))
break;
if (i >= ELEMENTSOF(verbs)) {
log_error("Unknown operation %s", argv[optind]);
return -EINVAL;
}
}
switch (verbs[i].argc_cmp) {
case EQUAL:
if (left != verbs[i].argc) {
log_error("Invalid number of arguments.");
return -EINVAL;
}
break;
case MORE:
if (left < verbs[i].argc) {
log_error("Too few arguments.");
return -EINVAL;
}
break;
case LESS:
if (left > verbs[i].argc) {
log_error("Too many arguments.");
return -EINVAL;
}
break;
default:
assert_not_reached("Unknown comparison operator.");
}
return verbs[i].dispatch(bus, argv + optind, left);
}
int main(int argc, char *argv[]) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
int r;
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
r = bus_open_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error("Failed to create bus connection: %s", strerror(-r));
goto finish;
}
r = timedatectl_main(bus, argc, argv);
finish:
pager_close();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}