timedatectl.c revision 07a062a79374406e8f6b5a1e2f80c80baf031567
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2012 Lennart Poettering
Copyright 2013 Kay Sievers
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <getopt.h>
#include <locale.h>
#include <string.h>
#include "sd-bus.h"
#include "bus-util.h"
#include "bus-error.h"
#include "util.h"
#include "spawn-polkit-agent.h"
#include "build.h"
#include "strv.h"
#include "pager.h"
#include "time-dst.h"
static bool arg_no_pager = false;
static bool arg_ask_password = true;
static bool arg_adjust_system_clock = false;
static void pager_open_if_enabled(void) {
if (arg_no_pager)
return;
pager_open(false);
}
static void polkit_agent_open_if_enabled(void) {
/* Open the polkit agent as a child process if necessary */
if (!arg_ask_password)
return;
if (arg_transport != BUS_TRANSPORT_LOCAL)
return;
}
typedef struct StatusInfo {
char *timezone;
bool rtc_local;
bool ntp_enabled;
bool ntp_capable;
bool ntp_synced;
} StatusInfo;
if (delta_minutes == 60)
return "one hour forward";
if (delta_minutes == -60)
return "one hour backwards";
if (delta_minutes < 0) {
return s;
}
if (delta_minutes > 0) {
return s;
}
return "";
}
static void print_status_info(const StatusInfo *i) {
char a[FORMAT_TIMESTAMP_MAX];
char b[FORMAT_TIMESTAMP_MAX];
char s[32];
bool have_time = false;
int dn = 0;
int r;
assert(i);
if (getenv("TZ")) {
fprintf(stderr, "Warning: Ignoring the TZ variable. Reading the system's time zone setting only.\n\n");
unsetenv("TZ");
}
if (i->time != 0) {
have_time = true;
} else if (arg_transport == BUS_TRANSPORT_LOCAL) {
have_time = true;
} else
if (have_time) {
char_array_0(a);
printf(" Local time: %s\n", a);
char_array_0(a);
printf(" Universal time: %s\n", a);
} else {
}
if (i->rtc_time > 0) {
char_array_0(a);
printf(" RTC time: %s\n", a);
} else
char_array_0(a);
printf(" Time zone: %s (%s)\n"
" NTP enabled: %s\n"
"NTP synchronized: %s\n"
" RTC in local TZ: %s\n",
yes_no(i->ntp_synced),
if (r < 0)
else if (have_time) {
t = tc - 1;
char_array_0(a);
char_array_0(b);
printf(" Last DST change: DST %s at\n"
" %s\n"
" %s\n",
t = tn - 1;
char_array_0(a);
char_array_0(b);
printf(" Next DST change: DST %s (the clock jumps %s) at\n"
" %s\n"
" %s\n",
} else
if (i->rtc_local)
"Warning: The RTC is configured to maintain time in the local time zone. This\n"
" mode is not fully supported and will create various problems with time\n"
" zone changes and daylight saving time adjustments. If at all possible, use\n"
}
StatusInfo info = {};
static const struct bus_properties_map map[] = {
{}
};
int r;
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
map,
&info);
if (r < 0) {
goto fail;
}
fail:
return r;
}
usec_t t;
int r;
assert(n == 2);
if (r < 0) {
return r;
}
r = sd_bus_call_method(bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetTime",
&error,
NULL,
if (r < 0)
return r;
}
int r;
assert(n == 2);
r = sd_bus_call_method(bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetTimezone",
&error,
NULL,
if (r < 0)
return r;
}
int r, b;
assert(n == 2);
if (b < 0) {
return b;
}
r = sd_bus_call_method(bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetLocalRTC",
&error,
NULL,
if (r < 0)
return r;
}
int b, r;
assert(n == 2);
if (b < 0) {
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)
return r;
}
assert(n == 1);
if (!f) {
log_error("Failed to open time zone database: %m");
return -errno;
}
for (;;) {
char l[LINE_MAX], *p, **z, *w;
size_t k;
if (!fgets(l, sizeof(l), f)) {
if (feof(f))
break;
log_error("Failed to read time zone database: %m");
return -errno;
}
p = strstrip(l);
if (isempty(p) || *p == '#')
continue;
/* Skip over country code */
p += strcspn(p, WHITESPACE);
p += strspn(p, WHITESPACE);
/* Skip over coordinates */
p += strcspn(p, WHITESPACE);
p += strspn(p, WHITESPACE);
/* Found timezone name */
k = strcspn(p, WHITESPACE);
if (k <= 0)
continue;
w = strndup(p, k);
if (!w)
return log_oom();
if (!z) {
free(w);
return log_oom();
}
zones = z;
}
if (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",
return 0;
}
enum {
ARG_VERSION = 0x100,
};
{}
};
int c;
switch (c) {
case 'h':
return help();
case ARG_VERSION:
return 0;
case 'H':
break;
case 'M':
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 const struct {
const char* verb;
const enum {
MORE,
LESS,
} argc_cmp;
const int argc;
} verbs[] = {
};
int left;
unsigned i;
if (left <= 0)
/* Special rule: no arguments means "status" */
i = 0;
else {
help();
return 0;
}
for (i = 0; i < ELEMENTSOF(verbs); i++)
break;
if (i >= ELEMENTSOF(verbs)) {
return -EINVAL;
}
}
case EQUAL:
log_error("Invalid number of arguments.");
return -EINVAL;
}
break;
case MORE:
log_error("Too few arguments.");
return -EINVAL;
}
break;
case LESS:
log_error("Too many arguments.");
return -EINVAL;
}
break;
default:
assert_not_reached("Unknown comparison operator.");
}
}
int r;
log_open();
if (r <= 0)
goto finish;
if (r < 0) {
goto finish;
}
pager_close();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}