xref: /netbsd-src/bin/pax/options.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
1 /*	$NetBSD: options.c,v 1.6 1996/03/26 23:54:18 mrg 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.6 1996/03/26 23:54:18 mrg 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((register int, register char **));
78 static void pax_usage __P((void));
79 static void tar_options __P((register int, register char **));
80 static void tar_usage __P((void));
81 #ifdef notdef
82 static void cpio_options __P((register int, register 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(register int argc, register char **argv)
148 #else
149 void
150 options(argc, argv)
151 	register int argc;
152 	register 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(register int argc, register char **argv)
186 #else
187 static void
188 pax_options(argc, argv)
189 	register int argc;
190 	register char **argv;
191 #endif
192 {
193 	register int c;
194 	register int i;
195 	unsigned int flg = 0;
196 	unsigned int bflg = 0;
197 	register 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(register int argc, register char **argv)
594 #else
595 static void
596 tar_options(argc, argv)
597 	register int argc;
598 	register char **argv;
599 #endif
600 {
601 	register 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(register int argc, register char **argv)
811 #else
812 static void
813 cpio_options(argc, argv)
814 	register int argc;
815 	register 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 	register 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(register char *str)
929 #else
930 int
931 opt_add(str)
932 	register char *str;
933 #endif
934 {
935 	register OPLIST *opt;
936 	register char *frpt;
937 	register char *pt;
938 	register 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