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