~ubuntu-branches/ubuntu/trusty/bash/trusty-security

« back to all changes in this revision

Viewing changes to lib/sh/mktime.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2014-03-03 22:52:05 UTC
  • mfrom: (1.3.5) (2.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20140303225205-87ltrt5kspeq0g1b
Tags: 4.3-1ubuntu1
* Merge with Debian; remaining changes:
  - skel.bashrc:
    - Run lesspipe.
    - Enable ls aliases.
    - Set options in ll alias to -alF.
    - Define an alert alias.
    - Enabled colored grep aliases.
  - etc.bash.bashrc:
    - Add sudo hint.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* mktime - convert struct tm to a time_t value */
 
2
 
 
3
/* Copyright (C) 1993-2002 Free Software Foundation, Inc.
 
4
 
 
5
   This file is part of GNU Bash, the Bourne Again SHell.
 
6
   Contributed by Paul Eggert (eggert@twinsun.com).
 
7
 
 
8
   Bash is free software: you can redistribute it and/or modify
 
9
   it under the terms of the GNU General Public License as published by
 
10
   the Free Software Foundation, either version 3 of the License, or
 
11
   (at your option) any later version.
 
12
 
 
13
   Bash is distributed in the hope that it will be useful,
 
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
   GNU General Public License for more details.
 
17
 
 
18
   You should have received a copy of the GNU General Public License
 
19
   along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 
20
*/
 
21
/* Define this to have a standalone program to test this implementation of
 
22
   mktime.  */
 
23
/* #define DEBUG 1 */
 
24
 
 
25
#ifdef HAVE_CONFIG_H
 
26
#include <config.h>
 
27
#endif
 
28
 
 
29
#ifdef _LIBC
 
30
# define HAVE_LIMITS_H 1
 
31
# define HAVE_LOCALTIME_R 1
 
32
# define STDC_HEADERS 1
 
33
#endif
 
34
 
 
35
/* Assume that leap seconds are possible, unless told otherwise.
 
36
   If the host has a `zic' command with a `-L leapsecondfilename' option,
 
37
   then it supports leap seconds; otherwise it probably doesn't.  */
 
38
#ifndef LEAP_SECONDS_POSSIBLE
 
39
#define LEAP_SECONDS_POSSIBLE 1
 
40
#endif
 
41
 
 
42
#ifndef VMS
 
43
#include <sys/types.h>          /* Some systems define `time_t' here.  */
 
44
#endif
 
45
#include <time.h>
 
46
 
 
47
#if HAVE_LIMITS_H
 
48
#include <limits.h>
 
49
#endif
 
50
 
 
51
#include "bashansi.h"
 
52
 
 
53
#if DEBUG
 
54
#include <stdio.h>
 
55
/* Make it work even if the system's libc has its own mktime routine.  */
 
56
#define mktime my_mktime
 
57
#endif /* DEBUG */
 
58
 
 
59
#ifndef __P
 
60
#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
 
61
#define __P(args) args
 
62
#else
 
63
#define __P(args) ()
 
64
#endif  /* GCC.  */
 
65
#endif  /* Not __P.  */
 
66
 
 
67
#ifndef CHAR_BIT
 
68
#define CHAR_BIT 8
 
69
#endif
 
70
 
 
71
#ifndef INT_MIN
 
72
#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
 
73
#endif
 
74
#ifndef INT_MAX
 
75
#define INT_MAX (~0 - INT_MIN)
 
76
#endif
 
77
 
 
78
#ifndef TIME_T_MIN
 
79
#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
 
80
                    : ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
 
81
#endif
 
82
#ifndef TIME_T_MAX
 
83
#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
 
84
#endif
 
85
 
 
86
#define TM_YEAR_BASE 1900
 
87
#define EPOCH_YEAR 1970
 
88
 
 
89
#ifndef __isleap
 
90
/* Nonzero if YEAR is a leap year (every 4 years,
 
91
   except every 100th isn't, and every 400th is).  */
 
92
#define __isleap(year)  \
 
93
  ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
 
94
#endif
 
95
 
 
96
/* How many days come before each month (0-12).  */
 
97
const unsigned short int __mon_yday[2][13] =
 
98
  {
 
99
    /* Normal years.  */
 
100
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
 
101
    /* Leap years.  */
 
102
    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
 
103
  };
 
104
 
 
105
static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
 
106
time_t __mktime_internal __P ((struct tm *,
 
107
                               struct tm *(*) (const time_t *, struct tm *),
 
108
                               time_t *));
 
109
 
 
110
 
 
111
static struct tm *my_localtime_r __P ((const time_t *, struct tm *));
 
112
static struct tm *
 
113
my_localtime_r (t, tp)
 
114
     const time_t *t;
 
115
     struct tm *tp;
 
116
{
 
117
  struct tm *l = localtime (t);
 
118
  if (! l)
 
119
    return 0;
 
120
  *tp = *l;
 
121
  return tp;
 
122
}
 
123
 
 
124
 
 
125
/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
 
126
   measured in seconds, ignoring leap seconds.
 
127
   YEAR uses the same numbering as TM->tm_year.
 
128
   All values are in range, except possibly YEAR.
 
129
   If overflow occurs, yield the low order bits of the correct answer.  */
 
130
static time_t
 
131
ydhms_tm_diff (year, yday, hour, min, sec, tp)
 
132
     int year, yday, hour, min, sec;
 
133
     const struct tm *tp;
 
134
{
 
135
  /* Compute intervening leap days correctly even if year is negative.
 
136
     Take care to avoid int overflow.  time_t overflow is OK, since
 
137
     only the low order bits of the correct time_t answer are needed.
 
138
     Don't convert to time_t until after all divisions are done, since
 
139
     time_t might be unsigned.  */
 
140
  int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
 
141
  int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
 
142
  int a100 = a4 / 25 - (a4 % 25 < 0);
 
143
  int b100 = b4 / 25 - (b4 % 25 < 0);
 
144
  int a400 = a100 >> 2;
 
145
  int b400 = b100 >> 2;
 
146
  int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
 
147
  time_t years = year - (time_t) tp->tm_year;
 
148
  time_t days = (365 * years + intervening_leap_days
 
149
                 + (yday - tp->tm_yday));
 
150
  return (60 * (60 * (24 * days + (hour - tp->tm_hour))
 
151
                + (min - tp->tm_min))
 
152
          + (sec - tp->tm_sec));
 
153
}
 
154
 
 
155
 
 
156
static time_t localtime_offset;
 
157
 
 
158
/* Convert *TP to a time_t value.  */
 
159
time_t
 
160
mktime (tp)
 
161
     struct tm *tp;
 
162
{
 
163
#ifdef _LIBC
 
164
  /* POSIX.1 8.1.1 requires that whenever mktime() is called, the
 
165
     time zone names contained in the external variable `tzname' shall
 
166
     be set as if the tzset() function had been called.  */
 
167
  __tzset ();
 
168
#endif
 
169
 
 
170
  return __mktime_internal (tp, my_localtime_r, &localtime_offset);
 
171
}
 
172
 
 
173
/* Convert *TP to a time_t value, inverting
 
174
   the monotonic and mostly-unit-linear conversion function CONVERT.
 
175
   Use *OFFSET to keep track of a guess at the offset of the result,
 
176
   compared to what the result would be for UTC without leap seconds.
 
177
   If *OFFSET's guess is correct, only one CONVERT call is needed.  */
 
178
time_t
 
179
__mktime_internal (tp, convert, offset)
 
180
     struct tm *tp;
 
181
     struct tm *(*convert) __P ((const time_t *, struct tm *));
 
182
     time_t *offset;
 
183
{
 
184
  time_t t, dt, t0;
 
185
  struct tm tm;
 
186
 
 
187
  /* The maximum number of probes (calls to CONVERT) should be enough
 
188
     to handle any combinations of time zone rule changes, solar time,
 
189
     and leap seconds.  Posix.1 prohibits leap seconds, but some hosts
 
190
     have them anyway.  */
 
191
  int remaining_probes = 4;
 
192
 
 
193
  /* Time requested.  Copy it in case CONVERT modifies *TP; this can
 
194
     occur if TP is localtime's returned value and CONVERT is localtime.  */
 
195
  int sec = tp->tm_sec;
 
196
  int min = tp->tm_min;
 
197
  int hour = tp->tm_hour;
 
198
  int mday = tp->tm_mday;
 
199
  int mon = tp->tm_mon;
 
200
  int year_requested = tp->tm_year;
 
201
  int isdst = tp->tm_isdst;
 
202
 
 
203
  /* Ensure that mon is in range, and set year accordingly.  */
 
204
  int mon_remainder = mon % 12;
 
205
  int negative_mon_remainder = mon_remainder < 0;
 
206
  int mon_years = mon / 12 - negative_mon_remainder;
 
207
  int year = year_requested + mon_years;
 
208
 
 
209
  /* The other values need not be in range:
 
210
     the remaining code handles minor overflows correctly,
 
211
     assuming int and time_t arithmetic wraps around.
 
212
     Major overflows are caught at the end.  */
 
213
 
 
214
  /* Calculate day of year from year, month, and day of month.
 
215
     The result need not be in range.  */
 
216
  int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
 
217
               [mon_remainder + 12 * negative_mon_remainder])
 
218
              + mday - 1);
 
219
 
 
220
#if LEAP_SECONDS_POSSIBLE
 
221
  /* Handle out-of-range seconds specially,
 
222
     since ydhms_tm_diff assumes every minute has 60 seconds.  */
 
223
  int sec_requested = sec;
 
224
  if (sec < 0)
 
225
    sec = 0;
 
226
  if (59 < sec)
 
227
    sec = 59;
 
228
#endif
 
229
 
 
230
  /* Invert CONVERT by probing.  First assume the same offset as last time.
 
231
     Then repeatedly use the error to improve the guess.  */
 
232
 
 
233
  tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
 
234
  tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
 
235
  t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
 
236
 
 
237
  for (t = t0 + *offset;
 
238
       (dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
 
239
       t += dt)
 
240
    if (--remaining_probes == 0)
 
241
      return -1;
 
242
 
 
243
  /* Check whether tm.tm_isdst has the requested value, if any.  */
 
244
  if (0 <= isdst && 0 <= tm.tm_isdst)
 
245
    {
 
246
      int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
 
247
      if (dst_diff)
 
248
        {
 
249
          /* Move two hours in the direction indicated by the disagreement,
 
250
             probe some more, and switch to a new time if found.
 
251
             The largest known fallback due to daylight savings is two hours:
 
252
             once, in Newfoundland, 1988-10-30 02:00 -> 00:00.  */
 
253
          time_t ot = t - 2 * 60 * 60 * dst_diff;
 
254
          while (--remaining_probes != 0)
 
255
            {
 
256
              struct tm otm;
 
257
              if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
 
258
                                         (*convert) (&ot, &otm))))
 
259
                {
 
260
                  t = ot;
 
261
                  tm = otm;
 
262
                  break;
 
263
                }
 
264
              if ((ot += dt) == t)
 
265
                break;  /* Avoid a redundant probe.  */
 
266
            }
 
267
        }
 
268
    }
 
269
 
 
270
  *offset = t - t0;
 
271
 
 
272
#if LEAP_SECONDS_POSSIBLE
 
273
  if (sec_requested != tm.tm_sec)
 
274
    {
 
275
      /* Adjust time to reflect the tm_sec requested, not the normalized value.
 
276
         Also, repair any damage from a false match due to a leap second.  */
 
277
      t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
 
278
      (*convert) (&t, &tm);
 
279
    }
 
280
#endif
 
281
 
 
282
  if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
 
283
    {
 
284
      /* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
 
285
         so check for major overflows.  A gross check suffices,
 
286
         since if t has overflowed, it is off by a multiple of
 
287
         TIME_T_MAX - TIME_T_MIN + 1.  So ignore any component of
 
288
         the difference that is bounded by a small value.  */
 
289
 
 
290
      double dyear = (double) year_requested + mon_years - tm.tm_year;
 
291
      double dday = 366 * dyear + mday;
 
292
      double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
 
293
 
 
294
      if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
 
295
        return -1;
 
296
    }
 
297
 
 
298
  *tp = tm;
 
299
  return t;
 
300
}
 
301
 
 
302
#ifdef weak_alias
 
303
weak_alias (mktime, timelocal)
 
304
#endif
 
305
 
 
306
#if DEBUG
 
307
 
 
308
static int
 
309
not_equal_tm (a, b)
 
310
     struct tm *a;
 
311
     struct tm *b;
 
312
{
 
313
  return ((a->tm_sec ^ b->tm_sec)
 
314
          | (a->tm_min ^ b->tm_min)
 
315
          | (a->tm_hour ^ b->tm_hour)
 
316
          | (a->tm_mday ^ b->tm_mday)
 
317
          | (a->tm_mon ^ b->tm_mon)
 
318
          | (a->tm_year ^ b->tm_year)
 
319
          | (a->tm_mday ^ b->tm_mday)
 
320
          | (a->tm_yday ^ b->tm_yday)
 
321
          | (a->tm_isdst ^ b->tm_isdst));
 
322
}
 
323
 
 
324
static void
 
325
print_tm (tp)
 
326
     struct tm *tp;
 
327
{
 
328
  printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
 
329
          tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
 
330
          tp->tm_hour, tp->tm_min, tp->tm_sec,
 
331
          tp->tm_yday, tp->tm_wday, tp->tm_isdst);
 
332
}
 
333
 
 
334
static int
 
335
check_result (tk, tmk, tl, tml)
 
336
     time_t tk;
 
337
     struct tm tmk;
 
338
     time_t tl;
 
339
     struct tm tml;
 
340
{
 
341
  if (tk != tl || not_equal_tm (&tmk, &tml))
 
342
    {
 
343
      printf ("mktime (");
 
344
      print_tm (&tmk);
 
345
      printf (")\nyields (");
 
346
      print_tm (&tml);
 
347
      printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
 
348
      return 1;
 
349
    }
 
350
 
 
351
  return 0;
 
352
}
 
353
 
 
354
int
 
355
main (argc, argv)
 
356
     int argc;
 
357
     char **argv;
 
358
{
 
359
  int status = 0;
 
360
  struct tm tm, tmk, tml;
 
361
  time_t tk, tl;
 
362
  char trailer;
 
363
 
 
364
  if ((argc == 3 || argc == 4)
 
365
      && (sscanf (argv[1], "%d-%d-%d%c",
 
366
                  &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
 
367
          == 3)
 
368
      && (sscanf (argv[2], "%d:%d:%d%c",
 
369
                  &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
 
370
          == 3))
 
371
    {
 
372
      tm.tm_year -= TM_YEAR_BASE;
 
373
      tm.tm_mon--;
 
374
      tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
 
375
      tmk = tm;
 
376
      tl = mktime (&tmk);
 
377
      tml = *localtime (&tl);
 
378
      printf ("mktime returns %ld == ", (long) tl);
 
379
      print_tm (&tmk);
 
380
      printf ("\n");
 
381
      status = check_result (tl, tmk, tl, tml);
 
382
    }
 
383
  else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
 
384
    {
 
385
      time_t from = atol (argv[1]);
 
386
      time_t by = atol (argv[2]);
 
387
      time_t to = atol (argv[3]);
 
388
 
 
389
      if (argc == 4)
 
390
        for (tl = from; tl <= to; tl += by)
 
391
          {
 
392
            tml = *localtime (&tl);
 
393
            tmk = tml;
 
394
            tk = mktime (&tmk);
 
395
            status |= check_result (tk, tmk, tl, tml);
 
396
          }
 
397
      else
 
398
        for (tl = from; tl <= to; tl += by)
 
399
          {
 
400
            /* Null benchmark.  */
 
401
            tml = *localtime (&tl);
 
402
            tmk = tml;
 
403
            tk = tl;
 
404
            status |= check_result (tk, tmk, tl, tml);
 
405
          }
 
406
    }
 
407
  else
 
408
    printf ("Usage:\
 
409
\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
 
410
\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
 
411
\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
 
412
            argv[0], argv[0], argv[0]);
 
413
 
 
414
  return status;
 
415
}
 
416
 
 
417
#endif /* DEBUG */
 
418
 
 
419
/*
 
420
Local Variables:
 
421
compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
 
422
End:
 
423
*/