]>
Commit | Line | Data |
---|---|---|
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 | } |