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