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