Allow arguments to appear in any order.
While I'm here, add a couple of extra sanity-checks to the argument parsing (reject -j -z, for instance) and update the docs a bit. Requested by: most everyone ;-)
This commit is contained in:
parent
41f1b2c460
commit
f6f4796250
@ -56,7 +56,7 @@ must be a mode indicator from the following list:
|
||||
.It Fl c
|
||||
Create a new archive containing the specified items.
|
||||
.It Fl r
|
||||
Like
|
||||
Like
|
||||
.Fl c ,
|
||||
but new entries are appended to the archive specified with the
|
||||
.Fl f
|
||||
@ -216,7 +216,6 @@ is specified, and the program is being run by the root user.
|
||||
In this case, the file modes and flags from
|
||||
the archive will be restored, but ACLs or owner information in
|
||||
the archive will be discarded.
|
||||
(not yet implemented)
|
||||
.It Fl P
|
||||
Preserve leading slashes.
|
||||
By default, absolute pathnames (those that begin with a / character)
|
||||
@ -227,8 +226,15 @@ This option suppresses that behavior.
|
||||
Preserve file permissions.
|
||||
Attempt to restore the full permissions, including owner, file modes, file
|
||||
flags and ACLs, if available, for each item extracted from the archive.
|
||||
By default, newly-created regular files have the file mode restored and
|
||||
By default, newly-created files are owned by the user running
|
||||
.Nm ,
|
||||
the file mode is restored for newly-created regular files, and
|
||||
all other types of entries receive default permissions.
|
||||
If
|
||||
.Nm
|
||||
is being run by root, the default is to restore the owner unless the
|
||||
.Fl o
|
||||
option is also specified.
|
||||
.It Fl T Ar filename
|
||||
(c mode only)
|
||||
Read names to be archived from
|
||||
@ -486,11 +492,6 @@ depend on the order of command-line options.
|
||||
This behavior differs from that of implementations that do
|
||||
not follow standard getopt argument parsing conventions.
|
||||
.Pp
|
||||
Since many options depend on the particular operating mode,
|
||||
the mode option itself must be specified first on the command line.
|
||||
This allows for more accurate detection and reporting of
|
||||
incorrect option usage.
|
||||
.Pp
|
||||
All archive output is written in correctly-sized blocks, even
|
||||
if the output is being compressed.
|
||||
Whether or not the last output block is padded to a full
|
||||
|
@ -52,7 +52,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include "bsdtar.h"
|
||||
|
||||
static void long_help(void);
|
||||
static void only_mode(char mode, char opt, const char *valid);
|
||||
static void only_mode(char mode, const char *opt,
|
||||
const char *valid);
|
||||
static const char *progname;
|
||||
static char ** rewrite_argv(int *argc, char ** src_argv,
|
||||
const char *optstring);
|
||||
@ -115,10 +116,13 @@ main(int argc, char **argv)
|
||||
{
|
||||
struct bsdtar *bsdtar, bsdtar_storage;
|
||||
struct passwd *pwent;
|
||||
int opt, mode;
|
||||
int opt;
|
||||
char mode;
|
||||
char buff[16];
|
||||
|
||||
if (setlocale(LC_ALL, "") == NULL)
|
||||
bsdtar_warnc(0, "Failed to set default locale");
|
||||
mode = '\0';
|
||||
|
||||
/*
|
||||
* Use a pointer for consistency, but stack-allocated storage
|
||||
@ -158,34 +162,6 @@ main(int argc, char **argv)
|
||||
bsdtar->argv = argv;
|
||||
bsdtar->argc = argc;
|
||||
|
||||
/* First option must be mode selector */
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
mode = getopt_long(bsdtar->argc, bsdtar->argv, tar_opts, tar_longopts,
|
||||
NULL);
|
||||
#else
|
||||
mode = getopt(bsdtar->argc, bsdtar->argv, tar_opts);
|
||||
#endif
|
||||
|
||||
switch (mode) {
|
||||
case -1:
|
||||
usage();
|
||||
break;
|
||||
case 'h':
|
||||
long_help();
|
||||
break;
|
||||
case 't':
|
||||
bsdtar->verbose = 1;
|
||||
break;
|
||||
case 'c': case 'r': case 'u': case 'x':
|
||||
break;
|
||||
default:
|
||||
bsdtar_errc(1, 0,
|
||||
"First option '%c' unrecognized; "
|
||||
"should be -c, -r, -t, -u, -x", mode);
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Process all remaining arguments now. */
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
while ((opt = getopt_long(bsdtar->argc, bsdtar->argv,
|
||||
@ -199,16 +175,22 @@ main(int argc, char **argv)
|
||||
bsdtar->bytes_per_block = 512 * atoi(optarg);
|
||||
break;
|
||||
case 'C': /* GNU tar */
|
||||
/* XXX How should multiple -C options be handled? */
|
||||
bsdtar->start_dir = optarg;
|
||||
break;
|
||||
case 'c': /* SUSv2 */
|
||||
if (mode != '\0')
|
||||
bsdtar_errc(1, 0,
|
||||
"Can't specify both -%c and -%c",
|
||||
opt, mode);
|
||||
mode = opt;
|
||||
break;
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
case OPTION_EXCLUDE: /* GNU tar */
|
||||
only_mode(mode, opt, "xtcr");
|
||||
exclude(bsdtar, optarg);
|
||||
break;
|
||||
#endif
|
||||
case 'F':
|
||||
only_mode(mode, opt, "c");
|
||||
bsdtar->create_format = optarg;
|
||||
break;
|
||||
case 'f': /* SUSv2 */
|
||||
@ -218,46 +200,46 @@ main(int argc, char **argv)
|
||||
break;
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
case OPTION_FAST_READ: /* GNU tar */
|
||||
only_mode(mode, opt, "tx");
|
||||
bsdtar->option_fast_read = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'H': /* BSD convention */
|
||||
only_mode(mode, opt, "cr");
|
||||
bsdtar->symlink_mode = 'H';
|
||||
break;
|
||||
case 'h':
|
||||
long_help();
|
||||
break;
|
||||
case 'j': /* GNU tar */
|
||||
if (bsdtar->create_compression != '\0')
|
||||
bsdtar_errc(1, 0,
|
||||
"Can't specify both -%c and -%c", opt,
|
||||
bsdtar->create_compression);
|
||||
bsdtar->create_compression = opt;
|
||||
break;
|
||||
case 'k': /* GNU tar */
|
||||
only_mode(mode, opt, "x");
|
||||
bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE;
|
||||
break;
|
||||
case 'L': /* BSD convention */
|
||||
only_mode(mode, opt, "cr");
|
||||
bsdtar->symlink_mode = 'L';
|
||||
break;
|
||||
case 'l': /* SUSv2 */
|
||||
only_mode(mode, opt, "cr");
|
||||
bsdtar->option_warn_links = 1;
|
||||
break;
|
||||
case 'm': /* SUSv2 */
|
||||
only_mode(mode, opt, "x");
|
||||
bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_TIME;
|
||||
break;
|
||||
case 'n': /* GNU tar */
|
||||
only_mode(mode, opt, "cr");
|
||||
bsdtar->option_no_subdirs = 1;
|
||||
break;
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
case OPTION_NODUMP: /* star */
|
||||
only_mode(mode, opt, "cr");
|
||||
bsdtar->option_honor_nodump = 1;
|
||||
break;
|
||||
#endif
|
||||
case 'O': /* GNU tar */
|
||||
only_mode(mode, opt, "x");
|
||||
bsdtar->option_stdout = 1;
|
||||
break;
|
||||
case 'o': /* SUSv2 */
|
||||
only_mode(mode, opt, "x");
|
||||
bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER;
|
||||
break;
|
||||
#if 0
|
||||
@ -272,22 +254,40 @@ main(int argc, char **argv)
|
||||
break;
|
||||
#endif
|
||||
case 'P': /* GNU tar */
|
||||
only_mode(mode, opt, "xcru");
|
||||
bsdtar->option_absolute_paths = 1;
|
||||
break;
|
||||
case 'p': /* GNU tar, star */
|
||||
only_mode(mode, opt, "x");
|
||||
umask(0);
|
||||
bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM;
|
||||
break;
|
||||
case 'r': /* SUSv2 */
|
||||
if (mode != '\0')
|
||||
bsdtar_errc(1, 0,
|
||||
"Can't specify both -%c and -%c",
|
||||
opt, mode);
|
||||
mode = opt;
|
||||
break;
|
||||
case 't': /* SUSv2 */
|
||||
if (mode != '\0')
|
||||
bsdtar_errc(1, 0,
|
||||
"Can't specify both -%c and -%c",
|
||||
opt, mode);
|
||||
mode = opt;
|
||||
bsdtar->verbose++;
|
||||
break;
|
||||
case 'T': /* GNU tar */
|
||||
only_mode(mode, opt, "c");
|
||||
bsdtar->names_from_file = optarg;
|
||||
break;
|
||||
case 'U': /* GNU tar */
|
||||
only_mode(mode, opt, "x");
|
||||
bsdtar->extract_flags |= ARCHIVE_EXTRACT_UNLINK;
|
||||
break;
|
||||
case 'u': /* SUSv2 */
|
||||
if (mode != '\0')
|
||||
bsdtar_errc(1, 0,
|
||||
"Can't specify both -%c and -%c",
|
||||
opt, mode);
|
||||
mode = opt;
|
||||
break;
|
||||
case 'v': /* SUSv2 */
|
||||
bsdtar->verbose++;
|
||||
break;
|
||||
@ -295,28 +295,76 @@ main(int argc, char **argv)
|
||||
bsdtar->option_interactive = 1;
|
||||
break;
|
||||
case 'X': /* -l in GNU tar */
|
||||
only_mode(mode, opt, "cr");
|
||||
bsdtar->option_dont_traverse_mounts = 1;
|
||||
break;
|
||||
case 'j': /* GNU tar */
|
||||
case 'x': /* SUSv2 */
|
||||
if (mode != '\0')
|
||||
bsdtar_errc(1, 0,
|
||||
"Can't specify both -%c and -%c",
|
||||
opt, mode);
|
||||
mode = opt;
|
||||
break;
|
||||
case 'y': /* FreeBSD version of GNU tar */
|
||||
case 'z': /* GNU tar, star */
|
||||
/*
|
||||
* Ignored in x/t modes, used in 'c' mode,
|
||||
* forbidden in r/u modes.
|
||||
*/
|
||||
only_mode(mode, opt, "cxt");
|
||||
if (bsdtar->create_compression != '\0')
|
||||
bsdtar_errc(1, 0,
|
||||
"Can't specify both -%c and -%c", opt,
|
||||
bsdtar->create_compression);
|
||||
bsdtar->create_compression = opt;
|
||||
break;
|
||||
case 'Z': /* GNU tar */
|
||||
bsdtar_warnc(0, ".Z compression not supported");
|
||||
usage();
|
||||
break;
|
||||
case 'z': /* GNU tar, star */
|
||||
if (bsdtar->create_compression != '\0')
|
||||
bsdtar_errc(1, 0,
|
||||
"Can't specify both -%c and -%c", opt,
|
||||
bsdtar->create_compression);
|
||||
bsdtar->create_compression = opt;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sanity-check options.
|
||||
*/
|
||||
if (mode == '\0')
|
||||
bsdtar_errc(1, 0, "Must specify one of -c, -r, -t, -u, -x");
|
||||
|
||||
/* Check boolean options only permitted in certain modes. */
|
||||
if (bsdtar->option_absolute_paths)
|
||||
only_mode(mode, "-P", "xcru");
|
||||
if (bsdtar->option_dont_traverse_mounts)
|
||||
only_mode(mode, "-X", "cru");
|
||||
if (bsdtar->option_fast_read)
|
||||
only_mode(mode, "--fast-read", "xt");
|
||||
if (bsdtar->option_honor_nodump)
|
||||
only_mode(mode, "--nodump", "cru");
|
||||
if (bsdtar->option_no_subdirs)
|
||||
only_mode(mode, "-n", "cru");
|
||||
if (bsdtar->option_stdout)
|
||||
only_mode(mode, "-O", "x");
|
||||
if (bsdtar->option_warn_links)
|
||||
only_mode(mode, "-l", "cr");
|
||||
|
||||
/* Check other parameters only permitted in certain modes. */
|
||||
if (bsdtar->create_compression != '\0') {
|
||||
strcpy(buff, "-?");
|
||||
buff[1] = bsdtar->create_compression;
|
||||
only_mode(mode, buff, "cxt");
|
||||
}
|
||||
if (bsdtar->create_format != NULL)
|
||||
only_mode(mode, "-F", "c");
|
||||
if (bsdtar->names_from_file != NULL)
|
||||
only_mode(mode, "-T", "cru");
|
||||
if (bsdtar->symlink_mode != '\0') {
|
||||
strcpy(buff, "-X");
|
||||
buff[1] = bsdtar->symlink_mode;
|
||||
only_mode(mode, buff, "cru");
|
||||
}
|
||||
|
||||
bsdtar->argc -= optind;
|
||||
bsdtar->argv += optind;
|
||||
|
||||
@ -338,8 +386,6 @@ main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (bsdtar->user_uname != NULL)
|
||||
free(bsdtar->user_uname);
|
||||
|
||||
@ -350,10 +396,10 @@ main(int argc, char **argv)
|
||||
* Verify that the mode is correct.
|
||||
*/
|
||||
static void
|
||||
only_mode(char mode, char opt, const char *valid_modes)
|
||||
only_mode(char mode, const char *opt, const char *valid_modes)
|
||||
{
|
||||
if (strchr(valid_modes, mode) == NULL)
|
||||
bsdtar_errc(1, 0, "Option -%c is not permitted in mode -%c",
|
||||
bsdtar_errc(1, 0, "Option %s is not permitted in mode -%c",
|
||||
opt, mode);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user