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