Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */ 2 : : 3 : : #include <errno.h> 4 : : #include <fcntl.h> 5 : : #include <limits.h> 6 : : #include <stdbool.h> 7 : : #include <time.h> 8 : : #include <linux/rtc.h> 9 : : #include <stdio.h> 10 : : #include <sys/ioctl.h> 11 : : #include <sys/time.h> 12 : : 13 : : #include "alloc-util.h" 14 : : #include "clock-util.h" 15 : : #include "errno-util.h" 16 : : #include "fd-util.h" 17 : : #include "fileio.h" 18 : : #include "macro.h" 19 : : #include "string-util.h" 20 : : 21 : 0 : int clock_get_hwclock(struct tm *tm) { 22 : 0 : _cleanup_close_ int fd = -1; 23 : : 24 [ # # ]: 0 : assert(tm); 25 : : 26 : 0 : fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC); 27 [ # # ]: 0 : if (fd < 0) 28 : 0 : return -errno; 29 : : 30 : : /* This leaves the timezone fields of struct tm 31 : : * uninitialized! */ 32 [ # # ]: 0 : if (ioctl(fd, RTC_RD_TIME, tm) < 0) 33 : 0 : return -errno; 34 : : 35 : : /* We don't know daylight saving, so we reset this in order not 36 : : * to confuse mktime(). */ 37 : 0 : tm->tm_isdst = -1; 38 : : 39 : 0 : return 0; 40 : : } 41 : : 42 : 0 : int clock_set_hwclock(const struct tm *tm) { 43 : 0 : _cleanup_close_ int fd = -1; 44 : : 45 [ # # ]: 0 : assert(tm); 46 : : 47 : 0 : fd = open("/dev/rtc", O_RDONLY|O_CLOEXEC); 48 [ # # ]: 0 : if (fd < 0) 49 : 0 : return -errno; 50 : : 51 [ # # ]: 0 : if (ioctl(fd, RTC_SET_TIME, tm) < 0) 52 : 0 : return -errno; 53 : : 54 : 0 : return 0; 55 : : } 56 : : 57 : 44 : int clock_is_localtime(const char* adjtime_path) { 58 : 44 : _cleanup_fclose_ FILE *f; 59 : : int r; 60 : : 61 [ + + ]: 44 : if (!adjtime_path) 62 : 4 : adjtime_path = "/etc/adjtime"; 63 : : 64 : : /* 65 : : * The third line of adjtime is "UTC" or "LOCAL" or nothing. 66 : : * # /etc/adjtime 67 : : * 0.0 0 0 68 : : * 0 69 : : * UTC 70 : : */ 71 : 44 : f = fopen(adjtime_path, "re"); 72 [ + + ]: 44 : if (f) { 73 : 40 : _cleanup_free_ char *line = NULL; 74 : : unsigned i; 75 : : 76 [ + + ]: 112 : for (i = 0; i < 2; i++) { /* skip the first two lines */ 77 : 80 : r = read_line(f, LONG_LINE_MAX, NULL); 78 [ - + ]: 80 : if (r < 0) 79 : 0 : return r; 80 [ + + ]: 80 : if (r == 0) 81 : 8 : return false; /* less than three lines → default to UTC */ 82 : : } 83 : : 84 : 32 : r = read_line(f, LONG_LINE_MAX, &line); 85 [ - + ]: 32 : if (r < 0) 86 : 0 : return r; 87 [ + + ]: 32 : if (r == 0) 88 : 8 : return false; /* less than three lines → default to UTC */ 89 : : 90 : 24 : return streq(line, "LOCAL"); 91 : : 92 [ - + ]: 4 : } else if (errno != ENOENT) 93 : 0 : return -errno; 94 : : 95 : : /* adjtime not present → default to UTC */ 96 : 4 : return false; 97 : : } 98 : : 99 : 0 : int clock_set_timezone(int *min) { 100 : 0 : const struct timeval *tv_null = NULL; 101 : : struct timespec ts; 102 : : struct tm tm; 103 : : int minutesdelta; 104 : : struct timezone tz; 105 : : 106 [ # # ]: 0 : assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0); 107 [ # # ]: 0 : assert_se(localtime_r(&ts.tv_sec, &tm)); 108 : 0 : minutesdelta = tm.tm_gmtoff / 60; 109 : : 110 : 0 : tz.tz_minuteswest = -minutesdelta; 111 : 0 : tz.tz_dsttime = 0; /* DST_NONE */ 112 : : 113 : : /* 114 : : * If the RTC does not run in UTC but in local time, the very first 115 : : * call to settimeofday() will set the kernel's timezone and will warp the 116 : : * system clock, so that it runs in UTC instead of the local time we 117 : : * have read from the RTC. 118 : : */ 119 [ # # ]: 0 : if (settimeofday(tv_null, &tz) < 0) 120 : 0 : return negative_errno(); 121 : : 122 [ # # ]: 0 : if (min) 123 : 0 : *min = minutesdelta; 124 : 0 : return 0; 125 : : } 126 : : 127 : 0 : int clock_reset_timewarp(void) { 128 : 0 : const struct timeval *tv_null = NULL; 129 : : struct timezone tz; 130 : : 131 : 0 : tz.tz_minuteswest = 0; 132 : 0 : tz.tz_dsttime = 0; /* DST_NONE */ 133 : : 134 : : /* 135 : : * The very first call to settimeofday() does time warp magic. Do a 136 : : * dummy call here, so the time warping is sealed and all later calls 137 : : * behave as expected. 138 : : */ 139 [ # # ]: 0 : if (settimeofday(tv_null, &tz) < 0) 140 : 0 : return -errno; 141 : : 142 : 0 : return 0; 143 : : } 144 : : 145 : : #define TIME_EPOCH_USEC ((usec_t) TIME_EPOCH * USEC_PER_SEC) 146 : : 147 : 0 : int clock_apply_epoch(void) { 148 : : struct timespec ts; 149 : : 150 [ # # ]: 0 : if (now(CLOCK_REALTIME) >= TIME_EPOCH_USEC) 151 : 0 : return 0; 152 : : 153 [ # # ]: 0 : if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, TIME_EPOCH_USEC)) < 0) 154 : 0 : return -errno; 155 : : 156 : 0 : return 1; 157 : : }