]> git.proxmox.com Git - systemd.git/blame - src/basic/clock-util.c
New upstream version 236
[systemd.git] / src / basic / clock-util.c
CommitLineData
52ad194e 1/* SPDX-License-Identifier: LGPL-2.1+ */
663996b3
MS
2/***
3 This file is part of systemd.
4
5 Copyright 2010-2012 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
663996b3 21#include <errno.h>
663996b3 22#include <fcntl.h>
4c89c718
MP
23#include <limits.h>
24#include <stdbool.h>
25#include <time.h>
db2df898
MP
26#include <linux/rtc.h>
27#include <stdio.h>
663996b3 28#include <sys/ioctl.h>
663996b3 29#include <sys/time.h>
663996b3 30
db2df898
MP
31#include "clock-util.h"
32#include "fd-util.h"
663996b3 33#include "macro.h"
db2df898 34#include "string-util.h"
663996b3 35#include "util.h"
663996b3 36
60f067b4
JS
37int clock_get_hwclock(struct tm *tm) {
38 _cleanup_close_ int fd = -1;
663996b3
MS
39
40 assert(tm);
41
42 fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC);
43 if (fd < 0)
44 return -errno;
45
46 /* This leaves the timezone fields of struct tm
47 * uninitialized! */
48 if (ioctl(fd, RTC_RD_TIME, tm) < 0)
60f067b4 49 return -errno;
663996b3
MS
50
51 /* We don't know daylight saving, so we reset this in order not
60f067b4 52 * to confuse mktime(). */
663996b3
MS
53 tm->tm_isdst = -1;
54
60f067b4 55 return 0;
663996b3
MS
56}
57
60f067b4
JS
58int clock_set_hwclock(const struct tm *tm) {
59 _cleanup_close_ int fd = -1;
663996b3
MS
60
61 assert(tm);
62
63 fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC);
64 if (fd < 0)
65 return -errno;
66
67 if (ioctl(fd, RTC_SET_TIME, tm) < 0)
60f067b4 68 return -errno;
663996b3 69
60f067b4 70 return 0;
663996b3
MS
71}
72
aa27b158 73int clock_is_localtime(const char* adjtime_path) {
663996b3
MS
74 _cleanup_fclose_ FILE *f;
75
52ad194e 76 if (!adjtime_path)
aa27b158
MP
77 adjtime_path = "/etc/adjtime";
78
663996b3
MS
79 /*
80 * The third line of adjtime is "UTC" or "LOCAL" or nothing.
81 * # /etc/adjtime
82 * 0.0 0 0
83 * 0
84 * UTC
85 */
aa27b158 86 f = fopen(adjtime_path, "re");
663996b3
MS
87 if (f) {
88 char line[LINE_MAX];
89 bool b;
90
91 b = fgets(line, sizeof(line), f) &&
92 fgets(line, sizeof(line), f) &&
93 fgets(line, sizeof(line), f);
94 if (!b)
aa27b158
MP
95 /* less than three lines -> default to UTC */
96 return 0;
663996b3
MS
97
98 truncate_nl(line);
99 return streq(line, "LOCAL");
100
101 } else if (errno != ENOENT)
102 return -errno;
103
aa27b158 104 /* adjtime not present -> default to UTC */
663996b3
MS
105 return 0;
106}
107
60f067b4 108int clock_set_timezone(int *min) {
663996b3
MS
109 const struct timeval *tv_null = NULL;
110 struct timespec ts;
111 struct tm *tm;
112 int minutesdelta;
113 struct timezone tz;
114
115 assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
116 assert_se(tm = localtime(&ts.tv_sec));
117 minutesdelta = tm->tm_gmtoff / 60;
118
119 tz.tz_minuteswest = -minutesdelta;
e735f4d4 120 tz.tz_dsttime = 0; /* DST_NONE */
663996b3
MS
121
122 /*
5eef597e
MP
123 * If the RTC does not run in UTC but in local time, the very first
124 * call to settimeofday() will set the kernel's timezone and will warp the
125 * system clock, so that it runs in UTC instead of the local time we
126 * have read from the RTC.
663996b3
MS
127 */
128 if (settimeofday(tv_null, &tz) < 0)
4c89c718
MP
129 return negative_errno();
130
663996b3
MS
131 if (min)
132 *min = minutesdelta;
133 return 0;
134}
135
5eef597e 136int clock_reset_timewarp(void) {
663996b3
MS
137 const struct timeval *tv_null = NULL;
138 struct timezone tz;
139
140 tz.tz_minuteswest = 0;
e735f4d4 141 tz.tz_dsttime = 0; /* DST_NONE */
663996b3
MS
142
143 /*
5eef597e
MP
144 * The very first call to settimeofday() does time warp magic. Do a
145 * dummy call here, so the time warping is sealed and all later calls
146 * behave as expected.
663996b3
MS
147 */
148 if (settimeofday(tv_null, &tz) < 0)
149 return -errno;
150
151 return 0;
152}
4c89c718
MP
153
154#define TIME_EPOCH_USEC ((usec_t) TIME_EPOCH * USEC_PER_SEC)
155
156int clock_apply_epoch(void) {
157 struct timespec ts;
158
159 if (now(CLOCK_REALTIME) >= TIME_EPOCH_USEC)
160 return 0;
161
162 if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, TIME_EPOCH_USEC)) < 0)
163 return -errno;
164
165 return 1;
166}