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