Merge from vendor branch BIND:
[dragonfly.git] / usr.sbin / zic / zic.c
1 #ifndef lint
2 #ifndef NOID
3 static char     elsieid[] = "@(#)zic.c  7.96";
4 #endif /* !defined NOID */
5 #endif /* !defined lint */
6
7 /*
8  * @(#)zic.c    7.96
9  * $FreeBSD: src/usr.sbin/zic/zic.c,v 1.11 1999/08/28 01:21:20 peter Exp $
10  * $DragonFly: src/usr.sbin/zic/zic.c,v 1.6 2004/12/18 22:48:15 swildner Exp $
11  */
12 #include "private.h"
13 #include "tzfile.h"
14 #include <err.h>
15 #include <locale.h>
16 #include <sys/stat.h>                   /* for umask manifest constants */
17 #include <sys/types.h>
18 #include <unistd.h>
19
20 /*
21 ** On some ancient hosts, predicates like `isspace(C)' are defined
22 ** only if isascii(C) || C == EOF.  Modern hosts obey the C Standard,
23 ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
24 ** Neither the C Standard nor Posix require that `isascii' exist.
25 ** For portability, we check both ancient and modern requirements.
26 ** If isascii is not defined, the isascii check succeeds trivially.
27 */
28 #include "ctype.h"
29 #ifndef isascii
30 #define isascii(x) 1
31 #endif
32
33 struct rule {
34         const char *    r_filename;
35         int             r_linenum;
36         const char *    r_name;
37
38         int             r_loyear;       /* for example, 1986 */
39         int             r_hiyear;       /* for example, 1986 */
40         const char *    r_yrtype;
41
42         int             r_month;        /* 0..11 */
43
44         int             r_dycode;       /* see below */
45         int             r_dayofmonth;
46         int             r_wday;
47
48         long            r_tod;          /* time from midnight */
49         int             r_todisstd;     /* above is standard time if TRUE */
50                                         /* or wall clock time if FALSE */
51         int             r_todisgmt;     /* above is GMT if TRUE */
52                                         /* or local time if FALSE */
53         long            r_stdoff;       /* offset from standard time */
54         const char *    r_abbrvar;      /* variable part of abbreviation */
55
56         int             r_todo;         /* a rule to do (used in outzone) */
57         time_t          r_temp;         /* used in outzone */
58 };
59
60 /*
61 **      r_dycode                r_dayofmonth    r_wday
62 */
63
64 #define DC_DOM          0       /* 1..31 */     /* unused */
65 #define DC_DOWGEQ       1       /* 1..31 */     /* 0..6 (Sun..Sat) */
66 #define DC_DOWLEQ       2       /* 1..31 */     /* 0..6 (Sun..Sat) */
67
68 struct zone {
69         const char *    z_filename;
70         int             z_linenum;
71
72         const char *    z_name;
73         long            z_gmtoff;
74         const char *    z_rule;
75         const char *    z_format;
76
77         long            z_stdoff;
78
79         struct rule *   z_rules;
80         int             z_nrules;
81
82         struct rule     z_untilrule;
83         time_t          z_untiltime;
84 };
85
86 static void     addtt(time_t starttime, int type);
87 static int      addtype(long gmtoff, const char *abbr, int isdst,
88                         int ttisstd, int ttisgmt);
89 static void     leapadd(time_t t, int positive, int rolling, int count);
90 static void     adjleap(void);
91 static void     associate(void);
92 static int      ciequal(const char *ap, const char *bp);
93 static void     convert(long val, char *buf);
94 static void     dolink(const char *fromfile, const char *tofile);
95 static void     doabbr(char *abbr, const char *format,
96                        const char *letters, int isdst);
97 static void     eat(const char *name, int num);
98 static void     eats(const char *name, int num,
99                      const char *rname, int rnum);
100 static long     eitol(int i);
101 static void     error(const char *message);
102 static char **  getfields(char *buf);
103 static long     gethms(const char *string, const char *errstrng,
104                        int signable);
105 static void     infile(const char *filename);
106 static void     inleap(char **fields, int nfields);
107 static void     inlink(char **fields, int nfields);
108 static void     inrule(char **fields, int nfields);
109 static int      inzcont(char **fields, int nfields);
110 static int      inzone(char **fields, int nfields);
111 static int      inzsub(char **fields, int nfields, int iscont);
112 static int      itsabbr(const char *abbr, const char *word);
113 static int      itsdir(const char *name);
114 static int      lowerit(int c);
115 static char *   memcheck(char *tocheck);
116 static int      mkdirs(char *filename);
117 static void     newabbr(const char *abbr);
118 static long     oadd(long t1, long t2);
119 static void     outzone(const struct zone *zp, int ntzones);
120 static void     puttzcode(long code, FILE *fp);
121 static int      rcomp(const void *leftp, const void *rightp);
122 static time_t   rpytime(const struct rule *rp, int wantedy);
123 static void     rulesub(struct rule *rp,
124                         const char *loyearp, const char *hiyearp,
125                         const char *typep, const char *monthp,
126                         const char *dayp, const char *timep);
127 static void     setboundaries(void);
128 static void     setgroup(gid_t *flag, const char *name);
129 static void     setuser(uid_t *flag, const char *name);
130 static time_t   tadd(time_t t1, long t2);
131 static void     usage(void);
132 static void     writezone(const char *name);
133 static int      yearistype(int year, const char *type);
134
135 #if !(HAVE_STRERROR - 0)
136 static char *   strerror(int);
137 #endif /* !(HAVE_STRERROR - 0) */
138
139 static int              charcnt;
140 static int              errors;
141 static const char *     filename;
142 static int              leapcnt;
143 static int              linenum;
144 static time_t           max_time;
145 static int              max_year;
146 static int              max_year_representable;
147 static time_t           min_time;
148 static int              min_year;
149 static int              min_year_representable;
150 static int              noise;
151 static const char *     rfilename;
152 static int              rlinenum;
153 static int              timecnt;
154 static int              typecnt;
155
156 /*
157 ** Line codes.
158 */
159
160 #define LC_RULE         0
161 #define LC_ZONE         1
162 #define LC_LINK         2
163 #define LC_LEAP         3
164
165 /*
166 ** Which fields are which on a Zone line.
167 */
168
169 #define ZF_NAME         1
170 #define ZF_GMTOFF       2
171 #define ZF_RULE         3
172 #define ZF_FORMAT       4
173 #define ZF_TILYEAR      5
174 #define ZF_TILMONTH     6
175 #define ZF_TILDAY       7
176 #define ZF_TILTIME      8
177 #define ZONE_MINFIELDS  5
178 #define ZONE_MAXFIELDS  9
179
180 /*
181 ** Which fields are which on a Zone continuation line.
182 */
183
184 #define ZFC_GMTOFF      0
185 #define ZFC_RULE        1
186 #define ZFC_FORMAT      2
187 #define ZFC_TILYEAR     3
188 #define ZFC_TILMONTH    4
189 #define ZFC_TILDAY      5
190 #define ZFC_TILTIME     6
191 #define ZONEC_MINFIELDS 3
192 #define ZONEC_MAXFIELDS 7
193
194 /*
195 ** Which files are which on a Rule line.
196 */
197
198 #define RF_NAME         1
199 #define RF_LOYEAR       2
200 #define RF_HIYEAR       3
201 #define RF_COMMAND      4
202 #define RF_MONTH        5
203 #define RF_DAY          6
204 #define RF_TOD          7
205 #define RF_STDOFF       8
206 #define RF_ABBRVAR      9
207 #define RULE_FIELDS     10
208
209 /*
210 ** Which fields are which on a Link line.
211 */
212
213 #define LF_FROM         1
214 #define LF_TO           2
215 #define LINK_FIELDS     3
216
217 /*
218 ** Which fields are which on a Leap line.
219 */
220
221 #define LP_YEAR         1
222 #define LP_MONTH        2
223 #define LP_DAY          3
224 #define LP_TIME         4
225 #define LP_CORR         5
226 #define LP_ROLL         6
227 #define LEAP_FIELDS     7
228
229 /*
230 ** Year synonyms.
231 */
232
233 #define YR_MINIMUM      0
234 #define YR_MAXIMUM      1
235 #define YR_ONLY         2
236
237 static struct rule *    rules;
238 static int              nrules; /* number of rules */
239
240 static struct zone *    zones;
241 static int              nzones; /* number of zones */
242
243 struct link {
244         const char *    l_filename;
245         int             l_linenum;
246         const char *    l_from;
247         const char *    l_to;
248 };
249
250 static struct link *    links;
251 static int              nlinks;
252
253 struct lookup {
254         const char *    l_word;
255         const int       l_value;
256 };
257
258 static struct lookup const      *byword(const char *string,
259                                         const struct lookup *lp);
260
261 static struct lookup const      line_codes[] = {
262         { "Rule",       LC_RULE },
263         { "Zone",       LC_ZONE },
264         { "Link",       LC_LINK },
265         { "Leap",       LC_LEAP },
266         { NULL,         0}
267 };
268
269 static struct lookup const      mon_names[] = {
270         { "January",    TM_JANUARY },
271         { "February",   TM_FEBRUARY },
272         { "March",      TM_MARCH },
273         { "April",      TM_APRIL },
274         { "May",        TM_MAY },
275         { "June",       TM_JUNE },
276         { "July",       TM_JULY },
277         { "August",     TM_AUGUST },
278         { "September",  TM_SEPTEMBER },
279         { "October",    TM_OCTOBER },
280         { "November",   TM_NOVEMBER },
281         { "December",   TM_DECEMBER },
282         { NULL,         0 }
283 };
284
285 static struct lookup const      wday_names[] = {
286         { "Sunday",     TM_SUNDAY },
287         { "Monday",     TM_MONDAY },
288         { "Tuesday",    TM_TUESDAY },
289         { "Wednesday",  TM_WEDNESDAY },
290         { "Thursday",   TM_THURSDAY },
291         { "Friday",     TM_FRIDAY },
292         { "Saturday",   TM_SATURDAY },
293         { NULL,         0 }
294 };
295
296 static struct lookup const      lasts[] = {
297         { "last-Sunday",        TM_SUNDAY },
298         { "last-Monday",        TM_MONDAY },
299         { "last-Tuesday",       TM_TUESDAY },
300         { "last-Wednesday",     TM_WEDNESDAY },
301         { "last-Thursday",      TM_THURSDAY },
302         { "last-Friday",        TM_FRIDAY },
303         { "last-Saturday",      TM_SATURDAY },
304         { NULL,                 0 }
305 };
306
307 static struct lookup const      begin_years[] = {
308         { "minimum",    YR_MINIMUM },
309         { "maximum",    YR_MAXIMUM },
310         { NULL,         0 }
311 };
312
313 static struct lookup const      end_years[] = {
314         { "minimum",    YR_MINIMUM },
315         { "maximum",    YR_MAXIMUM },
316         { "only",       YR_ONLY },
317         { NULL,         0 }
318 };
319
320 static struct lookup const      leap_types[] = {
321         { "Rolling",    TRUE },
322         { "Stationary", FALSE },
323         { NULL,         0 }
324 };
325
326 static const int        len_months[2][MONSPERYEAR] = {
327         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
328         { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
329 };
330
331 static const int        len_years[2] = {
332         DAYSPERNYEAR, DAYSPERLYEAR
333 };
334
335 static struct attype {
336         time_t          at;
337         unsigned char   type;
338 }                       attypes[TZ_MAX_TIMES];
339 static long             gmtoffs[TZ_MAX_TYPES];
340 static char             isdsts[TZ_MAX_TYPES];
341 static unsigned char    abbrinds[TZ_MAX_TYPES];
342 static char             ttisstds[TZ_MAX_TYPES];
343 static char             ttisgmts[TZ_MAX_TYPES];
344 static char             chars[TZ_MAX_CHARS];
345 static time_t           trans[TZ_MAX_LEAPS];
346 static long             corr[TZ_MAX_LEAPS];
347 static char             roll[TZ_MAX_LEAPS];
348
349 /*
350 ** Memory allocation.
351 */
352
353 static char *
354 memcheck(char * const ptr)
355 {
356         if (ptr == NULL)
357                 errx(EXIT_FAILURE, _("memory exhausted"));
358         return ptr;
359 }
360
361 #define emalloc(size)           memcheck(imalloc(size))
362 #define erealloc(ptr, size)     memcheck(irealloc((ptr), (size)))
363 #define ecpyalloc(ptr)          memcheck(icpyalloc(ptr))
364 #define ecatalloc(oldp, newp)   memcheck(icatalloc((oldp), (newp)))
365
366 /*
367 ** Error handling.
368 */
369
370 #if !(HAVE_STRERROR - 0)
371 static char *
372 strerror(int errnum)
373 {
374         extern char *   sys_errlist[];
375         extern int      sys_nerr;
376
377         return (errnum > 0 && errnum <= sys_nerr) ?
378                 sys_errlist[errnum] : _("Unknown system error");
379 }
380 #endif /* !(HAVE_STRERROR - 0) */
381
382 static void
383 eats(const char * const name, const int num,
384      const char * const rname, const int rnum)
385 {
386         filename = name;
387         linenum = num;
388         rfilename = rname;
389         rlinenum = rnum;
390 }
391
392 static void
393 eat(const char * const name, const int num)
394 {
395         eats(name, num, (char *) NULL, -1);
396 }
397
398 static void
399 error(const char * const string)
400 {
401         /*
402         ** Match the format of "cc" to allow sh users to
403         **      zic ... 2>&1 | error -t "*" -v
404         ** on BSD systems.
405         */
406         fprintf(stderr, _("\"%s\", line %d: %s"),
407                 filename, linenum, string);
408         if (rfilename != NULL)
409                 fprintf(stderr, _(" (rule from \"%s\", line %d)"),
410                         rfilename, rlinenum);
411         fprintf(stderr, "\n");
412         ++errors;
413 }
414
415 static void
416 warning(const char * const string)
417 {
418         char *  cp;
419
420         cp = ecpyalloc(_("warning: "));
421         cp = ecatalloc(cp, string);
422         error(cp);
423         ifree(cp);
424         --errors;
425 }
426
427 static void
428 usage(void)
429 {
430         fprintf(stderr, "%s\n%s\n",
431 _("usage: zic [-s] [-v] [-l localtime] [-p posixrules] [-d directory]"),
432 _("           [-L leapseconds] [-y yearistype] [filename ... ]"));
433         exit(EXIT_FAILURE);
434 }
435
436 static const char *     psxrules;
437 static const char *     lcltime;
438 static const char *     directory;
439 static const char *     leapsec;
440 static const char *     yitcommand;
441 static int              sflag = FALSE;
442 static int              Dflag;
443 static uid_t            uflag = (uid_t)-1;
444 static gid_t            gflag = (gid_t)-1;
445 static mode_t           mflag = (S_IRUSR | S_IRGRP | S_IROTH
446                                  | S_IWUSR);
447
448 int
449 main(int argc, char *argv[])
450 {
451         int i;
452         int j;
453         int c;
454
455 #ifdef unix
456         umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
457 #endif /* defined unix */
458 #if HAVE_GETTEXT - 0
459         setlocale(LC_MESSAGES, "");
460 #ifdef TZ_DOMAINDIR
461         bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
462 #endif /* defined TEXTDOMAINDIR */
463         textdomain(TZ_DOMAIN);
464 #endif /* HAVE_GETTEXT - 0 */
465         while ((c = getopt(argc, argv, "Dd:g:l:m:p:L:u:vsy:")) != -1)
466                 switch (c) {
467                         default:
468                                 usage();
469                         case 'D':
470                                 Dflag = 1;
471                                 break;
472                         case 'd':
473                                 if (directory == NULL)
474                                         directory = optarg;
475                                 else
476                                         errx(EXIT_FAILURE,
477 _("more than one -d option specified"));
478                                 break;
479                         case 'g':
480                                 setgroup(&gflag, optarg);
481                                 break;
482                         case 'l':
483                                 if (lcltime == NULL)
484                                         lcltime = optarg;
485                                 else
486                                         errx(EXIT_FAILURE,
487 _("more than one -l option specified"));
488                                 break;
489                         case 'm':
490                         {
491                                 void *set = setmode(optarg);
492                                 getmode(set, mflag);
493                                 break;
494                         }
495                         case 'p':
496                                 if (psxrules == NULL)
497                                         psxrules = optarg;
498                                 else
499                                         errx(EXIT_FAILURE,
500 _("more than one -p option specified"));
501                                 break;
502                         case 'u':
503                                 setuser(&uflag, optarg);
504                                 break;
505                         case 'y':
506                                 if (yitcommand == NULL)
507                                         yitcommand = optarg;
508                                 else
509                                         errx(EXIT_FAILURE,
510 _("more than one -y option specified"));
511                                 break;
512                         case 'L':
513                                 if (leapsec == NULL)
514                                         leapsec = optarg;
515                                 else
516                                         errx(EXIT_FAILURE,
517 _("more than one -L option specified"));
518                                 break;
519                         case 'v':
520                                 noise = TRUE;
521                                 break;
522                         case 's':
523                                 sflag = TRUE;
524                                 break;
525                 }
526         if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
527                 usage();        /* usage message by request */
528         if (directory == NULL)
529                 directory = TZDIR;
530         if (yitcommand == NULL)
531                 yitcommand = "yearistype";
532
533         setboundaries();
534
535         if (optind < argc && leapsec != NULL) {
536                 infile(leapsec);
537                 adjleap();
538         }
539
540         for (i = optind; i < argc; ++i)
541                 infile(argv[i]);
542         if (errors)
543                 exit(EXIT_FAILURE);
544         associate();
545         for (i = 0; i < nzones; i = j) {
546                 /*
547                 ** Find the next non-continuation zone entry.
548                 */
549                 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
550                         continue;
551                 outzone(&zones[i], j - i);
552         }
553         /*
554         ** Make links.
555         */
556         for (i = 0; i < nlinks; ++i)
557                 dolink(links[i].l_from, links[i].l_to);
558         if (lcltime != NULL)
559                 dolink(lcltime, TZDEFAULT);
560         if (psxrules != NULL)
561                 dolink(psxrules, TZDEFRULES);
562         return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
563 }
564
565 static void
566 dolink(const char * const fromfile, const char * const tofile)
567 {
568         char *fromname;
569         char *toname;
570
571         if (fromfile[0] == '/')
572                 fromname = ecpyalloc(fromfile);
573         else {
574                 fromname = ecpyalloc(directory);
575                 fromname = ecatalloc(fromname, "/");
576                 fromname = ecatalloc(fromname, fromfile);
577         }
578         if (tofile[0] == '/')
579                 toname = ecpyalloc(tofile);
580         else {
581                 toname = ecpyalloc(directory);
582                 toname = ecatalloc(toname, "/");
583                 toname = ecatalloc(toname, tofile);
584         }
585         /*
586         ** We get to be careful here since
587         ** there's a fair chance of root running us.
588         */
589         if (!itsdir(toname))
590                 remove(toname);
591         if (link(fromname, toname) != 0) {
592                 int     result;
593
594                 if (mkdirs(toname) != 0)
595                         exit(EXIT_FAILURE);
596                 result = link(fromname, toname);
597 #if (HAVE_SYMLINK - 0) 
598                 if (result != 0) {
599                         result = symlink(fromname, toname);
600                         if (result == 0)
601 warning(_("hard link failed, symbolic link used"));
602                 }
603 #endif
604                 if (result != 0) {
605                         err(EXIT_FAILURE, _("can't link from %s to %s"),
606                             fromname, toname);
607                 }
608         }
609         ifree(fromname);
610         ifree(toname);
611 }
612
613 #ifndef INT_MAX
614 #define INT_MAX ((int) (((unsigned)~0)>>1))
615 #endif /* !defined INT_MAX */
616
617 #ifndef INT_MIN
618 #define INT_MIN ((int) ~(((unsigned)~0)>>1))
619 #endif /* !defined INT_MIN */
620
621 /*
622 ** The tz file format currently allows at most 32-bit quantities.
623 ** This restriction should be removed before signed 32-bit values
624 ** wrap around in 2038, but unfortunately this will require a
625 ** change to the tz file format.
626 */
627
628 #define MAX_BITS_IN_FILE        32
629 #define TIME_T_BITS_IN_FILE     ((TYPE_BIT(time_t) < MAX_BITS_IN_FILE) ? TYPE_BIT(time_t) : MAX_BITS_IN_FILE)
630
631 static void
632 setboundaries(void)
633 {
634         if (TYPE_SIGNED(time_t)) {
635                 min_time = ~ (time_t) 0;
636                 min_time <<= TIME_T_BITS_IN_FILE - 1;
637                 max_time = ~ (time_t) 0 - min_time;
638                 if (sflag)
639                         min_time = 0;
640         } else {
641                 min_time = 0;
642                 max_time = 2 - sflag;
643                 max_time <<= TIME_T_BITS_IN_FILE - 1;
644                 --max_time;
645         }
646         min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
647         max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
648         min_year_representable = min_year;
649         max_year_representable = max_year;
650 }
651
652 static int
653 itsdir(const char * const name)
654 {
655         char *  myname;
656         int     accres;
657
658         myname = ecpyalloc(name);
659         myname = ecatalloc(myname, "/.");
660         accres = access(myname, F_OK);
661         ifree(myname);
662         return accres == 0;
663 }
664
665 /*
666 ** Associate sets of rules with zones.
667 */
668
669 /*
670 ** Sort by rule name.
671 */
672
673 static int
674 rcomp(const void *cp1, const void *cp2)
675 {
676         return strcmp(((const struct rule *) cp1)->r_name,
677                 ((const struct rule *) cp2)->r_name);
678 }
679
680 static void
681 associate(void)
682 {
683         struct zone *zp;
684         struct rule *rp;
685         int base, out;
686         int i, j;
687
688         if (nrules != 0) {
689                 qsort((void *) rules, (size_t) nrules,
690                         (size_t) sizeof *rules, rcomp);
691                 for (i = 0; i < nrules - 1; ++i) {
692                         if (strcmp(rules[i].r_name,
693                                 rules[i + 1].r_name) != 0)
694                                         continue;
695                         if (strcmp(rules[i].r_filename,
696                                 rules[i + 1].r_filename) == 0)
697                                         continue;
698                         eat(rules[i].r_filename, rules[i].r_linenum);
699                         warning(_("same rule name in multiple files"));
700                         eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
701                         warning(_("same rule name in multiple files"));
702                         for (j = i + 2; j < nrules; ++j) {
703                                 if (strcmp(rules[i].r_name,
704                                         rules[j].r_name) != 0)
705                                                 break;
706                                 if (strcmp(rules[i].r_filename,
707                                         rules[j].r_filename) == 0)
708                                                 continue;
709                                 if (strcmp(rules[i + 1].r_filename,
710                                         rules[j].r_filename) == 0)
711                                                 continue;
712                                 break;
713                         }
714                         i = j - 1;
715                 }
716         }
717         for (i = 0; i < nzones; ++i) {
718                 zp = &zones[i];
719                 zp->z_rules = NULL;
720                 zp->z_nrules = 0;
721         }
722         for (base = 0; base < nrules; base = out) {
723                 rp = &rules[base];
724                 for (out = base + 1; out < nrules; ++out)
725                         if (strcmp(rp->r_name, rules[out].r_name) != 0)
726                                 break;
727                 for (i = 0; i < nzones; ++i) {
728                         zp = &zones[i];
729                         if (strcmp(zp->z_rule, rp->r_name) != 0)
730                                 continue;
731                         zp->z_rules = rp;
732                         zp->z_nrules = out - base;
733                 }
734         }
735         for (i = 0; i < nzones; ++i) {
736                 zp = &zones[i];
737                 if (zp->z_nrules == 0) {
738                         /*
739                         ** Maybe we have a local standard time offset.
740                         */
741                         eat(zp->z_filename, zp->z_linenum);
742                         zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
743                                               TRUE);
744                         /*
745                         ** Note, though, that if there's no rule,
746                         ** a '%s' in the format is a bad thing.
747                         */
748                         if (strchr(zp->z_format, '%') != 0)
749                                 error(_("%s in ruleless zone"));
750                 }
751         }
752         if (errors)
753                 exit(EXIT_FAILURE);
754 }
755
756 static void
757 infile(const char *name)
758 {
759         FILE *fp;
760         char **fields;
761         char *cp;
762         const struct lookup *lp;
763         int nfields;
764         int wantcont;
765         int num;
766         char buf[BUFSIZ];
767
768         if (strcmp(name, "-") == 0) {
769                 name = _("standard input");
770                 fp = stdin;
771         } else if ((fp = fopen(name, "r")) == NULL)
772                 err(EXIT_FAILURE, _("can't open %s"), name);
773         wantcont = FALSE;
774         for (num = 1; ; ++num) {
775                 eat(name, num);
776                 if (fgets(buf, (int) sizeof buf, fp) != buf)
777                         break;
778                 cp = strchr(buf, '\n');
779                 if (cp == NULL) {
780                         error(_("line too long"));
781                         exit(EXIT_FAILURE);
782                 }
783                 *cp = '\0';
784                 fields = getfields(buf);
785                 nfields = 0;
786                 while (fields[nfields] != NULL) {
787                         static char     nada;
788
789                         if (strcmp(fields[nfields], "-") == 0)
790                                 fields[nfields] = &nada;
791                         ++nfields;
792                 }
793                 if (nfields == 0) {
794                         /* nothing to do */
795                 } else if (wantcont) {
796                         wantcont = inzcont(fields, nfields);
797                 } else {
798                         lp = byword(fields[0], line_codes);
799                         if (lp == NULL)
800                                 error(_("input line of unknown type"));
801                         else switch ((int) (lp->l_value)) {
802                                 case LC_RULE:
803                                         inrule(fields, nfields);
804                                         wantcont = FALSE;
805                                         break;
806                                 case LC_ZONE:
807                                         wantcont = inzone(fields, nfields);
808                                         break;
809                                 case LC_LINK:
810                                         inlink(fields, nfields);
811                                         wantcont = FALSE;
812                                         break;
813                                 case LC_LEAP:
814                                         if (name != leapsec)
815                                                 warnx(
816 _("leap line in non leap seconds file %s"), name);
817                                         else    inleap(fields, nfields);
818                                         wantcont = FALSE;
819                                         break;
820                                 default:        /* "cannot happen" */
821                                         errx(EXIT_FAILURE,
822 _("panic: invalid l_value %d"), lp->l_value);
823                         }
824                 }
825                 ifree((char *) fields);
826         }
827         if (ferror(fp))
828                 errx(EXIT_FAILURE, _("error reading %s"), filename);
829         if (fp != stdin && fclose(fp))
830                 err(EXIT_FAILURE, _("error closing %s"), filename);
831         if (wantcont)
832                 error(_("expected continuation line not found"));
833 }
834
835 /*
836 ** Convert a string of one of the forms
837 **      h       -h      hh:mm   -hh:mm  hh:mm:ss        -hh:mm:ss
838 ** into a number of seconds.
839 ** A null string maps to zero.
840 ** Call error with errstring and return zero on errors.
841 */
842
843 static long
844 gethms(const char *string, const char * const errstring, const int signable)
845 {
846         int     hh, mm, ss, sign;
847
848         if (string == NULL || *string == '\0')
849                 return 0;
850         if (!signable)
851                 sign = 1;
852         else if (*string == '-') {
853                 sign = -1;
854                 ++string;
855         } else  sign = 1;
856         if (sscanf(string, scheck(string, "%d"), &hh) == 1)
857                 mm = ss = 0;
858         else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
859                 ss = 0;
860         else if (sscanf(string, scheck(string, "%d:%d:%d"),
861                 &hh, &mm, &ss) != 3) {
862                         error(errstring);
863                         return 0;
864         }
865         if ((hh < 0 || hh >= HOURSPERDAY ||
866                 mm < 0 || mm >= MINSPERHOUR ||
867                 ss < 0 || ss > SECSPERMIN) &&
868                 !(hh == HOURSPERDAY && mm == 0 && ss == 0)) {
869                         error(errstring);
870                         return 0;
871         }
872         return eitol(sign) *
873                 (eitol(hh * MINSPERHOUR + mm) *
874                 eitol(SECSPERMIN) + eitol(ss));
875 }
876
877 static void
878 inrule(char ** const fields, const int nfields)
879 {
880         static struct rule      r;
881
882         if (nfields != RULE_FIELDS) {
883                 error(_("wrong number of fields on Rule line"));
884                 return;
885         }
886         if (*fields[RF_NAME] == '\0') {
887                 error(_("nameless rule"));
888                 return;
889         }
890         r.r_filename = filename;
891         r.r_linenum = linenum;
892         r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
893         rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
894                 fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
895         r.r_name = ecpyalloc(fields[RF_NAME]);
896         r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
897         rules = (struct rule *) (void *) erealloc((char *) rules,
898                 (int) ((nrules + 1) * sizeof *rules));
899         rules[nrules++] = r;
900 }
901
902 static int
903 inzone(char ** const fields, const int nfields)
904 {
905         int i;
906         static char *buf;
907
908         if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
909                 error(_("wrong number of fields on Zone line"));
910                 return FALSE;
911         }
912         if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
913                 buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
914                 sprintf(buf,
915 _("\"Zone %s\" line and -l option are mutually exclusive"),
916                         TZDEFAULT);
917                 error(buf);
918                 return FALSE;
919         }
920         if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
921                 buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
922                 sprintf(buf,
923 _("\"Zone %s\" line and -p option are mutually exclusive"),
924                         TZDEFRULES);
925                 error(buf);
926                 return FALSE;
927         }
928         for (i = 0; i < nzones; ++i)
929                 if (zones[i].z_name != NULL &&
930                         strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
931                                 buf = erealloc(buf, (int) (132 +
932                                         strlen(fields[ZF_NAME]) +
933                                         strlen(zones[i].z_filename)));
934                                 sprintf(buf,
935 _("duplicate zone name %s (file \"%s\", line %d)"),
936                                         fields[ZF_NAME],
937                                         zones[i].z_filename,
938                                         zones[i].z_linenum);
939                                 error(buf);
940                                 return FALSE;
941                 }
942         return inzsub(fields, nfields, FALSE);
943 }
944
945 static int
946 inzcont(char ** const fields, const int nfields)
947 {
948         if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
949                 error(_("wrong number of fields on Zone continuation line"));
950                 return FALSE;
951         }
952         return inzsub(fields, nfields, TRUE);
953 }
954
955 static int
956 inzsub(char ** const fields, const int nfields, const int iscont)
957 {
958         char *cp;
959         static struct zone z;
960         int i_gmtoff, i_rule, i_format;
961         int i_untilyear, i_untilmonth;
962         int i_untilday, i_untiltime;
963         int hasuntil;
964
965         if (iscont) {
966                 i_gmtoff = ZFC_GMTOFF;
967                 i_rule = ZFC_RULE;
968                 i_format = ZFC_FORMAT;
969                 i_untilyear = ZFC_TILYEAR;
970                 i_untilmonth = ZFC_TILMONTH;
971                 i_untilday = ZFC_TILDAY;
972                 i_untiltime = ZFC_TILTIME;
973                 z.z_name = NULL;
974         } else {
975                 i_gmtoff = ZF_GMTOFF;
976                 i_rule = ZF_RULE;
977                 i_format = ZF_FORMAT;
978                 i_untilyear = ZF_TILYEAR;
979                 i_untilmonth = ZF_TILMONTH;
980                 i_untilday = ZF_TILDAY;
981                 i_untiltime = ZF_TILTIME;
982                 z.z_name = ecpyalloc(fields[ZF_NAME]);
983         }
984         z.z_filename = filename;
985         z.z_linenum = linenum;
986         z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
987         if ((cp = strchr(fields[i_format], '%')) != 0) {
988                 if (*++cp != 's' || strchr(cp, '%') != 0) {
989                         error(_("invalid abbreviation format"));
990                         return FALSE;
991                 }
992         }
993         z.z_rule = ecpyalloc(fields[i_rule]);
994         z.z_format = ecpyalloc(fields[i_format]);
995         hasuntil = nfields > i_untilyear;
996         if (hasuntil) {
997                 z.z_untilrule.r_filename = filename;
998                 z.z_untilrule.r_linenum = linenum;
999                 rulesub(&z.z_untilrule,
1000                         fields[i_untilyear],
1001                         "only",
1002                         "",
1003                         (nfields > i_untilmonth) ?
1004                         fields[i_untilmonth] : "Jan",
1005                         (nfields > i_untilday) ? fields[i_untilday] : "1",
1006                         (nfields > i_untiltime) ? fields[i_untiltime] : "0");
1007                 z.z_untiltime = rpytime(&z.z_untilrule,
1008                         z.z_untilrule.r_loyear);
1009                 if (iscont && nzones > 0 &&
1010                         z.z_untiltime > min_time &&
1011                         z.z_untiltime < max_time &&
1012                         zones[nzones - 1].z_untiltime > min_time &&
1013                         zones[nzones - 1].z_untiltime < max_time &&
1014                         zones[nzones - 1].z_untiltime >= z.z_untiltime) {
1015                                 error(_("Zone continuation line end time is not after end time of previous line"));
1016                                 return FALSE;
1017                 }
1018         }
1019         zones = (struct zone *) (void *) erealloc((char *) zones,
1020                 (int) ((nzones + 1) * sizeof *zones));
1021         zones[nzones++] = z;
1022         /*
1023         ** If there was an UNTIL field on this line,
1024         ** there's more information about the zone on the next line.
1025         */
1026         return hasuntil;
1027 }
1028
1029 static void
1030 inleap(char ** const fields, const int nfields)
1031 {
1032         const char *cp;
1033         const struct lookup *lp;
1034         int i, j;
1035         int year, month, day;
1036         long dayoff, tod;
1037         time_t t;
1038
1039         if (nfields != LEAP_FIELDS) {
1040                 error(_("wrong number of fields on Leap line"));
1041                 return;
1042         }
1043         dayoff = 0;
1044         cp = fields[LP_YEAR];
1045         if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
1046                         /*
1047                          * Leapin' Lizards!
1048                          */
1049                         error(_("invalid leaping year"));
1050                         return;
1051         }
1052         j = EPOCH_YEAR;
1053         while (j != year) {
1054                 if (year > j) {
1055                         i = len_years[isleap(j)];
1056                         ++j;
1057                 } else {
1058                         --j;
1059                         i = -len_years[isleap(j)];
1060                 }
1061                 dayoff = oadd(dayoff, eitol(i));
1062         }
1063         if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
1064                 error(_("invalid month name"));
1065                 return;
1066         }
1067         month = lp->l_value;
1068         j = TM_JANUARY;
1069         while (j != month) {
1070                 i = len_months[isleap(year)][j];
1071                 dayoff = oadd(dayoff, eitol(i));
1072                 ++j;
1073         }
1074         cp = fields[LP_DAY];
1075         if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
1076                 day <= 0 || day > len_months[isleap(year)][month]) {
1077                         error(_("invalid day of month"));
1078                         return;
1079         }
1080         dayoff = oadd(dayoff, eitol(day - 1));
1081         if (dayoff < 0 && !TYPE_SIGNED(time_t)) {
1082                 error(_("time before zero"));
1083                 return;
1084         }
1085         t = (time_t) dayoff * SECSPERDAY;
1086         /*
1087         ** Cheap overflow check.
1088         */
1089         if (t / SECSPERDAY != dayoff) {
1090                 error(_("time overflow"));
1091                 return;
1092         }
1093         tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
1094         cp = fields[LP_CORR];
1095         {
1096                 int positive;
1097                 int count;
1098
1099                 if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
1100                         positive = FALSE;
1101                         count = 1;
1102                 } else if (strcmp(cp, "--") == 0) {
1103                         positive = FALSE;
1104                         count = 2;
1105                 } else if (strcmp(cp, "+") == 0) {
1106                         positive = TRUE;
1107                         count = 1;
1108                 } else if (strcmp(cp, "++") == 0) {
1109                         positive = TRUE;
1110                         count = 2;
1111                 } else {
1112                         error(_("illegal CORRECTION field on Leap line"));
1113                         return;
1114                 }
1115                 if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
1116                         error(_("illegal Rolling/Stationary field on Leap line"));
1117                         return;
1118                 }
1119                 leapadd(tadd(t, tod), positive, lp->l_value, count);
1120         }
1121 }
1122
1123 static void
1124 inlink(char ** const fields, const int nfields)
1125 {
1126         struct link     l;
1127
1128         if (nfields != LINK_FIELDS) {
1129                 error(_("wrong number of fields on Link line"));
1130                 return;
1131         }
1132         if (*fields[LF_FROM] == '\0') {
1133                 error(_("blank FROM field on Link line"));
1134                 return;
1135         }
1136         if (*fields[LF_TO] == '\0') {
1137                 error(_("blank TO field on Link line"));
1138                 return;
1139         }
1140         l.l_filename = filename;
1141         l.l_linenum = linenum;
1142         l.l_from = ecpyalloc(fields[LF_FROM]);
1143         l.l_to = ecpyalloc(fields[LF_TO]);
1144         links = (struct link *) (void *) erealloc((char *) links,
1145                 (int) ((nlinks + 1) * sizeof *links));
1146         links[nlinks++] = l;
1147 }
1148
1149 static void
1150 rulesub(struct rule * const rp,
1151         const char * const loyearp,
1152         const char * const hiyearp,
1153         const char * const typep,
1154         const char * const monthp,
1155         const char * const dayp,
1156         const char * const timep)
1157 {
1158         const struct lookup *lp;
1159         const char *cp;
1160         char *dp;
1161         char *ep;
1162
1163         if ((lp = byword(monthp, mon_names)) == NULL) {
1164                 error(_("invalid month name"));
1165                 return;
1166         }
1167         rp->r_month = lp->l_value;
1168         rp->r_todisstd = FALSE;
1169         rp->r_todisgmt = FALSE;
1170         dp = ecpyalloc(timep);
1171         if (*dp != '\0') {
1172                 ep = dp + strlen(dp) - 1;
1173                 switch (lowerit(*ep)) {
1174                         case 's':       /* Standard */
1175                                 rp->r_todisstd = TRUE;
1176                                 rp->r_todisgmt = FALSE;
1177                                 *ep = '\0';
1178                                 break;
1179                         case 'w':       /* Wall */
1180                                 rp->r_todisstd = FALSE;
1181                                 rp->r_todisgmt = FALSE;
1182                                 *ep = '\0';
1183                                 break;
1184                         case 'g':       /* Greenwich */
1185                         case 'u':       /* Universal */
1186                         case 'z':       /* Zulu */
1187                                 rp->r_todisstd = TRUE;
1188                                 rp->r_todisgmt = TRUE;
1189                                 *ep = '\0';
1190                                 break;
1191                 }
1192         }
1193         rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
1194         ifree(dp);
1195         /*
1196         ** Year work.
1197         */
1198         cp = loyearp;
1199         lp = byword(cp, begin_years);
1200         if (lp != NULL) switch ((int) lp->l_value) {
1201                 case YR_MINIMUM:
1202                         rp->r_loyear = INT_MIN;
1203                         break;
1204                 case YR_MAXIMUM:
1205                         rp->r_loyear = INT_MAX;
1206                         break;
1207                 default:        /* "cannot happen" */
1208                         errx(EXIT_FAILURE,
1209                                 _("panic: invalid l_value %d"), lp->l_value);
1210         } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
1211                 error(_("invalid starting year"));
1212                 return;
1213         } else if (noise) {
1214                 if (rp->r_loyear < min_year_representable)
1215                         warning(_("starting year too low to be represented"));
1216                 else if (rp->r_loyear > max_year_representable)
1217                         warning(_("starting year too high to be represented"));
1218         }
1219         cp = hiyearp;
1220         if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
1221                 case YR_MINIMUM:
1222                         rp->r_hiyear = INT_MIN;
1223                         break;
1224                 case YR_MAXIMUM:
1225                         rp->r_hiyear = INT_MAX;
1226                         break;
1227                 case YR_ONLY:
1228                         rp->r_hiyear = rp->r_loyear;
1229                         break;
1230                 default:        /* "cannot happen" */
1231                         errx(EXIT_FAILURE,
1232                                 _("panic: invalid l_value %d"), lp->l_value);
1233         } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
1234                 error(_("invalid ending year"));
1235                 return;
1236         } else if (noise) {
1237                 if (rp->r_loyear < min_year_representable)
1238                         warning(_("starting year too low to be represented"));
1239                 else if (rp->r_loyear > max_year_representable)
1240                         warning(_("starting year too high to be represented"));
1241         }
1242         if (rp->r_loyear > rp->r_hiyear) {
1243                 error(_("starting year greater than ending year"));
1244                 return;
1245         }
1246         if (*typep == '\0')
1247                 rp->r_yrtype = NULL;
1248         else {
1249                 if (rp->r_loyear == rp->r_hiyear) {
1250                         error(_("typed single year"));
1251                         return;
1252                 }
1253                 rp->r_yrtype = ecpyalloc(typep);
1254         }
1255         if (rp->r_loyear < min_year && rp->r_loyear > 0)
1256                 min_year = rp->r_loyear;
1257         /*
1258         ** Day work.
1259         ** Accept things such as:
1260         **      1
1261         **      last-Sunday
1262         **      Sun<=20
1263         **      Sun>=7
1264         */
1265         dp = ecpyalloc(dayp);
1266         if ((lp = byword(dp, lasts)) != NULL) {
1267                 rp->r_dycode = DC_DOWLEQ;
1268                 rp->r_wday = lp->l_value;
1269                 rp->r_dayofmonth = len_months[1][rp->r_month];
1270         } else {
1271                 if ((ep = strchr(dp, '<')) != 0)
1272                         rp->r_dycode = DC_DOWLEQ;
1273                 else if ((ep = strchr(dp, '>')) != 0)
1274                         rp->r_dycode = DC_DOWGEQ;
1275                 else {
1276                         ep = dp;
1277                         rp->r_dycode = DC_DOM;
1278                 }
1279                 if (rp->r_dycode != DC_DOM) {
1280                         *ep++ = 0;
1281                         if (*ep++ != '=') {
1282                                 error(_("invalid day of month"));
1283                                 ifree(dp);
1284                                 return;
1285                         }
1286                         if ((lp = byword(dp, wday_names)) == NULL) {
1287                                 error(_("invalid weekday name"));
1288                                 ifree(dp);
1289                                 return;
1290                         }
1291                         rp->r_wday = lp->l_value;
1292                 }
1293                 if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
1294                         rp->r_dayofmonth <= 0 ||
1295                         (rp->r_dayofmonth > len_months[1][rp->r_month])) {
1296                                 error(_("invalid day of month"));
1297                                 ifree(dp);
1298                                 return;
1299                 }
1300         }
1301         ifree(dp);
1302 }
1303
1304 static void
1305 convert(const long val, char * const buf)
1306 {
1307         int i;
1308         long shift;
1309
1310         for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
1311                 buf[i] = val >> shift;
1312 }
1313
1314 static void
1315 puttzcode(const long val, FILE * const fp)
1316 {
1317         char    buf[4];
1318
1319         convert(val, buf);
1320         fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1321 }
1322
1323 static int
1324 atcomp(const void *avp, const void *bvp)
1325 {
1326         const struct attype *ap = avp;
1327         const struct attype *bp = bvp;
1328
1329         if (ap->at < bp->at)
1330                 return -1;
1331         else if (ap->at > bp->at)
1332                 return 1;
1333         else    return 0;
1334 }
1335
1336 static void
1337 writezone(const char * const name)
1338 {
1339         FILE * fp;
1340         int i, j;
1341         static char *fullname;
1342         static struct tzhead tzh;
1343         time_t ats[TZ_MAX_TIMES];
1344         unsigned char types[TZ_MAX_TIMES];
1345
1346         /*
1347         ** Sort.
1348         */
1349         if (timecnt > 1)
1350                 qsort((void *) attypes, (size_t) timecnt,
1351                         (size_t) sizeof *attypes, atcomp);
1352         /*
1353         ** Optimize.
1354         */
1355         {
1356                 int     fromi;
1357                 int     toi;
1358
1359                 toi = 0;
1360                 fromi = 0;
1361                 while (fromi < timecnt && attypes[fromi].at < min_time)
1362                         ++fromi;
1363                 if (isdsts[0] == 0)
1364                         while (fromi < timecnt && attypes[fromi].type == 0)
1365                                 ++fromi;        /* handled by default rule */
1366                 for ( ; fromi < timecnt; ++fromi) {
1367                         if (toi != 0
1368                             && ((attypes[fromi].at
1369                                  + gmtoffs[attypes[toi - 1].type])
1370                                 <= (attypes[toi - 1].at
1371                                     + gmtoffs[toi == 1 ? 0
1372                                               : attypes[toi - 2].type]))) {
1373                                 attypes[toi - 1].type = attypes[fromi].type;
1374                                 continue;
1375                         }
1376                         if (toi == 0 ||
1377                                 attypes[toi - 1].type != attypes[fromi].type)
1378                                         attypes[toi++] = attypes[fromi];
1379                 }
1380                 timecnt = toi;
1381         }
1382         /*
1383         ** Transfer.
1384         */
1385         for (i = 0; i < timecnt; ++i) {
1386                 ats[i] = attypes[i].at;
1387                 types[i] = attypes[i].type;
1388         }
1389         fullname = erealloc(fullname,
1390                 (int) (strlen(directory) + 1 + strlen(name) + 1));
1391         sprintf(fullname, "%s/%s", directory, name);
1392
1393         /*
1394          * Remove old file, if any, to snap links.
1395          */
1396         if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT)
1397                 err(EXIT_FAILURE, _("can't remove %s"), fullname);
1398
1399         if ((fp = fopen(fullname, "wb")) == NULL) {
1400                 if (mkdirs(fullname) != 0)
1401                         exit(EXIT_FAILURE);
1402                 if ((fp = fopen(fullname, "wb")) == NULL)
1403                         err(EXIT_FAILURE, _("can't create %s"), fullname);
1404         }
1405         convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
1406         convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
1407         convert(eitol(leapcnt), tzh.tzh_leapcnt);
1408         convert(eitol(timecnt), tzh.tzh_timecnt);
1409         convert(eitol(typecnt), tzh.tzh_typecnt);
1410         convert(eitol(charcnt), tzh.tzh_charcnt);
1411         strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1412 #define DO(field)       fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp)
1413         DO(tzh_magic);
1414         DO(tzh_reserved);
1415         DO(tzh_ttisgmtcnt);
1416         DO(tzh_ttisstdcnt);
1417         DO(tzh_leapcnt);
1418         DO(tzh_timecnt);
1419         DO(tzh_typecnt);
1420         DO(tzh_charcnt);
1421 #undef DO
1422         for (i = 0; i < timecnt; ++i) {
1423                 j = leapcnt;
1424                 while (--j >= 0)
1425                         if (ats[i] >= trans[j]) {
1426                                 ats[i] = tadd(ats[i], corr[j]);
1427                                 break;
1428                         }
1429                 puttzcode((long) ats[i], fp);
1430         }
1431         if (timecnt > 0)
1432                 fwrite((void *) types, (size_t) sizeof types[0],
1433                         (size_t) timecnt, fp);
1434         for (i = 0; i < typecnt; ++i) {
1435                 puttzcode((long) gmtoffs[i], fp);
1436                 putc(isdsts[i], fp);
1437                 putc(abbrinds[i], fp);
1438         }
1439         if (charcnt != 0)
1440                 fwrite((void *) chars, (size_t) sizeof chars[0],
1441                         (size_t) charcnt, fp);
1442         for (i = 0; i < leapcnt; ++i) {
1443                 if (roll[i]) {
1444                         if (timecnt == 0 || trans[i] < ats[0]) {
1445                                 j = 0;
1446                                 while (isdsts[j])
1447                                         if (++j >= typecnt) {
1448                                                 j = 0;
1449                                                 break;
1450                                         }
1451                         } else {
1452                                 j = 1;
1453                                 while (j < timecnt && trans[i] >= ats[j])
1454                                         ++j;
1455                                 j = types[j - 1];
1456                         }
1457                         puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
1458                 } else  puttzcode((long) trans[i], fp);
1459                 puttzcode((long) corr[i], fp);
1460         }
1461         for (i = 0; i < typecnt; ++i)
1462                 putc(ttisstds[i], fp);
1463         for (i = 0; i < typecnt; ++i)
1464                 putc(ttisgmts[i], fp);
1465         if (ferror(fp) || fclose(fp))
1466                 errx(EXIT_FAILURE, _("error writing %s"), fullname);
1467         if (chmod(fullname, mflag) < 0)
1468                 err(EXIT_FAILURE, _("cannot change mode of %s to %03o"),
1469                     fullname, (unsigned)mflag);
1470         if ((uflag != (uid_t)-1 || gflag != (gid_t)-1)
1471             && chown(fullname, uflag, gflag) < 0)
1472                 err(EXIT_FAILURE, _("cannot change ownership of %s"), 
1473                     fullname);
1474 }
1475
1476 static void
1477 doabbr(char * const abbr, const char * const format,
1478        const char * const letters, const int isdst)
1479 {
1480         if (strchr(format, '/') == NULL) {
1481                 if (letters == NULL)
1482                         strcpy(abbr, format);
1483                 else    sprintf(abbr, format, letters);
1484         } else if (isdst)
1485                 strcpy(abbr, strchr(format, '/') + 1);
1486         else {
1487                 strcpy(abbr, format);
1488                 *strchr(abbr, '/') = '\0';
1489         }
1490 }
1491
1492 static void
1493 outzone(const struct zone * const zpfirst, const int zonecount)
1494 {
1495         const struct zone *zp;
1496         struct rule *rp;
1497         int i, j;
1498         int usestart, useuntil;
1499         time_t starttime, untiltime;
1500         long gmtoff;
1501         long stdoff;
1502         int year;
1503         long startoff;
1504         int startttisstd;
1505         int startttisgmt;
1506         int type;
1507         char startbuf[BUFSIZ];
1508
1509         INITIALIZE(untiltime);
1510         INITIALIZE(starttime);
1511         /*
1512         ** Now. . .finally. . .generate some useful data!
1513         */
1514         timecnt = 0;
1515         typecnt = 0;
1516         charcnt = 0;
1517         /*
1518         ** A guess that may well be corrected later.
1519         */
1520         stdoff = 0;
1521         /*
1522         ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)
1523         ** for noting the need to unconditionally initialize startttisstd.
1524         */
1525         startttisstd = FALSE;
1526         startttisgmt = FALSE;
1527         for (i = 0; i < zonecount; ++i) {
1528                 zp = &zpfirst[i];
1529                 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
1530                 useuntil = i < (zonecount - 1);
1531                 if (useuntil && zp->z_untiltime <= min_time)
1532                         continue;
1533                 gmtoff = zp->z_gmtoff;
1534                 eat(zp->z_filename, zp->z_linenum);
1535                 *startbuf = '\0';
1536                 startoff = zp->z_gmtoff;
1537                 if (zp->z_nrules == 0) {
1538                         stdoff = zp->z_stdoff;
1539                         doabbr(startbuf, zp->z_format,
1540                                 (char *) NULL, stdoff != 0);
1541                         type = addtype(oadd(zp->z_gmtoff, stdoff),
1542                                 startbuf, stdoff != 0, startttisstd,
1543                                 startttisgmt);
1544                         if (usestart) {
1545                                 addtt(starttime, type);
1546                                 usestart = FALSE;
1547                         }
1548                         else if (stdoff != 0)
1549                                 addtt(min_time, type);
1550                 } else for (year = min_year; year <= max_year; ++year) {
1551                         if (useuntil && year > zp->z_untilrule.r_hiyear)
1552                                 break;
1553                         /*
1554                         ** Mark which rules to do in the current year.
1555                         ** For those to do, calculate rpytime(rp, year);
1556                         */
1557                         for (j = 0; j < zp->z_nrules; ++j) {
1558                                 rp = &zp->z_rules[j];
1559                                 eats(zp->z_filename, zp->z_linenum,
1560                                         rp->r_filename, rp->r_linenum);
1561                                 rp->r_todo = year >= rp->r_loyear &&
1562                                                 year <= rp->r_hiyear &&
1563                                                 yearistype(year, rp->r_yrtype);
1564                                 if (rp->r_todo)
1565                                         rp->r_temp = rpytime(rp, year);
1566                         }
1567                         for ( ; ; ) {
1568                                 int k;
1569                                 time_t jtime, ktime;
1570                                 long offset;
1571                                 char buf[BUFSIZ];
1572
1573                                 INITIALIZE(ktime);
1574                                 if (useuntil) {
1575                                         /*
1576                                         ** Turn untiltime into UTC
1577                                         ** assuming the current gmtoff and
1578                                         ** stdoff values.
1579                                         */
1580                                         untiltime = zp->z_untiltime;
1581                                         if (!zp->z_untilrule.r_todisgmt)
1582                                                 untiltime = tadd(untiltime,
1583                                                         -gmtoff);
1584                                         if (!zp->z_untilrule.r_todisstd)
1585                                                 untiltime = tadd(untiltime,
1586                                                         -stdoff);
1587                                 }
1588                                 /*
1589                                 ** Find the rule (of those to do, if any)
1590                                 ** that takes effect earliest in the year.
1591                                 */
1592                                 k = -1;
1593                                 for (j = 0; j < zp->z_nrules; ++j) {
1594                                         rp = &zp->z_rules[j];
1595                                         if (!rp->r_todo)
1596                                                 continue;
1597                                         eats(zp->z_filename, zp->z_linenum,
1598                                                 rp->r_filename, rp->r_linenum);
1599                                         offset = rp->r_todisgmt ? 0 : gmtoff;
1600                                         if (!rp->r_todisstd)
1601                                                 offset = oadd(offset, stdoff);
1602                                         jtime = rp->r_temp;
1603                                         if (jtime == min_time ||
1604                                                 jtime == max_time)
1605                                                         continue;
1606                                         jtime = tadd(jtime, -offset);
1607                                         if (k < 0 || jtime < ktime) {
1608                                                 k = j;
1609                                                 ktime = jtime;
1610                                         }
1611                                 }
1612                                 if (k < 0)
1613                                         break;  /* go on to next year */
1614                                 rp = &zp->z_rules[k];
1615                                 rp->r_todo = FALSE;
1616                                 if (useuntil && ktime >= untiltime)
1617                                         break;
1618                                 stdoff = rp->r_stdoff;
1619                                 if (usestart && ktime == starttime)
1620                                         usestart = FALSE;
1621                                 if (usestart) {
1622                                         if (ktime < starttime) {
1623                                                 startoff = oadd(zp->z_gmtoff,
1624                                                         stdoff);
1625                                                 doabbr(startbuf, zp->z_format,
1626                                                         rp->r_abbrvar,
1627                                                         rp->r_stdoff != 0);
1628                                                 continue;
1629                                         }
1630                                         if (*startbuf == '\0' &&
1631                                             startoff == oadd(zp->z_gmtoff,
1632                                             stdoff)) {
1633                                                 doabbr(startbuf, zp->z_format,
1634                                                         rp->r_abbrvar,
1635                                                         rp->r_stdoff != 0);
1636                                         }
1637                                 }
1638                                 eats(zp->z_filename, zp->z_linenum,
1639                                         rp->r_filename, rp->r_linenum);
1640                                 doabbr(buf, zp->z_format, rp->r_abbrvar,
1641                                         rp->r_stdoff != 0);
1642                                 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1643                                 type = addtype(offset, buf, rp->r_stdoff != 0,
1644                                         rp->r_todisstd, rp->r_todisgmt);
1645                                 addtt(ktime, type);
1646                         }
1647                 }
1648                 if (usestart) {
1649                         if (*startbuf == '\0' &&
1650                                 zp->z_format != NULL &&
1651                                 strchr(zp->z_format, '%') == NULL &&
1652                                 strchr(zp->z_format, '/') == NULL)
1653                                         strcpy(startbuf, zp->z_format);
1654                         eat(zp->z_filename, zp->z_linenum);
1655                         if (*startbuf == '\0')
1656 error(_("can't determine time zone abbreviation to use just after until time"));
1657                         else    addtt(starttime,
1658                                         addtype(startoff, startbuf,
1659                                                 startoff != zp->z_gmtoff,
1660                                                 startttisstd,
1661                                                 startttisgmt));
1662                 }
1663                 /*
1664                 ** Now we may get to set starttime for the next zone line.
1665                 */
1666                 if (useuntil) {
1667                         startttisstd = zp->z_untilrule.r_todisstd;
1668                         startttisgmt = zp->z_untilrule.r_todisgmt;
1669                         starttime = zp->z_untiltime;
1670                         if (!startttisstd)
1671                                 starttime = tadd(starttime, -stdoff);
1672                         if (!startttisgmt)
1673                                 starttime = tadd(starttime, -gmtoff);
1674                 }
1675         }
1676         writezone(zpfirst->z_name);
1677 }
1678
1679 static void
1680 addtt(const time_t starttime, int type)
1681 {
1682         if (starttime <= min_time ||
1683                 (timecnt == 1 && attypes[0].at < min_time)) {
1684                 gmtoffs[0] = gmtoffs[type];
1685                 isdsts[0] = isdsts[type];
1686                 ttisstds[0] = ttisstds[type];
1687                 ttisgmts[0] = ttisgmts[type];
1688                 if (abbrinds[type] != 0)
1689                         strcpy(chars, &chars[abbrinds[type]]);
1690                 abbrinds[0] = 0;
1691                 charcnt = strlen(chars) + 1;
1692                 typecnt = 1;
1693                 timecnt = 0;
1694                 type = 0;
1695         }
1696         if (timecnt >= TZ_MAX_TIMES) {
1697                 error(_("too many transitions?!"));
1698                 exit(EXIT_FAILURE);
1699         }
1700         attypes[timecnt].at = starttime;
1701         attypes[timecnt].type = type;
1702         ++timecnt;
1703 }
1704
1705 static int
1706 addtype(const long gmtoff, const char * const abbr, const int isdst,
1707         const int ttisstd, const int ttisgmt)
1708 {
1709         int i, j;
1710
1711         if (isdst != TRUE && isdst != FALSE) {
1712                 error(_("internal error - addtype called with bad isdst"));
1713                 exit(EXIT_FAILURE);
1714         }
1715         if (ttisstd != TRUE && ttisstd != FALSE) {
1716                 error(_("internal error - addtype called with bad ttisstd"));
1717                 exit(EXIT_FAILURE);
1718         }
1719         if (ttisgmt != TRUE && ttisgmt != FALSE) {
1720                 error(_("internal error - addtype called with bad ttisgmt"));
1721                 exit(EXIT_FAILURE);
1722         }
1723         /*
1724         ** See if there's already an entry for this zone type.
1725         ** If so, just return its index.
1726         */
1727         for (i = 0; i < typecnt; ++i) {
1728                 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
1729                         strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
1730                         ttisstd == ttisstds[i] &&
1731                         ttisgmt == ttisgmts[i])
1732                                 return i;
1733         }
1734         /*
1735         ** There isn't one; add a new one, unless there are already too
1736         ** many.
1737         */
1738         if (typecnt >= TZ_MAX_TYPES) {
1739                 error(_("too many local time types"));
1740                 exit(EXIT_FAILURE);
1741         }
1742         gmtoffs[i] = gmtoff;
1743         isdsts[i] = isdst;
1744         ttisstds[i] = ttisstd;
1745         ttisgmts[i] = ttisgmt;
1746
1747         for (j = 0; j < charcnt; ++j)
1748                 if (strcmp(&chars[j], abbr) == 0)
1749                         break;
1750         if (j == charcnt)
1751                 newabbr(abbr);
1752         abbrinds[i] = j;
1753         ++typecnt;
1754         return i;
1755 }
1756
1757 static void
1758 leapadd(const time_t t, const int positive, const int rolling, int count)
1759 {
1760         int i, j;
1761
1762         if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
1763                 error(_("too many leap seconds"));
1764                 exit(EXIT_FAILURE);
1765         }
1766         for (i = 0; i < leapcnt; ++i)
1767                 if (t <= trans[i]) {
1768                         if (t == trans[i]) {
1769                                 error(_("repeated leap second moment"));
1770                                 exit(EXIT_FAILURE);
1771                         }
1772                         break;
1773                 }
1774         do {
1775                 for (j = leapcnt; j > i; --j) {
1776                         trans[j] = trans[j - 1];
1777                         corr[j] = corr[j - 1];
1778                         roll[j] = roll[j - 1];
1779                 }
1780                 trans[i] = t;
1781                 corr[i] = positive ? 1L : eitol(-count);
1782                 roll[i] = rolling;
1783                 ++leapcnt;
1784         } while (positive && --count != 0);
1785 }
1786
1787 static void
1788 adjleap(void)
1789 {
1790         int i;
1791         long last = 0;
1792
1793         /*
1794         ** propagate leap seconds forward
1795         */
1796         for (i = 0; i < leapcnt; ++i) {
1797                 trans[i] = tadd(trans[i], last);
1798                 last = corr[i] += last;
1799         }
1800 }
1801
1802 static int
1803 yearistype(const int year, const char * const type)
1804 {
1805         static char *   buf;
1806         int             result;
1807
1808         if (type == NULL || *type == '\0')
1809                 return TRUE;
1810         buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
1811         sprintf(buf, "%s %d %s", yitcommand, year, type);
1812         result = system(buf);
1813         if (result == 0)
1814                 return TRUE;
1815         if (result == (1 << 8))
1816                 return FALSE;
1817         error(_("wild result from command execution"));
1818         warnx(_("command was '%s', result was %d"), buf, result);
1819         for ( ; ; )
1820                 exit(EXIT_FAILURE);
1821 }
1822
1823 static int
1824 lowerit(int a)
1825 {
1826         a = (unsigned char) a;
1827         return (isascii(a) && isupper(a)) ? tolower(a) : a;
1828 }
1829
1830 static int
1831 ciequal(const char *ap, const char *bp) /* case-insensitive equality */
1832 {
1833         while (lowerit(*ap) == lowerit(*bp++))
1834                 if (*ap++ == '\0')
1835                         return TRUE;
1836         return FALSE;
1837 }
1838
1839 static int
1840 itsabbr(const char *abbr, const char *word)
1841 {
1842         if (lowerit(*abbr) != lowerit(*word))
1843                 return FALSE;
1844         ++word;
1845         while (*++abbr != '\0')
1846                 do {
1847                         if (*word == '\0')
1848                                 return FALSE;
1849                 } while (lowerit(*word++) != lowerit(*abbr));
1850         return TRUE;
1851 }
1852
1853 static const struct lookup *
1854 byword(const char * const word, const struct lookup * const table)
1855 {
1856         const struct lookup *foundlp;
1857         const struct lookup *lp;
1858
1859         if (word == NULL || table == NULL)
1860                 return NULL;
1861         /*
1862         ** Look for exact match.
1863         */
1864         for (lp = table; lp->l_word != NULL; ++lp)
1865                 if (ciequal(word, lp->l_word))
1866                         return lp;
1867         /*
1868         ** Look for inexact match.
1869         */
1870         foundlp = NULL;
1871         for (lp = table; lp->l_word != NULL; ++lp)
1872                 if (itsabbr(word, lp->l_word)) {
1873                         if (foundlp == NULL)
1874                                 foundlp = lp;
1875                         else    return NULL;    /* multiple inexact matches */
1876                 }
1877         return foundlp;
1878 }
1879
1880 static char **
1881 getfields(char *cp)
1882 {
1883         char *dp;
1884         char **array;
1885         int nsubs;
1886
1887         if (cp == NULL)
1888                 return NULL;
1889         array = (char **) (void *)
1890                 emalloc((int) ((strlen(cp) + 1) * sizeof *array));
1891         nsubs = 0;
1892         for ( ; ; ) {
1893                 while (isascii(*cp) && isspace((unsigned char) *cp))
1894                         ++cp;
1895                 if (*cp == '\0' || *cp == '#')
1896                         break;
1897                 array[nsubs++] = dp = cp;
1898                 do {
1899                         if ((*dp = *cp++) != '"')
1900                                 ++dp;
1901                         else while ((*dp = *cp++) != '"')
1902                                 if (*dp != '\0')
1903                                         ++dp;
1904                                 else    error(_("odd number of quotation marks"));
1905                 } while (*cp != '\0' && *cp != '#' &&
1906                         (!isascii(*cp) || !isspace((unsigned char) *cp)));
1907                 if (isascii(*cp) && isspace((unsigned char) *cp))
1908                         ++cp;
1909                 *dp = '\0';
1910         }
1911         array[nsubs] = NULL;
1912         return array;
1913 }
1914
1915 static long
1916 oadd(const long t1, const long t2)
1917 {
1918         long t;
1919
1920         t = t1 + t2;
1921         if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
1922                 error(_("time overflow"));
1923                 exit(EXIT_FAILURE);
1924         }
1925         return t;
1926 }
1927
1928 static time_t
1929 tadd(const time_t t1, const long t2)
1930 {
1931         time_t t;
1932
1933         if (t1 == max_time && t2 > 0)
1934                 return max_time;
1935         if (t1 == min_time && t2 < 0)
1936                 return min_time;
1937         t = t1 + t2;
1938         if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
1939                 error(_("time overflow"));
1940                 exit(EXIT_FAILURE);
1941         }
1942         return t;
1943 }
1944
1945 /*
1946 ** Given a rule, and a year, compute the date - in seconds since January 1,
1947 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
1948 */
1949
1950 static time_t
1951 rpytime(const struct rule * const rp, const int wantedy)
1952 {
1953         int y, m, i;
1954         long dayoff;                    /* with a nod to Margaret O. */
1955         time_t t;
1956
1957         if (wantedy == INT_MIN)
1958                 return min_time;
1959         if (wantedy == INT_MAX)
1960                 return max_time;
1961         dayoff = 0;
1962         m = TM_JANUARY;
1963         y = EPOCH_YEAR;
1964         while (wantedy != y) {
1965                 if (wantedy > y) {
1966                         i = len_years[isleap(y)];
1967                         ++y;
1968                 } else {
1969                         --y;
1970                         i = -len_years[isleap(y)];
1971                 }
1972                 dayoff = oadd(dayoff, eitol(i));
1973         }
1974         while (m != rp->r_month) {
1975                 i = len_months[isleap(y)][m];
1976                 dayoff = oadd(dayoff, eitol(i));
1977                 ++m;
1978         }
1979         i = rp->r_dayofmonth;
1980         if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
1981                 if (rp->r_dycode == DC_DOWLEQ)
1982                         --i;
1983                 else {
1984                         error(_("use of 2/29 in non leap-year"));
1985                         exit(EXIT_FAILURE);
1986                 }
1987         }
1988         --i;
1989         dayoff = oadd(dayoff, eitol(i));
1990         if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
1991                 long wday;
1992
1993 #define LDAYSPERWEEK    ((long) DAYSPERWEEK)
1994                 wday = eitol(EPOCH_WDAY);
1995                 /*
1996                 ** Don't trust mod of negative numbers.
1997                 */
1998                 if (dayoff >= 0)
1999                         wday = (wday + dayoff) % LDAYSPERWEEK;
2000                 else {
2001                         wday -= ((-dayoff) % LDAYSPERWEEK);
2002                         if (wday < 0)
2003                                 wday += LDAYSPERWEEK;
2004                 }
2005                 while (wday != eitol(rp->r_wday))
2006                         if (rp->r_dycode == DC_DOWGEQ) {
2007                                 dayoff = oadd(dayoff, (long) 1);
2008                                 if (++wday >= LDAYSPERWEEK)
2009                                         wday = 0;
2010                                 ++i;
2011                         } else {
2012                                 dayoff = oadd(dayoff, (long) -1);
2013                                 if (--wday < 0)
2014                                         wday = LDAYSPERWEEK - 1;
2015                                 --i;
2016                         }
2017                 if (i < 0 || i >= len_months[isleap(y)][m]) {
2018                         error(_("no day in month matches rule"));
2019                         exit(EXIT_FAILURE);
2020                 }
2021         }
2022         if (dayoff < 0 && !TYPE_SIGNED(time_t))
2023                 return min_time;
2024         t = (time_t) dayoff * SECSPERDAY;
2025         /*
2026         ** Cheap overflow check.
2027         */
2028         if (t / SECSPERDAY != dayoff)
2029                 return (dayoff > 0) ? max_time : min_time;
2030         return tadd(t, rp->r_tod);
2031 }
2032
2033 static void
2034 newabbr(const char * const string)
2035 {
2036         int i;
2037
2038         i = strlen(string) + 1;
2039         if (charcnt + i > TZ_MAX_CHARS) {
2040                 error(_("too many, or too long, time zone abbreviations"));
2041                 exit(EXIT_FAILURE);
2042         }
2043         strcpy(&chars[charcnt], string);
2044         charcnt += eitol(i);
2045 }
2046
2047 static int
2048 mkdirs(char * const argname)
2049 {
2050         char *name;
2051         char *cp;
2052
2053         if (argname == NULL || *argname == '\0' || Dflag)
2054                 return 0;
2055         cp = name = ecpyalloc(argname);
2056         while ((cp = strchr(cp + 1, '/')) != 0) {
2057                 *cp = '\0';
2058 #ifndef unix
2059                 /*
2060                 ** DOS drive specifier?
2061                 */
2062                 if (isalpha((unsigned char) name[0]) &&
2063                         name[1] == ':' && name[2] == '\0') {
2064                                 *cp = '/';
2065                                 continue;
2066                 }
2067 #endif /* !defined unix */
2068                 if (!itsdir(name)) {
2069                         /*
2070                         ** It doesn't seem to exist, so we try to create it.
2071                         ** Creation may fail because of the directory being
2072                         ** created by some other multiprocessor, so we get
2073                         ** to do extra checking.
2074                         */
2075                         if (mkdir(name, (S_IRUSR | S_IWUSR | S_IXUSR 
2076                                          | S_IRGRP | S_IXGRP | S_IROTH
2077                                          | S_IXOTH)) != 0
2078                                 && (errno != EEXIST || !itsdir(name))) {
2079                                 warn(_("can't create directory %s"), name);
2080                                 ifree(name);
2081                                 return -1;
2082                         }
2083                 }
2084                 *cp = '/';
2085         }
2086         ifree(name);
2087         return 0;
2088 }
2089
2090 static long
2091 eitol(const int i)
2092 {
2093         long    l;
2094
2095         l = i;
2096         if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0))
2097                 errx(EXIT_FAILURE, _("%d did not sign extend correctly"), i);
2098         return l;
2099 }
2100
2101 #include <grp.h>
2102 #include <pwd.h>
2103
2104 static void
2105 setgroup(gid_t *flag, const char *name)
2106 {
2107         struct group *gr;
2108
2109         if (*flag != (gid_t)-1)
2110                 errx(EXIT_FAILURE, _("multiple -g flags specified"));
2111
2112         gr = getgrnam(name);
2113         if (gr == 0) {
2114                 char *ep;
2115                 unsigned long ul;
2116
2117                 ul = strtoul(name, &ep, 10);
2118                 if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
2119                         *flag = ul;
2120                         return;
2121                 }
2122                 errx(EXIT_FAILURE, _("group `%s' not found"), name);
2123         }
2124         *flag = gr->gr_gid;
2125 }
2126
2127 static void
2128 setuser(uid_t *flag, const char *name)
2129 {
2130         struct passwd *pw;
2131
2132         if (*flag != (gid_t)-1)
2133                 errx(EXIT_FAILURE, _("multiple -u flags specified"));
2134
2135         pw = getpwnam(name);
2136         if (pw == 0) {
2137                 char *ep;
2138                 unsigned long ul;
2139
2140                 ul = strtoul(name, &ep, 10);
2141                 if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
2142                         *flag = ul;
2143                         return;
2144                 }
2145                 errx(EXIT_FAILURE, _("user `%s' not found"), name);
2146         }
2147         *flag = pw->pw_uid;
2148 }
2149
2150 /*
2151 ** UNIX was a registered trademark of UNIX System Laboratories in 1993.
2152 */