xref: /csrg-svn/old/cpio/cpio.c (revision 33828)
1*33828Sbostic /*	Copyright (c) 1988 AT&T	*/
2*33828Sbostic /*	  All Rights Reserved  	*/
3*33828Sbostic 
4*33828Sbostic /*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
5*33828Sbostic /*	The copyright notice above does not evidence any   	*/
6*33828Sbostic /*	actual or intended publication of such source code.	*/
7*33828Sbostic 
8*33828Sbostic #ident	"@(#)cpio:cpio.c	1.30.1.11"
9*33828Sbostic /*	/sccs/src/cmd/s.cpio.c
10*33828Sbostic 	cpio.c	1.30.1.11	1/11/86 13:46:48
11*33828Sbostic 	Reworked cpio which uses getopt(3) to interpret flag arguments and
12*33828Sbostic 	changes reels to the save file name.
13*33828Sbostic 	Performance and size improvements.
14*33828Sbostic */
15*33828Sbostic 
16*33828Sbostic /*	cpio	COMPILE:	cc -O cpio.c -s -i -o cpio -lgen -lerr
17*33828Sbostic 	cpio -- copy file collections
18*33828Sbostic 
19*33828Sbostic */
20*33828Sbostic #include "errmsg.h"
21*33828Sbostic #include <errno.h>
22*33828Sbostic #include <fcntl.h>
23*33828Sbostic #include <memory.h>
24*33828Sbostic #include <stdio.h>
25*33828Sbostic #include <string.h>
26*33828Sbostic #include <signal.h>
27*33828Sbostic #include <varargs.h>
28*33828Sbostic #include <sys/stat.h>
29*33828Sbostic 
30*33828Sbostic #define EQ(x,y)	(strcmp(x,y)==0)
31*33828Sbostic 
32*33828Sbostic 				/* MKSHORT:  for VAX, Interdata, ...	*/
33*33828Sbostic 				/* Take a 4-byte long, lv, and turn it	*/
34*33828Sbostic 				/* into an array of two 2-byte shorts, v*/
35*33828Sbostic #define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];}
36*33828Sbostic 
37*33828Sbostic #define MAGIC	070707		/* cpio magic number */
38*33828Sbostic #define IN	'i'		/* copy in */
39*33828Sbostic #define OUT	'o'		/* copy out */
40*33828Sbostic #define PASS	'p'		/* direct copy */
41*33828Sbostic #define HDRSIZE	(Hdr.h_name - (char *)&Hdr)	/* header size minus filename field */
42*33828Sbostic #define LINKS	500		/* no. of links allocated per bunch */
43*33828Sbostic #define CHARS	76		/* ASCII header size minus filename field */
44*33828Sbostic #define BUFSIZE 512		/* In u370, can't use BUFSIZ or BSIZE */
45*33828Sbostic #define CPIOBSZ 4096		/* file read/write */
46*33828Sbostic #define MK_USHORT(a)	(a & 00000177777)	/* Make unsigned shorts for portable  */
47*33828Sbostic 						/* header.  Hardware may only know    */
48*33828Sbostic 						/* integer operations and sign extend */
49*33828Sbostic 						/* the large unsigned short resulting */
50*33828Sbostic 						/* in 8 rather than 6 octal char in   */
51*33828Sbostic 						/* the header.			      */
52*33828Sbostic 
53*33828Sbostic static struct	stat	Statb, Xstatb;
54*33828Sbostic 
55*33828Sbostic 	/* Cpio header format */
56*33828Sbostic static struct header {
57*33828Sbostic 	short	h_magic;
58*33828Sbostic 	short	h_dev;
59*33828Sbostic 	ushort	h_ino;
60*33828Sbostic 	ushort	h_mode,
61*33828Sbostic 		h_uid,
62*33828Sbostic 		h_gid;
63*33828Sbostic 	short	h_nlink;
64*33828Sbostic 	short	h_rdev;
65*33828Sbostic 	short	h_mtime[2],
66*33828Sbostic 		h_namesize,
67*33828Sbostic 		h_filesize[2];
68*33828Sbostic 	char	h_name[256];
69*33828Sbostic } Hdr;
70*33828Sbostic 
71*33828Sbostic static unsigned	Bufsize = BUFSIZE;		/* default record size */
72*33828Sbostic static char	Buf[CPIOBSZ], *Cbuf;
73*33828Sbostic static char	*Cp;
74*33828Sbostic 
75*33828Sbostic 
76*33828Sbostic static
77*33828Sbostic short	Option,
78*33828Sbostic 	Dir,
79*33828Sbostic 	Uncond,
80*33828Sbostic 	PassLink,
81*33828Sbostic 	Rename,
82*33828Sbostic 	Toc,
83*33828Sbostic 	Verbose,
84*33828Sbostic 	Mod_time,
85*33828Sbostic 	Acc_time,
86*33828Sbostic 	Cflag,
87*33828Sbostic 	fflag,
88*33828Sbostic 	Swap,
89*33828Sbostic 	byteswap,
90*33828Sbostic 	bothswap,
91*33828Sbostic 	halfswap;
92*33828Sbostic 
93*33828Sbostic static
94*33828Sbostic int	Ifile,
95*33828Sbostic 	Ofile,
96*33828Sbostic 	Input = 0,
97*33828Sbostic 	Output = 1;
98*33828Sbostic 			/* sBlocks: short Blocks.  Cumulative character   */
99*33828Sbostic 			/* count for short reads in bread().  Encountered */
100*33828Sbostic 			/* with communication lines and pipes as in:      */
101*33828Sbostic 			/* split -100 cpio_archive; cat xa* | cpio -icd   */
102*33828Sbostic static
103*33828Sbostic long	sBlocks,
104*33828Sbostic 	Blocks,
105*33828Sbostic 	Longfile,
106*33828Sbostic 	Longtime;
107*33828Sbostic 
108*33828Sbostic static
109*33828Sbostic char	Fullname[256],
110*33828Sbostic 	Name[256];
111*33828Sbostic static
112*33828Sbostic int	Pathend;
113*33828Sbostic static
114*33828Sbostic char	*swfile;
115*33828Sbostic static
116*33828Sbostic char	*eommsg = "Change to part %d and press RETURN key. [q] ";
117*33828Sbostic 
118*33828Sbostic static
119*33828Sbostic FILE	*Rtty,
120*33828Sbostic 	*Wtty;
121*33828Sbostic static
122*33828Sbostic char	ttyname[] = "/dev/tty";
123*33828Sbostic 
124*33828Sbostic static
125*33828Sbostic char	**Pattern = 0;
126*33828Sbostic static
127*33828Sbostic char	Chdr[500];
128*33828Sbostic static
129*33828Sbostic short	Dev;
130*33828Sbostic ushort	Uid,
131*33828Sbostic 	A_directory,
132*33828Sbostic 	A_special,
133*33828Sbostic 	Filetype = S_IFMT;
134*33828Sbostic 
135*33828Sbostic extern	errno;
136*33828Sbostic extern	void exit();
137*33828Sbostic extern	char *sys_errlist[];
138*33828Sbostic char	*malloc();
139*33828Sbostic FILE 	*popen();
140*33828Sbostic 
141*33828Sbostic static
142*33828Sbostic union {
143*33828Sbostic 	long l;
144*33828Sbostic 	short s[2];
145*33828Sbostic 	char c[4];
146*33828Sbostic } U;
147*33828Sbostic 
148*33828Sbostic /* for VAX, Interdata, ... */
149*33828Sbostic static
150*33828Sbostic long mklong(v)
151*33828Sbostic short v[];
152*33828Sbostic {
153*33828Sbostic 	U.l = 1;
154*33828Sbostic 	if(U.c[0])
155*33828Sbostic 		U.s[0] = v[1], U.s[1] = v[0];
156*33828Sbostic 	else
157*33828Sbostic 		U.s[0] = v[0], U.s[1] = v[1];
158*33828Sbostic 	return U.l;
159*33828Sbostic }
160*33828Sbostic 
161*33828Sbostic main(argc, argv)
162*33828Sbostic char **argv;
163*33828Sbostic {
164*33828Sbostic 	register ct;
165*33828Sbostic 	long	filesz;
166*33828Sbostic 	register char *fullp;
167*33828Sbostic 	register i;
168*33828Sbostic 	int ans;
169*33828Sbostic 	short select;			/* set when files are selected */
170*33828Sbostic 	extern char	*optarg;
171*33828Sbostic 	extern int	optind;
172*33828Sbostic 
173*33828Sbostic 	errsource( *argv );
174*33828Sbostic 	errverb("notag,notofix");
175*33828Sbostic 	errexit( 2 );
176*33828Sbostic 	signal(SIGSYS, 1);
177*33828Sbostic 	if(*argv[1] != '-')
178*33828Sbostic 		usage();
179*33828Sbostic 	Uid = getuid();
180*33828Sbostic 	umask(0);
181*33828Sbostic 
182*33828Sbostic 	while( (ans = getopt( argc, argv, "aBC:ifopcdlmrSsbtuvVM:6eI:O:")) != EOF ) {
183*33828Sbostic 
184*33828Sbostic 		switch( ans ) {
185*33828Sbostic 		case 'a':		/* reset access time */
186*33828Sbostic 			Acc_time++;
187*33828Sbostic 			break;
188*33828Sbostic 		case 'B':		/* change record size to 5120 bytes */
189*33828Sbostic 			Bufsize = 5120;
190*33828Sbostic 			break;
191*33828Sbostic 		case 'C':		/* reset buffer size to arbitrary valu
192*33828Sbostic 					*/
193*33828Sbostic 			Bufsize = atoi( optarg );
194*33828Sbostic 			if( Bufsize == 0 )
195*33828Sbostic 				errmsg( EERROR,
196*33828Sbostic 					"Illegal argument to -%c, '%s'.",
197*33828Sbostic 					ans, optarg );
198*33828Sbostic 			break;
199*33828Sbostic 		case 'i':
200*33828Sbostic 			Option = IN;
201*33828Sbostic 			break;
202*33828Sbostic 		case 'f':	/* copy files not matched by patterns */
203*33828Sbostic 			fflag++;
204*33828Sbostic 			break;
205*33828Sbostic 		case 'o':
206*33828Sbostic 			Option = OUT;
207*33828Sbostic 			break;
208*33828Sbostic 		case 'p':
209*33828Sbostic 			Option = PASS;
210*33828Sbostic 			break;
211*33828Sbostic 		case 'c':		/* ASCII header */
212*33828Sbostic 			Cflag++;
213*33828Sbostic 			break;
214*33828Sbostic 		case 'd':		/* create directories when needed */
215*33828Sbostic 			Dir++;
216*33828Sbostic 			break;
217*33828Sbostic 		case 'l':		/* link files, when necessary */
218*33828Sbostic 			PassLink++;
219*33828Sbostic 			break;
220*33828Sbostic 		case 'm':		/* retain mod time */
221*33828Sbostic 			Mod_time++;
222*33828Sbostic 			break;
223*33828Sbostic 		case 'r':		/* rename files interactively */
224*33828Sbostic 			Rename++;
225*33828Sbostic 			Rtty = fopen(ttyname, "r");
226*33828Sbostic 			Wtty = fopen(ttyname, "w");
227*33828Sbostic 			if(Rtty==NULL || Wtty==NULL) {
228*33828Sbostic 				errmsg( EERROR, "Cannot rename (%s missing)",
229*33828Sbostic 					ttyname );
230*33828Sbostic 			}
231*33828Sbostic 			break;
232*33828Sbostic 		case 'S':		/* swap halfwords */
233*33828Sbostic 			halfswap++;
234*33828Sbostic 			Swap++;
235*33828Sbostic 			break;
236*33828Sbostic 		case 's':		/* swap bytes */
237*33828Sbostic 			byteswap++;
238*33828Sbostic 			Swap++;
239*33828Sbostic 			break;
240*33828Sbostic 		case 'b':		/* swap both bytes and halfwords */
241*33828Sbostic 			bothswap++;
242*33828Sbostic 			Swap++;
243*33828Sbostic 			break;
244*33828Sbostic 		case 't':		/* table of contents */
245*33828Sbostic 			Toc++;
246*33828Sbostic 			break;
247*33828Sbostic 		case 'u':		/* copy unconditionally */
248*33828Sbostic 			Uncond++;
249*33828Sbostic 			break;
250*33828Sbostic 		case 'v':		/* verbose - print out file names */
251*33828Sbostic 			Verbose = 1;
252*33828Sbostic 			break;
253*33828Sbostic 		case 'V':		/* print a dot '.' for each file */
254*33828Sbostic 			Verbose = 2;
255*33828Sbostic 			break;
256*33828Sbostic 		case 'M':		/* alternate message for end-of-media */
257*33828Sbostic 			eommsg = optarg;
258*33828Sbostic 			break;
259*33828Sbostic 		case '6':		/* for old, sixth-edition files */
260*33828Sbostic 			Filetype = 060000;
261*33828Sbostic 			break;
262*33828Sbostic 		case 'I':
263*33828Sbostic 			chkswfile( swfile, ans, Option );
264*33828Sbostic 			close( Input );
265*33828Sbostic 			if( open( optarg, O_RDONLY ) != Input )
266*33828Sbostic 				cannotopen( optarg, "input" );
267*33828Sbostic 			swfile = optarg;
268*33828Sbostic 			break;
269*33828Sbostic 		case 'O':
270*33828Sbostic 			chkswfile( swfile, ans, Option );
271*33828Sbostic 			close( Output );
272*33828Sbostic 			if( open( optarg, O_WRONLY | O_CREAT | O_TRUNC, 0666 )
273*33828Sbostic 				!= Output)
274*33828Sbostic 				cannotopen( optarg, "output" );
275*33828Sbostic 			swfile = optarg;
276*33828Sbostic 			break;
277*33828Sbostic 		default:
278*33828Sbostic 			usage();
279*33828Sbostic 		}
280*33828Sbostic 	}
281*33828Sbostic 	if(!Option) {
282*33828Sbostic 		errmsg( EERROR, "Options must include one: -o, -i, -p.");
283*33828Sbostic 	}
284*33828Sbostic 
285*33828Sbostic 	if(Option == PASS) {
286*33828Sbostic 		if(Rename) {
287*33828Sbostic 			errmsg( EERROR, "Pass and Rename cannot be used together.");
288*33828Sbostic 		}
289*33828Sbostic 		if( Bufsize != BUFSIZE ) {
290*33828Sbostic 			fprintf( stderr, "`B' or `C' option is irrelevant with the '-p' option\n");
291*33828Sbostic 			Bufsize = BUFSIZE;
292*33828Sbostic 		}
293*33828Sbostic 
294*33828Sbostic 	}else  {
295*33828Sbostic 		Cp = Cbuf = (char *)zmalloc( EERROR, Bufsize);
296*33828Sbostic 	}
297*33828Sbostic 	argc -= optind;
298*33828Sbostic 	argv += optind;
299*33828Sbostic 
300*33828Sbostic 	switch(Option) {
301*33828Sbostic 	case OUT:
302*33828Sbostic 		if(argc != 0)
303*33828Sbostic 			usage();
304*33828Sbostic 		/* get filename, copy header and file out */
305*33828Sbostic 		while(getname()) {
306*33828Sbostic 			if( mklong(Hdr.h_filesize) == 0L) {
307*33828Sbostic 				if( Cflag )
308*33828Sbostic 					bwrite(Chdr,CHARS+Hdr.h_namesize);
309*33828Sbostic 				else
310*33828Sbostic 					bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
311*33828Sbostic 				if(Verbose)
312*33828Sbostic 					verbdot( stderr, Hdr.h_name);
313*33828Sbostic 				continue;
314*33828Sbostic 			}
315*33828Sbostic 			if((Ifile = open(Hdr.h_name, 0)) < 0) {
316*33828Sbostic 				fperr("<%s> ?\n", Hdr.h_name);
317*33828Sbostic 				continue;
318*33828Sbostic 			}
319*33828Sbostic 			if ( Cflag )
320*33828Sbostic 				bwrite(Chdr,CHARS+Hdr.h_namesize);
321*33828Sbostic 			else
322*33828Sbostic 				bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
323*33828Sbostic 			for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
324*33828Sbostic 				ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
325*33828Sbostic 				if(read(Ifile, Buf, ct) < 0) {
326*33828Sbostic 					fperr("Cannot read %s\n", Hdr.h_name);
327*33828Sbostic 					continue;
328*33828Sbostic 				}
329*33828Sbostic 				bwrite(Buf,ct);
330*33828Sbostic 			}
331*33828Sbostic 			close(Ifile);
332*33828Sbostic 			if(Acc_time)
333*33828Sbostic 				utime(Hdr.h_name, &Statb.st_atime);
334*33828Sbostic 			if(Verbose)
335*33828Sbostic 				verbdot( stderr, Hdr.h_name);
336*33828Sbostic 		}
337*33828Sbostic 
338*33828Sbostic 	/* copy trailer, after all files have been copied */
339*33828Sbostic 		strcpy(Hdr.h_name, "TRAILER!!!");
340*33828Sbostic 		Hdr.h_magic = MAGIC;
341*33828Sbostic 		MKSHORT(Hdr.h_filesize, 0L);
342*33828Sbostic 		Hdr.h_namesize = strlen("TRAILER!!!") + 1;
343*33828Sbostic 		if ( Cflag )  {
344*33828Sbostic 			bintochar(0L);
345*33828Sbostic 			bwrite(Chdr, CHARS+Hdr.h_namesize);
346*33828Sbostic 		}
347*33828Sbostic 		else
348*33828Sbostic 			bwrite(&Hdr, HDRSIZE+Hdr.h_namesize);
349*33828Sbostic 		bwrite(Cbuf, Bufsize);
350*33828Sbostic 		break;
351*33828Sbostic 
352*33828Sbostic 	case IN:
353*33828Sbostic 		if(argc > 0 ) {	/* save patterns, if any */
354*33828Sbostic 			Pattern = argv;
355*33828Sbostic 		}
356*33828Sbostic 		pwd();
357*33828Sbostic 		chkhdr();
358*33828Sbostic 		while(gethdr()) {
359*33828Sbostic 			if( (select = ckname(Hdr.h_name))  &&  !Toc )
360*33828Sbostic 				Ofile = openout(Hdr.h_name);
361*33828Sbostic 			else
362*33828Sbostic 				Ofile = 0;
363*33828Sbostic 			for(filesz=mklong(Hdr.h_filesize); filesz>0; filesz-= CPIOBSZ){
364*33828Sbostic 				ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
365*33828Sbostic 				bread(Buf, ct);
366*33828Sbostic 				if(Ofile) {
367*33828Sbostic 					if(Swap)
368*33828Sbostic 						swap(Buf,ct);
369*33828Sbostic 					if(write(Ofile, Buf, ct) < 0) {
370*33828Sbostic 					 fperr("Cannot write %s\n", Hdr.h_name);
371*33828Sbostic 					 continue;
372*33828Sbostic 					}
373*33828Sbostic 				}
374*33828Sbostic 			}
375*33828Sbostic 			if( Ofile ) {
376*33828Sbostic 				zclose( EERROR, Ofile );
377*33828Sbostic 				zchmod( EWARN, Hdr.h_name, Hdr.h_mode);
378*33828Sbostic 				set_time(Hdr.h_name, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
379*33828Sbostic 			}
380*33828Sbostic 			if(select) {
381*33828Sbostic 				if(Verbose)
382*33828Sbostic 					if(Toc)
383*33828Sbostic 						pentry(Hdr.h_name);
384*33828Sbostic 					else
385*33828Sbostic 						verbdot( stdout, Hdr.h_name);
386*33828Sbostic 				else if(Toc)
387*33828Sbostic 					puts(Hdr.h_name);
388*33828Sbostic 			}
389*33828Sbostic 		}
390*33828Sbostic 		break;
391*33828Sbostic 
392*33828Sbostic 	case PASS:		/* move files around */
393*33828Sbostic 		if(argc != 1)
394*33828Sbostic 			usage();
395*33828Sbostic 		if(access(argv[0], 2) == -1) {
396*33828Sbostic 			errmsg( EERROR, "cannot write in <%s>", argv[0]);
397*33828Sbostic 		}
398*33828Sbostic 		strcpy(Fullname, argv[0]);	/* destination directory */
399*33828Sbostic 		zstat( EERROR, Fullname, &Xstatb );
400*33828Sbostic 		if((Xstatb.st_mode&S_IFMT) != S_IFDIR)
401*33828Sbostic 			errmsg( EERROR, "<%s> not a directory.", Fullname );
402*33828Sbostic 		Dev = Xstatb.st_dev;
403*33828Sbostic 		if( Fullname[ strlen(Fullname) - 1 ] != '/' )
404*33828Sbostic 			strcat(Fullname, "/");
405*33828Sbostic 		fullp = Fullname + strlen(Fullname);
406*33828Sbostic 
407*33828Sbostic 		while(getname()) {
408*33828Sbostic 			if (A_directory && !Dir)
409*33828Sbostic 				fperr("Use `-d' option to copy <%s>\n",
410*33828Sbostic 					Hdr.h_name);
411*33828Sbostic 			if(!ckname(Hdr.h_name))
412*33828Sbostic 				continue;
413*33828Sbostic 			i = 0;
414*33828Sbostic 			while(Hdr.h_name[i] == '/')
415*33828Sbostic 				i++;
416*33828Sbostic 			strcpy(fullp, &(Hdr.h_name[i]));
417*33828Sbostic 
418*33828Sbostic 			if( PassLink  &&  !A_directory  &&  Dev == Statb.st_dev ) {
419*33828Sbostic 				if(link(Hdr.h_name, Fullname) < 0) {
420*33828Sbostic 					switch(errno) {
421*33828Sbostic 						case ENOENT:
422*33828Sbostic 							if(missdir(Fullname) != 0) {
423*33828Sbostic 								fprintf(stderr,
424*33828Sbostic 									"cpio: cannot create directory for <%s>: %s\n",
425*33828Sbostic 									Fullname, sys_errlist[errno]);
426*33828Sbostic 								continue;
427*33828Sbostic 							}
428*33828Sbostic 							break;
429*33828Sbostic 						case EEXIST:
430*33828Sbostic 							if(unlink(Fullname) < 0) {
431*33828Sbostic 								fprintf(stderr,
432*33828Sbostic 									"cpio: cannot unlink <%s>: %s\n",
433*33828Sbostic 									Fullname, sys_errlist[errno]);
434*33828Sbostic 								continue;
435*33828Sbostic 							}
436*33828Sbostic 							break;
437*33828Sbostic 						default:
438*33828Sbostic 							fprintf(stderr,
439*33828Sbostic 								"Cpio: cannot link <%s> to <%s>: %s\n",
440*33828Sbostic 								Hdr.h_name, Fullname, sys_errlist[errno]);
441*33828Sbostic 							continue;
442*33828Sbostic 						}
443*33828Sbostic 					if(link(Hdr.h_name, Fullname) < 0) {
444*33828Sbostic 						fprintf(stderr,
445*33828Sbostic 							"cpio: cannot link <%s> to <%s>: %s\n",
446*33828Sbostic 							Hdr.h_name, Fullname, sys_errlist[errno]);
447*33828Sbostic 						continue;
448*33828Sbostic 					}
449*33828Sbostic 				}
450*33828Sbostic 
451*33828Sbostic 				goto ckverbose;
452*33828Sbostic 			}
453*33828Sbostic 			if(!(Ofile = openout(Fullname)))
454*33828Sbostic 				continue;
455*33828Sbostic 			if((Ifile = zopen( EWARN, Hdr.h_name, 0)) < 0) {
456*33828Sbostic 				close(Ofile);
457*33828Sbostic 				continue;
458*33828Sbostic 			}
459*33828Sbostic 			filesz = Statb.st_size;
460*33828Sbostic 			for(; filesz > 0; filesz -= CPIOBSZ) {
461*33828Sbostic 				ct = filesz>CPIOBSZ? CPIOBSZ: filesz;
462*33828Sbostic 				if(read(Ifile, Buf, ct) < 0) {
463*33828Sbostic 					fperr("Cannot read %s\n", Hdr.h_name);
464*33828Sbostic 					break;
465*33828Sbostic 				}
466*33828Sbostic 				if(Ofile)
467*33828Sbostic 					if(write(Ofile, Buf, ct) < 0) {
468*33828Sbostic 					 fperr("Cannot write %s\n", Hdr.h_name);
469*33828Sbostic 					 break;
470*33828Sbostic 					}
471*33828Sbostic 					/* Removed u370 ifdef which caused cpio */
472*33828Sbostic 					/* to report blocks in terms of 4096 bytes. */
473*33828Sbostic 
474*33828Sbostic 				Blocks += ((ct + (BUFSIZE - 1)) / BUFSIZE);
475*33828Sbostic 			}
476*33828Sbostic 			close(Ifile);
477*33828Sbostic 			if(Acc_time)
478*33828Sbostic 				utime(Hdr.h_name, &Statb.st_atime);
479*33828Sbostic 			if(Ofile) {
480*33828Sbostic 				close(Ofile);
481*33828Sbostic 				zchmod( EWARN, Fullname, Hdr.h_mode);
482*33828Sbostic 				set_time(Fullname, Statb.st_atime, mklong(Hdr.h_mtime));
483*33828Sbostic ckverbose:
484*33828Sbostic 				if(Verbose)
485*33828Sbostic 					verbdot( stdout, Fullname );
486*33828Sbostic 			}
487*33828Sbostic 		}
488*33828Sbostic 	}
489*33828Sbostic 	/* print number of blocks actually copied */
490*33828Sbostic 	Blocks += ((sBlocks + (BUFSIZE - 1)) / BUFSIZE);
491*33828Sbostic 	fperr("%ld blocks\n", Blocks * (Bufsize>>9));
492*33828Sbostic 	exit(0);
493*33828Sbostic }
494*33828Sbostic 
495*33828Sbostic static
496*33828Sbostic usage()
497*33828Sbostic {
498*33828Sbostic 	errusage("%s\n\t%s %s\n\t%s %s\n\t%s %s\n\t%s %s\n",
499*33828Sbostic 		    "-o[acvB] <name-list >collection",
500*33828Sbostic 	Err.source, "-o[acvB] -Ocollection <name-list",
501*33828Sbostic 	Err.source, "-i[cdmrstuvfB6] [pattern ...] <collection",
502*33828Sbostic 	Err.source, "-i[cdmrstuvfB6] -Icollection [pattern ...]",
503*33828Sbostic 	Err.source, "-p[adlmruv] directory <name-list");
504*33828Sbostic }
505*33828Sbostic 
506*33828Sbostic static
507*33828Sbostic chkswfile( sp, c, option )
508*33828Sbostic char	*sp;
509*33828Sbostic char	c;
510*33828Sbostic short	option;
511*33828Sbostic {
512*33828Sbostic 	if( !option )
513*33828Sbostic 		errmsg( EERROR, "-%c must be specified before -%c option.",
514*33828Sbostic 			c == 'I' ? 'i' : 'o', c );
515*33828Sbostic 	if( (c == 'I'  &&  option != IN)  ||  (c == 'O'  &&  option != OUT) )
516*33828Sbostic 		errmsg( EERROR, "-%c option not permitted with -%c option.", c,
517*33828Sbostic 			option );
518*33828Sbostic 	if( !sp )
519*33828Sbostic 		return;
520*33828Sbostic 	errmsg( EERROR, "No more than one -I or -O flag permitted.");
521*33828Sbostic }
522*33828Sbostic 
523*33828Sbostic static
524*33828Sbostic cannotopen( sp, mode )
525*33828Sbostic char	*sp, *mode;
526*33828Sbostic {
527*33828Sbostic 	errmsg( EERROR, "Cannot open <%s> for %s.", sp, mode );
528*33828Sbostic }
529*33828Sbostic 
530*33828Sbostic static
531*33828Sbostic getname()		/* get file name, get info for header */
532*33828Sbostic {
533*33828Sbostic 	register char *namep = Name;
534*33828Sbostic 	register ushort ftype;
535*33828Sbostic 	long tlong;
536*33828Sbostic 
537*33828Sbostic 	for(;;) {
538*33828Sbostic 		if(gets(namep) == NULL)
539*33828Sbostic 			return 0;
540*33828Sbostic 		while(*namep == '.' && namep[1] == '/') {
541*33828Sbostic 			namep++;
542*33828Sbostic 			while(*namep == '/') namep++;
543*33828Sbostic 		}
544*33828Sbostic 		strcpy(Hdr.h_name, namep);
545*33828Sbostic 		if(zstat( EWARN, namep, &Statb) < 0) {
546*33828Sbostic 			continue;
547*33828Sbostic 		}
548*33828Sbostic 		ftype = Statb.st_mode & Filetype;
549*33828Sbostic 		A_directory = (ftype == S_IFDIR);
550*33828Sbostic 		A_special = (ftype == S_IFBLK)
551*33828Sbostic 			|| (ftype == S_IFCHR)
552*33828Sbostic 			|| (ftype == S_IFIFO);
553*33828Sbostic 		Hdr.h_magic = MAGIC;
554*33828Sbostic 		Hdr.h_namesize = strlen(Hdr.h_name) + 1;
555*33828Sbostic 		Hdr.h_uid = Statb.st_uid;
556*33828Sbostic 		Hdr.h_gid = Statb.st_gid;
557*33828Sbostic 		Hdr.h_dev = Statb.st_dev;
558*33828Sbostic 		Hdr.h_ino = Statb.st_ino;
559*33828Sbostic 		Hdr.h_mode = Statb.st_mode;
560*33828Sbostic 		MKSHORT(Hdr.h_mtime, Statb.st_mtime);
561*33828Sbostic 		Hdr.h_nlink = Statb.st_nlink;
562*33828Sbostic 		tlong = (Hdr.h_mode&S_IFMT) == S_IFREG? Statb.st_size: 0L;
563*33828Sbostic 		MKSHORT(Hdr.h_filesize, tlong);
564*33828Sbostic 		Hdr.h_rdev = Statb.st_rdev;
565*33828Sbostic 		if( Cflag )
566*33828Sbostic 			bintochar(tlong);
567*33828Sbostic 		return 1;
568*33828Sbostic 	}
569*33828Sbostic }
570*33828Sbostic 
571*33828Sbostic static
572*33828Sbostic bintochar(t)		/* ASCII header write */
573*33828Sbostic long t;
574*33828Sbostic {
575*33828Sbostic 	sprintf(Chdr,"%.6o%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.6ho%.11lo%.6ho%.11lo%s",
576*33828Sbostic 		MAGIC, MK_USHORT(Statb.st_dev), MK_USHORT(Statb.st_ino), Statb.st_mode, Statb.st_uid,
577*33828Sbostic 		Statb.st_gid, Statb.st_nlink, MK_USHORT(Statb.st_rdev),
578*33828Sbostic 		Statb.st_mtime, (short)strlen(Hdr.h_name)+1, t, Hdr.h_name);
579*33828Sbostic }
580*33828Sbostic 
581*33828Sbostic static
582*33828Sbostic chartobin()		/* ASCII header read */
583*33828Sbostic {
584*33828Sbostic 	sscanf(Chdr, "%6ho%6ho%6ho%6ho%6ho%6ho%6ho%6ho%11lo%6ho%11lo",
585*33828Sbostic 		&Hdr.h_magic, &Hdr.h_dev, &Hdr.h_ino, &Hdr.h_mode, &Hdr.h_uid,
586*33828Sbostic 		&Hdr.h_gid, &Hdr.h_nlink, &Hdr.h_rdev, &Longtime,
587*33828Sbostic 		&Hdr.h_namesize, &Longfile);
588*33828Sbostic 	MKSHORT(Hdr.h_filesize, Longfile);
589*33828Sbostic 	MKSHORT(Hdr.h_mtime, Longtime);
590*33828Sbostic }
591*33828Sbostic 
592*33828Sbostic 
593*33828Sbostic /*	Check the header for the magic number.  Switch modes automatically to
594*33828Sbostic 	match the type of header found.
595*33828Sbostic */
596*33828Sbostic static
597*33828Sbostic chkhdr()
598*33828Sbostic {
599*33828Sbostic 	bread(Chdr, CHARS);
600*33828Sbostic 	chartobin();
601*33828Sbostic 	if( Hdr.h_magic == MAGIC )
602*33828Sbostic 		Cflag = 1;
603*33828Sbostic 	else {
604*33828Sbostic 		breread(&Hdr.h_magic, sizeof Hdr.h_magic);
605*33828Sbostic 		if( Hdr.h_magic == MAGIC )
606*33828Sbostic 			Cflag = 0;
607*33828Sbostic 		else
608*33828Sbostic 			errmsg( EERROR,
609*33828Sbostic 				"This is not a cpio file.  Bad magic number.");
610*33828Sbostic 	}
611*33828Sbostic 	breread(Chdr, 0);
612*33828Sbostic }
613*33828Sbostic 
614*33828Sbostic 
615*33828Sbostic static
616*33828Sbostic gethdr()		/* get file headers */
617*33828Sbostic {
618*33828Sbostic 	register ushort ftype;
619*33828Sbostic 
620*33828Sbostic 	if (Cflag)  {
621*33828Sbostic 		bread(Chdr, CHARS);
622*33828Sbostic 		chartobin();
623*33828Sbostic 	}
624*33828Sbostic 	else
625*33828Sbostic 		bread(&Hdr, HDRSIZE);
626*33828Sbostic 
627*33828Sbostic 	if( Hdr.h_magic != MAGIC ) {
628*33828Sbostic 		errmsg( EERROR, "Out of phase--get help.");
629*33828Sbostic 	}
630*33828Sbostic 	bread(Hdr.h_name, Hdr.h_namesize);
631*33828Sbostic 	if(EQ(Hdr.h_name, "TRAILER!!!"))
632*33828Sbostic 		return 0;
633*33828Sbostic 	ftype = Hdr.h_mode & Filetype;
634*33828Sbostic 	A_directory = (ftype == S_IFDIR);
635*33828Sbostic 	A_special = (ftype == S_IFBLK)
636*33828Sbostic 		||  (ftype == S_IFCHR)
637*33828Sbostic 		||  (ftype == S_IFIFO);
638*33828Sbostic 	return 1;
639*33828Sbostic }
640*33828Sbostic 
641*33828Sbostic static
642*33828Sbostic ckname(namep)	/* check filenames with patterns given on cmd line */
643*33828Sbostic register char *namep;
644*33828Sbostic {
645*33828Sbostic 	char	buf[sizeof Hdr.h_name];
646*33828Sbostic 
647*33828Sbostic 	if(fflag ^ !nmatch(namep, Pattern)) {
648*33828Sbostic 		return 0;
649*33828Sbostic 	}
650*33828Sbostic 	if(Rename && !A_directory) {	/* rename interactively */
651*33828Sbostic 		fprintf(Wtty, "Rename <%s>\n", namep);
652*33828Sbostic 		fflush(Wtty);
653*33828Sbostic 		fgets(buf, sizeof buf, Rtty);
654*33828Sbostic 		if(feof(Rtty))
655*33828Sbostic 			exit(2);
656*33828Sbostic 		buf[strlen(buf) - 1] = '\0';
657*33828Sbostic 		if(EQ(buf, "")) {
658*33828Sbostic 			strcpy(namep,buf);
659*33828Sbostic 			printf("Skipped\n");
660*33828Sbostic 			return 0;
661*33828Sbostic 		}
662*33828Sbostic 		else if(EQ(buf, "."))
663*33828Sbostic 			printf("Same name\n");
664*33828Sbostic 		else
665*33828Sbostic 			strcpy(namep,buf);
666*33828Sbostic 	}
667*33828Sbostic 	return  1;
668*33828Sbostic }
669*33828Sbostic 
670*33828Sbostic static
671*33828Sbostic openout(namep)	/* open files for writing, set all necessary info */
672*33828Sbostic register char *namep;
673*33828Sbostic {
674*33828Sbostic 	register f;
675*33828Sbostic 	register char *np;
676*33828Sbostic 	int ans;
677*33828Sbostic 
678*33828Sbostic 	if(!strncmp(namep, "./", 2))
679*33828Sbostic 		namep += 2;
680*33828Sbostic 	np = namep;
681*33828Sbostic 	if(A_directory) {
682*33828Sbostic 		if( !Dir  ||  Rename  ||  EQ(namep, ".")  ||  EQ(namep, "..") )
683*33828Sbostic 			/* do not consider . or .. files */
684*33828Sbostic 			return 0;
685*33828Sbostic 		if(stat(namep, &Xstatb) == -1) {
686*33828Sbostic 
687*33828Sbostic /* try creating (only twice) */
688*33828Sbostic 			ans = 0;
689*33828Sbostic 			do {
690*33828Sbostic 				if(makdir(namep) != 0) {
691*33828Sbostic 					ans += 1;
692*33828Sbostic 				}else {
693*33828Sbostic 					ans = 0;
694*33828Sbostic 					break;
695*33828Sbostic 				}
696*33828Sbostic 			}while(ans < 2 && missdir(namep) == 0);
697*33828Sbostic 			if(ans == 1) {
698*33828Sbostic 				fperrno("Cannot create directory for <%s>",
699*33828Sbostic 					namep);
700*33828Sbostic 				return(0);
701*33828Sbostic 			}else if(ans == 2) {
702*33828Sbostic 				fperrno("Cannot create directory <%s>", namep);
703*33828Sbostic 				return(0);
704*33828Sbostic 			}
705*33828Sbostic 		}
706*33828Sbostic 
707*33828Sbostic ret:
708*33828Sbostic 		zchmod( EWARN, namep, Hdr.h_mode);
709*33828Sbostic 		if(Uid == 0)
710*33828Sbostic 			zchown( EWARN, namep, Hdr.h_uid, Hdr.h_gid);
711*33828Sbostic 		set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
712*33828Sbostic 		return 0;
713*33828Sbostic 	}
714*33828Sbostic 	if(Hdr.h_nlink > 1)
715*33828Sbostic 		if(!postml(namep, np))
716*33828Sbostic 			return 0;
717*33828Sbostic 	if(stat(namep, &Xstatb) == 0) {
718*33828Sbostic 		if(Uncond && !((!(Xstatb.st_mode & S_IWRITE) || A_special) && (Uid != 0))) {
719*33828Sbostic 			if(unlink(namep) < 0) {
720*33828Sbostic 				fperrno("cannot unlink current <%s>", namep);
721*33828Sbostic 			}
722*33828Sbostic 		}
723*33828Sbostic 		if(!Uncond && (mklong(Hdr.h_mtime) <= Xstatb.st_mtime)) {
724*33828Sbostic 		/* There's a newer or same aged version of file on destination */
725*33828Sbostic 			fperr("current <%s> newer or same age\n", np);
726*33828Sbostic 			return 0;
727*33828Sbostic 		}
728*33828Sbostic 	}
729*33828Sbostic 	if( Option == PASS
730*33828Sbostic 		&& Hdr.h_ino == Xstatb.st_ino
731*33828Sbostic 		&& Hdr.h_dev == Xstatb.st_dev) {
732*33828Sbostic 		errmsg( EERROR, "Attempt to pass file to self!");
733*33828Sbostic 	}
734*33828Sbostic 	if(A_special) {
735*33828Sbostic 		if((Hdr.h_mode & Filetype) == S_IFIFO)
736*33828Sbostic 			Hdr.h_rdev = 0;
737*33828Sbostic 
738*33828Sbostic /* try creating (only twice) */
739*33828Sbostic 		ans = 0;
740*33828Sbostic 		do {
741*33828Sbostic 			if(mknod(namep, Hdr.h_mode, Hdr.h_rdev) < 0) {
742*33828Sbostic 				ans += 1;
743*33828Sbostic 			}else {
744*33828Sbostic 				ans = 0;
745*33828Sbostic 				break;
746*33828Sbostic 			}
747*33828Sbostic 		}while(ans < 2 && missdir(np) == 0);
748*33828Sbostic 		if(ans == 1) {
749*33828Sbostic 			fperrno("Cannot create directory for <%s>", namep);
750*33828Sbostic 			return(0);
751*33828Sbostic 		}else if(ans == 2) {
752*33828Sbostic 			fperrno("Cannot mknod <%s>", namep);
753*33828Sbostic 			return(0);
754*33828Sbostic 		}
755*33828Sbostic 
756*33828Sbostic 		goto ret;
757*33828Sbostic 	}
758*33828Sbostic 
759*33828Sbostic /* try creating (only twice) */
760*33828Sbostic 	ans = 0;
761*33828Sbostic 	do {
762*33828Sbostic 		if((f = creat(namep, Hdr.h_mode)) < 0) {
763*33828Sbostic 			ans += 1;
764*33828Sbostic 		}else {
765*33828Sbostic 			ans = 0;
766*33828Sbostic 			break;
767*33828Sbostic 		}
768*33828Sbostic 	}while(ans < 2 && missdir(np) == 0);
769*33828Sbostic 	if(ans == 1) {
770*33828Sbostic 		fperrno("Cannot create directory for <%s>", namep);
771*33828Sbostic 		return(0);
772*33828Sbostic 	}else if(ans == 2) {
773*33828Sbostic 		fperrno("Cannot create <%s>", namep);
774*33828Sbostic 		return(0);
775*33828Sbostic 	}
776*33828Sbostic 
777*33828Sbostic 	if(Uid == 0)
778*33828Sbostic 		zchown( EWARN, namep, Hdr.h_uid, Hdr.h_gid);
779*33828Sbostic 	return f;
780*33828Sbostic }
781*33828Sbostic 
782*33828Sbostic 
783*33828Sbostic /*	Shared by bread() and breread()
784*33828Sbostic */
785*33828Sbostic static int	nleft = 0;	/* unread chars left in Cbuf */
786*33828Sbostic static char	*ip;		/* pointer to next char to be read from Cbuf */
787*33828Sbostic 
788*33828Sbostic /*	Reread the current buffer Cbuf.
789*33828Sbostic 	A character count, c, of 0 simply resets the pointer so next bread gets
790*33828Sbostic 	the same data again.
791*33828Sbostic */
792*33828Sbostic static
793*33828Sbostic breread(b, c)
794*33828Sbostic char	*b;
795*33828Sbostic int	c;
796*33828Sbostic {
797*33828Sbostic 	ip = Cbuf;
798*33828Sbostic 	if( nleft )
799*33828Sbostic 		nleft = Bufsize;
800*33828Sbostic 	if( !c )
801*33828Sbostic 		return;
802*33828Sbostic 	bread(b, c);
803*33828Sbostic }
804*33828Sbostic 
805*33828Sbostic static
806*33828Sbostic bread(b, c)
807*33828Sbostic register char	*b;
808*33828Sbostic register int	c;
809*33828Sbostic {
810*33828Sbostic 	register int	rv;
811*33828Sbostic 	register char	*p = ip;
812*33828Sbostic 
813*33828Sbostic 	if( !Cflag ) {
814*33828Sbostic 		/* round c up to an even number */
815*33828Sbostic 		c = (c+1)/2;
816*33828Sbostic 		c *= 2;
817*33828Sbostic 	}
818*33828Sbostic 	while( c )  {
819*33828Sbostic 		if( nleft == 0 ) {
820*33828Sbostic 			while( (rv = read(Input, Cbuf, Bufsize)) == 0 ) {
821*33828Sbostic 				Input = chgreel(0, Input, rv);
822*33828Sbostic 			}
823*33828Sbostic 			if( rv == Bufsize ) {
824*33828Sbostic 				nleft = Bufsize;
825*33828Sbostic 				p = Cbuf;
826*33828Sbostic 				++Blocks;
827*33828Sbostic 			}
828*33828Sbostic 			else if( rv == -1 )
829*33828Sbostic 				errmsg( EERROR,
830*33828Sbostic 					"Read() in bread() failed\n");
831*33828Sbostic 			else if( rv < Bufsize ) {	/* short read */
832*33828Sbostic 				smemcpy( &Cbuf[ Bufsize - rv ], Cbuf, rv );
833*33828Sbostic 				nleft = rv;
834*33828Sbostic 				p = &Cbuf[ Bufsize - rv ];
835*33828Sbostic 				sBlocks += rv;
836*33828Sbostic 			}
837*33828Sbostic 			else
838*33828Sbostic 				errmsg( EHALT,
839*33828Sbostic 					"Impossible return from read(), %d\n",
840*33828Sbostic 					rv );
841*33828Sbostic 		}
842*33828Sbostic 		if( nleft <= c ) {
843*33828Sbostic 			memcpy( b, p, nleft );
844*33828Sbostic 			c -= nleft;
845*33828Sbostic 			b += nleft;
846*33828Sbostic 			p += nleft;
847*33828Sbostic 			nleft = 0;
848*33828Sbostic 		}
849*33828Sbostic 		else {
850*33828Sbostic 			memcpy( b, p, c );
851*33828Sbostic 			nleft -= c;
852*33828Sbostic 			b += c;
853*33828Sbostic 			p += c;
854*33828Sbostic 			c = 0;
855*33828Sbostic 		}
856*33828Sbostic 	}
857*33828Sbostic 	ip = p;
858*33828Sbostic }
859*33828Sbostic 
860*33828Sbostic 
861*33828Sbostic static
862*33828Sbostic bwrite(rp, c)
863*33828Sbostic register char *rp;
864*33828Sbostic register c;
865*33828Sbostic {
866*33828Sbostic 	register char	*cp = Cp;
867*33828Sbostic 	static unsigned	Ccnt = 0;
868*33828Sbostic 	register unsigned Cleft;
869*33828Sbostic 	register int	rv;
870*33828Sbostic 
871*33828Sbostic 	if( !Cflag ) {
872*33828Sbostic 		/* round c up to an even number */
873*33828Sbostic 		c = (c+1)/2;
874*33828Sbostic 		c *= 2;
875*33828Sbostic 	}
876*33828Sbostic 	while( c )  {
877*33828Sbostic 		if( (Cleft = Bufsize - Ccnt) <= c ) {
878*33828Sbostic 			memcpy( cp, rp, Cleft );
879*33828Sbostic 			rv = write(Output, Cbuf, Bufsize);
880*33828Sbostic 			if( rv == 0  ||  ( rv == -1  &&  errno == ENXIO ) ) {
881*33828Sbostic 				rv = eomchgreel();
882*33828Sbostic 			}
883*33828Sbostic 			if( rv == Bufsize ) {
884*33828Sbostic 				Ccnt = 0;
885*33828Sbostic 				cp = Cbuf;
886*33828Sbostic 			}
887*33828Sbostic 			else if( rv == -1 )
888*33828Sbostic 				errmsg( EERROR,
889*33828Sbostic 					"Write() in bwrite() failed\n");
890*33828Sbostic 			else if( rv < Bufsize ) {
891*33828Sbostic 				Output = chgreel(1, Output, 0);
892*33828Sbostic 				smemcpy( Cbuf, &Cbuf[ Bufsize - rv ], rv );
893*33828Sbostic 				Ccnt = Bufsize - rv;
894*33828Sbostic 				cp = &Cbuf[ rv ];
895*33828Sbostic 			}
896*33828Sbostic 			else
897*33828Sbostic 				errmsg( EHALT,
898*33828Sbostic 					"Impossible return from read(), %d\n",
899*33828Sbostic 					rv );
900*33828Sbostic 			++Blocks;
901*33828Sbostic 			rp += Cleft;
902*33828Sbostic 			c -= Cleft;
903*33828Sbostic 		}
904*33828Sbostic 		else {
905*33828Sbostic 			memcpy( cp, rp, c );
906*33828Sbostic 			Ccnt += c;
907*33828Sbostic 			cp += c;
908*33828Sbostic 			rp += c;
909*33828Sbostic 			c = 0;
910*33828Sbostic 		}
911*33828Sbostic 	}
912*33828Sbostic 	Cp = cp;
913*33828Sbostic }
914*33828Sbostic 
915*33828Sbostic 
916*33828Sbostic static int	reelcount = 1;	/* used below and in chgreel() */
917*33828Sbostic 
918*33828Sbostic /*	Change reel due to reaching end-of-media.
919*33828Sbostic 	Keep trying to get a successful write before considering the
920*33828Sbostic 	change-of-reel as successful.
921*33828Sbostic */
922*33828Sbostic static
923*33828Sbostic int
924*33828Sbostic eomchgreel()
925*33828Sbostic {
926*33828Sbostic 	int	rv;
927*33828Sbostic 
928*33828Sbostic 	while( 1 ) {
929*33828Sbostic 		Output = chgreel(1, Output, 0);
930*33828Sbostic 		rv = write(Output, Cbuf, Bufsize);
931*33828Sbostic 		if( rv == Bufsize )
932*33828Sbostic 			return  rv;
933*33828Sbostic 		fperr( "Unable to write this medium.  Try again.\n" );
934*33828Sbostic 		reelcount--;
935*33828Sbostic 	}
936*33828Sbostic 	/*NOTREACHED*/
937*33828Sbostic }
938*33828Sbostic 
939*33828Sbostic 
940*33828Sbostic static
941*33828Sbostic postml(namep, np)		/* linking funtion:  Postml() is called after */
942*33828Sbostic register char *namep, *np;	/* namep is created.  Postml() checks to see  */
943*33828Sbostic {				/* if namep should be linked to np.  If so,   */
944*33828Sbostic 				/* postml() removes the independent instance  */
945*33828Sbostic 	register i;		/* of namep and links namep to np.	      */
946*33828Sbostic 	static struct ml {
947*33828Sbostic 		short	m_dev;
948*33828Sbostic 		ushort	m_ino;
949*33828Sbostic 		char	m_name[2];
950*33828Sbostic 	} **ml = 0;
951*33828Sbostic 	register struct ml	*mlp;
952*33828Sbostic 	static unsigned	mlsize = 0;
953*33828Sbostic 	static unsigned	mlinks = 0;
954*33828Sbostic 	char		*lnamep;
955*33828Sbostic 	int		ans;
956*33828Sbostic 
957*33828Sbostic 	if( !ml ) {
958*33828Sbostic 		mlsize = LINKS;
959*33828Sbostic 		ml = (struct ml **) zmalloc( EERROR, mlsize * sizeof(struct ml));
960*33828Sbostic 	}
961*33828Sbostic 	else if( mlinks == mlsize ) {
962*33828Sbostic 		mlsize += LINKS;
963*33828Sbostic 		ml = (struct ml **) zrealloc( EERROR, ml, mlsize * sizeof(struct ml));
964*33828Sbostic 	}
965*33828Sbostic 	for(i = 0; i < mlinks; ++i) {
966*33828Sbostic 		mlp = ml[i];
967*33828Sbostic 		if(mlp->m_ino==Hdr.h_ino  &&  mlp->m_dev==Hdr.h_dev) {
968*33828Sbostic 			if(Verbose == 1)
969*33828Sbostic 				fprintf(stderr, "%s linked to %s\n", mlp->m_name, np);
970*33828Sbostic 			if(Verbose)
971*33828Sbostic 				verbdot(stdout, np);
972*33828Sbostic 			unlink(namep);
973*33828Sbostic 			if(Option == IN && *(mlp->m_name) != '/') {
974*33828Sbostic 				Fullname[Pathend] = '\0';
975*33828Sbostic 				strcat(Fullname, mlp->m_name);
976*33828Sbostic 				lnamep = Fullname;
977*33828Sbostic 			}
978*33828Sbostic 			lnamep = mlp->m_name;
979*33828Sbostic 
980*33828Sbostic /* try linking (only twice) */
981*33828Sbostic 			ans = 0;
982*33828Sbostic 			do {
983*33828Sbostic 				if(link(lnamep, namep) < 0) {
984*33828Sbostic 					ans += 1;
985*33828Sbostic 				}else {
986*33828Sbostic 					ans = 0;
987*33828Sbostic 					break;
988*33828Sbostic 				}
989*33828Sbostic 			}while(ans < 2 && missdir(np) == 0);
990*33828Sbostic 			if(ans == 1) {
991*33828Sbostic 				fperrno("Cannot create directory for <%s>", np);
992*33828Sbostic 				return(0);
993*33828Sbostic 			}else if(ans == 2) {
994*33828Sbostic 				fperrno("Cannot link <%s> & <%s>", lnamep, np);
995*33828Sbostic 				return(0);
996*33828Sbostic 			}
997*33828Sbostic 
998*33828Sbostic 			set_time(namep, mklong(Hdr.h_mtime), mklong(Hdr.h_mtime));
999*33828Sbostic 			return 0;
1000*33828Sbostic 		}
1001*33828Sbostic 	}
1002*33828Sbostic 	if( !(ml[mlinks] = (struct ml *)zmalloc( EWARN, strlen(np) + 2 + sizeof(struct ml)))) {
1003*33828Sbostic 		static int first=1;
1004*33828Sbostic 
1005*33828Sbostic 		if(first)
1006*33828Sbostic 			fperr("No memory for links (%d)\n", mlinks);
1007*33828Sbostic 		first = 0;
1008*33828Sbostic 		return 1;
1009*33828Sbostic 	}
1010*33828Sbostic 	ml[mlinks]->m_dev = Hdr.h_dev;
1011*33828Sbostic 	ml[mlinks]->m_ino = Hdr.h_ino;
1012*33828Sbostic 	strcpy(ml[mlinks]->m_name, np);
1013*33828Sbostic 	++mlinks;
1014*33828Sbostic 	return 1;
1015*33828Sbostic }
1016*33828Sbostic 
1017*33828Sbostic static
1018*33828Sbostic pentry(namep)		/* print verbose table of contents */
1019*33828Sbostic register char *namep;
1020*33828Sbostic {
1021*33828Sbostic 
1022*33828Sbostic 	static short lastid = -1;
1023*33828Sbostic #include <pwd.h>
1024*33828Sbostic 	static struct passwd *pw;
1025*33828Sbostic 	struct passwd *getpwuid();
1026*33828Sbostic 	static char tbuf[32];
1027*33828Sbostic 	char *ctime();
1028*33828Sbostic 
1029*33828Sbostic 	printf("%-7o", MK_USHORT(Hdr.h_mode));
1030*33828Sbostic 	if(lastid == Hdr.h_uid)
1031*33828Sbostic 		printf("%-6s", pw->pw_name);
1032*33828Sbostic 	else {
1033*33828Sbostic 		setpwent();
1034*33828Sbostic 		if(pw = getpwuid((int)Hdr.h_uid)) {
1035*33828Sbostic 			printf("%-6s", pw->pw_name);
1036*33828Sbostic 			lastid = Hdr.h_uid;
1037*33828Sbostic 		} else {
1038*33828Sbostic 			printf("%-6d", Hdr.h_uid);
1039*33828Sbostic 			lastid = -1;
1040*33828Sbostic 		}
1041*33828Sbostic 	}
1042*33828Sbostic 	printf("%7ld ", mklong(Hdr.h_filesize));
1043*33828Sbostic 	U.l = mklong(Hdr.h_mtime);
1044*33828Sbostic 	strcpy(tbuf, ctime((long *)&U.l));
1045*33828Sbostic 	tbuf[24] = '\0';
1046*33828Sbostic 	printf(" %s  %s\n", &tbuf[4], namep);
1047*33828Sbostic }
1048*33828Sbostic 
1049*33828Sbostic 		/* pattern matching functions */
1050*33828Sbostic static
1051*33828Sbostic nmatch(s, pat)
1052*33828Sbostic char *s, **pat;
1053*33828Sbostic {
1054*33828Sbostic 	if( !pat )
1055*33828Sbostic 		return 1;
1056*33828Sbostic 	while(*pat) {
1057*33828Sbostic 		if((**pat == '!' && !gmatch(s, *pat+1))
1058*33828Sbostic 		|| gmatch(s, *pat))
1059*33828Sbostic 			return 1;
1060*33828Sbostic 		++pat;
1061*33828Sbostic 	}
1062*33828Sbostic 	return 0;
1063*33828Sbostic }
1064*33828Sbostic 
1065*33828Sbostic 
1066*33828Sbostic static
1067*33828Sbostic gmatch(s, p)
1068*33828Sbostic register char *s, *p;
1069*33828Sbostic {
1070*33828Sbostic 	register int c;
1071*33828Sbostic 	register cc, ok, lc, scc;
1072*33828Sbostic 
1073*33828Sbostic 	scc = *s;
1074*33828Sbostic 	lc = 077777;
1075*33828Sbostic 	switch (c = *p) {
1076*33828Sbostic 
1077*33828Sbostic 	case '[':
1078*33828Sbostic 		ok = 0;
1079*33828Sbostic 		while (cc = *++p) {
1080*33828Sbostic 			switch (cc) {
1081*33828Sbostic 
1082*33828Sbostic 			case ']':
1083*33828Sbostic 				if (ok)
1084*33828Sbostic 					return(gmatch(++s, ++p));
1085*33828Sbostic 				else
1086*33828Sbostic 					return(0);
1087*33828Sbostic 
1088*33828Sbostic 			case '-':
1089*33828Sbostic 				ok |= ((lc <= scc) && (scc <= (cc=p[1])));
1090*33828Sbostic 			}
1091*33828Sbostic 			if (scc==(lc=cc)) ok++;
1092*33828Sbostic 		}
1093*33828Sbostic 		return(0);
1094*33828Sbostic 
1095*33828Sbostic 	case '?':
1096*33828Sbostic 	caseq:
1097*33828Sbostic 		if(scc) return(gmatch(++s, ++p));
1098*33828Sbostic 		return(0);
1099*33828Sbostic 	case '*':
1100*33828Sbostic 		return(umatch(s, ++p));
1101*33828Sbostic 	case 0:
1102*33828Sbostic 		return(!scc);
1103*33828Sbostic 	}
1104*33828Sbostic 	if (c==scc) goto caseq;
1105*33828Sbostic 	return(0);
1106*33828Sbostic }
1107*33828Sbostic 
1108*33828Sbostic 
1109*33828Sbostic 
1110*33828Sbostic static
1111*33828Sbostic umatch(s, p)
1112*33828Sbostic register char *s, *p;
1113*33828Sbostic {
1114*33828Sbostic 	if(*p==0) return(1);
1115*33828Sbostic 	while(*s)
1116*33828Sbostic 		if (gmatch(s++,p)) return(1);
1117*33828Sbostic 	return(0);
1118*33828Sbostic }
1119*33828Sbostic 
1120*33828Sbostic 
1121*33828Sbostic 
1122*33828Sbostic static
1123*33828Sbostic makdir(namep)		/* make needed directories */
1124*33828Sbostic register char *namep;
1125*33828Sbostic {
1126*33828Sbostic 	static status;
1127*33828Sbostic 	register pid;
1128*33828Sbostic 
1129*33828Sbostic 	pid = fork();
1130*33828Sbostic 	if (pid == 0) {			/* pid == 0 implies child process */
1131*33828Sbostic 		close(2);
1132*33828Sbostic 		execl("/bin/mkdir", "mkdir", namep, 0);
1133*33828Sbostic 		exit(2);
1134*33828Sbostic 	}
1135*33828Sbostic 	if (pid == -1) {		/* pid != 0 implies parent process */
1136*33828Sbostic 		fprintf(stderr,"Cannot fork, try again\n");
1137*33828Sbostic 		exit(2);
1138*33828Sbostic 	}
1139*33828Sbostic 	while(wait(&status) != pid);
1140*33828Sbostic 
1141*33828Sbostic 	return ((status>>8) & 0377)? 1: 0;
1142*33828Sbostic }
1143*33828Sbostic 
1144*33828Sbostic 
1145*33828Sbostic 
1146*33828Sbostic static
1147*33828Sbostic swap(buf, ct)		/* swap halfwords, bytes or both */
1148*33828Sbostic register ct;
1149*33828Sbostic register char *buf;
1150*33828Sbostic {
1151*33828Sbostic 	register char c;
1152*33828Sbostic 	register union swp { long	longw; short	shortv[2]; char charv[4]; } *pbuf;
1153*33828Sbostic 	int savect, n, i;
1154*33828Sbostic 	char *savebuf;
1155*33828Sbostic 	short cc;
1156*33828Sbostic 
1157*33828Sbostic 	savect = ct;	savebuf = buf;
1158*33828Sbostic 	if(byteswap || bothswap) {
1159*33828Sbostic 		if (ct % 2) buf[ct] = 0;
1160*33828Sbostic 		ct = (ct + 1) / 2;
1161*33828Sbostic 		while (ct--) {
1162*33828Sbostic 			c = *buf;
1163*33828Sbostic 			*buf = *(buf + 1);
1164*33828Sbostic 			*(buf + 1) = c;
1165*33828Sbostic 			buf += 2;
1166*33828Sbostic 		}
1167*33828Sbostic 		if (bothswap) {
1168*33828Sbostic 			ct = savect;
1169*33828Sbostic 			pbuf = (union swp *)savebuf;
1170*33828Sbostic 			if (n = ct % sizeof(union swp)) {
1171*33828Sbostic 				if(n % 2)
1172*33828Sbostic 					for(i = ct + 1; i <= ct + (sizeof(union swp) - n); i++) pbuf->charv[i] = 0;
1173*33828Sbostic 				else
1174*33828Sbostic 					for (i = ct; i < ct + (sizeof(union swp) - n); i++) pbuf->charv[i] = 0;
1175*33828Sbostic 			}
1176*33828Sbostic 			ct = (ct + (sizeof(union swp) -1)) / sizeof(union swp);
1177*33828Sbostic 			while(ct--) {
1178*33828Sbostic 				cc = pbuf->shortv[0];
1179*33828Sbostic 				pbuf->shortv[0] = pbuf->shortv[1];
1180*33828Sbostic 				pbuf->shortv[1] = cc;
1181*33828Sbostic 				++pbuf;
1182*33828Sbostic 			}
1183*33828Sbostic 		}
1184*33828Sbostic 	}
1185*33828Sbostic 	else if (halfswap) {
1186*33828Sbostic 		pbuf = (union swp *)buf;
1187*33828Sbostic 		if (n = ct % sizeof(union swp))
1188*33828Sbostic 			for (i = ct; i < ct + (sizeof(union swp) - n); i++) pbuf->charv[i] = 0;
1189*33828Sbostic 		ct = (ct + (sizeof(union swp) -1)) / sizeof(union swp);
1190*33828Sbostic 		while (ct--) {
1191*33828Sbostic 			cc = pbuf->shortv[0];
1192*33828Sbostic 			pbuf->shortv[0] = pbuf->shortv[1];
1193*33828Sbostic 			pbuf->shortv[1] = cc;
1194*33828Sbostic 			++pbuf;
1195*33828Sbostic 		}
1196*33828Sbostic 	}
1197*33828Sbostic }
1198*33828Sbostic 
1199*33828Sbostic 
1200*33828Sbostic static
1201*33828Sbostic set_time(namep, atime, mtime)	/* set access and modification times */
1202*33828Sbostic register char *namep;
1203*33828Sbostic time_t atime, mtime;
1204*33828Sbostic {
1205*33828Sbostic 	static time_t timevec[2];
1206*33828Sbostic 
1207*33828Sbostic 	if(!Mod_time)
1208*33828Sbostic 		return;
1209*33828Sbostic 	timevec[0] = atime;
1210*33828Sbostic 	timevec[1] = mtime;
1211*33828Sbostic 	utime(namep, timevec);
1212*33828Sbostic }
1213*33828Sbostic 
1214*33828Sbostic 
1215*33828Sbostic 
1216*33828Sbostic static
1217*33828Sbostic chgreel(x, fl, rv)
1218*33828Sbostic {
1219*33828Sbostic 	register f;
1220*33828Sbostic 	char str[BUFSIZ];
1221*33828Sbostic 	struct stat statb;
1222*33828Sbostic 
1223*33828Sbostic 	fstat(fl, &statb);
1224*33828Sbostic 	if((statb.st_mode&S_IFMT) != S_IFCHR) {
1225*33828Sbostic 		fperrno("Can't %s: ", x? "write output": "read input");
1226*33828Sbostic 		exit(2);
1227*33828Sbostic 	}
1228*33828Sbostic 	if( rv == 0  ||
1229*33828Sbostic 		( rv == -1  &&  ( errno == ENOSPC  ||  errno == ENXIO ) ) )
1230*33828Sbostic 		fperr( "\007Reached end of medium on %s.\n",
1231*33828Sbostic 			x? "output":"input" );
1232*33828Sbostic 	else {
1233*33828Sbostic 		fperrno( "\007Encountered an error on %s",
1234*33828Sbostic 			x? "output":"input" );
1235*33828Sbostic 		exit(2);
1236*33828Sbostic 	}
1237*33828Sbostic 	if( Rtty == NULL )
1238*33828Sbostic 		Rtty = zfopen( EERROR, ttyname, "r");
1239*33828Sbostic 	close(fl);
1240*33828Sbostic 	reelcount++;
1241*33828Sbostic again:
1242*33828Sbostic 	if( swfile ) {
1243*33828Sbostic 	    askagain:
1244*33828Sbostic 		fperr( eommsg, reelcount );
1245*33828Sbostic 		fgets(str, sizeof str, Rtty);
1246*33828Sbostic 		switch( *str ) {
1247*33828Sbostic 		case '\n':
1248*33828Sbostic 			strcpy( str, swfile );
1249*33828Sbostic 			break;
1250*33828Sbostic 		case 'q':
1251*33828Sbostic 			exit(2);
1252*33828Sbostic 		default:
1253*33828Sbostic 			goto askagain;
1254*33828Sbostic 		}
1255*33828Sbostic 	}
1256*33828Sbostic 	else {
1257*33828Sbostic 		fperr("If you want to go on, type device/file name when ready.\n");
1258*33828Sbostic 		fgets(str, sizeof str, Rtty);
1259*33828Sbostic 		str[strlen(str) - 1] = '\0';
1260*33828Sbostic 		if(!*str)
1261*33828Sbostic 			exit(2);
1262*33828Sbostic 	}
1263*33828Sbostic 	if((f = open(str, x? 1: 0)) < 0) {
1264*33828Sbostic 		fperr("That didn't work, cannot open \"%s\"\n", str);
1265*33828Sbostic 		if( errno )
1266*33828Sbostic 			perror("");
1267*33828Sbostic 		goto again;
1268*33828Sbostic 	}
1269*33828Sbostic 	return f;
1270*33828Sbostic }
1271*33828Sbostic 
1272*33828Sbostic 
1273*33828Sbostic 
1274*33828Sbostic static
1275*33828Sbostic missdir(namep)
1276*33828Sbostic register char *namep;
1277*33828Sbostic {
1278*33828Sbostic 	register char *np;
1279*33828Sbostic 	register ct = 2;
1280*33828Sbostic 
1281*33828Sbostic 	for(np = namep; *np; ++np)
1282*33828Sbostic 		if(*np == '/') {
1283*33828Sbostic 			if(np == namep) continue;	/* skip over 'root slash' */
1284*33828Sbostic 			*np = '\0';
1285*33828Sbostic 			if(stat(namep, &Xstatb) == -1) {
1286*33828Sbostic 				if(Dir) {
1287*33828Sbostic 					if((ct = makdir(namep)) != 0) {
1288*33828Sbostic 						*np = '/';
1289*33828Sbostic 						return(ct);
1290*33828Sbostic 					}
1291*33828Sbostic 				}else {
1292*33828Sbostic 					fperr("missing 'd' option\n");
1293*33828Sbostic 					return(-1);
1294*33828Sbostic 				}
1295*33828Sbostic 			}
1296*33828Sbostic 			*np = '/';
1297*33828Sbostic 		}
1298*33828Sbostic 	if (ct == 2) ct = 0;		/* the file already exists */
1299*33828Sbostic 	return ct;
1300*33828Sbostic }
1301*33828Sbostic 
1302*33828Sbostic 
1303*33828Sbostic 
1304*33828Sbostic static
1305*33828Sbostic pwd()		/* get working directory */
1306*33828Sbostic {
1307*33828Sbostic 	FILE *dir;
1308*33828Sbostic 
1309*33828Sbostic 	dir = popen("pwd", "r");
1310*33828Sbostic 	fgets(Fullname, sizeof Fullname, dir);
1311*33828Sbostic 	if(pclose(dir))
1312*33828Sbostic 		exit(2);
1313*33828Sbostic 	Pathend = strlen(Fullname);
1314*33828Sbostic 	Fullname[Pathend - 1] = '/';
1315*33828Sbostic }
1316*33828Sbostic 
1317*33828Sbostic 
1318*33828Sbostic static int	verbcount = 0;
1319*33828Sbostic static FILE	*verbout = 0;
1320*33828Sbostic /*
1321*33828Sbostic 	In -V verbose mode, print out a dot for each file processed.
1322*33828Sbostic */
1323*33828Sbostic static
1324*33828Sbostic verbdot( fp, cp )
1325*33828Sbostic FILE	*fp;
1326*33828Sbostic char	*cp;
1327*33828Sbostic {
1328*33828Sbostic 
1329*33828Sbostic 	if( !verbout )
1330*33828Sbostic 		verbout = fp;
1331*33828Sbostic 	if( Verbose == 2 ) {
1332*33828Sbostic 		fputc( '.', fp );
1333*33828Sbostic 		if( ++verbcount >= 50 ) {
1334*33828Sbostic 			/* start a new line of dots */
1335*33828Sbostic 			verbcount = 0;
1336*33828Sbostic 			fputc( '\n', fp );
1337*33828Sbostic 		}
1338*33828Sbostic 	}
1339*33828Sbostic 	else {
1340*33828Sbostic 		fputs( cp, fp );
1341*33828Sbostic 		fputc( '\n', fp );
1342*33828Sbostic 	}
1343*33828Sbostic }
1344*33828Sbostic 
1345*33828Sbostic 
1346*33828Sbostic /*
1347*33828Sbostic 	print message on the stderr
1348*33828Sbostic */
1349*33828Sbostic static
1350*33828Sbostic fperr( va_alist )
1351*33828Sbostic va_dcl
1352*33828Sbostic {
1353*33828Sbostic 	va_list	args;
1354*33828Sbostic 	char	*fmt;
1355*33828Sbostic 
1356*33828Sbostic 	resetverbcount();
1357*33828Sbostic 	va_start( args );
1358*33828Sbostic 	fmt = va_arg( args, char * );
1359*33828Sbostic 	vfprintf( stderr, fmt, args );
1360*33828Sbostic 	fflush( stderr );
1361*33828Sbostic }
1362*33828Sbostic 
1363*33828Sbostic /*
1364*33828Sbostic 	print message on the stderr followed by error number and meaning.
1365*33828Sbostic */
1366*33828Sbostic static
1367*33828Sbostic fperrno( va_alist )
1368*33828Sbostic va_dcl
1369*33828Sbostic {
1370*33828Sbostic 	va_list	args;
1371*33828Sbostic 	char	*fmt;
1372*33828Sbostic 
1373*33828Sbostic 	resetverbcount();
1374*33828Sbostic 	va_start( args );
1375*33828Sbostic 	fmt = va_arg( args, char * );
1376*33828Sbostic 	vfprintf( stderr, fmt, args );
1377*33828Sbostic 	fprintf( stderr, ", errno %d, ", errno );
1378*33828Sbostic 	fflush( stderr );
1379*33828Sbostic 	perror("");
1380*33828Sbostic }
1381*33828Sbostic 
1382*33828Sbostic 
1383*33828Sbostic static
1384*33828Sbostic resetverbcount()
1385*33828Sbostic {
1386*33828Sbostic 	if( Verbose == 2  &&  verbcount ) {
1387*33828Sbostic 		fputc( '\n', verbout );
1388*33828Sbostic 		verbcount = 0;
1389*33828Sbostic 	}
1390*33828Sbostic }
1391*33828Sbostic 
1392*33828Sbostic 
1393*33828Sbostic void
1394*33828Sbostic errbefore()
1395*33828Sbostic {
1396*33828Sbostic 	resetverbcount();
1397*33828Sbostic }
1398