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