home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 3 / Meeting_Pearls_III.iso / Pearls / arc / Archiver / cpio / src / main.c < prev    next >
C/C++ Source or Header  |  1992-09-19  |  12KB  |  462 lines

  1. /* main.c - main program and argument processing for cpio.
  2.    Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by Phil Nelson <phil@cs.wwu.edu>,
  19.    David MacKenzie <djm@gnu.ai.mit.edu>,
  20.    and John Oleynick <juo@klinzhai.rutgers.edu>.  */
  21.  
  22. #include <stdio.h>
  23. #include <getopt.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include "filetypes.h"
  27. #include "system.h"
  28. #include "cpiohdr.h"
  29. #include "dstring.h"
  30. #include "extern.h"
  31. #include "rmt.h"
  32.  
  33. struct option long_opts[] =
  34. {
  35.   {"null", 0, 0, '0'},
  36.   {"append", 0, 0, 'A'},
  37.   {"block-size", 1, 0, 130},
  38.   {"create", 0, 0, 'o'},
  39.   {"dereference", 0, 0, 'L'},
  40.   {"dot", 0, 0, 'V'},
  41.   {"extract", 0, 0, 'i'},
  42.   {"file", 1, 0, 'F'},
  43.   {"format", 1, 0, 'H'},
  44.   {"io-size", 1, 0, 'C'},
  45.   {"link", 0, &link_flag, TRUE},
  46.   {"list", 0, &table_flag, TRUE},
  47.   {"make-directories", 0, &create_dir_flag, TRUE},
  48.   {"message", 1, 0, 'M'},
  49.   {"no-preserve-owner", 0, 0, 134},
  50.   {"nonmatching", 0, ©_matching_files, FALSE},
  51.   {"numeric-uid-gid", 0, &numeric_uid, TRUE},
  52.   {"owner", 1, 0, 'R'},
  53.   {"pass-through", 0, 0, 'p'},
  54.   {"pattern-file", 1, 0, 'E'},
  55.   {"preserve-modification-time", 0, &retain_time_flag, TRUE},
  56.   {"rename", 0, &rename_flag, TRUE},
  57.   {"swap-bytes", 0, 0, 's'},
  58.   {"swap-halfwords", 0, 0, 'S'},
  59.   {"reset-access-time", 0, &reset_time_flag, TRUE},
  60.   {"unconditional", 0, &unconditional_flag, TRUE},
  61.   {"verbose", 0, &verbose_flag, TRUE},
  62.   {"version", 0, 0, 131},
  63.   {0, 0, 0, 0}
  64. };
  65.  
  66. /*  Print usage message and exit with error.  */
  67.  
  68. void
  69. usage ()
  70. {
  71.   fprintf (stderr, "\
  72. Usage: %s {-o|--create} [-0acvABLV] [-C bytes] [-H format] [-M message]\n\
  73.        [-O [[user@]host:]archive] [-F [[user@]host:]archive]\n\
  74.        [--file=[[user@]host:]archive] [--format=format] [--message=message]\n\
  75.        [--null] [--reset-access-time] [--verbose] [--dot] [--append]\n\
  76.        [--block-size=blocks] [--dereference] [--io-size=bytes]\n\
  77.        [--version] < name-list [> archive]\n", program_name);
  78.   fprintf (stderr, "\
  79.        %s {-i|--extract} [-bcdfmnrtsuvBSV] [-C bytes] [-E file] [-H format]\n\
  80.        [-M message] [-R [user][:.][group]] [-I [[user@]host:]archive]\n\
  81.        [-F [[user@]host:]archive] [--file=[[user@]host:]archive]\n\
  82.        [--make-directories] [--nonmatching] [--preserve-modification-time]\n\
  83.        [--numeric-uid-gid] [--rename] [--list] [--swap-bytes] [--dot]\n\
  84.        [--unconditional] [--verbose] [--block-size=blocks] [--swap-halfwords]\n\
  85.        [--io-size=bytes] [--pattern-file=file] [--format=format]\n\
  86.        [--owner=[user][:.][group]] [--no-preserve-owner] [--message=message]\n\
  87.        [--version] [pattern...] [< archive]\n",
  88.        program_name);
  89.   fprintf (stderr, "\
  90.        %s {-p|--pass-through} [-0adlmuvLV] [-R [user][:.][group]]\n\
  91.        [--null] [--reset-access-time] [--make-directories] [--link]\n\
  92.        [--preserve-modification-time] [--unconditional] [--verbose] [--dot]\n\
  93.        [--dereference] [--owner=[user][:.][group]] [--no-preserve-owner]\n\
  94.        [--version] destination-directory < name-list\n", program_name);
  95.   exit (2);
  96. }
  97.  
  98. /* Process the arguments.  Set all options and set up the copy pass
  99.    directory or the copy in patterns.  */
  100.  
  101. void
  102. process_args (argc, argv)
  103.      int argc;
  104.      char *argv[];
  105. {
  106.   extern char *version_string;
  107.   void (*copy_in) ();        /* Work around for pcc bug.  */
  108.   void (*copy_out) ();
  109.   int c;
  110.   char *input_archive_name = 0;
  111.   char *output_archive_name = 0;
  112.  
  113.   if (argc < 2)
  114.     usage ();
  115.  
  116.   xstat = lstat;
  117.  
  118.   while ((c = getopt_long (argc, argv,
  119.                "0aAbBcC:dfE:F:H:iI:lLmM:noO:prR:sStuvVz",
  120.                long_opts, (int *) 0)) != EOF)
  121.     {
  122.       switch (c)
  123.     {
  124.     case 0:            /* A long option that just sets a flag.  */
  125.       break;
  126.  
  127.     case '0':        /* Read null-terminated filenames.  */
  128.       name_end = '\0';
  129.       break;
  130.  
  131.     case 'a':        /* Reset access times.  */
  132.       reset_time_flag = TRUE;
  133.       break;
  134.  
  135.     case 'A':        /* Append to the archive.  */
  136.       append_flag = TRUE;
  137.       break;
  138.  
  139.     case 'b':        /* Swap bytes and halfwords.  */
  140.       swap_bytes_flag = TRUE;
  141.       swap_halfwords_flag = TRUE;
  142.       break;
  143.  
  144.     case 'B':        /* Set block size to 5120.  */
  145.       io_block_size = 5120;
  146.       break;
  147.  
  148.     case 130:        /* --block-size */
  149.       io_block_size = atoi (optarg);
  150.       if (io_block_size < 1)
  151.         error (2, 0, "invalid block size");
  152.       io_block_size *= 512;
  153.       break;
  154.  
  155.     case 'c':        /* Use the old portable ASCII format.  */
  156.       if (archive_format != arf_unknown)
  157.         usage ();
  158. #ifdef SVR4_COMPAT
  159.       archive_format = arf_newascii; /* -H newc.  */
  160. #else
  161.       archive_format = arf_oldascii; /* -H odc.  */
  162. #endif
  163.       break;
  164.  
  165.     case 'C':        /* Block size.  */
  166.       io_block_size = atoi (optarg);
  167.       if (io_block_size < 1)
  168.         error (2, 0, "invalid block size");
  169.       break;
  170.  
  171.     case 'd':        /* Create directories where needed.  */
  172.       create_dir_flag = TRUE;
  173.       break;
  174.  
  175.     case 'f':        /* Only copy files not matching patterns.  */
  176.       copy_matching_files = FALSE;
  177.       break;
  178.  
  179.     case 'E':        /* Pattern file name.  */
  180.       pattern_file_name = optarg;
  181.       break;
  182.  
  183.     case 'F':        /* Archive file name.  */
  184.       archive_name = optarg;
  185.       break;
  186.  
  187.     case 'H':        /* Header format name.  */
  188.       if (archive_format != arf_unknown)
  189.         usage ();
  190.       if (!strcmp (optarg, "crc") || !strcmp (optarg, "CRC"))
  191.         archive_format = arf_crcascii;
  192.       else if (!strcmp (optarg, "newc") || !strcmp (optarg, "NEWC"))
  193.         archive_format = arf_newascii;
  194.       else if (!strcmp (optarg, "odc") || !strcmp (optarg, "ODC"))
  195.         archive_format = arf_oldascii;
  196.       else if (!strcmp (optarg, "bin") || !strcmp (optarg, "BIN"))
  197.         archive_format = arf_binary;
  198.       else if (!strcmp (optarg, "ustar") || !strcmp (optarg, "USTAR"))
  199.         archive_format = arf_ustar;
  200.       else if (!strcmp (optarg, "tar") || !strcmp (optarg, "TAR"))
  201.         archive_format = arf_tar;
  202.       else
  203.         error (2, 0, "\
  204. invalid archive format `%s'; valid formats are:\n\
  205. crc newc odc bin ustar tar (all-caps also recognized)", optarg);
  206.       break;
  207.  
  208.     case 'i':        /* Copy-in mode.  */
  209.       if (copy_function != 0)
  210.         usage ();
  211.       copy_function = process_copy_in;
  212.       break;
  213.  
  214.     case 'I':        /* Input archive file name.  */
  215.       input_archive_name = optarg;
  216.       break;
  217.  
  218.     case 'k':        /* Handle corrupted archives.  We always handle
  219.                    corrupted archives, but recognize this
  220.                    option for compatability.  */
  221.       break;
  222.  
  223.     case 'l':        /* Link files when possible.  */
  224.       link_flag = TRUE;
  225.       break;
  226.  
  227.     case 'L':        /* Dereference symbolic links.  */
  228.       xstat = stat;
  229.       break;
  230.  
  231.     case 'm':        /* Retain previous file modify times.  */
  232.       retain_time_flag = TRUE;
  233.       break;
  234.  
  235.     case 'M':        /* New media message.  */
  236.       set_new_media_message (optarg);
  237.       break;
  238.  
  239.     case 'n':        /* Long list owner and group as numbers.  */
  240.       numeric_uid = TRUE;
  241.       break;
  242.  
  243.     case 134:        /* --no-preserve-owner */
  244.       if (set_owner_flag || set_group_flag)
  245.         usage ();
  246.       no_chown_flag = TRUE;
  247.       break;
  248.  
  249.     case 'o':        /* Copy-out mode.  */
  250.       if (copy_function != 0)
  251.         usage ();
  252.       copy_function = process_copy_out;
  253.       break;
  254.  
  255.     case 'O':        /* Output archive file name.  */
  256.       output_archive_name = optarg;
  257.       break;
  258.  
  259.     case 'p':        /* Copy-pass mode.  */
  260.       if (copy_function != 0)
  261.         usage ();
  262.       copy_function = process_copy_pass;
  263.       break;
  264.  
  265.     case 'r':        /* Interactively rename.  */
  266.       rename_flag = TRUE;
  267.       break;
  268.  
  269.     case 'R':        /* Set the owner.  */
  270.       if (no_chown_flag)
  271.         usage ();
  272. #ifndef __MSDOS__
  273.       {
  274.         char *e, *u, *g;
  275.  
  276.         e = parse_user_spec (optarg, &set_owner, &set_group, &u, &g);
  277.         if (e)
  278.           error (2, 0, "%s: %s", optarg, e);
  279.         if (u)
  280.           {
  281.         free (u);
  282.         set_owner_flag = TRUE;
  283.           }
  284.         if (g)
  285.           {
  286.         free (g);
  287.         set_group_flag = TRUE;
  288.           }
  289.       }
  290. #endif
  291.       break;
  292.  
  293.     case 's':        /* Swap bytes.  */
  294.       swap_bytes_flag = TRUE;
  295.       break;
  296.  
  297.     case 'S':        /* Swap halfwords.  */
  298.       swap_halfwords_flag = TRUE;
  299.       break;
  300.  
  301.     case 't':        /* Only print a list.  */
  302.       table_flag = TRUE;
  303.       break;
  304.  
  305.     case 'u':        /* Replace all!  Unconditionally!  */
  306.       unconditional_flag = TRUE;
  307.       break;
  308.  
  309.     case 'v':        /* Verbose!  */
  310.       verbose_flag = TRUE;
  311.       break;
  312.  
  313.     case 'V':        /* Print `.' for each file.  */
  314.       dot_flag = TRUE;
  315.       break;
  316.  
  317.     case 131:
  318.       printf ("%s", version_string);
  319.       exit (0);
  320.       break;
  321.  
  322.     default:
  323.       usage ();
  324.     }
  325.     }
  326.  
  327.   /* Do error checking and look at other args.  */
  328.  
  329.   if (copy_function == 0)
  330.     {
  331.       if (table_flag)
  332.     copy_function = process_copy_in;
  333.       else
  334.     usage ();
  335.     }
  336.  
  337.   if ((!table_flag || !verbose_flag) && numeric_uid)
  338.     usage ();
  339.  
  340.   /* Work around for pcc bug.  */
  341.   copy_in = process_copy_in;
  342.   copy_out = process_copy_out;
  343.  
  344.   if (copy_function == copy_in)
  345.     {
  346.       archive_des = 0;
  347.       if (link_flag || reset_time_flag || xstat != lstat || append_flag
  348.       || output_archive_name
  349.       || (archive_name && input_archive_name))
  350.     usage ();
  351.       if (archive_format == arf_crcascii)
  352.     crc_i_flag = TRUE;
  353.       num_patterns = argc - optind;
  354.       save_patterns = &argv[optind];
  355.       if (input_archive_name)
  356.     archive_name = input_archive_name;
  357.     }
  358.   else if (copy_function == copy_out)
  359.     {
  360.       archive_des = 1;
  361.       if (argc != optind || create_dir_flag || rename_flag
  362.       || table_flag || unconditional_flag || link_flag
  363.       || retain_time_flag || no_chown_flag || set_owner_flag
  364.       || set_group_flag || swap_bytes_flag || swap_halfwords_flag
  365.       || (append_flag && !(archive_name || output_archive_name))
  366.       || input_archive_name || (archive_name && output_archive_name))
  367.     usage ();
  368.       if (archive_format == arf_unknown)
  369.     archive_format = arf_binary;
  370.       if (output_archive_name)
  371.     archive_name = output_archive_name;
  372.     }
  373.   else
  374.     {
  375.       /* Copy pass.  */
  376.       archive_des = -1;
  377.       if (argc - 1 != optind || archive_format != arf_unknown
  378.       || swap_bytes_flag || swap_halfwords_flag
  379.       || table_flag || rename_flag || append_flag)
  380.     usage ();
  381.       directory_name = argv[optind];
  382.     }
  383.  
  384.   if (archive_name)
  385.     {
  386.       if (copy_function != copy_in && copy_function != copy_out)
  387.     usage ();
  388.       archive_des = open_archive (archive_name);
  389.       if (archive_des < 0)
  390.     error (1, errno, "%s", archive_name);
  391.     }
  392.  
  393.   /* Prevent SysV non-root users from giving away files inadvertantly.
  394.      This happens automatically on BSD, where only root can give
  395.      away files.  */
  396.   if (set_owner_flag == FALSE && set_group_flag == FALSE && geteuid ())
  397.     no_chown_flag = TRUE;
  398. }
  399.  
  400. /* Initialize the input and output buffers to their proper size and
  401.    initialize all variables associated with the input and output
  402.    buffers.  */
  403.  
  404. void
  405. initialize_buffers ()
  406. {
  407.   int buf_size;
  408.  
  409.   /* Make sure buffers can always hold 2 blocks and that they
  410.      are big enough to hold 1 tar record (512 bytes) even if it
  411.      is not aligned on a block boundary.  The extra buffer space
  412.      is needed by process_copyin and peek_in_buf to automatically
  413.      figure out what kind of archive it is reading.  */
  414.  
  415.   if (io_block_size >= 512)
  416.     buf_size = 2 * io_block_size;
  417.   else
  418.     buf_size = 1024;
  419.   input_buffer = (char *) xmalloc (buf_size);
  420.   in_buff = input_buffer;
  421.   input_size = 0;
  422.   input_bytes = 0;
  423.  
  424.   /* Leave space for an `int' sentinel for `empty_output_buffer',
  425.      in case we ever put back sparseness checking.  */
  426.   output_buffer = (char *) xmalloc (buf_size + sizeof (int) * 2);
  427.   out_buff = output_buffer;
  428.   output_size = 0;
  429.   output_bytes = 0;
  430.  
  431.   /* Clear the block of zeros.  */
  432.   bzero (zeros_512, 512);
  433. }
  434.  
  435. void
  436. main (argc, argv)
  437.      int argc;
  438.      char *argv[];
  439. {
  440.   program_name = argv[0];
  441.   umask (0);
  442.  
  443. #ifdef __TURBOC__
  444.   _fmode = O_BINARY;        /* Put stdin and stdout in binary mode.  */
  445. #endif
  446. #ifdef __EMX__            /* gcc on OS/2.  */
  447.   _response (&argc, &argv);
  448.   _wildcard (&argc, &argv);
  449. #endif
  450.  
  451.   process_args (argc, argv);
  452.  
  453.   initialize_buffers ();
  454.  
  455.   (*copy_function) ();
  456.  
  457.   if (archive_des >= 0 && rmtclose (archive_des) == -1)
  458.     error (1, errno, "error closing archive");
  459.  
  460.   exit (0);
  461. }
  462.