remove rcmd(3socket) interfaces and rmt(1m)
[unleashed.git] / usr / src / cmd / backup / dump / dumptape.c
blob6d0a63fe808e39b2995e002dde41cfcbaca51f8b
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 = (ino32_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 = (ino32_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 char *c;
1072 int unit;
1073 int rewind;
1075 if (fstat64(f, &sbuf) < 0) {
1076 msg(gettext(
1077 "Cannot obtain status of output device `%s'\n"),
1078 tape);
1079 dumpabort();
1080 /*NOTREACHED*/
1082 rewind = minor(sbuf.st_rdev) & MT_NOREWIND ? 0 : 1;
1083 return (rewind);
1086 static void
1087 #ifdef __STDC__
1088 just_rewind(void)
1089 #else
1090 just_rewind()
1091 #endif
1093 struct slaves *slavep;
1094 char *rewinding = gettext("Tape rewinding\n");
1096 for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++) {
1097 if (slavep->sl_slavepid > 0) /* signal normal exit */
1098 (void) kill(slavep->sl_slavepid, SIGTERM);
1099 if (slavep->sl_slavefd >= 0) {
1100 (void) close(slavep->sl_slavefd);
1101 slavep->sl_slavefd = -1;
1105 /* wait for any signals from slaves */
1106 while (waitpid(0, (int *)0, 0) >= 0)
1107 /*LINTED [empty body]*/
1108 continue;
1110 if (pipeout)
1111 return;
1113 if (doingverify) {
1115 * Space to the end of the tape.
1116 * Backup first in case we already read the EOF.
1118 static struct mtop bsr = { MTBSR, 1 };
1119 static struct mtop eom = { MTEOM, 1 };
1120 static struct mtop fsf = { MTFSF, 1 };
1122 (void) ioctl(to, MTIOCTOP, &bsr);
1123 if (ioctl(to, MTIOCTOP, &eom) < 0)
1124 (void) ioctl(to, MTIOCTOP, &fsf);
1128 * Guess whether the tape is rewinding so we can tell
1129 * the operator if it's going to take a long time.
1131 if (tapeout && isrewind(to)) {
1132 /* tape is probably rewinding */
1133 msg(rewinding);
1137 void
1138 #ifdef __STDC__
1139 trewind(void)
1140 #else
1141 trewind()
1142 #endif
1144 (void) timeclock((time_t)0);
1145 if (offline && (!verify || doingverify)) {
1146 close_rewind();
1147 } else {
1148 just_rewind();
1149 (void) close(to);
1153 void
1154 #ifdef __STDC__
1155 close_rewind(void)
1156 #else
1157 close_rewind()
1158 #endif
1160 char *rewinding = gettext("Tape rewinding\n");
1162 (void) timeclock((time_t)0);
1163 just_rewind();
1165 * The check in just_rewind won't catch the case in
1166 * which the current volume is being taken off-line
1167 * and is not mounted on a no-rewind device (and is
1168 * not the last volume, which is not taken off-line).
1170 if (tapeout && !isrewind(to) && offline) {
1171 /* tape is probably rewinding */
1172 msg(rewinding);
1174 if (offline || autoload) {
1175 static struct mtop offl = { MTOFFL, 0 };
1177 (void) ioctl(to, MTIOCTOP, &offl);
1178 if (diskette)
1179 (void) ioctl(to, FDEJECT, 0);
1181 (void) close(to);
1182 to = -1;
1185 void
1186 #ifdef __STDC__
1187 changevol(void)
1188 #else
1189 changevol()
1190 #endif
1192 char buf1[3000], buf2[3000];
1193 char volname[LBLSIZE+1];
1195 /*CONSTANTCONDITION*/
1196 assert(sizeof (spcl.c_label) < sizeof (volname));
1198 filenum = 1;
1199 nextdevice();
1200 (void) strcpy(spcl.c_label, tlabel);
1202 * Make volume switching as automatic as possible
1203 * while avoiding overwriting volumes. We will
1204 * switch automatically under the following condition:
1205 * 1) The user specified autoloading from the
1206 * command line.
1207 * At one time, we (in the guise of hsmdump) had the
1208 * concept of a sequence of devices to rotate through,
1209 * but that's never been a ufsdump feature.
1211 if (autoload) {
1212 int tries;
1215 * Stop the clock for throughput calculations.
1217 if ((telapsed != NULL) && (tstart_writing != NULL)) {
1218 *telapsed += time(NULL) - *tstart_writing;
1221 (void) snprintf(volname, sizeof (volname), "#%d", tapeno+1);
1222 (void) snprintf(buf1, sizeof (buf1), gettext(
1223 "Mounting volume %s on %s\n"), volname, dumpdev);
1224 msg(buf1);
1225 broadcast(buf1);
1228 * Wait for the tape to autoload. Note that the delay
1229 * period doesn't take into account however long it takes
1230 * for the open to fail (measured at 21 seconds for an
1231 * Exabyte 8200 under 2.7 on an Ultra 2).
1233 for (tries = 0; tries < autoload_tries; tries++) {
1234 int f, m;
1236 m = (access(tape, F_OK) == 0) ? 0 : O_CREAT;
1237 if ((f = doingverify ?
1238 safe_device_open(tape, O_RDONLY, 0600) :
1239 safe_device_open(tape, O_RDONLY|m, 0600))
1240 >= 0) {
1241 (void) close(f);
1242 return;
1244 (void) sleep(autoload_period);
1247 * Autoload timed out, ask the operator to do it.
1248 * Note that query() will update *telapsed, and we
1249 * shouldn't charge for the autoload time. So, since
1250 * we updated *telapsed ourselves above, we just set
1251 * tstart_writing to the current time, and query()
1252 * will end up making a null-effect change. This,
1253 * of course, assumes that our caller will be resetting
1254 * *tstart_writing. This is currently the case.
1255 * If tstart_writing is NULL (should never happen),
1256 * we're ok, since time(2) will accept a NULL pointer.
1258 (void) time(tstart_writing);
1261 if (strncmp(spcl.c_label, "none", 5)) {
1262 (void) strncpy(volname, spcl.c_label, sizeof (spcl.c_label));
1263 volname[sizeof (spcl.c_label)] = '\0';
1264 } else
1265 (void) snprintf(volname, sizeof (volname), "#%d", tapeno+1);
1267 timeest(1, spcl.c_tapea);
1268 (void) snprintf(buf1, sizeof (buf1), gettext(
1269 "Change Volumes: Mount volume `%s' on `%s'\n"), volname, dumpdev);
1270 msg(buf1);
1271 broadcast(gettext("CHANGE VOLUMES!\7\7\n"));
1272 (void) snprintf(buf1, sizeof (buf1), gettext(
1273 "Is the new volume (%s) mounted on `%s' and ready to go?: %s"),
1274 volname, dumpdev, gettext("(\"yes\" or \"no\") "));
1275 while (!query(buf1)) {
1276 (void) snprintf(buf2, sizeof (buf2), gettext(
1277 "Do you want to abort dump?: (\"yes\" or \"no\") "));
1278 if (query(buf2)) {
1279 dumpabort();
1280 /*NOTREACHED*/
1286 * We implement taking and restoring checkpoints on the tape level.
1287 * When each tape is opened, a new process is created by forking; this
1288 * saves all of the necessary context in the parent. The child
1289 * continues the dump; the parent waits around, saving the context.
1290 * If the child returns X_REWRITE, then it had problems writing that tape;
1291 * this causes the parent to fork again, duplicating the context, and
1292 * everything continues as if nothing had happened.
1295 void
1296 otape(int top)
1298 static struct mtget mt;
1299 char buf[3000];
1300 pid_t parentpid;
1301 pid_t childpid;
1302 pid_t waitproc;
1303 int status;
1304 struct sigvec sv, osv;
1306 sv.sv_flags = SA_RESTART;
1307 (void) sigemptyset(&sv.sa_mask);
1308 sv.sv_handler = SIG_IGN;
1309 (void) sigvec(SIGINT, &sv, NULL);
1311 parentpid = getpid();
1313 if (verify) {
1314 if (doingverify)
1315 doingverify = 0;
1316 else
1317 Exit(X_VERIFY);
1319 restore_check_point:
1321 sv.sv_handler = interrupt;
1322 (void) sigvec(SIGINT, &sv, NULL);
1323 (void) fflush(stderr);
1325 * All signals are inherited...
1327 sighold(SIGINT);
1328 childpid = fork();
1329 if (childpid < 0) {
1330 msg(gettext(
1331 "Context-saving fork failed in parent %ld\n"),
1332 (long)parentpid);
1333 Exit(X_ABORT);
1335 if (childpid != 0) {
1337 * PARENT:
1338 * save the context by waiting
1339 * until the child doing all of the work returns.
1340 * let the child catch user interrupts
1342 sv.sv_handler = SIG_IGN;
1343 (void) sigvec(SIGINT, &sv, NULL);
1344 sigrelse(SIGINT);
1345 #ifdef TDEBUG
1347 /* XGETTEXT: #ifdef TDEBUG only */
1348 msg(gettext(
1349 "Volume: %d; parent process: %ld child process %ld\n"),
1350 tapeno+1, (long)parentpid, (long)childpid);
1351 #endif /* TDEBUG */
1352 for (;;) {
1353 waitproc = waitpid(0, &status, 0);
1354 if (waitproc == childpid)
1355 break;
1356 msg(gettext(
1357 "Parent %ld waiting for child %ld had another child %ld return\n"),
1358 (long)parentpid, (long)childpid, (long)waitproc);
1360 if (WIFSIGNALED(status)) {
1361 msg(gettext("Process %ld killed by signal %d: %s\n"),
1362 (long)childpid, WTERMSIG(status),
1363 strsignal(WTERMSIG(status)));
1364 status = X_ABORT;
1365 } else
1366 status = WEXITSTATUS(status);
1367 #ifdef TDEBUG
1368 switch (status) {
1369 case X_FINOK:
1370 /* XGETTEXT: #ifdef TDEBUG only */
1371 msg(gettext(
1372 "Child %ld finishes X_FINOK\n"), (long)childpid);
1373 break;
1374 case X_ABORT:
1375 /* XGETTEXT: #ifdef TDEBUG only */
1376 msg(gettext(
1377 "Child %ld finishes X_ABORT\n"), (long)childpid);
1378 break;
1379 case X_REWRITE:
1380 /* XGETTEXT: #ifdef TDEBUG only */
1381 msg(gettext(
1382 "Child %ld finishes X_REWRITE\n"), (long)childpid);
1383 break;
1384 case X_RESTART:
1385 /* XGETTEXT: #ifdef TDEBUG only */
1386 msg(gettext(
1387 "Child %ld finishes X_RESTART\n"), (long)childpid);
1388 break;
1389 case X_VERIFY:
1390 /* XGETTEXT: #ifdef TDEBUG only */
1391 msg(gettext(
1392 "Child %ld finishes X_VERIFY\n"), (long)childpid);
1393 break;
1394 default:
1395 /* XGETTEXT: #ifdef TDEBUG only */
1396 msg(gettext("Child %ld finishes unknown %d\n"),
1397 (long)childpid, status);
1398 break;
1400 #endif /* TDEBUG */
1401 switch (status) {
1402 case X_FINOK:
1403 /* wait for children */
1404 while (waitpid(0, (int *)0, 0) >= 0)
1405 /*LINTED [empty body]*/
1406 continue;
1407 Exit(X_FINOK);
1408 /*NOTREACHED*/
1409 case X_ABORT:
1410 Exit(X_ABORT);
1411 /*NOTREACHED*/
1412 case X_VERIFY:
1413 doingverify++;
1414 goto restore_check_point;
1415 /*NOTREACHED*/
1416 case X_REWRITE:
1417 doingverify = 0;
1418 changevol();
1419 goto restore_check_point;
1420 /* NOTREACHED */
1421 case X_RESTART:
1422 doingverify = 0;
1423 if (!top) {
1424 Exit(X_RESTART);
1426 if (!offline)
1427 autoload = 0;
1428 changevol();
1429 sv.sv_handler = interrupt;
1430 (void) sigvec(SIGINT, &sv, NULL);
1431 return;
1432 /* NOTREACHED */
1433 default:
1434 msg(gettext("Bad return code from dump: %d\n"), status);
1435 Exit(X_ABORT);
1436 /*NOTREACHED*/
1438 /*NOTREACHED*/
1439 } else { /* we are the child; just continue */
1440 child_chdir();
1441 sigrelse(SIGINT);
1442 #ifdef TDEBUG
1443 (void) sleep(4); /* time for parent's message to get out */
1444 /* XGETTEXT: #ifdef TDEBUG only */
1445 msg(gettext(
1446 "Child on Volume %d has parent %ld, my pid = %ld\n"),
1447 tapeno+1, (long)parentpid, (long)getpid());
1448 #endif
1449 (void) snprintf(buf, sizeof (buf), gettext(
1450 "Cannot open `%s'. Do you want to retry the open?: (\"yes\" or \"no\") "),
1451 dumpdev);
1452 if (doingverify) {
1453 /* 1 for stdout */
1454 while ((to = pipeout ? 1 :
1455 safe_device_open(tape, O_RDONLY, 0600)) < 0) {
1456 perror(tape);
1457 if (autoload) {
1458 if (!query_once(buf, 1)) {
1459 dumpabort();
1460 /*NOTREACHED*/
1462 } else {
1463 if (!query(buf)) {
1464 dumpabort();
1465 /*NOTREACHED*/
1471 * If we're using the non-rewinding tape device,
1472 * the tape will be left positioned after the
1473 * EOF mark. We need to back up to the beginning
1474 * of this tape file (cross two tape marks in the
1475 * reverse direction and one in the forward
1476 * direction) before the verify pass.
1478 static struct mtop bsf = { MTBSF, 2 };
1479 static struct mtop fsf = { MTFSF, 1 };
1480 static struct mtop nbsf = { MTNBSF, 1 };
1482 if (ioctl(to, MTIOCTOP, &bsf) >= 0)
1483 (void) ioctl(to, MTIOCTOP, &fsf);
1484 else
1485 (void) ioctl(to, MTIOCTOP, &nbsf);
1486 } else {
1488 * XXX Add logic to test for "tape" being a
1489 * XXX device or a non-existent file.
1490 * Current behaviour is that it must exist,
1491 * and we over-write whatever's there.
1492 * This can be bad if tape == "/etc/passwd".
1494 if (!pipeout && doposition && (tapeno == 0)) {
1495 positiontape(buf);
1496 if (setjmp(alrm_buf)) {
1498 * The tape is rewinding;
1499 * we're screwed.
1501 msg(gettext(
1502 "Cannot position tape using rewind device!\n"));
1503 dumpabort();
1504 /*NOTREACHED*/
1505 } else {
1506 sv.sv_handler = alrm;
1507 (void) sigvec(SIGALRM, &sv, &osv);
1508 (void) alarm(15);
1510 while ((to = safe_device_open(tape, O_WRONLY,
1511 0600)) < 0)
1512 (void) sleep(10);
1513 (void) alarm(0);
1514 (void) sigvec(SIGALRM, &osv,
1515 NULL);
1516 } else {
1517 int m;
1518 m = (access(tape, F_OK) == 0) ? 0 : O_CREAT;
1520 * Only verify the tape label if label
1521 * verification is on and we are at BOT
1523 if (pipeout)
1524 to = 1;
1525 else while ((to = safe_device_open(tape,
1526 O_WRONLY|m, 0600)) < 0)
1527 if (!query_once(buf, 1)) {
1528 dumpabort();
1529 /*NOTREACHED*/
1533 if (!pipeout) {
1534 tapeout = ioctl(to, MTIOCGET, &mt) >= 0; /* set state */
1536 * Make sure the tape is positioned
1537 * where it is supposed to be
1539 if (tapeout && (tapeno > 0) &&
1540 (mt.mt_fileno != (filenum-1))) {
1541 (void) snprintf(buf, sizeof (buf), gettext(
1542 "Warning - tape positioning error!\n\
1543 \t%s current file %ld, should be %ld\n"),
1544 tape, mt.mt_fileno+1, filenum);
1545 msg(buf);
1546 dumpailing();
1549 tapeno++; /* current tape sequence */
1550 if (tapeno < TP_NINOS)
1551 inos[tapeno] = chkpt.sl_inos;
1552 spcl.c_firstrec = chkpt.sl_firstrec;
1553 spcl.c_tapea = (*tapea) = chkpt.sl_tapea;
1554 spcl.c_volume++;
1556 enslave(); /* Share tape buffers with slaves */
1558 #ifdef DEBUG
1559 if (xflag) {
1560 /* XGETTEXT: #ifdef DEBUG only */
1561 msg(gettext("Checkpoint state:\n"));
1562 msg(" blockswritten %u\n", blockswritten);
1563 msg(" ino %u\n", ino);
1564 msg(" pos %u\n", pos);
1565 msg(" left %u\n", leftover);
1566 msg(" tapea %u\n", (*tapea));
1567 msg(" state %d\n", dumpstate);
1569 #endif
1570 spcl.c_type = TS_TAPE;
1571 spcl.c_tpbsize = tp_bsize;
1572 if (leftover == 0) {
1573 spcl.c_count = 0;
1574 spclrec();
1575 newtape = 0;
1576 } else
1577 newtape++; /* new volume indication */
1578 if (doingverify) {
1579 msg(gettext("Starting verify pass\n"));
1580 } else if (tapeno > 1) {
1581 msg(gettext(
1582 "Volume %d begins with blocks from inode %lu\n"),
1583 tapeno, chkpt.sl_inos);
1585 (void) timeclock((time_t)1);
1586 (void) time(tstart_writing);
1587 timeest(0, spcl.c_tapea);
1591 void
1592 #ifdef __STDC__
1593 dumpabort(void)
1594 #else
1595 dumpabort()
1596 #endif
1599 if (master && master != getpid())
1601 * signal master to call dumpabort
1603 (void) kill(master, SIGTERM);
1604 else {
1605 killall();
1607 if (archivefile && archive_opened)
1608 (void) unlink(archivefile);
1609 msg(gettext("The ENTIRE dump is aborted.\n"));
1611 Exit(X_ABORT);
1614 void
1615 dumpailing(void)
1618 broadcast(gettext("DUMP IS AILING!\n"));
1619 if (!query(gettext(
1620 "Do you want to attempt to continue? (\"yes\" or \"no\") "))) {
1621 dumpabort();
1622 /*NOTREACHED*/
1626 void
1627 Exit(status)
1630 * Clean up message system
1632 #ifdef TDEBUG
1634 /* XGETTEXT: #ifdef TDEBUG only */
1635 msg(gettext("pid = %ld exits with status %d\n"),
1636 (long)getpid(), status);
1637 #endif /* TDEBUG */
1638 exit(status);
1641 static void
1642 #ifdef __STDC__
1643 killall(void)
1644 #else
1645 killall()
1646 #endif
1648 struct slaves *slavep;
1650 for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++)
1651 if (slavep->sl_slavepid > 0) {
1652 (void) kill(slavep->sl_slavepid, SIGKILL);
1653 #ifdef TDEBUG
1655 /* XGETTEXT: #ifdef TDEBUG only */
1656 msg(gettext("Slave child %ld killed\n"),
1657 (long)slavep->sl_slavepid);
1658 #endif
1660 if (writepid) {
1661 (void) kill(writepid, SIGKILL);
1662 #ifdef TDEBUG
1664 /* XGETTEXT: #ifdef TDEBUG only */
1665 msg(gettext("Writer child %ld killed\n"), (long)writepid);
1666 #endif
1668 if (archivepid) {
1669 (void) kill(archivepid, SIGKILL);
1670 #ifdef TDEBUG
1672 /* XGETTEXT: #ifdef TDEBUG only */
1673 msg(gettext("Archiver child %ld killed\n"), (long)archivepid);
1674 #endif
1678 /*ARGSUSED*/
1679 static void
1680 proceed(int sig)
1682 caught++;
1685 /*ARGSUSED*/
1686 static void
1687 die(int sig)
1689 Exit(X_FINOK);
1692 static void
1693 #ifdef __STDC__
1694 enslave(void)
1695 #else
1696 enslave()
1697 #endif
1699 int cmd[2]; /* file descriptors */
1700 int i;
1701 struct sigvec sv;
1702 struct slaves *slavep;
1703 int saverr;
1705 sv.sv_flags = SA_RESTART;
1706 (void) sigemptyset(&sv.sa_mask);
1707 master = getpid();
1709 * slave sends SIGTERM on dumpabort
1711 sv.sv_handler = (void(*)(int))dumpabort;
1712 (void) sigvec(SIGTERM, &sv, NULL);
1713 sv.sv_handler = tperror;
1714 (void) sigvec(SIGUSR2, &sv, NULL);
1715 sv.sv_handler = proceed;
1716 (void) sigvec(SIGUSR1, &sv, NULL);
1717 totalrecsout += recsout;
1718 caught = 0;
1719 recsout = 0;
1720 rotor = 0;
1721 bufclear();
1722 for (slavep = &slaves[0]; slavep < &slaves[SLAVES]; slavep++)
1723 slavep->sl_slavefd = -1;
1724 archivefd = arch = writer = -1;
1725 for (i = 0; i < SLAVES; i++) {
1726 if (pipe(cmd) < 0) {
1727 saverr = errno;
1728 msg(gettext(
1729 "Cannot create pipe for slave process: %s\n"),
1730 strerror(saverr));
1731 dumpabort();
1732 /*NOTREACHED*/
1734 sighold(SIGUSR2);
1735 sighold(SIGINT);
1736 sighold(SIGTERM);
1737 if ((slaves[i].sl_slavepid = fork()) < 0) {
1738 saverr = errno;
1739 msg(gettext("Cannot create slave process: %s\n"),
1740 strerror(saverr));
1741 dumpabort();
1742 /*NOTREACHED*/
1744 slaves[i].sl_slavefd = cmd[1];
1745 if (slaves[i].sl_slavepid == 0) { /* Slave starts up here */
1746 pid_t next; /* pid of neighbor */
1748 sv.sv_handler = SIG_DFL;
1749 (void) sigvec(SIGUSR2, &sv, NULL);
1750 sv.sv_handler = SIG_IGN; /* master handler INT */
1751 (void) sigvec(SIGINT, &sv, NULL);
1752 sv.sv_handler = die; /* normal slave exit */
1753 (void) sigvec(SIGTERM, &sv, NULL);
1755 child_chdir();
1756 sigrelse(SIGUSR2);
1757 sigrelse(SIGINT);
1758 sigrelse(SIGTERM);
1760 freeino(); /* release unneeded resources */
1761 #ifdef TDEBUG
1762 (void) sleep(4); /* time for parent's message to get out */
1763 /* XGETTEXT: #ifdef TDEBUG only */
1764 msg(gettext("Neighbor has pid = %ld\n"), (long)getpid());
1765 #endif
1766 /* Closes cmd[1] as a side-effect */
1767 for (slavep = &slaves[0];
1768 slavep < &slaves[SLAVES];
1769 slavep++)
1770 if (slavep->sl_slavefd >= 0) {
1771 (void) close(slavep->sl_slavefd);
1772 slavep->sl_slavefd = -1;
1774 (void) close(to);
1775 (void) close(fi); /* Need our own seek ptr */
1776 to = -1;
1778 fi = open(disk, O_RDONLY);
1780 if (fi < 0) {
1781 saverr = errno;
1782 msg(gettext(
1783 "Cannot open dump device `%s': %s\n"),
1784 disk, strerror(saverr));
1785 dumpabort();
1786 /*NOTREACHED*/
1789 if ((unsigned)atomic((int(*)())read, cmd[0],
1790 (char *)&next, sizeof (next)) != sizeof (next)) {
1791 cmdrderr();
1792 dumpabort();
1793 /*NOTREACHED*/
1795 dumpoffline(cmd[0], next, i);
1796 Exit(X_FINOK);
1798 /* Parent continues here */
1799 sigrelse(SIGUSR2);
1800 sigrelse(SIGINT);
1801 sigrelse(SIGTERM);
1802 (void) close(cmd[0]);
1805 if (archive) {
1806 archivepid = setuparchive();
1807 if (!archivepid) {
1808 dumpabort();
1809 /*NOTREACHED*/
1813 writepid = setupwriter();
1814 if (!writepid) {
1815 dumpabort();
1816 /*NOTREACHED*/
1819 if (arch >= 0) {
1820 (void) close(arch); /* only writer has this open */
1821 arch = -1;
1824 /* Tell each slave who follows it */
1825 for (i = 0; i < SLAVES; i++) {
1826 if ((unsigned)atomic((int(*)())write, slaves[i].sl_slavefd,
1827 (char *)&(slaves[(i + 1) % SLAVES].sl_slavepid),
1828 sizeof (int)) != sizeof (int)) {
1829 cmdwrterr();
1830 dumpabort();
1831 /*NOTREACHED*/
1834 sv.sv_handler = rollforward; /* rcvd from writer on EOT */
1835 (void) sigvec(SIGUSR1, &sv, NULL);
1836 slp = slaves;
1837 (void) kill(slp->sl_slavepid, SIGUSR1);
1838 master = 0;
1841 static void
1842 #ifdef __STDC__
1843 wait_our_turn(void)
1844 #else
1845 wait_our_turn()
1846 #endif
1848 (void) sighold(SIGUSR1);
1850 if (!caught) {
1851 #ifdef INSTRUMENT
1852 (*idle)++;
1853 #endif
1854 (void) sigpause(SIGUSR1);
1856 caught = 0;
1857 (void) sigrelse(SIGUSR1);
1860 static void
1861 dumpoffline(int cmd, pid_t next, int mynum)
1863 struct req *p = slaves[mynum].sl_req;
1864 ulong_t i;
1865 uchar_t *cp;
1866 uchar_t *blkbuf;
1867 int notactive = 0;
1869 blkbuf = xmalloc(sblock->fs_bsize);
1871 /*CONSTANTCONDITION*/
1872 assert(sizeof (spcl) == TP_BSIZE_MIN);
1874 while (atomic((int(*)())read, cmd, (char *)p, reqsiz) == reqsiz) {
1875 if (p->br_dblk) {
1876 bread(p->br_dblk, (uchar_t *)blkbuf, p->br_size);
1877 } else {
1878 bcopy((char *)p->br_spcl, (char *)&spcl,
1879 sizeof (spcl));
1880 ino = spcl.c_inumber;
1882 dumptoarchive = p->aflag & BUF_ARCHIVE;
1883 wait_our_turn();
1884 if (p->br_dblk) {
1885 for (i = p->br_size, cp = blkbuf;
1886 i > 0;
1887 /* LINTED character pointers aren't signed */
1888 cp += i > tp_bsize ? tp_bsize : i,
1889 i -= i > tp_bsize ? tp_bsize : i) {
1890 /* LINTED unsigned to signed conversion ok */
1891 taprec(cp, 0, i > tp_bsize ? tp_bsize : (int)i);
1893 } else
1894 spclrec();
1895 (void) kill(next, SIGUSR1); /* Next slave's turn */
1897 * Note that we lie about file activity since we don't
1898 * check for it.
1900 if ((unsigned)atomic((int(*)())write, cmd, (char *)&notactive,
1901 sizeof (notactive)) != sizeof (notactive)) {
1902 cmdwrterr();
1903 dumpabort();
1904 /*NOTREACHED*/
1908 free(blkbuf);
1911 static int count; /* tape blocks written since last spclrec */
1913 /*ARGSUSED*/
1914 static void
1915 onxfsz(int sig)
1917 msg(gettext("File size limit exceeded writing output volume %d\n"),
1918 tapeno);
1919 (void) kill(master, SIGUSR2);
1920 Exit(X_REWRITE);
1923 static long lastnonaddr; /* last DS_{INODE,CLRI,BITS} written */
1924 static long lastnonaddrm; /* and the mode thereof */
1926 * dowrite -- the main body of the output writer process
1928 static void
1929 dowrite(int cmd)
1931 struct bdesc *last =
1932 &bufp[(NBUF*ntrec)-1]; /* last buffer in pool */
1933 struct bdesc *bp = bufp; /* current buf in tape block */
1934 struct bdesc *begin = bufp; /* first buf of tape block */
1935 struct bdesc *end = bufp + (ntrec-1); /* last buf of tape block */
1936 int siz; /* bytes written (block) */
1937 int trecs; /* records written (block) */
1938 long asize = 0; /* number of 0.1" units... */
1939 /* ...written on current tape */
1940 char *tp, *rbuf = NULL;
1941 char *recmap = spcl.c_addr; /* current tape record map */
1942 char *endmp; /* end of valid map data */
1943 char *mp; /* current map entry */
1944 union u_spcl *sp;
1946 (void) signal(SIGXFSZ, onxfsz);
1948 bzero((char *)&spcl, sizeof (spcl));
1949 count = 0;
1951 if (doingverify) {
1952 rbuf = (char *)malloc((uint_t)writesize);
1953 if (rbuf == 0) {
1954 /* Restart from checkpoint */
1955 (void) kill(master, SIGUSR2);
1956 Exit(X_REWRITE);
1960 for (;;) {
1961 /* START: wait until all buffers in tape block are full */
1962 if ((bp->b_flags & BUF_FULL) == 0) {
1963 if (caught) { /* master signalled flush */
1964 (void) sighold(SIGUSR1);
1965 caught = 0;
1966 /* signal ready */
1967 (void) kill(master, SIGUSR1);
1968 chkpt.sl_count = 0; /* signal not at EOT */
1969 checkpoint(bp-1, cmd); /* send data */
1970 (void) sigpause(SIGUSR1);
1971 break;
1973 #ifdef INSTRUMENT
1974 (*readmissp)++;
1975 #endif
1976 nap(50);
1977 continue;
1979 if (bp < end) {
1980 bp++;
1981 continue;
1983 /* END: wait until all buffers in tape block are full */
1985 tp = begin->b_data;
1986 (void) sighold(SIGUSR1);
1987 if (!doingverify)
1988 siz = write(to, tp, writesize);
1989 else if ((siz = read(to, rbuf, writesize)) ==
1990 writesize && bcmp(rbuf, tp, writesize))
1991 siz = -1;
1992 if (siz < 0 && diskette && errno == ENOSPC)
1993 siz = 0; /* really EOF */
1994 (void) sigrelse(SIGUSR1);
1995 if (siz < 0 ||
1996 (pipeout && siz != writesize)) {
1997 char buf[3000];
2000 * Isn't i18n wonderful?
2002 if (doingverify) {
2003 if (diskette)
2004 (void) snprintf(buf, sizeof (buf),
2005 gettext(
2006 "Verification error %ld blocks into diskette %d\n"),
2007 asize * 2, tapeno);
2008 else if (tapeout)
2009 (void) snprintf(buf, sizeof (buf),
2010 gettext(
2011 "Verification error %ld feet into tape %d\n"),
2012 (cartridge ? asize/tracks :
2013 asize)/120L,
2014 tapeno);
2015 else
2016 (void) snprintf(buf, sizeof (buf),
2017 gettext(
2018 "Verification error %ld blocks into volume %d\n"),
2019 asize * 2, tapeno);
2021 } else {
2022 if (diskette)
2023 (void) snprintf(buf, sizeof (buf),
2024 gettext(
2025 "Write error %ld blocks into diskette %d\n"),
2026 asize * 2, tapeno);
2027 else if (tapeout)
2028 (void) snprintf(buf, sizeof (buf),
2029 gettext(
2030 "Write error %ld feet into tape %d\n"),
2031 (cartridge ? asize/tracks :
2032 asize)/120L, tapeno);
2033 else
2034 (void) snprintf(buf, sizeof (buf),
2035 gettext(
2036 "Write error %ld blocks into volume %d\n"),
2037 asize * 2, tapeno);
2040 msg(buf);
2041 /* Restart from checkpoint */
2042 #ifdef TDEBUG
2044 /* XGETTEXT: #ifdef TDEBUG only */
2045 msg(gettext("sending SIGUSR2 to pid %ld\n"), master);
2046 #endif
2047 (void) kill(master, SIGUSR2);
2048 Exit(X_REWRITE);
2050 trecs = siz / tp_bsize;
2051 if (diskette)
2052 asize += trecs; /* asize == blocks written */
2053 else
2054 asize += (siz/density + tenthsperirg);
2055 if (trecs)
2056 chkpt.sl_firstrec++;
2057 for (bp = begin; bp < begin + trecs; bp++) {
2058 if ((arch >= 0) && (bp->b_flags & BUF_ARCHIVE)) {
2059 if ((unsigned)atomic((int(*)())write, arch,
2060 (char *)&bp->b_flags, sizeof (bp->b_flags))
2061 != sizeof (bp->b_flags)) {
2062 cmdwrterr();
2063 dumpabort();
2064 /*NOTREACHED*/
2066 if (atomic((int(*)())write, arch, bp->b_data,
2067 tp_bsize) != tp_bsize) {
2068 cmdwrterr();
2069 dumpabort();
2070 /*NOTREACHED*/
2073 if (bp->b_flags & BUF_SPCLREC) {
2074 /*LINTED [bp->b_data is aligned]*/
2075 sp = (union u_spcl *)bp->b_data;
2076 if (sp->s_spcl.c_type != TS_ADDR) {
2077 lastnonaddr = sp->s_spcl.c_type;
2078 lastnonaddrm =
2079 sp->s_spcl.c_dinode.di_mode;
2080 if (sp->s_spcl.c_type != TS_TAPE)
2081 chkpt.sl_offset = 0;
2083 chkpt.sl_count = sp->s_spcl.c_count;
2084 bcopy((char *)sp,
2085 (char *)&spcl, sizeof (spcl));
2086 mp = recmap;
2087 endmp = &recmap[spcl.c_count];
2088 count = 0;
2089 } else {
2090 chkpt.sl_offset++;
2091 chkpt.sl_count--;
2092 count++;
2093 mp++;
2096 * Adjust for contiguous hole
2098 for (; mp < endmp; mp++) {
2099 if (*mp)
2100 break;
2101 chkpt.sl_offset++;
2102 chkpt.sl_count--;
2106 * Check for end of tape
2108 if (trecs < ntrec ||
2109 (!pipeout && tsize > 0 && asize > tsize)) {
2110 if (tapeout)
2111 msg(gettext("End-of-tape detected\n"));
2112 else
2113 msg(gettext("End-of-file detected\n"));
2114 (void) sighold(SIGUSR1);
2115 caught = 0;
2116 (void) kill(master, SIGUSR1); /* signal EOT */
2117 checkpoint(--bp, cmd); /* send checkpoint data */
2118 (void) sigpause(SIGUSR1);
2119 break;
2121 for (bp = begin; bp <= end; bp++)
2122 bp->b_flags = BUF_EMPTY;
2123 if (end + ntrec > last) {
2124 bp = begin = bufp;
2125 timeest(0, spcl.c_tapea);
2126 } else
2127 bp = begin = end+1;
2128 end = begin + (ntrec-1);
2131 free(rbuf);
2135 * Send checkpoint info back to master. This information
2136 * consists of the current inode number, number of logical
2137 * blocks written for that inode (or bitmap), the last logical
2138 * block number written, the number of logical blocks written
2139 * to this volume, the current dump state, and the current
2140 * special record map.
2142 static void
2143 checkpoint(struct bdesc *bp, int cmd)
2145 int state, type;
2146 ino_t ino;
2148 if (++bp >= &bufp[NBUF*ntrec])
2149 bp = bufp;
2152 * If we are dumping files and the record following
2153 * the last written to tape is a special record, use
2154 * it to get an accurate indication of current state.
2156 if ((bp->b_flags & BUF_SPCLREC) && (bp->b_flags & BUF_FULL) &&
2157 lastnonaddr == TS_INODE) {
2158 /*LINTED [bp->b_data is aligned]*/
2159 union u_spcl *nextspcl = (union u_spcl *)bp->b_data;
2161 if (nextspcl->s_spcl.c_type == TS_INODE) {
2162 chkpt.sl_offset = 0;
2163 chkpt.sl_count = 0;
2164 } else if (nextspcl->s_spcl.c_type == TS_END) {
2165 chkpt.sl_offset = 0;
2166 chkpt.sl_count = 1; /* EOT indicator */
2168 ino = nextspcl->s_spcl.c_inumber;
2169 type = nextspcl->s_spcl.c_type;
2170 } else {
2172 * If not, use what we have.
2174 ino = spcl.c_inumber;
2175 type = spcl.c_type;
2178 switch (type) { /* set output state */
2179 case TS_ADDR:
2180 switch (lastnonaddr) {
2181 case TS_INODE:
2182 case TS_TAPE:
2183 if ((lastnonaddrm & IFMT) == IFDIR ||
2184 (lastnonaddrm & IFMT) == IFATTRDIR)
2185 state = DS_DIRS;
2186 else
2187 state = DS_FILES;
2188 break;
2189 case TS_CLRI:
2190 state = DS_CLRI;
2191 break;
2192 case TS_BITS:
2193 state = DS_BITS;
2194 break;
2196 break;
2197 case TS_INODE:
2198 if ((spcl.c_dinode.di_mode & IFMT) == IFDIR ||
2199 (spcl.c_dinode.di_mode & IFMT) == IFATTRDIR)
2200 state = DS_DIRS;
2201 else
2202 state = DS_FILES;
2203 break;
2204 case 0: /* EOT on 1st record */
2205 case TS_TAPE:
2206 state = DS_START;
2207 ino = UFSROOTINO;
2208 break;
2209 case TS_CLRI:
2210 state = DS_CLRI;
2211 break;
2212 case TS_BITS:
2213 state = DS_BITS;
2214 break;
2215 case TS_END:
2216 if (spcl.c_type == TS_END)
2217 state = DS_DONE;
2218 else
2219 state = DS_END;
2220 break;
2224 * Checkpoint info to be processed by rollforward():
2225 * The inode with which the next volume should begin
2226 * The last inode number on this volume
2227 * The last logical block number on this volume
2228 * The current output state
2229 * The offset within the current inode (already in sl_offset)
2230 * The number of records left from last spclrec (in sl_count)
2231 * The physical block the next vol begins with (in sl_firstrec)
2233 chkpt.sl_inos = ino;
2234 chkpt.sl_tapea = spcl.c_tapea + count;
2235 chkpt.sl_state = state;
2237 if ((unsigned)atomic((int(*)())write, cmd, (char *)&chkpt,
2238 sizeof (chkpt)) != sizeof (chkpt)) {
2239 cmdwrterr();
2240 dumpabort();
2241 /*NOTREACHED*/
2243 if ((unsigned)atomic((int(*)())write, cmd, (char *)&spcl,
2244 sizeof (spcl)) != sizeof (spcl)) {
2245 cmdwrterr();
2246 dumpabort();
2247 /*NOTREACHED*/
2249 #ifdef DEBUG
2250 if (xflag) {
2251 /* XGETTEXT: #ifdef DEBUG only */
2252 msg(gettext("sent chkpt to master:\n"));
2253 msg(" ino %u\n", chkpt.sl_inos);
2254 msg(" 1strec %u\n", chkpt.sl_firstrec);
2255 msg(" lastrec %u\n", chkpt.sl_tapea);
2256 msg(" written %u\n", chkpt.sl_offset);
2257 msg(" left %u\n", chkpt.sl_count);
2258 msg(" state %d\n", chkpt.sl_state);
2260 #endif
2264 * Since a read from a pipe may not return all we asked for,
2265 * or a write may not write all we ask if we get a signal,
2266 * loop until the count is satisfied (or error).
2268 static ssize_t
2269 atomic(int (*func)(), int fd, char *buf, int count)
2271 ssize_t got = 0, need = count;
2273 /* don't inherit random value if immediately get zero back from func */
2274 errno = 0;
2275 while (need > 0) {
2276 got = (*func)(fd, buf, MIN(need, 4096));
2277 if (got < 0 && errno == EINTR)
2278 continue;
2279 if (got <= 0)
2280 break;
2281 buf += got;
2282 need -= got;
2284 /* if we got what was asked for, return count, else failure (got) */
2285 return ((need != 0) ? got : count);
2288 void
2289 #ifdef __STDC__
2290 positiontape(char *msgbuf)
2291 #else
2292 positiontape(char *msgbuf)
2293 #endif
2295 /* Static as never change, no need to waste stack space */
2296 static struct mtget mt;
2297 static struct mtop rew = { MTREW, 1 };
2298 static struct mtop fsf = { MTFSF, 1 };
2299 char *info = strdup(gettext("Positioning `%s' to file %ld\n"));
2300 char *fail = strdup(gettext("Cannot position tape to file %d\n"));
2301 int m;
2303 /* gettext()'s return value is volatile, hence the strdup()s */
2305 m = (access(tape, F_OK) == 0) ? 0 : O_CREAT;
2308 * To avoid writing tape marks at inappropriate places, we open the
2309 * device read-only, position it, close it, and reopen it for writing.
2311 while ((to = safe_device_open(tape, O_RDONLY|m, 0600)) < 0) {
2312 if (autoload) {
2313 if (!query_once(msgbuf, 1)) {
2314 dumpabort();
2315 /*NOTREACHED*/
2317 } else {
2318 if (!query(msgbuf)) {
2319 dumpabort();
2320 /*NOTREACHED*/
2325 if (ioctl(to, MTIOCGET, &mt) >= 0 &&
2326 ioctl(to, MTIOCTOP, &rew) >= 0 &&
2327 filenum > 1) {
2328 msg(info, dumpdev, filenum);
2329 fsf.mt_count = filenum - 1;
2330 if (ioctl(to, MTIOCTOP, &fsf) < 0) {
2331 msg(fail, filenum);
2332 dumpabort();
2333 /*NOTREACHED*/
2336 (void) close(to);
2337 to = -1;
2339 free(info);
2340 free(fail);
2343 static void
2344 #ifdef __STDC__
2345 cmdwrterr(void)
2346 #else
2347 cmdwrterr()
2348 #endif
2350 int saverr = errno;
2351 msg(gettext("Error writing command pipe: %s\n"), strerror(saverr));
2354 static void
2355 #ifdef __STDC__
2356 cmdrderr(void)
2357 #else
2358 cmdrderr()
2359 #endif
2361 int saverr = errno;
2362 msg(gettext("Error reading command pipe: %s\n"), strerror(saverr));