10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1053Smaheshvs * Common Development and Distribution License (the "License"). 6*1053Smaheshvs * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*1053Smaheshvs * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 270Sstevel@tonic-gate /* All Rights Reserved */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 310Sstevel@tonic-gate * under license from the Regents of the University of California. 320Sstevel@tonic-gate */ 330Sstevel@tonic-gate 340Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 350Sstevel@tonic-gate 360Sstevel@tonic-gate #include "dump.h" 370Sstevel@tonic-gate #include <rmt.h> 380Sstevel@tonic-gate #include <setjmp.h> 390Sstevel@tonic-gate #include <sys/fdio.h> 400Sstevel@tonic-gate #include <sys/mkdev.h> 410Sstevel@tonic-gate #include <assert.h> 420Sstevel@tonic-gate #include <limits.h> 430Sstevel@tonic-gate 440Sstevel@tonic-gate #define SLEEPMS 50 450Sstevel@tonic-gate 460Sstevel@tonic-gate static uint_t writesize; /* size of malloc()ed buffer for tape */ 470Sstevel@tonic-gate static ino_t inos[TP_NINOS]; /* starting inodes on each tape */ 480Sstevel@tonic-gate 490Sstevel@tonic-gate /* 500Sstevel@tonic-gate * The req structure is used to pass commands from the parent 510Sstevel@tonic-gate * process through the pipes to the slave processes. It comes 520Sstevel@tonic-gate * in two flavors, depending on which mode dump is operating under: 530Sstevel@tonic-gate * an inode request (on-line mode) and a disk block request ("old" mode). 540Sstevel@tonic-gate */ 550Sstevel@tonic-gate /* 560Sstevel@tonic-gate * The inode request structure is used during on-line mode. 570Sstevel@tonic-gate * The master passes inode numbers and starting offsets to 580Sstevel@tonic-gate * the slaves. The tape writer passes out the current inode, 590Sstevel@tonic-gate * offset, and number of tape records written after completing a volume. 600Sstevel@tonic-gate */ 610Sstevel@tonic-gate struct ireq { 620Sstevel@tonic-gate ino_t inumber; /* inode number to open/dump */ 630Sstevel@tonic-gate long igen; /* inode generation number */ 640Sstevel@tonic-gate off_t offset; /* starting offset in inode */ 650Sstevel@tonic-gate int count; /* count for 1st spclrec */ 660Sstevel@tonic-gate }; 670Sstevel@tonic-gate /* 680Sstevel@tonic-gate * The block request structure is used in off-line mode to pass 690Sstevel@tonic-gate * commands to dump disk blocks from the parent process through 700Sstevel@tonic-gate * the pipes to the slave processes. 710Sstevel@tonic-gate */ 720Sstevel@tonic-gate struct breq { 730Sstevel@tonic-gate diskaddr_t dblk; /* disk address to read */ 740Sstevel@tonic-gate size_t size; /* number of bytes to read from disk */ 750Sstevel@tonic-gate ulong_t spclrec[1]; /* actually longer */ 760Sstevel@tonic-gate }; 770Sstevel@tonic-gate 780Sstevel@tonic-gate struct req { 790Sstevel@tonic-gate short aflag; /* write data to archive process as well */ 800Sstevel@tonic-gate short tflag; /* begin new tape */ 810Sstevel@tonic-gate union reqdata { 820Sstevel@tonic-gate struct ireq ino; /* used for on-line mode */ 830Sstevel@tonic-gate struct breq blks; /* used for off-line mode */ 840Sstevel@tonic-gate } data; 850Sstevel@tonic-gate }; 860Sstevel@tonic-gate 870Sstevel@tonic-gate #define ir_inumber data.ino.inumber 880Sstevel@tonic-gate #define ir_igen data.ino.igen 890Sstevel@tonic-gate #define ir_offset data.ino.offset 900Sstevel@tonic-gate #define ir_count data.ino.count 910Sstevel@tonic-gate 920Sstevel@tonic-gate #define br_dblk data.blks.dblk 930Sstevel@tonic-gate #define br_size data.blks.size 940Sstevel@tonic-gate #define br_spcl data.blks.spclrec 950Sstevel@tonic-gate 960Sstevel@tonic-gate static int reqsiz = 0; /* alloctape will initialize */ 970Sstevel@tonic-gate 980Sstevel@tonic-gate #define SLAVES 3 990Sstevel@tonic-gate struct slaves { 1000Sstevel@tonic-gate int sl_slavefd; /* pipe from master to slave */ 1010Sstevel@tonic-gate pid_t sl_slavepid; /* slave pid; used by killall() */ 1020Sstevel@tonic-gate ino_t sl_inos; /* inos, if this record starts tape */ 1030Sstevel@tonic-gate int sl_offset; /* logical blocks written for object */ 1040Sstevel@tonic-gate int sl_count; /* logical blocks left in spclrec */ 1050Sstevel@tonic-gate int sl_tapea; /* header number, if starting tape */ 1060Sstevel@tonic-gate int sl_firstrec; /* number of first block on tape */ 1070Sstevel@tonic-gate int sl_state; /* dump output state */ 1080Sstevel@tonic-gate struct req *sl_req; /* instruction packet to slave */ 1090Sstevel@tonic-gate }; 1100Sstevel@tonic-gate static struct slaves slaves[SLAVES]; /* one per slave */ 1110Sstevel@tonic-gate static struct slaves *slp; /* pointer to current slave */ 1120Sstevel@tonic-gate static struct slaves chkpt; /* checkpointed data */ 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate struct bdesc { 1150Sstevel@tonic-gate char *b_data; /* pointer to buffer data */ 1160Sstevel@tonic-gate int b_flags; /* flags (see below) */ 1170Sstevel@tonic-gate }; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* 1200Sstevel@tonic-gate * The following variables are in shared memory, and must be 1210Sstevel@tonic-gate * explicitly checkpointed and/or reset. 1220Sstevel@tonic-gate */ 1230Sstevel@tonic-gate static caddr_t shared; /* pointer to block of shared memory */ 1240Sstevel@tonic-gate static struct bdesc *bufp; /* buffer descriptors */ 1250Sstevel@tonic-gate static struct bdesc **current; /* output buffer to fill */ 1260Sstevel@tonic-gate static int *tapea; /* logical record count */ 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate #ifdef INSTRUMENT 1290Sstevel@tonic-gate static int *readmissp; /* number of times writer was idle */ 1300Sstevel@tonic-gate static int *idle; /* number of times slaves were idle */ 1310Sstevel@tonic-gate #endif /* INSTRUMENT */ 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate /* 1340Sstevel@tonic-gate * Buffer flags 1350Sstevel@tonic-gate */ 1360Sstevel@tonic-gate #define BUF_EMPTY 0x0 /* nothing in buffer */ 1370Sstevel@tonic-gate #define BUF_FULL 0x1 /* data in buffer */ 1380Sstevel@tonic-gate #define BUF_SPCLREC 0x2 /* contains special record */ 1390Sstevel@tonic-gate #define BUF_ARCHIVE 0x4 /* dump to archive */ 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate static int recsout; /* number of req's sent to slaves */ 1420Sstevel@tonic-gate static int totalrecsout; /* total number of req's sent to slaves */ 1430Sstevel@tonic-gate static int rotor; /* next slave to be instructed */ 1440Sstevel@tonic-gate static pid_t master; /* pid of master, for sending error signals */ 1450Sstevel@tonic-gate static int writer = -1; /* fd of tape writer */ 1460Sstevel@tonic-gate static pid_t writepid; /* pid of tape writer */ 1470Sstevel@tonic-gate static int arch; /* fd of output archiver */ 1480Sstevel@tonic-gate static pid_t archivepid; /* pid of output archiver */ 1490Sstevel@tonic-gate static int archivefd; /* fd of archive file (proper) */ 1500Sstevel@tonic-gate static offset_t lf_archoffset; /* checkpointed offset into archive file */ 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate int caught; /* caught signal -- imported by mapfile() */ 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate #ifdef DEBUG 1550Sstevel@tonic-gate extern int xflag; 1560Sstevel@tonic-gate #endif 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate #ifdef __STDC__ 1590Sstevel@tonic-gate static void cmdwrterr(void); 1600Sstevel@tonic-gate static void cmdrderr(void); 1610Sstevel@tonic-gate static void freetape(void); 1620Sstevel@tonic-gate static void bufclear(void); 1630Sstevel@tonic-gate static pid_t setuparchive(void); 1640Sstevel@tonic-gate static pid_t setupwriter(void); 1650Sstevel@tonic-gate static void nextslave(void); 1660Sstevel@tonic-gate static void tperror(int); 1670Sstevel@tonic-gate static void rollforward(int); 1680Sstevel@tonic-gate static void nap(int); 1690Sstevel@tonic-gate static void alrm(int); 1700Sstevel@tonic-gate static void just_rewind(void); 1710Sstevel@tonic-gate static void killall(void); 1720Sstevel@tonic-gate static void proceed(int); 1730Sstevel@tonic-gate static void die(int); 1740Sstevel@tonic-gate static void enslave(void); 1750Sstevel@tonic-gate static void wait_our_turn(void); 1760Sstevel@tonic-gate static void dumpoffline(int, pid_t, int); 1770Sstevel@tonic-gate static void onxfsz(int); 1780Sstevel@tonic-gate static void dowrite(int); 1790Sstevel@tonic-gate static void checkpoint(struct bdesc *, int); 1800Sstevel@tonic-gate static ssize_t atomic(int (*)(), int, char *, int); 1810Sstevel@tonic-gate #else 1820Sstevel@tonic-gate static void cmdwrterr(); 1830Sstevel@tonic-gate static void cmdrderr(); 1840Sstevel@tonic-gate static void freetape(); 1850Sstevel@tonic-gate static void bufclear(); 1860Sstevel@tonic-gate static pid_t setuparchive(); 1870Sstevel@tonic-gate static pid_t setupwriter(); 1880Sstevel@tonic-gate static void nextslave(); 1890Sstevel@tonic-gate static void tperror(); 1900Sstevel@tonic-gate static void rollforward(); 1910Sstevel@tonic-gate static void nap(); 1920Sstevel@tonic-gate static void alrm(); 1930Sstevel@tonic-gate static void just_rewind(); 1940Sstevel@tonic-gate static void killall(); 1950Sstevel@tonic-gate static void proceed(); 1960Sstevel@tonic-gate static void die(); 1970Sstevel@tonic-gate static void enslave(); 1980Sstevel@tonic-gate static void wait_our_turn(); 1990Sstevel@tonic-gate static void dumpoffline(); 2000Sstevel@tonic-gate static void onxfsz(); 2010Sstevel@tonic-gate static void dowrite(); 2020Sstevel@tonic-gate static void checkpoint(); 2030Sstevel@tonic-gate static ssize_t atomic(); 2040Sstevel@tonic-gate #endif 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate static size_t tapesize; 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* 2090Sstevel@tonic-gate * Allocate buffers and shared memory variables. Tape buffers are 2100Sstevel@tonic-gate * allocated on page boundaries for tape write() efficiency. 2110Sstevel@tonic-gate */ 2120Sstevel@tonic-gate void 2130Sstevel@tonic-gate #ifdef __STDC__ 2140Sstevel@tonic-gate #else 2150Sstevel@tonic-gate #endif 2160Sstevel@tonic-gate alloctape(void) 2170Sstevel@tonic-gate { 2180Sstevel@tonic-gate struct slaves *slavep; 2190Sstevel@tonic-gate ulong_t pgoff = (unsigned)(getpagesize() - 1); /* 2**n - 1 */ 2200Sstevel@tonic-gate int mapfd; 2210Sstevel@tonic-gate char *obuf; 2220Sstevel@tonic-gate int saverr; 2230Sstevel@tonic-gate int i, j; 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate writesize = ntrec * tp_bsize; 2260Sstevel@tonic-gate if (!printsize) 2270Sstevel@tonic-gate msg(gettext("Writing %d Kilobyte records\n"), 2280Sstevel@tonic-gate writesize / TP_BSIZE_MIN); 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate /* 2310Sstevel@tonic-gate * set up shared memory seg for here and child 2320Sstevel@tonic-gate */ 2330Sstevel@tonic-gate mapfd = open("/dev/zero", O_RDWR); 2340Sstevel@tonic-gate if (mapfd == -1) { 2350Sstevel@tonic-gate saverr = errno; 2360Sstevel@tonic-gate msg(gettext("Cannot open `%s': %s\n"), 2370Sstevel@tonic-gate "/dev/zero", strerror(saverr)); 2380Sstevel@tonic-gate dumpabort(); 2390Sstevel@tonic-gate /*NOTREACHED*/ 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * Allocate space such that buffers are page-aligned and 2430Sstevel@tonic-gate * pointers are aligned on 4-byte boundaries (for SPARC). 2440Sstevel@tonic-gate * This code assumes that (NBUF * writesize) is a multiple 2450Sstevel@tonic-gate * of the page size and that pages are aligned on 4-byte 2460Sstevel@tonic-gate * boundaries. Space is allocated as follows: 2470Sstevel@tonic-gate * 2480Sstevel@tonic-gate * (NBUF * writesize) for the actual buffers 2490Sstevel@tonic-gate * (pagesize - 1) for padding so the buffers are page-aligned 2500Sstevel@tonic-gate * (NBUF * ntrec * sizeof (struct bdesc)) for each buffer 2510Sstevel@tonic-gate * (n * sizeof (int)) for [n] debugging variables/pointers 2520Sstevel@tonic-gate * (n * sizeof (int)) for [n] miscellaneous variables/pointers 2530Sstevel@tonic-gate */ 2540Sstevel@tonic-gate tapesize = 2550Sstevel@tonic-gate (NBUF * writesize) /* output buffers */ 2560Sstevel@tonic-gate /* LINTED: pgoff fits into a size_t */ 2570Sstevel@tonic-gate + (size_t)pgoff /* page alignment */ 2580Sstevel@tonic-gate /* buffer descriptors */ 2590Sstevel@tonic-gate + (((size_t)sizeof (struct bdesc)) * NBUF * ntrec) 2600Sstevel@tonic-gate #ifdef INSTRUMENT 2610Sstevel@tonic-gate + (2 * (size_t)sizeof (int *)) /* instrumentation */ 2620Sstevel@tonic-gate #endif 2630Sstevel@tonic-gate /* shared variables */ 2640Sstevel@tonic-gate + (size_t)sizeof (struct bdesc **) 2650Sstevel@tonic-gate + (size_t)sizeof (int *) 2660Sstevel@tonic-gate + (3 * (size_t)sizeof (time_t)); 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate shared = mmap((char *)0, tapesize, PROT_READ|PROT_WRITE, 2690Sstevel@tonic-gate MAP_SHARED, mapfd, (off_t)0); 2700Sstevel@tonic-gate if (shared == (caddr_t)-1) { 2710Sstevel@tonic-gate saverr = errno; 2720Sstevel@tonic-gate msg(gettext("Cannot memory map output buffers: %s\n"), 2730Sstevel@tonic-gate strerror(saverr)); 2740Sstevel@tonic-gate dumpabort(); 2750Sstevel@tonic-gate /*NOTREACHED*/ 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate (void) close(mapfd); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate /* 2800Sstevel@tonic-gate * Buffers and buffer headers 2810Sstevel@tonic-gate */ 2820Sstevel@tonic-gate obuf = (char *)(((ulong_t)shared + pgoff) & ~pgoff); 2830Sstevel@tonic-gate /* LINTED obuf and writesize are aligned */ 2840Sstevel@tonic-gate bufp = (struct bdesc *)(obuf + NBUF*writesize); 2850Sstevel@tonic-gate /* 2860Sstevel@tonic-gate * Shared memory variables 2870Sstevel@tonic-gate */ 2880Sstevel@tonic-gate current = (struct bdesc **)&bufp[NBUF*ntrec]; 2890Sstevel@tonic-gate tapea = (int *)(current + 1); 2900Sstevel@tonic-gate /* LINTED pointer alignment ok */ 2910Sstevel@tonic-gate telapsed = (time_t *)(tapea + 1); 2920Sstevel@tonic-gate tstart_writing = telapsed + 1; 2930Sstevel@tonic-gate tschedule = tstart_writing + 1; 2940Sstevel@tonic-gate #ifdef INSTRUMENT 2950Sstevel@tonic-gate /* 2960Sstevel@tonic-gate * Debugging and instrumentation variables 2970Sstevel@tonic-gate */ 2980Sstevel@tonic-gate readmissp = (int *)(tschedule + 1); 2990Sstevel@tonic-gate idle = readmissp + 1; 3000Sstevel@tonic-gate #endif 3010Sstevel@tonic-gate for (i = 0, j = 0; i < NBUF * ntrec; i++, j += tp_bsize) { 3020Sstevel@tonic-gate bufp[i].b_data = &obuf[j]; 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate reqsiz = sizeof (struct req) + tp_bsize - sizeof (long); 3060Sstevel@tonic-gate for (slavep = slaves; slavep < &slaves[SLAVES]; slavep++) 3070Sstevel@tonic-gate slavep->sl_req = (struct req *)xmalloc(reqsiz); 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate chkpt.sl_offset = 0; /* start at offset 0 */ 3100Sstevel@tonic-gate chkpt.sl_count = 0; 3110Sstevel@tonic-gate chkpt.sl_inos = UFSROOTINO; /* in root inode */ 3120Sstevel@tonic-gate chkpt.sl_firstrec = 1; 3130Sstevel@tonic-gate chkpt.sl_tapea = 0; 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate static void 3170Sstevel@tonic-gate #ifdef __STDC__ 3180Sstevel@tonic-gate freetape(void) 3190Sstevel@tonic-gate #else 3200Sstevel@tonic-gate freetape() 3210Sstevel@tonic-gate #endif 3220Sstevel@tonic-gate { 3230Sstevel@tonic-gate if (shared == NULL) 3240Sstevel@tonic-gate return; 3250Sstevel@tonic-gate (void) timeclock((time_t)0); 3260Sstevel@tonic-gate (void) munmap(shared, tapesize); 3270Sstevel@tonic-gate shared = NULL; 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate /* 3310Sstevel@tonic-gate * Reset tape state variables -- called 3320Sstevel@tonic-gate * before a pass to dump active files. 3330Sstevel@tonic-gate */ 3340Sstevel@tonic-gate void 3350Sstevel@tonic-gate #ifdef __STDC__ 3360Sstevel@tonic-gate reset(void) 3370Sstevel@tonic-gate #else 3380Sstevel@tonic-gate reset() 3390Sstevel@tonic-gate #endif 3400Sstevel@tonic-gate { 3410Sstevel@tonic-gate bufclear(); 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate #ifdef INSTRUMENT 3440Sstevel@tonic-gate (*readmissp) = 0; 3450Sstevel@tonic-gate (*idle) = 0; 3460Sstevel@tonic-gate #endif 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate spcl.c_flags = 0; 3490Sstevel@tonic-gate spcl.c_volume = 0; 3500Sstevel@tonic-gate tapeno = 0; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate chkpt.sl_offset = 0; /* start at offset 0 */ 3530Sstevel@tonic-gate chkpt.sl_count = 0; 3540Sstevel@tonic-gate chkpt.sl_inos = UFSROOTINO; /* in root inode */ 3550Sstevel@tonic-gate chkpt.sl_firstrec = 1; 3560Sstevel@tonic-gate chkpt.sl_tapea = 0; 3570Sstevel@tonic-gate } 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate static void 3600Sstevel@tonic-gate #ifdef __STDC__ 3610Sstevel@tonic-gate bufclear(void) 3620Sstevel@tonic-gate #else 3630Sstevel@tonic-gate bufclear() 3640Sstevel@tonic-gate #endif 3650Sstevel@tonic-gate { 3660Sstevel@tonic-gate struct bdesc *bp; 3670Sstevel@tonic-gate int i; 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate for (i = 0, bp = bufp; i < NBUF * ntrec; i++, bp++) 3700Sstevel@tonic-gate bp->b_flags = BUF_EMPTY; 3710Sstevel@tonic-gate if ((caddr_t)current < shared || 3720Sstevel@tonic-gate (caddr_t)current > (shared + tapesize)) { 3730Sstevel@tonic-gate msg(gettext( 3740Sstevel@tonic-gate "bufclear: current pointer out of range of shared memory\n")); 3750Sstevel@tonic-gate dumpabort(); 3760Sstevel@tonic-gate /*NOTREACHED*/ 3770Sstevel@tonic-gate } 3780Sstevel@tonic-gate if ((*current != NULL) && 3790Sstevel@tonic-gate (*current < &bufp[0] || *current > &bufp[NBUF*ntrec])) { 3800Sstevel@tonic-gate /* ANSI string catenation, to shut cstyle up */ 3810Sstevel@tonic-gate msg(gettext("bufclear: current buffer pointer (0x%x) " 3820Sstevel@tonic-gate "out of range of buffer\naddresses (0x%x - 0x%x)\n"), 3830Sstevel@tonic-gate *current, &bufp[0], &bufp[NBUF*ntrec]); 3840Sstevel@tonic-gate dumpabort(); 3850Sstevel@tonic-gate /*NOTREACHED*/ 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate *current = bufp; 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate /* 3910Sstevel@tonic-gate * Start a process to collect information describing the dump. 3920Sstevel@tonic-gate * This data takes two forms: 3930Sstevel@tonic-gate * the bitmap and directory information being written to 3940Sstevel@tonic-gate * the front of the tape (the "archive" file) 3950Sstevel@tonic-gate * information describing each directory and inode (to 3960Sstevel@tonic-gate * be included in the database tmp file) 3970Sstevel@tonic-gate * Write the data to the files as it is received so huge file 3980Sstevel@tonic-gate * systems don't cause dump to consume large amounts of memory. 3990Sstevel@tonic-gate */ 4000Sstevel@tonic-gate static pid_t 4010Sstevel@tonic-gate setuparchive(void) 4020Sstevel@tonic-gate { 4030Sstevel@tonic-gate struct slaves *slavep; 4040Sstevel@tonic-gate int cmd[2]; 4050Sstevel@tonic-gate pid_t pid; 4060Sstevel@tonic-gate ssize_t size; 4070Sstevel@tonic-gate char *data; 4080Sstevel@tonic-gate char *errmsg; 4090Sstevel@tonic-gate int flags, saverr; 4100Sstevel@tonic-gate int punt = 0; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * Both the archive and database tmp files are 4140Sstevel@tonic-gate * checkpointed by taking their current offsets 4150Sstevel@tonic-gate * (sizes) after completing each volume. Restoring 4160Sstevel@tonic-gate * from a checkpoint involves truncating to the 4170Sstevel@tonic-gate * checkpointed size. 4180Sstevel@tonic-gate */ 4190Sstevel@tonic-gate if (archive && !doingactive) { 4200Sstevel@tonic-gate /* It's allowed/expected to exist, so can't use O_EXCL */ 4210Sstevel@tonic-gate archivefd = safe_file_open(archivefile, O_WRONLY, 0600); 4220Sstevel@tonic-gate if (archivefd < 0) { 4230Sstevel@tonic-gate saverr = errno; 4240Sstevel@tonic-gate msg(gettext("Cannot open archive file `%s': %s\n"), 4250Sstevel@tonic-gate archivefile, strerror(saverr)); 4260Sstevel@tonic-gate dumpabort(); 4270Sstevel@tonic-gate /*NOTREACHED*/ 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate if (lseek64(archivefd, lf_archoffset, 0) < 0) { 4310Sstevel@tonic-gate saverr = errno; 4320Sstevel@tonic-gate msg(gettext( 4330Sstevel@tonic-gate "Cannot position archive file `%s' : %s\n"), 4340Sstevel@tonic-gate archivefile, strerror(saverr)); 4350Sstevel@tonic-gate dumpabort(); 4360Sstevel@tonic-gate /*NOTREACHED*/ 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate if (ftruncate64(archivefd, lf_archoffset) < 0) { 4390Sstevel@tonic-gate saverr = errno; 4400Sstevel@tonic-gate msg(gettext( 4410Sstevel@tonic-gate "Cannot truncate archive file `%s' : %s\n"), 4420Sstevel@tonic-gate archivefile, strerror(saverr)); 4430Sstevel@tonic-gate dumpabort(); 4440Sstevel@tonic-gate /*NOTREACHED*/ 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate } 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate if (pipe(cmd) < 0) { 4490Sstevel@tonic-gate saverr = errno; 4500Sstevel@tonic-gate msg(gettext("%s: %s error: %s\n"), 4510Sstevel@tonic-gate "setuparchive", "pipe", strerror(saverr)); 4520Sstevel@tonic-gate return (0); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate sighold(SIGINT); 4550Sstevel@tonic-gate if ((pid = fork()) < 0) { 4560Sstevel@tonic-gate saverr = errno; 4570Sstevel@tonic-gate msg(gettext("%s: %s error: %s\n"), 4580Sstevel@tonic-gate "setuparchive", "fork", strerror(saverr)); 4590Sstevel@tonic-gate return (0); 4600Sstevel@tonic-gate } 4610Sstevel@tonic-gate if (pid > 0) { 4620Sstevel@tonic-gate sigrelse(SIGINT); 4630Sstevel@tonic-gate /* parent process */ 4640Sstevel@tonic-gate (void) close(cmd[0]); 4650Sstevel@tonic-gate arch = cmd[1]; 4660Sstevel@tonic-gate return (pid); 4670Sstevel@tonic-gate } 4680Sstevel@tonic-gate /* 4690Sstevel@tonic-gate * child process 4700Sstevel@tonic-gate */ 4710Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); /* master handles this */ 4720Sstevel@tonic-gate #ifdef TDEBUG 4730Sstevel@tonic-gate (void) sleep(4); /* allow time for parent's message to get out */ 4740Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 4750Sstevel@tonic-gate msg(gettext("Archiver has pid = %ld\n"), (long)getpid()); 4760Sstevel@tonic-gate #endif 4770Sstevel@tonic-gate freeino(); /* release unneeded resources */ 4780Sstevel@tonic-gate freetape(); 4790Sstevel@tonic-gate for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) { 4800Sstevel@tonic-gate if (slavep->sl_slavefd != -1) { 4810Sstevel@tonic-gate (void) close(slavep->sl_slavefd); 4820Sstevel@tonic-gate slavep->sl_slavefd = -1; 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate (void) close(to); 4860Sstevel@tonic-gate (void) close(fi); 4870Sstevel@tonic-gate to = fi = -1; 4880Sstevel@tonic-gate (void) close(cmd[1]); 4890Sstevel@tonic-gate data = xmalloc(tp_bsize); 4900Sstevel@tonic-gate for (;;) { 4910Sstevel@tonic-gate size = atomic((int(*)())read, cmd[0], (char *)&flags, 4920Sstevel@tonic-gate sizeof (flags)); 4930Sstevel@tonic-gate if ((unsigned)size != sizeof (flags)) 4940Sstevel@tonic-gate break; 4950Sstevel@tonic-gate size = atomic((int(*)())read, cmd[0], data, tp_bsize); 4960Sstevel@tonic-gate if (size == tp_bsize) { 4970Sstevel@tonic-gate if (archive && flags & BUF_ARCHIVE && !punt && 4980Sstevel@tonic-gate (size = write(archivefd, data, tp_bsize)) 4990Sstevel@tonic-gate != tp_bsize) { 5000Sstevel@tonic-gate struct stat64 stats; 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate if (size != -1) { 5030Sstevel@tonic-gate errmsg = strdup(gettext( 5040Sstevel@tonic-gate "Output truncated")); 5050Sstevel@tonic-gate if (errmsg == NULL) 5060Sstevel@tonic-gate errmsg = ""; 5070Sstevel@tonic-gate } else { 5080Sstevel@tonic-gate errmsg = strerror(errno); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate if (fstat64(archivefd, &stats) < 0) 5120Sstevel@tonic-gate stats.st_size = -1; 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate /* cast to keep lint&printf happy */ 5150Sstevel@tonic-gate msg(gettext( 5160Sstevel@tonic-gate "Cannot write archive file `%s' at offset %lld: %s\n"), 5170Sstevel@tonic-gate archivefile, (longlong_t)stats.st_size, 5180Sstevel@tonic-gate errmsg); 5190Sstevel@tonic-gate msg(gettext( 5200Sstevel@tonic-gate "Archive file will be deleted, dump will continue\n")); 5210Sstevel@tonic-gate punt++; 5220Sstevel@tonic-gate if ((size != -1) && (*errmsg != '\0')) { 5230Sstevel@tonic-gate free(errmsg); 5240Sstevel@tonic-gate } 5250Sstevel@tonic-gate } 5260Sstevel@tonic-gate } else { 5270Sstevel@tonic-gate break; 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate (void) close(cmd[0]); 5310Sstevel@tonic-gate if (archive) { 5320Sstevel@tonic-gate (void) close(archivefd); 5330Sstevel@tonic-gate archivefd = -1; 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate if (punt) { 5360Sstevel@tonic-gate (void) unlink(archivefile); 5370Sstevel@tonic-gate Exit(X_ABORT); 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate Exit(X_FINOK); 5400Sstevel@tonic-gate /* NOTREACHED */ 541*1053Smaheshvs return (0); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /* 5450Sstevel@tonic-gate * Start a process to read the output buffers and write the data 5460Sstevel@tonic-gate * to the output device. 5470Sstevel@tonic-gate */ 5480Sstevel@tonic-gate static pid_t 5490Sstevel@tonic-gate setupwriter(void) 5500Sstevel@tonic-gate { 5510Sstevel@tonic-gate struct slaves *slavep; 5520Sstevel@tonic-gate int cmd[2]; 5530Sstevel@tonic-gate pid_t pid; 5540Sstevel@tonic-gate int saverr; 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate caught = 0; 5570Sstevel@tonic-gate if (pipe(cmd) < 0) { 5580Sstevel@tonic-gate saverr = errno; 5590Sstevel@tonic-gate msg(gettext("%s: %s error: %s\n"), 5600Sstevel@tonic-gate "setupwriter", "pipe", strerror(saverr)); 5610Sstevel@tonic-gate return (0); 5620Sstevel@tonic-gate } 5630Sstevel@tonic-gate sighold(SIGINT); 5640Sstevel@tonic-gate if ((pid = fork()) < 0) { 5650Sstevel@tonic-gate saverr = errno; 5660Sstevel@tonic-gate msg(gettext("%s: %s error: %s\n"), 5670Sstevel@tonic-gate "setupwriter", "fork", strerror(saverr)); 5680Sstevel@tonic-gate return (0); 5690Sstevel@tonic-gate } 5700Sstevel@tonic-gate if (pid > 0) { 5710Sstevel@tonic-gate /* 5720Sstevel@tonic-gate * Parent process 5730Sstevel@tonic-gate */ 5740Sstevel@tonic-gate sigrelse(SIGINT); 5750Sstevel@tonic-gate (void) close(cmd[0]); 5760Sstevel@tonic-gate writer = cmd[1]; 5770Sstevel@tonic-gate return (pid); 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate /* 5800Sstevel@tonic-gate * Child (writer) process 5810Sstevel@tonic-gate */ 5820Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); /* master handles this */ 5830Sstevel@tonic-gate #ifdef TDEBUG 5840Sstevel@tonic-gate (void) sleep(4); /* allow time for parent's message to get out */ 5850Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 5860Sstevel@tonic-gate msg(gettext("Writer has pid = %ld\n"), (long)getpid()); 5870Sstevel@tonic-gate #endif 5880Sstevel@tonic-gate child_chdir(); 5890Sstevel@tonic-gate freeino(); /* release unneeded resources */ 5900Sstevel@tonic-gate for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) { 5910Sstevel@tonic-gate if (slavep->sl_slavefd != -1) { 5920Sstevel@tonic-gate (void) close(slavep->sl_slavefd); 5930Sstevel@tonic-gate slavep->sl_slavefd = -1; 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate (void) close(fi); 5970Sstevel@tonic-gate fi = -1; 5980Sstevel@tonic-gate (void) close(cmd[1]); 5990Sstevel@tonic-gate dowrite(cmd[0]); 6000Sstevel@tonic-gate if (arch >= 0) { 6010Sstevel@tonic-gate (void) close(arch); 6020Sstevel@tonic-gate arch = -1; 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate (void) close(cmd[0]); 6050Sstevel@tonic-gate Exit(X_FINOK); 6060Sstevel@tonic-gate /* NOTREACHED */ 607*1053Smaheshvs return (0); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate void 6110Sstevel@tonic-gate #ifdef __STDC__ 6120Sstevel@tonic-gate spclrec(void) 6130Sstevel@tonic-gate #else 6140Sstevel@tonic-gate spclrec() 6150Sstevel@tonic-gate #endif 6160Sstevel@tonic-gate { 6170Sstevel@tonic-gate int s, i; 6180Sstevel@tonic-gate int32_t *ip; 6190Sstevel@tonic-gate int flags = BUF_SPCLREC; 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate if ((BIT(ino, shamap)) && (spcl.c_type == TS_INODE)) { 6220Sstevel@tonic-gate spcl.c_type = TS_ADDR; 6230Sstevel@tonic-gate /* LINTED: result fits in a short */ 6240Sstevel@tonic-gate spcl.c_dinode.di_mode &= ~S_IFMT; 6250Sstevel@tonic-gate /* LINTED: result fits in a short */ 6260Sstevel@tonic-gate spcl.c_dinode.di_mode |= IFSHAD; 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate /* 6300Sstevel@tonic-gate * Only TS_INODEs should have short metadata, if this 6310Sstevel@tonic-gate * isn't such a spclrec, clear the metadata flag and 6320Sstevel@tonic-gate * the c_shadow contents. 6330Sstevel@tonic-gate */ 6340Sstevel@tonic-gate if (!(spcl.c_type == TS_INODE && (spcl.c_flags & DR_HASMETA))) { 6350Sstevel@tonic-gate spcl.c_flags &= ~DR_HASMETA; 6360Sstevel@tonic-gate bcopy(c_shadow_save, &(spcl.c_shadow), 6370Sstevel@tonic-gate sizeof (spcl.c_shadow)); 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate if (spcl.c_type == TS_END) { 6410Sstevel@tonic-gate spcl.c_count = 1; 6420Sstevel@tonic-gate spcl.c_flags |= DR_INODEINFO; 6430Sstevel@tonic-gate bcopy((char *)inos, (char *)spcl.c_inos, sizeof (inos)); 6440Sstevel@tonic-gate } else if (spcl.c_type == TS_TAPE) { 6450Sstevel@tonic-gate spcl.c_flags |= DR_NEWHEADER; 6460Sstevel@tonic-gate if (doingactive) 6470Sstevel@tonic-gate spcl.c_flags |= DR_REDUMP; 6480Sstevel@tonic-gate } else if (spcl.c_type != TS_INODE) 6490Sstevel@tonic-gate flags = BUF_SPCLREC; 6500Sstevel@tonic-gate spcl.c_tapea = *tapea; 6510Sstevel@tonic-gate /* LINTED for now, max inode # is 2**31 (ufs max size is 4TB) */ 6520Sstevel@tonic-gate spcl.c_inumber = (ino32_t)ino; 6530Sstevel@tonic-gate spcl.c_magic = (tp_bsize == TP_BSIZE_MIN) ? NFS_MAGIC : MTB_MAGIC; 6540Sstevel@tonic-gate spcl.c_checksum = 0; 6550Sstevel@tonic-gate ip = (int32_t *)&spcl; 6560Sstevel@tonic-gate s = CHECKSUM; 6570Sstevel@tonic-gate assert((tp_bsize % sizeof (*ip)) == 0); 6580Sstevel@tonic-gate i = tp_bsize / sizeof (*ip); 6590Sstevel@tonic-gate assert((i%8) == 0); 6600Sstevel@tonic-gate i /= 8; 6610Sstevel@tonic-gate do { 6620Sstevel@tonic-gate s -= *ip++; s -= *ip++; s -= *ip++; s -= *ip++; 6630Sstevel@tonic-gate s -= *ip++; s -= *ip++; s -= *ip++; s -= *ip++; 6640Sstevel@tonic-gate } while (--i > 0); 6650Sstevel@tonic-gate spcl.c_checksum = s; 6660Sstevel@tonic-gate taprec((uchar_t *)&spcl, flags, sizeof (spcl)); 6670Sstevel@tonic-gate if (spcl.c_type == TS_END) 6680Sstevel@tonic-gate spcl.c_flags &= ~DR_INODEINFO; 6690Sstevel@tonic-gate else if (spcl.c_type == TS_TAPE) 6700Sstevel@tonic-gate spcl.c_flags &= ~(DR_NEWHEADER|DR_REDUMP|DR_TRUEINC); 6710Sstevel@tonic-gate } 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate /* 6740Sstevel@tonic-gate * Fill appropriate buffer 6750Sstevel@tonic-gate */ 6760Sstevel@tonic-gate void 677*1053Smaheshvs taprec(uchar_t *dp, int flags, int size) 6780Sstevel@tonic-gate { 6790Sstevel@tonic-gate if (size > tp_bsize) { 6800Sstevel@tonic-gate msg(gettext( 6810Sstevel@tonic-gate "taprec: Unexpected buffer size, expected %d, got %d.\n"), 6820Sstevel@tonic-gate tp_bsize, size); 6830Sstevel@tonic-gate dumpabort(); 6840Sstevel@tonic-gate /*NOTREACHED*/ 6850Sstevel@tonic-gate } 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate while ((*current)->b_flags & BUF_FULL) 6880Sstevel@tonic-gate nap(10); 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate bcopy(dp, (*current)->b_data, (size_t)size); 6910Sstevel@tonic-gate if (size < tp_bsize) { 6920Sstevel@tonic-gate bzero((*current)->b_data + size, tp_bsize - size); 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate if (dumptoarchive) 6960Sstevel@tonic-gate flags |= BUF_ARCHIVE; 6970Sstevel@tonic-gate 6980Sstevel@tonic-gate /* no locking as we assume only one reader and one writer active */ 6990Sstevel@tonic-gate (*current)->b_flags = (flags | BUF_FULL); 7000Sstevel@tonic-gate if (++*current >= &bufp[NBUF*ntrec]) 7010Sstevel@tonic-gate (*current) = &bufp[0]; 7020Sstevel@tonic-gate (*tapea)++; 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate void 706*1053Smaheshvs dmpblk(daddr32_t blkno, size_t size, off_t offset) 7070Sstevel@tonic-gate { 7080Sstevel@tonic-gate diskaddr_t dblkno; 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate assert((offset >> DEV_BSHIFT) <= INT32_MAX); 7110Sstevel@tonic-gate dblkno = fsbtodb(sblock, blkno) + (offset >> DEV_BSHIFT); 7120Sstevel@tonic-gate size = (size + DEV_BSIZE-1) & ~(DEV_BSIZE-1); 7130Sstevel@tonic-gate slp->sl_req->br_dblk = dblkno; 7140Sstevel@tonic-gate slp->sl_req->br_size = size; 7150Sstevel@tonic-gate if (dumptoarchive) { 7160Sstevel@tonic-gate /* LINTED: result fits in a short */ 7170Sstevel@tonic-gate slp->sl_req->aflag |= BUF_ARCHIVE; 7180Sstevel@tonic-gate } 7190Sstevel@tonic-gate toslave((void(*)())0, ino); 7200Sstevel@tonic-gate } 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate /*ARGSUSED*/ 7230Sstevel@tonic-gate static void 724*1053Smaheshvs tperror(int sig) 7250Sstevel@tonic-gate { 7260Sstevel@tonic-gate char buf[3000]; 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate if (pipeout) { 7290Sstevel@tonic-gate msg(gettext("Write error on %s\n"), tape); 7300Sstevel@tonic-gate msg(gettext("Cannot recover\n")); 7310Sstevel@tonic-gate dumpabort(); 7320Sstevel@tonic-gate /* NOTREACHED */ 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate if (!doingverify) { 7350Sstevel@tonic-gate broadcast(gettext("WRITE ERROR!\n")); 7360Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 7370Sstevel@tonic-gate gettext("Do you want to restart?: (\"yes\" or \"no\") ")); 7380Sstevel@tonic-gate if (!query(buf)) { 7390Sstevel@tonic-gate dumpabort(); 7400Sstevel@tonic-gate /*NOTREACHED*/ 7410Sstevel@tonic-gate } 7420Sstevel@tonic-gate if (tapeout && (isrewind(to) || offline)) { 7430Sstevel@tonic-gate /* ANSI string catenation, to shut cstyle up */ 7440Sstevel@tonic-gate msg(gettext("This tape will rewind. After " 7450Sstevel@tonic-gate "it is rewound,\nreplace the faulty tape " 7460Sstevel@tonic-gate "with a new one;\nthis dump volume will " 7470Sstevel@tonic-gate "be rewritten.\n")); 7480Sstevel@tonic-gate } 7490Sstevel@tonic-gate } else { 7500Sstevel@tonic-gate broadcast(gettext("TAPE VERIFICATION ERROR!\n")); 7510Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext( 7520Sstevel@tonic-gate "Do you want to rewrite?: (\"yes\" or \"no\") ")); 7530Sstevel@tonic-gate if (!query(buf)) { 7540Sstevel@tonic-gate dumpabort(); 7550Sstevel@tonic-gate /*NOTREACHED*/ 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate msg(gettext( 7580Sstevel@tonic-gate "This tape will be rewritten and then verified\n")); 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate killall(); 7610Sstevel@tonic-gate trewind(); 7620Sstevel@tonic-gate Exit(X_REWRITE); 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate /* 7660Sstevel@tonic-gate * Called by master from pass() to send a request to dump files/blocks 7670Sstevel@tonic-gate * to one of the slaves. Slaves return whether the file was active 7680Sstevel@tonic-gate * when it was being dumped. The tape writer process sends checkpoint 7690Sstevel@tonic-gate * info when it completes a volume. 7700Sstevel@tonic-gate */ 7710Sstevel@tonic-gate void 772*1053Smaheshvs toslave(void (*fn)(), ino_t inumber) 7730Sstevel@tonic-gate { 7740Sstevel@tonic-gate int wasactive; 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate if (recsout >= SLAVES) { 7770Sstevel@tonic-gate if ((unsigned)atomic((int(*)())read, slp->sl_slavefd, 7780Sstevel@tonic-gate (char *)&wasactive, sizeof (wasactive)) != 7790Sstevel@tonic-gate sizeof (wasactive)) { 7800Sstevel@tonic-gate cmdrderr(); 7810Sstevel@tonic-gate dumpabort(); 7820Sstevel@tonic-gate /*NOTREACHED*/ 7830Sstevel@tonic-gate } 7840Sstevel@tonic-gate if (wasactive) { 7850Sstevel@tonic-gate active++; 7860Sstevel@tonic-gate msg(gettext( 7870Sstevel@tonic-gate "The file at inode `%lu' was active and will be recopied\n"), 7880Sstevel@tonic-gate slp->sl_req->ir_inumber); 7890Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 7900Sstevel@tonic-gate BIS(slp->sl_req->ir_inumber, activemap); 7910Sstevel@tonic-gate } 7920Sstevel@tonic-gate } 7930Sstevel@tonic-gate slp->sl_req->aflag = 0; 7940Sstevel@tonic-gate if (dumptoarchive) { 7950Sstevel@tonic-gate /* LINTED: result fits in a short */ 7960Sstevel@tonic-gate slp->sl_req->aflag |= BUF_ARCHIVE; 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate if (fn) 7990Sstevel@tonic-gate (*fn)(inumber); 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate if (atomic((int(*)())write, slp->sl_slavefd, (char *)slp->sl_req, 8020Sstevel@tonic-gate reqsiz) != reqsiz) { 8030Sstevel@tonic-gate cmdwrterr(); 8040Sstevel@tonic-gate dumpabort(); 8050Sstevel@tonic-gate /*NOTREACHED*/ 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate ++recsout; 8080Sstevel@tonic-gate nextslave(); 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate void 812*1053Smaheshvs dospcl(ino_t inumber) 8130Sstevel@tonic-gate { 8140Sstevel@tonic-gate /* LINTED for now, max inode # is 2**31 (ufs max size is 1TB) */ 8150Sstevel@tonic-gate spcl.c_inumber = (ino32_t)inumber; 8160Sstevel@tonic-gate slp->sl_req->br_dblk = 0; 8170Sstevel@tonic-gate bcopy((char *)&spcl, (char *)slp->sl_req->br_spcl, tp_bsize); 8180Sstevel@tonic-gate } 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate static void 8210Sstevel@tonic-gate #ifdef __STDC__ 8220Sstevel@tonic-gate nextslave(void) 8230Sstevel@tonic-gate #else 8240Sstevel@tonic-gate nextslave() 8250Sstevel@tonic-gate #endif 8260Sstevel@tonic-gate { 8270Sstevel@tonic-gate if (++rotor >= SLAVES) { 8280Sstevel@tonic-gate rotor = 0; 8290Sstevel@tonic-gate } 8300Sstevel@tonic-gate slp = &slaves[rotor]; 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate void 8340Sstevel@tonic-gate #ifdef __STDC__ 8350Sstevel@tonic-gate flushcmds(void) 8360Sstevel@tonic-gate #else 8370Sstevel@tonic-gate flushcmds() 8380Sstevel@tonic-gate #endif 8390Sstevel@tonic-gate { 8400Sstevel@tonic-gate int i; 8410Sstevel@tonic-gate int wasactive; 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate /* 8440Sstevel@tonic-gate * Retrieve all slave status 8450Sstevel@tonic-gate */ 8460Sstevel@tonic-gate if (recsout < SLAVES) { 8470Sstevel@tonic-gate slp = slaves; 8480Sstevel@tonic-gate rotor = 0; 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate for (i = 0; i < (recsout < SLAVES ? recsout : SLAVES); i++) { 8510Sstevel@tonic-gate if ((unsigned)atomic((int(*)())read, slp->sl_slavefd, 8520Sstevel@tonic-gate (char *)&wasactive, sizeof (wasactive)) != 8530Sstevel@tonic-gate sizeof (wasactive)) { 8540Sstevel@tonic-gate cmdrderr(); 8550Sstevel@tonic-gate dumpabort(); 8560Sstevel@tonic-gate /*NOTREACHED*/ 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate if (wasactive) { 8590Sstevel@tonic-gate active++; 8600Sstevel@tonic-gate msg(gettext( 8610Sstevel@tonic-gate "inode %d was active and will be recopied\n"), 8620Sstevel@tonic-gate slp->sl_req->ir_inumber); 8630Sstevel@tonic-gate /* LINTED: 32-bit to 8-bit assignment ok */ 8640Sstevel@tonic-gate BIS(slp->sl_req->ir_inumber, activemap); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate nextslave(); 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate } 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate void 8710Sstevel@tonic-gate #ifdef __STDC__ 8720Sstevel@tonic-gate flusht(void) 8730Sstevel@tonic-gate #else 8740Sstevel@tonic-gate flusht() 8750Sstevel@tonic-gate #endif 8760Sstevel@tonic-gate { 8770Sstevel@tonic-gate sigset_t block_set, oset; /* hold SIGUSR1 and atomically sleep */ 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate (void) sigemptyset(&block_set); 8800Sstevel@tonic-gate (void) sigaddset(&block_set, SIGUSR1); 8810Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &block_set, &oset); 8820Sstevel@tonic-gate (void) kill(writepid, SIGUSR1); /* tell writer to flush */ 8830Sstevel@tonic-gate (void) sigpause(SIGUSR1); /* wait for SIGUSR1 from writer */ 8840Sstevel@tonic-gate /*NOTREACHED*/ 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate jmp_buf checkpoint_buf; 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate /* 8900Sstevel@tonic-gate * Roll forward to the next volume after receiving 8910Sstevel@tonic-gate * an EOT signal from writer. Get checkpoint data 8920Sstevel@tonic-gate * from writer and return if done, otherwise fork 8930Sstevel@tonic-gate * a new process and jump back to main state loop 8940Sstevel@tonic-gate * to begin the next volume. Installed as the master's 8950Sstevel@tonic-gate * signal handler for SIGUSR1. 8960Sstevel@tonic-gate */ 8970Sstevel@tonic-gate /*ARGSUSED*/ 8980Sstevel@tonic-gate static void 899*1053Smaheshvs rollforward(int sig) 9000Sstevel@tonic-gate { 9010Sstevel@tonic-gate int status; 9020Sstevel@tonic-gate (void) sighold(SIGUSR1); 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate /* 9050Sstevel@tonic-gate * Writer sends us checkpoint information after 9060Sstevel@tonic-gate * each volume. A returned state of DS_DONE with no 9070Sstevel@tonic-gate * unwritten (left-over) records differentiates a 9080Sstevel@tonic-gate * clean flush from one in which EOT was encountered. 9090Sstevel@tonic-gate */ 9100Sstevel@tonic-gate if ((unsigned)atomic((int(*)())read, writer, (char *)&chkpt, 9110Sstevel@tonic-gate sizeof (struct slaves)) != sizeof (struct slaves)) { 9120Sstevel@tonic-gate cmdrderr(); 9130Sstevel@tonic-gate dumpabort(); 9140Sstevel@tonic-gate /*NOTREACHED*/ 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate if (atomic((int(*)())read, writer, (char *)&spcl, 9170Sstevel@tonic-gate TP_BSIZE_MIN) != TP_BSIZE_MIN) { 9180Sstevel@tonic-gate cmdrderr(); 9190Sstevel@tonic-gate dumpabort(); 9200Sstevel@tonic-gate /*NOTREACHED*/ 9210Sstevel@tonic-gate } 9220Sstevel@tonic-gate ino = chkpt.sl_inos - 1; 9230Sstevel@tonic-gate pos = chkpt.sl_offset; 9240Sstevel@tonic-gate leftover = chkpt.sl_count; 9250Sstevel@tonic-gate dumpstate = chkpt.sl_state; 9260Sstevel@tonic-gate blockswritten = ++chkpt.sl_tapea; 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate if (dumpstate == DS_DONE) { 9290Sstevel@tonic-gate if (archivepid) { 9300Sstevel@tonic-gate /* 9310Sstevel@tonic-gate * If archiving (either archive or 9320Sstevel@tonic-gate * database), signal the archiver 9330Sstevel@tonic-gate * to finish up. This must happen 9340Sstevel@tonic-gate * before the writer exits in order 9350Sstevel@tonic-gate * to avoid a race. 9360Sstevel@tonic-gate */ 9370Sstevel@tonic-gate (void) kill(archivepid, SIGUSR1); 9380Sstevel@tonic-gate } 9390Sstevel@tonic-gate (void) signal(SIGUSR1, SIG_IGN); 9400Sstevel@tonic-gate (void) sigrelse(SIGUSR1); 9410Sstevel@tonic-gate (void) kill(writepid, SIGUSR1); /* tell writer to exit */ 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate lf_archoffset = 0LL; 9440Sstevel@tonic-gate longjmp(checkpoint_buf, 1); 9450Sstevel@tonic-gate /*NOTREACHED*/ 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate if (leftover) { 9490Sstevel@tonic-gate (void) memmove(spcl.c_addr, 9500Sstevel@tonic-gate &spcl.c_addr[spcl.c_count-leftover], leftover); 9510Sstevel@tonic-gate bzero(&spcl.c_addr[leftover], TP_NINDIR-leftover); 9520Sstevel@tonic-gate } 9530Sstevel@tonic-gate if (writepid) { 9540Sstevel@tonic-gate (void) kill(writepid, SIGUSR1); /* tell writer to exit */ 9550Sstevel@tonic-gate (void) close(writer); 9560Sstevel@tonic-gate writer = -1; 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate if (archivepid) { 9590Sstevel@tonic-gate (void) waitpid(archivepid, &status, 0); /* wait for archiver */ 9600Sstevel@tonic-gate #ifdef TDEBUG 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 9630Sstevel@tonic-gate msg(gettext("Archiver %ld returns with status %d\n"), 9640Sstevel@tonic-gate (long)archivepid, status); 9650Sstevel@tonic-gate #endif 9660Sstevel@tonic-gate archivepid = 0; 9670Sstevel@tonic-gate } 9680Sstevel@tonic-gate /* 9690Sstevel@tonic-gate * Checkpoint archive file 9700Sstevel@tonic-gate */ 9710Sstevel@tonic-gate if (!doingverify && archive) { 9720Sstevel@tonic-gate lf_archoffset = lseek64(archivefd, (off64_t)0, 2); 9730Sstevel@tonic-gate if (lf_archoffset < 0) { 9740Sstevel@tonic-gate int saverr = errno; 9750Sstevel@tonic-gate msg(gettext("Cannot position archive file `%s': %s\n"), 9760Sstevel@tonic-gate archivefile, strerror(saverr)); 9770Sstevel@tonic-gate dumpabort(); 9780Sstevel@tonic-gate /*NOTREACHED*/ 9790Sstevel@tonic-gate } 9800Sstevel@tonic-gate (void) close(archivefd); 9810Sstevel@tonic-gate archivefd = -1; 9820Sstevel@tonic-gate } 9830Sstevel@tonic-gate resetino(ino); 9840Sstevel@tonic-gate 9850Sstevel@tonic-gate if (dumpstate == DS_START) { 9860Sstevel@tonic-gate msg(gettext( 9870Sstevel@tonic-gate "Tape too short: changing volumes and restarting\n")); 9880Sstevel@tonic-gate reset(); 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate if (!pipeout) { 9920Sstevel@tonic-gate if (verify && !doingverify) 9930Sstevel@tonic-gate trewind(); 9940Sstevel@tonic-gate else { 9950Sstevel@tonic-gate close_rewind(); 9960Sstevel@tonic-gate changevol(); 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate (void) sigrelse(SIGUSR1); 10010Sstevel@tonic-gate otape(0); 10020Sstevel@tonic-gate longjmp(checkpoint_buf, 1); 10030Sstevel@tonic-gate /*NOTREACHED*/ 10040Sstevel@tonic-gate } 10050Sstevel@tonic-gate 10060Sstevel@tonic-gate static void 1007*1053Smaheshvs nap(int ms) 10080Sstevel@tonic-gate { 10090Sstevel@tonic-gate struct timeval tv; 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate tv.tv_sec = ms / 1000; 10120Sstevel@tonic-gate tv.tv_usec = (ms - tv.tv_sec * 1000) * 1000; 10130Sstevel@tonic-gate (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv); 10140Sstevel@tonic-gate } 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate static jmp_buf alrm_buf; 10170Sstevel@tonic-gate 10180Sstevel@tonic-gate /*ARGSUSED*/ 10190Sstevel@tonic-gate static void 1020*1053Smaheshvs alrm(int sig) 10210Sstevel@tonic-gate { 10220Sstevel@tonic-gate longjmp(alrm_buf, 1); 10230Sstevel@tonic-gate /*NOTREACHED*/ 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate void 10270Sstevel@tonic-gate #ifdef __STDC__ 10280Sstevel@tonic-gate nextdevice(void) 10290Sstevel@tonic-gate #else 10300Sstevel@tonic-gate nextdevice() 10310Sstevel@tonic-gate #endif 10320Sstevel@tonic-gate { 10330Sstevel@tonic-gate char *cp; 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate if (host != NULL) /* we set the host only once in ufsdump */ 10360Sstevel@tonic-gate return; 10370Sstevel@tonic-gate 10380Sstevel@tonic-gate host = NULL; 10390Sstevel@tonic-gate if (strchr(tape, ':')) { 10400Sstevel@tonic-gate if (diskette) { 10410Sstevel@tonic-gate msg(gettext("Cannot do remote dump to diskette\n")); 10420Sstevel@tonic-gate Exit(X_ABORT); 10430Sstevel@tonic-gate } 10440Sstevel@tonic-gate host = tape; 10450Sstevel@tonic-gate tape = strchr(host, ':'); 10460Sstevel@tonic-gate *tape++ = 0; 10470Sstevel@tonic-gate cp = strchr(host, '@'); /* user@host? */ 10480Sstevel@tonic-gate if (cp != (char *)0) 10490Sstevel@tonic-gate cp++; 10500Sstevel@tonic-gate else 10510Sstevel@tonic-gate cp = host; 10520Sstevel@tonic-gate } else 10530Sstevel@tonic-gate cp = spcl.c_host; 10540Sstevel@tonic-gate /* 10550Sstevel@tonic-gate * dumpdev is provided for use in prompts and is of 10560Sstevel@tonic-gate * the form: 10570Sstevel@tonic-gate * hostname:device 10580Sstevel@tonic-gate * sdumpdev is of the form: 10590Sstevel@tonic-gate * hostname:device 10600Sstevel@tonic-gate * for remote devices, and simply: 10610Sstevel@tonic-gate * device 10620Sstevel@tonic-gate * for local devices. 10630Sstevel@tonic-gate */ 10640Sstevel@tonic-gate if (dumpdev != (char *)NULL) { 10650Sstevel@tonic-gate /* LINTED: dumpdev is not NULL */ 10660Sstevel@tonic-gate free(dumpdev); 10670Sstevel@tonic-gate } 10680Sstevel@tonic-gate /*LINTED [cast to smaller integer]*/ 10690Sstevel@tonic-gate dumpdev = xmalloc((size_t)((sizeof (spcl.c_host) + strlen(tape) + 2))); 10700Sstevel@tonic-gate /* LINTED unsigned -> signed cast ok */ 10710Sstevel@tonic-gate (void) sprintf(dumpdev, "%.*s:%s", (int)sizeof (spcl.c_host), cp, tape); 10720Sstevel@tonic-gate if (cp == spcl.c_host) 10730Sstevel@tonic-gate sdumpdev = strchr(dumpdev, ':') + 1; 10740Sstevel@tonic-gate else 10750Sstevel@tonic-gate sdumpdev = dumpdev; 10760Sstevel@tonic-gate } 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate /* 10790Sstevel@tonic-gate * Gross hack due to misfeature of mt tape driver that causes 10800Sstevel@tonic-gate * the device to rewind if we generate any signals. Guess 10810Sstevel@tonic-gate * whether tape is rewind device or not -- for local devices 10820Sstevel@tonic-gate * we can just look at the minor number. For rmt devices, 10830Sstevel@tonic-gate * make an educated guess. 10840Sstevel@tonic-gate */ 10850Sstevel@tonic-gate int 1086*1053Smaheshvs isrewind(int f) 10870Sstevel@tonic-gate { 10880Sstevel@tonic-gate struct stat64 sbuf; 10890Sstevel@tonic-gate char *c; 10900Sstevel@tonic-gate int unit; 10910Sstevel@tonic-gate int rewind; 10920Sstevel@tonic-gate 10930Sstevel@tonic-gate if (host) { 10940Sstevel@tonic-gate c = strrchr(tape, '/'); 10950Sstevel@tonic-gate if (c == NULL) 10960Sstevel@tonic-gate c = tape; 10970Sstevel@tonic-gate else 10980Sstevel@tonic-gate c++; 10990Sstevel@tonic-gate /* 11000Sstevel@tonic-gate * If the last component begins or ends with an 'n', it is 11010Sstevel@tonic-gate * assumed to be a non-rewind device. 11020Sstevel@tonic-gate */ 11030Sstevel@tonic-gate if (c[0] == 'n' || c[strlen(c)-1] == 'n') 11040Sstevel@tonic-gate rewind = 0; 11050Sstevel@tonic-gate else if ((strstr(tape, "mt") || strstr(tape, "st")) && 11060Sstevel@tonic-gate sscanf(tape, "%*[a-zA-Z/]%d", &unit) == 1 && 11070Sstevel@tonic-gate (unit & MT_NOREWIND)) 11080Sstevel@tonic-gate rewind = 0; 11090Sstevel@tonic-gate else 11100Sstevel@tonic-gate rewind = 1; 11110Sstevel@tonic-gate } else { 11120Sstevel@tonic-gate if (fstat64(f, &sbuf) < 0) { 11130Sstevel@tonic-gate msg(gettext( 11140Sstevel@tonic-gate "Cannot obtain status of output device `%s'\n"), 11150Sstevel@tonic-gate tape); 11160Sstevel@tonic-gate dumpabort(); 11170Sstevel@tonic-gate /*NOTREACHED*/ 11180Sstevel@tonic-gate } 11190Sstevel@tonic-gate rewind = minor(sbuf.st_rdev) & MT_NOREWIND ? 0 : 1; 11200Sstevel@tonic-gate } 11210Sstevel@tonic-gate return (rewind); 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate static void 11250Sstevel@tonic-gate #ifdef __STDC__ 11260Sstevel@tonic-gate just_rewind(void) 11270Sstevel@tonic-gate #else 11280Sstevel@tonic-gate just_rewind() 11290Sstevel@tonic-gate #endif 11300Sstevel@tonic-gate { 11310Sstevel@tonic-gate struct slaves *slavep; 11320Sstevel@tonic-gate char *rewinding = gettext("Tape rewinding\n"); 11330Sstevel@tonic-gate 11340Sstevel@tonic-gate for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) { 11350Sstevel@tonic-gate if (slavep->sl_slavepid > 0) /* signal normal exit */ 11360Sstevel@tonic-gate (void) kill(slavep->sl_slavepid, SIGTERM); 11370Sstevel@tonic-gate if (slavep->sl_slavefd >= 0) { 11380Sstevel@tonic-gate (void) close(slavep->sl_slavefd); 11390Sstevel@tonic-gate slavep->sl_slavefd = -1; 11400Sstevel@tonic-gate } 11410Sstevel@tonic-gate } 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate /* wait for any signals from slaves */ 11440Sstevel@tonic-gate while (waitpid(0, (int *)0, 0) >= 0) 11450Sstevel@tonic-gate /*LINTED [empty body]*/ 11460Sstevel@tonic-gate continue; 11470Sstevel@tonic-gate 11480Sstevel@tonic-gate if (pipeout) 11490Sstevel@tonic-gate return; 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate if (doingverify) { 11520Sstevel@tonic-gate /* 11530Sstevel@tonic-gate * Space to the end of the tape. 11540Sstevel@tonic-gate * Backup first in case we already read the EOF. 11550Sstevel@tonic-gate */ 11560Sstevel@tonic-gate if (host) { 11570Sstevel@tonic-gate (void) rmtioctl(MTBSR, 1); 11580Sstevel@tonic-gate if (rmtioctl(MTEOM, 1) < 0) 11590Sstevel@tonic-gate (void) rmtioctl(MTFSF, 1); 11600Sstevel@tonic-gate } else { 11610Sstevel@tonic-gate static struct mtop bsr = { MTBSR, 1 }; 11620Sstevel@tonic-gate static struct mtop eom = { MTEOM, 1 }; 11630Sstevel@tonic-gate static struct mtop fsf = { MTFSF, 1 }; 11640Sstevel@tonic-gate 11650Sstevel@tonic-gate (void) ioctl(to, MTIOCTOP, &bsr); 11660Sstevel@tonic-gate if (ioctl(to, MTIOCTOP, &eom) < 0) 11670Sstevel@tonic-gate (void) ioctl(to, MTIOCTOP, &fsf); 11680Sstevel@tonic-gate } 11690Sstevel@tonic-gate } 11700Sstevel@tonic-gate 11710Sstevel@tonic-gate /* 11720Sstevel@tonic-gate * Guess whether the tape is rewinding so we can tell 11730Sstevel@tonic-gate * the operator if it's going to take a long time. 11740Sstevel@tonic-gate */ 11750Sstevel@tonic-gate if (tapeout && isrewind(to)) { 11760Sstevel@tonic-gate /* tape is probably rewinding */ 11770Sstevel@tonic-gate msg(rewinding); 11780Sstevel@tonic-gate } 11790Sstevel@tonic-gate } 11800Sstevel@tonic-gate 11810Sstevel@tonic-gate void 11820Sstevel@tonic-gate #ifdef __STDC__ 11830Sstevel@tonic-gate trewind(void) 11840Sstevel@tonic-gate #else 11850Sstevel@tonic-gate trewind() 11860Sstevel@tonic-gate #endif 11870Sstevel@tonic-gate { 11880Sstevel@tonic-gate (void) timeclock((time_t)0); 11890Sstevel@tonic-gate if (offline && (!verify || doingverify)) { 11900Sstevel@tonic-gate close_rewind(); 11910Sstevel@tonic-gate } else { 11920Sstevel@tonic-gate just_rewind(); 11930Sstevel@tonic-gate if (host) 11940Sstevel@tonic-gate rmtclose(); 11950Sstevel@tonic-gate else { 11960Sstevel@tonic-gate (void) close(to); 11970Sstevel@tonic-gate to = -1; 11980Sstevel@tonic-gate } 11990Sstevel@tonic-gate } 12000Sstevel@tonic-gate } 12010Sstevel@tonic-gate 12020Sstevel@tonic-gate void 12030Sstevel@tonic-gate #ifdef __STDC__ 12040Sstevel@tonic-gate close_rewind(void) 12050Sstevel@tonic-gate #else 12060Sstevel@tonic-gate close_rewind() 12070Sstevel@tonic-gate #endif 12080Sstevel@tonic-gate { 12090Sstevel@tonic-gate char *rewinding = gettext("Tape rewinding\n"); 12100Sstevel@tonic-gate 12110Sstevel@tonic-gate (void) timeclock((time_t)0); 12120Sstevel@tonic-gate just_rewind(); 12130Sstevel@tonic-gate /* 12140Sstevel@tonic-gate * The check in just_rewind won't catch the case in 12150Sstevel@tonic-gate * which the current volume is being taken off-line 12160Sstevel@tonic-gate * and is not mounted on a no-rewind device (and is 12170Sstevel@tonic-gate * not the last volume, which is not taken off-line). 12180Sstevel@tonic-gate */ 12190Sstevel@tonic-gate if (tapeout && !isrewind(to) && offline) { 12200Sstevel@tonic-gate /* tape is probably rewinding */ 12210Sstevel@tonic-gate msg(rewinding); 12220Sstevel@tonic-gate } 12230Sstevel@tonic-gate if (host) { 12240Sstevel@tonic-gate if (offline || autoload) 12250Sstevel@tonic-gate (void) rmtioctl(MTOFFL, 0); 12260Sstevel@tonic-gate rmtclose(); 12270Sstevel@tonic-gate } else { 12280Sstevel@tonic-gate if (offline || autoload) { 12290Sstevel@tonic-gate static struct mtop offl = { MTOFFL, 0 }; 12300Sstevel@tonic-gate 12310Sstevel@tonic-gate (void) ioctl(to, MTIOCTOP, &offl); 12320Sstevel@tonic-gate if (diskette) 12330Sstevel@tonic-gate (void) ioctl(to, FDEJECT, 0); 12340Sstevel@tonic-gate } 12350Sstevel@tonic-gate (void) close(to); 12360Sstevel@tonic-gate to = -1; 12370Sstevel@tonic-gate } 12380Sstevel@tonic-gate } 12390Sstevel@tonic-gate 12400Sstevel@tonic-gate void 12410Sstevel@tonic-gate #ifdef __STDC__ 12420Sstevel@tonic-gate changevol(void) 12430Sstevel@tonic-gate #else 12440Sstevel@tonic-gate changevol() 12450Sstevel@tonic-gate #endif 12460Sstevel@tonic-gate { 12470Sstevel@tonic-gate char buf1[3000], buf2[3000]; 12480Sstevel@tonic-gate char volname[LBLSIZE+1]; 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate /*CONSTANTCONDITION*/ 12510Sstevel@tonic-gate assert(sizeof (spcl.c_label) < sizeof (volname)); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate filenum = 1; 12540Sstevel@tonic-gate nextdevice(); 12550Sstevel@tonic-gate (void) strcpy(spcl.c_label, tlabel); 12560Sstevel@tonic-gate if (host) { 12570Sstevel@tonic-gate char *rhost = host; 12580Sstevel@tonic-gate char *cp = strchr(host, '@'); 12590Sstevel@tonic-gate if (cp == (char *)0) 12600Sstevel@tonic-gate cp = host; 12610Sstevel@tonic-gate else 12620Sstevel@tonic-gate cp++; 12630Sstevel@tonic-gate 12640Sstevel@tonic-gate if (rmthost(rhost, ntrec) == 0) { 12650Sstevel@tonic-gate msg(gettext("Cannot connect to tape host `%s'\n"), cp); 12660Sstevel@tonic-gate dumpabort(); 12670Sstevel@tonic-gate /*NOTREACHED*/ 12680Sstevel@tonic-gate } 12690Sstevel@tonic-gate if (rhost != host) 12700Sstevel@tonic-gate free(rhost); 12710Sstevel@tonic-gate } 12720Sstevel@tonic-gate 12730Sstevel@tonic-gate /* 12740Sstevel@tonic-gate * Make volume switching as automatic as possible 12750Sstevel@tonic-gate * while avoiding overwriting volumes. We will 12760Sstevel@tonic-gate * switch automatically under the following condition: 12770Sstevel@tonic-gate * 1) The user specified autoloading from the 12780Sstevel@tonic-gate * command line. 12790Sstevel@tonic-gate * At one time, we (in the guise of hsmdump) had the 12800Sstevel@tonic-gate * concept of a sequence of devices to rotate through, 12810Sstevel@tonic-gate * but that's never been a ufsdump feature. 12820Sstevel@tonic-gate */ 12830Sstevel@tonic-gate if (autoload) { 12840Sstevel@tonic-gate int tries; 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate /* 12870Sstevel@tonic-gate * Stop the clock for throughput calculations. 12880Sstevel@tonic-gate */ 12890Sstevel@tonic-gate if ((telapsed != NULL) && (tstart_writing != NULL)) { 12900Sstevel@tonic-gate *telapsed += time((time_t *)NULL) - *tstart_writing; 12910Sstevel@tonic-gate } 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate (void) snprintf(volname, sizeof (volname), "#%d", tapeno+1); 12940Sstevel@tonic-gate (void) snprintf(buf1, sizeof (buf1), gettext( 12950Sstevel@tonic-gate "Mounting volume %s on %s\n"), volname, dumpdev); 12960Sstevel@tonic-gate msg(buf1); 12970Sstevel@tonic-gate broadcast(buf1); 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate /* 13000Sstevel@tonic-gate * Wait for the tape to autoload. Note that the delay 13010Sstevel@tonic-gate * period doesn't take into account however long it takes 13020Sstevel@tonic-gate * for the open to fail (measured at 21 seconds for an 13030Sstevel@tonic-gate * Exabyte 8200 under 2.7 on an Ultra 2). 13040Sstevel@tonic-gate */ 13050Sstevel@tonic-gate for (tries = 0; tries < autoload_tries; tries++) { 13060Sstevel@tonic-gate if (host) { 13070Sstevel@tonic-gate if (rmtopen(tape, O_RDONLY) >= 0) { 13080Sstevel@tonic-gate rmtclose(); 13090Sstevel@tonic-gate return; 13100Sstevel@tonic-gate } 13110Sstevel@tonic-gate } else { 13120Sstevel@tonic-gate int f, m; 13130Sstevel@tonic-gate 13140Sstevel@tonic-gate m = (access(tape, F_OK) == 0) ? 0 : O_CREAT; 13150Sstevel@tonic-gate if ((f = doingverify ? 13160Sstevel@tonic-gate safe_device_open(tape, O_RDONLY, 0600) : 13170Sstevel@tonic-gate safe_device_open(tape, O_RDONLY|m, 0600)) 13180Sstevel@tonic-gate >= 0) { 13190Sstevel@tonic-gate (void) close(f); 13200Sstevel@tonic-gate return; 13210Sstevel@tonic-gate } 13220Sstevel@tonic-gate } 13230Sstevel@tonic-gate (void) sleep(autoload_period); 13240Sstevel@tonic-gate } 13250Sstevel@tonic-gate /* 13260Sstevel@tonic-gate * Autoload timed out, ask the operator to do it. 13270Sstevel@tonic-gate * Note that query() will update *telapsed, and we 13280Sstevel@tonic-gate * shouldn't charge for the autoload time. So, since 13290Sstevel@tonic-gate * we updated *telapsed ourselves above, we just set 13300Sstevel@tonic-gate * tstart_writing to the current time, and query() 13310Sstevel@tonic-gate * will end up making a null-effect change. This, 13320Sstevel@tonic-gate * of course, assumes that our caller will be resetting 13330Sstevel@tonic-gate * *tstart_writing. This is currently the case. 13340Sstevel@tonic-gate * If tstart_writing is NULL (should never happen), 13350Sstevel@tonic-gate * we're ok, since time(2) will accept a NULL pointer. 13360Sstevel@tonic-gate */ 13370Sstevel@tonic-gate (void) time(tstart_writing); 13380Sstevel@tonic-gate } 13390Sstevel@tonic-gate 13400Sstevel@tonic-gate if (strncmp(spcl.c_label, "none", 5)) { 13410Sstevel@tonic-gate (void) strncpy(volname, spcl.c_label, sizeof (spcl.c_label)); 13420Sstevel@tonic-gate volname[sizeof (spcl.c_label)] = '\0'; 13430Sstevel@tonic-gate } else 13440Sstevel@tonic-gate (void) snprintf(volname, sizeof (volname), "#%d", tapeno+1); 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate timeest(1, spcl.c_tapea); 13470Sstevel@tonic-gate (void) snprintf(buf1, sizeof (buf1), gettext( 13480Sstevel@tonic-gate "Change Volumes: Mount volume `%s' on `%s'\n"), volname, dumpdev); 13490Sstevel@tonic-gate msg(buf1); 13500Sstevel@tonic-gate broadcast(gettext("CHANGE VOLUMES!\7\7\n")); 13510Sstevel@tonic-gate (void) snprintf(buf1, sizeof (buf1), gettext( 13520Sstevel@tonic-gate "Is the new volume (%s) mounted on `%s' and ready to go?: %s"), 13530Sstevel@tonic-gate volname, dumpdev, gettext("(\"yes\" or \"no\") ")); 13540Sstevel@tonic-gate while (!query(buf1)) { 13550Sstevel@tonic-gate (void) snprintf(buf2, sizeof (buf2), gettext( 13560Sstevel@tonic-gate "Do you want to abort dump?: (\"yes\" or \"no\") ")); 13570Sstevel@tonic-gate if (query(buf2)) { 13580Sstevel@tonic-gate dumpabort(); 13590Sstevel@tonic-gate /*NOTREACHED*/ 13600Sstevel@tonic-gate } 13610Sstevel@tonic-gate } 13620Sstevel@tonic-gate } 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate /* 13650Sstevel@tonic-gate * We implement taking and restoring checkpoints on the tape level. 13660Sstevel@tonic-gate * When each tape is opened, a new process is created by forking; this 13670Sstevel@tonic-gate * saves all of the necessary context in the parent. The child 13680Sstevel@tonic-gate * continues the dump; the parent waits around, saving the context. 13690Sstevel@tonic-gate * If the child returns X_REWRITE, then it had problems writing that tape; 13700Sstevel@tonic-gate * this causes the parent to fork again, duplicating the context, and 13710Sstevel@tonic-gate * everything continues as if nothing had happened. 13720Sstevel@tonic-gate */ 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate void 1375*1053Smaheshvs otape(int top) 13760Sstevel@tonic-gate { 13770Sstevel@tonic-gate static struct mtget mt; 13780Sstevel@tonic-gate char buf[3000]; 13790Sstevel@tonic-gate pid_t parentpid; 13800Sstevel@tonic-gate pid_t childpid; 13810Sstevel@tonic-gate pid_t waitproc; 13820Sstevel@tonic-gate int status; 13830Sstevel@tonic-gate struct sigvec sv, osv; 13840Sstevel@tonic-gate 13850Sstevel@tonic-gate sv.sv_flags = SA_RESTART; 13860Sstevel@tonic-gate (void) sigemptyset(&sv.sa_mask); 13870Sstevel@tonic-gate sv.sv_handler = SIG_IGN; 13880Sstevel@tonic-gate (void) sigvec(SIGINT, &sv, (struct sigvec *)0); 13890Sstevel@tonic-gate 13900Sstevel@tonic-gate parentpid = getpid(); 13910Sstevel@tonic-gate 13920Sstevel@tonic-gate if (verify) { 13930Sstevel@tonic-gate if (doingverify) 13940Sstevel@tonic-gate doingverify = 0; 13950Sstevel@tonic-gate else 13960Sstevel@tonic-gate Exit(X_VERIFY); 13970Sstevel@tonic-gate } 13980Sstevel@tonic-gate restore_check_point: 13990Sstevel@tonic-gate 14000Sstevel@tonic-gate sv.sv_handler = interrupt; 14010Sstevel@tonic-gate (void) sigvec(SIGINT, &sv, (struct sigvec *)0); 14020Sstevel@tonic-gate (void) fflush(stderr); 14030Sstevel@tonic-gate /* 14040Sstevel@tonic-gate * All signals are inherited... 14050Sstevel@tonic-gate */ 14060Sstevel@tonic-gate sighold(SIGINT); 14070Sstevel@tonic-gate childpid = fork(); 14080Sstevel@tonic-gate if (childpid < 0) { 14090Sstevel@tonic-gate msg(gettext( 14100Sstevel@tonic-gate "Context-saving fork failed in parent %ld\n"), 14110Sstevel@tonic-gate (long)parentpid); 14120Sstevel@tonic-gate Exit(X_ABORT); 14130Sstevel@tonic-gate } 14140Sstevel@tonic-gate if (childpid != 0) { 14150Sstevel@tonic-gate /* 14160Sstevel@tonic-gate * PARENT: 14170Sstevel@tonic-gate * save the context by waiting 14180Sstevel@tonic-gate * until the child doing all of the work returns. 14190Sstevel@tonic-gate * let the child catch user interrupts 14200Sstevel@tonic-gate */ 14210Sstevel@tonic-gate sv.sv_handler = SIG_IGN; 14220Sstevel@tonic-gate (void) sigvec(SIGINT, &sv, (struct sigvec *)0); 14230Sstevel@tonic-gate sigrelse(SIGINT); 14240Sstevel@tonic-gate #ifdef TDEBUG 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 14270Sstevel@tonic-gate msg(gettext( 14280Sstevel@tonic-gate "Volume: %d; parent process: %ld child process %ld\n"), 14290Sstevel@tonic-gate tapeno+1, (long)parentpid, (long)childpid); 14300Sstevel@tonic-gate #endif /* TDEBUG */ 14310Sstevel@tonic-gate for (;;) { 14320Sstevel@tonic-gate waitproc = waitpid(0, &status, 0); 14330Sstevel@tonic-gate if (waitproc == childpid) 14340Sstevel@tonic-gate break; 14350Sstevel@tonic-gate msg(gettext( 14360Sstevel@tonic-gate "Parent %ld waiting for child %ld had another child %ld return\n"), 14370Sstevel@tonic-gate (long)parentpid, (long)childpid, (long)waitproc); 14380Sstevel@tonic-gate } 14390Sstevel@tonic-gate if (WIFSIGNALED(status)) { 14400Sstevel@tonic-gate msg(gettext("Process %ld killed by signal %d: %s\n"), 14410Sstevel@tonic-gate (long)childpid, WTERMSIG(status), 14420Sstevel@tonic-gate strsignal(WTERMSIG(status))); 14430Sstevel@tonic-gate status = X_ABORT; 14440Sstevel@tonic-gate } else 14450Sstevel@tonic-gate status = WEXITSTATUS(status); 14460Sstevel@tonic-gate #ifdef TDEBUG 14470Sstevel@tonic-gate switch (status) { 14480Sstevel@tonic-gate case X_FINOK: 14490Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 14500Sstevel@tonic-gate msg(gettext( 14510Sstevel@tonic-gate "Child %ld finishes X_FINOK\n"), (long)childpid); 14520Sstevel@tonic-gate break; 14530Sstevel@tonic-gate case X_ABORT: 14540Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 14550Sstevel@tonic-gate msg(gettext( 14560Sstevel@tonic-gate "Child %ld finishes X_ABORT\n"), (long)childpid); 14570Sstevel@tonic-gate break; 14580Sstevel@tonic-gate case X_REWRITE: 14590Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 14600Sstevel@tonic-gate msg(gettext( 14610Sstevel@tonic-gate "Child %ld finishes X_REWRITE\n"), (long)childpid); 14620Sstevel@tonic-gate break; 14630Sstevel@tonic-gate case X_RESTART: 14640Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 14650Sstevel@tonic-gate msg(gettext( 14660Sstevel@tonic-gate "Child %ld finishes X_RESTART\n"), (long)childpid); 14670Sstevel@tonic-gate break; 14680Sstevel@tonic-gate case X_VERIFY: 14690Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 14700Sstevel@tonic-gate msg(gettext( 14710Sstevel@tonic-gate "Child %ld finishes X_VERIFY\n"), (long)childpid); 14720Sstevel@tonic-gate break; 14730Sstevel@tonic-gate default: 14740Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 14750Sstevel@tonic-gate msg(gettext("Child %ld finishes unknown %d\n"), 14760Sstevel@tonic-gate (long)childpid, status); 14770Sstevel@tonic-gate break; 14780Sstevel@tonic-gate } 14790Sstevel@tonic-gate #endif /* TDEBUG */ 14800Sstevel@tonic-gate switch (status) { 14810Sstevel@tonic-gate case X_FINOK: 14820Sstevel@tonic-gate /* wait for children */ 14830Sstevel@tonic-gate while (waitpid(0, (int *)0, 0) >= 0) 14840Sstevel@tonic-gate /*LINTED [empty body]*/ 14850Sstevel@tonic-gate continue; 14860Sstevel@tonic-gate Exit(X_FINOK); 14870Sstevel@tonic-gate /*NOTREACHED*/ 14880Sstevel@tonic-gate case X_ABORT: 14890Sstevel@tonic-gate Exit(X_ABORT); 14900Sstevel@tonic-gate /*NOTREACHED*/ 14910Sstevel@tonic-gate case X_VERIFY: 14920Sstevel@tonic-gate doingverify++; 14930Sstevel@tonic-gate goto restore_check_point; 14940Sstevel@tonic-gate /*NOTREACHED*/ 14950Sstevel@tonic-gate case X_REWRITE: 14960Sstevel@tonic-gate doingverify = 0; 14970Sstevel@tonic-gate changevol(); 14980Sstevel@tonic-gate goto restore_check_point; 14990Sstevel@tonic-gate /* NOTREACHED */ 15000Sstevel@tonic-gate case X_RESTART: 15010Sstevel@tonic-gate doingverify = 0; 15020Sstevel@tonic-gate if (!top) { 15030Sstevel@tonic-gate Exit(X_RESTART); 15040Sstevel@tonic-gate } 15050Sstevel@tonic-gate if (!offline) 15060Sstevel@tonic-gate autoload = 0; 15070Sstevel@tonic-gate changevol(); 15080Sstevel@tonic-gate sv.sv_handler = interrupt; 15090Sstevel@tonic-gate (void) sigvec(SIGINT, &sv, (struct sigvec *)0); 15100Sstevel@tonic-gate return; 15110Sstevel@tonic-gate /* NOTREACHED */ 15120Sstevel@tonic-gate default: 15130Sstevel@tonic-gate msg(gettext("Bad return code from dump: %d\n"), status); 15140Sstevel@tonic-gate Exit(X_ABORT); 15150Sstevel@tonic-gate /*NOTREACHED*/ 15160Sstevel@tonic-gate } 15170Sstevel@tonic-gate /*NOTREACHED*/ 15180Sstevel@tonic-gate } else { /* we are the child; just continue */ 15190Sstevel@tonic-gate child_chdir(); 15200Sstevel@tonic-gate sigrelse(SIGINT); 15210Sstevel@tonic-gate #ifdef TDEBUG 15220Sstevel@tonic-gate (void) sleep(4); /* time for parent's message to get out */ 15230Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 15240Sstevel@tonic-gate msg(gettext( 15250Sstevel@tonic-gate "Child on Volume %d has parent %ld, my pid = %ld\n"), 15260Sstevel@tonic-gate tapeno+1, (long)parentpid, (long)getpid()); 15270Sstevel@tonic-gate #endif 15280Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext( 15290Sstevel@tonic-gate "Cannot open `%s'. Do you want to retry the open?: (\"yes\" or \"no\") "), 15300Sstevel@tonic-gate dumpdev); 15310Sstevel@tonic-gate if (doingverify) { 15320Sstevel@tonic-gate /* 1 for stdout */ 15330Sstevel@tonic-gate while ((to = host ? rmtopen(tape, O_RDONLY) : 15340Sstevel@tonic-gate pipeout ? 1 : 15350Sstevel@tonic-gate safe_device_open(tape, O_RDONLY, 0600)) < 0) { 15360Sstevel@tonic-gate perror(tape); 15370Sstevel@tonic-gate if (autoload) { 15380Sstevel@tonic-gate if (!query_once(buf, 1)) { 15390Sstevel@tonic-gate dumpabort(); 15400Sstevel@tonic-gate /*NOTREACHED*/ 15410Sstevel@tonic-gate } 15420Sstevel@tonic-gate } else { 15430Sstevel@tonic-gate if (!query(buf)) { 15440Sstevel@tonic-gate dumpabort(); 15450Sstevel@tonic-gate /*NOTREACHED*/ 15460Sstevel@tonic-gate } 15470Sstevel@tonic-gate } 15480Sstevel@tonic-gate } 15490Sstevel@tonic-gate 15500Sstevel@tonic-gate /* 15510Sstevel@tonic-gate * If we're using the non-rewinding tape device, 15520Sstevel@tonic-gate * the tape will be left positioned after the 15530Sstevel@tonic-gate * EOF mark. We need to back up to the beginning 15540Sstevel@tonic-gate * of this tape file (cross two tape marks in the 15550Sstevel@tonic-gate * reverse direction and one in the forward 15560Sstevel@tonic-gate * direction) before the verify pass. 15570Sstevel@tonic-gate */ 15580Sstevel@tonic-gate if (host) { 15590Sstevel@tonic-gate if (rmtioctl(MTBSF, 2) >= 0) 15600Sstevel@tonic-gate (void) rmtioctl(MTFSF, 1); 15610Sstevel@tonic-gate else 15620Sstevel@tonic-gate (void) rmtioctl(MTNBSF, 1); 15630Sstevel@tonic-gate } else { 15640Sstevel@tonic-gate static struct mtop bsf = { MTBSF, 2 }; 15650Sstevel@tonic-gate static struct mtop fsf = { MTFSF, 1 }; 15660Sstevel@tonic-gate static struct mtop nbsf = { MTNBSF, 1 }; 15670Sstevel@tonic-gate 15680Sstevel@tonic-gate if (ioctl(to, MTIOCTOP, &bsf) >= 0) 15690Sstevel@tonic-gate (void) ioctl(to, MTIOCTOP, &fsf); 15700Sstevel@tonic-gate else 15710Sstevel@tonic-gate (void) ioctl(to, MTIOCTOP, &nbsf); 15720Sstevel@tonic-gate } 15730Sstevel@tonic-gate } else { 15740Sstevel@tonic-gate /* 15750Sstevel@tonic-gate * XXX Add logic to test for "tape" being a 15760Sstevel@tonic-gate * XXX device or a non-existent file. 15770Sstevel@tonic-gate * Current behaviour is that it must exist, 15780Sstevel@tonic-gate * and we over-write whatever's there. 15790Sstevel@tonic-gate * This can be bad if tape == "/etc/passwd". 15800Sstevel@tonic-gate */ 15810Sstevel@tonic-gate if (!pipeout && doposition && (tapeno == 0)) { 15820Sstevel@tonic-gate positiontape(buf); 15830Sstevel@tonic-gate if (setjmp(alrm_buf)) { 15840Sstevel@tonic-gate /* 15850Sstevel@tonic-gate * The tape is rewinding; 15860Sstevel@tonic-gate * we're screwed. 15870Sstevel@tonic-gate */ 15880Sstevel@tonic-gate msg(gettext( 15890Sstevel@tonic-gate "Cannot position tape using rewind device!\n")); 15900Sstevel@tonic-gate dumpabort(); 15910Sstevel@tonic-gate /*NOTREACHED*/ 15920Sstevel@tonic-gate } else { 15930Sstevel@tonic-gate sv.sv_handler = alrm; 15940Sstevel@tonic-gate (void) sigvec(SIGALRM, &sv, &osv); 15950Sstevel@tonic-gate (void) alarm(15); 15960Sstevel@tonic-gate } 15970Sstevel@tonic-gate while ((to = host ? rmtopen(tape, O_WRONLY) : 15980Sstevel@tonic-gate safe_device_open(tape, O_WRONLY, 0600)) < 0) 15990Sstevel@tonic-gate (void) sleep(10); 16000Sstevel@tonic-gate (void) alarm(0); 16010Sstevel@tonic-gate (void) sigvec(SIGALRM, &osv, 16020Sstevel@tonic-gate (struct sigvec *)0); 16030Sstevel@tonic-gate } else { 16040Sstevel@tonic-gate int m; 16050Sstevel@tonic-gate m = (access(tape, F_OK) == 0) ? 0 : O_CREAT; 16060Sstevel@tonic-gate /* 16070Sstevel@tonic-gate * Only verify the tape label if label 16080Sstevel@tonic-gate * verification is on and we are at BOT 16090Sstevel@tonic-gate */ 16100Sstevel@tonic-gate if (pipeout) 16110Sstevel@tonic-gate to = 1; 16120Sstevel@tonic-gate else while ((to = host ? 16130Sstevel@tonic-gate rmtopen(tape, O_WRONLY) : 16140Sstevel@tonic-gate safe_device_open(tape, O_WRONLY|m, 0600)) 16150Sstevel@tonic-gate < 0) 16160Sstevel@tonic-gate if (!query_once(buf, 1)) { 16170Sstevel@tonic-gate dumpabort(); 16180Sstevel@tonic-gate /*NOTREACHED*/ 16190Sstevel@tonic-gate } 16200Sstevel@tonic-gate } 16210Sstevel@tonic-gate } 16220Sstevel@tonic-gate if (!pipeout) { 16230Sstevel@tonic-gate tapeout = host ? rmtstatus(&mt) >= 0 : 16240Sstevel@tonic-gate ioctl(to, MTIOCGET, &mt) >= 0; /* set state */ 16250Sstevel@tonic-gate /* 16260Sstevel@tonic-gate * Make sure the tape is positioned 16270Sstevel@tonic-gate * where it is supposed to be 16280Sstevel@tonic-gate */ 16290Sstevel@tonic-gate if (tapeout && (tapeno > 0) && 16300Sstevel@tonic-gate (mt.mt_fileno != (filenum-1))) { 16310Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), gettext( 16320Sstevel@tonic-gate "Warning - tape positioning error!\n\ 16330Sstevel@tonic-gate \t%s current file %ld, should be %ld\n"), 16340Sstevel@tonic-gate tape, mt.mt_fileno+1, filenum); 16350Sstevel@tonic-gate msg(buf); 16360Sstevel@tonic-gate dumpailing(); 16370Sstevel@tonic-gate } 16380Sstevel@tonic-gate } 16390Sstevel@tonic-gate tapeno++; /* current tape sequence */ 16400Sstevel@tonic-gate if (tapeno < TP_NINOS) 16410Sstevel@tonic-gate inos[tapeno] = chkpt.sl_inos; 16420Sstevel@tonic-gate spcl.c_firstrec = chkpt.sl_firstrec; 16430Sstevel@tonic-gate spcl.c_tapea = (*tapea) = chkpt.sl_tapea; 16440Sstevel@tonic-gate spcl.c_volume++; 16450Sstevel@tonic-gate 16460Sstevel@tonic-gate enslave(); /* Share tape buffers with slaves */ 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate #ifdef DEBUG 16490Sstevel@tonic-gate if (xflag) { 16500Sstevel@tonic-gate /* XGETTEXT: #ifdef DEBUG only */ 16510Sstevel@tonic-gate msg(gettext("Checkpoint state:\n")); 16520Sstevel@tonic-gate msg(" blockswritten %u\n", blockswritten); 16530Sstevel@tonic-gate msg(" ino %u\n", ino); 16540Sstevel@tonic-gate msg(" pos %u\n", pos); 16550Sstevel@tonic-gate msg(" left %u\n", leftover); 16560Sstevel@tonic-gate msg(" tapea %u\n", (*tapea)); 16570Sstevel@tonic-gate msg(" state %d\n", dumpstate); 16580Sstevel@tonic-gate } 16590Sstevel@tonic-gate #endif 16600Sstevel@tonic-gate spcl.c_type = TS_TAPE; 16610Sstevel@tonic-gate spcl.c_tpbsize = tp_bsize; 16620Sstevel@tonic-gate if (leftover == 0) { 16630Sstevel@tonic-gate spcl.c_count = 0; 16640Sstevel@tonic-gate spclrec(); 16650Sstevel@tonic-gate newtape = 0; 16660Sstevel@tonic-gate } else 16670Sstevel@tonic-gate newtape++; /* new volume indication */ 16680Sstevel@tonic-gate if (doingverify) { 16690Sstevel@tonic-gate msg(gettext("Starting verify pass\n")); 16700Sstevel@tonic-gate } else if (tapeno > 1) { 16710Sstevel@tonic-gate msg(gettext( 16720Sstevel@tonic-gate "Volume %d begins with blocks from inode %lu\n"), 16730Sstevel@tonic-gate tapeno, chkpt.sl_inos); 16740Sstevel@tonic-gate } 16750Sstevel@tonic-gate (void) timeclock((time_t)1); 16760Sstevel@tonic-gate (void) time(tstart_writing); 16770Sstevel@tonic-gate timeest(0, spcl.c_tapea); 16780Sstevel@tonic-gate } 16790Sstevel@tonic-gate } 16800Sstevel@tonic-gate 16810Sstevel@tonic-gate void 16820Sstevel@tonic-gate #ifdef __STDC__ 16830Sstevel@tonic-gate dumpabort(void) 16840Sstevel@tonic-gate #else 16850Sstevel@tonic-gate dumpabort() 16860Sstevel@tonic-gate #endif 16870Sstevel@tonic-gate { 16880Sstevel@tonic-gate 16890Sstevel@tonic-gate if (master && master != getpid()) 16900Sstevel@tonic-gate /* 16910Sstevel@tonic-gate * signal master to call dumpabort 16920Sstevel@tonic-gate */ 16930Sstevel@tonic-gate (void) kill(master, SIGTERM); 16940Sstevel@tonic-gate else { 16950Sstevel@tonic-gate killall(); 16960Sstevel@tonic-gate 16970Sstevel@tonic-gate if (archivefile) 16980Sstevel@tonic-gate (void) unlink(archivefile); 16990Sstevel@tonic-gate msg(gettext("The ENTIRE dump is aborted.\n")); 17000Sstevel@tonic-gate } 17010Sstevel@tonic-gate Exit(X_ABORT); 17020Sstevel@tonic-gate } 17030Sstevel@tonic-gate 17040Sstevel@tonic-gate void 17050Sstevel@tonic-gate dumpailing(void) 17060Sstevel@tonic-gate { 17070Sstevel@tonic-gate 17080Sstevel@tonic-gate broadcast(gettext("DUMP IS AILING!\n")); 17090Sstevel@tonic-gate if (!query(gettext( 17100Sstevel@tonic-gate "Do you want to attempt to continue? (\"yes\" or \"no\") "))) { 17110Sstevel@tonic-gate dumpabort(); 17120Sstevel@tonic-gate /*NOTREACHED*/ 17130Sstevel@tonic-gate } 17140Sstevel@tonic-gate } 17150Sstevel@tonic-gate 17160Sstevel@tonic-gate void 17170Sstevel@tonic-gate Exit(status) 17180Sstevel@tonic-gate { 17190Sstevel@tonic-gate /* 17200Sstevel@tonic-gate * Clean up message system 17210Sstevel@tonic-gate */ 17220Sstevel@tonic-gate #ifdef TDEBUG 17230Sstevel@tonic-gate 17240Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 17250Sstevel@tonic-gate msg(gettext("pid = %ld exits with status %d\n"), 17260Sstevel@tonic-gate (long)getpid(), status); 17270Sstevel@tonic-gate #endif /* TDEBUG */ 17280Sstevel@tonic-gate exit(status); 17290Sstevel@tonic-gate } 17300Sstevel@tonic-gate 17310Sstevel@tonic-gate static void 17320Sstevel@tonic-gate #ifdef __STDC__ 17330Sstevel@tonic-gate killall(void) 17340Sstevel@tonic-gate #else 17350Sstevel@tonic-gate killall() 17360Sstevel@tonic-gate #endif 17370Sstevel@tonic-gate { 17380Sstevel@tonic-gate struct slaves *slavep; 17390Sstevel@tonic-gate 17400Sstevel@tonic-gate for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) 17410Sstevel@tonic-gate if (slavep->sl_slavepid > 0) { 17420Sstevel@tonic-gate (void) kill(slavep->sl_slavepid, SIGKILL); 17430Sstevel@tonic-gate #ifdef TDEBUG 17440Sstevel@tonic-gate 17450Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 17460Sstevel@tonic-gate msg(gettext("Slave child %ld killed\n"), 17470Sstevel@tonic-gate (long)slavep->sl_slavepid); 17480Sstevel@tonic-gate #endif 17490Sstevel@tonic-gate } 17500Sstevel@tonic-gate if (writepid) { 17510Sstevel@tonic-gate (void) kill(writepid, SIGKILL); 17520Sstevel@tonic-gate #ifdef TDEBUG 17530Sstevel@tonic-gate 17540Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 17550Sstevel@tonic-gate msg(gettext("Writer child %ld killed\n"), (long)writepid); 17560Sstevel@tonic-gate #endif 17570Sstevel@tonic-gate } 17580Sstevel@tonic-gate if (archivepid) { 17590Sstevel@tonic-gate (void) kill(archivepid, SIGKILL); 17600Sstevel@tonic-gate #ifdef TDEBUG 17610Sstevel@tonic-gate 17620Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 17630Sstevel@tonic-gate msg(gettext("Archiver child %ld killed\n"), (long)archivepid); 17640Sstevel@tonic-gate #endif 17650Sstevel@tonic-gate } 17660Sstevel@tonic-gate } 17670Sstevel@tonic-gate 17680Sstevel@tonic-gate /*ARGSUSED*/ 17690Sstevel@tonic-gate static void 1770*1053Smaheshvs proceed(int sig) 17710Sstevel@tonic-gate { 17720Sstevel@tonic-gate caught++; 17730Sstevel@tonic-gate } 17740Sstevel@tonic-gate 17750Sstevel@tonic-gate /*ARGSUSED*/ 17760Sstevel@tonic-gate static void 1777*1053Smaheshvs die(int sig) 17780Sstevel@tonic-gate { 17790Sstevel@tonic-gate Exit(X_FINOK); 17800Sstevel@tonic-gate } 17810Sstevel@tonic-gate 17820Sstevel@tonic-gate static void 17830Sstevel@tonic-gate #ifdef __STDC__ 17840Sstevel@tonic-gate enslave(void) 17850Sstevel@tonic-gate #else 17860Sstevel@tonic-gate enslave() 17870Sstevel@tonic-gate #endif 17880Sstevel@tonic-gate { 17890Sstevel@tonic-gate int cmd[2]; /* file descriptors */ 17900Sstevel@tonic-gate int i; 17910Sstevel@tonic-gate struct sigvec sv; 17920Sstevel@tonic-gate struct slaves *slavep; 17930Sstevel@tonic-gate int saverr; 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate sv.sv_flags = SA_RESTART; 17960Sstevel@tonic-gate (void) sigemptyset(&sv.sa_mask); 17970Sstevel@tonic-gate master = getpid(); 17980Sstevel@tonic-gate /* 17990Sstevel@tonic-gate * slave sends SIGTERM on dumpabort 18000Sstevel@tonic-gate */ 18010Sstevel@tonic-gate sv.sv_handler = (void(*)(int))dumpabort; 18020Sstevel@tonic-gate (void) sigvec(SIGTERM, &sv, (struct sigvec *)0); 18030Sstevel@tonic-gate sv.sv_handler = tperror; 18040Sstevel@tonic-gate (void) sigvec(SIGUSR2, &sv, (struct sigvec *)0); 18050Sstevel@tonic-gate sv.sv_handler = proceed; 18060Sstevel@tonic-gate (void) sigvec(SIGUSR1, &sv, (struct sigvec *)0); 18070Sstevel@tonic-gate totalrecsout += recsout; 18080Sstevel@tonic-gate caught = 0; 18090Sstevel@tonic-gate recsout = 0; 18100Sstevel@tonic-gate rotor = 0; 18110Sstevel@tonic-gate bufclear(); 18120Sstevel@tonic-gate for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) 18130Sstevel@tonic-gate slavep->sl_slavefd = -1; 18140Sstevel@tonic-gate archivefd = arch = writer = -1; 18150Sstevel@tonic-gate for (i = 0; i < SLAVES; i++) { 18160Sstevel@tonic-gate if (pipe(cmd) < 0) { 18170Sstevel@tonic-gate saverr = errno; 18180Sstevel@tonic-gate msg(gettext( 18190Sstevel@tonic-gate "Cannot create pipe for slave process: %s\n"), 18200Sstevel@tonic-gate strerror(saverr)); 18210Sstevel@tonic-gate dumpabort(); 18220Sstevel@tonic-gate /*NOTREACHED*/ 18230Sstevel@tonic-gate } 18240Sstevel@tonic-gate sighold(SIGUSR2); 18250Sstevel@tonic-gate sighold(SIGINT); 18260Sstevel@tonic-gate sighold(SIGTERM); 18270Sstevel@tonic-gate if ((slaves[i].sl_slavepid = fork()) < 0) { 18280Sstevel@tonic-gate saverr = errno; 18290Sstevel@tonic-gate msg(gettext("Cannot create slave process: %s\n"), 18300Sstevel@tonic-gate strerror(saverr)); 18310Sstevel@tonic-gate dumpabort(); 18320Sstevel@tonic-gate /*NOTREACHED*/ 18330Sstevel@tonic-gate } 18340Sstevel@tonic-gate slaves[i].sl_slavefd = cmd[1]; 18350Sstevel@tonic-gate if (slaves[i].sl_slavepid == 0) { /* Slave starts up here */ 18360Sstevel@tonic-gate pid_t next; /* pid of neighbor */ 18370Sstevel@tonic-gate 18380Sstevel@tonic-gate sv.sv_handler = SIG_DFL; 18390Sstevel@tonic-gate (void) sigvec(SIGUSR2, &sv, (struct sigvec *)0); 18400Sstevel@tonic-gate sv.sv_handler = SIG_IGN; /* master handler INT */ 18410Sstevel@tonic-gate (void) sigvec(SIGINT, &sv, (struct sigvec *)0); 18420Sstevel@tonic-gate sv.sv_handler = die; /* normal slave exit */ 18430Sstevel@tonic-gate (void) sigvec(SIGTERM, &sv, (struct sigvec *)0); 18440Sstevel@tonic-gate 18450Sstevel@tonic-gate child_chdir(); 18460Sstevel@tonic-gate sigrelse(SIGUSR2); 18470Sstevel@tonic-gate sigrelse(SIGINT); 18480Sstevel@tonic-gate sigrelse(SIGTERM); 18490Sstevel@tonic-gate 18500Sstevel@tonic-gate freeino(); /* release unneeded resources */ 18510Sstevel@tonic-gate #ifdef TDEBUG 18520Sstevel@tonic-gate (void) sleep(4); /* time for parent's message to get out */ 18530Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 18540Sstevel@tonic-gate msg(gettext("Neighbor has pid = %ld\n"), (long)getpid()); 18550Sstevel@tonic-gate #endif 18560Sstevel@tonic-gate /* Closes cmd[1] as a side-effect */ 18570Sstevel@tonic-gate for (slavep = &slaves[0]; 18580Sstevel@tonic-gate slavep < &slaves[SLAVES]; 18590Sstevel@tonic-gate slavep++) 18600Sstevel@tonic-gate if (slavep->sl_slavefd >= 0) { 18610Sstevel@tonic-gate (void) close(slavep->sl_slavefd); 18620Sstevel@tonic-gate slavep->sl_slavefd = -1; 18630Sstevel@tonic-gate } 18640Sstevel@tonic-gate (void) close(to); 18650Sstevel@tonic-gate (void) close(fi); /* Need our own seek ptr */ 18660Sstevel@tonic-gate to = -1; 18670Sstevel@tonic-gate 18680Sstevel@tonic-gate fi = open(disk, O_RDONLY); 18690Sstevel@tonic-gate 18700Sstevel@tonic-gate if (fi < 0) { 18710Sstevel@tonic-gate saverr = errno; 18720Sstevel@tonic-gate msg(gettext( 18730Sstevel@tonic-gate "Cannot open dump device `%s': %s\n"), 18740Sstevel@tonic-gate disk, strerror(saverr)); 18750Sstevel@tonic-gate dumpabort(); 18760Sstevel@tonic-gate /*NOTREACHED*/ 18770Sstevel@tonic-gate } 18780Sstevel@tonic-gate 18790Sstevel@tonic-gate if ((unsigned)atomic((int(*)())read, cmd[0], 18800Sstevel@tonic-gate (char *)&next, sizeof (next)) != sizeof (next)) { 18810Sstevel@tonic-gate cmdrderr(); 18820Sstevel@tonic-gate dumpabort(); 18830Sstevel@tonic-gate /*NOTREACHED*/ 18840Sstevel@tonic-gate } 18850Sstevel@tonic-gate dumpoffline(cmd[0], next, i); 18860Sstevel@tonic-gate Exit(X_FINOK); 18870Sstevel@tonic-gate } 18880Sstevel@tonic-gate /* Parent continues here */ 18890Sstevel@tonic-gate sigrelse(SIGUSR2); 18900Sstevel@tonic-gate sigrelse(SIGINT); 18910Sstevel@tonic-gate sigrelse(SIGTERM); 18920Sstevel@tonic-gate (void) close(cmd[0]); 18930Sstevel@tonic-gate } 18940Sstevel@tonic-gate 18950Sstevel@tonic-gate if (archive) { 18960Sstevel@tonic-gate archivepid = setuparchive(); 18970Sstevel@tonic-gate if (!archivepid) { 18980Sstevel@tonic-gate dumpabort(); 18990Sstevel@tonic-gate /*NOTREACHED*/ 19000Sstevel@tonic-gate } 19010Sstevel@tonic-gate } 19020Sstevel@tonic-gate 19030Sstevel@tonic-gate writepid = setupwriter(); 19040Sstevel@tonic-gate if (!writepid) { 19050Sstevel@tonic-gate dumpabort(); 19060Sstevel@tonic-gate /*NOTREACHED*/ 19070Sstevel@tonic-gate } 19080Sstevel@tonic-gate 19090Sstevel@tonic-gate if (arch >= 0) { 19100Sstevel@tonic-gate (void) close(arch); /* only writer has this open */ 19110Sstevel@tonic-gate arch = -1; 19120Sstevel@tonic-gate } 19130Sstevel@tonic-gate 19140Sstevel@tonic-gate /* Tell each slave who follows it */ 19150Sstevel@tonic-gate for (i = 0; i < SLAVES; i++) { 19160Sstevel@tonic-gate if ((unsigned)atomic((int(*)())write, slaves[i].sl_slavefd, 19170Sstevel@tonic-gate (char *)&(slaves[(i + 1) % SLAVES].sl_slavepid), 19180Sstevel@tonic-gate sizeof (int)) != sizeof (int)) { 19190Sstevel@tonic-gate cmdwrterr(); 19200Sstevel@tonic-gate dumpabort(); 19210Sstevel@tonic-gate /*NOTREACHED*/ 19220Sstevel@tonic-gate } 19230Sstevel@tonic-gate } 19240Sstevel@tonic-gate sv.sv_handler = rollforward; /* rcvd from writer on EOT */ 19250Sstevel@tonic-gate (void) sigvec(SIGUSR1, &sv, (struct sigvec *)0); 19260Sstevel@tonic-gate slp = slaves; 19270Sstevel@tonic-gate (void) kill(slp->sl_slavepid, SIGUSR1); 19280Sstevel@tonic-gate master = 0; 19290Sstevel@tonic-gate } 19300Sstevel@tonic-gate 19310Sstevel@tonic-gate static void 19320Sstevel@tonic-gate #ifdef __STDC__ 19330Sstevel@tonic-gate wait_our_turn(void) 19340Sstevel@tonic-gate #else 19350Sstevel@tonic-gate wait_our_turn() 19360Sstevel@tonic-gate #endif 19370Sstevel@tonic-gate { 19380Sstevel@tonic-gate (void) sighold(SIGUSR1); 19390Sstevel@tonic-gate 19400Sstevel@tonic-gate if (!caught) { 19410Sstevel@tonic-gate #ifdef INSTRUMENT 19420Sstevel@tonic-gate (*idle)++; 19430Sstevel@tonic-gate #endif 19440Sstevel@tonic-gate (void) sigpause(SIGUSR1); 19450Sstevel@tonic-gate } 19460Sstevel@tonic-gate caught = 0; 19470Sstevel@tonic-gate (void) sigrelse(SIGUSR1); 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate static void 1951*1053Smaheshvs dumpoffline(int cmd, pid_t next, int mynum) 19520Sstevel@tonic-gate { 19530Sstevel@tonic-gate struct req *p = slaves[mynum].sl_req; 19540Sstevel@tonic-gate ulong_t i; 19550Sstevel@tonic-gate uchar_t *cp; 19560Sstevel@tonic-gate uchar_t *blkbuf; 19570Sstevel@tonic-gate int notactive = 0; 19580Sstevel@tonic-gate 19590Sstevel@tonic-gate blkbuf = xmalloc(sblock->fs_bsize); 19600Sstevel@tonic-gate 19610Sstevel@tonic-gate /*CONSTANTCONDITION*/ 19620Sstevel@tonic-gate assert(sizeof (spcl) == TP_BSIZE_MIN); 19630Sstevel@tonic-gate 19640Sstevel@tonic-gate while (atomic((int(*)())read, cmd, (char *)p, reqsiz) == reqsiz) { 19650Sstevel@tonic-gate if (p->br_dblk) { 19660Sstevel@tonic-gate bread(p->br_dblk, (uchar_t *)blkbuf, p->br_size); 19670Sstevel@tonic-gate } else { 19680Sstevel@tonic-gate bcopy((char *)p->br_spcl, (char *)&spcl, 19690Sstevel@tonic-gate sizeof (spcl)); 19700Sstevel@tonic-gate ino = spcl.c_inumber; 19710Sstevel@tonic-gate } 19720Sstevel@tonic-gate dumptoarchive = p->aflag & BUF_ARCHIVE; 19730Sstevel@tonic-gate wait_our_turn(); 19740Sstevel@tonic-gate if (p->br_dblk) { 19750Sstevel@tonic-gate for (i = p->br_size, cp = blkbuf; 19760Sstevel@tonic-gate i > 0; 19770Sstevel@tonic-gate /* LINTED character pointers aren't signed */ 19780Sstevel@tonic-gate cp += i > tp_bsize ? tp_bsize : i, 19790Sstevel@tonic-gate i -= i > tp_bsize ? tp_bsize : i) { 19800Sstevel@tonic-gate /* LINTED unsigned to signed conversion ok */ 19810Sstevel@tonic-gate taprec(cp, 0, i > tp_bsize ? tp_bsize : (int)i); 19820Sstevel@tonic-gate } 19830Sstevel@tonic-gate } else 19840Sstevel@tonic-gate spclrec(); 19850Sstevel@tonic-gate (void) kill(next, SIGUSR1); /* Next slave's turn */ 19860Sstevel@tonic-gate /* 19870Sstevel@tonic-gate * Note that we lie about file activity since we don't 19880Sstevel@tonic-gate * check for it. 19890Sstevel@tonic-gate */ 19900Sstevel@tonic-gate if ((unsigned)atomic((int(*)())write, cmd, (char *)¬active, 19910Sstevel@tonic-gate sizeof (notactive)) != sizeof (notactive)) { 19920Sstevel@tonic-gate cmdwrterr(); 19930Sstevel@tonic-gate dumpabort(); 19940Sstevel@tonic-gate /*NOTREACHED*/ 19950Sstevel@tonic-gate } 19960Sstevel@tonic-gate } 19970Sstevel@tonic-gate 19980Sstevel@tonic-gate free(blkbuf); 19990Sstevel@tonic-gate } 20000Sstevel@tonic-gate 20010Sstevel@tonic-gate static int count; /* tape blocks written since last spclrec */ 20020Sstevel@tonic-gate 20030Sstevel@tonic-gate /*ARGSUSED*/ 20040Sstevel@tonic-gate static void 2005*1053Smaheshvs onxfsz(int sig) 20060Sstevel@tonic-gate { 20070Sstevel@tonic-gate msg(gettext("File size limit exceeded writing output volume %d\n"), 20080Sstevel@tonic-gate tapeno); 20090Sstevel@tonic-gate (void) kill(master, SIGUSR2); 20100Sstevel@tonic-gate Exit(X_REWRITE); 20110Sstevel@tonic-gate } 20120Sstevel@tonic-gate 20130Sstevel@tonic-gate static long lastnonaddr; /* last DS_{INODE,CLRI,BITS} written */ 20140Sstevel@tonic-gate static long lastnonaddrm; /* and the mode thereof */ 20150Sstevel@tonic-gate /* 20160Sstevel@tonic-gate * dowrite -- the main body of the output writer process 20170Sstevel@tonic-gate */ 20180Sstevel@tonic-gate static void 2019*1053Smaheshvs dowrite(int cmd) 20200Sstevel@tonic-gate { 20210Sstevel@tonic-gate struct bdesc *last = 20220Sstevel@tonic-gate &bufp[(NBUF*ntrec)-1]; /* last buffer in pool */ 20230Sstevel@tonic-gate struct bdesc *bp = bufp; /* current buf in tape block */ 20240Sstevel@tonic-gate struct bdesc *begin = bufp; /* first buf of tape block */ 20250Sstevel@tonic-gate struct bdesc *end = bufp + (ntrec-1); /* last buf of tape block */ 20260Sstevel@tonic-gate int siz; /* bytes written (block) */ 20270Sstevel@tonic-gate int trecs; /* records written (block) */ 20280Sstevel@tonic-gate long asize = 0; /* number of 0.1" units... */ 20290Sstevel@tonic-gate /* ...written on current tape */ 20300Sstevel@tonic-gate char *tp, *rbuf = NULL; 20310Sstevel@tonic-gate char *recmap = spcl.c_addr; /* current tape record map */ 20320Sstevel@tonic-gate char *endmp; /* end of valid map data */ 20330Sstevel@tonic-gate char *mp; /* current map entry */ 20340Sstevel@tonic-gate union u_spcl *sp; 20350Sstevel@tonic-gate 20360Sstevel@tonic-gate (void) signal(SIGXFSZ, onxfsz); 20370Sstevel@tonic-gate 20380Sstevel@tonic-gate bzero((char *)&spcl, sizeof (spcl)); 20390Sstevel@tonic-gate count = 0; 20400Sstevel@tonic-gate 20410Sstevel@tonic-gate if (doingverify) { 20420Sstevel@tonic-gate rbuf = (char *)malloc((uint_t)writesize); 20430Sstevel@tonic-gate if (rbuf == 0) { 20440Sstevel@tonic-gate /* Restart from checkpoint */ 20450Sstevel@tonic-gate (void) kill(master, SIGUSR2); 20460Sstevel@tonic-gate Exit(X_REWRITE); 20470Sstevel@tonic-gate } 20480Sstevel@tonic-gate } 20490Sstevel@tonic-gate 20500Sstevel@tonic-gate for (;;) { 20510Sstevel@tonic-gate /* START: wait until all buffers in tape block are full */ 20520Sstevel@tonic-gate if ((bp->b_flags & BUF_FULL) == 0) { 20530Sstevel@tonic-gate if (caught) { /* master signalled flush */ 20540Sstevel@tonic-gate (void) sighold(SIGUSR1); 20550Sstevel@tonic-gate caught = 0; 20560Sstevel@tonic-gate /* signal ready */ 20570Sstevel@tonic-gate (void) kill(master, SIGUSR1); 20580Sstevel@tonic-gate chkpt.sl_count = 0; /* signal not at EOT */ 20590Sstevel@tonic-gate checkpoint(bp-1, cmd); /* send data */ 20600Sstevel@tonic-gate (void) sigpause(SIGUSR1); 20610Sstevel@tonic-gate break; 20620Sstevel@tonic-gate } 20630Sstevel@tonic-gate #ifdef INSTRUMENT 20640Sstevel@tonic-gate (*readmissp)++; 20650Sstevel@tonic-gate #endif 20660Sstevel@tonic-gate nap(50); 20670Sstevel@tonic-gate continue; 20680Sstevel@tonic-gate } 20690Sstevel@tonic-gate if (bp < end) { 20700Sstevel@tonic-gate bp++; 20710Sstevel@tonic-gate continue; 20720Sstevel@tonic-gate } 20730Sstevel@tonic-gate /* END: wait until all buffers in tape block are full */ 20740Sstevel@tonic-gate 20750Sstevel@tonic-gate tp = begin->b_data; 20760Sstevel@tonic-gate (void) sighold(SIGUSR1); 20770Sstevel@tonic-gate if (host) { 20780Sstevel@tonic-gate if (!doingverify) 20790Sstevel@tonic-gate siz = rmtwrite(tp, writesize); 20800Sstevel@tonic-gate else if ((siz = rmtread(rbuf, writesize)) == 20810Sstevel@tonic-gate writesize && bcmp(rbuf, tp, writesize)) 20820Sstevel@tonic-gate siz = -1; 20830Sstevel@tonic-gate } else { 20840Sstevel@tonic-gate if (!doingverify) 20850Sstevel@tonic-gate siz = write(to, tp, writesize); 20860Sstevel@tonic-gate else if ((siz = read(to, rbuf, writesize)) == 20870Sstevel@tonic-gate writesize && bcmp(rbuf, tp, writesize)) 20880Sstevel@tonic-gate siz = -1; 20890Sstevel@tonic-gate if (siz < 0 && diskette && errno == ENOSPC) 20900Sstevel@tonic-gate siz = 0; /* really EOF */ 20910Sstevel@tonic-gate } 20920Sstevel@tonic-gate (void) sigrelse(SIGUSR1); 20930Sstevel@tonic-gate if (siz < 0 || 20940Sstevel@tonic-gate (pipeout && siz != writesize)) { 20950Sstevel@tonic-gate char buf[3000]; 20960Sstevel@tonic-gate 20970Sstevel@tonic-gate /* 20980Sstevel@tonic-gate * Isn't i18n wonderful? 20990Sstevel@tonic-gate */ 21000Sstevel@tonic-gate if (doingverify) { 21010Sstevel@tonic-gate if (diskette) 21020Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 21030Sstevel@tonic-gate gettext( 21040Sstevel@tonic-gate "Verification error %ld blocks into diskette %d\n"), 21050Sstevel@tonic-gate asize * 2, tapeno); 21060Sstevel@tonic-gate else if (tapeout) 21070Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 21080Sstevel@tonic-gate gettext( 21090Sstevel@tonic-gate "Verification error %ld feet into tape %d\n"), 21100Sstevel@tonic-gate (cartridge ? asize/tracks : 21110Sstevel@tonic-gate asize)/120L, 21120Sstevel@tonic-gate tapeno); 21130Sstevel@tonic-gate else 21140Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 21150Sstevel@tonic-gate gettext( 21160Sstevel@tonic-gate "Verification error %ld blocks into volume %d\n"), 21170Sstevel@tonic-gate asize * 2, tapeno); 21180Sstevel@tonic-gate 21190Sstevel@tonic-gate } else { 21200Sstevel@tonic-gate if (diskette) 21210Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 21220Sstevel@tonic-gate gettext( 21230Sstevel@tonic-gate "Write error %ld blocks into diskette %d\n"), 21240Sstevel@tonic-gate asize * 2, tapeno); 21250Sstevel@tonic-gate else if (tapeout) 21260Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 21270Sstevel@tonic-gate gettext( 21280Sstevel@tonic-gate "Write error %ld feet into tape %d\n"), 21290Sstevel@tonic-gate (cartridge ? asize/tracks : 21300Sstevel@tonic-gate asize)/120L, tapeno); 21310Sstevel@tonic-gate else 21320Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 21330Sstevel@tonic-gate gettext( 21340Sstevel@tonic-gate "Write error %ld blocks into volume %d\n"), 21350Sstevel@tonic-gate asize * 2, tapeno); 21360Sstevel@tonic-gate } 21370Sstevel@tonic-gate 21380Sstevel@tonic-gate msg(buf); 21390Sstevel@tonic-gate /* Restart from checkpoint */ 21400Sstevel@tonic-gate #ifdef TDEBUG 21410Sstevel@tonic-gate 21420Sstevel@tonic-gate /* XGETTEXT: #ifdef TDEBUG only */ 21430Sstevel@tonic-gate msg(gettext("sending SIGUSR2 to pid %ld\n"), master); 21440Sstevel@tonic-gate #endif 21450Sstevel@tonic-gate (void) kill(master, SIGUSR2); 21460Sstevel@tonic-gate Exit(X_REWRITE); 21470Sstevel@tonic-gate } 21480Sstevel@tonic-gate trecs = siz / tp_bsize; 21490Sstevel@tonic-gate if (diskette) 21500Sstevel@tonic-gate asize += trecs; /* asize == blocks written */ 21510Sstevel@tonic-gate else 21520Sstevel@tonic-gate asize += (siz/density + tenthsperirg); 21530Sstevel@tonic-gate if (trecs) 21540Sstevel@tonic-gate chkpt.sl_firstrec++; 21550Sstevel@tonic-gate for (bp = begin; bp < begin + trecs; bp++) { 21560Sstevel@tonic-gate if ((arch >= 0) && (bp->b_flags & BUF_ARCHIVE)) { 21570Sstevel@tonic-gate if ((unsigned)atomic((int(*)())write, arch, 21580Sstevel@tonic-gate (char *)&bp->b_flags, sizeof (bp->b_flags)) 21590Sstevel@tonic-gate != sizeof (bp->b_flags)) { 21600Sstevel@tonic-gate cmdwrterr(); 21610Sstevel@tonic-gate dumpabort(); 21620Sstevel@tonic-gate /*NOTREACHED*/ 21630Sstevel@tonic-gate } 21640Sstevel@tonic-gate if (atomic((int(*)())write, arch, bp->b_data, 21650Sstevel@tonic-gate tp_bsize) != tp_bsize) { 21660Sstevel@tonic-gate cmdwrterr(); 21670Sstevel@tonic-gate dumpabort(); 21680Sstevel@tonic-gate /*NOTREACHED*/ 21690Sstevel@tonic-gate } 21700Sstevel@tonic-gate } 21710Sstevel@tonic-gate if (bp->b_flags & BUF_SPCLREC) { 21720Sstevel@tonic-gate /*LINTED [bp->b_data is aligned]*/ 21730Sstevel@tonic-gate sp = (union u_spcl *)bp->b_data; 21740Sstevel@tonic-gate if (sp->s_spcl.c_type != TS_ADDR) { 21750Sstevel@tonic-gate lastnonaddr = sp->s_spcl.c_type; 21760Sstevel@tonic-gate lastnonaddrm = 21770Sstevel@tonic-gate sp->s_spcl.c_dinode.di_mode; 21780Sstevel@tonic-gate if (sp->s_spcl.c_type != TS_TAPE) 21790Sstevel@tonic-gate chkpt.sl_offset = 0; 21800Sstevel@tonic-gate } 21810Sstevel@tonic-gate chkpt.sl_count = sp->s_spcl.c_count; 21820Sstevel@tonic-gate bcopy((char *)sp, 21830Sstevel@tonic-gate (char *)&spcl, sizeof (spcl)); 21840Sstevel@tonic-gate mp = recmap; 21850Sstevel@tonic-gate endmp = &recmap[spcl.c_count]; 21860Sstevel@tonic-gate count = 0; 21870Sstevel@tonic-gate } else { 21880Sstevel@tonic-gate chkpt.sl_offset++; 21890Sstevel@tonic-gate chkpt.sl_count--; 21900Sstevel@tonic-gate count++; 21910Sstevel@tonic-gate mp++; 21920Sstevel@tonic-gate } 21930Sstevel@tonic-gate /* 21940Sstevel@tonic-gate * Adjust for contiguous hole 21950Sstevel@tonic-gate */ 21960Sstevel@tonic-gate for (; mp < endmp; mp++) { 21970Sstevel@tonic-gate if (*mp) 21980Sstevel@tonic-gate break; 21990Sstevel@tonic-gate chkpt.sl_offset++; 22000Sstevel@tonic-gate chkpt.sl_count--; 22010Sstevel@tonic-gate } 22020Sstevel@tonic-gate } 22030Sstevel@tonic-gate /* 22040Sstevel@tonic-gate * Check for end of tape 22050Sstevel@tonic-gate */ 22060Sstevel@tonic-gate if (trecs < ntrec || 22070Sstevel@tonic-gate (!pipeout && tsize > 0 && asize > tsize)) { 22080Sstevel@tonic-gate if (tapeout) 22090Sstevel@tonic-gate msg(gettext("End-of-tape detected\n")); 22100Sstevel@tonic-gate else 22110Sstevel@tonic-gate msg(gettext("End-of-file detected\n")); 22120Sstevel@tonic-gate (void) sighold(SIGUSR1); 22130Sstevel@tonic-gate caught = 0; 22140Sstevel@tonic-gate (void) kill(master, SIGUSR1); /* signal EOT */ 22150Sstevel@tonic-gate checkpoint(--bp, cmd); /* send checkpoint data */ 22160Sstevel@tonic-gate (void) sigpause(SIGUSR1); 22170Sstevel@tonic-gate break; 22180Sstevel@tonic-gate } 22190Sstevel@tonic-gate for (bp = begin; bp <= end; bp++) 22200Sstevel@tonic-gate bp->b_flags = BUF_EMPTY; 22210Sstevel@tonic-gate if (end + ntrec > last) { 22220Sstevel@tonic-gate bp = begin = bufp; 22230Sstevel@tonic-gate timeest(0, spcl.c_tapea); 22240Sstevel@tonic-gate } else 22250Sstevel@tonic-gate bp = begin = end+1; 22260Sstevel@tonic-gate end = begin + (ntrec-1); 22270Sstevel@tonic-gate } 22280Sstevel@tonic-gate 22290Sstevel@tonic-gate if (rbuf != NULL) 22300Sstevel@tonic-gate free(rbuf); 22310Sstevel@tonic-gate } 22320Sstevel@tonic-gate 22330Sstevel@tonic-gate /* 22340Sstevel@tonic-gate * Send checkpoint info back to master. This information 22350Sstevel@tonic-gate * consists of the current inode number, number of logical 22360Sstevel@tonic-gate * blocks written for that inode (or bitmap), the last logical 22370Sstevel@tonic-gate * block number written, the number of logical blocks written 22380Sstevel@tonic-gate * to this volume, the current dump state, and the current 22390Sstevel@tonic-gate * special record map. 22400Sstevel@tonic-gate */ 22410Sstevel@tonic-gate static void 2242*1053Smaheshvs checkpoint(struct bdesc *bp, int cmd) 22430Sstevel@tonic-gate { 22440Sstevel@tonic-gate int state, type; 22450Sstevel@tonic-gate ino_t ino; 22460Sstevel@tonic-gate 22470Sstevel@tonic-gate if (++bp >= &bufp[NBUF*ntrec]) 22480Sstevel@tonic-gate bp = bufp; 22490Sstevel@tonic-gate 22500Sstevel@tonic-gate /* 22510Sstevel@tonic-gate * If we are dumping files and the record following 22520Sstevel@tonic-gate * the last written to tape is a special record, use 22530Sstevel@tonic-gate * it to get an accurate indication of current state. 22540Sstevel@tonic-gate */ 22550Sstevel@tonic-gate if ((bp->b_flags & BUF_SPCLREC) && (bp->b_flags & BUF_FULL) && 22560Sstevel@tonic-gate lastnonaddr == TS_INODE) { 22570Sstevel@tonic-gate /*LINTED [bp->b_data is aligned]*/ 22580Sstevel@tonic-gate union u_spcl *nextspcl = (union u_spcl *)bp->b_data; 22590Sstevel@tonic-gate 22600Sstevel@tonic-gate if (nextspcl->s_spcl.c_type == TS_INODE) { 22610Sstevel@tonic-gate chkpt.sl_offset = 0; 22620Sstevel@tonic-gate chkpt.sl_count = 0; 22630Sstevel@tonic-gate } else if (nextspcl->s_spcl.c_type == TS_END) { 22640Sstevel@tonic-gate chkpt.sl_offset = 0; 22650Sstevel@tonic-gate chkpt.sl_count = 1; /* EOT indicator */ 22660Sstevel@tonic-gate } 22670Sstevel@tonic-gate ino = nextspcl->s_spcl.c_inumber; 22680Sstevel@tonic-gate type = nextspcl->s_spcl.c_type; 22690Sstevel@tonic-gate } else { 22700Sstevel@tonic-gate /* 22710Sstevel@tonic-gate * If not, use what we have. 22720Sstevel@tonic-gate */ 22730Sstevel@tonic-gate ino = spcl.c_inumber; 22740Sstevel@tonic-gate type = spcl.c_type; 22750Sstevel@tonic-gate } 22760Sstevel@tonic-gate 22770Sstevel@tonic-gate switch (type) { /* set output state */ 22780Sstevel@tonic-gate case TS_ADDR: 22790Sstevel@tonic-gate switch (lastnonaddr) { 22800Sstevel@tonic-gate case TS_INODE: 22810Sstevel@tonic-gate case TS_TAPE: 22820Sstevel@tonic-gate if ((lastnonaddrm & IFMT) == IFDIR || 22830Sstevel@tonic-gate (lastnonaddrm & IFMT) == IFATTRDIR) 22840Sstevel@tonic-gate state = DS_DIRS; 22850Sstevel@tonic-gate else 22860Sstevel@tonic-gate state = DS_FILES; 22870Sstevel@tonic-gate break; 22880Sstevel@tonic-gate case TS_CLRI: 22890Sstevel@tonic-gate state = DS_CLRI; 22900Sstevel@tonic-gate break; 22910Sstevel@tonic-gate case TS_BITS: 22920Sstevel@tonic-gate state = DS_BITS; 22930Sstevel@tonic-gate break; 22940Sstevel@tonic-gate } 22950Sstevel@tonic-gate break; 22960Sstevel@tonic-gate case TS_INODE: 22970Sstevel@tonic-gate if ((spcl.c_dinode.di_mode & IFMT) == IFDIR || 22980Sstevel@tonic-gate (spcl.c_dinode.di_mode & IFMT) == IFATTRDIR) 22990Sstevel@tonic-gate state = DS_DIRS; 23000Sstevel@tonic-gate else 23010Sstevel@tonic-gate state = DS_FILES; 23020Sstevel@tonic-gate break; 23030Sstevel@tonic-gate case 0: /* EOT on 1st record */ 23040Sstevel@tonic-gate case TS_TAPE: 23050Sstevel@tonic-gate state = DS_START; 23060Sstevel@tonic-gate ino = UFSROOTINO; 23070Sstevel@tonic-gate break; 23080Sstevel@tonic-gate case TS_CLRI: 23090Sstevel@tonic-gate state = DS_CLRI; 23100Sstevel@tonic-gate break; 23110Sstevel@tonic-gate case TS_BITS: 23120Sstevel@tonic-gate state = DS_BITS; 23130Sstevel@tonic-gate break; 23140Sstevel@tonic-gate case TS_END: 23150Sstevel@tonic-gate if (spcl.c_type == TS_END) 23160Sstevel@tonic-gate state = DS_DONE; 23170Sstevel@tonic-gate else 23180Sstevel@tonic-gate state = DS_END; 23190Sstevel@tonic-gate break; 23200Sstevel@tonic-gate } 23210Sstevel@tonic-gate 23220Sstevel@tonic-gate /* 23230Sstevel@tonic-gate * Checkpoint info to be processed by rollforward(): 23240Sstevel@tonic-gate * The inode with which the next volume should begin 23250Sstevel@tonic-gate * The last inode number on this volume 23260Sstevel@tonic-gate * The last logical block number on this volume 23270Sstevel@tonic-gate * The current output state 23280Sstevel@tonic-gate * The offset within the current inode (already in sl_offset) 23290Sstevel@tonic-gate * The number of records left from last spclrec (in sl_count) 23300Sstevel@tonic-gate * The physical block the next vol begins with (in sl_firstrec) 23310Sstevel@tonic-gate */ 23320Sstevel@tonic-gate chkpt.sl_inos = ino; 23330Sstevel@tonic-gate chkpt.sl_tapea = spcl.c_tapea + count; 23340Sstevel@tonic-gate chkpt.sl_state = state; 23350Sstevel@tonic-gate 23360Sstevel@tonic-gate if ((unsigned)atomic((int(*)())write, cmd, (char *)&chkpt, 23370Sstevel@tonic-gate sizeof (chkpt)) != sizeof (chkpt)) { 23380Sstevel@tonic-gate cmdwrterr(); 23390Sstevel@tonic-gate dumpabort(); 23400Sstevel@tonic-gate /*NOTREACHED*/ 23410Sstevel@tonic-gate } 23420Sstevel@tonic-gate if ((unsigned)atomic((int(*)())write, cmd, (char *)&spcl, 23430Sstevel@tonic-gate sizeof (spcl)) != sizeof (spcl)) { 23440Sstevel@tonic-gate cmdwrterr(); 23450Sstevel@tonic-gate dumpabort(); 23460Sstevel@tonic-gate /*NOTREACHED*/ 23470Sstevel@tonic-gate } 23480Sstevel@tonic-gate #ifdef DEBUG 23490Sstevel@tonic-gate if (xflag) { 23500Sstevel@tonic-gate /* XGETTEXT: #ifdef DEBUG only */ 23510Sstevel@tonic-gate msg(gettext("sent chkpt to master:\n")); 23520Sstevel@tonic-gate msg(" ino %u\n", chkpt.sl_inos); 23530Sstevel@tonic-gate msg(" 1strec %u\n", chkpt.sl_firstrec); 23540Sstevel@tonic-gate msg(" lastrec %u\n", chkpt.sl_tapea); 23550Sstevel@tonic-gate msg(" written %u\n", chkpt.sl_offset); 23560Sstevel@tonic-gate msg(" left %u\n", chkpt.sl_count); 23570Sstevel@tonic-gate msg(" state %d\n", chkpt.sl_state); 23580Sstevel@tonic-gate } 23590Sstevel@tonic-gate #endif 23600Sstevel@tonic-gate } 23610Sstevel@tonic-gate 23620Sstevel@tonic-gate /* 23630Sstevel@tonic-gate * Since a read from a pipe may not return all we asked for, 23640Sstevel@tonic-gate * or a write may not write all we ask if we get a signal, 23650Sstevel@tonic-gate * loop until the count is satisfied (or error). 23660Sstevel@tonic-gate */ 23670Sstevel@tonic-gate static ssize_t 2368*1053Smaheshvs atomic(int (*func)(), int fd, char *buf, int count) 23690Sstevel@tonic-gate { 23700Sstevel@tonic-gate ssize_t got = 0, need = count; 23710Sstevel@tonic-gate 23720Sstevel@tonic-gate /* don't inherit random value if immediately get zero back from func */ 23730Sstevel@tonic-gate errno = 0; 23740Sstevel@tonic-gate while (need > 0) { 23750Sstevel@tonic-gate got = (*func)(fd, buf, MIN(need, 4096)); 23760Sstevel@tonic-gate if (got < 0 && errno == EINTR) 23770Sstevel@tonic-gate continue; 23780Sstevel@tonic-gate if (got <= 0) 23790Sstevel@tonic-gate break; 23800Sstevel@tonic-gate buf += got; 23810Sstevel@tonic-gate need -= got; 23820Sstevel@tonic-gate } 23830Sstevel@tonic-gate /* if we got what was asked for, return count, else failure (got) */ 23840Sstevel@tonic-gate return ((need != 0) ? got : count); 23850Sstevel@tonic-gate } 23860Sstevel@tonic-gate 23870Sstevel@tonic-gate void 23880Sstevel@tonic-gate #ifdef __STDC__ 23890Sstevel@tonic-gate positiontape(char *msgbuf) 23900Sstevel@tonic-gate #else 2391*1053Smaheshvs positiontape(char *msgbuf) 23920Sstevel@tonic-gate #endif 23930Sstevel@tonic-gate { 23940Sstevel@tonic-gate /* Static as never change, no need to waste stack space */ 23950Sstevel@tonic-gate static struct mtget mt; 23960Sstevel@tonic-gate static struct mtop rew = { MTREW, 1 }; 23970Sstevel@tonic-gate static struct mtop fsf = { MTFSF, 1 }; 23980Sstevel@tonic-gate char *info = strdup(gettext("Positioning `%s' to file %ld\n")); 23990Sstevel@tonic-gate char *fail = strdup(gettext("Cannot position tape to file %d\n")); 24000Sstevel@tonic-gate int m; 24010Sstevel@tonic-gate 24020Sstevel@tonic-gate /* gettext()'s return value is volatile, hence the strdup()s */ 24030Sstevel@tonic-gate 24040Sstevel@tonic-gate m = (access(tape, F_OK) == 0) ? 0 : O_CREAT; 24050Sstevel@tonic-gate 24060Sstevel@tonic-gate /* 24070Sstevel@tonic-gate * To avoid writing tape marks at inappropriate places, we open the 24080Sstevel@tonic-gate * device read-only, position it, close it, and reopen it for writing. 24090Sstevel@tonic-gate */ 24100Sstevel@tonic-gate while ((to = host ? rmtopen(tape, O_RDONLY) : 24110Sstevel@tonic-gate safe_device_open(tape, O_RDONLY|m, 0600)) < 0) { 24120Sstevel@tonic-gate if (autoload) { 24130Sstevel@tonic-gate if (!query_once(msgbuf, 1)) { 24140Sstevel@tonic-gate dumpabort(); 24150Sstevel@tonic-gate /*NOTREACHED*/ 24160Sstevel@tonic-gate } 24170Sstevel@tonic-gate } else { 24180Sstevel@tonic-gate if (!query(msgbuf)) { 24190Sstevel@tonic-gate dumpabort(); 24200Sstevel@tonic-gate /*NOTREACHED*/ 24210Sstevel@tonic-gate } 24220Sstevel@tonic-gate } 24230Sstevel@tonic-gate } 24240Sstevel@tonic-gate 24250Sstevel@tonic-gate if (host) { 24260Sstevel@tonic-gate if (rmtstatus(&mt) >= 0 && 24270Sstevel@tonic-gate rmtioctl(MTREW, 1) >= 0 && 24280Sstevel@tonic-gate filenum > 1) { 24290Sstevel@tonic-gate msg(info, dumpdev, filenum); 24300Sstevel@tonic-gate if (rmtioctl(MTFSF, filenum-1) < 0) { 24310Sstevel@tonic-gate msg(fail, filenum); 24320Sstevel@tonic-gate dumpabort(); 24330Sstevel@tonic-gate /*NOTREACHED*/ 24340Sstevel@tonic-gate } 24350Sstevel@tonic-gate } 24360Sstevel@tonic-gate rmtclose(); 24370Sstevel@tonic-gate } else { 24380Sstevel@tonic-gate if (ioctl(to, MTIOCGET, &mt) >= 0 && 24390Sstevel@tonic-gate ioctl(to, MTIOCTOP, &rew) >= 0 && 24400Sstevel@tonic-gate filenum > 1) { 24410Sstevel@tonic-gate msg(info, dumpdev, filenum); 24420Sstevel@tonic-gate fsf.mt_count = filenum - 1; 24430Sstevel@tonic-gate if (ioctl(to, MTIOCTOP, &fsf) < 0) { 24440Sstevel@tonic-gate msg(fail, filenum); 24450Sstevel@tonic-gate dumpabort(); 24460Sstevel@tonic-gate /*NOTREACHED*/ 24470Sstevel@tonic-gate } 24480Sstevel@tonic-gate } 24490Sstevel@tonic-gate (void) close(to); 24500Sstevel@tonic-gate to = -1; 24510Sstevel@tonic-gate } 24520Sstevel@tonic-gate 24530Sstevel@tonic-gate free(info); 24540Sstevel@tonic-gate free(fail); 24550Sstevel@tonic-gate } 24560Sstevel@tonic-gate 24570Sstevel@tonic-gate static void 24580Sstevel@tonic-gate #ifdef __STDC__ 24590Sstevel@tonic-gate cmdwrterr(void) 24600Sstevel@tonic-gate #else 24610Sstevel@tonic-gate cmdwrterr() 24620Sstevel@tonic-gate #endif 24630Sstevel@tonic-gate { 24640Sstevel@tonic-gate int saverr = errno; 24650Sstevel@tonic-gate msg(gettext("Error writing command pipe: %s\n"), strerror(saverr)); 24660Sstevel@tonic-gate } 24670Sstevel@tonic-gate 24680Sstevel@tonic-gate static void 24690Sstevel@tonic-gate #ifdef __STDC__ 24700Sstevel@tonic-gate cmdrderr(void) 24710Sstevel@tonic-gate #else 24720Sstevel@tonic-gate cmdrderr() 24730Sstevel@tonic-gate #endif 24740Sstevel@tonic-gate { 24750Sstevel@tonic-gate int saverr = errno; 24760Sstevel@tonic-gate msg(gettext("Error reading command pipe: %s\n"), strerror(saverr)); 24770Sstevel@tonic-gate } 2478