xref: /csrg-svn/local/ukc/dump/dumplab.c (revision 32017)
1*32017Spc #ifndef lint
2*32017Spc static char *sccsid = "@(#)dumplab.c	1.1 (UKC) 08/07/87";
3*32017Spc #endif not lint
4*32017Spc /*
5*32017Spc  *	This file included by Peter Collinson
6*32017Spc  *	to handle tape labelling
7*32017Spc  *	There are two dump parameters which are used to specify labels
8*32017Spc  *	-l	Give the basic label format string - this may contain
9*32017Spc  *		a single %s to insert the volume number string
10*32017Spc  *	-m	Map string - used to map volume numbers into a string
11*32017Spc  *
12*32017Spc  *	Routines are:
13*32017Spc  *	storelabel(arg)		- called from main() to store a label format
14*32017Spc  *
15*32017Spc  *	storelabelmap(arg)	- called from main() to process a map argument
16*32017Spc  *				- which is
17*32017Spc  *					string		simple string
18*32017Spc  *					string-string	expanded by incrementing
19*32017Spc  *					string,string,..list of the above
20*32017Spc  *	char *
21*32017Spc  *	createlabel(volno)	- returns a label appropriate for the volume
22*32017Spc  *
23*32017Spc  *	initialtape()		- called to print an operator message asking for
24*32017Spc  *				- the 1st tape
25*32017Spc  *
26*32017Spc  *	labelest(etapes)	- checks if there are enough tape labels
27*32017Spc  *				- specified for a given dump
28*32017Spc  *
29*32017Spc  *	labelcheck()		- reads one record from tape
30*32017Spc  *				- checks that the labels match
31*32017Spc  *				- backspace one record back
32*32017Spc  *				- so that multi-volume dumps work
33*32017Spc  *
34*32017Spc  *	log_volume()		- write a logfile entry for the volume
35*32017Spc  *
36*32017Spc  *	This file also contains the rewind_offline() routine so that
37*32017Spc  *	the tape can be dismounted at the end of each volume write
38*32017Spc  *
39*32017Spc  */
40*32017Spc 
41*32017Spc #include "dump.h"
42*32017Spc #include <sys/ioctl.h>
43*32017Spc #include <sys/mtio.h>
44*32017Spc #include <math.h>
45*32017Spc 
46*32017Spc 
47*32017Spc #define	LABMAX	100		/* get space for 100 */
48*32017Spc 
49*32017Spc char	*labfmt;		/* Basic tape format */
50*32017Spc 
51*32017Spc char	*labarg[LABMAX];	/* Pointer to argument list */
52*32017Spc 
53*32017Spc int	labct;			/* number of entries */
54*32017Spc 				/* if zero then no labels used */
55*32017Spc 
56*32017Spc int	labchk;			/* check labels - set by t(est) flag */
57*32017Spc 
58*32017Spc /*
59*32017Spc  *	The file /etc/dumpvolumes is used to maintain a log of
60*32017Spc  *	tapes which are/have been used for tape dumping
61*32017Spc  *	The format is:
62*32017Spc  *	label: date dev=<devname> level=<dump level> reel=<volume number> inode=<start inode>
63*32017Spc  */
64*32017Spc char dumpvolumes[] = "/etc/dumpvolumes";
65*32017Spc 
66*32017Spc /*
67*32017Spc  *	Called from argument decoding to store the
68*32017Spc  *	basic label format
69*32017Spc  *	This is the parameter to the -l parameter
70*32017Spc  */
71*32017Spc storelabel(arg)
72*32017Spc 	char *arg;
73*32017Spc {
74*32017Spc 	labelarg = arg;
75*32017Spc 
76*32017Spc }
77*32017Spc 
78*32017Spc /*
79*32017Spc  *	Store map list
80*32017Spc  *	The map list
81*32017Spc  *	allows a simple way to specify a range of tapes
82*32017Spc  *	This generates a string which is inserted into the label format
83*32017Spc  *	by use of an sprint operation
84*32017Spc  *
85*32017Spc  *	The basic form here is:
86*32017Spc  *	<string>			a single string
87*32017Spc  *	<string>,<string>,......	a list of strings
88*32017Spc  *	<string>-<string>		a range of strings
89*32017Spc  *					where the string is `incremented'
90*32017Spc  *					to generate a list
91*32017Spc  */
92*32017Spc storelabelmap(arg)
93*32017Spc 	char *arg;
94*32017Spc {
95*32017Spc 	register char *ss, *es;
96*32017Spc 	register char *incbase, *incr;
97*32017Spc 	register lastc;
98*32017Spc 	char *labskip();
99*32017Spc 
100*32017Spc 	/*
101*32017Spc 	 *	Parse the argument looking for a single string
102*32017Spc 	 */
103*32017Spc 	for (ss = arg; *ss; ss = es, labct++) {
104*32017Spc 		es = labskip(ss);
105*32017Spc 		lastc = *es;	/* save last character */
106*32017Spc 		*es++ = '\0';	/* make the first label into a string */
107*32017Spc 		if (labct > LABMAX)
108*32017Spc 			labfatal("Too many (> %d) tape labels specified\n", LABMAX);
109*32017Spc 		lablist[labct++] = strstore(ss);
110*32017Spc 
111*32017Spc 		if (lastch == 0)
112*32017Spc 			break;		/* end of list */
113*32017Spc 
114*32017Spc 		if (lastch == '-') {
115*32017Spc 			/*
116*32017Spc 			 * this gives a tape range
117*32017Spc 			 * increment the source number until it equals the final
118*32017Spc 			 * value
119*32017Spc 			 */
120*32017Spc 			incbase = ss;
121*32017Spc 			ss = es;
122*32017Spc 			es = labskip(ss);
123*32017Spc 			if (*es == '-')
124*32017Spc 				labfatal("Range has the format <string>-<string>\n");
125*32017Spc 			lastch = *es;
126*32017Spc 			*es = '\0';
127*32017Spc 			/*
128*32017Spc 			 * basic test the source string length must be equal to the
129*32017Spc 			 * end string length
130*32017Spc 			 */
131*32017Spc 			if (strlen(incbase) != strlen(ss))
132*32017Spc 				labfatal("strlen(\"%s\") != strlen(\"%s\")\n", incbase, ss);
133*32017Spc 			labelrange(incbase, ss);
134*32017Spc 		}
135*32017Spc 	}
136*32017Spc }
137*32017Spc 
138*32017Spc /*
139*32017Spc  *	Expand a label range
140*32017Spc  */
141*32017Spc /* static */
142*32017Spc labelrange(startrange, endrange)
143*32017Spc 	char *startrange, *endrange;
144*32017Spc {
145*32017Spc 	register char *incr;
146*32017Spc 	register int carry;
147*32017Spc 
148*32017Spc 
149*32017Spc 	for (incr = startrange + strlen(startrange) - 1;
150*32017Spc 			strcmp(startrange, endrange) != 0; ) {
151*32017Spc 		/* start incrementing */
152*32017Spc 		for (carry = 0; carry; ) {
153*32017Spc 			if (isdigit(*incr)) {
154*32017Spc 				if (*incr == '9') {
155*32017Spc 					*incr = '0';
156*32017Spc 					carry = 1;
157*32017Spc 				} else
158*32017Spc 					*incr++;
159*32017Spc 			} else
160*32017Spc 			if (isupper(*incr)) {
161*32017Spc 				if (*incr == 'Z') {
162*32017Spc 					*incr = 'A';
163*32017Spc 					carry = 1;
164*32017Spc 				} else
165*32017Spc 					*incr++;
166*32017Spc 			} else
167*32017Spc 			if (islower(*incr)) {
168*32017Spc 				if (*incr == 'z') {
169*32017Spc 					*incr = 'a';
170*32017Spc 					carry = 1;
171*32017Spc 				} else
172*32017Spc 					*incr++;
173*32017Spc 			} else
174*32017Spc 				labfatal("Problem with label map range spec - can only increment alphanumeric values\n");
175*32017Spc 			if (carry) {
176*32017Spc 				incr--;
177*32017Spc 				if (incr < startrange)
178*32017Spc 					labfatal("Problem with label map range spec - end of range reached\n");
179*32017Spc 			}
180*32017Spc 		}
181*32017Spc 		if (labct > LABMAX)
182*32017Spc 			labfatal("Too many (> %d) tape labels specified\n", LABMAX);
183*32017Spc 		lablist[labct++] = strstore(startrange);
184*32017Spc 
185*32017Spc 	}
186*32017Spc }
187*32017Spc 
188*32017Spc /*
189*32017Spc  *	Store a string using malloc
190*32017Spc  */
191*32017Spc /* static */
192*32017Spc char *
193*32017Spc strstore(arg)
194*32017Spc 	char *arg;
195*32017Spc {
196*32017Spc 	register len = strlen(arg)+1;
197*32017Spc 	register char *dest;
198*32017Spc 
199*32017Spc 	dest = malloc(len);
200*32017Spc 	if (dest == NULL)
201*32017Spc 		labfatal("No memory for string storage\n");
202*32017Spc 	bcopy(arg, dest, len);
203*32017Spc 	return(dest);
204*32017Spc }
205*32017Spc 
206*32017Spc /*
207*32017Spc  *	Create a tape label from a volume number
208*32017Spc  *	if have not had a -l or -m parameter - return none
209*32017Spc  *	if have not had a -l parameter - set format to %s
210*32017Spc  *	if have not had a -m paramter - pass the volume number as a string
211*32017Spc  */
212*32017Spc char *
213*32017Spc createlabel(volno)
214*32017Spc 	int volno;
215*32017Spc {
216*32017Spc 	static char buf[LBLSIZE+LBLSIZE];
217*32017Spc 	static char volbuf[8];
218*32017Spc 	static int lastvol;
219*32017Spc 	register char *arg;
220*32017Spc 
221*32017Spc 	if (labfmt == NULL && labct == 0)
222*32017Spc 		return ("none");		/* previous behaviour */
223*32017Spc 
224*32017Spc 	if (volno == lastvol)
225*32017Spc 		return(buf);
226*32017Spc 
227*32017Spc 	if (labelfmt == NULL)
228*32017Spc 		labelfmt = "%s";
229*32017Spc 
230*32017Spc 	if (labct == 0)
231*32017Spc 	{	(void) sprintf(volbuf, "%d", volno);
232*32017Spc 		arg = volbuf;
233*32017Spc 	}
234*32017Spc 	else
235*32017Spc 		arg = lablist[volno];
236*32017Spc 	(void) sprintf(buf, labelfmt, lablist[volno - 1]);	/* volumes run 1-> */
237*32017Spc 	buf[LBLSIZE-1] = '\0';
238*32017Spc 	return(buf);
239*32017Spc }
240*32017Spc 
241*32017Spc initialtape()
242*32017Spc {	static firstpr;
243*32017Spc 
244*32017Spc 	if (labchk == 0)
245*32017Spc 		return;
246*32017Spc 	if (firstpr == 0)
247*32017Spc 		msg("Mount tape %s for reel 1 of the dump\n", createlabel(0));
248*32017Spc 	firstpr = 1;
249*32017Spc }
250*32017Spc 
251*32017Spc /*
252*32017Spc  *	given an estimated number of tapes, check that
253*32017Spc  *	there are enough tapes on the label list
254*32017Spc  */
255*32017Spc labelest(etapes)
256*32017Spc 	double etapes;
257*32017Spc {	int et;
258*32017Spc 
259*32017Spc 	if (labct) {
260*32017Spc 		et = ceil(etapes);
261*32017Spc 		if (et > labct)
262*32017Spc 			labfatal("Only %d labe%s given, estimated need %d\n",
263*32017Spc 				labct, labct == 1 ? "l" : "ls", et);
264*32017Spc 	}
265*32017Spc }
266*32017Spc 
267*32017Spc /*
268*32017Spc  *	labelcheck
269*32017Spc  *	read a dump header and check that the tape header contains
270*32017Spc  *	the label we expected
271*32017Spc  *	close the fd on error to allow upper levels to loop
272*32017Spc  */
273*32017Spc labelcheck(fd, tno)
274*32017Spc 	int fd;
275*32017Spc 	int tno;
276*32017Spc {
277*32017Spc 	union u_spcl uin;	/* lots on the stack but that should be OK */
278*32017Spc 	register char *label;
279*32017Spc 	register char *ontape = uin.s_spcl.c_label;
280*32017Spc 	struct mtop mtop;
281*32017Spc 
282*32017Spc 	if (labchk == 0 || pipeout)
283*32017Spc 		return(0);
284*32017Spc 	label = createlabel(tno);
285*32017Spc 	if (read(fd, (char *)&uin, sizeof uin) != sizeof uin) {
286*32017Spc 		msg("Tape does not start with the correctly sized record\n");
287*32017Spc 		close(fd);
288*32017Spc 		return(-1);
289*32017Spc 	}
290*32017Spc 	if (ontape[0] == '\0' ||
291*32017Spc 	    strcmp(ontape, "none") == 0 ||
292*32017Spc 	    strcmp(ontape, label) == 0) {
293*32017Spc 		/* skip back one record */
294*32017Spc 		mtop.mt_op = MTBSR;
295*32017Spc 		mtop.mt_count = 1;
296*32017Spc #ifdef RDUMP
297*32017Spc 		if (rmtioctl(fd, MTIOCTOP, &mtop) < 0)
298*32017Spc #else RDUMP
299*32017Spc 		if (ioctl(fd, MTIOCTOP, &mtop) < 0)
300*32017Spc #endif RDUMP
301*32017Spc 			labfatal("Label check cannot backspace tape\n");
302*32017Spc 		return(0);
303*32017Spc 	}
304*32017Spc 	msg("Tape labels do not match should be `%s' is `%s'\n", label, ontape);
305*32017Spc 	close(fd);
306*32017Spc 	return(-1);
307*32017Spc }
308*32017Spc 
309*32017Spc /*
310*32017Spc  *	write a log entry for the volume into the log file
311*32017Spc  */
312*32017Spc log_volume()
313*32017Spc {
314*32017Spc 	char *ctime();
315*32017Spc 	FILE *logfd;
316*32017Spc 
317*32017Spc 	if (uflag == 0 || labchk == 0)
318*32017Spc 		return;
319*32017Spc 	if ((logfd = fopen(dumpvolume, "a")) == NULL)
320*32017Spc 		return;
321*32017Spc 	fprintf(logfd, "%s: date=%20.20s dev=%s level=%c reel=%d ino=%d\n",
322*32017Spc 			tlabel, ctime(&spcl.c_date)+4, disk, incno, tapeno,
323*32017Spc 			tapeno == 1 ? ROOTINO : ino);
324*32017Spc 	fclose(logfd);
325*32017Spc }
326*32017Spc 
327*32017Spc /*
328*32017Spc  *	skip forward looking for valid end of label characters
329*32017Spc  */
330*32017Spc /* static */
331*32017Spc char *
332*32017Spc labskip(str)
333*32017Spc 	register char *str;
334*32017Spc {
335*32017Spc 	while (*str != ',' && *str != '-' && *str)
336*32017Spc 		str++;
337*32017Spc 	return (str);
338*32017Spc }
339*32017Spc 
340*32017Spc /*
341*32017Spc  *	generate a fatal error message
342*32017Spc  */
343*32017Spc 	/* VARARGS1 */
344*32017Spc 	/* ARGSUSED */
345*32017Spc labfatal(fmt, a1, a2, a3, a4, a5)
346*32017Spc 	char	*fmt;
347*32017Spc 	int	a1, a2, a3, a4, a5;
348*32017Spc {
349*32017Spc 	msg(fmt, a1, a2, a3, a4, a5);
350*32017Spc 	dumpabort();
351*32017Spc }
352*32017Spc 
353*32017Spc 
354*32017Spc /*
355*32017Spc  *	put a tape drive offline
356*32017Spc  */
357*32017Spc rewind_offline(fd)
358*32017Spc {
359*32017Spc 	struct mtop mtop;
360*32017Spc 
361*32017Spc #ifdef RDUMP
362*32017Spc #define ioctl rmtioctl
363*32017Spc #endif RDUMP
364*32017Spc 
365*32017Spc 	mtop.mt_op = MTWEOF;
366*32017Spc 	mtop.mt_count = 1;
367*32017Spc 	if (ioctl(fd, MTIOCTOP, &mtop) < 0)
368*32017Spc 		perror("Cannot write end of file record");
369*32017Spc 	mtop.mt_op = MTWEOF;
370*32017Spc 	mtop.mt_count = 1;
371*32017Spc 	if (ioctl(fd, MTIOCTOP, &mtop) < 0)
372*32017Spc 		perror("Cannot write end of file record");
373*32017Spc 	mtop.mt_op = MTOFFL;
374*32017Spc 	mtop.mt_count = 1;
375*32017Spc 	if (ioctl(fd, MTIOCTOP, &mtop) < 0)
376*32017Spc 		perror("Cannot put the tape offline");
377*32017Spc }
378