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