1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * Copyright (c) 1980 Regents of the University of California.
32 * All rights reserved. The Berkeley software License Agreement
33 * specifies the terms and conditions for redistribution.
34 */
35
36 #include "dump.h"
37 #include <rmt.h>
38 #include <sys/mtio.h>
39 #include <limits.h>
40 #include <priv_utils.h>
41 #include "roll_log.h"
42 #include <unistd.h>
43
44 int notify = 0; /* notify operator flag */
45 int blockswritten = 0; /* number of blocks written on current tape */
46 uint_t tapeno = 0; /* current tape number */
47 daddr32_t filenum = 0; /* current file number on tape */
48 int density = 0; /* density in bytes/0.1" */
49 int tenthsperirg; /* inter-record-gap in 0.1"'s */
50 uint_t ntrec = 0; /* # tape blocks in each tape record */
51 uint_t saved_ntrec = 0; /* saved value of ntrec */
52 uint_t forceflag = 0; /* forced to change tp_bsize */
53 int cartridge = 0; /* assume non-cartridge tape */
54 uint_t tracks; /* # tracks on a cartridge tape */
55 int diskette = 0; /* assume not dumping to a diskette */
56 int printsize = 0; /* just print estimated size and exit */
57 int mapfd = -1; /* if >= 0, file descriptor for mmap */
58 int32_t tp_bsize = TP_BSIZE_MIN; /* tape block record size (frag size) */
59 #ifdef DEBUG
60 int xflag; /* debugging switch */
61 #endif
62
63 char *myname;
64
65 /*
66 * This should be struct fs, but there are trailing bits on disk
67 * that we also need to read in as part of it. It's an array of
68 * longs instead of char to force proper alignment.
69 */
70 static long sblock_buf[SBSIZE/sizeof (long)];
71
72 #ifdef __STDC__
73 static char *mb(u_offset_t);
74 static void nextstate(int);
75 #else
76 static char *mb();
77 static void nextstate();
78 #endif
79
80 extern jmp_buf checkpoint_buf; /* context for return from checkpoint */
81 #define FUDGE_FACTOR 0x2000000
82
83 int
main(int argc,char * argv[])84 main(int argc, char *argv[])
85 {
86 char *arg;
87 int bflag = 0, i, error = 0, saverr;
88 double fetapes = 0.0;
89 struct mnttab *dt;
90 char msgbuf[3000], *msgp;
91 char kbsbuf[BUFSIZ];
92 u_offset_t esize_shift = 0;
93 int32_t new_mult = 0;
94 time32_t snapdate;
95
96 host = NULL;
97
98 if (myname = strrchr(argv[0], '/'))
99 myname++;
100 else
101 myname = argv[0];
102
103 if (strcmp("hsmdump", myname) == 0) {
104 msg(gettext("hsmdump emulation is no longer supported.\n"));
105 Exit(X_ABORT);
106 }
107
108 tape = DEFTAPE;
109 autoload_period = 12;
110 autoload_tries = 12; /* traditional default of ~2.5 minutes */
111
112 (void) setlocale(LC_ALL, "");
113 #if !defined(TEXT_DOMAIN)
114 #define TEXT_DOMAIN "SYS_TEST"
115 #endif /* TEXT_DOMAIN */
116 (void) textdomain(TEXT_DOMAIN);
117
118 /*
119 * If someone strips the set-uid bit, dump will still work for local
120 * tapes. Fail when we try to access a remote tape.
121 */
122 (void) __init_suid_priv(0, PRIV_NET_PRIVADDR, (char *)NULL);
123
124 if (sysinfo(SI_HOSTNAME, spcl.c_host, sizeof (spcl.c_host)) < 0) {
125 saverr = errno;
126 msg(gettext("Could not get host name: %s\n"),
127 strerror(saverr));
128 bzero(spcl.c_host, sizeof (spcl.c_host));
129 }
130
131 dumppid = getpid();
132 tsize = 0; /* no default size, detect EOT dynamically */
133
134 archive_opened = 0;
135 disk = NULL;
136 dname = NULL;
137 disk_dynamic = 0;
138 increm = NINCREM;
139 incno = '9';
140 uflag = 0;
141 arg = "u";
142 tlabel = "none";
143 if (argc > 1) {
144 argv++;
145 argc--;
146 arg = *argv;
147 if (*arg == '-')
148 arg++;
149 }
150 while (*arg)
151 switch (*arg++) { /* BE CAUTIOUS OF FALLTHROUGHS */
152 case 'M':
153 /*
154 * This undocumented option causes each process to
155 * mkdir debug_chdir/getpid(), and chdir to it. This is
156 * to ease the collection of profiling information and
157 * core dumps.
158 */
159 if (argc > 1) {
160 argv++;
161 argc--;
162 debug_chdir = *argv;
163 msg(gettext(
164 "Each process shall try to chdir to %s/<pid>\n"),
165 debug_chdir);
166 child_chdir();
167 } else {
168 msg(gettext("Missing move-to-dir (M) name\n"));
169 dumpabort();
170 /*NOTREACHED*/
171 }
172 break;
173
174 case 'w':
175 lastdump('w'); /* tell us only what has to be done */
176 exit(0);
177 break;
178
179 case 'W': /* what to do */
180 lastdump('W'); /* tell state of what has been done */
181 exit(0); /* do nothing else */
182 break;
183
184 case 'T':
185 if (argc > 1) {
186 int count;
187 int multiplier;
188 char units;
189
190 argv++;
191 argc--;
192 count = atoi(*argv);
193 if (count < 1) {
194 msg(gettext(
195 "Unreasonable autoload timeout period\n"));
196 dumpabort();
197 /*NOTREACHED*/
198 }
199 units = *(*argv + strlen(*argv) - 1);
200 switch (units) {
201 case 's':
202 multiplier = 1;
203 break;
204 case 'h':
205 multiplier = 3600;
206 break;
207 case '0': case '1': case '2': case '3': case '4':
208 case '5': case '6': case '7': case '8': case '9':
209 case 'm':
210 multiplier = 60;
211 break;
212 default:
213 msg(gettext(
214 "Unknown timeout units indicator `%c'\n"),
215 units);
216 dumpabort();
217 /*NOTREACHED*/
218 }
219 autoload_tries = 1 +
220 ((count * multiplier) / autoload_period);
221 } else {
222 msg(gettext("Missing autoload timeout period\n"));
223 dumpabort();
224 /*NOTREACHED*/
225 }
226 break;
227
228 case 'f': /* output file */
229 if (argc > 1) {
230 argv++;
231 argc--;
232 tape = *argv;
233 if (*tape == '\0') {
234 msg(gettext("Bad output device name\n"));
235 dumpabort();
236 /*NOTREACHED*/
237 }
238 } else {
239 msg(gettext("Missing output device name\n"));
240 dumpabort();
241 /*NOTREACHED*/
242 }
243 if (strcmp(tape, "-") == 0 && verify) {
244 msg(gettext(
245 "Cannot verify when dumping to standard out.\n"));
246 dumpabort();
247 /*NOTREACHED*/
248 }
249 break;
250
251 case 'd': /* density, in bits per inch */
252 if (argc > 1) {
253 argv++;
254 argc--;
255 density = atoi(*argv) / 10;
256 if (density <= 0) {
257 msg(gettext(
258 "Density must be a positive integer\n"));
259 dumpabort();
260 /*NOTREACHED*/
261 }
262 } else {
263 msg(gettext("Missing density\n"));
264 dumpabort();
265 /*NOTREACHED*/
266 }
267 break;
268
269 case 's': /* tape size, feet */
270 if (argc > 1) {
271 argv++;
272 argc--;
273 tsize = atol(*argv);
274 if ((*argv[0] == '-') || (tsize == 0)) {
275 msg(gettext(
276 "Tape size must be a positive integer\n"));
277 dumpabort();
278 /*NOTREACHED*/
279 }
280 } else {
281 msg(gettext("Missing tape size\n"));
282 dumpabort();
283 /*NOTREACHED*/
284 }
285 break;
286
287 case 't': /* tracks */
288 if (argc > 1) {
289 argv++;
290 argc--;
291 tracks = atoi(*argv);
292 } else {
293 msg(gettext("Missing track count\n"));
294 dumpabort();
295 /*NOTREACHED*/
296 }
297 break;
298
299 case 'b': /* blocks per tape write */
300 if (argc > 1) {
301 argv++;
302 argc--;
303 bflag++;
304 /*
305 * We save the ntrec in case we need to change
306 * tp_bsize later, we will have to recalculate
307 * it.
308 */
309 saved_ntrec = ntrec = atoi(*argv);
310 if (ntrec == 0 || (ntrec&1) || ntrec > (MAXNTREC*2)) {
311 msg(gettext(
312 "Block size must be a positive, even integer <= %d\n"),
313 MAXNTREC*2);
314 dumpabort();
315 /*NOTREACHED*/
316 }
317 ntrec /= (tp_bsize/DEV_BSIZE);
318 } else {
319 msg(gettext("Missing blocking factor\n"));
320 dumpabort();
321 /*NOTREACHED*/
322 }
323 break;
324
325 case 'c': /* Tape is cart. not 9-track */
326 case 'C': /* 'C' to be consistent with 'D' */
327 cartridge++;
328 break;
329
330 case '0': /* dump level */
331 case '1':
332 case '2':
333 case '3':
334 case '4':
335 case '5':
336 case '6':
337 case '7':
338 case '8':
339 case '9':
340 incno = arg[-1];
341 break;
342
343 case 'u': /* update /etc/dumpdates */
344 uflag++;
345 break;
346
347 case 'n': /* notify operators */
348 notify++;
349 break;
350
351 case 'a': /* create archive file */
352 archive = 1;
353 if (argc > 1) {
354 argv++;
355 argc--;
356 if (**argv == '\0') {
357 msg(gettext("Bad archive file name\n"));
358 dumpabort();
359 /*NOTREACHED*/
360 }
361 archivefile = strdup(*argv);
362 if (archivefile == NULL) {
363 saverr = errno;
364 msg(gettext("Cannot allocate memory: %s\n"),
365 strerror(saverr));
366 dumpabort();
367 /*NOTREACHED*/
368 }
369 } else {
370 msg(gettext("Missing archive file name\n"));
371 dumpabort();
372 /*NOTREACHED*/
373 }
374 break;
375
376 case 'v':
377 verify++;
378 doingverify++;
379 if (strcmp(tape, "-") == 0) {
380 msg(gettext(
381 "Cannot verify when dumping to standard out.\n"));
382 dumpabort();
383 /*NOTREACHED*/
384 }
385 break;
386
387 case 'D':
388 diskette++;
389 break;
390
391 case 'N':
392 if (argc > 1) {
393 argv++;
394 argc--;
395 if (**argv == '\0') {
396 msg(gettext("Missing name for dumpdates "
397 "entry.\n"));
398 dumpabort();
399 /*NOTREACHED*/
400 }
401 dname = *argv;
402 if (strlen(dname) > MAXNAMLEN + 2) {
403 msg(gettext("Dumpdates entry name too "
404 "long.\n"));
405 dumpabort();
406 /*NOTREACHED*/
407 }
408 for (i = 0; i < strlen(dname); i++) {
409 if (isspace(*(dname+i))) {
410 msg(gettext("Dumpdates entry name may "
411 "not contain white space.\n"));
412 dumpabort();
413 /*NOTREACHED*/
414 }
415 }
416 } else {
417 msg(gettext("Missing name for dumpdates entry.\n"));
418 dumpabort();
419 /*NOTREACHED*/
420 }
421 break;
422 case 'L':
423 if (argc > 1) {
424 argv++;
425 argc--;
426 if (**argv == '\0') {
427 msg(gettext("Missing tape label name\n"));
428 dumpabort();
429 /*NOTREACHED*/
430 }
431 tlabel = *argv;
432 if (strlen(tlabel) > (sizeof (spcl.c_label) - 1)) {
433 tlabel[sizeof (spcl.c_label) - 1] = '\0';
434 msg(gettext(
435 "Truncating label to maximum supported length: `%s'\n"),
436 tlabel);
437 }
438 } else {
439 msg(gettext("Missing tape label name\n"));
440 dumpabort();
441 /*NOTREACHED*/
442 }
443 break;
444
445 case 'l':
446 autoload++;
447 break;
448
449 case 'o':
450 offline++;
451 break;
452
453 case 'S':
454 printsize++;
455 break;
456
457 #ifdef DEBUG
458 case 'z':
459 xflag++;
460 break;
461 #endif
462
463 default:
464 msg(gettext("Bad option `%c'\n"), arg[-1]);
465 dumpabort();
466 /*NOTREACHED*/
467 }
468 if (argc > 1) {
469 argv++;
470 argc--;
471 if (**argv == '\0') {
472 msg(gettext("Bad disk name\n"));
473 dumpabort();
474 /*NOTREACHED*/
475 }
476 disk = *argv;
477 disk_dynamic = 0;
478 }
479 if (disk == NULL) {
480 (void) fprintf(stderr, gettext(
481 "Usage: %s [0123456789fustdWwnNDCcbavloS [argument]] filesystem\n"),
482 myname);
483 Exit(X_ABORT);
484 }
485 if (!filenum)
486 filenum = 1;
487
488 if (signal(SIGINT, interrupt) == SIG_IGN)
489 (void) signal(SIGINT, SIG_IGN);
490
491 if (strcmp(tape, "-") == 0) {
492 pipeout++;
493 tape = gettext("standard output");
494 dumpdev = sdumpdev = strdup(tape);
495 if (dumpdev == NULL) {
496 saverr = errno;
497 msg(gettext("Cannot allocate memory: %s\n"),
498 strerror(saverr));
499 dumpabort();
500 /*NOTREACHED*/
501 }
502 /*CONSTANTCONDITION*/
503 assert(sizeof (spcl.c_label) > 5);
504 (void) strcpy(spcl.c_label, "none");
505 } else if (*tape == '+') {
506 nextdevice();
507 (void) strcpy(spcl.c_label, tlabel);
508 } else {
509 /* if not already set, set diskette to default */
510 if (diskette && strcmp(tape, DEFTAPE) == 0)
511 tape = DISKETTE;
512 nextdevice();
513 (void) strcpy(spcl.c_label, tlabel);
514 }
515 if (cartridge && diskette) {
516 error = 1;
517 msg(gettext("Cannot select both cartridge and diskette\n"));
518 }
519 if (density && diskette) {
520 error = 1;
521 msg(gettext("Cannot select density of diskette\n"));
522 }
523 if (tracks && diskette) {
524 error = 1;
525 msg(gettext("Cannot select number of tracks of diskette\n"));
526 }
527 if (error) {
528 dumpabort();
529 /*NOTREACHED*/
530 }
531
532 /*
533 * Determine how to default tape size and density
534 *
535 * density tape size
536 * 9-track 1600 bpi (160 bytes/.1") 2300 ft.
537 * 9-track 6250 bpi (625 bytes/.1") 2300 ft.
538 *
539 * Most Sun-2's came with 4 track (20MB) cartridge tape drives,
540 * while most other machines (Sun-3's and non-Sun's) come with
541 * 9 track (45MB) cartridge tape drives. Some Sun-2's came with
542 * 9 track drives, but there is no way for the software to detect
543 * which drive type is installed. Sigh... We make the gross
544 * assumption that #ifdef mc68010 will test for a Sun-2.
545 *
546 * cartridge 8000 bpi (100 bytes/.1") 425 * tracks ft.
547 */
548 if (density == 0)
549 density = cartridge ? 100 : 625;
550 if (tracks == 0)
551 tracks = 9;
552 if (!bflag) {
553 if (cartridge)
554 ntrec = CARTRIDGETREC;
555 else if (diskette)
556 ntrec = NTREC;
557 else if (density >= 625)
558 ntrec = HIGHDENSITYTREC;
559 else
560 ntrec = NTREC;
561 /*
562 * save ntrec in case we have to change tp_bsize later.
563 */
564 saved_ntrec = (ntrec * (tp_bsize/DEV_BSIZE));
565 }
566 if (!diskette) {
567 tsize *= 12L*10L;
568 if (cartridge)
569 tsize *= tracks;
570 }
571 rmtinit(msg, Exit);
572 if (host) {
573 char *cp = strchr(host, '@');
574 if (cp == (char *)0)
575 cp = host;
576 else
577 cp++;
578
579 if (rmthost(host, ntrec) == 0) {
580 msg(gettext("Cannot connect to tape host `%s'\n"), cp);
581 dumpabort();
582 /*NOTREACHED*/
583 }
584 }
585 if (signal(SIGHUP, sigAbort) == SIG_IGN)
586 (void) signal(SIGHUP, SIG_IGN);
587 if (signal(SIGTRAP, sigAbort) == SIG_IGN)
588 (void) signal(SIGTRAP, SIG_IGN);
589 if (signal(SIGFPE, sigAbort) == SIG_IGN)
590 (void) signal(SIGFPE, SIG_IGN);
591 if (signal(SIGBUS, sigAbort) == SIG_IGN)
592 (void) signal(SIGBUS, SIG_IGN);
593 if (signal(SIGSEGV, sigAbort) == SIG_IGN)
594 (void) signal(SIGSEGV, SIG_IGN);
595 if (signal(SIGTERM, sigAbort) == SIG_IGN)
596 (void) signal(SIGTERM, SIG_IGN);
597 if (signal(SIGUSR1, sigAbort) == SIG_IGN)
598 (void) signal(SIGUSR1, SIG_IGN);
599 if (signal(SIGPIPE, sigAbort) == SIG_IGN)
600 (void) signal(SIGPIPE, SIG_IGN);
601
602 mnttabread(); /* /etc/fstab, /etc/mtab snarfed */
603
604 /*
605 * disk can be either the full special file name,
606 * the suffix of the special file name,
607 * the special name missing the leading '/',
608 * the file system name with or without the leading '/'.
609 * NB: we attempt to avoid dumping the block device
610 * (using rawname) because specfs and the vm system
611 * are not necessarily in sync.
612 */
613
614 /*
615 * Attempt to roll the log if its root user before doing the dump.
616 * There's nothing the user can do if we are unable to roll the log,
617 * so we'll silently ignore failures.
618 */
619 if (getuid() == 0 && rl_roll_log(disk) != RL_SUCCESS &&
620 disk[0] != '/') {
621 /* Try it again with leading '/'. */
622 char *slashed;
623
624 slashed = (char *)malloc(strlen(disk) + 2);
625 if (slashed != (char *)NULL) {
626 (void) sprintf(slashed, "%c%s", '/', disk);
627 (void) rl_roll_log(slashed);
628 free(slashed);
629 }
630 }
631 dt = mnttabsearch(disk, 0);
632 if (dt != 0) {
633 filesystem = dt->mnt_mountp;
634 if (disk_dynamic) {
635 /* LINTED: disk is not NULL */
636 free(disk);
637 }
638 disk = rawname(dt->mnt_special);
639 disk_dynamic = (disk != dt->mnt_special);
640
641 (void) strncpy(spcl.c_dev, dt->mnt_special,
642 sizeof (spcl.c_dev));
643 spcl.c_dev[sizeof (spcl.c_dev) - 1] = '\0';
644 (void) strncpy(spcl.c_filesys, dt->mnt_mountp,
645 sizeof (spcl.c_filesys));
646 spcl.c_filesys[sizeof (spcl.c_filesys) - 1] = '\0';
647 } else {
648 (void) strncpy(spcl.c_dev, disk, sizeof (spcl.c_dev));
649 spcl.c_dev[sizeof (spcl.c_dev) - 1] = '\0';
650 #ifdef PARTIAL
651 /* check for partial filesystem dump */
652 partial_check();
653 dt = mnttabsearch(disk, 1);
654 if (dt != 0) {
655 filesystem = dt->mnt_mountp;
656 if (disk_dynamic)
657 free(disk);
658 disk = rawname(dt->mnt_special);
659 disk_dynamic = (disk != dt->mnt_special);
660
661 (void) strncpy(spcl.c_filesys,
662 "a partial file system", sizeof (spcl.c_filesys));
663 spcl.c_filesys[sizeof (spcl.c_filesys) - 1] = '\0';
664 }
665 else
666 #endif /* PARTIAL */
667 {
668 char *old_disk = disk;
669
670 (void) strncpy(spcl.c_filesys,
671 "an unlisted file system",
672 sizeof (spcl.c_filesys));
673 spcl.c_filesys[sizeof (spcl.c_filesys) - 1] = '\0';
674
675 disk = rawname(old_disk);
676 if (disk != old_disk) {
677 if (disk_dynamic)
678 free(old_disk);
679 disk_dynamic = 1;
680 }
681 /*
682 * If disk == old_disk, then disk_dynamic's state
683 * does not change.
684 */
685 }
686 }
687
688 fi = open64(disk, O_RDONLY);
689
690 if (fi < 0) {
691 saverr = errno;
692 msg(gettext("Cannot open dump device `%s': %s\n"),
693 disk, strerror(saverr));
694 Exit(X_ABORT);
695 }
696
697 if (sscanf(&incno, "%1d", &spcl.c_level) != 1) {
698 msg(gettext("Bad dump level `%c' specified\n"), incno);
699 dumpabort();
700 /*NOTREACHED*/
701 }
702 getitime(); /* /etc/dumpdates snarfed */
703
704 sblock = (struct fs *)&sblock_buf;
705 sync();
706
707 bread((diskaddr_t)SBLOCK, (uchar_t *)sblock, (long)SBSIZE);
708 if ((sblock->fs_magic != FS_MAGIC) &&
709 (sblock->fs_magic != MTB_UFS_MAGIC)) {
710 msg(gettext(
711 "Warning - super-block on device `%s' is corrupt - run fsck\n"),
712 disk);
713 dumpabort();
714 /*NOTREACHED*/
715 }
716
717 if (sblock->fs_magic == FS_MAGIC &&
718 (sblock->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
719 sblock->fs_version != UFS_VERSION_MIN)) {
720 msg(gettext("Unrecognized UFS version: %d\n"),
721 sblock->fs_version);
722 dumpabort();
723 /*NOTREACHED*/
724 }
725
726 if (sblock->fs_magic == MTB_UFS_MAGIC &&
727 (sblock->fs_version < MTB_UFS_VERSION_MIN ||
728 sblock->fs_version > MTB_UFS_VERSION_1)) {
729 msg(gettext("Unrecognized UFS version: %d\n"),
730 sblock->fs_version);
731 dumpabort();
732 /*NOTREACHED*/
733 }
734
735 /*
736 * Try to set up for using mmap(2). It only works on the block
737 * device, but if we can use it, things go somewhat faster. If
738 * we can't open it, we'll silently fall back to the old method
739 * (read/memcpy). We also only try this if it's been cleanly
740 * unmounted. Dumping a live filesystem this way runs into
741 * buffer consistency problems. Of course, we don't support
742 * running dump on a mounted filesystem, but some people do it
743 * anyway.
744 */
745 if (sblock->fs_clean == FSCLEAN) {
746 char *block = unrawname(disk);
747
748 if (block != NULL) {
749 mapfd = open(block, O_RDONLY, 0);
750 free(block);
751 }
752 }
753
754 restart:
755 bread((diskaddr_t)SBLOCK, (uchar_t *)sblock, (long)SBSIZE);
756 if ((sblock->fs_magic != FS_MAGIC) &&
757 (sblock->fs_magic != MTB_UFS_MAGIC)) { /* paranoia */
758 msg(gettext("bad super-block magic number, run fsck\n"));
759 dumpabort();
760 /*NOTREACHED*/
761 }
762
763 if (sblock->fs_magic == FS_MAGIC &&
764 (sblock->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
765 sblock->fs_version != UFS_VERSION_MIN)) {
766 msg(gettext("Unrecognized UFS version: %d\n"),
767 sblock->fs_version);
768 dumpabort();
769 /*NOTREACHED*/
770 }
771
772 if (sblock->fs_magic == MTB_UFS_MAGIC &&
773 (sblock->fs_version < MTB_UFS_VERSION_MIN ||
774 sblock->fs_version > MTB_UFS_VERSION_1)) {
775 msg(gettext("Unrecognized UFS version: %d\n"),
776 sblock->fs_version);
777 dumpabort();
778 /*NOTREACHED*/
779 }
780
781 if (!doingactive)
782 allocino();
783
784 /* XXX should sanity-check the super block before trusting/using it */
785
786 /* LINTED XXX time truncated - tolerate until tape format changes */
787 spcl.c_date = (time32_t)time((time_t *)NULL);
788 bcopy(&(spcl.c_shadow), c_shadow_save, sizeof (c_shadow_save));
789
790 snapdate = is_fssnap_dump(disk);
791 if (snapdate)
792 spcl.c_date = snapdate;
793
794 if (!printsize) {
795 msg(gettext("Date of this level %c dump: %s\n"),
796 incno, prdate(spcl.c_date));
797 msg(gettext("Date of last level %c dump: %s\n"),
798 (uchar_t)lastincno, prdate(spcl.c_ddate));
799 msg(gettext("Dumping %s "), disk);
800 if (filesystem != 0)
801 msgtail("(%.*s:%s) ",
802 /* LINTED unsigned -> signed cast ok */
803 (int)sizeof (spcl.c_host), spcl.c_host, filesystem);
804 msgtail(gettext("to %s.\n"), sdumpdev);
805 }
806
807 esize = f_esize = o_esize = 0;
808 msiz = roundup(d_howmany(sblock->fs_ipg * sblock->fs_ncg, NBBY),
809 TP_BSIZE_MAX);
810 if (!doingactive) {
811 clrmap = (uchar_t *)xcalloc(msiz, sizeof (*clrmap));
812 filmap = (uchar_t *)xcalloc(msiz, sizeof (*filmap));
813 dirmap = (uchar_t *)xcalloc(msiz, sizeof (*dirmap));
814 nodmap = (uchar_t *)xcalloc(msiz, sizeof (*nodmap));
815 shamap = (uchar_t *)xcalloc(msiz, sizeof (*shamap));
816 activemap = (uchar_t *)xcalloc(msiz, sizeof (*activemap));
817 } else {
818 if (clrmap == NULL || filmap == NULL || dirmap == NULL ||
819 nodmap == NULL || shamap == NULL || activemap == NULL) {
820 msg(gettext(
821 "Internal error: NULL map pointer while re-dumping active files"));
822 dumpabort();
823 /*NOTREACHED*/
824 }
825 bzero(clrmap, msiz);
826 bzero(filmap, msiz);
827 bzero(dirmap, msiz);
828 bzero(nodmap, msiz);
829 bzero(shamap, msiz);
830 /* retain active map */
831 }
832
833 dumpstate = DS_INIT;
834 dumptoarchive = 1;
835
836 /*
837 * Read cylinder group inode-used bitmaps to avoid reading clear inodes.
838 */
839 {
840 uchar_t *clrp = clrmap;
841 struct cg *cgp =
842 (struct cg *)xcalloc((uint_t)sblock->fs_cgsize, 1);
843
844 for (i = 0; i < sblock->fs_ncg; i++) {
845 bread(fsbtodb(sblock, cgtod(sblock, i)),
846 (uchar_t *)cgp, sblock->fs_cgsize);
847 bcopy(cg_inosused(cgp), clrp,
848 (int)sblock->fs_ipg / NBBY);
849 clrp += sblock->fs_ipg / NBBY;
850 }
851 free((char *)cgp);
852 /* XXX right-shift clrmap one bit. why? */
853 for (i = 0; clrp > clrmap; i <<= NBBY) {
854 i |= *--clrp & ((1<<NBBY) - 1);
855 *clrp = i >> 1;
856 }
857 }
858
859 if (!printsize) {
860 msgp = gettext("Mapping (Pass I) [regular files]\n");
861 msg(msgp);
862 }
863
864 ino = 0;
865 #ifdef PARTIAL
866 if (partial_mark(argc, argv)) {
867 #endif /* PARTIAL */
868 if (!doingactive)
869 pass(mark, clrmap); /* mark updates 'x'_esize */
870 else
871 pass(active_mark, clrmap); /* updates 'x'_esize */
872 #ifdef PARTIAL
873 }
874 #endif /* PARTIAL */
875 do {
876 if (!printsize) {
877 msgp = gettext("Mapping (Pass II) [directories]\n");
878 msg(msgp);
879 }
880 nadded = 0;
881 ino = 0;
882 pass(add, dirmap);
883 } while (nadded);
884
885 ino = 0; /* adjust estimated size for shadow inodes */
886 pass(markshad, nodmap);
887 ino = 0;
888 pass(estshad, shamap);
889 freeshad();
890
891 bmapest(clrmap);
892 bmapest(nodmap);
893 esize = o_esize + f_esize;
894 if (diskette) {
895 /* estimate number of floppies */
896 if (tsize != 0)
897 fetapes = (double)(esize + ntrec) / (double)tsize;
898 } else if (cartridge) {
899 /*
900 * Estimate number of tapes, assuming streaming stops at
901 * the end of each block written, and not in mid-block.
902 * Assume no erroneous blocks; this can be compensated for
903 * with an artificially low tape size.
904 */
905 tenthsperirg = 16; /* actually 15.48, says Archive */
906 if (tsize != 0)
907 fetapes = ((double)esize /* blocks */
908 * (tp_bsize /* bytes/block */
909 * (1.0/density)) /* 0.1" / byte */
910 +
911 (double)esize /* blocks */
912 * (1.0/ntrec) /* streaming-stops per block */
913 * tenthsperirg) /* 0.1" / streaming-stop */
914 * (1.0 / tsize); /* tape / 0.1" */
915 } else {
916 /* Estimate number of tapes, for old fashioned 9-track tape */
917 #ifdef sun
918 /* sun has long irg's */
919 tenthsperirg = (density == 625) ? 6 : 12;
920 #else
921 tenthsperirg = (density == 625) ? 5 : 8;
922 #endif
923 if (tsize != 0)
924 fetapes = ((double)esize /* blocks */
925 * (tp_bsize /* bytes / block */
926 * (1.0/density)) /* 0.1" / byte */
927 +
928 (double)esize /* blocks */
929 * (1.0/ntrec) /* IRG's / block */
930 * tenthsperirg) /* 0.1" / IRG */
931 * (1.0 / tsize); /* tape / 0.1" */
932 }
933
934 etapes = fetapes; /* truncating assignment */
935 etapes++;
936 /* count the nodemap on each additional tape */
937 for (i = 1; i < etapes; i++)
938 bmapest(nodmap);
939 /*
940 * If the above bmapest is called, it changes o_esize and f_esize.
941 * So we will recalculate esize here anyway to make sure.
942 * Also, add tape headers and trailer records.
943 */
944 esize = o_esize + f_esize + etapes + ntrec;
945
946 /*
947 * If the estimated number of tp_bsize tape blocks is greater than
948 * INT_MAX we have to adjust tp_bsize and ntrec to handle
949 * the larger dump. esize is an estimate, so we 'fudge'
950 * INT_MAX a little. If tp_bsize is adjusted, it will be adjusted
951 * to the size needed for this dump (2048, 4096, 8192, ...)
952 */
953 if (esize > (INT_MAX - FUDGE_FACTOR)) { /* esize is too big */
954 forceflag++;
955 esize_shift =
956 ((esize + (INT_MAX - FUDGE_FACTOR) - 1)/
957 ((u_offset_t)(INT_MAX - FUDGE_FACTOR))) - 1;
958 if ((esize_shift > ESIZE_SHIFT_MAX) || (ntrec == 0)) {
959 msgp = gettext(
960 "Block factor %d ('b' flag) is too small for this size dump.");
961 msg(msgp, saved_ntrec);
962 dumpabort();
963 /*NOTREACHED*/
964 }
965 /*
966 * recalculate esize from:
967 * o_esize - header tape records
968 * (f_esize + (num_mult -1)) >> esize_shift - new non-header
969 * tape records for files/maps
970 * etapes - TS_TAPE records
971 * ntrec - TS_END records
972 *
973 * ntrec is adjusted so a tape record is still 'b' flag
974 * number of DEV_BSIZE (512) in size
975 */
976 new_mult = (tp_bsize << esize_shift)/tp_bsize;
977 tp_bsize = (tp_bsize << esize_shift);
978 esize = o_esize + ((f_esize +
979 (new_mult - 1)) >> esize_shift) + etapes + ntrec;
980 ntrec = (saved_ntrec/(tp_bsize/DEV_BSIZE));
981 }
982 if (forceflag != 0) {
983 msgp = gettext(
984 "Forcing larger tape block size (%d).\n");
985 msg(msgp, tp_bsize);
986 }
987 alloctape(); /* allocate tape buffers */
988
989 assert((tp_bsize / DEV_BSIZE != 0) && (tp_bsize % DEV_BSIZE == 0));
990 /*
991 * If all we wanted was the size estimate,
992 * just print it out and exit.
993 */
994 if (printsize) {
995 (void) printf("%llu\n", esize * tp_bsize);
996 Exit(0);
997 }
998
999 if (tsize != 0) {
1000 if (diskette)
1001 msgp = gettext(
1002 "Estimated %lld blocks (%s) on %3.2f diskettes.\n");
1003 else
1004 msgp = gettext(
1005 "Estimated %lld blocks (%s) on %3.2f tapes.\n");
1006
1007 msg(msgp,
1008 (esize*(tp_bsize/DEV_BSIZE)), mb(esize), fetapes);
1009 } else {
1010 msgp = gettext("Estimated %lld blocks (%s).\n");
1011 msg(msgp, (esize*(tp_bsize/DEV_BSIZE)), mb(esize));
1012 }
1013
1014 dumpstate = DS_CLRI;
1015
1016 otape(1); /* bitmap is the first to tape write */
1017 *telapsed = 0;
1018 (void) time(tstart_writing);
1019
1020 /* filmap indicates all non-directory inodes */
1021 {
1022 uchar_t *np, *fp, *dp;
1023 np = nodmap;
1024 dp = dirmap;
1025 fp = filmap;
1026 for (i = 0; i < msiz; i++)
1027 *fp++ = *np++ ^ *dp++;
1028 }
1029
1030 while (dumpstate != DS_DONE) {
1031 /*
1032 * When we receive EOT notification from
1033 * the writer, the signal handler calls
1034 * rollforward and then jumps here.
1035 */
1036 (void) setjmp(checkpoint_buf);
1037 switch (dumpstate) {
1038 case DS_INIT:
1039 /*
1040 * We get here if a tape error occurred
1041 * after releasing the name lock but before
1042 * the volume containing the last of the
1043 * dir info was completed. We have to start
1044 * all over in this case.
1045 */
1046 {
1047 char *rmsg = gettext(
1048 "Warning - output error occurred after releasing name lock\n\
1049 \tThe dump will restart\n");
1050 msg(rmsg);
1051 goto restart;
1052 }
1053 /* NOTREACHED */
1054 case DS_START:
1055 case DS_CLRI:
1056 ino = UFSROOTINO;
1057 dumptoarchive = 1;
1058 bitmap(clrmap, TS_CLRI);
1059 nextstate(DS_BITS);
1060 /* FALLTHROUGH */
1061 case DS_BITS:
1062 ino = UFSROOTINO;
1063 dumptoarchive = 1;
1064 if (BIT(UFSROOTINO, nodmap)) /* empty dump check */
1065 bitmap(nodmap, TS_BITS);
1066 nextstate(DS_DIRS);
1067 if (!doingverify) {
1068 msgp = gettext(
1069 "Dumping (Pass III) [directories]\n");
1070 msg(msgp);
1071 }
1072 /* FALLTHROUGH */
1073 case DS_DIRS:
1074 dumptoarchive = 1;
1075 pass(dirdump, dirmap);
1076 nextstate(DS_FILES);
1077 if (!doingverify) {
1078 msgp = gettext(
1079 "Dumping (Pass IV) [regular files]\n");
1080 msg(msgp);
1081 }
1082 /* FALLTHROUGH */
1083 case DS_FILES:
1084 dumptoarchive = 0;
1085
1086 pass(lf_dump, filmap);
1087
1088 flushcmds();
1089 dumpstate = DS_END; /* don't reset ino */
1090 /* FALLTHROUGH */
1091 case DS_END:
1092 dumptoarchive = 1;
1093 spcl.c_type = TS_END;
1094 for (i = 0; i < ntrec; i++) {
1095 spclrec();
1096 }
1097 flusht();
1098 break;
1099 case DS_DONE:
1100 break;
1101 default:
1102 msg(gettext("Internal state error\n"));
1103 dumpabort();
1104 /*NOTREACHED*/
1105 }
1106 }
1107
1108 if ((! doingactive) && (! active))
1109 trewind();
1110 if (verify && !doingverify) {
1111 msgp = gettext("Finished writing last dump volume\n");
1112 msg(msgp);
1113 Exit(X_VERIFY);
1114 }
1115 if (spcl.c_volume > 1)
1116 (void) snprintf(msgbuf, sizeof (msgbuf),
1117 gettext("%lld blocks (%s) on %ld volumes"),
1118 ((uint64_t)spcl.c_tapea*(tp_bsize/DEV_BSIZE)),
1119 mb((u_offset_t)(unsigned)(spcl.c_tapea)),
1120 spcl.c_volume);
1121 else
1122 (void) snprintf(msgbuf, sizeof (msgbuf),
1123 gettext("%lld blocks (%s) on 1 volume"),
1124 ((uint64_t)spcl.c_tapea*(tp_bsize/DEV_BSIZE)),
1125 mb((u_offset_t)(unsigned)(spcl.c_tapea)));
1126 if (timeclock((time_t)0) != (time_t)0) {
1127 (void) snprintf(kbsbuf, sizeof (kbsbuf),
1128 gettext(" at %ld KB/sec"),
1129 (long)(((float)spcl.c_tapea / (float)timeclock((time_t)0))
1130 * 1000.0));
1131 (void) strcat(msgbuf, kbsbuf);
1132 }
1133 (void) strcat(msgbuf, "\n");
1134 msg(msgbuf);
1135 (void) timeclock((time_t)-1);
1136
1137 if (archive)
1138 msg(gettext("Archiving dump to `%s'\n"), archivefile);
1139 if (active && !verify) {
1140 nextstate(DS_INIT);
1141 activepass();
1142 goto restart;
1143 }
1144 msgp = gettext("DUMP IS DONE\n");
1145 msg(msgp);
1146 broadcast(msgp);
1147 if (! doingactive)
1148 putitime();
1149 Exit(X_FINOK);
1150
1151 /*NOTREACHED*/
1152 return (0);
1153 }
1154
1155 void
sigAbort(int sig)1156 sigAbort(int sig)
1157 {
1158 char *sigtype;
1159
1160 switch (sig) {
1161 case SIGHUP:
1162 sigtype = "SIGHUP";
1163 break;
1164 case SIGTRAP:
1165 sigtype = "SIGTRAP";
1166 break;
1167 case SIGFPE:
1168 sigtype = "SIGFPE";
1169 break;
1170 case SIGBUS:
1171 msg(gettext("%s ABORTING!\n"), "SIGBUS()");
1172 (void) signal(SIGUSR2, SIG_DFL);
1173 abort();
1174 /*NOTREACHED*/
1175 case SIGSEGV:
1176 msg(gettext("%s ABORTING!\n"), "SIGSEGV()");
1177 (void) signal(SIGUSR2, SIG_DFL);
1178 abort();
1179 /*NOTREACHED*/
1180 case SIGALRM:
1181 sigtype = "SIGALRM";
1182 break;
1183 case SIGTERM:
1184 sigtype = "SIGTERM";
1185 break;
1186 case SIGPIPE:
1187 msg(gettext("Broken pipe\n"));
1188 dumpabort();
1189 /*NOTREACHED*/
1190 default:
1191 sigtype = "SIGNAL";
1192 break;
1193 }
1194 msg(gettext("%s() try rewriting\n"), sigtype);
1195 if (pipeout) {
1196 msg(gettext("Unknown signal, Cannot recover\n"));
1197 dumpabort();
1198 /*NOTREACHED*/
1199 }
1200 msg(gettext("Rewriting attempted as response to unknown signal.\n"));
1201 (void) fflush(stderr);
1202 (void) fflush(stdout);
1203 close_rewind();
1204 Exit(X_REWRITE);
1205 }
1206
1207 /* Note that returned value is malloc'd if != cp && != NULL */
1208 char *
rawname(char * cp)1209 rawname(char *cp)
1210 {
1211 struct stat64 st;
1212 char *dp;
1213 extern char *getfullrawname();
1214
1215 if (stat64(cp, &st) < 0 || (st.st_mode & S_IFMT) != S_IFBLK)
1216 return (cp);
1217
1218 dp = getfullrawname(cp);
1219 if (dp == 0)
1220 return (0);
1221 if (*dp == '\0') {
1222 free(dp);
1223 return (0);
1224 }
1225
1226 if (stat64(dp, &st) < 0 || (st.st_mode & S_IFMT) != S_IFCHR) {
1227 free(dp);
1228 return (cp);
1229 }
1230
1231 return (dp);
1232 }
1233
1234 static char *
mb(u_offset_t blks)1235 mb(u_offset_t blks)
1236 {
1237 static char buf[16];
1238
1239 if (blks < 1024)
1240 (void) snprintf(buf, sizeof (buf), "%lldKB", blks);
1241 else
1242 (void) snprintf(buf, sizeof (buf), "%.2fMB",
1243 ((double)(blks*tp_bsize)) / (double)(1024*1024));
1244 return (buf);
1245 }
1246
1247 #ifdef signal
nsignal(int sig,void (* act)(int))1248 void (*nsignal(int sig, void (*act)(int)))(int)
1249 {
1250 struct sigaction sa, osa;
1251
1252 sa.sa_handler = act;
1253 (void) sigemptyset(&sa.sa_mask);
1254 sa.sa_flags = SA_RESTART;
1255 if (sigaction(sig, &sa, &osa) < 0)
1256 return ((void (*)(int))-1);
1257 return (osa.sa_handler);
1258 }
1259 #endif
1260
1261 static void
nextstate(int state)1262 nextstate(int state)
1263 {
1264 /* LINTED assigned value never used - kept for documentary purposes */
1265 dumpstate = state;
1266 /* LINTED assigned value never used - kept for documentary purposes */
1267 ino = 0;
1268 /* LINTED assigned value never used - kept for documentary purposes */
1269 pos = 0;
1270 leftover = 0;
1271 }
1272
1273 /*
1274 * timeclock() function, for keeping track of how much time we've spent
1275 * writing to the tape device. it always returns the amount of time
1276 * already spent, in milliseconds. if you pass it a positive, then that's
1277 * telling it that we're writing, so the time counts. if you pass it a
1278 * zero, then that's telling it we're not writing; perhaps we're waiting
1279 * for user input.
1280 *
1281 * a state of -1 resets everything.
1282 */
1283 time32_t
timeclock(time32_t state)1284 timeclock(time32_t state)
1285 {
1286 static int *currentState = NULL;
1287 static struct timeval *clockstart;
1288 static time32_t *emilli;
1289
1290 struct timeval current[1];
1291 int fd, saverr;
1292
1293 #ifdef DEBUG
1294 fprintf(stderr, "pid=%d timeclock ", getpid());
1295 if (state == (time32_t)-1)
1296 fprintf(stderr, "cleared\n");
1297 else if (state > 0)
1298 fprintf(stderr, "ticking\n");
1299 else
1300 fprintf(stderr, "paused\n");
1301 #endif /* DEBUG */
1302
1303 /* if we haven't setup the shared memory, init */
1304 if (currentState == (int *)NULL) {
1305 if ((fd = open("/dev/zero", O_RDWR)) < 0) {
1306 saverr = errno;
1307 msg(gettext("Cannot open `%s': %s\n"),
1308 "/dev/zero", strerror(saverr));
1309 dumpabort();
1310 /*NOTREACHED*/
1311 }
1312 /*LINTED [mmap always returns an aligned value]*/
1313 currentState = (int *)mmap((char *)0, getpagesize(),
1314 PROT_READ|PROT_WRITE, MAP_SHARED, fd, (off_t)0);
1315 if (currentState == (int *)-1) {
1316 saverr = errno;
1317 msg(gettext(
1318 "Cannot memory map monitor variables: %s\n"),
1319 strerror(saverr));
1320 dumpabort();
1321 /*NOTREACHED*/
1322 }
1323 (void) close(fd);
1324
1325 /* LINTED currentState is sufficiently aligned */
1326 clockstart = (struct timeval *)(currentState + 1);
1327 emilli = (time32_t *)(clockstart + 1);
1328 /* Note everything is initialized to zero via /dev/zero */
1329 }
1330
1331 if (state == (time32_t)-1) {
1332 bzero(clockstart, sizeof (*clockstart));
1333 *currentState = 0;
1334 *emilli = (time32_t)0;
1335 return (0);
1336 }
1337
1338 (void) gettimeofday(current, NULL);
1339
1340 if (*currentState != 0) {
1341 current->tv_usec += 1000000;
1342 current->tv_sec--;
1343
1344 /* LINTED: result will fit in a time32_t */
1345 *emilli += (current->tv_sec - clockstart->tv_sec) * 1000;
1346 /* LINTED: result will fit in a time32_t */
1347 *emilli += (current->tv_usec - clockstart->tv_usec) / 1000;
1348 }
1349
1350 if (state != 0)
1351 bcopy(current, clockstart, sizeof (current));
1352
1353 *currentState = state;
1354
1355 return (*emilli);
1356 }
1357
1358 static int
statcmp(const struct stat64 * left,const struct stat64 * right)1359 statcmp(const struct stat64 *left, const struct stat64 *right)
1360 {
1361 int result = 1;
1362
1363 if ((left->st_dev == right->st_dev) &&
1364 (left->st_ino == right->st_ino) &&
1365 (left->st_mode == right->st_mode) &&
1366 (left->st_nlink == right->st_nlink) &&
1367 (left->st_uid == right->st_uid) &&
1368 (left->st_gid == right->st_gid) &&
1369 (left->st_rdev == right->st_rdev) &&
1370 (left->st_ctim.tv_sec == right->st_ctim.tv_sec) &&
1371 (left->st_ctim.tv_nsec == right->st_ctim.tv_nsec) &&
1372 (left->st_mtim.tv_sec == right->st_mtim.tv_sec) &&
1373 (left->st_mtim.tv_nsec == right->st_mtim.tv_nsec)) {
1374 /*
1375 * Unlike in the ufsrestore version
1376 * st_blocks and st_blksiz are not
1377 * compared. The reason for this is
1378 * problems with zfs dump files. Zfs
1379 * changes it's statistics in those
1380 * fields.
1381 */
1382 result = 0;
1383 }
1384
1385 return (result);
1386 }
1387
1388 /*
1389 * Safely open a file or device.
1390 */
1391 static int
safe_open_common(const char * filename,int mode,int perms,int device)1392 safe_open_common(const char *filename, int mode, int perms, int device)
1393 {
1394 int fd;
1395 int working_mode;
1396 int saverr;
1397 char *errtext;
1398 struct stat64 pre_stat, pre_lstat;
1399 struct stat64 post_stat, post_lstat;
1400
1401 /*
1402 * Don't want to be spoofed into trashing something we
1403 * shouldn't, thus the following rigamarole. If it doesn't
1404 * exist, we create it and proceed. Otherwise, require that
1405 * what's there be a real file with no extraneous links and
1406 * owned by whoever ran us.
1407 *
1408 * The silliness with using both lstat() and fstat() is to avoid
1409 * race-condition games with someone replacing the file with a
1410 * symlink after we've opened it. If there was an flstat(),
1411 * we wouldn't need the fstat().
1412 *
1413 * The initial open with the hard-coded flags is ok even if we
1414 * are intending to open only for reading. If it succeeds,
1415 * then the file did not exist, and we'll synthesize an appropriate
1416 * complaint below. Otherwise, it does exist, so we won't be
1417 * truncating it with the open.
1418 */
1419 if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_LARGEFILE,
1420 perms)) < 0) {
1421 if (errno == EEXIST) {
1422 if (lstat64(filename, &pre_lstat) < 0) {
1423 return (-1);
1424 }
1425
1426 if (stat64(filename, &pre_stat) < 0) {
1427 return (-1);
1428 }
1429
1430 working_mode = mode & (O_WRONLY|O_RDWR|O_RDONLY);
1431 working_mode |= O_LARGEFILE;
1432 if ((fd = open(filename, working_mode)) < 0) {
1433 if (errno == ENOENT) {
1434 errtext = gettext(
1435 "Unexpected condition detected: %s used to exist, but doesn't any longer\n");
1436 msg(errtext, filename);
1437 syslog(LOG_WARNING, errtext, filename);
1438 errno = ENOENT;
1439 }
1440 return (-1);
1441 }
1442
1443 if (lstat64(filename, &post_lstat) < 0) {
1444 saverr = errno;
1445 (void) close(fd);
1446 errno = saverr;
1447 return (-1);
1448 }
1449
1450 if (fstat64(fd, &post_stat) < 0) {
1451 saverr = errno;
1452 (void) close(fd);
1453 errno = saverr;
1454 return (-1);
1455 }
1456
1457 /*
1458 * Can't just use memcmp(3C), because the access
1459 * time is updated by open(2).
1460 */
1461 if (statcmp(&pre_lstat, &post_lstat) != 0) {
1462 errtext = gettext("Unexpected change detected: "
1463 "%s's lstat(2) information changed\n");
1464 msg(errtext, filename);
1465 syslog(LOG_WARNING, errtext, filename);
1466 errno = EPERM;
1467 return (-1);
1468 }
1469
1470 if (statcmp(&pre_stat, &post_stat) != 0) {
1471 errtext = gettext("Unexpected change detected: "
1472 "%s's stat(2) information changed\n"),
1473 msg(errtext, filename);
1474 syslog(LOG_WARNING, errtext, filename);
1475 errno = EPERM;
1476 return (-1);
1477 }
1478
1479 /*
1480 * If inode, device, or type are wrong, bail out.
1481 * Note using post_stat instead of post_lstat for the
1482 * S_ISCHR() test. This is to allow the /dev ->
1483 * /devices bit to work, as long as the final target
1484 * is a character device (i.e., raw disk or tape).
1485 */
1486 if (device && !(S_ISCHR(post_stat.st_mode)) &&
1487 !(S_ISFIFO(post_stat.st_mode)) &&
1488 !(S_ISREG(post_lstat.st_mode))) {
1489 errtext = gettext("Unexpected condition "
1490 "detected: %s is not a supported device\n"),
1491 msg(errtext, filename);
1492 syslog(LOG_WARNING, errtext, filename);
1493 (void) close(fd);
1494 errno = EPERM;
1495 return (-1);
1496 } else if (!device &&
1497 (!S_ISREG(post_lstat.st_mode) ||
1498 (post_stat.st_ino != post_lstat.st_ino) ||
1499 (post_stat.st_dev != post_lstat.st_dev))) {
1500 errtext = gettext("Unexpected condition "
1501 "detected: %s is not a regular file\n"),
1502 msg(errtext, filename);
1503 syslog(LOG_WARNING, errtext, filename);
1504 (void) close(fd);
1505 errno = EPERM;
1506 return (-1);
1507 }
1508
1509 /*
1510 * Bad link count implies someone's linked our
1511 * target to something else, which we probably
1512 * shouldn't step on.
1513 */
1514 if (post_lstat.st_nlink != 1) {
1515 errtext = gettext("Unexpected condition "
1516 "detected: %s must have exactly one "
1517 "link\n"), msg(errtext, filename);
1518 syslog(LOG_WARNING, errtext, filename);
1519 (void) close(fd);
1520 errno = EPERM;
1521 return (-1);
1522 }
1523 /*
1524 * Root might make a file, but non-root might
1525 * need to open it. If the permissions let us
1526 * get this far, then let it through.
1527 */
1528 if (post_lstat.st_uid != getuid() &&
1529 post_lstat.st_uid != 0) {
1530 errtext = gettext("Unsupported "
1531 "condition detected: %s "
1532 "must be owned by uid %ld or 0\n"),
1533 msg(errtext, filename, (long)getuid());
1534 syslog(LOG_WARNING, errtext, filename,
1535 (long)getuid());
1536 (void) close(fd);
1537 errno = EPERM;
1538 return (-1);
1539 }
1540 if (mode & O_TRUNC) {
1541 if (ftruncate(fd, (off_t)0) < 0) {
1542 msg("ftruncate(%s): %s\n",
1543 filename, strerror(errno));
1544 (void) close(fd);
1545 return (-1);
1546 }
1547 }
1548 } else {
1549 /*
1550 * Didn't exist, but couldn't open it.
1551 */
1552 return (-1);
1553 }
1554 } else {
1555 /*
1556 * If truncating open succeeded for a read-only open,
1557 * bail out, as we really shouldn't have succeeded.
1558 */
1559 if (mode & O_RDONLY) {
1560 /* Undo the O_CREAT */
1561 (void) unlink(filename);
1562 msg("open(%s): %s\n",
1563 filename, strerror(ENOENT));
1564 (void) close(fd);
1565 errno = ENOENT;
1566 return (-1);
1567 }
1568 }
1569
1570 return (fd);
1571 }
1572
1573 /*
1574 * Safely open a file.
1575 */
1576 int
safe_file_open(const char * filename,int mode,int perms)1577 safe_file_open(const char *filename, int mode, int perms)
1578 {
1579 return (safe_open_common(filename, mode, perms, 0));
1580 }
1581
1582 /*
1583 * Safely open a device.
1584 */
1585 int
safe_device_open(const char * filename,int mode,int perms)1586 safe_device_open(const char *filename, int mode, int perms)
1587 {
1588 return (safe_open_common(filename, mode, perms, 1));
1589 }
1590
1591 /*
1592 * STDIO version of safe_open
1593 */
1594 FILE *
safe_fopen(const char * filename,const char * smode,int perms)1595 safe_fopen(const char *filename, const char *smode, int perms)
1596 {
1597 int fd;
1598 int bmode;
1599
1600 /*
1601 * accepts only modes "r", "r+", and "w"
1602 */
1603 if (smode[0] == 'r') {
1604 if (smode[1] == '\0') {
1605 bmode = O_RDONLY;
1606 } else if ((smode[1] == '+') && (smode[2] == '\0')) {
1607 bmode = O_RDWR;
1608 }
1609 } else if ((smode[0] == 'w') && (smode[1] == '\0')) {
1610 bmode = O_WRONLY;
1611 } else {
1612 msg(gettext("internal error: safe_fopen: invalid mode `%s'\n"),
1613 smode);
1614 return (NULL);
1615 }
1616
1617 fd = safe_file_open(filename, bmode, perms);
1618
1619 /*
1620 * caller is expected to report error.
1621 */
1622 if (fd >= 0)
1623 return (fdopen(fd, smode));
1624
1625 return ((FILE *)NULL);
1626 }
1627
1628 void
child_chdir(void)1629 child_chdir(void)
1630 {
1631 char name[MAXPATHLEN];
1632
1633 if (debug_chdir != NULL) {
1634 snprintf(name, sizeof (name), "%s/%ld",
1635 debug_chdir, (long)getpid());
1636 if (mkdir(name, 0755) < 0)
1637 msg("mkdir(%s): %s", name, strerror(errno));
1638 if (chdir(name) < 0)
1639 msg("chdir(%s): %s", name, strerror(errno));
1640 }
1641 }
1642