hwclock.c revision 2f6a59070559786428d9eaf199ae3d61772b2225
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering/***
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering This file is part of systemd.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Copyright 2010-2012 Lennart Poettering
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is free software; you can redistribute it and/or modify it
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering under the terms of the GNU Lesser General Public License as published by
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering (at your option) any later version.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering systemd is distributed in the hope that it will be useful, but
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering Lesser General Public License for more details.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering You should have received a copy of the GNU Lesser General Public License
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering***/
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <assert.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <string.h>
a9cdc94f7ff40f22a3cf9472f612a80730a1b010Dave Reisner#include <unistd.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <errno.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <stdlib.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <signal.h>
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen#include <stdio.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <sys/types.h>
a281d9c7851b16c4c9195d042901540ee9ced799Thomas Hindoe Paaboel Andersen#include <sys/stat.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <fcntl.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <sys/ioctl.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <stdarg.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <ctype.h>
288a74cce597f81d3ba01d8a5ca7d2ba5b654b7eRonny Chevalier#include <sys/prctl.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <sys/time.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include <linux/rtc.h>
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "macro.h"
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering#include "util.h"
7085053a437456ab87d726f3697002dd811fdf7aDaniel Wallace#include "log.h"
e1636421f46db6d06fbd028ef20a3113fa3e11f8Lennart Poettering#include "strv.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "hwclock.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering#include "fileio.h"
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poetteringint hwclock_get_time(struct tm *tm) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int fd;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering int err = 0;
1b12a7b5896f94bdf33b3a6661ebabd761ea6adcHarald Hoyer
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(tm);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering if (fd < 0)
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return -errno;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* This leaves the timezone fields of struct tm
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * uninitialized! */
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering if (ioctl(fd, RTC_RD_TIME, tm) < 0)
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering err = -errno;
46e65dcc3a522b5e992e165b5e61d14254026859Lennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /* We don't know daylight saving, so we reset this in order not
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * to confuse mktime(). */
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering tm->tm_isdst = -1;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers close_nointr_nofail(fd);
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers return err;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers}
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sieversint hwclock_set_time(const struct tm *tm) {
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers int fd;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers int err = 0;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert(tm);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC);
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann if (fd < 0)
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann return -errno;
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann if (ioctl(fd, RTC_SET_TIME, tm) < 0)
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann err = -errno;
e7e55dbdc38f929805ab2407fbd50886043a9e7cDavid Herrmann
ffc06c3513d9a0693c7f810d03b20705127ba55aKay Sievers close_nointr_nofail(fd);
f18ca9dcdeda247e208f7143e834fd2fb2070d80Kay Sievers
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering return err;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering}
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poetteringint hwclock_is_localtime(void) {
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering _cleanup_fclose_ FILE *f;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering
599659860c770058f2eb04d578c521c16e0b1853Lennart Poettering /*
599659860c770058f2eb04d578c521c16e0b1853Lennart Poettering * The third line of adjtime is "UTC" or "LOCAL" or nothing.
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering * # /etc/adjtime
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering * 0.0 0 0
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering * 0
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering * UTC
2311eb2ff0c3ff80ec3645b02c97170c9a565454Kay Sievers */
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering f = fopen("/etc/adjtime", "re");
bdeb9e603ab3f43d0d39f27ce6272f1114a4ee96Lennart Poettering if (f) {
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering char line[LINE_MAX];
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering bool b;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
3e5e74d5b7f6fcbeff7b6e4e06abd931aab14c48Shawn Landden b = fgets(line, sizeof(line), f) &&
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden fgets(line, sizeof(line), f) &&
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden fgets(line, sizeof(line), f);
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden if (!b)
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering return -EIO;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden truncate_nl(line);
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden return streq(line, "LOCAL");
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering } else if (errno != ENOENT)
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden return -errno;
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek return 0;
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek}
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmekint hwclock_set_timezone(int *min) {
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden const struct timeval *tv_null = NULL;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden struct timespec ts;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden struct tm *tm;
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden int minutesdelta;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering struct timezone tz;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering assert_se(tm = localtime(&ts.tv_sec));
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering minutesdelta = tm->tm_gmtoff / 60;
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek tz.tz_minuteswest = -minutesdelta;
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers tz.tz_dsttime = 0; /* DST_NONE*/
9ff09bcb86fb125768667aca9bc0b10b1745370aShawn Landden
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering /*
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek * If the hardware clock does not run in UTC, but in local time:
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek * The very first time we set the kernel's timezone, it will warp
2667cc25896a15f82f9f1583e80d416beb1316e1Thomas Hindoe Paaboel Andersen * the clock so that it runs in UTC instead of local time.
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering */
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering if (settimeofday(tv_null, &tz) < 0)
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering return -errno;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering if (min)
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering *min = minutesdelta;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering return 0;
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering}
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poetteringint hwclock_reset_timezone(void) {
d95a74ed1191bb09f5be57b0619d3d77708e019dLennart Poettering const struct timeval *tv_null = NULL;
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek struct timezone tz;
b90930c73b1c82a3dc4d4f2603799993f042aaffLennart Poettering
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering tz.tz_minuteswest = 0;
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering tz.tz_dsttime = 0; /* DST_NONE*/
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers /*
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers * The very first time we set the kernel's timezone, it will warp
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers * the clock. Do a dummy call here, so the time warping is sealed
6d0274f11547a0f11200bb82bf598a5a253e12cfLennart Poettering * and we set only the timezone with next call.
2f6a59070559786428d9eaf199ae3d61772b2225Kay Sievers */
1fc464f6fbecfc5d8ba9f7b98d19e21fb324bfb9Lennart Poettering if (settimeofday(tv_null, &tz) < 0)
ab59f4123a6f9c32953e522cc9afc5fc610d59caVedran Miletić return -errno;
ab59f4123a6f9c32953e522cc9afc5fc610d59caVedran Miletić
ab59f4123a6f9c32953e522cc9afc5fc610d59caVedran Miletić return 0;
ab59f4123a6f9c32953e522cc9afc5fc610d59caVedran Miletić}
ab59f4123a6f9c32953e522cc9afc5fc610d59caVedran Miletić