xref: /csrg-svn/bin/pax/pax.c (revision 60676)
157112Smuller /*-
257112Smuller  * Copyright (c) 1992 Keith Muller.
3*60676Sbostic  * Copyright (c) 1992, 1993
4*60676Sbostic  *	The Regents of the University of California.  All rights reserved.
557112Smuller  *
657112Smuller  * This code is derived from software contributed to Berkeley by
757112Smuller  * Keith Muller of the University of California, San Diego.
857112Smuller  *
957112Smuller  * %sccs.include.redist.c%
1057112Smuller  */
1157112Smuller 
1257112Smuller #ifndef lint
1357579Smuller static char copyright[] =
14*60676Sbostic "@(#) Copyright (c) 1992, 1993\n\
15*60676Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1657112Smuller #endif /* not lint */
1757112Smuller 
1857112Smuller #ifndef lint
19*60676Sbostic static char sccsid[] = "@(#)pax.c	8.1 (Berkeley) 05/31/93";
2057112Smuller #endif /* not lint */
2157112Smuller 
2257112Smuller #include <stdio.h>
2357112Smuller #include <sys/types.h>
2457112Smuller #include <sys/param.h>
2557112Smuller #include <sys/stat.h>
2657112Smuller #include <sys/time.h>
2757112Smuller #include <sys/resource.h>
2857112Smuller #include <signal.h>
2957112Smuller #include <unistd.h>
3057112Smuller #include <stdlib.h>
3157112Smuller #include <errno.h>
3257112Smuller #include "pax.h"
3357112Smuller #include "extern.h"
3457112Smuller static int gen_init __P((void));
3557112Smuller 
3657112Smuller /*
3757543Smuller  * PAX main routines, general globals and some simple start up routines
3857112Smuller  */
3957112Smuller 
4057112Smuller /*
4157112Smuller  * Variables that can be accessed by any routine within pax
4257112Smuller  */
4357112Smuller int	act = DEFOP;		/* read/write/append/copy */
4457112Smuller FSUB	*frmt = NULL;		/* archive format type */
4557112Smuller int	cflag;			/* match all EXCEPT pattern/file */
4657112Smuller int	dflag;			/* directory member match only  */
4757112Smuller int	iflag;			/* interactive file/archive rename */
4857112Smuller int	kflag;			/* do not overwrite existing files */
4957112Smuller int	lflag;			/* use hard links when possible */
5057112Smuller int	nflag;			/* select first archive member match */
5157112Smuller int	tflag;			/* restore access time after read */
5257112Smuller int	uflag;			/* ignore older modification time files */
5357112Smuller int	vflag;			/* produce verbose output */
5457543Smuller int	Dflag;			/* same as uflag except inode change time */
5557112Smuller int	Hflag;			/* follow command line symlinks (write only) */
5657112Smuller int	Lflag;			/* follow symlinks when writing archive */
5757112Smuller int	Xflag;			/* archive files with same device id only */
5857543Smuller int	Yflag;			/* same as Dflg except after name mode */
5957543Smuller int	Zflag;			/* same as uflg except after name mode */
6057112Smuller int	vfpart;			/* is partial verbose output in progress */
6157112Smuller int	patime = 1;		/* preserve file access time */
6257112Smuller int	pmtime = 1;		/* preserve file modification times */
6357112Smuller int	pmode;			/* preserve file mode bits */
6457112Smuller int	pids;			/* preserve file uid/gid */
6557112Smuller int	exit_val;		/* exit value */
6657112Smuller int	docrc;			/* check/create file crc */
6757112Smuller char	*dirptr;		/* destination dir in a copy */
6857112Smuller char	*ltmfrmt;		/* -v locale time format (if any) */
6957112Smuller sigset_t s_mask;		/* signal mask for cleanup critical sect */
7057112Smuller 
7157112Smuller /*
7257112Smuller  *	PAX - Portable Archive Interchange
7357112Smuller  *
7457112Smuller  * 	A utility to read, write, and write lists of the members of archive
7557112Smuller  *	files and copy directory hierarchies. A variety of archive formats
7657112Smuller  *	are supported (some are described in POSIX 1003.1 10.1):
7757112Smuller  *
7857112Smuller  *		ustar - 10.1.1 extended tar interchange format
7957112Smuller  *		cpio  - 10.1.2 extended cpio interchange format
8057112Smuller  *		tar - old BSD 4.3 tar format
8157112Smuller  *		binary cpio - old cpio with binary header format
8257112Smuller  *		sysVR4 cpio -  with and without CRC
8357112Smuller  *
8457112Smuller  * This version is a superset of IEEE Std 1003.2b-d3
8557112Smuller  *
8657112Smuller  * Summary of Extensions to the IEEE Standard:
8757112Smuller  *
8857543Smuller  * 1	READ ENHANCEMENTS
8957112Smuller  * 1.1	Operations which read archives will continue to operate even when
9057112Smuller  *	processing archives which may be damaged, truncated, or fail to meet
9157112Smuller  *	format specs in several different ways. Damaged sections of archives
9257112Smuller  *	are detected and avoided if possible. Attempts will be made to resync
9357112Smuller  *	archive read operations even with badly damaged media.
9457112Smuller  * 1.2	Blocksize requirements are not strictly enforced on archive read.
9557112Smuller  *	Tapes which have variable sized records can be read without errors.
9657112Smuller  * 1.3	The user can specify via the non-standard option flag -E if error
9757112Smuller  *	resync operation should stop on a media error, try a specified number
9857112Smuller  *	of times to correct, or try to correct forever.
9957112Smuller  * 1.4	Sparse files (lseek holes) stored on the archive (but stored with blocks
10057112Smuller  *	of all zeros will be restored with holes appropriate for the target
10157112Smuller  *	filesystem
10257112Smuller  * 1.5	The user is notified whenever something is found during archive
10357112Smuller  *	read operations which violates spec (but the read will continue).
10457112Smuller  * 1.6	Multiple archive volumes can be read and may span over different
10557112Smuller  *	archive devices
10657112Smuller  * 1.7	Rigidly restores all file attributes exactly as they are stored on the
10757112Smuller  *	archive.
10857543Smuller  * 1.8	Modification change time ranges can be specified via multiple -T
10957543Smuller  *	options. These allow a user to select files whose modification time
11057543Smuller  *	lies within a specific time range.
11157112Smuller  * 1.9	Files can be selected based on owner (user name or uid) via one or more
11257112Smuller  *	-U options.
11357112Smuller  * 1.10	Files can be selected based on group (group name or gid) via one o
11457112Smuller  *	more -G options.
11557112Smuller  * 1.11	File modification time can be checked against exisiting file after
11657112Smuller  *	name modification (-Z)
11757112Smuller  *
11857543Smuller  * 2	WRITE ENHANCEMENTS
11957112Smuller  * 2.1	Write operation will stop instead of allowing a user to create a flawed
12057112Smuller  *	flawed archive (due to any problem).
12157112Smuller  * 2.2	Archives writtens by pax are forced to strictly conform to both the
12257112Smuller  *	archive and pax the spceific format specifications.
12357112Smuller  * 2.3	Blocking size and format is rigidly enforced on writes.
12457112Smuller  * 2.4	Formats which may exhibit header overflow problems (they have fields
12557112Smuller  *	too small for large file systems, such as inode number storage), use
12657112Smuller  *	routines designed to repair this problem. These techniques still
12757112Smuller  *	conform to both pax and format specifications, but no longer truncate
12857112Smuller  *	these fields. This removes any restrictions on using these archive
12957112Smuller  *	formats on large file systems.
13057112Smuller  * 2.5	Multiple archive volumes can be written and may span over different
13157112Smuller  *	archive devices
13257112Smuller  * 2.6	A archive volume record limit allows the user to specify the number
13357112Smuller  *	of bytes stored on an archive volume. When reached the user is
13457112Smuller  *	prompted for the next archive volume. This is specified with the
13557112Smuller  *	non-standard -B flag. THe limit is rounded up to the next blocksize.
13657112Smuller  * 2.7	All archive padding during write use zero filled sections. This makes
13757112Smuller  *	it much easier to pull data out of flawed archive during read
13857112Smuller  *	operations.
13957112Smuller  * 2.8	Access time reset with the -t applies to all file nodes (including
14057112Smuller  *	directories).
14157112Smuller  * 2.9	Symbolic links can be followed with -L (optional in the spec).
14257543Smuller  * 2.10	Modification or inode change time ranges can be specified via
14357543Smuller  *	multiple -T options. These allow a user to select files whose
14457543Smuller  *	modification or inode change time lies within a specific time range.
14557112Smuller  * 2.11	Files can be selected based on owner (user name or uid) via one or more
14657112Smuller  *	-U options.
14757112Smuller  * 2.12	Files can be selected based on group (group name or gid) via one o
14857112Smuller  *	more -G options.
14957112Smuller  * 2.13	Symlinks which appear on the command line can be followed (without
15057112Smuller  *	following other symlinks; -H flag)
15157112Smuller  *
15257543Smuller  * 3	COPY ENHANCEMENTS
15357112Smuller  * 3.1	Sparse files (lseek holes) can be copied without expanding the holes
15457112Smuller  *	into zero filled blocks. The file copy is created with holes which are
15557112Smuller  *	appropriate for the target filesystem
15657112Smuller  * 3.2	Access time as well as modification time on copied file trees can be
15757112Smuller  *	preserved with the appropriate -p options.
15857112Smuller  * 3.3	Access time reset with the -t applies to all file nodes (including
15957112Smuller  *	directories).
16057112Smuller  * 3.4	Symbolic links can be followed with -L (optional in the spec).
16157543Smuller  * 3.5	Modification or inode change time ranges can be specified via
16257543Smuller  *	multiple -T options. These allow a user to select files whose
16357543Smuller  *	modification or inode change time lies within a specific time range.
16457112Smuller  * 3.6	Files can be selected based on owner (user name or uid) via one or more
16557112Smuller  *	-U options.
16657112Smuller  * 3.7	Files can be selected based on group (group name or gid) via one o
16757112Smuller  *	more -G options.
16857112Smuller  * 3.8	Symlinks which appear on the command line can be followed (without
16957112Smuller  *	following other symlinks; -H flag)
17057543Smuller  * 3.9  File inode change time can be checked against exisiting file before
17157543Smuller  *	name modification (-D)
17257543Smuller  * 3.10 File inode change time can be checked against exisiting file after
17357543Smuller  *	name modification (-Y)
17457543Smuller  * 3.11	File modification time can be checked against exisiting file after
17557112Smuller  *	name modification (-Z)
17657112Smuller  *
17757543Smuller  * 4	GENERAL ENHANCEMENTS
17857112Smuller  * 4.1	Internal structure is designed to isolate format dependent and
17957112Smuller  *	independent functions. Formats are selected via a format driver table.
18057112Smuller  *	This encourages the addition of new archive formats by only having to
18157112Smuller  *	write those routines which id, read and write the archive header.
18257112Smuller  */
18357112Smuller 
18457543Smuller /*
18557543Smuller  * main()
18657543Smuller  *	parse options, set up and operate as specified by the user.
18757543Smuller  *	any operational flaw will set exit_val to non-zero
18857543Smuller  * Return: 0 if ok, 1 otherwise
18957543Smuller  */
19057543Smuller 
19157112Smuller #if __STDC__
19257112Smuller int
19357112Smuller main(int argc, char **argv)
19457112Smuller #else
19557112Smuller int
19657112Smuller main(argc, argv)
19757112Smuller 	int argc;
19857112Smuller 	char **argv;
19957112Smuller #endif
20057112Smuller {
20157112Smuller 	/*
20257543Smuller 	 * parse options, determine operational mode, general init
20357112Smuller 	 */
20457112Smuller 	options(argc, argv);
20557112Smuller         if ((gen_init() < 0) || (tty_init() < 0))
20657112Smuller 		return(exit_val);
20757112Smuller 
20857112Smuller 	/*
20957112Smuller 	 * select a primary operation mode
21057112Smuller 	 */
21157112Smuller 	switch(act) {
21257112Smuller 	case EXTRACT:
21357112Smuller 		extract();
21457112Smuller 		break;
21557112Smuller 	case ARCHIVE:
21657112Smuller 		archive();
21757112Smuller 		break;
21857112Smuller 	case APPND:
21957112Smuller 		append();
22057112Smuller 		break;
22157112Smuller 	case COPY:
22257112Smuller 		copy();
22357112Smuller 		break;
22457112Smuller 	default:
22557112Smuller 	case LIST:
22657112Smuller 		list();
22757112Smuller 		break;
22857112Smuller 	}
22957112Smuller 	return(exit_val);
23057112Smuller }
23157112Smuller 
23257112Smuller /*
23357112Smuller  * sig_cleanup()
23457112Smuller  *	when interrupted we try to do whatever delayed processing we can.
23557112Smuller  *	This is not critical, but we really ought to limit our damage when we
23657112Smuller  *	are aborted by the user.
23757112Smuller  * Return:
23857112Smuller  *	never....
23957112Smuller  */
24057112Smuller 
24157112Smuller #if __STDC__
24257112Smuller void
24357112Smuller sig_cleanup(int which_sig)
24457112Smuller #else
24557112Smuller void
24657112Smuller sig_cleanup(which_sig)
24757112Smuller 	int which_sig;
24857112Smuller #endif
24957112Smuller {
25057112Smuller 	/*
25157112Smuller 	 * restore modes and times for any dirs we may have created
25257543Smuller 	 * or any dirs we may have read. Set vflag and vfpart so the user
25357543Smuller 	 * will clearly see the message on a line by itself.
25457112Smuller 	 */
25557543Smuller 	vflag = vfpart = 1;
25657112Smuller 	if (which_sig == SIGXCPU)
25757112Smuller 		warn(0, "Cpu time limit reached, cleaning up.");
25857112Smuller 	else
25957112Smuller 		warn(0, "Signal caught, cleaning up.");
26057543Smuller 
26157112Smuller 	ar_close();
26257112Smuller 	proc_dir();
26357112Smuller 	if (tflag)
26457112Smuller 		atdir_end();
26557112Smuller 	exit(1);
26657112Smuller }
26757112Smuller 
26857112Smuller /*
26957112Smuller  * gen_init()
27057112Smuller  *	general setup routines. Not all are required, but they really help
27157112Smuller  *	when dealing with a medium to large sized archives.
27257112Smuller  */
27357112Smuller 
27457112Smuller #if __STDC__
27557112Smuller static int
27657112Smuller gen_init(void)
27757112Smuller #else
27857112Smuller static int
27957112Smuller gen_init()
28057112Smuller #endif
28157112Smuller {
28257112Smuller 	struct rlimit reslimit;
28357112Smuller 	struct sigaction n_hand;
28457112Smuller 	struct sigaction o_hand;
28557112Smuller 
28657112Smuller 	/*
28757112Smuller 	 * Really needed to handle large archives. We can run out of memory for
28857112Smuller 	 * internal tables really fast when we have a whole lot of files...
28957112Smuller 	 */
29057112Smuller 	if (getrlimit(RLIMIT_DATA , &reslimit) == 0){
29157112Smuller 		reslimit.rlim_cur = reslimit.rlim_max;
29257112Smuller 		(void)setrlimit(RLIMIT_DATA , &reslimit);
29357112Smuller 	}
29457112Smuller 
29557112Smuller 	/*
29657112Smuller 	 * should file size limits be waived? if the os limits us, this is
29757112Smuller 	 * needed if we want to write a large archive
29857112Smuller 	 */
29957112Smuller 	if (getrlimit(RLIMIT_FSIZE , &reslimit) == 0){
30057112Smuller 		reslimit.rlim_cur = reslimit.rlim_max;
30157112Smuller 		(void)setrlimit(RLIMIT_FSIZE , &reslimit);
30257112Smuller 	}
30357112Smuller 
30457112Smuller 	/*
30557112Smuller 	 * increase the size the stack can grow to
30657112Smuller 	 */
30757112Smuller 	if (getrlimit(RLIMIT_STACK , &reslimit) == 0){
30857112Smuller 		reslimit.rlim_cur = reslimit.rlim_max;
30957112Smuller 		(void)setrlimit(RLIMIT_STACK , &reslimit);
31057112Smuller 	}
31157112Smuller 
31257112Smuller 	/*
31357112Smuller 	 * not really needed, but doesn't hurt
31457112Smuller 	 */
31557112Smuller 	if (getrlimit(RLIMIT_RSS , &reslimit) == 0){
31657112Smuller 		reslimit.rlim_cur = reslimit.rlim_max;
31757112Smuller 		(void)setrlimit(RLIMIT_RSS , &reslimit);
31857112Smuller 	}
31957112Smuller 
32057112Smuller 	/*
32157112Smuller 	 * Handle posix locale
32257112Smuller 	 *
32357112Smuller 	 * set user defines time printing format for -v option
32457112Smuller 	 */
32557112Smuller 	ltmfrmt = getenv("LC_TIME");
32657112Smuller 
32757112Smuller 	/*
32857112Smuller 	 * signal handling to reset stored directory times and modes. Since
32957112Smuller 	 * we deal with broken pipes via failed writes we ignore it. We also
33057543Smuller 	 * deal with any file size limit thorugh failed writes. Cpu time
33157543Smuller 	 * limits are caught and a cleanup is forced.
33257112Smuller 	 */
33357112Smuller 	if ((sigemptyset(&s_mask) < 0) || (sigaddset(&s_mask, SIGTERM) < 0) ||
33457112Smuller 	    (sigaddset(&s_mask,SIGINT) < 0)||(sigaddset(&s_mask,SIGHUP) < 0) ||
33557112Smuller 	    (sigaddset(&s_mask,SIGPIPE) < 0)||(sigaddset(&s_mask,SIGQUIT)<0) ||
33657112Smuller 	    (sigaddset(&s_mask,SIGXCPU) < 0)||(sigaddset(&s_mask,SIGXFSZ)<0)) {
33757112Smuller 		warn(1, "Unable to set up signal mask");
33857112Smuller 		return(-1);
33957112Smuller 	}
34057112Smuller 	n_hand.sa_mask = s_mask;
34157112Smuller 	n_hand.sa_flags = 0;
34257112Smuller 	n_hand.sa_handler = sig_cleanup;
34357112Smuller 
34457112Smuller 	if ((sigaction(SIGHUP, &n_hand, &o_hand) < 0) &&
34557112Smuller 	    (o_hand.sa_handler == SIG_IGN) &&
34657112Smuller 	    (sigaction(SIGHUP, &o_hand, &o_hand) < 0))
34757112Smuller 		goto out;
34857112Smuller 
34957112Smuller 	if ((sigaction(SIGTERM, &n_hand, &o_hand) < 0) &&
35057112Smuller 	    (o_hand.sa_handler == SIG_IGN) &&
35157112Smuller 	    (sigaction(SIGTERM, &o_hand, &o_hand) < 0))
35257112Smuller 		goto out;
35357112Smuller 
35457112Smuller 	if ((sigaction(SIGINT, &n_hand, &o_hand) < 0) &&
35557112Smuller 	    (o_hand.sa_handler == SIG_IGN) &&
35657112Smuller 	    (sigaction(SIGINT, &o_hand, &o_hand) < 0))
35757112Smuller 		goto out;
35857112Smuller 
35957112Smuller 	if ((sigaction(SIGQUIT, &n_hand, &o_hand) < 0) &&
36057112Smuller 	    (o_hand.sa_handler == SIG_IGN) &&
36157112Smuller 	    (sigaction(SIGQUIT, &o_hand, &o_hand) < 0))
36257112Smuller 		goto out;
36357112Smuller 
36457112Smuller 	if ((sigaction(SIGXCPU, &n_hand, &o_hand) < 0) &&
36557112Smuller 	    (o_hand.sa_handler == SIG_IGN) &&
36657112Smuller 	    (sigaction(SIGXCPU, &o_hand, &o_hand) < 0))
36757112Smuller 		goto out;
36857112Smuller 
36957112Smuller 	n_hand.sa_handler = SIG_IGN;
37057112Smuller 	if ((sigaction(SIGPIPE, &n_hand, &o_hand) < 0) ||
37157112Smuller 	    (sigaction(SIGXFSZ, &n_hand, &o_hand) < 0))
37257112Smuller 		goto out;
37357112Smuller 	return(0);
37457112Smuller 
37557112Smuller     out:
37657112Smuller 	syswarn(1, errno, "Unable to set up signal handler");
37757112Smuller 	return(-1);
37857112Smuller }
37957543Smuller 
38057543Smuller /*
38157543Smuller  * usage()
38257543Smuller  *	print the usage summary to the user
38357543Smuller  */
38457543Smuller 
38557543Smuller #if __STDC__
38657543Smuller void
38757543Smuller usage(void)
38857543Smuller #else
38957543Smuller void
39057543Smuller usage()
39157543Smuller #endif
39257543Smuller {
39357543Smuller 	(void)fputs("usage: pax [-cdnv] [-E limit] [-f archive] ", stderr);
39457543Smuller 	(void)fputs("[-s replstr] ... [-U user] ...", stderr);
39557543Smuller 	(void)fputs("\n           [-G group] ... ", stderr);
39657543Smuller 	(void)fputs("[-T [from_date][,to_date]] ... ", stderr);
39757543Smuller 	(void)fputs("[pattern ...]\n", stderr);
39857543Smuller 	(void)fputs("       pax -r [-cdiknuvDYZ] [-E limit] ", stderr);
39957543Smuller 	(void)fputs("[-f archive] [-o options] ... \n", stderr);
40057543Smuller 	(void)fputs("           [-p string] ... [-s replstr] ... ", stderr);
40157543Smuller 	(void)fputs("[-U user] ... [-G group] ...\n           ", stderr);
40257543Smuller 	(void)fputs("[-T [from_date][,to_date]] ... ", stderr);
40357543Smuller 	(void)fputs(" [pattern ...]\n", stderr);
40457543Smuller 	(void)fputs("       pax -w [-dituvHLX] [-b blocksize] ", stderr);
40557543Smuller 	(void)fputs("[ [-a] [-f archive] ] [-x format] \n", stderr);
40657543Smuller 	(void)fputs("           [-B bytes] [-s replstr] ... ", stderr);
40757543Smuller 	(void)fputs("[-o options] ... [-U user] ...", stderr);
40857543Smuller 	(void)fputs("\n           [-G group] ... ", stderr);
40957543Smuller 	(void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
41057543Smuller 	(void)fputs("[file ...]\n", stderr);
41157543Smuller 	(void)fputs("       pax -r -w [-diklntuvDHLXYZ]", stderr);
41257543Smuller 	(void)fputs("[-p string] ... [-s replstr] ... [-U user] ...", stderr);
41357543Smuller 	(void)fputs("\n           [-G group] ... ", stderr);
41457543Smuller 	(void)fputs("[-T [from_date][,to_date][/[c][m]]] ... ", stderr);
41557543Smuller 	(void)fputs("[file ...]\n           directory\n", stderr);
41657543Smuller 	exit(1);
41757543Smuller }
418