timedatectl.c revision 1b12a7b5896f94bdf33b3a6661ebabd761ea6adc
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2012 Lennart Poettering
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 "dbus-common.h"
#include "util.h"
#include "spawn-polkit-agent.h"
#include "build.h"
#include "hwclock.h"
#include "strv.h"
#include "pager.h"
#include "time-dst.h"
static bool arg_adjust_system_clock = false;
static bool arg_no_pager = false;
static enum transport {
static bool arg_ask_password = true;
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;
}
typedef struct StatusInfo {
const char *timezone;
bool local_rtc;
bool ntp;
} StatusInfo;
static bool ntp_synced(void) {
return false;
return false;
return true;
}
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(StatusInfo *i) {
usec_t n;
char a[FORMAT_TIMESTAMP_MAX];
char b[FORMAT_TIMESTAMP_MAX];
char s[32];
int dn;
int r;
assert(i);
if (getenv("TZ")) {
fprintf(stderr, "Warning: ignoring the TZ variable, reading the system's timezone setting only.\n\n");
unsetenv("TZ");
}
n = now(CLOCK_REALTIME);
char_array_0(a);
printf(" Local time: %s\n", a);
char_array_0(a);
printf(" Universal time: %s\n", a);
r = hwclock_get_time(&tm);
if (r >= 0) {
/* Calculcate the week-day */
char_array_0(a);
printf(" RTC time: %s\n", a);
}
char_array_0(a);
printf(" Timezone: %s (%s)\n"
" NTP enabled: %s\n"
"NTP synchronized: %s\n"
" RTC in local TZ: %s\n",
a,
yes_no(ntp_synced()),
if (r < 0)
printf(" DST active: n/a\n");
else {
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",
}
if (i->local_rtc)
"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 adjustments. If at all possible use\n"
}
switch (dbus_message_iter_get_arg_type(iter)) {
case DBUS_TYPE_STRING: {
const char *s;
if (!isempty(s)) {
i->timezone = s;
}
break;
}
case DBUS_TYPE_BOOLEAN: {
dbus_bool_t b;
i->local_rtc = b;
i->ntp = b;
}
}
return 0;
}
const char *interface = "";
int r;
bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.DBus.Properties",
"GetAll",
&reply,
NULL,
if (r < 0)
return r;
log_error("Failed to parse reply.");
return -EIO;
}
const char *name;
log_error("Failed to parse reply.");
return -EIO;
}
log_error("Failed to parse reply.");
return -EIO;
}
log_error("Failed to parse reply.");
return -EIO;
}
if (r < 0) {
log_error("Failed to parse reply.");
return r;
}
}
return 0;
}
usec_t t;
dbus_int64_t u;
int r;
assert(n == 2);
if (r < 0) {
return r;
}
u = (dbus_uint64_t) t;
return bus_method_call_with_reply(
bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetTime",
&reply,
NULL,
DBUS_TYPE_INT64, &u,
}
dbus_bool_t interactive = true;
assert(n == 2);
return bus_method_call_with_reply(
bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetTimezone",
&reply,
NULL,
}
dbus_bool_t interactive = true, b, q;
int r;
assert(n == 2);
if (r < 0) {
return r;
}
b = r;
return bus_method_call_with_reply(
bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetLocalRTC",
&reply,
NULL,
DBUS_TYPE_BOOLEAN, &b,
DBUS_TYPE_BOOLEAN, &q,
}
dbus_bool_t interactive = true, b;
int r;
assert(n == 2);
if (r < 0) {
return r;
}
b = r;
return bus_method_call_with_reply(
bus,
"org.freedesktop.timedate1",
"/org/freedesktop/timedate1",
"org.freedesktop.timedate1",
"SetNTP",
&reply,
NULL,
DBUS_TYPE_BOOLEAN, &b,
}
assert(n == 1);
if (!f) {
log_error("Failed to open timezone 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 timezone 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\n"
" --version Show package version\n"
" --adjust-system-clock\n"
" Adjust system clock when changing local RTC mode\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\n"
"Commands:\n"
" status Show current time settings\n"
" set-time TIME Set system time\n"
" set-timezone ZONE Set system timezone\n"
" list-timezones Show known timezones\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':
help();
return 0;
case ARG_VERSION:
return 0;
case 'P':
break;
case 'H':
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:
log_error("Unknown option code %c", c);
return -EINVAL;
}
}
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.");
}
if (!bus) {
return -EIO;
}
}
int r, retval = EXIT_FAILURE;
log_open();
if (r < 0)
goto finish;
else if (r == 0) {
goto finish;
}
if (arg_transport == TRANSPORT_NORMAL)
else if (arg_transport == TRANSPORT_POLKIT)
else if (arg_transport == TRANSPORT_SSH)
else
assert_not_reached("Uh, invalid transport...");
retval = r < 0 ? EXIT_FAILURE : r;
if (bus) {
}
pager_close();
return retval;
}