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