options.c revision 1556
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
39static 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
63static char flgch[] = FLGCH;	/* list of all possible flags */
64static OPLIST *ophead = NULL;	/* head for format specific options -x */
65static OPLIST *optail = NULL;	/* option tail */
66
67static int no_op __P((void));
68static void printflg __P((unsigned int));
69static int c_frmt __P((const void *, const void *));
70static off_t str_offt __P((char *));
71static void pax_options __P((register int, register char **));
72static void pax_usage __P((void));
73static void tar_options __P((register int, register char **));
74static void tar_usage __P((void));
75#ifdef notdef
76static void cpio_options __P((register int, register char **));
77static 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
89FSUB 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 */
128int 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__
137void
138options(register int argc, register char **argv)
139#else
140void
141options(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__
175static void
176pax_options(register int argc, register char **argv)
177#else
178static void
179pax_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__
576static void
577tar_options(register int argc, register char **argv)
578#else
579static void
580tar_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__
794static void
795cpio_options(register int argc, register char **argv)
796#else
797static void
798cpio_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__
812static void
813printflg(unsigned int flg)
814#else
815static void
816printflg(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__
839static int
840c_frmt(const void *a, const void *b)
841#else
842static int
843c_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__
860OPLIST *
861opt_next(void)
862#else
863OPLIST *
864opt_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__
881int
882bad_opt(void)
883#else
884int
885bad_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__
912int
913opt_add(register char *str)
914#else
915int
916opt_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__
981static off_t
982str_offt(char *val)
983#else
984static off_t
985str_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__
1056static int
1057no_op(void)
1058#else
1059static int
1060no_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__
1072void
1073pax_usage(void)
1074#else
1075void
1076pax_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__
1111void
1112tar_usage(void)
1113#else
1114void
1115tar_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__
1131void
1132cpio_usage(void)
1133#else
1134void
1135cpio_usage()
1136#endif
1137{
1138	exit(1);
1139}
1140#endif
1141