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