xref: /plan9/sys/src/ape/cmd/pax/tar.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier /* $Source: /u/mark/src/pax/RCS/tar.c,v $
2*9a747e4fSDavid du Colombier  *
3*9a747e4fSDavid du Colombier  * $Revision: 1.2 $
4*9a747e4fSDavid du Colombier  *
5*9a747e4fSDavid du Colombier  * tar.c - tar specific functions for archive handling
6*9a747e4fSDavid du Colombier  *
7*9a747e4fSDavid du Colombier  * DESCRIPTION
8*9a747e4fSDavid du Colombier  *
9*9a747e4fSDavid du Colombier  *	These routines provide a tar conforming interface to the pax
10*9a747e4fSDavid du Colombier  *	program.
11*9a747e4fSDavid du Colombier  *
12*9a747e4fSDavid du Colombier  * AUTHOR
13*9a747e4fSDavid du Colombier  *
14*9a747e4fSDavid du Colombier  *	Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
15*9a747e4fSDavid du Colombier  *
16*9a747e4fSDavid du Colombier  * Sponsored by The USENIX Association for public distribution.
17*9a747e4fSDavid du Colombier  *
18*9a747e4fSDavid du Colombier  * Copyright (c) 1989 Mark H. Colburn.
19*9a747e4fSDavid du Colombier  * All rights reserved.
20*9a747e4fSDavid du Colombier  *
21*9a747e4fSDavid du Colombier  * Redistribution and use in source and binary forms are permitted
22*9a747e4fSDavid du Colombier  * provided that the above copyright notice is duplicated in all such
23*9a747e4fSDavid du Colombier  * forms and that any documentation, advertising materials, and other
24*9a747e4fSDavid du Colombier  * materials related to such distribution and use acknowledge that the
25*9a747e4fSDavid du Colombier  * software was developed by Mark H. Colburn and sponsored by The
26*9a747e4fSDavid du Colombier  * USENIX Association.
27*9a747e4fSDavid du Colombier  *
28*9a747e4fSDavid du Colombier  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29*9a747e4fSDavid du Colombier  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30*9a747e4fSDavid du Colombier  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31*9a747e4fSDavid du Colombier  *
32*9a747e4fSDavid du Colombier  * $Log:	tar.c,v $
33*9a747e4fSDavid du Colombier  * Revision 1.2  89/02/12  10:06:05  mark
34*9a747e4fSDavid du Colombier  * 1.2 release fixes
35*9a747e4fSDavid du Colombier  *
36*9a747e4fSDavid du Colombier  * Revision 1.1  88/12/23  18:02:38  mark
37*9a747e4fSDavid du Colombier  * Initial revision
38*9a747e4fSDavid du Colombier  *
39*9a747e4fSDavid du Colombier  */
40*9a747e4fSDavid du Colombier 
41*9a747e4fSDavid du Colombier #ifndef lint
42*9a747e4fSDavid du Colombier static char *ident = "$Id: tar.c,v 1.2 89/02/12 10:06:05 mark Exp $";
43*9a747e4fSDavid du Colombier static char *copyright ="Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.";
44*9a747e4fSDavid du Colombier #endif /* not lint */
45*9a747e4fSDavid du Colombier 
46*9a747e4fSDavid du Colombier /* Headers */
47*9a747e4fSDavid du Colombier 
48*9a747e4fSDavid du Colombier #include "pax.h"
49*9a747e4fSDavid du Colombier 
50*9a747e4fSDavid du Colombier 
51*9a747e4fSDavid du Colombier /* Defines */
52*9a747e4fSDavid du Colombier 
53*9a747e4fSDavid du Colombier #define DEF_BLOCKING	20	/* default blocking factor for extract */
54*9a747e4fSDavid du Colombier 
55*9a747e4fSDavid du Colombier 
56*9a747e4fSDavid du Colombier /* Function Prototypes */
57*9a747e4fSDavid du Colombier 
58*9a747e4fSDavid du Colombier #ifdef __STDC__
59*9a747e4fSDavid du Colombier 
60*9a747e4fSDavid du Colombier static int taropt(int , char **, char *);
61*9a747e4fSDavid du Colombier static void usage(void);
62*9a747e4fSDavid du Colombier 
63*9a747e4fSDavid du Colombier #else /* !__STDC__ */
64*9a747e4fSDavid du Colombier 
65*9a747e4fSDavid du Colombier static int taropt();
66*9a747e4fSDavid du Colombier static void usage();
67*9a747e4fSDavid du Colombier 
68*9a747e4fSDavid du Colombier #endif /* __STDC__ */
69*9a747e4fSDavid du Colombier 
70*9a747e4fSDavid du Colombier 
71*9a747e4fSDavid du Colombier /* do_tar - main routine for tar.
72*9a747e4fSDavid du Colombier  *
73*9a747e4fSDavid du Colombier  * DESCRIPTION
74*9a747e4fSDavid du Colombier  *
75*9a747e4fSDavid du Colombier  *	Provides a tar interface to the PAX program.  All tar standard
76*9a747e4fSDavid du Colombier  *	command line options are supported.
77*9a747e4fSDavid du Colombier  *
78*9a747e4fSDavid du Colombier  * PARAMETERS
79*9a747e4fSDavid du Colombier  *
80*9a747e4fSDavid du Colombier  *	int argc	- argument count (argc from main)
81*9a747e4fSDavid du Colombier  *	char **argv	- argument list (argv from main)
82*9a747e4fSDavid du Colombier  *
83*9a747e4fSDavid du Colombier  * RETURNS
84*9a747e4fSDavid du Colombier  *
85*9a747e4fSDavid du Colombier  *	zero
86*9a747e4fSDavid du Colombier  */
87*9a747e4fSDavid du Colombier 
88*9a747e4fSDavid du Colombier #ifdef __STDC__
89*9a747e4fSDavid du Colombier 
do_tar(int argc,char ** argv)90*9a747e4fSDavid du Colombier int do_tar(int argc, char **argv)
91*9a747e4fSDavid du Colombier 
92*9a747e4fSDavid du Colombier #else
93*9a747e4fSDavid du Colombier 
94*9a747e4fSDavid du Colombier int do_tar(argc, argv)
95*9a747e4fSDavid du Colombier int             argc;		/* argument count (argc from main) */
96*9a747e4fSDavid du Colombier char          **argv;		/* argument list (argv from main) */
97*9a747e4fSDavid du Colombier 
98*9a747e4fSDavid du Colombier #endif
99*9a747e4fSDavid du Colombier {
100*9a747e4fSDavid du Colombier     int             c;		/* Option letter */
101*9a747e4fSDavid du Colombier 
102*9a747e4fSDavid du Colombier     /* Set default option values */
103*9a747e4fSDavid du Colombier     names_from_stdin = 0;
104*9a747e4fSDavid du Colombier     ar_file = getenv("TAPE");	/* From environment, or */
105*9a747e4fSDavid du Colombier     if (ar_file == 0) {
106*9a747e4fSDavid du Colombier 	ar_file = DEF_AR_FILE;	/* From Makefile */
107*9a747e4fSDavid du Colombier     }
108*9a747e4fSDavid du Colombier 
109*9a747e4fSDavid du Colombier     /*
110*9a747e4fSDavid du Colombier      * set up the flags to reflect the default pax inteface.  Unfortunately
111*9a747e4fSDavid du Colombier      * the pax interface has several options which are completely opposite
112*9a747e4fSDavid du Colombier      * of the tar and/or cpio interfaces...
113*9a747e4fSDavid du Colombier      */
114*9a747e4fSDavid du Colombier     f_unconditional = 1;
115*9a747e4fSDavid du Colombier     f_mtime = 1;
116*9a747e4fSDavid du Colombier     f_dir_create = 1;
117*9a747e4fSDavid du Colombier     blocking = 0;
118*9a747e4fSDavid du Colombier     ar_interface = TAR;
119*9a747e4fSDavid du Colombier     ar_format = TAR;
120*9a747e4fSDavid du Colombier     msgfile=stderr;
121*9a747e4fSDavid du Colombier 
122*9a747e4fSDavid du Colombier     /* Parse options */
123*9a747e4fSDavid du Colombier     while ((c = taropt(argc, argv, "b:cf:hlmortuvwx")) != EOF) {
124*9a747e4fSDavid du Colombier 	switch (c) {
125*9a747e4fSDavid du Colombier 	case 'b':		/* specify blocking factor */
126*9a747e4fSDavid du Colombier 	    /*
127*9a747e4fSDavid du Colombier 	     * FIXME - we should use a conversion routine that does
128*9a747e4fSDavid du Colombier 	     * some kind of reasonable error checking, but...
129*9a747e4fSDavid du Colombier 	     */
130*9a747e4fSDavid du Colombier 	    blocking = atoi(optarg);
131*9a747e4fSDavid du Colombier 	    break;
132*9a747e4fSDavid du Colombier 	case 'c':		/* create a new archive */
133*9a747e4fSDavid du Colombier 	    f_create = 1;
134*9a747e4fSDavid du Colombier 	    break;
135*9a747e4fSDavid du Colombier 	case 'f':		/* specify input/output file */
136*9a747e4fSDavid du Colombier 	    ar_file = optarg;
137*9a747e4fSDavid du Colombier 	    break;
138*9a747e4fSDavid du Colombier 	case 'h':
139*9a747e4fSDavid du Colombier 	    f_follow_links = 1;	/* follow symbolic links */
140*9a747e4fSDavid du Colombier 	    break;
141*9a747e4fSDavid du Colombier 	case 'l':		/* report unresolved links */
142*9a747e4fSDavid du Colombier 	    f_linksleft = 1;
143*9a747e4fSDavid du Colombier 	    break;
144*9a747e4fSDavid du Colombier 	case 'm':		/* don't restore modification times */
145*9a747e4fSDavid du Colombier 	    f_modified = 1;
146*9a747e4fSDavid du Colombier 	    break;
147*9a747e4fSDavid du Colombier 	case 'o':		/* take on user's group rather than
148*9a747e4fSDavid du Colombier 				 * archives */
149*9a747e4fSDavid du Colombier 	    break;
150*9a747e4fSDavid du Colombier 	case 'r':		/* named files are appended to archive */
151*9a747e4fSDavid du Colombier 	    f_append = 1;
152*9a747e4fSDavid du Colombier 	    break;
153*9a747e4fSDavid du Colombier 	case 't':
154*9a747e4fSDavid du Colombier 	    f_list = 1;		/* list files in archive */
155*9a747e4fSDavid du Colombier 	    break;
156*9a747e4fSDavid du Colombier 	case 'u':		/* named files are added to archive */
157*9a747e4fSDavid du Colombier 	    f_newer = 1;
158*9a747e4fSDavid du Colombier 	    break;
159*9a747e4fSDavid du Colombier 	case 'v':		/* verbose mode */
160*9a747e4fSDavid du Colombier 	    f_verbose = 1;
161*9a747e4fSDavid du Colombier 	    break;
162*9a747e4fSDavid du Colombier 	case 'w':		/* user interactive mode */
163*9a747e4fSDavid du Colombier 	    f_disposition = 1;
164*9a747e4fSDavid du Colombier 	    break;
165*9a747e4fSDavid du Colombier 	case 'x':		/* named files are extracted from archive */
166*9a747e4fSDavid du Colombier 	    f_extract = 1;
167*9a747e4fSDavid du Colombier 	    break;
168*9a747e4fSDavid du Colombier 	case '?':
169*9a747e4fSDavid du Colombier 	    usage();
170*9a747e4fSDavid du Colombier 	    exit(EX_ARGSBAD);
171*9a747e4fSDavid du Colombier 	}
172*9a747e4fSDavid du Colombier     }
173*9a747e4fSDavid du Colombier 
174*9a747e4fSDavid du Colombier     /* check command line argument sanity */
175*9a747e4fSDavid du Colombier     if (f_create + f_extract + f_list + f_append + f_newer != 1) {
176*9a747e4fSDavid du Colombier 	(void) fprintf(stderr,
177*9a747e4fSDavid du Colombier 	   "%s: you must specify exactly one of the c, t, r, u or x options\n",
178*9a747e4fSDavid du Colombier 		       myname);
179*9a747e4fSDavid du Colombier 	usage();
180*9a747e4fSDavid du Colombier 	exit(EX_ARGSBAD);
181*9a747e4fSDavid du Colombier     }
182*9a747e4fSDavid du Colombier 
183*9a747e4fSDavid du Colombier     /* set the blocking factor, if not set by the user */
184*9a747e4fSDavid du Colombier     if (blocking == 0) {
185*9a747e4fSDavid du Colombier #ifdef USG
186*9a747e4fSDavid du Colombier 	if (f_extract || f_list) {
187*9a747e4fSDavid du Colombier 	    blocking = DEF_BLOCKING;
188*9a747e4fSDavid du Colombier 	    fprintf(stderr, "Tar: blocksize = %d\n", blocking);
189*9a747e4fSDavid du Colombier 	} else {
190*9a747e4fSDavid du Colombier 	    blocking = 1;
191*9a747e4fSDavid du Colombier 	}
192*9a747e4fSDavid du Colombier #else /* !USG */
193*9a747e4fSDavid du Colombier 	blocking = 20;
194*9a747e4fSDavid du Colombier #endif /* USG */
195*9a747e4fSDavid du Colombier     }
196*9a747e4fSDavid du Colombier     blocksize = blocking * BLOCKSIZE;
197*9a747e4fSDavid du Colombier     buf_allocate((OFFSET) blocksize);
198*9a747e4fSDavid du Colombier 
199*9a747e4fSDavid du Colombier     if (f_create) {
200*9a747e4fSDavid du Colombier 	open_archive(AR_WRITE);
201*9a747e4fSDavid du Colombier 	create_archive();	/* create the archive */
202*9a747e4fSDavid du Colombier     } else if (f_extract) {
203*9a747e4fSDavid du Colombier 	open_archive(AR_READ);
204*9a747e4fSDavid du Colombier 	read_archive();		/* extract files from archive */
205*9a747e4fSDavid du Colombier     } else if (f_list) {
206*9a747e4fSDavid du Colombier 	open_archive(AR_READ);
207*9a747e4fSDavid du Colombier 	read_archive();		/* read and list contents of archive */
208*9a747e4fSDavid du Colombier     } else if (f_append) {
209*9a747e4fSDavid du Colombier 	open_archive(AR_APPEND);
210*9a747e4fSDavid du Colombier 	append_archive();	/* append files to archive */
211*9a747e4fSDavid du Colombier     }
212*9a747e4fSDavid du Colombier 
213*9a747e4fSDavid du Colombier     if (f_linksleft) {
214*9a747e4fSDavid du Colombier 	linkleft(); 		/* report any unresolved links */
215*9a747e4fSDavid du Colombier     }
216*9a747e4fSDavid du Colombier 
217*9a747e4fSDavid du Colombier     return (0);
218*9a747e4fSDavid du Colombier }
219*9a747e4fSDavid du Colombier 
220*9a747e4fSDavid du Colombier 
221*9a747e4fSDavid du Colombier /* taropt -  tar specific getopt
222*9a747e4fSDavid du Colombier  *
223*9a747e4fSDavid du Colombier  * DESCRIPTION
224*9a747e4fSDavid du Colombier  *
225*9a747e4fSDavid du Colombier  * 	Plug-compatible replacement for getopt() for parsing tar-like
226*9a747e4fSDavid du Colombier  * 	arguments.  If the first argument begins with "-", it uses getopt;
227*9a747e4fSDavid du Colombier  * 	otherwise, it uses the old rules used by tar, dump, and ps.
228*9a747e4fSDavid du Colombier  *
229*9a747e4fSDavid du Colombier  * PARAMETERS
230*9a747e4fSDavid du Colombier  *
231*9a747e4fSDavid du Colombier  *	int argc	- argument count (argc from main)
232*9a747e4fSDavid du Colombier  *	char **argv	- argument list (argv from main)
233*9a747e4fSDavid du Colombier  *	char *optstring	- sring which describes allowable options
234*9a747e4fSDavid du Colombier  *
235*9a747e4fSDavid du Colombier  * RETURNS
236*9a747e4fSDavid du Colombier  *
237*9a747e4fSDavid du Colombier  *	Returns the next option character in the option string(s).  If the
238*9a747e4fSDavid du Colombier  *	option requires an argument and an argument was given, the argument
239*9a747e4fSDavid du Colombier  *	is pointed to by "optarg".  If no option character was found,
240*9a747e4fSDavid du Colombier  *	returns an EOF.
241*9a747e4fSDavid du Colombier  *
242*9a747e4fSDavid du Colombier  */
243*9a747e4fSDavid du Colombier 
244*9a747e4fSDavid du Colombier #ifdef __STDC__
245*9a747e4fSDavid du Colombier 
taropt(int argc,char ** argv,char * optstring)246*9a747e4fSDavid du Colombier static int taropt(int argc, char **argv, char *optstring)
247*9a747e4fSDavid du Colombier 
248*9a747e4fSDavid du Colombier #else
249*9a747e4fSDavid du Colombier 
250*9a747e4fSDavid du Colombier static int taropt(argc, argv, optstring)
251*9a747e4fSDavid du Colombier int             argc;
252*9a747e4fSDavid du Colombier char          **argv;
253*9a747e4fSDavid du Colombier char           *optstring;
254*9a747e4fSDavid du Colombier 
255*9a747e4fSDavid du Colombier #endif
256*9a747e4fSDavid du Colombier {
257*9a747e4fSDavid du Colombier     extern char    *optarg;	/* Points to next arg */
258*9a747e4fSDavid du Colombier     extern int      optind;	/* Global argv index */
259*9a747e4fSDavid du Colombier     static char    *key;	/* Points to next keyletter */
260*9a747e4fSDavid du Colombier     static char     use_getopt;	/* !=0 if argv[1][0] was '-' */
261*9a747e4fSDavid du Colombier     char            c;
262*9a747e4fSDavid du Colombier     char           *place;
263*9a747e4fSDavid du Colombier 
264*9a747e4fSDavid du Colombier     optarg = (char *)NULL;
265*9a747e4fSDavid du Colombier 
266*9a747e4fSDavid du Colombier     if (key == (char *)NULL) {		/* First time */
267*9a747e4fSDavid du Colombier 	if (argc < 2)
268*9a747e4fSDavid du Colombier 	    return EOF;
269*9a747e4fSDavid du Colombier 	key = argv[1];
270*9a747e4fSDavid du Colombier 	if (*key == '-')
271*9a747e4fSDavid du Colombier 	    use_getopt++;
272*9a747e4fSDavid du Colombier 	else
273*9a747e4fSDavid du Colombier 	    optind = 2;
274*9a747e4fSDavid du Colombier     }
275*9a747e4fSDavid du Colombier     if (use_getopt) {
276*9a747e4fSDavid du Colombier 	return getopt(argc, argv, optstring);
277*9a747e4fSDavid du Colombier     }
278*9a747e4fSDavid du Colombier 
279*9a747e4fSDavid du Colombier     c = *key++;
280*9a747e4fSDavid du Colombier     if (c == '\0') {
281*9a747e4fSDavid du Colombier 	key--;
282*9a747e4fSDavid du Colombier 	return EOF;
283*9a747e4fSDavid du Colombier     }
284*9a747e4fSDavid du Colombier     place = strchr(optstring, c);
285*9a747e4fSDavid du Colombier 
286*9a747e4fSDavid du Colombier     if (place == (char *)NULL || c == ':') {
287*9a747e4fSDavid du Colombier 	fprintf(stderr, "%s: unknown option %c\n", argv[0], c);
288*9a747e4fSDavid du Colombier 	return ('?');
289*9a747e4fSDavid du Colombier     }
290*9a747e4fSDavid du Colombier     place++;
291*9a747e4fSDavid du Colombier     if (*place == ':') {
292*9a747e4fSDavid du Colombier 	if (optind < argc) {
293*9a747e4fSDavid du Colombier 	    optarg = argv[optind];
294*9a747e4fSDavid du Colombier 	    optind++;
295*9a747e4fSDavid du Colombier 	} else {
296*9a747e4fSDavid du Colombier 	    fprintf(stderr, "%s: %c argument missing\n",
297*9a747e4fSDavid du Colombier 		    argv[0], c);
298*9a747e4fSDavid du Colombier 	    return ('?');
299*9a747e4fSDavid du Colombier 	}
300*9a747e4fSDavid du Colombier     }
301*9a747e4fSDavid du Colombier     return (c);
302*9a747e4fSDavid du Colombier }
303*9a747e4fSDavid du Colombier 
304*9a747e4fSDavid du Colombier 
305*9a747e4fSDavid du Colombier /* usage - print a helpful message and exit
306*9a747e4fSDavid du Colombier  *
307*9a747e4fSDavid du Colombier  * DESCRIPTION
308*9a747e4fSDavid du Colombier  *
309*9a747e4fSDavid du Colombier  *	Usage prints out the usage message for the TAR interface and then
310*9a747e4fSDavid du Colombier  *	exits with a non-zero termination status.  This is used when a user
311*9a747e4fSDavid du Colombier  *	has provided non-existant or incompatible command line arguments.
312*9a747e4fSDavid du Colombier  *
313*9a747e4fSDavid du Colombier  * RETURNS
314*9a747e4fSDavid du Colombier  *
315*9a747e4fSDavid du Colombier  *	Returns an exit status of 1 to the parent process.
316*9a747e4fSDavid du Colombier  *
317*9a747e4fSDavid du Colombier  */
318*9a747e4fSDavid du Colombier 
319*9a747e4fSDavid du Colombier #ifdef __STDC__
320*9a747e4fSDavid du Colombier 
usage(void)321*9a747e4fSDavid du Colombier static void usage(void)
322*9a747e4fSDavid du Colombier 
323*9a747e4fSDavid du Colombier #else
324*9a747e4fSDavid du Colombier 
325*9a747e4fSDavid du Colombier static void usage()
326*9a747e4fSDavid du Colombier 
327*9a747e4fSDavid du Colombier #endif
328*9a747e4fSDavid du Colombier {
329*9a747e4fSDavid du Colombier     fprintf(stderr, "Usage: %s -c[bfvw] device block filename..\n", myname);
330*9a747e4fSDavid du Colombier     fprintf(stderr, "       %s -r[bvw] device block [filename...]\n", myname);
331*9a747e4fSDavid du Colombier     fprintf(stderr, "       %s -t[vf] device\n", myname);
332*9a747e4fSDavid du Colombier     fprintf(stderr, "       %s -u[bvw] device block [filename...]\n", myname);
333*9a747e4fSDavid du Colombier     fprintf(stderr, "       %s -x[flmovw] device [filename...]\n", myname);
334*9a747e4fSDavid du Colombier     exit(1);
335*9a747e4fSDavid du Colombier }
336