/* A tar (tape archiver) program.
- Copyright 1988, 92,93,94,95,96,97, 1999 Free Software Foundation, Inc.
+
+ Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000,
+ 2001, 2003 Free Software Foundation, Inc.
+
Written by John Gilmore, starting 1985-08-25.
This program is free software; you can redistribute it and/or modify it
#include "system.h"
+#include <fnmatch.h>
#include <getopt.h>
#include <signal.h>
#define GLOBAL
#include "common.h"
-#include "xstrtol.h"
-
-time_t get_date ();
+#include <getdate.h>
+#include <localedir.h>
+#include <prepargs.h>
+#include <quotearg.h>
+#include <xstrtol.h>
/* Local declarations. */
# define DEFAULT_BLOCKING 20
#endif
-static void usage PARAMS ((int));
+static void usage (int) __attribute__ ((noreturn));
\f
/* Miscellaneous. */
-/*----------------------------------------------.
-| Doesn't return if stdin already requested. |
-`----------------------------------------------*/
-
/* Name of option using stdin. */
static const char *stdin_used_by;
+/* Doesn't return if stdin already requested. */
void
request_stdin (const char *option)
{
stdin_used_by = option;
}
-/*--------------------------------------------------------.
-| Returns true if and only if the user typed 'y' or 'Y'. |
-`--------------------------------------------------------*/
-
+/* Returns true if and only if the user typed 'y' or 'Y'. */
int
confirm (const char *message_action, const char *message_name)
{
static FILE *confirm_file;
+ static int confirm_file_EOF;
if (!confirm_file)
{
if (archive == 0 || stdin_used_by)
- confirm_file = fopen (TTY_NAME, "r");
+ {
+ confirm_file = fopen (TTY_NAME, "r");
+ if (! confirm_file)
+ open_fatal (TTY_NAME);
+ }
else
{
request_stdin ("-w");
confirm_file = stdin;
}
-
- if (!confirm_file)
- FATAL_ERROR ((0, 0, _("Cannot read confirmation from user")));
}
- fprintf (stdlis, "%s %s?", message_action, message_name);
+ fprintf (stdlis, "%s %s?", message_action, quote (message_name));
fflush (stdlis);
{
- int reply = getc (confirm_file);
+ int reply = confirm_file_EOF ? EOF : getc (confirm_file);
int character;
for (character = reply;
- character != '\n' && character != EOF;
+ character != '\n';
character = getc (confirm_file))
- continue;
+ if (character == EOF)
+ {
+ confirm_file_EOF = 1;
+ fputc ('\n', stdlis);
+ fflush (stdlis);
+ break;
+ }
return reply == 'y' || reply == 'Y';
}
}
enum
{
- BACKUP_OPTION = CHAR_MAX + 1,
+ ANCHORED_OPTION = CHAR_MAX + 1,
+ ATIME_PRESERVE_OPTION,
+ BACKUP_OPTION,
+ CHECKPOINT_OPTION,
DELETE_OPTION,
EXCLUDE_OPTION,
+ FORCE_LOCAL_OPTION,
GROUP_OPTION,
+ IGNORE_CASE_OPTION,
+ IGNORE_FAILED_READ_OPTION,
+ INDEX_FILE_OPTION,
MODE_OPTION,
NEWER_MTIME_OPTION,
- NO_RECURSE_OPTION,
+ NO_ANCHORED_OPTION,
+ NO_IGNORE_CASE_OPTION,
+ NO_OVERWRITE_DIR_OPTION,
+ NO_WILDCARDS_OPTION,
+ NO_WILDCARDS_MATCH_SLASH_OPTION,
NULL_OPTION,
+ NUMERIC_OWNER_OPTION,
+ OVERWRITE_OPTION,
OWNER_OPTION,
POSIX_OPTION,
PRESERVE_OPTION,
RECORD_SIZE_OPTION,
+ RECURSIVE_UNLINK_OPTION,
+ REMOVE_FILES_OPTION,
RSH_COMMAND_OPTION,
+ SHOW_OMITTED_DIRS_OPTION,
SUFFIX_OPTION,
+ TOTALS_OPTION,
USE_COMPRESS_PROGRAM_OPTION,
VOLNO_FILE_OPTION,
+ WILDCARDS_OPTION,
+ WILDCARDS_MATCH_SLASH_OPTION,
/* Some cleanup is being made in GNU tar long options. Using old names is
allowed for a while, but will also send a warning to stderr. Take old
/* If nonzero, print the version on standard output and exit. */
static int show_version;
-struct option long_options[] =
+static struct option long_options[] =
{
{"absolute-names", no_argument, 0, 'P'},
{"absolute-paths", no_argument, 0, OBSOLETE_ABSOLUTE_NAMES},
{"after-date", required_argument, 0, 'N'},
+ {"anchored", no_argument, 0, ANCHORED_OPTION},
{"append", no_argument, 0, 'r'},
- {"atime-preserve", no_argument, &atime_preserve_option, 1},
+ {"atime-preserve", no_argument, 0, ATIME_PRESERVE_OPTION},
{"backup", optional_argument, 0, BACKUP_OPTION},
{"block-compress", no_argument, 0, OBSOLETE_BLOCK_COMPRESS},
{"block-number", no_argument, 0, 'R'},
{"block-size", required_argument, 0, OBSOLETE_BLOCKING_FACTOR},
{"blocking-factor", required_argument, 0, 'b'},
- {"bzip2", no_argument, 0, 'I'},
+ {"bzip2", no_argument, 0, 'j'},
{"catenate", no_argument, 0, 'A'},
- {"checkpoint", no_argument, &checkpoint_option, 1},
+ {"checkpoint", no_argument, 0, CHECKPOINT_OPTION},
{"compare", no_argument, 0, 'd'},
{"compress", no_argument, 0, 'Z'},
{"concatenate", no_argument, 0, 'A'},
{"extract", no_argument, 0, 'x'},
{"file", required_argument, 0, 'f'},
{"files-from", required_argument, 0, 'T'},
- {"force-local", no_argument, &force_local_option, 1},
+ {"force-local", no_argument, 0, FORCE_LOCAL_OPTION},
{"get", no_argument, 0, 'x'},
{"group", required_argument, 0, GROUP_OPTION},
{"gunzip", no_argument, 0, 'z'},
{"gzip", no_argument, 0, 'z'},
{"help", no_argument, &show_help, 1},
- {"ignore-failed-read", no_argument, &ignore_failed_read_option, 1},
+ {"ignore-case", no_argument, 0, IGNORE_CASE_OPTION},
+ {"ignore-failed-read", no_argument, 0, IGNORE_FAILED_READ_OPTION},
{"ignore-zeros", no_argument, 0, 'i'},
/* FIXME: --ignore-end as a new name for --ignore-zeros? */
{"incremental", no_argument, 0, 'G'},
+ {"index-file", required_argument, 0, INDEX_FILE_OPTION},
{"info-script", required_argument, 0, 'F'},
{"interactive", no_argument, 0, 'w'},
{"keep-old-files", no_argument, 0, 'k'},
{"newer", required_argument, 0, 'N'},
{"newer-mtime", required_argument, 0, NEWER_MTIME_OPTION},
{"null", no_argument, 0, NULL_OPTION},
- {"no-recursion", no_argument, 0, NO_RECURSE_OPTION},
- {"numeric-owner", no_argument, &numeric_owner_option, 1},
+ {"no-anchored", no_argument, 0, NO_ANCHORED_OPTION},
+ {"no-ignore-case", no_argument, 0, NO_IGNORE_CASE_OPTION},
+ {"no-overwrite-dir", no_argument, 0, NO_OVERWRITE_DIR_OPTION},
+ {"no-wildcards", no_argument, 0, NO_WILDCARDS_OPTION},
+ {"no-wildcards-match-slash", no_argument, 0, NO_WILDCARDS_MATCH_SLASH_OPTION},
+ {"no-recursion", no_argument, &recursion_option, 0},
+ {"no-same-owner", no_argument, &same_owner_option, -1},
+ {"no-same-permissions", no_argument, &same_permissions_option, -1},
+ {"numeric-owner", no_argument, 0, NUMERIC_OWNER_OPTION},
{"old-archive", no_argument, 0, 'o'},
{"one-file-system", no_argument, 0, 'l'},
+ {"overwrite", no_argument, 0, OVERWRITE_OPTION},
{"owner", required_argument, 0, OWNER_OPTION},
{"portability", no_argument, 0, 'o'},
{"posix", no_argument, 0, POSIX_OPTION},
{"preserve", no_argument, 0, PRESERVE_OPTION},
{"preserve-order", no_argument, 0, 's'},
{"preserve-permissions", no_argument, 0, 'p'},
- {"recursive-unlink", no_argument, &recursive_unlink_option, 1},
+ {"recursion", no_argument, &recursion_option, FNM_LEADING_DIR},
+ {"recursive-unlink", no_argument, 0, RECURSIVE_UNLINK_OPTION},
{"read-full-blocks", no_argument, 0, OBSOLETE_READ_FULL_RECORDS},
{"read-full-records", no_argument, 0, 'B'},
/* FIXME: --partial-blocks might be a synonym for --read-full-records? */
{"record-number", no_argument, 0, OBSOLETE_BLOCK_NUMBER},
{"record-size", required_argument, 0, RECORD_SIZE_OPTION},
- {"remove-files", no_argument, &remove_files_option, 1},
+ {"remove-files", no_argument, 0, REMOVE_FILES_OPTION},
{"rsh-command", required_argument, 0, RSH_COMMAND_OPTION},
{"same-order", no_argument, 0, 's'},
{"same-owner", no_argument, &same_owner_option, 1},
{"same-permissions", no_argument, 0, 'p'},
- {"show-omitted-dirs", no_argument, &show_omitted_dirs_option, 1},
+ {"show-omitted-dirs", no_argument, 0, SHOW_OMITTED_DIRS_OPTION},
{"sparse", no_argument, 0, 'S'},
{"starting-file", required_argument, 0, 'K'},
{"suffix", required_argument, 0, SUFFIX_OPTION},
{"tape-length", required_argument, 0, 'L'},
{"to-stdout", no_argument, 0, 'O'},
- {"totals", no_argument, &totals_option, 1},
+ {"totals", no_argument, 0, TOTALS_OPTION},
{"touch", no_argument, 0, 'm'},
{"uncompress", no_argument, 0, 'Z'},
{"ungzip", no_argument, 0, 'z'},
{"version", no_argument, &show_version, 1},
{"version-control", required_argument, 0, OBSOLETE_VERSION_CONTROL},
{"volno-file", required_argument, 0, VOLNO_FILE_OPTION},
+ {"wildcards", no_argument, 0, WILDCARDS_OPTION},
+ {"wildcards-match-slash", no_argument, 0, WILDCARDS_MATCH_SLASH_OPTION},
{0, 0, 0, 0}
};
-/*---------------------------------------------.
-| Print a usage message and exit with STATUS. |
-`---------------------------------------------*/
-
+/* Print a usage message and exit with STATUS. */
static void
usage (int status)
{
GNU `tar' saves many files together into a single tape or disk archive, and\n\
can restore individual files from the archive.\n"),
stdout);
- printf (_("\nUsage: %s [OPTION]... [FILE]...\n"), program_name);
+ printf (_("\nUsage: %s [OPTION]... [FILE]...\n\
+\n\
+Examples:\n\
+ %s -cf archive.tar foo bar # Create archive.tar from files foo and bar.\n\
+ %s -tvf archive.tar # List all files in archive.tar verbosely.\n\
+ %s -xf archive.tar # Extract all files from archive.tar.\n"),
+ program_name, program_name, program_name, program_name);
fputs (_("\
\n\
If a long option shows an argument as mandatory, then it is mandatory\n\
Operation modifiers:\n\
-W, --verify attempt to verify the archive after writing it\n\
--remove-files remove files after adding them to the archive\n\
- -k, --keep-old-files don't overwrite existing files when extracting\n\
+ -k, --keep-old-files don't replace existing files when extracting\n\
+ --overwrite overwrite existing files when extracting\n\
+ --no-overwrite-dir preserve metadata of existing directories\n\
-U, --unlink-first remove each file prior to extracting over it\n\
--recursive-unlink empty hierarchies prior to extracting directory\n\
-S, --sparse handle sparse files efficiently\n\
-O, --to-stdout extract files to standard output\n\
-G, --incremental handle old GNU-format incremental backup\n\
- -g, --listed-incremental handle new GNU-format incremental backup\n\
+ -g, --listed-incremental=FILE\n\
+ handle new GNU-format incremental backup\n\
--ignore-failed-read do not exit with nonzero on unreadable files\n"),
stdout);
fputs (_("\
--atime-preserve don't change access times on dumped files\n\
-m, --modification-time don't extract file modified time\n\
--same-owner try extracting files with the same ownership\n\
+ --no-same-owner extract files as yourself\n\
--numeric-owner always use numbers for user/group names\n\
- -p, --same-permissions extract all protection information\n\
+ -p, --same-permissions extract permissions information\n\
+ --no-same-permissions do not extract permissions information\n\
--preserve-permissions same as -p\n\
-s, --same-order sort names to extract to match archive\n\
--preserve-order same as -s\n\
PATTERN at list/extract time, a globbing PATTERN\n\
-o, --old-archive, --portability write a V7 format archive\n\
--posix write a POSIX format archive\n\
- -I, --bzip2 filter the archive through bzip2\n\
+ -j, --bzip2 filter the archive through bzip2\n\
-z, --gzip, --ungzip filter the archive through gzip\n\
-Z, --compress, --uncompress filter the archive through compress\n\
--use-compress-program=PROG filter through PROG (must accept -d)\n"),
-C, --directory=DIR change to directory DIR\n\
-T, --files-from=NAME get names to extract or create from file NAME\n\
--null -T reads null-terminated names, disable -C\n\
- --exclude=PATTERN exclude files, given as a globbing PATTERN\n\
- -X, --exclude-from=FILE exclude globbing patterns listed in FILE\n\
+ --exclude=PATTERN exclude files, given as a PATTERN\n\
+ -X, --exclude-from=FILE exclude patterns listed in FILE\n\
+ --anchored exclude patterns match file name start (default)\n\
+ --no-anchored exclude patterns match after any /\n\
+ --ignore-case exclusion ignores case\n\
+ --no-ignore-case exclusion is case sensitive (default)\n\
+ --wildcards exclude patterns use wildcards (default)\n\
+ --no-wildcards exclude patterns are plain strings\n\
+ --wildcards-match-slash exclude pattern wildcards match '/' (default)\n\
+ --no-wildcards-match-slash exclude pattern wildcards do not match '/'\n\
-P, --absolute-names don't strip leading `/'s from file names\n\
-h, --dereference dump instead the files symlinks point to\n\
--no-recursion avoid descending automatically in directories\n\
#if !MSDOS
fputs (_("\
-N, --newer=DATE only store files newer than DATE\n\
- --newer-mtime compare date and time when data changed only\n\
+ --newer-mtime=DATE compare date and time when data changed only\n\
--after-date=DATE same as -N\n"),
stdout);
#endif
-v, --verbose verbosely list files processed\n\
--checkpoint print directory names while reading the archive\n\
--totals print total bytes written while creating archive\n\
+ --index-file=FILE send verbose output to FILE\n\
-R, --block-number show block number within archive with each message\n\
-w, --interactive ask for confirmation for every action\n\
--confirmation same as -w\n"),
GNU tar cannot read nor produce `--posix' archives. If POSIXLY_CORRECT\n\
is set in the environment, GNU extensions are disallowed with `--posix'.\n\
Support for POSIX is only partially implemented, don't count on it yet.\n\
-ARCHIVE may be FILE, HOST:FILE or USER@HOST:FILE; and FILE may be a file\n\
-or a device. *This* `tar' defaults to `-f%s -b%d'.\n"),
+ARCHIVE may be FILE, HOST:FILE or USER@HOST:FILE; DATE may be a textual date\n\
+or a file name starting with `/' or `.', in which case the file's date is used.\n\
+*This* `tar' defaults to `-f%s -b%d'.\n"),
DEFAULT_ARCHIVE, DEFAULT_BLOCKING);
- fputs (_("\
-\n\
-Report bugs to <bug-tar@gnu.org>.\n"),
- stdout);
+ printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
exit (status);
}
-/*----------------------------.
-| Parse the options for tar. |
-`----------------------------*/
+/* Parse the options for tar. */
-/* Available option letters are DEHJQY and aejnqy. Some are reserved:
+/* Available option letters are DEHIJQY and aenqy. Some are reserved:
+ e exit immediately with a nonzero exit status if unexpected errors occur
+ E use extended headers (draft POSIX headers, that is)
+ I same as T (for compatibility with Solaris tar)
+ n the archive is quickly seekable, so don't worry about random seeks
+ q stop after extracting the first occurrence of the named file
y per-file gzip compression
Y per-block gzip compression */
#define OPTION_STRING \
- "-01234567ABC:F:GIK:L:MN:OPRST:UV:WX:Zb:cdf:g:hiklmoprstuvwxz"
+ "-01234567ABC:F:GIK:L:MN:OPRST:UV:WX:Zb:cdf:g:hijklmoprstuvwxyz"
static void
set_subcommand_option (enum subcommand subcommand)
use_compress_program_option = string;
}
-/* Ignore DUMMY (which will always be null in practice), and add
- PATTERN to the proper set of patterns to be excluded -- either
- patterns with slashes, or patterns without. */
-static void
-add_filtered_exclude (struct exclude *dummy, char const *pattern)
-{
- add_exclude ((strchr (pattern, '/')
- ? excluded_with_slash
- : excluded_without_slash),
- pattern);
-}
-
static void
-decode_options (int argc, char *const *argv)
+decode_options (int argc, char **argv)
{
int optchar; /* option letter */
int input_files; /* number of input files */
- const char *backup_suffix_string;
- const char *version_control_string = 0;
+ char const *textual_date_option = 0;
+ char const *backup_suffix_string;
+ char const *version_control_string = 0;
+ int exclude_options = EXCLUDE_WILDCARDS;
/* Set some default option values. */
archive_format = DEFAULT_FORMAT;
blocking_factor = DEFAULT_BLOCKING;
record_size = DEFAULT_BLOCKING * BLOCKSIZE;
- excluded_with_slash = new_exclude ();
- excluded_without_slash = new_exclude ();
+ excluded = new_exclude ();
newer_mtime_option = TYPE_MINIMUM (time_t);
+ recursion_option = FNM_LEADING_DIR;
owner_option = -1;
group_option = -1;
/* Allocate a new argument array, and copy program name in it. */
new_argc = argc - 1 + strlen (argv[1]);
- new_argv = xmalloc (new_argc * sizeof (char *));
+ new_argv = xmalloc ((new_argc + 1) * sizeof (char *));
in = argv;
out = new_argv;
*out++ = *in++;
while (in < argv + argc)
*out++ = *in++;
+ *out = 0;
/* Replace the old option list by the new one. */
input_files = 0;
+ prepend_default_options (getenv ("TAR_OPTIONS"), &argc, &argv);
+
while (optchar = getopt_long (argc, argv, OPTION_STRING, long_options, 0),
optchar != -1)
switch (optchar)
&& u == (blocking_factor = u)
&& 0 < blocking_factor
&& u == (record_size = u * BLOCKSIZE) / BLOCKSIZE))
- USAGE_ERROR ((0, 0, _("Invalid blocking factor")));
+ USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+ _("Invalid blocking factor")));
}
break;
break;
case 'I':
+ USAGE_ERROR ((0, 0,
+ _("Warning: the -I option is not supported;"
+ " perhaps you meant -j or -T?")));
+ break;
+
+ case 'j':
set_use_compress_program_option ("bzip2");
break;
case 'k':
- /* Don't overwrite existing files. */
-
- keep_old_files_option = 1;
+ /* Don't replace existing files. */
+ old_files_option = KEEP_OLD_FILES;
break;
case 'K':
{
uintmax_t u;
if (xstrtoumax (optarg, 0, 10, &u, "") != LONGINT_OK)
- USAGE_ERROR ((0, 0, _("Invalid tape length")));
+ USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+ _("Invalid tape length")));
tape_length_option = 1024 * (tarlong) u;
multi_volume_option = 1;
}
/* Fall through. */
case NEWER_MTIME_OPTION:
- if (newer_mtime_option != TYPE_MINIMUM (time_t))
+ if (newer_mtime_option != TYPE_MINIMUM (time_t))
USAGE_ERROR ((0, 0, _("More than one threshold date")));
- newer_mtime_option = get_date (optarg, 0);
- if (newer_mtime_option == (time_t) -1)
- USAGE_ERROR ((0, 0, _("Invalid date format `%s'"), optarg));
+ if (FILESYSTEM_PREFIX_LEN (optarg) != 0
+ || ISSLASH (*optarg)
+ || *optarg == '.')
+ {
+ struct stat st;
+ if (deref_stat (dereference_option, optarg, &st) != 0)
+ {
+ stat_error (optarg);
+ USAGE_ERROR ((0, 0, _("Date file not found")));
+ }
+ newer_mtime_option = st.st_mtime;
+ }
+ else
+ {
+ newer_mtime_option = get_date (optarg, 0);
+ if (newer_mtime_option == (time_t) -1)
+ WARN ((0, 0, _("Substituting %s for unknown date format %s"),
+ tartime (newer_mtime_option), quote (optarg)));
+ else
+ textual_date_option = optarg;
+ }
break;
#endif /* not MSDOS */
break;
case 'U':
- unlink_first_option = 1;
+ old_files_option = UNLINK_FIRST_OLD_FILES;
break;
case 'v':
break;
case 'X':
- if (add_exclude_file (add_filtered_exclude, 0, optarg, '\n') != 0)
- FATAL_ERROR ((0, errno, "%s", optarg));
+ if (add_exclude_file (add_exclude, excluded, optarg,
+ exclude_options | recursion_option, '\n')
+ != 0)
+ {
+ int e = errno;
+ FATAL_ERROR ((0, e, "%s", quotearg_colon (optarg)));
+ }
+ break;
+
+ case 'y':
+ USAGE_ERROR ((0, 0,
+ _("Warning: the -y option is not supported;"
+ " perhaps you meant -j?")));
break;
case 'z':
WARN ((0, 0, _("Obsolete option name replaced by --backup")));
/* Fall through. */
+ case ANCHORED_OPTION:
+ exclude_options |= EXCLUDE_ANCHORED;
+ break;
+
+ case ATIME_PRESERVE_OPTION:
+ atime_preserve_option = 1;
+ break;
+
+ case CHECKPOINT_OPTION:
+ checkpoint_option = 1;
+ break;
+
case BACKUP_OPTION:
backup_option = 1;
if (optarg)
break;
case EXCLUDE_OPTION:
- add_filtered_exclude (0, optarg);
+ add_exclude (excluded, optarg, exclude_options | recursion_option);
+ break;
+
+ case FORCE_LOCAL_OPTION:
+ force_local_option = 1;
+ break;
+
+ case INDEX_FILE_OPTION:
+ index_file_name = optarg;
+ break;
+
+ case IGNORE_CASE_OPTION:
+ exclude_options |= FNM_CASEFOLD;
+ break;
+
+ case IGNORE_FAILED_READ_OPTION:
+ ignore_failed_read_option = 1;
break;
case GROUP_OPTION:
&& g == (gid_t) g)
group_option = g;
else
- FATAL_ERROR ((0, 0, _("Invalid group given on option")));
+ FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+ _("%s: Invalid group")));
}
break;
if (mode_option == MODE_INVALID)
FATAL_ERROR ((0, 0, _("Invalid mode given on option")));
if (mode_option == MODE_MEMORY_EXHAUSTED)
- FATAL_ERROR ((0, 0, _("Memory exhausted")));
+ xalloc_die ();
+ break;
+
+ case NO_ANCHORED_OPTION:
+ exclude_options &= ~ EXCLUDE_ANCHORED;
+ break;
+
+ case NO_IGNORE_CASE_OPTION:
+ exclude_options &= ~ FNM_CASEFOLD;
+ break;
+
+ case NO_OVERWRITE_DIR_OPTION:
+ old_files_option = NO_OVERWRITE_DIR_OLD_FILES;
+ break;
+
+ case NO_WILDCARDS_OPTION:
+ exclude_options &= ~ EXCLUDE_WILDCARDS;
break;
- case NO_RECURSE_OPTION:
- no_recurse_option = 1;
+ case NO_WILDCARDS_MATCH_SLASH_OPTION:
+ exclude_options |= FNM_FILE_NAME;
break;
case NULL_OPTION:
filename_terminator = '\0';
break;
+ case NUMERIC_OWNER_OPTION:
+ numeric_owner_option = 1;
+ break;
+
+ case OVERWRITE_OPTION:
+ old_files_option = OVERWRITE_OLD_FILES;
+ break;
+
case OWNER_OPTION:
if (! (strlen (optarg) < UNAME_FIELD_SIZE
&& uname_to_uid (optarg, &owner_option)))
&& u == (uid_t) u)
owner_option = u;
else
- FATAL_ERROR ((0, 0, _("Invalid owner given on option")));
+ FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+ _("Invalid owner")));
}
break;
uintmax_t u;
if (! (xstrtoumax (optarg, 0, 10, &u, "") == LONGINT_OK
&& u == (size_t) u))
- USAGE_ERROR ((0, 0, _("Invalid record size")));
+ USAGE_ERROR ((0, 0, "%s: %s", quotearg_colon (optarg),
+ _("Invalid record size")));
record_size = u;
if (record_size % BLOCKSIZE != 0)
USAGE_ERROR ((0, 0, _("Record size must be a multiple of %d."),
}
break;
+ case RECURSIVE_UNLINK_OPTION:
+ recursive_unlink_option = 1;
+ break;
+
+ case REMOVE_FILES_OPTION:
+ remove_files_option = 1;
+ break;
+
case RSH_COMMAND_OPTION:
rsh_command_option = optarg;
break;
backup_suffix_string = optarg;
break;
+ case USE_COMPRESS_PROGRAM_OPTION:
+ set_use_compress_program_option (optarg);
+ break;
+
case VOLNO_FILE_OPTION:
volno_file_option = optarg;
break;
- case USE_COMPRESS_PROGRAM_OPTION:
- set_use_compress_program_option (optarg);
+ case WILDCARDS_OPTION:
+ exclude_options |= EXCLUDE_WILDCARDS;
+ break;
+
+ case WILDCARDS_MATCH_SLASH_OPTION:
+ exclude_options &= ~ FNM_FILE_NAME;
break;
case '0':
if (show_version)
{
- printf ("tar (GNU %s) %s\n", PACKAGE, VERSION);
- fputs (_("\
-\n\
-Copyright 1988, 92,93,94,95,96,97,98, 1999 Free Software Foundation, Inc.\n"),
- stdout);
- fputs (_("\
-This is free software; see the source for copying conditions. There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"),
- stdout);
- fputs (_("\
-\n\
-Written by John Gilmore and Jay Fenlason.\n"),
- stdout);
+ printf ("tar (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ printf (_("Copyright (C) %d Free Software Foundation, Inc.\n"), 2003);
+ puts (_("\
+This program comes with NO WARRANTY, to the extent permitted by law.\n\
+You may redistribute it under the terms of the GNU General Public License;\n\
+see the file named COPYING for details."));
+
+ puts (_("Written by John Gilmore and Jay Fenlason."));
+
exit (TAREXIT_SUCCESS);
}
USAGE_ERROR ((0, 0,
_("Cannot combine --listed-incremental with --newer")));
+ if (volume_label_option)
+ {
+ size_t volume_label_max_len =
+ (sizeof current_header->header.name
+ - 1 /* for trailing '\0' */
+ - (multi_volume_option
+ ? (sizeof " Volume "
+ - 1 /* for null at end of " Volume " */
+ + INT_STRLEN_BOUND (int) /* for volume number */
+ - 1 /* for sign, as 0 <= volno */)
+ : 0));
+ if (volume_label_max_len < strlen (volume_label_option))
+ USAGE_ERROR ((0, 0,
+ _("%s: Volume label is too long (limit is %lu bytes)"),
+ quotearg_colon (volume_label_option),
+ (unsigned long) volume_label_max_len));
+ }
+
/* If ready to unlink hierarchies, so we are for simpler files. */
if (recursive_unlink_option)
- unlink_first_option = 1;
+ old_files_option = UNLINK_FIRST_OLD_FILES;
/* Forbid using -c with no input files whatsoever. Check that `-f -',
explicit or implied, is used correctly. */
if (backup_option)
backup_type = xget_version ("--backup", version_control_string);
+
+ if (verbose_option && textual_date_option)
+ {
+ char const *treated_as = tartime (newer_mtime_option);
+ if (strcmp (textual_date_option, treated_as) != 0)
+ WARN ((0, 0, _("Treating date `%s' as %s"),
+ textual_date_option, treated_as));
+ }
}
\f
/* Tar proper. */
-/*-----------------------.
-| Main routine for tar. |
-`-----------------------*/
-
+/* Main routine for tar. */
int
-main (int argc, char *const *argv)
+main (int argc, char **argv)
{
+#if HAVE_CLOCK_GETTIME
+ if (clock_gettime (CLOCK_REALTIME, &start_timespec) != 0)
+#endif
+ start_time = time (0);
program_name = argv[0];
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
exit_status = TAREXIT_SUCCESS;
filename_terminator = '\n';
+ set_quoting_style (0, escape_quoting_style);
/* Pre-allocate a few structures. */
case EXTRACT_SUBCOMMAND:
extr_init ();
read_and (extract_archive);
+
+ /* FIXME: should extract_finish () even if an ordinary signal is
+ received. */
+ extract_finish ();
+
break;
case LIST_SUBCOMMAND:
free (archive_name_array);
name_term ();
- if (stdlis == stdout && (ferror (stdout) || fclose (stdout) != 0))
+ if (stdlis != stderr && (ferror (stdlis) || fclose (stdlis) != 0))
FATAL_ERROR ((0, 0, _("Error in writing to standard output")));
if (exit_status == TAREXIT_FAILURE)
error (0, 0, _("Error exit delayed from previous errors"));
+ if (ferror (stderr) || fclose (stderr) != 0)
+ exit_status = TAREXIT_FAILURE;
exit (exit_status);
}