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