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