tzset.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #include <stdlib.h>
  2. #include <sys/types.h>
  3. #include <fcntl.h>
  4. #include <time.h>
  5. #include <ctype.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #define TZFILE "/etc/TZ"
  9. static char TZ[128];
  10. static char std[32] = "GMT0";
  11. static char dst[32];
  12. char *tzname[2] = {
  13. std, dst
  14. };
  15. time_t tzoffset, tzdstoffset;
  16. int tzdst = 0;
  17. static int
  18. offset(char *env, time_t *off)
  19. {
  20. int n, sign;
  21. size_t len, retlen;
  22. retlen = 0;
  23. sign = 1;
  24. /*
  25. * strictly, no sign is allowed in the 'time' part of the
  26. * dst start/stop rules, but who cares?
  27. */
  28. if (*env == '-' || *env == '+') {
  29. if (*env++ == '-')
  30. sign = -1;
  31. retlen++;
  32. }
  33. if ((len = strspn(env, ":0123456789")) == 0)
  34. return 0;
  35. retlen += len;
  36. for (*off = 0; len && isdigit(*env); len--) /* hours */
  37. *off = *off*10 + (*env++ - '0')*60*60;
  38. if (len) {
  39. if (*env++ != ':')
  40. return 0;
  41. len--;
  42. }
  43. for (n = 0; len && isdigit(*env); len--) /* minutes */
  44. n = n*10 + (*env++ - '0')*60;
  45. *off += n;
  46. if (len) {
  47. if (*env++ != ':')
  48. return 0;
  49. len--;
  50. }
  51. for (n = 0; len && isdigit(*env); len--) /* seconds */
  52. n = n*10 + (*env++ - '0');
  53. *off = (*off + n)*sign;
  54. return retlen;
  55. }
  56. /*
  57. * TZ=stdoffset[dst[offset][,start[/time],end[/time]]]
  58. */
  59. void
  60. tzset(void)
  61. {
  62. char *env, *p, envbuf[128];
  63. int fd, i;
  64. size_t len, retlen;
  65. time_t off;
  66. /*
  67. * get the TZ environment variable and check for validity.
  68. * the implementation-defined manner for dealing with the
  69. * leading ':' format is to reject it.
  70. * if it's ok, stash a copy away for quick comparison next time.
  71. */
  72. if ((env = getenv("TZ")) == 0) {
  73. if ((fd = open(TZFILE, O_RDONLY)) == -1)
  74. return;
  75. if (read(fd, envbuf, sizeof(envbuf)-1) == -1) {
  76. close(fd);
  77. return;
  78. }
  79. close(fd);
  80. for (i = 0; i < sizeof(envbuf); i++) {
  81. if (envbuf[i] != '\n')
  82. continue;
  83. envbuf[i] = '\0';
  84. break;
  85. }
  86. env = envbuf;
  87. }
  88. if (strcmp(env, TZ) == 0)
  89. return;
  90. if (*env == 0 || *env == ':')
  91. return;
  92. strncpy(TZ, env, sizeof(TZ)-1);
  93. TZ[sizeof(TZ)-1] = 0;
  94. /*
  95. * get the 'std' string.
  96. * before committing, check there is a valid offset.
  97. */
  98. if ((len = strcspn(env, ":0123456789,-+")) == 0)
  99. return;
  100. if ((retlen = offset(env+len, &off)) == 0)
  101. return;
  102. for (p = std, i = len+retlen; i; i--)
  103. *p++ = *env++;
  104. *p = 0;
  105. tzoffset = -off;
  106. /*
  107. * get the 'dst' string (if any).
  108. */
  109. if (*env == 0 || (len = strcspn(env, ":0123456789,-+")) == 0)
  110. return;
  111. for (p = dst; len; len--)
  112. *p++ = *env++;
  113. *p = 0;
  114. /*
  115. * optional dst offset.
  116. * default is one hour.
  117. */
  118. tzdst = 1;
  119. if (retlen = offset(env+len, &off)) {
  120. tzdstoffset = -off;
  121. env += retlen;
  122. }
  123. else
  124. tzdstoffset = tzoffset + 60*60;
  125. /*
  126. * optional rule(s) for start/end of dst.
  127. */
  128. if (*env == 0 || *env != ',' || *(env+1) == 0)
  129. return;
  130. env++;
  131. /*
  132. * we could go on...
  133. * but why bother?
  134. */
  135. }