diff options
author | Kay Sievers <kay@vrfy.org> | 2015-03-24 13:52:04 +0100 |
---|---|---|
committer | Kay Sievers <kay@vrfy.org> | 2015-03-24 15:03:36 +0100 |
commit | 16c6ea29348ddac73998f339166f863bee0dfef6 (patch) | |
tree | 03cc2575b9c645eb22a92d09b072dc945cfe16de /src | |
parent | 3e5e74d5b7f6fcbeff7b6e4e06abd931aab14c48 (diff) |
timedate: remove daylight saving time handling and tzfile parser
We planned to support (the conceptually broken) daylight saving
time/local time features in the kernel, SCSI, networking, FAT
filesystem, but it turned out to be a race we cannot win and do
not want to get involved. Systemd should not fiddle with daylight
saving time or parse timezone information itself.
Leave everything to glibc or tools like date(1) and do not make any
promises or raise expectations that systemd should handle anything
like this.
Diffstat (limited to 'src')
-rw-r--r-- | src/shared/time-dst.c | 329 | ||||
-rw-r--r-- | src/shared/time-dst.h | 26 | ||||
-rw-r--r-- | src/timedate/timedatectl.c | 56 |
3 files changed, 0 insertions, 411 deletions
diff --git a/src/shared/time-dst.c b/src/shared/time-dst.c deleted file mode 100644 index 2797d1a796..0000000000 --- a/src/shared/time-dst.c +++ /dev/null @@ -1,329 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Timezone file reading code from glibc 2.16. - - Copyright (C) 1991-2012 Free Software Foundation, Inc. - Copyright 2012 Kay Sievers - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ -#include <errno.h> -#include <stddef.h> -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <endian.h> -#include <stdint.h> -#include <stdbool.h> -#include <sys/stat.h> - -#include "time-dst.h" -#include "util.h" - -/* - * If tzh_version is '2' or greater, the above is followed by a second instance - * of tzhead and a second instance of the data in which each coded transition - * time uses 8 rather than 4 chars, then a POSIX-TZ-environment-variable-style - * string for use in handling instants after the last transition time stored in - * the file * (with nothing between the newlines if there is no POSIX - * representation for such instants). - */ -#define TZ_MAGIC "TZif" -struct tzhead { - char tzh_magic[4]; /* TZ_MAGIC */ - char tzh_version[1]; /* '\0' or '2' as of 2005 */ - char tzh_reserved[15]; /* reserved--must be zero */ - char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ - char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ - char tzh_leapcnt[4]; /* coded number of leap seconds */ - char tzh_timecnt[4]; /* coded number of transition times */ - char tzh_typecnt[4]; /* coded number of local time types */ - char tzh_charcnt[4]; /* coded number of abbr. chars */ -}; - -struct ttinfo { - long int offset; /* Seconds east of GMT. */ - unsigned char isdst; /* Used to set tm_isdst. */ - unsigned char idx; /* Index into `zone_names'. */ - unsigned char isstd; /* Transition times are in standard time. */ - unsigned char isgmt; /* Transition times are in GMT. */ -}; - -struct leap { - time_t transition; /* Time the transition takes effect. */ - long int change; /* Seconds of correction to apply. */ -}; - -static inline int decode(const void *ptr) { - return be32toh(*(int *)ptr); -} - -static inline int64_t decode64(const void *ptr) { - return be64toh(*(int64_t *)ptr); -} - -int time_get_dst(time_t date, const char *tzfile, - time_t *switch_cur, char **zone_cur, bool *dst_cur, - time_t *switch_next, int *delta_next, char **zone_next, bool *dst_next) { - unsigned char *type_idxs = 0; - size_t num_types = 0; - struct ttinfo *types = NULL; - char *zone_names = NULL; - struct stat st; - size_t num_isstd, num_isgmt; - struct tzhead tzhead; - size_t chars; - size_t i; - size_t total_size; - size_t types_idx; - int trans_width = 4; - size_t tzspec_len; - size_t num_leaps; - size_t lo, hi; - size_t num_transitions = 0; - _cleanup_free_ time_t *transitions = NULL; - _cleanup_fclose_ FILE *f; - - f = fopen(tzfile, "re"); - if (f == NULL) - return -errno; - - if (fstat(fileno(f), &st) < 0) - return -errno; - -read_again: - if (fread((void *)&tzhead, sizeof(tzhead), 1, f) != 1 || - memcmp(tzhead.tzh_magic, TZ_MAGIC, sizeof(tzhead.tzh_magic)) != 0) - return -EINVAL; - - num_transitions = (size_t)decode(tzhead.tzh_timecnt); - num_types = (size_t)decode(tzhead.tzh_typecnt); - chars = (size_t)decode(tzhead.tzh_charcnt); - num_leaps = (size_t)decode(tzhead.tzh_leapcnt); - num_isstd = (size_t)decode(tzhead.tzh_ttisstdcnt); - num_isgmt = (size_t)decode(tzhead.tzh_ttisgmtcnt); - - /* For platforms with 64-bit time_t we use the new format if available. */ - if (sizeof(time_t) == 8 && trans_width == 4 && tzhead.tzh_version[0] != '\0') { - size_t to_skip; - - /* We use the 8-byte format. */ - trans_width = 8; - - /* Position the stream before the second header. */ - to_skip = (num_transitions * (4 + 1) - + num_types * 6 - + chars - + num_leaps * 8 + num_isstd + num_isgmt); - if (fseek(f, to_skip, SEEK_CUR) != 0) - return -EINVAL; - - goto read_again; - } - - if (num_transitions > ((SIZE_MAX - (__alignof__(struct ttinfo) - 1)) / (sizeof(time_t) + 1))) - return -EINVAL; - - total_size = num_transitions * (sizeof(time_t) + 1); - total_size = ((total_size + __alignof__(struct ttinfo) - 1) & ~(__alignof__(struct ttinfo) - 1)); - types_idx = total_size; - if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct ttinfo)) - return -EINVAL; - - total_size += num_types * sizeof(struct ttinfo); - if (chars > SIZE_MAX - total_size) - return -EINVAL; - - total_size += chars; - if (__alignof__(struct leap) - 1 > SIZE_MAX - total_size) - return -EINVAL; - - total_size = ((total_size + __alignof__(struct leap) - 1) & ~(__alignof__(struct leap) - 1)); - if (num_leaps > (SIZE_MAX - total_size) / sizeof(struct leap)) - return -EINVAL; - - total_size += num_leaps * sizeof(struct leap); - tzspec_len = 0; - if (sizeof(time_t) == 8 && trans_width == 8) { - off_t rem = st.st_size - ftello(f); - - if (rem < 0 || (size_t) rem < (num_transitions * (8 + 1) + num_types * 6 + chars)) - return -EINVAL; - tzspec_len = (size_t) rem - (num_transitions * (8 + 1) + num_types * 6 + chars); - if (num_leaps > SIZE_MAX / 12 || tzspec_len < num_leaps * 12) - return -EINVAL; - tzspec_len -= num_leaps * 12; - if (tzspec_len < num_isstd) - return -EINVAL; - tzspec_len -= num_isstd; - if (tzspec_len == 0 || tzspec_len - 1 < num_isgmt) - return -EINVAL; - tzspec_len -= num_isgmt + 1; - if (SIZE_MAX - total_size < tzspec_len) - return -EINVAL; - } - - /* leave space for additional zone_names zero terminator */ - transitions = malloc0(total_size + tzspec_len + 1); - if (transitions == NULL) - return -EINVAL; - - type_idxs = (unsigned char *)transitions + (num_transitions - * sizeof(time_t)); - types = (struct ttinfo *)((char *)transitions + types_idx); - zone_names = (char *)types + num_types * sizeof(struct ttinfo); - - if (sizeof(time_t) == 4 || trans_width == 8) { - if (fread(transitions, trans_width + 1, num_transitions, f) != num_transitions) - return -EINVAL; - } else { - if (fread(transitions, 4, num_transitions, f) != num_transitions || - fread(type_idxs, 1, num_transitions, f) != num_transitions) - return -EINVAL; - } - - /* Check for bogus indices in the data file, so we can hereafter - safely use type_idxs[T] as indices into `types' and never crash. */ - for (i = 0; i < num_transitions; ++i) - if (type_idxs[i] >= num_types) - return -EINVAL; - - if (__BYTE_ORDER == __BIG_ENDIAN ? sizeof(time_t) == 8 && trans_width == 4 - : sizeof(time_t) == 4 || trans_width == 4) { - /* Decode the transition times, stored as 4-byte integers in - network (big-endian) byte order. We work from the end of - the array so as not to clobber the next element to be - processed when sizeof (time_t) > 4. */ - i = num_transitions; - while (i-- > 0) - transitions[i] = decode((char *)transitions + i * 4); - } else if (__BYTE_ORDER != __BIG_ENDIAN && sizeof(time_t) == 8) { - /* Decode the transition times, stored as 8-byte integers in - network (big-endian) byte order. */ - for (i = 0; i < num_transitions; ++i) - transitions[i] = decode64((char *)transitions + i * 8); - } - - for (i = 0; i < num_types; ++i) { - unsigned char x[4]; - int c; - - if (fread(x, 1, sizeof(x), f) != sizeof(x)) - return -EINVAL; - c = getc(f); - if ((unsigned int)c > 1u) - return -EINVAL; - types[i].isdst = c; - c = getc(f); - if ((size_t) c > chars) - /* Bogus index in data file. */ - return -EINVAL; - types[i].idx = c; - types[i].offset = (long int)decode(x); - } - - if (fread(zone_names, 1, chars, f) != chars) - return -EINVAL; - - zone_names[chars] = '\0'; - - for (i = 0; i < num_isstd; ++i) { - int c = getc(f); - if (c == EOF) - return -EINVAL; - types[i].isstd = c != 0; - } - - while (i < num_types) - types[i++].isstd = 0; - - for (i = 0; i < num_isgmt; ++i) { - int c = getc(f); - if (c == EOF) - return -EINVAL; - types[i].isgmt = c != 0; - } - - while (i < num_types) - types[i++].isgmt = 0; - - if (num_transitions == 0) - return -EINVAL; - - if (date < transitions[0] || date >= transitions[num_transitions - 1]) - return -EINVAL; - - /* Find the first transition after TIMER, and - then pick the type of the transition before it. */ - lo = 0; - hi = num_transitions - 1; - - /* Assume that DST is changing twice a year and guess initial - search spot from it. - Half of a gregorian year has on average 365.2425 * 86400 / 2 - = 15778476 seconds. */ - i = (transitions[num_transitions - 1] - date) / 15778476; - if (i < num_transitions) { - i = num_transitions - 1 - i; - if (date < transitions[i]) { - if (i < 10 || date >= transitions[i - 10]) { - /* Linear search. */ - while (date < transitions[i - 1]) - i--; - goto found; - } - hi = i - 10; - } else { - if (i + 10 >= num_transitions || date < transitions[i + 10]) { - /* Linear search. */ - while (date >= transitions[i]) - i++; - goto found; - } - lo = i + 10; - } - } - - /* Binary search. */ - while (lo + 1 < hi) { - i = (lo + hi) / 2; - if (date < transitions[i]) - hi = i; - else - lo = i; - } - i = hi; - -found: - if (switch_cur) - *switch_cur = transitions[i-1]; - if (zone_cur) - *zone_cur = strdup(&zone_names[types[type_idxs[i - 1]].idx]); - if (dst_cur) - *dst_cur = types[type_idxs[i-1]].isdst; - - if (switch_next) - *switch_next = transitions[i]; - if (delta_next) - *delta_next = (types[type_idxs[i]].offset - types[type_idxs[i-1]].offset) / 60; - if (zone_next) - *zone_next = strdup(&zone_names[types[type_idxs[i]].idx]); - if (dst_next) - *dst_next = types[type_idxs[i]].isdst; - - return 0; -} diff --git a/src/shared/time-dst.h b/src/shared/time-dst.h deleted file mode 100644 index 536b6bbdfb..0000000000 --- a/src/shared/time-dst.h +++ /dev/null @@ -1,26 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2012 Kay Sievers - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -int time_get_dst(time_t date, const char *tzfile, - time_t *switch_cur, char **zone_cur, bool *dst_cur, - time_t *switch_next, int *delta_next, char **zone_next, bool *dst_next); diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 44d329ecc2..ab5c8a1f6a 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -33,7 +33,6 @@ #include "build.h" #include "strv.h" #include "pager.h" -#include "time-dst.h" static bool arg_no_pager = false; static bool arg_ask_password = true; @@ -73,33 +72,12 @@ typedef struct StatusInfo { bool ntp_synced; } StatusInfo; -static const char *jump_str(int delta_minutes, char *s, size_t size) { - if (delta_minutes == 60) - return "one hour forward"; - if (delta_minutes == -60) - return "one hour backwards"; - if (delta_minutes < 0) { - snprintf(s, size, "%i minutes backwards", -delta_minutes); - return s; - } - if (delta_minutes > 0) { - snprintf(s, size, "%i minutes forward", delta_minutes); - return s; - } - return ""; -} - static void print_status_info(const StatusInfo *i) { char a[FORMAT_TIMESTAMP_MAX]; - char b[FORMAT_TIMESTAMP_MAX]; - char s[32]; struct tm tm; time_t sec; bool have_time = false; _cleanup_free_ char *zc = NULL, *zn = NULL; - time_t t, tc, tn; - int dn = 0; - bool is_dstc = false, is_dstn = false; int r; assert(i); @@ -158,40 +136,6 @@ static void print_status_info(const StatusInfo *i) { yes_no(i->ntp_synced), yes_no(i->rtc_local)); - if (have_time) { - r = time_get_dst(sec, "/etc/localtime", - &tc, &zc, &is_dstc, - &tn, &dn, &zn, &is_dstn); - if (r < 0) - printf(" DST active: %s\n", "n/a"); - else { - printf(" DST active: %s\n", yes_no(is_dstc)); - - t = tc - 1; - xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)); - - xstrftime(b, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tc, &tm)); - printf(" Last DST change: DST %s at\n" - " %.*s\n" - " %.*s\n", - is_dstc ? "began" : "ended", - (int) sizeof(a), a, - (int) sizeof(b), b); - - t = tn - 1; - xstrftime(a, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&t, &tm)); - xstrftime(b, "%a %Y-%m-%d %H:%M:%S %Z", localtime_r(&tn, &tm)); - printf(" Next DST change: DST %s (the clock jumps %s) at\n" - " %.*s\n" - " %.*s\n", - is_dstn ? "begins" : "ends", - jump_str(dn, s, sizeof(s)), - (int) sizeof(a), a, - (int) sizeof(b), b); - } - } else - printf(" DST active: %s\n", yes_no(is_dstc)); - if (i->rtc_local) fputs("\n" ANSI_HIGHLIGHT_ON "Warning: The system is configured to read the RTC time in the local time zone. This\n" |