1 /* @(#)volhdr.c	1.48 19/12/03 Copyright 1994, 2003-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)volhdr.c	1.48 19/12/03 Copyright 1994, 2003-2019 J. Schilling";
6 #endif
7 /*
8  *	Volume header related routines.
9  *
10  *	Copyright (c) 1994, 2003-2019 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 
27 #include <schily/stdio.h>
28 #include <schily/stdlib.h>
29 #include <schily/unistd.h>
30 #include <schily/hostname.h>
31 #include "star.h"
32 #include "props.h"
33 #include "table.h"
34 #include <schily/standard.h>
35 #include <schily/string.h>
36 #define	__XDEV__	/* Needed to activate _dev_major()/_dev_minor() */
37 #include <schily/device.h>
38 #define	GT_COMERR		/* #define comerr gtcomerr */
39 #define	GT_ERROR		/* #define error gterror   */
40 #include <schily/schily.h>
41 #include <schily/libport.h>
42 #include "starsubs.h"
43 #include "dumpdate.h"
44 #include "xtab.h"
45 #include "fifo.h"
46 
47 extern	FILE	*vpr;
48 extern	BOOL	multivol;
49 extern	BOOL	binflag;
50 extern	long	chdrtype;
51 extern	char	*vers;
52 extern	int	verbose;
53 extern	Ullong	tsize;
54 extern	BOOL	ghdr;
55 
56 extern struct timespec	ddate;			/* The current dump date	*/
57 
58 extern	m_stats	*stats;
59 
60 extern	GINFO	*gip;				/* Global information pointer	*/
61 extern	GINFO	*grip;				/* Global read info pointer	*/
62 
63 EXPORT	void	ginit		__PR((void));
64 EXPORT	void	grinit		__PR((void));
65 LOCAL	int	xstrcpy		__PR((char **newp, char *old, char *p, int len));
66 EXPORT	void	gipsetup	__PR((GINFO *gp));
67 EXPORT	void	griprint	__PR((GINFO *gp));
68 EXPORT	BOOL	verifyvol	__PR((char *buf, int amt, int volno, int *skipp));
69 LOCAL	BOOL	vrfy_gvolhdr	__PR((char *buf, int amt, int volno, int *skipp));
70 EXPORT	char	*dt_name	__PR((int type));
71 EXPORT	int	dt_type		__PR((char *name));
72 EXPORT	void	put_release	__PR((void));
73 EXPORT	void	put_archtype	__PR((void));
74 EXPORT	void	put_gvolhdr	__PR((char *name));
75 EXPORT	void	put_volhdr	__PR((char *name, BOOL putv));
76 EXPORT	void	put_svolhdr	__PR((char *name));
77 EXPORT	void	put_multhdr	__PR((off_t size, off_t off));
78 EXPORT	BOOL	get_volhdr	__PR((FINFO *info, char *vhname));
79 LOCAL	void	get_label	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
80 LOCAL	void	get_hostname	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
81 LOCAL	void	get_filesys	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
82 LOCAL	void	get_cwd		__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
83 LOCAL	void	get_device	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
84 LOCAL	void	get_dumptype	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
85 LOCAL	void	get_dumplevel	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
86 LOCAL	void	get_reflevel	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
87 LOCAL	void	get_dumpdate	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
88 LOCAL	void	get_refdate	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
89 LOCAL	void	get_volno	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
90 LOCAL	void	get_blockoff	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
91 LOCAL	void	get_blocksize	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
92 LOCAL	void	get_tapesize	__PR((FINFO *info, char *keyword, int klen, char *arg, size_t len));
93 
94 /*
95  * Important for the correctness of gen_number(): As long as we stay <= 55
96  * chars for the keyword, a 128 bit number entry will fit into 100 chars.
97  */
98 EXPORT xtab_t volhtab[] = {
99 			{ "SCHILY.volhdr.label",	19, get_label,	   0	},
100 			{ "SCHILY.volhdr.hostname",	22, get_hostname,  0	},
101 			{ "SCHILY.volhdr.filesys",	21, get_filesys,   0	},
102 			{ "SCHILY.volhdr.cwd",		17, get_cwd,	   0	},
103 			{ "SCHILY.volhdr.device",	20, get_device,	   0	},
104 			{ "SCHILY.volhdr.dumptype",	22, get_dumptype,  0	},
105 			{ "SCHILY.volhdr.dumplevel",	23, get_dumplevel, 0	},
106 			{ "SCHILY.volhdr.reflevel",	22, get_reflevel,  0	},
107 			{ "SCHILY.volhdr.dumpdate",	22, get_dumpdate,  0	},
108 			{ "SCHILY.volhdr.refdate",	21, get_refdate,   0	},
109 			{ "SCHILY.volhdr.volno",	19, get_volno,	   0	},
110 			{ "SCHILY.volhdr.blockoff",	22, get_blockoff,  0	},
111 			{ "SCHILY.volhdr.blocksize",	23, get_blocksize, 0	},
112 			{ "SCHILY.volhdr.tapesize",	22, get_tapesize,  0	},
113 
114 			{ NULL,				0, NULL,	   0	}};
115 
116 EXPORT void
ginit()117 ginit()
118 {
119 extern	int	dumplevel;
120 extern	int	nblocks;
121 
122 	gip->label	= NULL;
123 	gip->hostname	= NULL;
124 	gip->filesys	= NULL;
125 	gip->cwd	= NULL;
126 	gip->device	= NULL;
127 	gip->release	= vers;
128 	gip->archtype	= chdrtype;
129 	gip->dumptype	= 0;
130 	gip->dumplevel	= dumplevel;
131 	gip->reflevel	= -1;
132 	gip->dumpdate	= ddate;
133 	gip->refdate.tv_sec  = 0;
134 	gip->refdate.tv_nsec = 0;
135 	gip->volno	= 1;
136 	gip->tapesize	= tsize;
137 	gip->blockoff	= 0;
138 	gip->blocksize	= nblocks;
139 	gip->gflags	=   GF_RELEASE|GF_DUMPLEVEL|GF_REFLEVEL|GF_DUMPDATE|
140 			    GF_VOLNO|GF_TAPESIZE|GF_BLOCKOFF|GF_BLOCKSIZE;
141 }
142 
143 EXPORT void
grinit()144 grinit()
145 {
146 	if (grip->label) {
147 		if ((grip->gflags & GF_NOALLOC) == 0)
148 			free(grip->label);
149 		grip->label	= NULL;
150 	}
151 	if (grip->hostname) {
152 		if ((grip->gflags & GF_NOALLOC) == 0)
153 			free(grip->hostname);
154 		grip->hostname	= NULL;
155 	}
156 	if (grip->filesys) {
157 		if ((grip->gflags & GF_NOALLOC) == 0)
158 			free(grip->filesys);
159 		grip->filesys	= NULL;
160 	}
161 	if (grip->cwd) {
162 		if ((grip->gflags & GF_NOALLOC) == 0)
163 			free(grip->cwd);
164 		grip->cwd	= NULL;
165 	}
166 	if (grip->device) {
167 		if ((grip->gflags & GF_NOALLOC) == 0)
168 			free(grip->device);
169 		grip->device	= NULL;
170 	}
171 	if (grip->release) {
172 		if ((grip->gflags & GF_NOALLOC) == 0)
173 			free(grip->release);
174 		grip->release	= NULL;
175 	}
176 	grip->archtype	= H_UNDEF;
177 	grip->dumptype	= 0;
178 	grip->dumplevel	= 0;
179 	grip->reflevel	= 0;
180 	grip->dumpdate.tv_sec  = 0;
181 	grip->dumpdate.tv_nsec = 0;
182 	grip->refdate.tv_sec   = 0;
183 	grip->refdate.tv_nsec  = 0;
184 	grip->volno	= 0;
185 	grip->tapesize	= 0;
186 	grip->blockoff	= 0;
187 	grip->blocksize	= 0;
188 	grip->gflags	= 0;
189 }
190 
191 /*
192  * A special string copy that is used copy strings into the limited space
193  * in the shared memory.
194  */
195 LOCAL int
xstrcpy(newp,old,p,len)196 xstrcpy(newp, old, p, len)
197 	char	**newp;
198 	char	*old;
199 	char	*p;
200 	int	len;
201 {
202 	int	slen;
203 
204 	if (old == NULL)
205 		return (0);
206 
207 	slen = strlen(old) + 1;
208 	if (slen > len)
209 		return (0);
210 	*newp = p;
211 	strncpy(p, old, len);
212 	p[len-1] = '\0';
213 
214 	return (slen);
215 }
216 
217 /*
218  * Set up the global GINFO *gip structure from a structure that just
219  * has been read from the information on the current medium.
220  * This structure is inside the shared memory if we are using the fifo.
221  */
222 EXPORT void
gipsetup(gp)223 gipsetup(gp)
224 	GINFO	*gp;
225 {
226 #ifdef	FIFO
227 extern	m_head	*mp;
228 extern	BOOL	use_fifo;
229 #endif
230 	if (gip->gflags & GF_MINIT) {
231 		return;
232 	}
233 	*gip = *gp;
234 	gip->label	= NULL;
235 	gip->hostname	= NULL;
236 	gip->filesys	= NULL;
237 	gip->cwd	= NULL;
238 	gip->device	= NULL;
239 	gip->release	= NULL;
240 
241 #ifdef	FIFO
242 	if (use_fifo) {
243 		char	*p = (char *)&gip[1];
244 		int	len = mp->rsize;
245 		int	slen;
246 
247 		slen = xstrcpy(&gip->label, gp->label, p, len);
248 		p += slen;
249 		len -= slen;
250 		slen = xstrcpy(&gip->filesys, gp->filesys, p, len);
251 		p += slen;
252 		len -= slen;
253 		slen = xstrcpy(&gip->cwd, gp->cwd, p, len);
254 		p += slen;
255 		len -= slen;
256 		slen = xstrcpy(&gip->hostname, gp->hostname, p, len);
257 		p += slen;
258 		len -= slen;
259 		slen = xstrcpy(&gip->release, gp->release, p, len);
260 		p += slen;
261 		len -= slen;
262 		slen = xstrcpy(&gip->device, gp->device, p, len);
263 		p += slen;
264 		len -= slen;
265 		gip->gflags |= GF_NOALLOC;
266 	} else
267 #endif
268 	{
269 		if (gp->label) {
270 			if (gip->label)
271 				free(gip->label);
272 			gip->label = ___savestr(gp->label);
273 		}
274 		if (gp->filesys) {
275 			if (gip->filesys)
276 				free(gip->filesys);
277 			gip->filesys = ___savestr(gp->filesys);
278 		}
279 		if (gp->cwd) {
280 			if (gip->cwd)
281 				free(gip->cwd);
282 			gip->cwd = ___savestr(gp->cwd);
283 		}
284 		if (gp->hostname) {
285 			if (gip->hostname)
286 				free(gip->hostname);
287 			gip->hostname = ___savestr(gp->hostname);
288 		}
289 		if (gp->release) {
290 			if (gip->release)
291 				free(gip->release);
292 			gip->release = ___savestr(gp->release);
293 		}
294 		if (gp->device) {
295 			if (gip->device)
296 				free(gip->device);
297 			gip->device = ___savestr(gp->device);
298 		}
299 	}
300 	if (gp->volno > 1)		/* Allow to start with vol # != 1 */
301 		stats->volno = gp->volno;
302 	gip->gflags |= GF_MINIT;
303 }
304 
305 EXPORT void
griprint(gp)306 griprint(gp)
307 	GINFO	*gp;
308 {
309 	register FILE	*f = vpr;
310 
311 	if (verbose <= 0)
312 		return;
313 
314 	if (gp->label)
315 		fgtprintf(f, "Label       %s\n", gp->label);
316 
317 	if (gp->hostname)
318 		fgtprintf(f, "Host name   %s\n", gp->hostname);
319 
320 	if (gp->filesys)
321 		fgtprintf(f, "File system %s\n", gp->filesys);
322 
323 	if (gp->cwd)
324 		fgtprintf(f, "Working dir %s\n", gp->cwd);
325 
326 	if (gp->device)
327 		fgtprintf(f, "Device      %s\n", gp->device);
328 
329 	if (gp->release)
330 		fgtprintf(f, "Release     %s\n", gp->release);
331 
332 	if (gp->archtype != H_UNDEF)
333 		fgtprintf(f, "Archtype    %s\n", hdr_name(gp->archtype));
334 
335 	if (gp->gflags & GF_DUMPTYPE)
336 		fgtprintf(f, "Dumptype    %s\n", dt_name(gp->dumptype));
337 
338 	if (gp->gflags & GF_DUMPLEVEL)
339 		fgtprintf(f, "Dumplevel   %d\n", gp->dumplevel);
340 
341 	if (gp->gflags & GF_REFLEVEL)
342 		fgtprintf(f, "Reflevel    %d\n", gp->reflevel);
343 
344 	if (gp->gflags & GF_DUMPDATE) {
345 		fgtprintf(f, "Dumpdate    %lld.%9.9lld (%s)\n",
346 			(Llong)gp->dumpdate.tv_sec,
347 			(Llong)gp->dumpdate.tv_nsec,
348 			dumpdate(&gp->dumpdate));
349 	}
350 	if (gp->gflags & GF_REFDATE) {
351 		fgtprintf(f, "Refdate     %lld.%9.9lld (%s)\n",
352 			(Llong)gp->refdate.tv_sec,
353 			(Llong)gp->refdate.tv_nsec,
354 			dumpdate(&gp->refdate));
355 	}
356 	if (gp->gflags & GF_VOLNO)
357 		fgtprintf(f, "Volno       %d\n", gp->volno);
358 	if (gp->gflags & GF_BLOCKOFF)
359 		fgtprintf(f, "Blockoff    %llu records\n", gp->blockoff);
360 	if (gp->gflags & GF_BLOCKSIZE)
361 		fprintf(f, "Blocksize   %d records\n", gp->blocksize);
362 	if (gp->gflags & GF_TAPESIZE)
363 		fgtprintf(f, "Tapesize    %llu records\n", gp->tapesize);
364 }
365 
366 EXPORT BOOL
verifyvol(buf,amt,volno,skipp)367 verifyvol(buf, amt, volno, skipp)
368 	char	*buf;
369 	int	amt;
370 	int	volno;
371 	int	*skipp;
372 {
373 	TCB	*ptb = (TCB *)buf;
374 
375 	*skipp = 0;
376 
377 	/*
378 	 * Minimale Blockgroesse ist 2,5k
379 	 * 'g' Header, 512 Byte Content and a 'V' header
380 	 */
381 	if (ptb->ustar_dbuf.t_typeflag == 'g') {
382 		if (pr_validtype(ptb->ustar_dbuf.t_typeflag) &&
383 		    tarsum_ok(ptb))
384 			return (vrfy_gvolhdr(buf, amt, volno, skipp));
385 	}
386 	if (ptb->ustar_dbuf.t_typeflag == 'x') {
387 		if (pr_validtype(ptb->ustar_dbuf.t_typeflag) &&
388 		    tarsum_ok(ptb)) {
389 			Ullong	ull;
390 			int	xlen;
391 
392 			stolli(ptb->dbuf.t_size, &ull);
393 			xlen = ull;
394 			xlen = 1 + tarblocks(xlen);
395 			*skipp += xlen;
396 			ptb = (TCB *)&((char *)ptb)[*skipp * TBLOCK];
397 		}
398 	}
399 
400 	if (ptb->ustar_dbuf.t_typeflag == 'V' ||
401 	    ptb->ustar_dbuf.t_typeflag == 'M') {
402 		if (pr_validtype(ptb->ustar_dbuf.t_typeflag) &&
403 		    tarsum_ok(ptb)) {
404 			*skipp += 1;
405 			ptb = (TCB *)&buf[*skipp * TBLOCK];
406 		}
407 	}
408 	return (TRUE);
409 }
410 
411 LOCAL BOOL
vrfy_gvolhdr(buf,amt,volno,skipp)412 vrfy_gvolhdr(buf, amt, volno, skipp)
413 	char	*buf;
414 	int	amt;
415 	int	volno;
416 	int	*skipp;
417 {
418 	TCB	*ptb = (TCB *)buf;
419 	FINFO	finfo;
420 	Ullong	ull;
421 	int	xlen = amt - TBLOCK - 1;
422 	char	*p = &buf[TBLOCK];
423 	char	*ep;
424 	char	ec;
425 	Llong	bytes;
426 	Llong	blockoff;
427 	BOOL	ret = FALSE;
428 
429 	fillbytes((char *)&finfo, sizeof (finfo), '\0');
430 	finfo.f_tcb = ptb;
431 
432 	if (init_pspace(PS_STDERR, &finfo.f_pname) < 0)
433 		return (FALSE);
434 	if (init_pspace(PS_STDERR, &finfo.f_plname) < 0)
435 		return (FALSE);
436 
437 	finfo.f_name = finfo.f_pname.ps_path;
438 	finfo.f_lname = finfo.f_plname.ps_path;
439 
440 	/*
441 	 * File size is strlen of extended header
442 	 */
443 	stolli(ptb->dbuf.t_size, &ull);
444 	if (xlen > ull)
445 		xlen = ull;
446 
447 	grinit();	/* Clear/initialize current GINFO read struct */
448 	ep = p+xlen;
449 	ec = *ep;
450 	*ep = '\0';
451 	xhparse(&finfo, p, p+xlen);
452 	*ep = ec;
453 	griprint(grip);
454 
455 	/*
456 	 * Return TRUE (no skip) if this was not a volume continuation header.
457 	 */
458 	if ((grip->gflags & GF_VOLNO) == 0) {
459 		ret = TRUE;
460 		goto out;
461 	}
462 
463 	if ((gip->dumpdate.tv_sec != grip->dumpdate.tv_sec) ||
464 	    (gip->dumpdate.tv_nsec != grip->dumpdate.tv_nsec)) {
465 		errmsgno(EX_BAD,
466 			"Dump date %s does not match expected",
467 					dumpdate(&grip->dumpdate));
468 		error(" %s\n", dumpdate(&gip->dumpdate));
469 		ret = FALSE;
470 		goto out;
471 	}
472 	if (volno != grip->volno) {
473 		errmsgno(EX_BAD,
474 			"Volume number %d does not match expected %d\n",
475 					grip->volno, volno);
476 		ret = FALSE;
477 		goto out;
478 	}
479 	bytes = stats->Tblocks * (Llong)stats->blocksize + stats->Tparts;
480 	blockoff = bytes / TBLOCK;
481 	/*
482 	 * In case we did start past Volume #1, we need to add
483 	 * the offset of the first volume we did see.
484 	 */
485 	blockoff += gip->blockoff;
486 
487 	if (grip->blockoff != 0 &&
488 	    blockoff != grip->blockoff) {
489 		comerrno(EX_BAD,
490 			"Volume offset %lld does not match expected %lld\n",
491 				grip->blockoff, blockoff);
492 			/* NOTREACHED */
493 	}
494 
495 	*skipp += 1 + tarblocks(xlen);
496 
497 	/*
498 	 * Hier mu� noch ein 'V' Header hin, sonst ist das Archiv nicht
499 	 * konform zum POSIX Standard.
500 	 * Alternativ kann aber auch ein 'M'ultivol continuation Header stehen.
501 	 */
502 	ptb = (TCB *)&buf[(1 + tarblocks(xlen)) * TBLOCK];
503 
504 	if (ptb->ustar_dbuf.t_typeflag == 'x') {
505 		if (pr_validtype(ptb->ustar_dbuf.t_typeflag) &&
506 		    tarsum_ok(ptb)) {
507 			stolli(ptb->dbuf.t_size, &ull);
508 			xlen = ull;
509 			xlen = 1 + tarblocks(xlen);
510 			*skipp += xlen;
511 			ptb = (TCB *)&((char *)ptb)[xlen * TBLOCK];
512 		}
513 	}
514 
515 	if (ptb->ustar_dbuf.t_typeflag == 'V' ||
516 	    ptb->ustar_dbuf.t_typeflag == 'M') {
517 		if (pr_validtype(ptb->ustar_dbuf.t_typeflag) &&
518 		    tarsum_ok(ptb)) {
519 			*skipp += 1;
520 		}
521 	}
522 	ret = TRUE;
523 
524 out:
525 	free_pspace(&finfo.f_pname);
526 	free_pspace(&finfo.f_plname);
527 	return (ret);
528 }
529 
530 EXPORT char *
dt_name(type)531 dt_name(type)
532 	int	type;
533 {
534 	switch (type) {
535 
536 	case DT_NONE:		return ("none");
537 	case DT_FULL:		return ("full");
538 	case DT_PARTIAL:	return ("partial");
539 	default:		return ("unknown");
540 	}
541 }
542 
543 EXPORT int
dt_type(name)544 dt_type(name)
545 	char	*name;
546 {
547 	if (streql(name, "none")) {
548 		return (DT_NONE);
549 	} else if (streql(name, "full")) {
550 		return (DT_FULL);
551 	} else if (streql(name, "partial")) {
552 		return (DT_PARTIAL);
553 	} else {
554 		return (DT_UNKN);
555 	}
556 }
557 
558 
559 EXPORT void
put_release()560 put_release()
561 {
562 	if ((props.pr_flags & PR_VU_XHDR) == 0 || props.pr_xc != 'x')
563 		return;
564 
565 	/*
566 	 * We may change this in future when more tar implementations
567 	 * implement POSIX.1-2001
568 	 */
569 	if (H_TYPE(chdrtype) == H_XUSTAR)
570 		return;
571 
572 	gen_text("SCHILY.release", vers, (size_t)-1, 0);
573 
574 	ghdr = TRUE;
575 }
576 
577 EXPORT void
put_archtype()578 put_archtype()
579 {
580 	if ((props.pr_flags & PR_VU_XHDR) == 0 || props.pr_xc != 'x')
581 		return;
582 
583 	/*
584 	 * We may change this in future when more tar implementations
585 	 * implement POSIX.1-2001
586 	 */
587 	if (H_TYPE(chdrtype) == H_XUSTAR)
588 		return;
589 
590 	gen_text("SCHILY.archtype", hdr_name(chdrtype), (size_t)-1, 0);
591 
592 	ghdr = TRUE;
593 }
594 
595 EXPORT void
put_gvolhdr(name)596 put_gvolhdr(name)
597 	char	*name;
598 {
599 	char	nbuf[1024];
600 extern	BOOL dodump;
601 
602 	if ((props.pr_flags & PR_VU_XHDR) == 0 || props.pr_xc != 'x')
603 		return;
604 
605 	/*
606 	 * We may change this in future when more tar implementations
607 	 * implement POSIX.1-2001
608 	 */
609 	if (H_TYPE(chdrtype) == H_XUSTAR)
610 		return;
611 
612 #ifndef	DEV_MINOR_NONCONTIG
613 	gen_unumber("SCHILY.devminorbits", minorbits);
614 #endif
615 
616 	gip->label = name;
617 	if (gip->dumplevel >= 0 || dodump > 1) {
618 		nbuf[0] = '\0';
619 		gethostname(nbuf, sizeof (nbuf));
620 		gip->hostname = ___savestr(nbuf);
621 	}
622 
623 	if (gip->label)
624 		gen_text("SCHILY.volhdr.label", gip->label, (size_t)-1, 0);
625 	if (gip->hostname)
626 		gen_text("SCHILY.volhdr.hostname", gip->hostname,
627 							(size_t)-1, 0);
628 	if (gip->filesys)
629 		gen_text("SCHILY.volhdr.filesys", gip->filesys, (size_t)-1, 0);
630 	if (gip->cwd)
631 		gen_text("SCHILY.volhdr.cwd", gip->cwd, (size_t)-1, 0);
632 	if (gip->device)
633 		gen_text("SCHILY.volhdr.device", gip->device, (size_t)-1, 0);
634 
635 	if (gip->dumptype > 0)
636 		gen_text("SCHILY.volhdr.dumptype", dt_name(gip->dumptype),
637 							(size_t)-1, 0);
638 	if (gip->dumplevel >= 0)
639 		gen_number("SCHILY.volhdr.dumplevel", gip->dumplevel);
640 	if (gip->reflevel >= 0)
641 		gen_number("SCHILY.volhdr.reflevel", gip->reflevel);
642 
643 	gen_xtime("SCHILY.volhdr.dumpdate", gip->dumpdate.tv_sec, gip->dumpdate.tv_nsec);
644 	if (gip->refdate.tv_sec)
645 		gen_xtime("SCHILY.volhdr.refdate", gip->refdate.tv_sec, gip->refdate.tv_nsec);
646 
647 	if (gip->volno > 0)
648 		gen_number("SCHILY.volhdr.volno", gip->volno);
649 	if (gip->blockoff > 0)
650 		gen_number("SCHILY.volhdr.blockoff", gip->blockoff);
651 	if (gip->blocksize > 0)
652 		gen_number("SCHILY.volhdr.blocksize", gip->blocksize);
653 	if (gip->tapesize > 0)
654 		gen_number("SCHILY.volhdr.tapesize", gip->tapesize);
655 
656 	if (binflag)
657 		gen_text("hdrcharset", "BINARY", (size_t)-1, 0);
658 
659 	if ((xhsize() + 2 * TBLOCK) > (gip->blocksize * TBLOCK)) {
660 		errmsgno(EX_BAD, "Panic: Tape record size too small.\n");
661 		comerrno(EX_BAD, "Panic: Shorten label or increase tape block size.\n");
662 	}
663 	ghdr = TRUE;
664 }
665 
666 EXPORT void
put_volhdr(name,putv)667 put_volhdr(name, putv)
668 	char	*name;
669 	BOOL	putv;
670 {
671 extern	Ullong	tsize;
672 
673 	if ((multivol || tsize > 0) && name == 0)
674 		name = "<none>";
675 
676 	put_gvolhdr(name);
677 
678 	if (name == 0)
679 		return;
680 
681 	if (!putv)
682 		return;	/* Only a 'g' header is needed */
683 
684 	put_svolhdr(name);
685 }
686 
687 EXPORT void
put_svolhdr(name)688 put_svolhdr(name)
689 	char	*name;
690 {
691 	FINFO	finfo;
692 	TCB	tb;
693 
694 	if ((props.pr_flags & PR_VOLHDR) == 0)
695 		return;
696 
697 	if (name == 0 || *name == '\0')
698 		name = "<none>";
699 
700 	fillbytes((char *)&finfo, sizeof (FINFO), '\0');
701 	filltcb(&tb);
702 	finfo.f_name = name;
703 	finfo.f_namelen = strlen(name);
704 	finfo.f_xftype = XT_VOLHDR;
705 	finfo.f_rxftype = XT_VOLHDR;
706 	finfo.f_mtime = ddate.tv_sec;
707 	finfo.f_mnsec = ddate.tv_nsec;
708 	finfo.f_atime = gip->volno;
709 	finfo.f_ansec = 0;
710 	finfo.f_tcb = &tb;
711 	finfo.f_xflags = XF_NOTIME;
712 
713 	if (!name_to_tcb(&finfo, &tb))	/* Name too long */
714 		return;
715 
716 	info_to_tcb(&finfo, &tb);
717 	put_tcb(&tb, &finfo);
718 	vprint(&finfo);
719 }
720 
721 EXPORT void
put_multhdr(size,off)722 put_multhdr(size, off)
723 	off_t	size;
724 	off_t	off;
725 {
726 extern	BOOL dodump;
727 	FINFO	finfo;
728 	TCB	tb;
729 	TCB	*mptb;
730 	BOOL	ododump = dodump;
731 
732 	fillbytes((char *)&finfo, sizeof (finfo), '\0');
733 
734 	if ((mptb = (TCB *)get_block(TBLOCK)) == NULL)
735 		mptb = &tb;
736 	else
737 		finfo.f_flags |= F_TCB_BUF;
738 	filltcb(mptb);
739 	strcpy(mptb->dbuf.t_name, "././@MultHeader");
740 	finfo.f_mode = TUREAD|TUWRITE;
741 	finfo.f_size = size;
742 	finfo.f_rsize = size - off;
743 	finfo.f_contoffset = off;
744 	finfo.f_xftype = XT_MULTIVOL;
745 	finfo.f_rxftype = XT_MULTIVOL;
746 	if (props.pr_flags & PR_XHDR)
747 		finfo.f_xflags |= XF_NOTIME|XF_REALSIZE|XF_OFFSET;
748 
749 	info_to_tcb(&finfo, mptb);
750 
751 	dodump = FALSE;
752 	put_tcb(mptb, &finfo);
753 	dodump = ododump;
754 }
755 
756 EXPORT BOOL
get_volhdr(info,vhname)757 get_volhdr(info, vhname)
758 	FINFO	*info;
759 	char	*vhname;
760 {
761 	error("Volhdr: %s\n", info->f_name);
762 
763 	if (vhname) {
764 		if (!streql(info->f_name, vhname))
765 			return (FALSE);
766 	}
767 
768 	return (TRUE);
769 }
770 
771 /* ARGSUSED */
772 LOCAL void
get_label(info,keyword,klen,arg,len)773 get_label(info, keyword, klen, arg, len)
774 	FINFO	*info;
775 	char	*keyword;
776 	int	klen;
777 	char	*arg;
778 	size_t	len;
779 {
780 	grip->gflags |= GF_LABEL;
781 	grip->label = ___savestr(arg);
782 }
783 
784 /* ARGSUSED */
785 LOCAL void
get_hostname(info,keyword,klen,arg,len)786 get_hostname(info, keyword, klen, arg, len)
787 	FINFO	*info;
788 	char	*keyword;
789 	int	klen;
790 	char	*arg;
791 	size_t	len;
792 {
793 	grip->gflags |= GF_HOSTNAME;
794 	grip->hostname = ___savestr(arg);
795 }
796 
797 /* ARGSUSED */
798 LOCAL void
get_filesys(info,keyword,klen,arg,len)799 get_filesys(info, keyword, klen, arg, len)
800 	FINFO	*info;
801 	char	*keyword;
802 	int	klen;
803 	char	*arg;
804 	size_t	len;
805 {
806 	grip->gflags |= GF_FILESYS;
807 	grip->filesys = ___savestr(arg);
808 }
809 
810 /* ARGSUSED */
811 LOCAL void
get_cwd(info,keyword,klen,arg,len)812 get_cwd(info, keyword, klen, arg, len)
813 	FINFO	*info;
814 	char	*keyword;
815 	int	klen;
816 	char	*arg;
817 	size_t	len;
818 {
819 	grip->gflags |= GF_CWD;
820 	grip->cwd    = ___savestr(arg);
821 }
822 
823 /* ARGSUSED */
824 LOCAL void
get_device(info,keyword,klen,arg,len)825 get_device(info, keyword, klen, arg, len)
826 	FINFO	*info;
827 	char	*keyword;
828 	int	klen;
829 	char	*arg;
830 	size_t	len;
831 {
832 	grip->gflags |= GF_DEVICE;
833 	grip->device = ___savestr(arg);
834 }
835 
836 /* ARGSUSED */
837 LOCAL void
get_dumptype(info,keyword,klen,arg,len)838 get_dumptype(info, keyword, klen, arg, len)
839 	FINFO	*info;
840 	char	*keyword;
841 	int	klen;
842 	char	*arg;
843 	size_t	len;
844 {
845 	if (len == 0) {
846 		grip->gflags &= ~GF_DUMPTYPE;
847 		grip->dumptype = 0;
848 		return;
849 	}
850 	grip->dumptype = dt_type(arg);
851 	if (grip->dumptype == DT_UNKN)
852 		errmsgno(EX_BAD, "Unknown dump type '%s'\n", arg);
853 	else
854 		grip->gflags |= GF_DUMPTYPE;
855 }
856 
857 /* ARGSUSED */
858 LOCAL void
get_dumplevel(info,keyword,klen,arg,len)859 get_dumplevel(info, keyword, klen, arg, len)
860 	FINFO	*info;
861 	char	*keyword;
862 	int	klen;
863 	char	*arg;
864 	size_t	len;
865 {
866 	Ullong	ull;
867 
868 	if (len == 0) {
869 		grip->gflags &= ~GF_DUMPLEVEL;
870 		grip->dumplevel = 0;
871 		return;
872 	}
873 	if (get_unumber(keyword, arg, &ull, 1000)) {
874 		grip->gflags |= GF_DUMPLEVEL;
875 		grip->dumplevel = ull;
876 		if (grip->dumplevel != ull) {
877 			xh_rangeerr(keyword, arg, len);
878 			grip->dumplevel = 0;
879 		}
880 	}
881 }
882 
883 /* ARGSUSED */
884 LOCAL void
get_reflevel(info,keyword,klen,arg,len)885 get_reflevel(info, keyword, klen, arg, len)
886 	FINFO	*info;
887 	char	*keyword;
888 	int	klen;
889 	char	*arg;
890 	size_t	len;
891 {
892 	Ullong	ull;
893 
894 	if (len == 0) {
895 		grip->gflags &= ~GF_REFLEVEL;
896 		grip->reflevel = 0;
897 		return;
898 	}
899 	if (get_unumber(keyword, arg, &ull, 1000)) {
900 		grip->gflags |= GF_REFLEVEL;
901 		grip->reflevel = ull;
902 		if (grip->reflevel != ull) {
903 			xh_rangeerr(keyword, arg, len);
904 			grip->reflevel = 0;
905 		}
906 	}
907 }
908 
909 /* ARGSUSED */
910 LOCAL void
get_dumpdate(info,keyword,klen,arg,len)911 get_dumpdate(info, keyword, klen, arg, len)
912 	FINFO	*info;
913 	char	*keyword;
914 	int	klen;
915 	char	*arg;
916 	size_t	len;
917 {
918 	long	nsec;
919 	time_t	t;	/* FreeBSD/MacOS X have broken tv_sec/time_t */
920 
921 	if (len == 0) {
922 		grip->gflags &= ~GF_DUMPDATE;
923 		grip->dumpdate.tv_sec  = 0;
924 		grip->dumpdate.tv_nsec = 0;
925 		return;
926 	}
927 	if (get_xtime(keyword, arg, len, &t, &nsec)) {
928 		grip->gflags |= GF_DUMPDATE;
929 		grip->dumpdate.tv_sec  = t;
930 		grip->dumpdate.tv_nsec = nsec;
931 	}
932 }
933 
934 /* ARGSUSED */
935 LOCAL void
get_refdate(info,keyword,klen,arg,len)936 get_refdate(info, keyword, klen, arg, len)
937 	FINFO	*info;
938 	char	*keyword;
939 	int	klen;
940 	char	*arg;
941 	size_t	len;
942 {
943 	long	nsec;
944 	time_t	t;	/* FreeBSD/MacOS X have broken tv_sec/time_t */
945 
946 	if (len == 0) {
947 		grip->gflags &= ~GF_REFDATE;
948 		grip->refdate.tv_sec  = 0;
949 		grip->refdate.tv_nsec = 0;
950 		return;
951 	}
952 	if (get_xtime(keyword, arg, len, &t, &nsec)) {
953 		grip->gflags |= GF_REFDATE;
954 		grip->refdate.tv_sec  = t;
955 		grip->refdate.tv_nsec = nsec;
956 	}
957 }
958 
959 /* ARGSUSED */
960 LOCAL void
get_volno(info,keyword,klen,arg,len)961 get_volno(info, keyword, klen, arg, len)
962 	FINFO	*info;
963 	char	*keyword;
964 	int	klen;
965 	char	*arg;
966 	size_t	len;
967 {
968 	Ullong	ull;
969 
970 	if (len == 0) {
971 		grip->gflags &= ~GF_VOLNO;
972 		grip->volno = 0;
973 		return;
974 	}
975 	if (get_unumber(keyword, arg, &ull, INT_MAX)) {
976 		grip->gflags |= GF_VOLNO;
977 		grip->volno = ull;
978 		if (grip->volno != ull) {
979 			xh_rangeerr(keyword, arg, len);
980 			grip->volno = 0;
981 		}
982 	}
983 }
984 
985 /* ARGSUSED */
986 LOCAL void
get_blockoff(info,keyword,klen,arg,len)987 get_blockoff(info, keyword, klen, arg, len)
988 	FINFO	*info;
989 	char	*keyword;
990 	int	klen;
991 	char	*arg;
992 	size_t	len;
993 {
994 	Ullong	ull;
995 
996 	if (len == 0) {
997 		grip->gflags &= ~GF_BLOCKOFF;
998 		grip->blockoff = 0;
999 		return;
1000 	}
1001 	if (get_unumber(keyword, arg, &ull, ULLONG_MAX)) {
1002 		grip->gflags |= GF_BLOCKOFF;
1003 		grip->blockoff = ull;
1004 		if (grip->blockoff != ull) {
1005 			xh_rangeerr(keyword, arg, len);
1006 			grip->blockoff = 0;
1007 		}
1008 	}
1009 }
1010 
1011 /* ARGSUSED */
1012 LOCAL void
get_blocksize(info,keyword,klen,arg,len)1013 get_blocksize(info, keyword, klen, arg, len)
1014 	FINFO	*info;
1015 	char	*keyword;
1016 	int	klen;
1017 	char	*arg;
1018 	size_t	len;
1019 {
1020 	Ullong	ull;
1021 
1022 	if (len == 0) {
1023 		grip->gflags &= ~GF_BLOCKSIZE;
1024 		grip->blocksize = 0;
1025 		return;
1026 	}
1027 	if (get_unumber(keyword, arg, &ull, INT_MAX)) {
1028 		grip->gflags |= GF_BLOCKSIZE;
1029 		grip->blocksize = ull;
1030 		if (grip->blocksize != ull) {
1031 			xh_rangeerr(keyword, arg, len);
1032 			grip->blocksize = 0;
1033 		}
1034 	}
1035 }
1036 
1037 /* ARGSUSED */
1038 LOCAL void
get_tapesize(info,keyword,klen,arg,len)1039 get_tapesize(info, keyword, klen, arg, len)
1040 	FINFO	*info;
1041 	char	*keyword;
1042 	int	klen;
1043 	char	*arg;
1044 	size_t	len;
1045 {
1046 	Ullong	ull;
1047 
1048 	if (len == 0) {
1049 		grip->gflags &= ~GF_TAPESIZE;
1050 		grip->tapesize = 0;
1051 		return;
1052 	}
1053 	if (get_unumber(keyword, arg, &ull, ULLONG_MAX)) {
1054 		grip->gflags |= GF_TAPESIZE;
1055 		grip->tapesize = ull;
1056 		if (grip->tapesize != ull) {
1057 			xh_rangeerr(keyword, arg, len);
1058 			grip->tapesize = 0;
1059 		}
1060 	}
1061 }
1062