]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/tar/bsdtar.c
Merge r283,r423 from libarchive.googlecode.com: Use libarchive's new
[FreeBSD/FreeBSD.git] / usr.bin / tar / bsdtar.c
1 /*-
2  * Copyright (c) 2003-2008 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "bsdtar_platform.h"
27 __FBSDID("$FreeBSD$");
28
29 #ifdef HAVE_SYS_PARAM_H
30 #include <sys/param.h>
31 #endif
32 #ifdef HAVE_SYS_STAT_H
33 #include <sys/stat.h>
34 #endif
35 #ifdef HAVE_ERRNO_H
36 #include <errno.h>
37 #endif
38 #ifdef HAVE_FCNTL_H
39 #include <fcntl.h>
40 #endif
41 #ifdef HAVE_LANGINFO_H
42 #include <langinfo.h>
43 #endif
44 #ifdef HAVE_LOCALE_H
45 #include <locale.h>
46 #endif
47 #ifdef HAVE_PATHS_H
48 #include <paths.h>
49 #endif
50 #include <stdio.h>
51 #ifdef HAVE_STDLIB_H
52 #include <stdlib.h>
53 #endif
54 #ifdef HAVE_STRING_H
55 #include <string.h>
56 #endif
57 #ifdef HAVE_TIME_H
58 #include <time.h>
59 #endif
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 #if HAVE_ZLIB_H
64 #include <zlib.h>
65 #endif
66
67 #include "bsdtar.h"
68
69 /*
70  * Per POSIX.1-1988, tar defaults to reading/writing archives to/from
71  * the default tape device for the system.  Pick something reasonable here.
72  */
73 #ifdef __linux
74 #define _PATH_DEFTAPE "/dev/st0"
75 #endif
76
77 #ifndef _PATH_DEFTAPE
78 #define _PATH_DEFTAPE "/dev/tape"
79 #endif
80
81 /* External function to parse a date/time string (from getdate.y) */
82 time_t get_date(const char *);
83
84 static void              long_help(struct bsdtar *);
85 static void              only_mode(struct bsdtar *, const char *opt,
86                              const char *valid);
87 static void              set_mode(struct bsdtar *, char opt);
88 static void              version(void);
89
90 /* A basic set of security flags to request from libarchive. */
91 #define SECURITY                                        \
92         (ARCHIVE_EXTRACT_SECURE_SYMLINKS                \
93          | ARCHIVE_EXTRACT_SECURE_NODOTDOT)
94
95 int
96 main(int argc, char **argv)
97 {
98         struct bsdtar           *bsdtar, bsdtar_storage;
99         int                      opt, t;
100         char                     option_o;
101         char                     possible_help_request;
102         char                     buff[16];
103
104         /*
105          * Use a pointer for consistency, but stack-allocated storage
106          * for ease of cleanup.
107          */
108         bsdtar = &bsdtar_storage;
109         memset(bsdtar, 0, sizeof(*bsdtar));
110         bsdtar->fd = -1; /* Mark as "unused" */
111         option_o = 0;
112
113         /* Need bsdtar->progname before calling bsdtar_warnc. */
114         if (*argv == NULL)
115                 bsdtar->progname = "bsdtar";
116         else {
117                 bsdtar->progname = strrchr(*argv, '/');
118                 if (bsdtar->progname != NULL)
119                         bsdtar->progname++;
120                 else
121                         bsdtar->progname = *argv;
122         }
123
124         if (setlocale(LC_ALL, "") == NULL)
125                 bsdtar_warnc(bsdtar, 0, "Failed to set default locale");
126 #if defined(HAVE_NL_LANGINFO) && defined(HAVE_D_MD_ORDER)
127         bsdtar->day_first = (*nl_langinfo(D_MD_ORDER) == 'd');
128 #endif
129         possible_help_request = 0;
130
131         /* Look up uid of current user for future reference */
132         bsdtar->user_uid = geteuid();
133
134         /* Default: open tape drive. */
135         bsdtar->filename = getenv("TAPE");
136         if (bsdtar->filename == NULL)
137                 bsdtar->filename = _PATH_DEFTAPE;
138
139         /* Default: preserve mod time on extract */
140         bsdtar->extract_flags = ARCHIVE_EXTRACT_TIME;
141
142         /* Default: Perform basic security checks. */
143         bsdtar->extract_flags |= SECURITY;
144
145         /* Defaults for root user: */
146         if (bsdtar->user_uid == 0) {
147                 /* --same-owner */
148                 bsdtar->extract_flags |= ARCHIVE_EXTRACT_OWNER;
149                 /* -p */
150                 bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM;
151                 bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL;
152                 bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR;
153                 bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS;
154         }
155
156         bsdtar->argv = argv;
157         bsdtar->argc = argc;
158
159         /*
160          * Comments following each option indicate where that option
161          * originated:  SUSv2, POSIX, GNU tar, star, etc.  If there's
162          * no such comment, then I don't know of anyone else who
163          * implements that option.
164          */
165         while ((opt = bsdtar_getopt(bsdtar)) != -1) {
166                 switch (opt) {
167                 case 'B': /* GNU tar */
168                         /* libarchive doesn't need this; just ignore it. */
169                         break;
170                 case 'b': /* SUSv2 */
171                         t = atoi(bsdtar->optarg);
172                         if (t <= 0 || t > 1024)
173                                 bsdtar_errc(bsdtar, 1, 0,
174                                     "Argument to -b is out of range (1..1024)");
175                         bsdtar->bytes_per_block = 512 * t;
176                         break;
177                 case 'C': /* GNU tar */
178                         set_chdir(bsdtar, bsdtar->optarg);
179                         break;
180                 case 'c': /* SUSv2 */
181                         set_mode(bsdtar, opt);
182                         break;
183                 case OPTION_CHECK_LINKS: /* GNU tar */
184                         bsdtar->option_warn_links = 1;
185                         break;
186                 case OPTION_CHROOT: /* NetBSD */
187                         bsdtar->option_chroot = 1;
188                         break;
189                 case OPTION_EXCLUDE: /* GNU tar */
190                         if (exclude(bsdtar, bsdtar->optarg))
191                                 bsdtar_errc(bsdtar, 1, 0,
192                                     "Couldn't exclude %s\n", bsdtar->optarg);
193                         break;
194                 case OPTION_FORMAT: /* GNU tar, others */
195                         bsdtar->create_format = bsdtar->optarg;
196                         break;
197                 case 'f': /* SUSv2 */
198                         bsdtar->filename = bsdtar->optarg;
199                         if (strcmp(bsdtar->filename, "-") == 0)
200                                 bsdtar->filename = NULL;
201                         break;
202                 case 'H': /* BSD convention */
203                         bsdtar->symlink_mode = 'H';
204                         break;
205                 case 'h': /* Linux Standards Base, gtar; synonym for -L */
206                         bsdtar->symlink_mode = 'L';
207                         /* Hack: -h by itself is the "help" command. */
208                         possible_help_request = 1;
209                         break;
210                 case OPTION_HELP: /* GNU tar, others */
211                         long_help(bsdtar);
212                         exit(0);
213                         break;
214                 case 'I': /* GNU tar */
215                         /*
216                          * TODO: Allow 'names' to come from an archive,
217                          * not just a text file.  Design a good UI for
218                          * allowing names and mode/owner to be read
219                          * from an archive, with contents coming from
220                          * disk.  This can be used to "refresh" an
221                          * archive or to design archives with special
222                          * permissions without having to create those
223                          * permissions on disk.
224                          */
225                         bsdtar->names_from_file = bsdtar->optarg;
226                         break;
227                 case OPTION_INCLUDE:
228                         /*
229                          * Noone else has the @archive extension, so
230                          * noone else needs this to filter entries
231                          * when transforming archives.
232                          */
233                         if (include(bsdtar, bsdtar->optarg))
234                                 bsdtar_errc(bsdtar, 1, 0,
235                                     "Failed to add %s to inclusion list",
236                                     bsdtar->optarg);
237                         break;
238                 case 'j': /* GNU tar */
239 #if HAVE_LIBBZ2
240                         if (bsdtar->create_compression != '\0')
241                                 bsdtar_errc(bsdtar, 1, 0,
242                                     "Can't specify both -%c and -%c", opt,
243                                     bsdtar->create_compression);
244                         bsdtar->create_compression = opt;
245 #else
246                         bsdtar_warnc(bsdtar, 0,
247                             "bzip2 compression not supported by this version of bsdtar");
248                         usage(bsdtar);
249 #endif
250                         break;
251                 case 'k': /* GNU tar */
252                         bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE;
253                         break;
254                 case OPTION_KEEP_NEWER_FILES: /* GNU tar */
255                         bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
256                         break;
257                 case 'L': /* BSD convention */
258                         bsdtar->symlink_mode = 'L';
259                         break;
260                 case 'l': /* SUSv2 and GNU tar beginning with 1.16 */
261                         /* GNU tar 1.13  used -l for --one-file-system */
262                         bsdtar->option_warn_links = 1;
263                         break;
264                 case 'm': /* SUSv2 */
265                         bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_TIME;
266                         break;
267                 case 'n': /* GNU tar */
268                         bsdtar->option_no_subdirs = 1;
269                         break;
270                 /*
271                  * Selecting files by time:
272                  *    --newer-?time='date' Only files newer than 'date'
273                  *    --newer-?time-than='file' Only files newer than time
274                  *         on specified file (useful for incremental backups)
275                  * TODO: Add corresponding "older" options to reverse these.
276                  */
277                 case OPTION_NEWER_CTIME: /* GNU tar */
278                         bsdtar->newer_ctime_sec = get_date(bsdtar->optarg);
279                         break;
280                 case OPTION_NEWER_CTIME_THAN:
281                         {
282                                 struct stat st;
283                                 if (stat(bsdtar->optarg, &st) != 0)
284                                         bsdtar_errc(bsdtar, 1, 0,
285                                             "Can't open file %s", bsdtar->optarg);
286                                 bsdtar->newer_ctime_sec = st.st_ctime;
287                                 bsdtar->newer_ctime_nsec =
288                                     ARCHIVE_STAT_CTIME_NANOS(&st);
289                         }
290                         break;
291                 case OPTION_NEWER_MTIME: /* GNU tar */
292                         bsdtar->newer_mtime_sec = get_date(bsdtar->optarg);
293                         break;
294                 case OPTION_NEWER_MTIME_THAN:
295                         {
296                                 struct stat st;
297                                 if (stat(bsdtar->optarg, &st) != 0)
298                                         bsdtar_errc(bsdtar, 1, 0,
299                                             "Can't open file %s", bsdtar->optarg);
300                                 bsdtar->newer_mtime_sec = st.st_mtime;
301                                 bsdtar->newer_mtime_nsec =
302                                     ARCHIVE_STAT_MTIME_NANOS(&st);
303                         }
304                         break;
305                 case OPTION_NODUMP: /* star */
306                         bsdtar->option_honor_nodump = 1;
307                         break;
308                 case OPTION_NO_SAME_OWNER: /* GNU tar */
309                         bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER;
310                         break;
311                 case OPTION_NO_SAME_PERMISSIONS: /* GNU tar */
312                         bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_PERM;
313                         bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_ACL;
314                         bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_XATTR;
315                         bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_FFLAGS;
316                         break;
317                 case OPTION_NULL: /* GNU tar */
318                         bsdtar->option_null++;
319                         break;
320                 case OPTION_NUMERIC_OWNER: /* GNU tar */
321                         bsdtar->option_numeric_owner++;
322                         break;
323                 case 'O': /* GNU tar */
324                         bsdtar->option_stdout = 1;
325                         break;
326                 case 'o': /* SUSv2 and GNU conflict here, but not fatally */
327                         option_o = 1; /* Record it and resolve it later. */
328                         break;
329                 case OPTION_ONE_FILE_SYSTEM: /* GNU tar */
330                         bsdtar->option_dont_traverse_mounts = 1;
331                         break;
332 #if 0
333                 /*
334                  * The common BSD -P option is not necessary, since
335                  * our default is to archive symlinks, not follow
336                  * them.  This is convenient, as -P conflicts with GNU
337                  * tar anyway.
338                  */
339                 case 'P': /* BSD convention */
340                         /* Default behavior, no option necessary. */
341                         break;
342 #endif
343                 case 'P': /* GNU tar */
344                         bsdtar->extract_flags &= ~SECURITY;
345                         bsdtar->option_absolute_paths = 1;
346                         break;
347                 case 'p': /* GNU tar, star */
348                         bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM;
349                         bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL;
350                         bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR;
351                         bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS;
352                         break;
353                 case OPTION_POSIX: /* GNU tar */
354                         bsdtar->create_format = "pax";
355                         break;
356                 case 'q': /* FreeBSD GNU tar --fast-read, NetBSD -q */
357                         bsdtar->option_fast_read = 1;
358                         break;
359                 case 'r': /* SUSv2 */
360                         set_mode(bsdtar, opt);
361                         break;
362                 case 'S': /* NetBSD pax-as-tar */
363                         bsdtar->extract_flags |= ARCHIVE_EXTRACT_SPARSE;
364                         break;
365                 case 's': /* NetBSD pax-as-tar */
366 #if HAVE_REGEX_H
367                         add_substitution(bsdtar, bsdtar->optarg);
368 #else
369                         bsdtar_warnc(bsdtar, 0,
370                             "-s is not supported by this version of bsdtar");
371                         usage(bsdtar);
372 #endif
373                         break;
374                 case OPTION_STRIP_COMPONENTS: /* GNU tar 1.15 */
375                         bsdtar->strip_components = atoi(bsdtar->optarg);
376                         break;
377                 case 'T': /* GNU tar */
378                         bsdtar->names_from_file = bsdtar->optarg;
379                         break;
380                 case 't': /* SUSv2 */
381                         set_mode(bsdtar, opt);
382                         bsdtar->verbose++;
383                         break;
384                 case OPTION_TOTALS: /* GNU tar */
385                         bsdtar->option_totals++;
386                         break;
387                 case 'U': /* GNU tar */
388                         bsdtar->extract_flags |= ARCHIVE_EXTRACT_UNLINK;
389                         bsdtar->option_unlink_first = 1;
390                         break;
391                 case 'u': /* SUSv2 */
392                         set_mode(bsdtar, opt);
393                         break;
394                 case 'v': /* SUSv2 */
395                         bsdtar->verbose++;
396                         break;
397                 case OPTION_VERSION: /* GNU convention */
398                         version();
399                         break;
400 #if 0
401                 /*
402                  * The -W longopt feature is handled inside of
403                  * bsdtar_getopt(), so -W is not available here.
404                  */
405                 case 'W': /* Obscure GNU convention. */
406                         break;
407 #endif
408                 case 'w': /* SUSv2 */
409                         bsdtar->option_interactive = 1;
410                         break;
411                 case 'X': /* GNU tar */
412                         if (exclude_from_file(bsdtar, bsdtar->optarg))
413                                 bsdtar_errc(bsdtar, 1, 0,
414                                     "failed to process exclusions from file %s",
415                                     bsdtar->optarg);
416                         break;
417                 case 'x': /* SUSv2 */
418                         set_mode(bsdtar, opt);
419                         break;
420                 case 'y': /* FreeBSD version of GNU tar */
421 #if HAVE_LIBBZ2
422                         if (bsdtar->create_compression != '\0')
423                                 bsdtar_errc(bsdtar, 1, 0,
424                                     "Can't specify both -%c and -%c", opt,
425                                     bsdtar->create_compression);
426                         bsdtar->create_compression = opt;
427 #else
428                         bsdtar_warnc(bsdtar, 0,
429                             "bzip2 compression not supported by this version of bsdtar");
430                         usage(bsdtar);
431 #endif
432                         break;
433                 case 'Z': /* GNU tar */
434                         if (bsdtar->create_compression != '\0')
435                                 bsdtar_errc(bsdtar, 1, 0,
436                                     "Can't specify both -%c and -%c", opt,
437                                     bsdtar->create_compression);
438                         bsdtar->create_compression = opt;
439                         break;
440                 case 'z': /* GNU tar, star, many others */
441 #if HAVE_LIBZ
442                         if (bsdtar->create_compression != '\0')
443                                 bsdtar_errc(bsdtar, 1, 0,
444                                     "Can't specify both -%c and -%c", opt,
445                                     bsdtar->create_compression);
446                         bsdtar->create_compression = opt;
447 #else
448                         bsdtar_warnc(bsdtar, 0,
449                             "gzip compression not supported by this version of bsdtar");
450                         usage(bsdtar);
451 #endif
452                         break;
453                 case OPTION_USE_COMPRESS_PROGRAM:
454                         bsdtar->compress_program = bsdtar->optarg;
455                         break;
456                 default:
457                         usage(bsdtar);
458                 }
459         }
460
461         /*
462          * Sanity-check options.
463          */
464
465         /* If no "real" mode was specified, treat -h as --help. */
466         if ((bsdtar->mode == '\0') && possible_help_request) {
467                 long_help(bsdtar);
468                 exit(0);
469         }
470
471         /* Otherwise, a mode is required. */
472         if (bsdtar->mode == '\0')
473                 bsdtar_errc(bsdtar, 1, 0,
474                     "Must specify one of -c, -r, -t, -u, -x");
475
476         /* Check boolean options only permitted in certain modes. */
477         if (bsdtar->option_dont_traverse_mounts)
478                 only_mode(bsdtar, "--one-file-system", "cru");
479         if (bsdtar->option_fast_read)
480                 only_mode(bsdtar, "--fast-read", "xt");
481         if (bsdtar->option_honor_nodump)
482                 only_mode(bsdtar, "--nodump", "cru");
483         if (option_o > 0) {
484                 switch (bsdtar->mode) {
485                 case 'c':
486                         /*
487                          * In GNU tar, -o means "old format."  The
488                          * "ustar" format is the closest thing
489                          * supported by libarchive.
490                          */
491                         bsdtar->create_format = "ustar";
492                         /* TODO: bsdtar->create_format = "v7"; */
493                         break;
494                 case 'x':
495                         /* POSIX-compatible behavior. */
496                         bsdtar->option_no_owner = 1;
497                         bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER;
498                         break;
499                 default:
500                         only_mode(bsdtar, "-o", "xc");
501                         break;
502                 }
503         }
504         if (bsdtar->option_no_subdirs)
505                 only_mode(bsdtar, "-n", "cru");
506         if (bsdtar->option_stdout)
507                 only_mode(bsdtar, "-O", "xt");
508         if (bsdtar->option_unlink_first)
509                 only_mode(bsdtar, "-U", "x");
510         if (bsdtar->option_warn_links)
511                 only_mode(bsdtar, "--check-links", "cr");
512
513         /* Check other parameters only permitted in certain modes. */
514         if (bsdtar->create_compression != '\0') {
515                 strcpy(buff, "-?");
516                 buff[1] = bsdtar->create_compression;
517                 only_mode(bsdtar, buff, "cxt");
518         }
519         if (bsdtar->create_format != NULL)
520                 only_mode(bsdtar, "--format", "cru");
521         if (bsdtar->symlink_mode != '\0') {
522                 strcpy(buff, "-?");
523                 buff[1] = bsdtar->symlink_mode;
524                 only_mode(bsdtar, buff, "cru");
525         }
526         if (bsdtar->strip_components != 0)
527                 only_mode(bsdtar, "--strip-components", "xt");
528
529         switch(bsdtar->mode) {
530         case 'c':
531                 tar_mode_c(bsdtar);
532                 break;
533         case 'r':
534                 tar_mode_r(bsdtar);
535                 break;
536         case 't':
537                 tar_mode_t(bsdtar);
538                 break;
539         case 'u':
540                 tar_mode_u(bsdtar);
541                 break;
542         case 'x':
543                 tar_mode_x(bsdtar);
544                 break;
545         }
546
547         cleanup_exclusions(bsdtar);
548 #if HAVE_REGEX_H
549         cleanup_substitution(bsdtar);
550 #endif
551
552         if (bsdtar->return_value != 0)
553                 bsdtar_warnc(bsdtar, 0,
554                     "Error exit delayed from previous errors.");
555         return (bsdtar->return_value);
556 }
557
558 static void
559 set_mode(struct bsdtar *bsdtar, char opt)
560 {
561         if (bsdtar->mode != '\0' && bsdtar->mode != opt)
562                 bsdtar_errc(bsdtar, 1, 0,
563                     "Can't specify both -%c and -%c", opt, bsdtar->mode);
564         bsdtar->mode = opt;
565 }
566
567 /*
568  * Verify that the mode is correct.
569  */
570 static void
571 only_mode(struct bsdtar *bsdtar, const char *opt, const char *valid_modes)
572 {
573         if (strchr(valid_modes, bsdtar->mode) == NULL)
574                 bsdtar_errc(bsdtar, 1, 0,
575                     "Option %s is not permitted in mode -%c",
576                     opt, bsdtar->mode);
577 }
578
579
580 void
581 usage(struct bsdtar *bsdtar)
582 {
583         const char      *p;
584
585         p = bsdtar->progname;
586
587         fprintf(stderr, "Usage:\n");
588         fprintf(stderr, "  List:    %s -tf <archive-filename>\n", p);
589         fprintf(stderr, "  Extract: %s -xf <archive-filename>\n", p);
590         fprintf(stderr, "  Create:  %s -cf <archive-filename> [filenames...]\n", p);
591         fprintf(stderr, "  Help:    %s --help\n", p);
592         exit(1);
593 }
594
595 static void
596 version(void)
597 {
598         printf("bsdtar %s - %s\n",
599             BSDTAR_VERSION_STRING,
600             archive_version());
601         exit(0);
602 }
603
604 static const char *long_help_msg =
605         "First option must be a mode specifier:\n"
606         "  -c Create  -r Add/Replace  -t List  -u Update  -x Extract\n"
607         "Common Options:\n"
608         "  -b #  Use # 512-byte records per I/O block\n"
609         "  -f <filename>  Location of archive (default " _PATH_DEFTAPE ")\n"
610         "  -v    Verbose\n"
611         "  -w    Interactive\n"
612         "Create: %p -c [options] [<file> | <dir> | @<archive> | -C <dir> ]\n"
613         "  <file>, <dir>  add these items to archive\n"
614         "  -z, -j  Compress archive with gzip/bzip2\n"
615         "  --format {ustar|pax|cpio|shar}  Select archive format\n"
616         "  --exclude <pattern>  Skip files that match pattern\n"
617         "  -C <dir>  Change to <dir> before processing remaining files\n"
618         "  @<archive>  Add entries from <archive> to output\n"
619         "List: %p -t [options] [<patterns>]\n"
620         "  <patterns>  If specified, list only entries that match\n"
621         "Extract: %p -x [options] [<patterns>]\n"
622         "  <patterns>  If specified, extract only entries that match\n"
623         "  -k    Keep (don't overwrite) existing files\n"
624         "  -m    Don't restore modification times\n"
625         "  -O    Write entries to stdout, don't restore to disk\n"
626         "  -p    Restore permissions (including ACLs, owner, file flags)\n";
627
628
629 /*
630  * Note that the word 'bsdtar' will always appear in the first line
631  * of output.
632  *
633  * In particular, /bin/sh scripts that need to test for the presence
634  * of bsdtar can use the following template:
635  *
636  * if (tar --help 2>&1 | grep bsdtar >/dev/null 2>&1 ) then \
637  *          echo bsdtar; else echo not bsdtar; fi
638  */
639 static void
640 long_help(struct bsdtar *bsdtar)
641 {
642         const char      *prog;
643         const char      *p;
644
645         prog = bsdtar->progname;
646
647         fflush(stderr);
648
649         p = (strcmp(prog,"bsdtar") != 0) ? "(bsdtar)" : "";
650         printf("%s%s: manipulate archive files\n", prog, p);
651
652         for (p = long_help_msg; *p != '\0'; p++) {
653                 if (*p == '%') {
654                         if (p[1] == 'p') {
655                                 fputs(prog, stdout);
656                                 p++;
657                         } else
658                                 putchar('%');
659                 } else
660                         putchar(*p);
661         }
662         version();
663 }