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