timedatectl.c revision 3e5e74d5b7f6fcbeff7b6e4e06abd931aab14c48
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering/***
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering This file is part of systemd.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering Copyright 2012 Lennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering Copyright 2013 Kay Sievers
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering systemd is free software; you can redistribute it and/or modify it
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering under the terms of the GNU Lesser General Public License as published by
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering (at your option) any later version.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering systemd is distributed in the hope that it will be useful, but
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering Lesser General Public License for more details.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering You should have received a copy of the GNU Lesser General Public License
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering***/
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
4ad7f2761da661853dcc29d542efb4727abb1101Nick Owens#include <stdlib.h>
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include <stdbool.h>
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include <getopt.h>
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include <locale.h>
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "sd-bus.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "bus-util.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "bus-error.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "util.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "spawn-polkit-agent.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "build.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "strv.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "pager.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering#include "time-dst.h"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_no_pager = false;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_ask_password = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic char *arg_host = NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic bool arg_adjust_system_clock = false;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void pager_open_if_enabled(void) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (arg_no_pager)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering pager_open(false);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering}
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void polkit_agent_open_if_enabled(void) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Open the polkit agent as a child process if necessary */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (!arg_ask_password)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (arg_transport != BUS_TRANSPORT_LOCAL)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering polkit_agent_open();
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering}
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringtypedef struct StatusInfo {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering usec_t time;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering char *timezone;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering usec_t rtc_time;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering bool rtc_local;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering bool ntp_enabled;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering bool ntp_capable;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering bool ntp_synced;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering} StatusInfo;
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poetteringstatic const char *jump_str(int delta_minutes, char *s, size_t size) {
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if (delta_minutes == 60)
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering return "one hour forward";
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if (delta_minutes == -60)
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering return "one hour backwards";
7e8e0422aeb16f2a09a40546c61df753d10029b6Lennart Poettering if (delta_minutes < 0) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering snprintf(s, size, "%i minutes backwards", -delta_minutes);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return s;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (delta_minutes > 0) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering snprintf(s, size, "%i minutes forward", delta_minutes);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return s;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return "";
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering}
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic void print_status_info(const StatusInfo *i) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering char a[FORMAT_TIMESTAMP_MAX];
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering char b[FORMAT_TIMESTAMP_MAX];
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering char s[32];
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering struct tm tm;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering time_t sec;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering bool have_time = false;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering _cleanup_free_ char *zc = NULL, *zn = NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering time_t t, tc, tn;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering int dn = 0;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering bool is_dstc = false, is_dstn = false;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering int r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert(i);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering /* Enforce the values of /etc/localtime */
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (getenv("TZ")) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering fprintf(stderr, "Warning: Ignoring the TZ variable.\n\n");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering unsetenv("TZ");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = setenv("TZ", i->timezone, false);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (r < 0) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error_errno(errno, "Failed to set TZ environment variable: %m");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering exit(EXIT_FAILURE);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
34b9656f0b2890743eee6a746ef08d817abfd5e9Lennart Poettering tzset();
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (i->time != 0) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering sec = (time_t) (i->time / USEC_PER_SEC);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering have_time = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering } else if (IN_SET(arg_transport, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE)) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering sec = time(NULL);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering have_time = true;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering } else
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering fprintf(stderr, "Warning: Could not get time from timedated and not operating locally.\n\n");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (have_time) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&sec, &tm));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" Local time: %.*s\n", (int) sizeof(a), a);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering xstrftime(a, "%a %Y-%m-%d %H:%M:%S UTC", gmtime_r(&sec, &tm));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" Universal time: %.*s\n", (int) sizeof(a), a);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering } else {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" Local time: %s\n", "n/a");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" Universal time: %s\n", "n/a");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
34b9656f0b2890743eee6a746ef08d817abfd5e9Lennart Poettering if (i->rtc_time > 0) {
34b9656f0b2890743eee6a746ef08d817abfd5e9Lennart Poettering time_t rtc_sec;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering rtc_sec = (time_t)(i->rtc_time / USEC_PER_SEC);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering xstrftime(a, "%a %Y-%m-%d %H:%M:%S", gmtime_r(&rtc_sec, &tm));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" RTC time: %.*s\n", (int) sizeof(a), a);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering } else
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" RTC time: %s\n", "n/a");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (have_time)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering xstrftime(a, "%Z, %z", localtime_r(&sec, &tm));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" Time zone: %s (%.*s)\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering " NTP enabled: %s\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "NTP synchronized: %s\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering " RTC in local TZ: %s\n",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering strna(i->timezone), (int) sizeof(a), have_time ? a : "n/a",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering i->ntp_capable ? yes_no(i->ntp_enabled) : "n/a",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering yes_no(i->ntp_synced),
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering yes_no(i->rtc_local));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (have_time) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = time_get_dst(sec, "/etc/localtime",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering &tc, &zc, &is_dstc,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering &tn, &dn, &zn, &is_dstn);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (r < 0)
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" DST active: %s\n", "n/a");
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering else {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" DST active: %s\n", yes_no(is_dstc));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering t = tc - 1;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering xstrftime(b, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" Last DST change: DST %s at\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering " %.*s\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering " %.*s\n",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering is_dstc ? "began" : "ended",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering (int) sizeof(a), a,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering (int) sizeof(b), b);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering t = tn - 1;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering xstrftime(b, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering printf(" Next DST change: DST %s (the clock jumps %s) at\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering " %.*s\n"
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering " %.*s\n",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering is_dstn ? "begins" : "ends",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering jump_str(dn, s, sizeof(s)),
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering (int) sizeof(a), a,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering (int) sizeof(b), b);
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering }
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering } else
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering printf(" DST active: %s\n", yes_no(is_dstc));
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering if (i->rtc_local)
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering fputs("\n" ANSI_HIGHLIGHT_ON
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering "Warning: The system is configured to read the RTC time in the local time zone. This\n"
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering " mode can not be fully supported. It will create various problems with time\n"
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering " zone changes and daylight saving time adjustments. The RTC time is never updated,\n"
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering " it relies on external facilities to maintain it. If at all possible, use\n"
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering " RTC in UTC by calling 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout);
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering}
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poetteringstatic int show_status(sd_bus *bus, char **args, unsigned n) {
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering StatusInfo info = {};
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering static const struct bus_properties_map map[] = {
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering { "Timezone", "s", NULL, offsetof(StatusInfo, timezone) },
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering { "LocalRTC", "b", NULL, offsetof(StatusInfo, rtc_local) },
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering { "NTP", "b", NULL, offsetof(StatusInfo, ntp_enabled) },
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering { "CanNTP", "b", NULL, offsetof(StatusInfo, ntp_capable) },
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering { "NTPSynchronized", "b", NULL, offsetof(StatusInfo, ntp_synced) },
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering { "TimeUSec", "t", NULL, offsetof(StatusInfo, time) },
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering { "RTCTimeUSec", "t", NULL, offsetof(StatusInfo, rtc_time) },
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering {}
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering };
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering int r;
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering assert(bus);
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering r = bus_map_all_properties(bus,
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering "org.freedesktop.timedate1",
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering "/org/freedesktop/timedate1",
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering map,
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering &info);
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering if (r < 0) {
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering log_error_errno(r, "Failed to query server: %m");
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering goto fail;
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering }
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering
1086182d83d4c02a75f96f0184d5e8e5d3af6528Lennart Poettering print_status_info(&info);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringfail:
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering free(info.timezone);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering}
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int set_time(sd_bus *bus, char **args, unsigned n) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering bool relative = false, interactive = arg_ask_password;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering usec_t t;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering int r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert(args);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert(n == 2);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering polkit_agent_open_if_enabled();
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = parse_timestamp(args[1], &t);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (r < 0) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering log_error("Failed to parse time specification: %s", args[1]);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering }
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = sd_bus_call_method(bus,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "org.freedesktop.timedate1",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "/org/freedesktop/timedate1",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "org.freedesktop.timedate1",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "SetTime",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering &error,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering NULL,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "xbb", (int64_t)t, relative, interactive);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering if (r < 0)
34b9656f0b2890743eee6a746ef08d817abfd5e9Lennart Poettering log_error("Failed to set time: %s", bus_error_message(&error, -r));
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering return r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering}
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poetteringstatic int set_timezone(sd_bus *bus, char **args, unsigned n) {
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering int r;
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert(args);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering assert(n == 2);
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering polkit_agent_open_if_enabled();
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering r = sd_bus_call_method(bus,
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "org.freedesktop.timedate1",
faa133f3aa7a18f26563dc5d6b95898cb315c37aLennart Poettering "/org/freedesktop/timedate1",
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering "org.freedesktop.timedate1",
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering "SetTimezone",
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering &error,
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering NULL,
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering "sb", args[1], arg_ask_password);
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering if (r < 0)
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering log_error("Failed to set time zone: %s", bus_error_message(&error, -r));
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering return r;
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering}
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poetteringstatic int set_local_rtc(sd_bus *bus, char **args, unsigned n) {
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering int r, b;
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering assert(args);
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering assert(n == 2);
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering polkit_agent_open_if_enabled();
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering b = parse_boolean(args[1]);
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering if (b < 0) {
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering log_error("Failed to parse local RTC setting: %s", args[1]);
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering return b;
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering }
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering r = sd_bus_call_method(bus,
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering "org.freedesktop.timedate1",
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering "/org/freedesktop/timedate1",
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering "org.freedesktop.timedate1",
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering "SetLocalRTC",
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering &error,
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering NULL,
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering "bbb", b, arg_adjust_system_clock, arg_ask_password);
b914e211f3a40f507b3cdc572838ec7f3fd5e4cfLennart Poettering 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)
return log_error_errno(r, "Failed to read list of time zones: %m");
pager_open_if_enabled();
strv_print(zones);
return 0;
}
static void 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);
}
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':
help();
return 0;
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_MACHINE;
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_close_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_errno(r, "Failed to create bus connection: %m");
goto finish;
}
r = timedatectl_main(bus, argc, argv);
finish:
pager_close();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}