Home | History | Annotate | Line # | Download | only in pax
options.c revision 1.2
      1 /*-
      2  * Copyright (c) 1992 Keith Muller.
      3  * Copyright (c) 1992, 1993
      4  *	The Regents of the University of California.  All rights reserved.
      5  *
      6  * This code is derived from software contributed to Berkeley by
      7  * Keith Muller of the University of California, San Diego.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *	This product includes software developed by the University of
     20  *	California, Berkeley and its contributors.
     21  * 4. Neither the name of the University nor the names of its contributors
     22  *    may be used to endorse or promote products derived from this software
     23  *    without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  */
     37 
     38 #ifndef lint
     39 /*static char sccsid[] = "from: @(#)options.c	8.2 (Berkeley) 4/18/94";*/
     40 static char rcsid[] = "$Id: options.c,v 1.2 1994/06/13 16:34:06 jtc Exp $";
     41 #endif /* not lint */
     42 
     43 #include <sys/types.h>
     44 #include <sys/time.h>
     45 #include <sys/stat.h>
     46 #include <sys/mtio.h>
     47 #include <sys/param.h>
     48 #include <stdio.h>
     49 #include <ctype.h>
     50 #include <string.h>
     51 #include <unistd.h>
     52 #include <stdlib.h>
     53 #include <limits.h>
     54 #include "pax.h"
     55 #include "options.h"
     56 #include "cpio.h"
     57 #include "tar.h"
     58 #include "extern.h"
     59 
     60 /*
     61  * Routines which handle command line options
     62  */
     63 
     64 static char flgch[] = FLGCH;	/* list of all possible flags */
     65 static OPLIST *ophead = NULL;	/* head for format specific options -x */
     66 static OPLIST *optail = NULL;	/* option tail */
     67 
     68 static int no_op __P((void));
     69 static void printflg __P((unsigned int));
     70 static int c_frmt __P((const void *, const void *));
     71 static off_t str_offt __P((char *));
     72 static void pax_options __P((register int, register char **));
     73 static void pax_usage __P((void));
     74 static void tar_options __P((register int, register char **));
     75 static void tar_usage __P((void));
     76 #ifdef notdef
     77 static void cpio_options __P((register int, register char **));
     78 static void cpio_usage __P((void));
     79 #endif
     80 
     81 /*
     82  *	Format specific routine table - MUST BE IN SORTED ORDER BY NAME
     83  *	(see pax.h for description of each function)
     84  *
     85  * 	name, blksz, hdsz, udev, hlk, blkagn, inhead, id, st_read,
     86  *	read, end_read, st_write, write, end_write, trail,
     87  *	rd_data, wr_data, options
     88  */
     89 
     90 FSUB fsub[] = {
     91 /* 0: OLD BINARY CPIO */
     92 	"bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd,
     93 	bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, cpio_trail,
     94 	rd_wrfile, wr_rdfile, bad_opt,
     95 
     96 /* 1: OLD OCTAL CHARACTER CPIO */
     97 	"cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd,
     98 	cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, cpio_trail,
     99 	rd_wrfile, wr_rdfile, bad_opt,
    100 
    101 /* 2: SVR4 HEX CPIO */
    102 	"sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd,
    103 	vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, cpio_trail,
    104 	rd_wrfile, wr_rdfile, bad_opt,
    105 
    106 /* 3: SVR4 HEX CPIO WITH CRC */
    107 	"sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd,
    108 	vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, cpio_trail,
    109 	rd_wrfile, wr_rdfile, bad_opt,
    110 
    111 /* 4: OLD TAR */
    112 	"tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op,
    113 	tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, tar_trail,
    114 	rd_wrfile, wr_rdfile, tar_opt,
    115 
    116 /* 5: POSIX USTAR */
    117 	"ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd,
    118 	ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, tar_trail,
    119 	rd_wrfile, wr_rdfile, bad_opt,
    120 };
    121 #define F_TAR	4	/* format when called as tar */
    122 #define DEFLT	5	/* default write format from list above */
    123 
    124 /*
    125  * ford is the archive search order used by get_arc() to determine what kind
    126  * of archive we are dealing with. This helps to properly id  archive formats
    127  * some formats may be subsets of others....
    128  */
    129 int ford[] = {5, 4, 3, 2, 1, 0, -1 };
    130 
    131 /*
    132  * options()
    133  *	figure out if we are pax, tar or cpio. Call the appropriate options
    134  *	parser
    135  */
    136 
    137 #if __STDC__
    138 void
    139 options(register int argc, register char **argv)
    140 #else
    141 void
    142 options(argc, argv)
    143 	register int argc;
    144 	register char **argv;
    145 #endif
    146 {
    147 
    148 	/*
    149 	 * Are we acting like pax, tar or cpio (based on argv[0])
    150 	 */
    151 	if ((argv0 = strrchr(argv[0], '/')) != NULL)
    152 		argv0++;
    153 	else
    154 		argv0 = argv[0];
    155 
    156 	if (strcmp(NM_TAR, argv0) == 0)
    157 		return(tar_options(argc, argv));
    158 #	ifdef notdef
    159 	else if (strcmp(NM_CPIO, argv0) == 0)
    160 		return(cpio_options(argc, argv));
    161 #	endif
    162 	/*
    163 	 * assume pax as the default
    164 	 */
    165 	argv0 = NM_PAX;
    166 	return(pax_options(argc, argv));
    167 }
    168 
    169 /*
    170  * pax_options()
    171  *	look at the user specified flags. set globals as required and check if
    172  *	the user specified a legal set of flags. If not, complain and exit
    173  */
    174 
    175 #if __STDC__
    176 static void
    177 pax_options(register int argc, register char **argv)
    178 #else
    179 static void
    180 pax_options(argc, argv)
    181 	register int argc;
    182 	register char **argv;
    183 #endif
    184 {
    185 	register int c;
    186 	register int i;
    187 	unsigned int flg = 0;
    188 	unsigned int bflg = 0;
    189 	register char *pt;
    190         FSUB tmp;
    191 	extern char *optarg;
    192 	extern int optind;
    193 
    194 	/*
    195 	 * process option flags
    196 	 */
    197 	while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:B:DE:G:HLPT:U:XYZ"))
    198 	    != EOF) {
    199 		switch (c) {
    200 		case 'a':
    201 			/*
    202 			 * append
    203 			 */
    204 			flg |= AF;
    205 			break;
    206 		case 'b':
    207 			/*
    208 			 * specify blocksize
    209 			 */
    210 			flg |= BF;
    211 			if ((wrblksz = (int)str_offt(optarg)) <= 0) {
    212 				warn(1, "Invalid block size %s", optarg);
    213 				pax_usage();
    214 			}
    215 			break;
    216 		case 'c':
    217 			/*
    218 			 * inverse match on patterns
    219 			 */
    220 			cflag = 1;
    221 			flg |= CF;
    222 			break;
    223 		case 'd':
    224 			/*
    225 			 * match only dir on extract, not the subtree at dir
    226 			 */
    227 			dflag = 1;
    228 			flg |= DF;
    229 			break;
    230 		case 'f':
    231 			/*
    232 			 * filename where the archive is stored
    233 			 */
    234 			arcname = optarg;
    235 			flg |= FF;
    236 			break;
    237 		case 'i':
    238 			/*
    239 			 * interactive file rename
    240 			 */
    241 			iflag = 1;
    242 			flg |= IF;
    243 			break;
    244 		case 'k':
    245 			/*
    246 			 * do not clobber files that exist
    247 			 */
    248 			kflag = 1;
    249 			flg |= KF;
    250 			break;
    251 		case 'l':
    252 			/*
    253 			 * try to link src to dest with copy (-rw)
    254 			 */
    255 			lflag = 1;
    256 			flg |= LF;
    257 			break;
    258 		case 'n':
    259 			/*
    260 			 * select first match for a pattern only
    261 			 */
    262 			nflag = 1;
    263 			flg |= NF;
    264 			break;
    265 		case 'o':
    266 			/*
    267 			 * pass format specific options
    268 			 */
    269 			flg |= OF;
    270 			if (opt_add(optarg) < 0)
    271 				pax_usage();
    272 			break;
    273 		case 'p':
    274 			/*
    275 			 * specify file characteristic options
    276 			 */
    277 			for (pt = optarg; *pt != '\0'; ++pt) {
    278 				switch(*pt) {
    279 				case 'a':
    280 					/*
    281 					 * do not preserve access time
    282 					 */
    283 					patime = 0;
    284 					break;
    285 				case 'e':
    286 					/*
    287 					 * preserve user id, group id, file
    288 					 * mode, access/modification times
    289 					 */
    290 					pids = 1;
    291 					pmode = 1;
    292 					patime = 1;
    293 					pmtime = 1;
    294 					break;
    295 				case 'm':
    296 					/*
    297 					 * do not preserve modification time
    298 					 */
    299 					pmtime = 0;
    300 					break;
    301 				case 'o':
    302 					/*
    303 					 * preserve uid/gid
    304 					 */
    305 					pids = 1;
    306 					break;
    307 				case 'p':
    308 					/*
    309 					 * preserver file mode bits
    310 					 */
    311 					pmode = 1;
    312 					break;
    313 				default:
    314 					warn(1, "Invalid -p string: %c", *pt);
    315 					pax_usage();
    316 					break;
    317 				}
    318 			}
    319 			flg |= PF;
    320 			break;
    321 		case 'r':
    322 			/*
    323 			 * read the archive
    324 			 */
    325 			flg |= RF;
    326 			break;
    327 		case 's':
    328 			/*
    329 			 * file name substitution name pattern
    330 			 */
    331 			if (rep_add(optarg) < 0) {
    332 				pax_usage();
    333 				break;
    334 			}
    335 			flg |= SF;
    336 			break;
    337 		case 't':
    338 			/*
    339 			 * preserve access time on filesystem nodes we read
    340 			 */
    341 			tflag = 1;
    342 			flg |= TF;
    343 			break;
    344 		case 'u':
    345 			/*
    346 			 * ignore those older files
    347 			 */
    348 			uflag = 1;
    349 			flg |= UF;
    350 			break;
    351 		case 'v':
    352 			/*
    353 			 * verbose operation mode
    354 			 */
    355 			vflag = 1;
    356 			flg |= VF;
    357 			break;
    358 		case 'w':
    359 			/*
    360 			 * write an archive
    361 			 */
    362 			flg |= WF;
    363 			break;
    364 		case 'x':
    365 			/*
    366 			 * specify an archive format on write
    367 			 */
    368 			tmp.name = optarg;
    369 			if (frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub,
    370 			    sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt)) {
    371 				flg |= XF;
    372 				break;
    373 			}
    374 			warn(1, "Unknown -x format: %s", optarg);
    375 			(void)fputs("pax: Known -x formats are:", stderr);
    376 			for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
    377 				(void)fprintf(stderr, " %s", fsub[i].name);
    378 			(void)fputs("\n\n", stderr);
    379 			pax_usage();
    380 			break;
    381 		case 'B':
    382 			/*
    383 			 * non-standard option on number of bytes written on a
    384 			 * single archive volume.
    385 			 */
    386 			if ((wrlimit = str_offt(optarg)) <= 0) {
    387 				warn(1, "Invalid write limit %s", optarg);
    388 				pax_usage();
    389 			}
    390 			if (wrlimit % BLKMULT) {
    391 				warn(1, "Write limit is not a %d byte multiple",
    392 				    BLKMULT);
    393 				pax_usage();
    394 			}
    395 			flg |= CBF;
    396 			break;
    397 		case 'D':
    398 			/*
    399 			 * On extraction check file inode change time before the
    400 			 * modification of the file name. Non standard option.
    401 			 */
    402 			Dflag = 1;
    403 			flg |= CDF;
    404 			break;
    405 		case 'E':
    406 			/*
    407 			 * non-standard limit on read faults
    408 			 * 0 indicates stop after first error, values
    409 			 * indicate a limit, "NONE" try forever
    410 			 */
    411 			flg |= CEF;
    412 			if (strcmp(NONE, optarg) == 0)
    413 				maxflt = -1;
    414 			else if ((maxflt = atoi(optarg)) < 0) {
    415 				warn(1, "Error count value must be positive");
    416 				pax_usage();
    417 			}
    418 			break;
    419 		case 'G':
    420 			/*
    421 			 * non-standard option for selecting files within an
    422 			 * archive by group (gid or name)
    423 			 */
    424 			if (grp_add(optarg) < 0) {
    425 				pax_usage();
    426 				break;
    427 			}
    428 			flg |= CGF;
    429 			break;
    430 		case 'H':
    431 			/*
    432 			 * follow command line symlinks only
    433 			 */
    434 			Hflag = 1;
    435 			flg |= CHF;
    436 			break;
    437 		case 'L':
    438 			/*
    439 			 * follow symlinks
    440 			 */
    441 			Lflag = 1;
    442 			flg |= CLF;
    443 			break;
    444 		case 'P':
    445 			/*
    446 			 * do NOT follow symlinks (default)
    447 			 */
    448 			Lflag = 0;
    449 			flg |= CPF;
    450 			break;
    451 		case 'T':
    452 			/*
    453 			 * non-standard option for selecting files within an
    454 			 * archive by modification time range (lower,upper)
    455 			 */
    456 			if (trng_add(optarg) < 0) {
    457 				pax_usage();
    458 				break;
    459 			}
    460 			flg |= CTF;
    461 			break;
    462 		case 'U':
    463 			/*
    464 			 * non-standard option for selecting files within an
    465 			 * archive by user (uid or name)
    466 			 */
    467 			if (usr_add(optarg) < 0) {
    468 				pax_usage();
    469 				break;
    470 			}
    471 			flg |= CUF;
    472 			break;
    473 		case 'X':
    474 			/*
    475 			 * do not pass over mount points in the file system
    476 			 */
    477 			Xflag = 1;
    478 			flg |= CXF;
    479 			break;
    480 		case 'Y':
    481 			/*
    482 			 * On extraction check file inode change time after the
    483 			 * modification of the file name. Non standard option.
    484 			 */
    485 			Yflag = 1;
    486 			flg |= CYF;
    487 			break;
    488 		case 'Z':
    489 			/*
    490 			 * On extraction check modification time after the
    491 			 * modification of the file name. Non standard option.
    492 			 */
    493 			Zflag = 1;
    494 			flg |= CZF;
    495 			break;
    496 		case '?':
    497 		default:
    498 			pax_usage();
    499 			break;
    500 		}
    501 	}
    502 
    503 	/*
    504 	 * figure out the operation mode of pax read,write,extract,copy,append
    505 	 * or list. check that we have not been given a bogus set of flags
    506 	 * for the operation mode.
    507 	 */
    508 	if (ISLIST(flg)) {
    509 		act = LIST;
    510 		bflg = flg & BDLIST;
    511 	} else if (ISEXTRACT(flg)) {
    512 		act = EXTRACT;
    513 		bflg = flg & BDEXTR;
    514 	} else if (ISARCHIVE(flg)) {
    515 		act = ARCHIVE;
    516 		bflg = flg & BDARCH;
    517 	} else if (ISAPPND(flg)) {
    518 		act = APPND;
    519 		bflg = flg & BDARCH;
    520 	} else if (ISCOPY(flg)) {
    521 		act = COPY;
    522 		bflg = flg & BDCOPY;
    523 	} else
    524 		pax_usage();
    525 	if (bflg) {
    526 		printflg(flg);
    527 		pax_usage();
    528 	}
    529 
    530 	/*
    531 	 * if we are writing (ARCHIVE) we use the default format if the user
    532 	 * did not specify a format. when we write during an APPEND, we will
    533 	 * adopt the format of the existing archive if none was supplied.
    534 	 */
    535 	if (!(flg & XF) && (act == ARCHIVE))
    536 		frmt = &(fsub[DEFLT]);
    537 
    538 	/*
    539 	 * process the args as they are interpreted by the operation mode
    540 	 */
    541 	switch (act) {
    542 	case LIST:
    543 	case EXTRACT:
    544 		for (; optind < argc; optind++)
    545 			if (pat_add(argv[optind]) < 0)
    546 				pax_usage();
    547 		break;
    548 	case COPY:
    549 		if (optind >= argc) {
    550 			warn(0, "Destination directory was not supplied");
    551 			pax_usage();
    552 		}
    553 		--argc;
    554 		dirptr = argv[argc];
    555 		/* FALL THROUGH */
    556 	case ARCHIVE:
    557 	case APPND:
    558 		for (; optind < argc; optind++)
    559 			if (ftree_add(argv[optind]) < 0)
    560 				pax_usage();
    561 		/*
    562 		 * no read errors allowed on updates/append operation!
    563 		 */
    564 		maxflt = 0;
    565 		break;
    566 	}
    567 }
    568 
    569 
    570 /*
    571  * tar_options()
    572  *	look at the user specified flags. set globals as required and check if
    573  *	the user specified a legal set of flags. If not, complain and exit
    574  */
    575 
    576 #if __STDC__
    577 static void
    578 tar_options(register int argc, register char **argv)
    579 #else
    580 static void
    581 tar_options(argc, argv)
    582 	register int argc;
    583 	register char **argv;
    584 #endif
    585 {
    586 	register char *cp;
    587 	int fstdin = 0;
    588 
    589 	if (argc < 2)
    590 		tar_usage();
    591 	/*
    592 	 * process option flags
    593 	 */
    594 	++argv;
    595 	for (cp = *argv++; *cp != '\0'; ++cp) {
    596 		switch (*cp) {
    597 		case '-':
    598 			/*
    599 			 * skip over -
    600 			 */
    601 			break;
    602 		case 'b':
    603 			/*
    604 			 * specify blocksize
    605 			 */
    606 			if (*argv == (char *)NULL) {
    607 				warn(1,"blocksize must be specified with 'b'");
    608 				tar_usage();
    609 			}
    610 			if ((wrblksz = (int)str_offt(*argv)) <= 0) {
    611 				warn(1, "Invalid block size %s", *argv);
    612 				tar_usage();
    613 			}
    614 			++argv;
    615 			break;
    616 		case 'c':
    617 			/*
    618 			 * create an archive
    619 			 */
    620 			act = ARCHIVE;
    621 			break;
    622 		case 'e':
    623 			/*
    624 			 * stop after first error
    625 			 */
    626 			maxflt = 0;
    627 			break;
    628 		case 'f':
    629 			/*
    630 			 * filename where the archive is stored
    631 			 */
    632 			if (*argv == (char *)NULL) {
    633 				warn(1, "filename must be specified with 'f'");
    634 				tar_usage();
    635 			}
    636 			if ((argv[0][0] == '-') && (argv[0][1]== '\0')) {
    637 				/*
    638 				 * treat a - as stdin
    639 				 */
    640 				++argv;
    641 				++fstdin;
    642 				arcname = (char *)0;
    643 				break;
    644 			}
    645 			fstdin = 0;
    646 			arcname = *argv++;
    647 			break;
    648 		case 'm':
    649 			/*
    650 			 * do not preserve modification time
    651 			 */
    652 			pmtime = 0;
    653 			break;
    654 		case 'o':
    655 			if (opt_add("write_opt=nodir") < 0)
    656 				tar_usage();
    657 			break;
    658 		case 'p':
    659 			/*
    660 			 * preserve user id, group id, file
    661 			 * mode, access/modification times
    662 			 */
    663 			pids = 1;
    664 			pmode = 1;
    665 			patime = 1;
    666 			pmtime = 1;
    667 			break;
    668 		case 'r':
    669 		case 'u':
    670 			/*
    671 			 * append to the archive
    672 			 */
    673 			act = APPND;
    674 			break;
    675 		case 't':
    676 			/*
    677 			 * list contents of the tape
    678 			 */
    679 			act = LIST;
    680 			break;
    681 		case 'v':
    682 			/*
    683 			 * verbose operation mode
    684 			 */
    685 			vflag = 1;
    686 			break;
    687 		case 'w':
    688 			/*
    689 			 * interactive file rename
    690 			 */
    691 			iflag = 1;
    692 			break;
    693 		case 'x':
    694 			/*
    695 			 * write an archive
    696 			 */
    697 			act = EXTRACT;
    698 			break;
    699 		case 'B':
    700 			/*
    701 			 * Nothing to do here, this is pax default
    702 			 */
    703 			break;
    704 		case 'H':
    705 			/*
    706 			 * follow command line symlinks only
    707 			 */
    708 			Hflag = 1;
    709 			break;
    710 		case 'L':
    711 			/*
    712 			 * follow symlinks
    713 			 */
    714 			Lflag = 1;
    715 			break;
    716 		case 'P':
    717 			/*
    718 			 * do not follow symlinks
    719 			 */
    720 			Lflag = 0;
    721 			break;
    722 		case 'X':
    723 			/*
    724 			 * do not pass over mount points in the file system
    725 			 */
    726 			Xflag = 1;
    727 			break;
    728 		case '0':
    729 			arcname = DEV_0;
    730 			break;
    731 		case '1':
    732 			arcname = DEV_1;
    733 			break;
    734 		case '4':
    735 			arcname = DEV_4;
    736 			break;
    737 		case '5':
    738 			arcname = DEV_5;
    739 			break;
    740 		case '7':
    741 			arcname = DEV_7;
    742 			break;
    743 		case '8':
    744 			arcname = DEV_8;
    745 			break;
    746 		default:
    747 			tar_usage();
    748 			break;
    749 		}
    750 	}
    751 
    752 	/*
    753 	 * if we are writing (ARCHIVE) specify tar, otherwise run like pax
    754 	 */
    755 	if (act == ARCHIVE)
    756 		frmt = &(fsub[F_TAR]);
    757 
    758 	/*
    759 	 * process the args as they are interpreted by the operation mode
    760 	 */
    761 	switch (act) {
    762 	case LIST:
    763 	case EXTRACT:
    764 	default:
    765 		while (*argv != (char *)NULL)
    766 			if (pat_add(*argv++) < 0)
    767 				tar_usage();
    768 		break;
    769 	case ARCHIVE:
    770 	case APPND:
    771 		while (*argv != (char *)NULL)
    772 			if (ftree_add(*argv++) < 0)
    773 				tar_usage();
    774 		/*
    775 		 * no read errors allowed on updates/append operation!
    776 		 */
    777 		maxflt = 0;
    778 		break;
    779 	}
    780 	if (!fstdin && ((arcname == (char *)NULL) || (*arcname == '\0'))) {
    781 		arcname = getenv("TAPE");
    782 		if ((arcname == (char *)NULL) || (*arcname == '\0'))
    783 			arcname = DEV_8;
    784 	}
    785 }
    786 
    787 #ifdef notdef
    788 /*
    789  * cpio_options()
    790  *	look at the user specified flags. set globals as required and check if
    791  *	the user specified a legal set of flags. If not, complain and exit
    792  */
    793 
    794 #if __STDC__
    795 static void
    796 cpio_options(register int argc, register char **argv)
    797 #else
    798 static void
    799 cpio_options(argc, argv)
    800 	register int argc;
    801 	register char **argv;
    802 #endif
    803 {
    804 }
    805 #endif
    806 
    807 /*
    808  * printflg()
    809  *	print out those invalid flag sets found to the user
    810  */
    811 
    812 #if __STDC__
    813 static void
    814 printflg(unsigned int flg)
    815 #else
    816 static void
    817 printflg(flg)
    818 	unsigned int flg;
    819 #endif
    820 {
    821 	int nxt;
    822 	int pos = 0;
    823 
    824 	(void)fprintf(stderr,"%s: Invalid combination of options:", argv0);
    825 	while (nxt = ffs(flg)) {
    826 		flg = flg >> nxt;
    827 		pos += nxt;
    828 		(void)fprintf(stderr, " -%c", flgch[pos-1]);
    829 	}
    830 	(void)putc('\n', stderr);
    831 }
    832 
    833 /*
    834  * c_frmt()
    835  *	comparison routine used by bsearch to find the format specified
    836  *	by the user
    837  */
    838 
    839 #if __STDC__
    840 static int
    841 c_frmt(const void *a, const void *b)
    842 #else
    843 static int
    844 c_frmt(a, b)
    845         void *a;
    846         void *b;
    847 #endif
    848 {
    849         return(strcmp(((FSUB *)a)->name, ((FSUB *)b)->name));
    850 }
    851 
    852 /*
    853  * opt_next()
    854  *	called by format specific options routines to get each format specific
    855  *	flag and value specified with -o
    856  * Return:
    857  *	pointer to next OPLIST entry or NULL (end of list).
    858  */
    859 
    860 #if __STDC__
    861 OPLIST *
    862 opt_next(void)
    863 #else
    864 OPLIST *
    865 opt_next()
    866 #endif
    867 {
    868 	OPLIST *opt;
    869 
    870 	if ((opt = ophead) != NULL)
    871 		ophead = ophead->fow;
    872 	return(opt);
    873 }
    874 
    875 /*
    876  * bad_opt()
    877  *	generic routine used to complain about a format specific options
    878  *	when the format does not support options.
    879  */
    880 
    881 #if __STDC__
    882 int
    883 bad_opt(void)
    884 #else
    885 int
    886 bad_opt()
    887 #endif
    888 {
    889 	register OPLIST *opt;
    890 
    891 	if (ophead == NULL)
    892 		return(0);
    893 	/*
    894 	 * print all we were given
    895 	 */
    896 	warn(1,"These format options are not supported");
    897 	while ((opt = opt_next()) != NULL)
    898 		(void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value);
    899 	pax_usage();
    900 	return(0);
    901 }
    902 
    903 /*
    904  * opt_add()
    905  *	breaks the value supplied to -o into a option name and value. options
    906  *	are given to -o in the form -o name-value,name=value
    907  *	mulltiple -o may be specified.
    908  * Return:
    909  *	0 if format in name=value format, -1 if -o is passed junk
    910  */
    911 
    912 #if __STDC__
    913 int
    914 opt_add(register char *str)
    915 #else
    916 int
    917 opt_add(str)
    918 	register char *str;
    919 #endif
    920 {
    921 	register OPLIST *opt;
    922 	register char *frpt;
    923 	register char *pt;
    924 	register char *endpt;
    925 
    926 	if ((str == NULL) || (*str == '\0')) {
    927 		warn(0, "Invalid option name");
    928 		return(-1);
    929 	}
    930 	frpt = endpt = str;
    931 
    932 	/*
    933 	 * break into name and values pieces and stuff each one into a
    934 	 * OPLIST structure. When we know the format, the format specific
    935 	 * option function will go through this list
    936 	 */
    937 	while ((frpt != NULL) && (*frpt != '\0')) {
    938 		if ((endpt = strchr(frpt, ',')) != NULL)
    939 			*endpt = '\0';
    940 		if ((pt = strchr(frpt, '=')) == NULL) {
    941 			warn(0, "Invalid options format");
    942 			return(-1);
    943 		}
    944 		if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) {
    945 			warn(0, "Unable to allocate space for option list");
    946 			return(-1);
    947 		}
    948 		*pt++ = '\0';
    949 		opt->name = frpt;
    950 		opt->value = pt;
    951 		opt->fow = NULL;
    952 		if (endpt != NULL)
    953 			frpt = endpt + 1;
    954 		else
    955 			frpt = NULL;
    956 		if (ophead == NULL) {
    957 			optail = ophead = opt;
    958 			continue;
    959 		}
    960 		optail->fow = opt;
    961 		optail = opt;
    962 	}
    963 	return(0);
    964 }
    965 
    966 /*
    967  * str_offt()
    968  *	Convert an expression of the following forms to an off_t > 0.
    969  * 	1) A positive decimal number.
    970  *	2) A positive decimal number followed by a b (mult by 512).
    971  *	3) A positive decimal number followed by a k (mult by 1024).
    972  *	4) A positive decimal number followed by a m (mult by 512).
    973  *	5) A positive decimal number followed by a w (mult by sizeof int)
    974  *	6) Two or more positive decimal numbers (with/without k,b or w).
    975  *	   seperated by x (also * for backwards compatibility), specifying
    976  *	   the product of the indicated values.
    977  * Return:
    978  *	0 for an error, a positive value o.w.
    979  */
    980 
    981 #if __STDC__
    982 static off_t
    983 str_offt(char *val)
    984 #else
    985 static off_t
    986 str_offt(val)
    987 	char *val;
    988 #endif
    989 {
    990 	char *expr;
    991 	off_t num, t;
    992 
    993 #	ifdef NET2_STAT
    994 	num = strtol(val, &expr, 0);
    995 	if ((num == LONG_MAX) || (num <= 0) || (expr == val))
    996 #	else
    997 	num = strtoq(val, &expr, 0);
    998 	if ((num == QUAD_MAX) || (num <= 0) || (expr == val))
    999 #	endif
   1000 		return(0);
   1001 
   1002 	switch(*expr) {
   1003 	case 'b':
   1004 		t = num;
   1005 		num *= 512;
   1006 		if (t > num)
   1007 			return(0);
   1008 		++expr;
   1009 		break;
   1010 	case 'k':
   1011 		t = num;
   1012 		num *= 1024;
   1013 		if (t > num)
   1014 			return(0);
   1015 		++expr;
   1016 		break;
   1017 	case 'm':
   1018 		t = num;
   1019 		num *= 1048576;
   1020 		if (t > num)
   1021 			return(0);
   1022 		++expr;
   1023 		break;
   1024 	case 'w':
   1025 		t = num;
   1026 		num *= sizeof(int);
   1027 		if (t > num)
   1028 			return(0);
   1029 		++expr;
   1030 		break;
   1031 	}
   1032 
   1033 	switch(*expr) {
   1034 		case '\0':
   1035 			break;
   1036 		case '*':
   1037 		case 'x':
   1038 			t = num;
   1039 			num *= str_offt(expr + 1);
   1040 			if (t > num)
   1041 				return(0);
   1042 			break;
   1043 		default:
   1044 			return(0);
   1045 	}
   1046 	return(num);
   1047 }
   1048 
   1049 /*
   1050  * no_op()
   1051  *	for those option functions where the archive format has nothing to do.
   1052  * Return:
   1053  *	0
   1054  */
   1055 
   1056 #if __STDC__
   1057 static int
   1058 no_op(void)
   1059 #else
   1060 static int
   1061 no_op()
   1062 #endif
   1063 {
   1064 	return(0);
   1065 }
   1066 
   1067 /*
   1068  * pax_usage()
   1069  *	print the usage summary to the user
   1070  */
   1071 
   1072 #if __STDC__
   1073 void
   1074 pax_usage(void)
   1075 #else
   1076 void
   1077 pax_usage()
   1078 #endif
   1079 {
   1080 	(void)fputs("usage: pax [-cdnv] [-E limit] [-f archive] ", stderr);
   1081 	(void)fputs("[-s replstr] ... [-U user] ...", stderr);
   1082 	(void)fputs("\n           [-G group] ... ", stderr);
   1083 	(void)fputs("[-T [from_date][,to_date]] ... ", stderr);
   1084 	(void)fputs("[pattern ...]\n", stderr);
   1085 	(void)fputs("       pax -r [-cdiknuvDYZ] [-E limit] ", stderr);
   1086 	(void)fputs("[-f archive] [-o options] ... \n", stderr);
   1087 	(void)fputs("           [-p string] ... [-s replstr] ... ", stderr);
   1088 	(void)fputs("[-U user] ... [-G group] ...\n           ", stderr);
   1089 	(void)fputs("[-T [from_date][,to_date]] ... ", stderr);
   1090 	(void)fputs(" [pattern ...]\n", stderr);
   1091 	(void)fputs("       pax -w [-dituvHLPX] [-b blocksize] ", stderr);
   1092 	(void)fputs("[ [-a] [-f archive] ] [-x format] \n", stderr);
   1093 	(void)fputs("           [-B bytes] [-s replstr] ... ", stderr);
   1094 	(void)fputs("[-o options] ... [-U user] ...", stderr);
   1095 	(void)fputs("\n           [-G group] ... ", stderr);
   1096 	(void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
   1097 	(void)fputs("[file ...]\n", stderr);
   1098 	(void)fputs("       pax -r -w [-diklntuvDHLPXYZ] ", stderr);
   1099 	(void)fputs("[-p string] ... [-s replstr] ...", stderr);
   1100 	(void)fputs("\n           [-U user] ... [-G group] ... ", stderr);
   1101 	(void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
   1102 	(void)fputs("\n           [file ...] directory\n", stderr);
   1103 	exit(1);
   1104 }
   1105 
   1106 /*
   1107  * tar_usage()
   1108  *	print the usage summary to the user
   1109  */
   1110 
   1111 #if __STDC__
   1112 void
   1113 tar_usage(void)
   1114 #else
   1115 void
   1116 tar_usage()
   1117 #endif
   1118 {
   1119 	(void)fputs("usage: tar -{txru}[cevfbmopwBHLPX014578] [tapefile] ",
   1120 		 stderr);
   1121 	(void)fputs("[blocksize] file1 file2...\n", stderr);
   1122 	exit(1);
   1123 }
   1124 
   1125 #ifdef notdef
   1126 /*
   1127  * cpio_usage()
   1128  *	print the usage summary to the user
   1129  */
   1130 
   1131 #if __STDC__
   1132 void
   1133 cpio_usage(void)
   1134 #else
   1135 void
   1136 cpio_usage()
   1137 #endif
   1138 {
   1139 	exit(1);
   1140 }
   1141 #endif
   1142