home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 May / W2KPRK.iso / apps / posix / source / PAX / PAX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-17  |  15.5 KB  |  610 lines

  1. /* $Source: /u/mark/src/pax/RCS/pax.c,v $
  2.  *
  3.  * $Revision: 1.2 $
  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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  50.  *
  51.  * $Log:    pax.c,v $
  52.  * Revision 1.2  89/02/12  10:05:17  mark
  53.  * 1.2 release fixes
  54.  * 
  55.  * Revision 1.1  88/12/23  18:02:23  mark
  56.  * Initial revision
  57.  * 
  58.  */
  59.  
  60. #ifndef lint
  61. static char *ident = "$Id: pax.c,v 1.2 89/02/12 10:05:17 mark Exp $";
  62. static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
  63. #endif /* ! lint */
  64.  
  65.  
  66. /* Headers */
  67.  
  68. #define NO_EXTERN
  69. #include "pax.h"
  70.  
  71.  
  72. /* Globally Available Identifiers */
  73.  
  74. char           *ar_file;        /* File containing name of archive */
  75. char           *bufend;            /* End of data within archive buffer */
  76. char           *bufstart;        /* Archive buffer */
  77. char           *bufidx;            /* Archive buffer index */
  78. char           *myname;            /* name of executable (argv[0]) */
  79. char          **n_argv;            /* Argv used by name routines */
  80. int             n_argc;            /* Argc used by name routines */
  81. int             archivefd;        /* Archive file descriptor */
  82. int             blocking;        /* Size of each block, in records */
  83. #ifdef _POSIX_SOURCE  /* Xn */
  84. gid_t           gid;            /* Group ID */  /* Xn */
  85. #else  /* Xn */
  86. int             gid;            /* Group ID */
  87. #endif  /* Xn */
  88. int             head_standard;        /* true if archive is POSIX format */
  89. int             ar_interface;        /* defines interface we are using */
  90. int             ar_format;        /* defines current archve format */
  91. #ifdef _POSIX_SOURCE  /* Xn */
  92. mode_t          mask;            /* File creation mask */  /* Xn */
  93. #else  /* Xn */
  94. int             mask;            /* File creation mask */
  95. #endif  /* Xn */
  96. int             ttyf;            /* For interactive queries */
  97. #ifdef _POSIX_SOURCE  /* Xn */
  98. uid_t           uid;            /* User ID */  /* Xn */
  99. #else  /* Xn */
  100. int             uid;            /* User ID */
  101. #endif  /* Xn */
  102. int        names_from_stdin;    /* names for files are from stdin */
  103. OFFSET          total;            /* Total number of bytes transferred */
  104. short           f_access_time;        /* Reset access times of input files */
  105. short           areof;            /* End of input volume reached */
  106. short           f_dir_create;        /* Create missing directories */
  107. short           f_append;        /* Add named files to end of archive */
  108. short           f_create;        /* create a new archive */
  109. short           f_extract;        /* Extract named files from archive */
  110. short           f_follow_links;        /* follow symbolic links */
  111. short           f_interactive;        /* Interactivly extract files */
  112. short           f_linksleft;        /* Report on unresolved links */
  113. short           f_list;            /* List files on the archive */
  114. short           f_modified;        /* Don't restore modification times */
  115. short           f_verbose;        /* Turn on verbose mode */
  116. short        f_link;            /* link files where possible */
  117. short        f_owner;        /* extract files as the user */
  118. short        f_pass;            /* pass files between directories */
  119. short           f_newer;        /* append files to archive if newer */
  120. short        f_disposition;        /* ask for file disposition */
  121. short           f_reverse_match;    /* Reverse sense of pattern match */
  122. short           f_mtime;        /* Retain file modification time */
  123. short           f_unconditional;    /* Copy unconditionally */
  124. short           f_quiet;        /* Don't beep for volume change */  /* Xn */
  125. time_t          now = 0;        /* Current time */
  126. uint            arvolume;        /* Volume number */
  127. uint            blocksize = BLOCKSIZE;    /* Archive block size */
  128. FILE           *msgfile;        /* message outpu file stdout/stderr */
  129. Replstr        *rplhead = (Replstr *)NULL;    /*  head of replstr list */
  130. Replstr        *rpltail;        /* pointer to tail of replstr list */
  131.  
  132. #if 1 && WIN_NT
  133. pid_t ppid;
  134. int globulation;
  135. #endif
  136.  
  137.  
  138. /* Function Prototypes */
  139.  
  140. #ifdef __STDC__
  141.  
  142. static void     usage(void);
  143. static OFFSET   pax_optsize(char *);
  144.  
  145. #else /* !__STDC__ */
  146.  
  147. static void     usage();
  148. static OFFSET   pax_optsize();
  149.  
  150. #endif /* __STDC__ */
  151.  
  152.  
  153. /* main - main routine for handling all archive formats.
  154.  *
  155.  * DESCRIPTION
  156.  *
  157.  *     Set up globals and call the proper interface as specified by the user.
  158.  *
  159.  * PARAMETERS
  160.  *
  161.  *    int argc    - count of user supplied arguments
  162.  *    char **argv    - user supplied arguments 
  163.  *
  164.  * RETURNS
  165.  *
  166.  *    Returns an exit code of 0 to the parent process.
  167.  */
  168.  
  169. #ifdef __STDC__
  170.  
  171. int main(int argc, char **argv)
  172.  
  173. #else
  174.  
  175. int main(argc, argv)
  176. int             argc;
  177. char          **argv;
  178.  
  179. #endif
  180. {
  181.     /* strip the pathname off of the name of the executable */
  182. #ifdef DF_TRACE_DEBUG
  183. printf("DF_TRACE_DEBUG: int main() in pax.c\n");
  184. #endif
  185. #if 1 && WIN_NT
  186.     ppid = getppid();
  187.     if ((myname = strrchr(argv[0], (ppid == (pid_t) 1) ? '\\' : '/')) != (char *)NULL) {
  188. #else
  189.     if ((myname = strrchr(argv[0], '/')) != (char *)NULL) {
  190. #endif
  191.     myname++;
  192.     } else {
  193.     myname = argv[0];
  194.     }
  195.  
  196.     /* set upt for collecting other command line arguments */
  197.     name_init(argc, argv);
  198.  
  199.     /* get all our necessary information */
  200.     mask = umask(0);
  201.     uid = getuid();
  202.     gid = getgid();
  203.     now = time((time_t *) 0);
  204.  
  205.     /* open terminal for interactive queries */
  206.     ttyf = open_tty();
  207.  
  208.     if (strcmp(myname, "tar")==0) {
  209.     do_tar(argc, argv);
  210.     } else if (strcmp(myname, "cpio")==0) {
  211.     do_cpio(argc, argv);
  212.     } else {
  213.     do_pax(argc, argv);
  214.     }
  215.     return 0;  /* Xn */
  216.     /* NOTREACHED */
  217. }
  218.  
  219.  
  220. /* do_pax - provide a PAX conformant user interface for archive handling
  221.  *
  222.  * DESCRIPTION
  223.  *
  224.  *    Process the command line parameters given, doing some minimal sanity
  225.  *    checking, and then launch the specified archiving functions.
  226.  *
  227.  * PARAMETERS
  228.  *
  229.  *    int ac        - A count of arguments in av.  Should be passed argc 
  230.  *              from main
  231.  *    char **av        - A pointer to an argument list.  Should be passed 
  232.  *              argv from main
  233.  *
  234.  * RETURNS
  235.  *
  236.  *    Normally returns 0.  If an error occurs, -1 is returned 
  237.  *    and state is set to reflect the error.
  238.  *
  239.  */
  240.  
  241. #ifdef __STDC__
  242.  
  243. int do_pax(int ac, char **av)
  244.  
  245. #else
  246.  
  247. int do_pax(ac, av)
  248. int             ac;        /* argument counter */
  249. char          **av;        /* arguments */
  250.  
  251. #endif
  252. {
  253.     int             c;
  254.     char       *dirname;
  255.     Stat        st;
  256.  
  257.     /* default input/output file for PAX is STDIN/STDOUT */
  258.     ar_file = "-";
  259.  
  260.     /*
  261.      * set up the flags to reflect the default pax inteface.  Unfortunately
  262.      * the pax interface has several options which are completely opposite
  263.      * of the tar and/or cpio interfaces...
  264.      */
  265.     f_unconditional = 1;
  266.     f_mtime = 1;
  267.     f_dir_create = 1;
  268.     f_list = 1;
  269.     blocksize = 0;
  270.     blocking = 0;
  271.     ar_interface = PAX;
  272.     ar_format = TAR;    /* default interface if none given for -w */
  273.     msgfile=stdout;
  274.  
  275. #ifdef _POSIX2_SOURCE  /* Xn */
  276. #ifdef DF_TRACE_DEBUG
  277. printf("DF_TRACE_DEBUG: int do_pax() in pax.c\n");
  278. #endif
  279.     while ((c = getopt(ac, (const char * const *) av, "ab:cdf:ilmopqrs:t:uvwx:y")) != EOF) {  /* Xn */
  280. #else  /* Xn */
  281.     while ((c = getopt(ac, av, "ab:cdf:ilmopqrs:t:uvwx:y")) != EOF) {  /* Xn */
  282. #endif  /* Xn */
  283.     switch (c) {
  284.     case 'a':
  285.         f_append = 1;
  286.         f_list = 0;
  287.         break;
  288.     case 'b':
  289.         if ((blocksize = (uint)pax_optsize(optarg)) == 0) {  /* Xn */
  290.         fatal("Bad block size");
  291.         }
  292.         break;
  293.     case 'c':
  294.         f_reverse_match = 1;
  295.         break;
  296.     case 'd':
  297.         f_dir_create = 0;
  298.         break;
  299.     case 'f':
  300.         if (blocksize == 0) {
  301.         blocking = 1;
  302.         blocksize = 1 * BLOCKSIZE;
  303.         }
  304.         ar_file = optarg;
  305.         break;
  306.     case 'i':
  307.         f_interactive = 1;
  308.         break;
  309.     case 'l':
  310.         f_link = 1;
  311.         break;
  312.     case 'm':
  313.         f_mtime = 0;
  314.         break;
  315.     case 'o':
  316.         f_owner = 1;
  317.         break;
  318.     case 'p':
  319.         f_access_time = 1;
  320.         break;
  321.     case 'q':  /* Xn */
  322.         f_quiet = 1;  /* Xn */
  323.         break;  /* Xn */
  324.     case 'r':
  325.         if (f_create) {
  326.         f_create = 0;
  327.         f_pass = 1;
  328.         } else {
  329.         f_list = 0;
  330.         f_extract = 1;
  331.         } 
  332.         msgfile=stderr;
  333.         break;
  334.     case 's':
  335.         add_replstr(optarg);
  336.         break;
  337.     case 't':
  338.         if (blocksize == 0) {
  339.         blocking = 1;
  340.         blocksize = 10 * BLOCKSIZE;
  341.         }
  342.         ar_file = optarg;
  343.         break;
  344.     case 'u':
  345.         f_unconditional = 1;
  346.         break;
  347.     case 'v':
  348.         f_verbose = 1;
  349.         break;
  350.     case 'w':
  351.         if (f_extract) {
  352.         f_extract = 0;
  353.         f_pass = 1;
  354.         } else {
  355.         f_list = 0;
  356.         f_create = 1;
  357.         } 
  358.         msgfile=stderr;
  359.         break;
  360.     case 'x':
  361.         if (strcmp(optarg, "ustar") == 0) {
  362.         ar_format = TAR;
  363.         } else if (strcmp(optarg, "cpio") == 0) {
  364.         ar_format = CPIO;
  365.         } else {
  366.         usage();
  367.         }
  368.         break;
  369.     case 'y':
  370.         f_disposition = 1;
  371.         break;
  372.     default:
  373.         usage();
  374.     }
  375.     }
  376. #if 1 && WIN_NT
  377.     if (ppid == (pid_t) 1) /* if parent is CMD.EXE */
  378.     {
  379.     globulation = globulate(optind, ac, av);
  380. #if 0
  381.     (void) printf("globulate: %d\n", globulation);
  382. #endif
  383.     if (globulation == 0)
  384.     {
  385.         n_argc = globulated_argc;
  386.         n_argv = globulated_argv;
  387. #if 0
  388.         (void) printf("ac: %d; av: ", ac);
  389.         for (uid = 0; uid < ac; ++uid)
  390.         (void) printf("[%s] ", av[uid]);
  391.         (void) printf("NULL\nn_argc: %d; n_argv: ", n_argc);
  392.         for (uid = 0; uid < n_argc; ++uid)
  393.         (void) printf("[%s] ", n_argv[uid]);
  394.         (void) printf("NULL\n");
  395. #endif
  396.     }
  397.     }
  398. #endif
  399.  
  400.     if (blocksize == 0) {
  401.     blocking = 1;
  402.     blocksize = blocking * BLOCKSIZE;
  403.     }
  404.     buf_allocate((OFFSET) blocksize);
  405.  
  406.     if (f_extract || f_list) {
  407.     open_archive(AR_READ);
  408.     get_archive_type();
  409.     read_archive();
  410. #if 0 && WIN_NT
  411.     exit(1);
  412. #endif
  413.     } else if (f_append) {  /* this block used to be after the f_create--Xn */
  414.     open_archive(AR_APPEND);
  415.     get_archive_type();
  416.     append_archive();
  417.     } else if (f_create) {
  418.     if (optind >= n_argc) {
  419.         names_from_stdin++;        /* args from stdin */
  420.     }
  421.     open_archive(AR_WRITE);
  422.     create_archive();
  423.     } else if (f_pass && optind < n_argc) {
  424.     dirname = n_argv[--n_argc];
  425.     if (LSTAT(dirname, &st) < 0) {
  426.         fatal(strerror(errno));  /* Xn */
  427.     }
  428.     if ((st.sb_mode & S_IFMT) != S_IFDIR) {
  429.         fatal("Not a directory");
  430.     }
  431.     if (optind >= n_argc) {
  432.         names_from_stdin++;        /* args from stdin */
  433.     }
  434.     pass(dirname);
  435.     } else {
  436.     usage();
  437.     }
  438.  
  439. #if 1 && WIN_NT
  440.     if (ppid == (pid_t) 1 && globulation == 0)
  441.     deglobulate();
  442. #endif
  443.     return (0);
  444. }
  445.  
  446.  
  447. /* get_archive_type - determine input archive type from archive header
  448.  *
  449.  * DESCRIPTION
  450.  *
  451.  *     reads the first block of the archive and determines the archive 
  452.  *    type from the data.  If the archive type cannot be determined, 
  453.  *    processing stops, and a 1 is returned to the caller.  If verbose
  454.  *    mode is on, then the archive type will be printed on the standard
  455.  *    error device as it is determined.
  456.  *
  457.  * FIXME 
  458.  *
  459.  *    be able to understand TAR and CPIO magic numbers
  460.  */
  461.  
  462. #ifdef __STDC__
  463.  
  464. void get_archive_type(void)
  465.  
  466. #else
  467.  
  468. void get_archive_type()
  469.  
  470. #endif
  471. {
  472. #ifdef DF_TRACE_DEBUG
  473. printf("DF_TRACE_DEBUG: void get_archive_type() in pax.c\n");
  474. #endif
  475.     if (ar_read() != 0) {
  476.     fatal("Unable to determine archive type.");
  477.     }
  478.     if (strncmp(bufstart, "070707", 6) == 0) {
  479.     ar_format = CPIO;
  480.     if (f_verbose) {
  481.         fputs("CPIO format archive\n", stderr);
  482.     }
  483.     } else if (strncmp(&bufstart[257], "ustar", 5) == 0) {
  484.     ar_format = TAR;
  485.     if (f_verbose) {
  486.         fputs("USTAR format archive\n", stderr);
  487.     }
  488.     } else {
  489.     ar_format = TAR;
  490.     }
  491. }
  492.  
  493.  
  494. /* pax_optsize - interpret a size argument
  495.  *
  496.  * DESCRIPTION
  497.  *
  498.  *     Recognizes suffixes for blocks (512-bytes), k-bytes and megabytes.  
  499.  *     Also handles simple expressions containing '+' for addition.
  500.  *
  501.  * PARAMETERS
  502.  *
  503.  *    char     *str    - A pointer to the string to interpret
  504.  *
  505.  * RETURNS
  506.  *
  507.  *    Normally returns the value represented by the expression in the 
  508.  *    the string.
  509.  *
  510.  * ERRORS
  511.  *
  512.  *    If the string cannot be interpretted, the program will fail, since
  513.  *    the buffering will be incorrect.
  514.  *
  515.  */
  516.  
  517. #ifdef __STDC__
  518.  
  519. static OFFSET pax_optsize(char *str)
  520.  
  521. #else
  522.  
  523. static OFFSET pax_optsize(str)
  524. char           *str;        /* pointer to string to interpret */
  525.  
  526. #endif
  527. {
  528.     char           *idx;
  529.     OFFSET          number;    /* temporary storage for current number */
  530.     OFFSET          result;    /* cumulative total to be returned to caller */
  531.  
  532.     result = 0;
  533.     idx = str;
  534. #ifdef DF_TRACE_DEBUG
  535. printf("DF_TRACE_DEBUG: static OFFSET pax_optsize() in pax.c\n");
  536. #endif
  537.     for (;;) {
  538.     number = 0;
  539.     while (*idx >= '0' && *idx <= '9')
  540.         number = number * 10 + *idx++ - '0';
  541.     switch (*idx++) {
  542.     case 'b':
  543.         result += number * 512L;
  544.         continue;
  545.     case 'k':
  546.         result += number * 1024L;
  547.         continue;
  548.     case 'm':
  549.         result += number * 1024L * 1024L;
  550.         continue;
  551.     case '+':
  552.         result += number;
  553.         continue;
  554.     case '\0':
  555.         result += number;
  556.         break;
  557.     default:
  558.         break;
  559.     }
  560.     break;
  561.     }
  562.     if (*--idx) {
  563.     fatal("Unrecognizable value");
  564.     }
  565.     return (result);
  566. }
  567.  
  568.  
  569. /* usage - print a helpful message and exit
  570.  *
  571.  * DESCRIPTION
  572.  *
  573.  *    Usage prints out the usage message for the PAX interface and then
  574.  *    exits with a non-zero termination status.  This is used when a user
  575.  *    has provided non-existant or incompatible command line arguments.
  576.  *
  577.  * RETURNS
  578.  *
  579.  *    Returns an exit status of 1 to the parent process.
  580.  *
  581.  */
  582.  
  583. #ifdef __STDC__
  584.  
  585. static void usage(void)
  586.  
  587. #else
  588.  
  589. static void usage()
  590.  
  591. #endif
  592. {
  593. #ifdef DF_TRACE_DEBUG
  594. printf("DF_TRACE_DEBUG: static void usage() in pax.c\n");
  595. #endif
  596.     fprintf(stderr, "Usage: %s -[cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
  597.     myname);
  598.     fprintf(stderr, "       %s -r [-cimopuvy] [-f archive] [-s replstr] [-t device] [pattern...]\n",
  599.     myname);
  600.     fprintf(stderr, "       %s -w [-adimuvy] [-b blocking] [-f archive] [-s replstr]\n              [-t device] [-x format] [pathname...]\n",
  601.     myname);
  602.     fprintf(stderr, "       %s -r -w [-ilmopuvy] [-s replstr] [pathname...] directory\n",
  603.     myname);
  604. #if 1 && WIN_NT
  605.     if (ppid == (pid_t) 1 && globulation == 0)
  606.     deglobulate();
  607. #endif
  608.     exit(1);
  609. }
  610.