LCOV - code coverage report
Current view: top level - shared - clock-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 19 66 28.8 %
Date: 2019-08-22 15:41:25 Functions: 1 6 16.7 %

          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          11 : int clock_is_localtime(const char* adjtime_path) {
      58          11 :         _cleanup_fclose_ FILE *f;
      59             :         int r;
      60             : 
      61          11 :         if (!adjtime_path)
      62           1 :                 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          11 :         f = fopen(adjtime_path, "re");
      72          11 :         if (f) {
      73          10 :                 _cleanup_free_ char *line = NULL;
      74             :                 unsigned i;
      75             : 
      76          28 :                 for (i = 0; i < 2; i++) { /* skip the first two lines */
      77          20 :                         r = read_line(f, LONG_LINE_MAX, NULL);
      78          20 :                         if (r < 0)
      79           0 :                                 return r;
      80          20 :                         if (r == 0)
      81           2 :                                 return false; /* less than three lines → default to UTC */
      82             :                 }
      83             : 
      84           8 :                 r = read_line(f, LONG_LINE_MAX, &line);
      85           8 :                 if (r < 0)
      86           0 :                         return r;
      87           8 :                 if (r == 0)
      88           2 :                         return false; /* less than three lines → default to UTC */
      89             : 
      90           6 :                 return streq(line, "LOCAL");
      91             : 
      92           1 :         } else if (errno != ENOENT)
      93           0 :                 return -errno;
      94             : 
      95             :         /* adjtime not present → default to UTC */
      96           1 :         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             : }

Generated by: LCOV version 1.14