]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/clock-util.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / basic / clock-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
bbc98d32
KS
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
bbc98d32 21#include <errno.h>
bbc98d32 22#include <fcntl.h>
11c3a366
TA
23#include <limits.h>
24#include <stdbool.h>
25#include <time.h>
07630cea
LP
26#include <linux/rtc.h>
27#include <stdio.h>
bbc98d32 28#include <sys/ioctl.h>
bbc98d32 29#include <sys/time.h>
bbc98d32 30
3ffd4af2
LP
31#include "clock-util.h"
32#include "fd-util.h"
bbc98d32 33#include "macro.h"
07630cea 34#include "string-util.h"
9c4615fb 35#include "util.h"
bbc98d32 36
60989612 37int clock_get_hwclock(struct tm *tm) {
8e64fd11 38 _cleanup_close_ int fd = -1;
bbc98d32
KS
39
40 assert(tm);
41
67fb4482 42 fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC);
bbc98d32
KS
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)
8e64fd11 49 return -errno;
bbc98d32
KS
50
51 /* We don't know daylight saving, so we reset this in order not
2f6a5907 52 * to confuse mktime(). */
bbc98d32
KS
53 tm->tm_isdst = -1;
54
8e64fd11 55 return 0;
bbc98d32
KS
56}
57
60989612 58int clock_set_hwclock(const struct tm *tm) {
8e64fd11 59 _cleanup_close_ int fd = -1;
bbc98d32
KS
60
61 assert(tm);
62
67fb4482 63 fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC);
bbc98d32
KS
64 if (fd < 0)
65 return -errno;
66
67 if (ioctl(fd, RTC_SET_TIME, tm) < 0)
8e64fd11 68 return -errno;
bbc98d32 69
8e64fd11 70 return 0;
bbc98d32 71}
a866073d 72
6369641d 73int clock_is_localtime(const char* adjtime_path) {
7fd1b19b 74 _cleanup_fclose_ FILE *f;
bbc98d32 75
6369641d
MP
76 if (adjtime_path == NULL)
77 adjtime_path = "/etc/adjtime";
78
bbc98d32
KS
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 */
6369641d 86 f = fopen(adjtime_path, "re");
bbc98d32
KS
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);
bbc98d32 94 if (!b)
35f7216f
MP
95 /* less than three lines -> default to UTC */
96 return 0;
bbc98d32
KS
97
98 truncate_nl(line);
8e2f9ebf 99 return streq(line, "LOCAL");
bbc98d32 100
bcb161b0 101 } else if (errno != ENOENT)
bbc98d32
KS
102 return -errno;
103
35f7216f 104 /* adjtime not present -> default to UTC */
8e2f9ebf 105 return 0;
bbc98d32
KS
106}
107
24efb112 108int clock_set_timezone(int *min) {
bbc98d32
KS
109 const struct timeval *tv_null = NULL;
110 struct timespec ts;
111 struct tm *tm;
19e65613 112 int minutesdelta;
bbc98d32
KS
113 struct timezone tz;
114
115 assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
116 assert_se(tm = localtime(&ts.tv_sec));
19e65613 117 minutesdelta = tm->tm_gmtoff / 60;
bbc98d32 118
19e65613 119 tz.tz_minuteswest = -minutesdelta;
cc13b327 120 tz.tz_dsttime = 0; /* DST_NONE */
bbc98d32
KS
121
122 /*
c264aeab
KS
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.
bbc98d32
KS
127 */
128 if (settimeofday(tv_null, &tz) < 0)
9c4615fb
ZJS
129 return negative_errno();
130
bbc98d32 131 if (min)
19e65613 132 *min = minutesdelta;
bbc98d32
KS
133 return 0;
134}
135
c264aeab 136int clock_reset_timewarp(void) {
bbc98d32
KS
137 const struct timeval *tv_null = NULL;
138 struct timezone tz;
139
140 tz.tz_minuteswest = 0;
cc13b327 141 tz.tz_dsttime = 0; /* DST_NONE */
bbc98d32 142
72edcff5 143 /*
c264aeab
KS
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.
72edcff5 147 */
bbc98d32
KS
148 if (settimeofday(tv_null, &tz) < 0)
149 return -errno;
150
151 return 0;
152}
021dd87b
LP
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}