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