1 /* @(#)buffer.c	1.199 20/07/08 Copyright 1985, 1995, 2001-2020 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)buffer.c	1.199 20/07/08 Copyright 1985, 1995, 2001-2020 J. Schilling";
6 #endif
7 /*
8  *	Buffer handling routines
9  *
10  *	Copyright (c) 1985, 1995, 2001-2020 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include <schily/mconfig.h>
27 
28 /*
29  * XXX Until we find a better way, the next definitions must be in sync
30  * XXX with the definitions in librmt/remote.c
31  */
32 #if !defined(HAVE_FORK) || !defined(HAVE_SOCKETPAIR) || !defined(HAVE_DUP2)
33 #undef	USE_RCMD_RSH
34 #endif
35 #if !defined(HAVE_GETSERVBYNAME)
36 #undef	USE_REMOTE				/* Cannot get rcmd() port # */
37 #endif
38 #if (!defined(HAVE_NETDB_H) || !defined(HAVE_RCMD)) && !defined(USE_RCMD_RSH)
39 #undef	USE_REMOTE				/* There is no rcmd() */
40 #endif
41 
42 #include <schily/stdio.h>
43 #include <schily/stdlib.h>
44 #include <schily/unistd.h>
45 #include <schily/fcntl.h>
46 #include <schily/ioctl.h>
47 #include <schily/varargs.h>
48 #include "star.h"
49 #include "props.h"
50 #include <schily/errno.h>
51 #include <schily/standard.h>
52 #include "fifo.h"
53 #include <schily/string.h>
54 #include <schily/wait.h>
55 #include <schily/mtio.h>
56 #include <schily/librmt.h>
57 #define	GT_COMERR		/* #define comerr gtcomerr */
58 #define	GT_ERROR		/* #define error gterror   */
59 #include <schily/schily.h>
60 #include "starsubs.h"
61 
62 #include <schily/io.h>		/* for setmode() prototype */
63 #include <schily/libport.h>	/* getpagesize() */
64 
65 #include <schily/nlsdefs.h>
66 
67 /*
68  * Warning: we need the siginfo_t feature that has been introduced in 1989
69  * with SVr4 and in 1995 with SUSv1. You need a platform that is maintained
70  * since 1995.
71  *
72  * defined(HAVE_SIGPROCMASK) && defined(SA_RESTART) identifies a system that
73  * supports sigaction().
74  *
75  * defined(HAVE_SIGINFO_T) && defined(HAVE_WAITID) is needed in order to get
76  * useful values in siginfo_t. Note that Mac OS X before approx. 2018 e.g.
77  * neither fills in sip->si_pid nor sip->si_code, making siginfo_t useless.
78  */
79 #if	defined(HAVE_SIGPROCMASK) && defined(SA_RESTART) && \
80 	defined(SA_SIGINFO) && \
81 	defined(HAVE_SIGINFO_T) && defined(HAVE_WAITID)
82 #define	USE_SIGCLD
83 #endif
84 
85 long	bigcnt	= 0;
86 long	bigsize	= 0;		/* Tape block size (may shrink < bigbsize) */
87 long	bigbsize = 0;		/* Big buffer size */
88 long	bufsize	= 0;		/* Available buffer size */
89 char	*bigbase = NULL;
90 char	*bigbuf	= NULL;
91 char	*bigptr	= NULL;
92 char	*eofptr	= NULL;
93 Llong	curblockno;
94 
95 m_stats	bstat;
96 m_stats	*stats	= &bstat;
97 int	pid;
98 
99 #ifdef	timerclear
100 LOCAL	struct	timespec	starttime;
101 LOCAL	struct	timespec	stoptime;
102 #endif
103 
104 LOCAL	BOOL	isremote = FALSE;
105 LOCAL	int	remfd	= -1;
106 LOCAL	char	*remfn;
107 
108 #ifdef __DJGPP__
109 LOCAL	FILE	*compress_tarf_save;	/* Old value of tarf	 */
110 LOCAL	FILE	*compress_tmpf = NULL;	/* FILE * from tmpfile() */
111 #endif
112 
113 extern	FILE	*tarf;
114 extern	FILE	*tty;
115 extern	FILE	*vpr;
116 extern	char	*tarfiles[];
117 extern	int	ntarfiles;
118 extern	int	tarfindex;
119 extern	BOOL	force_noremote;
120 extern	char	*rsh;
121 extern	char	*rmt;
122 LOCAL	int	lastremote = -1;
123 extern	BOOL	multivol;
124 extern	char	*newvol_script;
125 extern	BOOL	use_fifo;
126 extern	int	swapflg;
127 extern	int	cmptype;
128 extern	BOOL	debug;
129 extern	BOOL	print_artype;
130 extern	BOOL	silent;
131 extern	BOOL	showtime;
132 extern	BOOL	no_stats;
133 extern	BOOL	cpio_stats;
134 extern	BOOL	do_fifostats;
135 extern	BOOL	cflag;
136 extern	BOOL	uflag;
137 extern	BOOL	rflag;
138 extern	BOOL	copyflag;
139 extern	BOOL	Zflag;
140 extern	BOOL	zflag;
141 extern	BOOL	bzflag;
142 extern	BOOL	lzoflag;
143 extern	BOOL	p7zflag;
144 extern	BOOL	xzflag;
145 extern	BOOL	lzipflag;
146 extern	BOOL	zstdflag;
147 extern	BOOL	lzmaflag;
148 extern	BOOL	freezeflag;
149 extern	char	*compress_prg;
150 extern	BOOL	multblk;
151 extern	BOOL	partial;
152 extern	BOOL	wready;
153 extern	BOOL	nullout;
154 extern	Ullong	tsize;
155 extern	BOOL	nowarn;
156 
157 extern	int	intr;
158 
159 extern	GINFO	*gip;
160 
161 
162 EXPORT	void	opt_remote	__PR((void));
163 EXPORT	BOOL	openremote	__PR((void));
164 EXPORT	void	opentape	__PR((void));
165 EXPORT	void	closetape	__PR((void));
166 EXPORT	void	changetape	__PR((BOOL donext));
167 EXPORT	void	runnewvolscript	__PR((int volno, int nindex));
168 EXPORT	void	nextitape	__PR((void));
169 EXPORT	void	nextotape	__PR((void));
170 EXPORT	long	startvol	__PR((char *buf, long amount));
171 EXPORT	void	newvolhdr	__PR((char *buf, long amount, BOOL do_fifo));
172 #ifdef	FIFO
173 LOCAL	void	fbit_ffss	__PR((bitstr_t *name, long startb, long stopb,
174 					long *value));
175 LOCAL	BOOL	fifo_hpos	__PR((char *buf, off_t *posp));
176 #endif
177 EXPORT	void	initbuf		__PR((int nblocks));
178 EXPORT	void	markeof		__PR((void));
179 EXPORT	void	syncbuf		__PR((void));
180 EXPORT	long	peekblock	__PR((char *buf, long amount));
181 EXPORT	long	readblock	__PR((char *buf, long amount));
182 LOCAL	long	readtblock	__PR((char *buf, long amount));
183 LOCAL	void	readbuf		__PR((void));
184 EXPORT	ssize_t	readtape	__PR((char *buf, size_t amount));
185 EXPORT	void	filltcb		__PR((TCB *ptb));
186 EXPORT	void	movetcb		__PR((TCB *from_ptb, TCB *to_ptb));
187 EXPORT	void	*get_block	__PR((long amount));
188 EXPORT	void	put_block	__PR((long amount));
189 EXPORT	char	*writeblock	__PR((char *buf));
190 EXPORT	ssize_t	writetape	__PR((char *buf, size_t amount));
191 LOCAL	void	writebuf	__PR((long amount));
192 LOCAL	void	flushbuf	__PR((void));
193 EXPORT	void	writeempty	__PR((void));
194 EXPORT	void	weof		__PR((void));
195 EXPORT	void	buf_sync	__PR((long size));
196 EXPORT	void	buf_drain	__PR((void));
197 EXPORT	long	buf_wait	__PR((long amount));
198 EXPORT	void	buf_wake	__PR((long amount));
199 EXPORT	long	buf_rwait	__PR((long amount));
200 EXPORT	void	buf_rwake	__PR((long amount));
201 EXPORT	void	buf_resume	__PR((void));
202 EXPORT	void	backtape	__PR((void));
203 EXPORT	int	mtioctl		__PR((int cmd, int count));
204 EXPORT	off_t	mtseek		__PR((off_t offset, int whence));
205 EXPORT	void	marktcb		__PR((char *addr));
206 EXPORT	Llong	tblocks		__PR((void));
207 EXPORT	void	prstats		__PR((void));
208 EXPORT	BOOL	checkerrs	__PR((void));
209 EXPORT	void	exprstats	__PR((int ret));
210 EXPORT	void	excomerrno	__PR((int err, char *fmt, ...)) __printflike__(2, 3);
211 EXPORT	void	excomerr	__PR((char *fmt, ...)) __printflike__(1, 2);
212 EXPORT	void	die		__PR((int err));
213 #ifdef	USE_SIGCLD
214 LOCAL	void	cldhandler	__PR((int sig, siginfo_t *sip, void *context));
215 LOCAL	void	handlecld	__PR((void));
216 #endif
217 LOCAL	void	compressopen	__PR((void));
218 LOCAL	void	compressclose	__PR((void));
219 
220 EXPORT void
opt_remote()221 opt_remote()
222 {
223 #ifdef	USE_REMOTE
224 	printf(" remote");
225 #endif
226 }
227 
228 /*
229  * Check whether the current tarfiles[tarfindex] refers to a remote archive
230  * location and open a remote connection if needed.
231  * Called from star.c main() and from changetape().
232  */
233 EXPORT BOOL
openremote()234 openremote()
235 {
236 	char	host[128];
237 	char	lasthost[128];
238 
239 	if ((!nullout || (uflag || rflag)) && !force_noremote &&
240 			(remfn = rmtfilename(tarfiles[tarfindex])) != NULL) {
241 
242 #ifdef	USE_REMOTE
243 		isremote = TRUE;
244 		rmtdebug(debug);
245 		if (rsh)
246 			rmtrsh(rsh);
247 #ifdef	USE_SSH
248 		else
249 			rmtrsh("ssh");
250 #endif
251 		if (rmt)
252 			rmtrmt(rmt);
253 		rmthostname(host, sizeof (host), tarfiles[tarfindex]);
254 		if (debug)
255 			errmsgno(EX_BAD, "Remote: %s Host: %s file: %s\n",
256 					tarfiles[tarfindex], host, remfn);
257 
258 		if (lastremote >= 0) {
259 			rmthostname(lasthost, sizeof (lasthost),
260 							tarfiles[lastremote]);
261 			if (!streql(host, lasthost)) {
262 				close(remfd);
263 				remfd = -1;
264 				lastremote = -1;
265 			}
266 		}
267 		if (remfd < 0 && (remfd = rmtgetconn(host, bigsize, 0)) < 0)
268 			comerrno(EX_BAD, "Cannot get connection to '%s'.\n",
269 				/* errno not valid !! */		host);
270 		lastremote = tarfindex;
271 #else
272 		comerrno(EX_BAD, "Remote tape support not present.\n");
273 #endif
274 	} else {
275 		isremote = FALSE;
276 	}
277 	return (isremote);
278 }
279 
280 /*
281  * Open the current tarfiles[tarfindex] (a remote connection must be open)
282  * Called from star.c main() and from changetape().
283  */
284 EXPORT void
opentape()285 opentape()
286 {
287 	int	n = 0;
288 	extern	dev_t	tape_dev;
289 	extern	ino_t	tape_ino;
290 	extern	BOOL	tape_isreg;
291 	extern	Llong	mtskip;
292 
293 	if (copyflag || (nullout && !(uflag || rflag))) {
294 		tarfiles[tarfindex] = "null";
295 		tarf = (FILE *)NULL;
296 	} else if (streql(tarfiles[tarfindex], "-")) {
297 		if (cflag) {
298 			tarf = stdout;
299 		} else {
300 			tarf = stdin;
301 			multblk = TRUE;
302 		}
303 		setbuf(tarf, (char *)NULL);
304 		setmode(fileno(tarf), O_BINARY);
305 	} else if (isremote) {
306 #ifdef	USE_REMOTE
307 		/*
308 		 * isremote will always be FALSE if USE_REMOTE is not defined.
309 		 * NOTE any open flag bejond O_RDWR is not portable across
310 		 * different platforms. The remote tape library will check
311 		 * whether the current /etc/rmt server supports symbolic
312 		 * open flags. If there is no symbolic support in the
313 		 * remote server, our rmt client code will mask off all
314 		 * non portable bits. The remote rmt server defaults to
315 		 * O_BINARY as the client (we) may not know about O_BINARY.
316 		 * XXX Should we add an option that allows to specify O_TRUNC?
317 		 */
318 		while (rmtopen(remfd, remfn, (cflag ? O_RDWR|O_CREAT:O_RDONLY)|O_BINARY) < 0) {
319 			if (!wready || n++ > 12 ||
320 			    (geterrno() != EIO && geterrno() != EBUSY)) {
321 				comerr("Cannot open remote '%s'.\n",
322 						tarfiles[tarfindex]);
323 			} else {
324 				sleep(10);
325 			}
326 		}
327 #endif
328 	} else {
329 		FINFO	finfo;
330 	extern	BOOL	follow;
331 	extern	BOOL	fcompat;
332 	extern	int	ptype;
333 
334 		if (fcompat && (cflag && !(uflag || rflag))) {
335 			/*
336 			 * The old syntax has a high risk of corrupting
337 			 * files if the user disorders the args.
338 			 * For this reason, we do not allow to overwrite
339 			 * a plain file in compat mode.
340 			 * XXX What if we implement 'r' & 'u' ???
341 			 */
342 			follow++;
343 			n = _getinfo(tarfiles[tarfindex], &finfo);
344 			follow--;
345 			if (n >= 0 && is_file(&finfo) && finfo.f_size > (off_t)0) {
346 				if (ptype != P_SUNTAR) {
347 					comerrno(EX_BAD,
348 					"Will not overwrite non empty plain files in compat mode.\n");
349 				} else {
350 					errmsgno(EX_BAD,
351 					"WARNING: Overwriting archive file '%s'.\n",
352 					tarfiles[tarfindex]);
353 				}
354 			}
355 		}
356 
357 		n = 0;
358 		/*
359 		 * XXX Should we add an option that allows to specify O_TRUNC?
360 		 */
361 		while ((tarf = lfilemopen(tarfiles[tarfindex],
362 						cflag?"rwcub":"rub",
363 						S_IRWALL)) ==
364 								(FILE *)NULL) {
365 			if (!wready || n++ > 12 ||
366 			    (geterrno() != EIO && geterrno() != EBUSY)) {
367 				comerr("Cannot open '%s'.\n",
368 						tarfiles[tarfindex]);
369 			} else {
370 				sleep(10);
371 			}
372 		}
373 	}
374 	if (tarf != (FILE *)NULL && isatty(fdown(tarf)))
375 		comerrno(EX_BAD, "Archive cannot be a tty.\n");
376 	if (!isremote && (!nullout || (uflag || rflag)) &&
377 	    tarf != (FILE *)NULL) {
378 		file_raise(tarf, FALSE);
379 		checkarch(tarf);
380 	}
381 	vpr = tarf == stdout ? stderr : stdout;	/* f=stdout redirect listing */
382 	if (samefile(tarf, vpr)) {		/* Catch -f /dev/stdout case */
383 		if (tarf != stdin)		/* Don't redirect for -tv <  */
384 			vpr = stderr;
385 	}
386 
387 	/*
388 	 * If the archive is a plain file and thus seekable
389 	 * do automatic compression detection.
390 	 */
391 	if (stats->volno == 1 &&
392 	    tape_isreg && !cflag && (!Zflag && !zflag && !bzflag && !lzoflag &&
393 	    !p7zflag && !xzflag && !lzipflag && !zstdflag && !lzmaflag &&
394 	    !freezeflag &&
395 	    !compress_prg)) {
396 		long	htype;
397 		TCB	*ptb;
398 
399 		readtblock(bigbuf, TBLOCK);
400 		ptb = (TCB *)bigbuf;
401 		htype = get_hdrtype(ptb, FALSE);
402 
403 		if (htype == H_UNDEF) {
404 			switch (cmptype = get_compression(ptb)) {
405 
406 			case C_NONE:
407 				break;
408 			case C_PACK:
409 			case C_GZIP:
410 			case C_LZW:
411 			case C_FREEZE:
412 			case C_LZH:
413 			case C_PKZIP:
414 				if (!silent && !print_artype) errmsgno(EX_BAD,
415 					"WARNING: Archive is '%s' compressed, trying to use the -z option.\n",
416 						get_cmpname(cmptype));
417 				zflag = TRUE;
418 				break;
419 			case C_BZIP2:
420 				if (!silent && !print_artype) errmsgno(EX_BAD,
421 					"WARNING: Archive is 'bzip2' compressed, trying to use the -bz option.\n");
422 				bzflag = TRUE;
423 				break;
424 			case C_LZO:
425 				if (!silent && !print_artype) errmsgno(EX_BAD,
426 					"WARNING: Archive is 'lzop' compressed, trying to use the -lzo option.\n");
427 				lzoflag = TRUE;
428 				break;
429 			case C_7Z:
430 				if (!silent && !print_artype) errmsgno(EX_BAD,
431 					"WARNING: Archive is '7z' compressed, trying to use the -7z option.\n");
432 				p7zflag = TRUE;
433 				break;
434 			case C_XZ:
435 				if (!silent && !print_artype) errmsgno(EX_BAD,
436 					"WARNING: Archive is 'xz' compressed, trying to use the -xz option.\n");
437 				xzflag = TRUE;
438 				break;
439 			case C_LZIP:
440 				if (!silent && !print_artype) errmsgno(EX_BAD,
441 					"WARNING: Archive is 'lzip' compressed, trying to use the -lzip option.\n");
442 				lzipflag = TRUE;
443 				break;
444 			case C_ZSTD:
445 				if (!silent && !print_artype) errmsgno(EX_BAD,
446 					"WARNING: Archive is 'zstd' compressed, trying to use the -zstd option.\n");
447 				zstdflag = TRUE;
448 				break;
449 			case C_LZMA:
450 				if (!silent && !print_artype) errmsgno(EX_BAD,
451 					"WARNING: Archive is 'lzma' compressed, trying to use the -lzma option.\n");
452 				lzmaflag = TRUE;
453 				break;
454 			case C_FREEZE2:
455 				if (!silent && !print_artype) errmsgno(EX_BAD,
456 					"WARNING: Archive is 'freeze2' compressed, trying to use the -freeze option.\n");
457 				freezeflag = TRUE;
458 				break;
459 			default:
460 				if (!silent) errmsgno(EX_BAD,
461 					"WARNING: Unknown compression type %d.\n", cmptype);
462 				break;
463 			}
464 		}
465 		mtseek((off_t)0, SEEK_SET);
466 	}
467 	if (Zflag || zflag || bzflag || lzoflag ||
468 	    p7zflag || xzflag || lzipflag || zstdflag || lzmaflag || freezeflag ||
469 	    compress_prg) {
470 		extern long	iskip;
471 
472 		iskip = 0;	/* We cannot skip in compressed archives. */
473 		mtskip = 0;	/* We cannot skip in compressed archives. */
474 
475 		if (isremote)
476 			comerrno(EX_BAD, "Cannot compress remote archives (yet).\n");
477 		/*
478 		 * If both values are zero, this is a device and thus may be a tape.
479 		 */
480 		if (tape_dev || tape_ino)
481 			compressopen();
482 		else
483 			comerrno(EX_BAD, "Can only compress files.\n");
484 
485 	} else if (stats->volno == 1 && mtskip) {
486 		if (tape_isreg) {
487 			if (mtseek((off_t)mtskip * TBLOCK, SEEK_SET) == -1)
488 				excomerr("Cannot seek input for mtskip=.\n");
489 			mtskip = 0;
490 		} else if (mtioctl(MTNOP, 0) >= 0) {
491 		extern	int	nblocks;
492 			int	count = mtskip / nblocks;
493 
494 			if (mtioctl(MTFSR, count) == -1)
495 				excomerr("Cannot position tape for mtskip=.\n");
496 		}
497 	}
498 
499 #ifdef	timerclear
500 	if (showtime && starttime.tv_sec == 0 && starttime.tv_nsec == 0 &&
501 	    getnstimeofday(&starttime) < 0)
502 		comerr("Cannot get starttime\n");
503 #endif
504 }
505 
506 /*
507  * Close the current open tarf/remfd (a remote connection must be open)
508  * Called from star.c main() and from changetape().
509  */
510 EXPORT void
closetape()511 closetape()
512 {
513 	if (isremote) {
514 #ifdef	USE_REMOTE
515 		/*
516 		 * isremote will always be FALSE if USE_REMOTE is not defined.
517 		 */
518 		if (rmtclose(remfd) < 0)
519 			errmsg("Remote close failed.\n");
520 #endif
521 	} else {
522 		compressclose();
523 		if (tarf)
524 			fclose(tarf);
525 	}
526 }
527 
528 /*
529  * Low level medium change routine.
530  * Called from nextitape()/nextotape() and fifo_owait().
531  */
532 EXPORT void
changetape(donext)533 changetape(donext)
534 	BOOL	donext;
535 {
536 	char	ans[3];
537 	int	nextindex;
538 
539 	if (donext) {
540 		pid_t	opid = pid;
541 
542 		if (pid == 0)
543 			pid = 1; /* Make sure the statistics are printed */
544 		prstats();
545 		pid = opid;
546 		if (!cflag &&
547 		    (gip->tapesize > 0) &&
548 		    (stats->blocks*stats->nblocks + stats->parts/TBLOCK) !=
549 							    gip->tapesize) {
550 			errmsgno(EX_BAD,
551 			"WARNING: Archive size error.\n");
552 			errmsgno(EX_BAD,
553 			"Expected size %llu blocks, actual size %lld blocks.\n",
554 			gip->tapesize,
555 			stats->blocks*stats->nblocks + stats->parts/TBLOCK);
556 		}
557 		stats->Tblocks += stats->blocks;
558 		stats->Tparts += stats->parts;
559 	}
560 	stats->blocks = 0L;
561 	stats->parts = 0L;
562 	closetape();
563 	/*
564 	 * XXX Was passiert, wenn wir das 2. Mal bei einem Band vorbeikommen?
565 	 * XXX Zur Zeit wird gnadenlos ueberschrieben.
566 	 */
567 	if (donext) {
568 		stats->volno++;
569 		gip->volno = stats->volno;
570 		nextindex = tarfindex + 1;
571 		if (nextindex >= ntarfiles)
572 			nextindex = 0;
573 	} else {
574 		nextindex = tarfindex;
575 	}
576 	/*
577 	 * XXX We need to add something like the -l & -o option from
578 	 * XXX ufsdump.
579 	 */
580 	if (newvol_script) {
581 		fflush(vpr);
582 		if (!donext) {
583 			errmsgno(EX_BAD,
584 			"Mounted volume on '%s' did not match archive",
585 				tarfiles[nextindex]);
586 			comerrno(EX_BAD, "Aborting.\n");
587 		}
588 		runnewvolscript(stats->volno, nextindex);
589 	} else {
590 		int	len;
591 
592 		errmsgno(EX_BAD, "Mount volume #%d on '%s' and hit <RETURN>",
593 			stats->volno, tarfiles[nextindex]);
594 		ans[0] = '\n';
595 		len = fgetstr(tty, ans, sizeof (ans));
596 		if (len > 0 && ans[len-1] != '\n') {
597 			while (getc(tty) != '\n') {
598 				if (feof(tty) || ferror(tty))
599 					break;
600 			}
601 		}
602 
603 		if (ttyerr(tty))
604 			exit(1);
605 	}
606 	tarfindex = nextindex;
607 	openremote();
608 	opentape();
609 }
610 
611 EXPORT void
runnewvolscript(volno,nindex)612 runnewvolscript(volno, nindex)
613 	int	volno;
614 	int	nindex;
615 {
616 	char	scrbuf[PATH_MAX];
617 
618 	if (!newvol_script)
619 		return;
620 
621 	if (nindex >= ntarfiles)
622 		nindex = 0;
623 	/*
624 	 * The script is called with the next volume # and volume name
625 	 * as argument.
626 	 */
627 	js_snprintf(scrbuf, sizeof (scrbuf), "%s '%d' '%s'",
628 			newvol_script,
629 			volno, tarfiles[nindex]);
630 	system(scrbuf);
631 }
632 
633 /*
634  * High level input medium change routine.
635  * Currently called from buf_rwait().
636  * Volume verification in the fifo case is done in the fifo process.
637  * For this reason, we only verify the new volume in the non fifo case.
638  */
639 EXPORT void
nextitape()640 nextitape()
641 {
642 #ifdef	FIFO
643 	if (use_fifo) {
644 		fifo_chitape();
645 	} else
646 #endif
647 	{
648 		int	skip;
649 
650 		changetape(TRUE);
651 		readbuf();
652 		while (bigcnt > 0 && !verifyvol(bigptr, bigcnt, stats->volno, &skip)) {
653 			changetape(FALSE);
654 			readbuf();
655 		}
656 		if (skip > 0)
657 			buf_rwake(skip*TBLOCK);
658 	}
659 	if (intr)
660 		exit(2);
661 }
662 
663 /*
664  * High level output medium change routine.
665  * Currently called from write_tcb() and only used if
666  * -multivol has not been specified. So this is always called
667  * from the tar process and never from the fifo background process.
668  */
669 EXPORT void
nextotape()670 nextotape()
671 {
672 	weof();
673 #ifdef	FIFO
674 	if (use_fifo) {
675 		fifo_chotape();
676 	} else
677 #endif
678 	changetape(TRUE);
679 	if (intr)
680 		exit(2);
681 }
682 
683 /*
684  * Called from writetape()
685  */
686 EXPORT long
startvol(buf,amount)687 startvol(buf, amount)
688 	char	*buf;		/* The original buffer address		*/
689 	long	amount;		/* The related requested transfer count	*/
690 {
691 	char	*obuf = bigbuf;
692 	char	*optr = bigptr;
693 	long	ocnt = bigcnt;
694 	long	xcnt = 0;
695 	BOOL	ofifo = use_fifo;
696 static	BOOL	active = FALSE;	/* If TRUE: We are already in a media change */
697 extern	m_head	*mp;
698 
699 	if (amount <= 0)
700 		return (amount);
701 	if (active)
702 		comerrno(EX_BAD, "Panic: recursive media change requested!\n");
703 	if (amount > bigsize) {
704 		comerrno(EX_BAD,
705 		"Panic: trying to write more than bs (%ld > %ld)!\n",
706 		amount, bigsize);
707 	}
708 #ifdef	FIFO
709 	if (use_fifo) {
710 		mp->chreel = TRUE;
711 
712 		/*
713 		 * Make sure the put side of the FIFO is waiting either on
714 		 * mp->iblocked (because the FIFO is full) or on mp->reelwait
715 		 * before temporary disabling the FIFO during media change.
716 		 */
717 		while ((mp->eflags & FIFO_EXIT) == 0 &&
718 		    mp->iblocked == FALSE && mp->reelwait == FALSE) {
719 			usleep(100000);
720 		}
721 	}
722 #endif
723 	active = TRUE;
724 
725 	/*
726 	 * Save the current write data in "bigbase".
727 	 */
728 	movebytes(buf, bigbase, amount);
729 
730 	use_fifo = FALSE;
731 	bigbuf = &bigbase[bigsize];
732 	bigptr = bigbuf;
733 	bigcnt = 0;
734 
735 	newvolhdr(buf, amount, ofifo);
736 
737 	if (bigcnt > 0) {	/* We did create a volhdr */
738 		xcnt = bigsize - bigcnt;
739 		if (amount < xcnt)
740 			xcnt = amount;
741 		if (xcnt > 0) {
742 			/*
743 			 * Move data from original buffer past the volhdr to
744 			 * fill up a complete block size.
745 			 */
746 			movebytes(bigbase, bigptr, xcnt);
747 			bigcnt += xcnt;
748 		}
749 		writetape(bigbuf, bigcnt);
750 	}
751 
752 	movebytes(bigbase, buf, amount);
753 	bigbuf = obuf;
754 	bigptr = optr;
755 	bigcnt = ocnt;
756 	use_fifo = ofifo;
757 	active = FALSE;
758 #ifdef	FIFO
759 	if (use_fifo) {
760 		mp->chreel = FALSE;
761 		fifo_reelwake();
762 	}
763 #endif
764 	return (xcnt);		/* Return the amount taken from orig. buffer */
765 }
766 
767 EXPORT void
newvolhdr(buf,amount,do_fifo)768 newvolhdr(buf, amount, do_fifo)
769 	char	*buf;		/* The original buffer address		*/
770 	long	amount;		/* The related requested transfer count	*/
771 	BOOL	do_fifo;
772 {
773 extern	m_head	*mp;
774 	off_t	scur_size;
775 	off_t	scur_off;
776 	off_t	sold_size;
777 	off_t	sold_off;
778 #ifdef	FIFO
779 	off_t	new_size = 0;
780 	BOOL	nsize_valid = FALSE;
781 #endif
782 
783 	fifo_lock_critical();
784 	scur_size = stats->cur_size;
785 	scur_off  = stats->cur_off;
786 	sold_size = stats->old_size;
787 	sold_off  = stats->old_off;
788 #ifdef	FIFO
789 	/*
790 	 * If needed, find next header position in FIFO bitmap.
791 	 */
792 	if (do_fifo && buf != NULL)	/* buf == NULL -> called from put_tcb */
793 		nsize_valid = fifo_hpos(buf, &new_size);
794 #endif
795 	fifo_unlock_critical();
796 
797 	xbbackup();		/* Save current xheader data */
798 
799 	gip->blockoff = stats->Tblocks * stats->nblocks +
800 			stats->Tparts / TBLOCK;
801 
802 	put_release();		/* Pax 'g' vendor unique */
803 	put_archtype();		/* Pax 'g' vendor unique */
804 
805 #ifdef	FIFO
806 	if (do_fifo && buf != NULL) {	/* buf == NULL -> called from put_tcb */
807 		off_t	new_off = 0;
808 
809 		if (!nsize_valid) {
810 			new_size = scur_size;
811 			new_off  = scur_off - FIFO_AMOUNT(mp);
812 		}
813 		/*
814 		 * Write a 'g'-header and either a 'V'-header
815 		 * or a 'M'-header.
816 		 */
817 		put_volhdr(gip->label, new_size <= 0);
818 		if (new_size > 0)
819 			put_multhdr(new_size, new_off);
820 	} else
821 #endif
822 	/*
823 	 * Write a 'g'-header and either a 'V'-header
824 	 * or a 'M'-header.
825 	 */
826 	if (!do_fifo && (sold_off < sold_size)) {
827 		put_volhdr(gip->label, FALSE);
828 		put_multhdr(sold_size, sold_off);
829 	} else {
830 		put_volhdr(gip->label, TRUE);
831 	}
832 
833 	xbrestore();		/* Restore current xheader data */
834 	stats->cur_size = scur_size;
835 	stats->cur_off  = scur_off;
836 	stats->old_size = sold_size;
837 	stats->old_off  = sold_off;
838 }
839 
840 #ifdef	FIFO
841 /*
842  * Make the macro a function...
843  */
844 LOCAL void
fbit_ffss(name,startb,stopb,value)845 fbit_ffss(name, startb, stopb, value)
846 	register bitstr_t *name;
847 	register long	startb;
848 	register long	stopb;
849 	register long	*value;
850 {
851 	bit_lffss(name, startb, stopb, value);
852 }
853 
854 /*
855  * Find next header position in FIFO bitmap.
856  */
857 LOCAL BOOL
fifo_hpos(buf,posp)858 fifo_hpos(buf, posp)
859 	char	*buf;
860 	off_t	*posp;
861 {
862 		long	startb;
863 		long	stopb;
864 		long	endb;
865 		long	bitpos = -1;
866 	extern	m_head	*mp;
867 
868 	startb = (buf - mp->base) / TBLOCK;
869 	stopb  = -1 + (mp->putptr - mp->base) / TBLOCK;
870 	endb   = -1 + (mp->size) / TBLOCK;
871 
872 	if (buf < mp->base) {
873 		stopb = mp->bmlast;
874 		startb = stopb + 1 - (mp->base - buf) / TBLOCK;
875 
876 		fbit_ffss(mp->bmap, startb, stopb, &bitpos);
877 		if (bitpos >= 0) {
878 			*posp = (bitpos - startb) * TBLOCK;
879 			return (TRUE);
880 		}
881 		startb = 0;
882 		stopb = -1 + (mp->putptr - mp->base) / TBLOCK;
883 	}
884 	if (stopb < startb)
885 		fbit_ffss(mp->bmap, startb, endb, &bitpos);
886 	else
887 		fbit_ffss(mp->bmap, startb, stopb, &bitpos);
888 	if (bitpos >= 0) {
889 		*posp = (bitpos - startb) * TBLOCK;
890 		return (TRUE);
891 	}
892 	if (stopb < startb) {
893 		fbit_ffss(mp->bmap, 0, stopb, &bitpos);
894 		if (bitpos >= 0) {
895 			/*
896 			 * endb+1 - startb == # of bits in rear part
897 			 */
898 			*posp = (bitpos + endb+1 - startb) * TBLOCK;
899 			return (TRUE);
900 		}
901 	}
902 	return (FALSE);
903 }
904 #endif
905 
906 /*
907  * Init buffer or fifo.
908  * called from star.c main().
909  */
910 EXPORT void
initbuf(nblocks)911 initbuf(nblocks)
912 	int	nblocks;
913 {
914 	BOOL	cvolhdr = cflag && (multivol || tsize > 0);
915 
916 	pid = getpid();
917 	bufsize = bigsize = nblocks * TBLOCK;
918 #ifdef	FIFO
919 	if (use_fifo) {
920 		initfifo();
921 	}
922 #endif
923 	/*
924 	 * As bigbuf is allocated here only in case that we have no FIFO or we
925 	 * are in create mode, there are no aliasing problems with bigbuf and
926 	 * the shared memory in the FIFO while trying to detect the archive
927 	 * format and byte swapping in read/extract modes.
928 	 * Note that -r and -u currently disable the FIFO.
929 	 * In case that we enable the FIFO for -r and -u, we need to add
930 	 * another exception here in order to have space to remember the last
931 	 * block of significant data that needs to be modified to append.
932 	 */
933 	if (!use_fifo || cvolhdr || rflag || uflag) {
934 		int	pagesize = getpagesize();
935 
936 		/*
937 		 * llitos() overshoots by one space (' ') in cpio mode,
938 		 * add 10 bytes.
939 		 * If we create multi volume archives that need volume
940 		 * headers, we need additional space to prepare the
941 		 * first write to a new medium after a medium change.
942 		 * "bufsize" may be modified by initfifo() in the FIFO case,
943 		 * so we use "bigsize" for the extra multivol buffer to
944 		 * avoid allocating an unneeded huge amount of data here.
945 		 * In "replace" or "update" mode, we also may need to
946 		 * save/restore * the buffer for the tape record when doing
947 		 * EOF detection. As this space is needed at a different
948 		 * time, it may be shared with the extra multivol buffer.
949 		 */
950 		if (cvolhdr || rflag || uflag)
951 			bigsize *= 2;
952 
953 		/*
954 		 * roundup(x, y), x needs to be unsigned or x+y non-genative.
955 		 */
956 #undef	roundup
957 #define	roundup(x, y)	((((x)+((y)-1))/(y))*(y))
958 
959 		bigptr = bigbuf = ___malloc((size_t)bigsize+10+pagesize,
960 								"buffer");
961 		bigptr = bigbuf = (char *)roundup((UIntptr_t)bigptr, pagesize);
962 		fillbytes(bigbuf, bigsize, '\0');
963 		fillbytes(&bigbuf[bigsize], 10, 'U');
964 
965 		if (cvolhdr || rflag || uflag) {
966 			bigsize /= 2;
967 			bigbase = bigbuf;
968 			bigbuf = bigptr = &bigbase[bigsize];
969 		}
970 	}
971 	stats->nblocks = nblocks;
972 	stats->blocksize = bigbsize = bigsize;
973 	stats->volno = 1;
974 	stats->swapflg = -1;
975 }
976 
977 /*
978  * Mark the EOF position (the position of the first logical TAR EOF block)
979  * We need this position for later repositioning when appending to an archive.
980  */
981 EXPORT void
markeof()982 markeof()
983 {
984 #ifdef	FIFO
985 	if (use_fifo) {
986 		/*
987 		 * Remember current FIFO status.
988 		 */
989 		/* EMPTY */
990 	}
991 #endif
992 	eofptr = bigptr - TBLOCK;
993 
994 	if (debug) {
995 		error("Blocks: %lld\n", tblocks());
996 		error(
997 		"bigptr - bigbuff: %lld bigbuf: %p bigptr: %p eofptr: %p lastsize: %ld\n",
998 			(Llong)(bigptr - bigbuf),
999 			(void *)bigbuf, (void *)bigptr, (void *)eofptr,
1000 			stats->lastsize);
1001 	}
1002 }
1003 
1004 EXPORT void
marktcb(addr)1005 marktcb(addr)
1006 	char	*addr;
1007 {
1008 #ifdef	FIFO
1009 	extern	m_head  *mp;
1010 	register long	bit;
1011 #endif
1012 	if (!multivol || !use_fifo)
1013 		return;
1014 	/*
1015 	 * As long as we don't start supporting -multivol with CPIO archives,
1016 	 * we will never come here when writing unblocked archives.
1017 	 */
1018 #ifdef	FIFO
1019 	bit = addr - mp->base;
1020 	if (bit % TBLOCK)		/* Remove this paranoia test in future. */
1021 		errmsgno(EX_BAD, "TCB offset not mudulo 512.\n");
1022 	bit /= TBLOCK;
1023 	if (bit_test(mp->bmap, bit))	/* Remove this paranoia test in future. */
1024 		errmsgno(EX_BAD, "Bit %ld is already set.\n", bit);
1025 	bit_set(mp->bmap, bit);
1026 #endif
1027 }
1028 
1029 /*
1030  * Prepare the buffer/fifo for reversing the direction from reading to writing.
1031  * Called from star.c main() after skipall() is ready.
1032  */
1033 EXPORT void
syncbuf()1034 syncbuf()
1035 {
1036 #ifdef	FIFO
1037 	if (use_fifo) {
1038 		/*
1039 		 * Switch FIFO direction.
1040 		 */
1041 		excomerr("Cannot update tape with FIFO.\n");
1042 	}
1043 #endif
1044 	if (eofptr) {
1045 		/*
1046 		 * Only back up to "eofptr" if markeof() has been called,
1047 		 * this is not the case when we did ancounter a hard EOF
1048 		 * at the beginning of the archive (empty file),
1049 		 */
1050 		bigptr = eofptr;
1051 		bigcnt = eofptr - bigbuf;
1052 	}
1053 }
1054 
1055 /*
1056  * Peek into buffer for amount bytes.
1057  * Return at most TBLOCK (512) bytes.
1058  *
1059  * Called from get_tcb() for checking the archive format of the first
1060  * tape block.
1061  */
1062 EXPORT long
peekblock(buf,amount)1063 peekblock(buf, amount)
1064 	register char	*buf;
1065 	register long	amount;
1066 {
1067 	register long	n;
1068 
1069 	if ((n = buf_rwait(amount)) == 0)
1070 		return (EOF);
1071 	if (n > amount)
1072 		n = amount;
1073 	if (n >= TBLOCK) {
1074 		n = TBLOCK;
1075 		movetcb((TCB *)bigptr, (TCB *)buf);
1076 	} else {
1077 		movebytes(bigptr, buf, n);
1078 	}
1079 	return (n);
1080 }
1081 
1082 /*
1083  * Read amount bytes.
1084  * Return at most TBLOCK (512) bytes.
1085  * Do CPIO buffer wrap handling here.
1086  *
1087  * Called from get_tcb() and from the sparse handling functions in hole.c
1088  */
1089 EXPORT long
readblock(buf,amount)1090 readblock(buf, amount)
1091 	register char	*buf;
1092 	register long	amount;
1093 {
1094 	register long	n;
1095 
1096 	if ((n = peekblock(buf, amount)) != EOF) {
1097 		buf_rwake(n);
1098 		if (n < amount) {
1099 			if ((amount = readblock(&buf[n], amount-n)) == EOF)
1100 				return (n);
1101 			return (n + amount);
1102 		}
1103 	}
1104 	return (n);
1105 }
1106 
1107 /*
1108  * Low level routine to read a TAPE Block (usually 10k)
1109  * Called from opentape() to check the compression and from readtape().
1110  */
1111 LOCAL long
readtblock(buf,amount)1112 readtblock(buf, amount)
1113 	char	*buf;
1114 	long	amount;
1115 {
1116 	long	cnt;
1117 
1118 	stats->reading = TRUE;
1119 	if (isremote) {
1120 #ifdef	USE_REMOTE
1121 		/*
1122 		 * isremote will always be FALSE if USE_REMOTE is not defined.
1123 		 */
1124 		if ((cnt = rmtread(remfd, buf, amount)) < 0)
1125 			excomerr("Error reading '%s'.\n", tarfiles[tarfindex]);
1126 #endif
1127 	} else {
1128 		if ((cnt = _niread(fileno(tarf), buf, amount)) < 0)
1129 			excomerr("Error reading '%s'.\n", tarfiles[tarfindex]);
1130 	}
1131 	return (cnt);
1132 }
1133 
1134 /*
1135  * Refill the buffer if no fifo.
1136  * Called from buf_rwait()
1137  */
1138 LOCAL void
readbuf()1139 readbuf()
1140 {
1141 	bigcnt = readtape(bigbuf, bigsize);
1142 	bigptr = bigbuf;
1143 }
1144 
1145 /*
1146  * Mid level function to read a tape block (usually 10k)
1147  * Called from the fifo fill code and from readbuf().
1148  */
1149 EXPORT ssize_t
readtape(buf,amount)1150 readtape(buf, amount)
1151 	char	*buf;
1152 	size_t	amount;
1153 {
1154 	size_t	amt;
1155 	ssize_t	cnt;
1156 	char	*bp;
1157 	size_t	size;
1158 static	BOOL	teof = FALSE;
1159 
1160 	if (teof)
1161 		return (0);
1162 
1163 	amt = 0;
1164 	bp = buf;
1165 	size = amount;
1166 
1167 	do {
1168 		cnt = readtblock(bp, size);
1169 
1170 		amt += cnt;
1171 		bp += cnt;
1172 		size -= cnt;
1173 	} while (amt < amount && cnt > 0 && multblk);
1174 
1175 	if (amt == 0)
1176 		return (amt);
1177 	if (amt < TBLOCK) {
1178 		errmsgno(EX_BAD, "Error reading '%s' size (%zd) too small.\n",
1179 						tarfiles[tarfindex], amt);
1180 		/*
1181 		 * Do not continue after we did read less than 512 bytes.
1182 		 */
1183 		teof = TRUE;
1184 	}
1185 	/*
1186 	 * First block
1187 	 */
1188 	if (stats->swapflg < 0) {
1189 		if ((amt % TBLOCK) != 0)
1190 			comerrno(EX_BAD, "Invalid blocksize %zd bytes.\n", amt);
1191 		if (amt < amount) {
1192 			stats->blocksize = bigsize = amt;
1193 			stats->nblocks = bigsize/TBLOCK;
1194 #ifdef	FIFO
1195 			if (use_fifo)
1196 				fifo_ibs_shrink(amt);
1197 #endif
1198 			errmsgno(EX_BAD, "Blocksize = %ld records.\n",
1199 						stats->blocksize/TBLOCK);
1200 		}
1201 	}
1202 	if (stats->swapflg > 0)
1203 		swabbytes(buf, amt);
1204 
1205 	if (amt == stats->blocksize)
1206 		stats->blocks++;
1207 	else
1208 		stats->parts += amt;
1209 	stats->lastsize = amt;
1210 #ifdef	DEBUG
1211 	error("readbuf: cnt: %d.\n", amt);
1212 #endif
1213 	return (amt);
1214 }
1215 
1216 #define	DO8(a)	a; a; a; a; a; a; a; a;
1217 
1218 #ifdef	MY_SWABBYTES
1219 
1220 void
swabbytes(bp,cnt)1221 swabbytes(bp, cnt)
1222 	register char	*bp;
1223 	register long	cnt;
1224 {
1225 	register char	c;
1226 
1227 	cnt /= 2;	/* even count only */
1228 	while ((cnt -= 8) >= 0) {
1229 		DO8(c = *bp++; bp[-1] = *bp; *bp++ = c);
1230 	}
1231 	cnt += 8;
1232 
1233 	while (--cnt >= 0) {
1234 		c = *bp++; bp[-1] = *bp; *bp++ = c;
1235 	}
1236 }
1237 #endif
1238 
1239 #define	DO16(a)		DO8(a) DO8(a)
1240 
1241 EXPORT void
filltcb(ptb)1242 filltcb(ptb)
1243 	register TCB	*ptb;
1244 {
1245 	register int	i;
1246 	register long	*lp = ptb->ldummy;
1247 
1248 	for (i = 512/sizeof (long)/16; --i >= 0; ) {
1249 		DO16(*lp++ = 0L)
1250 	}
1251 }
1252 
1253 EXPORT void
movetcb(from_ptb,to_ptb)1254 movetcb(from_ptb, to_ptb)
1255 	register TCB	*from_ptb;
1256 	register TCB	*to_ptb;
1257 {
1258 	register int	i;
1259 	register long	*from = from_ptb->ldummy;
1260 	register long	*to   = to_ptb->ldummy;
1261 
1262 	for (i = 512/sizeof (long)/16; --i >= 0; ) {
1263 		DO16(*to++ = *from++)
1264 	}
1265 }
1266 
1267 /*
1268  * Try to allocate 'amount' bytes from the buffer or from the fifo.
1269  * If it is not possible to get 'amount' bytes in a single chunk, return NULL.
1270  */
1271 EXPORT void *
get_block(amount)1272 get_block(amount)
1273 	long	amount;
1274 {
1275 	if (buf_wait(amount) < amount)
1276 		return ((void *)NULL);
1277 	return ((void *)bigptr);
1278 }
1279 
1280 /*
1281  * Tell the buffer or the fifo that 'amount' bytes in the buffer/fifo space
1282  * are ready to be written.
1283  */
1284 EXPORT void
put_block(amount)1285 put_block(amount)
1286 	long	amount;
1287 {
1288 	buf_wake(amount);
1289 }
1290 
1291 /*
1292  * Write TBLOCK bytes into the buffer/fifo space and tell the buffer/fifo
1293  * that TBLOCK bytes are ready to be written.
1294  */
1295 EXPORT char *
writeblock(buf)1296 writeblock(buf)
1297 	char	*buf;
1298 {
1299 	char	*obp;
1300 
1301 	buf_wait(TBLOCK);
1302 	obp = bigptr;
1303 	movetcb((TCB *)buf, (TCB *)bigptr);
1304 	buf_wake(TBLOCK);
1305 
1306 	return (obp);
1307 }
1308 
1309 /*
1310  * Mid level function to write a tape block (usually 10k)
1311  * Called from the fifo fill output code and from writebuf().
1312  */
1313 EXPORT ssize_t
writetape(buf,amount)1314 writetape(buf, amount)
1315 	char	*buf;
1316 	size_t	amount;
1317 {
1318 	ssize_t	cnt;
1319 	int	err = 0;
1320 					/* hartes oder weiches EOF ???  */
1321 					/* d.h. < 0 oder <= 0		*/
1322 	stats->reading = FALSE;
1323 	if (multivol && tsize) {
1324 		Ullong	cursize;
1325 
1326 		cursize = stats->blocks * stats->nblocks + stats->parts / TBLOCK;
1327 
1328 		if (cursize >= tsize) {	/* tsize= induced change */
1329 			changetape(TRUE);
1330 			cnt = startvol(buf, amount);
1331 			if (cnt > 0)
1332 				return (cnt);
1333 		}
1334 	}
1335 	seterrno(0);
1336 	if (nullout) {
1337 		cnt = amount;
1338 #ifdef	USE_REMOTE
1339 	} else if (isremote) {
1340 		cnt = rmtwrite(remfd, buf, amount);	   /* Handles EINTR */
1341 #endif
1342 	} else {
1343 		cnt = _niwrite(fileno(tarf), buf, amount); /* Handles EINTR */
1344 	}
1345 	if (cnt == 0) {
1346 		err = EFBIG;
1347 	} else if (cnt < 0) {
1348 		err = geterrno();
1349 	}
1350 
1351 	if (multivol && (err == EFBIG || err == ENOSPC)) {
1352 		/*
1353 		 * QIC tapes (unblocked) may do partial writes at EOT.
1354 		 * We do the tape change not at the point when we write less
1355 		 * than a tape block (this may happen on pipes too) but after
1356 		 * we got a true EOF condition.
1357 		 */
1358 		return (-2);
1359 	}
1360 	if (multivol && (err == ENXIO)) {
1361 		/*
1362 		 * EOF condition on disk devices
1363 		 */
1364 		return (-2);
1365 	}
1366 
1367 	if (cnt == stats->blocksize)
1368 		stats->blocks++;
1369 	else if (cnt >= 0)
1370 		stats->parts += cnt;
1371 
1372 	if (cnt <= 0)
1373 		excomerrno(err, "Error writing '%s'.\n", tarfiles[tarfindex]);
1374 	return (cnt);
1375 }
1376 
1377 /*
1378  * Write output the buffer if no fifo.
1379  * Called from buf_wait()
1380  */
1381 LOCAL void
writebuf(amount)1382 writebuf(amount)
1383 	long	amount;
1384 {
1385 	long	cnt;
1386 
1387 
1388 nextwrite:
1389 	cnt = writetape(bigbuf, amount);
1390 
1391 	if (cnt < amount) {
1392 		if (cnt == -2) {		/* EOT induced change */
1393 			changetape(TRUE);
1394 			if ((cnt = startvol(bigbuf, amount)) <= 0)
1395 				goto nextwrite;
1396 		}
1397 		/*
1398 		 * QIC tapes (unblocked) may do partial writes at EOT
1399 		 *
1400 		 * Even if we hit a "planned" tape change, the fact
1401 		 * that we need to write a vol header looks from higher
1402 		 * levels as if there was a partial write.
1403 		 */
1404 		bigptr  = &bigbuf[cnt];
1405 		bigcnt -= cnt;
1406 		movebytes(bigptr, bigbuf, bigcnt);
1407 		bigptr  = &bigbuf[bigcnt];
1408 	} else {
1409 		bigptr = bigbuf;
1410 		bigcnt = 0;
1411 	}
1412 	stats->old_size = stats->cur_size;
1413 	stats->old_off  = stats->cur_off;
1414 }
1415 
1416 /*
1417  * Called only from weof()
1418  */
1419 LOCAL void
flushbuf()1420 flushbuf()
1421 {
1422 #ifdef	FIFO
1423 	if (!use_fifo)
1424 #endif
1425 	{
1426 		/*
1427 		 * Loop because a tape change and writing a vol header
1428 		 * may look like an incomplete write and need a second
1429 		 * write to really flush the buffer.
1430 		 */
1431 		while (bigcnt > 0)
1432 			writebuf(bigcnt);
1433 	}
1434 }
1435 
1436 /*
1437  * Write an empty TBLOCK
1438  * Called from weof() and cr_file()
1439  */
1440 EXPORT void
writeempty()1441 writeempty()
1442 {
1443 	TCB	tb;
1444 
1445 	filltcb(&tb);
1446 	writeblock((char *)&tb);
1447 }
1448 
1449 /*
1450  * Write a logical TAR EOF (2 empty TBLOCK sized blocks)
1451  * or a CPIO EOF marker.
1452  */
1453 EXPORT void
weof()1454 weof()
1455 {
1456 	if ((props.pr_flags & PR_CPIO) != 0) {
1457 		cpio_weof();
1458 		buf_sync(TBLOCK);
1459 	} else {
1460 		writeempty();
1461 		writeempty();
1462 	}
1463 	if (!partial)
1464 		buf_sync(0);
1465 	flushbuf();
1466 }
1467 
1468 /*
1469  * If size == 0, fill the buffer up to a TAPE record (usually 10k),
1470  * if size != 0, fill the buffer up to size.
1471  */
1472 EXPORT void
buf_sync(size)1473 buf_sync(size)
1474 	long	size;
1475 {
1476 #ifdef	FIFO
1477 	if (use_fifo) {
1478 		fifo_sync(size);
1479 	} else
1480 #endif
1481 	if (size) {
1482 		long	amt = 0;
1483 
1484 		if ((bigcnt % size) != 0)
1485 			amt = size - bigcnt%size;
1486 
1487 		fillbytes(bigptr, amt, '\0');
1488 		bigcnt += amt;
1489 		bigptr += amt;
1490 	} else {
1491 		fillbytes(bigptr, bigsize - bigcnt, '\0');
1492 		bigcnt = bigsize;
1493 	}
1494 }
1495 
1496 /*
1497  * Drain the fifo if in fifo mode.
1498  */
1499 EXPORT void
buf_drain()1500 buf_drain()
1501 {
1502 #ifdef	FIFO
1503 	if (use_fifo) {
1504 		fifo_oflush();	/* Set FIFO_MEOF flag and wake other side */
1505 		fifo_oclose();	/* Close sync pipe to finally wake other side */
1506 		wait(0);
1507 	}
1508 #endif
1509 }
1510 
1511 /*
1512  * Wait until we may put amount bytes into the buffer/fifo.
1513  * The returned count may be lower. Callers need to be prepared about this.
1514  */
1515 EXPORT long
buf_wait(amount)1516 buf_wait(amount)
1517 	long	amount;
1518 {
1519 #ifdef	FIFO
1520 	if (use_fifo) {
1521 		return (fifo_iwait(amount));
1522 	} else
1523 #endif
1524 	{
1525 		if (bigcnt >= bigsize)
1526 			writebuf(bigsize);
1527 		return (bigsize - bigcnt);
1528 	}
1529 }
1530 
1531 /*
1532  * Tell the buffer/fifo management that amount bytes are ready to be written.
1533  * The space may now be written to the media and the space may be made
1534  * avbailable for being filled up again.
1535  */
1536 EXPORT void
buf_wake(amount)1537 buf_wake(amount)
1538 	long	amount;
1539 {
1540 #ifdef	FIFO
1541 	if (use_fifo) {
1542 		fifo_owake(amount);
1543 	} else
1544 #endif
1545 	{
1546 		bigptr += amount;
1547 		bigcnt += amount;
1548 	}
1549 	if (copyflag) {
1550 		/*
1551 		 * In copy mode, there is no blocked read/write from the fifo
1552 		 * Tape process. For this reason, we increment the byte count
1553 		 * at this place.
1554 		 */
1555 		stats->parts += amount;
1556 	}
1557 }
1558 
1559 /*
1560  * Wait until we may read amount bytes from the buffer/fifo.
1561  * The returned count may be lower. Callers need to be prepared about this.
1562  */
1563 EXPORT long
buf_rwait(amount)1564 buf_rwait(amount)
1565 	long	amount;
1566 {
1567 	long	cnt;
1568 
1569 again:
1570 #ifdef	FIFO
1571 	if (use_fifo) {
1572 		cnt = fifo_owait(amount);
1573 	} else
1574 #endif
1575 	{
1576 		if (bigcnt <= 0)
1577 			readbuf();
1578 		cnt = bigcnt;
1579 	}
1580 	if (cnt == 0 && multivol) {
1581 		nextitape();
1582 		goto again;
1583 	}
1584 	return (cnt);
1585 }
1586 
1587 /*
1588  * Tell the buffer/fifo management that amount bytes are no longer needed for
1589  * read access. The space may now be filled up with new data from the medium.
1590  */
1591 EXPORT void
buf_rwake(amount)1592 buf_rwake(amount)
1593 	long	amount;
1594 {
1595 #ifdef	FIFO
1596 	if (use_fifo) {
1597 		fifo_iwake(amount);
1598 	} else
1599 #endif
1600 	{
1601 		bigptr += amount;
1602 		bigcnt -= amount;
1603 	}
1604 }
1605 
1606 /*
1607  * Resume the fifo if the fifo has been blocked after the first read
1608  * TAPE block (usually 10 k).
1609  * If the fifo is active, fifo_resume() triggers a shadow call to
1610  * setprops() in the fifo background process.
1611  */
1612 EXPORT void
buf_resume()1613 buf_resume()
1614 {
1615 extern	long	hdrtype;
1616 	stats->swapflg = swapflg;	/* copy over for fifo process */
1617 	stats->hdrtype = hdrtype;	/* copy over for fifo process */
1618 	bigsize = stats->blocksize;	/* copy over for tar process */
1619 #ifdef	FIFO
1620 	if (use_fifo)
1621 		fifo_resume();
1622 #endif
1623 }
1624 
1625 /*
1626  * Backspace tape or medium to prepare it for appending to an archive.
1627  * Note that this currently only handles TAR archives and that even then it
1628  * will not work if the TAPE record size is < 2*TBLOCK (1024 bytes).
1629  */
1630 EXPORT void
backtape()1631 backtape()
1632 {
1633 	Llong	ret;
1634 	BOOL	istape = FALSE;
1635 
1636 	if (debug) {
1637 		error("Blocks: %lld\n", tblocks());
1638 		error("filepos: %lld seeking to: %lld bigsize: %ld\n",
1639 		(Llong)mtseek((off_t)0, SEEK_CUR),
1640 		(Llong)mtseek((off_t)0, SEEK_CUR) - (Llong)stats->lastsize, bigsize);
1641 	}
1642 
1643 	if (mtioctl(MTNOP, 0) >= 0) {
1644 		istape = TRUE;
1645 		if (debug)
1646 			error("Is a tape: BSR 1...\n");
1647 		ret = mtioctl(MTBSR, 1);
1648 	} else {
1649 		if (debug)
1650 			error("Is a file: lseek()\n");
1651 		ret = mtseek(-stats->lastsize, SEEK_CUR);
1652 	}
1653 	if (ret == (Llong)-1)
1654 		excomerr("Cannot backspace %s.\n", istape ? "tape":"medium");
1655 
1656 	if (stats->lastsize == stats->blocksize)
1657 		stats->blocks--;
1658 	else
1659 		stats->parts -= stats->lastsize;
1660 }
1661 
1662 /*
1663  * Send an MTIOCTOP call to the file descriptor that is use for the medium.
1664  */
1665 EXPORT int
mtioctl(cmd,count)1666 mtioctl(cmd, count)
1667 	int	cmd;
1668 	int	count;
1669 {
1670 	int	ret;
1671 
1672 	if (nullout && !(uflag || rflag)) {
1673 		return (0);
1674 #ifdef	USE_REMOTE
1675 	} else if (isremote) {
1676 		ret = rmtioctl(remfd, cmd, count);
1677 #endif
1678 	} else {
1679 #if	defined(MTIOCTOP) && defined(HAVE_IOCTL)
1680 		struct mtop mtop;
1681 
1682 		mtop.mt_op = cmd;
1683 		mtop.mt_count = count;
1684 
1685 		ret = ioctl(fdown(tarf), MTIOCTOP, &mtop);
1686 #else
1687 #ifdef	ENOSYS
1688 		seterrno(ENOSYS);
1689 #else
1690 		seterrno(EINVAL);
1691 #endif
1692 		return (-1);
1693 #endif
1694 	}
1695 	if (ret < 0 && debug) {
1696 		errmsg("Error sending mtioctl(%d, %d) to '%s'.\n",
1697 					cmd, count, tarfiles[tarfindex]);
1698 	}
1699 	return (ret);
1700 }
1701 
1702 /*
1703  * Make an lseek() call to the file descriptor that is use for the medium.
1704  */
1705 EXPORT off_t
mtseek(offset,whence)1706 mtseek(offset, whence)
1707 	off_t	offset;
1708 	int	whence;
1709 {
1710 	if (nullout && !(uflag || rflag)) {
1711 		return (0L);
1712 #ifdef	USE_REMOTE
1713 	} else if (isremote) {
1714 		return (rmtseek(remfd, offset, whence));
1715 #endif
1716 	} else {
1717 		return (lseek(fileno(tarf), offset, whence));
1718 	}
1719 }
1720 
1721 /*
1722  * Return the current archive block number based on 512 byte (TBLOCK) units.
1723  */
1724 EXPORT Llong
tblocks()1725 tblocks()
1726 {
1727 	long	fifo_cnt = 0;
1728 	Llong	ret;
1729 
1730 #ifdef	FIFO
1731 	if (use_fifo)
1732 		fifo_cnt = fifo_amount()/TBLOCK;
1733 #endif
1734 	if (stats->reading)
1735 		ret = (-fifo_cnt + stats->blocks * stats->nblocks +
1736 				(stats->parts - (bigcnt+TBLOCK))/TBLOCK);
1737 	else
1738 		ret = (fifo_cnt + stats->blocks * stats->nblocks +
1739 				(stats->parts + bigcnt)/TBLOCK);
1740 	if (debug) {
1741 		error("tblocks: %lld blocks: %lld blocksize: %ld parts: %lld bigcnt: %ld fifo_cnt: %ld\n",
1742 		ret, stats->blocks, stats->blocksize, stats->parts, bigcnt, fifo_cnt);
1743 	}
1744 	curblockno = ret;
1745 	return (ret);
1746 }
1747 
1748 EXPORT void
prstats()1749 prstats()
1750 {
1751 	Llong	bytes;
1752 	Llong	kbytes;
1753 	int	per;
1754 #ifdef	timerclear
1755 	int	sec;
1756 	int	nsec;
1757 	int	tmsec;
1758 #endif
1759 	char	*p;
1760 
1761 #ifdef	FIFO
1762 	if (use_fifo) {
1763 		extern	m_head  *mp;
1764 		p = mp->end;
1765 	} else
1766 #endif
1767 		p = &bigbuf[bigbsize];
1768 
1769 	if ((*p != 'U' && *p != ' ') || p[1] != 'U')
1770 		errmsgno(EX_BAD, "The buffer has been overwritten, please contact the author.\n");
1771 
1772 	if (no_stats)
1773 		return;
1774 	if (pid == 0)	/* child */
1775 		return;
1776 
1777 #ifdef	timerclear
1778 	if (showtime && getnstimeofday(&stoptime) < 0)
1779 		comerr("Cannot get stoptime\n");
1780 #endif
1781 #ifdef	FIFO
1782 	if (use_fifo && do_fifostats)
1783 		fifo_stats();
1784 #endif
1785 
1786 	bytes = stats->blocks * (Llong)stats->blocksize + stats->parts;
1787 	kbytes = bytes >> 10;
1788 	per = ((bytes&1023)<<10)/10485;
1789 
1790 	if (cpio_stats) {
1791 		bytes = stats->Tblocks * (Llong)stats->blocksize + stats->Tparts;
1792 
1793 		error("%lld blocks\n", stats->eofblock + 1 + bytes/512);
1794 		return;
1795 	}
1796 
1797 	errmsgno(EX_BAD,
1798 		"%lld blocks + %lld bytes (total of %lld bytes = %lld.%02dk).\n",
1799 		stats->blocks, stats->parts, bytes, kbytes, per);
1800 
1801 	if (stats->Tblocks + stats->Tparts) {
1802 		bytes = (stats->blocks + stats->Tblocks) *
1803 						(Llong)stats->blocksize +
1804 						(stats->parts + stats->Tparts);
1805 		kbytes = bytes >> 10;
1806 		per = ((bytes&1023)<<10)/10485;
1807 
1808 		errmsgno(EX_BAD,
1809 		"Total %lld blocks + %lld bytes (total of %lld bytes = %lld.%02dk).\n",
1810 		stats->blocks + stats->Tblocks,
1811 		stats->parts + stats->Tparts,
1812 		bytes, kbytes, per);
1813 	}
1814 #ifdef	timerclear
1815 	if (showtime) {
1816 		Llong	kbs;
1817 
1818 		sec = stoptime.tv_sec - starttime.tv_sec;
1819 		nsec = stoptime.tv_nsec - starttime.tv_nsec;
1820 		tmsec = sec*1000 + nsec/1000000;
1821 		if (nsec < 0) {
1822 			sec--;
1823 			nsec += 1000000000;
1824 		}
1825 		if (tmsec == 0)
1826 			tmsec++;
1827 
1828 		kbs = kbytes*(Llong)1000/tmsec;
1829 
1830 		errmsgno(EX_BAD, "Total time %d.%03dsec (%lld kBytes/sec)\n",
1831 				sec, nsec/1000000, kbs);
1832 	}
1833 #endif
1834 #ifdef	DBG_MALLOC
1835 	aprintlist(stdout, 1);
1836 #endif
1837 }
1838 
1839 EXPORT BOOL
checkerrs()1840 checkerrs()
1841 {
1842 	if (xstats.s_staterrs	||
1843 #ifdef	USE_ACL
1844 	    xstats.s_getaclerrs	||
1845 #endif
1846 	    xstats.s_openerrs	||
1847 	    xstats.s_rwerrs	||
1848 	    xstats.s_misslinks	||
1849 	    xstats.s_toolong	||
1850 	    xstats.s_toobig	||
1851 	    xstats.s_isspecial	||
1852 	    xstats.s_sizeerrs	||
1853 	    xstats.s_chdir	||
1854 	    xstats.s_iconv	||
1855 	    xstats.s_id		||
1856 	    xstats.s_time	||
1857 
1858 	    xstats.s_settime	||
1859 	    xstats.s_security	||
1860 	    xstats.s_lsecurity	||
1861 	    xstats.s_samefile	||
1862 #ifdef	USE_ACL
1863 	    xstats.s_badacl	||
1864 	    xstats.s_setacl	||
1865 #endif
1866 #ifdef USE_XATTR
1867 	    xstats.s_getxattr	||
1868 	    xstats.s_setxattr	||
1869 #endif
1870 	    xstats.s_setmodes	||
1871 	    xstats.s_restore	||
1872 	    xstats.s_compress	||
1873 	    xstats.s_hardeof	||
1874 	    xstats.s_substerrs	||
1875 	    xstats.s_selinuxerrs) {
1876 		if (nowarn || no_stats || (pid == 0) /* child */)
1877 			return (TRUE);
1878 
1879 		errmsgno(EX_BAD, "The following problems occurred during archive processing:\n");
1880 		errmsgno(EX_BAD, "Cannot: stat %d, open %d, read/write %d, chdir %d, iconv %d.\n",
1881 				xstats.s_staterrs,
1882 				xstats.s_openerrs,
1883 				xstats.s_rwerrs,
1884 				xstats.s_chdir,
1885 				xstats.s_iconv);
1886 		if (xstats.s_id || xstats.s_time)
1887 			errmsgno(EX_BAD, "Range errors: uid/gid %d, time: %d.\n",
1888 				xstats.s_id, xstats.s_time);
1889 		errmsgno(EX_BAD, "Size changed %d.\n",
1890 				xstats.s_sizeerrs);
1891 		errmsgno(EX_BAD, "Missing links %d, Name too long %d, File too big %d, Not dumped %d.\n",
1892 				xstats.s_misslinks,
1893 				xstats.s_toolong,
1894 				xstats.s_toobig,
1895 				xstats.s_isspecial);
1896 		if (xstats.s_settime || xstats.s_setmodes)
1897 			errmsgno(EX_BAD, "Cannot set: time %d, modes %d.\n",
1898 				xstats.s_settime,
1899 				xstats.s_setmodes);
1900 		if (xstats.s_security || xstats.s_lsecurity)
1901 			errmsgno(EX_BAD, "Skipped for security reason: path name %d, link name %d.\n",
1902 				xstats.s_security, xstats.s_lsecurity);
1903 		if (xstats.s_samefile)
1904 			errmsgno(EX_BAD, "Skipped same file %d.\n",
1905 				xstats.s_samefile);
1906 #ifdef	USE_ACL
1907 		if (xstats.s_getaclerrs || xstats.s_badacl || xstats.s_setacl)
1908 			errmsgno(EX_BAD, "Cannot get ACL: %d set ACL: %d. Bad ACL %d.\n",
1909 				xstats.s_getaclerrs,
1910 				xstats.s_setacl,
1911 				xstats.s_badacl);
1912 #endif
1913 #ifdef USE_XATTR
1914 		if (xstats.s_getxattr || xstats.s_setxattr)
1915 			errmsgno(EX_BAD, "Cannot get xattr: %d set xattr: %d.\n",
1916 				xstats.s_getxattr,
1917 				xstats.s_setxattr);
1918 #endif
1919 #ifdef USE_SELINUX
1920 		if (xstats.s_selinuxerrs)
1921 			errmsgno(EX_BAD, "Cannot set SELinux security context: %d.\n",
1922 				xstats.s_selinuxerrs);
1923 #endif
1924 		if (xstats.s_restore)
1925 			errmsgno(EX_BAD, "Problems with restore database.\n");
1926 		if (xstats.s_compress)
1927 			errmsgno(EX_BAD, "Problems with compress program.\n");
1928 		if (xstats.s_substerrs)
1929 			errmsgno(EX_BAD,
1930 				"%d Problem(s) with path substitution.\n",
1931 				xstats.s_substerrs);
1932 		if (xstats.s_hardeof)
1933 			errmsgno(EX_BAD, "Hard EOF on input.\n");
1934 
1935 		if (xstats.s_security)
1936 			errmsgno(EX_BAD, "See option -.. on why some files have been skipped.\n");
1937 		if (xstats.s_lsecurity)
1938 			errmsgno(EX_BAD, "See option -secure-links on why some links have been skipped.\n");
1939 		return (TRUE);
1940 	}
1941 	return (FALSE);
1942 }
1943 
1944 EXPORT void
exprstats(ret)1945 exprstats(ret)
1946 	int	ret;
1947 {
1948 	prstats();
1949 	checkerrs();
1950 	if (use_fifo)
1951 		fifo_exit(ret);
1952 	exit(ret);
1953 }
1954 
1955 /* VARARGS2 */
1956 #ifdef	PROTOTYPES
1957 EXPORT void
excomerrno(int err,char * fmt,...)1958 excomerrno(int err, char *fmt, ...)
1959 #else
1960 EXPORT void
1961 excomerrno(err, fmt, va_alist)
1962 	int	err;
1963 	char	*fmt;
1964 	va_dcl
1965 #endif
1966 {
1967 	va_list	args;
1968 
1969 #ifdef	PROTOTYPES
1970 	va_start(args, fmt);
1971 #else
1972 	va_start(args);
1973 #endif
1974 	errmsgno(err, "%r", _(fmt), args);
1975 	va_end(args);
1976 #ifdef	FIFO
1977 	fifo_exit(err);
1978 #endif
1979 	exprstats(err);
1980 	/* NOTREACHED */
1981 }
1982 
1983 /* VARARGS1 */
1984 #ifdef	PROTOTYPES
1985 EXPORT void
excomerr(char * fmt,...)1986 excomerr(char *fmt, ...)
1987 #else
1988 EXPORT void
1989 excomerr(fmt, va_alist)
1990 	char	*fmt;
1991 	va_dcl
1992 #endif
1993 {
1994 	va_list	args;
1995 	int	err = geterrno();
1996 
1997 #ifdef	PROTOTYPES
1998 	va_start(args, fmt);
1999 #else
2000 	va_start(args);
2001 #endif
2002 	errmsgno(err, "%r", _(fmt), args);
2003 	va_end(args);
2004 #ifdef	FIFO
2005 	fifo_exit(err);
2006 #endif
2007 	exprstats(err);
2008 	/* NOTREACHED */
2009 }
2010 
2011 EXPORT void
die(err)2012 die(err)
2013 	int	err;
2014 {
2015 	excomerrno(err, "Cannot recover from error - exiting.\n");
2016 }
2017 
2018 /*
2019  * Quick hack to implement a -z flag. May be changed soon.
2020  */
2021 #include <schily/signal.h>
2022 #if	defined(SIGDEFER) || defined(SVR4)
2023 #define	signal	sigset
2024 #endif
2025 
2026 LOCAL	pid_t	compresspid;
2027 
2028 #ifdef	USE_SIGCLD
2029 LOCAL void
cldhandler(sig,sip,context)2030 cldhandler(sig, sip, context)
2031 	int		sig;
2032 	siginfo_t	*sip;
2033 	void		*context;
2034 {
2035 	if (sip->si_pid != compresspid)
2036 		return;
2037 
2038 	if (sip->si_status != 0 || sip->si_code != CLD_EXITED)
2039 		xstats.s_compress++;
2040 
2041 	if (sip->si_status != 0 && sip->si_code == CLD_EXITED)
2042 		errmsgno(EX_BAD,
2043 		"Compress program exited with status %d.\n",
2044 			sip->si_status);
2045 	else if (sip->si_status != 0)
2046 		errmsgno(EX_BAD,
2047 		"Compress program died with signal %d.\n",
2048 			sip->si_status);
2049 }
2050 
2051 LOCAL void
handlecld()2052 handlecld()
2053 {
2054 	struct sigaction sa;
2055 
2056 	sa.sa_sigaction = cldhandler;
2057 	sigemptyset(&sa.sa_mask);
2058 	sa.sa_flags = SA_RESTART|SA_SIGINFO;
2059 
2060 	sigaction(SIGCHLD, &sa, NULL);
2061 }
2062 #endif	/* USE_SIGCLD */
2063 
2064 LOCAL void
compressopen()2065 compressopen()
2066 {
2067 #ifdef	HAVE_FORK
2068 	FILE	*pp[2];
2069 	int	mypid;
2070 	char	*zip_prog = "gzip";
2071 
2072 	if (compress_prg)
2073 		zip_prog = compress_prg;
2074 	else if (bzflag)
2075 		zip_prog = "bzip2";
2076 	else if (Zflag)
2077 		zip_prog = "compress";
2078 	else if (lzoflag)
2079 		zip_prog = "lzop";
2080 	else if (p7zflag)
2081 		zip_prog = "p7zip";
2082 	else if (xzflag)
2083 		zip_prog = "xz";
2084 	else if (lzipflag)
2085 		zip_prog = "lzip";
2086 	else if (zstdflag)
2087 		zip_prog = "zstd";
2088 	else if (lzmaflag)
2089 		zip_prog = "lzma";
2090 	else if (freezeflag)
2091 		zip_prog = "freeze";
2092 
2093 	multblk = TRUE;
2094 
2095 	if (cflag && (uflag || rflag))
2096 		comerrno(EX_BAD, "Cannot update compressed archives.\n");
2097 
2098 #ifdef __DJGPP__
2099 	if (cflag) {
2100 		/*
2101 		 * We try to emulate a command line like:
2102 		 *
2103 		 *	"star -c dir | %s > dir.tar.%s\n",
2104 		 *	zip_prog,
2105 		 *	Zflag?"Z":bzflag?"bz2":compress_prg?compress_prg:"gz");
2106 		 *
2107 		 * If we would use popen() instead, DJGPP will run the program
2108 		 * from popen() first, so there would
2109 		 * be no data from the "tarf" File pointer.
2110 		 * We use the temporary file instead.
2111 		 */
2112 		if ((compress_tmpf = tmpfile()) == NULL)
2113 			comerr("Compress pipe failed\n");
2114 		compress_tarf_save = tarf;
2115 		tarf = compress_tmpf;
2116 
2117 	} else {
2118 		int	stdin_save;
2119 		char	zip_cmd[256];
2120 
2121 		/*
2122 		 * We try to emulate a command line like:
2123 		 *
2124 		 *	"%s -d < archive.tar.%s | star -x\n",
2125 		 *	zip_prog,
2126 		 *	Zflag?"Z":bzflag?"bz2":compress_prg?compress_prg:"gz");
2127 		 */
2128 		js_snprintf(zip_cmd, sizeof (zip_cmd), "%s.exe -d", zip_prog);
2129 
2130 		stdin_save = dup(STDIN_FILENO);
2131 		dup2(fileno(tarf), STDIN_FILENO);
2132 		compress_tarf_save = tarf;
2133 		if ((tarf = popen(zip_cmd, "rb")) == NULL)
2134 			comerr("Compress pipe failed\n");
2135 		dup2(stdin_save, STDIN_FILENO);
2136 		fclose(compress_tarf_save);
2137 	}
2138 #else
2139 	if (fpipe(pp) == 0)
2140 		comerr("Compress pipe failed\n");
2141 #ifdef	USE_SIGCLD
2142 	handlecld();
2143 #endif
2144 	mypid = fork();
2145 	if (mypid < 0)
2146 		comerr("Compress fork failed\n");
2147 	if (mypid == 0) {
2148 		FILE	*null;
2149 		char	*flg = getenv("STAR_COMPRESS_FLAG"); /* Temporary ? */
2150 
2151 		signal(SIGQUIT, SIG_IGN);
2152 		if (cflag)
2153 			fclose(pp[1]);
2154 		else
2155 			fclose(pp[0]);
2156 
2157 #ifdef	NEED_O_BINARY
2158 		if (cflag)
2159 			setmode(fileno(pp[0]), O_BINARY);
2160 		else
2161 			setmode(fileno(pp[1]), O_BINARY);
2162 #endif
2163 
2164 		/* We don't want to see errors */
2165 		null = lfilemopen("/dev/null", "rw", S_IRWALL);
2166 		if (null == NULL) {
2167 			errmsg("Cannot open '%s'.\n", "/dev/null");
2168 			goto err;
2169 		}
2170 
2171 		if (cflag)
2172 			fexecl(zip_prog, pp[0], tarf, null, zip_prog, flg, (char *)NULL);
2173 		else
2174 			fexecl(zip_prog, tarf, pp[1], null, zip_prog, "-d", (char *)NULL);
2175 err:
2176 		errmsg("Compress: exec of '%s' failed\n", zip_prog);
2177 		_exit(-1);
2178 	} else {
2179 		compresspid = mypid;
2180 	}
2181 	fclose(tarf);
2182 	if (cflag) {
2183 		tarf = pp[1];
2184 		fclose(pp[0]);
2185 	} else {
2186 		tarf = pp[0];
2187 		fclose(pp[1]);
2188 	}
2189 	setmode(fileno(tarf), O_BINARY);
2190 #endif /* !__DJGPP__ */
2191 #else  /* !HAVE_FORK */
2192 	comerrno(EX_BAD, "Inline compression not available.\n");
2193 #endif
2194 }
2195 
2196 LOCAL void
compressclose()2197 compressclose()
2198 {
2199 #ifdef HAVE_FORK
2200 #ifdef __DJGPP__
2201 	if (cflag) {
2202 		if (compress_tmpf) {
2203 			char	zip_cmd[256];
2204 			FILE	*zipf;
2205 			int	cnt = -1;
2206 			char	buf[8192];
2207 			char	*zip_prog = "gzip";
2208 
2209 			if (compress_prg)
2210 				zip_prog = compress_prg;
2211 			else if (bzflag)
2212 				zip_prog = "bzip2";
2213 			else if (Zflag)
2214 				zip_prog = "compress";
2215 			else if (lzoflag)
2216 				zip_prog = "lzop";
2217 			else if (p7zflag)
2218 				zip_prog = "p7zip";
2219 			else if (xzflag)
2220 				zip_prog = "xz";
2221 			else if (lzipflag)
2222 				zip_prog = "lzip";
2223 			else if (zstdflag)
2224 				zip_prog = "zstd";
2225 			else if (lzmaflag)
2226 				zip_prog = "lzma";
2227 			else if (freezeflag)
2228 				zip_prog = "freeze";
2229 
2230 			js_snprintf(zip_cmd, sizeof (zip_cmd), "%s.exe", zip_prog);
2231 
2232 			dup2(fileno(compress_tarf_save), STDOUT_FILENO);
2233 
2234 			if ((zipf = popen(zip_cmd, "wb")) == NULL)
2235 				comerr("Compress pipe failed\n");
2236 
2237 			fseek(compress_tmpf, 0l, SEEK_SET);
2238 
2239 			while ((cnt = ffileread(compress_tmpf, buf, sizeof (buf))) > 0)
2240 				ffilewrite(zipf, buf, cnt);
2241 
2242 			pclose(zipf);
2243 			fclose(compress_tmpf);
2244 			compress_tmpf = (FILE *)NULL;
2245 		}
2246 
2247 	} else {
2248 		pclose(tarf);
2249 	}
2250 #endif
2251 #endif
2252 }
2253