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