rtc.c 2.0 KB

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