160b4ad09SPeter Avalos /*- 28029ab02SPeter Avalos * Copyright (c) 2003-2008 Tim Kientzle 360b4ad09SPeter Avalos * All rights reserved. 460b4ad09SPeter Avalos * 560b4ad09SPeter Avalos * Redistribution and use in source and binary forms, with or without 660b4ad09SPeter Avalos * modification, are permitted provided that the following conditions 760b4ad09SPeter Avalos * are met: 860b4ad09SPeter Avalos * 1. Redistributions of source code must retain the above copyright 960b4ad09SPeter Avalos * notice, this list of conditions and the following disclaimer. 1060b4ad09SPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 1160b4ad09SPeter Avalos * notice, this list of conditions and the following disclaimer in the 1260b4ad09SPeter Avalos * documentation and/or other materials provided with the distribution. 1360b4ad09SPeter Avalos * 1460b4ad09SPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 1560b4ad09SPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1660b4ad09SPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1760b4ad09SPeter Avalos * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 1860b4ad09SPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1960b4ad09SPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2060b4ad09SPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2160b4ad09SPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2260b4ad09SPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2360b4ad09SPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2460b4ad09SPeter Avalos */ 2560b4ad09SPeter Avalos 2660b4ad09SPeter Avalos #include "bsdtar_platform.h" 278029ab02SPeter Avalos __FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.93 2008/11/08 04:43:24 kientzle Exp $"); 2860b4ad09SPeter Avalos 2960b4ad09SPeter Avalos #ifdef HAVE_SYS_PARAM_H 3060b4ad09SPeter Avalos #include <sys/param.h> 3160b4ad09SPeter Avalos #endif 3260b4ad09SPeter Avalos #ifdef HAVE_SYS_STAT_H 3360b4ad09SPeter Avalos #include <sys/stat.h> 3460b4ad09SPeter Avalos #endif 35c09f92d2SPeter Avalos #ifdef HAVE_COPYFILE_H 36c09f92d2SPeter Avalos #include <copyfile.h> 37c09f92d2SPeter Avalos #endif 3860b4ad09SPeter Avalos #ifdef HAVE_ERRNO_H 3960b4ad09SPeter Avalos #include <errno.h> 4060b4ad09SPeter Avalos #endif 4160b4ad09SPeter Avalos #ifdef HAVE_FCNTL_H 4260b4ad09SPeter Avalos #include <fcntl.h> 4360b4ad09SPeter Avalos #endif 4460b4ad09SPeter Avalos #ifdef HAVE_LANGINFO_H 4560b4ad09SPeter Avalos #include <langinfo.h> 4660b4ad09SPeter Avalos #endif 4760b4ad09SPeter Avalos #ifdef HAVE_LOCALE_H 4860b4ad09SPeter Avalos #include <locale.h> 4960b4ad09SPeter Avalos #endif 5060b4ad09SPeter Avalos #ifdef HAVE_PATHS_H 5160b4ad09SPeter Avalos #include <paths.h> 5260b4ad09SPeter Avalos #endif 539c82a63eSPeter Avalos #ifdef HAVE_SIGNAL_H 549c82a63eSPeter Avalos #include <signal.h> 559c82a63eSPeter Avalos #endif 5660b4ad09SPeter Avalos #include <stdio.h> 5760b4ad09SPeter Avalos #ifdef HAVE_STDLIB_H 5860b4ad09SPeter Avalos #include <stdlib.h> 5960b4ad09SPeter Avalos #endif 6060b4ad09SPeter Avalos #ifdef HAVE_STRING_H 6160b4ad09SPeter Avalos #include <string.h> 6260b4ad09SPeter Avalos #endif 6360b4ad09SPeter Avalos #ifdef HAVE_TIME_H 6460b4ad09SPeter Avalos #include <time.h> 6560b4ad09SPeter Avalos #endif 6660b4ad09SPeter Avalos #ifdef HAVE_UNISTD_H 6760b4ad09SPeter Avalos #include <unistd.h> 6860b4ad09SPeter Avalos #endif 6960b4ad09SPeter Avalos 7060b4ad09SPeter Avalos #include "bsdtar.h" 719c82a63eSPeter Avalos #include "err.h" 7260b4ad09SPeter Avalos 7360b4ad09SPeter Avalos /* 7460b4ad09SPeter Avalos * Per POSIX.1-1988, tar defaults to reading/writing archives to/from 7560b4ad09SPeter Avalos * the default tape device for the system. Pick something reasonable here. 7660b4ad09SPeter Avalos */ 7760b4ad09SPeter Avalos #ifdef __linux 7860b4ad09SPeter Avalos #define _PATH_DEFTAPE "/dev/st0" 7960b4ad09SPeter Avalos #endif 808029ab02SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 818029ab02SPeter Avalos #define _PATH_DEFTAPE "\\\\.\\tape0" 828029ab02SPeter Avalos #endif 83c09f92d2SPeter Avalos #if defined(__APPLE__) 84c09f92d2SPeter Avalos #undef _PATH_DEFTAPE 85c09f92d2SPeter Avalos #define _PATH_DEFTAPE "-" /* Mac OS has no tape support, default to stdio. */ 86c09f92d2SPeter Avalos #endif 8760b4ad09SPeter Avalos 8860b4ad09SPeter Avalos #ifndef _PATH_DEFTAPE 8960b4ad09SPeter Avalos #define _PATH_DEFTAPE "/dev/tape" 9060b4ad09SPeter Avalos #endif 9160b4ad09SPeter Avalos 929c82a63eSPeter Avalos #ifdef __MINGW32__ 939c82a63eSPeter Avalos int _CRT_glob = 0; /* Disable broken CRT globbing. */ 949c82a63eSPeter Avalos #endif 959c82a63eSPeter Avalos 969c82a63eSPeter Avalos #if defined(HAVE_SIGACTION) && (defined(SIGINFO) || defined(SIGUSR1)) 979c82a63eSPeter Avalos static volatile int siginfo_occurred; 989c82a63eSPeter Avalos 999c82a63eSPeter Avalos static void 1009c82a63eSPeter Avalos siginfo_handler(int sig) 1019c82a63eSPeter Avalos { 1029c82a63eSPeter Avalos (void)sig; /* UNUSED */ 1039c82a63eSPeter Avalos siginfo_occurred = 1; 1049c82a63eSPeter Avalos } 1059c82a63eSPeter Avalos 1069c82a63eSPeter Avalos int 1079c82a63eSPeter Avalos need_report(void) 1089c82a63eSPeter Avalos { 1099c82a63eSPeter Avalos int r = siginfo_occurred; 1109c82a63eSPeter Avalos siginfo_occurred = 0; 1119c82a63eSPeter Avalos return (r); 1129c82a63eSPeter Avalos } 1139c82a63eSPeter Avalos #else 1149c82a63eSPeter Avalos int 1159c82a63eSPeter Avalos need_report(void) 1169c82a63eSPeter Avalos { 1179c82a63eSPeter Avalos return (0); 1189c82a63eSPeter Avalos } 1199c82a63eSPeter Avalos #endif 1209c82a63eSPeter Avalos 1219c82a63eSPeter Avalos static void long_help(void); 12260b4ad09SPeter Avalos static void only_mode(struct bsdtar *, const char *opt, 12360b4ad09SPeter Avalos const char *valid); 12460b4ad09SPeter Avalos static void set_mode(struct bsdtar *, char opt); 12560b4ad09SPeter Avalos static void version(void); 12660b4ad09SPeter Avalos 12760b4ad09SPeter Avalos /* A basic set of security flags to request from libarchive. */ 12860b4ad09SPeter Avalos #define SECURITY \ 12960b4ad09SPeter Avalos (ARCHIVE_EXTRACT_SECURE_SYMLINKS \ 13060b4ad09SPeter Avalos | ARCHIVE_EXTRACT_SECURE_NODOTDOT) 13160b4ad09SPeter Avalos 13260b4ad09SPeter Avalos int 13360b4ad09SPeter Avalos main(int argc, char **argv) 13460b4ad09SPeter Avalos { 13560b4ad09SPeter Avalos struct bsdtar *bsdtar, bsdtar_storage; 13660b4ad09SPeter Avalos int opt, t; 137*d4d8193eSPeter Avalos char compression, compression2; 138*d4d8193eSPeter Avalos const char *compression_name, *compression2_name; 139*d4d8193eSPeter Avalos const char *compress_program; 140*d4d8193eSPeter Avalos char option_a, option_o; 14160b4ad09SPeter Avalos char possible_help_request; 14260b4ad09SPeter Avalos char buff[16]; 14360b4ad09SPeter Avalos 14460b4ad09SPeter Avalos /* 14560b4ad09SPeter Avalos * Use a pointer for consistency, but stack-allocated storage 14660b4ad09SPeter Avalos * for ease of cleanup. 14760b4ad09SPeter Avalos */ 148c09f92d2SPeter Avalos bsdtar = &bsdtar_storage; 14960b4ad09SPeter Avalos memset(bsdtar, 0, sizeof(*bsdtar)); 15060b4ad09SPeter Avalos bsdtar->fd = -1; /* Mark as "unused" */ 151c09f92d2SPeter Avalos bsdtar->gid = -1; 152c09f92d2SPeter Avalos bsdtar->uid = -1; 153*d4d8193eSPeter Avalos option_a = option_o = 0; 154*d4d8193eSPeter Avalos compression = compression2 = '\0'; 155*d4d8193eSPeter Avalos compression_name = compression2_name = NULL; 156*d4d8193eSPeter Avalos compress_program = NULL; 1579c82a63eSPeter Avalos 158c09f92d2SPeter Avalos #if defined(HAVE_SIGACTION) 159c09f92d2SPeter Avalos { /* Set up signal handling. */ 1609c82a63eSPeter Avalos struct sigaction sa; 1619c82a63eSPeter Avalos sa.sa_handler = siginfo_handler; 1629c82a63eSPeter Avalos sigemptyset(&sa.sa_mask); 1639c82a63eSPeter Avalos sa.sa_flags = 0; 1649c82a63eSPeter Avalos #ifdef SIGINFO 1659c82a63eSPeter Avalos if (sigaction(SIGINFO, &sa, NULL)) 1669c82a63eSPeter Avalos lafe_errc(1, errno, "sigaction(SIGINFO) failed"); 1679c82a63eSPeter Avalos #endif 1689c82a63eSPeter Avalos #ifdef SIGUSR1 1699c82a63eSPeter Avalos /* ... and treat SIGUSR1 the same way as SIGINFO. */ 1709c82a63eSPeter Avalos if (sigaction(SIGUSR1, &sa, NULL)) 1719c82a63eSPeter Avalos lafe_errc(1, errno, "sigaction(SIGUSR1) failed"); 1729c82a63eSPeter Avalos #endif 173c09f92d2SPeter Avalos #ifdef SIGPIPE 174c09f92d2SPeter Avalos /* Ignore SIGPIPE signals. */ 175c09f92d2SPeter Avalos sa.sa_handler = SIG_IGN; 176c09f92d2SPeter Avalos sigaction(SIGPIPE, &sa, NULL); 177c09f92d2SPeter Avalos #endif 1789c82a63eSPeter Avalos } 1798029ab02SPeter Avalos #endif 18060b4ad09SPeter Avalos 1819c82a63eSPeter Avalos 1829c82a63eSPeter Avalos /* Need lafe_progname before calling lafe_warnc. */ 18360b4ad09SPeter Avalos if (*argv == NULL) 1849c82a63eSPeter Avalos lafe_progname = "bsdtar"; 18560b4ad09SPeter Avalos else { 1868029ab02SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 1879c82a63eSPeter Avalos lafe_progname = strrchr(*argv, '\\'); 18859bf7050SPeter Avalos if (strrchr(*argv, '/') > lafe_progname) 1898029ab02SPeter Avalos #endif 19059bf7050SPeter Avalos lafe_progname = strrchr(*argv, '/'); 1919c82a63eSPeter Avalos if (lafe_progname != NULL) 1929c82a63eSPeter Avalos lafe_progname++; 19360b4ad09SPeter Avalos else 1949c82a63eSPeter Avalos lafe_progname = *argv; 19560b4ad09SPeter Avalos } 19660b4ad09SPeter Avalos 1979c82a63eSPeter Avalos #if HAVE_SETLOCALE 19860b4ad09SPeter Avalos if (setlocale(LC_ALL, "") == NULL) 1999c82a63eSPeter Avalos lafe_warnc(0, "Failed to set default locale"); 2009c82a63eSPeter Avalos #endif 20160b4ad09SPeter Avalos #if defined(HAVE_NL_LANGINFO) && defined(HAVE_D_MD_ORDER) 20260b4ad09SPeter Avalos bsdtar->day_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 20360b4ad09SPeter Avalos #endif 20460b4ad09SPeter Avalos possible_help_request = 0; 20560b4ad09SPeter Avalos 20660b4ad09SPeter Avalos /* Look up uid of current user for future reference */ 20760b4ad09SPeter Avalos bsdtar->user_uid = geteuid(); 20860b4ad09SPeter Avalos 20960b4ad09SPeter Avalos /* Default: open tape drive. */ 21060b4ad09SPeter Avalos bsdtar->filename = getenv("TAPE"); 21160b4ad09SPeter Avalos if (bsdtar->filename == NULL) 21260b4ad09SPeter Avalos bsdtar->filename = _PATH_DEFTAPE; 21360b4ad09SPeter Avalos 214c09f92d2SPeter Avalos /* Default block size settings. */ 215c09f92d2SPeter Avalos bsdtar->bytes_per_block = DEFAULT_BYTES_PER_BLOCK; 216c09f92d2SPeter Avalos /* Allow library to default this unless user specifies -b. */ 217c09f92d2SPeter Avalos bsdtar->bytes_in_last_block = -1; 218c09f92d2SPeter Avalos 21960b4ad09SPeter Avalos /* Default: preserve mod time on extract */ 22060b4ad09SPeter Avalos bsdtar->extract_flags = ARCHIVE_EXTRACT_TIME; 22160b4ad09SPeter Avalos 22260b4ad09SPeter Avalos /* Default: Perform basic security checks. */ 22360b4ad09SPeter Avalos bsdtar->extract_flags |= SECURITY; 22460b4ad09SPeter Avalos 2259c82a63eSPeter Avalos #ifndef _WIN32 2269c82a63eSPeter Avalos /* On POSIX systems, assume --same-owner and -p when run by 2279c82a63eSPeter Avalos * the root user. This doesn't make any sense on Windows. */ 2289c82a63eSPeter Avalos if (bsdtar->user_uid == 0) { 22960b4ad09SPeter Avalos /* --same-owner */ 23060b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER; 23160b4ad09SPeter Avalos /* -p */ 23260b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; 23360b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; 23460b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; 23560b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; 236c09f92d2SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_MAC_METADATA; 23760b4ad09SPeter Avalos } 2389c82a63eSPeter Avalos #endif 23960b4ad09SPeter Avalos 240c09f92d2SPeter Avalos /* 241c09f92d2SPeter Avalos * Enable Mac OS "copyfile()" extension by default. 242c09f92d2SPeter Avalos * This has no effect on other platforms. 243c09f92d2SPeter Avalos */ 24459bf7050SPeter Avalos bsdtar->readdisk_flags |= ARCHIVE_READDISK_MAC_COPYFILE; 245c09f92d2SPeter Avalos #ifdef COPYFILE_DISABLE_VAR 246c09f92d2SPeter Avalos if (getenv(COPYFILE_DISABLE_VAR)) 24759bf7050SPeter Avalos bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE; 248c09f92d2SPeter Avalos #endif 24959bf7050SPeter Avalos bsdtar->matching = archive_match_new(); 25059bf7050SPeter Avalos if (bsdtar->matching == NULL) 25159bf7050SPeter Avalos lafe_errc(1, errno, "Out of memory"); 252*d4d8193eSPeter Avalos bsdtar->cset = cset_new(); 253*d4d8193eSPeter Avalos if (bsdtar->cset == NULL) 254*d4d8193eSPeter Avalos lafe_errc(1, errno, "Out of memory"); 255c09f92d2SPeter Avalos 25660b4ad09SPeter Avalos bsdtar->argv = argv; 25760b4ad09SPeter Avalos bsdtar->argc = argc; 25860b4ad09SPeter Avalos 25960b4ad09SPeter Avalos /* 26060b4ad09SPeter Avalos * Comments following each option indicate where that option 26160b4ad09SPeter Avalos * originated: SUSv2, POSIX, GNU tar, star, etc. If there's 26260b4ad09SPeter Avalos * no such comment, then I don't know of anyone else who 26360b4ad09SPeter Avalos * implements that option. 26460b4ad09SPeter Avalos */ 2658029ab02SPeter Avalos while ((opt = bsdtar_getopt(bsdtar)) != -1) { 26660b4ad09SPeter Avalos switch (opt) { 267*d4d8193eSPeter Avalos case 'a': /* GNU tar */ 268*d4d8193eSPeter Avalos option_a = 1; /* Record it and resolve it later. */ 269*d4d8193eSPeter Avalos break; 27060b4ad09SPeter Avalos case 'B': /* GNU tar */ 27160b4ad09SPeter Avalos /* libarchive doesn't need this; just ignore it. */ 27260b4ad09SPeter Avalos break; 27360b4ad09SPeter Avalos case 'b': /* SUSv2 */ 274c09f92d2SPeter Avalos t = atoi(bsdtar->argument); 2759c82a63eSPeter Avalos if (t <= 0 || t > 8192) 2769c82a63eSPeter Avalos lafe_errc(1, 0, 2779c82a63eSPeter Avalos "Argument to -b is out of range (1..8192)"); 27860b4ad09SPeter Avalos bsdtar->bytes_per_block = 512 * t; 279c09f92d2SPeter Avalos /* Explicit -b forces last block size. */ 280c09f92d2SPeter Avalos bsdtar->bytes_in_last_block = bsdtar->bytes_per_block; 28160b4ad09SPeter Avalos break; 282*d4d8193eSPeter Avalos case OPTION_B64ENCODE: 283*d4d8193eSPeter Avalos if (compression2 != '\0') 284*d4d8193eSPeter Avalos lafe_errc(1, 0, 285*d4d8193eSPeter Avalos "Can't specify both --uuencode and " 286*d4d8193eSPeter Avalos "--b64encode"); 287*d4d8193eSPeter Avalos compression2 = opt; 288*d4d8193eSPeter Avalos compression2_name = "b64encode"; 289*d4d8193eSPeter Avalos break; 29060b4ad09SPeter Avalos case 'C': /* GNU tar */ 291c09f92d2SPeter Avalos if (strlen(bsdtar->argument) == 0) 292c09f92d2SPeter Avalos lafe_errc(1, 0, 293c09f92d2SPeter Avalos "Meaningless option: -C ''"); 294c09f92d2SPeter Avalos 295c09f92d2SPeter Avalos set_chdir(bsdtar, bsdtar->argument); 29660b4ad09SPeter Avalos break; 29760b4ad09SPeter Avalos case 'c': /* SUSv2 */ 29860b4ad09SPeter Avalos set_mode(bsdtar, opt); 29960b4ad09SPeter Avalos break; 30060b4ad09SPeter Avalos case OPTION_CHECK_LINKS: /* GNU tar */ 30160b4ad09SPeter Avalos bsdtar->option_warn_links = 1; 30260b4ad09SPeter Avalos break; 30360b4ad09SPeter Avalos case OPTION_CHROOT: /* NetBSD */ 30460b4ad09SPeter Avalos bsdtar->option_chroot = 1; 30560b4ad09SPeter Avalos break; 306c09f92d2SPeter Avalos case OPTION_DISABLE_COPYFILE: /* Mac OS X */ 30759bf7050SPeter Avalos bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE; 308c09f92d2SPeter Avalos break; 30960b4ad09SPeter Avalos case OPTION_EXCLUDE: /* GNU tar */ 31059bf7050SPeter Avalos if (archive_match_exclude_pattern( 31159bf7050SPeter Avalos bsdtar->matching, bsdtar->argument) != ARCHIVE_OK) 3129c82a63eSPeter Avalos lafe_errc(1, 0, 313c09f92d2SPeter Avalos "Couldn't exclude %s\n", bsdtar->argument); 31460b4ad09SPeter Avalos break; 31560b4ad09SPeter Avalos case OPTION_FORMAT: /* GNU tar, others */ 316*d4d8193eSPeter Avalos cset_set_format(bsdtar->cset, bsdtar->argument); 31760b4ad09SPeter Avalos break; 31860b4ad09SPeter Avalos case 'f': /* SUSv2 */ 319c09f92d2SPeter Avalos bsdtar->filename = bsdtar->argument; 320c09f92d2SPeter Avalos break; 321c09f92d2SPeter Avalos case OPTION_GID: /* cpio */ 322c09f92d2SPeter Avalos t = atoi(bsdtar->argument); 323c09f92d2SPeter Avalos if (t < 0) 324c09f92d2SPeter Avalos lafe_errc(1, 0, 325c09f92d2SPeter Avalos "Argument to --gid must be positive"); 326c09f92d2SPeter Avalos bsdtar->gid = t; 327c09f92d2SPeter Avalos break; 328c09f92d2SPeter Avalos case OPTION_GNAME: /* cpio */ 329c09f92d2SPeter Avalos bsdtar->gname = bsdtar->argument; 33060b4ad09SPeter Avalos break; 331*d4d8193eSPeter Avalos case OPTION_GRZIP: 332*d4d8193eSPeter Avalos if (compression != '\0') 333*d4d8193eSPeter Avalos lafe_errc(1, 0, 334*d4d8193eSPeter Avalos "Can't specify both -%c and -%c", opt, 335*d4d8193eSPeter Avalos compression); 336*d4d8193eSPeter Avalos compression = opt; 337*d4d8193eSPeter Avalos compression_name = "grzip"; 338*d4d8193eSPeter Avalos break; 33960b4ad09SPeter Avalos case 'H': /* BSD convention */ 34060b4ad09SPeter Avalos bsdtar->symlink_mode = 'H'; 34160b4ad09SPeter Avalos break; 34260b4ad09SPeter Avalos case 'h': /* Linux Standards Base, gtar; synonym for -L */ 34360b4ad09SPeter Avalos bsdtar->symlink_mode = 'L'; 34460b4ad09SPeter Avalos /* Hack: -h by itself is the "help" command. */ 34560b4ad09SPeter Avalos possible_help_request = 1; 34660b4ad09SPeter Avalos break; 34760b4ad09SPeter Avalos case OPTION_HELP: /* GNU tar, others */ 3489c82a63eSPeter Avalos long_help(); 34960b4ad09SPeter Avalos exit(0); 35060b4ad09SPeter Avalos break; 351*d4d8193eSPeter Avalos case OPTION_HFS_COMPRESSION: /* Mac OS X v10.6 or later */ 352*d4d8193eSPeter Avalos bsdtar->extract_flags |= 353*d4d8193eSPeter Avalos ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED; 354*d4d8193eSPeter Avalos break; 35560b4ad09SPeter Avalos case 'I': /* GNU tar */ 35660b4ad09SPeter Avalos /* 35760b4ad09SPeter Avalos * TODO: Allow 'names' to come from an archive, 35860b4ad09SPeter Avalos * not just a text file. Design a good UI for 35960b4ad09SPeter Avalos * allowing names and mode/owner to be read 36060b4ad09SPeter Avalos * from an archive, with contents coming from 36160b4ad09SPeter Avalos * disk. This can be used to "refresh" an 36260b4ad09SPeter Avalos * archive or to design archives with special 36360b4ad09SPeter Avalos * permissions without having to create those 36460b4ad09SPeter Avalos * permissions on disk. 36560b4ad09SPeter Avalos */ 366c09f92d2SPeter Avalos bsdtar->names_from_file = bsdtar->argument; 36760b4ad09SPeter Avalos break; 36860b4ad09SPeter Avalos case OPTION_INCLUDE: 36960b4ad09SPeter Avalos /* 37060b4ad09SPeter Avalos * No one else has the @archive extension, so 37160b4ad09SPeter Avalos * no one else needs this to filter entries 37260b4ad09SPeter Avalos * when transforming archives. 37360b4ad09SPeter Avalos */ 37459bf7050SPeter Avalos if (archive_match_include_pattern(bsdtar->matching, 37559bf7050SPeter Avalos bsdtar->argument) != ARCHIVE_OK) 3769c82a63eSPeter Avalos lafe_errc(1, 0, 37760b4ad09SPeter Avalos "Failed to add %s to inclusion list", 378c09f92d2SPeter Avalos bsdtar->argument); 37960b4ad09SPeter Avalos break; 38060b4ad09SPeter Avalos case 'j': /* GNU tar */ 381*d4d8193eSPeter Avalos if (compression != '\0') 3829c82a63eSPeter Avalos lafe_errc(1, 0, 38360b4ad09SPeter Avalos "Can't specify both -%c and -%c", opt, 384*d4d8193eSPeter Avalos compression); 385*d4d8193eSPeter Avalos compression = opt; 386*d4d8193eSPeter Avalos compression_name = "bzip2"; 3878029ab02SPeter Avalos break; 3888029ab02SPeter Avalos case 'J': /* GNU tar 1.21 and later */ 389*d4d8193eSPeter Avalos if (compression != '\0') 3909c82a63eSPeter Avalos lafe_errc(1, 0, 3918029ab02SPeter Avalos "Can't specify both -%c and -%c", opt, 392*d4d8193eSPeter Avalos compression); 393*d4d8193eSPeter Avalos compression = opt; 394*d4d8193eSPeter Avalos compression_name = "xz"; 39560b4ad09SPeter Avalos break; 39660b4ad09SPeter Avalos case 'k': /* GNU tar */ 39760b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE; 39860b4ad09SPeter Avalos break; 39960b4ad09SPeter Avalos case OPTION_KEEP_NEWER_FILES: /* GNU tar */ 40060b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; 40160b4ad09SPeter Avalos break; 40260b4ad09SPeter Avalos case 'L': /* BSD convention */ 40360b4ad09SPeter Avalos bsdtar->symlink_mode = 'L'; 40460b4ad09SPeter Avalos break; 40560b4ad09SPeter Avalos case 'l': /* SUSv2 and GNU tar beginning with 1.16 */ 40660b4ad09SPeter Avalos /* GNU tar 1.13 used -l for --one-file-system */ 40760b4ad09SPeter Avalos bsdtar->option_warn_links = 1; 40860b4ad09SPeter Avalos break; 409*d4d8193eSPeter Avalos case OPTION_LRZIP: 410c09f92d2SPeter Avalos case OPTION_LZIP: /* GNU tar beginning with 1.23 */ 411c09f92d2SPeter Avalos case OPTION_LZMA: /* GNU tar beginning with 1.20 */ 412*d4d8193eSPeter Avalos case OPTION_LZOP: /* GNU tar beginning with 1.21 */ 413*d4d8193eSPeter Avalos if (compression != '\0') 4149c82a63eSPeter Avalos lafe_errc(1, 0, 4158029ab02SPeter Avalos "Can't specify both -%c and -%c", opt, 416*d4d8193eSPeter Avalos compression); 417*d4d8193eSPeter Avalos compression = opt; 418*d4d8193eSPeter Avalos switch (opt) { 419*d4d8193eSPeter Avalos case OPTION_LRZIP: compression_name = "lrzip"; break; 420*d4d8193eSPeter Avalos case OPTION_LZIP: compression_name = "lzip"; break; 421*d4d8193eSPeter Avalos case OPTION_LZMA: compression_name = "lzma"; break; 422*d4d8193eSPeter Avalos case OPTION_LZOP: compression_name = "lzop"; break; 423*d4d8193eSPeter Avalos } 4248029ab02SPeter Avalos break; 42560b4ad09SPeter Avalos case 'm': /* SUSv2 */ 42660b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_TIME; 42760b4ad09SPeter Avalos break; 42860b4ad09SPeter Avalos case 'n': /* GNU tar */ 42960b4ad09SPeter Avalos bsdtar->option_no_subdirs = 1; 43060b4ad09SPeter Avalos break; 43160b4ad09SPeter Avalos /* 43260b4ad09SPeter Avalos * Selecting files by time: 43360b4ad09SPeter Avalos * --newer-?time='date' Only files newer than 'date' 43460b4ad09SPeter Avalos * --newer-?time-than='file' Only files newer than time 43560b4ad09SPeter Avalos * on specified file (useful for incremental backups) 43660b4ad09SPeter Avalos */ 43760b4ad09SPeter Avalos case OPTION_NEWER_CTIME: /* GNU tar */ 43859bf7050SPeter Avalos if (archive_match_include_date(bsdtar->matching, 43959bf7050SPeter Avalos ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER, 44059bf7050SPeter Avalos bsdtar->argument) != ARCHIVE_OK) 44159bf7050SPeter Avalos lafe_errc(1, 0, "Error : %s", 44259bf7050SPeter Avalos archive_error_string(bsdtar->matching)); 44360b4ad09SPeter Avalos break; 44460b4ad09SPeter Avalos case OPTION_NEWER_CTIME_THAN: 44559bf7050SPeter Avalos if (archive_match_include_file_time(bsdtar->matching, 44659bf7050SPeter Avalos ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER, 44759bf7050SPeter Avalos bsdtar->argument) != ARCHIVE_OK) 44859bf7050SPeter Avalos lafe_errc(1, 0, "Error : %s", 44959bf7050SPeter Avalos archive_error_string(bsdtar->matching)); 45060b4ad09SPeter Avalos break; 45160b4ad09SPeter Avalos case OPTION_NEWER_MTIME: /* GNU tar */ 45259bf7050SPeter Avalos if (archive_match_include_date(bsdtar->matching, 45359bf7050SPeter Avalos ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER, 45459bf7050SPeter Avalos bsdtar->argument) != ARCHIVE_OK) 45559bf7050SPeter Avalos lafe_errc(1, 0, "Error : %s", 45659bf7050SPeter Avalos archive_error_string(bsdtar->matching)); 45760b4ad09SPeter Avalos break; 45860b4ad09SPeter Avalos case OPTION_NEWER_MTIME_THAN: 45959bf7050SPeter Avalos if (archive_match_include_file_time(bsdtar->matching, 46059bf7050SPeter Avalos ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER, 46159bf7050SPeter Avalos bsdtar->argument) != ARCHIVE_OK) 46259bf7050SPeter Avalos lafe_errc(1, 0, "Error : %s", 46359bf7050SPeter Avalos archive_error_string(bsdtar->matching)); 46460b4ad09SPeter Avalos break; 46560b4ad09SPeter Avalos case OPTION_NODUMP: /* star */ 46659bf7050SPeter Avalos bsdtar->readdisk_flags |= ARCHIVE_READDISK_HONOR_NODUMP; 46760b4ad09SPeter Avalos break; 468*d4d8193eSPeter Avalos case OPTION_NOPRESERVE_HFS_COMPRESSION: 469*d4d8193eSPeter Avalos /* Mac OS X v10.6 or later */ 470*d4d8193eSPeter Avalos bsdtar->extract_flags |= 471*d4d8193eSPeter Avalos ARCHIVE_EXTRACT_NO_HFS_COMPRESSION; 472*d4d8193eSPeter Avalos break; 47360b4ad09SPeter Avalos case OPTION_NO_SAME_OWNER: /* GNU tar */ 47460b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; 47560b4ad09SPeter Avalos break; 47660b4ad09SPeter Avalos case OPTION_NO_SAME_PERMISSIONS: /* GNU tar */ 47760b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_PERM; 47860b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_ACL; 47960b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_XATTR; 48060b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_FFLAGS; 481c09f92d2SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_MAC_METADATA; 48260b4ad09SPeter Avalos break; 48360b4ad09SPeter Avalos case OPTION_NULL: /* GNU tar */ 48460b4ad09SPeter Avalos bsdtar->option_null++; 48560b4ad09SPeter Avalos break; 48660b4ad09SPeter Avalos case OPTION_NUMERIC_OWNER: /* GNU tar */ 487c09f92d2SPeter Avalos bsdtar->uname = ""; 488c09f92d2SPeter Avalos bsdtar->gname = ""; 48960b4ad09SPeter Avalos bsdtar->option_numeric_owner++; 49060b4ad09SPeter Avalos break; 49160b4ad09SPeter Avalos case 'O': /* GNU tar */ 49260b4ad09SPeter Avalos bsdtar->option_stdout = 1; 49360b4ad09SPeter Avalos break; 49460b4ad09SPeter Avalos case 'o': /* SUSv2 and GNU conflict here, but not fatally */ 49560b4ad09SPeter Avalos option_o = 1; /* Record it and resolve it later. */ 49660b4ad09SPeter Avalos break; 497*d4d8193eSPeter Avalos /* 498*d4d8193eSPeter Avalos * Selecting files by time: 499*d4d8193eSPeter Avalos * --older-?time='date' Only files older than 'date' 500*d4d8193eSPeter Avalos * --older-?time-than='file' Only files older than time 501*d4d8193eSPeter Avalos * on specified file 502*d4d8193eSPeter Avalos */ 503*d4d8193eSPeter Avalos case OPTION_OLDER_CTIME: 504*d4d8193eSPeter Avalos if (archive_match_include_date(bsdtar->matching, 505*d4d8193eSPeter Avalos ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_OLDER, 506*d4d8193eSPeter Avalos bsdtar->argument) != ARCHIVE_OK) 507*d4d8193eSPeter Avalos lafe_errc(1, 0, "Error : %s", 508*d4d8193eSPeter Avalos archive_error_string(bsdtar->matching)); 509*d4d8193eSPeter Avalos break; 510*d4d8193eSPeter Avalos case OPTION_OLDER_CTIME_THAN: 511*d4d8193eSPeter Avalos if (archive_match_include_file_time(bsdtar->matching, 512*d4d8193eSPeter Avalos ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_OLDER, 513*d4d8193eSPeter Avalos bsdtar->argument) != ARCHIVE_OK) 514*d4d8193eSPeter Avalos lafe_errc(1, 0, "Error : %s", 515*d4d8193eSPeter Avalos archive_error_string(bsdtar->matching)); 516*d4d8193eSPeter Avalos break; 517*d4d8193eSPeter Avalos case OPTION_OLDER_MTIME: 518*d4d8193eSPeter Avalos if (archive_match_include_date(bsdtar->matching, 519*d4d8193eSPeter Avalos ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER, 520*d4d8193eSPeter Avalos bsdtar->argument) != ARCHIVE_OK) 521*d4d8193eSPeter Avalos lafe_errc(1, 0, "Error : %s", 522*d4d8193eSPeter Avalos archive_error_string(bsdtar->matching)); 523*d4d8193eSPeter Avalos break; 524*d4d8193eSPeter Avalos case OPTION_OLDER_MTIME_THAN: 525*d4d8193eSPeter Avalos if (archive_match_include_file_time(bsdtar->matching, 526*d4d8193eSPeter Avalos ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER, 527*d4d8193eSPeter Avalos bsdtar->argument) != ARCHIVE_OK) 528*d4d8193eSPeter Avalos lafe_errc(1, 0, "Error : %s", 529*d4d8193eSPeter Avalos archive_error_string(bsdtar->matching)); 530*d4d8193eSPeter Avalos break; 53160b4ad09SPeter Avalos case OPTION_ONE_FILE_SYSTEM: /* GNU tar */ 53259bf7050SPeter Avalos bsdtar->readdisk_flags |= 53359bf7050SPeter Avalos ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS; 53460b4ad09SPeter Avalos break; 535c09f92d2SPeter Avalos case OPTION_OPTIONS: 536c09f92d2SPeter Avalos bsdtar->option_options = bsdtar->argument; 537c09f92d2SPeter Avalos break; 53860b4ad09SPeter Avalos #if 0 53960b4ad09SPeter Avalos /* 54060b4ad09SPeter Avalos * The common BSD -P option is not necessary, since 54160b4ad09SPeter Avalos * our default is to archive symlinks, not follow 54260b4ad09SPeter Avalos * them. This is convenient, as -P conflicts with GNU 54360b4ad09SPeter Avalos * tar anyway. 54460b4ad09SPeter Avalos */ 54560b4ad09SPeter Avalos case 'P': /* BSD convention */ 54660b4ad09SPeter Avalos /* Default behavior, no option necessary. */ 54760b4ad09SPeter Avalos break; 54860b4ad09SPeter Avalos #endif 54960b4ad09SPeter Avalos case 'P': /* GNU tar */ 55060b4ad09SPeter Avalos bsdtar->extract_flags &= ~SECURITY; 55160b4ad09SPeter Avalos bsdtar->option_absolute_paths = 1; 55260b4ad09SPeter Avalos break; 55360b4ad09SPeter Avalos case 'p': /* GNU tar, star */ 55460b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; 55560b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; 55660b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; 55760b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; 558c09f92d2SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_MAC_METADATA; 55960b4ad09SPeter Avalos break; 56060b4ad09SPeter Avalos case OPTION_POSIX: /* GNU tar */ 561*d4d8193eSPeter Avalos cset_set_format(bsdtar->cset, "pax"); 56260b4ad09SPeter Avalos break; 56360b4ad09SPeter Avalos case 'q': /* FreeBSD GNU tar --fast-read, NetBSD -q */ 56460b4ad09SPeter Avalos bsdtar->option_fast_read = 1; 56560b4ad09SPeter Avalos break; 56660b4ad09SPeter Avalos case 'r': /* SUSv2 */ 56760b4ad09SPeter Avalos set_mode(bsdtar, opt); 56860b4ad09SPeter Avalos break; 56960b4ad09SPeter Avalos case 'S': /* NetBSD pax-as-tar */ 57060b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_SPARSE; 57160b4ad09SPeter Avalos break; 57260b4ad09SPeter Avalos case 's': /* NetBSD pax-as-tar */ 573*d4d8193eSPeter Avalos #if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) 574c09f92d2SPeter Avalos add_substitution(bsdtar, bsdtar->argument); 57560b4ad09SPeter Avalos #else 5769c82a63eSPeter Avalos lafe_warnc(0, 5778029ab02SPeter Avalos "-s is not supported by this version of bsdtar"); 5789c82a63eSPeter Avalos usage(); 57960b4ad09SPeter Avalos #endif 58060b4ad09SPeter Avalos break; 5818029ab02SPeter Avalos case OPTION_SAME_OWNER: /* GNU tar */ 5828029ab02SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER; 5838029ab02SPeter Avalos break; 58460b4ad09SPeter Avalos case OPTION_STRIP_COMPONENTS: /* GNU tar 1.15 */ 585c09f92d2SPeter Avalos errno = 0; 586c09f92d2SPeter Avalos bsdtar->strip_components = strtol(bsdtar->argument, 587c09f92d2SPeter Avalos NULL, 0); 588c09f92d2SPeter Avalos if (errno) 589c09f92d2SPeter Avalos lafe_errc(1, 0, 590c09f92d2SPeter Avalos "Invalid --strip-components argument: %s", 591c09f92d2SPeter Avalos bsdtar->argument); 59260b4ad09SPeter Avalos break; 59360b4ad09SPeter Avalos case 'T': /* GNU tar */ 594c09f92d2SPeter Avalos bsdtar->names_from_file = bsdtar->argument; 59560b4ad09SPeter Avalos break; 59660b4ad09SPeter Avalos case 't': /* SUSv2 */ 59760b4ad09SPeter Avalos set_mode(bsdtar, opt); 59860b4ad09SPeter Avalos bsdtar->verbose++; 59960b4ad09SPeter Avalos break; 60060b4ad09SPeter Avalos case OPTION_TOTALS: /* GNU tar */ 60160b4ad09SPeter Avalos bsdtar->option_totals++; 60260b4ad09SPeter Avalos break; 60360b4ad09SPeter Avalos case 'U': /* GNU tar */ 60460b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_UNLINK; 60560b4ad09SPeter Avalos bsdtar->option_unlink_first = 1; 60660b4ad09SPeter Avalos break; 60760b4ad09SPeter Avalos case 'u': /* SUSv2 */ 60860b4ad09SPeter Avalos set_mode(bsdtar, opt); 60960b4ad09SPeter Avalos break; 610c09f92d2SPeter Avalos case OPTION_UID: /* cpio */ 611c09f92d2SPeter Avalos t = atoi(bsdtar->argument); 612c09f92d2SPeter Avalos if (t < 0) 613c09f92d2SPeter Avalos lafe_errc(1, 0, 614c09f92d2SPeter Avalos "Argument to --uid must be positive"); 615c09f92d2SPeter Avalos bsdtar->uid = t; 616c09f92d2SPeter Avalos break; 617c09f92d2SPeter Avalos case OPTION_UNAME: /* cpio */ 618c09f92d2SPeter Avalos bsdtar->uname = bsdtar->argument; 619c09f92d2SPeter Avalos break; 620*d4d8193eSPeter Avalos case OPTION_UUENCODE: 621*d4d8193eSPeter Avalos if (compression2 != '\0') 622*d4d8193eSPeter Avalos lafe_errc(1, 0, 623*d4d8193eSPeter Avalos "Can't specify both --uuencode and " 624*d4d8193eSPeter Avalos "--b64encode"); 625*d4d8193eSPeter Avalos compression2 = opt; 626*d4d8193eSPeter Avalos compression2_name = "uuencode"; 627*d4d8193eSPeter Avalos break; 62860b4ad09SPeter Avalos case 'v': /* SUSv2 */ 62960b4ad09SPeter Avalos bsdtar->verbose++; 63060b4ad09SPeter Avalos break; 63160b4ad09SPeter Avalos case OPTION_VERSION: /* GNU convention */ 63260b4ad09SPeter Avalos version(); 63360b4ad09SPeter Avalos break; 63460b4ad09SPeter Avalos #if 0 63560b4ad09SPeter Avalos /* 63660b4ad09SPeter Avalos * The -W longopt feature is handled inside of 6378029ab02SPeter Avalos * bsdtar_getopt(), so -W is not available here. 63860b4ad09SPeter Avalos */ 6398029ab02SPeter Avalos case 'W': /* Obscure GNU convention. */ 64060b4ad09SPeter Avalos break; 64160b4ad09SPeter Avalos #endif 64260b4ad09SPeter Avalos case 'w': /* SUSv2 */ 64360b4ad09SPeter Avalos bsdtar->option_interactive = 1; 64460b4ad09SPeter Avalos break; 64560b4ad09SPeter Avalos case 'X': /* GNU tar */ 64659bf7050SPeter Avalos if (archive_match_exclude_pattern_from_file( 64759bf7050SPeter Avalos bsdtar->matching, bsdtar->argument, 0) 64859bf7050SPeter Avalos != ARCHIVE_OK) 64959bf7050SPeter Avalos lafe_errc(1, 0, "Error : %s", 65059bf7050SPeter Avalos archive_error_string(bsdtar->matching)); 65160b4ad09SPeter Avalos break; 65260b4ad09SPeter Avalos case 'x': /* SUSv2 */ 65360b4ad09SPeter Avalos set_mode(bsdtar, opt); 65460b4ad09SPeter Avalos break; 65560b4ad09SPeter Avalos case 'y': /* FreeBSD version of GNU tar */ 656*d4d8193eSPeter Avalos if (compression != '\0') 6579c82a63eSPeter Avalos lafe_errc(1, 0, 65860b4ad09SPeter Avalos "Can't specify both -%c and -%c", opt, 659*d4d8193eSPeter Avalos compression); 660*d4d8193eSPeter Avalos compression = opt; 661*d4d8193eSPeter Avalos compression_name = "bzip2"; 66260b4ad09SPeter Avalos break; 66360b4ad09SPeter Avalos case 'Z': /* GNU tar */ 664*d4d8193eSPeter Avalos if (compression != '\0') 6659c82a63eSPeter Avalos lafe_errc(1, 0, 66660b4ad09SPeter Avalos "Can't specify both -%c and -%c", opt, 667*d4d8193eSPeter Avalos compression); 668*d4d8193eSPeter Avalos compression = opt; 669*d4d8193eSPeter Avalos compression_name = "compress"; 67060b4ad09SPeter Avalos break; 67160b4ad09SPeter Avalos case 'z': /* GNU tar, star, many others */ 672*d4d8193eSPeter Avalos if (compression != '\0') 6739c82a63eSPeter Avalos lafe_errc(1, 0, 67460b4ad09SPeter Avalos "Can't specify both -%c and -%c", opt, 675*d4d8193eSPeter Avalos compression); 676*d4d8193eSPeter Avalos compression = opt; 677*d4d8193eSPeter Avalos compression_name = "gzip"; 67860b4ad09SPeter Avalos break; 67960b4ad09SPeter Avalos case OPTION_USE_COMPRESS_PROGRAM: 680*d4d8193eSPeter Avalos compress_program = bsdtar->argument; 68160b4ad09SPeter Avalos break; 68260b4ad09SPeter Avalos default: 6839c82a63eSPeter Avalos usage(); 68460b4ad09SPeter Avalos } 68560b4ad09SPeter Avalos } 68660b4ad09SPeter Avalos 68760b4ad09SPeter Avalos /* 68860b4ad09SPeter Avalos * Sanity-check options. 68960b4ad09SPeter Avalos */ 69060b4ad09SPeter Avalos 69160b4ad09SPeter Avalos /* If no "real" mode was specified, treat -h as --help. */ 69260b4ad09SPeter Avalos if ((bsdtar->mode == '\0') && possible_help_request) { 6939c82a63eSPeter Avalos long_help(); 69460b4ad09SPeter Avalos exit(0); 69560b4ad09SPeter Avalos } 69660b4ad09SPeter Avalos 69760b4ad09SPeter Avalos /* Otherwise, a mode is required. */ 69860b4ad09SPeter Avalos if (bsdtar->mode == '\0') 6999c82a63eSPeter Avalos lafe_errc(1, 0, 70060b4ad09SPeter Avalos "Must specify one of -c, -r, -t, -u, -x"); 70160b4ad09SPeter Avalos 70260b4ad09SPeter Avalos /* Check boolean options only permitted in certain modes. */ 703*d4d8193eSPeter Avalos if (option_a) 704*d4d8193eSPeter Avalos only_mode(bsdtar, "-a", "c"); 70559bf7050SPeter Avalos if (bsdtar->readdisk_flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) 70660b4ad09SPeter Avalos only_mode(bsdtar, "--one-file-system", "cru"); 70760b4ad09SPeter Avalos if (bsdtar->option_fast_read) 70860b4ad09SPeter Avalos only_mode(bsdtar, "--fast-read", "xt"); 709*d4d8193eSPeter Avalos if (bsdtar->extract_flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED) 710*d4d8193eSPeter Avalos only_mode(bsdtar, "--hfsCompression", "x"); 711*d4d8193eSPeter Avalos if (bsdtar->extract_flags & ARCHIVE_EXTRACT_NO_HFS_COMPRESSION) 712*d4d8193eSPeter Avalos only_mode(bsdtar, "--nopreserveHFSCompression", "x"); 71359bf7050SPeter Avalos if (bsdtar->readdisk_flags & ARCHIVE_READDISK_HONOR_NODUMP) 71460b4ad09SPeter Avalos only_mode(bsdtar, "--nodump", "cru"); 71560b4ad09SPeter Avalos if (option_o > 0) { 71660b4ad09SPeter Avalos switch (bsdtar->mode) { 71760b4ad09SPeter Avalos case 'c': 71860b4ad09SPeter Avalos /* 71960b4ad09SPeter Avalos * In GNU tar, -o means "old format." The 72060b4ad09SPeter Avalos * "ustar" format is the closest thing 72160b4ad09SPeter Avalos * supported by libarchive. 72260b4ad09SPeter Avalos */ 723*d4d8193eSPeter Avalos cset_set_format(bsdtar->cset, "ustar"); 72460b4ad09SPeter Avalos /* TODO: bsdtar->create_format = "v7"; */ 72560b4ad09SPeter Avalos break; 72660b4ad09SPeter Avalos case 'x': 72760b4ad09SPeter Avalos /* POSIX-compatible behavior. */ 72860b4ad09SPeter Avalos bsdtar->option_no_owner = 1; 72960b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; 73060b4ad09SPeter Avalos break; 73160b4ad09SPeter Avalos default: 73260b4ad09SPeter Avalos only_mode(bsdtar, "-o", "xc"); 73360b4ad09SPeter Avalos break; 73460b4ad09SPeter Avalos } 73560b4ad09SPeter Avalos } 73660b4ad09SPeter Avalos if (bsdtar->option_no_subdirs) 73760b4ad09SPeter Avalos only_mode(bsdtar, "-n", "cru"); 73860b4ad09SPeter Avalos if (bsdtar->option_stdout) 73960b4ad09SPeter Avalos only_mode(bsdtar, "-O", "xt"); 74060b4ad09SPeter Avalos if (bsdtar->option_unlink_first) 74160b4ad09SPeter Avalos only_mode(bsdtar, "-U", "x"); 74260b4ad09SPeter Avalos if (bsdtar->option_warn_links) 74360b4ad09SPeter Avalos only_mode(bsdtar, "--check-links", "cr"); 74460b4ad09SPeter Avalos 745*d4d8193eSPeter Avalos if (option_a && cset_auto_compress(bsdtar->cset, bsdtar->filename)) { 746*d4d8193eSPeter Avalos /* Ignore specified compressions if auto-compress works. */ 747*d4d8193eSPeter Avalos compression = '\0'; 748*d4d8193eSPeter Avalos compression2 = '\0'; 74960b4ad09SPeter Avalos } 750*d4d8193eSPeter Avalos /* Check other parameters only permitted in certain modes. */ 751*d4d8193eSPeter Avalos if (compress_program != NULL) { 752*d4d8193eSPeter Avalos only_mode(bsdtar, "--use-compress-program", "cxt"); 753*d4d8193eSPeter Avalos cset_add_filter_program(bsdtar->cset, compress_program); 754*d4d8193eSPeter Avalos /* Ignore specified compressions. */ 755*d4d8193eSPeter Avalos compression = '\0'; 756*d4d8193eSPeter Avalos compression2 = '\0'; 757*d4d8193eSPeter Avalos } 758*d4d8193eSPeter Avalos if (compression != '\0') { 759*d4d8193eSPeter Avalos switch (compression) { 760*d4d8193eSPeter Avalos case 'J': case 'j': case 'y': case 'Z': case 'z': 761*d4d8193eSPeter Avalos strcpy(buff, "-?"); 762*d4d8193eSPeter Avalos buff[1] = compression; 763*d4d8193eSPeter Avalos break; 764*d4d8193eSPeter Avalos default: 765*d4d8193eSPeter Avalos strcpy(buff, "--"); 766*d4d8193eSPeter Avalos strcat(buff, compression_name); 767*d4d8193eSPeter Avalos break; 768*d4d8193eSPeter Avalos } 769*d4d8193eSPeter Avalos only_mode(bsdtar, buff, "cxt"); 770*d4d8193eSPeter Avalos cset_add_filter(bsdtar->cset, compression_name); 771*d4d8193eSPeter Avalos } 772*d4d8193eSPeter Avalos if (compression2 != '\0') { 773*d4d8193eSPeter Avalos strcpy(buff, "--"); 774*d4d8193eSPeter Avalos strcat(buff, compression2_name); 775*d4d8193eSPeter Avalos only_mode(bsdtar, buff, "cxt"); 776*d4d8193eSPeter Avalos cset_add_filter(bsdtar->cset, compression2_name); 777*d4d8193eSPeter Avalos } 778*d4d8193eSPeter Avalos if (cset_get_format(bsdtar->cset) != NULL) 77960b4ad09SPeter Avalos only_mode(bsdtar, "--format", "cru"); 78060b4ad09SPeter Avalos if (bsdtar->symlink_mode != '\0') { 78160b4ad09SPeter Avalos strcpy(buff, "-?"); 78260b4ad09SPeter Avalos buff[1] = bsdtar->symlink_mode; 78360b4ad09SPeter Avalos only_mode(bsdtar, buff, "cru"); 78460b4ad09SPeter Avalos } 785c09f92d2SPeter Avalos 786c09f92d2SPeter Avalos /* Filename "-" implies stdio. */ 787c09f92d2SPeter Avalos if (strcmp(bsdtar->filename, "-") == 0) 788c09f92d2SPeter Avalos bsdtar->filename = NULL; 78960b4ad09SPeter Avalos 79060b4ad09SPeter Avalos switch(bsdtar->mode) { 79160b4ad09SPeter Avalos case 'c': 79260b4ad09SPeter Avalos tar_mode_c(bsdtar); 79360b4ad09SPeter Avalos break; 79460b4ad09SPeter Avalos case 'r': 79560b4ad09SPeter Avalos tar_mode_r(bsdtar); 79660b4ad09SPeter Avalos break; 79760b4ad09SPeter Avalos case 't': 79860b4ad09SPeter Avalos tar_mode_t(bsdtar); 79960b4ad09SPeter Avalos break; 80060b4ad09SPeter Avalos case 'u': 80160b4ad09SPeter Avalos tar_mode_u(bsdtar); 80260b4ad09SPeter Avalos break; 80360b4ad09SPeter Avalos case 'x': 80460b4ad09SPeter Avalos tar_mode_x(bsdtar); 80560b4ad09SPeter Avalos break; 80660b4ad09SPeter Avalos } 80760b4ad09SPeter Avalos 80859bf7050SPeter Avalos archive_match_free(bsdtar->matching); 809*d4d8193eSPeter Avalos #if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) 81060b4ad09SPeter Avalos cleanup_substitution(bsdtar); 81160b4ad09SPeter Avalos #endif 812*d4d8193eSPeter Avalos cset_free(bsdtar->cset); 81360b4ad09SPeter Avalos 81460b4ad09SPeter Avalos if (bsdtar->return_value != 0) 8159c82a63eSPeter Avalos lafe_warnc(0, 81660b4ad09SPeter Avalos "Error exit delayed from previous errors."); 81760b4ad09SPeter Avalos return (bsdtar->return_value); 81860b4ad09SPeter Avalos } 81960b4ad09SPeter Avalos 82060b4ad09SPeter Avalos static void 82160b4ad09SPeter Avalos set_mode(struct bsdtar *bsdtar, char opt) 82260b4ad09SPeter Avalos { 82360b4ad09SPeter Avalos if (bsdtar->mode != '\0' && bsdtar->mode != opt) 8249c82a63eSPeter Avalos lafe_errc(1, 0, 82560b4ad09SPeter Avalos "Can't specify both -%c and -%c", opt, bsdtar->mode); 82660b4ad09SPeter Avalos bsdtar->mode = opt; 82760b4ad09SPeter Avalos } 82860b4ad09SPeter Avalos 82960b4ad09SPeter Avalos /* 83060b4ad09SPeter Avalos * Verify that the mode is correct. 83160b4ad09SPeter Avalos */ 83260b4ad09SPeter Avalos static void 83360b4ad09SPeter Avalos only_mode(struct bsdtar *bsdtar, const char *opt, const char *valid_modes) 83460b4ad09SPeter Avalos { 83560b4ad09SPeter Avalos if (strchr(valid_modes, bsdtar->mode) == NULL) 8369c82a63eSPeter Avalos lafe_errc(1, 0, 83760b4ad09SPeter Avalos "Option %s is not permitted in mode -%c", 83860b4ad09SPeter Avalos opt, bsdtar->mode); 83960b4ad09SPeter Avalos } 84060b4ad09SPeter Avalos 84160b4ad09SPeter Avalos 84260b4ad09SPeter Avalos void 8439c82a63eSPeter Avalos usage(void) 84460b4ad09SPeter Avalos { 84560b4ad09SPeter Avalos const char *p; 84660b4ad09SPeter Avalos 8479c82a63eSPeter Avalos p = lafe_progname; 84860b4ad09SPeter Avalos 84960b4ad09SPeter Avalos fprintf(stderr, "Usage:\n"); 85060b4ad09SPeter Avalos fprintf(stderr, " List: %s -tf <archive-filename>\n", p); 85160b4ad09SPeter Avalos fprintf(stderr, " Extract: %s -xf <archive-filename>\n", p); 85260b4ad09SPeter Avalos fprintf(stderr, " Create: %s -cf <archive-filename> [filenames...]\n", p); 85360b4ad09SPeter Avalos fprintf(stderr, " Help: %s --help\n", p); 85460b4ad09SPeter Avalos exit(1); 85560b4ad09SPeter Avalos } 85660b4ad09SPeter Avalos 85760b4ad09SPeter Avalos static void 85860b4ad09SPeter Avalos version(void) 85960b4ad09SPeter Avalos { 86060b4ad09SPeter Avalos printf("bsdtar %s - %s\n", 86160b4ad09SPeter Avalos BSDTAR_VERSION_STRING, 862c09f92d2SPeter Avalos archive_version_string()); 86360b4ad09SPeter Avalos exit(0); 86460b4ad09SPeter Avalos } 86560b4ad09SPeter Avalos 86660b4ad09SPeter Avalos static const char *long_help_msg = 86760b4ad09SPeter Avalos "First option must be a mode specifier:\n" 86860b4ad09SPeter Avalos " -c Create -r Add/Replace -t List -u Update -x Extract\n" 86960b4ad09SPeter Avalos "Common Options:\n" 87060b4ad09SPeter Avalos " -b # Use # 512-byte records per I/O block\n" 87160b4ad09SPeter Avalos " -f <filename> Location of archive (default " _PATH_DEFTAPE ")\n" 87260b4ad09SPeter Avalos " -v Verbose\n" 87360b4ad09SPeter Avalos " -w Interactive\n" 87460b4ad09SPeter Avalos "Create: %p -c [options] [<file> | <dir> | @<archive> | -C <dir> ]\n" 87560b4ad09SPeter Avalos " <file>, <dir> add these items to archive\n" 8768029ab02SPeter Avalos " -z, -j, -J, --lzma Compress archive with gzip/bzip2/xz/lzma\n" 87760b4ad09SPeter Avalos " --format {ustar|pax|cpio|shar} Select archive format\n" 87860b4ad09SPeter Avalos " --exclude <pattern> Skip files that match pattern\n" 87960b4ad09SPeter Avalos " -C <dir> Change to <dir> before processing remaining files\n" 88060b4ad09SPeter Avalos " @<archive> Add entries from <archive> to output\n" 88160b4ad09SPeter Avalos "List: %p -t [options] [<patterns>]\n" 88260b4ad09SPeter Avalos " <patterns> If specified, list only entries that match\n" 88360b4ad09SPeter Avalos "Extract: %p -x [options] [<patterns>]\n" 88460b4ad09SPeter Avalos " <patterns> If specified, extract only entries that match\n" 88560b4ad09SPeter Avalos " -k Keep (don't overwrite) existing files\n" 88660b4ad09SPeter Avalos " -m Don't restore modification times\n" 88760b4ad09SPeter Avalos " -O Write entries to stdout, don't restore to disk\n" 88860b4ad09SPeter Avalos " -p Restore permissions (including ACLs, owner, file flags)\n"; 88960b4ad09SPeter Avalos 89060b4ad09SPeter Avalos 89160b4ad09SPeter Avalos /* 89260b4ad09SPeter Avalos * Note that the word 'bsdtar' will always appear in the first line 89360b4ad09SPeter Avalos * of output. 89460b4ad09SPeter Avalos * 89560b4ad09SPeter Avalos * In particular, /bin/sh scripts that need to test for the presence 89660b4ad09SPeter Avalos * of bsdtar can use the following template: 89760b4ad09SPeter Avalos * 89860b4ad09SPeter Avalos * if (tar --help 2>&1 | grep bsdtar >/dev/null 2>&1 ) then \ 89960b4ad09SPeter Avalos * echo bsdtar; else echo not bsdtar; fi 90060b4ad09SPeter Avalos */ 90160b4ad09SPeter Avalos static void 9029c82a63eSPeter Avalos long_help(void) 90360b4ad09SPeter Avalos { 90460b4ad09SPeter Avalos const char *prog; 90560b4ad09SPeter Avalos const char *p; 90660b4ad09SPeter Avalos 9079c82a63eSPeter Avalos prog = lafe_progname; 90860b4ad09SPeter Avalos 90960b4ad09SPeter Avalos fflush(stderr); 91060b4ad09SPeter Avalos 91160b4ad09SPeter Avalos p = (strcmp(prog,"bsdtar") != 0) ? "(bsdtar)" : ""; 91260b4ad09SPeter Avalos printf("%s%s: manipulate archive files\n", prog, p); 91360b4ad09SPeter Avalos 91460b4ad09SPeter Avalos for (p = long_help_msg; *p != '\0'; p++) { 91560b4ad09SPeter Avalos if (*p == '%') { 91660b4ad09SPeter Avalos if (p[1] == 'p') { 91760b4ad09SPeter Avalos fputs(prog, stdout); 91860b4ad09SPeter Avalos p++; 91960b4ad09SPeter Avalos } else 92060b4ad09SPeter Avalos putchar('%'); 92160b4ad09SPeter Avalos } else 92260b4ad09SPeter Avalos putchar(*p); 92360b4ad09SPeter Avalos } 92460b4ad09SPeter Avalos version(); 92560b4ad09SPeter Avalos } 926