De-K&R-ify function prototyps and remove register keyword.
[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.3 2004/02/29 16:55:28 joerg 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         (void) fprintf(stderr, _("\"%s\", line %d: %s"),
407                 filename, linenum, string);
408         if (rfilename != NULL)
409                 (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
410                         rfilename, rlinenum);
411         (void) 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         (void) fprintf(stderr, "%s\n%s\n",
431 _("usage: zic [-s] [-v] [-l localtime] [-p posixrules] [-d directory]"),
432 _("           [-L leapseconds] [-y yearistype] [filename ... ]"));
433         (void) 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         (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
457 #endif /* defined unix */
458 #if HAVE_GETTEXT - 0
459         (void) setlocale(LC_MESSAGES, "");
460 #ifdef TZ_DOMAINDIR
461         (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
462 #endif /* defined TEXTDOMAINDIR */
463         (void) 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                 (void) 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                 (void) remove(toname);
591         if (link(fromname, toname) != 0) {
592                 int     result;
593
594                 if (mkdirs(toname) != 0)
595                         (void) 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                 (void) 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                 (void) 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                         (void) 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                 (void) 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                 (void) 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                                 (void) 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                 register 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         (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
1321 }
1322
1323 static int
1324 atcomp(void *avp, void *bvp)
1325 {
1326         if (((struct attype *) avp)->at < ((struct attype *) bvp)->at)
1327                 return -1;
1328         else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at)
1329                 return 1;
1330         else    return 0;
1331 }
1332
1333 static void
1334 writezone(const char * const name)
1335 {
1336         FILE * fp;
1337         int i, j;
1338         static char *fullname;
1339         static struct tzhead tzh;
1340         time_t ats[TZ_MAX_TIMES];
1341         unsigned char types[TZ_MAX_TIMES];
1342
1343         /*
1344         ** Sort.
1345         */
1346         if (timecnt > 1)
1347                 (void) qsort((void *) attypes, (size_t) timecnt,
1348                         (size_t) sizeof *attypes, atcomp);
1349         /*
1350         ** Optimize.
1351         */
1352         {
1353                 int     fromi;
1354                 int     toi;
1355
1356                 toi = 0;
1357                 fromi = 0;
1358                 while (fromi < timecnt && attypes[fromi].at < min_time)
1359                         ++fromi;
1360                 if (isdsts[0] == 0)
1361                         while (fromi < timecnt && attypes[fromi].type == 0)
1362                                 ++fromi;        /* handled by default rule */
1363                 for ( ; fromi < timecnt; ++fromi) {
1364                         if (toi != 0
1365                             && ((attypes[fromi].at
1366                                  + gmtoffs[attypes[toi - 1].type])
1367                                 <= (attypes[toi - 1].at
1368                                     + gmtoffs[toi == 1 ? 0
1369                                               : attypes[toi - 2].type]))) {
1370                                 attypes[toi - 1].type = attypes[fromi].type;
1371                                 continue;
1372                         }
1373                         if (toi == 0 ||
1374                                 attypes[toi - 1].type != attypes[fromi].type)
1375                                         attypes[toi++] = attypes[fromi];
1376                 }
1377                 timecnt = toi;
1378         }
1379         /*
1380         ** Transfer.
1381         */
1382         for (i = 0; i < timecnt; ++i) {
1383                 ats[i] = attypes[i].at;
1384                 types[i] = attypes[i].type;
1385         }
1386         fullname = erealloc(fullname,
1387                 (int) (strlen(directory) + 1 + strlen(name) + 1));
1388         (void) sprintf(fullname, "%s/%s", directory, name);
1389
1390         /*
1391          * Remove old file, if any, to snap links.
1392          */
1393         if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT)
1394                 err(EXIT_FAILURE, _("can't remove %s"), fullname);
1395
1396         if ((fp = fopen(fullname, "wb")) == NULL) {
1397                 if (mkdirs(fullname) != 0)
1398                         (void) exit(EXIT_FAILURE);
1399                 if ((fp = fopen(fullname, "wb")) == NULL)
1400                         err(EXIT_FAILURE, _("can't create %s"), fullname);
1401         }
1402         convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
1403         convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
1404         convert(eitol(leapcnt), tzh.tzh_leapcnt);
1405         convert(eitol(timecnt), tzh.tzh_timecnt);
1406         convert(eitol(typecnt), tzh.tzh_typecnt);
1407         convert(eitol(charcnt), tzh.tzh_charcnt);
1408         (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
1409 #define DO(field)       (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp)
1410         DO(tzh_magic);
1411         DO(tzh_reserved);
1412         DO(tzh_ttisgmtcnt);
1413         DO(tzh_ttisstdcnt);
1414         DO(tzh_leapcnt);
1415         DO(tzh_timecnt);
1416         DO(tzh_typecnt);
1417         DO(tzh_charcnt);
1418 #undef DO
1419         for (i = 0; i < timecnt; ++i) {
1420                 j = leapcnt;
1421                 while (--j >= 0)
1422                         if (ats[i] >= trans[j]) {
1423                                 ats[i] = tadd(ats[i], corr[j]);
1424                                 break;
1425                         }
1426                 puttzcode((long) ats[i], fp);
1427         }
1428         if (timecnt > 0)
1429                 (void) fwrite((void *) types, (size_t) sizeof types[0],
1430                         (size_t) timecnt, fp);
1431         for (i = 0; i < typecnt; ++i) {
1432                 puttzcode((long) gmtoffs[i], fp);
1433                 (void) putc(isdsts[i], fp);
1434                 (void) putc(abbrinds[i], fp);
1435         }
1436         if (charcnt != 0)
1437                 (void) fwrite((void *) chars, (size_t) sizeof chars[0],
1438                         (size_t) charcnt, fp);
1439         for (i = 0; i < leapcnt; ++i) {
1440                 if (roll[i]) {
1441                         if (timecnt == 0 || trans[i] < ats[0]) {
1442                                 j = 0;
1443                                 while (isdsts[j])
1444                                         if (++j >= typecnt) {
1445                                                 j = 0;
1446                                                 break;
1447                                         }
1448                         } else {
1449                                 j = 1;
1450                                 while (j < timecnt && trans[i] >= ats[j])
1451                                         ++j;
1452                                 j = types[j - 1];
1453                         }
1454                         puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
1455                 } else  puttzcode((long) trans[i], fp);
1456                 puttzcode((long) corr[i], fp);
1457         }
1458         for (i = 0; i < typecnt; ++i)
1459                 (void) putc(ttisstds[i], fp);
1460         for (i = 0; i < typecnt; ++i)
1461                 (void) putc(ttisgmts[i], fp);
1462         if (ferror(fp) || fclose(fp))
1463                 errx(EXIT_FAILURE, _("error writing %s"), fullname);
1464         if (chmod(fullname, mflag) < 0)
1465                 err(EXIT_FAILURE, _("cannot change mode of %s to %03o"),
1466                     fullname, (unsigned)mflag);
1467         if ((uflag != (uid_t)-1 || gflag != (gid_t)-1)
1468             && chown(fullname, uflag, gflag) < 0)
1469                 err(EXIT_FAILURE, _("cannot change ownership of %s"), 
1470                     fullname);
1471 }
1472
1473 static void
1474 doabbr(char * const abbr, const char * const format,
1475        const char * const letters, const int isdst)
1476 {
1477         if (strchr(format, '/') == NULL) {
1478                 if (letters == NULL)
1479                         (void) strcpy(abbr, format);
1480                 else    (void) sprintf(abbr, format, letters);
1481         } else if (isdst)
1482                 (void) strcpy(abbr, strchr(format, '/') + 1);
1483         else {
1484                 (void) strcpy(abbr, format);
1485                 *strchr(abbr, '/') = '\0';
1486         }
1487 }
1488
1489 static void
1490 outzone(const struct zone * const zpfirst, const int zonecount)
1491 {
1492         const struct zone *zp;
1493         struct rule *rp;
1494         int i, j;
1495         int usestart, useuntil;
1496         time_t starttime, untiltime;
1497         long gmtoff;
1498         long stdoff;
1499         int year;
1500         long startoff;
1501         int startttisstd;
1502         int startttisgmt;
1503         int type;
1504         char startbuf[BUFSIZ];
1505
1506         INITIALIZE(untiltime);
1507         INITIALIZE(starttime);
1508         /*
1509         ** Now. . .finally. . .generate some useful data!
1510         */
1511         timecnt = 0;
1512         typecnt = 0;
1513         charcnt = 0;
1514         /*
1515         ** A guess that may well be corrected later.
1516         */
1517         stdoff = 0;
1518         /*
1519         ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)
1520         ** for noting the need to unconditionally initialize startttisstd.
1521         */
1522         startttisstd = FALSE;
1523         startttisgmt = FALSE;
1524         for (i = 0; i < zonecount; ++i) {
1525                 zp = &zpfirst[i];
1526                 usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
1527                 useuntil = i < (zonecount - 1);
1528                 if (useuntil && zp->z_untiltime <= min_time)
1529                         continue;
1530                 gmtoff = zp->z_gmtoff;
1531                 eat(zp->z_filename, zp->z_linenum);
1532                 *startbuf = '\0';
1533                 startoff = zp->z_gmtoff;
1534                 if (zp->z_nrules == 0) {
1535                         stdoff = zp->z_stdoff;
1536                         doabbr(startbuf, zp->z_format,
1537                                 (char *) NULL, stdoff != 0);
1538                         type = addtype(oadd(zp->z_gmtoff, stdoff),
1539                                 startbuf, stdoff != 0, startttisstd,
1540                                 startttisgmt);
1541                         if (usestart) {
1542                                 addtt(starttime, type);
1543                                 usestart = FALSE;
1544                         }
1545                         else if (stdoff != 0)
1546                                 addtt(min_time, type);
1547                 } else for (year = min_year; year <= max_year; ++year) {
1548                         if (useuntil && year > zp->z_untilrule.r_hiyear)
1549                                 break;
1550                         /*
1551                         ** Mark which rules to do in the current year.
1552                         ** For those to do, calculate rpytime(rp, year);
1553                         */
1554                         for (j = 0; j < zp->z_nrules; ++j) {
1555                                 rp = &zp->z_rules[j];
1556                                 eats(zp->z_filename, zp->z_linenum,
1557                                         rp->r_filename, rp->r_linenum);
1558                                 rp->r_todo = year >= rp->r_loyear &&
1559                                                 year <= rp->r_hiyear &&
1560                                                 yearistype(year, rp->r_yrtype);
1561                                 if (rp->r_todo)
1562                                         rp->r_temp = rpytime(rp, year);
1563                         }
1564                         for ( ; ; ) {
1565                                 register int    k;
1566                                 register time_t jtime, ktime;
1567                                 register long   offset;
1568                                 char            buf[BUFSIZ];
1569
1570                                 INITIALIZE(ktime);
1571                                 if (useuntil) {
1572                                         /*
1573                                         ** Turn untiltime into UTC
1574                                         ** assuming the current gmtoff and
1575                                         ** stdoff values.
1576                                         */
1577                                         untiltime = zp->z_untiltime;
1578                                         if (!zp->z_untilrule.r_todisgmt)
1579                                                 untiltime = tadd(untiltime,
1580                                                         -gmtoff);
1581                                         if (!zp->z_untilrule.r_todisstd)
1582                                                 untiltime = tadd(untiltime,
1583                                                         -stdoff);
1584                                 }
1585                                 /*
1586                                 ** Find the rule (of those to do, if any)
1587                                 ** that takes effect earliest in the year.
1588                                 */
1589                                 k = -1;
1590                                 for (j = 0; j < zp->z_nrules; ++j) {
1591                                         rp = &zp->z_rules[j];
1592                                         if (!rp->r_todo)
1593                                                 continue;
1594                                         eats(zp->z_filename, zp->z_linenum,
1595                                                 rp->r_filename, rp->r_linenum);
1596                                         offset = rp->r_todisgmt ? 0 : gmtoff;
1597                                         if (!rp->r_todisstd)
1598                                                 offset = oadd(offset, stdoff);
1599                                         jtime = rp->r_temp;
1600                                         if (jtime == min_time ||
1601                                                 jtime == max_time)
1602                                                         continue;
1603                                         jtime = tadd(jtime, -offset);
1604                                         if (k < 0 || jtime < ktime) {
1605                                                 k = j;
1606                                                 ktime = jtime;
1607                                         }
1608                                 }
1609                                 if (k < 0)
1610                                         break;  /* go on to next year */
1611                                 rp = &zp->z_rules[k];
1612                                 rp->r_todo = FALSE;
1613                                 if (useuntil && ktime >= untiltime)
1614                                         break;
1615                                 stdoff = rp->r_stdoff;
1616                                 if (usestart && ktime == starttime)
1617                                         usestart = FALSE;
1618                                 if (usestart) {
1619                                         if (ktime < starttime) {
1620                                                 startoff = oadd(zp->z_gmtoff,
1621                                                         stdoff);
1622                                                 doabbr(startbuf, zp->z_format,
1623                                                         rp->r_abbrvar,
1624                                                         rp->r_stdoff != 0);
1625                                                 continue;
1626                                         }
1627                                         if (*startbuf == '\0' &&
1628                                             startoff == oadd(zp->z_gmtoff,
1629                                             stdoff)) {
1630                                                 doabbr(startbuf, zp->z_format,
1631                                                         rp->r_abbrvar,
1632                                                         rp->r_stdoff != 0);
1633                                         }
1634                                 }
1635                                 eats(zp->z_filename, zp->z_linenum,
1636                                         rp->r_filename, rp->r_linenum);
1637                                 doabbr(buf, zp->z_format, rp->r_abbrvar,
1638                                         rp->r_stdoff != 0);
1639                                 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
1640                                 type = addtype(offset, buf, rp->r_stdoff != 0,
1641                                         rp->r_todisstd, rp->r_todisgmt);
1642                                 addtt(ktime, type);
1643                         }
1644                 }
1645                 if (usestart) {
1646                         if (*startbuf == '\0' &&
1647                                 zp->z_format != NULL &&
1648                                 strchr(zp->z_format, '%') == NULL &&
1649                                 strchr(zp->z_format, '/') == NULL)
1650                                         (void) strcpy(startbuf, zp->z_format);
1651                         eat(zp->z_filename, zp->z_linenum);
1652                         if (*startbuf == '\0')
1653 error(_("can't determine time zone abbreviation to use just after until time"));
1654                         else    addtt(starttime,
1655                                         addtype(startoff, startbuf,
1656                                                 startoff != zp->z_gmtoff,
1657                                                 startttisstd,
1658                                                 startttisgmt));
1659                 }
1660                 /*
1661                 ** Now we may get to set starttime for the next zone line.
1662                 */
1663                 if (useuntil) {
1664                         startttisstd = zp->z_untilrule.r_todisstd;
1665                         startttisgmt = zp->z_untilrule.r_todisgmt;
1666                         starttime = zp->z_untiltime;
1667                         if (!startttisstd)
1668                                 starttime = tadd(starttime, -stdoff);
1669                         if (!startttisgmt)
1670                                 starttime = tadd(starttime, -gmtoff);
1671                 }
1672         }
1673         writezone(zpfirst->z_name);
1674 }
1675
1676 static void
1677 addtt(const time_t starttime, int type)
1678 {
1679         if (starttime <= min_time ||
1680                 (timecnt == 1 && attypes[0].at < min_time)) {
1681                 gmtoffs[0] = gmtoffs[type];
1682                 isdsts[0] = isdsts[type];
1683                 ttisstds[0] = ttisstds[type];
1684                 ttisgmts[0] = ttisgmts[type];
1685                 if (abbrinds[type] != 0)
1686                         (void) strcpy(chars, &chars[abbrinds[type]]);
1687                 abbrinds[0] = 0;
1688                 charcnt = strlen(chars) + 1;
1689                 typecnt = 1;
1690                 timecnt = 0;
1691                 type = 0;
1692         }
1693         if (timecnt >= TZ_MAX_TIMES) {
1694                 error(_("too many transitions?!"));
1695                 (void) exit(EXIT_FAILURE);
1696         }
1697         attypes[timecnt].at = starttime;
1698         attypes[timecnt].type = type;
1699         ++timecnt;
1700 }
1701
1702 static int
1703 addtype(const long gmtoff, const char * const abbr, const int isdst,
1704         const int ttisstd, const int ttisgmt)
1705 {
1706         int i, j;
1707
1708         if (isdst != TRUE && isdst != FALSE) {
1709                 error(_("internal error - addtype called with bad isdst"));
1710                 (void) exit(EXIT_FAILURE);
1711         }
1712         if (ttisstd != TRUE && ttisstd != FALSE) {
1713                 error(_("internal error - addtype called with bad ttisstd"));
1714                 (void) exit(EXIT_FAILURE);
1715         }
1716         if (ttisgmt != TRUE && ttisgmt != FALSE) {
1717                 error(_("internal error - addtype called with bad ttisgmt"));
1718                 (void) exit(EXIT_FAILURE);
1719         }
1720         /*
1721         ** See if there's already an entry for this zone type.
1722         ** If so, just return its index.
1723         */
1724         for (i = 0; i < typecnt; ++i) {
1725                 if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
1726                         strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
1727                         ttisstd == ttisstds[i] &&
1728                         ttisgmt == ttisgmts[i])
1729                                 return i;
1730         }
1731         /*
1732         ** There isn't one; add a new one, unless there are already too
1733         ** many.
1734         */
1735         if (typecnt >= TZ_MAX_TYPES) {
1736                 error(_("too many local time types"));
1737                 (void) exit(EXIT_FAILURE);
1738         }
1739         gmtoffs[i] = gmtoff;
1740         isdsts[i] = isdst;
1741         ttisstds[i] = ttisstd;
1742         ttisgmts[i] = ttisgmt;
1743
1744         for (j = 0; j < charcnt; ++j)
1745                 if (strcmp(&chars[j], abbr) == 0)
1746                         break;
1747         if (j == charcnt)
1748                 newabbr(abbr);
1749         abbrinds[i] = j;
1750         ++typecnt;
1751         return i;
1752 }
1753
1754 static void
1755 leapadd(const time_t t, const int positive, const int rolling, int count)
1756 {
1757         int i, j;
1758
1759         if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
1760                 error(_("too many leap seconds"));
1761                 (void) exit(EXIT_FAILURE);
1762         }
1763         for (i = 0; i < leapcnt; ++i)
1764                 if (t <= trans[i]) {
1765                         if (t == trans[i]) {
1766                                 error(_("repeated leap second moment"));
1767                                 (void) exit(EXIT_FAILURE);
1768                         }
1769                         break;
1770                 }
1771         do {
1772                 for (j = leapcnt; j > i; --j) {
1773                         trans[j] = trans[j - 1];
1774                         corr[j] = corr[j - 1];
1775                         roll[j] = roll[j - 1];
1776                 }
1777                 trans[i] = t;
1778                 corr[i] = positive ? 1L : eitol(-count);
1779                 roll[i] = rolling;
1780                 ++leapcnt;
1781         } while (positive && --count != 0);
1782 }
1783
1784 static void
1785 adjleap(void)
1786 {
1787         int i;
1788         long last = 0;
1789
1790         /*
1791         ** propagate leap seconds forward
1792         */
1793         for (i = 0; i < leapcnt; ++i) {
1794                 trans[i] = tadd(trans[i], last);
1795                 last = corr[i] += last;
1796         }
1797 }
1798
1799 static int
1800 yearistype(const int year, const char * const type)
1801 {
1802         static char *   buf;
1803         int             result;
1804
1805         if (type == NULL || *type == '\0')
1806                 return TRUE;
1807         buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
1808         (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
1809         result = system(buf);
1810         if (result == 0)
1811                 return TRUE;
1812         if (result == (1 << 8))
1813                 return FALSE;
1814         error(_("wild result from command execution"));
1815         warnx(_("command was '%s', result was %d"), buf, result);
1816         for ( ; ; )
1817                 (void) exit(EXIT_FAILURE);
1818 }
1819
1820 static int
1821 lowerit(int a)
1822 {
1823         a = (unsigned char) a;
1824         return (isascii(a) && isupper(a)) ? tolower(a) : a;
1825 }
1826
1827 static int
1828 ciequal(ap, bp)         /* case-insensitive equality */
1829 register const char *   ap;
1830 register const char *   bp;
1831 {
1832         while (lowerit(*ap) == lowerit(*bp++))
1833                 if (*ap++ == '\0')
1834                         return TRUE;
1835         return FALSE;
1836 }
1837
1838 static int
1839 itsabbr(abbr, word)
1840 register const char *   abbr;
1841 register const char *   word;
1842 {
1843         if (lowerit(*abbr) != lowerit(*word))
1844                 return FALSE;
1845         ++word;
1846         while (*++abbr != '\0')
1847                 do {
1848                         if (*word == '\0')
1849                                 return FALSE;
1850                 } while (lowerit(*word++) != lowerit(*abbr));
1851         return TRUE;
1852 }
1853
1854 static const struct lookup *
1855 byword(word, table)
1856 register const char * const             word;
1857 register const struct lookup * const    table;
1858 {
1859         register const struct lookup *  foundlp;
1860         register const struct lookup *  lp;
1861
1862         if (word == NULL || table == NULL)
1863                 return NULL;
1864         /*
1865         ** Look for exact match.
1866         */
1867         for (lp = table; lp->l_word != NULL; ++lp)
1868                 if (ciequal(word, lp->l_word))
1869                         return lp;
1870         /*
1871         ** Look for inexact match.
1872         */
1873         foundlp = NULL;
1874         for (lp = table; lp->l_word != NULL; ++lp)
1875                 if (itsabbr(word, lp->l_word)) {
1876                         if (foundlp == NULL)
1877                                 foundlp = lp;
1878                         else    return NULL;    /* multiple inexact matches */
1879                 }
1880         return foundlp;
1881 }
1882
1883 static char **
1884 getfields(cp)
1885 register char * cp;
1886 {
1887         register char *         dp;
1888         register char **        array;
1889         register int            nsubs;
1890
1891         if (cp == NULL)
1892                 return NULL;
1893         array = (char **) (void *)
1894                 emalloc((int) ((strlen(cp) + 1) * sizeof *array));
1895         nsubs = 0;
1896         for ( ; ; ) {
1897                 while (isascii(*cp) && isspace((unsigned char) *cp))
1898                         ++cp;
1899                 if (*cp == '\0' || *cp == '#')
1900                         break;
1901                 array[nsubs++] = dp = cp;
1902                 do {
1903                         if ((*dp = *cp++) != '"')
1904                                 ++dp;
1905                         else while ((*dp = *cp++) != '"')
1906                                 if (*dp != '\0')
1907                                         ++dp;
1908                                 else    error(_("odd number of quotation marks"));
1909                 } while (*cp != '\0' && *cp != '#' &&
1910                         (!isascii(*cp) || !isspace((unsigned char) *cp)));
1911                 if (isascii(*cp) && isspace((unsigned char) *cp))
1912                         ++cp;
1913                 *dp = '\0';
1914         }
1915         array[nsubs] = NULL;
1916         return array;
1917 }
1918
1919 static long
1920 oadd(t1, t2)
1921 const long      t1;
1922 const long      t2;
1923 {
1924         register long   t;
1925
1926         t = t1 + t2;
1927         if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
1928                 error(_("time overflow"));
1929                 (void) exit(EXIT_FAILURE);
1930         }
1931         return t;
1932 }
1933
1934 static time_t
1935 tadd(t1, t2)
1936 const time_t    t1;
1937 const long      t2;
1938 {
1939         register time_t t;
1940
1941         if (t1 == max_time && t2 > 0)
1942                 return max_time;
1943         if (t1 == min_time && t2 < 0)
1944                 return min_time;
1945         t = t1 + t2;
1946         if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
1947                 error(_("time overflow"));
1948                 (void) exit(EXIT_FAILURE);
1949         }
1950         return t;
1951 }
1952
1953 /*
1954 ** Given a rule, and a year, compute the date - in seconds since January 1,
1955 ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
1956 */
1957
1958 static time_t
1959 rpytime(rp, wantedy)
1960 register const struct rule * const      rp;
1961 register const int                      wantedy;
1962 {
1963         register int    y, m, i;
1964         register long   dayoff;                 /* with a nod to Margaret O. */
1965         register time_t t;
1966
1967         if (wantedy == INT_MIN)
1968                 return min_time;
1969         if (wantedy == INT_MAX)
1970                 return max_time;
1971         dayoff = 0;
1972         m = TM_JANUARY;
1973         y = EPOCH_YEAR;
1974         while (wantedy != y) {
1975                 if (wantedy > y) {
1976                         i = len_years[isleap(y)];
1977                         ++y;
1978                 } else {
1979                         --y;
1980                         i = -len_years[isleap(y)];
1981                 }
1982                 dayoff = oadd(dayoff, eitol(i));
1983         }
1984         while (m != rp->r_month) {
1985                 i = len_months[isleap(y)][m];
1986                 dayoff = oadd(dayoff, eitol(i));
1987                 ++m;
1988         }
1989         i = rp->r_dayofmonth;
1990         if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
1991                 if (rp->r_dycode == DC_DOWLEQ)
1992                         --i;
1993                 else {
1994                         error(_("use of 2/29 in non leap-year"));
1995                         (void) exit(EXIT_FAILURE);
1996                 }
1997         }
1998         --i;
1999         dayoff = oadd(dayoff, eitol(i));
2000         if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
2001                 register long   wday;
2002
2003 #define LDAYSPERWEEK    ((long) DAYSPERWEEK)
2004                 wday = eitol(EPOCH_WDAY);
2005                 /*
2006                 ** Don't trust mod of negative numbers.
2007                 */
2008                 if (dayoff >= 0)
2009                         wday = (wday + dayoff) % LDAYSPERWEEK;
2010                 else {
2011                         wday -= ((-dayoff) % LDAYSPERWEEK);
2012                         if (wday < 0)
2013                                 wday += LDAYSPERWEEK;
2014                 }
2015                 while (wday != eitol(rp->r_wday))
2016                         if (rp->r_dycode == DC_DOWGEQ) {
2017                                 dayoff = oadd(dayoff, (long) 1);
2018                                 if (++wday >= LDAYSPERWEEK)
2019                                         wday = 0;
2020                                 ++i;
2021                         } else {
2022                                 dayoff = oadd(dayoff, (long) -1);
2023                                 if (--wday < 0)
2024                                         wday = LDAYSPERWEEK - 1;
2025                                 --i;
2026                         }
2027                 if (i < 0 || i >= len_months[isleap(y)][m]) {
2028                         error(_("no day in month matches rule"));
2029                         (void) exit(EXIT_FAILURE);
2030                 }
2031         }
2032         if (dayoff < 0 && !TYPE_SIGNED(time_t))
2033                 return min_time;
2034         t = (time_t) dayoff * SECSPERDAY;
2035         /*
2036         ** Cheap overflow check.
2037         */
2038         if (t / SECSPERDAY != dayoff)
2039                 return (dayoff > 0) ? max_time : min_time;
2040         return tadd(t, rp->r_tod);
2041 }
2042
2043 static void
2044 newabbr(string)
2045 const char * const      string;
2046 {
2047         register int    i;
2048
2049         i = strlen(string) + 1;
2050         if (charcnt + i > TZ_MAX_CHARS) {
2051                 error(_("too many, or too long, time zone abbreviations"));
2052                 (void) exit(EXIT_FAILURE);
2053         }
2054         (void) strcpy(&chars[charcnt], string);
2055         charcnt += eitol(i);
2056 }
2057
2058 static int
2059 mkdirs(argname)
2060 char * const    argname;
2061 {
2062         register char * name;
2063         register char * cp;
2064
2065         if (argname == NULL || *argname == '\0' || Dflag)
2066                 return 0;
2067         cp = name = ecpyalloc(argname);
2068         while ((cp = strchr(cp + 1, '/')) != 0) {
2069                 *cp = '\0';
2070 #ifndef unix
2071                 /*
2072                 ** DOS drive specifier?
2073                 */
2074                 if (isalpha((unsigned char) name[0]) &&
2075                         name[1] == ':' && name[2] == '\0') {
2076                                 *cp = '/';
2077                                 continue;
2078                 }
2079 #endif /* !defined unix */
2080                 if (!itsdir(name)) {
2081                         /*
2082                         ** It doesn't seem to exist, so we try to create it.
2083                         ** Creation may fail because of the directory being
2084                         ** created by some other multiprocessor, so we get
2085                         ** to do extra checking.
2086                         */
2087                         if (mkdir(name, (S_IRUSR | S_IWUSR | S_IXUSR 
2088                                          | S_IRGRP | S_IXGRP | S_IROTH
2089                                          | S_IXOTH)) != 0
2090                                 && (errno != EEXIST || !itsdir(name))) {
2091                                 warn(_("can't create directory %s"), name);
2092                                 ifree(name);
2093                                 return -1;
2094                         }
2095                 }
2096                 *cp = '/';
2097         }
2098         ifree(name);
2099         return 0;
2100 }
2101
2102 static long
2103 eitol(i)
2104 const int       i;
2105 {
2106         long    l;
2107
2108         l = i;
2109         if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0))
2110                 errx(EXIT_FAILURE, _("%d did not sign extend correctly"), i);
2111         return l;
2112 }
2113
2114 #include <grp.h>
2115 #include <pwd.h>
2116
2117 static void
2118 setgroup(flag, name)
2119         gid_t *flag;
2120         const char *name;
2121 {
2122         struct group *gr;
2123
2124         if (*flag != (gid_t)-1)
2125                 errx(EXIT_FAILURE, _("multiple -g flags specified"));
2126
2127         gr = getgrnam(name);
2128         if (gr == 0) {
2129                 char *ep;
2130                 unsigned long ul;
2131
2132                 ul = strtoul(name, &ep, 10);
2133                 if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
2134                         *flag = ul;
2135                         return;
2136                 }
2137                 errx(EXIT_FAILURE, _("group `%s' not found"), name);
2138         }
2139         *flag = gr->gr_gid;
2140 }
2141
2142 static void
2143 setuser(flag, name)
2144         uid_t *flag;
2145         const char *name;
2146 {
2147         struct passwd *pw;
2148
2149         if (*flag != (gid_t)-1)
2150                 errx(EXIT_FAILURE, _("multiple -u flags specified"));
2151
2152         pw = getpwnam(name);
2153         if (pw == 0) {
2154                 char *ep;
2155                 unsigned long ul;
2156
2157                 ul = strtoul(name, &ep, 10);
2158                 if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
2159                         *flag = ul;
2160                         return;
2161                 }
2162                 errx(EXIT_FAILURE, _("user `%s' not found"), name);
2163         }
2164         *flag = pw->pw_uid;
2165 }
2166
2167 /*
2168 ** UNIX was a registered trademark of UNIX System Laboratories in 1993.
2169 */