]> git.saurik.com Git - apple/system_cmds.git/blobdiff - zic.tproj/zic.c
system_cmds-735.20.1.tar.gz
[apple/system_cmds.git] / zic.tproj / zic.c
index a381bd424bb4a390d91a99ca7653bcb6b5c5e306..8efedaac329bacb57ff628f87a21a3a3e5599dda 100644 (file)
@@ -1,46 +1,26 @@
-/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
- * Reserved.  This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License').  You may not use this file
- * except in compliance with the License.  Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
- * License for the specific language governing rights and limitations
- * under the License."
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-#if defined(LIBC_SCCS) && !defined(lint)
-#if 0
-static char    elsieid[] = "@(#)zic.c  7.80";
-#else
-static char rcsid[] = "$OpenBSD: zic.c,v 1.6 1997/01/15 23:40:55 millert Exp $";
-#endif
-#endif /* LIBC_SCCS and not lint */
+static const char      elsieid[] = "@(#)zic.c  7.116";
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static const char rcsid[] =
+  "$FreeBSD: src/usr.sbin/zic/zic.c,v 1.18 2007/12/03 10:45:44 kevlo Exp $";
+#endif /* not lint */
 
 #include "private.h"
-#include "locale.h"
 #include "tzfile.h"
-#ifdef unix
-#include "sys/stat.h"                  /* for umask manifest constants */
-#endif /* defined unix */
+#include <err.h>
+#include <locale.h>
+#include <sys/stat.h>                  /* for umask manifest constants */
+#include <sys/types.h>
+#include <unistd.h>
+
+#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
 
 /*
 ** On some ancient hosts, predicates like `isspace(C)' are defined
 ** only if isascii(C) || C == EOF.  Modern hosts obey the C Standard,
 ** which says they are defined only if C == ((unsigned char) C) || C == EOF.
-** Neither the C Standard nor Posix require that `isascii' exist.
+** Neither the C Standard nor POSIX require that `isascii' exist.
 ** For portability, we check both ancient and modern requirements.
 ** If isascii is not defined, the isascii check succeeds trivially.
 */
@@ -102,18 +82,6 @@ struct zone {
        time_t          z_untiltime;
 };
 
-extern int     getopt P((int argc, char * const argv[],
-                       const char * options));
-extern char *  icatalloc P((char * old, const char * new));
-extern char *  icpyalloc P((const char * string));
-extern void    ifree P((char * p));
-extern char *  imalloc P((int n));
-extern void *  irealloc P((void * old, int n));
-extern int     link P((const char * fromname, const char * toname));
-extern char *  optarg;
-extern int     optind;
-extern char *  scheck P((const char * string, const char * format));
-
 static void    addtt P((time_t starttime, int type));
 static int     addtype P((long gmtoff, const char * abbr, int isdst,
                                int ttisstd, int ttisgmt));
@@ -156,6 +124,8 @@ static void rulesub P((struct rule * rp,
                        const char * typep, const char * monthp,
                        const char * dayp, const char * timep));
 static void    setboundaries P((void));
+static void    setgroup P((gid_t *flag, const char *name));
+static void    setuser P((uid_t *flag, const char *name));
 static time_t  tadd P((time_t t1, long t2));
 static void    usage P((void));
 static void    writezone P((const char * name));
@@ -172,12 +142,13 @@ static int                leapcnt;
 static int             linenum;
 static time_t          max_time;
 static int             max_year;
+static int             max_year_representable;
 static time_t          min_time;
 static int             min_year;
+static int             min_year_representable;
 static int             noise;
 static const char *    rfilename;
 static int             rlinenum;
-static const char *    progname;
 static int             timecnt;
 static int             typecnt;
 
@@ -379,16 +350,10 @@ static char               roll[TZ_MAX_LEAPS];
 */
 
 static char *
-memcheck(ptr)
-char * const   ptr;
+memcheck(char * const ptr)
 {
-       if (ptr == NULL) {
-               const char *e = strerror(errno);
-
-               (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
-                       progname, e);
-               (void) exit(EXIT_FAILURE);
-       }
+       if (ptr == NULL)
+               errx(EXIT_FAILURE, _("memory exhausted"));
        return ptr;
 }
 
@@ -403,23 +368,19 @@ char * const      ptr;
 
 #if !(HAVE_STRERROR - 0)
 static char *
-strerror(errnum)
-int    errnum;
+strerror(int errnum)
 {
        extern char *   sys_errlist[];
        extern int      sys_nerr;
 
        return (errnum > 0 && errnum <= sys_nerr) ?
-               sys_errlist[errnum] : "Unknown system error";
+               sys_errlist[errnum] : _("Unknown system error");
 }
 #endif /* !(HAVE_STRERROR - 0) */
 
 static void
-eats(name, num, rname, rnum)
-const char * const     name;
-const int              num;
-const char * const     rname;
-const int              rnum;
+eats(const char * const name, const int num, const char * const        rname,
+     const int rnum)
 {
        filename = name;
        linenum = num;
@@ -428,16 +389,13 @@ const int         rnum;
 }
 
 static void
-eat(name, num)
-const char * const     name;
-const int              num;
+eat(const char * const name, const int num)
 {
        eats(name, num, (char *) NULL, -1);
 }
 
 static void
-error(string)
-const char * const     string;
+error(const char * const string)
 {
        /*
        ** Match the format of "cc" to allow sh users to
@@ -454,14 +412,13 @@ const char * const        string;
 }
 
 static void
-warning(string)
-const char * const     string;
+warning(const char * const string)
 {
        char *  cp;
 
-       cp = ecpyalloc("warning: ");
+       cp = ecpyalloc(_("warning: "));
        cp = ecatalloc(cp, string);
-       error(string);
+       error(cp);
        ifree(cp);
        --errors;
 }
@@ -469,8 +426,9 @@ const char * const  string;
 static void
 usage P((void))
 {
-       (void) fprintf(stderr, _("%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ]\n\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n"),
-               progname, progname);
+       (void) fprintf(stderr, "%s\n%s\n",
+_("usage: zic [--version] [-s] [-v] [-l localtime] [-p posixrules] [-d directory]"),
+_("           [-L leapseconds] [-y yearistype] [filename ... ]"));
        (void) exit(EXIT_FAILURE);
 }
 
@@ -480,15 +438,18 @@ static const char *       directory;
 static const char *    leapsec;
 static const char *    yitcommand;
 static int             sflag = FALSE;
+static int             Dflag;
+static uid_t           uflag = (uid_t)-1;
+static gid_t           gflag = (gid_t)-1;
+static mode_t          mflag = (S_IRUSR | S_IRGRP | S_IROTH
+                                | S_IWUSR);
 
 int
-main(argc, argv)
-int    argc;
-char * argv[];
+main(int argc, char * argv[])
 {
-       register int    i;
-       register int    j;
-       register int    c;
+       int     i;
+       int     j;
+       int     c;
 
 #ifdef unix
        (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
@@ -500,60 +461,67 @@ char *    argv[];
 #endif /* defined TEXTDOMAINDIR */
        (void) textdomain(TZ_DOMAIN);
 #endif /* HAVE_GETTEXT - 0 */
-       progname = argv[0];
-       while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != -1)
+       for (i = 1; i < argc; ++i)
+               if (strcmp(argv[i], "--version") == 0) {
+                       errx(EXIT_SUCCESS, "%s", elsieid);
+               }
+       while ((c = getopt(argc, argv, "Dd:g:l:m:p:L:u:vsy:")) != -1)
                switch (c) {
                        default:
                                usage();
+                       case 'D':
+                               Dflag = 1;
+                               break;
                        case 'd':
                                if (directory == NULL)
                                        directory = optarg;
-                               else {
-                                       (void) fprintf(stderr,
-_("%s: More than one -d option specified\n"),
-                                               progname);
-                                       (void) exit(EXIT_FAILURE);
-                               }
+                               else
+                                       errx(EXIT_FAILURE,
+_("more than one -d option specified"));
+                               break;
+                       case 'g':
+                               setgroup(&gflag, optarg);
                                break;
                        case 'l':
                                if (lcltime == NULL)
                                        lcltime = optarg;
-                               else {
-                                       (void) fprintf(stderr,
-_("%s: More than one -l option specified\n"),
-                                               progname);
-                                       (void) exit(EXIT_FAILURE);
-                               }
+                               else
+                                       errx(EXIT_FAILURE,
+_("more than one -l option specified"));
                                break;
+                       case 'm':
+                       {
+                               void *set = setmode(optarg);
+                               if (set == NULL)
+                                       errx(EXIT_FAILURE,
+_("invalid file mode"));
+                               mflag = getmode(set, mflag);
+                               free(set);
+                               break;
+                       }
                        case 'p':
                                if (psxrules == NULL)
                                        psxrules = optarg;
-                               else {
-                                       (void) fprintf(stderr,
-_("%s: More than one -p option specified\n"),
-                                               progname);
-                                       (void) exit(EXIT_FAILURE);
-                               }
+                               else
+                                       errx(EXIT_FAILURE,
+_("more than one -p option specified"));
+                               break;
+                       case 'u':
+                               setuser(&uflag, optarg);
                                break;
                        case 'y':
                                if (yitcommand == NULL)
                                        yitcommand = optarg;
-                               else {
-                                       (void) fprintf(stderr,
-_("%s: More than one -y option specified\n"),
-                                               progname);
-                                       (void) exit(EXIT_FAILURE);
-                               }
+                               else
+                                       errx(EXIT_FAILURE,
+_("more than one -y option specified"));
                                break;
                        case 'L':
                                if (leapsec == NULL)
                                        leapsec = optarg;
-                               else {
-                                       (void) fprintf(stderr,
-_("%s: More than one -L option specified\n"),
-                                               progname);
-                                       (void) exit(EXIT_FAILURE);
-                               }
+                               else
+                                       errx(EXIT_FAILURE,
+_("more than one -L option specified"));
                                break;
                        case 'v':
                                noise = TRUE;
@@ -592,22 +560,26 @@ _("%s: More than one -L option specified\n"),
        /*
        ** Make links.
        */
-       for (i = 0; i < nlinks; ++i)
+       for (i = 0; i < nlinks; ++i) {
+               eat(links[i].l_filename, links[i].l_linenum);
                dolink(links[i].l_from, links[i].l_to);
-       if (lcltime != NULL)
+       }
+       if (lcltime != NULL) {
+               eat("command line", 1);
                dolink(lcltime, TZDEFAULT);
-       if (psxrules != NULL)
+       }
+       if (psxrules != NULL) {
+               eat("command line", 1);
                dolink(psxrules, TZDEFRULES);
+       }
        return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 static void
-dolink(fromfile, tofile)
-const char * const     fromfile;
-const char * const     tofile;
+dolink(const char * const fromfile, const char * const tofile)
 {
-       register char * fromname;
-       register char * toname;
+       char *  fromname;
+       char *  toname;
 
        if (fromfile[0] == '/')
                fromname = ecpyalloc(fromfile);
@@ -630,15 +602,31 @@ const char * const        tofile;
        if (!itsdir(toname))
                (void) remove(toname);
        if (link(fromname, toname) != 0) {
+               int     result;
+
                if (mkdirs(toname) != 0)
                        (void) exit(EXIT_FAILURE);
-               if (link(fromname, toname) != 0) {
-                       const char *e = strerror(errno);
 
-                       (void) fprintf(stderr,
-                               _("%s: Can't link from %s to %s: %s\n"),
-                               progname, fromname, toname, e);
-                       (void) exit(EXIT_FAILURE);
+               result = link(fromname, toname);
+#if (HAVE_SYMLINK - 0)
+               if (result != 0 &&
+                   access(fromname, F_OK) == 0 &&
+                   !itsdir(fromname)) {
+                       const char *s = tofile;
+                       char * symlinkcontents = NULL;
+                       while ((s = strchr(s+1, '/')) != NULL)
+                               symlinkcontents = ecatalloc(symlinkcontents, "../");
+                       symlinkcontents = ecatalloc(symlinkcontents, fromfile);
+
+                       result = symlink(symlinkcontents, toname);
+                       if (result == 0)
+warning(_("hard link failed, symbolic link used"));
+                       ifree(symlinkcontents);
+               }
+#endif
+               if (result != 0) {
+                       err(EXIT_FAILURE, _("can't link from %s to %s"),
+                           fromname, toname);
                }
        }
        ifree(fromname);
@@ -680,14 +668,15 @@ setboundaries P((void))
        }
        min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
        max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
+       min_year_representable = min_year;
+       max_year_representable = max_year;
 }
 
 static int
-itsdir(name)
-const char * const     name;
+itsdir(const char * const name)
 {
-       register char * myname;
-       register int    accres;
+       char *  myname;
+       int     accres;
 
        myname = ecpyalloc(name);
        myname = ecatalloc(myname, "/.");
@@ -705,9 +694,7 @@ const char * const  name;
 */
 
 static int
-rcomp(cp1, cp2)
-const void *   cp1;
-const void *   cp2;
+rcomp(const void *cp1, const void *cp2)
 {
        return strcmp(((const struct rule *) cp1)->r_name,
                ((const struct rule *) cp2)->r_name);
@@ -716,10 +703,10 @@ const void *      cp2;
 static void
 associate P((void))
 {
-       register struct zone *  zp;
-       register struct rule *  rp;
-       register int            base, out;
-       register int            i, j;
+       struct zone *   zp;
+       struct rule *   rp;
+       int             base, out;
+       int             i, j;
 
        if (nrules != 0) {
                (void) qsort((void *) rules, (size_t) nrules,
@@ -790,28 +777,22 @@ associate P((void))
 }
 
 static void
-infile(name)
-const char *   name;
+infile(const char * name)
 {
-       register FILE *                 fp;
-       register char **                fields;
-       register char *                 cp;
-       register const struct lookup *  lp;
-       register int                    nfields;
-       register int                    wantcont;
-       register int                    num;
-       char                            buf[BUFSIZ];
+       FILE *                  fp;
+       char **                 fields;
+       char *                  cp;
+       const struct lookup *   lp;
+       int                     nfields;
+       int                     wantcont;
+       int                     num;
+       char                    buf[BUFSIZ];
 
        if (strcmp(name, "-") == 0) {
                name = _("standard input");
                fp = stdin;
-       } else if ((fp = fopen(name, "r")) == NULL) {
-               const char *e = strerror(errno);
-
-               (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
-                       progname, name, e);
-               (void) exit(EXIT_FAILURE);
-       }
+       } else if ((fp = fopen(name, "r")) == NULL)
+               err(EXIT_FAILURE, _("can't open %s"), name);
        wantcont = FALSE;
        for (num = 1; ; ++num) {
                eat(name, num);
@@ -854,33 +835,22 @@ const char *      name;
                                        break;
                                case LC_LEAP:
                                        if (name != leapsec)
-                                               (void) fprintf(stderr,
-_("%s: Leap line in non leap seconds file %s\n"),
-                                                       progname, name);
+                                               warnx(
+_("leap line in non leap seconds file %s"), name);
                                        else    inleap(fields, nfields);
                                        wantcont = FALSE;
                                        break;
                                default:        /* "cannot happen" */
-                                       (void) fprintf(stderr,
-_("%s: panic: Invalid l_value %d\n"),
-                                               progname, lp->l_value);
-                                       (void) exit(EXIT_FAILURE);
+                                       errx(EXIT_FAILURE,
+_("panic: invalid l_value %d"), lp->l_value);
                        }
                }
                ifree((char *) fields);
        }
-       if (ferror(fp)) {
-               (void) fprintf(stderr, _("%s: Error reading %s\n"),
-                       progname, filename);
-               (void) exit(EXIT_FAILURE);
-       }
-       if (fp != stdin && fclose(fp)) {
-               const char *e = strerror(errno);
-
-               (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
-                       progname, filename, e);
-               (void) exit(EXIT_FAILURE);
-       }
+       if (ferror(fp))
+               errx(EXIT_FAILURE, _("error reading %s"), filename);
+       if (fp != stdin && fclose(fp))
+               err(EXIT_FAILURE, _("error closing %s"), filename);
        if (wantcont)
                error(_("expected continuation line not found"));
 }
@@ -894,10 +864,7 @@ _("%s: panic: Invalid l_value %d\n"),
 */
 
 static long
-gethms(string, errstring, signable)
-const char *           string;
-const char * const     errstring;
-const int              signable;
+gethms(const char *string, const char * const errstring, const int signable)
 {
        int     hh, mm, ss, sign;
 
@@ -918,21 +885,22 @@ const int         signable;
                        error(errstring);
                        return 0;
        }
-       if (hh < 0 || hh >= HOURSPERDAY ||
+       if ((hh < 0 || hh >= HOURSPERDAY ||
                mm < 0 || mm >= MINSPERHOUR ||
-               ss < 0 || ss > SECSPERMIN) {
+               ss < 0 || ss > SECSPERMIN) &&
+               !(hh == HOURSPERDAY && mm == 0 && ss == 0)) {
                        error(errstring);
                        return 0;
        }
+       if (noise && hh == HOURSPERDAY)
+               warning(_("24:00 not handled by pre-1998 versions of zic"));
        return eitol(sign) *
                (eitol(hh * MINSPERHOUR + mm) *
                eitol(SECSPERMIN) + eitol(ss));
 }
 
 static void
-inrule(fields, nfields)
-register char ** const fields;
-const int              nfields;
+inrule(char ** const fields, const int nfields)
 {
        static struct rule      r;
 
@@ -957,11 +925,9 @@ const int          nfields;
 }
 
 static int
-inzone(fields, nfields)
-register char ** const fields;
-const int              nfields;
+inzone(char ** const fields, const int nfields)
 {
-       register int    i;
+       int             i;
        static char *   buf;
 
        if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
@@ -1002,9 +968,7 @@ _("duplicate zone name %s (file \"%s\", line %d)"),
 }
 
 static int
-inzcont(fields, nfields)
-register char ** const fields;
-const int              nfields;
+inzcont(char ** const fields, const int nfields)
 {
        if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
                error(_("wrong number of fields on Zone continuation line"));
@@ -1014,17 +978,14 @@ const int                nfields;
 }
 
 static int
-inzsub(fields, nfields, iscont)
-register char ** const fields;
-const int              nfields;
-const int              iscont;
+inzsub(char ** const fields, const int nfields, const int iscont)
 {
-       register char *         cp;
+       char *          cp;
        static struct zone      z;
-       register int            i_gmtoff, i_rule, i_format;
-       register int            i_untilyear, i_untilmonth;
-       register int            i_untilday, i_untiltime;
-       register int            hasuntil;
+       int             i_gmtoff, i_rule, i_format;
+       int             i_untilyear, i_untilmonth;
+       int             i_untilday, i_untiltime;
+       int             hasuntil;
 
        if (iscont) {
                i_gmtoff = ZFC_GMTOFF;
@@ -1047,7 +1008,7 @@ const int         iscont;
        }
        z.z_filename = filename;
        z.z_linenum = linenum;
-       z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid GMT offset"), TRUE);
+       z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
        if ((cp = strchr(fields[i_format], '%')) != 0) {
                if (*++cp != 's' || strchr(cp, '%') != 0) {
                        error(_("invalid abbreviation format"));
@@ -1091,16 +1052,14 @@ const int               iscont;
 }
 
 static void
-inleap(fields, nfields)
-register char ** const fields;
-const int              nfields;
+inleap(char ** const fields, const int nfields)
 {
-       register const char *           cp;
-       register const struct lookup *  lp;
-       register int                    i, j;
-       int                             year, month, day;
-       long                            dayoff, tod;
-       time_t                          t;
+       const char *            cp;
+       const struct lookup *   lp;
+       int                     i, j;
+       int                     year, month, day;
+       long                    dayoff, tod;
+       time_t                  t;
 
        if (nfields != LEAP_FIELDS) {
                error(_("wrong number of fields on Leap line"));
@@ -1148,19 +1107,20 @@ const int               nfields;
                error(_("time before zero"));
                return;
        }
-       t = (time_t) dayoff * SECSPERDAY;
-       /*
-       ** Cheap overflow check.
-       */
-       if (t / SECSPERDAY != dayoff) {
-               error(_("time overflow"));
+       if (dayoff < min_time / SECSPERDAY) {
+               error(_("time too small"));
                return;
        }
+       if (dayoff > max_time / SECSPERDAY) {
+               error(_("time too large"));
+               return;
+       }
+       t = (time_t) dayoff * SECSPERDAY;
        tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
        cp = fields[LP_CORR];
        {
-               register int    positive;
-               int             count;
+               int     positive;
+               int     count;
 
                if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
                        positive = FALSE;
@@ -1187,9 +1147,7 @@ const int         nfields;
 }
 
 static void
-inlink(fields, nfields)
-register char ** const fields;
-const int              nfields;
+inlink(char ** const fields, const int nfields)
 {
        struct link     l;
 
@@ -1215,19 +1173,15 @@ const int               nfields;
 }
 
 static void
-rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
-register struct rule * const   rp;
-const char * const             loyearp;
-const char * const             hiyearp;
-const char * const             typep;
-const char * const             monthp;
-const char * const             dayp;
-const char * const             timep;
+rulesub(struct rule * const rp, const char * const loyearp,
+       const char * const hiyearp, const char * const typep,
+       const char * const monthp, const char * const dayp,
+       const char * const timep)
 {
-       register const struct lookup *  lp;
-       register const char *           cp;
-       register char *                 dp;
-       register char *                 ep;
+       const struct lookup *   lp;
+       const char *            cp;
+       char *                  dp;
+       char *                  ep;
 
        if ((lp = byword(monthp, mon_names)) == NULL) {
                error(_("invalid month name"));
@@ -1249,6 +1203,7 @@ const char * const                timep;
                                rp->r_todisstd = FALSE;
                                rp->r_todisgmt = FALSE;
                                *ep = '\0';
+                               break;
                        case 'g':       /* Greenwich */
                        case 'u':       /* Universal */
                        case 'z':       /* Zulu */
@@ -1273,13 +1228,16 @@ const char * const              timep;
                        rp->r_loyear = INT_MAX;
                        break;
                default:        /* "cannot happen" */
-                       (void) fprintf(stderr,
-                               _("%s: panic: Invalid l_value %d\n"),
-                               progname, lp->l_value);
-                       (void) exit(EXIT_FAILURE);
+                       errx(EXIT_FAILURE,
+                               _("panic: invalid l_value %d"), lp->l_value);
        } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
                error(_("invalid starting year"));
                return;
+       } else if (noise) {
+               if (rp->r_loyear < min_year_representable)
+                       warning(_("starting year too low to be represented"));
+               else if (rp->r_loyear > max_year_representable)
+                       warning(_("starting year too high to be represented"));
        }
        cp = hiyearp;
        if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
@@ -1293,13 +1251,16 @@ const char * const              timep;
                        rp->r_hiyear = rp->r_loyear;
                        break;
                default:        /* "cannot happen" */
-                       (void) fprintf(stderr,
-                               _("%s: panic: Invalid l_value %d\n"),
-                               progname, lp->l_value);
-                       (void) exit(EXIT_FAILURE);
+                       errx(EXIT_FAILURE,
+                               _("panic: invalid l_value %d"), lp->l_value);
        } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
                error(_("invalid ending year"));
                return;
+       } else if (noise) {
+               if (rp->r_loyear < min_year_representable)
+                       warning(_("ending year too low to be represented"));
+               else if (rp->r_loyear > max_year_representable)
+                       warning(_("ending year too high to be represented"));
        }
        if (rp->r_loyear > rp->r_hiyear) {
                error(_("starting year greater than ending year"));
@@ -1314,6 +1275,8 @@ const char * const                timep;
                }
                rp->r_yrtype = ecpyalloc(typep);
        }
+       if (rp->r_loyear < min_year && rp->r_loyear > 0)
+               min_year = rp->r_loyear;
        /*
        ** Day work.
        ** Accept things such as:
@@ -1362,21 +1325,17 @@ const char * const              timep;
 }
 
 static void
-convert(val, buf)
-const long     val;
-char * const   buf;
+convert(const long val, char * const buf)
 {
-       register int    i;
-       register long   shift;
+       int     i;
+       long    shift;
 
        for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
                buf[i] = val >> shift;
 }
 
 static void
-puttzcode(val, fp)
-const long     val;
-FILE * const   fp;
+puttzcode(const long val, FILE * const fp)
 {
        char    buf[4];
 
@@ -1385,23 +1344,20 @@ FILE * const    fp;
 }
 
 static int
-atcomp(avp, bvp)
-void * avp;
-void * bvp;
+atcomp(const void *avp, const void *bvp)
 {
-       if (((struct attype *) avp)->at < ((struct attype *) bvp)->at)
+       if (((const struct attype *) avp)->at < ((const struct attype *) bvp)->at)
                return -1;
-       else if (((struct attype *) avp)->at > ((struct attype *) bvp)->at)
+       else if (((const struct attype *) avp)->at > ((const struct attype *) bvp)->at)
                return 1;
        else    return 0;
 }
 
 static void
-writezone(name)
-const char * const     name;
+writezone(const char * const name)
 {
-       register FILE *         fp;
-       register int            i, j;
+       FILE *                  fp;
+       int                     i, j;
        static char *           fullname;
        static struct tzhead    tzh;
        time_t                  ats[TZ_MAX_TIMES];
@@ -1422,8 +1378,10 @@ const char * const       name;
 
                toi = 0;
                fromi = 0;
+               while (fromi < timecnt && attypes[fromi].at < min_time)
+                       ++fromi;
                if (isdsts[0] == 0)
-                       while (attypes[fromi].type == 0)
+                       while (fromi < timecnt && attypes[fromi].type == 0)
                                ++fromi;        /* handled by default rule */
                for ( ; fromi < timecnt; ++fromi) {
                        if (toi != 0
@@ -1451,26 +1409,18 @@ const char * const      name;
        fullname = erealloc(fullname,
                (int) (strlen(directory) + 1 + strlen(name) + 1));
        (void) sprintf(fullname, "%s/%s", directory, name);
+
        /*
-       ** Remove old file, if any, to snap links.
-       */
-       if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
-               const char *e = strerror(errno);
+        * Remove old file, if any, to snap links.
+        */
+       if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT)
+               err(EXIT_FAILURE, _("can't remove %s"), fullname);
 
-               (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
-                       progname, fullname, e);
-               (void) exit(EXIT_FAILURE);
-       }
        if ((fp = fopen(fullname, "wb")) == NULL) {
                if (mkdirs(fullname) != 0)
                        (void) exit(EXIT_FAILURE);
-               if ((fp = fopen(fullname, "wb")) == NULL) {
-                       const char *e = strerror(errno);
-
-                       (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
-                               progname, fullname, e);
-                       (void) exit(EXIT_FAILURE);
-               }
+               if ((fp = fopen(fullname, "wb")) == NULL)
+                       err(EXIT_FAILURE, _("can't create %s"), fullname);
        }
        convert(eitol(typecnt), tzh.tzh_ttisgmtcnt);
        convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
@@ -1478,7 +1428,9 @@ const char * const        name;
        convert(eitol(timecnt), tzh.tzh_timecnt);
        convert(eitol(typecnt), tzh.tzh_typecnt);
        convert(eitol(charcnt), tzh.tzh_charcnt);
+       (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
 #define DO(field)      (void) fwrite((void *) tzh.field, (size_t) sizeof tzh.field, (size_t) 1, fp)
+       DO(tzh_magic);
        DO(tzh_reserved);
        DO(tzh_ttisgmtcnt);
        DO(tzh_ttisstdcnt);
@@ -1530,19 +1482,20 @@ const char * const      name;
                (void) putc(ttisstds[i], fp);
        for (i = 0; i < typecnt; ++i)
                (void) putc(ttisgmts[i], fp);
-       if (ferror(fp) || fclose(fp)) {
-               (void) fprintf(stderr, _("%s: Error writing %s\n"),
-                       progname, fullname);
-               (void) exit(EXIT_FAILURE);
-       }
+       if (ferror(fp) || fclose(fp))
+               errx(EXIT_FAILURE, _("error writing %s"), fullname);
+       if (chmod(fullname, mflag) < 0)
+               err(EXIT_FAILURE, _("cannot change mode of %s to %03o"),
+                   fullname, (unsigned)mflag);
+       if ((uflag != (uid_t)-1 || gflag != (gid_t)-1)
+           && chown(fullname, uflag, gflag) < 0)
+               err(EXIT_FAILURE, _("cannot change ownership of %s"), 
+                   fullname);
 }
 
 static void
-doabbr(abbr, format, letters, isdst)
-char * const           abbr;
-const char * const     format;
-const char * const     letters;
-const int              isdst;
+doabbr(char * const abbr, const char * const format, const char * const letters,
+       const int isdst)
 {
        if (strchr(format, '/') == NULL) {
                if (letters == NULL)
@@ -1557,23 +1510,21 @@ const int               isdst;
 }
 
 static void
-outzone(zpfirst, zonecount)
-const struct zone * const      zpfirst;
-const int                      zonecount;
+outzone(const struct zone * const zpfirst, const int zonecount)
 {
-       register const struct zone *    zp;
-       register struct rule *          rp;
-       register int                    i, j;
-       register int                    usestart, useuntil;
-       register time_t                 starttime, untiltime;
-       register long                   gmtoff;
-       register long                   stdoff;
-       register int                    year;
-       register long                   startoff;
-       register int                    startttisstd;
-       register int                    startttisgmt;
-       register int                    type;
-       char                            startbuf[BUFSIZ];
+       const struct zone *     zp;
+       struct rule *           rp;
+       int                     i, j;
+       int                     usestart, useuntil;
+       time_t                  starttime, untiltime;
+       long                    gmtoff;
+       long                    stdoff;
+       int                     year;
+       long                    startoff;
+       int                     startttisstd;
+       int                     startttisgmt;
+       int                     type;
+       char                    startbuf[BUFSIZ];
 
        INITIALIZE(untiltime);
        INITIALIZE(starttime);
@@ -1584,16 +1535,16 @@ const int                       zonecount;
        typecnt = 0;
        charcnt = 0;
        /*
-       ** A guess that may well be corrected later.
-       */
-       stdoff = 0;
-       /*
        ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)
        ** for noting the need to unconditionally initialize startttisstd.
        */
        startttisstd = FALSE;
        startttisgmt = FALSE;
        for (i = 0; i < zonecount; ++i) {
+               /*
+               ** A guess that may well be corrected later.
+               */
+               stdoff = 0;
                zp = &zpfirst[i];
                usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
                useuntil = i < (zonecount - 1);
@@ -1613,8 +1564,7 @@ const int                 zonecount;
                        if (usestart) {
                                addtt(starttime, type);
                                usestart = FALSE;
-                       }
-                       else if (stdoff != 0)
+                       } else if (stdoff != 0)
                                addtt(min_time, type);
                } else for (year = min_year; year <= max_year; ++year) {
                        if (useuntil && year > zp->z_untilrule.r_hiyear)
@@ -1634,15 +1584,15 @@ const int                       zonecount;
                                        rp->r_temp = rpytime(rp, year);
                        }
                        for ( ; ; ) {
-                               register int    k;
-                               register time_t jtime, ktime;
-                               register long   offset;
-                               char            buf[BUFSIZ];
+                               int     k;
+                               time_t  jtime, ktime;
+                               long    offset;
+                               char    buf[BUFSIZ];
 
                                INITIALIZE(ktime);
                                if (useuntil) {
                                        /*
-                                       ** Turn untiltime into GMT
+                                       ** Turn untiltime into UTC
                                        ** assuming the current gmtoff and
                                        ** stdoff values.
                                        */
@@ -1746,10 +1696,22 @@ error(_("can't determine time zone abbreviation to use just after until time"));
 }
 
 static void
-addtt(starttime, type)
-const time_t   starttime;
-const int      type;
+addtt(const time_t starttime, int type)
 {
+       if (starttime <= min_time ||
+               (timecnt == 1 && attypes[0].at < min_time)) {
+               gmtoffs[0] = gmtoffs[type];
+               isdsts[0] = isdsts[type];
+               ttisstds[0] = ttisstds[type];
+               ttisgmts[0] = ttisgmts[type];
+               if (abbrinds[type] != 0)
+                       (void) strcpy(chars, &chars[abbrinds[type]]);
+               abbrinds[0] = 0;
+               charcnt = (int)strlen(chars) + 1;
+               typecnt = 1;
+               timecnt = 0;
+               type = 0;
+       }
        if (timecnt >= TZ_MAX_TIMES) {
                error(_("too many transitions?!"));
                (void) exit(EXIT_FAILURE);
@@ -1760,14 +1722,10 @@ const int       type;
 }
 
 static int
-addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
-const long             gmtoff;
-const char * const     abbr;
-const int              isdst;
-const int              ttisstd;
-const int              ttisgmt;
+addtype(const long gmtoff, const char * const abbr, const int isdst,
+       const int ttisstd, const int ttisgmt)
 {
-       register int    i, j;
+       int     i, j;
 
        if (isdst != TRUE && isdst != FALSE) {
                error(_("internal error - addtype called with bad isdst"));
@@ -1816,13 +1774,9 @@ const int                ttisgmt;
 }
 
 static void
-leapadd(t, positive, rolling, count)
-const time_t   t;
-const int      positive;
-const int      rolling;
-int            count;
+leapadd(const time_t t, const int positive, const int rolling, int count)
 {
-       register int    i, j;
+       int     i, j;
 
        if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
                error(_("too many leap seconds"));
@@ -1852,8 +1806,8 @@ int               count;
 static void
 adjleap P((void))
 {
-       register int    i;
-       register long   last = 0;
+       int     i;
+       long    last = 0;
 
        /*
        ** propagate leap seconds forward
@@ -1865,9 +1819,7 @@ adjleap P((void))
 }
 
 static int
-yearistype(year, type)
-const int              year;
-const char * const     type;
+yearistype(const int year, const char * const type)
 {
        static char *   buf;
        int             result;
@@ -1877,29 +1829,28 @@ const char * const      type;
        buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
        (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
        result = system(buf);
-       if (result == 0)
-               return TRUE;
-       if (result == (1 << 8))
-               return FALSE;
-       error(_("Wild result from command execution"));
-       (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
-               progname, buf, result);
+       if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
+               case 0:
+                       return TRUE;
+               case 1:
+                       return FALSE;
+       }
+       error(_("wild result from command execution"));
+       warnx(_("command was '%s', result was %d"), buf, result);
        for ( ; ; )
                (void) exit(EXIT_FAILURE);
 }
 
 static int
-lowerit(a)
-int    a;
+lowerit(int a)
 {
        a = (unsigned char) a;
        return (isascii(a) && isupper(a)) ? tolower(a) : a;
 }
 
+/* case-insensitive equality */
 static int
-ciequal(ap, bp)                /* case-insensitive equality */
-register const char *  ap;
-register const char *  bp;
+ciequal(const char *ap, const char *bp)
 {
        while (lowerit(*ap) == lowerit(*bp++))
                if (*ap++ == '\0')
@@ -1908,9 +1859,7 @@ register const char *     bp;
 }
 
 static int
-itsabbr(abbr, word)
-register const char *  abbr;
-register const char *  word;
+itsabbr(const char *abbr, const char *word)
 {
        if (lowerit(*abbr) != lowerit(*word))
                return FALSE;
@@ -1924,12 +1873,10 @@ register const char *   word;
 }
 
 static const struct lookup *
-byword(word, table)
-register const char * const            word;
-register const struct lookup * const   table;
+byword(const char * const word, const struct lookup * const table)
 {
-       register const struct lookup *  foundlp;
-       register const struct lookup *  lp;
+       const struct lookup *   foundlp;
+       const struct lookup *   lp;
 
        if (word == NULL || table == NULL)
                return NULL;
@@ -1944,20 +1891,20 @@ register const struct lookup * const    table;
        */
        foundlp = NULL;
        for (lp = table; lp->l_word != NULL; ++lp)
-               if (itsabbr(word, lp->l_word))
+               if (itsabbr(word, lp->l_word)) {
                        if (foundlp == NULL)
                                foundlp = lp;
                        else    return NULL;    /* multiple inexact matches */
+               }
        return foundlp;
 }
 
 static char **
-getfields(cp)
-register char *        cp;
+getfields(char *cp)
 {
-       register char *         dp;
-       register char **        array;
-       register int            nsubs;
+       char *          dp;
+       char **         array;
+       int             nsubs;
 
        if (cp == NULL)
                return NULL;
@@ -1976,7 +1923,10 @@ register char *  cp;
                        else while ((*dp = *cp++) != '"')
                                if (*dp != '\0')
                                        ++dp;
-                               else    error(_("Odd number of quotation marks"));
+                               else {
+                                       error(_("odd number of quotation marks"));
+                                       exit(EXIT_FAILURE);
+                               }
                } while (*cp != '\0' && *cp != '#' &&
                        (!isascii(*cp) || !isspace((unsigned char) *cp)));
                if (isascii(*cp) && isspace((unsigned char) *cp))
@@ -1988,11 +1938,9 @@ register char *  cp;
 }
 
 static long
-oadd(t1, t2)
-const long     t1;
-const long     t2;
+oadd(const long t1, const long t2)
 {
-       register long   t;
+       long    t;
 
        t = t1 + t2;
        if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
@@ -2003,11 +1951,9 @@ const long       t2;
 }
 
 static time_t
-tadd(t1, t2)
-const time_t   t1;
-const long     t2;
+tadd(const time_t t1, const long t2)
 {
-       register time_t t;
+       time_t  t;
 
        if (t1 == max_time && t2 > 0)
                return max_time;
@@ -2027,13 +1973,11 @@ const long      t2;
 */
 
 static time_t
-rpytime(rp, wantedy)
-register const struct rule * const     rp;
-register const int                     wantedy;
+rpytime(const struct rule * const rp, const int wantedy)
 {
-       register int    y, m, i;
-       register long   dayoff;                 /* with a nod to Margaret O. */
-       register time_t t;
+       int     y, m, i;
+       long    dayoff;                 /* with a nod to Margaret O. */
+       time_t  t;
 
        if (wantedy == INT_MIN)
                return min_time;
@@ -2069,7 +2013,7 @@ register const int                        wantedy;
        --i;
        dayoff = oadd(dayoff, eitol(i));
        if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
-               register long   wday;
+               long    wday;
 
 #define LDAYSPERWEEK   ((long) DAYSPERWEEK)
                wday = eitol(EPOCH_WDAY);
@@ -2096,28 +2040,26 @@ register const int                      wantedy;
                                --i;
                        }
                if (i < 0 || i >= len_months[isleap(y)][m]) {
-                       error(_("no day in month matches rule"));
-                       (void) exit(EXIT_FAILURE);
+                       if (noise)
+                               warning(_("rule goes past start/end of month--will not work with pre-2004 versions of zic"));
                }
        }
        if (dayoff < 0 && !TYPE_SIGNED(time_t))
                return min_time;
+       if (dayoff < min_time / SECSPERDAY)
+               return min_time;
+       if (dayoff > max_time / SECSPERDAY)
+               return max_time;
        t = (time_t) dayoff * SECSPERDAY;
-       /*
-       ** Cheap overflow check.
-       */
-       if (t / SECSPERDAY != dayoff)
-               return (dayoff > 0) ? max_time : min_time;
        return tadd(t, rp->r_tod);
 }
 
 static void
-newabbr(string)
-const char * const     string;
+newabbr(const char * const string)
 {
-       register int    i;
+       int     i;
 
-       i = strlen(string) + 1;
+       i = (int)strlen(string) + 1;
        if (charcnt + i > TZ_MAX_CHARS) {
                error(_("too many, or too long, time zone abbreviations"));
                (void) exit(EXIT_FAILURE);
@@ -2127,13 +2069,12 @@ const char * const      string;
 }
 
 static int
-mkdirs(argname)
-char * const   argname;
+mkdirs(char * const argname)
 {
-       register char * name;
-       register char * cp;
+       char *  name;
+       char *  cp;
 
-       if (argname == NULL || *argname == '\0')
+       if (argname == NULL || *argname == '\0' || Dflag)
                return 0;
        cp = name = ecpyalloc(argname);
        while ((cp = strchr(cp + 1, '/')) != 0) {
@@ -2151,13 +2092,13 @@ char * const    argname;
                if (!itsdir(name)) {
                        /*
                        ** It doesn't seem to exist, so we try to create it.
+                       ** Creation may fail because of the directory being
+                       ** created by some other multiprocessor, so we get
+                       ** to do extra checking.
                        */
-                       if (mkdir(name, 0755) != 0) {
-                               const char *e = strerror(errno);
-
-                               (void) fprintf(stderr,
-                                   _("%s: Can't create directory %s: %s\n"),
-                                   progname, name, e);
+                       if (mkdir(name, MKDIR_UMASK) != 0
+                               && (errno != EEXIST || !itsdir(name))) {
+                               warn(_("can't create directory %s"), name);
                                ifree(name);
                                return -1;
                        }
@@ -2169,21 +2110,65 @@ char * const    argname;
 }
 
 static long
-eitol(i)
-const int      i;
+eitol(const int i)
 {
        long    l;
 
        l = i;
-       if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
-               (void) fprintf(stderr,
-                       _("%s: %d did not sign extend correctly\n"),
-                       progname, i);
-               (void) exit(EXIT_FAILURE);
-       }
+       if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0))
+               errx(EXIT_FAILURE, _("%d did not sign extend correctly"), i);
        return l;
 }
 
+#include <grp.h>
+#include <pwd.h>
+
+static void
+setgroup(gid_t *flag, const char *name)
+{
+       struct group *gr;
+
+       if (*flag != (gid_t)-1)
+               errx(EXIT_FAILURE, _("multiple -g flags specified"));
+
+       gr = getgrnam(name);
+       if (gr == 0) {
+               char *ep;
+               unsigned long ul;
+
+               ul = strtoul(name, &ep, 10);
+               if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
+                       *flag = (gid_t)ul;
+                       return;
+               }
+               errx(EXIT_FAILURE, _("group `%s' not found"), name);
+       }
+       *flag = gr->gr_gid;
+}
+
+static void
+setuser(uid_t *flag, const char *name)
+{
+       struct passwd *pw;
+
+       if (*flag != (gid_t)-1)
+               errx(EXIT_FAILURE, _("multiple -u flags specified"));
+
+       pw = getpwnam(name);
+       if (pw == 0) {
+               char *ep;
+               unsigned long ul;
+
+               ul = strtoul(name, &ep, 10);
+               if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
+                       *flag = (uid_t)ul;
+                       return;
+               }
+               errx(EXIT_FAILURE, _("user `%s' not found"), name);
+       }
+       *flag = pw->pw_uid;
+}
+
 /*
-** UNIX was a registered trademark of UNIX System Laboratories in 1993.
+** UNIX was a registered trademark of The Open Group in 2003.
 */