busybox/libbb/rtc.c
<<
>>
Prefs
   1/*
   2 * Common RTC functions
   3 *
   4 * Licensed under GPLv2, see file LICENSE in this source tree.
   5 */
   6
   7#include "libbb.h"
   8#include "rtc_.h"
   9
  10#if ENABLE_FEATURE_HWCLOCK_ADJTIME_FHS
  11# define ADJTIME_PATH "/var/lib/hwclock/adjtime"
  12#else
  13# define ADJTIME_PATH "/etc/adjtime"
  14#endif
  15
  16int FAST_FUNC rtc_adjtime_is_utc(void)
  17{
  18        int utc = 0;
  19        FILE *f = fopen_for_read(ADJTIME_PATH);
  20
  21        if (f) {
  22                char buffer[128];
  23
  24                while (fgets(buffer, sizeof(buffer), f)) {
  25                        if (is_prefixed_with(buffer, "UTC")) {
  26                                utc = 1;
  27                                break;
  28                        }
  29                }
  30                fclose(f);
  31        }
  32
  33        return utc;
  34}
  35
  36/* rtc opens are exclusive.
  37 * Try to run two "hwclock -w" at the same time to see it.
  38 * Users wouldn't expect that to fail merely because /dev/rtc
  39 * was momentarily busy, let's try a bit harder on errno == EBUSY.
  40 */
  41static int open_loop_on_busy(const char *name, int flags)
  42{
  43        int rtc;
  44        /*
  45         * Tested with two parallel "hwclock -w" loops.
  46         * With try = 10, no failures with 2x1000000 loop iterations.
  47         */
  48        int try = 1000 / 20;
  49 again:
  50        errno = 0;
  51        rtc = open(name, flags);
  52        if (errno == EBUSY) {
  53                usleep(20 * 1000);
  54                if (--try != 0)
  55                        goto again;
  56                /* EBUSY. Last try, exit on error instead of returning -1 */
  57                return xopen(name, flags);
  58        }
  59        return rtc;
  60}
  61
  62/* Never fails */
  63int FAST_FUNC rtc_xopen(const char **default_rtc, int flags)
  64{
  65        int rtc;
  66        const char *name =
  67                "/dev/rtc""\0"
  68                "/dev/rtc0""\0"
  69                "/dev/misc/rtc""\0";
  70
  71        if (!*default_rtc)
  72                goto try_name;
  73        name = ""; /*else: we have rtc name, don't try other names */
  74
  75        for (;;) {
  76                rtc = open_loop_on_busy(*default_rtc, flags);
  77                if (rtc >= 0)
  78                        return rtc;
  79                if (!name[0])
  80                        return xopen(*default_rtc, flags);
  81 try_name:
  82                *default_rtc = name;
  83                name += strlen(name) + 1;
  84        }
  85}
  86
  87void FAST_FUNC rtc_read_tm(struct tm *ptm, int fd)
  88{
  89        memset(ptm, 0, sizeof(*ptm));
  90        xioctl(fd, RTC_RD_TIME, ptm);
  91        ptm->tm_isdst = -1; /* "not known" */
  92}
  93
  94time_t FAST_FUNC rtc_tm2time(struct tm *ptm, int utc)
  95{
  96        char *oldtz = oldtz; /* for compiler */
  97        time_t t;
  98
  99        if (utc) {
 100                oldtz = getenv("TZ");
 101                putenv((char*)"TZ=UTC0");
 102                tzset();
 103        }
 104
 105        t = mktime(ptm);
 106
 107        if (utc) {
 108                unsetenv("TZ");
 109                if (oldtz)
 110                        putenv(oldtz - 3);
 111                tzset();
 112        }
 113
 114        return t;
 115}
 116