123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- /*
- * Common RTC functions
- *
- * Licensed under GPLv2, see file LICENSE in this source tree.
- */
- #include "libbb.h"
- #include "rtc_.h"
- #if ENABLE_FEATURE_HWCLOCK_ADJTIME_FHS
- # define ADJTIME_PATH "/var/lib/hwclock/adjtime"
- #else
- # define ADJTIME_PATH "/etc/adjtime"
- #endif
- int FAST_FUNC rtc_adjtime_is_utc(void)
- {
- int utc = 0;
- FILE *f = fopen_for_read(ADJTIME_PATH);
- if (f) {
- char buffer[128];
- while (fgets(buffer, sizeof(buffer), f)) {
- if (is_prefixed_with(buffer, "UTC")) {
- utc = 1;
- break;
- }
- }
- fclose(f);
- }
- return utc;
- }
- /* rtc opens are exclusive.
- * Try to run two "hwclock -w" at the same time to see it.
- * Users wouldn't expect that to fail merely because /dev/rtc
- * was momentarily busy, let's try a bit harder on errno == EBUSY.
- */
- static int open_loop_on_busy(const char *name, int flags)
- {
- int rtc;
- /*
- * Tested with two parallel "hwclock -w" loops.
- * With try = 10, no failures with 2x1000000 loop iterations.
- */
- int try = 1000 / 20;
- again:
- errno = 0;
- rtc = open(name, flags);
- if (errno == EBUSY) {
- usleep(20 * 1000);
- if (--try != 0)
- goto again;
- /* EBUSY. Last try, exit on error instead of returning -1 */
- return xopen(name, flags);
- }
- return rtc;
- }
- /* Never fails */
- int FAST_FUNC rtc_xopen(const char **default_rtc, int flags)
- {
- int rtc;
- const char *name =
- "/dev/rtc""\0"
- "/dev/rtc0""\0"
- "/dev/misc/rtc""\0";
- if (!*default_rtc)
- goto try_name;
- name = ""; /*else: we have rtc name, don't try other names */
- for (;;) {
- rtc = open_loop_on_busy(*default_rtc, flags);
- if (rtc >= 0)
- return rtc;
- if (!name[0])
- return xopen(*default_rtc, flags);
- try_name:
- *default_rtc = name;
- name += strlen(name) + 1;
- }
- }
- void FAST_FUNC rtc_read_tm(struct tm *ptm, int fd)
- {
- memset(ptm, 0, sizeof(*ptm));
- xioctl(fd, RTC_RD_TIME, ptm);
- ptm->tm_isdst = -1; /* "not known" */
- }
- time_t FAST_FUNC rtc_tm2time(struct tm *ptm, int utc)
- {
- char *oldtz = oldtz; /* for compiler */
- time_t t;
- if (utc) {
- oldtz = getenv("TZ");
- putenv((char*)"TZ=UTC0");
- tzset();
- }
- t = mktime(ptm);
- if (utc) {
- unsetenv("TZ");
- if (oldtz)
- putenv(oldtz - 3);
- tzset();
- }
- return t;
- }
|