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