Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}