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