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