hwclock.c revision 67fb4482acb0ecccb8a30e7ca49e5de28ba49eaf
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend/***
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend This file is part of systemd.
7ec4d5cc4aa574e3191bc5a612e68fd8f25ab7earpluem
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend Copyright 2010-2012 Lennart Poettering
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend systemd is free software; you can redistribute it and/or modify it
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend under the terms of the GNU Lesser General Public License as published by
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend the Free Software Foundation; either version 2.1 of the License, or
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend (at your option) any later version.
367d146f245f3b1c9f77c18e6ec591b52e0b344cbnicholes
909ce17e2bd0faef7b1c294f2307f009793fd493nd systemd is distributed in the hope that it will be useful, but
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend WITHOUT ANY WARRANTY; without even the implied warranty of
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0ce5630695a7aa568811a9dd0aceedd685f040dend Lesser General Public License for more details.
42af92a661a06b3cebc88d585aad75064a309d51nd
367d146f245f3b1c9f77c18e6ec591b52e0b344cbnicholes You should have received a copy of the GNU Lesser General Public License
6fe26506780e73be2a412d758af77fafdf03291and along with systemd; If not, see <http://www.gnu.org/licenses/>.
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend***/
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <assert.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <string.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <unistd.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <errno.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <stdlib.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <signal.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <stdio.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <sys/types.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <sys/stat.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <fcntl.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <sys/ioctl.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <stdarg.h>
05ede5110427cb9dc071cc671d5aaba5d3b88c79nd#include <ctype.h>
e8b603fa9ccf7b17b11b42df6d8916fd97c2331dnd#include <sys/prctl.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <sys/time.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include <linux/rtc.h>
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
d6ce05b6521a82cc93da69f7c2116c4a5bc54f8cjim#include "macro.h"
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include "util.h"
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include "log.h"
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include "strv.h"
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include "hwclock.h"
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend#include "fileio.h"
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
03a4ff9ac4c9b8009249010e7c53bb86ff05915andint hwclock_get_time(struct tm *tm) {
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend int fd;
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend int err = 0;
7d15331eeb5429d7148d13d6fd914a641bf1c000pquerna
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend assert(tm);
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC);
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend if (fd < 0)
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend return -errno;
d2b809e5d72658bff23819d8b77f20e4939af541nd
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend /* This leaves the timezone fields of struct tm
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend * uninitialized! */
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend if (ioctl(fd, RTC_RD_TIME, tm) < 0)
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend err = -errno;
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend /* We don't know daylight saving, so we reset this in order not
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend * to confused mktime(). */
6b0fe1f447ba35827cd5cf1d2a703bd8517f33ffmturk tm->tm_isdst = -1;
6b0fe1f447ba35827cd5cf1d2a703bd8517f33ffmturk
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend close_nointr_nofail(fd);
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend return err;
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend}
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fendint hwclock_set_time(const struct tm *tm) {
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend int fd;
0ce5630695a7aa568811a9dd0aceedd685f040dend int err = 0;
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
10eed2803538d660048f6e733602e82a75ef6885noodl assert(tm);
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC);
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend if (fd < 0)
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend return -errno;
03c25fb6f628ac81f2ecb637d1e7502dcee783f3nd
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend if (ioctl(fd, RTC_SET_TIME, tm) < 0)
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend err = -errno;
0ce5630695a7aa568811a9dd0aceedd685f040dend
7fa75a06a4fee19e995c069ee00310455d1452e1pquerna close_nointr_nofail(fd);
0ce5630695a7aa568811a9dd0aceedd685f040dend
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend return err;
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend}
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fendint hwclock_is_localtime(void) {
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend _cleanup_fclose_ FILE *f;
0ce5630695a7aa568811a9dd0aceedd685f040dend
0ce5630695a7aa568811a9dd0aceedd685f040dend /*
f73f2c2fae0ded6c8273c28d025ba8aa8136a0fend * The third line of adjtime is "UTC" or "LOCAL" or nothing.
* # /etc/adjtime
* 0.0 0 0
* 0
* UTC
*/
f = fopen("/etc/adjtime", "re");
if (f) {
char line[LINE_MAX];
bool b;
b = fgets(line, sizeof(line), f) &&
fgets(line, sizeof(line), f) &&
fgets(line, sizeof(line), f);
if (!b)
return -EIO;
truncate_nl(line);
return streq(line, "LOCAL");
} else if (errno != ENOENT)
return -errno;
return 0;
}
int hwclock_set_timezone(int *min) {
const struct timeval *tv_null = NULL;
struct timespec ts;
struct tm *tm;
int minutesdelta;
struct timezone tz;
assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
assert_se(tm = localtime(&ts.tv_sec));
minutesdelta = tm->tm_gmtoff / 60;
tz.tz_minuteswest = -minutesdelta;
tz.tz_dsttime = 0; /* DST_NONE*/
/*
* If the hardware clock does not run in UTC, but in local time:
* The very first time we set the kernel's timezone, it will warp
* the clock so that it runs in UTC instead of local time.
*/
if (settimeofday(tv_null, &tz) < 0)
return -errno;
if (min)
*min = minutesdelta;
return 0;
}
int hwclock_reset_timezone(void) {
const struct timeval *tv_null = NULL;
struct timezone tz;
tz.tz_minuteswest = 0;
tz.tz_dsttime = 0; /* DST_NONE*/
/*
* The very first time we set the kernel's timezone, it will warp
* the clock. Do a dummy call here, so the time warping is sealed
* and we set only the time zone with next call.
*/
if (settimeofday(tv_null, &tz) < 0)
return -errno;
return 0;
}