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