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