options.c revision 1.24 1 /* $NetBSD: options.c,v 1.24 1999/11/01 01:35:59 mrg Exp $ */
2
3 /*-
4 * Copyright (c) 1992 Keith Muller.
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Keith Muller of the University of California, San Diego.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 */
39
40 #include <sys/cdefs.h>
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 4/18/94";
44 #else
45 __RCSID("$NetBSD: options.c,v 1.24 1999/11/01 01:35:59 mrg Exp $");
46 #endif
47 #endif /* not lint */
48
49 #include <sys/types.h>
50 #include <sys/time.h>
51 #include <sys/stat.h>
52 #include <sys/mtio.h>
53 #include <sys/param.h>
54 #include <stdio.h>
55 #include <ctype.h>
56 #include <string.h>
57 #include <unistd.h>
58 #include <stdlib.h>
59 #include <limits.h>
60 #include "pax.h"
61 #include "options.h"
62 #include "cpio.h"
63 #include "tar.h"
64 #include "extern.h"
65
66 /*
67 * Routines which handle command line options
68 */
69
70 int cpio_mode; /* set if we are in cpio mode */
71
72 static int nopids; /* tar mode: suppress "pids" for -p option */
73 static char *flgch = FLGCH; /* list of all possible flags (pax) */
74 static OPLIST *ophead = NULL; /* head for format specific options -x */
75 static OPLIST *optail = NULL; /* option tail */
76 static char *firstminusC; /* first -C argument encountered. */
77
78 static int no_op __P((void));
79 static void printflg __P((unsigned int));
80 static int c_frmt __P((const void *, const void *));
81 static off_t str_offt __P((char *));
82 static void pax_options __P((int, char **));
83 static void pax_usage __P((void));
84 static void tar_options __P((int, char **));
85 static void tar_usage __P((void));
86 static void cpio_options __P((int, char **));
87 static void cpio_usage __P((void));
88
89 static void checkpositionalminusC __P((char ***, int (*)(char *, int)));
90
91 #define GZIP_CMD "gzip" /* command to run as gzip */
92 #define COMPRESS_CMD "compress" /* command to run as compress */
93
94 /*
95 * Format specific routine table - MUST BE IN SORTED ORDER BY NAME
96 * (see pax.h for description of each function)
97 *
98 * name, blksz, hdsz, udev, hlk, blkagn, inhead, id, st_read,
99 * read, end_read, st_write, write, end_write, trail,
100 * rd_data, wr_data, options
101 */
102
103 FSUB fsub[] = {
104 /* 0: OLD BINARY CPIO */
105 { "bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd,
106 bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, NULL,
107 cpio_subtrail, rd_wrfile, wr_rdfile, bad_opt },
108
109 /* 1: OLD OCTAL CHARACTER CPIO */
110 { "cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd,
111 cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, NULL,
112 cpio_subtrail, rd_wrfile, wr_rdfile, bad_opt },
113
114 /* 2: SVR4 HEX CPIO */
115 { "sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd,
116 vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, NULL,
117 cpio_subtrail, rd_wrfile, wr_rdfile, bad_opt },
118
119 /* 3: SVR4 HEX CPIO WITH CRC */
120 { "sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd,
121 vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, NULL,
122 cpio_subtrail, rd_wrfile, wr_rdfile, bad_opt },
123
124 /* 4: OLD TAR */
125 { "tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op,
126 tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, tar_trail,
127 NULL, rd_wrfile, wr_rdfile, tar_opt },
128
129 /* 5: POSIX USTAR */
130 { "ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd,
131 ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, tar_trail,
132 NULL, rd_wrfile, wr_rdfile, bad_opt }
133 };
134 #define F_BCPIO 0 /* old binary cpio format */
135 #define F_CPIO 1 /* old octal character cpio format */
136 #define F_SV4CPIO 2 /* SVR4 hex cpio format */
137 #define F_SV4CRC 3 /* SVR4 hex with crc cpio format */
138 #define F_TAR 4 /* old V7 UNIX tar format */
139 #define F_USTAR 5 /* ustar format */
140 #define DEFLT F_USTAR /* default write format from list above */
141
142 /*
143 * ford is the archive search order used by get_arc() to determine what kind
144 * of archive we are dealing with. This helps to properly id archive formats
145 * some formats may be subsets of others....
146 */
147 int ford[] = {F_USTAR, F_TAR, F_SV4CRC, F_SV4CPIO, F_CPIO, F_BCPIO, -1};
148
149 /*
150 * options()
151 * figure out if we are pax, tar or cpio. Call the appropriate options
152 * parser
153 */
154
155 #if __STDC__
156 void
157 options(int argc, char **argv)
158 #else
159 void
160 options(argc, argv)
161 int argc;
162 char **argv;
163 #endif
164 {
165
166 /*
167 * Are we acting like pax, tar or cpio (based on argv[0])
168 */
169 if ((argv0 = strrchr(argv[0], '/')) != NULL)
170 argv0++;
171 else
172 argv0 = argv[0];
173
174 if (strcmp(NM_TAR, argv0) == 0)
175 tar_options(argc, argv);
176 else if (strcmp(NM_CPIO, argv0) == 0)
177 cpio_options(argc, argv);
178 else {
179 argv0 = NM_PAX;
180 pax_options(argc, argv);
181 }
182 }
183
184 /*
185 * pax_options()
186 * look at the user specified flags. set globals as required and check if
187 * the user specified a legal set of flags. If not, complain and exit
188 */
189
190 #if __STDC__
191 static void
192 pax_options(int argc, char **argv)
193 #else
194 static void
195 pax_options(argc, argv)
196 int argc;
197 char **argv;
198 #endif
199 {
200 int c;
201 int i;
202 unsigned int flg = 0;
203 unsigned int bflg = 0;
204 char *pt;
205 FSUB tmp;
206 extern char *optarg;
207 extern int optind;
208
209 /*
210 * process option flags
211 */
212 while ((c=getopt(argc,argv,"ab:cdf:iklno:p:rs:tuvwx:zAB:DE:G:HLPT:U:XYZ"))
213 != -1) {
214 switch (c) {
215 case 'a':
216 /*
217 * append
218 */
219 flg |= AF;
220 break;
221 case 'b':
222 /*
223 * specify blocksize
224 */
225 flg |= BF;
226 if ((wrblksz = (int)str_offt(optarg)) <= 0) {
227 tty_warn(1, "Invalid block size %s", optarg);
228 pax_usage();
229 }
230 break;
231 case 'c':
232 /*
233 * inverse match on patterns
234 */
235 cflag = 1;
236 flg |= CF;
237 break;
238 case 'd':
239 /*
240 * match only dir on extract, not the subtree at dir
241 */
242 dflag = 1;
243 flg |= DF;
244 break;
245 case 'f':
246 /*
247 * filename where the archive is stored
248 */
249 arcname = optarg;
250 flg |= FF;
251 break;
252 case 'i':
253 /*
254 * interactive file rename
255 */
256 iflag = 1;
257 flg |= IF;
258 break;
259 case 'k':
260 /*
261 * do not clobber files that exist
262 */
263 kflag = 1;
264 flg |= KF;
265 break;
266 case 'l':
267 /*
268 * try to link src to dest with copy (-rw)
269 */
270 lflag = 1;
271 flg |= LF;
272 break;
273 case 'n':
274 /*
275 * select first match for a pattern only
276 */
277 nflag = 1;
278 flg |= NF;
279 break;
280 case 'o':
281 /*
282 * pass format specific options
283 */
284 flg |= OF;
285 if (opt_add(optarg) < 0)
286 pax_usage();
287 break;
288 case 'p':
289 /*
290 * specify file characteristic options
291 */
292 for (pt = optarg; *pt != '\0'; ++pt) {
293 switch(*pt) {
294 case 'a':
295 /*
296 * do not preserve access time
297 */
298 patime = 0;
299 break;
300 case 'e':
301 /*
302 * preserve user id, group id, file
303 * mode, access/modification times
304 * and file flags.
305 */
306 pids = 1;
307 pmode = 1;
308 patime = 1;
309 pmtime = 1;
310 pfflags = 1;
311 break;
312 case 'f':
313 /*
314 * do not preserve file flags
315 */
316 pfflags = 0;
317 break;
318 case 'm':
319 /*
320 * do not preserve modification time
321 */
322 pmtime = 0;
323 break;
324 case 'o':
325 /*
326 * preserve uid/gid
327 */
328 pids = 1;
329 break;
330 case 'p':
331 /*
332 * preserver file mode bits
333 */
334 pmode = 1;
335 break;
336 default:
337 tty_warn(1,
338 "Invalid -p string: %c", *pt);
339 pax_usage();
340 break;
341 }
342 }
343 flg |= PF;
344 break;
345 case 'r':
346 /*
347 * read the archive
348 */
349 flg |= RF;
350 break;
351 case 's':
352 /*
353 * file name substitution name pattern
354 */
355 if (rep_add(optarg) < 0) {
356 pax_usage();
357 break;
358 }
359 flg |= SF;
360 break;
361 case 't':
362 /*
363 * preserve access time on filesystem nodes we read
364 */
365 tflag = 1;
366 flg |= TF;
367 break;
368 case 'u':
369 /*
370 * ignore those older files
371 */
372 uflag = 1;
373 flg |= UF;
374 break;
375 case 'v':
376 /*
377 * verbose operation mode
378 */
379 vflag = 1;
380 flg |= VF;
381 break;
382 case 'w':
383 /*
384 * write an archive
385 */
386 flg |= WF;
387 break;
388 case 'x':
389 /*
390 * specify an archive format on write
391 */
392 tmp.name = optarg;
393 frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub,
394 sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt);
395 if (frmt != NULL) {
396 flg |= XF;
397 break;
398 }
399 tty_warn(1, "Unknown -x format: %s", optarg);
400 (void)fputs("pax: Known -x formats are:", stderr);
401 for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
402 (void)fprintf(stderr, " %s", fsub[i].name);
403 (void)fputs("\n\n", stderr);
404 pax_usage();
405 break;
406 case 'z':
407 /*
408 * use gzip. Non standard option.
409 */
410 zflag = 1;
411 gzip_program = GZIP_CMD;
412 break;
413 case 'A':
414 Aflag = 1;
415 flg |= CAF;
416 break;
417 case 'B':
418 /*
419 * non-standard option on number of bytes written on a
420 * single archive volume.
421 */
422 if ((wrlimit = str_offt(optarg)) <= 0) {
423 tty_warn(1, "Invalid write limit %s", optarg);
424 pax_usage();
425 }
426 if (wrlimit % BLKMULT) {
427 tty_warn(1,
428 "Write limit is not a %d byte multiple",
429 BLKMULT);
430 pax_usage();
431 }
432 flg |= CBF;
433 break;
434 case 'D':
435 /*
436 * On extraction check file inode change time before the
437 * modification of the file name. Non standard option.
438 */
439 Dflag = 1;
440 flg |= CDF;
441 break;
442 case 'E':
443 /*
444 * non-standard limit on read faults
445 * 0 indicates stop after first error, values
446 * indicate a limit, "NONE" try forever
447 */
448 flg |= CEF;
449 if (strcmp(NONE, optarg) == 0)
450 maxflt = -1;
451 else if ((maxflt = atoi(optarg)) < 0) {
452 tty_warn(1,
453 "Error count value must be positive");
454 pax_usage();
455 }
456 break;
457 case 'G':
458 /*
459 * non-standard option for selecting files within an
460 * archive by group (gid or name)
461 */
462 if (grp_add(optarg) < 0) {
463 pax_usage();
464 break;
465 }
466 flg |= CGF;
467 break;
468 case 'H':
469 /*
470 * follow command line symlinks only
471 */
472 Hflag = 1;
473 flg |= CHF;
474 break;
475 case 'L':
476 /*
477 * follow symlinks
478 */
479 Lflag = 1;
480 flg |= CLF;
481 break;
482 case 'P':
483 /*
484 * do NOT follow symlinks (default)
485 */
486 Lflag = 0;
487 flg |= CPF;
488 break;
489 case 'T':
490 /*
491 * non-standard option for selecting files within an
492 * archive by modification time range (lower,upper)
493 */
494 if (trng_add(optarg) < 0) {
495 pax_usage();
496 break;
497 }
498 flg |= CTF;
499 break;
500 case 'U':
501 /*
502 * non-standard option for selecting files within an
503 * archive by user (uid or name)
504 */
505 if (usr_add(optarg) < 0) {
506 pax_usage();
507 break;
508 }
509 flg |= CUF;
510 break;
511 case 'X':
512 /*
513 * do not pass over mount points in the file system
514 */
515 Xflag = 1;
516 flg |= CXF;
517 break;
518 case 'Y':
519 /*
520 * On extraction check file inode change time after the
521 * modification of the file name. Non standard option.
522 */
523 Yflag = 1;
524 flg |= CYF;
525 break;
526 case 'Z':
527 /*
528 * On extraction check modification time after the
529 * modification of the file name. Non standard option.
530 */
531 Zflag = 1;
532 flg |= CZF;
533 break;
534 case '?':
535 default:
536 pax_usage();
537 break;
538 }
539 }
540
541 /*
542 * figure out the operation mode of pax read,write,extract,copy,append
543 * or list. check that we have not been given a bogus set of flags
544 * for the operation mode.
545 */
546 if (ISLIST(flg)) {
547 act = LIST;
548 bflg = flg & BDLIST;
549 } else if (ISEXTRACT(flg)) {
550 act = EXTRACT;
551 bflg = flg & BDEXTR;
552 } else if (ISARCHIVE(flg)) {
553 act = ARCHIVE;
554 bflg = flg & BDARCH;
555 } else if (ISAPPND(flg)) {
556 act = APPND;
557 bflg = flg & BDARCH;
558 } else if (ISCOPY(flg)) {
559 act = COPY;
560 bflg = flg & BDCOPY;
561 } else
562 pax_usage();
563 if (bflg) {
564 printflg(flg);
565 pax_usage();
566 }
567
568 /*
569 * if we are writing (ARCHIVE) we use the default format if the user
570 * did not specify a format. when we write during an APPEND, we will
571 * adopt the format of the existing archive if none was supplied.
572 */
573 if (!(flg & XF) && (act == ARCHIVE))
574 frmt = &(fsub[DEFLT]);
575
576 /*
577 * process the args as they are interpreted by the operation mode
578 */
579 switch (act) {
580 case LIST:
581 case EXTRACT:
582 for (; optind < argc; optind++)
583 if (pat_add(argv[optind], 0) < 0)
584 pax_usage();
585 break;
586 case COPY:
587 if (optind >= argc) {
588 tty_warn(0, "Destination directory was not supplied");
589 pax_usage();
590 }
591 --argc;
592 dirptr = argv[argc];
593 /* FALLTHROUGH */
594 case ARCHIVE:
595 case APPND:
596 for (; optind < argc; optind++)
597 if (ftree_add(argv[optind], 0) < 0)
598 pax_usage();
599 /*
600 * no read errors allowed on updates/append operation!
601 */
602 maxflt = 0;
603 break;
604 }
605 }
606
607
608 /*
609 * tar_options()
610 * look at the user specified flags. set globals as required and check if
611 * the user specified a legal set of flags. If not, complain and exit
612 */
613
614 #if __STDC__
615 static void
616 tar_options(int argc, char **argv)
617 #else
618 static void
619 tar_options(argc, argv)
620 int argc;
621 char **argv;
622 #endif
623 {
624 int c;
625 int fstdin = 0;
626
627 /*
628 * process option flags
629 */
630 while ((c = getoldopt(argc, argv, "b:cef:hlmoprutvwxzBC:LPX:Z014578"))
631 != -1) {
632 switch(c) {
633 case 'b':
634 /*
635 * specify blocksize
636 */
637 if ((wrblksz = (int)str_offt(optarg)) <= 0) {
638 tty_warn(1, "Invalid block size %s", optarg);
639 tar_usage();
640 }
641 break;
642 case 'c':
643 /*
644 * create an archive
645 */
646 act = ARCHIVE;
647 break;
648 case 'C':
649 /*
650 * chdir here before extracting.
651 * do so lazily, in case it's a list
652 */
653 firstminusC = optarg;
654 break;
655 case 'e':
656 /*
657 * stop after first error
658 */
659 maxflt = 0;
660 break;
661 case 'f':
662 /*
663 * filename where the archive is stored
664 */
665 if ((optarg[0] == '-') && (optarg[1]== '\0')) {
666 /*
667 * treat a - as stdin
668 */
669 fstdin = 1;
670 arcname = (char *)0;
671 break;
672 }
673 fstdin = 0;
674 arcname = optarg;
675 break;
676 case 'h':
677 /*
678 * follow command line symlinks only
679 */
680 Hflag = 1;
681 break;
682 case 'l':
683 /*
684 * do not pass over mount points in the file system
685 */
686 Xflag = 1;
687 break;
688 case 'm':
689 /*
690 * do not preserve modification time
691 */
692 pmtime = 0;
693 break;
694 case 'o':
695 /*
696 * This option does several things based on whether
697 * this is a create or extract operation.
698 */
699 if (act == ARCHIVE) {
700 /* 4.2BSD: don't add directory entries. */
701 if (opt_add("write_opt=nodir") < 0)
702 tar_usage();
703
704 /* GNU tar: write V7 format archives. */
705 frmt = &(fsub[F_TAR]);
706 } else {
707 /* SUS: don't preserve owner/group. */
708 pids = 0;
709 nopids = 1;
710 }
711 break;
712 case 'p':
713 /*
714 * preserve user id, group id, file
715 * mode, access/modification times
716 */
717 if (!nopids)
718 pids = 1;
719 pmode = 1;
720 patime = 1;
721 pmtime = 1;
722 break;
723 case 'r':
724 case 'u':
725 /*
726 * append to the archive
727 */
728 act = APPND;
729 break;
730 case 't':
731 /*
732 * list contents of the tape
733 */
734 act = LIST;
735 break;
736 case 'v':
737 /*
738 * verbose operation mode
739 */
740 vflag = 1;
741 break;
742 case 'w':
743 /*
744 * interactive file rename
745 */
746 iflag = 1;
747 break;
748 case 'x':
749 /*
750 * write an archive
751 */
752 act = EXTRACT;
753 break;
754 case 'z':
755 /*
756 * use gzip. Non standard option.
757 */
758 zflag = 1;
759 gzip_program = GZIP_CMD;
760 break;
761 case 'B':
762 /*
763 * Nothing to do here, this is pax default
764 */
765 break;
766 case 'L':
767 /*
768 * follow symlinks
769 */
770 Lflag = 1;
771 break;
772 case 'P':
773 Aflag = 1;
774 break;
775 case 'X':
776 /*
777 * GNU tar compat: exclude the files listed in optarg
778 */
779 if (tar_gnutar_X_compat(optarg) != 0)
780 tar_usage();
781 break;
782 case 'Z':
783 /*
784 * use compress.
785 */
786 zflag = 1;
787 gzip_program = COMPRESS_CMD;
788 break;
789 case '0':
790 arcname = DEV_0;
791 break;
792 case '1':
793 arcname = DEV_1;
794 break;
795 case '4':
796 arcname = DEV_4;
797 break;
798 case '5':
799 arcname = DEV_5;
800 break;
801 case '7':
802 arcname = DEV_7;
803 break;
804 case '8':
805 arcname = DEV_8;
806 break;
807 default:
808 tar_usage();
809 break;
810 }
811 }
812 argc -= optind;
813 argv += optind;
814
815 if (firstminusC && (opt_chdir(firstminusC) < 0))
816 tty_warn(1, "can't remember -C directory");
817
818 /*
819 * if we are writing (ARCHIVE) specify tar, otherwise run like pax
820 */
821 if (act == ARCHIVE && frmt == NULL)
822 frmt = &(fsub[F_USTAR]);
823
824 /*
825 * process the args as they are interpreted by the operation mode
826 */
827 switch (act) {
828 case LIST:
829 default:
830 while (*argv != (char *)NULL)
831 if (pat_add(*argv++, 0) < 0)
832 tar_usage();
833 break;
834 case EXTRACT:
835 checkpositionalminusC(&argv, pat_add);
836 break;
837 case ARCHIVE:
838 case APPND:
839 checkpositionalminusC(&argv, ftree_add);
840 /*
841 * no read errors allowed on updates/append operation!
842 */
843 maxflt = 0;
844 break;
845 }
846 if (!fstdin && ((arcname == (char *)NULL) || (*arcname == '\0'))) {
847 arcname = getenv("TAPE");
848 if ((arcname == (char *)NULL) || (*arcname == '\0'))
849 arcname = DEV_8;
850 }
851 }
852
853 /*
854 * cpio_options()
855 * look at the user specified flags. set globals as required and check if
856 * the user specified a legal set of flags. If not, complain and exit
857 */
858
859 #if __STDC__
860 static void
861 cpio_options(int argc, char **argv)
862 #else
863 static void
864 cpio_options(argc, argv)
865 int argc;
866 char **argv;
867 #endif
868 {
869 FSUB tmp;
870 unsigned int flg = 0;
871 unsigned int bflg = 0;
872 int c, i;
873
874 cpio_mode = uflag = 1;
875 /*
876 * process option flags
877 */
878 while ((c = getoldopt(argc, argv, "ABC:E:H:I:LM:O:R:SVabcdfiklmoprstuv"))
879 != -1) {
880 switch(c) {
881 case 'A':
882 /*
883 * append to an archive
884 */
885 act = APPND;
886 flg |= AF;
887 break;
888 case 'B':
889 /*
890 * set blocksize to 5120
891 */
892 blksz = 5120;
893 break;
894 case 'C':
895 /*
896 * specify blocksize
897 */
898 if ((blksz = (int)str_offt(optarg)) <= 0) {
899 tty_warn(1, "Invalid block size %s", optarg);
900 tar_usage();
901 }
902 break;
903 #ifdef notyet
904 case 'E':
905 arg = optarg;
906 break;
907 #endif
908 case 'H':
909 /*
910 * specify an archive format on write
911 */
912 tmp.name = optarg;
913 frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub,
914 sizeof(fsub)/sizeof(FSUB), sizeof(FSUB), c_frmt);
915 if (frmt != NULL) {
916 flg |= XF;
917 break;
918 }
919 tty_warn(1, "Unknown -H format: %s", optarg);
920 (void)fputs("cpio: Known -H formats are:", stderr);
921 for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
922 (void)fprintf(stderr, " %s", fsub[i].name);
923 (void)fputs("\n\n", stderr);
924 tar_usage();
925 break;
926 case 'I':
927 case 'O':
928 /*
929 * filename where the archive is stored
930 */
931 if ((optarg[0] == '-') && (optarg[1]== '\0')) {
932 /*
933 * treat a - as stdin
934 */
935 arcname = (char *)0;
936 break;
937 }
938 arcname = optarg;
939 break;
940 case 'L':
941 /*
942 * follow symlinks
943 */
944 Lflag = 1;
945 flg |= CLF;
946 break;
947 #ifdef notyet
948 case 'M':
949 arg = optarg;
950 break;
951 case 'R':
952 arg = optarg;
953 break;
954 #endif
955 case 'S':
956 cpio_swp_head = 1;
957 break;
958 #ifdef notyet
959 case 'V':
960 break;
961 #endif
962 case 'a':
963 /*
964 * preserve access time on filesystem nodes we read
965 */
966 tflag = 1;
967 flg |= TF;
968 break;
969 #ifdef notyet
970 case 'b':
971 break;
972 #endif
973 case 'c':
974 frmt = &fsub[F_SV4CPIO];
975 break;
976 case 'd':
977 /*
978 * pax does this by default ..
979 */
980 flg |= RF;
981 break;
982 case 'f':
983 /*
984 * inverse match on patterns
985 */
986 cflag = 1;
987 flg |= CF;
988 break;
989 case 'i':
990 /*
991 * read the archive
992 */
993 flg |= RF;
994 break;
995 #ifdef notyet
996 case 'k':
997 break;
998 #endif
999 case 'l':
1000 /*
1001 * try to link src to dest with copy (-rw)
1002 */
1003 lflag = 1;
1004 flg |= LF;
1005 break;
1006 case 'm':
1007 /*
1008 * preserve mtime
1009 */
1010 flg |= PF;
1011 pmtime = 1;
1012 break;
1013 case 'o':
1014 /*
1015 * write an archive
1016 */
1017 flg |= WF;
1018 break;
1019 case 'p':
1020 /*
1021 * cpio -p is like pax -rw
1022 */
1023 flg |= RF | WF;
1024 break;
1025 case 'r':
1026 /*
1027 * interactive file rename
1028 */
1029 iflag = 1;
1030 flg |= IF;
1031 break;
1032 #ifdef notyet
1033 case 's':
1034 break;
1035 #endif
1036 case 't':
1037 act = LIST;
1038 break;
1039 case 'u':
1040 /*
1041 * don't ignore those older files
1042 */
1043 uflag = 0;
1044 flg |= UF;
1045 break;
1046 case 'v':
1047 /*
1048 * verbose operation mode
1049 */
1050 vflag = 1;
1051 flg |= VF;
1052 break;
1053 default:
1054 cpio_usage();
1055 break;
1056 }
1057 }
1058
1059 /*
1060 * figure out the operation mode of cpio. check that we have not been
1061 * given a bogus set of flags for the operation mode.
1062 */
1063 if (ISLIST(flg)) {
1064 act = LIST;
1065 bflg = flg & BDLIST;
1066 } else if (ISEXTRACT(flg)) {
1067 act = EXTRACT;
1068 bflg = flg & BDEXTR;
1069 } else if (ISARCHIVE(flg)) {
1070 act = ARCHIVE;
1071 bflg = flg & BDARCH;
1072 } else if (ISAPPND(flg)) {
1073 act = APPND;
1074 bflg = flg & BDARCH;
1075 } else if (ISCOPY(flg)) {
1076 act = COPY;
1077 bflg = flg & BDCOPY;
1078 } else
1079 cpio_usage();
1080 if (bflg) {
1081 cpio_usage();
1082 }
1083
1084 /*
1085 * if we are writing (ARCHIVE) we use the default format if the user
1086 * did not specify a format. when we write during an APPEND, we will
1087 * adopt the format of the existing archive if none was supplied.
1088 */
1089 if (!(flg & XF) && (act == ARCHIVE))
1090 frmt = &(fsub[F_BCPIO]);
1091
1092 /*
1093 * process the args as they are interpreted by the operation mode
1094 */
1095 switch (act) {
1096 case LIST:
1097 case EXTRACT:
1098 for (; optind < argc; optind++)
1099 if (pat_add(argv[optind], 0) < 0)
1100 cpio_usage();
1101 break;
1102 case COPY:
1103 if (optind >= argc) {
1104 tty_warn(0, "Destination directory was not supplied");
1105 cpio_usage();
1106 }
1107 --argc;
1108 dirptr = argv[argc];
1109 /* FALLTHROUGH */
1110 case ARCHIVE:
1111 case APPND:
1112 for (; optind < argc; optind++)
1113 if (ftree_add(argv[optind], 0) < 0)
1114 cpio_usage();
1115 /*
1116 * no read errors allowed on updates/append operation!
1117 */
1118 maxflt = 0;
1119 break;
1120 }
1121 }
1122
1123 /*
1124 * printflg()
1125 * print out those invalid flag sets found to the user
1126 */
1127
1128 #if __STDC__
1129 static void
1130 printflg(unsigned int flg)
1131 #else
1132 static void
1133 printflg(flg)
1134 unsigned int flg;
1135 #endif
1136 {
1137 int nxt;
1138 int pos = 0;
1139
1140 (void)fprintf(stderr,"%s: Invalid combination of options:", argv0);
1141 while ((nxt = ffs(flg)) != 0) {
1142 flg = flg >> nxt;
1143 pos += nxt;
1144 (void)fprintf(stderr, " -%c", flgch[pos-1]);
1145 }
1146 (void)putc('\n', stderr);
1147 }
1148
1149 /*
1150 * c_frmt()
1151 * comparison routine used by bsearch to find the format specified
1152 * by the user
1153 */
1154
1155 #if __STDC__
1156 static int
1157 c_frmt(const void *a, const void *b)
1158 #else
1159 static int
1160 c_frmt(a, b)
1161 void *a;
1162 void *b;
1163 #endif
1164 {
1165 return(strcmp(((FSUB *)a)->name, ((FSUB *)b)->name));
1166 }
1167
1168 /*
1169 * opt_next()
1170 * called by format specific options routines to get each format specific
1171 * flag and value specified with -o
1172 * Return:
1173 * pointer to next OPLIST entry or NULL (end of list).
1174 */
1175
1176 #if __STDC__
1177 OPLIST *
1178 opt_next(void)
1179 #else
1180 OPLIST *
1181 opt_next()
1182 #endif
1183 {
1184 OPLIST *opt;
1185
1186 if ((opt = ophead) != NULL)
1187 ophead = ophead->fow;
1188 return(opt);
1189 }
1190
1191 /*
1192 * bad_opt()
1193 * generic routine used to complain about a format specific options
1194 * when the format does not support options.
1195 */
1196
1197 #if __STDC__
1198 int
1199 bad_opt(void)
1200 #else
1201 int
1202 bad_opt()
1203 #endif
1204 {
1205 OPLIST *opt;
1206
1207 if (ophead == NULL)
1208 return(0);
1209 /*
1210 * print all we were given
1211 */
1212 tty_warn(1,"These format options are not supported");
1213 while ((opt = opt_next()) != NULL)
1214 (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value);
1215 pax_usage();
1216 return(0);
1217 }
1218
1219 /*
1220 * opt_add()
1221 * breaks the value supplied to -o into a option name and value. options
1222 * are given to -o in the form -o name-value,name=value
1223 * mulltiple -o may be specified.
1224 * Return:
1225 * 0 if format in name=value format, -1 if -o is passed junk
1226 */
1227
1228 #if __STDC__
1229 int
1230 opt_add(const char *str)
1231 #else
1232 int
1233 opt_add(str)
1234 const char *str;
1235 #endif
1236 {
1237 OPLIST *opt;
1238 char *frpt;
1239 char *pt;
1240 char *endpt;
1241
1242 if ((str == NULL) || (*str == '\0')) {
1243 tty_warn(0, "Invalid option name");
1244 return(-1);
1245 }
1246 frpt = endpt = strdup(str);
1247
1248 /*
1249 * break into name and values pieces and stuff each one into a
1250 * OPLIST structure. When we know the format, the format specific
1251 * option function will go through this list
1252 */
1253 while ((frpt != NULL) && (*frpt != '\0')) {
1254 if ((endpt = strchr(frpt, ',')) != NULL)
1255 *endpt = '\0';
1256 if ((pt = strchr(frpt, '=')) == NULL) {
1257 tty_warn(0, "Invalid options format");
1258 return(-1);
1259 }
1260 if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) {
1261 tty_warn(0, "Unable to allocate space for option list");
1262 return(-1);
1263 }
1264 *pt++ = '\0';
1265 opt->name = frpt;
1266 opt->value = pt;
1267 opt->fow = NULL;
1268 if (endpt != NULL)
1269 frpt = endpt + 1;
1270 else
1271 frpt = NULL;
1272 if (ophead == NULL) {
1273 optail = ophead = opt;
1274 continue;
1275 }
1276 optail->fow = opt;
1277 optail = opt;
1278 }
1279 return(0);
1280 }
1281
1282 /*
1283 * str_offt()
1284 * Convert an expression of the following forms to an off_t > 0.
1285 * 1) A positive decimal number.
1286 * 2) A positive decimal number followed by a b (mult by 512).
1287 * 3) A positive decimal number followed by a k (mult by 1024).
1288 * 4) A positive decimal number followed by a m (mult by 512).
1289 * 5) A positive decimal number followed by a w (mult by sizeof int)
1290 * 6) Two or more positive decimal numbers (with/without k,b or w).
1291 * seperated by x (also * for backwards compatibility), specifying
1292 * the product of the indicated values.
1293 * Return:
1294 * 0 for an error, a positive value o.w.
1295 */
1296
1297 #if __STDC__
1298 static off_t
1299 str_offt(char *val)
1300 #else
1301 static off_t
1302 str_offt(val)
1303 char *val;
1304 #endif
1305 {
1306 char *expr;
1307 off_t num, t;
1308
1309 # ifdef NET2_STAT
1310 num = strtol(val, &expr, 0);
1311 if ((num == LONG_MAX) || (num <= 0) || (expr == val))
1312 # else
1313 num = strtoq(val, &expr, 0);
1314 if ((num == QUAD_MAX) || (num <= 0) || (expr == val))
1315 # endif
1316 return(0);
1317
1318 switch(*expr) {
1319 case 'b':
1320 t = num;
1321 num *= 512;
1322 if (t > num)
1323 return(0);
1324 ++expr;
1325 break;
1326 case 'k':
1327 t = num;
1328 num *= 1024;
1329 if (t > num)
1330 return(0);
1331 ++expr;
1332 break;
1333 case 'm':
1334 t = num;
1335 num *= 1048576;
1336 if (t > num)
1337 return(0);
1338 ++expr;
1339 break;
1340 case 'w':
1341 t = num;
1342 num *= sizeof(int);
1343 if (t > num)
1344 return(0);
1345 ++expr;
1346 break;
1347 }
1348
1349 switch(*expr) {
1350 case '\0':
1351 break;
1352 case '*':
1353 case 'x':
1354 t = num;
1355 num *= str_offt(expr + 1);
1356 if (t > num)
1357 return(0);
1358 break;
1359 default:
1360 return(0);
1361 }
1362 return(num);
1363 }
1364
1365 /*
1366 * no_op()
1367 * for those option functions where the archive format has nothing to do.
1368 * Return:
1369 * 0
1370 */
1371
1372 #if __STDC__
1373 static int
1374 no_op(void)
1375 #else
1376 static int
1377 no_op()
1378 #endif
1379 {
1380 return(0);
1381 }
1382
1383 /*
1384 * pax_usage()
1385 * print the usage summary to the user
1386 */
1387
1388 #if __STDC__
1389 void
1390 pax_usage(void)
1391 #else
1392 void
1393 pax_usage()
1394 #endif
1395 {
1396 (void)fputs("usage: pax [-cdnvz] [-E limit] [-f archive] ", stderr);
1397 (void)fputs("[-s replstr] ... [-U user] ...", stderr);
1398 (void)fputs("\n [-G group] ... ", stderr);
1399 (void)fputs("[-T [from_date][,to_date]] ... ", stderr);
1400 (void)fputs("[pattern ...]\n", stderr);
1401 (void)fputs(" pax -r [-cdiknuvzDYZ] [-E limit] ", stderr);
1402 (void)fputs("[-f archive] [-o options] ... \n", stderr);
1403 (void)fputs(" [-p string] ... [-s replstr] ... ", stderr);
1404 (void)fputs("[-U user] ... [-G group] ...\n ", stderr);
1405 (void)fputs("[-T [from_date][,to_date]] ... ", stderr);
1406 (void)fputs(" [pattern ...]\n", stderr);
1407 (void)fputs(" pax -w [-dituvzHLPX] [-b blocksize] ", stderr);
1408 (void)fputs("[[-a] [-f archive]] [-x format] \n", stderr);
1409 (void)fputs(" [-B bytes] [-o options] ... ", stderr);
1410 (void)fputs("[-s replstr] ... [-U user] ...", stderr);
1411 (void)fputs("\n [-G group] ... ", stderr);
1412 (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
1413 (void)fputs("[file ...]\n", stderr);
1414 (void)fputs(" pax -r -w [-diklntuvzDHLPXYZ] ", stderr);
1415 (void)fputs("[-p string] ... [-s replstr] ...", stderr);
1416 (void)fputs("\n [-U user] ... [-G group] ... ", stderr);
1417 (void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
1418 (void)fputs("\n [file ...] directory\n", stderr);
1419 exit(1);
1420 /* NOTREACHED */
1421 }
1422
1423 /*
1424 * tar_usage()
1425 * print the usage summary to the user
1426 */
1427
1428 #if __STDC__
1429 void
1430 tar_usage(void)
1431 #else
1432 void
1433 tar_usage()
1434 #endif
1435 {
1436 (void)fputs("usage: tar -{txru}[cevfbhlmopwBLPX014578] [tapefile] ",
1437 stderr);
1438 (void)fputs("[blocksize] [exclude-file] file1 file2...\n", stderr);
1439 exit(1);
1440 /* NOTREACHED */
1441 }
1442
1443 /*
1444 * cpio_usage()
1445 * print the usage summary to the user
1446 */
1447
1448 #if __STDC__
1449 void
1450 cpio_usage(void)
1451 #else
1452 void
1453 cpio_usage()
1454 #endif
1455 {
1456
1457 #if 1
1458 (void)fputs(
1459 "usage: cpio -i [-BcdfmrStuv] [ -C blksize ] [ -H header ]\n",
1460 stderr);
1461 (void)fputs(" [ -I file ] [ pattern ... ]\n", stderr);
1462 (void)fputs("usage: cpio -o [-aABcLv] [ -C bufsize ] [ -H header ]\n",
1463 stderr);
1464 (void)fputs(" [ -O file ]\n", stderr);
1465 (void)fputs("usage: cpio -p [ adlLmuv ] directory\n", stderr);
1466 #else
1467 /* no E, M, R, V, b, k or s */
1468 (void)fputs("usage: cpio -i [-bBcdfkmrsStuvV] [ -C bufsize ]\n", stderr);
1469 (void)fputs(" [ -E file ] [ -H header ] [ -I file [ -M message ] ]\n",
1470 stderr);
1471 (void)fputs(" [ -R id ] [ pattern ... ]\n", stderr);
1472 (void)fputs("usage: cpio -o [-aABcLvV] [ -C bufsize ] [ -H header ]\n",
1473 stderr);
1474 (void)fputs(" [ -O file [ -M message ] ]\n", stderr);
1475 (void)fputs("usage: cpio -p [ adlLmuvV ] [ -R id ] directory\n", stderr);
1476 #endif
1477 exit(1);
1478 /* NOTREACHED */
1479 }
1480
1481 /*
1482 * opt_chdir
1483 * call ftree_add or pat_add, depending on archive type.
1484 *
1485 * Returns: -1 for listing, else what ftree_add or pat_add returned.
1486 */
1487
1488 #ifdef __STDC__
1489 int
1490 opt_chdir(char *name)
1491 #else
1492 int
1493 opt_chdir(name)
1494 char *name;
1495 #endif
1496 {
1497 switch (act) {
1498 default:
1499 return (-1);
1500 break;
1501 case ARCHIVE:
1502 case APPND:
1503 return (ftree_add(name, 1));
1504 break;
1505 case EXTRACT:
1506 return (pat_add(name, 1));
1507 break;
1508 }
1509 }
1510
1511 /*
1512 * checkpositionalminusC(argvp, addfunc)
1513 */
1514
1515 #ifdef __STDC__
1516 void
1517 checkpositionalminusC(char ***argvp, int (*addfunc)(char *, int))
1518 #else
1519 void
1520 checkpositionalminusC(argvp, addfunc)
1521 char ***argvp;
1522 int (*addfunc)();
1523 #endif
1524 {
1525 while (**argvp != (char *)NULL) {
1526 if (!strcmp(**argvp, "-C")) {
1527 /* XXX should be allow for positional -C/dir, too? */
1528 if ((*addfunc)(*++*argvp, 1) < 0) {
1529 tar_usage();
1530 }
1531 ++*argvp;
1532 continue;
1533 }
1534 if ((*addfunc)(*(*argvp)++, 0) < 0)
1535 tar_usage();
1536 }
1537 }
1538