]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/clock-util.c
edd2669d0373cf6717ed9ecc7c43731848ca9be0
[thirdparty/systemd.git] / src / shared / clock-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <stdio.h>
4 #include <sys/time.h>
5
6 #include "alloc-util.h"
7 #include "clock-util.h"
8 #include "fd-util.h"
9 #include "fileio.h"
10 #include "string-util.h"
11 #include "time-util.h"
12
13 int clock_is_localtime(const char *adjtime_path) {
14 int r;
15
16 if (!adjtime_path)
17 adjtime_path = "/etc/adjtime";
18
19 /*
20 * The third line of adjtime is "UTC" or "LOCAL" or nothing.
21 * # /etc/adjtime
22 * 0.0 0 0
23 * 0
24 * UTC
25 */
26 _cleanup_fclose_ FILE *f = fopen(adjtime_path, "re");
27 if (!f) {
28 if (errno != ENOENT)
29 return -errno;
30
31 /* adjtime_path not present → default to UTC */
32 return false;
33 }
34
35 _cleanup_free_ char *line = NULL;
36 for (unsigned i = 0; i < 2; i++) { /* skip the first two lines */
37 r = read_line(f, LONG_LINE_MAX, NULL);
38 if (r < 0)
39 return r;
40 if (r == 0)
41 return false; /* less than three lines → default to UTC */
42 }
43
44 r = read_line(f, LONG_LINE_MAX, &line);
45 if (r < 0)
46 return r;
47 if (r == 0)
48 return false; /* less than three lines → default to UTC */
49
50 return streq(line, "LOCAL");
51 }
52
53 int clock_set_timezone(int *ret_minutesdelta) {
54 struct tm tm;
55 int r;
56
57 r = localtime_or_gmtime_usec(now(CLOCK_REALTIME), /* utc= */ false, &tm);
58 if (r < 0)
59 return r;
60
61 int minutesdelta = tm.tm_gmtoff / 60;
62
63 struct timezone tz = {
64 .tz_minuteswest = -minutesdelta,
65 .tz_dsttime = 0, /* DST_NONE */
66 };
67
68 /* If the RTC does not run in UTC but in local time, the very first call to settimeofday() will set
69 * the kernel's timezone and will warp the system clock, so that it runs in UTC instead of the local
70 * time we have read from the RTC. */
71 if (settimeofday(NULL, &tz) < 0)
72 return -errno;
73
74 if (ret_minutesdelta)
75 *ret_minutesdelta = minutesdelta;
76
77 return 0;
78 }