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