rtc.c 2.1 KB

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