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