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 3560b4ad09SPeter Avalos #ifdef HAVE_ERRNO_H 3660b4ad09SPeter Avalos #include <errno.h> 3760b4ad09SPeter Avalos #endif 3860b4ad09SPeter Avalos #ifdef HAVE_FCNTL_H 3960b4ad09SPeter Avalos #include <fcntl.h> 4060b4ad09SPeter Avalos #endif 4160b4ad09SPeter Avalos #ifdef HAVE_LANGINFO_H 4260b4ad09SPeter Avalos #include <langinfo.h> 4360b4ad09SPeter Avalos #endif 4460b4ad09SPeter Avalos #ifdef HAVE_LOCALE_H 4560b4ad09SPeter Avalos #include <locale.h> 4660b4ad09SPeter Avalos #endif 4760b4ad09SPeter Avalos #ifdef HAVE_PATHS_H 4860b4ad09SPeter Avalos #include <paths.h> 4960b4ad09SPeter Avalos #endif 50*9c82a63eSPeter Avalos #ifdef HAVE_SIGNAL_H 51*9c82a63eSPeter Avalos #include <signal.h> 52*9c82a63eSPeter Avalos #endif 5360b4ad09SPeter Avalos #include <stdio.h> 5460b4ad09SPeter Avalos #ifdef HAVE_STDLIB_H 5560b4ad09SPeter Avalos #include <stdlib.h> 5660b4ad09SPeter Avalos #endif 5760b4ad09SPeter Avalos #ifdef HAVE_STRING_H 5860b4ad09SPeter Avalos #include <string.h> 5960b4ad09SPeter Avalos #endif 6060b4ad09SPeter Avalos #ifdef HAVE_TIME_H 6160b4ad09SPeter Avalos #include <time.h> 6260b4ad09SPeter Avalos #endif 6360b4ad09SPeter Avalos #ifdef HAVE_UNISTD_H 6460b4ad09SPeter Avalos #include <unistd.h> 6560b4ad09SPeter Avalos #endif 6660b4ad09SPeter Avalos #if HAVE_ZLIB_H 6760b4ad09SPeter Avalos #include <zlib.h> 6860b4ad09SPeter Avalos #endif 6960b4ad09SPeter Avalos 7060b4ad09SPeter Avalos #include "bsdtar.h" 71*9c82a63eSPeter 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 8360b4ad09SPeter Avalos 8460b4ad09SPeter Avalos #ifndef _PATH_DEFTAPE 8560b4ad09SPeter Avalos #define _PATH_DEFTAPE "/dev/tape" 8660b4ad09SPeter Avalos #endif 8760b4ad09SPeter Avalos 88*9c82a63eSPeter Avalos #ifdef __MINGW32__ 89*9c82a63eSPeter Avalos int _CRT_glob = 0; /* Disable broken CRT globbing. */ 90*9c82a63eSPeter Avalos #endif 91*9c82a63eSPeter Avalos 92*9c82a63eSPeter Avalos static struct bsdtar *_bsdtar; 93*9c82a63eSPeter Avalos 94*9c82a63eSPeter Avalos #if defined(HAVE_SIGACTION) && (defined(SIGINFO) || defined(SIGUSR1)) 95*9c82a63eSPeter Avalos static volatile int siginfo_occurred; 96*9c82a63eSPeter Avalos 97*9c82a63eSPeter Avalos static void 98*9c82a63eSPeter Avalos siginfo_handler(int sig) 99*9c82a63eSPeter Avalos { 100*9c82a63eSPeter Avalos (void)sig; /* UNUSED */ 101*9c82a63eSPeter Avalos siginfo_occurred = 1; 102*9c82a63eSPeter Avalos } 103*9c82a63eSPeter Avalos 104*9c82a63eSPeter Avalos int 105*9c82a63eSPeter Avalos need_report(void) 106*9c82a63eSPeter Avalos { 107*9c82a63eSPeter Avalos int r = siginfo_occurred; 108*9c82a63eSPeter Avalos siginfo_occurred = 0; 109*9c82a63eSPeter Avalos return (r); 110*9c82a63eSPeter Avalos } 111*9c82a63eSPeter Avalos #else 112*9c82a63eSPeter Avalos int 113*9c82a63eSPeter Avalos need_report(void) 114*9c82a63eSPeter Avalos { 115*9c82a63eSPeter Avalos return (0); 116*9c82a63eSPeter Avalos } 117*9c82a63eSPeter Avalos #endif 118*9c82a63eSPeter Avalos 119*9c82a63eSPeter Avalos /* External function to parse a date/time string */ 1208029ab02SPeter Avalos time_t get_date(time_t, const char *); 12160b4ad09SPeter Avalos 122*9c82a63eSPeter Avalos static void long_help(void); 12360b4ad09SPeter Avalos static void only_mode(struct bsdtar *, const char *opt, 12460b4ad09SPeter Avalos const char *valid); 12560b4ad09SPeter Avalos static void set_mode(struct bsdtar *, char opt); 12660b4ad09SPeter Avalos static void version(void); 12760b4ad09SPeter Avalos 12860b4ad09SPeter Avalos /* A basic set of security flags to request from libarchive. */ 12960b4ad09SPeter Avalos #define SECURITY \ 13060b4ad09SPeter Avalos (ARCHIVE_EXTRACT_SECURE_SYMLINKS \ 13160b4ad09SPeter Avalos | ARCHIVE_EXTRACT_SECURE_NODOTDOT) 13260b4ad09SPeter Avalos 13360b4ad09SPeter Avalos int 13460b4ad09SPeter Avalos main(int argc, char **argv) 13560b4ad09SPeter Avalos { 13660b4ad09SPeter Avalos struct bsdtar *bsdtar, bsdtar_storage; 13760b4ad09SPeter Avalos int opt, t; 13860b4ad09SPeter Avalos char option_o; 13960b4ad09SPeter Avalos char possible_help_request; 14060b4ad09SPeter Avalos char buff[16]; 1418029ab02SPeter Avalos time_t now; 14260b4ad09SPeter Avalos 14360b4ad09SPeter Avalos /* 14460b4ad09SPeter Avalos * Use a pointer for consistency, but stack-allocated storage 14560b4ad09SPeter Avalos * for ease of cleanup. 14660b4ad09SPeter Avalos */ 147*9c82a63eSPeter Avalos _bsdtar = bsdtar = &bsdtar_storage; 14860b4ad09SPeter Avalos memset(bsdtar, 0, sizeof(*bsdtar)); 14960b4ad09SPeter Avalos bsdtar->fd = -1; /* Mark as "unused" */ 15060b4ad09SPeter Avalos option_o = 0; 151*9c82a63eSPeter Avalos 152*9c82a63eSPeter Avalos #if defined(HAVE_SIGACTION) && (defined(SIGINFO) || defined(SIGUSR1)) 153*9c82a63eSPeter Avalos { /* Catch SIGINFO and SIGUSR1, if they exist. */ 154*9c82a63eSPeter Avalos struct sigaction sa; 155*9c82a63eSPeter Avalos sa.sa_handler = siginfo_handler; 156*9c82a63eSPeter Avalos sigemptyset(&sa.sa_mask); 157*9c82a63eSPeter Avalos sa.sa_flags = 0; 158*9c82a63eSPeter Avalos #ifdef SIGINFO 159*9c82a63eSPeter Avalos if (sigaction(SIGINFO, &sa, NULL)) 160*9c82a63eSPeter Avalos lafe_errc(1, errno, "sigaction(SIGINFO) failed"); 161*9c82a63eSPeter Avalos #endif 162*9c82a63eSPeter Avalos #ifdef SIGUSR1 163*9c82a63eSPeter Avalos /* ... and treat SIGUSR1 the same way as SIGINFO. */ 164*9c82a63eSPeter Avalos if (sigaction(SIGUSR1, &sa, NULL)) 165*9c82a63eSPeter Avalos lafe_errc(1, errno, "sigaction(SIGUSR1) failed"); 166*9c82a63eSPeter Avalos #endif 167*9c82a63eSPeter Avalos } 1688029ab02SPeter Avalos #endif 16960b4ad09SPeter Avalos 170*9c82a63eSPeter Avalos 171*9c82a63eSPeter Avalos /* Need lafe_progname before calling lafe_warnc. */ 17260b4ad09SPeter Avalos if (*argv == NULL) 173*9c82a63eSPeter Avalos lafe_progname = "bsdtar"; 17460b4ad09SPeter Avalos else { 1758029ab02SPeter Avalos #if defined(_WIN32) && !defined(__CYGWIN__) 176*9c82a63eSPeter Avalos lafe_progname = strrchr(*argv, '\\'); 1778029ab02SPeter Avalos #else 178*9c82a63eSPeter Avalos lafe_progname = strrchr(*argv, '/'); 1798029ab02SPeter Avalos #endif 180*9c82a63eSPeter Avalos if (lafe_progname != NULL) 181*9c82a63eSPeter Avalos lafe_progname++; 18260b4ad09SPeter Avalos else 183*9c82a63eSPeter Avalos lafe_progname = *argv; 18460b4ad09SPeter Avalos } 18560b4ad09SPeter Avalos 1868029ab02SPeter Avalos time(&now); 1878029ab02SPeter Avalos 188*9c82a63eSPeter Avalos #if HAVE_SETLOCALE 18960b4ad09SPeter Avalos if (setlocale(LC_ALL, "") == NULL) 190*9c82a63eSPeter Avalos lafe_warnc(0, "Failed to set default locale"); 191*9c82a63eSPeter Avalos #endif 19260b4ad09SPeter Avalos #if defined(HAVE_NL_LANGINFO) && defined(HAVE_D_MD_ORDER) 19360b4ad09SPeter Avalos bsdtar->day_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 19460b4ad09SPeter Avalos #endif 19560b4ad09SPeter Avalos possible_help_request = 0; 19660b4ad09SPeter Avalos 19760b4ad09SPeter Avalos /* Look up uid of current user for future reference */ 19860b4ad09SPeter Avalos bsdtar->user_uid = geteuid(); 19960b4ad09SPeter Avalos 20060b4ad09SPeter Avalos /* Default: open tape drive. */ 20160b4ad09SPeter Avalos bsdtar->filename = getenv("TAPE"); 20260b4ad09SPeter Avalos if (bsdtar->filename == NULL) 20360b4ad09SPeter Avalos bsdtar->filename = _PATH_DEFTAPE; 20460b4ad09SPeter Avalos 20560b4ad09SPeter Avalos /* Default: preserve mod time on extract */ 20660b4ad09SPeter Avalos bsdtar->extract_flags = ARCHIVE_EXTRACT_TIME; 20760b4ad09SPeter Avalos 20860b4ad09SPeter Avalos /* Default: Perform basic security checks. */ 20960b4ad09SPeter Avalos bsdtar->extract_flags |= SECURITY; 21060b4ad09SPeter Avalos 211*9c82a63eSPeter Avalos #ifndef _WIN32 212*9c82a63eSPeter Avalos /* On POSIX systems, assume --same-owner and -p when run by 213*9c82a63eSPeter Avalos * the root user. This doesn't make any sense on Windows. */ 214*9c82a63eSPeter Avalos if (bsdtar->user_uid == 0) { 21560b4ad09SPeter Avalos /* --same-owner */ 21660b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER; 21760b4ad09SPeter Avalos /* -p */ 21860b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; 21960b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; 22060b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; 22160b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; 22260b4ad09SPeter Avalos } 223*9c82a63eSPeter Avalos #endif 22460b4ad09SPeter Avalos 22560b4ad09SPeter Avalos bsdtar->argv = argv; 22660b4ad09SPeter Avalos bsdtar->argc = argc; 22760b4ad09SPeter Avalos 22860b4ad09SPeter Avalos /* 22960b4ad09SPeter Avalos * Comments following each option indicate where that option 23060b4ad09SPeter Avalos * originated: SUSv2, POSIX, GNU tar, star, etc. If there's 23160b4ad09SPeter Avalos * no such comment, then I don't know of anyone else who 23260b4ad09SPeter Avalos * implements that option. 23360b4ad09SPeter Avalos */ 2348029ab02SPeter Avalos while ((opt = bsdtar_getopt(bsdtar)) != -1) { 23560b4ad09SPeter Avalos switch (opt) { 23660b4ad09SPeter Avalos case 'B': /* GNU tar */ 23760b4ad09SPeter Avalos /* libarchive doesn't need this; just ignore it. */ 23860b4ad09SPeter Avalos break; 23960b4ad09SPeter Avalos case 'b': /* SUSv2 */ 2408029ab02SPeter Avalos t = atoi(bsdtar->optarg); 241*9c82a63eSPeter Avalos if (t <= 0 || t > 8192) 242*9c82a63eSPeter Avalos lafe_errc(1, 0, 243*9c82a63eSPeter Avalos "Argument to -b is out of range (1..8192)"); 24460b4ad09SPeter Avalos bsdtar->bytes_per_block = 512 * t; 24560b4ad09SPeter Avalos break; 24660b4ad09SPeter Avalos case 'C': /* GNU tar */ 2478029ab02SPeter Avalos set_chdir(bsdtar, bsdtar->optarg); 24860b4ad09SPeter Avalos break; 24960b4ad09SPeter Avalos case 'c': /* SUSv2 */ 25060b4ad09SPeter Avalos set_mode(bsdtar, opt); 25160b4ad09SPeter Avalos break; 25260b4ad09SPeter Avalos case OPTION_CHECK_LINKS: /* GNU tar */ 25360b4ad09SPeter Avalos bsdtar->option_warn_links = 1; 25460b4ad09SPeter Avalos break; 25560b4ad09SPeter Avalos case OPTION_CHROOT: /* NetBSD */ 25660b4ad09SPeter Avalos bsdtar->option_chroot = 1; 25760b4ad09SPeter Avalos break; 25860b4ad09SPeter Avalos case OPTION_EXCLUDE: /* GNU tar */ 259*9c82a63eSPeter Avalos if (lafe_exclude(&bsdtar->matching, bsdtar->optarg)) 260*9c82a63eSPeter Avalos lafe_errc(1, 0, 2618029ab02SPeter Avalos "Couldn't exclude %s\n", bsdtar->optarg); 26260b4ad09SPeter Avalos break; 26360b4ad09SPeter Avalos case OPTION_FORMAT: /* GNU tar, others */ 2648029ab02SPeter Avalos bsdtar->create_format = bsdtar->optarg; 2658029ab02SPeter Avalos break; 2668029ab02SPeter Avalos case OPTION_OPTIONS: 2678029ab02SPeter Avalos bsdtar->option_options = bsdtar->optarg; 26860b4ad09SPeter Avalos break; 26960b4ad09SPeter Avalos case 'f': /* SUSv2 */ 2708029ab02SPeter Avalos bsdtar->filename = bsdtar->optarg; 27160b4ad09SPeter Avalos if (strcmp(bsdtar->filename, "-") == 0) 27260b4ad09SPeter Avalos bsdtar->filename = NULL; 27360b4ad09SPeter Avalos break; 27460b4ad09SPeter Avalos case 'H': /* BSD convention */ 27560b4ad09SPeter Avalos bsdtar->symlink_mode = 'H'; 27660b4ad09SPeter Avalos break; 27760b4ad09SPeter Avalos case 'h': /* Linux Standards Base, gtar; synonym for -L */ 27860b4ad09SPeter Avalos bsdtar->symlink_mode = 'L'; 27960b4ad09SPeter Avalos /* Hack: -h by itself is the "help" command. */ 28060b4ad09SPeter Avalos possible_help_request = 1; 28160b4ad09SPeter Avalos break; 28260b4ad09SPeter Avalos case OPTION_HELP: /* GNU tar, others */ 283*9c82a63eSPeter Avalos long_help(); 28460b4ad09SPeter Avalos exit(0); 28560b4ad09SPeter Avalos break; 28660b4ad09SPeter Avalos case 'I': /* GNU tar */ 28760b4ad09SPeter Avalos /* 28860b4ad09SPeter Avalos * TODO: Allow 'names' to come from an archive, 28960b4ad09SPeter Avalos * not just a text file. Design a good UI for 29060b4ad09SPeter Avalos * allowing names and mode/owner to be read 29160b4ad09SPeter Avalos * from an archive, with contents coming from 29260b4ad09SPeter Avalos * disk. This can be used to "refresh" an 29360b4ad09SPeter Avalos * archive or to design archives with special 29460b4ad09SPeter Avalos * permissions without having to create those 29560b4ad09SPeter Avalos * permissions on disk. 29660b4ad09SPeter Avalos */ 2978029ab02SPeter Avalos bsdtar->names_from_file = bsdtar->optarg; 29860b4ad09SPeter Avalos break; 29960b4ad09SPeter Avalos case OPTION_INCLUDE: 30060b4ad09SPeter Avalos /* 30160b4ad09SPeter Avalos * Noone else has the @archive extension, so 30260b4ad09SPeter Avalos * noone else needs this to filter entries 30360b4ad09SPeter Avalos * when transforming archives. 30460b4ad09SPeter Avalos */ 305*9c82a63eSPeter Avalos if (lafe_include(&bsdtar->matching, bsdtar->optarg)) 306*9c82a63eSPeter Avalos lafe_errc(1, 0, 30760b4ad09SPeter Avalos "Failed to add %s to inclusion list", 3088029ab02SPeter Avalos bsdtar->optarg); 30960b4ad09SPeter Avalos break; 31060b4ad09SPeter Avalos case 'j': /* GNU tar */ 31160b4ad09SPeter Avalos if (bsdtar->create_compression != '\0') 312*9c82a63eSPeter Avalos lafe_errc(1, 0, 31360b4ad09SPeter Avalos "Can't specify both -%c and -%c", opt, 31460b4ad09SPeter Avalos bsdtar->create_compression); 31560b4ad09SPeter Avalos bsdtar->create_compression = opt; 3168029ab02SPeter Avalos break; 3178029ab02SPeter Avalos case 'J': /* GNU tar 1.21 and later */ 3188029ab02SPeter Avalos if (bsdtar->create_compression != '\0') 319*9c82a63eSPeter Avalos lafe_errc(1, 0, 3208029ab02SPeter Avalos "Can't specify both -%c and -%c", opt, 3218029ab02SPeter Avalos bsdtar->create_compression); 3228029ab02SPeter Avalos bsdtar->create_compression = opt; 32360b4ad09SPeter Avalos break; 32460b4ad09SPeter Avalos case 'k': /* GNU tar */ 32560b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE; 32660b4ad09SPeter Avalos break; 32760b4ad09SPeter Avalos case OPTION_KEEP_NEWER_FILES: /* GNU tar */ 32860b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; 32960b4ad09SPeter Avalos break; 33060b4ad09SPeter Avalos case 'L': /* BSD convention */ 33160b4ad09SPeter Avalos bsdtar->symlink_mode = 'L'; 33260b4ad09SPeter Avalos break; 33360b4ad09SPeter Avalos case 'l': /* SUSv2 and GNU tar beginning with 1.16 */ 33460b4ad09SPeter Avalos /* GNU tar 1.13 used -l for --one-file-system */ 33560b4ad09SPeter Avalos bsdtar->option_warn_links = 1; 33660b4ad09SPeter Avalos break; 3378029ab02SPeter Avalos case OPTION_LZMA: 3388029ab02SPeter Avalos if (bsdtar->create_compression != '\0') 339*9c82a63eSPeter Avalos lafe_errc(1, 0, 3408029ab02SPeter Avalos "Can't specify both -%c and -%c", opt, 3418029ab02SPeter Avalos bsdtar->create_compression); 3428029ab02SPeter Avalos bsdtar->create_compression = opt; 3438029ab02SPeter Avalos break; 34460b4ad09SPeter Avalos case 'm': /* SUSv2 */ 34560b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_TIME; 34660b4ad09SPeter Avalos break; 34760b4ad09SPeter Avalos case 'n': /* GNU tar */ 34860b4ad09SPeter Avalos bsdtar->option_no_subdirs = 1; 34960b4ad09SPeter Avalos break; 35060b4ad09SPeter Avalos /* 35160b4ad09SPeter Avalos * Selecting files by time: 35260b4ad09SPeter Avalos * --newer-?time='date' Only files newer than 'date' 35360b4ad09SPeter Avalos * --newer-?time-than='file' Only files newer than time 35460b4ad09SPeter Avalos * on specified file (useful for incremental backups) 35560b4ad09SPeter Avalos * TODO: Add corresponding "older" options to reverse these. 35660b4ad09SPeter Avalos */ 35760b4ad09SPeter Avalos case OPTION_NEWER_CTIME: /* GNU tar */ 3588029ab02SPeter Avalos bsdtar->newer_ctime_sec = get_date(now, bsdtar->optarg); 35960b4ad09SPeter Avalos break; 36060b4ad09SPeter Avalos case OPTION_NEWER_CTIME_THAN: 36160b4ad09SPeter Avalos { 36260b4ad09SPeter Avalos struct stat st; 3638029ab02SPeter Avalos if (stat(bsdtar->optarg, &st) != 0) 364*9c82a63eSPeter Avalos lafe_errc(1, 0, 3658029ab02SPeter Avalos "Can't open file %s", bsdtar->optarg); 36660b4ad09SPeter Avalos bsdtar->newer_ctime_sec = st.st_ctime; 36760b4ad09SPeter Avalos bsdtar->newer_ctime_nsec = 36860b4ad09SPeter Avalos ARCHIVE_STAT_CTIME_NANOS(&st); 36960b4ad09SPeter Avalos } 37060b4ad09SPeter Avalos break; 37160b4ad09SPeter Avalos case OPTION_NEWER_MTIME: /* GNU tar */ 3728029ab02SPeter Avalos bsdtar->newer_mtime_sec = get_date(now, bsdtar->optarg); 37360b4ad09SPeter Avalos break; 37460b4ad09SPeter Avalos case OPTION_NEWER_MTIME_THAN: 37560b4ad09SPeter Avalos { 37660b4ad09SPeter Avalos struct stat st; 3778029ab02SPeter Avalos if (stat(bsdtar->optarg, &st) != 0) 378*9c82a63eSPeter Avalos lafe_errc(1, 0, 3798029ab02SPeter Avalos "Can't open file %s", bsdtar->optarg); 38060b4ad09SPeter Avalos bsdtar->newer_mtime_sec = st.st_mtime; 38160b4ad09SPeter Avalos bsdtar->newer_mtime_nsec = 38260b4ad09SPeter Avalos ARCHIVE_STAT_MTIME_NANOS(&st); 38360b4ad09SPeter Avalos } 38460b4ad09SPeter Avalos break; 38560b4ad09SPeter Avalos case OPTION_NODUMP: /* star */ 38660b4ad09SPeter Avalos bsdtar->option_honor_nodump = 1; 38760b4ad09SPeter Avalos break; 38860b4ad09SPeter Avalos case OPTION_NO_SAME_OWNER: /* GNU tar */ 38960b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; 39060b4ad09SPeter Avalos break; 39160b4ad09SPeter Avalos case OPTION_NO_SAME_PERMISSIONS: /* GNU tar */ 39260b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_PERM; 39360b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_ACL; 39460b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_XATTR; 39560b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_FFLAGS; 39660b4ad09SPeter Avalos break; 39760b4ad09SPeter Avalos case OPTION_NULL: /* GNU tar */ 39860b4ad09SPeter Avalos bsdtar->option_null++; 39960b4ad09SPeter Avalos break; 40060b4ad09SPeter Avalos case OPTION_NUMERIC_OWNER: /* GNU tar */ 40160b4ad09SPeter Avalos bsdtar->option_numeric_owner++; 40260b4ad09SPeter Avalos break; 40360b4ad09SPeter Avalos case 'O': /* GNU tar */ 40460b4ad09SPeter Avalos bsdtar->option_stdout = 1; 40560b4ad09SPeter Avalos break; 40660b4ad09SPeter Avalos case 'o': /* SUSv2 and GNU conflict here, but not fatally */ 40760b4ad09SPeter Avalos option_o = 1; /* Record it and resolve it later. */ 40860b4ad09SPeter Avalos break; 40960b4ad09SPeter Avalos case OPTION_ONE_FILE_SYSTEM: /* GNU tar */ 41060b4ad09SPeter Avalos bsdtar->option_dont_traverse_mounts = 1; 41160b4ad09SPeter Avalos break; 41260b4ad09SPeter Avalos #if 0 41360b4ad09SPeter Avalos /* 41460b4ad09SPeter Avalos * The common BSD -P option is not necessary, since 41560b4ad09SPeter Avalos * our default is to archive symlinks, not follow 41660b4ad09SPeter Avalos * them. This is convenient, as -P conflicts with GNU 41760b4ad09SPeter Avalos * tar anyway. 41860b4ad09SPeter Avalos */ 41960b4ad09SPeter Avalos case 'P': /* BSD convention */ 42060b4ad09SPeter Avalos /* Default behavior, no option necessary. */ 42160b4ad09SPeter Avalos break; 42260b4ad09SPeter Avalos #endif 42360b4ad09SPeter Avalos case 'P': /* GNU tar */ 42460b4ad09SPeter Avalos bsdtar->extract_flags &= ~SECURITY; 42560b4ad09SPeter Avalos bsdtar->option_absolute_paths = 1; 42660b4ad09SPeter Avalos break; 42760b4ad09SPeter Avalos case 'p': /* GNU tar, star */ 42860b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM; 42960b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL; 43060b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR; 43160b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS; 43260b4ad09SPeter Avalos break; 43360b4ad09SPeter Avalos case OPTION_POSIX: /* GNU tar */ 43460b4ad09SPeter Avalos bsdtar->create_format = "pax"; 43560b4ad09SPeter Avalos break; 43660b4ad09SPeter Avalos case 'q': /* FreeBSD GNU tar --fast-read, NetBSD -q */ 43760b4ad09SPeter Avalos bsdtar->option_fast_read = 1; 43860b4ad09SPeter Avalos break; 43960b4ad09SPeter Avalos case 'r': /* SUSv2 */ 44060b4ad09SPeter Avalos set_mode(bsdtar, opt); 44160b4ad09SPeter Avalos break; 44260b4ad09SPeter Avalos case 'S': /* NetBSD pax-as-tar */ 44360b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_SPARSE; 44460b4ad09SPeter Avalos break; 44560b4ad09SPeter Avalos case 's': /* NetBSD pax-as-tar */ 44660b4ad09SPeter Avalos #if HAVE_REGEX_H 4478029ab02SPeter Avalos add_substitution(bsdtar, bsdtar->optarg); 44860b4ad09SPeter Avalos #else 449*9c82a63eSPeter Avalos lafe_warnc(0, 4508029ab02SPeter Avalos "-s is not supported by this version of bsdtar"); 451*9c82a63eSPeter Avalos usage(); 45260b4ad09SPeter Avalos #endif 45360b4ad09SPeter Avalos break; 4548029ab02SPeter Avalos case OPTION_SAME_OWNER: /* GNU tar */ 4558029ab02SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER; 4568029ab02SPeter Avalos break; 45760b4ad09SPeter Avalos case OPTION_STRIP_COMPONENTS: /* GNU tar 1.15 */ 4588029ab02SPeter Avalos bsdtar->strip_components = atoi(bsdtar->optarg); 45960b4ad09SPeter Avalos break; 46060b4ad09SPeter Avalos case 'T': /* GNU tar */ 4618029ab02SPeter Avalos bsdtar->names_from_file = bsdtar->optarg; 46260b4ad09SPeter Avalos break; 46360b4ad09SPeter Avalos case 't': /* SUSv2 */ 46460b4ad09SPeter Avalos set_mode(bsdtar, opt); 46560b4ad09SPeter Avalos bsdtar->verbose++; 46660b4ad09SPeter Avalos break; 46760b4ad09SPeter Avalos case OPTION_TOTALS: /* GNU tar */ 46860b4ad09SPeter Avalos bsdtar->option_totals++; 46960b4ad09SPeter Avalos break; 47060b4ad09SPeter Avalos case 'U': /* GNU tar */ 47160b4ad09SPeter Avalos bsdtar->extract_flags |= ARCHIVE_EXTRACT_UNLINK; 47260b4ad09SPeter Avalos bsdtar->option_unlink_first = 1; 47360b4ad09SPeter Avalos break; 47460b4ad09SPeter Avalos case 'u': /* SUSv2 */ 47560b4ad09SPeter Avalos set_mode(bsdtar, opt); 47660b4ad09SPeter Avalos break; 47760b4ad09SPeter Avalos case 'v': /* SUSv2 */ 47860b4ad09SPeter Avalos bsdtar->verbose++; 47960b4ad09SPeter Avalos break; 48060b4ad09SPeter Avalos case OPTION_VERSION: /* GNU convention */ 48160b4ad09SPeter Avalos version(); 48260b4ad09SPeter Avalos break; 48360b4ad09SPeter Avalos #if 0 48460b4ad09SPeter Avalos /* 48560b4ad09SPeter Avalos * The -W longopt feature is handled inside of 4868029ab02SPeter Avalos * bsdtar_getopt(), so -W is not available here. 48760b4ad09SPeter Avalos */ 4888029ab02SPeter Avalos case 'W': /* Obscure GNU convention. */ 48960b4ad09SPeter Avalos break; 49060b4ad09SPeter Avalos #endif 49160b4ad09SPeter Avalos case 'w': /* SUSv2 */ 49260b4ad09SPeter Avalos bsdtar->option_interactive = 1; 49360b4ad09SPeter Avalos break; 49460b4ad09SPeter Avalos case 'X': /* GNU tar */ 495*9c82a63eSPeter Avalos if (lafe_exclude_from_file(&bsdtar->matching, bsdtar->optarg)) 496*9c82a63eSPeter Avalos lafe_errc(1, 0, 49760b4ad09SPeter Avalos "failed to process exclusions from file %s", 4988029ab02SPeter Avalos bsdtar->optarg); 49960b4ad09SPeter Avalos break; 50060b4ad09SPeter Avalos case 'x': /* SUSv2 */ 50160b4ad09SPeter Avalos set_mode(bsdtar, opt); 50260b4ad09SPeter Avalos break; 50360b4ad09SPeter Avalos case 'y': /* FreeBSD version of GNU tar */ 50460b4ad09SPeter Avalos if (bsdtar->create_compression != '\0') 505*9c82a63eSPeter Avalos lafe_errc(1, 0, 50660b4ad09SPeter Avalos "Can't specify both -%c and -%c", opt, 50760b4ad09SPeter Avalos bsdtar->create_compression); 50860b4ad09SPeter Avalos bsdtar->create_compression = opt; 50960b4ad09SPeter Avalos break; 51060b4ad09SPeter Avalos case 'Z': /* GNU tar */ 51160b4ad09SPeter Avalos if (bsdtar->create_compression != '\0') 512*9c82a63eSPeter Avalos lafe_errc(1, 0, 51360b4ad09SPeter Avalos "Can't specify both -%c and -%c", opt, 51460b4ad09SPeter Avalos bsdtar->create_compression); 51560b4ad09SPeter Avalos bsdtar->create_compression = opt; 51660b4ad09SPeter Avalos break; 51760b4ad09SPeter Avalos case 'z': /* GNU tar, star, many others */ 51860b4ad09SPeter Avalos if (bsdtar->create_compression != '\0') 519*9c82a63eSPeter Avalos lafe_errc(1, 0, 52060b4ad09SPeter Avalos "Can't specify both -%c and -%c", opt, 52160b4ad09SPeter Avalos bsdtar->create_compression); 52260b4ad09SPeter Avalos bsdtar->create_compression = opt; 52360b4ad09SPeter Avalos break; 52460b4ad09SPeter Avalos case OPTION_USE_COMPRESS_PROGRAM: 5258029ab02SPeter Avalos bsdtar->compress_program = bsdtar->optarg; 52660b4ad09SPeter Avalos break; 52760b4ad09SPeter Avalos default: 528*9c82a63eSPeter Avalos usage(); 52960b4ad09SPeter Avalos } 53060b4ad09SPeter Avalos } 53160b4ad09SPeter Avalos 53260b4ad09SPeter Avalos /* 53360b4ad09SPeter Avalos * Sanity-check options. 53460b4ad09SPeter Avalos */ 53560b4ad09SPeter Avalos 53660b4ad09SPeter Avalos /* If no "real" mode was specified, treat -h as --help. */ 53760b4ad09SPeter Avalos if ((bsdtar->mode == '\0') && possible_help_request) { 538*9c82a63eSPeter Avalos long_help(); 53960b4ad09SPeter Avalos exit(0); 54060b4ad09SPeter Avalos } 54160b4ad09SPeter Avalos 54260b4ad09SPeter Avalos /* Otherwise, a mode is required. */ 54360b4ad09SPeter Avalos if (bsdtar->mode == '\0') 544*9c82a63eSPeter Avalos lafe_errc(1, 0, 54560b4ad09SPeter Avalos "Must specify one of -c, -r, -t, -u, -x"); 54660b4ad09SPeter Avalos 54760b4ad09SPeter Avalos /* Check boolean options only permitted in certain modes. */ 54860b4ad09SPeter Avalos if (bsdtar->option_dont_traverse_mounts) 54960b4ad09SPeter Avalos only_mode(bsdtar, "--one-file-system", "cru"); 55060b4ad09SPeter Avalos if (bsdtar->option_fast_read) 55160b4ad09SPeter Avalos only_mode(bsdtar, "--fast-read", "xt"); 55260b4ad09SPeter Avalos if (bsdtar->option_honor_nodump) 55360b4ad09SPeter Avalos only_mode(bsdtar, "--nodump", "cru"); 55460b4ad09SPeter Avalos if (option_o > 0) { 55560b4ad09SPeter Avalos switch (bsdtar->mode) { 55660b4ad09SPeter Avalos case 'c': 55760b4ad09SPeter Avalos /* 55860b4ad09SPeter Avalos * In GNU tar, -o means "old format." The 55960b4ad09SPeter Avalos * "ustar" format is the closest thing 56060b4ad09SPeter Avalos * supported by libarchive. 56160b4ad09SPeter Avalos */ 56260b4ad09SPeter Avalos bsdtar->create_format = "ustar"; 56360b4ad09SPeter Avalos /* TODO: bsdtar->create_format = "v7"; */ 56460b4ad09SPeter Avalos break; 56560b4ad09SPeter Avalos case 'x': 56660b4ad09SPeter Avalos /* POSIX-compatible behavior. */ 56760b4ad09SPeter Avalos bsdtar->option_no_owner = 1; 56860b4ad09SPeter Avalos bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; 56960b4ad09SPeter Avalos break; 57060b4ad09SPeter Avalos default: 57160b4ad09SPeter Avalos only_mode(bsdtar, "-o", "xc"); 57260b4ad09SPeter Avalos break; 57360b4ad09SPeter Avalos } 57460b4ad09SPeter Avalos } 57560b4ad09SPeter Avalos if (bsdtar->option_no_subdirs) 57660b4ad09SPeter Avalos only_mode(bsdtar, "-n", "cru"); 57760b4ad09SPeter Avalos if (bsdtar->option_stdout) 57860b4ad09SPeter Avalos only_mode(bsdtar, "-O", "xt"); 57960b4ad09SPeter Avalos if (bsdtar->option_unlink_first) 58060b4ad09SPeter Avalos only_mode(bsdtar, "-U", "x"); 58160b4ad09SPeter Avalos if (bsdtar->option_warn_links) 58260b4ad09SPeter Avalos only_mode(bsdtar, "--check-links", "cr"); 58360b4ad09SPeter Avalos 58460b4ad09SPeter Avalos /* Check other parameters only permitted in certain modes. */ 58560b4ad09SPeter Avalos if (bsdtar->create_compression != '\0') { 58660b4ad09SPeter Avalos strcpy(buff, "-?"); 58760b4ad09SPeter Avalos buff[1] = bsdtar->create_compression; 58860b4ad09SPeter Avalos only_mode(bsdtar, buff, "cxt"); 58960b4ad09SPeter Avalos } 59060b4ad09SPeter Avalos if (bsdtar->create_format != NULL) 59160b4ad09SPeter Avalos only_mode(bsdtar, "--format", "cru"); 59260b4ad09SPeter Avalos if (bsdtar->symlink_mode != '\0') { 59360b4ad09SPeter Avalos strcpy(buff, "-?"); 59460b4ad09SPeter Avalos buff[1] = bsdtar->symlink_mode; 59560b4ad09SPeter Avalos only_mode(bsdtar, buff, "cru"); 59660b4ad09SPeter Avalos } 59760b4ad09SPeter Avalos if (bsdtar->strip_components != 0) 59860b4ad09SPeter Avalos only_mode(bsdtar, "--strip-components", "xt"); 59960b4ad09SPeter Avalos 60060b4ad09SPeter Avalos switch(bsdtar->mode) { 60160b4ad09SPeter Avalos case 'c': 60260b4ad09SPeter Avalos tar_mode_c(bsdtar); 60360b4ad09SPeter Avalos break; 60460b4ad09SPeter Avalos case 'r': 60560b4ad09SPeter Avalos tar_mode_r(bsdtar); 60660b4ad09SPeter Avalos break; 60760b4ad09SPeter Avalos case 't': 60860b4ad09SPeter Avalos tar_mode_t(bsdtar); 60960b4ad09SPeter Avalos break; 61060b4ad09SPeter Avalos case 'u': 61160b4ad09SPeter Avalos tar_mode_u(bsdtar); 61260b4ad09SPeter Avalos break; 61360b4ad09SPeter Avalos case 'x': 61460b4ad09SPeter Avalos tar_mode_x(bsdtar); 61560b4ad09SPeter Avalos break; 61660b4ad09SPeter Avalos } 61760b4ad09SPeter Avalos 618*9c82a63eSPeter Avalos lafe_cleanup_exclusions(&bsdtar->matching); 61960b4ad09SPeter Avalos #if HAVE_REGEX_H 62060b4ad09SPeter Avalos cleanup_substitution(bsdtar); 62160b4ad09SPeter Avalos #endif 62260b4ad09SPeter Avalos 62360b4ad09SPeter Avalos if (bsdtar->return_value != 0) 624*9c82a63eSPeter Avalos lafe_warnc(0, 62560b4ad09SPeter Avalos "Error exit delayed from previous errors."); 62660b4ad09SPeter Avalos return (bsdtar->return_value); 62760b4ad09SPeter Avalos } 62860b4ad09SPeter Avalos 62960b4ad09SPeter Avalos static void 63060b4ad09SPeter Avalos set_mode(struct bsdtar *bsdtar, char opt) 63160b4ad09SPeter Avalos { 63260b4ad09SPeter Avalos if (bsdtar->mode != '\0' && bsdtar->mode != opt) 633*9c82a63eSPeter Avalos lafe_errc(1, 0, 63460b4ad09SPeter Avalos "Can't specify both -%c and -%c", opt, bsdtar->mode); 63560b4ad09SPeter Avalos bsdtar->mode = opt; 63660b4ad09SPeter Avalos } 63760b4ad09SPeter Avalos 63860b4ad09SPeter Avalos /* 63960b4ad09SPeter Avalos * Verify that the mode is correct. 64060b4ad09SPeter Avalos */ 64160b4ad09SPeter Avalos static void 64260b4ad09SPeter Avalos only_mode(struct bsdtar *bsdtar, const char *opt, const char *valid_modes) 64360b4ad09SPeter Avalos { 64460b4ad09SPeter Avalos if (strchr(valid_modes, bsdtar->mode) == NULL) 645*9c82a63eSPeter Avalos lafe_errc(1, 0, 64660b4ad09SPeter Avalos "Option %s is not permitted in mode -%c", 64760b4ad09SPeter Avalos opt, bsdtar->mode); 64860b4ad09SPeter Avalos } 64960b4ad09SPeter Avalos 65060b4ad09SPeter Avalos 65160b4ad09SPeter Avalos void 652*9c82a63eSPeter Avalos usage(void) 65360b4ad09SPeter Avalos { 65460b4ad09SPeter Avalos const char *p; 65560b4ad09SPeter Avalos 656*9c82a63eSPeter Avalos p = lafe_progname; 65760b4ad09SPeter Avalos 65860b4ad09SPeter Avalos fprintf(stderr, "Usage:\n"); 65960b4ad09SPeter Avalos fprintf(stderr, " List: %s -tf <archive-filename>\n", p); 66060b4ad09SPeter Avalos fprintf(stderr, " Extract: %s -xf <archive-filename>\n", p); 66160b4ad09SPeter Avalos fprintf(stderr, " Create: %s -cf <archive-filename> [filenames...]\n", p); 66260b4ad09SPeter Avalos fprintf(stderr, " Help: %s --help\n", p); 66360b4ad09SPeter Avalos exit(1); 66460b4ad09SPeter Avalos } 66560b4ad09SPeter Avalos 66660b4ad09SPeter Avalos static void 66760b4ad09SPeter Avalos version(void) 66860b4ad09SPeter Avalos { 66960b4ad09SPeter Avalos printf("bsdtar %s - %s\n", 67060b4ad09SPeter Avalos BSDTAR_VERSION_STRING, 67160b4ad09SPeter Avalos archive_version()); 67260b4ad09SPeter Avalos exit(0); 67360b4ad09SPeter Avalos } 67460b4ad09SPeter Avalos 67560b4ad09SPeter Avalos static const char *long_help_msg = 67660b4ad09SPeter Avalos "First option must be a mode specifier:\n" 67760b4ad09SPeter Avalos " -c Create -r Add/Replace -t List -u Update -x Extract\n" 67860b4ad09SPeter Avalos "Common Options:\n" 67960b4ad09SPeter Avalos " -b # Use # 512-byte records per I/O block\n" 68060b4ad09SPeter Avalos " -f <filename> Location of archive (default " _PATH_DEFTAPE ")\n" 68160b4ad09SPeter Avalos " -v Verbose\n" 68260b4ad09SPeter Avalos " -w Interactive\n" 68360b4ad09SPeter Avalos "Create: %p -c [options] [<file> | <dir> | @<archive> | -C <dir> ]\n" 68460b4ad09SPeter Avalos " <file>, <dir> add these items to archive\n" 6858029ab02SPeter Avalos " -z, -j, -J, --lzma Compress archive with gzip/bzip2/xz/lzma\n" 68660b4ad09SPeter Avalos " --format {ustar|pax|cpio|shar} Select archive format\n" 68760b4ad09SPeter Avalos " --exclude <pattern> Skip files that match pattern\n" 68860b4ad09SPeter Avalos " -C <dir> Change to <dir> before processing remaining files\n" 68960b4ad09SPeter Avalos " @<archive> Add entries from <archive> to output\n" 69060b4ad09SPeter Avalos "List: %p -t [options] [<patterns>]\n" 69160b4ad09SPeter Avalos " <patterns> If specified, list only entries that match\n" 69260b4ad09SPeter Avalos "Extract: %p -x [options] [<patterns>]\n" 69360b4ad09SPeter Avalos " <patterns> If specified, extract only entries that match\n" 69460b4ad09SPeter Avalos " -k Keep (don't overwrite) existing files\n" 69560b4ad09SPeter Avalos " -m Don't restore modification times\n" 69660b4ad09SPeter Avalos " -O Write entries to stdout, don't restore to disk\n" 69760b4ad09SPeter Avalos " -p Restore permissions (including ACLs, owner, file flags)\n"; 69860b4ad09SPeter Avalos 69960b4ad09SPeter Avalos 70060b4ad09SPeter Avalos /* 70160b4ad09SPeter Avalos * Note that the word 'bsdtar' will always appear in the first line 70260b4ad09SPeter Avalos * of output. 70360b4ad09SPeter Avalos * 70460b4ad09SPeter Avalos * In particular, /bin/sh scripts that need to test for the presence 70560b4ad09SPeter Avalos * of bsdtar can use the following template: 70660b4ad09SPeter Avalos * 70760b4ad09SPeter Avalos * if (tar --help 2>&1 | grep bsdtar >/dev/null 2>&1 ) then \ 70860b4ad09SPeter Avalos * echo bsdtar; else echo not bsdtar; fi 70960b4ad09SPeter Avalos */ 71060b4ad09SPeter Avalos static void 711*9c82a63eSPeter Avalos long_help(void) 71260b4ad09SPeter Avalos { 71360b4ad09SPeter Avalos const char *prog; 71460b4ad09SPeter Avalos const char *p; 71560b4ad09SPeter Avalos 716*9c82a63eSPeter Avalos prog = lafe_progname; 71760b4ad09SPeter Avalos 71860b4ad09SPeter Avalos fflush(stderr); 71960b4ad09SPeter Avalos 72060b4ad09SPeter Avalos p = (strcmp(prog,"bsdtar") != 0) ? "(bsdtar)" : ""; 72160b4ad09SPeter Avalos printf("%s%s: manipulate archive files\n", prog, p); 72260b4ad09SPeter Avalos 72360b4ad09SPeter Avalos for (p = long_help_msg; *p != '\0'; p++) { 72460b4ad09SPeter Avalos if (*p == '%') { 72560b4ad09SPeter Avalos if (p[1] == 'p') { 72660b4ad09SPeter Avalos fputs(prog, stdout); 72760b4ad09SPeter Avalos p++; 72860b4ad09SPeter Avalos } else 72960b4ad09SPeter Avalos putchar('%'); 73060b4ad09SPeter Avalos } else 73160b4ad09SPeter Avalos putchar(*p); 73260b4ad09SPeter Avalos } 73360b4ad09SPeter Avalos version(); 73460b4ad09SPeter Avalos } 735