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