diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2004-08-30 16:15:01 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2004-08-30 16:15:01 +0000 |
commit | fdcc59045ba08204517a7540c693887ff98546f3 (patch) | |
tree | f6668ebf17578ad718c06d2f276da821440143ed /src/main.c | |
parent | 072559619e5105fe148b2390ae00c72a5e9772bc (diff) | |
download | cpio-fdcc59045ba08204517a7540c693887ff98546f3.tar.gz cpio-fdcc59045ba08204517a7540c693887ff98546f3.tar.bz2 |
Option parsing rewritten using argp. Improved option consistency checking.
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 850 |
1 files changed, 504 insertions, 346 deletions
@@ -17,7 +17,8 @@ /* Written by Phil Nelson <phil@cs.wwu.edu>, David MacKenzie <djm@gnu.ai.mit.edu>, - and John Oleynick <juo@klinzhai.rutgers.edu>. */ + John Oleynick <juo@klinzhai.rutgers.edu>, + and Sergey Poznyakoff <gray@mirddin.farlep.net> */ #if defined(HAVE_CONFIG_H) # include <config.h> @@ -25,6 +26,7 @@ #include <stdio.h> #include <getopt.h> +#include <argp.h> #include <sys/types.h> #include <sys/stat.h> @@ -40,345 +42,474 @@ #include "rmt.h" #include "localedir.h" -struct option long_opts[] = -{ - {"null", 0, 0, '0'}, - {"append", 0, 0, 'A'}, - {"block-size", 1, 0, 130}, - {"create", 0, 0, 'o'}, - {"dereference", 0, 0, 'L'}, - {"dot", 0, 0, 'V'}, - {"extract", 0, 0, 'i'}, - {"file", 1, 0, 'F'}, - {"force-local", 0, &f_force_local, 1}, - {"format", 1, 0, 'H'}, - {"help", 0, 0, 132}, - {"io-size", 1, 0, 'C'}, - {"link", 0, &link_flag, TRUE}, - {"list", 0, &table_flag, TRUE}, - {"make-directories", 0, &create_dir_flag, TRUE}, - {"message", 1, 0, 'M'}, - {"no-absolute-filenames", 0, 0, 136}, - {"no-preserve-owner", 0, 0, 134}, - {"nonmatching", 0, ©_matching_files, FALSE}, - {"numeric-uid-gid", 0, &numeric_uid, TRUE}, - {"only-verify-crc", 0, 0, 139}, - {"owner", 1, 0, 'R'}, - {"pass-through", 0, 0, 'p'}, - {"pattern-file", 1, 0, 'E'}, - {"preserve-modification-time", 0, &retain_time_flag, TRUE}, - {"rename", 0, &rename_flag, TRUE}, - {"rename-batch-file", 1, 0, 137}, - {"rsh-command", 1, 0, 140}, - {"quiet", 0, 0, 138}, - {"sparse", 0, 0, 135}, - {"swap", 0, 0, 'b'}, - {"swap-bytes", 0, 0, 's'}, - {"swap-halfwords", 0, 0, 'S'}, - {"reset-access-time", 0, &reset_time_flag, TRUE}, - {"unconditional", 0, &unconditional_flag, TRUE}, - {"verbose", 0, &verbose_flag, TRUE}, - {"version", 0, 0, 131}, +#define ARG_NO_ABSOLUTE_FILENAMES 256 +#define ARG_NO_PRESERVE_OWNER 257 +#define ARG_ONLY_VERIFY_CRC 258 +#define ARG_RENAME_BATCH_FILE 259 +#define ARG_RSH_COMMAND 260 +#define ARG_QUIET 261 +#define ARG_SPARSE 262 +#define ARG_FORCE_LOCAL 263 +#define ARG_DEBUG 264 +#define ARG_BLOCK_SIZE 265 + +#define USAGE_OPTION 266 +#define LICENSE_OPTION 267 +#define VERSION_OPTION 268 + +const char *argp_program_version = "cpio (" PACKAGE_NAME ") " VERSION; +const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; +static char doc[] = N_("GNU `cpio' copies files to and from archives\n\ +\n\ +Examples:\n\ + # Copy files named in name-list to the archive\n\ + cpio -o < name-list [> archive]\n\ + # Extract files from the archive\n\ + cpio -i [< archive]\n\ + # Copy files named in name-list to destination-directory\n\ + cpio -p destination-directory < name-list\n"); + +/* Print usage error message and exit with error. */ + +#define USAGE_ERROR(args) do { error args; exit(2); } while (0) +#define CHECK_USAGE(cond, opt, mode_opt) \ + if (cond) USAGE_ERROR((0, 0, _("%s is meaningless with %s"), opt, mode_opt)); + +static struct argp_option options[] = { + {NULL, 0, NULL, 0, + N_("Main operation mode:"), 10}, + {"create", 'o', 0, 0, + N_("Create the archive (run in copy-out mode)"), 10}, + {"extract", 'i', 0, 0, + N_("Extract files from an archive (run in copy-in mode)")}, + {"pass-through", 'p', 0, 0, + N_("Run in copy-pass mode"), 10}, + {"list", 't', 0, 0, + N_("Print a table of contents of the input"), 10}, + + {NULL, 0, NULL, 0, + N_("Operation modifiers valid in any mode:"), 100}, + + {"file", 'F', N_("[[USER@]HOST:]FILE-NAME"), 0, + N_("Use this FILE-NAME instead of standard input or output. Optional USER and HOST specify the user and host names in case of a remote archive"), 110}, + {"force-local", ARG_FORCE_LOCAL, 0, 0, + N_("Archive file is local, even if its name contains colons"), 110}, + {"format", 'H', N_("FORMAT"), 0, + N_("Use given archive FORMAT"), 110}, + {NULL, 'B', NULL, 0, + N_("Set the I/O block size to 5120 bytes"), 110}, + {"block-size", ARG_BLOCK_SIZE, N_("BLOCK-SIZE"), 0, + N_("Set the I/O block size to BLOCK-SIZE * 512 bytes"), 110}, + {NULL, 'c', NULL, 0, + N_("Use the old portable (ASCII) archive format"), 0}, + {"dot", 'V', NULL, 0, + N_("Print a \".\" for each file processed"), 110}, + {"io-size", 'C', N_("NUMBER"), 0, + N_("Set the I/O block size to the given NUMBER of bytes"), 110}, + {"message", 'M', N_("STRING"), 0, + N_("Print STRING when the end of a volume of the backup media is reached"), + 110}, + {"nonmatching", 'f', 0, 0, + N_("Only copy files that do not match any of the given patterns"), 110}, + {"numeric-uid-gid", 'n', 0, 0, + N_("In the verbose table of contents listing, show numeric UID and GID"), + 110}, + {"rsh-command", ARG_RSH_COMMAND, N_("COMMAND"), 0, + N_("Use remote COMMAND instead of rsh"), 110}, + {"quiet", ARG_QUIET, NULL, 0, + N_("Do not print the number of blocks copied"), 110}, + {"verbose", 'v', NULL, 0, + N_("Verbosely list the files processed"), 110}, #ifdef DEBUG_CPIO - {"debug", 0, &debug_flag, TRUE}, + {"debug", ARG_DEBUG, NULL, 0, + N_("Enable debugging info"), 110}, #endif + + /* ********** */ + {NULL, 0, NULL, 0, + N_("Operation modifiers valid only in copy-in mode:"), 200}, + {"pattern-file", 'E', N_("FILE"), 0, + N_("In copy-in mode, read additional patterns specifying filenames to extract or list from FILE"), 210}, + {"no-absolute-filenames", ARG_NO_ABSOLUTE_FILENAMES, 0, 0, + N_("Create all files relative to the current directory"), 210}, + {"only-verify-crc", ARG_ONLY_VERIFY_CRC, 0, 0, + N_("When reading a CRC format archive in copy-in mode, only verify the CRC's of each file in the archive, don't actually extract the files"), 210}, + {"rename", 'r', 0, 0, + N_("Interactively rename files"), 210}, + {"rename-batch-file", ARG_RENAME_BATCH_FILE, N_("FILE"), OPTION_HIDDEN, + "", 210}, + {"swap", 'b', NULL, 0, + N_("Swap both halfwords of words and bytes of halfwords in the data. Equivalent to -sS"), 210}, + {"swap-bytes", 's', NULL, 0, + N_("Swap the bytes of each halfword in the files"), 210}, + {"swap-halfwords", 'S', NULL, 0, + N_("Swap the halfwords of each word (4 bytes) in the files"), + 210}, + + /* ********** */ + {NULL, 0, NULL, 0, + N_("Operation modifiers valid only in copy-out mode:"), 300}, + {"append", 'A', 0, 0, + N_("Append to an existing archive."), 310 }, + {NULL, 'O', N_("[[USER@]HOST:]FILE-NAME"), 0, + N_("Archive filename to use instead of standard output. Optional USER and HOST specify the user and host names in case of a remote archive"), 310}, + + /* ********** */ + {NULL, 0, NULL, 0, + N_("Operation modifiers valid only in copy-pass mode:"), 400}, + {"link", 'l', 0, 0, + N_("Link files instead of copying them, when possible"), 410}, + + /* ********** */ + {NULL, 0, NULL, 0, + N_("Operation modifiers valid for copy-out and copy-pass modes:"), 500}, + {"null", '0', 0, 0, + N_("A list of filenames is terminated by a null character instead of a newline"), 510 }, + {NULL, 'I', N_("[[USER@]HOST:]FILE-NAME"), 0, + N_("Archive filename to use instead of standard input. Optional USER and HOST specify the user and host names in case of a remote archive"), 510}, + {"dereference", 'L', 0, 0, + N_("Dereference symbolic links (copy the files that they point to instead of copying the links)."), 510}, + {"owner", 'R', N_("[USER][:.][GROUP]"), 0, + N_("Set the ownership of all files created to the specified USER and/or GROUP"), 510}, + {"sparse", ARG_SPARSE, NULL, 0, + N_("Write files with large blocks of zeros as sparse files"), 510}, + {"reset-access-time", 'a', NULL, 0, + N_("Reset the access times of files after reading them"), 510}, + + /* ********** */ + {NULL, 0, NULL, 0, + N_("Operation modifiers valid for copy-in and copy-pass modes:"), 600}, + {"preserve-modification-time", 'm', 0, 0, + N_("Retain previous file modification times when creating files"), 610}, + {"make-directories", 'd', 0, 0, + N_("Create leading directories where needed"), 610}, + {"no-preserve-owner", ARG_NO_PRESERVE_OWNER, 0, 0, + N_("Do not change the ownership of the files"), 610}, + {"unconditional", 'u', NULL, 0, + N_("Replace all files unconditionally"), 610}, + + {NULL, 0, NULL, 0, + N_("Informative options:"), 700 }, + + {"help", '?', 0, 0, N_("Give this help list"), -1}, + {"usage", USAGE_OPTION, 0, 0, N_("Give a short usage message"), -1}, + {"license", LICENSE_OPTION, 0, 0, N_("Print license and exit"), -1}, + {"version", VERSION_OPTION, 0, 0, N_("Print program version"), -1}, + /* FIXME -V (--dot) conflicts with the default short option for + --version */ + {0, 0, 0, 0} }; -/* Print usage message and exit with error. */ +static char *input_archive_name = 0; +static char *output_archive_name = 0; -void -usage (fp, status) - FILE *fp; - int status; +static void +license () { - fprintf (fp, _("\ -Usage: %s {-o|--create} [-0acvABLV] [-C bytes] [-H format] [-M message]\n\ - [-O [[user@]host:]archive] [-F [[user@]host:]archive]\n\ - [--file=[[user@]host:]archive] [--format=format] [--message=message]\n\ - [--null] [--reset-access-time] [--verbose] [--dot] [--append]\n\ - [--block-size=blocks] [--dereference] [--io-size=bytes] [--quiet]\n\ - [--force-local] [--rsh-command=command] [--help] [--version] < name-list\n\ - [> archive]\n"), program_name); - fprintf (fp, _("\ - %s {-i|--extract} [-bcdfmnrtsuvBSV] [-C bytes] [-E file] [-H format]\n\ - [-M message] [-R [user][:.][group]] [-I [[user@]host:]archive]\n\ - [-F [[user@]host:]archive] [--file=[[user@]host:]archive]\n\ - [--make-directories] [--nonmatching] [--preserve-modification-time]\n\ - [--numeric-uid-gid] [--rename] [--list] [--swap-bytes] [--swap] [--dot]\n\ - [--unconditional] [--verbose] [--block-size=blocks] [--swap-halfwords]\n\ - [--io-size=bytes] [--pattern-file=file] [--format=format]\n\ - [--owner=[user][:.][group]] [--no-preserve-owner] [--message=message]\n\ - [--force-local] [--no-absolute-filenames] [--sparse] [--only-verify-crc]\n\ - [--quiet] [--rsh-command=command] [--help] [--version] [pattern...]\n\ - [< archive]\n"), - program_name); - fprintf (fp, _("\ - %s {-p|--pass-through} [-0adlmuvLV] [-R [user][:.][group]]\n\ - [--null] [--reset-access-time] [--make-directories] [--link] [--quiet]\n\ - [--preserve-modification-time] [--unconditional] [--verbose] [--dot]\n\ - [--dereference] [--owner=[user][:.][group]] [--no-preserve-owner]\n\ - [--sparse] [--help] [--version] destination-directory < name-list\n"), program_name); - exit (status); + printf ("%s (%s) %s\n%s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION, + "Copyright (C) 2004 Free Software Foundation, Inc.\n"); + printf (_(" GNU cpio is free software; you can redistribute it and/or modify\n" + " it under the terms of the GNU General Public License as published by\n" + " the Free Software Foundation; either version 2 of the License, or\n" + " (at your option) any later version.\n" + "\n" + " GNU cpio is distributed in the hope that it will be useful,\n" + " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + " GNU General Public License for more details.\n" + "\n" + " You should have received a copy of the GNU General Public License\n" + " along with GNU cpio; if not, write to the Free Software\n" + " Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\n")); + exit (0); } -/* Process the arguments. Set all options and set up the copy pass - directory or the copy in patterns. */ - -void -process_args (argc, argv) - int argc; - char *argv[]; +static error_t +parse_opt (int key, char *optarg, struct argp_state *state) { - void (*copy_in) (); /* Work around for pcc bug. */ - void (*copy_out) (); - int c; - char *input_archive_name = 0; - char *output_archive_name = 0; - - if (argc < 2) - usage (stderr, 2); - - xstat = lstat; - - while ((c = getopt_long (argc, argv, - "0aAbBcC:dfE:F:H:iI:lLmM:noO:prR:sStuvVz", - long_opts, (int *) 0)) != -1) + switch (key) { - switch (c) - { - case 0: /* A long option that just sets a flag. */ - break; - - case '0': /* Read null-terminated filenames. */ - name_end = '\0'; - break; - - case 'a': /* Reset access times. */ - reset_time_flag = TRUE; - break; - - case 'A': /* Append to the archive. */ - append_flag = TRUE; - break; - - case 'b': /* Swap bytes and halfwords. */ - swap_bytes_flag = TRUE; - swap_halfwords_flag = TRUE; - break; - - case 'B': /* Set block size to 5120. */ - io_block_size = 5120; - break; - - case 130: /* --block-size */ - io_block_size = atoi (optarg); - if (io_block_size < 1) - error (2, 0, _("invalid block size")); - io_block_size *= 512; - break; - - case 'c': /* Use the old portable ASCII format. */ - if (archive_format != arf_unknown) - usage (stderr, 2); + case '0': /* Read null-terminated filenames. */ + name_end = '\0'; + break; + + case 'a': /* Reset access times. */ + reset_time_flag = TRUE; + break; + + case 'A': /* Append to the archive. */ + append_flag = TRUE; + break; + + case 'b': /* Swap bytes and halfwords. */ + swap_bytes_flag = TRUE; + swap_halfwords_flag = TRUE; + break; + + case 'B': /* Set block size to 5120. */ + io_block_size = 5120; + break; + + case ARG_BLOCK_SIZE: /* --block-size */ + io_block_size = atoi (optarg); + if (io_block_size < 1) + error (2, 0, _("invalid block size")); + io_block_size *= 512; + break; + + case 'c': /* Use the old portable ASCII format. */ + if (archive_format != arf_unknown) + USAGE_ERROR ((0, 0, _("Archive format multiply defined"))); #ifdef SVR4_COMPAT - archive_format = arf_newascii; /* -H newc. */ + archive_format = arf_newascii; /* -H newc. */ #else - archive_format = arf_oldascii; /* -H odc. */ + archive_format = arf_oldascii; /* -H odc. */ #endif - break; - - case 'C': /* Block size. */ - io_block_size = atoi (optarg); - if (io_block_size < 1) - error (2, 0, _("invalid block size")); - break; - - case 'd': /* Create directories where needed. */ - create_dir_flag = TRUE; - break; - - case 'f': /* Only copy files not matching patterns. */ - copy_matching_files = FALSE; - break; - - case 'E': /* Pattern file name. */ - pattern_file_name = optarg; - break; - - case 'F': /* Archive file name. */ - archive_name = optarg; - break; - - case 'H': /* Header format name. */ - if (archive_format != arf_unknown) - usage (stderr, 2); - if (!strcmp (optarg, "crc") || !strcmp (optarg, "CRC")) - archive_format = arf_crcascii; - else if (!strcmp (optarg, "newc") || !strcmp (optarg, "NEWC")) - archive_format = arf_newascii; - else if (!strcmp (optarg, "odc") || !strcmp (optarg, "ODC")) - archive_format = arf_oldascii; - else if (!strcmp (optarg, "bin") || !strcmp (optarg, "BIN")) - archive_format = arf_binary; - else if (!strcmp (optarg, "ustar") || !strcmp (optarg, "USTAR")) - archive_format = arf_ustar; - else if (!strcmp (optarg, "tar") || !strcmp (optarg, "TAR")) - archive_format = arf_tar; - else if (!strcmp (optarg, "hpodc") || !strcmp (optarg, "HPODC")) - archive_format = arf_hpoldascii; - else if (!strcmp (optarg, "hpbin") || !strcmp (optarg, "HPBIN")) - archive_format = arf_hpbinary; - else - error (2, 0, _("\ + break; + + case 'C': /* Block size. */ + io_block_size = atoi (optarg); + if (io_block_size < 1) + error (2, 0, _("invalid block size")); + break; + + case 'd': /* Create directories where needed. */ + create_dir_flag = TRUE; + break; + + case 'f': /* Only copy files not matching patterns. */ + copy_matching_files = FALSE; + break; + + case 'E': /* Pattern file name. */ + pattern_file_name = optarg; + break; + + case 'F': /* Archive file name. */ + archive_name = optarg; + break; + + case 'H': /* Header format name. */ + if (archive_format != arf_unknown) + USAGE_ERROR ((0, 0, _("Archive format multiply defined"))); + if (!strcasecmp (optarg, "crc")) + archive_format = arf_crcascii; + else if (!strcasecmp (optarg, "newc")) + archive_format = arf_newascii; + else if (!strcasecmp (optarg, "odc")) + archive_format = arf_oldascii; + else if (!strcasecmp (optarg, "bin")) + archive_format = arf_binary; + else if (!strcasecmp (optarg, "ustar")) + archive_format = arf_ustar; + else if (!strcasecmp (optarg, "tar")) + archive_format = arf_tar; + else if (!strcasecmp (optarg, "hpodc")) + archive_format = arf_hpoldascii; + else if (!strcasecmp (optarg, "hpbin")) + archive_format = arf_hpbinary; + else + error (2, 0, _("\ invalid archive format `%s'; valid formats are:\n\ crc newc odc bin ustar tar (all-caps also recognized)"), optarg); - break; - - case 'i': /* Copy-in mode. */ - if (copy_function != 0) - usage (stderr, 2); - copy_function = process_copy_in; - break; - - case 'I': /* Input archive file name. */ - input_archive_name = optarg; - break; - - case 'k': /* Handle corrupted archives. We always handle - corrupted archives, but recognize this - option for compatability. */ - break; - - case 'l': /* Link files when possible. */ - link_flag = TRUE; - break; - - case 'L': /* Dereference symbolic links. */ - xstat = stat; - break; - - case 'm': /* Retain previous file modify times. */ - retain_time_flag = TRUE; - break; - - case 'M': /* New media message. */ - set_new_media_message (optarg); - break; - - case 'n': /* Long list owner and group as numbers. */ - numeric_uid = TRUE; - break; - - case 136: /* --no-absolute-filenames */ - no_abs_paths_flag = TRUE; - break; + break; + + case 'i': /* Copy-in mode. */ + if (copy_function != 0) + USAGE_ERROR ((0, 0, _("Mode already defined"))); + copy_function = process_copy_in; + break; + + case 'I': /* Input archive file name. */ + input_archive_name = optarg; + break; + + case 'k': /* Handle corrupted archives. We always handle + corrupted archives, but recognize this + option for compatability. */ + break; + + case 'l': /* Link files when possible. */ + link_flag = TRUE; + break; + + case 'L': /* Dereference symbolic links. */ + xstat = stat; + break; + + case 'm': /* Retain previous file modify times. */ + retain_time_flag = TRUE; + break; + + case 'M': /* New media message. */ + set_new_media_message (optarg); + break; + + case 'n': /* Long list owner and group as numbers. */ + numeric_uid = TRUE; + break; + + case ARG_NO_ABSOLUTE_FILENAMES: /* --no-absolute-filenames */ + no_abs_paths_flag = TRUE; + break; - case 134: /* --no-preserve-owner */ - if (set_owner_flag || set_group_flag) - usage (stderr, 2); - no_chown_flag = TRUE; - break; - - case 'o': /* Copy-out mode. */ - if (copy_function != 0) - usage (stderr, 2); - copy_function = process_copy_out; - break; - - case 'O': /* Output archive file name. */ - output_archive_name = optarg; - break; - - case 139: - only_verify_crc_flag = TRUE; - break; - - case 'p': /* Copy-pass mode. */ - if (copy_function != 0) - usage (stderr, 2); - copy_function = process_copy_pass; - break; - - case 140: - rsh_command_option = optarg; - break; - - case 'r': /* Interactively rename. */ - rename_flag = TRUE; - break; - - case 137: - rename_batch_file = optarg; - break; - - case 138: - quiet_flag = TRUE; - break; - - case 'R': /* Set the owner. */ - if (no_chown_flag) - usage (stderr, 2); + case ARG_NO_PRESERVE_OWNER: /* --no-preserve-owner */ + if (set_owner_flag || set_group_flag) + USAGE_ERROR ((0, 0, + _("--no-preserve-owner cannot be used with --owner"))); + no_chown_flag = TRUE; + break; + + case 'o': /* Copy-out mode. */ + if (copy_function != 0) + USAGE_ERROR ((0, 0, _("Mode already defined"))); + copy_function = process_copy_out; + break; + + case 'O': /* Output archive file name. */ + output_archive_name = optarg; + break; + + case ARG_ONLY_VERIFY_CRC: + only_verify_crc_flag = TRUE; + break; + + case 'p': /* Copy-pass mode. */ + if (copy_function != 0) + USAGE_ERROR ((0, 0, _("Mode already defined"))); + copy_function = process_copy_pass; + break; + + case ARG_RSH_COMMAND: + rsh_command_option = optarg; + break; + + case 'r': /* Interactively rename. */ + rename_flag = TRUE; + break; + + case ARG_RENAME_BATCH_FILE: + rename_batch_file = optarg; + break; + + case ARG_QUIET: + quiet_flag = TRUE; + break; + + case 'R': /* Set the owner. */ + if (no_chown_flag) + USAGE_ERROR ((0, 0, + _("--owner cannot be used with --no-preserve-owner"))); + { + char *e, *u, *g; + + e = parse_user_spec (optarg, &set_owner, &set_group, &u, &g); + if (e) + error (2, 0, "%s: %s", optarg, e); + if (u) + { + free (u); + set_owner_flag = TRUE; + } + if (g) { - char *e, *u, *g; - - e = parse_user_spec (optarg, &set_owner, &set_group, &u, &g); - if (e) - error (2, 0, "%s: %s", optarg, e); - if (u) - { - free (u); - set_owner_flag = TRUE; - } - if (g) - { - free (g); - set_group_flag = TRUE; - } + free (g); + set_group_flag = TRUE; } - break; + } + break; - case 's': /* Swap bytes. */ - swap_bytes_flag = TRUE; - break; + case 's': /* Swap bytes. */ + swap_bytes_flag = TRUE; + break; - case 'S': /* Swap halfwords. */ - swap_halfwords_flag = TRUE; - break; + case 'S': /* Swap halfwords. */ + swap_halfwords_flag = TRUE; + break; - case 't': /* Only print a list. */ - table_flag = TRUE; - break; + case 't': /* Only print a list. */ + table_flag = TRUE; + break; - case 'u': /* Replace all! Unconditionally! */ - unconditional_flag = TRUE; - break; + case 'u': /* Replace all! Unconditionally! */ + unconditional_flag = TRUE; + break; - case 'v': /* Verbose! */ - verbose_flag = TRUE; - break; + case 'v': /* Verbose! */ + verbose_flag = TRUE; + break; - case 'V': /* Print `.' for each file. */ - dot_flag = TRUE; - break; + case 'V': /* Print `.' for each file. */ + dot_flag = TRUE; + break; - case 131: - printf ("%s\n", PACKAGE_STRING); - exit (0); - break; + case ARG_SPARSE: + sparse_flag = TRUE; + break; - case 135: - sparse_flag = TRUE; - break; + case ARG_FORCE_LOCAL: + f_force_local = 1; + break; - case 132: /* --help */ - usage (stdout, 0); - break; +#ifdef DEBUG_CPIO + case ARG_DEBUG: + debug_flag = TRUE; + break; +#endif - default: - usage (stderr, 2); - } + case '?': + argp_state_help (state, state->out_stream, ARGP_HELP_STD_HELP); + break; + + case USAGE_OPTION: + argp_state_help (state, state->out_stream, + ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK); + break; + + case VERSION_OPTION: + fprintf (state->out_stream, "%s\n", argp_program_version); + exit (0); + + case LICENSE_OPTION: + license (); + break; + + default: + return ARGP_ERR_UNKNOWN; } + return 0; +} + +static struct argp argp = { + options, + parse_opt, + N_("[destination-directory]"), + doc, + NULL, + NULL, + NULL +}; + +/* Process the arguments. Set all options and set up the copy pass + directory or the copy in patterns. */ + +void +process_args (int argc, char *argv[]) +{ + void (*copy_in) (); /* Work around for pcc bug. */ + void (*copy_out) (); + int index; + + if (argc < 2) + USAGE_ERROR ((0, 0, + _("You must specify one of -oipt options.\nTry `%s --help' or `%s --usage' for more information.\n"), + program_name, program_name)); + + xstat = lstat; + + if (argp_parse (&argp, argc, argv, ARGP_IN_ORDER|ARGP_NO_HELP, &index, NULL)) + exit (1); /* Do error checking and look at other args. */ @@ -387,27 +518,30 @@ crc newc odc bin ustar tar (all-caps also recognized)"), optarg); if (table_flag) copy_function = process_copy_in; else - usage (stderr, 2); + USAGE_ERROR ((0, 0, + _("You must specify one of -oipt options.\nTry `%s --help' or `%s --usage' for more information.\n"), + program_name, program_name)); } - /* Debian hack: This version of cpio uses the -n flag also to extract - tar archives using the numeric UID/GID instead of the user/group - names in /etc/passwd and /etc/groups. (98/10/15) -BEM */ - /* Work around for pcc bug. */ copy_in = process_copy_in; copy_out = process_copy_out; if (copy_function == copy_in) { + if (index != argc) + USAGE_ERROR ((0, 0, _("Too many arguments"))); + archive_des = 0; - if (link_flag || reset_time_flag || xstat != lstat || append_flag - /* Debian hack: The sparse option is used with copy-in not - copy-out. This bug has been reported to - "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */ - || output_archive_name - || (archive_name && input_archive_name)) - usage (stderr, 2); + CHECK_USAGE(link_flag, "--link", "--extract"); + CHECK_USAGE(reset_time_flag, "--reset", "--extract"); + CHECK_USAGE(xstat != lstat, "--dereference", "--extract"); + CHECK_USAGE(append_flag, "--append", "--extract"); + CHECK_USAGE(sparse_flag, "--sparse", "--extract"); + CHECK_USAGE(output_archive_name, "-O", "--extract"); + if (archive_name && input_archive_name) + USAGE_ERROR((0, 0, _("Both -I and -F are used in copy-in mode"))); + if (archive_format == arf_crcascii) crc_i_flag = TRUE; num_patterns = argc - optind; @@ -417,19 +551,33 @@ crc newc odc bin ustar tar (all-caps also recognized)"), optarg); } else if (copy_function == copy_out) { + if (index != argc) + USAGE_ERROR ((0, 0, _("Too many arguments"))); + archive_des = 1; - if (argc != optind || create_dir_flag || rename_flag - || table_flag || unconditional_flag || link_flag - || retain_time_flag || no_chown_flag || set_owner_flag - || set_group_flag || swap_bytes_flag || swap_halfwords_flag - || (append_flag && !(archive_name || output_archive_name)) - || rename_batch_file || no_abs_paths_flag - /* Debian hack: The sparse option is used with copy-in not - copy-out. This bug has been reported to - "bug-gnu-utils@prep.ai.mit.edu". (96/7/10) -BEM */ - || sparse_flag - || input_archive_name || (archive_name && output_archive_name)) - usage (stderr, 2); + CHECK_USAGE(create_dir_flag, "--make-directories", "--create"); + CHECK_USAGE(rename_flag, "--rename", "--create"); + CHECK_USAGE(table_flag, "--list", "--create"); + CHECK_USAGE(unconditional_flag, "--unconditional", "--create"); + CHECK_USAGE(link_flag, "--link", "--create"); + CHECK_USAGE(retain_time_flag, "--preserve-modification-time", + "--create"); + CHECK_USAGE(no_chown_flag, "--no-preserve-owner", "--create"); + CHECK_USAGE(set_owner_flag||set_group_flag, "--owner", "--create"); + CHECK_USAGE(swap_bytes_flag, "--swap-bytes (--swap)", "--create"); + CHECK_USAGE(swap_halfwords_flag, "--swap-halfwords (--swap)", + "--create"); + + if (append_flag && !(archive_name || output_archive_name)) + USAGE_ERROR ((0, 0, + _("--append is used but no archive file name is given (use -F or -O options"))); + + CHECK_USAGE(rename_batch_file, "--rename-batch-file", "--create"); + CHECK_USAGE(no_abs_paths_flag, "--no-absolute-pathnames", "--create"); + CHECK_USAGE(input_archive_name, "-I", "--create"); + if (archive_name && output_archive_name) + USAGE_ERROR ((0, 0, _("Both -O and -F are used in copy-out mode"))); + if (archive_format == arf_unknown) archive_format = arf_binary; if (output_archive_name) @@ -438,24 +586,36 @@ crc newc odc bin ustar tar (all-caps also recognized)"), optarg); else { /* Copy pass. */ - archive_des = -1; - if (argc - 1 != optind || archive_format != arf_unknown - || swap_bytes_flag || swap_halfwords_flag - || table_flag || rename_flag || append_flag - || rename_batch_file || no_abs_paths_flag) - usage (stderr, 2); - directory_name = argv[optind]; + if (index != argc - 1) + USAGE_ERROR ((0, 0, _("Too many arguments"))); + + if (archive_format != arf_unknown) + USAGE_ERROR((0, 0, + _("Archive format is not specified in copy-pass mode (use --format option)"))); + + CHECK_USAGE(swap_bytes_flag, "--swap-bytes (--swap)", "--pass-through"); + CHECK_USAGE(swap_halfwords_flag, "--swap-halfwords (--swap)", + "--pass-through"); + CHECK_USAGE(table_flag, "--list", "--pass-through"); + CHECK_USAGE(rename_flag, "--rename", "--pass-through"); + CHECK_USAGE(append_flag, "--append", "--pass-through"); + CHECK_USAGE(rename_batch_file, "--rename-batch-file", "--pass-through"); + CHECK_USAGE(no_abs_paths_flag, "--no-absolute-pathnames", + "--pass-through"); + + directory_name = argv[index]; } if (archive_name) { if (copy_function != copy_in && copy_function != copy_out) - usage (stderr, 2); + USAGE_ERROR ((0, 0, + _("-F can be used only with --create or --extract"))); archive_des = open_archive (archive_name); if (archive_des < 0) error (1, errno, "%s", archive_name); } - + /* Prevent SysV non-root users from giving away files inadvertantly. This happens automatically on BSD, where only root can give away files. */ @@ -512,9 +672,7 @@ initialize_buffers () } int -main (argc, argv) - int argc; - char *argv[]; +main (int argc, char *argv[]) { #ifdef HAVE_LOCALE_H setlocale (LC_ALL, ""); |