]> git.saurik.com Git - apple/file_cmds.git/blobdiff - pax/options.c
file_cmds-321.100.10.0.1.tar.gz
[apple/file_cmds.git] / pax / options.c
index 0bbcaa9c5ea925420acaa379bee75be68a7748fc..0544e5efa9ebf93ab8602e818ac10a2ab0d2398b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: options.c,v 1.31 1998/01/22 06:21:29 millert Exp $    */
+/*     $OpenBSD: options.c,v 1.70 2008/06/11 00:49:08 pvalchev Exp $   */
 /*     $NetBSD: options.c,v 1.6 1996/03/26 23:54:18 mrg Exp $  */
 
 /*-
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
  * SUCH DAMAGE.
  */
 
+#include <sys/cdefs.h>
 #ifndef lint
 #if 0
-static char sccsid[] = "@(#)options.c  8.2 (Berkeley) 4/18/94";
+static const char sccsid[] = "@(#)options.c    8.2 (Berkeley) 4/18/94";
 #else
-static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: options.c,v 1.31 1998/01/22 06:21:29 millert Exp $";
+__used static const char rcsid[] = "$OpenBSD: options.c,v 1.70 2008/06/11 00:49:08 pvalchev Exp $";
 #endif
 #endif /* not lint */
 
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/stat.h>
+#include <search.h>
+#ifndef __APPLE__
 #include <sys/mtio.h>
+#endif /* __APPLE__ */
 #include <sys/param.h>
 #include <stdio.h>
 #include <string.h>
@@ -58,6 +58,7 @@ static char rcsid[] __attribute__((__unused__)) = "$OpenBSD: options.c,v 1.31 19
 #include <stdlib.h>
 #include <limits.h>
 #include <paths.h>
+#include <getopt.h>
 #include "pax.h"
 #include "options.h"
 #include "cpio.h"
@@ -72,19 +73,27 @@ static char flgch[] = FLGCH;        /* list of all possible flags */
 static OPLIST *ophead = NULL;  /* head for format specific options -x */
 static OPLIST *optail = NULL;  /* option tail */
 
-static int no_op __P((void));
-static void printflg __P((unsigned int));
-static int c_frmt __P((const void *, const void *));
-static off_t str_offt __P((char *));
-static void pax_options __P((register int, register char **));
-static void pax_usage __P((void));
-static void tar_options __P((register int, register char **));
-static void tar_usage __P((void));
-static void cpio_options __P((register int, register char **));
-static void cpio_usage __P((void));
+static int no_op(void);
+static void printflg(unsigned int);
+static int c_frmt(const void *, const void *);
+static off_t str_offt(char *);
+static char *pax_getline(FILE *fp);
+static void pax_options(int, char **);
+void pax_usage(void);
+static void tar_options(int, char **);
+static void tar_usage(void);
+static void cpio_options(int, char **);
+static void cpio_usage(void);
+
+/* errors from getline */
+#define GETLINE_FILE_CORRUPT 1
+#define GETLINE_OUT_OF_MEM 2
+static int getline_error;
+
 
 #define GZIP_CMD       "gzip"          /* command to run as gzip */
 #define COMPRESS_CMD   "compress"      /* command to run as compress */
+#define BZIP2_CMD      "bzip2"         /* command to run as bzip2 */
 
 /*
  *     Format specific routine table - MUST BE IN SORTED ORDER BY NAME
@@ -95,50 +104,62 @@ static void cpio_usage __P((void));
  *     rd_data, wr_data, options
  */
 
-FSUB fsub[] = {
-/* 0: OLD BINARY CPIO */
+const FSUB fsub[] = {
+/* OLD BINARY CPIO */
        {"bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd,
        bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, cpio_trail,
        rd_wrfile, wr_rdfile, bad_opt},
 
-/* 1: OLD OCTAL CHARACTER CPIO */
+/* OLD OCTAL CHARACTER CPIO */
        {"cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd,
        cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, cpio_trail,
        rd_wrfile, wr_rdfile, bad_opt},
 
-/* 2: SVR4 HEX CPIO */
+/* POSIX 3 PAX */
+       {"pax", 5120, BLKMULT, 0, 1, BLKMULT, 0, pax_id, ustar_strd,
+       pax_rd, tar_endrd, ustar_stwr, pax_wr, tar_endwr, tar_trail,
+       rd_wrfile, wr_rdfile, pax_opt},
+
+/* SVR4 HEX CPIO */
        {"sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd,
        vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, cpio_trail,
        rd_wrfile, wr_rdfile, bad_opt},
 
-/* 3: SVR4 HEX CPIO WITH CRC */
+/* SVR4 HEX CPIO WITH CRC */
        {"sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd,
        vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, cpio_trail,
        rd_wrfile, wr_rdfile, bad_opt},
 
-/* 4: OLD TAR */
+/* OLD TAR */
        {"tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op,
        tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, tar_trail,
        rd_wrfile, wr_rdfile, tar_opt},
 
-/* 5: POSIX USTAR */
+/* POSIX USTAR */
        {"ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd,
        ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, tar_trail,
        rd_wrfile, wr_rdfile, bad_opt},
 };
-#define        F_OCPIO 0       /* format when called as cpio -6 */
-#define        F_ACPIO 1       /* format when called as cpio -c */
-#define        F_CPIO  3       /* format when called as cpio */
-#define F_OTAR 4       /* format when called as tar -o */
-#define F_TAR  5       /* format when called as tar */
-#define DEFLT  5       /* default write format from list above */
+#define F_OCPIO        0       /* format when called as cpio -6 */
+#define F_ACPIO        1       /* format when called as cpio -c */
+#define F_PAX  2       /* -x pax */
+#define F_SCPIO        3       /* -x sv4cpio */
+#define F_CPIO 4       /* format when called as cpio */
+#define F_OTAR 5       /* format when called as tar -o */
+#define F_TAR  6       /* format when called as tar */
+#define DEFLT  F_TAR   /* default write format from list above */
 
 /*
  * ford is the archive search order used by get_arc() to determine what kind
- * of archive we are dealing with. This helps to properly id  archive formats
+ * of archive we are dealing with. This helps to properly id archive formats
  * some formats may be subsets of others....
  */
-int ford[] = {5, 4, 3, 2, 1, 0, -1 };
+int ford[] = {F_PAX, F_TAR, F_OTAR, F_CPIO, F_SCPIO, F_ACPIO, F_OCPIO, -1 };
+
+/*
+ * Do we have -C anywhere?
+ */
+int havechd = 0;
 
 /*
  * options()
@@ -146,15 +167,8 @@ int ford[] = {5, 4, 3, 2, 1, 0, -1 };
  *     parser
  */
 
-#ifdef __STDC__
-void
-options(register int argc, register char **argv)
-#else
 void
-options(argc, argv)
-       register int argc;
-       register char **argv;
-#endif
+options(int argc, char **argv)
 {
 
        /*
@@ -165,48 +179,58 @@ options(argc, argv)
        else
                argv0 = argv[0];
 
-       if (strcmp(NM_TAR, argv0) == 0)
-               return(tar_options(argc, argv));
-       else if (strcmp(NM_CPIO, argv0) == 0)
-               return(cpio_options(argc, argv));
+       if (strcmp(NM_TAR, argv0) == 0) {
+               tar_options(argc, argv);
+               return;
+       } else if (strcmp(NM_CPIO, argv0) == 0) {
+               cpio_options(argc, argv);
+               return;
+       }
        /*
         * assume pax as the default
         */
        argv0 = NM_PAX;
-       return(pax_options(argc, argv));
+       pax_options(argc, argv);
 }
 
+#define OPT_INSECURE 1
+struct option pax_longopts[] = {
+       { "insecure",       no_argument,        0,  OPT_INSECURE },
+       { 0,                0,                  0,  0 },
+};
+
 /*
  * pax_options()
  *     look at the user specified flags. set globals as required and check if
  *     the user specified a legal set of flags. If not, complain and exit
  */
 
-#ifdef __STDC__
-static void
-pax_options(register int argc, register char **argv)
-#else
 static void
-pax_options(argc, argv)
-       register int argc;
-       register char **argv;
-#endif
+pax_options(int argc, char **argv)
 {
-       register int c;
-       register int i;
+       int c;
+       size_t i;
        unsigned int flg = 0;
        unsigned int bflg = 0;
-       register char *pt;
+       char *pt;
        FSUB tmp;
-       extern char *optarg;
-       extern int optind;
+       size_t n_fsub;
+       char * tmp_name;
 
+       listf = stderr;
        /*
         * process option flags
         */
-       while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:zB:DE:G:HLPT:U:XYZ"))
-           != EOF) {
+       while ((c=getopt_long(argc,argv,"0ab:cdf:ijklno:p:rs:tuvwx:zB:DE:G:HLOPT:U:XYZ", pax_longopts, NULL)) != -1) {
                switch (c) {
+               case '0':
+                       /*
+                        * Use \0 as pathname terminator.
+                        * (For use with the -print0 option of find(1).)
+                        */
+                       zeroflag = 1;
+                       flg |= C0F;
+                       break;
                case 'a':
                        /*
                         * append
@@ -241,6 +265,13 @@ pax_options(argc, argv)
                        /*
                         * filename where the archive is stored
                         */
+                       if ((optarg[0] == '-') && (optarg[1]== '\0')) {
+                               /*
+                                * treat a - as stdin (like tar)
+                                */
+                               arcname = NULL;
+                               break;
+                       }
                        arcname = optarg;
                        flg |= FF;
                        break;
@@ -251,6 +282,12 @@ pax_options(argc, argv)
                        iflag = 1;
                        flg |= IF;
                        break;
+               case 'j':
+                       /*
+                        * use bzip2.  Non standard option.
+                        */
+                       gzip_program = BZIP2_CMD;
+                       break;
                case 'k':
                        /*
                         * do not clobber files that exist
@@ -277,7 +314,7 @@ pax_options(argc, argv)
                         * pass format specific options
                         */
                        flg |= OF;
-                       if (opt_add(optarg) < 0)
+                       if (pax_format_opt_add(optarg) < 0)
                                pax_usage();
                        break;
                case 'p':
@@ -285,7 +322,7 @@ pax_options(argc, argv)
                         * specify file characteristic options
                         */
                        for (pt = optarg; *pt != '\0'; ++pt) {
-                               switch(*pt) {
+                               switch (*pt) {
                                case 'a':
                                        /*
                                         * do not preserve access time
@@ -316,7 +353,7 @@ pax_options(argc, argv)
                                        break;
                                case 'p':
                                        /*
-                                        * preserver file mode bits
+                                        * preserve file mode bits
                                         */
                                        pmode = 1;
                                        break;
@@ -332,6 +369,7 @@ pax_options(argc, argv)
                        /*
                         * read the archive
                         */
+                       pax_read_or_list_mode=1;
                        flg |= RF;
                        break;
                case 's':
@@ -376,11 +414,9 @@ pax_options(argc, argv)
                         * specify an archive format on write
                         */
                        tmp.name = optarg;
-                       if (0 == strcmp("pax", optarg)) { /* alias for ustar */
-                               tmp.name = "ustar";
-                       }
-                       if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub,
-                           sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL) {
+                       n_fsub = sizeof(fsub)/sizeof(FSUB);
+                       if ((frmt = (FSUB *)bsearch(&tmp, fsub, n_fsub, sizeof(FSUB),
+                                                   c_frmt)) != NULL) {
                                flg |= XF;
                                break;
                        }
@@ -395,7 +431,6 @@ pax_options(argc, argv)
                        /*
                         * use gzip.  Non standard option.
                         */
-                       zflag = 1;
                        gzip_program = GZIP_CMD;
                        break;
                case 'B':
@@ -453,6 +488,8 @@ pax_options(argc, argv)
                         */
                        Hflag = 1;
                        flg |= CHF;
+                       Lflag = 0;      /* -H and -L are mutually exclusive     */
+                       flg &= ~CLF;    /* only use the last one seen           */
                        break;
                case 'L':
                        /*
@@ -460,6 +497,14 @@ pax_options(argc, argv)
                         */
                        Lflag = 1;
                        flg |= CLF;
+                       Hflag = 0;      /* -H and -L are mutually exclusive     */
+                       flg &= ~CHF;    /* only use the last one seen           */
+                       break;
+               case 'O':
+                       /*
+                        * Force one volume.  Non standard option.
+                        */
+                       force_one_volume = 1;
                        break;
                case 'P':
                        /*
@@ -513,12 +558,23 @@ pax_options(argc, argv)
                        Zflag = 1;
                        flg |= CZF;
                        break;
+               case OPT_INSECURE:
+                       secure = 0;
+                       break;
                default:
                        pax_usage();
                        break;
                }
        }
 
+       /*
+        * Fix for POSIX.cmd/pax/pax.ex test 132: force -wu options to look
+        * like -wua options were specified.
+       */
+       if (uflag && (flg & WF) && !(flg & RF)) {       /* -w but not -r -w */
+               flg |= AF;
+       }
+
        /*
         * figure out the operation mode of pax read,write,extract,copy,append
         * or list. check that we have not been given a bogus set of flags
@@ -526,6 +582,8 @@ pax_options(argc, argv)
         */
        if (ISLIST(flg)) {
                act = LIST;
+               pax_read_or_list_mode=1;
+               listf = stdout;
                bflg = flg & BDLIST;
        } else if (ISEXTRACT(flg)) {
                act = EXTRACT;
@@ -554,6 +612,23 @@ pax_options(argc, argv)
        if (!(flg & XF) && (act == ARCHIVE))
                frmt = &(fsub[DEFLT]);
 
+       /*
+        * if copying (-r and -w) and there is no -x specified, we act as
+        * if -x pax was specified.
+        */
+       if (!(flg & XF) && (act == COPY))
+               frmt = &(fsub[F_PAX]);
+
+       /*
+        * Initialize the global extended header template.
+        */
+       tmp_name = getenv("TMPDIR");
+       if (tmp_name) {
+               asprintf(&header_name_g, "%s%s", tmp_name, "/GlobalHead.%p.%n");
+       } else {
+               header_name_g = "/tmp/GlobalHead.%p.%n";
+       }
+
        /*
         * process the args as they are interpreted by the operation mode
         */
@@ -592,19 +667,19 @@ pax_options(argc, argv)
  *     the user specified a legal set of flags. If not, complain and exit
  */
 
-#ifdef __STDC__
-static void
-tar_options(register int argc, register char **argv)
-#else
 static void
-tar_options(argc, argv)
-       register int argc;
-       register char **argv;
-#endif
+tar_options(int argc, char **argv)
 {
-       register int c;
+       int c;
        int fstdin = 0;
        int Oflag = 0;
+       int nincfiles = 0;
+       int incfiles_max = 0;
+       struct incfile {
+               char *file;
+               char *dir;
+       };
+       struct incfile *incfiles = NULL;
 
        /*
         * Set default values.
@@ -615,9 +690,8 @@ tar_options(argc, argv)
         * process option flags
         */
        while ((c = getoldopt(argc, argv,
-           "b:cef:hmopruts:vwxzBC:HLOPXZ014578"))
-           != EOF) {
-               switch(c) {
+           "b:cef:hjmopqruts:vwxzBC:HI:LOPXZ014578")) != -1) {
+               switch (c) {
                case 'b':
                        /*
                         * specify blocksize in 512-byte blocks
@@ -661,27 +735,36 @@ tar_options(argc, argv)
                         */
                        Lflag = 1;
                        break;
+               case 'j':
+                       /*
+                        * use bzip2.  Non standard option.
+                        */
+                       gzip_program = BZIP2_CMD;
+                       break;
                case 'm':
                        /*
                         * do not preserve modification time
                         */
                        pmtime = 0;
                        break;
-               case 'o':
-                       if (opt_add("write_opt=nodir") < 0)
-                               tar_usage();
                case 'O':
                        Oflag = 1;
                        break;
+               case 'o':
+                       Oflag = 2;
+                       break;
                case 'p':
                        /*
-                        * preserve user id, group id, file
-                        * mode, access/modification times
+                        * preserve uid/gid and file mode, regardless of umask
                         */
-                       pids = 1;
                        pmode = 1;
-                       patime = 1;
-                       pmtime = 1;
+                       pids = 1;
+                       break;
+               case 'q':
+                       /*
+                        * select first match for a pattern only
+                        */
+                       nflag = 1;
                        break;
                case 'r':
                case 'u':
@@ -719,17 +802,16 @@ tar_options(argc, argv)
                        break;
                case 'x':
                        /*
-                        * write an archive, preserve ids if root
+                        * extract an archive, preserving mode,
+                        * and mtime if possible.
                         */
                        act = EXTRACT;
-                       if (geteuid() == 0)
-                               pids = 1;
+                       pmtime = 1;
                        break;
                case 'z':
                        /*
                         * use gzip.  Non standard option.
                         */
-                       zflag = 1;
                        gzip_program = GZIP_CMD;
                        break;
                case 'B':
@@ -738,6 +820,7 @@ tar_options(argc, argv)
                         */
                        break;
                case 'C':
+                       havechd++;
                        chdname = optarg;
                        break;
                case 'H':
@@ -746,6 +829,20 @@ tar_options(argc, argv)
                         */
                        Hflag = 1;
                        break;
+               case 'I':
+                       if (++nincfiles > incfiles_max) {
+                               incfiles_max = nincfiles + 3;
+                               incfiles = realloc(incfiles,
+                                   sizeof(*incfiles) * incfiles_max);
+                               if (incfiles == NULL) {
+                                       paxwarn(0, "Unable to allocate space "
+                                           "for option list");
+                                       exit(1);
+                               }
+                       }
+                       incfiles[nincfiles - 1].file = optarg;
+                       incfiles[nincfiles - 1].dir = chdname;
+                       break;
                case 'L':
                        /*
                         * follow symlinks
@@ -768,7 +865,6 @@ tar_options(argc, argv)
                        /*
                         * use compress.
                         */
-                       zflag = 1;
                        gzip_program = COMPRESS_CMD;
                        break;
                case '0':
@@ -797,20 +893,15 @@ tar_options(argc, argv)
        argc -= optind;
        argv += optind;
 
-       /* Traditional tar behaviour (pax wants to read filelist from stdin) */
-       if ((act == ARCHIVE || act == APPND) && argc == 0)
-               exit(0);
+       /* Traditional tar behaviour (pax uses stderr unless in list mode) */
+       if (fstdin == 1 && act == ARCHIVE)
+               listf = stderr;
+       else
+               listf = stdout;
 
-       /*
-        * if we are writing (ARCHIVE) specify tar, otherwise run like pax
-        * (unless -o specified)
-        */
-       if (act == ARCHIVE || act == APPND)
-               frmt = &(fsub[Oflag ? F_OTAR : F_TAR]);
-       else if (Oflag) {
-               paxwarn(1, "The -O/-o options are only valid when writing an archive");
-               tar_usage();            /* only valid when writing */
-       }
+       /* Traditional tar behaviour (pax wants to read file list from stdin) */
+       if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0)
+               exit(0);
 
        /*
         * process the args as they are interpreted by the operation mode
@@ -821,22 +912,62 @@ tar_options(argc, argv)
        default:
                {
                        int sawpat = 0;
+                       char *file, *dir = NULL;
 
-                       while (*argv != NULL) {
-                               if (strcmp(*argv, "-C") == 0) {
-                                       if(*++argv == NULL)
+                       while (nincfiles || *argv != NULL) {
+                               /*
+                                * If we queued up any include files,
+                                * pull them in now.  Otherwise, check
+                                * for -I and -C positional flags.
+                                * Anything else must be a file to
+                                * extract.
+                                */
+                               if (nincfiles) {
+                                       file = incfiles->file;
+                                       dir = incfiles->dir;
+                                       incfiles++;
+                                       nincfiles--;
+                               } else if (strcmp(*argv, "-I") == 0) {
+                                       if (*++argv == NULL)
+                                               break;
+                                       file = *argv++;
+                                       dir = chdname;
+                               } else
+                                       file = NULL;
+                               if (file != NULL) {
+                                       FILE *fp;
+                                       char *str;
+
+                                       if (strcmp(file, "-") == 0)
+                                               fp = stdin;
+                                       else if ((fp = fopen(file, "r")) == NULL) {
+                                               paxwarn(1, "Unable to open file '%s' for read", file);
+                                               tar_usage();
+                                       }
+                                       while ((str = pax_getline(fp)) != NULL) {
+                                               if (pat_add(str, dir) < 0)
+                                                       tar_usage();
+                                               sawpat = 1;
+                                       }
+                                       if (strcmp(file, "-") != 0)
+                                               fclose(fp);
+                                       if (getline_error) {
+                                               paxwarn(1, "Problem with file '%s'", file);
+                                               tar_usage();
+                                       }
+                               } else if (strcmp(*argv, "-C") == 0) {
+                                       if (*++argv == NULL)
                                                break;
                                        chdname = *argv++;
-
-                                       continue;
-                               }
-                               if (pat_add(*argv++, chdname) < 0)
+                                       havechd++;
+                               } else if (pat_add(*argv++, chdname) < 0)
                                        tar_usage();
-                               sawpat++;
+                               else
+                                       sawpat = 1;
                        }
                        /*
                         * if patterns were added, we are doing chdir()
-                        * on a file-by-file basis, else, just one 
+                        * on a file-by-file basis, else, just one
                         * global chdir (if any) after opening input.
                         */
                        if (sawpat > 0)
@@ -845,21 +976,72 @@ tar_options(argc, argv)
                break;
        case ARCHIVE:
        case APPND:
+               frmt = &(fsub[Oflag ? F_OTAR : F_TAR]);
+
+               if (Oflag == 2 && opt_add("write_opt=nodir") < 0)
+                       tar_usage();
+
                if (chdname != NULL) {  /* initial chdir() */
                        if (ftree_add(chdname, 1) < 0)
                                tar_usage();
                }
 
-               while (*argv != NULL) {
-                       if (!strcmp(*argv, "-C")) {
+               while (nincfiles || *argv != NULL) {
+                       char *file, *dir = NULL;
+
+                       /*
+                        * If we queued up any include files, pull them in
+                        * now.  Otherwise, check for -I and -C positional
+                        * flags.  Anything else must be a file to include
+                        * in the archive.
+                        */
+                       if (nincfiles) {
+                               file = incfiles->file;
+                               dir = incfiles->dir;
+                               incfiles++;
+                               nincfiles--;
+                       } else if (strcmp(*argv, "-I") == 0) {
                                if (*++argv == NULL)
                                        break;
-                               if (ftree_add(*argv++, 1) < 0)
+                               file = *argv++;
+                               dir = NULL;
+                       } else
+                               file = NULL;
+                       if (file != NULL) {
+                               FILE *fp;
+                               char *str;
+
+                               /* Set directory if needed */
+                               if (dir) {
+                                       if (ftree_add(dir, 1) < 0)
+                                               tar_usage();
+                               }
+
+                               if (strcmp(file, "-") == 0)
+                                       fp = stdin;
+                               else if ((fp = fopen(file, "r")) == NULL) {
+                                       paxwarn(1, "Unable to open file '%s' for read", file);
                                        tar_usage();
-                       } else {
-                               if (ftree_add(*argv++, 0) < 0)
+                               }
+                               while ((str = pax_getline(fp)) != NULL) {
+                                       if (ftree_add(str, 0) < 0)
+                                               tar_usage();
+                               }
+                               if (strcmp(file, "-") != 0)
+                                       fclose(fp);
+                               if (getline_error) {
+                                       paxwarn(1, "Problem with file '%s'",
+                                           file);
                                        tar_usage();
-                       }
+                               }
+                       } else if (strcmp(*argv, "-C") == 0) {
+                               if (*++argv == NULL)
+                                       break;
+                               if (ftree_add(*argv++, 1) < 0)
+                                       tar_usage();
+                               havechd++;
+                       } else if (ftree_add(*argv++, 0) < 0)
+                               tar_usage();
                }
                /*
                 * no read errors allowed on updates/append operation!
@@ -874,12 +1056,14 @@ tar_options(argc, argv)
        }
 }
 
+int mkpath(char *);
+
 int
 mkpath(path)
        char *path;
 {
        struct stat sb;
-       register char *slash;
+       char *slash;
        int done = 0;
 
        slash = path;
@@ -913,21 +1097,14 @@ mkpath(path)
  *     the user specified a legal set of flags. If not, complain and exit
  */
 
-#ifdef __STDC__
 static void
-cpio_options(register int argc, register char **argv)
-#else
-static void
-cpio_options(argc, argv)
-       register int argc;
-       register char **argv;
-#endif
+cpio_options(int argc, char **argv)
 {
-       register int c, i;
-       size_t len;
+       int c, i;
        char *str;
        FSUB tmp;
        FILE *fp;
+       size_t n_fsub;
 
        kflag = 1;
        pids = 1;
@@ -937,7 +1114,7 @@ cpio_options(argc, argv)
        dflag = 1;
        act = -1;
        nodirs = 1;
-       while ((c=getopt(argc,argv,"abcdfiklmoprstuvzABC:E:F:H:I:LO:SZ6")) != EOF)
+       while ((c=getopt(argc,argv,"abcdfijklmoprstuvzABC:E:F:H:I:LO:SZ6")) != -1)
                switch (c) {
                        case 'a':
                                /*
@@ -974,6 +1151,12 @@ cpio_options(argc, argv)
                                 */
                                act = EXTRACT;
                                break;
+                       case 'j':
+                               /*
+                                * use bzip2.  Non standard option.
+                                */
+                               gzip_program = BZIP2_CMD;
+                               break;
                        case 'k':
                                break;
                        case 'l':
@@ -1017,6 +1200,7 @@ cpio_options(argc, argv)
                                 * list contents of archive
                                 */
                                act = LIST;
+                               listf = stdout;
                                break;
                        case 'u':
                                /*
@@ -1034,7 +1218,6 @@ cpio_options(argc, argv)
                                /*
                                 * use gzip.  Non standard option.
                                 */
-                               zflag = 1;
                                gzip_program = GZIP_CMD;
                                break;
                        case 'A':
@@ -1063,11 +1246,14 @@ cpio_options(argc, argv)
                                        paxwarn(1, "Unable to open file '%s' for read", optarg);
                                        cpio_usage();
                                }
-                               while ((str = fgetln(fp, &len)) != NULL) {
-                                       str[len - 1] = '\0';
+                               while ((str = pax_getline(fp)) != NULL) {
                                        pat_add(str, NULL);
                                }
                                fclose(fp);
+                               if (getline_error) {
+                                       paxwarn(1, "Problem with file '%s'", optarg);
+                                       cpio_usage();
+                               }
                                break;
                        case 'F':
                        case 'I':
@@ -1089,8 +1275,9 @@ cpio_options(argc, argv)
                                 * specify an archive format on write
                                 */
                                tmp.name = optarg;
+                               n_fsub = sizeof(fsub)/sizeof(FSUB);
                                if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub,
-                                   sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) != NULL)
+                                               n_fsub, sizeof(FSUB), c_frmt)) != NULL)
                                        break;
                                paxwarn(1, "Unknown -H format: %s", optarg);
                                (void)fputs("cpio: Known -H formats are:", stderr);
@@ -1114,7 +1301,6 @@ cpio_options(argc, argv)
                                /*
                                 * use compress.  Non standard option.
                                 */
-                               zflag = 1;
                                gzip_program = COMPRESS_CMD;
                                break;
                        case '6':
@@ -1160,9 +1346,12 @@ cpio_options(argc, argv)
                         * no read errors allowed on updates/append operation!
                         */
                        maxflt = 0;
-                       while ((str = fgetln(stdin, &len)) != NULL) {
-                               str[len - 1] = '\0';
-                               ftree_add(strdup(str), NULL);
+                       while ((str = pax_getline(stdin)) != NULL) {
+                               ftree_add(str, 0);
+                       }
+                       if (getline_error) {
+                               paxwarn(1, "Problem while reading stdin");
+                               cpio_usage();
                        }
                        break;
                default:
@@ -1176,14 +1365,8 @@ cpio_options(argc, argv)
  *     print out those invalid flag sets found to the user
  */
 
-#ifdef __STDC__
 static void
 printflg(unsigned int flg)
-#else
-static void
-printflg(flg)
-       unsigned int flg;
-#endif
 {
        int nxt;
        int pos = 0;
@@ -1203,17 +1386,10 @@ printflg(flg)
  *     by the user
  */
 
-#ifdef __STDC__
 static int
 c_frmt(const void *a, const void *b)
-#else
-static int
-c_frmt(a, b)
-       void *a;
-       void *b;
-#endif
 {
-       return(strcmp(((FSUB *)a)->name, ((FSUB *)b)->name));
+       return(strcmp(((const FSUB *)a)->name, ((const FSUB *)b)->name));
 }
 
 /*
@@ -1224,13 +1400,8 @@ c_frmt(a, b)
  *     pointer to next OPLIST entry or NULL (end of list).
  */
 
-#ifdef __STDC__
 OPLIST *
 opt_next(void)
-#else
-OPLIST *
-opt_next()
-#endif
 {
        OPLIST *opt;
 
@@ -1245,15 +1416,10 @@ opt_next()
  *     when the format does not support options.
  */
 
-#ifdef __STDC__
 int
 bad_opt(void)
-#else
-int
-bad_opt()
-#endif
 {
-       register OPLIST *opt;
+       OPLIST *opt;
 
        if (ophead == NULL)
                return(0);
@@ -1261,34 +1427,101 @@ bad_opt()
         * print all we were given
         */
        paxwarn(1,"These format options are not supported");
-       while ((opt = opt_next()) != NULL)
-               (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value);
+       while ((opt = opt_next()) != NULL) {
+               if (opt->separator == SEP_EQ) {
+                       (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value);
+               } else if (opt->separator == SEP_COLONEQ ) {
+                       (void)fprintf(stderr, "\t%s := %s\n", opt->name, opt->value);
+               } else {        /* SEP_NONE */
+                       (void)fprintf(stderr, "\t%s\n", opt->name);
+               }
+       }
        pax_usage();
        return(0);
 }
 
 /*
  * opt_add()
+ *     breaks the value supplied to -o into an option name and value. Options
+ *     are given to -o in the form -o name-value,name=value
+ *     multiple -o may be specified.
+ * Return:
+ *     0 if format in name=value format, -1 if -o is passed junk.
+ */
+
+int
+opt_add(const char *str)
+{
+       OPLIST *opt;
+       char *frpt;
+       char *pt;
+       char *dstr;
+       char *endpt;
+
+       if ((str == NULL) || (*str == '\0')) {
+               paxwarn(0, "Invalid option name");
+               return(-1);
+       }
+       if ((dstr = strdup(str)) == NULL) {
+               paxwarn(0, "Unable to allocate space for option list");
+               return(-1);
+       }
+       frpt = dstr;
+
+       /*
+        * break into name and values pieces and stuff each one into a
+        * OPLIST structure. When we know the format, the format specific
+        * option function will go through this list
+        */
+       while ((frpt != NULL) && (*frpt != '\0')) {
+               if ((endpt = strchr(frpt, ',')) != NULL)
+                       *endpt = '\0';
+               if ((pt = strchr(frpt, '=')) == NULL) {
+                       paxwarn(0, "Invalid options format");
+                       free(dstr);
+                       return(-1);
+               }
+               if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) {
+                       paxwarn(0, "Unable to allocate space for option list");
+                       free(dstr);
+                       return(-1);
+               }
+               *pt++ = '\0';
+               opt->name = frpt;
+               opt->value = pt;
+               opt->separator = SEP_EQ;
+               opt->fow = NULL;
+               if (endpt != NULL)
+                       frpt = endpt + 1;
+               else
+                       frpt = NULL;
+               if (ophead == NULL) {
+                       optail = ophead = opt;
+                       continue;
+               }
+               optail->fow = opt;
+               optail = opt;
+       }
+       return(0);
+}
+
+/*
+ * pax_format_opt_add()
  *     breaks the value supplied to -o into a option name and value. options
  *     are given to -o in the form -o name-value,name=value
- *     mulltiple -o may be specified.
+ *     multiple -o may be specified.
  * Return:
  *     0 if format in name=value format, -1 if -o is passed junk
  */
 
-#ifdef __STDC__
 int
-opt_add(register char *str)
-#else
-int
-opt_add(str)
-       register char *str;
-#endif
+pax_format_opt_add(register char *str)
 {
        register OPLIST *opt;
        register char *frpt;
        register char *pt;
        register char *endpt;
+       register int separator;
 
        if ((str == NULL) || (*str == '\0')) {
                paxwarn(0, "Invalid option name");
@@ -1298,7 +1531,7 @@ opt_add(str)
                paxwarn(0, "Unable to allocate space for option list");
                return(-1);
        }
-       frpt = endpt = str;
+       frpt = str;
 
        /*
         * break into name and values pieces and stuff each one into a
@@ -1308,19 +1541,25 @@ opt_add(str)
        while ((frpt != NULL) && (*frpt != '\0')) {
                if ((endpt = strchr(frpt, ',')) != NULL)
                        *endpt = '\0';
-               if ((pt = strchr(frpt, '=')) == NULL) {
-                       paxwarn(0, "Invalid options format");
-                       free(str);
-                       return(-1);
+               if ((pt = strstr(frpt, ":=")) != NULL) {
+                       *pt++ = '\0';
+                       pt++;   /* beyond the := */
+                       separator = SEP_COLONEQ;
+               } else if ((pt = strchr(frpt, '=')) != NULL) {
+                       *pt++ = '\0';
+                       separator = SEP_EQ;
+               } else {
+                       /* keyword with no value */
+                       separator = SEP_NONE;
                }
                if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) {
                        paxwarn(0, "Unable to allocate space for option list");
                        free(str);
                        return(-1);
                }
-               *pt++ = '\0';
                opt->name = frpt;
                opt->value = pt;
+               opt->separator = separator;
                opt->fow = NULL;
                if (endpt != NULL)
                        frpt = endpt + 1;
@@ -1345,25 +1584,19 @@ opt_add(str)
  *     4) A positive decimal number followed by a m (mult by 512).
  *     5) A positive decimal number followed by a w (mult by sizeof int)
  *     6) Two or more positive decimal numbers (with/without k,b or w).
- *        seperated by x (also * for backwards compatibility), specifying
+ *        separated by x (also * for backwards compatibility), specifying
  *        the product of the indicated values.
  * Return:
  *     0 for an error, a positive value o.w.
  */
 
-#ifdef __STDC__
 static off_t
 str_offt(char *val)
-#else
-static off_t
-str_offt(val)
-       char *val;
-#endif
 {
        char *expr;
        off_t num, t;
 
-#      ifdef NET2_STAT
+#      ifdef LONG_OFF_T
        num = strtol(val, &expr, 0);
        if ((num == LONG_MAX) || (num <= 0) || (expr == val))
 #      else
@@ -1372,7 +1605,7 @@ str_offt(val)
 #      endif
                return(0);
 
-       switch(*expr) {
+       switch (*expr) {
        case 'b':
                t = num;
                num *= 512;
@@ -1403,7 +1636,7 @@ str_offt(val)
                break;
        }
 
-       switch(*expr) {
+       switch (*expr) {
                case '\0':
                        break;
                case '*':
@@ -1419,6 +1652,29 @@ str_offt(val)
        return(num);
 }
 
+char *
+pax_getline(FILE *f)
+{
+       char *name, *temp;
+       size_t len;
+
+       name = fgetln(f, &len);
+       if (!name) {
+               getline_error = ferror(f) ? GETLINE_FILE_CORRUPT : 0;
+               return(0);
+       }
+       if (name[len-1] != '\n')
+               len++;
+       temp = malloc(len);
+       if (!temp) {
+               getline_error = GETLINE_OUT_OF_MEM;
+               return(0);
+       }
+       memcpy(temp, name, len-1);
+       temp[len-1] = 0;
+       return(temp);
+}
+                       
 /*
  * no_op()
  *     for those option functions where the archive format has nothing to do.
@@ -1426,13 +1682,8 @@ str_offt(val)
  *     0
  */
 
-#ifdef __STDC__
 static int
 no_op(void)
-#else
-static int
-no_op()
-#endif
 {
        return(0);
 }
@@ -1442,37 +1693,20 @@ no_op()
  *     print the usage summary to the user
  */
 
-#ifdef __STDC__
 void
 pax_usage(void)
-#else
-void
-pax_usage()
-#endif
 {
-       (void)fputs("usage: pax [-cdnv] [-E limit] [-f archive] ", stderr);
-       (void)fputs("[-s replstr] ... [-U user] ...", stderr);
-       (void)fputs("\n           [-G group] ... ", stderr);
-       (void)fputs("[-T [from_date][,to_date]] ... ", stderr);
-       (void)fputs("[pattern ...]\n", stderr);
-       (void)fputs("       pax -r [-cdiknuvDYZ] [-E limit] ", stderr);
-       (void)fputs("[-f archive] [-o options] ... \n", stderr);
-       (void)fputs("           [-p string] ... [-s replstr] ... ", stderr);
-       (void)fputs("[-U user] ... [-G group] ...\n           ", stderr);
-       (void)fputs("[-T [from_date][,to_date]] ... ", stderr);
-       (void)fputs(" [pattern ...]\n", stderr);
-       (void)fputs("       pax -w [-dituvHLPX] [-b blocksize] ", stderr);
-       (void)fputs("[ [-a] [-f archive] ] [-x format] \n", stderr);
-       (void)fputs("           [-B bytes] [-s replstr] ... ", stderr);
-       (void)fputs("[-o options] ... [-U user] ...", stderr);
-       (void)fputs("\n           [-G group] ... ", stderr);
-       (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
-       (void)fputs("[file ...]\n", stderr);
-       (void)fputs("       pax -r -w [-diklntuvDHLPXYZ] ", stderr);
-       (void)fputs("[-p string] ... [-s replstr] ...", stderr);
-       (void)fputs("\n           [-U user] ... [-G group] ... ", stderr);
-       (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
-       (void)fputs("\n           [file ...] directory\n", stderr);
+       (void)fputs(
+           "usage: pax [-0cdjnOvz] [-E limit] [-f archive] [-G group] [-s replstr]\n"
+           "           [-T range] [-U user] [--insecure] [pattern ...]\n"
+           "       pax -r [-0cDdijknOuvYZz] [-E limit] [-f archive] [-G group] [-o options]\n"
+           "           [-p string] [-s replstr] [-T range] [-U user] [--insecure] [pattern ...]\n"
+           "       pax -w [-0adHijLOPtuvXz] [-B bytes] [-b blocksize] [-f archive]\n"
+           "           [-G group] [-o options] [-s replstr] [-T range] [-U user]\n"
+           "           [-x format] [--insecure] [file ...]\n"
+           "       pax -rw [-0DdHikLlnOPtuvXYZ] [-G group] [-p string] [-s replstr]\n"
+           "           [-T range] [-U user] [--insecure] [file ...] directory\n",
+           stderr);
        exit(1);
 }
 
@@ -1481,17 +1715,15 @@ pax_usage()
  *     print the usage summary to the user
  */
 
-#ifdef __STDC__
 void
 tar_usage(void)
-#else
-void
-tar_usage()
-#endif
 {
-       (void)fputs("usage: tar -{txru}[cevfbmopswzBHLPXZ014578] [tapefile] ",
-                stderr);
-       (void)fputs("[blocksize] [replstr] [-C directory] file1 file2...\n",
+       (void)fputs(
+           "usage: tar {crtux}[014578befHhjLmOoPpqsvwXZz]\n"
+           "           [blocking-factor | archive | replstr] [-C directory] [-I file]\n"
+           "           [file ...]\n"
+           "       tar {-crtux} [-014578eHhjLmOoPpqvwXZz] [-b blocking-factor]\n"
+           "           [-C directory] [-f archive] [-I file] [-s replstr] [file ...]\n",
            stderr);
        exit(1);
 }
@@ -1501,18 +1733,15 @@ tar_usage()
  *     print the usage summary to the user
  */
 
-#ifdef __STDC__
 void
 cpio_usage(void)
-#else
-void
-cpio_usage()
-#endif
 {
-       (void)fputs("usage: cpio -o [-aABcLvVzZ] [-C bytes] [-H format] [-O archive]\n", stderr);
-       (void)fputs("               [-F archive] < name-list [> archive]\n", stderr);
-       (void)fputs("       cpio -i [-bBcdfmnrsStuvVzZ6] [-C bytes] [-E file] [-H format]\n", stderr);
-       (void)fputs("               [-I archive] [-F archive] [pattern...] [< archive]\n", stderr);
-       (void)fputs("       cpio -p [-adlLmuvV] destination-directory < name-list\n", stderr);
+       (void)fputs(
+           "usage: cpio -o [-AaBcjLvZz] [-C bytes] [-F archive] [-H format]\n"
+           "            [-O archive] < name-list [> archive]\n"
+           "       cpio -i [-6BbcdfjmrSstuvZz] [-C bytes] [-E file] [-F archive] [-H format]\n"
+           "            [-I archive] [pattern ...] [< archive]\n"
+           "       cpio -p [-adLlmuv] destination-directory < name-list\n",
+           stderr);
        exit(1);
 }