1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2003-2008 Tim Kientzle 5 * All rights reserved. 6 */ 7 8 #include "bsdtar_platform.h" 9 10 #ifdef HAVE_LIMITS_H 11 #include <limits.h> 12 #endif 13 #ifdef HAVE_SYS_PARAM_H 14 #include <sys/param.h> 15 #endif 16 #ifdef HAVE_SYS_STAT_H 17 #include <sys/stat.h> 18 #endif 19 #ifdef HAVE_COPYFILE_H 20 #include <copyfile.h> 21 #endif 22 #ifdef HAVE_ERRNO_H 23 #include <errno.h> 24 #endif 25 #ifdef HAVE_FCNTL_H 26 #include <fcntl.h> 27 #endif 28 #ifdef HAVE_LANGINFO_H 29 #include <langinfo.h> 30 #endif 31 #ifdef HAVE_LIMITS_H 32 #include <limits.h> 33 #endif 34 #ifdef HAVE_LOCALE_H 35 #include <locale.h> 36 #endif 37 #ifdef HAVE_PATHS_H 38 #include <paths.h> 39 #endif 40 #ifdef HAVE_SIGNAL_H 41 #include <signal.h> 42 #endif 43 #include <stdio.h> 44 #ifdef HAVE_STDLIB_H 45 #include <stdlib.h> 46 #endif 47 #ifdef HAVE_STRING_H 48 #include <string.h> 49 #endif 50 #ifdef HAVE_TIME_H 51 #include <time.h> 52 #endif 53 #ifdef HAVE_UNISTD_H 54 #include <unistd.h> 55 #endif 56 57 #include "bsdtar.h" 58 #include "lafe_err.h" 59 60 #if ARCHIVE_VERSION_NUMBER < 4000000 && !defined(_PATH_DEFTAPE) 61 // Libarchive 4.0 and later will NOT define _PATH_DEFTAPE 62 // but will honor it if it's set in the build. 63 // Until then, we'll continue to set it by default on certain platforms: 64 #if defined(__linux) 65 #define _PATH_DEFTAPE "/dev/st0" 66 #elif defined(_WIN32) && !defined(__CYGWIN__) 67 #define _PATH_DEFTAPE "\\\\.\\tape0" 68 #elif !defined(__APPLE__) 69 #define _PATH_DEFTAPE "/dev/tape" 70 #endif 71 #endif 72 73 #define _PATH_STDIO "-" 74 75 #ifdef __MINGW32__ 76 int _CRT_glob = 0; /* Disable broken CRT globbing. */ 77 #endif 78 79 #if defined(HAVE_SIGACTION) && (defined(SIGINFO) || defined(SIGUSR1)) 80 static volatile int siginfo_occurred; 81 82 static void 83 siginfo_handler(int sig) 84 { 85 (void)sig; /* UNUSED */ 86 siginfo_occurred = 1; 87 } 88 89 int 90 need_report(void) 91 { 92 int r = siginfo_occurred; 93 siginfo_occurred = 0; 94 return (r); 95 } 96 #else 97 int 98 need_report(void) 99 { 100 return (0); 101 } 102 #endif 103 104 static __LA_NORETURN void long_help(void); 105 static void only_mode(struct bsdtar *, const char *opt, 106 const char *valid); 107 static void set_mode(struct bsdtar *, int opt); 108 static __LA_NORETURN void version(void); 109 110 /* A basic set of security flags to request from libarchive. */ 111 #define SECURITY \ 112 (ARCHIVE_EXTRACT_SECURE_SYMLINKS \ 113 | ARCHIVE_EXTRACT_SECURE_NODOTDOT) 114 115 static char const * const vcs_files[] = { 116 /* CVS */ 117 "CVS", ".cvsignore", 118 /* RCS */ 119 "RCS", 120 /* SCCS */ 121 "SCCS", 122 /* SVN */ 123 ".svn", 124 /* git */ 125 ".git", ".gitignore", ".gitattributes", ".gitmodules", 126 /* Arch */ 127 ".arch-ids", "{arch}", "=RELEASE-ID", "=meta-update", "=update", 128 /* Bazaar */ 129 ".bzr", ".bzrignore", ".bzrtags", 130 /* Mercurial */ 131 ".hg", ".hgignore", ".hgtags", 132 /* darcs */ 133 "_darcs", 134 NULL 135 }; 136 137 int 138 main(int argc, char **argv) 139 { 140 struct bsdtar *bsdtar, bsdtar_storage; 141 int opt, t; 142 int compression, compression2; 143 const char *compression_name, *compression2_name; 144 const char *compress_program; 145 char *tptr, *uptr; 146 char possible_help_request; 147 char buff[16]; 148 long l; 149 time_t now; 150 151 /* 152 * Use a pointer for consistency, but stack-allocated storage 153 * for ease of cleanup. 154 */ 155 bsdtar = &bsdtar_storage; 156 memset(bsdtar, 0, sizeof(*bsdtar)); 157 bsdtar->fd = -1; /* Mark as "unused" */ 158 bsdtar->gid = -1; 159 bsdtar->uid = -1; 160 bsdtar->flags = 0; 161 compression = compression2 = '\0'; 162 compression_name = compression2_name = NULL; 163 compress_program = NULL; 164 time(&now); 165 166 #if defined(HAVE_SIGACTION) 167 { /* Set up signal handling. */ 168 struct sigaction sa; 169 sa.sa_handler = siginfo_handler; 170 sigemptyset(&sa.sa_mask); 171 sa.sa_flags = 0; 172 #ifdef SIGINFO 173 if (sigaction(SIGINFO, &sa, NULL)) 174 lafe_errc(1, errno, "sigaction(SIGINFO) failed"); 175 #endif 176 #ifdef SIGUSR1 177 /* ... and treat SIGUSR1 the same way as SIGINFO. */ 178 if (sigaction(SIGUSR1, &sa, NULL)) 179 lafe_errc(1, errno, "sigaction(SIGUSR1) failed"); 180 #endif 181 #ifdef SIGPIPE 182 /* Ignore SIGPIPE signals. */ 183 sa.sa_handler = SIG_IGN; 184 sigaction(SIGPIPE, &sa, NULL); 185 #endif 186 #ifdef SIGCHLD 187 /* Do not ignore SIGCHLD. */ 188 sa.sa_handler = SIG_DFL; 189 sigaction(SIGCHLD, &sa, NULL); 190 #endif 191 } 192 #endif 193 194 /* Set lafe_progname before calling lafe_warnc. */ 195 lafe_setprogname(*argv, "bsdtar"); 196 197 #if HAVE_SETLOCALE 198 if (setlocale(LC_ALL, "") == NULL) 199 lafe_warnc(0, "Failed to set default locale"); 200 #endif 201 #if defined(HAVE_NL_LANGINFO) && defined(HAVE_D_MD_ORDER) 202 bsdtar->day_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 203 #endif 204 possible_help_request = 0; 205 206 /* Look up uid of current user for future reference */ 207 bsdtar->user_uid = geteuid(); 208 209 /* Default: open tape drive. */ 210 bsdtar->filename = getenv("TAPE"); 211 #if defined(_PATH_DEFTAPE) 212 if (bsdtar->filename == NULL) { 213 #if defined(_WIN32) && !defined(__CYGWIN__) 214 int tapeExists = !_access(_PATH_DEFTAPE, 0); 215 #else 216 int tapeExists = !access(_PATH_DEFTAPE, F_OK); 217 #endif 218 if (tapeExists) { 219 bsdtar->filename = _PATH_DEFTAPE; 220 } 221 } 222 #endif 223 if (bsdtar->filename == NULL) { 224 bsdtar->filename = _PATH_STDIO; 225 } 226 227 /* Default block size settings. */ 228 bsdtar->bytes_per_block = DEFAULT_BYTES_PER_BLOCK; 229 /* Allow library to default this unless user specifies -b. */ 230 bsdtar->bytes_in_last_block = -1; 231 232 /* Default: preserve mod time on extract */ 233 bsdtar->extract_flags = ARCHIVE_EXTRACT_TIME; 234 235 /* Default: Perform basic security checks. */ 236 bsdtar->extract_flags |= SECURITY; 237 238 /* Default: Extract atomically if possible */ 239 bsdtar->extract_flags |= ARCHIVE_EXTRACT_SAFE_WRITES; 240 241 #ifndef _WIN32 242 /* On POSIX systems, assume --same-owner and -p when run by 243 * the root user. This doesn't make any sense on Windows. */ 244 if (bsdtar->user_uid == 0) { 245 /* --same-owner */ 246 bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER; 247 /* -p */ 248 bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; 249 bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; 250 bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; 251 bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; 252 bsdtar->extract_flags |= ARCHIVE_EXTRACT_MAC_METADATA; 253 } 254 #endif 255 256 /* 257 * Enable Mac OS "copyfile()" extension by default. 258 * This has no effect on other platforms. 259 */ 260 bsdtar->readdisk_flags |= ARCHIVE_READDISK_MAC_COPYFILE; 261 #ifdef COPYFILE_DISABLE_VAR 262 if (getenv(COPYFILE_DISABLE_VAR)) 263 bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE; 264 #endif 265 #if defined(__APPLE__) 266 /* 267 * On Mac OS ACLs are archived with copyfile() (--mac-metadata) 268 * Translation to NFSv4 ACLs has to be requested explicitly with --acls 269 */ 270 bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_ACL; 271 #endif 272 273 bsdtar->matching = archive_match_new(); 274 if (bsdtar->matching == NULL) 275 lafe_errc(1, errno, "Out of memory"); 276 bsdtar->cset = cset_new(); 277 if (bsdtar->cset == NULL) 278 lafe_errc(1, errno, "Out of memory"); 279 280 bsdtar->argv = argv; 281 bsdtar->argc = argc; 282 283 /* 284 * Comments following each option indicate where that option 285 * originated: SUSv2, POSIX, GNU tar, star, etc. If there's 286 * no such comment, then I don't know of anyone else who 287 * implements that option. 288 */ 289 while ((opt = bsdtar_getopt(bsdtar)) != -1) { 290 switch (opt) { 291 case 'a': /* GNU tar */ 292 bsdtar->flags |= OPTFLAG_AUTO_COMPRESS; 293 break; 294 case OPTION_ACLS: /* GNU tar */ 295 bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; 296 bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_NO_ACL; 297 bsdtar->flags |= OPTFLAG_ACLS; 298 break; 299 case 'B': /* GNU tar */ 300 /* libarchive doesn't need this; just ignore it. */ 301 break; 302 case 'b': /* SUSv2 */ 303 tptr = NULL; 304 l = strtol(bsdtar->argument, &tptr, 10); 305 if (l <= 0 || l > 8192L || 306 *(bsdtar->argument) == '\0' || tptr == NULL || 307 *tptr != '\0') { 308 lafe_errc(1, 0, "Invalid or out of range " 309 "(1..8192) argument to -b"); 310 } 311 bsdtar->bytes_per_block = 512 * (int)l; 312 /* Explicit -b forces last block size. */ 313 bsdtar->bytes_in_last_block = bsdtar->bytes_per_block; 314 break; 315 case OPTION_B64ENCODE: 316 if (compression2 != '\0') 317 lafe_errc(1, 0, 318 "Can't specify both --uuencode and " 319 "--b64encode"); 320 compression2 = opt; 321 compression2_name = "b64encode"; 322 break; 323 case 'C': /* GNU tar */ 324 if (strlen(bsdtar->argument) == 0) 325 lafe_errc(1, 0, 326 "Meaningless option: -C ''"); 327 328 set_chdir(bsdtar, bsdtar->argument); 329 break; 330 case 'c': /* SUSv2 */ 331 set_mode(bsdtar, opt); 332 break; 333 case OPTION_CHECK_LINKS: /* GNU tar */ 334 bsdtar->flags |= OPTFLAG_WARN_LINKS; 335 break; 336 case OPTION_CHROOT: /* NetBSD */ 337 bsdtar->flags |= OPTFLAG_CHROOT; 338 break; 339 case OPTION_CLEAR_NOCHANGE_FFLAGS: 340 bsdtar->extract_flags |= 341 ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS; 342 break; 343 case OPTION_EXCLUDE: /* GNU tar */ 344 if (archive_match_exclude_pattern( 345 bsdtar->matching, bsdtar->argument) != ARCHIVE_OK) 346 lafe_errc(1, 0, 347 "Couldn't exclude %s", bsdtar->argument); 348 break; 349 case OPTION_EXCLUDE_VCS: /* GNU tar */ 350 for(t=0; vcs_files[t]; t++) { 351 if (archive_match_exclude_pattern( 352 bsdtar->matching, 353 vcs_files[t]) != ARCHIVE_OK) 354 lafe_errc(1, 0, "Couldn't " 355 "exclude %s", vcs_files[t]); 356 } 357 break; 358 case OPTION_FFLAGS: 359 bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; 360 bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_NO_FFLAGS; 361 bsdtar->flags |= OPTFLAG_FFLAGS; 362 break; 363 case OPTION_FORMAT: /* GNU tar, others */ 364 cset_set_format(bsdtar->cset, bsdtar->argument); 365 break; 366 case 'f': /* SUSv2 */ 367 bsdtar->filename = bsdtar->argument; 368 break; 369 case OPTION_GID: /* cpio */ 370 tptr = NULL; 371 l = strtol(bsdtar->argument, &tptr, 10); 372 if (l < 0 || l >= INT_MAX || *(bsdtar->argument) == '\0' || 373 tptr == NULL || *tptr != '\0') { 374 lafe_errc(1, 0, "Invalid argument to --gid"); 375 } 376 bsdtar->gid = (int)l; 377 break; 378 case OPTION_GNAME: /* cpio */ 379 bsdtar->gname = bsdtar->argument; 380 break; 381 case OPTION_GROUP: /* GNU tar */ 382 tptr = NULL; 383 384 uptr = strchr(bsdtar->argument, ':'); 385 if (uptr != NULL) { 386 if (uptr[1] == '\0') { 387 lafe_errc(1, 0, "Invalid argument to --group (missing id after :)"); 388 } 389 uptr[0] = 0; 390 uptr++; 391 l = strtol(uptr, &tptr, 10); 392 if (l < 0 || l >= INT_MAX || *uptr == '\0' || 393 tptr == NULL || *tptr != '\0') { 394 lafe_errc(1, 0, "Invalid argument to --group (%s is not a number)", uptr); 395 } else { 396 bsdtar->gid = (int)l; 397 } 398 bsdtar->gname = bsdtar->argument; 399 } else { 400 l = strtol(bsdtar->argument, &tptr, 10); 401 if (l < 0 || l >= INT_MAX || *(bsdtar->argument) == '\0' || 402 tptr == NULL || *tptr != '\0') { 403 bsdtar->gname = bsdtar->argument; 404 } else { 405 bsdtar->gid = (int)l; 406 bsdtar->gname = ""; 407 } 408 } 409 break; 410 case OPTION_GRZIP: 411 if (compression != '\0') 412 lafe_errc(1, 0, 413 "Can't specify both -%c and -%c", opt, 414 compression); 415 compression = opt; 416 compression_name = "grzip"; 417 break; 418 case 'H': /* BSD convention */ 419 bsdtar->symlink_mode = 'H'; 420 break; 421 case 'h': /* Linux Standards Base, gtar; synonym for -L */ 422 bsdtar->symlink_mode = 'L'; 423 /* Hack: -h by itself is the "help" command. */ 424 possible_help_request = 1; 425 break; 426 case OPTION_HELP: /* GNU tar, others */ 427 long_help(); 428 /* NOTREACHED*/ 429 case OPTION_HFS_COMPRESSION: /* Mac OS X v10.6 or later */ 430 bsdtar->extract_flags |= 431 ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED; 432 break; 433 case OPTION_IGNORE_ZEROS: 434 bsdtar->flags |= OPTFLAG_IGNORE_ZEROS; 435 break; 436 case 'I': /* GNU tar */ 437 /* 438 * TODO: Allow 'names' to come from an archive, 439 * not just a text file. Design a good UI for 440 * allowing names and mode/owner to be read 441 * from an archive, with contents coming from 442 * disk. This can be used to "refresh" an 443 * archive or to design archives with special 444 * permissions without having to create those 445 * permissions on disk. 446 */ 447 bsdtar->names_from_file = bsdtar->argument; 448 break; 449 case OPTION_INCLUDE: 450 /* 451 * No one else has the @archive extension, so 452 * no one else needs this to filter entries 453 * when transforming archives. 454 */ 455 if (archive_match_include_pattern(bsdtar->matching, 456 bsdtar->argument) != ARCHIVE_OK) 457 lafe_errc(1, 0, 458 "Failed to add %s to inclusion list", 459 bsdtar->argument); 460 break; 461 case 'j': /* GNU tar */ 462 if (compression != '\0') 463 lafe_errc(1, 0, 464 "Can't specify both -%c and -%c", opt, 465 compression); 466 compression = opt; 467 compression_name = "bzip2"; 468 break; 469 case 'J': /* GNU tar 1.21 and later */ 470 if (compression != '\0') 471 lafe_errc(1, 0, 472 "Can't specify both -%c and -%c", opt, 473 compression); 474 compression = opt; 475 compression_name = "xz"; 476 break; 477 case 'k': /* GNU tar */ 478 bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE; 479 break; 480 case OPTION_KEEP_NEWER_FILES: /* GNU tar */ 481 bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; 482 break; 483 case 'L': /* BSD convention */ 484 bsdtar->symlink_mode = 'L'; 485 break; 486 case 'l': /* SUSv2 and GNU tar beginning with 1.16 */ 487 /* GNU tar 1.13 used -l for --one-file-system */ 488 bsdtar->flags |= OPTFLAG_WARN_LINKS; 489 break; 490 case OPTION_LRZIP: 491 case OPTION_LZ4: 492 case OPTION_LZIP: /* GNU tar beginning with 1.23 */ 493 case OPTION_LZMA: /* GNU tar beginning with 1.20 */ 494 case OPTION_LZOP: /* GNU tar beginning with 1.21 */ 495 case OPTION_ZSTD: 496 if (compression != '\0') 497 lafe_errc(1, 0, 498 "Can't specify both -%c and -%c", opt, 499 compression); 500 compression = opt; 501 switch (opt) { 502 case OPTION_LRZIP: compression_name = "lrzip"; break; 503 case OPTION_LZ4: compression_name = "lz4"; break; 504 case OPTION_LZIP: compression_name = "lzip"; break; 505 case OPTION_LZMA: compression_name = "lzma"; break; 506 case OPTION_LZOP: compression_name = "lzop"; break; 507 case OPTION_ZSTD: compression_name = "zstd"; break; 508 } 509 break; 510 case 'm': /* SUSv2 */ 511 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_TIME; 512 break; 513 case OPTION_MAC_METADATA: /* Mac OS X */ 514 bsdtar->readdisk_flags |= ARCHIVE_READDISK_MAC_COPYFILE; 515 bsdtar->extract_flags |= ARCHIVE_EXTRACT_MAC_METADATA; 516 bsdtar->flags |= OPTFLAG_MAC_METADATA; 517 break; 518 case 'n': /* GNU tar */ 519 bsdtar->flags |= OPTFLAG_NO_SUBDIRS; 520 break; 521 /* 522 * Selecting files by time: 523 * --newer-?time='date' Only files newer than 'date' 524 * --newer-?time-than='file' Only files newer than time 525 * on specified file (useful for incremental backups) 526 */ 527 case OPTION_NEWER_CTIME: /* GNU tar */ 528 if (archive_match_include_date(bsdtar->matching, 529 ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER, 530 bsdtar->argument) != ARCHIVE_OK) 531 lafe_errc(1, 0, "%s", 532 archive_error_string(bsdtar->matching)); 533 break; 534 case OPTION_NEWER_CTIME_THAN: 535 if (archive_match_include_file_time(bsdtar->matching, 536 ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER, 537 bsdtar->argument) != ARCHIVE_OK) 538 lafe_errc(1, 0, "%s", 539 archive_error_string(bsdtar->matching)); 540 break; 541 case OPTION_NEWER_MTIME: /* GNU tar */ 542 if (archive_match_include_date(bsdtar->matching, 543 ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER, 544 bsdtar->argument) != ARCHIVE_OK) 545 lafe_errc(1, 0, "%s", 546 archive_error_string(bsdtar->matching)); 547 break; 548 case OPTION_NEWER_MTIME_THAN: 549 if (archive_match_include_file_time(bsdtar->matching, 550 ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER, 551 bsdtar->argument) != ARCHIVE_OK) 552 lafe_errc(1, 0, "%s", 553 archive_error_string(bsdtar->matching)); 554 break; 555 case OPTION_NODUMP: /* star */ 556 bsdtar->readdisk_flags |= ARCHIVE_READDISK_HONOR_NODUMP; 557 break; 558 case OPTION_NOPRESERVE_HFS_COMPRESSION: 559 /* Mac OS X v10.6 or later */ 560 bsdtar->extract_flags |= 561 ARCHIVE_EXTRACT_NO_HFS_COMPRESSION; 562 break; 563 case OPTION_NO_ACLS: /* GNU tar */ 564 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_ACL; 565 bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_ACL; 566 bsdtar->flags |= OPTFLAG_NO_ACLS; 567 break; 568 case OPTION_NO_FFLAGS: 569 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_FFLAGS; 570 bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_FFLAGS; 571 bsdtar->flags |= OPTFLAG_NO_FFLAGS; 572 break; 573 case OPTION_NO_MAC_METADATA: /* Mac OS X */ 574 bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE; 575 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_MAC_METADATA; 576 bsdtar->flags |= OPTFLAG_NO_MAC_METADATA; 577 break; 578 case OPTION_NO_READ_SPARSE: 579 bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_SPARSE; 580 bsdtar->flags |= OPTFLAG_NO_READ_SPARSE; 581 break; 582 case OPTION_NO_SAFE_WRITES: 583 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_SAFE_WRITES; 584 break; 585 case OPTION_NO_SAME_OWNER: /* GNU tar */ 586 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; 587 break; 588 case OPTION_NO_SAME_PERMISSIONS: /* GNU tar */ 589 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_PERM; 590 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_ACL; 591 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_XATTR; 592 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_FFLAGS; 593 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_MAC_METADATA; 594 break; 595 case OPTION_NO_XATTRS: /* GNU tar */ 596 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_XATTR; 597 bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_XATTR; 598 bsdtar->flags |= OPTFLAG_NO_XATTRS; 599 break; 600 case OPTION_NULL: /* GNU tar */ 601 bsdtar->flags |= OPTFLAG_NULL; 602 break; 603 case OPTION_NUMERIC_OWNER: /* GNU tar */ 604 bsdtar->uname = ""; 605 bsdtar->gname = ""; 606 bsdtar->flags |= OPTFLAG_NUMERIC_OWNER; 607 break; 608 case 'O': /* GNU tar */ 609 bsdtar->flags |= OPTFLAG_STDOUT; 610 break; 611 case 'o': /* SUSv2 and GNU conflict here, but not fatally */ 612 bsdtar->flags |= OPTFLAG_O; 613 break; 614 /* 615 * Selecting files by time: 616 * --older-?time='date' Only files older than 'date' 617 * --older-?time-than='file' Only files older than time 618 * on specified file 619 */ 620 case OPTION_OLDER_CTIME: 621 if (archive_match_include_date(bsdtar->matching, 622 ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_OLDER, 623 bsdtar->argument) != ARCHIVE_OK) 624 lafe_errc(1, 0, "%s", 625 archive_error_string(bsdtar->matching)); 626 break; 627 case OPTION_OLDER_CTIME_THAN: 628 if (archive_match_include_file_time(bsdtar->matching, 629 ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_OLDER, 630 bsdtar->argument) != ARCHIVE_OK) 631 lafe_errc(1, 0, "%s", 632 archive_error_string(bsdtar->matching)); 633 break; 634 case OPTION_OLDER_MTIME: 635 if (archive_match_include_date(bsdtar->matching, 636 ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER, 637 bsdtar->argument) != ARCHIVE_OK) 638 lafe_errc(1, 0, "%s", 639 archive_error_string(bsdtar->matching)); 640 break; 641 case OPTION_OLDER_MTIME_THAN: 642 if (archive_match_include_file_time(bsdtar->matching, 643 ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER, 644 bsdtar->argument) != ARCHIVE_OK) 645 lafe_errc(1, 0, "%s", 646 archive_error_string(bsdtar->matching)); 647 break; 648 case OPTION_ONE_FILE_SYSTEM: /* GNU tar */ 649 bsdtar->readdisk_flags |= 650 ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS; 651 break; 652 case OPTION_OPTIONS: 653 if (bsdtar->option_options != NULL) { 654 lafe_warnc(0, 655 "Ignoring previous option '%s', separate multiple options with commas", 656 bsdtar->option_options); 657 } 658 bsdtar->option_options = bsdtar->argument; 659 break; 660 case OPTION_OWNER: /* GNU tar */ 661 tptr = NULL; 662 663 uptr = strchr(bsdtar->argument, ':'); 664 if (uptr != NULL) { 665 if (uptr[1] == 0) { 666 lafe_errc(1, 0, "Invalid argument to --owner (missing id after :)"); 667 } 668 uptr[0] = 0; 669 uptr++; 670 l = strtol(uptr, &tptr, 10); 671 if (l < 0 || l >= INT_MAX || *uptr == '\0' || 672 tptr == NULL || *tptr != '\0') { 673 lafe_errc(1, 0, "Invalid argument to --owner (%s is not a number)", uptr); 674 } else { 675 bsdtar->uid = (int)l; 676 } 677 bsdtar->uname = bsdtar->argument; 678 } else { 679 l = strtol(bsdtar->argument, &tptr, 10); 680 if (l < 0 || l >= INT_MAX || *(bsdtar->argument) == '\0' || 681 tptr == NULL || *tptr != '\0') { 682 bsdtar->uname = bsdtar->argument; 683 } else { 684 bsdtar->uid = (int)l; 685 bsdtar->uname = ""; 686 } 687 } 688 break; 689 case OPTION_MTIME: /* GNU tar */ 690 bsdtar->has_mtime = 1; 691 bsdtar->mtime = archive_parse_date(now, bsdtar->argument); 692 if (bsdtar->mtime == (time_t)-1) { 693 lafe_errc(1, 0, "Invalid argument to --mtime (bad date string)"); 694 } 695 break; 696 case OPTION_CLAMP_MTIME: /* GNU tar */ 697 bsdtar->clamp_mtime = 1; 698 break; 699 #if 0 700 /* 701 * The common BSD -P option is not necessary, since 702 * our default is to archive symlinks, not follow 703 * them. This is convenient, as -P conflicts with GNU 704 * tar anyway. 705 */ 706 case 'P': /* BSD convention */ 707 /* Default behavior, no option necessary. */ 708 break; 709 #endif 710 case 'P': /* GNU tar */ 711 bsdtar->extract_flags &= ~SECURITY; 712 bsdtar->flags |= OPTFLAG_ABSOLUTE_PATHS; 713 break; 714 case 'p': /* GNU tar, star */ 715 bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; 716 bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; 717 bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; 718 bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; 719 bsdtar->extract_flags |= ARCHIVE_EXTRACT_MAC_METADATA; 720 break; 721 case OPTION_PASSPHRASE: 722 bsdtar->passphrase = bsdtar->argument; 723 break; 724 case OPTION_POSIX: /* GNU tar */ 725 cset_set_format(bsdtar->cset, "pax"); 726 break; 727 case 'q': /* FreeBSD GNU tar --fast-read, NetBSD -q */ 728 bsdtar->flags |= OPTFLAG_FAST_READ; 729 break; 730 case 'r': /* SUSv2 */ 731 set_mode(bsdtar, opt); 732 break; 733 case OPTION_READ_SPARSE: 734 bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_NO_SPARSE; 735 bsdtar->flags |= OPTFLAG_READ_SPARSE; 736 break; 737 case 'S': /* NetBSD pax-as-tar */ 738 bsdtar->extract_flags |= ARCHIVE_EXTRACT_SPARSE; 739 break; 740 case 's': /* NetBSD pax-as-tar */ 741 #if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) || defined(HAVE_PCRE2POSIX_H) 742 add_substitution(bsdtar, bsdtar->argument); 743 #else 744 lafe_warnc(0, 745 "-s is not supported by this version of bsdtar"); 746 usage(); 747 #endif 748 break; 749 case OPTION_SAFE_WRITES: 750 bsdtar->extract_flags |= ARCHIVE_EXTRACT_SAFE_WRITES; 751 break; 752 case OPTION_SAME_OWNER: /* GNU tar */ 753 bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER; 754 break; 755 case OPTION_STRIP_COMPONENTS: /* GNU tar 1.15 */ 756 tptr = NULL; 757 l = strtol(bsdtar->argument, &tptr, 10); 758 if (l < 0 || l > 100000L || *(bsdtar->argument) == '\0' || 759 tptr == NULL || *tptr != '\0') { 760 lafe_errc(1, 0, "Invalid argument to " 761 "--strip-components"); 762 } 763 bsdtar->strip_components = (int)l; 764 break; 765 case 'T': /* GNU tar */ 766 if (bsdtar->names_from_file) 767 lafe_errc(1, 0, "Multiple --files-from/-T options are not supported"); 768 bsdtar->names_from_file = bsdtar->argument; 769 break; 770 case 't': /* SUSv2 */ 771 set_mode(bsdtar, opt); 772 bsdtar->verbose++; 773 break; 774 case OPTION_TOTALS: /* GNU tar */ 775 bsdtar->flags |= OPTFLAG_TOTALS; 776 break; 777 case 'U': /* GNU tar */ 778 bsdtar->extract_flags |= ARCHIVE_EXTRACT_UNLINK; 779 bsdtar->flags |= OPTFLAG_UNLINK_FIRST; 780 break; 781 case 'u': /* SUSv2 */ 782 set_mode(bsdtar, opt); 783 break; 784 case OPTION_UID: /* cpio */ 785 tptr = NULL; 786 l = strtol(bsdtar->argument, &tptr, 10); 787 if (l < 0 || l >= INT_MAX || *(bsdtar->argument) == '\0' || 788 tptr == NULL || *tptr != '\0') { 789 lafe_errc(1, 0, "Invalid argument to --uid"); 790 } 791 bsdtar->uid = (int)l; 792 break; 793 case OPTION_UNAME: /* cpio */ 794 bsdtar->uname = bsdtar->argument; 795 break; 796 case OPTION_UUENCODE: 797 if (compression2 != '\0') 798 lafe_errc(1, 0, 799 "Can't specify both --uuencode and " 800 "--b64encode"); 801 compression2 = opt; 802 compression2_name = "uuencode"; 803 break; 804 case 'v': /* SUSv2 */ 805 bsdtar->verbose++; 806 break; 807 case OPTION_VERSION: /* GNU convention */ 808 version(); 809 /* NOTREACHED */ 810 #if 0 811 /* 812 * The -W longopt feature is handled inside of 813 * bsdtar_getopt(), so -W is not available here. 814 */ 815 case 'W': /* Obscure GNU convention. */ 816 break; 817 #endif 818 case 'w': /* SUSv2 */ 819 bsdtar->flags |= OPTFLAG_INTERACTIVE; 820 break; 821 case 'X': /* GNU tar */ 822 if (archive_match_exclude_pattern_from_file( 823 bsdtar->matching, bsdtar->argument, 0) 824 != ARCHIVE_OK) 825 lafe_errc(1, 0, "%s", 826 archive_error_string(bsdtar->matching)); 827 break; 828 case 'x': /* SUSv2 */ 829 set_mode(bsdtar, opt); 830 break; 831 case OPTION_XATTRS: /* GNU tar */ 832 bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; 833 bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_NO_XATTR; 834 bsdtar->flags |= OPTFLAG_XATTRS; 835 break; 836 case 'y': /* FreeBSD version of GNU tar */ 837 if (compression != '\0') 838 lafe_errc(1, 0, 839 "Can't specify both -%c and -%c", opt, 840 compression); 841 compression = opt; 842 compression_name = "bzip2"; 843 break; 844 case 'Z': /* GNU tar */ 845 if (compression != '\0') 846 lafe_errc(1, 0, 847 "Can't specify both -%c and -%c", opt, 848 compression); 849 compression = opt; 850 compression_name = "compress"; 851 break; 852 case 'z': /* GNU tar, star, many others */ 853 if (compression != '\0') 854 lafe_errc(1, 0, 855 "Can't specify both -%c and -%c", opt, 856 compression); 857 compression = opt; 858 compression_name = "gzip"; 859 break; 860 case OPTION_USE_COMPRESS_PROGRAM: 861 compress_program = bsdtar->argument; 862 break; 863 default: 864 usage(); 865 } 866 } 867 868 /* 869 * Sanity-check options. 870 */ 871 872 /* If no "real" mode was specified, treat -h as --help. */ 873 if ((bsdtar->mode == '\0') && possible_help_request) { 874 long_help(); 875 } 876 877 /* Otherwise, a mode is required. */ 878 if (bsdtar->mode == '\0') 879 lafe_errc(1, 0, 880 "Must specify one of -c, -r, -t, -u, -x"); 881 882 /* Check boolean options only permitted in certain modes. */ 883 if (bsdtar->flags & OPTFLAG_AUTO_COMPRESS) { 884 only_mode(bsdtar, "-a", "cx"); 885 if (bsdtar->mode == 'x') { 886 bsdtar->flags &= ~OPTFLAG_AUTO_COMPRESS; 887 lafe_warnc(0, 888 "Ignoring option -a in mode -x"); 889 } 890 } 891 if (bsdtar->readdisk_flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) 892 only_mode(bsdtar, "--one-file-system", "cru"); 893 if (bsdtar->flags & OPTFLAG_FAST_READ) 894 only_mode(bsdtar, "--fast-read", "xt"); 895 if (bsdtar->extract_flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) 896 only_mode(bsdtar, "--hfsCompression", "x"); 897 if (bsdtar->extract_flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) 898 only_mode(bsdtar, "--nopreserveHFSCompression", "x"); 899 if (bsdtar->readdisk_flags & ARCHIVE_READDISK_HONOR_NODUMP) 900 only_mode(bsdtar, "--nodump", "cru"); 901 if (bsdtar->flags & OPTFLAG_ACLS) 902 only_mode(bsdtar, "--acls", "crux"); 903 if (bsdtar->flags & OPTFLAG_NO_ACLS) 904 only_mode(bsdtar, "--no-acls", "crux"); 905 if (bsdtar->flags & OPTFLAG_XATTRS) 906 only_mode(bsdtar, "--xattrs", "crux"); 907 if (bsdtar->flags & OPTFLAG_NO_XATTRS) 908 only_mode(bsdtar, "--no-xattrs", "crux"); 909 if (bsdtar->flags & OPTFLAG_FFLAGS) 910 only_mode(bsdtar, "--fflags", "crux"); 911 if (bsdtar->flags & OPTFLAG_NO_FFLAGS) 912 only_mode(bsdtar, "--no-fflags", "crux"); 913 if (bsdtar->flags & OPTFLAG_MAC_METADATA) 914 only_mode(bsdtar, "--mac-metadata", "crux"); 915 if (bsdtar->flags & OPTFLAG_NO_MAC_METADATA) 916 only_mode(bsdtar, "--no-mac-metadata", "crux"); 917 if (bsdtar->flags & OPTFLAG_O) { 918 switch (bsdtar->mode) { 919 case 'c': 920 /* 921 * In GNU tar, -o means "old format." The 922 * "ustar" format is the closest thing 923 * supported by libarchive. 924 */ 925 cset_set_format(bsdtar->cset, "ustar"); 926 /* TODO: bsdtar->create_format = "v7"; */ 927 break; 928 case 'x': 929 /* POSIX-compatible behavior. */ 930 bsdtar->flags |= OPTFLAG_NO_OWNER; 931 bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; 932 break; 933 default: 934 only_mode(bsdtar, "-o", "xc"); 935 break; 936 } 937 } 938 if (bsdtar->flags & OPTFLAG_STDOUT) 939 only_mode(bsdtar, "-O", "xt"); 940 if (bsdtar->flags & OPTFLAG_UNLINK_FIRST) 941 only_mode(bsdtar, "-U", "x"); 942 if (bsdtar->flags & OPTFLAG_WARN_LINKS) 943 only_mode(bsdtar, "--check-links", "cr"); 944 945 if ((bsdtar->flags & OPTFLAG_AUTO_COMPRESS) && 946 cset_auto_compress(bsdtar->cset, bsdtar->filename)) { 947 /* Ignore specified compressions if auto-compress works. */ 948 compression = '\0'; 949 compression2 = '\0'; 950 } 951 /* Check other parameters only permitted in certain modes. */ 952 if (compress_program != NULL) { 953 only_mode(bsdtar, "--use-compress-program", "cxt"); 954 cset_add_filter_program(bsdtar->cset, compress_program); 955 /* Ignore specified compressions. */ 956 compression = '\0'; 957 compression2 = '\0'; 958 } 959 if (compression != '\0') { 960 switch (compression) { 961 case 'J': case 'j': case 'y': case 'Z': case 'z': 962 strcpy(buff, "-?"); 963 buff[1] = (char)compression; 964 break; 965 default: 966 strcpy(buff, "--"); 967 strcat(buff, compression_name); 968 break; 969 } 970 only_mode(bsdtar, buff, "cxt"); 971 cset_add_filter(bsdtar->cset, compression_name); 972 } 973 if (compression2 != '\0') { 974 strcpy(buff, "--"); 975 strcat(buff, compression2_name); 976 only_mode(bsdtar, buff, "cxt"); 977 cset_add_filter(bsdtar->cset, compression2_name); 978 } 979 if (cset_get_format(bsdtar->cset) != NULL) 980 only_mode(bsdtar, "--format", "cru"); 981 if (bsdtar->symlink_mode != '\0') { 982 strcpy(buff, "-?"); 983 buff[1] = bsdtar->symlink_mode; 984 only_mode(bsdtar, buff, "cru"); 985 } 986 987 if (!bsdtar->has_mtime && bsdtar->clamp_mtime) 988 lafe_errc(1, 0, 989 "--clamp-mtime is not valid without --mtime <date>"); 990 991 /* 992 * When creating an archive from a directory tree, the directory 993 * walking code will already avoid entering directories when 994 * recursive inclusion of directory content is disabled, therefore 995 * changing the matching behavior has no effect for creation modes. 996 * It is relevant for extraction or listing. 997 */ 998 archive_match_set_inclusion_recursion(bsdtar->matching, 999 !(bsdtar->flags & OPTFLAG_NO_SUBDIRS)); 1000 1001 /* Filename "-" implies stdio. */ 1002 if (strcmp(bsdtar->filename, "-") == 0) 1003 bsdtar->filename = NULL; 1004 1005 switch(bsdtar->mode) { 1006 case 'c': 1007 tar_mode_c(bsdtar); 1008 break; 1009 case 'r': 1010 tar_mode_r(bsdtar); 1011 break; 1012 case 't': 1013 tar_mode_t(bsdtar); 1014 break; 1015 case 'u': 1016 tar_mode_u(bsdtar); 1017 break; 1018 case 'x': 1019 tar_mode_x(bsdtar); 1020 break; 1021 } 1022 1023 archive_match_free(bsdtar->matching); 1024 #if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) || defined(HAVE_PCRE2POSIX_H) 1025 cleanup_substitution(bsdtar); 1026 #endif 1027 cset_free(bsdtar->cset); 1028 passphrase_free(bsdtar->ppbuff); 1029 1030 if (bsdtar->return_value != 0) 1031 lafe_warnc(0, 1032 "Error exit delayed from previous errors"); 1033 return (bsdtar->return_value); 1034 } 1035 1036 static void 1037 set_mode(struct bsdtar *bsdtar, int opt) 1038 { 1039 if (bsdtar->mode != '\0' && bsdtar->mode != opt) 1040 lafe_errc(1, 0, 1041 "Can't specify both -%c and -%c", opt, bsdtar->mode); 1042 bsdtar->mode = opt; 1043 } 1044 1045 /* 1046 * Verify that the mode is correct. 1047 */ 1048 static void 1049 only_mode(struct bsdtar *bsdtar, const char *opt, const char *valid_modes) 1050 { 1051 if (strchr(valid_modes, bsdtar->mode) == NULL) 1052 lafe_errc(1, 0, 1053 "Option %s is not permitted in mode -%c", 1054 opt, bsdtar->mode); 1055 } 1056 1057 1058 void 1059 usage(void) 1060 { 1061 const char *p; 1062 1063 p = lafe_getprogname(); 1064 1065 fprintf(stderr, "Usage:\n"); 1066 fprintf(stderr, " List: %s -tf <archive-filename>\n", p); 1067 fprintf(stderr, " Extract: %s -xf <archive-filename>\n", p); 1068 fprintf(stderr, " Create: %s -cf <archive-filename> [filenames...]\n", p); 1069 fprintf(stderr, " Help: %s --help\n", p); 1070 exit(1); 1071 } 1072 1073 static void 1074 version(void) 1075 { 1076 printf("bsdtar %s - %s \n", 1077 BSDTAR_VERSION_STRING, 1078 archive_version_details()); 1079 exit(0); 1080 } 1081 1082 static const char *long_help_msg = 1083 "First option must be a mode specifier:\n" 1084 " -c Create -r Add/Replace -t List -u Update -x Extract\n" 1085 "Common Options:\n" 1086 " -b # Use # 512-byte records per I/O block\n" 1087 " -f <filename> Location of archive (default " _PATH_DEFTAPE ")\n" 1088 " -v Verbose\n" 1089 " -w Interactive\n" 1090 "Create: %p -c [options] [<file> | <dir> | @<archive> | -C <dir> ]\n" 1091 " <file>, <dir> add these items to archive\n" 1092 " -z, -j, -J, --lzma Compress archive with gzip/bzip2/xz/lzma\n" 1093 " --format {ustar|pax|cpio|shar} Select archive format\n" 1094 " --exclude <pattern> Skip files that match pattern\n" 1095 " --mtime <date> Set modification times for added files\n" 1096 " --clamp-mtime Only set modification times for files newer than --mtime\n" 1097 " -C <dir> Change to <dir> before processing remaining files\n" 1098 " @<archive> Add entries from <archive> to output\n" 1099 "List: %p -t [options] [<patterns>]\n" 1100 " <patterns> If specified, list only entries that match\n" 1101 "Extract: %p -x [options] [<patterns>]\n" 1102 " <patterns> If specified, extract only entries that match\n" 1103 " -k Keep (don't overwrite) existing files\n" 1104 " -m Don't restore modification times\n" 1105 " -O Write entries to stdout, don't restore to disk\n" 1106 " -p Restore permissions (including ACLs, owner, file flags)\n"; 1107 1108 1109 /* 1110 * Note that the word 'bsdtar' will always appear in the first line 1111 * of output. 1112 * 1113 * In particular, /bin/sh scripts that need to test for the presence 1114 * of bsdtar can use the following template: 1115 * 1116 * if (tar --help 2>&1 | grep bsdtar >/dev/null 2>&1 ) then \ 1117 * echo bsdtar; else echo not bsdtar; fi 1118 */ 1119 static void 1120 long_help(void) 1121 { 1122 const char *prog; 1123 const char *p; 1124 1125 prog = lafe_getprogname(); 1126 1127 fflush(stderr); 1128 1129 p = (strcmp(prog,"bsdtar") != 0) ? "(bsdtar)" : ""; 1130 printf("%s%s: manipulate archive files\n", prog, p); 1131 1132 for (p = long_help_msg; *p != '\0'; p++) { 1133 if (*p == '%') { 1134 if (p[1] == 'p') { 1135 fputs(prog, stdout); 1136 p++; 1137 } else 1138 putchar('%'); 1139 } else 1140 putchar(*p); 1141 } 1142 version(); 1143 } 1144