1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 32*0Sstevel@tonic-gate * under license from the Regents of the University of California. 33*0Sstevel@tonic-gate */ 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 36*0Sstevel@tonic-gate 37*0Sstevel@tonic-gate #include "dump.h" 38*0Sstevel@tonic-gate #include <rmt.h> 39*0Sstevel@tonic-gate #include <setjmp.h> 40*0Sstevel@tonic-gate #include <sys/fdio.h> 41*0Sstevel@tonic-gate #include <sys/mkdev.h> 42*0Sstevel@tonic-gate #include <assert.h> 43*0Sstevel@tonic-gate #include <limits.h> 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #define SLEEPMS 50 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate static uint_t writesize; /* size of malloc()ed buffer for tape */ 48*0Sstevel@tonic-gate static ino_t inos[TP_NINOS]; /* starting inodes on each tape */ 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate /* 51*0Sstevel@tonic-gate * The req structure is used to pass commands from the parent 52*0Sstevel@tonic-gate * process through the pipes to the slave processes. It comes 53*0Sstevel@tonic-gate * in two flavors, depending on which mode dump is operating under: 54*0Sstevel@tonic-gate * an inode request (on-line mode) and a disk block request ("old" mode). 55*0Sstevel@tonic-gate */ 56*0Sstevel@tonic-gate /* 57*0Sstevel@tonic-gate * The inode request structure is used during on-line mode. 58*0Sstevel@tonic-gate * The master passes inode numbers and starting offsets to 59*0Sstevel@tonic-gate * the slaves. The tape writer passes out the current inode, 60*0Sstevel@tonic-gate * offset, and number of tape records written after completing a volume. 61*0Sstevel@tonic-gate */ 62*0Sstevel@tonic-gate struct ireq { 63*0Sstevel@tonic-gate ino_t inumber; /* inode number to open/dump */ 64*0Sstevel@tonic-gate long igen; /* inode generation number */ 65*0Sstevel@tonic-gate off_t offset; /* starting offset in inode */ 66*0Sstevel@tonic-gate int count; /* count for 1st spclrec */ 67*0Sstevel@tonic-gate }; 68*0Sstevel@tonic-gate /* 69*0Sstevel@tonic-gate * The block request structure is used in off-line mode to pass 70*0Sstevel@tonic-gate * commands to dump disk blocks from the parent process through 71*0Sstevel@tonic-gate * the pipes to the slave processes. 72*0Sstevel@tonic-gate */ 73*0Sstevel@tonic-gate struct breq { 74*0Sstevel@tonic-gate diskaddr_t dblk; /* disk address to read */ 75*0Sstevel@tonic-gate size_t size; /* number of bytes to read from disk */ 76*0Sstevel@tonic-gate ulong_t spclrec[1]; /* actually longer */ 77*0Sstevel@tonic-gate }; 78*0Sstevel@tonic-gate 79*0Sstevel@tonic-gate struct req { 80*0Sstevel@tonic-gate short aflag; /* write data to archive process as well */ 81*0Sstevel@tonic-gate short tflag; /* begin new tape */ 82*0Sstevel@tonic-gate union reqdata { 83*0Sstevel@tonic-gate struct ireq ino; /* used for on-line mode */ 84*0Sstevel@tonic-gate struct breq blks; /* used for off-line mode */ 85*0Sstevel@tonic-gate } data; 86*0Sstevel@tonic-gate }; 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate #define ir_inumber data.ino.inumber 89*0Sstevel@tonic-gate #define ir_igen data.ino.igen 90*0Sstevel@tonic-gate #define ir_offset data.ino.offset 91*0Sstevel@tonic-gate #define ir_count data.ino.count 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate #define br_dblk data.blks.dblk 94*0Sstevel@tonic-gate #define br_size data.blks.size 95*0Sstevel@tonic-gate #define br_spcl data.blks.spclrec 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate static int reqsiz = 0; /* alloctape will initialize */ 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate #define SLAVES 3 100*0Sstevel@tonic-gate struct slaves { 101*0Sstevel@tonic-gate int sl_slavefd; /* pipe from master to slave */ 102*0Sstevel@tonic-gate pid_t sl_slavepid; /* slave pid; used by killall() */ 103*0Sstevel@tonic-gate ino_t sl_inos; /* inos, if this record starts tape */ 104*0Sstevel@tonic-gate int sl_offset; /* logical blocks written for object */ 105*0Sstevel@tonic-gate int sl_count; /* logical blocks left in spclrec */ 106*0Sstevel@tonic-gate int sl_tapea; /* header number, if starting tape */ 107*0Sstevel@tonic-gate int sl_firstrec; /* number of first block on tape */ 108*0Sstevel@tonic-gate int sl_state; /* dump output state */ 109*0Sstevel@tonic-gate struct req *sl_req; /* instruction packet to slave */ 110*0Sstevel@tonic-gate }; 111*0Sstevel@tonic-gate static struct slaves slaves[SLAVES]; /* one per slave */ 112*0Sstevel@tonic-gate static struct slaves *slp; /* pointer to current slave */ 113*0Sstevel@tonic-gate static struct slaves chkpt; /* checkpointed data */ 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate struct bdesc { 116*0Sstevel@tonic-gate char *b_data; /* pointer to buffer data */ 117*0Sstevel@tonic-gate int b_flags; /* flags (see below) */ 118*0Sstevel@tonic-gate }; 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate /* 121*0Sstevel@tonic-gate * The following variables are in shared memory, and must be 122*0Sstevel@tonic-gate * explicitly checkpointed and/or reset. 123*0Sstevel@tonic-gate */ 124*0Sstevel@tonic-gate static caddr_t shared; /* pointer to block of shared memory */ 125*0Sstevel@tonic-gate static struct bdesc *bufp; /* buffer descriptors */ 126*0Sstevel@tonic-gate static struct bdesc **current; /* output buffer to fill */ 127*0Sstevel@tonic-gate static int *tapea; /* logical record count */ 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate #ifdef INSTRUMENT 130*0Sstevel@tonic-gate static int *readmissp; /* number of times writer was idle */ 131*0Sstevel@tonic-gate static int *idle; /* number of times slaves were idle */ 132*0Sstevel@tonic-gate #endif /* INSTRUMENT */ 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate /* 135*0Sstevel@tonic-gate * Buffer flags 136*0Sstevel@tonic-gate */ 137*0Sstevel@tonic-gate #define BUF_EMPTY 0x0 /* nothing in buffer */ 138*0Sstevel@tonic-gate #define BUF_FULL 0x1 /* data in buffer */ 139*0Sstevel@tonic-gate #define BUF_SPCLREC 0x2 /* contains special record */ 140*0Sstevel@tonic-gate #define BUF_ARCHIVE 0x4 /* dump to archive */ 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate static int recsout; /* number of req's sent to slaves */ 143*0Sstevel@tonic-gate static int totalrecsout; /* total number of req's sent to slaves */ 144*0Sstevel@tonic-gate static int rotor; /* next slave to be instructed */ 145*0Sstevel@tonic-gate static pid_t master; /* pid of master, for sending error signals */ 146*0Sstevel@tonic-gate static int writer = -1; /* fd of tape writer */ 147*0Sstevel@tonic-gate static pid_t writepid; /* pid of tape writer */ 148*0Sstevel@tonic-gate static int arch; /* fd of output archiver */ 149*0Sstevel@tonic-gate static pid_t archivepid; /* pid of output archiver */ 150*0Sstevel@tonic-gate static int archivefd; /* fd of archive file (proper) */ 151*0Sstevel@tonic-gate static offset_t lf_archoffset; /* checkpointed offset into archive file */ 152*0Sstevel@tonic-gate 153*0Sstevel@tonic-gate int caught; /* caught signal -- imported by mapfile() */ 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate #ifdef DEBUG 156*0Sstevel@tonic-gate extern int xflag; 157*0Sstevel@tonic-gate #endif 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate #ifdef __STDC__ 160*0Sstevel@tonic-gate static void cmdwrterr(void); 161*0Sstevel@tonic-gate static void cmdrderr(void); 162*0Sstevel@tonic-gate static void freetape(void); 163*0Sstevel@tonic-gate static void bufclear(void); 164*0Sstevel@tonic-gate static pid_t setuparchive(void); 165*0Sstevel@tonic-gate static pid_t setupwriter(void); 166*0Sstevel@tonic-gate static void nextslave(void); 167*0Sstevel@tonic-gate static void tperror(int); 168*0Sstevel@tonic-gate static void rollforward(int); 169*0Sstevel@tonic-gate static void nap(int); 170*0Sstevel@tonic-gate static void alrm(int); 171*0Sstevel@tonic-gate static void just_rewind(void); 172*0Sstevel@tonic-gate static void killall(void); 173*0Sstevel@tonic-gate static void proceed(int); 174*0Sstevel@tonic-gate static void die(int); 175*0Sstevel@tonic-gate static void enslave(void); 176*0Sstevel@tonic-gate static void wait_our_turn(void); 177*0Sstevel@tonic-gate static void dumpoffline(int, pid_t, int); 178*0Sstevel@tonic-gate static void onxfsz(int); 179*0Sstevel@tonic-gate static void dowrite(int); 180*0Sstevel@tonic-gate static void checkpoint(struct bdesc *, int); 181*0Sstevel@tonic-gate static ssize_t atomic(int (*)(), int, char *, int); 182*0Sstevel@tonic-gate #else 183*0Sstevel@tonic-gate static void cmdwrterr(); 184*0Sstevel@tonic-gate static void cmdrderr(); 185*0Sstevel@tonic-gate static void freetape(); 186*0Sstevel@tonic-gate static void bufclear(); 187*0Sstevel@tonic-gate static pid_t setuparchive(); 188*0Sstevel@tonic-gate static pid_t setupwriter(); 189*0Sstevel@tonic-gate static void nextslave(); 190*0Sstevel@tonic-gate static void tperror(); 191*0Sstevel@tonic-gate static void rollforward(); 192*0Sstevel@tonic-gate static void nap(); 193*0Sstevel@tonic-gate static void alrm(); 194*0Sstevel@tonic-gate static void just_rewind(); 195*0Sstevel@tonic-gate static void killall(); 196*0Sstevel@tonic-gate static void proceed(); 197*0Sstevel@tonic-gate static void die(); 198*0Sstevel@tonic-gate static void enslave(); 199*0Sstevel@tonic-gate static void wait_our_turn(); 200*0Sstevel@tonic-gate static void dumpoffline(); 201*0Sstevel@tonic-gate static void onxfsz(); 202*0Sstevel@tonic-gate static void dowrite(); 203*0Sstevel@tonic-gate static void checkpoint(); 204*0Sstevel@tonic-gate static ssize_t atomic(); 205*0Sstevel@tonic-gate #endif 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate static size_t tapesize; 208*0Sstevel@tonic-gate 209*0Sstevel@tonic-gate /* 210*0Sstevel@tonic-gate * Allocate buffers and shared memory variables. Tape buffers are 211*0Sstevel@tonic-gate * allocated on page boundaries for tape write() efficiency. 212*0Sstevel@tonic-gate */ 213*0Sstevel@tonic-gate void 214*0Sstevel@tonic-gate #ifdef __STDC__ 215*0Sstevel@tonic-gate #else 216*0Sstevel@tonic-gate #endif 217*0Sstevel@tonic-gate alloctape(void) 218*0Sstevel@tonic-gate { 219*0Sstevel@tonic-gate struct slaves *slavep; 220*0Sstevel@tonic-gate ulong_t pgoff = (unsigned)(getpagesize() - 1); /* 2**n - 1 */ 221*0Sstevel@tonic-gate int mapfd; 222*0Sstevel@tonic-gate char *obuf; 223*0Sstevel@tonic-gate int saverr; 224*0Sstevel@tonic-gate int i, j; 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate writesize = ntrec * tp_bsize; 227*0Sstevel@tonic-gate if (!printsize) 228*0Sstevel@tonic-gate msg(gettext("Writing %d Kilobyte records\n"), 229*0Sstevel@tonic-gate writesize / TP_BSIZE_MIN); 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate /* 232*0Sstevel@tonic-gate * set up shared memory seg for here and child 233*0Sstevel@tonic-gate */ 234*0Sstevel@tonic-gate mapfd = open("/dev/zero", O_RDWR); 235*0Sstevel@tonic-gate if (mapfd == -1) { 236*0Sstevel@tonic-gate saverr = errno; 237*0Sstevel@tonic-gate msg(gettext("Cannot open `%s': %s\n"), 238*0Sstevel@tonic-gate "/dev/zero", strerror(saverr)); 239*0Sstevel@tonic-gate dumpabort(); 240*0Sstevel@tonic-gate /*NOTREACHED*/ 241*0Sstevel@tonic-gate } 242*0Sstevel@tonic-gate /* 243*0Sstevel@tonic-gate * Allocate space such that buffers are page-aligned and 244*0Sstevel@tonic-gate * pointers are aligned on 4-byte boundaries (for SPARC). 245*0Sstevel@tonic-gate * This code assumes that (NBUF * writesize) is a multiple 246*0Sstevel@tonic-gate * of the page size and that pages are aligned on 4-byte 247*0Sstevel@tonic-gate * boundaries. Space is allocated as follows: 248*0Sstevel@tonic-gate * 249*0Sstevel@tonic-gate * (NBUF * writesize) for the actual buffers 250*0Sstevel@tonic-gate * (pagesize - 1) for padding so the buffers are page-aligned 251*0Sstevel@tonic-gate * (NBUF * ntrec * sizeof (struct bdesc)) for each buffer 252*0Sstevel@tonic-gate * (n * sizeof (int)) for [n] debugging variables/pointers 253*0Sstevel@tonic-gate * (n * sizeof (int)) for [n] miscellaneous variables/pointers 254*0Sstevel@tonic-gate */ 255*0Sstevel@tonic-gate tapesize = 256*0Sstevel@tonic-gate (NBUF * writesize) /* output buffers */ 257*0Sstevel@tonic-gate /* LINTED: pgoff fits into a size_t */ 258*0Sstevel@tonic-gate + (size_t)pgoff /* page alignment */ 259*0Sstevel@tonic-gate /* buffer descriptors */ 260*0Sstevel@tonic-gate + (((size_t)sizeof (struct bdesc)) * NBUF * ntrec) 261*0Sstevel@tonic-gate #ifdef INSTRUMENT 262*0Sstevel@tonic-gate + (2 * (size_t)sizeof (int *)) /* instrumentation */ 263*0Sstevel@tonic-gate #endif 264*0Sstevel@tonic-gate /* shared variables */ 265*0Sstevel@tonic-gate + (size_t)sizeof (struct bdesc **) 266*0Sstevel@tonic-gate + (size_t)sizeof (int *) 267*0Sstevel@tonic-gate + (3 * (size_t)sizeof (time_t)); 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate shared = mmap((char *)0, tapesize, PROT_READ|PROT_WRITE, 270*0Sstevel@tonic-gate MAP_SHARED, mapfd, (off_t)0); 271*0Sstevel@tonic-gate if (shared == (caddr_t)-1) { 272*0Sstevel@tonic-gate saverr = errno; 273*0Sstevel@tonic-gate msg(gettext("Cannot memory map output buffers: %s\n"), 274*0Sstevel@tonic-gate strerror(saverr)); 275*0Sstevel@tonic-gate dumpabort(); 276*0Sstevel@tonic-gate /*NOTREACHED*/ 277*0Sstevel@tonic-gate } 278*0Sstevel@tonic-gate (void) close(mapfd); 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate /* 281*0Sstevel@tonic-gate * Buffers and buffer headers 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate obuf = (char *)(((ulong_t)shared + pgoff) & ~pgoff); 284*0Sstevel@tonic-gate /* LINTED obuf and writesize are aligned */ 285*0Sstevel@tonic-gate bufp = (struct bdesc *)(obuf + NBUF*writesize); 286*0Sstevel@tonic-gate /* 287*0Sstevel@tonic-gate * Shared memory variables 288*0Sstevel@tonic-gate */ 289*0Sstevel@tonic-gate current = (struct bdesc **)&bufp[NBUF*ntrec]; 290*0Sstevel@tonic-gate tapea = (int *)(current + 1); 291*0Sstevel@tonic-gate /* LINTED pointer alignment ok */ 292*0Sstevel@tonic-gate telapsed = (time_t *)(tapea + 1); 293*0Sstevel@tonic-gate tstart_writing = telapsed + 1; 294*0Sstevel@tonic-gate tschedule = tstart_writing + 1; 295*0Sstevel@tonic-gate #ifdef INSTRUMENT 296*0Sstevel@tonic-gate /* 297*0Sstevel@tonic-gate * Debugging and instrumentation variables 298*0Sstevel@tonic-gate */ 299*0Sstevel@tonic-gate readmissp = (int *)(tschedule + 1); 300*0Sstevel@tonic-gate idle = readmissp + 1; 301*0Sstevel@tonic-gate #endif 302*0Sstevel@tonic-gate for (i = 0, j = 0; i < NBUF * ntrec; i++, j += tp_bsize) { 303*0Sstevel@tonic-gate bufp[i].b_data = &obuf[j]; 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate reqsiz = sizeof (struct req) + tp_bsize - sizeof (long); 307*0Sstevel@tonic-gate for (slavep = slaves; slavep < &slaves[SLAVES]; slavep++) 308*0Sstevel@tonic-gate slavep->sl_req = (struct req *)xmalloc(reqsiz); 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate chkpt.sl_offset = 0; /* start at offset 0 */ 311*0Sstevel@tonic-gate chkpt.sl_count = 0; 312*0Sstevel@tonic-gate chkpt.sl_inos = UFSROOTINO; /* in root inode */ 313*0Sstevel@tonic-gate chkpt.sl_firstrec = 1; 314*0Sstevel@tonic-gate chkpt.sl_tapea = 0; 315*0Sstevel@tonic-gate } 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate static void 318*0Sstevel@tonic-gate #ifdef __STDC__ 319*0Sstevel@tonic-gate freetape(void) 320*0Sstevel@tonic-gate #else 321*0Sstevel@tonic-gate freetape() 322*0Sstevel@tonic-gate #endif 323*0Sstevel@tonic-gate { 324*0Sstevel@tonic-gate if (shared == NULL) 325*0Sstevel@tonic-gate return; 326*0Sstevel@tonic-gate (void) timeclock((time_t)0); 327*0Sstevel@tonic-gate (void) munmap(shared, tapesize); 328*0Sstevel@tonic-gate shared = NULL; 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate /* 332*0Sstevel@tonic-gate * Reset tape state variables -- called 333*0Sstevel@tonic-gate * before a pass to dump active files. 334*0Sstevel@tonic-gate */ 335*0Sstevel@tonic-gate void 336*0Sstevel@tonic-gate #ifdef __STDC__ 337*0Sstevel@tonic-gate reset(void) 338*0Sstevel@tonic-gate #else 339*0Sstevel@tonic-gate reset() 340*0Sstevel@tonic-gate #endif 341*0Sstevel@tonic-gate { 342*0Sstevel@tonic-gate bufclear(); 343*0Sstevel@tonic-gate 344*0Sstevel@tonic-gate #ifdef INSTRUMENT 345*0Sstevel@tonic-gate (*readmissp) = 0; 346*0Sstevel@tonic-gate (*idle) = 0; 347*0Sstevel@tonic-gate #endif 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate spcl.c_flags = 0; 350*0Sstevel@tonic-gate spcl.c_volume = 0; 351*0Sstevel@tonic-gate tapeno = 0; 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate chkpt.sl_offset = 0; /* start at offset 0 */ 354*0Sstevel@tonic-gate chkpt.sl_count = 0; 355*0Sstevel@tonic-gate chkpt.sl_inos = UFSROOTINO; /* in root inode */ 356*0Sstevel@tonic-gate chkpt.sl_firstrec = 1; 357*0Sstevel@tonic-gate chkpt.sl_tapea = 0; 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate static void 361*0Sstevel@tonic-gate #ifdef __STDC__ 362*0Sstevel@tonic-gate bufclear(void) 363*0Sstevel@tonic-gate #else 364*0Sstevel@tonic-gate bufclear() 365*0Sstevel@tonic-gate #endif 366*0Sstevel@tonic-gate { 367*0Sstevel@tonic-gate struct bdesc *bp; 368*0Sstevel@tonic-gate int i; 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate for (i = 0, bp = bufp; i < NBUF * ntrec; i++, bp++) 371*0Sstevel@tonic-gate bp->b_flags = BUF_EMPTY; 372*0Sstevel@tonic-gate if ((caddr_t)current < shared || 373*0Sstevel@tonic-gate (caddr_t)current > (shared + tapesize)) { 374*0Sstevel@tonic-gate msg(gettext( 375*0Sstevel@tonic-gate "bufclear: current pointer out of range of shared memory\n")); 376*0Sstevel@tonic-gate dumpabort(); 377*0Sstevel@tonic-gate /*NOTREACHED*/ 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate if ((*current != NULL) && 380*0Sstevel@tonic-gate (*current < &bufp[0] || *current > &bufp[NBUF*ntrec])) { 381*0Sstevel@tonic-gate /* ANSI string catenation, to shut cstyle up */ 382*0Sstevel@tonic-gate msg(gettext("bufclear: current buffer pointer (0x%x) " 383*0Sstevel@tonic-gate "out of range of buffer\naddresses (0x%x - 0x%x)\n"), 384*0Sstevel@tonic-gate *current, &bufp[0], &bufp[NBUF*ntrec]); 385*0Sstevel@tonic-gate dumpabort(); 386*0Sstevel@tonic-gate /*NOTREACHED*/ 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate *current = bufp; 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate /* 392*0Sstevel@tonic-gate * Start a process to collect information describing the dump. 393*0Sstevel@tonic-gate * This data takes two forms: 394*0Sstevel@tonic-gate * the bitmap and directory information being written to 395*0Sstevel@tonic-gate * the front of the tape (the "archive" file) 396*0Sstevel@tonic-gate * information describing each directory and inode (to 397*0Sstevel@tonic-gate * be included in the database tmp file) 398*0Sstevel@tonic-gate * Write the data to the files as it is received so huge file 399*0Sstevel@tonic-gate * systems don't cause dump to consume large amounts of memory. 400*0Sstevel@tonic-gate */ 401*0Sstevel@tonic-gate static pid_t 402*0Sstevel@tonic-gate #ifdef __STDC__ 403*0Sstevel@tonic-gate setuparchive(void) 404*0Sstevel@tonic-gate #else 405*0Sstevel@tonic-gate setuparchive() 406*0Sstevel@tonic-gate #endif 407*0Sstevel@tonic-gate { 408*0Sstevel@tonic-gate struct slaves *slavep; 409*0Sstevel@tonic-gate int cmd[2]; 410*0Sstevel@tonic-gate pid_t pid; 411*0Sstevel@tonic-gate ssize_t size; 412*0Sstevel@tonic-gate char *data; 413*0Sstevel@tonic-gate char *errmsg; 414*0Sstevel@tonic-gate int flags, saverr; 415*0Sstevel@tonic-gate int punt = 0; 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate /* 418*0Sstevel@tonic-gate * Both the archive and database tmp files are 419*0Sstevel@tonic-gate * checkpointed by taking their current offsets 420*0Sstevel@tonic-gate * (sizes) after completing each volume. Restoring 421*0Sstevel@tonic-gate * from a checkpoint involves truncating to the 422*0Sstevel@tonic-gate * checkpointed size. 423*0Sstevel@tonic-gate */ 424*0Sstevel@tonic-gate if (archive && !doingactive) { 425*0Sstevel@tonic-gate /* It's allowed/expected to exist, so can't use O_EXCL */ 426*0Sstevel@tonic-gate archivefd = safe_file_open(archivefile, O_WRONLY, 0600); 427*0Sstevel@tonic-gate if (archivefd < 0) { 428*0Sstevel@tonic-gate saverr = errno; 429*0Sstevel@tonic-gate msg(gettext("Cannot open archive file `%s': %s\n"), 430*0Sstevel@tonic-gate archivefile, strerror(saverr)); 431*0Sstevel@tonic-gate dumpabort(); 432*0Sstevel@tonic-gate /*NOTREACHED*/ 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate if (lseek64(archivefd, lf_archoffset, 0) < 0) { 436*0Sstevel@tonic-gate saverr = errno; 437*0Sstevel@tonic-gate msg(gettext( 438*0Sstevel@tonic-gate "Cannot position archive file `%s' : %s\n"), 439*0Sstevel@tonic-gate archivefile, strerror(saverr)); 440*0Sstevel@tonic-gate dumpabort(); 441*0Sstevel@tonic-gate /*NOTREACHED*/ 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate if (ftruncate64(archivefd, lf_archoffset) < 0) { 444*0Sstevel@tonic-gate saverr = errno; 445*0Sstevel@tonic-gate msg(gettext( 446*0Sstevel@tonic-gate "Cannot truncate archive file `%s' : %s\n"), 447*0Sstevel@tonic-gate archivefile, strerror(saverr)); 448*0Sstevel@tonic-gate dumpabort(); 449*0Sstevel@tonic-gate /*NOTREACHED*/ 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate } 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate if (pipe(cmd) < 0) { 454*0Sstevel@tonic-gate saverr = errno; 455*0Sstevel@tonic-gate msg(gettext("%s: %s error: %s\n"), 456*0Sstevel@tonic-gate "setuparchive", "pipe", strerror(saverr)); 457*0Sstevel@tonic-gate return (0); 458*0Sstevel@tonic-gate } 459*0Sstevel@tonic-gate sighold(SIGINT); 460*0Sstevel@tonic-gate if ((pid = fork()) < 0) { 461*0Sstevel@tonic-gate saverr = errno; 462*0Sstevel@tonic-gate msg(gettext("%s: %s error: %s\n"), 463*0Sstevel@tonic-gate "setuparchive", "fork", strerror(saverr)); 464*0Sstevel@tonic-gate return (0); 465*0Sstevel@tonic-gate } 466*0Sstevel@tonic-gate if (pid > 0) { 467*0Sstevel@tonic-gate sigrelse(SIGINT); 468*0Sstevel@tonic-gate /* parent process */ 469*0Sstevel@tonic-gate (void) close(cmd[0]); 470*0Sstevel@tonic-gate arch = cmd[1]; 471*0Sstevel@tonic-gate return (pid); 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate /* 474*0Sstevel@tonic-gate * child process 475*0Sstevel@tonic-gate */ 476*0Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); /* master handles this */ 477*0Sstevel@tonic-gate #ifdef TDEBUG 478*0Sstevel@tonic-gate (void) sleep(4); /* allow time for parent's message to get out */ 479*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 480*0Sstevel@tonic-gate msg(gettext("Archiver has pid = %ld\n"), (long)getpid()); 481*0Sstevel@tonic-gate #endif 482*0Sstevel@tonic-gate freeino(); /* release unneeded resources */ 483*0Sstevel@tonic-gate freetape(); 484*0Sstevel@tonic-gate for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) { 485*0Sstevel@tonic-gate if (slavep->sl_slavefd != -1) { 486*0Sstevel@tonic-gate (void) close(slavep->sl_slavefd); 487*0Sstevel@tonic-gate slavep->sl_slavefd = -1; 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate } 490*0Sstevel@tonic-gate (void) close(to); 491*0Sstevel@tonic-gate (void) close(fi); 492*0Sstevel@tonic-gate to = fi = -1; 493*0Sstevel@tonic-gate (void) close(cmd[1]); 494*0Sstevel@tonic-gate data = xmalloc(tp_bsize); 495*0Sstevel@tonic-gate for (;;) { 496*0Sstevel@tonic-gate size = atomic((int(*)())read, cmd[0], (char *)&flags, 497*0Sstevel@tonic-gate sizeof (flags)); 498*0Sstevel@tonic-gate if ((unsigned)size != sizeof (flags)) 499*0Sstevel@tonic-gate break; 500*0Sstevel@tonic-gate size = atomic((int(*)())read, cmd[0], data, tp_bsize); 501*0Sstevel@tonic-gate if (size == tp_bsize) { 502*0Sstevel@tonic-gate if (archive && flags & BUF_ARCHIVE && !punt && 503*0Sstevel@tonic-gate (size = write(archivefd, data, tp_bsize)) 504*0Sstevel@tonic-gate != tp_bsize) { 505*0Sstevel@tonic-gate struct stat64 stats; 506*0Sstevel@tonic-gate 507*0Sstevel@tonic-gate if (size != -1) { 508*0Sstevel@tonic-gate errmsg = strdup(gettext( 509*0Sstevel@tonic-gate "Output truncated")); 510*0Sstevel@tonic-gate if (errmsg == NULL) 511*0Sstevel@tonic-gate errmsg = ""; 512*0Sstevel@tonic-gate } else { 513*0Sstevel@tonic-gate errmsg = strerror(errno); 514*0Sstevel@tonic-gate } 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate if (fstat64(archivefd, &stats) < 0) 517*0Sstevel@tonic-gate stats.st_size = -1; 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate /* cast to keep lint&printf happy */ 520*0Sstevel@tonic-gate msg(gettext( 521*0Sstevel@tonic-gate "Cannot write archive file `%s' at offset %lld: %s\n"), 522*0Sstevel@tonic-gate archivefile, (longlong_t)stats.st_size, 523*0Sstevel@tonic-gate errmsg); 524*0Sstevel@tonic-gate msg(gettext( 525*0Sstevel@tonic-gate "Archive file will be deleted, dump will continue\n")); 526*0Sstevel@tonic-gate punt++; 527*0Sstevel@tonic-gate if ((size != -1) && (*errmsg != '\0')) { 528*0Sstevel@tonic-gate free(errmsg); 529*0Sstevel@tonic-gate } 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate } else { 532*0Sstevel@tonic-gate break; 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate (void) close(cmd[0]); 536*0Sstevel@tonic-gate if (archive) { 537*0Sstevel@tonic-gate (void) close(archivefd); 538*0Sstevel@tonic-gate archivefd = -1; 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate if (punt) { 541*0Sstevel@tonic-gate (void) unlink(archivefile); 542*0Sstevel@tonic-gate Exit(X_ABORT); 543*0Sstevel@tonic-gate } 544*0Sstevel@tonic-gate Exit(X_FINOK); 545*0Sstevel@tonic-gate /* NOTREACHED */ 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate /* 549*0Sstevel@tonic-gate * Start a process to read the output buffers and write the data 550*0Sstevel@tonic-gate * to the output device. 551*0Sstevel@tonic-gate */ 552*0Sstevel@tonic-gate static pid_t 553*0Sstevel@tonic-gate #ifdef __STDC__ 554*0Sstevel@tonic-gate setupwriter(void) 555*0Sstevel@tonic-gate #else 556*0Sstevel@tonic-gate setupwriter() 557*0Sstevel@tonic-gate #endif 558*0Sstevel@tonic-gate { 559*0Sstevel@tonic-gate struct slaves *slavep; 560*0Sstevel@tonic-gate int cmd[2]; 561*0Sstevel@tonic-gate pid_t pid; 562*0Sstevel@tonic-gate int saverr; 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate caught = 0; 565*0Sstevel@tonic-gate if (pipe(cmd) < 0) { 566*0Sstevel@tonic-gate saverr = errno; 567*0Sstevel@tonic-gate msg(gettext("%s: %s error: %s\n"), 568*0Sstevel@tonic-gate "setupwriter", "pipe", strerror(saverr)); 569*0Sstevel@tonic-gate return (0); 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate sighold(SIGINT); 572*0Sstevel@tonic-gate if ((pid = fork()) < 0) { 573*0Sstevel@tonic-gate saverr = errno; 574*0Sstevel@tonic-gate msg(gettext("%s: %s error: %s\n"), 575*0Sstevel@tonic-gate "setupwriter", "fork", strerror(saverr)); 576*0Sstevel@tonic-gate return (0); 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate if (pid > 0) { 579*0Sstevel@tonic-gate /* 580*0Sstevel@tonic-gate * Parent process 581*0Sstevel@tonic-gate */ 582*0Sstevel@tonic-gate sigrelse(SIGINT); 583*0Sstevel@tonic-gate (void) close(cmd[0]); 584*0Sstevel@tonic-gate writer = cmd[1]; 585*0Sstevel@tonic-gate return (pid); 586*0Sstevel@tonic-gate } 587*0Sstevel@tonic-gate /* 588*0Sstevel@tonic-gate * Child (writer) process 589*0Sstevel@tonic-gate */ 590*0Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); /* master handles this */ 591*0Sstevel@tonic-gate #ifdef TDEBUG 592*0Sstevel@tonic-gate (void) sleep(4); /* allow time for parent's message to get out */ 593*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 594*0Sstevel@tonic-gate msg(gettext("Writer has pid = %ld\n"), (long)getpid()); 595*0Sstevel@tonic-gate #endif 596*0Sstevel@tonic-gate child_chdir(); 597*0Sstevel@tonic-gate freeino(); /* release unneeded resources */ 598*0Sstevel@tonic-gate for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) { 599*0Sstevel@tonic-gate if (slavep->sl_slavefd != -1) { 600*0Sstevel@tonic-gate (void) close(slavep->sl_slavefd); 601*0Sstevel@tonic-gate slavep->sl_slavefd = -1; 602*0Sstevel@tonic-gate } 603*0Sstevel@tonic-gate } 604*0Sstevel@tonic-gate (void) close(fi); 605*0Sstevel@tonic-gate fi = -1; 606*0Sstevel@tonic-gate (void) close(cmd[1]); 607*0Sstevel@tonic-gate dowrite(cmd[0]); 608*0Sstevel@tonic-gate if (arch >= 0) { 609*0Sstevel@tonic-gate (void) close(arch); 610*0Sstevel@tonic-gate arch = -1; 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate (void) close(cmd[0]); 613*0Sstevel@tonic-gate Exit(X_FINOK); 614*0Sstevel@tonic-gate /* NOTREACHED */ 615*0Sstevel@tonic-gate } 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate void 618*0Sstevel@tonic-gate #ifdef __STDC__ 619*0Sstevel@tonic-gate spclrec(void) 620*0Sstevel@tonic-gate #else 621*0Sstevel@tonic-gate spclrec() 622*0Sstevel@tonic-gate #endif 623*0Sstevel@tonic-gate { 624*0Sstevel@tonic-gate int s, i; 625*0Sstevel@tonic-gate int32_t *ip; 626*0Sstevel@tonic-gate int flags = BUF_SPCLREC; 627*0Sstevel@tonic-gate 628*0Sstevel@tonic-gate if ((BIT(ino, shamap)) && (spcl.c_type == TS_INODE)) { 629*0Sstevel@tonic-gate spcl.c_type = TS_ADDR; 630*0Sstevel@tonic-gate /* LINTED: result fits in a short */ 631*0Sstevel@tonic-gate spcl.c_dinode.di_mode &= ~S_IFMT; 632*0Sstevel@tonic-gate /* LINTED: result fits in a short */ 633*0Sstevel@tonic-gate spcl.c_dinode.di_mode |= IFSHAD; 634*0Sstevel@tonic-gate } 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate /* 637*0Sstevel@tonic-gate * Only TS_INODEs should have short metadata, if this 638*0Sstevel@tonic-gate * isn't such a spclrec, clear the metadata flag and 639*0Sstevel@tonic-gate * the c_shadow contents. 640*0Sstevel@tonic-gate */ 641*0Sstevel@tonic-gate if (!(spcl.c_type == TS_INODE && (spcl.c_flags & DR_HASMETA))) { 642*0Sstevel@tonic-gate spcl.c_flags &= ~DR_HASMETA; 643*0Sstevel@tonic-gate bcopy(c_shadow_save, &(spcl.c_shadow), 644*0Sstevel@tonic-gate sizeof (spcl.c_shadow)); 645*0Sstevel@tonic-gate } 646*0Sstevel@tonic-gate 647*0Sstevel@tonic-gate if (spcl.c_type == TS_END) { 648*0Sstevel@tonic-gate spcl.c_count = 1; 649*0Sstevel@tonic-gate spcl.c_flags |= DR_INODEINFO; 650*0Sstevel@tonic-gate bcopy((char *)inos, (char *)spcl.c_inos, sizeof (inos)); 651*0Sstevel@tonic-gate } else if (spcl.c_type == TS_TAPE) { 652*0Sstevel@tonic-gate spcl.c_flags |= DR_NEWHEADER; 653*0Sstevel@tonic-gate if (doingactive) 654*0Sstevel@tonic-gate spcl.c_flags |= DR_REDUMP; 655*0Sstevel@tonic-gate } else if (spcl.c_type != TS_INODE) 656*0Sstevel@tonic-gate flags = BUF_SPCLREC; 657*0Sstevel@tonic-gate spcl.c_tapea = *tapea; 658*0Sstevel@tonic-gate /* LINTED for now, max inode # is 2**31 (ufs max size is 4TB) */ 659*0Sstevel@tonic-gate spcl.c_inumber = (ino32_t)ino; 660*0Sstevel@tonic-gate spcl.c_magic = (tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC; 661*0Sstevel@tonic-gate spcl.c_checksum = 0; 662*0Sstevel@tonic-gate ip = (int32_t *)&spcl; 663*0Sstevel@tonic-gate s = CHECKSUM; 664*0Sstevel@tonic-gate assert((tp_bsize % sizeof (*ip)) == 0); 665*0Sstevel@tonic-gate i = tp_bsize / sizeof (*ip); 666*0Sstevel@tonic-gate assert((i%8) == 0); 667*0Sstevel@tonic-gate i /= 8; 668*0Sstevel@tonic-gate do { 669*0Sstevel@tonic-gate s -= *ip++; s -= *ip++; s -= *ip++; s -= *ip++; 670*0Sstevel@tonic-gate s -= *ip++; s -= *ip++; s -= *ip++; s -= *ip++; 671*0Sstevel@tonic-gate } while (--i > 0); 672*0Sstevel@tonic-gate spcl.c_checksum = s; 673*0Sstevel@tonic-gate taprec((uchar_t *)&spcl, flags, sizeof (spcl)); 674*0Sstevel@tonic-gate if (spcl.c_type == TS_END) 675*0Sstevel@tonic-gate spcl.c_flags &= ~DR_INODEINFO; 676*0Sstevel@tonic-gate else if (spcl.c_type == TS_TAPE) 677*0Sstevel@tonic-gate spcl.c_flags &= ~(DR_NEWHEADER|DR_REDUMP|DR_TRUEINC); 678*0Sstevel@tonic-gate } 679*0Sstevel@tonic-gate 680*0Sstevel@tonic-gate /* 681*0Sstevel@tonic-gate * Fill appropriate buffer 682*0Sstevel@tonic-gate */ 683*0Sstevel@tonic-gate void 684*0Sstevel@tonic-gate taprec(dp, flags, size) 685*0Sstevel@tonic-gate uchar_t *dp; 686*0Sstevel@tonic-gate int flags; 687*0Sstevel@tonic-gate int size; 688*0Sstevel@tonic-gate { 689*0Sstevel@tonic-gate if (size > tp_bsize) { 690*0Sstevel@tonic-gate msg(gettext( 691*0Sstevel@tonic-gate "taprec: Unexpected buffer size, expected %d, got %d.\n"), 692*0Sstevel@tonic-gate tp_bsize, size); 693*0Sstevel@tonic-gate dumpabort(); 694*0Sstevel@tonic-gate /*NOTREACHED*/ 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate while ((*current)->b_flags & BUF_FULL) 698*0Sstevel@tonic-gate nap(10); 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate bcopy(dp, (*current)->b_data, (size_t)size); 701*0Sstevel@tonic-gate if (size < tp_bsize) { 702*0Sstevel@tonic-gate bzero((*current)->b_data + size, tp_bsize - size); 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate if (dumptoarchive) 706*0Sstevel@tonic-gate flags |= BUF_ARCHIVE; 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate /* no locking as we assume only one reader and one writer active */ 709*0Sstevel@tonic-gate (*current)->b_flags = (flags | BUF_FULL); 710*0Sstevel@tonic-gate if (++*current >= &bufp[NBUF*ntrec]) 711*0Sstevel@tonic-gate (*current) = &bufp[0]; 712*0Sstevel@tonic-gate (*tapea)++; 713*0Sstevel@tonic-gate } 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate void 716*0Sstevel@tonic-gate dmpblk(blkno, size, offset) 717*0Sstevel@tonic-gate daddr32_t blkno; 718*0Sstevel@tonic-gate size_t size; 719*0Sstevel@tonic-gate off_t offset; 720*0Sstevel@tonic-gate { 721*0Sstevel@tonic-gate diskaddr_t dblkno; 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate assert((offset >> DEV_BSHIFT) <= INT32_MAX); 724*0Sstevel@tonic-gate dblkno = fsbtodb(sblock, blkno) + (offset >> DEV_BSHIFT); 725*0Sstevel@tonic-gate size = (size + DEV_BSIZE-1) & ~(DEV_BSIZE-1); 726*0Sstevel@tonic-gate slp->sl_req->br_dblk = dblkno; 727*0Sstevel@tonic-gate slp->sl_req->br_size = size; 728*0Sstevel@tonic-gate if (dumptoarchive) { 729*0Sstevel@tonic-gate /* LINTED: result fits in a short */ 730*0Sstevel@tonic-gate slp->sl_req->aflag |= BUF_ARCHIVE; 731*0Sstevel@tonic-gate } 732*0Sstevel@tonic-gate toslave((void(*)())0, ino); 733*0Sstevel@tonic-gate } 734*0Sstevel@tonic-gate 735*0Sstevel@tonic-gate /*ARGSUSED*/ 736*0Sstevel@tonic-gate static void 737*0Sstevel@tonic-gate tperror(sig) 738*0Sstevel@tonic-gate int sig; 739*0Sstevel@tonic-gate { 740*0Sstevel@tonic-gate char buf[3000]; 741*0Sstevel@tonic-gate 742*0Sstevel@tonic-gate if (pipeout) { 743*0Sstevel@tonic-gate msg(gettext("Write error on %s\n"), tape); 744*0Sstevel@tonic-gate msg(gettext("Cannot recover\n")); 745*0Sstevel@tonic-gate dumpabort(); 746*0Sstevel@tonic-gate /* NOTREACHED */ 747*0Sstevel@tonic-gate } 748*0Sstevel@tonic-gate if (!doingverify) { 749*0Sstevel@tonic-gate broadcast(gettext("WRITE ERROR!\n")); 750*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 751*0Sstevel@tonic-gate gettext("Do you want to restart?: (\"yes\" or \"no\") ")); 752*0Sstevel@tonic-gate if (!query(buf)) { 753*0Sstevel@tonic-gate dumpabort(); 754*0Sstevel@tonic-gate /*NOTREACHED*/ 755*0Sstevel@tonic-gate } 756*0Sstevel@tonic-gate if (tapeout && (isrewind(to) || offline)) { 757*0Sstevel@tonic-gate /* ANSI string catenation, to shut cstyle up */ 758*0Sstevel@tonic-gate msg(gettext("This tape will rewind. After " 759*0Sstevel@tonic-gate "it is rewound,\nreplace the faulty tape " 760*0Sstevel@tonic-gate "with a new one;\nthis dump volume will " 761*0Sstevel@tonic-gate "be rewritten.\n")); 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate } else { 764*0Sstevel@tonic-gate broadcast(gettext("TAPE VERIFICATION ERROR!\n")); 765*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext( 766*0Sstevel@tonic-gate "Do you want to rewrite?: (\"yes\" or \"no\") ")); 767*0Sstevel@tonic-gate if (!query(buf)) { 768*0Sstevel@tonic-gate dumpabort(); 769*0Sstevel@tonic-gate /*NOTREACHED*/ 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate msg(gettext( 772*0Sstevel@tonic-gate "This tape will be rewritten and then verified\n")); 773*0Sstevel@tonic-gate } 774*0Sstevel@tonic-gate killall(); 775*0Sstevel@tonic-gate trewind(); 776*0Sstevel@tonic-gate Exit(X_REWRITE); 777*0Sstevel@tonic-gate } 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate /* 780*0Sstevel@tonic-gate * Called by master from pass() to send a request to dump files/blocks 781*0Sstevel@tonic-gate * to one of the slaves. Slaves return whether the file was active 782*0Sstevel@tonic-gate * when it was being dumped. The tape writer process sends checkpoint 783*0Sstevel@tonic-gate * info when it completes a volume. 784*0Sstevel@tonic-gate */ 785*0Sstevel@tonic-gate void 786*0Sstevel@tonic-gate toslave(fn, inumber) 787*0Sstevel@tonic-gate void (*fn)(); 788*0Sstevel@tonic-gate ino_t inumber; 789*0Sstevel@tonic-gate { 790*0Sstevel@tonic-gate int wasactive; 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate if (recsout >= SLAVES) { 793*0Sstevel@tonic-gate if ((unsigned)atomic((int(*)())read, slp->sl_slavefd, 794*0Sstevel@tonic-gate (char *)&wasactive, sizeof (wasactive)) != 795*0Sstevel@tonic-gate sizeof (wasactive)) { 796*0Sstevel@tonic-gate cmdrderr(); 797*0Sstevel@tonic-gate dumpabort(); 798*0Sstevel@tonic-gate /*NOTREACHED*/ 799*0Sstevel@tonic-gate } 800*0Sstevel@tonic-gate if (wasactive) { 801*0Sstevel@tonic-gate active++; 802*0Sstevel@tonic-gate msg(gettext( 803*0Sstevel@tonic-gate "The file at inode `%lu' was active and will be recopied\n"), 804*0Sstevel@tonic-gate slp->sl_req->ir_inumber); 805*0Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 806*0Sstevel@tonic-gate BIS(slp->sl_req->ir_inumber, activemap); 807*0Sstevel@tonic-gate } 808*0Sstevel@tonic-gate } 809*0Sstevel@tonic-gate slp->sl_req->aflag = 0; 810*0Sstevel@tonic-gate if (dumptoarchive) { 811*0Sstevel@tonic-gate /* LINTED: result fits in a short */ 812*0Sstevel@tonic-gate slp->sl_req->aflag |= BUF_ARCHIVE; 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate if (fn) 815*0Sstevel@tonic-gate (*fn)(inumber); 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate if (atomic((int(*)())write, slp->sl_slavefd, (char *)slp->sl_req, 818*0Sstevel@tonic-gate reqsiz) != reqsiz) { 819*0Sstevel@tonic-gate cmdwrterr(); 820*0Sstevel@tonic-gate dumpabort(); 821*0Sstevel@tonic-gate /*NOTREACHED*/ 822*0Sstevel@tonic-gate } 823*0Sstevel@tonic-gate ++recsout; 824*0Sstevel@tonic-gate nextslave(); 825*0Sstevel@tonic-gate } 826*0Sstevel@tonic-gate 827*0Sstevel@tonic-gate void 828*0Sstevel@tonic-gate dospcl(inumber) 829*0Sstevel@tonic-gate ino_t inumber; 830*0Sstevel@tonic-gate { 831*0Sstevel@tonic-gate /* LINTED for now, max inode # is 2**31 (ufs max size is 1TB) */ 832*0Sstevel@tonic-gate spcl.c_inumber = (ino32_t)inumber; 833*0Sstevel@tonic-gate slp->sl_req->br_dblk = 0; 834*0Sstevel@tonic-gate bcopy((char *)&spcl, (char *)slp->sl_req->br_spcl, tp_bsize); 835*0Sstevel@tonic-gate } 836*0Sstevel@tonic-gate 837*0Sstevel@tonic-gate static void 838*0Sstevel@tonic-gate #ifdef __STDC__ 839*0Sstevel@tonic-gate nextslave(void) 840*0Sstevel@tonic-gate #else 841*0Sstevel@tonic-gate nextslave() 842*0Sstevel@tonic-gate #endif 843*0Sstevel@tonic-gate { 844*0Sstevel@tonic-gate if (++rotor >= SLAVES) { 845*0Sstevel@tonic-gate rotor = 0; 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate slp = &slaves[rotor]; 848*0Sstevel@tonic-gate } 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gate void 851*0Sstevel@tonic-gate #ifdef __STDC__ 852*0Sstevel@tonic-gate flushcmds(void) 853*0Sstevel@tonic-gate #else 854*0Sstevel@tonic-gate flushcmds() 855*0Sstevel@tonic-gate #endif 856*0Sstevel@tonic-gate { 857*0Sstevel@tonic-gate int i; 858*0Sstevel@tonic-gate int wasactive; 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate /* 861*0Sstevel@tonic-gate * Retrieve all slave status 862*0Sstevel@tonic-gate */ 863*0Sstevel@tonic-gate if (recsout < SLAVES) { 864*0Sstevel@tonic-gate slp = slaves; 865*0Sstevel@tonic-gate rotor = 0; 866*0Sstevel@tonic-gate } 867*0Sstevel@tonic-gate for (i = 0; i < (recsout < SLAVES ? recsout : SLAVES); i++) { 868*0Sstevel@tonic-gate if ((unsigned)atomic((int(*)())read, slp->sl_slavefd, 869*0Sstevel@tonic-gate (char *)&wasactive, sizeof (wasactive)) != 870*0Sstevel@tonic-gate sizeof (wasactive)) { 871*0Sstevel@tonic-gate cmdrderr(); 872*0Sstevel@tonic-gate dumpabort(); 873*0Sstevel@tonic-gate /*NOTREACHED*/ 874*0Sstevel@tonic-gate } 875*0Sstevel@tonic-gate if (wasactive) { 876*0Sstevel@tonic-gate active++; 877*0Sstevel@tonic-gate msg(gettext( 878*0Sstevel@tonic-gate "inode %d was active and will be recopied\n"), 879*0Sstevel@tonic-gate slp->sl_req->ir_inumber); 880*0Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 881*0Sstevel@tonic-gate BIS(slp->sl_req->ir_inumber, activemap); 882*0Sstevel@tonic-gate } 883*0Sstevel@tonic-gate nextslave(); 884*0Sstevel@tonic-gate } 885*0Sstevel@tonic-gate } 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate void 888*0Sstevel@tonic-gate #ifdef __STDC__ 889*0Sstevel@tonic-gate flusht(void) 890*0Sstevel@tonic-gate #else 891*0Sstevel@tonic-gate flusht() 892*0Sstevel@tonic-gate #endif 893*0Sstevel@tonic-gate { 894*0Sstevel@tonic-gate sigset_t block_set, oset; /* hold SIGUSR1 and atomically sleep */ 895*0Sstevel@tonic-gate 896*0Sstevel@tonic-gate (void) sigemptyset(&block_set); 897*0Sstevel@tonic-gate (void) sigaddset(&block_set, SIGUSR1); 898*0Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &block_set, &oset); 899*0Sstevel@tonic-gate (void) kill(writepid, SIGUSR1); /* tell writer to flush */ 900*0Sstevel@tonic-gate (void) sigpause(SIGUSR1); /* wait for SIGUSR1 from writer */ 901*0Sstevel@tonic-gate /*NOTREACHED*/ 902*0Sstevel@tonic-gate } 903*0Sstevel@tonic-gate 904*0Sstevel@tonic-gate jmp_buf checkpoint_buf; 905*0Sstevel@tonic-gate 906*0Sstevel@tonic-gate /* 907*0Sstevel@tonic-gate * Roll forward to the next volume after receiving 908*0Sstevel@tonic-gate * an EOT signal from writer. Get checkpoint data 909*0Sstevel@tonic-gate * from writer and return if done, otherwise fork 910*0Sstevel@tonic-gate * a new process and jump back to main state loop 911*0Sstevel@tonic-gate * to begin the next volume. Installed as the master's 912*0Sstevel@tonic-gate * signal handler for SIGUSR1. 913*0Sstevel@tonic-gate */ 914*0Sstevel@tonic-gate /*ARGSUSED*/ 915*0Sstevel@tonic-gate static void 916*0Sstevel@tonic-gate rollforward(sig) 917*0Sstevel@tonic-gate int sig; 918*0Sstevel@tonic-gate { 919*0Sstevel@tonic-gate int status; 920*0Sstevel@tonic-gate (void) sighold(SIGUSR1); 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate /* 923*0Sstevel@tonic-gate * Writer sends us checkpoint information after 924*0Sstevel@tonic-gate * each volume. A returned state of DS_DONE with no 925*0Sstevel@tonic-gate * unwritten (left-over) records differentiates a 926*0Sstevel@tonic-gate * clean flush from one in which EOT was encountered. 927*0Sstevel@tonic-gate */ 928*0Sstevel@tonic-gate if ((unsigned)atomic((int(*)())read, writer, (char *)&chkpt, 929*0Sstevel@tonic-gate sizeof (struct slaves)) != sizeof (struct slaves)) { 930*0Sstevel@tonic-gate cmdrderr(); 931*0Sstevel@tonic-gate dumpabort(); 932*0Sstevel@tonic-gate /*NOTREACHED*/ 933*0Sstevel@tonic-gate } 934*0Sstevel@tonic-gate if (atomic((int(*)())read, writer, (char *)&spcl, 935*0Sstevel@tonic-gate TP_BSIZE_MIN) != TP_BSIZE_MIN) { 936*0Sstevel@tonic-gate cmdrderr(); 937*0Sstevel@tonic-gate dumpabort(); 938*0Sstevel@tonic-gate /*NOTREACHED*/ 939*0Sstevel@tonic-gate } 940*0Sstevel@tonic-gate ino = chkpt.sl_inos - 1; 941*0Sstevel@tonic-gate pos = chkpt.sl_offset; 942*0Sstevel@tonic-gate leftover = chkpt.sl_count; 943*0Sstevel@tonic-gate dumpstate = chkpt.sl_state; 944*0Sstevel@tonic-gate blockswritten = ++chkpt.sl_tapea; 945*0Sstevel@tonic-gate 946*0Sstevel@tonic-gate if (dumpstate == DS_DONE) { 947*0Sstevel@tonic-gate if (archivepid) { 948*0Sstevel@tonic-gate /* 949*0Sstevel@tonic-gate * If archiving (either archive or 950*0Sstevel@tonic-gate * database), signal the archiver 951*0Sstevel@tonic-gate * to finish up. This must happen 952*0Sstevel@tonic-gate * before the writer exits in order 953*0Sstevel@tonic-gate * to avoid a race. 954*0Sstevel@tonic-gate */ 955*0Sstevel@tonic-gate (void) kill(archivepid, SIGUSR1); 956*0Sstevel@tonic-gate } 957*0Sstevel@tonic-gate (void) signal(SIGUSR1, SIG_IGN); 958*0Sstevel@tonic-gate (void) sigrelse(SIGUSR1); 959*0Sstevel@tonic-gate (void) kill(writepid, SIGUSR1); /* tell writer to exit */ 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate lf_archoffset = 0LL; 962*0Sstevel@tonic-gate longjmp(checkpoint_buf, 1); 963*0Sstevel@tonic-gate /*NOTREACHED*/ 964*0Sstevel@tonic-gate } 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate if (leftover) { 967*0Sstevel@tonic-gate (void) memmove(spcl.c_addr, 968*0Sstevel@tonic-gate &spcl.c_addr[spcl.c_count-leftover], leftover); 969*0Sstevel@tonic-gate bzero(&spcl.c_addr[leftover], TP_NINDIR-leftover); 970*0Sstevel@tonic-gate } 971*0Sstevel@tonic-gate if (writepid) { 972*0Sstevel@tonic-gate (void) kill(writepid, SIGUSR1); /* tell writer to exit */ 973*0Sstevel@tonic-gate (void) close(writer); 974*0Sstevel@tonic-gate writer = -1; 975*0Sstevel@tonic-gate } 976*0Sstevel@tonic-gate if (archivepid) { 977*0Sstevel@tonic-gate (void) waitpid(archivepid, &status, 0); /* wait for archiver */ 978*0Sstevel@tonic-gate #ifdef TDEBUG 979*0Sstevel@tonic-gate 980*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 981*0Sstevel@tonic-gate msg(gettext("Archiver %ld returns with status %d\n"), 982*0Sstevel@tonic-gate (long)archivepid, status); 983*0Sstevel@tonic-gate #endif 984*0Sstevel@tonic-gate archivepid = 0; 985*0Sstevel@tonic-gate } 986*0Sstevel@tonic-gate /* 987*0Sstevel@tonic-gate * Checkpoint archive file 988*0Sstevel@tonic-gate */ 989*0Sstevel@tonic-gate if (!doingverify && archive) { 990*0Sstevel@tonic-gate lf_archoffset = lseek64(archivefd, (off64_t)0, 2); 991*0Sstevel@tonic-gate if (lf_archoffset < 0) { 992*0Sstevel@tonic-gate int saverr = errno; 993*0Sstevel@tonic-gate msg(gettext("Cannot position archive file `%s': %s\n"), 994*0Sstevel@tonic-gate archivefile, strerror(saverr)); 995*0Sstevel@tonic-gate dumpabort(); 996*0Sstevel@tonic-gate /*NOTREACHED*/ 997*0Sstevel@tonic-gate } 998*0Sstevel@tonic-gate (void) close(archivefd); 999*0Sstevel@tonic-gate archivefd = -1; 1000*0Sstevel@tonic-gate } 1001*0Sstevel@tonic-gate resetino(ino); 1002*0Sstevel@tonic-gate 1003*0Sstevel@tonic-gate if (dumpstate == DS_START) { 1004*0Sstevel@tonic-gate msg(gettext( 1005*0Sstevel@tonic-gate "Tape too short: changing volumes and restarting\n")); 1006*0Sstevel@tonic-gate reset(); 1007*0Sstevel@tonic-gate } 1008*0Sstevel@tonic-gate 1009*0Sstevel@tonic-gate if (!pipeout) { 1010*0Sstevel@tonic-gate if (verify && !doingverify) 1011*0Sstevel@tonic-gate trewind(); 1012*0Sstevel@tonic-gate else { 1013*0Sstevel@tonic-gate close_rewind(); 1014*0Sstevel@tonic-gate changevol(); 1015*0Sstevel@tonic-gate } 1016*0Sstevel@tonic-gate } 1017*0Sstevel@tonic-gate 1018*0Sstevel@tonic-gate (void) sigrelse(SIGUSR1); 1019*0Sstevel@tonic-gate otape(0); 1020*0Sstevel@tonic-gate longjmp(checkpoint_buf, 1); 1021*0Sstevel@tonic-gate /*NOTREACHED*/ 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate 1024*0Sstevel@tonic-gate static void 1025*0Sstevel@tonic-gate nap(ms) 1026*0Sstevel@tonic-gate int ms; 1027*0Sstevel@tonic-gate { 1028*0Sstevel@tonic-gate struct timeval tv; 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gate tv.tv_sec = ms / 1000; 1031*0Sstevel@tonic-gate tv.tv_usec = (ms - tv.tv_sec * 1000) * 1000; 1032*0Sstevel@tonic-gate (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv); 1033*0Sstevel@tonic-gate } 1034*0Sstevel@tonic-gate 1035*0Sstevel@tonic-gate static jmp_buf alrm_buf; 1036*0Sstevel@tonic-gate 1037*0Sstevel@tonic-gate /*ARGSUSED*/ 1038*0Sstevel@tonic-gate static void 1039*0Sstevel@tonic-gate alrm(sig) 1040*0Sstevel@tonic-gate int sig; 1041*0Sstevel@tonic-gate { 1042*0Sstevel@tonic-gate longjmp(alrm_buf, 1); 1043*0Sstevel@tonic-gate /*NOTREACHED*/ 1044*0Sstevel@tonic-gate } 1045*0Sstevel@tonic-gate 1046*0Sstevel@tonic-gate void 1047*0Sstevel@tonic-gate #ifdef __STDC__ 1048*0Sstevel@tonic-gate nextdevice(void) 1049*0Sstevel@tonic-gate #else 1050*0Sstevel@tonic-gate nextdevice() 1051*0Sstevel@tonic-gate #endif 1052*0Sstevel@tonic-gate { 1053*0Sstevel@tonic-gate char *cp; 1054*0Sstevel@tonic-gate 1055*0Sstevel@tonic-gate if (host != NULL) /* we set the host only once in ufsdump */ 1056*0Sstevel@tonic-gate return; 1057*0Sstevel@tonic-gate 1058*0Sstevel@tonic-gate host = NULL; 1059*0Sstevel@tonic-gate if (strchr(tape, ':')) { 1060*0Sstevel@tonic-gate if (diskette) { 1061*0Sstevel@tonic-gate msg(gettext("Cannot do remote dump to diskette\n")); 1062*0Sstevel@tonic-gate Exit(X_ABORT); 1063*0Sstevel@tonic-gate } 1064*0Sstevel@tonic-gate host = tape; 1065*0Sstevel@tonic-gate tape = strchr(host, ':'); 1066*0Sstevel@tonic-gate *tape++ = 0; 1067*0Sstevel@tonic-gate cp = strchr(host, '@'); /* user@host? */ 1068*0Sstevel@tonic-gate if (cp != (char *)0) 1069*0Sstevel@tonic-gate cp++; 1070*0Sstevel@tonic-gate else 1071*0Sstevel@tonic-gate cp = host; 1072*0Sstevel@tonic-gate } else 1073*0Sstevel@tonic-gate cp = spcl.c_host; 1074*0Sstevel@tonic-gate /* 1075*0Sstevel@tonic-gate * dumpdev is provided for use in prompts and is of 1076*0Sstevel@tonic-gate * the form: 1077*0Sstevel@tonic-gate * hostname:device 1078*0Sstevel@tonic-gate * sdumpdev is of the form: 1079*0Sstevel@tonic-gate * hostname:device 1080*0Sstevel@tonic-gate * for remote devices, and simply: 1081*0Sstevel@tonic-gate * device 1082*0Sstevel@tonic-gate * for local devices. 1083*0Sstevel@tonic-gate */ 1084*0Sstevel@tonic-gate if (dumpdev != (char *)NULL) { 1085*0Sstevel@tonic-gate /* LINTED: dumpdev is not NULL */ 1086*0Sstevel@tonic-gate free(dumpdev); 1087*0Sstevel@tonic-gate } 1088*0Sstevel@tonic-gate /*LINTED [cast to smaller integer]*/ 1089*0Sstevel@tonic-gate dumpdev = xmalloc((size_t)((sizeof (spcl.c_host) + strlen(tape) + 2))); 1090*0Sstevel@tonic-gate /* LINTED unsigned -> signed cast ok */ 1091*0Sstevel@tonic-gate (void) sprintf(dumpdev, "%.*s:%s", (int)sizeof (spcl.c_host), cp, tape); 1092*0Sstevel@tonic-gate if (cp == spcl.c_host) 1093*0Sstevel@tonic-gate sdumpdev = strchr(dumpdev, ':') + 1; 1094*0Sstevel@tonic-gate else 1095*0Sstevel@tonic-gate sdumpdev = dumpdev; 1096*0Sstevel@tonic-gate } 1097*0Sstevel@tonic-gate 1098*0Sstevel@tonic-gate /* 1099*0Sstevel@tonic-gate * Gross hack due to misfeature of mt tape driver that causes 1100*0Sstevel@tonic-gate * the device to rewind if we generate any signals. Guess 1101*0Sstevel@tonic-gate * whether tape is rewind device or not -- for local devices 1102*0Sstevel@tonic-gate * we can just look at the minor number. For rmt devices, 1103*0Sstevel@tonic-gate * make an educated guess. 1104*0Sstevel@tonic-gate */ 1105*0Sstevel@tonic-gate int 1106*0Sstevel@tonic-gate isrewind(f) 1107*0Sstevel@tonic-gate int f; /* fd, if local device */ 1108*0Sstevel@tonic-gate { 1109*0Sstevel@tonic-gate struct stat64 sbuf; 1110*0Sstevel@tonic-gate char *c; 1111*0Sstevel@tonic-gate int unit; 1112*0Sstevel@tonic-gate int rewind; 1113*0Sstevel@tonic-gate 1114*0Sstevel@tonic-gate if (host) { 1115*0Sstevel@tonic-gate c = strrchr(tape, '/'); 1116*0Sstevel@tonic-gate if (c == NULL) 1117*0Sstevel@tonic-gate c = tape; 1118*0Sstevel@tonic-gate else 1119*0Sstevel@tonic-gate c++; 1120*0Sstevel@tonic-gate /* 1121*0Sstevel@tonic-gate * If the last component begins or ends with an 'n', it is 1122*0Sstevel@tonic-gate * assumed to be a non-rewind device. 1123*0Sstevel@tonic-gate */ 1124*0Sstevel@tonic-gate if (c[0] == 'n' || c[strlen(c)-1] == 'n') 1125*0Sstevel@tonic-gate rewind = 0; 1126*0Sstevel@tonic-gate else if ((strstr(tape, "mt") || strstr(tape, "st")) && 1127*0Sstevel@tonic-gate sscanf(tape, "%*[a-zA-Z/]%d", &unit) == 1 && 1128*0Sstevel@tonic-gate (unit & MT_NOREWIND)) 1129*0Sstevel@tonic-gate rewind = 0; 1130*0Sstevel@tonic-gate else 1131*0Sstevel@tonic-gate rewind = 1; 1132*0Sstevel@tonic-gate } else { 1133*0Sstevel@tonic-gate if (fstat64(f, &sbuf) < 0) { 1134*0Sstevel@tonic-gate msg(gettext( 1135*0Sstevel@tonic-gate "Cannot obtain status of output device `%s'\n"), 1136*0Sstevel@tonic-gate tape); 1137*0Sstevel@tonic-gate dumpabort(); 1138*0Sstevel@tonic-gate /*NOTREACHED*/ 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate rewind = minor(sbuf.st_rdev) & MT_NOREWIND ? 0 : 1; 1141*0Sstevel@tonic-gate } 1142*0Sstevel@tonic-gate return (rewind); 1143*0Sstevel@tonic-gate } 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate static void 1146*0Sstevel@tonic-gate #ifdef __STDC__ 1147*0Sstevel@tonic-gate just_rewind(void) 1148*0Sstevel@tonic-gate #else 1149*0Sstevel@tonic-gate just_rewind() 1150*0Sstevel@tonic-gate #endif 1151*0Sstevel@tonic-gate { 1152*0Sstevel@tonic-gate struct slaves *slavep; 1153*0Sstevel@tonic-gate char *rewinding = gettext("Tape rewinding\n"); 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) { 1156*0Sstevel@tonic-gate if (slavep->sl_slavepid > 0) /* signal normal exit */ 1157*0Sstevel@tonic-gate (void) kill(slavep->sl_slavepid, SIGTERM); 1158*0Sstevel@tonic-gate if (slavep->sl_slavefd >= 0) { 1159*0Sstevel@tonic-gate (void) close(slavep->sl_slavefd); 1160*0Sstevel@tonic-gate slavep->sl_slavefd = -1; 1161*0Sstevel@tonic-gate } 1162*0Sstevel@tonic-gate } 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate /* wait for any signals from slaves */ 1165*0Sstevel@tonic-gate while (waitpid(0, (int *)0, 0) >= 0) 1166*0Sstevel@tonic-gate /*LINTED [empty body]*/ 1167*0Sstevel@tonic-gate continue; 1168*0Sstevel@tonic-gate 1169*0Sstevel@tonic-gate if (pipeout) 1170*0Sstevel@tonic-gate return; 1171*0Sstevel@tonic-gate 1172*0Sstevel@tonic-gate if (doingverify) { 1173*0Sstevel@tonic-gate /* 1174*0Sstevel@tonic-gate * Space to the end of the tape. 1175*0Sstevel@tonic-gate * Backup first in case we already read the EOF. 1176*0Sstevel@tonic-gate */ 1177*0Sstevel@tonic-gate if (host) { 1178*0Sstevel@tonic-gate (void) rmtioctl(MTBSR, 1); 1179*0Sstevel@tonic-gate if (rmtioctl(MTEOM, 1) < 0) 1180*0Sstevel@tonic-gate (void) rmtioctl(MTFSF, 1); 1181*0Sstevel@tonic-gate } else { 1182*0Sstevel@tonic-gate static struct mtop bsr = { MTBSR, 1 }; 1183*0Sstevel@tonic-gate static struct mtop eom = { MTEOM, 1 }; 1184*0Sstevel@tonic-gate static struct mtop fsf = { MTFSF, 1 }; 1185*0Sstevel@tonic-gate 1186*0Sstevel@tonic-gate (void) ioctl(to, MTIOCTOP, &bsr); 1187*0Sstevel@tonic-gate if (ioctl(to, MTIOCTOP, &eom) < 0) 1188*0Sstevel@tonic-gate (void) ioctl(to, MTIOCTOP, &fsf); 1189*0Sstevel@tonic-gate } 1190*0Sstevel@tonic-gate } 1191*0Sstevel@tonic-gate 1192*0Sstevel@tonic-gate /* 1193*0Sstevel@tonic-gate * Guess whether the tape is rewinding so we can tell 1194*0Sstevel@tonic-gate * the operator if it's going to take a long time. 1195*0Sstevel@tonic-gate */ 1196*0Sstevel@tonic-gate if (tapeout && isrewind(to)) { 1197*0Sstevel@tonic-gate /* tape is probably rewinding */ 1198*0Sstevel@tonic-gate msg(rewinding); 1199*0Sstevel@tonic-gate } 1200*0Sstevel@tonic-gate } 1201*0Sstevel@tonic-gate 1202*0Sstevel@tonic-gate void 1203*0Sstevel@tonic-gate #ifdef __STDC__ 1204*0Sstevel@tonic-gate trewind(void) 1205*0Sstevel@tonic-gate #else 1206*0Sstevel@tonic-gate trewind() 1207*0Sstevel@tonic-gate #endif 1208*0Sstevel@tonic-gate { 1209*0Sstevel@tonic-gate (void) timeclock((time_t)0); 1210*0Sstevel@tonic-gate if (offline && (!verify || doingverify)) { 1211*0Sstevel@tonic-gate close_rewind(); 1212*0Sstevel@tonic-gate } else { 1213*0Sstevel@tonic-gate just_rewind(); 1214*0Sstevel@tonic-gate if (host) 1215*0Sstevel@tonic-gate rmtclose(); 1216*0Sstevel@tonic-gate else { 1217*0Sstevel@tonic-gate (void) close(to); 1218*0Sstevel@tonic-gate to = -1; 1219*0Sstevel@tonic-gate } 1220*0Sstevel@tonic-gate } 1221*0Sstevel@tonic-gate } 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate void 1224*0Sstevel@tonic-gate #ifdef __STDC__ 1225*0Sstevel@tonic-gate close_rewind(void) 1226*0Sstevel@tonic-gate #else 1227*0Sstevel@tonic-gate close_rewind() 1228*0Sstevel@tonic-gate #endif 1229*0Sstevel@tonic-gate { 1230*0Sstevel@tonic-gate char *rewinding = gettext("Tape rewinding\n"); 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate (void) timeclock((time_t)0); 1233*0Sstevel@tonic-gate just_rewind(); 1234*0Sstevel@tonic-gate /* 1235*0Sstevel@tonic-gate * The check in just_rewind won't catch the case in 1236*0Sstevel@tonic-gate * which the current volume is being taken off-line 1237*0Sstevel@tonic-gate * and is not mounted on a no-rewind device (and is 1238*0Sstevel@tonic-gate * not the last volume, which is not taken off-line). 1239*0Sstevel@tonic-gate */ 1240*0Sstevel@tonic-gate if (tapeout && !isrewind(to) && offline) { 1241*0Sstevel@tonic-gate /* tape is probably rewinding */ 1242*0Sstevel@tonic-gate msg(rewinding); 1243*0Sstevel@tonic-gate } 1244*0Sstevel@tonic-gate if (host) { 1245*0Sstevel@tonic-gate if (offline || autoload) 1246*0Sstevel@tonic-gate (void) rmtioctl(MTOFFL, 0); 1247*0Sstevel@tonic-gate rmtclose(); 1248*0Sstevel@tonic-gate } else { 1249*0Sstevel@tonic-gate if (offline || autoload) { 1250*0Sstevel@tonic-gate static struct mtop offl = { MTOFFL, 0 }; 1251*0Sstevel@tonic-gate 1252*0Sstevel@tonic-gate (void) ioctl(to, MTIOCTOP, &offl); 1253*0Sstevel@tonic-gate if (diskette) 1254*0Sstevel@tonic-gate (void) ioctl(to, FDEJECT, 0); 1255*0Sstevel@tonic-gate } 1256*0Sstevel@tonic-gate (void) close(to); 1257*0Sstevel@tonic-gate to = -1; 1258*0Sstevel@tonic-gate } 1259*0Sstevel@tonic-gate } 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate void 1262*0Sstevel@tonic-gate #ifdef __STDC__ 1263*0Sstevel@tonic-gate changevol(void) 1264*0Sstevel@tonic-gate #else 1265*0Sstevel@tonic-gate changevol() 1266*0Sstevel@tonic-gate #endif 1267*0Sstevel@tonic-gate { 1268*0Sstevel@tonic-gate char buf1[3000], buf2[3000]; 1269*0Sstevel@tonic-gate char volname[LBLSIZE+1]; 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gate /*CONSTANTCONDITION*/ 1272*0Sstevel@tonic-gate assert(sizeof (spcl.c_label) < sizeof (volname)); 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate filenum = 1; 1275*0Sstevel@tonic-gate nextdevice(); 1276*0Sstevel@tonic-gate (void) strcpy(spcl.c_label, tlabel); 1277*0Sstevel@tonic-gate if (host) { 1278*0Sstevel@tonic-gate char *rhost = host; 1279*0Sstevel@tonic-gate char *cp = strchr(host, '@'); 1280*0Sstevel@tonic-gate if (cp == (char *)0) 1281*0Sstevel@tonic-gate cp = host; 1282*0Sstevel@tonic-gate else 1283*0Sstevel@tonic-gate cp++; 1284*0Sstevel@tonic-gate 1285*0Sstevel@tonic-gate if (rmthost(rhost, ntrec) == 0) { 1286*0Sstevel@tonic-gate msg(gettext("Cannot connect to tape host `%s'\n"), cp); 1287*0Sstevel@tonic-gate dumpabort(); 1288*0Sstevel@tonic-gate /*NOTREACHED*/ 1289*0Sstevel@tonic-gate } 1290*0Sstevel@tonic-gate if (rhost != host) 1291*0Sstevel@tonic-gate free(rhost); 1292*0Sstevel@tonic-gate } 1293*0Sstevel@tonic-gate 1294*0Sstevel@tonic-gate /* 1295*0Sstevel@tonic-gate * Make volume switching as automatic as possible 1296*0Sstevel@tonic-gate * while avoiding overwriting volumes. We will 1297*0Sstevel@tonic-gate * switch automatically under the following condition: 1298*0Sstevel@tonic-gate * 1) The user specified autoloading from the 1299*0Sstevel@tonic-gate * command line. 1300*0Sstevel@tonic-gate * At one time, we (in the guise of hsmdump) had the 1301*0Sstevel@tonic-gate * concept of a sequence of devices to rotate through, 1302*0Sstevel@tonic-gate * but that's never been a ufsdump feature. 1303*0Sstevel@tonic-gate */ 1304*0Sstevel@tonic-gate if (autoload) { 1305*0Sstevel@tonic-gate int tries; 1306*0Sstevel@tonic-gate 1307*0Sstevel@tonic-gate /* 1308*0Sstevel@tonic-gate * Stop the clock for throughput calculations. 1309*0Sstevel@tonic-gate */ 1310*0Sstevel@tonic-gate if ((telapsed != NULL) && (tstart_writing != NULL)) { 1311*0Sstevel@tonic-gate *telapsed += time((time_t *)NULL) - *tstart_writing; 1312*0Sstevel@tonic-gate } 1313*0Sstevel@tonic-gate 1314*0Sstevel@tonic-gate (void) snprintf(volname, sizeof (volname), "#%d", tapeno+1); 1315*0Sstevel@tonic-gate (void) snprintf(buf1, sizeof (buf1), gettext( 1316*0Sstevel@tonic-gate "Mounting volume %s on %s\n"), volname, dumpdev); 1317*0Sstevel@tonic-gate msg(buf1); 1318*0Sstevel@tonic-gate broadcast(buf1); 1319*0Sstevel@tonic-gate 1320*0Sstevel@tonic-gate /* 1321*0Sstevel@tonic-gate * Wait for the tape to autoload. Note that the delay 1322*0Sstevel@tonic-gate * period doesn't take into account however long it takes 1323*0Sstevel@tonic-gate * for the open to fail (measured at 21 seconds for an 1324*0Sstevel@tonic-gate * Exabyte 8200 under 2.7 on an Ultra 2). 1325*0Sstevel@tonic-gate */ 1326*0Sstevel@tonic-gate for (tries = 0; tries < autoload_tries; tries++) { 1327*0Sstevel@tonic-gate if (host) { 1328*0Sstevel@tonic-gate if (rmtopen(tape, O_RDONLY) >= 0) { 1329*0Sstevel@tonic-gate rmtclose(); 1330*0Sstevel@tonic-gate return; 1331*0Sstevel@tonic-gate } 1332*0Sstevel@tonic-gate } else { 1333*0Sstevel@tonic-gate int f, m; 1334*0Sstevel@tonic-gate 1335*0Sstevel@tonic-gate m = (access(tape, F_OK) == 0) ? 0 : O_CREAT; 1336*0Sstevel@tonic-gate if ((f = doingverify ? 1337*0Sstevel@tonic-gate safe_device_open(tape, O_RDONLY, 0600) : 1338*0Sstevel@tonic-gate safe_device_open(tape, O_RDONLY|m, 0600)) 1339*0Sstevel@tonic-gate >= 0) { 1340*0Sstevel@tonic-gate (void) close(f); 1341*0Sstevel@tonic-gate return; 1342*0Sstevel@tonic-gate } 1343*0Sstevel@tonic-gate } 1344*0Sstevel@tonic-gate (void) sleep(autoload_period); 1345*0Sstevel@tonic-gate } 1346*0Sstevel@tonic-gate /* 1347*0Sstevel@tonic-gate * Autoload timed out, ask the operator to do it. 1348*0Sstevel@tonic-gate * Note that query() will update *telapsed, and we 1349*0Sstevel@tonic-gate * shouldn't charge for the autoload time. So, since 1350*0Sstevel@tonic-gate * we updated *telapsed ourselves above, we just set 1351*0Sstevel@tonic-gate * tstart_writing to the current time, and query() 1352*0Sstevel@tonic-gate * will end up making a null-effect change. This, 1353*0Sstevel@tonic-gate * of course, assumes that our caller will be resetting 1354*0Sstevel@tonic-gate * *tstart_writing. This is currently the case. 1355*0Sstevel@tonic-gate * If tstart_writing is NULL (should never happen), 1356*0Sstevel@tonic-gate * we're ok, since time(2) will accept a NULL pointer. 1357*0Sstevel@tonic-gate */ 1358*0Sstevel@tonic-gate (void) time(tstart_writing); 1359*0Sstevel@tonic-gate } 1360*0Sstevel@tonic-gate 1361*0Sstevel@tonic-gate if (strncmp(spcl.c_label, "none", 5)) { 1362*0Sstevel@tonic-gate (void) strncpy(volname, spcl.c_label, sizeof (spcl.c_label)); 1363*0Sstevel@tonic-gate volname[sizeof (spcl.c_label)] = '\0'; 1364*0Sstevel@tonic-gate } else 1365*0Sstevel@tonic-gate (void) snprintf(volname, sizeof (volname), "#%d", tapeno+1); 1366*0Sstevel@tonic-gate 1367*0Sstevel@tonic-gate timeest(1, spcl.c_tapea); 1368*0Sstevel@tonic-gate (void) snprintf(buf1, sizeof (buf1), gettext( 1369*0Sstevel@tonic-gate "Change Volumes: Mount volume `%s' on `%s'\n"), volname, dumpdev); 1370*0Sstevel@tonic-gate msg(buf1); 1371*0Sstevel@tonic-gate broadcast(gettext("CHANGE VOLUMES!\7\7\n")); 1372*0Sstevel@tonic-gate (void) snprintf(buf1, sizeof (buf1), gettext( 1373*0Sstevel@tonic-gate "Is the new volume (%s) mounted on `%s' and ready to go?: %s"), 1374*0Sstevel@tonic-gate volname, dumpdev, gettext("(\"yes\" or \"no\") ")); 1375*0Sstevel@tonic-gate while (!query(buf1)) { 1376*0Sstevel@tonic-gate (void) snprintf(buf2, sizeof (buf2), gettext( 1377*0Sstevel@tonic-gate "Do you want to abort dump?: (\"yes\" or \"no\") ")); 1378*0Sstevel@tonic-gate if (query(buf2)) { 1379*0Sstevel@tonic-gate dumpabort(); 1380*0Sstevel@tonic-gate /*NOTREACHED*/ 1381*0Sstevel@tonic-gate } 1382*0Sstevel@tonic-gate } 1383*0Sstevel@tonic-gate } 1384*0Sstevel@tonic-gate 1385*0Sstevel@tonic-gate /* 1386*0Sstevel@tonic-gate * We implement taking and restoring checkpoints on the tape level. 1387*0Sstevel@tonic-gate * When each tape is opened, a new process is created by forking; this 1388*0Sstevel@tonic-gate * saves all of the necessary context in the parent. The child 1389*0Sstevel@tonic-gate * continues the dump; the parent waits around, saving the context. 1390*0Sstevel@tonic-gate * If the child returns X_REWRITE, then it had problems writing that tape; 1391*0Sstevel@tonic-gate * this causes the parent to fork again, duplicating the context, and 1392*0Sstevel@tonic-gate * everything continues as if nothing had happened. 1393*0Sstevel@tonic-gate */ 1394*0Sstevel@tonic-gate 1395*0Sstevel@tonic-gate void 1396*0Sstevel@tonic-gate otape(top) 1397*0Sstevel@tonic-gate int top; 1398*0Sstevel@tonic-gate { 1399*0Sstevel@tonic-gate static struct mtget mt; 1400*0Sstevel@tonic-gate char buf[3000]; 1401*0Sstevel@tonic-gate pid_t parentpid; 1402*0Sstevel@tonic-gate pid_t childpid; 1403*0Sstevel@tonic-gate pid_t waitproc; 1404*0Sstevel@tonic-gate int status; 1405*0Sstevel@tonic-gate struct sigvec sv, osv; 1406*0Sstevel@tonic-gate 1407*0Sstevel@tonic-gate sv.sv_flags = SA_RESTART; 1408*0Sstevel@tonic-gate (void) sigemptyset(&sv.sa_mask); 1409*0Sstevel@tonic-gate sv.sv_handler = SIG_IGN; 1410*0Sstevel@tonic-gate (void) sigvec(SIGINT, &sv, (struct sigvec *)0); 1411*0Sstevel@tonic-gate 1412*0Sstevel@tonic-gate parentpid = getpid(); 1413*0Sstevel@tonic-gate 1414*0Sstevel@tonic-gate if (verify) { 1415*0Sstevel@tonic-gate if (doingverify) 1416*0Sstevel@tonic-gate doingverify = 0; 1417*0Sstevel@tonic-gate else 1418*0Sstevel@tonic-gate Exit(X_VERIFY); 1419*0Sstevel@tonic-gate } 1420*0Sstevel@tonic-gate restore_check_point: 1421*0Sstevel@tonic-gate 1422*0Sstevel@tonic-gate sv.sv_handler = interrupt; 1423*0Sstevel@tonic-gate (void) sigvec(SIGINT, &sv, (struct sigvec *)0); 1424*0Sstevel@tonic-gate (void) fflush(stderr); 1425*0Sstevel@tonic-gate /* 1426*0Sstevel@tonic-gate * All signals are inherited... 1427*0Sstevel@tonic-gate */ 1428*0Sstevel@tonic-gate sighold(SIGINT); 1429*0Sstevel@tonic-gate childpid = fork(); 1430*0Sstevel@tonic-gate if (childpid < 0) { 1431*0Sstevel@tonic-gate msg(gettext( 1432*0Sstevel@tonic-gate "Context-saving fork failed in parent %ld\n"), 1433*0Sstevel@tonic-gate (long)parentpid); 1434*0Sstevel@tonic-gate Exit(X_ABORT); 1435*0Sstevel@tonic-gate } 1436*0Sstevel@tonic-gate if (childpid != 0) { 1437*0Sstevel@tonic-gate /* 1438*0Sstevel@tonic-gate * PARENT: 1439*0Sstevel@tonic-gate * save the context by waiting 1440*0Sstevel@tonic-gate * until the child doing all of the work returns. 1441*0Sstevel@tonic-gate * let the child catch user interrupts 1442*0Sstevel@tonic-gate */ 1443*0Sstevel@tonic-gate sv.sv_handler = SIG_IGN; 1444*0Sstevel@tonic-gate (void) sigvec(SIGINT, &sv, (struct sigvec *)0); 1445*0Sstevel@tonic-gate sigrelse(SIGINT); 1446*0Sstevel@tonic-gate #ifdef TDEBUG 1447*0Sstevel@tonic-gate 1448*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1449*0Sstevel@tonic-gate msg(gettext( 1450*0Sstevel@tonic-gate "Volume: %d; parent process: %ld child process %ld\n"), 1451*0Sstevel@tonic-gate tapeno+1, (long)parentpid, (long)childpid); 1452*0Sstevel@tonic-gate #endif /* TDEBUG */ 1453*0Sstevel@tonic-gate for (;;) { 1454*0Sstevel@tonic-gate waitproc = waitpid(0, &status, 0); 1455*0Sstevel@tonic-gate if (waitproc == childpid) 1456*0Sstevel@tonic-gate break; 1457*0Sstevel@tonic-gate msg(gettext( 1458*0Sstevel@tonic-gate "Parent %ld waiting for child %ld had another child %ld return\n"), 1459*0Sstevel@tonic-gate (long)parentpid, (long)childpid, (long)waitproc); 1460*0Sstevel@tonic-gate } 1461*0Sstevel@tonic-gate if (WIFSIGNALED(status)) { 1462*0Sstevel@tonic-gate msg(gettext("Process %ld killed by signal %d: %s\n"), 1463*0Sstevel@tonic-gate (long)childpid, WTERMSIG(status), 1464*0Sstevel@tonic-gate strsignal(WTERMSIG(status))); 1465*0Sstevel@tonic-gate status = X_ABORT; 1466*0Sstevel@tonic-gate } else 1467*0Sstevel@tonic-gate status = WEXITSTATUS(status); 1468*0Sstevel@tonic-gate #ifdef TDEBUG 1469*0Sstevel@tonic-gate switch (status) { 1470*0Sstevel@tonic-gate case X_FINOK: 1471*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1472*0Sstevel@tonic-gate msg(gettext( 1473*0Sstevel@tonic-gate "Child %ld finishes X_FINOK\n"), (long)childpid); 1474*0Sstevel@tonic-gate break; 1475*0Sstevel@tonic-gate case X_ABORT: 1476*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1477*0Sstevel@tonic-gate msg(gettext( 1478*0Sstevel@tonic-gate "Child %ld finishes X_ABORT\n"), (long)childpid); 1479*0Sstevel@tonic-gate break; 1480*0Sstevel@tonic-gate case X_REWRITE: 1481*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1482*0Sstevel@tonic-gate msg(gettext( 1483*0Sstevel@tonic-gate "Child %ld finishes X_REWRITE\n"), (long)childpid); 1484*0Sstevel@tonic-gate break; 1485*0Sstevel@tonic-gate case X_RESTART: 1486*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1487*0Sstevel@tonic-gate msg(gettext( 1488*0Sstevel@tonic-gate "Child %ld finishes X_RESTART\n"), (long)childpid); 1489*0Sstevel@tonic-gate break; 1490*0Sstevel@tonic-gate case X_VERIFY: 1491*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1492*0Sstevel@tonic-gate msg(gettext( 1493*0Sstevel@tonic-gate "Child %ld finishes X_VERIFY\n"), (long)childpid); 1494*0Sstevel@tonic-gate break; 1495*0Sstevel@tonic-gate default: 1496*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1497*0Sstevel@tonic-gate msg(gettext("Child %ld finishes unknown %d\n"), 1498*0Sstevel@tonic-gate (long)childpid, status); 1499*0Sstevel@tonic-gate break; 1500*0Sstevel@tonic-gate } 1501*0Sstevel@tonic-gate #endif /* TDEBUG */ 1502*0Sstevel@tonic-gate switch (status) { 1503*0Sstevel@tonic-gate case X_FINOK: 1504*0Sstevel@tonic-gate /* wait for children */ 1505*0Sstevel@tonic-gate while (waitpid(0, (int *)0, 0) >= 0) 1506*0Sstevel@tonic-gate /*LINTED [empty body]*/ 1507*0Sstevel@tonic-gate continue; 1508*0Sstevel@tonic-gate Exit(X_FINOK); 1509*0Sstevel@tonic-gate /*NOTREACHED*/ 1510*0Sstevel@tonic-gate case X_ABORT: 1511*0Sstevel@tonic-gate Exit(X_ABORT); 1512*0Sstevel@tonic-gate /*NOTREACHED*/ 1513*0Sstevel@tonic-gate case X_VERIFY: 1514*0Sstevel@tonic-gate doingverify++; 1515*0Sstevel@tonic-gate goto restore_check_point; 1516*0Sstevel@tonic-gate /*NOTREACHED*/ 1517*0Sstevel@tonic-gate case X_REWRITE: 1518*0Sstevel@tonic-gate doingverify = 0; 1519*0Sstevel@tonic-gate changevol(); 1520*0Sstevel@tonic-gate goto restore_check_point; 1521*0Sstevel@tonic-gate /* NOTREACHED */ 1522*0Sstevel@tonic-gate case X_RESTART: 1523*0Sstevel@tonic-gate doingverify = 0; 1524*0Sstevel@tonic-gate if (!top) { 1525*0Sstevel@tonic-gate Exit(X_RESTART); 1526*0Sstevel@tonic-gate } 1527*0Sstevel@tonic-gate if (!offline) 1528*0Sstevel@tonic-gate autoload = 0; 1529*0Sstevel@tonic-gate changevol(); 1530*0Sstevel@tonic-gate sv.sv_handler = interrupt; 1531*0Sstevel@tonic-gate (void) sigvec(SIGINT, &sv, (struct sigvec *)0); 1532*0Sstevel@tonic-gate return; 1533*0Sstevel@tonic-gate /* NOTREACHED */ 1534*0Sstevel@tonic-gate default: 1535*0Sstevel@tonic-gate msg(gettext("Bad return code from dump: %d\n"), status); 1536*0Sstevel@tonic-gate Exit(X_ABORT); 1537*0Sstevel@tonic-gate /*NOTREACHED*/ 1538*0Sstevel@tonic-gate } 1539*0Sstevel@tonic-gate /*NOTREACHED*/ 1540*0Sstevel@tonic-gate } else { /* we are the child; just continue */ 1541*0Sstevel@tonic-gate child_chdir(); 1542*0Sstevel@tonic-gate sigrelse(SIGINT); 1543*0Sstevel@tonic-gate #ifdef TDEBUG 1544*0Sstevel@tonic-gate (void) sleep(4); /* time for parent's message to get out */ 1545*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1546*0Sstevel@tonic-gate msg(gettext( 1547*0Sstevel@tonic-gate "Child on Volume %d has parent %ld, my pid = %ld\n"), 1548*0Sstevel@tonic-gate tapeno+1, (long)parentpid, (long)getpid()); 1549*0Sstevel@tonic-gate #endif 1550*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext( 1551*0Sstevel@tonic-gate "Cannot open `%s'. Do you want to retry the open?: (\"yes\" or \"no\") "), 1552*0Sstevel@tonic-gate dumpdev); 1553*0Sstevel@tonic-gate if (doingverify) { 1554*0Sstevel@tonic-gate /* 1 for stdout */ 1555*0Sstevel@tonic-gate while ((to = host ? rmtopen(tape, O_RDONLY) : 1556*0Sstevel@tonic-gate pipeout ? 1 : 1557*0Sstevel@tonic-gate safe_device_open(tape, O_RDONLY, 0600)) < 0) { 1558*0Sstevel@tonic-gate perror(tape); 1559*0Sstevel@tonic-gate if (autoload) { 1560*0Sstevel@tonic-gate if (!query_once(buf, 1)) { 1561*0Sstevel@tonic-gate dumpabort(); 1562*0Sstevel@tonic-gate /*NOTREACHED*/ 1563*0Sstevel@tonic-gate } 1564*0Sstevel@tonic-gate } else { 1565*0Sstevel@tonic-gate if (!query(buf)) { 1566*0Sstevel@tonic-gate dumpabort(); 1567*0Sstevel@tonic-gate /*NOTREACHED*/ 1568*0Sstevel@tonic-gate } 1569*0Sstevel@tonic-gate } 1570*0Sstevel@tonic-gate } 1571*0Sstevel@tonic-gate 1572*0Sstevel@tonic-gate /* 1573*0Sstevel@tonic-gate * If we're using the non-rewinding tape device, 1574*0Sstevel@tonic-gate * the tape will be left positioned after the 1575*0Sstevel@tonic-gate * EOF mark. We need to back up to the beginning 1576*0Sstevel@tonic-gate * of this tape file (cross two tape marks in the 1577*0Sstevel@tonic-gate * reverse direction and one in the forward 1578*0Sstevel@tonic-gate * direction) before the verify pass. 1579*0Sstevel@tonic-gate */ 1580*0Sstevel@tonic-gate if (host) { 1581*0Sstevel@tonic-gate if (rmtioctl(MTBSF, 2) >= 0) 1582*0Sstevel@tonic-gate (void) rmtioctl(MTFSF, 1); 1583*0Sstevel@tonic-gate else 1584*0Sstevel@tonic-gate (void) rmtioctl(MTNBSF, 1); 1585*0Sstevel@tonic-gate } else { 1586*0Sstevel@tonic-gate static struct mtop bsf = { MTBSF, 2 }; 1587*0Sstevel@tonic-gate static struct mtop fsf = { MTFSF, 1 }; 1588*0Sstevel@tonic-gate static struct mtop nbsf = { MTNBSF, 1 }; 1589*0Sstevel@tonic-gate 1590*0Sstevel@tonic-gate if (ioctl(to, MTIOCTOP, &bsf) >= 0) 1591*0Sstevel@tonic-gate (void) ioctl(to, MTIOCTOP, &fsf); 1592*0Sstevel@tonic-gate else 1593*0Sstevel@tonic-gate (void) ioctl(to, MTIOCTOP, &nbsf); 1594*0Sstevel@tonic-gate } 1595*0Sstevel@tonic-gate } else { 1596*0Sstevel@tonic-gate /* 1597*0Sstevel@tonic-gate * XXX Add logic to test for "tape" being a 1598*0Sstevel@tonic-gate * XXX device or a non-existent file. 1599*0Sstevel@tonic-gate * Current behaviour is that it must exist, 1600*0Sstevel@tonic-gate * and we over-write whatever's there. 1601*0Sstevel@tonic-gate * This can be bad if tape == "/etc/passwd". 1602*0Sstevel@tonic-gate */ 1603*0Sstevel@tonic-gate if (!pipeout && doposition && (tapeno == 0)) { 1604*0Sstevel@tonic-gate positiontape(buf); 1605*0Sstevel@tonic-gate if (setjmp(alrm_buf)) { 1606*0Sstevel@tonic-gate /* 1607*0Sstevel@tonic-gate * The tape is rewinding; 1608*0Sstevel@tonic-gate * we're screwed. 1609*0Sstevel@tonic-gate */ 1610*0Sstevel@tonic-gate msg(gettext( 1611*0Sstevel@tonic-gate "Cannot position tape using rewind device!\n")); 1612*0Sstevel@tonic-gate dumpabort(); 1613*0Sstevel@tonic-gate /*NOTREACHED*/ 1614*0Sstevel@tonic-gate } else { 1615*0Sstevel@tonic-gate sv.sv_handler = alrm; 1616*0Sstevel@tonic-gate (void) sigvec(SIGALRM, &sv, &osv); 1617*0Sstevel@tonic-gate (void) alarm(15); 1618*0Sstevel@tonic-gate } 1619*0Sstevel@tonic-gate while ((to = host ? rmtopen(tape, O_WRONLY) : 1620*0Sstevel@tonic-gate safe_device_open(tape, O_WRONLY, 0600)) < 0) 1621*0Sstevel@tonic-gate (void) sleep(10); 1622*0Sstevel@tonic-gate (void) alarm(0); 1623*0Sstevel@tonic-gate (void) sigvec(SIGALRM, &osv, 1624*0Sstevel@tonic-gate (struct sigvec *)0); 1625*0Sstevel@tonic-gate } else { 1626*0Sstevel@tonic-gate int m; 1627*0Sstevel@tonic-gate m = (access(tape, F_OK) == 0) ? 0 : O_CREAT; 1628*0Sstevel@tonic-gate /* 1629*0Sstevel@tonic-gate * Only verify the tape label if label 1630*0Sstevel@tonic-gate * verification is on and we are at BOT 1631*0Sstevel@tonic-gate */ 1632*0Sstevel@tonic-gate if (pipeout) 1633*0Sstevel@tonic-gate to = 1; 1634*0Sstevel@tonic-gate else while ((to = host ? 1635*0Sstevel@tonic-gate rmtopen(tape, O_WRONLY) : 1636*0Sstevel@tonic-gate safe_device_open(tape, O_WRONLY|m, 0600)) 1637*0Sstevel@tonic-gate < 0) 1638*0Sstevel@tonic-gate if (!query_once(buf, 1)) { 1639*0Sstevel@tonic-gate dumpabort(); 1640*0Sstevel@tonic-gate /*NOTREACHED*/ 1641*0Sstevel@tonic-gate } 1642*0Sstevel@tonic-gate } 1643*0Sstevel@tonic-gate } 1644*0Sstevel@tonic-gate if (!pipeout) { 1645*0Sstevel@tonic-gate tapeout = host ? rmtstatus(&mt) >= 0 : 1646*0Sstevel@tonic-gate ioctl(to, MTIOCGET, &mt) >= 0; /* set state */ 1647*0Sstevel@tonic-gate /* 1648*0Sstevel@tonic-gate * Make sure the tape is positioned 1649*0Sstevel@tonic-gate * where it is supposed to be 1650*0Sstevel@tonic-gate */ 1651*0Sstevel@tonic-gate if (tapeout && (tapeno > 0) && 1652*0Sstevel@tonic-gate (mt.mt_fileno != (filenum-1))) { 1653*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext( 1654*0Sstevel@tonic-gate "Warning - tape positioning error!\n\ 1655*0Sstevel@tonic-gate \t%s current file %ld, should be %ld\n"), 1656*0Sstevel@tonic-gate tape, mt.mt_fileno+1, filenum); 1657*0Sstevel@tonic-gate msg(buf); 1658*0Sstevel@tonic-gate dumpailing(); 1659*0Sstevel@tonic-gate } 1660*0Sstevel@tonic-gate } 1661*0Sstevel@tonic-gate tapeno++; /* current tape sequence */ 1662*0Sstevel@tonic-gate if (tapeno < TP_NINOS) 1663*0Sstevel@tonic-gate inos[tapeno] = chkpt.sl_inos; 1664*0Sstevel@tonic-gate spcl.c_firstrec = chkpt.sl_firstrec; 1665*0Sstevel@tonic-gate spcl.c_tapea = (*tapea) = chkpt.sl_tapea; 1666*0Sstevel@tonic-gate spcl.c_volume++; 1667*0Sstevel@tonic-gate 1668*0Sstevel@tonic-gate enslave(); /* Share tape buffers with slaves */ 1669*0Sstevel@tonic-gate 1670*0Sstevel@tonic-gate #ifdef DEBUG 1671*0Sstevel@tonic-gate if (xflag) { 1672*0Sstevel@tonic-gate /* XGETTEXT: #ifdef DEBUG only */ 1673*0Sstevel@tonic-gate msg(gettext("Checkpoint state:\n")); 1674*0Sstevel@tonic-gate msg(" blockswritten %u\n", blockswritten); 1675*0Sstevel@tonic-gate msg(" ino %u\n", ino); 1676*0Sstevel@tonic-gate msg(" pos %u\n", pos); 1677*0Sstevel@tonic-gate msg(" left %u\n", leftover); 1678*0Sstevel@tonic-gate msg(" tapea %u\n", (*tapea)); 1679*0Sstevel@tonic-gate msg(" state %d\n", dumpstate); 1680*0Sstevel@tonic-gate } 1681*0Sstevel@tonic-gate #endif 1682*0Sstevel@tonic-gate spcl.c_type = TS_TAPE; 1683*0Sstevel@tonic-gate spcl.c_tpbsize = tp_bsize; 1684*0Sstevel@tonic-gate if (leftover == 0) { 1685*0Sstevel@tonic-gate spcl.c_count = 0; 1686*0Sstevel@tonic-gate spclrec(); 1687*0Sstevel@tonic-gate newtape = 0; 1688*0Sstevel@tonic-gate } else 1689*0Sstevel@tonic-gate newtape++; /* new volume indication */ 1690*0Sstevel@tonic-gate if (doingverify) { 1691*0Sstevel@tonic-gate msg(gettext("Starting verify pass\n")); 1692*0Sstevel@tonic-gate } else if (tapeno > 1) { 1693*0Sstevel@tonic-gate msg(gettext( 1694*0Sstevel@tonic-gate "Volume %d begins with blocks from inode %lu\n"), 1695*0Sstevel@tonic-gate tapeno, chkpt.sl_inos); 1696*0Sstevel@tonic-gate } 1697*0Sstevel@tonic-gate (void) timeclock((time_t)1); 1698*0Sstevel@tonic-gate (void) time(tstart_writing); 1699*0Sstevel@tonic-gate timeest(0, spcl.c_tapea); 1700*0Sstevel@tonic-gate } 1701*0Sstevel@tonic-gate } 1702*0Sstevel@tonic-gate 1703*0Sstevel@tonic-gate void 1704*0Sstevel@tonic-gate #ifdef __STDC__ 1705*0Sstevel@tonic-gate dumpabort(void) 1706*0Sstevel@tonic-gate #else 1707*0Sstevel@tonic-gate dumpabort() 1708*0Sstevel@tonic-gate #endif 1709*0Sstevel@tonic-gate { 1710*0Sstevel@tonic-gate 1711*0Sstevel@tonic-gate if (master && master != getpid()) 1712*0Sstevel@tonic-gate /* 1713*0Sstevel@tonic-gate * signal master to call dumpabort 1714*0Sstevel@tonic-gate */ 1715*0Sstevel@tonic-gate (void) kill(master, SIGTERM); 1716*0Sstevel@tonic-gate else { 1717*0Sstevel@tonic-gate killall(); 1718*0Sstevel@tonic-gate 1719*0Sstevel@tonic-gate if (archivefile) 1720*0Sstevel@tonic-gate (void) unlink(archivefile); 1721*0Sstevel@tonic-gate msg(gettext("The ENTIRE dump is aborted.\n")); 1722*0Sstevel@tonic-gate } 1723*0Sstevel@tonic-gate Exit(X_ABORT); 1724*0Sstevel@tonic-gate } 1725*0Sstevel@tonic-gate 1726*0Sstevel@tonic-gate void 1727*0Sstevel@tonic-gate dumpailing(void) 1728*0Sstevel@tonic-gate { 1729*0Sstevel@tonic-gate 1730*0Sstevel@tonic-gate broadcast(gettext("DUMP IS AILING!\n")); 1731*0Sstevel@tonic-gate if (!query(gettext( 1732*0Sstevel@tonic-gate "Do you want to attempt to continue? (\"yes\" or \"no\") "))) { 1733*0Sstevel@tonic-gate dumpabort(); 1734*0Sstevel@tonic-gate /*NOTREACHED*/ 1735*0Sstevel@tonic-gate } 1736*0Sstevel@tonic-gate } 1737*0Sstevel@tonic-gate 1738*0Sstevel@tonic-gate void 1739*0Sstevel@tonic-gate Exit(status) 1740*0Sstevel@tonic-gate { 1741*0Sstevel@tonic-gate /* 1742*0Sstevel@tonic-gate * Clean up message system 1743*0Sstevel@tonic-gate */ 1744*0Sstevel@tonic-gate #ifdef TDEBUG 1745*0Sstevel@tonic-gate 1746*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1747*0Sstevel@tonic-gate msg(gettext("pid = %ld exits with status %d\n"), 1748*0Sstevel@tonic-gate (long)getpid(), status); 1749*0Sstevel@tonic-gate #endif /* TDEBUG */ 1750*0Sstevel@tonic-gate exit(status); 1751*0Sstevel@tonic-gate } 1752*0Sstevel@tonic-gate 1753*0Sstevel@tonic-gate static void 1754*0Sstevel@tonic-gate #ifdef __STDC__ 1755*0Sstevel@tonic-gate killall(void) 1756*0Sstevel@tonic-gate #else 1757*0Sstevel@tonic-gate killall() 1758*0Sstevel@tonic-gate #endif 1759*0Sstevel@tonic-gate { 1760*0Sstevel@tonic-gate struct slaves *slavep; 1761*0Sstevel@tonic-gate 1762*0Sstevel@tonic-gate for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) 1763*0Sstevel@tonic-gate if (slavep->sl_slavepid > 0) { 1764*0Sstevel@tonic-gate (void) kill(slavep->sl_slavepid, SIGKILL); 1765*0Sstevel@tonic-gate #ifdef TDEBUG 1766*0Sstevel@tonic-gate 1767*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1768*0Sstevel@tonic-gate msg(gettext("Slave child %ld killed\n"), 1769*0Sstevel@tonic-gate (long)slavep->sl_slavepid); 1770*0Sstevel@tonic-gate #endif 1771*0Sstevel@tonic-gate } 1772*0Sstevel@tonic-gate if (writepid) { 1773*0Sstevel@tonic-gate (void) kill(writepid, SIGKILL); 1774*0Sstevel@tonic-gate #ifdef TDEBUG 1775*0Sstevel@tonic-gate 1776*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1777*0Sstevel@tonic-gate msg(gettext("Writer child %ld killed\n"), (long)writepid); 1778*0Sstevel@tonic-gate #endif 1779*0Sstevel@tonic-gate } 1780*0Sstevel@tonic-gate if (archivepid) { 1781*0Sstevel@tonic-gate (void) kill(archivepid, SIGKILL); 1782*0Sstevel@tonic-gate #ifdef TDEBUG 1783*0Sstevel@tonic-gate 1784*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1785*0Sstevel@tonic-gate msg(gettext("Archiver child %ld killed\n"), (long)archivepid); 1786*0Sstevel@tonic-gate #endif 1787*0Sstevel@tonic-gate } 1788*0Sstevel@tonic-gate } 1789*0Sstevel@tonic-gate 1790*0Sstevel@tonic-gate /*ARGSUSED*/ 1791*0Sstevel@tonic-gate static void 1792*0Sstevel@tonic-gate proceed(sig) 1793*0Sstevel@tonic-gate int sig; 1794*0Sstevel@tonic-gate { 1795*0Sstevel@tonic-gate caught++; 1796*0Sstevel@tonic-gate } 1797*0Sstevel@tonic-gate 1798*0Sstevel@tonic-gate /*ARGSUSED*/ 1799*0Sstevel@tonic-gate static void 1800*0Sstevel@tonic-gate die(sig) 1801*0Sstevel@tonic-gate int sig; 1802*0Sstevel@tonic-gate { 1803*0Sstevel@tonic-gate Exit(X_FINOK); 1804*0Sstevel@tonic-gate } 1805*0Sstevel@tonic-gate 1806*0Sstevel@tonic-gate static void 1807*0Sstevel@tonic-gate #ifdef __STDC__ 1808*0Sstevel@tonic-gate enslave(void) 1809*0Sstevel@tonic-gate #else 1810*0Sstevel@tonic-gate enslave() 1811*0Sstevel@tonic-gate #endif 1812*0Sstevel@tonic-gate { 1813*0Sstevel@tonic-gate int cmd[2]; /* file descriptors */ 1814*0Sstevel@tonic-gate int i; 1815*0Sstevel@tonic-gate struct sigvec sv; 1816*0Sstevel@tonic-gate struct slaves *slavep; 1817*0Sstevel@tonic-gate int saverr; 1818*0Sstevel@tonic-gate 1819*0Sstevel@tonic-gate sv.sv_flags = SA_RESTART; 1820*0Sstevel@tonic-gate (void) sigemptyset(&sv.sa_mask); 1821*0Sstevel@tonic-gate master = getpid(); 1822*0Sstevel@tonic-gate /* 1823*0Sstevel@tonic-gate * slave sends SIGTERM on dumpabort 1824*0Sstevel@tonic-gate */ 1825*0Sstevel@tonic-gate sv.sv_handler = (void(*)(int))dumpabort; 1826*0Sstevel@tonic-gate (void) sigvec(SIGTERM, &sv, (struct sigvec *)0); 1827*0Sstevel@tonic-gate sv.sv_handler = tperror; 1828*0Sstevel@tonic-gate (void) sigvec(SIGUSR2, &sv, (struct sigvec *)0); 1829*0Sstevel@tonic-gate sv.sv_handler = proceed; 1830*0Sstevel@tonic-gate (void) sigvec(SIGUSR1, &sv, (struct sigvec *)0); 1831*0Sstevel@tonic-gate totalrecsout += recsout; 1832*0Sstevel@tonic-gate caught = 0; 1833*0Sstevel@tonic-gate recsout = 0; 1834*0Sstevel@tonic-gate rotor = 0; 1835*0Sstevel@tonic-gate bufclear(); 1836*0Sstevel@tonic-gate for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) 1837*0Sstevel@tonic-gate slavep->sl_slavefd = -1; 1838*0Sstevel@tonic-gate archivefd = arch = writer = -1; 1839*0Sstevel@tonic-gate for (i = 0; i < SLAVES; i++) { 1840*0Sstevel@tonic-gate if (pipe(cmd) < 0) { 1841*0Sstevel@tonic-gate saverr = errno; 1842*0Sstevel@tonic-gate msg(gettext( 1843*0Sstevel@tonic-gate "Cannot create pipe for slave process: %s\n"), 1844*0Sstevel@tonic-gate strerror(saverr)); 1845*0Sstevel@tonic-gate dumpabort(); 1846*0Sstevel@tonic-gate /*NOTREACHED*/ 1847*0Sstevel@tonic-gate } 1848*0Sstevel@tonic-gate sighold(SIGUSR2); 1849*0Sstevel@tonic-gate sighold(SIGINT); 1850*0Sstevel@tonic-gate sighold(SIGTERM); 1851*0Sstevel@tonic-gate if ((slaves[i].sl_slavepid = fork()) < 0) { 1852*0Sstevel@tonic-gate saverr = errno; 1853*0Sstevel@tonic-gate msg(gettext("Cannot create slave process: %s\n"), 1854*0Sstevel@tonic-gate strerror(saverr)); 1855*0Sstevel@tonic-gate dumpabort(); 1856*0Sstevel@tonic-gate /*NOTREACHED*/ 1857*0Sstevel@tonic-gate } 1858*0Sstevel@tonic-gate slaves[i].sl_slavefd = cmd[1]; 1859*0Sstevel@tonic-gate if (slaves[i].sl_slavepid == 0) { /* Slave starts up here */ 1860*0Sstevel@tonic-gate pid_t next; /* pid of neighbor */ 1861*0Sstevel@tonic-gate 1862*0Sstevel@tonic-gate sv.sv_handler = SIG_DFL; 1863*0Sstevel@tonic-gate (void) sigvec(SIGUSR2, &sv, (struct sigvec *)0); 1864*0Sstevel@tonic-gate sv.sv_handler = SIG_IGN; /* master handler INT */ 1865*0Sstevel@tonic-gate (void) sigvec(SIGINT, &sv, (struct sigvec *)0); 1866*0Sstevel@tonic-gate sv.sv_handler = die; /* normal slave exit */ 1867*0Sstevel@tonic-gate (void) sigvec(SIGTERM, &sv, (struct sigvec *)0); 1868*0Sstevel@tonic-gate 1869*0Sstevel@tonic-gate child_chdir(); 1870*0Sstevel@tonic-gate sigrelse(SIGUSR2); 1871*0Sstevel@tonic-gate sigrelse(SIGINT); 1872*0Sstevel@tonic-gate sigrelse(SIGTERM); 1873*0Sstevel@tonic-gate 1874*0Sstevel@tonic-gate freeino(); /* release unneeded resources */ 1875*0Sstevel@tonic-gate #ifdef TDEBUG 1876*0Sstevel@tonic-gate (void) sleep(4); /* time for parent's message to get out */ 1877*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 1878*0Sstevel@tonic-gate msg(gettext("Neighbor has pid = %ld\n"), (long)getpid()); 1879*0Sstevel@tonic-gate #endif 1880*0Sstevel@tonic-gate /* Closes cmd[1] as a side-effect */ 1881*0Sstevel@tonic-gate for (slavep = &slaves[0]; 1882*0Sstevel@tonic-gate slavep < &slaves[SLAVES]; 1883*0Sstevel@tonic-gate slavep++) 1884*0Sstevel@tonic-gate if (slavep->sl_slavefd >= 0) { 1885*0Sstevel@tonic-gate (void) close(slavep->sl_slavefd); 1886*0Sstevel@tonic-gate slavep->sl_slavefd = -1; 1887*0Sstevel@tonic-gate } 1888*0Sstevel@tonic-gate (void) close(to); 1889*0Sstevel@tonic-gate (void) close(fi); /* Need our own seek ptr */ 1890*0Sstevel@tonic-gate to = -1; 1891*0Sstevel@tonic-gate 1892*0Sstevel@tonic-gate fi = open(disk, O_RDONLY); 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate if (fi < 0) { 1895*0Sstevel@tonic-gate saverr = errno; 1896*0Sstevel@tonic-gate msg(gettext( 1897*0Sstevel@tonic-gate "Cannot open dump device `%s': %s\n"), 1898*0Sstevel@tonic-gate disk, strerror(saverr)); 1899*0Sstevel@tonic-gate dumpabort(); 1900*0Sstevel@tonic-gate /*NOTREACHED*/ 1901*0Sstevel@tonic-gate } 1902*0Sstevel@tonic-gate 1903*0Sstevel@tonic-gate if ((unsigned)atomic((int(*)())read, cmd[0], 1904*0Sstevel@tonic-gate (char *)&next, sizeof (next)) != sizeof (next)) { 1905*0Sstevel@tonic-gate cmdrderr(); 1906*0Sstevel@tonic-gate dumpabort(); 1907*0Sstevel@tonic-gate /*NOTREACHED*/ 1908*0Sstevel@tonic-gate } 1909*0Sstevel@tonic-gate dumpoffline(cmd[0], next, i); 1910*0Sstevel@tonic-gate Exit(X_FINOK); 1911*0Sstevel@tonic-gate } 1912*0Sstevel@tonic-gate /* Parent continues here */ 1913*0Sstevel@tonic-gate sigrelse(SIGUSR2); 1914*0Sstevel@tonic-gate sigrelse(SIGINT); 1915*0Sstevel@tonic-gate sigrelse(SIGTERM); 1916*0Sstevel@tonic-gate (void) close(cmd[0]); 1917*0Sstevel@tonic-gate } 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate if (archive) { 1920*0Sstevel@tonic-gate archivepid = setuparchive(); 1921*0Sstevel@tonic-gate if (!archivepid) { 1922*0Sstevel@tonic-gate dumpabort(); 1923*0Sstevel@tonic-gate /*NOTREACHED*/ 1924*0Sstevel@tonic-gate } 1925*0Sstevel@tonic-gate } 1926*0Sstevel@tonic-gate 1927*0Sstevel@tonic-gate writepid = setupwriter(); 1928*0Sstevel@tonic-gate if (!writepid) { 1929*0Sstevel@tonic-gate dumpabort(); 1930*0Sstevel@tonic-gate /*NOTREACHED*/ 1931*0Sstevel@tonic-gate } 1932*0Sstevel@tonic-gate 1933*0Sstevel@tonic-gate if (arch >= 0) { 1934*0Sstevel@tonic-gate (void) close(arch); /* only writer has this open */ 1935*0Sstevel@tonic-gate arch = -1; 1936*0Sstevel@tonic-gate } 1937*0Sstevel@tonic-gate 1938*0Sstevel@tonic-gate /* Tell each slave who follows it */ 1939*0Sstevel@tonic-gate for (i = 0; i < SLAVES; i++) { 1940*0Sstevel@tonic-gate if ((unsigned)atomic((int(*)())write, slaves[i].sl_slavefd, 1941*0Sstevel@tonic-gate (char *)&(slaves[(i + 1) % SLAVES].sl_slavepid), 1942*0Sstevel@tonic-gate sizeof (int)) != sizeof (int)) { 1943*0Sstevel@tonic-gate cmdwrterr(); 1944*0Sstevel@tonic-gate dumpabort(); 1945*0Sstevel@tonic-gate /*NOTREACHED*/ 1946*0Sstevel@tonic-gate } 1947*0Sstevel@tonic-gate } 1948*0Sstevel@tonic-gate sv.sv_handler = rollforward; /* rcvd from writer on EOT */ 1949*0Sstevel@tonic-gate (void) sigvec(SIGUSR1, &sv, (struct sigvec *)0); 1950*0Sstevel@tonic-gate slp = slaves; 1951*0Sstevel@tonic-gate (void) kill(slp->sl_slavepid, SIGUSR1); 1952*0Sstevel@tonic-gate master = 0; 1953*0Sstevel@tonic-gate } 1954*0Sstevel@tonic-gate 1955*0Sstevel@tonic-gate static void 1956*0Sstevel@tonic-gate #ifdef __STDC__ 1957*0Sstevel@tonic-gate wait_our_turn(void) 1958*0Sstevel@tonic-gate #else 1959*0Sstevel@tonic-gate wait_our_turn() 1960*0Sstevel@tonic-gate #endif 1961*0Sstevel@tonic-gate { 1962*0Sstevel@tonic-gate (void) sighold(SIGUSR1); 1963*0Sstevel@tonic-gate 1964*0Sstevel@tonic-gate if (!caught) { 1965*0Sstevel@tonic-gate #ifdef INSTRUMENT 1966*0Sstevel@tonic-gate (*idle)++; 1967*0Sstevel@tonic-gate #endif 1968*0Sstevel@tonic-gate (void) sigpause(SIGUSR1); 1969*0Sstevel@tonic-gate } 1970*0Sstevel@tonic-gate caught = 0; 1971*0Sstevel@tonic-gate (void) sigrelse(SIGUSR1); 1972*0Sstevel@tonic-gate } 1973*0Sstevel@tonic-gate 1974*0Sstevel@tonic-gate static void 1975*0Sstevel@tonic-gate dumpoffline(cmd, next, mynum) 1976*0Sstevel@tonic-gate int cmd; 1977*0Sstevel@tonic-gate pid_t next; 1978*0Sstevel@tonic-gate int mynum; 1979*0Sstevel@tonic-gate { 1980*0Sstevel@tonic-gate struct req *p = slaves[mynum].sl_req; 1981*0Sstevel@tonic-gate ulong_t i; 1982*0Sstevel@tonic-gate uchar_t *cp; 1983*0Sstevel@tonic-gate uchar_t *blkbuf; 1984*0Sstevel@tonic-gate int notactive = 0; 1985*0Sstevel@tonic-gate 1986*0Sstevel@tonic-gate blkbuf = xmalloc(sblock->fs_bsize); 1987*0Sstevel@tonic-gate 1988*0Sstevel@tonic-gate /*CONSTANTCONDITION*/ 1989*0Sstevel@tonic-gate assert(sizeof (spcl) == TP_BSIZE_MIN); 1990*0Sstevel@tonic-gate 1991*0Sstevel@tonic-gate while (atomic((int(*)())read, cmd, (char *)p, reqsiz) == reqsiz) { 1992*0Sstevel@tonic-gate if (p->br_dblk) { 1993*0Sstevel@tonic-gate bread(p->br_dblk, (uchar_t *)blkbuf, p->br_size); 1994*0Sstevel@tonic-gate } else { 1995*0Sstevel@tonic-gate bcopy((char *)p->br_spcl, (char *)&spcl, 1996*0Sstevel@tonic-gate sizeof (spcl)); 1997*0Sstevel@tonic-gate ino = spcl.c_inumber; 1998*0Sstevel@tonic-gate } 1999*0Sstevel@tonic-gate dumptoarchive = p->aflag & BUF_ARCHIVE; 2000*0Sstevel@tonic-gate wait_our_turn(); 2001*0Sstevel@tonic-gate if (p->br_dblk) { 2002*0Sstevel@tonic-gate for (i = p->br_size, cp = blkbuf; 2003*0Sstevel@tonic-gate i > 0; 2004*0Sstevel@tonic-gate /* LINTED character pointers aren't signed */ 2005*0Sstevel@tonic-gate cp += i > tp_bsize ? tp_bsize : i, 2006*0Sstevel@tonic-gate i -= i > tp_bsize ? tp_bsize : i) { 2007*0Sstevel@tonic-gate /* LINTED unsigned to signed conversion ok */ 2008*0Sstevel@tonic-gate taprec(cp, 0, i > tp_bsize ? tp_bsize : (int)i); 2009*0Sstevel@tonic-gate } 2010*0Sstevel@tonic-gate } else 2011*0Sstevel@tonic-gate spclrec(); 2012*0Sstevel@tonic-gate (void) kill(next, SIGUSR1); /* Next slave's turn */ 2013*0Sstevel@tonic-gate /* 2014*0Sstevel@tonic-gate * Note that we lie about file activity since we don't 2015*0Sstevel@tonic-gate * check for it. 2016*0Sstevel@tonic-gate */ 2017*0Sstevel@tonic-gate if ((unsigned)atomic((int(*)())write, cmd, (char *)¬active, 2018*0Sstevel@tonic-gate sizeof (notactive)) != sizeof (notactive)) { 2019*0Sstevel@tonic-gate cmdwrterr(); 2020*0Sstevel@tonic-gate dumpabort(); 2021*0Sstevel@tonic-gate /*NOTREACHED*/ 2022*0Sstevel@tonic-gate } 2023*0Sstevel@tonic-gate } 2024*0Sstevel@tonic-gate 2025*0Sstevel@tonic-gate free(blkbuf); 2026*0Sstevel@tonic-gate } 2027*0Sstevel@tonic-gate 2028*0Sstevel@tonic-gate static int count; /* tape blocks written since last spclrec */ 2029*0Sstevel@tonic-gate 2030*0Sstevel@tonic-gate /*ARGSUSED*/ 2031*0Sstevel@tonic-gate static void 2032*0Sstevel@tonic-gate onxfsz(sig) 2033*0Sstevel@tonic-gate int sig; 2034*0Sstevel@tonic-gate { 2035*0Sstevel@tonic-gate msg(gettext("File size limit exceeded writing output volume %d\n"), 2036*0Sstevel@tonic-gate tapeno); 2037*0Sstevel@tonic-gate (void) kill(master, SIGUSR2); 2038*0Sstevel@tonic-gate Exit(X_REWRITE); 2039*0Sstevel@tonic-gate } 2040*0Sstevel@tonic-gate 2041*0Sstevel@tonic-gate static long lastnonaddr; /* last DS_{INODE,CLRI,BITS} written */ 2042*0Sstevel@tonic-gate static long lastnonaddrm; /* and the mode thereof */ 2043*0Sstevel@tonic-gate /* 2044*0Sstevel@tonic-gate * dowrite -- the main body of the output writer process 2045*0Sstevel@tonic-gate */ 2046*0Sstevel@tonic-gate static void 2047*0Sstevel@tonic-gate dowrite(cmd) 2048*0Sstevel@tonic-gate int cmd; 2049*0Sstevel@tonic-gate { 2050*0Sstevel@tonic-gate struct bdesc *last = 2051*0Sstevel@tonic-gate &bufp[(NBUF*ntrec)-1]; /* last buffer in pool */ 2052*0Sstevel@tonic-gate struct bdesc *bp = bufp; /* current buf in tape block */ 2053*0Sstevel@tonic-gate struct bdesc *begin = bufp; /* first buf of tape block */ 2054*0Sstevel@tonic-gate struct bdesc *end = bufp + (ntrec-1); /* last buf of tape block */ 2055*0Sstevel@tonic-gate int siz; /* bytes written (block) */ 2056*0Sstevel@tonic-gate int trecs; /* records written (block) */ 2057*0Sstevel@tonic-gate long asize = 0; /* number of 0.1" units... */ 2058*0Sstevel@tonic-gate /* ...written on current tape */ 2059*0Sstevel@tonic-gate char *tp, *rbuf = NULL; 2060*0Sstevel@tonic-gate char *recmap = spcl.c_addr; /* current tape record map */ 2061*0Sstevel@tonic-gate char *endmp; /* end of valid map data */ 2062*0Sstevel@tonic-gate char *mp; /* current map entry */ 2063*0Sstevel@tonic-gate union u_spcl *sp; 2064*0Sstevel@tonic-gate 2065*0Sstevel@tonic-gate (void) signal(SIGXFSZ, onxfsz); 2066*0Sstevel@tonic-gate 2067*0Sstevel@tonic-gate bzero((char *)&spcl, sizeof (spcl)); 2068*0Sstevel@tonic-gate count = 0; 2069*0Sstevel@tonic-gate 2070*0Sstevel@tonic-gate if (doingverify) { 2071*0Sstevel@tonic-gate rbuf = (char *)malloc((uint_t)writesize); 2072*0Sstevel@tonic-gate if (rbuf == 0) { 2073*0Sstevel@tonic-gate /* Restart from checkpoint */ 2074*0Sstevel@tonic-gate (void) kill(master, SIGUSR2); 2075*0Sstevel@tonic-gate Exit(X_REWRITE); 2076*0Sstevel@tonic-gate } 2077*0Sstevel@tonic-gate } 2078*0Sstevel@tonic-gate 2079*0Sstevel@tonic-gate for (;;) { 2080*0Sstevel@tonic-gate /* START: wait until all buffers in tape block are full */ 2081*0Sstevel@tonic-gate if ((bp->b_flags & BUF_FULL) == 0) { 2082*0Sstevel@tonic-gate if (caught) { /* master signalled flush */ 2083*0Sstevel@tonic-gate (void) sighold(SIGUSR1); 2084*0Sstevel@tonic-gate caught = 0; 2085*0Sstevel@tonic-gate /* signal ready */ 2086*0Sstevel@tonic-gate (void) kill(master, SIGUSR1); 2087*0Sstevel@tonic-gate chkpt.sl_count = 0; /* signal not at EOT */ 2088*0Sstevel@tonic-gate checkpoint(bp-1, cmd); /* send data */ 2089*0Sstevel@tonic-gate (void) sigpause(SIGUSR1); 2090*0Sstevel@tonic-gate break; 2091*0Sstevel@tonic-gate } 2092*0Sstevel@tonic-gate #ifdef INSTRUMENT 2093*0Sstevel@tonic-gate (*readmissp)++; 2094*0Sstevel@tonic-gate #endif 2095*0Sstevel@tonic-gate nap(50); 2096*0Sstevel@tonic-gate continue; 2097*0Sstevel@tonic-gate } 2098*0Sstevel@tonic-gate if (bp < end) { 2099*0Sstevel@tonic-gate bp++; 2100*0Sstevel@tonic-gate continue; 2101*0Sstevel@tonic-gate } 2102*0Sstevel@tonic-gate /* END: wait until all buffers in tape block are full */ 2103*0Sstevel@tonic-gate 2104*0Sstevel@tonic-gate tp = begin->b_data; 2105*0Sstevel@tonic-gate (void) sighold(SIGUSR1); 2106*0Sstevel@tonic-gate if (host) { 2107*0Sstevel@tonic-gate if (!doingverify) 2108*0Sstevel@tonic-gate siz = rmtwrite(tp, writesize); 2109*0Sstevel@tonic-gate else if ((siz = rmtread(rbuf, writesize)) == 2110*0Sstevel@tonic-gate writesize && bcmp(rbuf, tp, writesize)) 2111*0Sstevel@tonic-gate siz = -1; 2112*0Sstevel@tonic-gate } else { 2113*0Sstevel@tonic-gate if (!doingverify) 2114*0Sstevel@tonic-gate siz = write(to, tp, writesize); 2115*0Sstevel@tonic-gate else if ((siz = read(to, rbuf, writesize)) == 2116*0Sstevel@tonic-gate writesize && bcmp(rbuf, tp, writesize)) 2117*0Sstevel@tonic-gate siz = -1; 2118*0Sstevel@tonic-gate if (siz < 0 && diskette && errno == ENOSPC) 2119*0Sstevel@tonic-gate siz = 0; /* really EOF */ 2120*0Sstevel@tonic-gate } 2121*0Sstevel@tonic-gate (void) sigrelse(SIGUSR1); 2122*0Sstevel@tonic-gate if (siz < 0 || 2123*0Sstevel@tonic-gate (pipeout && siz != writesize)) { 2124*0Sstevel@tonic-gate char buf[3000]; 2125*0Sstevel@tonic-gate 2126*0Sstevel@tonic-gate /* 2127*0Sstevel@tonic-gate * Isn't i18n wonderful? 2128*0Sstevel@tonic-gate */ 2129*0Sstevel@tonic-gate if (doingverify) { 2130*0Sstevel@tonic-gate if (diskette) 2131*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 2132*0Sstevel@tonic-gate gettext( 2133*0Sstevel@tonic-gate "Verification error %ld blocks into diskette %d\n"), 2134*0Sstevel@tonic-gate asize * 2, tapeno); 2135*0Sstevel@tonic-gate else if (tapeout) 2136*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 2137*0Sstevel@tonic-gate gettext( 2138*0Sstevel@tonic-gate "Verification error %ld feet into tape %d\n"), 2139*0Sstevel@tonic-gate (cartridge ? asize/tracks : 2140*0Sstevel@tonic-gate asize)/120L, 2141*0Sstevel@tonic-gate tapeno); 2142*0Sstevel@tonic-gate else 2143*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 2144*0Sstevel@tonic-gate gettext( 2145*0Sstevel@tonic-gate "Verification error %ld blocks into volume %d\n"), 2146*0Sstevel@tonic-gate asize * 2, tapeno); 2147*0Sstevel@tonic-gate 2148*0Sstevel@tonic-gate } else { 2149*0Sstevel@tonic-gate if (diskette) 2150*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 2151*0Sstevel@tonic-gate gettext( 2152*0Sstevel@tonic-gate "Write error %ld blocks into diskette %d\n"), 2153*0Sstevel@tonic-gate asize * 2, tapeno); 2154*0Sstevel@tonic-gate else if (tapeout) 2155*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 2156*0Sstevel@tonic-gate gettext( 2157*0Sstevel@tonic-gate "Write error %ld feet into tape %d\n"), 2158*0Sstevel@tonic-gate (cartridge ? asize/tracks : 2159*0Sstevel@tonic-gate asize)/120L, tapeno); 2160*0Sstevel@tonic-gate else 2161*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 2162*0Sstevel@tonic-gate gettext( 2163*0Sstevel@tonic-gate "Write error %ld blocks into volume %d\n"), 2164*0Sstevel@tonic-gate asize * 2, tapeno); 2165*0Sstevel@tonic-gate } 2166*0Sstevel@tonic-gate 2167*0Sstevel@tonic-gate msg(buf); 2168*0Sstevel@tonic-gate /* Restart from checkpoint */ 2169*0Sstevel@tonic-gate #ifdef TDEBUG 2170*0Sstevel@tonic-gate 2171*0Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 2172*0Sstevel@tonic-gate msg(gettext("sending SIGUSR2 to pid %ld\n"), master); 2173*0Sstevel@tonic-gate #endif 2174*0Sstevel@tonic-gate (void) kill(master, SIGUSR2); 2175*0Sstevel@tonic-gate Exit(X_REWRITE); 2176*0Sstevel@tonic-gate } 2177*0Sstevel@tonic-gate trecs = siz / tp_bsize; 2178*0Sstevel@tonic-gate if (diskette) 2179*0Sstevel@tonic-gate asize += trecs; /* asize == blocks written */ 2180*0Sstevel@tonic-gate else 2181*0Sstevel@tonic-gate asize += (siz/density + tenthsperirg); 2182*0Sstevel@tonic-gate if (trecs) 2183*0Sstevel@tonic-gate chkpt.sl_firstrec++; 2184*0Sstevel@tonic-gate for (bp = begin; bp < begin + trecs; bp++) { 2185*0Sstevel@tonic-gate if ((arch >= 0) && (bp->b_flags & BUF_ARCHIVE)) { 2186*0Sstevel@tonic-gate if ((unsigned)atomic((int(*)())write, arch, 2187*0Sstevel@tonic-gate (char *)&bp->b_flags, sizeof (bp->b_flags)) 2188*0Sstevel@tonic-gate != sizeof (bp->b_flags)) { 2189*0Sstevel@tonic-gate cmdwrterr(); 2190*0Sstevel@tonic-gate dumpabort(); 2191*0Sstevel@tonic-gate /*NOTREACHED*/ 2192*0Sstevel@tonic-gate } 2193*0Sstevel@tonic-gate if (atomic((int(*)())write, arch, bp->b_data, 2194*0Sstevel@tonic-gate tp_bsize) != tp_bsize) { 2195*0Sstevel@tonic-gate cmdwrterr(); 2196*0Sstevel@tonic-gate dumpabort(); 2197*0Sstevel@tonic-gate /*NOTREACHED*/ 2198*0Sstevel@tonic-gate } 2199*0Sstevel@tonic-gate } 2200*0Sstevel@tonic-gate if (bp->b_flags & BUF_SPCLREC) { 2201*0Sstevel@tonic-gate /*LINTED [bp->b_data is aligned]*/ 2202*0Sstevel@tonic-gate sp = (union u_spcl *)bp->b_data; 2203*0Sstevel@tonic-gate if (sp->s_spcl.c_type != TS_ADDR) { 2204*0Sstevel@tonic-gate lastnonaddr = sp->s_spcl.c_type; 2205*0Sstevel@tonic-gate lastnonaddrm = 2206*0Sstevel@tonic-gate sp->s_spcl.c_dinode.di_mode; 2207*0Sstevel@tonic-gate if (sp->s_spcl.c_type != TS_TAPE) 2208*0Sstevel@tonic-gate chkpt.sl_offset = 0; 2209*0Sstevel@tonic-gate } 2210*0Sstevel@tonic-gate chkpt.sl_count = sp->s_spcl.c_count; 2211*0Sstevel@tonic-gate bcopy((char *)sp, 2212*0Sstevel@tonic-gate (char *)&spcl, sizeof (spcl)); 2213*0Sstevel@tonic-gate mp = recmap; 2214*0Sstevel@tonic-gate endmp = &recmap[spcl.c_count]; 2215*0Sstevel@tonic-gate count = 0; 2216*0Sstevel@tonic-gate } else { 2217*0Sstevel@tonic-gate chkpt.sl_offset++; 2218*0Sstevel@tonic-gate chkpt.sl_count--; 2219*0Sstevel@tonic-gate count++; 2220*0Sstevel@tonic-gate mp++; 2221*0Sstevel@tonic-gate } 2222*0Sstevel@tonic-gate /* 2223*0Sstevel@tonic-gate * Adjust for contiguous hole 2224*0Sstevel@tonic-gate */ 2225*0Sstevel@tonic-gate for (; mp < endmp; mp++) { 2226*0Sstevel@tonic-gate if (*mp) 2227*0Sstevel@tonic-gate break; 2228*0Sstevel@tonic-gate chkpt.sl_offset++; 2229*0Sstevel@tonic-gate chkpt.sl_count--; 2230*0Sstevel@tonic-gate } 2231*0Sstevel@tonic-gate } 2232*0Sstevel@tonic-gate /* 2233*0Sstevel@tonic-gate * Check for end of tape 2234*0Sstevel@tonic-gate */ 2235*0Sstevel@tonic-gate if (trecs < ntrec || 2236*0Sstevel@tonic-gate (!pipeout && tsize > 0 && asize > tsize)) { 2237*0Sstevel@tonic-gate if (tapeout) 2238*0Sstevel@tonic-gate msg(gettext("End-of-tape detected\n")); 2239*0Sstevel@tonic-gate else 2240*0Sstevel@tonic-gate msg(gettext("End-of-file detected\n")); 2241*0Sstevel@tonic-gate (void) sighold(SIGUSR1); 2242*0Sstevel@tonic-gate caught = 0; 2243*0Sstevel@tonic-gate (void) kill(master, SIGUSR1); /* signal EOT */ 2244*0Sstevel@tonic-gate checkpoint(--bp, cmd); /* send checkpoint data */ 2245*0Sstevel@tonic-gate (void) sigpause(SIGUSR1); 2246*0Sstevel@tonic-gate break; 2247*0Sstevel@tonic-gate } 2248*0Sstevel@tonic-gate for (bp = begin; bp <= end; bp++) 2249*0Sstevel@tonic-gate bp->b_flags = BUF_EMPTY; 2250*0Sstevel@tonic-gate if (end + ntrec > last) { 2251*0Sstevel@tonic-gate bp = begin = bufp; 2252*0Sstevel@tonic-gate timeest(0, spcl.c_tapea); 2253*0Sstevel@tonic-gate } else 2254*0Sstevel@tonic-gate bp = begin = end+1; 2255*0Sstevel@tonic-gate end = begin + (ntrec-1); 2256*0Sstevel@tonic-gate } 2257*0Sstevel@tonic-gate 2258*0Sstevel@tonic-gate if (rbuf != NULL) 2259*0Sstevel@tonic-gate free(rbuf); 2260*0Sstevel@tonic-gate } 2261*0Sstevel@tonic-gate 2262*0Sstevel@tonic-gate /* 2263*0Sstevel@tonic-gate * Send checkpoint info back to master. This information 2264*0Sstevel@tonic-gate * consists of the current inode number, number of logical 2265*0Sstevel@tonic-gate * blocks written for that inode (or bitmap), the last logical 2266*0Sstevel@tonic-gate * block number written, the number of logical blocks written 2267*0Sstevel@tonic-gate * to this volume, the current dump state, and the current 2268*0Sstevel@tonic-gate * special record map. 2269*0Sstevel@tonic-gate */ 2270*0Sstevel@tonic-gate static void 2271*0Sstevel@tonic-gate checkpoint(bp, cmd) 2272*0Sstevel@tonic-gate struct bdesc *bp; 2273*0Sstevel@tonic-gate int cmd; 2274*0Sstevel@tonic-gate { 2275*0Sstevel@tonic-gate int state, type; 2276*0Sstevel@tonic-gate ino_t ino; 2277*0Sstevel@tonic-gate 2278*0Sstevel@tonic-gate if (++bp >= &bufp[NBUF*ntrec]) 2279*0Sstevel@tonic-gate bp = bufp; 2280*0Sstevel@tonic-gate 2281*0Sstevel@tonic-gate /* 2282*0Sstevel@tonic-gate * If we are dumping files and the record following 2283*0Sstevel@tonic-gate * the last written to tape is a special record, use 2284*0Sstevel@tonic-gate * it to get an accurate indication of current state. 2285*0Sstevel@tonic-gate */ 2286*0Sstevel@tonic-gate if ((bp->b_flags & BUF_SPCLREC) && (bp->b_flags & BUF_FULL) && 2287*0Sstevel@tonic-gate lastnonaddr == TS_INODE) { 2288*0Sstevel@tonic-gate /*LINTED [bp->b_data is aligned]*/ 2289*0Sstevel@tonic-gate union u_spcl *nextspcl = (union u_spcl *)bp->b_data; 2290*0Sstevel@tonic-gate 2291*0Sstevel@tonic-gate if (nextspcl->s_spcl.c_type == TS_INODE) { 2292*0Sstevel@tonic-gate chkpt.sl_offset = 0; 2293*0Sstevel@tonic-gate chkpt.sl_count = 0; 2294*0Sstevel@tonic-gate } else if (nextspcl->s_spcl.c_type == TS_END) { 2295*0Sstevel@tonic-gate chkpt.sl_offset = 0; 2296*0Sstevel@tonic-gate chkpt.sl_count = 1; /* EOT indicator */ 2297*0Sstevel@tonic-gate } 2298*0Sstevel@tonic-gate ino = nextspcl->s_spcl.c_inumber; 2299*0Sstevel@tonic-gate type = nextspcl->s_spcl.c_type; 2300*0Sstevel@tonic-gate } else { 2301*0Sstevel@tonic-gate /* 2302*0Sstevel@tonic-gate * If not, use what we have. 2303*0Sstevel@tonic-gate */ 2304*0Sstevel@tonic-gate ino = spcl.c_inumber; 2305*0Sstevel@tonic-gate type = spcl.c_type; 2306*0Sstevel@tonic-gate } 2307*0Sstevel@tonic-gate 2308*0Sstevel@tonic-gate switch (type) { /* set output state */ 2309*0Sstevel@tonic-gate case TS_ADDR: 2310*0Sstevel@tonic-gate switch (lastnonaddr) { 2311*0Sstevel@tonic-gate case TS_INODE: 2312*0Sstevel@tonic-gate case TS_TAPE: 2313*0Sstevel@tonic-gate if ((lastnonaddrm & IFMT) == IFDIR || 2314*0Sstevel@tonic-gate (lastnonaddrm & IFMT) == IFATTRDIR) 2315*0Sstevel@tonic-gate state = DS_DIRS; 2316*0Sstevel@tonic-gate else 2317*0Sstevel@tonic-gate state = DS_FILES; 2318*0Sstevel@tonic-gate break; 2319*0Sstevel@tonic-gate case TS_CLRI: 2320*0Sstevel@tonic-gate state = DS_CLRI; 2321*0Sstevel@tonic-gate break; 2322*0Sstevel@tonic-gate case TS_BITS: 2323*0Sstevel@tonic-gate state = DS_BITS; 2324*0Sstevel@tonic-gate break; 2325*0Sstevel@tonic-gate } 2326*0Sstevel@tonic-gate break; 2327*0Sstevel@tonic-gate case TS_INODE: 2328*0Sstevel@tonic-gate if ((spcl.c_dinode.di_mode & IFMT) == IFDIR || 2329*0Sstevel@tonic-gate (spcl.c_dinode.di_mode & IFMT) == IFATTRDIR) 2330*0Sstevel@tonic-gate state = DS_DIRS; 2331*0Sstevel@tonic-gate else 2332*0Sstevel@tonic-gate state = DS_FILES; 2333*0Sstevel@tonic-gate break; 2334*0Sstevel@tonic-gate case 0: /* EOT on 1st record */ 2335*0Sstevel@tonic-gate case TS_TAPE: 2336*0Sstevel@tonic-gate state = DS_START; 2337*0Sstevel@tonic-gate ino = UFSROOTINO; 2338*0Sstevel@tonic-gate break; 2339*0Sstevel@tonic-gate case TS_CLRI: 2340*0Sstevel@tonic-gate state = DS_CLRI; 2341*0Sstevel@tonic-gate break; 2342*0Sstevel@tonic-gate case TS_BITS: 2343*0Sstevel@tonic-gate state = DS_BITS; 2344*0Sstevel@tonic-gate break; 2345*0Sstevel@tonic-gate case TS_END: 2346*0Sstevel@tonic-gate if (spcl.c_type == TS_END) 2347*0Sstevel@tonic-gate state = DS_DONE; 2348*0Sstevel@tonic-gate else 2349*0Sstevel@tonic-gate state = DS_END; 2350*0Sstevel@tonic-gate break; 2351*0Sstevel@tonic-gate } 2352*0Sstevel@tonic-gate 2353*0Sstevel@tonic-gate /* 2354*0Sstevel@tonic-gate * Checkpoint info to be processed by rollforward(): 2355*0Sstevel@tonic-gate * The inode with which the next volume should begin 2356*0Sstevel@tonic-gate * The last inode number on this volume 2357*0Sstevel@tonic-gate * The last logical block number on this volume 2358*0Sstevel@tonic-gate * The current output state 2359*0Sstevel@tonic-gate * The offset within the current inode (already in sl_offset) 2360*0Sstevel@tonic-gate * The number of records left from last spclrec (in sl_count) 2361*0Sstevel@tonic-gate * The physical block the next vol begins with (in sl_firstrec) 2362*0Sstevel@tonic-gate */ 2363*0Sstevel@tonic-gate chkpt.sl_inos = ino; 2364*0Sstevel@tonic-gate chkpt.sl_tapea = spcl.c_tapea + count; 2365*0Sstevel@tonic-gate chkpt.sl_state = state; 2366*0Sstevel@tonic-gate 2367*0Sstevel@tonic-gate if ((unsigned)atomic((int(*)())write, cmd, (char *)&chkpt, 2368*0Sstevel@tonic-gate sizeof (chkpt)) != sizeof (chkpt)) { 2369*0Sstevel@tonic-gate cmdwrterr(); 2370*0Sstevel@tonic-gate dumpabort(); 2371*0Sstevel@tonic-gate /*NOTREACHED*/ 2372*0Sstevel@tonic-gate } 2373*0Sstevel@tonic-gate if ((unsigned)atomic((int(*)())write, cmd, (char *)&spcl, 2374*0Sstevel@tonic-gate sizeof (spcl)) != sizeof (spcl)) { 2375*0Sstevel@tonic-gate cmdwrterr(); 2376*0Sstevel@tonic-gate dumpabort(); 2377*0Sstevel@tonic-gate /*NOTREACHED*/ 2378*0Sstevel@tonic-gate } 2379*0Sstevel@tonic-gate #ifdef DEBUG 2380*0Sstevel@tonic-gate if (xflag) { 2381*0Sstevel@tonic-gate /* XGETTEXT: #ifdef DEBUG only */ 2382*0Sstevel@tonic-gate msg(gettext("sent chkpt to master:\n")); 2383*0Sstevel@tonic-gate msg(" ino %u\n", chkpt.sl_inos); 2384*0Sstevel@tonic-gate msg(" 1strec %u\n", chkpt.sl_firstrec); 2385*0Sstevel@tonic-gate msg(" lastrec %u\n", chkpt.sl_tapea); 2386*0Sstevel@tonic-gate msg(" written %u\n", chkpt.sl_offset); 2387*0Sstevel@tonic-gate msg(" left %u\n", chkpt.sl_count); 2388*0Sstevel@tonic-gate msg(" state %d\n", chkpt.sl_state); 2389*0Sstevel@tonic-gate } 2390*0Sstevel@tonic-gate #endif 2391*0Sstevel@tonic-gate } 2392*0Sstevel@tonic-gate 2393*0Sstevel@tonic-gate /* 2394*0Sstevel@tonic-gate * Since a read from a pipe may not return all we asked for, 2395*0Sstevel@tonic-gate * or a write may not write all we ask if we get a signal, 2396*0Sstevel@tonic-gate * loop until the count is satisfied (or error). 2397*0Sstevel@tonic-gate */ 2398*0Sstevel@tonic-gate static ssize_t 2399*0Sstevel@tonic-gate atomic(func, fd, buf, count) 2400*0Sstevel@tonic-gate int (*func)(), fd, count; 2401*0Sstevel@tonic-gate char *buf; 2402*0Sstevel@tonic-gate { 2403*0Sstevel@tonic-gate ssize_t got = 0, need = count; 2404*0Sstevel@tonic-gate 2405*0Sstevel@tonic-gate /* don't inherit random value if immediately get zero back from func */ 2406*0Sstevel@tonic-gate errno = 0; 2407*0Sstevel@tonic-gate while (need > 0) { 2408*0Sstevel@tonic-gate got = (*func)(fd, buf, MIN(need, 4096)); 2409*0Sstevel@tonic-gate if (got < 0 && errno == EINTR) 2410*0Sstevel@tonic-gate continue; 2411*0Sstevel@tonic-gate if (got <= 0) 2412*0Sstevel@tonic-gate break; 2413*0Sstevel@tonic-gate buf += got; 2414*0Sstevel@tonic-gate need -= got; 2415*0Sstevel@tonic-gate } 2416*0Sstevel@tonic-gate /* if we got what was asked for, return count, else failure (got) */ 2417*0Sstevel@tonic-gate return ((need != 0) ? got : count); 2418*0Sstevel@tonic-gate } 2419*0Sstevel@tonic-gate 2420*0Sstevel@tonic-gate void 2421*0Sstevel@tonic-gate #ifdef __STDC__ 2422*0Sstevel@tonic-gate positiontape(char *msgbuf) 2423*0Sstevel@tonic-gate #else 2424*0Sstevel@tonic-gate positiontape(msgbuf) 2425*0Sstevel@tonic-gate char *msgbuf; 2426*0Sstevel@tonic-gate #endif 2427*0Sstevel@tonic-gate { 2428*0Sstevel@tonic-gate /* Static as never change, no need to waste stack space */ 2429*0Sstevel@tonic-gate static struct mtget mt; 2430*0Sstevel@tonic-gate static struct mtop rew = { MTREW, 1 }; 2431*0Sstevel@tonic-gate static struct mtop fsf = { MTFSF, 1 }; 2432*0Sstevel@tonic-gate char *info = strdup(gettext("Positioning `%s' to file %ld\n")); 2433*0Sstevel@tonic-gate char *fail = strdup(gettext("Cannot position tape to file %d\n")); 2434*0Sstevel@tonic-gate int m; 2435*0Sstevel@tonic-gate 2436*0Sstevel@tonic-gate /* gettext()'s return value is volatile, hence the strdup()s */ 2437*0Sstevel@tonic-gate 2438*0Sstevel@tonic-gate m = (access(tape, F_OK) == 0) ? 0 : O_CREAT; 2439*0Sstevel@tonic-gate 2440*0Sstevel@tonic-gate /* 2441*0Sstevel@tonic-gate * To avoid writing tape marks at inappropriate places, we open the 2442*0Sstevel@tonic-gate * device read-only, position it, close it, and reopen it for writing. 2443*0Sstevel@tonic-gate */ 2444*0Sstevel@tonic-gate while ((to = host ? rmtopen(tape, O_RDONLY) : 2445*0Sstevel@tonic-gate safe_device_open(tape, O_RDONLY|m, 0600)) < 0) { 2446*0Sstevel@tonic-gate if (autoload) { 2447*0Sstevel@tonic-gate if (!query_once(msgbuf, 1)) { 2448*0Sstevel@tonic-gate dumpabort(); 2449*0Sstevel@tonic-gate /*NOTREACHED*/ 2450*0Sstevel@tonic-gate } 2451*0Sstevel@tonic-gate } else { 2452*0Sstevel@tonic-gate if (!query(msgbuf)) { 2453*0Sstevel@tonic-gate dumpabort(); 2454*0Sstevel@tonic-gate /*NOTREACHED*/ 2455*0Sstevel@tonic-gate } 2456*0Sstevel@tonic-gate } 2457*0Sstevel@tonic-gate } 2458*0Sstevel@tonic-gate 2459*0Sstevel@tonic-gate if (host) { 2460*0Sstevel@tonic-gate if (rmtstatus(&mt) >= 0 && 2461*0Sstevel@tonic-gate rmtioctl(MTREW, 1) >= 0 && 2462*0Sstevel@tonic-gate filenum > 1) { 2463*0Sstevel@tonic-gate msg(info, dumpdev, filenum); 2464*0Sstevel@tonic-gate if (rmtioctl(MTFSF, filenum-1) < 0) { 2465*0Sstevel@tonic-gate msg(fail, filenum); 2466*0Sstevel@tonic-gate dumpabort(); 2467*0Sstevel@tonic-gate /*NOTREACHED*/ 2468*0Sstevel@tonic-gate } 2469*0Sstevel@tonic-gate } 2470*0Sstevel@tonic-gate rmtclose(); 2471*0Sstevel@tonic-gate } else { 2472*0Sstevel@tonic-gate if (ioctl(to, MTIOCGET, &mt) >= 0 && 2473*0Sstevel@tonic-gate ioctl(to, MTIOCTOP, &rew) >= 0 && 2474*0Sstevel@tonic-gate filenum > 1) { 2475*0Sstevel@tonic-gate msg(info, dumpdev, filenum); 2476*0Sstevel@tonic-gate fsf.mt_count = filenum - 1; 2477*0Sstevel@tonic-gate if (ioctl(to, MTIOCTOP, &fsf) < 0) { 2478*0Sstevel@tonic-gate msg(fail, filenum); 2479*0Sstevel@tonic-gate dumpabort(); 2480*0Sstevel@tonic-gate /*NOTREACHED*/ 2481*0Sstevel@tonic-gate } 2482*0Sstevel@tonic-gate } 2483*0Sstevel@tonic-gate (void) close(to); 2484*0Sstevel@tonic-gate to = -1; 2485*0Sstevel@tonic-gate } 2486*0Sstevel@tonic-gate 2487*0Sstevel@tonic-gate free(info); 2488*0Sstevel@tonic-gate free(fail); 2489*0Sstevel@tonic-gate } 2490*0Sstevel@tonic-gate 2491*0Sstevel@tonic-gate static void 2492*0Sstevel@tonic-gate #ifdef __STDC__ 2493*0Sstevel@tonic-gate cmdwrterr(void) 2494*0Sstevel@tonic-gate #else 2495*0Sstevel@tonic-gate cmdwrterr() 2496*0Sstevel@tonic-gate #endif 2497*0Sstevel@tonic-gate { 2498*0Sstevel@tonic-gate int saverr = errno; 2499*0Sstevel@tonic-gate msg(gettext("Error writing command pipe: %s\n"), strerror(saverr)); 2500*0Sstevel@tonic-gate } 2501*0Sstevel@tonic-gate 2502*0Sstevel@tonic-gate static void 2503*0Sstevel@tonic-gate #ifdef __STDC__ 2504*0Sstevel@tonic-gate cmdrderr(void) 2505*0Sstevel@tonic-gate #else 2506*0Sstevel@tonic-gate cmdrderr() 2507*0Sstevel@tonic-gate #endif 2508*0Sstevel@tonic-gate { 2509*0Sstevel@tonic-gate int saverr = errno; 2510*0Sstevel@tonic-gate msg(gettext("Error reading command pipe: %s\n"), strerror(saverr)); 2511*0Sstevel@tonic-gate } 2512