1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 3*0Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 4*0Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 5*0Sstevel@tonic-gate */ 6*0Sstevel@tonic-gate 7*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 8*0Sstevel@tonic-gate /* All Rights Reserved */ 9*0Sstevel@tonic-gate 10*0Sstevel@tonic-gate /* 11*0Sstevel@tonic-gate * Copyright 1994, 1996, 1998-2003 Sun Microsystems, Inc. All rights reserved. 12*0Sstevel@tonic-gate * Use is subject to license terms. 13*0Sstevel@tonic-gate */ 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate #include <setjmp.h> 18*0Sstevel@tonic-gate #include "restore.h" 19*0Sstevel@tonic-gate #include <byteorder.h> 20*0Sstevel@tonic-gate #include <rmt.h> 21*0Sstevel@tonic-gate #include <sys/mtio.h> 22*0Sstevel@tonic-gate #include <utime.h> 23*0Sstevel@tonic-gate #include <sys/errno.h> 24*0Sstevel@tonic-gate #include <sys/fdio.h> 25*0Sstevel@tonic-gate #include <sys/sysmacros.h> /* for expdev */ 26*0Sstevel@tonic-gate #include <assert.h> 27*0Sstevel@tonic-gate #include <limits.h> 28*0Sstevel@tonic-gate #include <priv_utils.h> 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #define MAXINO 65535 /* KLUDGE */ 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #define MAXTAPES 128 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate static size_t fssize = MAXBSIZE; /* preferred size of writes to filesystem */ 35*0Sstevel@tonic-gate int mt = -1; 36*0Sstevel@tonic-gate static int continuemap = 0; 37*0Sstevel@tonic-gate char magtape[BUFSIZ]; 38*0Sstevel@tonic-gate int pipein = 0; 39*0Sstevel@tonic-gate char *host; /* used in dumprmt.c */ 40*0Sstevel@tonic-gate daddr32_t rec_position; 41*0Sstevel@tonic-gate static char *archivefile; /* used in metamucil.c */ 42*0Sstevel@tonic-gate static int bct; /* block # index into tape record buffer */ 43*0Sstevel@tonic-gate static int numtrec; /* # of logical blocks in current tape record */ 44*0Sstevel@tonic-gate static char *tbf = NULL; 45*0Sstevel@tonic-gate static size_t tbfsize = 0; 46*0Sstevel@tonic-gate static int recsread; 47*0Sstevel@tonic-gate static union u_spcl endoftapemark; 48*0Sstevel@tonic-gate static struct s_spcl dumpinfo; 49*0Sstevel@tonic-gate static long blksread; /* # of logical blocks actually read/touched */ 50*0Sstevel@tonic-gate static long tapea; /* current logical block # on tape */ 51*0Sstevel@tonic-gate static uchar_t tapesread[MAXTAPES]; 52*0Sstevel@tonic-gate static jmp_buf restart; 53*0Sstevel@tonic-gate static int gettingfile = 0; /* restart has a valid frame */ 54*0Sstevel@tonic-gate static int ofile; 55*0Sstevel@tonic-gate static char *map, *beginmap; 56*0Sstevel@tonic-gate static char *endmap; 57*0Sstevel@tonic-gate static char lnkbuf[MAXPATHLEN + 2]; 58*0Sstevel@tonic-gate static int pathlen; 59*0Sstevel@tonic-gate static int inodeinfo; /* Have starting volume information */ 60*0Sstevel@tonic-gate static int hostinfo; /* Have dump host information */ 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate #ifdef __STDC__ 63*0Sstevel@tonic-gate static int autoload_tape(void); 64*0Sstevel@tonic-gate static void setdumpnum(void); 65*0Sstevel@tonic-gate static void metacheck(struct s_spcl *); 66*0Sstevel@tonic-gate static void xtrmeta(char *, size_t); 67*0Sstevel@tonic-gate static void metaskip(char *, size_t); 68*0Sstevel@tonic-gate static void xtrfile(char *, size_t); 69*0Sstevel@tonic-gate static void xtrskip(char *, size_t); 70*0Sstevel@tonic-gate static void xtrlnkfile(char *, size_t); 71*0Sstevel@tonic-gate static void xtrlnkskip(char *, size_t); 72*0Sstevel@tonic-gate static void xtrmap(char *, size_t); 73*0Sstevel@tonic-gate static void xtrmapskip(char *, size_t); 74*0Sstevel@tonic-gate static void readtape(char *); 75*0Sstevel@tonic-gate static int checkvol(struct s_spcl *, int); 76*0Sstevel@tonic-gate static void accthdr(struct s_spcl *); 77*0Sstevel@tonic-gate static int ishead(struct s_spcl *); 78*0Sstevel@tonic-gate static checktype(struct s_spcl *, int); 79*0Sstevel@tonic-gate static void metaset(char *name); 80*0Sstevel@tonic-gate #else 81*0Sstevel@tonic-gate static int autoload_tape(); 82*0Sstevel@tonic-gate static void setdumpnum(); 83*0Sstevel@tonic-gate static void metacheck(); 84*0Sstevel@tonic-gate static void xtrmeta(); 85*0Sstevel@tonic-gate static void metaskip(); 86*0Sstevel@tonic-gate static void xtrfile(); 87*0Sstevel@tonic-gate static void xtrskip(); 88*0Sstevel@tonic-gate static void xtrlnkfile(); 89*0Sstevel@tonic-gate static void xtrlnkskip(); 90*0Sstevel@tonic-gate static void xtrmap(); 91*0Sstevel@tonic-gate static void xtrmapskip(); 92*0Sstevel@tonic-gate static void readtape(); 93*0Sstevel@tonic-gate static int checkvol(); 94*0Sstevel@tonic-gate static void accthdr(); 95*0Sstevel@tonic-gate static int ishead(); 96*0Sstevel@tonic-gate static checktype(); 97*0Sstevel@tonic-gate static void metaset(); 98*0Sstevel@tonic-gate #endif 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate /* 101*0Sstevel@tonic-gate * Set up an input source 102*0Sstevel@tonic-gate */ 103*0Sstevel@tonic-gate void 104*0Sstevel@tonic-gate setinput(source, archive) 105*0Sstevel@tonic-gate char *source; 106*0Sstevel@tonic-gate char *archive; 107*0Sstevel@tonic-gate { 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate flsht(); 110*0Sstevel@tonic-gate archivefile = archive; 111*0Sstevel@tonic-gate if (bflag == 0) { 112*0Sstevel@tonic-gate ntrec = ((CARTRIDGETREC > HIGHDENSITYTREC) ? 113*0Sstevel@tonic-gate (NTREC > CARTRIDGETREC ? NTREC : CARTRIDGETREC) : 114*0Sstevel@tonic-gate (NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC)); 115*0Sstevel@tonic-gate saved_ntrec = (ntrec * (tp_bsize/DEV_BSIZE)); 116*0Sstevel@tonic-gate } 117*0Sstevel@tonic-gate newtapebuf(ntrec); 118*0Sstevel@tonic-gate terminal = stdin; 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate if (source == NULL) { 121*0Sstevel@tonic-gate /* A can't-happen */ 122*0Sstevel@tonic-gate (void) fprintf(stderr, 123*0Sstevel@tonic-gate gettext("Internal consistency check failed.\n")); 124*0Sstevel@tonic-gate done(1); 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate if (strchr(source, ':')) { 128*0Sstevel@tonic-gate char *tape; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate host = source; 131*0Sstevel@tonic-gate tape = strchr(host, ':'); 132*0Sstevel@tonic-gate *tape++ = '\0'; 133*0Sstevel@tonic-gate if (strlen(tape) > (sizeof (magtape) - 1)) { 134*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Tape name too long\n")); 135*0Sstevel@tonic-gate done(1); 136*0Sstevel@tonic-gate } 137*0Sstevel@tonic-gate (void) strcpy(magtape, tape); 138*0Sstevel@tonic-gate if (rmthost(host, ntrec) == 0) 139*0Sstevel@tonic-gate done(1); 140*0Sstevel@tonic-gate } else { 141*0Sstevel@tonic-gate if (strlen(source) > (sizeof (magtape) - 1)) { 142*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Tape name too long\n")); 143*0Sstevel@tonic-gate done(1); 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate /* Not remote, no need for privileges */ 146*0Sstevel@tonic-gate __priv_relinquish(); 147*0Sstevel@tonic-gate host = NULL; 148*0Sstevel@tonic-gate if (strcmp(source, "-") == 0) { 149*0Sstevel@tonic-gate /* 150*0Sstevel@tonic-gate * Since input is coming from a pipe we must establish 151*0Sstevel@tonic-gate * our own connection to the terminal. 152*0Sstevel@tonic-gate */ 153*0Sstevel@tonic-gate terminal = fopen("/dev/tty", "r"); 154*0Sstevel@tonic-gate if (terminal == NULL) { 155*0Sstevel@tonic-gate int saverr = errno; 156*0Sstevel@tonic-gate char *msg = 157*0Sstevel@tonic-gate gettext("Cannot open(\"/dev/tty\")"); 158*0Sstevel@tonic-gate errno = saverr; 159*0Sstevel@tonic-gate perror(msg); 160*0Sstevel@tonic-gate terminal = fopen("/dev/null", "r"); 161*0Sstevel@tonic-gate if (terminal == NULL) { 162*0Sstevel@tonic-gate saverr = errno; 163*0Sstevel@tonic-gate msg = gettext( 164*0Sstevel@tonic-gate "Cannot open(\"/dev/null\")"); 165*0Sstevel@tonic-gate errno = saverr; 166*0Sstevel@tonic-gate perror(msg); 167*0Sstevel@tonic-gate done(1); 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate pipein++; 171*0Sstevel@tonic-gate if (archive) { 172*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 173*0Sstevel@tonic-gate "Cannot specify an archive file when reading from a pipe\n")); 174*0Sstevel@tonic-gate done(1); 175*0Sstevel@tonic-gate } 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate (void) strcpy(magtape, source); 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate } 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate void 182*0Sstevel@tonic-gate newtapebuf(size) 183*0Sstevel@tonic-gate size_t size; 184*0Sstevel@tonic-gate { 185*0Sstevel@tonic-gate size_t nsize; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate nsize = size * tp_bsize; 188*0Sstevel@tonic-gate ntrec = size; 189*0Sstevel@tonic-gate if (nsize <= tbfsize) 190*0Sstevel@tonic-gate return; 191*0Sstevel@tonic-gate if (tbf != NULL) 192*0Sstevel@tonic-gate free(tbf); 193*0Sstevel@tonic-gate tbf = (char *)malloc(nsize); 194*0Sstevel@tonic-gate if (tbf == NULL) { 195*0Sstevel@tonic-gate (void) fprintf(stderr, 196*0Sstevel@tonic-gate gettext("Cannot allocate space for buffer\n")); 197*0Sstevel@tonic-gate done(1); 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate tbfsize = nsize; 200*0Sstevel@tonic-gate } 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate /* 203*0Sstevel@tonic-gate * Verify that the tape drive can be accessed and 204*0Sstevel@tonic-gate * that it actually is a dump tape. 205*0Sstevel@tonic-gate */ 206*0Sstevel@tonic-gate void 207*0Sstevel@tonic-gate #ifdef __STDC__ 208*0Sstevel@tonic-gate setup(void) 209*0Sstevel@tonic-gate #else 210*0Sstevel@tonic-gate setup() 211*0Sstevel@tonic-gate #endif 212*0Sstevel@tonic-gate { 213*0Sstevel@tonic-gate int i, j; 214*0Sstevel@tonic-gate int32_t *ip; 215*0Sstevel@tonic-gate struct stat stbuf; 216*0Sstevel@tonic-gate size_t mapsize; 217*0Sstevel@tonic-gate char *syment = RESTORESYMTABLE; 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate vprintf(stdout, gettext("Verify volume and initialize maps\n")); 220*0Sstevel@tonic-gate if (archivefile) { 221*0Sstevel@tonic-gate mt = open(archivefile, O_RDONLY|O_LARGEFILE); 222*0Sstevel@tonic-gate if (mt < 0) { 223*0Sstevel@tonic-gate perror(archivefile); 224*0Sstevel@tonic-gate done(1); 225*0Sstevel@tonic-gate } 226*0Sstevel@tonic-gate volno = 0; 227*0Sstevel@tonic-gate } else if (host) { 228*0Sstevel@tonic-gate if ((mt = rmtopen(magtape, O_RDONLY)) < 0) { 229*0Sstevel@tonic-gate perror(magtape); 230*0Sstevel@tonic-gate done(1); 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate volno = 1; 233*0Sstevel@tonic-gate } else { 234*0Sstevel@tonic-gate if (pipein) 235*0Sstevel@tonic-gate mt = 0; 236*0Sstevel@tonic-gate else if ((mt = open(magtape, O_RDONLY|O_LARGEFILE)) < 0) { 237*0Sstevel@tonic-gate perror(magtape); 238*0Sstevel@tonic-gate done(1); 239*0Sstevel@tonic-gate } 240*0Sstevel@tonic-gate volno = 1; 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate setdumpnum(); 243*0Sstevel@tonic-gate flsht(); 244*0Sstevel@tonic-gate if (!pipein && !bflag) 245*0Sstevel@tonic-gate if (archivefile) 246*0Sstevel@tonic-gate findtapeblksize(ARCHIVE_FILE); 247*0Sstevel@tonic-gate else 248*0Sstevel@tonic-gate findtapeblksize(TAPE_FILE); 249*0Sstevel@tonic-gate if (bflag == 1) { 250*0Sstevel@tonic-gate tape_rec_size = saved_ntrec * DEV_BSIZE; 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate /* 254*0Sstevel@tonic-gate * Get the first header. If c_magic is NOT NFS_MAGIC or if 255*0Sstevel@tonic-gate * the checksum is in error, it will fail. The magic could then 256*0Sstevel@tonic-gate * be either OFS_MAGIC or MTB_MAGIC. If OFS_MAGIC, assume we 257*0Sstevel@tonic-gate * have an old dump, and try to convert it. If it is MTB_MAGIC, we 258*0Sstevel@tonic-gate * procees this after. 259*0Sstevel@tonic-gate */ 260*0Sstevel@tonic-gate if ((gethead(&spcl) == FAIL) && (spcl.c_magic != MTB_MAGIC)) { 261*0Sstevel@tonic-gate bct--; /* push back this block */ 262*0Sstevel@tonic-gate blksread--; 263*0Sstevel@tonic-gate tapea--; 264*0Sstevel@tonic-gate cvtflag++; 265*0Sstevel@tonic-gate if (gethead(&spcl) == FAIL) { 266*0Sstevel@tonic-gate (void) fprintf(stderr, 267*0Sstevel@tonic-gate gettext("Volume is not in dump format\n")); 268*0Sstevel@tonic-gate done(1); 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate (void) fprintf(stderr, 271*0Sstevel@tonic-gate gettext("Converting to new file system format.\n")); 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate /* 274*0Sstevel@tonic-gate * The above gethead will have failed if the magic is 275*0Sstevel@tonic-gate * MTB_MAGIC. If that is true, we need to adjust tp_bsize. 276*0Sstevel@tonic-gate * We have assumed to this time that tp_bsize was 1024, if 277*0Sstevel@tonic-gate * this is a newer dump, get the real tp_bsize from the header, 278*0Sstevel@tonic-gate * and recalculate ntrec, numtrec. 279*0Sstevel@tonic-gate */ 280*0Sstevel@tonic-gate if (spcl.c_magic == MTB_MAGIC) { 281*0Sstevel@tonic-gate tp_bsize = spcl.c_tpbsize; 282*0Sstevel@tonic-gate if ((tp_bsize % TP_BSIZE_MIN != 0) || 283*0Sstevel@tonic-gate (tp_bsize > TP_BSIZE_MAX)) { 284*0Sstevel@tonic-gate (void) fprintf(stderr, 285*0Sstevel@tonic-gate gettext("Volume is not in dump format\n")); 286*0Sstevel@tonic-gate done(1); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate ntrec = (tape_rec_size/tp_bsize); 289*0Sstevel@tonic-gate numtrec = ntrec; 290*0Sstevel@tonic-gate newtapebuf(ntrec); 291*0Sstevel@tonic-gate bct--; /* push back this block */ 292*0Sstevel@tonic-gate blksread--; 293*0Sstevel@tonic-gate tapea--; 294*0Sstevel@tonic-gate /* we have to re-do this in case checksum is wrong */ 295*0Sstevel@tonic-gate if (gethead(&spcl) == FAIL) { 296*0Sstevel@tonic-gate (void) fprintf(stderr, 297*0Sstevel@tonic-gate gettext("Volume is not in dump format\n")); 298*0Sstevel@tonic-gate done(1); 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate if (vflag) 302*0Sstevel@tonic-gate byteorder_banner(byteorder, stdout); 303*0Sstevel@tonic-gate if (pipein) { 304*0Sstevel@tonic-gate endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : 305*0Sstevel@tonic-gate ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC); 306*0Sstevel@tonic-gate endoftapemark.s_spcl.c_type = TS_END; 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate /* 309*0Sstevel@tonic-gate * include this since the `resync' loop in findinode 310*0Sstevel@tonic-gate * expects to find a header with the c_date field 311*0Sstevel@tonic-gate * filled in. 312*0Sstevel@tonic-gate */ 313*0Sstevel@tonic-gate endoftapemark.s_spcl.c_date = spcl.c_date; 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate ip = (int32_t *)&endoftapemark; 316*0Sstevel@tonic-gate /*LINTED [assertion always true]*/ 317*0Sstevel@tonic-gate assert((sizeof (endoftapemark) % sizeof (int32_t)) == 0); 318*0Sstevel@tonic-gate j = sizeof (endoftapemark) / sizeof (int32_t); 319*0Sstevel@tonic-gate i = 0; 320*0Sstevel@tonic-gate do 321*0Sstevel@tonic-gate i += *ip++; 322*0Sstevel@tonic-gate while (--j); 323*0Sstevel@tonic-gate endoftapemark.s_spcl.c_checksum = CHECKSUM - i; 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate if (vflag && command != 't') 326*0Sstevel@tonic-gate printdumpinfo(); 327*0Sstevel@tonic-gate dumptime = spcl.c_ddate; 328*0Sstevel@tonic-gate dumpdate = spcl.c_date; 329*0Sstevel@tonic-gate if (stat(".", &stbuf) < 0) { 330*0Sstevel@tonic-gate perror(gettext("cannot stat .")); 331*0Sstevel@tonic-gate done(1); 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate if (stbuf.st_blksize >= tp_bsize && stbuf.st_blksize <= MAXBSIZE) { 334*0Sstevel@tonic-gate /* LINTED: value fits in a size_t */ 335*0Sstevel@tonic-gate fssize = stbuf.st_blksize; 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate if (((fssize - 1) & fssize) != 0) { 338*0Sstevel@tonic-gate (void) fprintf(stderr, 339*0Sstevel@tonic-gate gettext("bad filesystem block size %d\n"), fssize); 340*0Sstevel@tonic-gate done(1); 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate if (checkvol(&spcl, 1) == FAIL) { 343*0Sstevel@tonic-gate (void) fprintf(stderr, 344*0Sstevel@tonic-gate gettext("This is not volume 1 of the dump\n")); 345*0Sstevel@tonic-gate done(1); 346*0Sstevel@tonic-gate } 347*0Sstevel@tonic-gate if (readhdr(&spcl) == FAIL) 348*0Sstevel@tonic-gate panic(gettext("no header after volume mark!\n")); 349*0Sstevel@tonic-gate 350*0Sstevel@tonic-gate findinode(&spcl); /* sets curfile, resyncs the tape if need be */ 351*0Sstevel@tonic-gate if (checktype(&spcl, TS_CLRI) == FAIL) { 352*0Sstevel@tonic-gate (void) fprintf(stderr, 353*0Sstevel@tonic-gate gettext("Cannot find file removal list\n")); 354*0Sstevel@tonic-gate done(1); 355*0Sstevel@tonic-gate } 356*0Sstevel@tonic-gate maxino = (unsigned)((spcl.c_count * tp_bsize * NBBY) + 1); 357*0Sstevel@tonic-gate dprintf(stdout, "maxino = %lu\n", maxino); 358*0Sstevel@tonic-gate /* 359*0Sstevel@tonic-gate * Allocate space for at least MAXINO inodes to allow us 360*0Sstevel@tonic-gate * to restore partial dump tapes written before dump was 361*0Sstevel@tonic-gate * fixed to write out the entire inode map. 362*0Sstevel@tonic-gate */ 363*0Sstevel@tonic-gate if (maxino > ULONG_MAX) { 364*0Sstevel@tonic-gate (void) fprintf(stderr, 365*0Sstevel@tonic-gate gettext("file system too large\n")); 366*0Sstevel@tonic-gate done(1); 367*0Sstevel@tonic-gate } 368*0Sstevel@tonic-gate /* LINTED maxino size-checked above */ 369*0Sstevel@tonic-gate mapsize = (size_t)d_howmany(maxino > MAXINO ? maxino : MAXINO, NBBY); 370*0Sstevel@tonic-gate beginmap = map = calloc((size_t)1, mapsize); 371*0Sstevel@tonic-gate if (map == (char *)NIL) { 372*0Sstevel@tonic-gate (void) fprintf(stderr, 373*0Sstevel@tonic-gate gettext("no memory for file removal list\n")); 374*0Sstevel@tonic-gate done(1); 375*0Sstevel@tonic-gate } 376*0Sstevel@tonic-gate endmap = map + mapsize; 377*0Sstevel@tonic-gate clrimap = map; 378*0Sstevel@tonic-gate curfile.action = USING; 379*0Sstevel@tonic-gate continuemap = 1; 380*0Sstevel@tonic-gate getfile(xtrmap, xtrmapskip); 381*0Sstevel@tonic-gate if (MAXINO > maxino) 382*0Sstevel@tonic-gate maxino = MAXINO; 383*0Sstevel@tonic-gate if (checktype(&spcl, TS_BITS) == FAIL) { 384*0Sstevel@tonic-gate /* if we have TS_CLRI then no TS_BITS then a TS_END */ 385*0Sstevel@tonic-gate /* then we have an empty dump file */ 386*0Sstevel@tonic-gate if (gethead(&spcl) == GOOD && checktype(&spcl, TS_END) == GOOD) 387*0Sstevel@tonic-gate { 388*0Sstevel@tonic-gate if ((command == 'r') || (command == 'R')) { 389*0Sstevel@tonic-gate initsymtable(syment); 390*0Sstevel@tonic-gate dumpsymtable(syment, volno); 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate done(0); 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate /* otherwise we have an error */ 395*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Cannot find file dump list\n")); 396*0Sstevel@tonic-gate done(1); 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate /* LINTED maxino size-checked above */ 399*0Sstevel@tonic-gate mapsize = (size_t)d_howmany(maxino, NBBY); 400*0Sstevel@tonic-gate beginmap = map = calloc((size_t)1, mapsize); 401*0Sstevel@tonic-gate if (map == (char *)NULL) { 402*0Sstevel@tonic-gate (void) fprintf(stderr, 403*0Sstevel@tonic-gate gettext("no memory for file dump list\n")); 404*0Sstevel@tonic-gate done(1); 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate endmap = map + mapsize; 407*0Sstevel@tonic-gate dumpmap = map; 408*0Sstevel@tonic-gate curfile.action = USING; 409*0Sstevel@tonic-gate continuemap = 1; 410*0Sstevel@tonic-gate getfile(xtrmap, xtrmapskip); 411*0Sstevel@tonic-gate continuemap = 0; 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate /* 415*0Sstevel@tonic-gate * Initialize fssize variable for 'R' command to work. 416*0Sstevel@tonic-gate */ 417*0Sstevel@tonic-gate void 418*0Sstevel@tonic-gate #ifdef __STDC__ 419*0Sstevel@tonic-gate setupR(void) 420*0Sstevel@tonic-gate #else 421*0Sstevel@tonic-gate setupR() 422*0Sstevel@tonic-gate #endif 423*0Sstevel@tonic-gate { 424*0Sstevel@tonic-gate struct stat stbuf; 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate if (stat(".", &stbuf) < 0) { 427*0Sstevel@tonic-gate perror(gettext("cannot stat .")); 428*0Sstevel@tonic-gate done(1); 429*0Sstevel@tonic-gate } 430*0Sstevel@tonic-gate if (stbuf.st_blksize >= tp_bsize && stbuf.st_blksize <= MAXBSIZE) { 431*0Sstevel@tonic-gate /* LINTED: value fits in a size_t */ 432*0Sstevel@tonic-gate fssize = stbuf.st_blksize; 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate if (((fssize - 1) & fssize) != 0) { 435*0Sstevel@tonic-gate (void) fprintf(stderr, 436*0Sstevel@tonic-gate gettext("bad filesystem block size %d\n"), fssize); 437*0Sstevel@tonic-gate done(1); 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate /* 442*0Sstevel@tonic-gate * Prompt user to load a new dump volume. 443*0Sstevel@tonic-gate * "Nextvol" is the next suggested volume to use. 444*0Sstevel@tonic-gate * This suggested volume is enforced when doing full 445*0Sstevel@tonic-gate * or incremental restores, but can be overrridden by 446*0Sstevel@tonic-gate * the user when only extracting a subset of the files. 447*0Sstevel@tonic-gate * 448*0Sstevel@tonic-gate * first_time is used with archive files and can have 1 of 3 states: 449*0Sstevel@tonic-gate * FT_STATE_1 Tape has not been read yet 450*0Sstevel@tonic-gate * FT_STATE_2 Tape has been read but not positioned past directory 451*0Sstevel@tonic-gate * information 452*0Sstevel@tonic-gate * FT_STATE_3 Tape has been read and is reading file information 453*0Sstevel@tonic-gate */ 454*0Sstevel@tonic-gate #define FT_STATE_1 1 455*0Sstevel@tonic-gate #define FT_STATE_2 2 456*0Sstevel@tonic-gate #define FT_STATE_3 3 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate void 459*0Sstevel@tonic-gate getvol(nextvol) 460*0Sstevel@tonic-gate int nextvol; 461*0Sstevel@tonic-gate { 462*0Sstevel@tonic-gate int newvol; 463*0Sstevel@tonic-gate long savecnt, savetapea, wantnext; 464*0Sstevel@tonic-gate long i; 465*0Sstevel@tonic-gate union u_spcl tmpspcl; 466*0Sstevel@tonic-gate #define tmpbuf tmpspcl.s_spcl 467*0Sstevel@tonic-gate char buf[TP_BSIZE_MAX]; 468*0Sstevel@tonic-gate static int first_time = FT_STATE_1; 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate if (tbf == NULL) { 471*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 472*0Sstevel@tonic-gate "Internal consistency failure in getvol: tbf is NULL\n")); 473*0Sstevel@tonic-gate done(1); 474*0Sstevel@tonic-gate } 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate if (nextvol == 1) { 477*0Sstevel@tonic-gate for (i = 0; i < MAXTAPES; i++) 478*0Sstevel@tonic-gate tapesread[i] = 0; 479*0Sstevel@tonic-gate gettingfile = 0; 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate if (pipein) { 482*0Sstevel@tonic-gate if (nextvol != 1) 483*0Sstevel@tonic-gate panic(gettext("changing volumes on pipe input\n")); 484*0Sstevel@tonic-gate if (volno == 1) 485*0Sstevel@tonic-gate return; 486*0Sstevel@tonic-gate goto gethdr; 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate savecnt = blksread; /* ignore volume verification tape i/o */ 489*0Sstevel@tonic-gate savetapea = tapea; 490*0Sstevel@tonic-gate again: 491*0Sstevel@tonic-gate if (pipein) 492*0Sstevel@tonic-gate done(1); /* pipes do not get a second chance */ 493*0Sstevel@tonic-gate if (command == 'R' || command == 'r' || curfile.action != SKIP) { 494*0Sstevel@tonic-gate wantnext = 1; 495*0Sstevel@tonic-gate newvol = nextvol; 496*0Sstevel@tonic-gate } else { 497*0Sstevel@tonic-gate wantnext = 0; 498*0Sstevel@tonic-gate newvol = 0; 499*0Sstevel@tonic-gate } 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate if (autoload) { 502*0Sstevel@tonic-gate if ((volno == 1) && (nextvol == 1)) { 503*0Sstevel@tonic-gate tapesread[volno-1]++; 504*0Sstevel@tonic-gate return; 505*0Sstevel@tonic-gate } 506*0Sstevel@tonic-gate if (autoload_tape()) { 507*0Sstevel@tonic-gate goto gethdr; 508*0Sstevel@tonic-gate } 509*0Sstevel@tonic-gate } 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate while (newvol <= 0) { 512*0Sstevel@tonic-gate int n = 0; 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate for (i = 0; i < MAXTAPES; i++) 515*0Sstevel@tonic-gate if (tapesread[i]) 516*0Sstevel@tonic-gate n++; 517*0Sstevel@tonic-gate if (n == 0) { 518*0Sstevel@tonic-gate (void) fprintf(stderr, "%s", gettext( 519*0Sstevel@tonic-gate "You have not read any volumes yet.\n\ 520*0Sstevel@tonic-gate Unless you know which volume your file(s) are on you should start\n\ 521*0Sstevel@tonic-gate with the last volume and work towards the first.\n")); 522*0Sstevel@tonic-gate } else { 523*0Sstevel@tonic-gate (void) fprintf(stderr, 524*0Sstevel@tonic-gate gettext("You have read volumes")); 525*0Sstevel@tonic-gate (void) strcpy(tbf, ": "); 526*0Sstevel@tonic-gate for (i = 0; i < MAXTAPES; i++) 527*0Sstevel@tonic-gate if (tapesread[i]) { 528*0Sstevel@tonic-gate (void) fprintf(stderr, "%s%ld", 529*0Sstevel@tonic-gate tbf, i+1); 530*0Sstevel@tonic-gate (void) strcpy(tbf, ", "); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate do { 535*0Sstevel@tonic-gate (void) fprintf(stderr, 536*0Sstevel@tonic-gate gettext("Specify next volume #: ")); 537*0Sstevel@tonic-gate (void) fflush(stderr); 538*0Sstevel@tonic-gate /* LINTED tbfsize is limited to a few MB */ 539*0Sstevel@tonic-gate (void) fgets(tbf, (int)tbfsize, terminal); 540*0Sstevel@tonic-gate } while (!feof(terminal) && tbf[0] == '\n'); 541*0Sstevel@tonic-gate if (feof(terminal)) 542*0Sstevel@tonic-gate done(1); 543*0Sstevel@tonic-gate newvol = atoi(tbf); 544*0Sstevel@tonic-gate if (newvol <= 0) { 545*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 546*0Sstevel@tonic-gate "Volume numbers are positive numerics\n")); 547*0Sstevel@tonic-gate } 548*0Sstevel@tonic-gate if (newvol > MAXTAPES) { 549*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 550*0Sstevel@tonic-gate "This program can only deal with %d volumes\n"), 551*0Sstevel@tonic-gate MAXTAPES); 552*0Sstevel@tonic-gate newvol = 0; 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate if (newvol == volno) { 556*0Sstevel@tonic-gate tapesread[volno-1]++; 557*0Sstevel@tonic-gate return; 558*0Sstevel@tonic-gate } 559*0Sstevel@tonic-gate closemt(); 560*0Sstevel@tonic-gate /* 561*0Sstevel@tonic-gate * XXX: if we are switching devices, we should probably try 562*0Sstevel@tonic-gate * the device once without prompting to enable unattended 563*0Sstevel@tonic-gate * operation. 564*0Sstevel@tonic-gate */ 565*0Sstevel@tonic-gate if (host) 566*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 567*0Sstevel@tonic-gate "Mount volume %d\nthen enter volume name on host %s (default: %s) "), 568*0Sstevel@tonic-gate newvol, host, magtape); 569*0Sstevel@tonic-gate else 570*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 571*0Sstevel@tonic-gate "Mount volume %d\nthen enter volume name (default: %s) "), 572*0Sstevel@tonic-gate newvol, magtape); 573*0Sstevel@tonic-gate (void) fflush(stderr); 574*0Sstevel@tonic-gate /* LINTED tbfsize is limited to a few MB */ 575*0Sstevel@tonic-gate (void) fgets(tbf, (int)tbfsize, terminal); 576*0Sstevel@tonic-gate if (feof(terminal)) 577*0Sstevel@tonic-gate done(1); 578*0Sstevel@tonic-gate /* 579*0Sstevel@tonic-gate * XXX We don't allow rotating among tape hosts, just drives. 580*0Sstevel@tonic-gate */ 581*0Sstevel@tonic-gate if (tbf[0] != '\n') { 582*0Sstevel@tonic-gate (void) strncpy(magtape, tbf, sizeof (magtape)); 583*0Sstevel@tonic-gate magtape[sizeof (magtape) - 1] = '\0'; 584*0Sstevel@tonic-gate /* LINTED unsigned -> signed conversion ok */ 585*0Sstevel@tonic-gate i = (int)strlen(magtape); 586*0Sstevel@tonic-gate if (magtape[i - 1] == '\n') 587*0Sstevel@tonic-gate magtape[i - 1] = '\0'; 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate if ((host != NULL && (mt = rmtopen(magtape, O_RDONLY)) == -1) || 590*0Sstevel@tonic-gate (host == NULL && 591*0Sstevel@tonic-gate (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) { 592*0Sstevel@tonic-gate int error = errno; 593*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Cannot open %s: %s\n"), 594*0Sstevel@tonic-gate magtape, strerror(error)); 595*0Sstevel@tonic-gate volno = -1; 596*0Sstevel@tonic-gate goto again; 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate gethdr: 599*0Sstevel@tonic-gate volno = newvol; 600*0Sstevel@tonic-gate setdumpnum(); 601*0Sstevel@tonic-gate flsht(); 602*0Sstevel@tonic-gate if (!pipein && !bflag && archivefile && (first_time == FT_STATE_1)) { 603*0Sstevel@tonic-gate first_time = FT_STATE_2; 604*0Sstevel@tonic-gate findtapeblksize(TAPE_FILE); 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate if (readhdr(&tmpbuf) == FAIL) { 607*0Sstevel@tonic-gate (void) fprintf(stderr, 608*0Sstevel@tonic-gate gettext("volume is not in dump format\n")); 609*0Sstevel@tonic-gate volno = 0; 610*0Sstevel@tonic-gate goto again; 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate if (checkvol(&tmpbuf, volno) == FAIL) { 613*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Wrong volume (%d)\n"), 614*0Sstevel@tonic-gate tmpbuf.c_volume); 615*0Sstevel@tonic-gate volno = 0; 616*0Sstevel@tonic-gate goto again; 617*0Sstevel@tonic-gate } 618*0Sstevel@tonic-gate 619*0Sstevel@tonic-gate if (((time_t)(tmpbuf.c_date) != dumpdate) || 620*0Sstevel@tonic-gate ((time_t)(tmpbuf.c_ddate) != dumptime)) { 621*0Sstevel@tonic-gate char *tmp_ct; 622*0Sstevel@tonic-gate time_t lc_date = (time_t)tmpbuf.c_date; 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate /* 625*0Sstevel@tonic-gate * This is used to save the return value from lctime(), 626*0Sstevel@tonic-gate * since that's volatile across lctime() invocations. 627*0Sstevel@tonic-gate */ 628*0Sstevel@tonic-gate tmp_ct = strdup(lctime(&lc_date)); 629*0Sstevel@tonic-gate if (tmp_ct == (char *)0) { 630*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 631*0Sstevel@tonic-gate "Cannot allocate space for time string\n")); 632*0Sstevel@tonic-gate done(1); 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate (void) fprintf(stderr, 636*0Sstevel@tonic-gate gettext("Wrong dump date\n\tgot: %s\twanted: %s"), 637*0Sstevel@tonic-gate tmp_ct, lctime(&dumpdate)); 638*0Sstevel@tonic-gate volno = 0; 639*0Sstevel@tonic-gate free(tmp_ct); 640*0Sstevel@tonic-gate goto again; 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate tapesread[volno-1]++; 643*0Sstevel@tonic-gate blksread = savecnt; 644*0Sstevel@tonic-gate tapea = savetapea; 645*0Sstevel@tonic-gate /* 646*0Sstevel@tonic-gate * If continuing from the previous volume, skip over any 647*0Sstevel@tonic-gate * blocks read already at the end of the previous volume. 648*0Sstevel@tonic-gate * 649*0Sstevel@tonic-gate * If coming to this volume at random, skip to the beginning 650*0Sstevel@tonic-gate * of the next record. 651*0Sstevel@tonic-gate */ 652*0Sstevel@tonic-gate if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) { 653*0Sstevel@tonic-gate if (!wantnext) { 654*0Sstevel@tonic-gate if (archivefile && first_time == FT_STATE_2) { 655*0Sstevel@tonic-gate first_time = FT_STATE_3; 656*0Sstevel@tonic-gate } 657*0Sstevel@tonic-gate recsread = tmpbuf.c_firstrec; 658*0Sstevel@tonic-gate tapea = tmpbuf.c_tapea; 659*0Sstevel@tonic-gate dprintf(stdout, 660*0Sstevel@tonic-gate "restore skipping %d records\n", 661*0Sstevel@tonic-gate tmpbuf.c_count); 662*0Sstevel@tonic-gate for (i = tmpbuf.c_count; i > 0; i--) 663*0Sstevel@tonic-gate readtape(buf); 664*0Sstevel@tonic-gate } else if (tmpbuf.c_firstrec != 0) { 665*0Sstevel@tonic-gate savecnt = blksread; 666*0Sstevel@tonic-gate savetapea = tapea; 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate if (archivefile && first_time == FT_STATE_2) { 669*0Sstevel@tonic-gate /* 670*0Sstevel@tonic-gate * subtract 2, 1 for archive file's TS_END 671*0Sstevel@tonic-gate * and 1 for tape's TS_TAPE 672*0Sstevel@tonic-gate */ 673*0Sstevel@tonic-gate first_time = FT_STATE_3; 674*0Sstevel@tonic-gate i = tapea - tmpbuf.c_tapea - 2; 675*0Sstevel@tonic-gate } else { 676*0Sstevel@tonic-gate i = tapea - tmpbuf.c_tapea; 677*0Sstevel@tonic-gate } 678*0Sstevel@tonic-gate if (i > 0) 679*0Sstevel@tonic-gate dprintf(stdout, gettext( 680*0Sstevel@tonic-gate "restore skipping %d duplicate records\n"), 681*0Sstevel@tonic-gate i); 682*0Sstevel@tonic-gate else if (i < 0) 683*0Sstevel@tonic-gate dprintf(stdout, gettext( 684*0Sstevel@tonic-gate "restore duplicate record botch (%d)\n"), 685*0Sstevel@tonic-gate i); 686*0Sstevel@tonic-gate while (--i >= 0) 687*0Sstevel@tonic-gate readtape(buf); 688*0Sstevel@tonic-gate blksread = savecnt; 689*0Sstevel@tonic-gate tapea = savetapea + 1; /* <= (void) gethead() below */ 690*0Sstevel@tonic-gate } 691*0Sstevel@tonic-gate } 692*0Sstevel@tonic-gate if (curfile.action == USING) { 693*0Sstevel@tonic-gate if (volno == 1) 694*0Sstevel@tonic-gate panic(gettext("active file into volume 1\n")); 695*0Sstevel@tonic-gate return; 696*0Sstevel@tonic-gate } 697*0Sstevel@tonic-gate (void) gethead(&spcl); 698*0Sstevel@tonic-gate findinode(&spcl); /* do we always restart files in full? */ 699*0Sstevel@tonic-gate if (gettingfile) { /* i.e. will we lose metadata? */ 700*0Sstevel@tonic-gate gettingfile = 0; 701*0Sstevel@tonic-gate longjmp(restart, 1); /* will this set f1 & f2? */ 702*0Sstevel@tonic-gate } 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate /* 706*0Sstevel@tonic-gate * handle multiple dumps per tape by skipping forward to the 707*0Sstevel@tonic-gate * appropriate one. Note we don't use absolute positioning, 708*0Sstevel@tonic-gate * as that may take a very long time. 709*0Sstevel@tonic-gate */ 710*0Sstevel@tonic-gate static void 711*0Sstevel@tonic-gate #ifdef __STDC__ 712*0Sstevel@tonic-gate setdumpnum(void) 713*0Sstevel@tonic-gate #else 714*0Sstevel@tonic-gate setdumpnum() 715*0Sstevel@tonic-gate #endif 716*0Sstevel@tonic-gate { 717*0Sstevel@tonic-gate struct mtop tcom; 718*0Sstevel@tonic-gate int retval; 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate if (dumpnum == 1 || volno != 1) 721*0Sstevel@tonic-gate return; 722*0Sstevel@tonic-gate if (pipein) { 723*0Sstevel@tonic-gate (void) fprintf(stderr, 724*0Sstevel@tonic-gate gettext("Cannot have multiple dumps on pipe input\n")); 725*0Sstevel@tonic-gate done(1); 726*0Sstevel@tonic-gate } 727*0Sstevel@tonic-gate tcom.mt_op = MTFSF; 728*0Sstevel@tonic-gate tcom.mt_count = dumpnum - 1; 729*0Sstevel@tonic-gate if (host) 730*0Sstevel@tonic-gate retval = rmtioctl(MTFSF, dumpnum - 1); 731*0Sstevel@tonic-gate else 732*0Sstevel@tonic-gate retval = ioctl(mt, (int)MTIOCTOP, (char *)&tcom); 733*0Sstevel@tonic-gate if (retval < 0) 734*0Sstevel@tonic-gate perror("ioctl MTFSF"); 735*0Sstevel@tonic-gate } 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate void 738*0Sstevel@tonic-gate #ifdef __STDC__ 739*0Sstevel@tonic-gate printdumpinfo(void) 740*0Sstevel@tonic-gate #else 741*0Sstevel@tonic-gate printdumpinfo() 742*0Sstevel@tonic-gate #endif 743*0Sstevel@tonic-gate { 744*0Sstevel@tonic-gate int i; 745*0Sstevel@tonic-gate time_t date; 746*0Sstevel@tonic-gate static char *epoch = NULL; 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate if (epoch == NULL) { 749*0Sstevel@tonic-gate epoch = strdup(gettext("the epoch\n")); 750*0Sstevel@tonic-gate if (epoch == NULL) { 751*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Out of memory\n")); 752*0Sstevel@tonic-gate return; 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate } 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate date = (time_t)dumpinfo.c_date; 757*0Sstevel@tonic-gate (void) fprintf(stdout, 758*0Sstevel@tonic-gate gettext("Dump date: %s"), lctime(&date)); 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate date = (time_t)dumpinfo.c_ddate; 761*0Sstevel@tonic-gate (void) fprintf(stdout, gettext("Dumped from: %s"), 762*0Sstevel@tonic-gate (dumpinfo.c_ddate == 0) ? epoch : lctime(&date)); 763*0Sstevel@tonic-gate if (hostinfo) { 764*0Sstevel@tonic-gate (void) fprintf(stdout, 765*0Sstevel@tonic-gate gettext("Level %d dump of %s on %.*s:%s\n"), 766*0Sstevel@tonic-gate dumpinfo.c_level, dumpinfo.c_filesys, 767*0Sstevel@tonic-gate sizeof (dumpinfo.c_host), dumpinfo.c_host, dumpinfo.c_dev); 768*0Sstevel@tonic-gate (void) fprintf(stdout, 769*0Sstevel@tonic-gate gettext("Label: %.*s\n"), 770*0Sstevel@tonic-gate sizeof (dumpinfo.c_label), dumpinfo.c_label); 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate if (inodeinfo) { 773*0Sstevel@tonic-gate (void) fprintf(stdout, 774*0Sstevel@tonic-gate gettext("Starting inode numbers by volume:\n")); 775*0Sstevel@tonic-gate for (i = 1; i <= dumpinfo.c_volume; i++) 776*0Sstevel@tonic-gate (void) fprintf(stdout, gettext("\tVolume %d: %6d\n"), 777*0Sstevel@tonic-gate i, dumpinfo.c_inos[i]); 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate } 780*0Sstevel@tonic-gate 781*0Sstevel@tonic-gate extractfile(name) 782*0Sstevel@tonic-gate char *name; 783*0Sstevel@tonic-gate { 784*0Sstevel@tonic-gate static int complained_chown = 0; 785*0Sstevel@tonic-gate static int complained_lchown = 0; 786*0Sstevel@tonic-gate static int complained_chmod = 0; 787*0Sstevel@tonic-gate static int complained_utime = 0; 788*0Sstevel@tonic-gate static int complained_mknod = 0; 789*0Sstevel@tonic-gate mode_t mode; 790*0Sstevel@tonic-gate time_t timep[2]; 791*0Sstevel@tonic-gate struct entry *ep; 792*0Sstevel@tonic-gate uid_t uid; 793*0Sstevel@tonic-gate gid_t gid; 794*0Sstevel@tonic-gate char *errmsg; 795*0Sstevel@tonic-gate int result, saverr; 796*0Sstevel@tonic-gate dev_t full_dev; 797*0Sstevel@tonic-gate int dfd; 798*0Sstevel@tonic-gate char *rname; 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate curfile.name = name; 801*0Sstevel@tonic-gate curfile.action = USING; 802*0Sstevel@tonic-gate timep[0] = (time_t)curfile.dip->di_atime; 803*0Sstevel@tonic-gate timep[1] = (time_t)curfile.dip->di_mtime; 804*0Sstevel@tonic-gate mode = curfile.dip->di_mode; 805*0Sstevel@tonic-gate 806*0Sstevel@tonic-gate uid = curfile.dip->di_suid == UID_LONG ? 807*0Sstevel@tonic-gate curfile.dip->di_uid : (uid_t)curfile.dip->di_suid; 808*0Sstevel@tonic-gate gid = curfile.dip->di_sgid == GID_LONG ? 809*0Sstevel@tonic-gate curfile.dip->di_gid : (gid_t)curfile.dip->di_sgid; 810*0Sstevel@tonic-gate 811*0Sstevel@tonic-gate resolve(name, &dfd, &rname); 812*0Sstevel@tonic-gate if (dfd != AT_FDCWD) { 813*0Sstevel@tonic-gate if (fchdir(dfd) < 0) { 814*0Sstevel@tonic-gate saverr = errno; 815*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 816*0Sstevel@tonic-gate "%s: unable to set attribute context: %s\n"), 817*0Sstevel@tonic-gate rname, strerror(saverr)); 818*0Sstevel@tonic-gate skipfile(); 819*0Sstevel@tonic-gate (void) close(dfd); 820*0Sstevel@tonic-gate return (FAIL); 821*0Sstevel@tonic-gate } 822*0Sstevel@tonic-gate } 823*0Sstevel@tonic-gate 824*0Sstevel@tonic-gate switch (mode & IFMT) { 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate default: 827*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s: unknown file mode 0%lo\n"), 828*0Sstevel@tonic-gate rname, (ulong_t)(mode&IFMT)); 829*0Sstevel@tonic-gate skipfile(); 830*0Sstevel@tonic-gate result = FAIL; 831*0Sstevel@tonic-gate break; 832*0Sstevel@tonic-gate 833*0Sstevel@tonic-gate case IFSOCK: 834*0Sstevel@tonic-gate vprintf(stdout, gettext("skipped socket %s\n"), rname); 835*0Sstevel@tonic-gate skipfile(); 836*0Sstevel@tonic-gate result = GOOD; 837*0Sstevel@tonic-gate break; 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate case IFDIR: 840*0Sstevel@tonic-gate if (mflag) { 841*0Sstevel@tonic-gate ep = lookupname(name); 842*0Sstevel@tonic-gate if (ep == NIL || ep->e_flags & EXTRACT) { 843*0Sstevel@tonic-gate panic(gettext( 844*0Sstevel@tonic-gate "directory %s was not restored\n"), 845*0Sstevel@tonic-gate rname); 846*0Sstevel@tonic-gate skipfile(); 847*0Sstevel@tonic-gate result = FAIL; 848*0Sstevel@tonic-gate break; 849*0Sstevel@tonic-gate } 850*0Sstevel@tonic-gate skipfile(); 851*0Sstevel@tonic-gate result = GOOD; 852*0Sstevel@tonic-gate break; 853*0Sstevel@tonic-gate } 854*0Sstevel@tonic-gate vprintf(stdout, gettext("extract file %s\n"), rname); 855*0Sstevel@tonic-gate result = genliteraldir(rname, curfile.ino); 856*0Sstevel@tonic-gate break; 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate case IFLNK: 859*0Sstevel@tonic-gate lnkbuf[0] = '\0'; 860*0Sstevel@tonic-gate pathlen = 0; 861*0Sstevel@tonic-gate getfile(xtrlnkfile, xtrlnkskip); 862*0Sstevel@tonic-gate if (pathlen == 0) { 863*0Sstevel@tonic-gate vprintf(stdout, gettext( 864*0Sstevel@tonic-gate "%s: zero length symbolic link (ignored)\n"), 865*0Sstevel@tonic-gate rname); 866*0Sstevel@tonic-gate result = GOOD; 867*0Sstevel@tonic-gate break; 868*0Sstevel@tonic-gate } 869*0Sstevel@tonic-gate if ((result = lf_linkit(lnkbuf, rname, SYMLINK)) != GOOD) 870*0Sstevel@tonic-gate break; 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate /* 1254700: set uid/gid (previously missing) */ 873*0Sstevel@tonic-gate if (lchown(rname, uid, gid) < 0 && !complained_lchown) { 874*0Sstevel@tonic-gate /* Just a warning */ 875*0Sstevel@tonic-gate saverr = errno; 876*0Sstevel@tonic-gate errmsg = gettext( 877*0Sstevel@tonic-gate "Unable to restore ownership of symlink %s: %s\n"); 878*0Sstevel@tonic-gate (void) fprintf(stderr, errmsg, 879*0Sstevel@tonic-gate rname, strerror(saverr)); 880*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 881*0Sstevel@tonic-gate "Additional such failures will be ignored.\n")); 882*0Sstevel@tonic-gate complained_lchown = 1; 883*0Sstevel@tonic-gate } 884*0Sstevel@tonic-gate metaset(rname); 885*0Sstevel@tonic-gate result = GOOD; 886*0Sstevel@tonic-gate break; 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate case IFCHR: 889*0Sstevel@tonic-gate case IFBLK: 890*0Sstevel@tonic-gate case IFIFO: 891*0Sstevel@tonic-gate vprintf(stdout, gettext("extract special file %s\n"), rname); 892*0Sstevel@tonic-gate /* put device rdev into dev_t expanded format */ 893*0Sstevel@tonic-gate /* XXX does this always do the right thing? */ 894*0Sstevel@tonic-gate /* XXX does dump do the right thing? */ 895*0Sstevel@tonic-gate if (((curfile.dip->di_ordev & 0xFFFF0000) == 0) || 896*0Sstevel@tonic-gate ((curfile.dip->di_ordev & 0xFFFF0000) == 0xFFFF0000)) { 897*0Sstevel@tonic-gate full_dev = expdev((unsigned)(curfile.dip->di_ordev)); 898*0Sstevel@tonic-gate } else { 899*0Sstevel@tonic-gate /* LINTED sign extension ok */ 900*0Sstevel@tonic-gate full_dev = (unsigned)(curfile.dip->di_ordev); 901*0Sstevel@tonic-gate } 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate if (mknod(rname, mode, full_dev) < 0) 904*0Sstevel@tonic-gate { 905*0Sstevel@tonic-gate struct stat64 s[1]; 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate saverr = errno; 908*0Sstevel@tonic-gate if ((stat64(rname, s)) || 909*0Sstevel@tonic-gate ((s->st_mode & S_IFMT) != (mode & S_IFMT)) || 910*0Sstevel@tonic-gate (s->st_rdev != full_dev)) { 911*0Sstevel@tonic-gate if (saverr != EPERM || !complained_mknod) { 912*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", rname); 913*0Sstevel@tonic-gate (void) fflush(stderr); 914*0Sstevel@tonic-gate errno = saverr; 915*0Sstevel@tonic-gate perror(gettext( 916*0Sstevel@tonic-gate "cannot create special file")); 917*0Sstevel@tonic-gate if (saverr == EPERM) { 918*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 919*0Sstevel@tonic-gate "Additional such failures will be ignored.\n")); 920*0Sstevel@tonic-gate complained_mknod = 1; 921*0Sstevel@tonic-gate } 922*0Sstevel@tonic-gate } 923*0Sstevel@tonic-gate skipfile(); 924*0Sstevel@tonic-gate result = FAIL; 925*0Sstevel@tonic-gate break; 926*0Sstevel@tonic-gate } 927*0Sstevel@tonic-gate } 928*0Sstevel@tonic-gate if (chown(rname, uid, gid) < 0 && !complained_chown) { 929*0Sstevel@tonic-gate /* Just a warning */ 930*0Sstevel@tonic-gate saverr = errno; 931*0Sstevel@tonic-gate errmsg = gettext( 932*0Sstevel@tonic-gate "Unable to restore ownership of %s: %s\n"); 933*0Sstevel@tonic-gate (void) fprintf(stderr, errmsg, 934*0Sstevel@tonic-gate rname, strerror(saverr)); 935*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 936*0Sstevel@tonic-gate "Additional such failures will be ignored.\n")); 937*0Sstevel@tonic-gate complained_chown = 1; 938*0Sstevel@tonic-gate } 939*0Sstevel@tonic-gate if (chmod(rname, mode) < 0 && !complained_chmod) { 940*0Sstevel@tonic-gate saverr = errno; 941*0Sstevel@tonic-gate errmsg = gettext( 942*0Sstevel@tonic-gate "Unable to restore permissions on %s: %s\n"); 943*0Sstevel@tonic-gate (void) fprintf(stderr, errmsg, 944*0Sstevel@tonic-gate rname, strerror(saverr)); 945*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 946*0Sstevel@tonic-gate "Additional such failures will be ignored.\n")); 947*0Sstevel@tonic-gate complained_chmod = 1; 948*0Sstevel@tonic-gate } 949*0Sstevel@tonic-gate skipfile(); 950*0Sstevel@tonic-gate metaset(rname); /* skipfile() got the metadata, if any */ 951*0Sstevel@tonic-gate if (utime(rname, (struct utimbuf *)timep) < 0 && 952*0Sstevel@tonic-gate !complained_utime) { 953*0Sstevel@tonic-gate saverr = errno; 954*0Sstevel@tonic-gate errmsg = gettext( 955*0Sstevel@tonic-gate "Unable to restore times on %s: %s\n"); 956*0Sstevel@tonic-gate (void) fprintf(stderr, errmsg, 957*0Sstevel@tonic-gate rname, strerror(saverr)); 958*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 959*0Sstevel@tonic-gate "Additional such failures will be ignored.\n")); 960*0Sstevel@tonic-gate complained_utime = 1; 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate result = GOOD; 963*0Sstevel@tonic-gate break; 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate case IFREG: 966*0Sstevel@tonic-gate vprintf(stdout, gettext("extract file %s\n"), rname); 967*0Sstevel@tonic-gate ofile = creat64(rname, 0666); 968*0Sstevel@tonic-gate 969*0Sstevel@tonic-gate if (ofile < 0) { 970*0Sstevel@tonic-gate saverr = errno; 971*0Sstevel@tonic-gate errmsg = gettext("cannot create file"); 972*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", rname); 973*0Sstevel@tonic-gate (void) fflush(stderr); 974*0Sstevel@tonic-gate errno = saverr; 975*0Sstevel@tonic-gate perror(errmsg); 976*0Sstevel@tonic-gate skipfile(); 977*0Sstevel@tonic-gate result = FAIL; 978*0Sstevel@tonic-gate break; 979*0Sstevel@tonic-gate } 980*0Sstevel@tonic-gate if (fchown(ofile, uid, gid) < 0 && !complained_chown) { 981*0Sstevel@tonic-gate /* Just a warning */ 982*0Sstevel@tonic-gate saverr = errno; 983*0Sstevel@tonic-gate errmsg = gettext( 984*0Sstevel@tonic-gate "Unable to restore ownership of %s: %s\n"); 985*0Sstevel@tonic-gate (void) fprintf(stderr, errmsg, 986*0Sstevel@tonic-gate rname, strerror(saverr)); 987*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 988*0Sstevel@tonic-gate "Additional such failures will be ignored.\n")); 989*0Sstevel@tonic-gate complained_chown = 1; 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate if (fchmod(ofile, mode) < 0 && !complained_chmod) { 992*0Sstevel@tonic-gate saverr = errno; 993*0Sstevel@tonic-gate errmsg = gettext( 994*0Sstevel@tonic-gate "Unable to restore permissions on %s: %s\n"); 995*0Sstevel@tonic-gate (void) fprintf(stderr, errmsg, 996*0Sstevel@tonic-gate rname, strerror(saverr)); 997*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 998*0Sstevel@tonic-gate "Additional such failures will be ignored.\n")); 999*0Sstevel@tonic-gate complained_chmod = 1; 1000*0Sstevel@tonic-gate } 1001*0Sstevel@tonic-gate getfile(xtrfile, xtrskip); 1002*0Sstevel@tonic-gate metaset(rname); /* we don't have metadata until after */ 1003*0Sstevel@tonic-gate /* getfile() - maybe fchmod(0) then */ 1004*0Sstevel@tonic-gate /* fchmod(real) after this? */ 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate /* 1007*0Sstevel@tonic-gate * Some errors don't get reported until we close(2), so 1008*0Sstevel@tonic-gate * check for them. 1009*0Sstevel@tonic-gate * XXX unlink the file if an error is reported? 1010*0Sstevel@tonic-gate */ 1011*0Sstevel@tonic-gate if (close(ofile) < 0) { 1012*0Sstevel@tonic-gate saverr = errno; 1013*0Sstevel@tonic-gate errmsg = gettext("error closing file"); 1014*0Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", rname); 1015*0Sstevel@tonic-gate (void) fflush(stderr); 1016*0Sstevel@tonic-gate errno = saverr; 1017*0Sstevel@tonic-gate perror(errmsg); 1018*0Sstevel@tonic-gate result = FAIL; 1019*0Sstevel@tonic-gate break; 1020*0Sstevel@tonic-gate } 1021*0Sstevel@tonic-gate if (utime(rname, (struct utimbuf *)timep) < 0 && 1022*0Sstevel@tonic-gate !complained_utime) { 1023*0Sstevel@tonic-gate saverr = errno; 1024*0Sstevel@tonic-gate errmsg = gettext( 1025*0Sstevel@tonic-gate "Unable to restore times on %s: %s\n"); 1026*0Sstevel@tonic-gate (void) fprintf(stderr, errmsg, 1027*0Sstevel@tonic-gate rname, strerror(saverr)); 1028*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1029*0Sstevel@tonic-gate "Additional such failures will be ignored.\n")); 1030*0Sstevel@tonic-gate complained_utime = 1; 1031*0Sstevel@tonic-gate } 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate result = GOOD; 1034*0Sstevel@tonic-gate break; 1035*0Sstevel@tonic-gate } 1036*0Sstevel@tonic-gate if (dfd != AT_FDCWD) { 1037*0Sstevel@tonic-gate fchdir(savepwd); 1038*0Sstevel@tonic-gate (void) close(dfd); 1039*0Sstevel@tonic-gate } 1040*0Sstevel@tonic-gate return (result); 1041*0Sstevel@tonic-gate } 1042*0Sstevel@tonic-gate 1043*0Sstevel@tonic-gate /* 1044*0Sstevel@tonic-gate * skip over bit maps on the tape 1045*0Sstevel@tonic-gate */ 1046*0Sstevel@tonic-gate void 1047*0Sstevel@tonic-gate #ifdef __STDC__ 1048*0Sstevel@tonic-gate skipmaps(void) 1049*0Sstevel@tonic-gate #else 1050*0Sstevel@tonic-gate skipmaps() 1051*0Sstevel@tonic-gate #endif 1052*0Sstevel@tonic-gate { 1053*0Sstevel@tonic-gate continuemap = 1; 1054*0Sstevel@tonic-gate while (checktype(&spcl, TS_CLRI) == GOOD || 1055*0Sstevel@tonic-gate checktype(&spcl, TS_BITS) == GOOD) 1056*0Sstevel@tonic-gate skipfile(); 1057*0Sstevel@tonic-gate continuemap = 0; 1058*0Sstevel@tonic-gate } 1059*0Sstevel@tonic-gate 1060*0Sstevel@tonic-gate /* 1061*0Sstevel@tonic-gate * skip over a file on the tape 1062*0Sstevel@tonic-gate */ 1063*0Sstevel@tonic-gate void 1064*0Sstevel@tonic-gate #ifdef __STDC__ 1065*0Sstevel@tonic-gate skipfile(void) 1066*0Sstevel@tonic-gate #else 1067*0Sstevel@tonic-gate skipfile() 1068*0Sstevel@tonic-gate #endif 1069*0Sstevel@tonic-gate { 1070*0Sstevel@tonic-gate curfile.action = SKIP; 1071*0Sstevel@tonic-gate getfile(null, null); 1072*0Sstevel@tonic-gate } 1073*0Sstevel@tonic-gate /* 1074*0Sstevel@tonic-gate * Do the file extraction, calling the supplied functions 1075*0Sstevel@tonic-gate * with the blocks 1076*0Sstevel@tonic-gate */ 1077*0Sstevel@tonic-gate void 1078*0Sstevel@tonic-gate getfile(f1, f2) 1079*0Sstevel@tonic-gate void (*f2)(), (*f1)(); 1080*0Sstevel@tonic-gate { 1081*0Sstevel@tonic-gate int i; 1082*0Sstevel@tonic-gate size_t curblk = 0; 1083*0Sstevel@tonic-gate offset_t size = (offset_t)spcl.c_dinode.di_size; 1084*0Sstevel@tonic-gate static char clearedbuf[MAXBSIZE]; 1085*0Sstevel@tonic-gate char buf[TP_BSIZE_MAX]; 1086*0Sstevel@tonic-gate char *bufptr; 1087*0Sstevel@tonic-gate char junk[TP_BSIZE_MAX]; 1088*0Sstevel@tonic-gate 1089*0Sstevel@tonic-gate assert(MAXBSIZE >= tp_bsize); 1090*0Sstevel@tonic-gate 1091*0Sstevel@tonic-gate metaset(NULL); /* flush old metadata */ 1092*0Sstevel@tonic-gate if (checktype(&spcl, TS_END) == GOOD) { 1093*0Sstevel@tonic-gate panic(gettext("ran off end of volume\n")); 1094*0Sstevel@tonic-gate return; 1095*0Sstevel@tonic-gate } 1096*0Sstevel@tonic-gate if (ishead(&spcl) == FAIL) { 1097*0Sstevel@tonic-gate panic(gettext("not at beginning of a file\n")); 1098*0Sstevel@tonic-gate return; 1099*0Sstevel@tonic-gate } 1100*0Sstevel@tonic-gate metacheck(&spcl); /* check for metadata in header */ 1101*0Sstevel@tonic-gate if (!gettingfile && setjmp(restart) != 0) { 1102*0Sstevel@tonic-gate gettingfile = 0; /* paranoia; longjmp'er should do */ 1103*0Sstevel@tonic-gate return; 1104*0Sstevel@tonic-gate } 1105*0Sstevel@tonic-gate gettingfile++; 1106*0Sstevel@tonic-gate loop: 1107*0Sstevel@tonic-gate if ((spcl.c_dinode.di_mode & IFMT) == IFSHAD) { 1108*0Sstevel@tonic-gate f1 = xtrmeta; 1109*0Sstevel@tonic-gate f2 = metaskip; 1110*0Sstevel@tonic-gate } 1111*0Sstevel@tonic-gate for (i = 0, bufptr = buf; i < spcl.c_count; i++) { 1112*0Sstevel@tonic-gate if ((i >= TP_NINDIR) || (spcl.c_addr[i])) { 1113*0Sstevel@tonic-gate readtape(bufptr); 1114*0Sstevel@tonic-gate bufptr += tp_bsize; 1115*0Sstevel@tonic-gate curblk++; 1116*0Sstevel@tonic-gate if (curblk == (fssize / tp_bsize)) { 1117*0Sstevel@tonic-gate (*f1)(buf, size > tp_bsize ? 1118*0Sstevel@tonic-gate (size_t)(fssize) : 1119*0Sstevel@tonic-gate /* LINTED size <= tp_bsize */ 1120*0Sstevel@tonic-gate (curblk - 1) * tp_bsize + (size_t)size); 1121*0Sstevel@tonic-gate curblk = 0; 1122*0Sstevel@tonic-gate bufptr = buf; 1123*0Sstevel@tonic-gate } 1124*0Sstevel@tonic-gate } else { 1125*0Sstevel@tonic-gate if (curblk > 0) { 1126*0Sstevel@tonic-gate (*f1)(buf, size > tp_bsize ? 1127*0Sstevel@tonic-gate (size_t)(curblk * tp_bsize) : 1128*0Sstevel@tonic-gate /* LINTED size <= tp_bsize */ 1129*0Sstevel@tonic-gate (curblk - 1) * tp_bsize + (size_t)size); 1130*0Sstevel@tonic-gate curblk = 0; 1131*0Sstevel@tonic-gate bufptr = buf; 1132*0Sstevel@tonic-gate } 1133*0Sstevel@tonic-gate (*f2)(clearedbuf, size > tp_bsize ? 1134*0Sstevel@tonic-gate /* LINTED size <= tp_bsize */ 1135*0Sstevel@tonic-gate (long)tp_bsize : (size_t)size); 1136*0Sstevel@tonic-gate } 1137*0Sstevel@tonic-gate if ((size -= tp_bsize) <= 0) { 1138*0Sstevel@tonic-gate for (i++; i < spcl.c_count; i++) 1139*0Sstevel@tonic-gate if ((i >= TP_NINDIR) || (spcl.c_addr[i])) 1140*0Sstevel@tonic-gate readtape(junk); 1141*0Sstevel@tonic-gate break; 1142*0Sstevel@tonic-gate } 1143*0Sstevel@tonic-gate } 1144*0Sstevel@tonic-gate if (curblk > 0) { 1145*0Sstevel@tonic-gate /* 1146*0Sstevel@tonic-gate * Ok to cast size to size_t here. The above for loop reads 1147*0Sstevel@tonic-gate * data into the buffer then writes it to the output file. The 1148*0Sstevel@tonic-gate * call to f1 here is to write out the data that's in the 1149*0Sstevel@tonic-gate * buffer that has not yet been written to the file. 1150*0Sstevel@tonic-gate * This will be less than N-KB of data, since the 1151*0Sstevel@tonic-gate * above loop writes to the file in filesystem- 1152*0Sstevel@tonic-gate * blocksize chunks. 1153*0Sstevel@tonic-gate */ 1154*0Sstevel@tonic-gate /* LINTED: size fits into a size_t at this point */ 1155*0Sstevel@tonic-gate (*f1)(buf, (curblk * tp_bsize) + (size_t)size); 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate curblk = 0; 1158*0Sstevel@tonic-gate bufptr = buf; 1159*0Sstevel@tonic-gate } 1160*0Sstevel@tonic-gate if ((readhdr(&spcl) == GOOD) && (checktype(&spcl, TS_ADDR) == GOOD)) { 1161*0Sstevel@tonic-gate if (continuemap) 1162*0Sstevel@tonic-gate size = (offset_t)spcl.c_count * tp_bsize; 1163*0Sstevel@tonic-gate /* big bitmap */ 1164*0Sstevel@tonic-gate else if ((size <= 0) && 1165*0Sstevel@tonic-gate ((spcl.c_dinode.di_mode & IFMT) == IFSHAD)) { 1166*0Sstevel@tonic-gate /* LINTED unsigned to signed conversion ok */ 1167*0Sstevel@tonic-gate size = spcl.c_dinode.di_size; 1168*0Sstevel@tonic-gate } 1169*0Sstevel@tonic-gate if (size > 0) 1170*0Sstevel@tonic-gate goto loop; 1171*0Sstevel@tonic-gate } 1172*0Sstevel@tonic-gate if (size > 0) 1173*0Sstevel@tonic-gate dprintf(stdout, 1174*0Sstevel@tonic-gate gettext("Missing address (header) block for %s\n"), 1175*0Sstevel@tonic-gate curfile.name); 1176*0Sstevel@tonic-gate findinode(&spcl); 1177*0Sstevel@tonic-gate gettingfile = 0; 1178*0Sstevel@tonic-gate } 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate /* 1181*0Sstevel@tonic-gate * The next routines are called during file extraction to 1182*0Sstevel@tonic-gate * put the data into the right form and place. 1183*0Sstevel@tonic-gate */ 1184*0Sstevel@tonic-gate static void 1185*0Sstevel@tonic-gate xtrfile(buf, size) 1186*0Sstevel@tonic-gate char *buf; 1187*0Sstevel@tonic-gate size_t size; 1188*0Sstevel@tonic-gate { 1189*0Sstevel@tonic-gate if (write(ofile, buf, (size_t)size) == -1) { 1190*0Sstevel@tonic-gate int saverr = errno; 1191*0Sstevel@tonic-gate (void) fprintf(stderr, 1192*0Sstevel@tonic-gate gettext("write error extracting inode %d, name %s\n"), 1193*0Sstevel@tonic-gate curfile.ino, curfile.name); 1194*0Sstevel@tonic-gate errno = saverr; 1195*0Sstevel@tonic-gate perror("write"); 1196*0Sstevel@tonic-gate done(1); 1197*0Sstevel@tonic-gate } 1198*0Sstevel@tonic-gate } 1199*0Sstevel@tonic-gate 1200*0Sstevel@tonic-gate /* 1201*0Sstevel@tonic-gate * Even though size is a size_t, it's seeking to a relative 1202*0Sstevel@tonic-gate * offset. Thus, the seek could go beyond 2 GB, so lseek64 is needed. 1203*0Sstevel@tonic-gate */ 1204*0Sstevel@tonic-gate 1205*0Sstevel@tonic-gate /*ARGSUSED*/ 1206*0Sstevel@tonic-gate static void 1207*0Sstevel@tonic-gate xtrskip(buf, size) 1208*0Sstevel@tonic-gate char *buf; 1209*0Sstevel@tonic-gate size_t size; 1210*0Sstevel@tonic-gate { 1211*0Sstevel@tonic-gate if (lseek64(ofile, (offset_t)size, 1) == -1) { 1212*0Sstevel@tonic-gate int saverr = errno; 1213*0Sstevel@tonic-gate (void) fprintf(stderr, 1214*0Sstevel@tonic-gate gettext("seek error extracting inode %d, name %s\n"), 1215*0Sstevel@tonic-gate curfile.ino, curfile.name); 1216*0Sstevel@tonic-gate errno = saverr; 1217*0Sstevel@tonic-gate perror("lseek64"); 1218*0Sstevel@tonic-gate done(1); 1219*0Sstevel@tonic-gate } 1220*0Sstevel@tonic-gate } 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate /* these are local to the next five functions */ 1223*0Sstevel@tonic-gate static char *metadata = NULL; 1224*0Sstevel@tonic-gate static size_t metasize = 0; 1225*0Sstevel@tonic-gate 1226*0Sstevel@tonic-gate static void 1227*0Sstevel@tonic-gate metacheck(head) 1228*0Sstevel@tonic-gate struct s_spcl *head; 1229*0Sstevel@tonic-gate { 1230*0Sstevel@tonic-gate if (! (head->c_flags & DR_HASMETA)) 1231*0Sstevel@tonic-gate return; 1232*0Sstevel@tonic-gate if ((metadata = malloc(metasize = (size_t)sizeof (head->c_shadow))) 1233*0Sstevel@tonic-gate == NULL) { 1234*0Sstevel@tonic-gate (void) fprintf(stderr, 1235*0Sstevel@tonic-gate gettext("Cannot malloc for metadata\n")); 1236*0Sstevel@tonic-gate done(1); 1237*0Sstevel@tonic-gate } 1238*0Sstevel@tonic-gate bcopy(&(head->c_shadow), metadata, metasize); 1239*0Sstevel@tonic-gate } 1240*0Sstevel@tonic-gate 1241*0Sstevel@tonic-gate static void 1242*0Sstevel@tonic-gate xtrmeta(buf, size) 1243*0Sstevel@tonic-gate char *buf; 1244*0Sstevel@tonic-gate size_t size; 1245*0Sstevel@tonic-gate { 1246*0Sstevel@tonic-gate if ((metadata == NULL) && ((spcl.c_dinode.di_mode & IFMT) != IFSHAD)) 1247*0Sstevel@tonic-gate return; 1248*0Sstevel@tonic-gate if ((metadata = realloc(metadata, metasize + size)) == NULL) { 1249*0Sstevel@tonic-gate (void) fprintf(stderr, 1250*0Sstevel@tonic-gate gettext("Cannot malloc for metadata\n")); 1251*0Sstevel@tonic-gate done(1); 1252*0Sstevel@tonic-gate } 1253*0Sstevel@tonic-gate bcopy(buf, metadata + metasize, size); 1254*0Sstevel@tonic-gate metasize += size; 1255*0Sstevel@tonic-gate } 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gate /* ARGSUSED */ 1258*0Sstevel@tonic-gate static void 1259*0Sstevel@tonic-gate metaskip(buf, size) 1260*0Sstevel@tonic-gate char *buf; 1261*0Sstevel@tonic-gate size_t size; 1262*0Sstevel@tonic-gate { 1263*0Sstevel@tonic-gate if (metadata == NULL) 1264*0Sstevel@tonic-gate return; 1265*0Sstevel@tonic-gate if ((metadata = realloc(metadata, metasize + size)) == NULL) { 1266*0Sstevel@tonic-gate (void) fprintf(stderr, 1267*0Sstevel@tonic-gate gettext("Cannot malloc for metadata\n")); 1268*0Sstevel@tonic-gate done(1); 1269*0Sstevel@tonic-gate } 1270*0Sstevel@tonic-gate bzero(metadata + metasize, size); 1271*0Sstevel@tonic-gate metasize += size; 1272*0Sstevel@tonic-gate } 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate static void 1275*0Sstevel@tonic-gate metaset(name) 1276*0Sstevel@tonic-gate char *name; 1277*0Sstevel@tonic-gate { 1278*0Sstevel@tonic-gate if (metadata == NULL) 1279*0Sstevel@tonic-gate return; 1280*0Sstevel@tonic-gate if (name != NULL) 1281*0Sstevel@tonic-gate metaproc(name, metadata, metasize); 1282*0Sstevel@tonic-gate (void) free(metadata); 1283*0Sstevel@tonic-gate metadata = NULL; 1284*0Sstevel@tonic-gate metasize = 0; 1285*0Sstevel@tonic-gate } 1286*0Sstevel@tonic-gate 1287*0Sstevel@tonic-gate void 1288*0Sstevel@tonic-gate metaget(data, size) 1289*0Sstevel@tonic-gate char **data; 1290*0Sstevel@tonic-gate size_t *size; 1291*0Sstevel@tonic-gate { 1292*0Sstevel@tonic-gate *data = metadata; 1293*0Sstevel@tonic-gate *size = metasize; 1294*0Sstevel@tonic-gate } 1295*0Sstevel@tonic-gate 1296*0Sstevel@tonic-gate static void 1297*0Sstevel@tonic-gate fsd_acl(name, aclp, size) 1298*0Sstevel@tonic-gate char *name, *aclp; 1299*0Sstevel@tonic-gate unsigned size; 1300*0Sstevel@tonic-gate { 1301*0Sstevel@tonic-gate static aclent_t *aclent = NULL; 1302*0Sstevel@tonic-gate ufs_acl_t *diskacl; 1303*0Sstevel@tonic-gate static int n = 0; 1304*0Sstevel@tonic-gate uint_t i; 1305*0Sstevel@tonic-gate int saverr, j; 1306*0Sstevel@tonic-gate 1307*0Sstevel@tonic-gate if (aclp == NULL) { 1308*0Sstevel@tonic-gate if (aclent != NULL) 1309*0Sstevel@tonic-gate free(aclent); 1310*0Sstevel@tonic-gate aclent = NULL; 1311*0Sstevel@tonic-gate n = 0; 1312*0Sstevel@tonic-gate return; 1313*0Sstevel@tonic-gate } 1314*0Sstevel@tonic-gate 1315*0Sstevel@tonic-gate /*LINTED [aclp is malloc'd]*/ 1316*0Sstevel@tonic-gate diskacl = (ufs_acl_t *)aclp; 1317*0Sstevel@tonic-gate /* LINTED: result fits in an int */ 1318*0Sstevel@tonic-gate j = size / sizeof (*diskacl); 1319*0Sstevel@tonic-gate normacls(byteorder, diskacl, j); 1320*0Sstevel@tonic-gate 1321*0Sstevel@tonic-gate i = n; 1322*0Sstevel@tonic-gate n += j; 1323*0Sstevel@tonic-gate aclent = realloc(aclent, n * (size_t)sizeof (*aclent)); 1324*0Sstevel@tonic-gate if (aclent == NULL) { 1325*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Cannot malloc acl list\n")); 1326*0Sstevel@tonic-gate done(1); 1327*0Sstevel@tonic-gate } 1328*0Sstevel@tonic-gate 1329*0Sstevel@tonic-gate j = 0; 1330*0Sstevel@tonic-gate while (i < n) { 1331*0Sstevel@tonic-gate aclent[i].a_type = diskacl[j].acl_tag; 1332*0Sstevel@tonic-gate aclent[i].a_id = diskacl[j].acl_who; 1333*0Sstevel@tonic-gate aclent[i].a_perm = diskacl[j].acl_perm; 1334*0Sstevel@tonic-gate ++i; 1335*0Sstevel@tonic-gate ++j; 1336*0Sstevel@tonic-gate } 1337*0Sstevel@tonic-gate 1338*0Sstevel@tonic-gate if (acl(name, SETACL, n, aclent) == -1) { 1339*0Sstevel@tonic-gate static int once = 0; 1340*0Sstevel@tonic-gate 1341*0Sstevel@tonic-gate /* 1342*0Sstevel@tonic-gate * Treat some errors from the acl subsystem specially to 1343*0Sstevel@tonic-gate * avoid being too noisy: 1344*0Sstevel@tonic-gate * 1345*0Sstevel@tonic-gate * ENOSYS - ACLs not supported on this file system 1346*0Sstevel@tonic-gate * EPERM - not the owner or not privileged 1347*0Sstevel@tonic-gate * 1348*0Sstevel@tonic-gate * The following is also supported for backwards compat. 1349*0Sstevel@tonic-gate * since acl(2) used to return the wrong errno: 1350*0Sstevel@tonic-gate * 1351*0Sstevel@tonic-gate * EINVAL - not the owner of the object 1352*0Sstevel@tonic-gate */ 1353*0Sstevel@tonic-gate if (errno == ENOSYS || errno == EPERM || errno == EINVAL) { 1354*0Sstevel@tonic-gate if (once == 0) { 1355*0Sstevel@tonic-gate saverr = errno; 1356*0Sstevel@tonic-gate ++once; 1357*0Sstevel@tonic-gate fprintf(stderr, 1358*0Sstevel@tonic-gate gettext("setacl failed: %s\n"), 1359*0Sstevel@tonic-gate strerror(saverr)); 1360*0Sstevel@tonic-gate } 1361*0Sstevel@tonic-gate } else { 1362*0Sstevel@tonic-gate saverr = errno; 1363*0Sstevel@tonic-gate fprintf(stderr, gettext("setacl on %s failed: %s\n"), 1364*0Sstevel@tonic-gate name, strerror(saverr)); 1365*0Sstevel@tonic-gate } 1366*0Sstevel@tonic-gate } 1367*0Sstevel@tonic-gate } 1368*0Sstevel@tonic-gate 1369*0Sstevel@tonic-gate static struct fsdtypes { 1370*0Sstevel@tonic-gate int type; 1371*0Sstevel@tonic-gate void (*function)(); 1372*0Sstevel@tonic-gate } fsdtypes[] = { 1373*0Sstevel@tonic-gate {FSD_ACL, fsd_acl}, 1374*0Sstevel@tonic-gate {FSD_DFACL, fsd_acl}, 1375*0Sstevel@tonic-gate {0, NULL} 1376*0Sstevel@tonic-gate }; 1377*0Sstevel@tonic-gate 1378*0Sstevel@tonic-gate void 1379*0Sstevel@tonic-gate metaproc(name, mdata, msize) 1380*0Sstevel@tonic-gate char *name, *mdata; 1381*0Sstevel@tonic-gate size_t msize; 1382*0Sstevel@tonic-gate { 1383*0Sstevel@tonic-gate struct fsdtypes *fsdtype; 1384*0Sstevel@tonic-gate ufs_fsd_t *fsd; 1385*0Sstevel@tonic-gate char *c; 1386*0Sstevel@tonic-gate 1387*0Sstevel@tonic-gate /* 1388*0Sstevel@tonic-gate * for the whole shadow inode, dispatch each piece 1389*0Sstevel@tonic-gate * to the appropriate function. 1390*0Sstevel@tonic-gate */ 1391*0Sstevel@tonic-gate c = mdata; 1392*0Sstevel@tonic-gate /* LINTED (c - mdata) fits into a size_t */ 1393*0Sstevel@tonic-gate while ((size_t)(c - mdata) < msize) { 1394*0Sstevel@tonic-gate /*LINTED [mdata is malloc'd]*/ 1395*0Sstevel@tonic-gate fsd = (ufs_fsd_t *)c; 1396*0Sstevel@tonic-gate assert((fsd->fsd_size % 4) == 0); 1397*0Sstevel@tonic-gate /* LINTED: lint thinks pointers are signed */ 1398*0Sstevel@tonic-gate c += FSD_RECSZ(fsd, fsd->fsd_size); 1399*0Sstevel@tonic-gate if ((fsd->fsd_type == FSD_FREE) || 1400*0Sstevel@tonic-gate ((unsigned)(fsd->fsd_size) <= sizeof (ufs_fsd_t)) || 1401*0Sstevel@tonic-gate (c > (mdata + msize))) 1402*0Sstevel@tonic-gate break; 1403*0Sstevel@tonic-gate for (fsdtype = fsdtypes; fsdtype->type; fsdtype++) 1404*0Sstevel@tonic-gate if (fsdtype->type == fsd->fsd_type) 1405*0Sstevel@tonic-gate (*fsdtype->function)(name, fsd->fsd_data, 1406*0Sstevel@tonic-gate (unsigned)(fsd->fsd_size) - 1407*0Sstevel@tonic-gate sizeof (fsd->fsd_type) - 1408*0Sstevel@tonic-gate sizeof (fsd->fsd_size)); 1409*0Sstevel@tonic-gate /* ^^^ be sure to change if fsd ever changes ^^^ */ 1410*0Sstevel@tonic-gate } 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gate /* reset the state of all the functions */ 1413*0Sstevel@tonic-gate for (fsdtype = fsdtypes; fsdtype->type; fsdtype++) 1414*0Sstevel@tonic-gate (*fsdtype->function)(NULL, NULL, 0); 1415*0Sstevel@tonic-gate } 1416*0Sstevel@tonic-gate 1417*0Sstevel@tonic-gate static void 1418*0Sstevel@tonic-gate xtrlnkfile(buf, size) 1419*0Sstevel@tonic-gate char *buf; 1420*0Sstevel@tonic-gate size_t size; 1421*0Sstevel@tonic-gate { 1422*0Sstevel@tonic-gate /* LINTED: signed/unsigned mix ok */ 1423*0Sstevel@tonic-gate pathlen += size; 1424*0Sstevel@tonic-gate if (pathlen > MAXPATHLEN) { 1425*0Sstevel@tonic-gate (void) fprintf(stderr, 1426*0Sstevel@tonic-gate gettext("symbolic link name: %s->%s%s; too long %d\n"), 1427*0Sstevel@tonic-gate curfile.name, lnkbuf, buf, pathlen); 1428*0Sstevel@tonic-gate done(1); 1429*0Sstevel@tonic-gate } 1430*0Sstevel@tonic-gate buf[size] = '\0'; 1431*0Sstevel@tonic-gate (void) strcat(lnkbuf, buf); 1432*0Sstevel@tonic-gate /* add an extra NULL to make this a legal complex string */ 1433*0Sstevel@tonic-gate lnkbuf[pathlen+1] = '\0'; 1434*0Sstevel@tonic-gate } 1435*0Sstevel@tonic-gate 1436*0Sstevel@tonic-gate /*ARGSUSED*/ 1437*0Sstevel@tonic-gate static void 1438*0Sstevel@tonic-gate xtrlnkskip(buf, size) 1439*0Sstevel@tonic-gate char *buf; 1440*0Sstevel@tonic-gate size_t size; 1441*0Sstevel@tonic-gate { 1442*0Sstevel@tonic-gate (void) fprintf(stderr, 1443*0Sstevel@tonic-gate gettext("unallocated block in symbolic link %s\n"), 1444*0Sstevel@tonic-gate curfile.name); 1445*0Sstevel@tonic-gate done(1); 1446*0Sstevel@tonic-gate } 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate static void 1449*0Sstevel@tonic-gate xtrmap(buf, size) 1450*0Sstevel@tonic-gate char *buf; 1451*0Sstevel@tonic-gate size_t size; 1452*0Sstevel@tonic-gate { 1453*0Sstevel@tonic-gate if ((map+size) > endmap) { 1454*0Sstevel@tonic-gate int64_t mapsize, increment; 1455*0Sstevel@tonic-gate int64_t diff; 1456*0Sstevel@tonic-gate 1457*0Sstevel@tonic-gate if (spcl.c_type != TS_ADDR) { 1458*0Sstevel@tonic-gate (void) fprintf(stderr, 1459*0Sstevel@tonic-gate gettext("xtrmap: current record not TS_ADDR\n")); 1460*0Sstevel@tonic-gate done(1); 1461*0Sstevel@tonic-gate } 1462*0Sstevel@tonic-gate if ((spcl.c_count < 0) || (spcl.c_count > TP_NINDIR)) { 1463*0Sstevel@tonic-gate (void) fprintf(stderr, 1464*0Sstevel@tonic-gate gettext("xtrmap: illegal c_count field (%d)\n"), 1465*0Sstevel@tonic-gate spcl.c_count); 1466*0Sstevel@tonic-gate done(1); 1467*0Sstevel@tonic-gate } 1468*0Sstevel@tonic-gate 1469*0Sstevel@tonic-gate increment = d_howmany( 1470*0Sstevel@tonic-gate ((spcl.c_count * tp_bsize * NBBY) + 1), NBBY); 1471*0Sstevel@tonic-gate mapsize = endmap - beginmap + increment; 1472*0Sstevel@tonic-gate if (mapsize > UINT_MAX) { 1473*0Sstevel@tonic-gate (void) fprintf(stderr, 1474*0Sstevel@tonic-gate gettext("xtrmap: maximum bitmap size exceeded")); 1475*0Sstevel@tonic-gate done(1); 1476*0Sstevel@tonic-gate } 1477*0Sstevel@tonic-gate 1478*0Sstevel@tonic-gate diff = map - beginmap; 1479*0Sstevel@tonic-gate /* LINTED mapsize checked above */ 1480*0Sstevel@tonic-gate beginmap = realloc(beginmap, (size_t)mapsize); 1481*0Sstevel@tonic-gate if (beginmap == NULL) { 1482*0Sstevel@tonic-gate (void) fprintf(stderr, 1483*0Sstevel@tonic-gate gettext("xtrmap: realloc failed\n")); 1484*0Sstevel@tonic-gate done(1); 1485*0Sstevel@tonic-gate } 1486*0Sstevel@tonic-gate map = beginmap + diff; 1487*0Sstevel@tonic-gate endmap = beginmap + mapsize; 1488*0Sstevel@tonic-gate /* LINTED endmap - map cannot exceed 32 bits */ 1489*0Sstevel@tonic-gate bzero(map, (size_t)(endmap - map)); 1490*0Sstevel@tonic-gate maxino = NBBY * mapsize + 1; 1491*0Sstevel@tonic-gate } 1492*0Sstevel@tonic-gate 1493*0Sstevel@tonic-gate bcopy(buf, map, size); 1494*0Sstevel@tonic-gate /* LINTED character pointers aren't signed */ 1495*0Sstevel@tonic-gate map += size; 1496*0Sstevel@tonic-gate } 1497*0Sstevel@tonic-gate 1498*0Sstevel@tonic-gate /*ARGSUSED*/ 1499*0Sstevel@tonic-gate static void 1500*0Sstevel@tonic-gate xtrmapskip(buf, size) 1501*0Sstevel@tonic-gate char *buf; 1502*0Sstevel@tonic-gate size_t size; 1503*0Sstevel@tonic-gate { 1504*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("hole in map\n")); 1505*0Sstevel@tonic-gate done(1); 1506*0Sstevel@tonic-gate } 1507*0Sstevel@tonic-gate 1508*0Sstevel@tonic-gate /*ARGSUSED*/ 1509*0Sstevel@tonic-gate void 1510*0Sstevel@tonic-gate null(buf, size) 1511*0Sstevel@tonic-gate char *buf; 1512*0Sstevel@tonic-gate size_t size; 1513*0Sstevel@tonic-gate { 1514*0Sstevel@tonic-gate } 1515*0Sstevel@tonic-gate 1516*0Sstevel@tonic-gate /* 1517*0Sstevel@tonic-gate * Do the tape i/o, dealing with volume changes 1518*0Sstevel@tonic-gate * etc.. 1519*0Sstevel@tonic-gate */ 1520*0Sstevel@tonic-gate static void 1521*0Sstevel@tonic-gate readtape(b) 1522*0Sstevel@tonic-gate char *b; 1523*0Sstevel@tonic-gate { 1524*0Sstevel@tonic-gate int i; 1525*0Sstevel@tonic-gate int rd, newvol; 1526*0Sstevel@tonic-gate int cnt; 1527*0Sstevel@tonic-gate struct s_spcl *sp; 1528*0Sstevel@tonic-gate int32_t expected_magic; 1529*0Sstevel@tonic-gate 1530*0Sstevel@tonic-gate if (tbf == NULL) { 1531*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1532*0Sstevel@tonic-gate "Internal consistency failure in readtape: tbf is NULL\n")); 1533*0Sstevel@tonic-gate done(1); 1534*0Sstevel@tonic-gate } 1535*0Sstevel@tonic-gate expected_magic = ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC); 1536*0Sstevel@tonic-gate 1537*0Sstevel@tonic-gate top: 1538*0Sstevel@tonic-gate if (bct < numtrec) { 1539*0Sstevel@tonic-gate /* 1540*0Sstevel@tonic-gate * check for old-dump floppy EOM -- it may appear in 1541*0Sstevel@tonic-gate * the middle of a buffer. The Dflag used to be used for 1542*0Sstevel@tonic-gate * this, but since it doesn't hurt to always do this we 1543*0Sstevel@tonic-gate * got rid of the Dflag. 1544*0Sstevel@tonic-gate */ 1545*0Sstevel@tonic-gate /*LINTED [tbf = malloc()]*/ 1546*0Sstevel@tonic-gate sp = &((union u_spcl *)&tbf[bct*tp_bsize])->s_spcl; 1547*0Sstevel@tonic-gate if (sp->c_magic == expected_magic && sp->c_type == TS_EOM && 1548*0Sstevel@tonic-gate (time_t)(sp->c_date) == dumpdate && 1549*0Sstevel@tonic-gate (time_t)(sp->c_ddate) == dumptime) { 1550*0Sstevel@tonic-gate for (i = 0; i < ntrec; i++) 1551*0Sstevel@tonic-gate /*LINTED [tbf = malloc()]*/ 1552*0Sstevel@tonic-gate ((struct s_spcl *) 1553*0Sstevel@tonic-gate &tbf[i*tp_bsize])->c_magic = 0; 1554*0Sstevel@tonic-gate bct = 0; 1555*0Sstevel@tonic-gate rd = 0; 1556*0Sstevel@tonic-gate i = 0; 1557*0Sstevel@tonic-gate goto nextvol; 1558*0Sstevel@tonic-gate } 1559*0Sstevel@tonic-gate bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize); 1560*0Sstevel@tonic-gate blksread++; 1561*0Sstevel@tonic-gate tapea++; 1562*0Sstevel@tonic-gate return; 1563*0Sstevel@tonic-gate } 1564*0Sstevel@tonic-gate /*LINTED [assertion always true]*/ 1565*0Sstevel@tonic-gate assert(sizeof (union u_spcl) == TP_BSIZE_MAX); 1566*0Sstevel@tonic-gate for (i = 0; i < ntrec; i++) 1567*0Sstevel@tonic-gate /*LINTED [tbf = malloc()]*/ 1568*0Sstevel@tonic-gate ((struct s_spcl *)&tbf[i*sizeof (struct s_spcl)])->c_magic = 0; 1569*0Sstevel@tonic-gate if (numtrec == 0) { 1570*0Sstevel@tonic-gate /* LINTED unsigned/signed assignment ok */ 1571*0Sstevel@tonic-gate numtrec = ntrec; 1572*0Sstevel@tonic-gate } 1573*0Sstevel@tonic-gate /* LINTED unsigned/signed assignment ok */ 1574*0Sstevel@tonic-gate cnt = ntrec*tp_bsize; 1575*0Sstevel@tonic-gate rd = 0; 1576*0Sstevel@tonic-gate getmore: 1577*0Sstevel@tonic-gate if (host) 1578*0Sstevel@tonic-gate i = rmtread(&tbf[rd], cnt); 1579*0Sstevel@tonic-gate else 1580*0Sstevel@tonic-gate i = read(mt, &tbf[rd], cnt); 1581*0Sstevel@tonic-gate /* 1582*0Sstevel@tonic-gate * Check for mid-tape short read error. 1583*0Sstevel@tonic-gate * If found, return rest of buffer. 1584*0Sstevel@tonic-gate */ 1585*0Sstevel@tonic-gate if (numtrec < ntrec && i != 0) { 1586*0Sstevel@tonic-gate /* LINTED unsigned/signed assignment ok */ 1587*0Sstevel@tonic-gate numtrec = ntrec; 1588*0Sstevel@tonic-gate goto top; 1589*0Sstevel@tonic-gate } 1590*0Sstevel@tonic-gate /* 1591*0Sstevel@tonic-gate * Handle partial block read. 1592*0Sstevel@tonic-gate */ 1593*0Sstevel@tonic-gate if (i > 0 && i != ntrec*tp_bsize) { 1594*0Sstevel@tonic-gate if (pipein) { 1595*0Sstevel@tonic-gate rd += i; 1596*0Sstevel@tonic-gate cnt -= i; 1597*0Sstevel@tonic-gate if (cnt > 0) 1598*0Sstevel@tonic-gate goto getmore; 1599*0Sstevel@tonic-gate i = rd; 1600*0Sstevel@tonic-gate } else { 1601*0Sstevel@tonic-gate if (i % tp_bsize != 0) 1602*0Sstevel@tonic-gate panic(gettext( 1603*0Sstevel@tonic-gate "partial block read: %d should be %d\n"), 1604*0Sstevel@tonic-gate i, ntrec * tp_bsize); 1605*0Sstevel@tonic-gate numtrec = i / tp_bsize; 1606*0Sstevel@tonic-gate if (numtrec == 0) 1607*0Sstevel@tonic-gate /* 1608*0Sstevel@tonic-gate * it's possible to read only 512 bytes 1609*0Sstevel@tonic-gate * from a QIC device... 1610*0Sstevel@tonic-gate */ 1611*0Sstevel@tonic-gate i = 0; 1612*0Sstevel@tonic-gate } 1613*0Sstevel@tonic-gate } 1614*0Sstevel@tonic-gate /* 1615*0Sstevel@tonic-gate * Handle read error. 1616*0Sstevel@tonic-gate */ 1617*0Sstevel@tonic-gate if (i < 0) { 1618*0Sstevel@tonic-gate switch (curfile.action) { 1619*0Sstevel@tonic-gate default: 1620*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1621*0Sstevel@tonic-gate "Read error while trying to set up volume\n")); 1622*0Sstevel@tonic-gate break; 1623*0Sstevel@tonic-gate case UNKNOWN: 1624*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1625*0Sstevel@tonic-gate "Read error while trying to resynchronize\n")); 1626*0Sstevel@tonic-gate break; 1627*0Sstevel@tonic-gate case USING: 1628*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1629*0Sstevel@tonic-gate "Read error while restoring %s\n"), 1630*0Sstevel@tonic-gate curfile.name); 1631*0Sstevel@tonic-gate break; 1632*0Sstevel@tonic-gate case SKIP: 1633*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1634*0Sstevel@tonic-gate "Read error while skipping over inode %d\n"), 1635*0Sstevel@tonic-gate curfile.ino); 1636*0Sstevel@tonic-gate break; 1637*0Sstevel@tonic-gate } 1638*0Sstevel@tonic-gate if (!yflag && !reply(gettext("continue"))) 1639*0Sstevel@tonic-gate done(1); 1640*0Sstevel@tonic-gate /* LINTED: unsigned->signed conversion ok */ 1641*0Sstevel@tonic-gate i = (int)(ntrec*tp_bsize); 1642*0Sstevel@tonic-gate bzero(tbf, (size_t)i); 1643*0Sstevel@tonic-gate if ((host != 0 && rmtseek(i, 1) < 0) || 1644*0Sstevel@tonic-gate (host == 0 && (lseek64(mt, (offset_t)i, 1) == 1645*0Sstevel@tonic-gate (off64_t)-1))) { 1646*0Sstevel@tonic-gate perror(gettext("continuation failed")); 1647*0Sstevel@tonic-gate done(1); 1648*0Sstevel@tonic-gate } 1649*0Sstevel@tonic-gate } 1650*0Sstevel@tonic-gate /* 1651*0Sstevel@tonic-gate * Handle end of tape. The Dflag used to be used, but since it doesn't 1652*0Sstevel@tonic-gate * hurt to always check we got rid if it. 1653*0Sstevel@tonic-gate */ 1654*0Sstevel@tonic-gate 1655*0Sstevel@tonic-gate /* 1656*0Sstevel@tonic-gate * if the first record in the buffer just read is EOM, 1657*0Sstevel@tonic-gate * change volumes. 1658*0Sstevel@tonic-gate */ 1659*0Sstevel@tonic-gate /*LINTED [tbf = malloc()]*/ 1660*0Sstevel@tonic-gate sp = &((union u_spcl *)tbf)->s_spcl; 1661*0Sstevel@tonic-gate if (i != 0 && sp->c_magic == expected_magic && sp->c_type == TS_EOM && 1662*0Sstevel@tonic-gate (time_t)(sp->c_date) == dumpdate && 1663*0Sstevel@tonic-gate (time_t)(sp->c_ddate) == dumptime) { 1664*0Sstevel@tonic-gate i = 0; 1665*0Sstevel@tonic-gate } 1666*0Sstevel@tonic-gate nextvol: 1667*0Sstevel@tonic-gate if (i == 0) { 1668*0Sstevel@tonic-gate if (!pipein) { 1669*0Sstevel@tonic-gate newvol = volno + 1; 1670*0Sstevel@tonic-gate volno = 0; 1671*0Sstevel@tonic-gate numtrec = 0; 1672*0Sstevel@tonic-gate getvol(newvol); 1673*0Sstevel@tonic-gate readtape(b); /* XXX tail recursion, not goto top? */ 1674*0Sstevel@tonic-gate return; 1675*0Sstevel@tonic-gate } 1676*0Sstevel@tonic-gate /* XXX if panic returns, should we round rd up? */ 1677*0Sstevel@tonic-gate /* XXX if we do, then we should zero the intervening space */ 1678*0Sstevel@tonic-gate if (rd % tp_bsize != 0) 1679*0Sstevel@tonic-gate panic(gettext("partial block read: %d should be %d\n"), 1680*0Sstevel@tonic-gate rd, ntrec * tp_bsize); 1681*0Sstevel@tonic-gate bcopy((char *)&endoftapemark, &tbf[rd], (size_t)tp_bsize); 1682*0Sstevel@tonic-gate } 1683*0Sstevel@tonic-gate bct = 0; 1684*0Sstevel@tonic-gate bcopy(&tbf[(bct++*tp_bsize)], b, (size_t)tp_bsize); 1685*0Sstevel@tonic-gate blksread++; 1686*0Sstevel@tonic-gate recsread++; 1687*0Sstevel@tonic-gate tapea++; 1688*0Sstevel@tonic-gate rec_position++; 1689*0Sstevel@tonic-gate } 1690*0Sstevel@tonic-gate 1691*0Sstevel@tonic-gate void 1692*0Sstevel@tonic-gate #ifdef __STDC__ 1693*0Sstevel@tonic-gate findtapeblksize(int arfile) 1694*0Sstevel@tonic-gate #else 1695*0Sstevel@tonic-gate findtapeblksize(arfile) 1696*0Sstevel@tonic-gate int arfile; 1697*0Sstevel@tonic-gate #endif 1698*0Sstevel@tonic-gate { 1699*0Sstevel@tonic-gate int i; 1700*0Sstevel@tonic-gate 1701*0Sstevel@tonic-gate if (tbf == NULL) { 1702*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1703*0Sstevel@tonic-gate "Internal consistency failure in findtapeblksize: " 1704*0Sstevel@tonic-gate "tbf is NULL\n")); 1705*0Sstevel@tonic-gate assert(tbf != NULL); 1706*0Sstevel@tonic-gate done(1); 1707*0Sstevel@tonic-gate } 1708*0Sstevel@tonic-gate 1709*0Sstevel@tonic-gate for (i = 0; i < ntrec; i++) 1710*0Sstevel@tonic-gate /*LINTED [tbf = malloc()]*/ 1711*0Sstevel@tonic-gate ((struct s_spcl *)&tbf[i * tp_bsize])->c_magic = 0; 1712*0Sstevel@tonic-gate bct = 0; 1713*0Sstevel@tonic-gate if (host && arfile == TAPE_FILE) 1714*0Sstevel@tonic-gate tape_rec_size = rmtread(tbf, ntrec * tp_bsize); 1715*0Sstevel@tonic-gate else 1716*0Sstevel@tonic-gate tape_rec_size = read(mt, tbf, ntrec * tp_bsize); 1717*0Sstevel@tonic-gate recsread++; 1718*0Sstevel@tonic-gate rec_position++; 1719*0Sstevel@tonic-gate if (tape_rec_size == (ssize_t)-1) { 1720*0Sstevel@tonic-gate int saverr = errno; 1721*0Sstevel@tonic-gate char *errmsg = gettext("Media read error"); 1722*0Sstevel@tonic-gate errno = saverr; 1723*0Sstevel@tonic-gate perror(errmsg); 1724*0Sstevel@tonic-gate done(1); 1725*0Sstevel@tonic-gate } 1726*0Sstevel@tonic-gate if (tape_rec_size % tp_bsize != 0) { 1727*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1728*0Sstevel@tonic-gate "Record size (%d) is not a multiple of dump block size (%d)\n"), 1729*0Sstevel@tonic-gate tape_rec_size, tp_bsize); 1730*0Sstevel@tonic-gate done(1); 1731*0Sstevel@tonic-gate } 1732*0Sstevel@tonic-gate ntrec = (int)tape_rec_size / tp_bsize; 1733*0Sstevel@tonic-gate /* LINTED unsigned/signed assignment ok */ 1734*0Sstevel@tonic-gate numtrec = ntrec; 1735*0Sstevel@tonic-gate vprintf(stdout, gettext("Media block size is %d\n"), ntrec*2); 1736*0Sstevel@tonic-gate } 1737*0Sstevel@tonic-gate 1738*0Sstevel@tonic-gate void 1739*0Sstevel@tonic-gate #ifdef __STDC__ 1740*0Sstevel@tonic-gate flsht(void) 1741*0Sstevel@tonic-gate #else 1742*0Sstevel@tonic-gate flsht() 1743*0Sstevel@tonic-gate #endif 1744*0Sstevel@tonic-gate { 1745*0Sstevel@tonic-gate /* LINTED unsigned/signed assignment ok */ 1746*0Sstevel@tonic-gate bct = ntrec+1; 1747*0Sstevel@tonic-gate } 1748*0Sstevel@tonic-gate 1749*0Sstevel@tonic-gate void 1750*0Sstevel@tonic-gate #ifdef __STDC__ 1751*0Sstevel@tonic-gate closemt(void) 1752*0Sstevel@tonic-gate #else 1753*0Sstevel@tonic-gate closemt() 1754*0Sstevel@tonic-gate #endif 1755*0Sstevel@tonic-gate { 1756*0Sstevel@tonic-gate static struct mtop mtop = { MTOFFL, 0 }; 1757*0Sstevel@tonic-gate 1758*0Sstevel@tonic-gate if (mt < 0) 1759*0Sstevel@tonic-gate return; 1760*0Sstevel@tonic-gate if (offline) 1761*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Rewinding tape\n")); 1762*0Sstevel@tonic-gate if (host) { 1763*0Sstevel@tonic-gate if (offline) 1764*0Sstevel@tonic-gate (void) rmtioctl(MTOFFL, 1); 1765*0Sstevel@tonic-gate rmtclose(); 1766*0Sstevel@tonic-gate } else if (pipein) { 1767*0Sstevel@tonic-gate char buffy[MAXBSIZE]; 1768*0Sstevel@tonic-gate 1769*0Sstevel@tonic-gate while (read(mt, buffy, sizeof (buffy)) > 0) { 1770*0Sstevel@tonic-gate continue; 1771*0Sstevel@tonic-gate /*LINTED [assertion always true]*/ 1772*0Sstevel@tonic-gate } 1773*0Sstevel@tonic-gate (void) close(mt); 1774*0Sstevel@tonic-gate } else { 1775*0Sstevel@tonic-gate /* 1776*0Sstevel@tonic-gate * Only way to tell if this is a floppy is to issue an ioctl 1777*0Sstevel@tonic-gate * but why waste one - if the eject fails, tough! 1778*0Sstevel@tonic-gate */ 1779*0Sstevel@tonic-gate if (offline) 1780*0Sstevel@tonic-gate (void) ioctl(mt, MTIOCTOP, &mtop); 1781*0Sstevel@tonic-gate (void) ioctl(mt, FDEJECT, 0); 1782*0Sstevel@tonic-gate (void) close(mt); 1783*0Sstevel@tonic-gate } 1784*0Sstevel@tonic-gate mt = -1; 1785*0Sstevel@tonic-gate } 1786*0Sstevel@tonic-gate 1787*0Sstevel@tonic-gate static int 1788*0Sstevel@tonic-gate checkvol(b, t) 1789*0Sstevel@tonic-gate struct s_spcl *b; 1790*0Sstevel@tonic-gate int t; 1791*0Sstevel@tonic-gate { 1792*0Sstevel@tonic-gate 1793*0Sstevel@tonic-gate if (b->c_volume != t) 1794*0Sstevel@tonic-gate return (FAIL); 1795*0Sstevel@tonic-gate return (GOOD); 1796*0Sstevel@tonic-gate } 1797*0Sstevel@tonic-gate 1798*0Sstevel@tonic-gate readhdr(b) 1799*0Sstevel@tonic-gate struct s_spcl *b; 1800*0Sstevel@tonic-gate { 1801*0Sstevel@tonic-gate 1802*0Sstevel@tonic-gate if (gethead(b) == FAIL) { 1803*0Sstevel@tonic-gate dprintf(stdout, gettext("readhdr fails at %ld blocks\n"), 1804*0Sstevel@tonic-gate blksread); 1805*0Sstevel@tonic-gate return (FAIL); 1806*0Sstevel@tonic-gate } 1807*0Sstevel@tonic-gate return (GOOD); 1808*0Sstevel@tonic-gate } 1809*0Sstevel@tonic-gate 1810*0Sstevel@tonic-gate /* 1811*0Sstevel@tonic-gate * read the tape into buf, then return whether or 1812*0Sstevel@tonic-gate * or not it is a header block. 1813*0Sstevel@tonic-gate */ 1814*0Sstevel@tonic-gate gethead(buf) 1815*0Sstevel@tonic-gate struct s_spcl *buf; 1816*0Sstevel@tonic-gate { 1817*0Sstevel@tonic-gate int i; 1818*0Sstevel@tonic-gate union u_ospcl { 1819*0Sstevel@tonic-gate char dummy[TP_BSIZE_MIN]; 1820*0Sstevel@tonic-gate struct s_ospcl { 1821*0Sstevel@tonic-gate int32_t c_type; 1822*0Sstevel@tonic-gate int32_t c_date; 1823*0Sstevel@tonic-gate int32_t c_ddate; 1824*0Sstevel@tonic-gate int32_t c_volume; 1825*0Sstevel@tonic-gate int32_t c_tapea; 1826*0Sstevel@tonic-gate ushort_t c_inumber; 1827*0Sstevel@tonic-gate int32_t c_magic; 1828*0Sstevel@tonic-gate int32_t c_checksum; 1829*0Sstevel@tonic-gate struct odinode { 1830*0Sstevel@tonic-gate unsigned short odi_mode; 1831*0Sstevel@tonic-gate ushort_t odi_nlink; 1832*0Sstevel@tonic-gate ushort_t odi_uid; 1833*0Sstevel@tonic-gate ushort_t odi_gid; 1834*0Sstevel@tonic-gate int32_t odi_size; 1835*0Sstevel@tonic-gate int32_t odi_rdev; 1836*0Sstevel@tonic-gate char odi_addr[36]; 1837*0Sstevel@tonic-gate int32_t odi_atime; 1838*0Sstevel@tonic-gate int32_t odi_mtime; 1839*0Sstevel@tonic-gate int32_t odi_ctime; 1840*0Sstevel@tonic-gate } c_dinode; 1841*0Sstevel@tonic-gate int32_t c_count; 1842*0Sstevel@tonic-gate char c_baddr[256]; 1843*0Sstevel@tonic-gate } s_ospcl; 1844*0Sstevel@tonic-gate } u_ospcl; 1845*0Sstevel@tonic-gate 1846*0Sstevel@tonic-gate if (cvtflag) { 1847*0Sstevel@tonic-gate readtape((char *)(&u_ospcl.s_ospcl)); 1848*0Sstevel@tonic-gate bzero((char *)buf, (size_t)TP_BSIZE_MIN); 1849*0Sstevel@tonic-gate buf->c_type = u_ospcl.s_ospcl.c_type; 1850*0Sstevel@tonic-gate buf->c_date = u_ospcl.s_ospcl.c_date; 1851*0Sstevel@tonic-gate buf->c_ddate = u_ospcl.s_ospcl.c_ddate; 1852*0Sstevel@tonic-gate buf->c_volume = u_ospcl.s_ospcl.c_volume; 1853*0Sstevel@tonic-gate buf->c_tapea = u_ospcl.s_ospcl.c_tapea; 1854*0Sstevel@tonic-gate buf->c_inumber = u_ospcl.s_ospcl.c_inumber; 1855*0Sstevel@tonic-gate buf->c_checksum = u_ospcl.s_ospcl.c_checksum; 1856*0Sstevel@tonic-gate buf->c_magic = u_ospcl.s_ospcl.c_magic; 1857*0Sstevel@tonic-gate buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode; 1858*0Sstevel@tonic-gate /* LINTED: unsigned/signed combination ok */ 1859*0Sstevel@tonic-gate buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink; 1860*0Sstevel@tonic-gate buf->c_dinode.di_size = 1861*0Sstevel@tonic-gate (unsigned)(u_ospcl.s_ospcl.c_dinode.odi_size); 1862*0Sstevel@tonic-gate buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid; 1863*0Sstevel@tonic-gate buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid; 1864*0Sstevel@tonic-gate buf->c_dinode.di_suid = UID_LONG; 1865*0Sstevel@tonic-gate buf->c_dinode.di_sgid = GID_LONG; 1866*0Sstevel@tonic-gate buf->c_dinode.di_ordev = u_ospcl.s_ospcl.c_dinode.odi_rdev; 1867*0Sstevel@tonic-gate buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime; 1868*0Sstevel@tonic-gate buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime; 1869*0Sstevel@tonic-gate buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime; 1870*0Sstevel@tonic-gate buf->c_count = u_ospcl.s_ospcl.c_count; 1871*0Sstevel@tonic-gate bcopy(u_ospcl.s_ospcl.c_baddr, buf->c_addr, 1872*0Sstevel@tonic-gate sizeof (u_ospcl.s_ospcl.c_baddr)); 1873*0Sstevel@tonic-gate 1874*0Sstevel@tonic-gate /*CONSTANTCONDITION*/ 1875*0Sstevel@tonic-gate assert(sizeof (u_ospcl.s_ospcl) < sizeof (union u_spcl)); 1876*0Sstevel@tonic-gate 1877*0Sstevel@tonic-gate /* we byte-swap the new spclrec, but checksum the old */ 1878*0Sstevel@tonic-gate /* (see comments in normspcl()) */ 1879*0Sstevel@tonic-gate if (normspcl(byteorder, buf, 1880*0Sstevel@tonic-gate (int *)(&u_ospcl.s_ospcl), sizeof (u_ospcl.s_ospcl), 1881*0Sstevel@tonic-gate OFS_MAGIC)) 1882*0Sstevel@tonic-gate return (FAIL); 1883*0Sstevel@tonic-gate buf->c_magic = 1884*0Sstevel@tonic-gate ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC); 1885*0Sstevel@tonic-gate } else { 1886*0Sstevel@tonic-gate readtape((char *)buf); 1887*0Sstevel@tonic-gate if (normspcl(byteorder, buf, (int *)buf, tp_bsize, 1888*0Sstevel@tonic-gate ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC))) 1889*0Sstevel@tonic-gate return (FAIL); 1890*0Sstevel@tonic-gate } 1891*0Sstevel@tonic-gate 1892*0Sstevel@tonic-gate switch (buf->c_type) { 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate case TS_CLRI: 1895*0Sstevel@tonic-gate case TS_BITS: 1896*0Sstevel@tonic-gate /* 1897*0Sstevel@tonic-gate * Have to patch up missing information in bit map headers 1898*0Sstevel@tonic-gate */ 1899*0Sstevel@tonic-gate buf->c_inumber = 0; 1900*0Sstevel@tonic-gate buf->c_dinode.di_size = (offset_t)buf->c_count * tp_bsize; 1901*0Sstevel@tonic-gate for (i = 0; i < buf->c_count && i < TP_NINDIR; i++) 1902*0Sstevel@tonic-gate buf->c_addr[i] = 1; 1903*0Sstevel@tonic-gate break; 1904*0Sstevel@tonic-gate 1905*0Sstevel@tonic-gate case TS_TAPE: 1906*0Sstevel@tonic-gate case TS_END: 1907*0Sstevel@tonic-gate if (dumpinfo.c_date == 0) { 1908*0Sstevel@tonic-gate dumpinfo.c_date = spcl.c_date; 1909*0Sstevel@tonic-gate dumpinfo.c_ddate = spcl.c_ddate; 1910*0Sstevel@tonic-gate } 1911*0Sstevel@tonic-gate if (!hostinfo && spcl.c_host[0] != '\0') { 1912*0Sstevel@tonic-gate bcopy(spcl.c_label, dumpinfo.c_label, 1913*0Sstevel@tonic-gate sizeof (spcl.c_label)); 1914*0Sstevel@tonic-gate bcopy(spcl.c_filesys, dumpinfo.c_filesys, 1915*0Sstevel@tonic-gate sizeof (spcl.c_filesys)); 1916*0Sstevel@tonic-gate bcopy(spcl.c_dev, dumpinfo.c_dev, 1917*0Sstevel@tonic-gate sizeof (spcl.c_dev)); 1918*0Sstevel@tonic-gate bcopy(spcl.c_host, dumpinfo.c_host, 1919*0Sstevel@tonic-gate sizeof (spcl.c_host)); 1920*0Sstevel@tonic-gate dumpinfo.c_level = spcl.c_level; 1921*0Sstevel@tonic-gate hostinfo++; 1922*0Sstevel@tonic-gate if (c_label != NULL && 1923*0Sstevel@tonic-gate strncmp(c_label, spcl.c_label, 1924*0Sstevel@tonic-gate sizeof (spcl.c_label)) 1925*0Sstevel@tonic-gate != 0) { 1926*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1927*0Sstevel@tonic-gate "Incorrect tape label. Expected `%s', got `%.*s'\n"), 1928*0Sstevel@tonic-gate c_label, 1929*0Sstevel@tonic-gate sizeof (spcl.c_label), spcl.c_label); 1930*0Sstevel@tonic-gate done(1); 1931*0Sstevel@tonic-gate } 1932*0Sstevel@tonic-gate } 1933*0Sstevel@tonic-gate if (!inodeinfo && (spcl.c_flags & DR_INODEINFO)) { 1934*0Sstevel@tonic-gate dumpinfo.c_volume = spcl.c_volume; 1935*0Sstevel@tonic-gate bcopy(spcl.c_inos, dumpinfo.c_inos, 1936*0Sstevel@tonic-gate sizeof (spcl.c_inos)); 1937*0Sstevel@tonic-gate inodeinfo++; 1938*0Sstevel@tonic-gate } 1939*0Sstevel@tonic-gate buf->c_inumber = 0; 1940*0Sstevel@tonic-gate break; 1941*0Sstevel@tonic-gate 1942*0Sstevel@tonic-gate case TS_INODE: 1943*0Sstevel@tonic-gate case TS_ADDR: 1944*0Sstevel@tonic-gate break; 1945*0Sstevel@tonic-gate 1946*0Sstevel@tonic-gate default: 1947*0Sstevel@tonic-gate panic(gettext("%s: unknown inode type %d\n"), 1948*0Sstevel@tonic-gate "gethead", buf->c_type); 1949*0Sstevel@tonic-gate return (FAIL); 1950*0Sstevel@tonic-gate } 1951*0Sstevel@tonic-gate if (dflag) 1952*0Sstevel@tonic-gate accthdr(buf); 1953*0Sstevel@tonic-gate return (GOOD); 1954*0Sstevel@tonic-gate } 1955*0Sstevel@tonic-gate 1956*0Sstevel@tonic-gate /* 1957*0Sstevel@tonic-gate * Check that a header is where it belongs and predict the next header 1958*0Sstevel@tonic-gate */ 1959*0Sstevel@tonic-gate static void 1960*0Sstevel@tonic-gate accthdr(header) 1961*0Sstevel@tonic-gate struct s_spcl *header; 1962*0Sstevel@tonic-gate { 1963*0Sstevel@tonic-gate static ino_t previno = (ino_t)(unsigned)-1; 1964*0Sstevel@tonic-gate static int prevtype; 1965*0Sstevel@tonic-gate static long predict; 1966*0Sstevel@tonic-gate int blks, i; 1967*0Sstevel@tonic-gate 1968*0Sstevel@tonic-gate if (header->c_type == TS_TAPE) { 1969*0Sstevel@tonic-gate if (header->c_firstrec) 1970*0Sstevel@tonic-gate (void) fprintf(stderr, 1971*0Sstevel@tonic-gate gettext("Volume header begins with record %d"), 1972*0Sstevel@tonic-gate header->c_firstrec); 1973*0Sstevel@tonic-gate else 1974*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Volume header")); 1975*0Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 1976*0Sstevel@tonic-gate previno = (ino_t)(unsigned)-1; 1977*0Sstevel@tonic-gate return; 1978*0Sstevel@tonic-gate } 1979*0Sstevel@tonic-gate if (previno == (ino_t)(unsigned)-1) 1980*0Sstevel@tonic-gate goto newcalc; 1981*0Sstevel@tonic-gate switch (prevtype) { 1982*0Sstevel@tonic-gate case TS_BITS: 1983*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Dump mask header")); 1984*0Sstevel@tonic-gate break; 1985*0Sstevel@tonic-gate case TS_CLRI: 1986*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("Remove mask header")); 1987*0Sstevel@tonic-gate break; 1988*0Sstevel@tonic-gate case TS_INODE: 1989*0Sstevel@tonic-gate (void) fprintf(stderr, 1990*0Sstevel@tonic-gate gettext("File header, ino %d at record %d"), 1991*0Sstevel@tonic-gate previno, rec_position); 1992*0Sstevel@tonic-gate break; 1993*0Sstevel@tonic-gate case TS_ADDR: 1994*0Sstevel@tonic-gate (void) fprintf(stderr, 1995*0Sstevel@tonic-gate gettext("File continuation header, ino %d"), 1996*0Sstevel@tonic-gate previno); 1997*0Sstevel@tonic-gate break; 1998*0Sstevel@tonic-gate case TS_END: 1999*0Sstevel@tonic-gate (void) fprintf(stderr, gettext("End of media header")); 2000*0Sstevel@tonic-gate break; 2001*0Sstevel@tonic-gate } 2002*0Sstevel@tonic-gate if (predict != blksread - 1) 2003*0Sstevel@tonic-gate (void) fprintf(stderr, 2004*0Sstevel@tonic-gate gettext("; predicted %ld blocks, got %ld blocks"), 2005*0Sstevel@tonic-gate predict, blksread - 1); 2006*0Sstevel@tonic-gate (void) fprintf(stderr, "\n"); 2007*0Sstevel@tonic-gate newcalc: 2008*0Sstevel@tonic-gate blks = 0; 2009*0Sstevel@tonic-gate if (header->c_type != TS_END) 2010*0Sstevel@tonic-gate for (i = 0; i < header->c_count; i++) 2011*0Sstevel@tonic-gate if ((i >= TP_NINDIR) || (header->c_addr[i] != 0)) 2012*0Sstevel@tonic-gate blks++; 2013*0Sstevel@tonic-gate predict = blks; 2014*0Sstevel@tonic-gate blksread = 0; 2015*0Sstevel@tonic-gate prevtype = header->c_type; 2016*0Sstevel@tonic-gate previno = header->c_inumber; 2017*0Sstevel@tonic-gate } 2018*0Sstevel@tonic-gate 2019*0Sstevel@tonic-gate /* 2020*0Sstevel@tonic-gate * Try to determine which volume a file resides on. 2021*0Sstevel@tonic-gate */ 2022*0Sstevel@tonic-gate volnumber(inum) 2023*0Sstevel@tonic-gate ino_t inum; 2024*0Sstevel@tonic-gate { 2025*0Sstevel@tonic-gate int i; 2026*0Sstevel@tonic-gate 2027*0Sstevel@tonic-gate if (inodeinfo == 0) 2028*0Sstevel@tonic-gate return (0); 2029*0Sstevel@tonic-gate for (i = 1; i <= dumpinfo.c_volume; i++) 2030*0Sstevel@tonic-gate if (inum < (ino_t)(unsigned)(dumpinfo.c_inos[i])) 2031*0Sstevel@tonic-gate break; 2032*0Sstevel@tonic-gate return (i - 1); 2033*0Sstevel@tonic-gate } 2034*0Sstevel@tonic-gate 2035*0Sstevel@tonic-gate /* 2036*0Sstevel@tonic-gate * Find an inode header. 2037*0Sstevel@tonic-gate * Note that *header must be stable storage, as curfile will end up with 2038*0Sstevel@tonic-gate * pointers into it. 2039*0Sstevel@tonic-gate */ 2040*0Sstevel@tonic-gate void 2041*0Sstevel@tonic-gate findinode(header) 2042*0Sstevel@tonic-gate struct s_spcl *header; 2043*0Sstevel@tonic-gate { 2044*0Sstevel@tonic-gate long skipcnt = 0; 2045*0Sstevel@tonic-gate int i; 2046*0Sstevel@tonic-gate char buf[TP_BSIZE_MAX]; 2047*0Sstevel@tonic-gate 2048*0Sstevel@tonic-gate curfile.name = gettext("<name unknown>"); 2049*0Sstevel@tonic-gate curfile.action = UNKNOWN; 2050*0Sstevel@tonic-gate curfile.dip = (struct dinode *)NULL; 2051*0Sstevel@tonic-gate curfile.ino = 0; 2052*0Sstevel@tonic-gate curfile.ts = 0; 2053*0Sstevel@tonic-gate if (ishead(header) == FAIL) { 2054*0Sstevel@tonic-gate skipcnt++; 2055*0Sstevel@tonic-gate while (gethead(header) == FAIL || 2056*0Sstevel@tonic-gate (time_t)(header->c_date) != dumpdate) 2057*0Sstevel@tonic-gate skipcnt++; 2058*0Sstevel@tonic-gate } 2059*0Sstevel@tonic-gate for (;;) { 2060*0Sstevel@tonic-gate if (checktype(header, TS_ADDR) == GOOD) { 2061*0Sstevel@tonic-gate /* 2062*0Sstevel@tonic-gate * Skip up to the beginning of the next record 2063*0Sstevel@tonic-gate */ 2064*0Sstevel@tonic-gate for (i = 0; i < header->c_count; i++) 2065*0Sstevel@tonic-gate if ((i >= TP_NINDIR) || (header->c_addr[i])) 2066*0Sstevel@tonic-gate readtape(buf); 2067*0Sstevel@tonic-gate (void) gethead(header); 2068*0Sstevel@tonic-gate continue; 2069*0Sstevel@tonic-gate } 2070*0Sstevel@tonic-gate if (checktype(header, TS_INODE) == GOOD) { 2071*0Sstevel@tonic-gate curfile.dip = &header->c_dinode; 2072*0Sstevel@tonic-gate if (curfile.dip->di_suid != UID_LONG) 2073*0Sstevel@tonic-gate curfile.dip->di_uid = curfile.dip->di_suid; 2074*0Sstevel@tonic-gate if (curfile.dip->di_sgid != GID_LONG) 2075*0Sstevel@tonic-gate curfile.dip->di_gid = curfile.dip->di_sgid; 2076*0Sstevel@tonic-gate curfile.ino = header->c_inumber; 2077*0Sstevel@tonic-gate curfile.ts = TS_INODE; 2078*0Sstevel@tonic-gate break; 2079*0Sstevel@tonic-gate } 2080*0Sstevel@tonic-gate if (checktype(header, TS_END) == GOOD) { 2081*0Sstevel@tonic-gate curfile.ino = maxino; 2082*0Sstevel@tonic-gate curfile.ts = TS_END; 2083*0Sstevel@tonic-gate break; 2084*0Sstevel@tonic-gate } 2085*0Sstevel@tonic-gate if (checktype(header, TS_CLRI) == GOOD) { 2086*0Sstevel@tonic-gate curfile.name = gettext("<file removal list>"); 2087*0Sstevel@tonic-gate curfile.ts = TS_CLRI; 2088*0Sstevel@tonic-gate break; 2089*0Sstevel@tonic-gate } 2090*0Sstevel@tonic-gate if (checktype(header, TS_BITS) == GOOD) { 2091*0Sstevel@tonic-gate curfile.name = gettext("<file dump list>"); 2092*0Sstevel@tonic-gate curfile.ts = TS_BITS; 2093*0Sstevel@tonic-gate break; 2094*0Sstevel@tonic-gate } 2095*0Sstevel@tonic-gate while (gethead(header) == FAIL) 2096*0Sstevel@tonic-gate skipcnt++; 2097*0Sstevel@tonic-gate } 2098*0Sstevel@tonic-gate if (skipcnt > 0) 2099*0Sstevel@tonic-gate (void) fprintf(stderr, 2100*0Sstevel@tonic-gate gettext("resync restore, skipped %d blocks\n"), 2101*0Sstevel@tonic-gate skipcnt); 2102*0Sstevel@tonic-gate } 2103*0Sstevel@tonic-gate 2104*0Sstevel@tonic-gate /* 2105*0Sstevel@tonic-gate * return whether or not the buffer contains a header block 2106*0Sstevel@tonic-gate */ 2107*0Sstevel@tonic-gate static int 2108*0Sstevel@tonic-gate ishead(buf) 2109*0Sstevel@tonic-gate struct s_spcl *buf; 2110*0Sstevel@tonic-gate { 2111*0Sstevel@tonic-gate if (buf->c_magic != 2112*0Sstevel@tonic-gate ((tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC)) 2113*0Sstevel@tonic-gate return (FAIL); 2114*0Sstevel@tonic-gate return (GOOD); 2115*0Sstevel@tonic-gate } 2116*0Sstevel@tonic-gate 2117*0Sstevel@tonic-gate static 2118*0Sstevel@tonic-gate checktype(b, t) 2119*0Sstevel@tonic-gate struct s_spcl *b; 2120*0Sstevel@tonic-gate int t; 2121*0Sstevel@tonic-gate { 2122*0Sstevel@tonic-gate if (b->c_type != t) 2123*0Sstevel@tonic-gate return (FAIL); 2124*0Sstevel@tonic-gate return (GOOD); 2125*0Sstevel@tonic-gate } 2126*0Sstevel@tonic-gate 2127*0Sstevel@tonic-gate /* 2128*0Sstevel@tonic-gate * If autoloading is enabled, attempt to do it. If we succeed, 2129*0Sstevel@tonic-gate * return non-zero. 2130*0Sstevel@tonic-gate */ 2131*0Sstevel@tonic-gate static int 2132*0Sstevel@tonic-gate #ifdef __STDC__ 2133*0Sstevel@tonic-gate autoload_tape(void) 2134*0Sstevel@tonic-gate #else 2135*0Sstevel@tonic-gate autoload_tape() 2136*0Sstevel@tonic-gate #endif 2137*0Sstevel@tonic-gate { 2138*0Sstevel@tonic-gate int result = 0; /* assume failure */ 2139*0Sstevel@tonic-gate int tries; 2140*0Sstevel@tonic-gate int fd; 2141*0Sstevel@tonic-gate 2142*0Sstevel@tonic-gate if (autoload) { 2143*0Sstevel@tonic-gate /* 2144*0Sstevel@tonic-gate * Wait for the tape to autoload. Note that the delay 2145*0Sstevel@tonic-gate * period doesn't take into account however long it takes 2146*0Sstevel@tonic-gate * for the open to fail (measured at 21 seconds for an 2147*0Sstevel@tonic-gate * Exabyte 8200 under 2.7 on an Ultra 2). 2148*0Sstevel@tonic-gate */ 2149*0Sstevel@tonic-gate closemt(); 2150*0Sstevel@tonic-gate (void) fprintf(stderr, 2151*0Sstevel@tonic-gate gettext("Attempting to autoload next volume\n")); 2152*0Sstevel@tonic-gate for (tries = 0; tries < autoload_tries; tries++) { 2153*0Sstevel@tonic-gate if (host) { 2154*0Sstevel@tonic-gate if (rmtopen(magtape, O_RDONLY) >= 0) { 2155*0Sstevel@tonic-gate rmtclose(); 2156*0Sstevel@tonic-gate result = 1; 2157*0Sstevel@tonic-gate break; 2158*0Sstevel@tonic-gate } 2159*0Sstevel@tonic-gate } else { 2160*0Sstevel@tonic-gate if ((fd = open(magtape, O_RDONLY|O_LARGEFILE, 2161*0Sstevel@tonic-gate 0600)) >= 0) { 2162*0Sstevel@tonic-gate (void) close(fd); 2163*0Sstevel@tonic-gate result = 1; 2164*0Sstevel@tonic-gate break; 2165*0Sstevel@tonic-gate } 2166*0Sstevel@tonic-gate } 2167*0Sstevel@tonic-gate (void) sleep(autoload_period); 2168*0Sstevel@tonic-gate } 2169*0Sstevel@tonic-gate if (result == 0) { 2170*0Sstevel@tonic-gate /* Assume caller will deal with manual change-over */ 2171*0Sstevel@tonic-gate (void) fprintf(stderr, 2172*0Sstevel@tonic-gate gettext("Autoload timed out\n")); 2173*0Sstevel@tonic-gate } else { 2174*0Sstevel@tonic-gate if ((host != NULL && 2175*0Sstevel@tonic-gate (mt = rmtopen(magtape, O_RDONLY)) == -1) || 2176*0Sstevel@tonic-gate (host == NULL && 2177*0Sstevel@tonic-gate (mt = open(magtape, O_RDONLY|O_LARGEFILE)) == -1)) { 2178*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2179*0Sstevel@tonic-gate "Autoload could not re-open tape\n")); 2180*0Sstevel@tonic-gate result = 0; 2181*0Sstevel@tonic-gate } else { 2182*0Sstevel@tonic-gate (void) fprintf(stderr, gettext( 2183*0Sstevel@tonic-gate "Tape loaded\n")); 2184*0Sstevel@tonic-gate } 2185*0Sstevel@tonic-gate } 2186*0Sstevel@tonic-gate } 2187*0Sstevel@tonic-gate 2188*0Sstevel@tonic-gate return (result); 2189*0Sstevel@tonic-gate } 2190