home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / std_unix / pax / 4 / pax.c < prev   
C/C++ Source or Header  |  1989-01-07  |  13KB  |  533 lines

  1. /* $Source: /u/mark/src/pax/RCS/pax.c,v $
  2.  *
  3.  * $Revision: 1.1 $
  4.  *
  5.  * DESCRIPTION
  6.  *
  7.  *    Pax is the archiver described in IEEE P1003.2.  It is an archiver
  8.  *    which understands both tar and cpio archives and has a new interface.
  9.  *
  10.  * SYNOPSIS
  11.  *
  12.  *    pax -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]
  13.  *    pax -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]
  14.  *    pax -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]...]
  15.  *           [-t device][-x format][pathname...]
  16.  *    pax -r -w [-ilmopuvy][-s replstr][pathname...] directory
  17.  *
  18.  * DESCRIPTION
  19.  *
  20.  *     PAX - POSIX conforming tar and cpio archive handler.  This
  21.  *    program implements POSIX conformant versions of tar, cpio and pax
  22.  *    archive handlers for UNIX.  These handlers have defined befined
  23.  *    by the IEEE P1003.2 commitee.
  24.  *
  25.  * COMPILATION
  26.  *
  27.  *    A number of different compile time configuration options are
  28.  *    available, please see the Makefile and config.h for more details.
  29.  *
  30.  * AUTHOR
  31.  *
  32.  *     Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
  33.  *
  34.  *
  35.  * Sponsored by The USENIX Association for public distribution. 
  36.  *
  37.  * Copyright (c) 1989 Mark H. Colburn.
  38.  * All rights reserved.
  39.  *
  40.  * Redistribution and use in source and binary forms are permitted
  41.  * provided that the above copyright notice is duplicated in all such 
  42.  * forms and that any documentation, advertising materials, and other 
  43.  * materials related to such distribution and use acknowledge that the 
  44.  * software was developed * by Mark H. Colburn and sponsored by The 
  45.  * USENIX Association. 
  46.  *
  47.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  48.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  49.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  50.  *
  51.  * $Log:    pax.c,v $
  52.  * Revision 1.1  88/12/23  18:02:23  mark
  53.  * Initial revision
  54.  * 
  55.  */
  56.  
  57. #ifndef lint
  58. static char *ident = "$Id: pax.c,v 1.1 88/12/23 18:02:23 mark Rel $";
  59. static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
  60. #endif /* ! lint */
  61.  
  62.  
  63. /* Headers */
  64.  
  65. #define NO_EXTERN
  66. #include "pax.h"
  67.  
  68.  
  69. /* Globally Available Identifiers */
  70.  
  71. char           *ar_file;        /* File containing name of archive */
  72. char           *bufend;            /* End of data within archive buffer */
  73. char           *bufstart;        /* Archive buffer */
  74. char           *bufidx;            /* Archive buffer index */
  75. char           *myname;            /* name of executable (argv[0]) */
  76. char          **n_argv;            /* Argv used by name routines */
  77. int             n_argc;            /* Argc used by name routines */
  78. int             archivefd;        /* Archive file descriptor */
  79. int             blocking;        /* Size of each block, in records */
  80. int             gid;            /* Group ID */
  81. int             head_standard;        /* true if archive is POSIX format */
  82. int             ar_interface;        /* defines interface we are using */
  83. int             ar_format;        /* defines current archve format */
  84. int             mask;            /* File creation mask */
  85. int             ttyf;            /* For interactive queries */
  86. int             uid;            /* User ID */
  87. int        names_from_stdin;    /* names for files are from stdin */
  88. OFFSET          total;            /* Total number of bytes transferred */
  89. short           f_access_time;        /* Reset access times of input files */
  90. short           areof;            /* End of input volume reached */
  91. short           f_create_dirs;        /* Create missing directories */
  92. short           f_append;        /* Add named files to end of archive */
  93. short           f_create;        /* create a new archive */
  94. short           f_extract;        /* Extract named files from archive */
  95. short           f_follow_links;        /* follow symbolic links */
  96. short           f_interactive;        /* Interactivly extract files */
  97. short           f_linksleft;        /* Report on unresolved links */
  98. short           f_list;            /* List files on the archive */
  99. short           f_modified;        /* Don't restore modification times */
  100. short           f_verbose;        /* Turn on verbose mode */
  101. short        f_link;            /* link files where possible */
  102. short        f_owner;        /* extract files as the user */
  103. short        f_pass;            /* pass files between directories */
  104. short           f_newer;        /* append files to archive if newer */
  105. short        f_disposition;        /* ask for file disposition */
  106. short           f_reverse_match;    /* Reverse sense of pattern match */
  107. short           f_modification_time;    /* Retain file modification time */
  108. short           f_unconditional;    /* Copy unconditionally */
  109. time_t          now = 0;        /* Current time */
  110. uint            arvolume;        /* Volume number */
  111. uint            blocksize = BLOCKSIZE;    /* Archive block size */
  112. FILE           *msgfile;        /* message outpu file stdout/stderr */
  113. Replstr        *rplhead = NULL;        /* pointer to head of replstr list */
  114. Replstr        *rpltail;        /* pointer to tail of replstr list */
  115.  
  116.  
  117. /* Function Prototypes */
  118.  
  119. #ifdef __STDC__
  120.  
  121. static void     usage(void);
  122. static OFFSET   pax_optsize(char *);
  123.  
  124. #else /* !__STDC__ */
  125.  
  126. static void     usage();
  127. static OFFSET   pax_optsize();
  128.  
  129. #endif /* __STDC__ */
  130.  
  131.  
  132. /* main - main routine for handling all archive formats.
  133.  *
  134.  * DESCRIPTION
  135.  *
  136.  *     Set up globals and call the proper interface as specified by the user.
  137.  *
  138.  * PARAMETERS
  139.  *
  140.  *    int argc    - count of user supplied arguments
  141.  *    char **argv    - user supplied arguments 
  142.  *
  143.  * RETURNS
  144.  *
  145.  *    Returns an exit code of 0 to the parent process.
  146.  */
  147.  
  148. #ifdef __STDC__
  149.  
  150. int main(int argc, char **argv)
  151.  
  152. #else
  153.  
  154. int main(argc, argv)
  155. int             argc;
  156. char          **argv;
  157.  
  158. #endif
  159. {
  160.     /* strip the pathname off of the name of the executable */
  161.     if ((myname = strrchr(argv[0], '/')) != (char *)NULL) {
  162.     myname++;
  163.     } else {
  164.     myname = argv[0];
  165.     }
  166.  
  167.     /* set upt for collecting other command line arguments */
  168.     name_init(argc, argv);
  169.  
  170.     /* get all our necessary information */
  171.     mask = umask(0);
  172.     uid = getuid();
  173.     gid = getgid();
  174.     now = time((time_t *) 0);
  175.  
  176.     /* open terminal for interactive queries */
  177.     ttyf = open_tty();
  178.  
  179.     if (strcmp(myname, "tar")==0) {
  180.     do_tar(argc, argv);
  181.     } else if (strcmp(myname, "cpio")==0) {
  182.     do_cpio(argc, argv);
  183.     } else {
  184.     do_pax(argc, argv);
  185.     }
  186.     exit(0);
  187.     /* NOTREACHED */
  188. }
  189.  
  190.  
  191. /* do_pax - provide a PAX conformant user interface for archive handling
  192.  *
  193.  * DESCRIPTION
  194.  *
  195.  *    Process the command line parameters given, doing some minimal sanity
  196.  *    checking, and then launch the specified archiving functions.
  197.  *
  198.  * PARAMETERS
  199.  *
  200.  *    int ac        - A count of arguments in av.  Should be passed argc 
  201.  *              from main
  202.  *    char **av        - A pointer to an argument list.  Should be passed 
  203.  *              argv from main
  204.  *
  205.  * RETURNS
  206.  *
  207.  *    Normally returns 0.  If an error occurs, -1 is returned 
  208.  *    and state is set to reflect the error.
  209.  *
  210.  */
  211.  
  212. #ifdef __STDC__
  213.  
  214. int do_pax(int ac, char **av)
  215.  
  216. #else
  217.  
  218. int do_pax(ac, av)
  219. int             ac;        /* argument counter */
  220. char          **av;        /* arguments */
  221.  
  222. #endif
  223. {
  224.     int             c;
  225.     char       *dirname;
  226.     Stat        st;
  227.  
  228.     /* default input/output file for PAX is STDIN/STDOUT */
  229.     ar_file = "-";
  230.  
  231.     /*
  232.      * set up the flags to reflect the default pax inteface.  Unfortunately
  233.      * the pax interface has several options which are completely opposite
  234.      * of the tar and/or cpio interfaces...
  235.      */
  236.     f_unconditional = 1;
  237.     f_modification_time = 1;
  238.     f_create_dirs = 1;
  239.     f_list = 1;
  240.     blocksize = 0;
  241.     blocking = 0;
  242.     ar_interface = PAX;
  243.     ar_format = TAR;    /* default interface if none given for -w */
  244.     msgfile=stdout;
  245.  
  246.     while ((c = getopt(ac, av, "ab:cdf:ilmoprs:t:uvwx:y")) != EOF) {
  247.     switch (c) {
  248.     case 'a':
  249.         f_append = 1;
  250.         f_list = 0;
  251.         break;
  252.     case 'b':
  253.         if ((blocksize = pax_optsize(optarg)) == 0) {
  254.         fatal("Bad block size");
  255.         }
  256.         break;
  257.     case 'c':
  258.         f_reverse_match = 1;
  259.         break;
  260.     case 'd':
  261.         f_create_dirs = 0;
  262.         break;
  263.     case 'f':
  264.         if (blocksize == 0) {
  265.         blocking = 1;
  266.         blocksize = 1 * BLOCKSIZE;
  267.         }
  268.         ar_file = optarg;
  269.         break;
  270.     case 'i':
  271.         f_interactive = 1;
  272.         break;
  273.     case 'l':
  274.         f_link = 1;
  275.         break;
  276.     case 'm':
  277.         f_modification_time = 0;
  278.         break;
  279.     case 'o':
  280.         f_owner = 1;
  281.         break;
  282.     case 'p':
  283.         f_access_time = 1;
  284.         break;
  285.     case 'r':
  286.         if (f_create) {
  287.         f_create = 0;
  288.         f_pass = 1;
  289.         } else {
  290.         f_list = 0;
  291.         f_extract = 1;
  292.         } 
  293.         msgfile=stderr;
  294.         break;
  295.     case 's':
  296.         add_replstr(optarg);
  297.         break;
  298.     case 't':
  299.         if (blocksize == 0) {
  300.         blocking = 1;
  301.         blocksize = 10 * BLOCKSIZE;
  302.         }
  303.         ar_file = optarg;
  304.         break;
  305.     case 'u':
  306.         f_unconditional = 1;
  307.         break;
  308.     case 'v':
  309.         f_verbose = 1;
  310.         break;
  311.     case 'w':
  312.         if (f_extract) {
  313.         f_extract = 0;
  314.         f_pass = 1;
  315.         } else {
  316.         f_list = 0;
  317.         f_create = 1;
  318.         } 
  319.         msgfile=stderr;
  320.         break;
  321.     case 'x':
  322.         if (strcmp(optarg, "ustar") == 0) {
  323.         ar_format = TAR;
  324.         } else if (strcmp(optarg, "cpio") == 0) {
  325.         ar_format = CPIO;
  326.         } else {
  327.         usage();
  328.         }
  329.         break;
  330.     case 'y':
  331.         f_disposition = 1;
  332.         break;
  333.     default:
  334.         usage();
  335.     }
  336.     }
  337.  
  338.     if (blocksize == 0) {
  339.     blocking = 1;
  340.     blocksize = blocking * BLOCKSIZE;
  341.     }
  342.     buf_allocate((OFFSET) blocksize);
  343.  
  344.     if (f_extract || f_list) {
  345.     open_archive(AR_READ);
  346.     get_archive_type();
  347.     read_archive();
  348.     } else if (f_create) {
  349.     if (optind >= n_argc) {
  350.         names_from_stdin++;        /* args from stdin */
  351.     }
  352.     open_archive(AR_WRITE);
  353.     create_archive();
  354.     } else if (f_append) {
  355.     open_archive(AR_APPEND);
  356.     get_archive_type();
  357.     append_archive();
  358.     } else if (f_pass && optind < n_argc) {
  359.     dirname = n_argv[--n_argc];
  360.     if (LSTAT(dirname, &st) < 0) {
  361.         fatal(syserr());
  362.     }
  363.     if ((st.sb_mode & S_IFMT) != S_IFDIR) {
  364.         fatal("Not a directory");
  365.     }
  366.     if (optind >= n_argc) {
  367.         names_from_stdin++;        /* args from stdin */
  368.     }
  369.     pass(dirname);
  370.     } else {
  371.     usage();
  372.     }
  373.  
  374.     return (0);
  375. }
  376.  
  377.  
  378. /* get_archive_type - determine input archive type from archive header
  379.  *
  380.  * DESCRIPTION
  381.  *
  382.  *     reads the first block of the archive and determines the archive 
  383.  *    type from the data.  If the archive type cannot be determined, 
  384.  *    processing stops, and a 1 is returned to the caller.  If verbose
  385.  *    mode is on, then the archive type will be printed on the standard
  386.  *    error device as it is determined.
  387.  *
  388.  * FIXME 
  389.  *
  390.  *    be able to understand TAR and CPIO magic numbers
  391.  */
  392.  
  393. #ifdef __STDC__
  394.  
  395. void get_archive_type(void)
  396.  
  397. #else
  398.  
  399. void get_archive_type()
  400.  
  401. #endif
  402. {
  403.     if (ar_read() != 0) {
  404.     fatal("Unable to determine archive type.");
  405.     }
  406.     if (strncmp(bufstart, "070707", 6) == 0) {
  407.     ar_format = CPIO;
  408.     if (f_verbose) {
  409.         fputs("CPIO format archive\n", stderr);
  410.     }
  411.     } else if (strncmp(&bufstart[257], "ustar", 5) == 0) {
  412.     ar_format = TAR;
  413.     if (f_verbose) {
  414.         fputs("USTAR format archive\n", stderr);
  415.     }
  416.     } else {
  417.     ar_format = TAR;
  418.     }
  419. }
  420.  
  421.  
  422. /* pax_optsize - interpret a size argument
  423.  *
  424.  * DESCRIPTION
  425.  *
  426.  *     Recognizes suffixes for blocks (512-bytes), k-bytes and megabytes.  
  427.  *     Also handles simple expressions containing '+' for addition.
  428.  *
  429.  * PARAMETERS
  430.  *
  431.  *    char     *str    - A pointer to the string to interpret
  432.  *
  433.  * RETURNS
  434.  *
  435.  *    Normally returns the value represented by the expression in the 
  436.  *    the string.
  437.  *
  438.  * ERRORS
  439.  *
  440.  *    If the string cannot be interpretted, the program will fail, since
  441.  *    the buffering will be incorrect.
  442.  *
  443.  */
  444.  
  445. #ifdef __STDC__
  446.  
  447. static OFFSET pax_optsize(char *str)
  448.  
  449. #else
  450.  
  451. static OFFSET pax_optsize(str)
  452. char           *str;        /* pointer to string to interpret */
  453.  
  454. #endif
  455. {
  456.     char           *idx;
  457.     OFFSET          number;    /* temporary storage for current number */
  458.     OFFSET          result;    /* cumulative total to be returned to caller */
  459.  
  460.     result = 0;
  461.     idx = str;
  462.     for (;;) {
  463.     number = 0;
  464.     while (*idx >= '0' && *idx <= '9')
  465.         number = number * 10 + *idx++ - '0';
  466.     switch (*idx++) {
  467.     case 'b':
  468.         result += number * 512;
  469.         continue;
  470.     case 'k':
  471.         result += number * 1024;
  472.         continue;
  473.     case 'm':
  474.         result += number * 1024 * 1024;
  475.         continue;
  476.     case '+':
  477.         result += number;
  478.         continue;
  479.     case '\0':
  480.         result += number;
  481.         break;
  482.     default:
  483.         break;
  484.     }
  485.     break;
  486.     }
  487.     if (*--idx) {
  488.     fatal("Unrecognizable value");
  489.     }
  490.     return (result);
  491. }
  492.  
  493.  
  494. /* usage - print a helpful message and exit
  495.  *
  496.  * DESCRIPTION
  497.  *
  498.  *    Usage prints out the usage message for the PAX interface and then
  499.  *    exits with a non-zero termination status.  This is used when a user
  500.  *    has provided non-existant or incompatible command line arguments.
  501.  *
  502.  * RETURNS
  503.  *
  504.  *    Returns an exit status of 1 to the parent process.
  505.  *
  506.  */
  507.  
  508. #ifdef __STDC__
  509.  
  510. static void usage(void)
  511.  
  512. #else
  513.  
  514. static void usage()
  515.  
  516. #endif
  517. {
  518.     fprintf(stderr, "\
  519. Usage: %s -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
  520.     myname);
  521.     fprintf(stderr, "\
  522.        %s -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
  523.     myname);
  524.     fprintf(stderr, "\
  525.        %s -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]\n\
  526.        [-t device] [-x format] [pathname...]\n",
  527.     myname);
  528.     fprintf(stderr, "\
  529.        %s -r -w [-ilmopuvy] [-s replstr] [pathname...] directory\n",
  530.     myname);
  531.     exit(1);
  532. }
  533.