Home | History | Annotate | Line # | Download | only in dump
main.c revision 1.69.2.2
      1  1.69.2.1       tls /*	$NetBSD: main.c,v 1.69.2.2 2014/08/20 00:02:24 tls Exp $	*/
      2       1.6       cgd 
      3       1.1       cgd /*-
      4       1.3   mycroft  * Copyright (c) 1980, 1991, 1993, 1994
      5       1.3   mycroft  *	The Regents of the University of California.  All rights reserved.
      6       1.1       cgd  *
      7       1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8       1.1       cgd  * modification, are permitted provided that the following conditions
      9       1.1       cgd  * are met:
     10       1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11       1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12       1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14       1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15      1.56       agc  * 3. Neither the name of the University nor the names of its contributors
     16       1.1       cgd  *    may be used to endorse or promote products derived from this software
     17       1.1       cgd  *    without specific prior written permission.
     18       1.1       cgd  *
     19       1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20       1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21       1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22       1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23       1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24       1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25       1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26       1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27       1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28       1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29       1.1       cgd  * SUCH DAMAGE.
     30       1.1       cgd  */
     31       1.1       cgd 
     32      1.15     lukem #include <sys/cdefs.h>
     33       1.1       cgd #ifndef lint
     34      1.64     lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1991, 1993, 1994\
     35      1.64     lukem  The Regents of the University of California.  All rights reserved.");
     36       1.1       cgd #endif /* not lint */
     37       1.1       cgd 
     38       1.1       cgd #ifndef lint
     39       1.6       cgd #if 0
     40      1.16     lukem static char sccsid[] = "@(#)main.c	8.6 (Berkeley) 5/1/95";
     41       1.6       cgd #else
     42  1.69.2.1       tls __RCSID("$NetBSD: main.c,v 1.69.2.2 2014/08/20 00:02:24 tls Exp $");
     43       1.6       cgd #endif
     44       1.1       cgd #endif /* not lint */
     45       1.1       cgd 
     46       1.3   mycroft #include <sys/param.h>
     47       1.3   mycroft #include <sys/time.h>
     48      1.14     lukem #include <sys/stat.h>
     49      1.14     lukem #include <sys/mount.h>
     50      1.14     lukem 
     51       1.3   mycroft #include <ufs/ffs/fs.h>
     52      1.18    bouyer #include <ufs/ffs/ffs_extern.h>
     53       1.3   mycroft 
     54       1.3   mycroft #include <ctype.h>
     55       1.5   mycroft #include <err.h>
     56       1.3   mycroft #include <errno.h>
     57       1.1       cgd #include <fcntl.h>
     58       1.1       cgd #include <fstab.h>
     59       1.3   mycroft #include <signal.h>
     60       1.1       cgd #include <stdio.h>
     61       1.1       cgd #include <stdlib.h>
     62       1.1       cgd #include <string.h>
     63      1.10     lukem #include <time.h>
     64       1.3   mycroft #include <unistd.h>
     65      1.68  christos #include <util.h>
     66       1.3   mycroft 
     67       1.1       cgd #include "dump.h"
     68       1.1       cgd #include "pathnames.h"
     69      1.58   hannken #include "snapshot.h"
     70       1.1       cgd 
     71      1.44     lukem int	timestamp;		/* print message timestamps */
     72      1.27       scw int	notify;			/* notify operator flag */
     73      1.27       scw int	blockswritten;		/* number of blocks written on current tape */
     74      1.27       scw int	tapeno;			/* current tape number */
     75      1.27       scw int	density;		/* density in bytes/0.1" */
     76      1.17     lukem int	ntrec = NTREC;		/* # tape blocks in each tape record */
     77      1.27       scw int	cartridge;		/* Assume non-cartridge tape */
     78      1.17     lukem long	dev_bsize = 1;		/* recalculated below */
     79      1.27       scw long	blocksperfile;		/* output blocks per file */
     80      1.59  christos const char *host;		/* remote host (if any) */
     81      1.22    bouyer int	readcache = -1;		/* read cache size (in readblksize blks) */
     82      1.22    bouyer int	readblksize = 32 * 1024; /* read block size */
     83      1.39     blymn char    default_time_string[] = "%T %Z"; /* default timestamp string */
     84      1.39     blymn char    *time_string = default_time_string; /* timestamp string */
     85       1.1       cgd 
     86      1.59  christos static long numarg(const char *, long, long);
     87      1.31     lukem static void obsolete(int *, char **[]);
     88      1.31     lukem static void usage(void);
     89       1.3   mycroft 
     90       1.3   mycroft int
     91      1.31     lukem main(int argc, char *argv[])
     92       1.1       cgd {
     93      1.11     lukem 	ino_t ino;
     94      1.45     lukem 	int dirty;
     95      1.55      fvdl 	union dinode *dp;
     96      1.33     lukem 	struct fstab *dt;
     97      1.57  christos 	struct statvfs *mntinfo, fsbuf;
     98      1.59  christos 	char *map, *cp;
     99      1.11     lukem 	int ch;
    100      1.38     lukem 	int i, anydirskipped, bflag = 0, Tflag = 0, Fflag = 0, honorlevel = 1;
    101      1.58   hannken 	int snap_internal = 0;
    102       1.1       cgd 	ino_t maxino;
    103      1.18    bouyer 	time_t tnow, date;
    104      1.33     lukem 	int dirc;
    105      1.33     lukem 	char *mountpoint;
    106      1.17     lukem 	int just_estimate = 0;
    107      1.21     lukem 	char labelstr[LBLSIZE];
    108      1.69  christos 	char buf[MAXPATHLEN], rbuf[MAXPATHLEN];
    109      1.39     blymn 	char *new_time_format;
    110      1.58   hannken 	char *snap_backup = NULL;
    111      1.45     lukem 
    112       1.1       cgd 	spcl.c_date = 0;
    113      1.47     lukem 	(void)time(&tnow);
    114      1.47     lukem 	spcl.c_date = tnow;
    115      1.39     blymn 	tzset(); /* set up timezone for strftime */
    116      1.39     blymn 	if ((new_time_format = getenv("TIMEFORMAT")) != NULL)
    117      1.39     blymn 		time_string = new_time_format;
    118      1.45     lukem 
    119       1.1       cgd 	tsize = 0;	/* Default later, based on 'c' option for cart tapes */
    120       1.7       mrg 	if ((tape = getenv("TAPE")) == NULL)
    121       1.7       mrg 		tape = _PATH_DEFTAPE;
    122       1.1       cgd 	dumpdates = _PATH_DUMPDATES;
    123       1.1       cgd 	temp = _PATH_DTMP;
    124      1.21     lukem 	strcpy(labelstr, "none");	/* XXX safe strcpy. */
    125       1.1       cgd 	if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0)
    126       1.1       cgd 		quit("TP_BSIZE must be a multiple of DEV_BSIZE\n");
    127       1.1       cgd 	level = '0';
    128      1.39     blymn 	timestamp = 0;
    129      1.45     lukem 
    130       1.5   mycroft 	if (argc < 2)
    131       1.5   mycroft 		usage();
    132       1.5   mycroft 
    133       1.5   mycroft 	obsolete(&argc, &argv);
    134      1.17     lukem 	while ((ch = getopt(argc, argv,
    135      1.65  christos 	    "0123456789aB:b:cd:eFf:h:ik:l:L:nr:s:StT:uWwx:X")) != -1)
    136       1.5   mycroft 		switch (ch) {
    137       1.5   mycroft 		/* dump level */
    138       1.5   mycroft 		case '0': case '1': case '2': case '3': case '4':
    139       1.5   mycroft 		case '5': case '6': case '7': case '8': case '9':
    140       1.5   mycroft 			level = ch;
    141       1.3   mycroft 			break;
    142       1.1       cgd 
    143      1.49     lukem 		case 'a':		/* `auto-size', Write to EOM. */
    144      1.49     lukem 			unlimited = 1;
    145      1.49     lukem 			break;
    146      1.49     lukem 
    147       1.5   mycroft 		case 'B':		/* blocks per output file */
    148       1.5   mycroft 			blocksperfile = numarg("blocks per file", 1L, 0L);
    149       1.5   mycroft 			break;
    150       1.1       cgd 
    151       1.5   mycroft 		case 'b':		/* blocks per tape write */
    152       1.5   mycroft 			ntrec = numarg("blocks per write", 1L, 1000L);
    153       1.9     mikel 			bflag = 1;
    154       1.5   mycroft 			break;
    155       1.1       cgd 
    156       1.5   mycroft 		case 'c':		/* Tape is cart. not 9-track */
    157       1.5   mycroft 			cartridge = 1;
    158       1.3   mycroft 			break;
    159       1.1       cgd 
    160       1.1       cgd 		case 'd':		/* density, in bits per inch */
    161       1.5   mycroft 			density = numarg("density", 10L, 327670L) / 10;
    162       1.1       cgd 			if (density >= 625 && !bflag)
    163       1.1       cgd 				ntrec = HIGHDENSITYTREC;
    164      1.28      tron 			break;
    165      1.28      tron 
    166      1.38     lukem 		case 'e':		/* eject full tapes */
    167      1.28      tron 			eflag = 1;
    168       1.3   mycroft 			break;
    169       1.1       cgd 
    170      1.38     lukem 		case 'F':		/* files-to-dump is an fs image */
    171      1.38     lukem 			Fflag = 1;
    172      1.38     lukem 			break;
    173      1.38     lukem 
    174       1.5   mycroft 		case 'f':		/* output file */
    175       1.5   mycroft 			tape = optarg;
    176       1.5   mycroft 			break;
    177       1.5   mycroft 
    178       1.5   mycroft 		case 'h':
    179       1.5   mycroft 			honorlevel = numarg("honor level", 0L, 10L);
    180       1.5   mycroft 			break;
    181       1.5   mycroft 
    182      1.66  christos 		case 'i':	/* "true incremental" regardless level */
    183      1.66  christos 			level = 'i';
    184      1.65  christos 			trueinc = 1;
    185      1.65  christos 			break;
    186      1.65  christos 
    187      1.22    bouyer 		case 'k':
    188      1.22    bouyer 			readblksize = numarg("read block size", 0, 64) * 1024;
    189      1.22    bouyer 			break;
    190      1.22    bouyer 
    191      1.41    bouyer 		case 'l':		/* autoload after eject full tapes */
    192      1.41    bouyer 			eflag = 1;
    193      1.50    bouyer 			lflag = numarg("timeout (in seconds)", 1, 0);
    194      1.41    bouyer 			break;
    195      1.41    bouyer 
    196      1.21     lukem 		case 'L':
    197      1.21     lukem 			/*
    198      1.21     lukem 			 * Note that although there are LBLSIZE characters,
    199      1.21     lukem 			 * the last must be '\0', so the limit on strlen()
    200      1.21     lukem 			 * is really LBLSIZE-1.
    201      1.21     lukem 			 */
    202      1.51    itojun 			if (strlcpy(labelstr, optarg, sizeof(labelstr))
    203      1.51    itojun 			    >= sizeof(labelstr)) {
    204      1.21     lukem 				msg(
    205      1.53    itojun 		"WARNING Label `%s' is larger than limit of %lu characters.\n",
    206      1.53    itojun 				    optarg,
    207      1.53    itojun 				    (unsigned long)sizeof(labelstr) - 1);
    208      1.21     lukem 				msg("WARNING: Using truncated label `%s'.\n",
    209      1.21     lukem 				    labelstr);
    210      1.21     lukem 			}
    211      1.21     lukem 			break;
    212       1.5   mycroft 		case 'n':		/* notify operators */
    213       1.5   mycroft 			notify = 1;
    214       1.5   mycroft 			break;
    215       1.5   mycroft 
    216      1.22    bouyer 		case 'r':		/* read cache size */
    217      1.22    bouyer 			readcache = numarg("read cache size", 0, 512);
    218      1.22    bouyer 			break;
    219      1.45     lukem 
    220       1.1       cgd 		case 's':		/* tape size, feet */
    221       1.5   mycroft 			tsize = numarg("tape size", 1L, 0L) * 12 * 10;
    222       1.3   mycroft 			break;
    223       1.1       cgd 
    224      1.17     lukem 		case 'S':		/* exit after estimating # of tapes */
    225      1.17     lukem 			just_estimate = 1;
    226      1.17     lukem 			break;
    227      1.17     lukem 
    228      1.39     blymn 		case 't':
    229      1.39     blymn 			timestamp = 1;
    230      1.39     blymn 			break;
    231      1.39     blymn 
    232       1.1       cgd 		case 'T':		/* time of last dump */
    233       1.5   mycroft 			spcl.c_ddate = unctime(optarg);
    234       1.1       cgd 			if (spcl.c_ddate < 0) {
    235       1.3   mycroft 				(void)fprintf(stderr, "bad time \"%s\"\n",
    236       1.5   mycroft 				    optarg);
    237      1.48     lukem 				exit(X_STARTUP);
    238       1.1       cgd 			}
    239       1.3   mycroft 			Tflag = 1;
    240       1.1       cgd 			lastlevel = '?';
    241       1.3   mycroft 			break;
    242       1.1       cgd 
    243       1.1       cgd 		case 'u':		/* update /etc/dumpdates */
    244       1.3   mycroft 			uflag = 1;
    245       1.3   mycroft 			break;
    246       1.1       cgd 
    247       1.5   mycroft 		case 'W':		/* what to do */
    248       1.5   mycroft 		case 'w':
    249       1.5   mycroft 			lastdump(ch);
    250      1.48     lukem 			exit(X_FINOK);	/* do nothing else */
    251       1.1       cgd 
    252      1.58   hannken 		case 'x':
    253      1.58   hannken 			snap_backup = optarg;
    254      1.58   hannken 			break;
    255      1.58   hannken 
    256      1.58   hannken 		case 'X':
    257      1.58   hannken 			snap_internal = 1;
    258      1.58   hannken 			break;
    259      1.58   hannken 
    260       1.1       cgd 		default:
    261       1.5   mycroft 			usage();
    262       1.1       cgd 		}
    263       1.5   mycroft 	argc -= optind;
    264       1.5   mycroft 	argv += optind;
    265       1.5   mycroft 
    266       1.1       cgd 	if (argc < 1) {
    267      1.38     lukem 		(void)fprintf(stderr,
    268      1.38     lukem 		    "Must specify disk or image, or file list\n");
    269      1.48     lukem 		exit(X_STARTUP);
    270       1.1       cgd 	}
    271      1.14     lukem 
    272      1.33     lukem 
    273      1.14     lukem 	/*
    274      1.14     lukem 	 *	determine if disk is a subdirectory, and setup appropriately
    275      1.14     lukem 	 */
    276      1.33     lukem 	getfstab();		/* /etc/fstab snarfed */
    277      1.33     lukem 	disk = NULL;
    278      1.63   hannken 	disk_dev = NULL;
    279      1.33     lukem 	mountpoint = NULL;
    280      1.33     lukem 	dirc = 0;
    281      1.14     lukem 	for (i = 0; i < argc; i++) {
    282      1.14     lukem 		struct stat sb;
    283  1.69.2.2       tls 		int error;
    284      1.14     lukem 
    285  1.69.2.2       tls 		error = lstat(argv[i], &sb);
    286  1.69.2.2       tls 		if (Fflag || (!error && (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)))) {
    287  1.69.2.2       tls 			if (error)
    288  1.69.2.2       tls 				quit("Cannot stat %s: %s\n", argv[i], strerror(errno));
    289      1.33     lukem 			disk = argv[i];
    290      1.33     lukem  multicheck:
    291      1.33     lukem 			if (dirc != 0)
    292  1.69.2.2       tls 				quit("Can't dump a disk or image at the same time as a file list\n");
    293      1.14     lukem 			break;
    294      1.14     lukem 		}
    295      1.33     lukem 		if ((dt = fstabsearch(argv[i])) != NULL) {
    296  1.69.2.2       tls 			disk = argv[i];
    297      1.34   hannken 			mountpoint = xstrdup(dt->fs_file);
    298      1.33     lukem 			goto multicheck;
    299      1.14     lukem 		}
    300      1.57  christos 		if (statvfs(argv[i], &fsbuf) == -1)
    301      1.57  christos 			quit("Cannot statvfs %s: %s\n", argv[i],
    302      1.33     lukem 			    strerror(errno));
    303      1.33     lukem 		disk = fsbuf.f_mntfromname;
    304      1.33     lukem 		if (strcmp(argv[i], fsbuf.f_mntonname) == 0)
    305      1.33     lukem 			goto multicheck;
    306      1.33     lukem 		if (mountpoint == NULL) {
    307      1.33     lukem 			mountpoint = xstrdup(fsbuf.f_mntonname);
    308      1.14     lukem 			if (uflag) {
    309      1.14     lukem 				msg("Ignoring u flag for subdir dump\n");
    310      1.14     lukem 				uflag = 0;
    311      1.14     lukem 			}
    312      1.14     lukem 			if (level > '0') {
    313      1.14     lukem 				msg("Subdir dump is done at level 0\n");
    314      1.14     lukem 				level = '0';
    315      1.14     lukem 			}
    316      1.33     lukem 			msg("Dumping sub files/directories from %s\n",
    317      1.33     lukem 			    mountpoint);
    318      1.14     lukem 		} else {
    319      1.33     lukem 			if (strcmp(mountpoint, fsbuf.f_mntonname) != 0)
    320      1.33     lukem 				quit("%s is not on %s\n", argv[i], mountpoint);
    321      1.14     lukem 		}
    322      1.14     lukem 		msg("Dumping file/directory %s\n", argv[i]);
    323      1.33     lukem 		dirc++;
    324      1.14     lukem 	}
    325      1.33     lukem 	if (mountpoint)
    326      1.33     lukem 		free(mountpoint);
    327      1.33     lukem 
    328      1.33     lukem 	if (dirc == 0) {
    329      1.33     lukem 		argv++;
    330      1.14     lukem 		if (argc != 1) {
    331      1.14     lukem 			(void)fprintf(stderr, "Excess arguments to dump:");
    332      1.14     lukem 			while (--argc)
    333      1.14     lukem 				(void)fprintf(stderr, " %s", *argv++);
    334      1.14     lukem 			(void)fprintf(stderr, "\n");
    335      1.48     lukem 			exit(X_STARTUP);
    336      1.14     lukem 		}
    337       1.1       cgd 	}
    338       1.1       cgd 	if (Tflag && uflag) {
    339      1.44     lukem 		(void)fprintf(stderr,
    340       1.1       cgd 		    "You cannot use the T and u flags together.\n");
    341      1.48     lukem 		exit(X_STARTUP);
    342       1.1       cgd 	}
    343       1.1       cgd 	if (strcmp(tape, "-") == 0) {
    344       1.1       cgd 		pipeout++;
    345       1.1       cgd 		tape = "standard output";
    346       1.1       cgd 	}
    347       1.1       cgd 
    348       1.1       cgd 	if (blocksperfile)
    349       1.1       cgd 		blocksperfile = blocksperfile / ntrec * ntrec; /* round down */
    350      1.49     lukem 	else if (!unlimited) {
    351       1.1       cgd 		/*
    352       1.1       cgd 		 * Determine how to default tape size and density
    353       1.1       cgd 		 *
    354      1.44     lukem 		 *		density				tape size
    355       1.1       cgd 		 * 9-track	1600 bpi (160 bytes/.1")	2300 ft.
    356       1.1       cgd 		 * 9-track	6250 bpi (625 bytes/.1")	2300 ft.
    357       1.1       cgd 		 * cartridge	8000 bpi (100 bytes/.1")	1700 ft.
    358       1.1       cgd 		 *						(450*4 - slop)
    359       1.1       cgd 		 */
    360       1.1       cgd 		if (density == 0)
    361       1.1       cgd 			density = cartridge ? 100 : 160;
    362       1.1       cgd 		if (tsize == 0)
    363       1.1       cgd 			tsize = cartridge ? 1700L*120L : 2300L*120L;
    364       1.1       cgd 	}
    365       1.1       cgd 
    366      1.59  christos 	if ((cp = strchr(tape, ':')) != NULL) {
    367       1.1       cgd 		host = tape;
    368      1.59  christos 		/* This is fine, because all the const strings don't have : */
    369      1.59  christos 		*cp++ = '\0';
    370      1.59  christos 		tape = cp;
    371       1.1       cgd #ifdef RDUMP
    372       1.1       cgd 		if (rmthost(host) == 0)
    373      1.48     lukem 			exit(X_STARTUP);
    374       1.1       cgd #else
    375       1.3   mycroft 		(void)fprintf(stderr, "remote dump not enabled\n");
    376      1.48     lukem 		exit(X_STARTUP);
    377       1.1       cgd #endif
    378       1.1       cgd 	}
    379       1.1       cgd 
    380       1.1       cgd 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
    381       1.1       cgd 		signal(SIGHUP, sig);
    382       1.1       cgd 	if (signal(SIGTRAP, SIG_IGN) != SIG_IGN)
    383       1.1       cgd 		signal(SIGTRAP, sig);
    384       1.1       cgd 	if (signal(SIGFPE, SIG_IGN) != SIG_IGN)
    385       1.1       cgd 		signal(SIGFPE, sig);
    386       1.1       cgd 	if (signal(SIGBUS, SIG_IGN) != SIG_IGN)
    387       1.1       cgd 		signal(SIGBUS, sig);
    388      1.55      fvdl #if 0
    389       1.1       cgd 	if (signal(SIGSEGV, SIG_IGN) != SIG_IGN)
    390       1.1       cgd 		signal(SIGSEGV, sig);
    391      1.55      fvdl #endif
    392       1.1       cgd 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
    393       1.1       cgd 		signal(SIGTERM, sig);
    394       1.1       cgd 	if (signal(SIGINT, interrupt) == SIG_IGN)
    395       1.1       cgd 		signal(SIGINT, SIG_IGN);
    396      1.14     lukem 
    397       1.1       cgd 	/*
    398      1.33     lukem 	 *	disk can be either the full special file name, or
    399      1.33     lukem 	 *	the file system name.
    400       1.1       cgd 	 */
    401      1.33     lukem 	mountpoint = NULL;
    402      1.58   hannken 	mntinfo = mntinfosearch(disk);
    403      1.33     lukem 	if ((dt = fstabsearch(disk)) != NULL) {
    404      1.68  christos 		if (getfsspecname(buf, sizeof(buf), dt->fs_spec) == NULL)
    405      1.68  christos 			quit("%s (%s)", buf, strerror(errno));
    406      1.69  christos 		if (getdiskrawname(rbuf, sizeof(rbuf), buf) == NULL)
    407      1.69  christos 			quit("Can't get disk raw name for `%s' (%s)",
    408      1.69  christos 			    buf, strerror(errno));
    409      1.69  christos 		disk = rbuf;
    410      1.33     lukem 		mountpoint = dt->fs_file;
    411      1.33     lukem 		msg("Found %s on %s in %s\n", disk, mountpoint, _PATH_FSTAB);
    412      1.58   hannken 	} else if (mntinfo != NULL) {
    413      1.69  christos 		if (getdiskrawname(rbuf, sizeof(rbuf), mntinfo->f_mntfromname)
    414      1.69  christos 		    == NULL)
    415      1.69  christos 			quit("Can't get disk raw name for `%s' (%s)",
    416      1.69  christos 			    mntinfo->f_mntfromname, strerror(errno));
    417  1.69.2.2       tls 		disk = rbuf;
    418      1.33     lukem 		mountpoint = mntinfo->f_mntonname;
    419      1.33     lukem 		msg("Found %s on %s in mount table\n", disk, mountpoint);
    420      1.33     lukem 	}
    421      1.33     lukem 	if (mountpoint != NULL) {
    422      1.33     lukem 		if (dirc != 0)
    423      1.51    itojun 			(void)snprintf(spcl.c_filesys, sizeof(spcl.c_filesys),
    424      1.33     lukem 			    "a subset of %s", mountpoint);
    425      1.14     lukem 		else
    426      1.51    itojun 			(void)strlcpy(spcl.c_filesys, mountpoint,
    427      1.51    itojun 			    sizeof(spcl.c_filesys));
    428      1.38     lukem 	} else if (Fflag) {
    429      1.51    itojun 		(void)strlcpy(spcl.c_filesys, "a file system image",
    430      1.51    itojun 		    sizeof(spcl.c_filesys));
    431       1.1       cgd 	} else {
    432      1.51    itojun 		(void)strlcpy(spcl.c_filesys, "an unlisted file system",
    433      1.51    itojun 		    sizeof(spcl.c_filesys));
    434       1.1       cgd 	}
    435      1.51    itojun 	(void)strlcpy(spcl.c_dev, disk, sizeof(spcl.c_dev));
    436      1.51    itojun 	(void)strlcpy(spcl.c_label, labelstr, sizeof(spcl.c_label));
    437      1.51    itojun 	(void)gethostname(spcl.c_host, sizeof(spcl.c_host));
    438      1.19       mrg 	spcl.c_host[sizeof(spcl.c_host) - 1] = '\0';
    439      1.18    bouyer 
    440      1.58   hannken 	if ((snap_backup != NULL || snap_internal) && mntinfo == NULL) {
    441      1.58   hannken 		msg("WARNING: Cannot use -x or -X on unmounted file system.\n");
    442      1.58   hannken 		snap_backup = NULL;
    443      1.58   hannken 		snap_internal = 0;
    444      1.58   hannken 	}
    445      1.62  perseant 
    446      1.62  perseant #ifdef DUMP_LFS
    447      1.62  perseant 	sync();
    448      1.62  perseant 	if (snap_backup != NULL || snap_internal) {
    449      1.62  perseant 		if (lfs_wrap_stop(mountpoint) < 0) {
    450      1.62  perseant 			msg("Cannot stop writing on %s\n", mountpoint);
    451      1.62  perseant 			exit(X_STARTUP);
    452      1.62  perseant 		}
    453      1.62  perseant 	}
    454      1.62  perseant 	if ((diskfd = open(disk, O_RDONLY)) < 0) {
    455      1.62  perseant 		msg("Cannot open %s\n", disk);
    456      1.62  perseant 		exit(X_STARTUP);
    457      1.62  perseant 	}
    458      1.63   hannken 	disk_dev = disk;
    459      1.62  perseant #else /* ! DUMP_LFS */
    460      1.58   hannken 	if (snap_backup != NULL || snap_internal) {
    461      1.63   hannken 		diskfd = snap_open(mntinfo->f_mntonname, snap_backup,
    462      1.63   hannken 		    &tnow, &disk_dev);
    463      1.58   hannken 		if (diskfd < 0) {
    464      1.58   hannken 			msg("Cannot open snapshot of %s\n",
    465      1.58   hannken 				mntinfo->f_mntonname);
    466      1.58   hannken 			exit(X_STARTUP);
    467      1.58   hannken 		}
    468      1.58   hannken 		spcl.c_date = tnow;
    469      1.58   hannken 	} else {
    470      1.58   hannken 		if ((diskfd = open(disk, O_RDONLY)) < 0) {
    471      1.58   hannken 			msg("Cannot open %s\n", disk);
    472      1.58   hannken 			exit(X_STARTUP);
    473      1.58   hannken 		}
    474      1.63   hannken 		disk_dev = disk;
    475      1.18    bouyer 	}
    476      1.18    bouyer 	sync();
    477      1.62  perseant #endif /* ! DUMP_LFS */
    478      1.25  perseant 
    479      1.25  perseant 	needswap = fs_read_sblock(sblock_buf);
    480      1.18    bouyer 
    481      1.66  christos 	/* true incremental is always a level 10 dump */
    482      1.66  christos 	spcl.c_level = trueinc? iswap32(10): iswap32(level - '0');
    483      1.18    bouyer 	spcl.c_type = iswap32(TS_TAPE);
    484      1.18    bouyer 	spcl.c_date = iswap32(spcl.c_date);
    485      1.18    bouyer 	spcl.c_ddate = iswap32(spcl.c_ddate);
    486       1.1       cgd 	if (!Tflag)
    487      1.44     lukem 		getdumptime();		/* /etc/dumpdates snarfed */
    488       1.1       cgd 
    489      1.18    bouyer 	date = iswap32(spcl.c_date);
    490       1.1       cgd 	msg("Date of this level %c dump: %s", level,
    491      1.18    bouyer 		spcl.c_date == 0 ? "the epoch\n" : ctime(&date));
    492      1.18    bouyer 	date = iswap32(spcl.c_ddate);
    493       1.1       cgd  	msg("Date of last level %c dump: %s", lastlevel,
    494      1.18    bouyer 		spcl.c_ddate == 0 ? "the epoch\n" : ctime(&date));
    495      1.17     lukem 	msg("Dumping ");
    496      1.61   hannken 	if (snap_backup != NULL || snap_internal)
    497      1.58   hannken 		msgtail("a snapshot of ");
    498      1.33     lukem 	if (dirc != 0)
    499      1.17     lukem 		msgtail("a subset of ");
    500      1.17     lukem 	msgtail("%s (%s) ", disk, spcl.c_filesys);
    501       1.1       cgd 	if (host)
    502       1.1       cgd 		msgtail("to %s on host %s\n", tape, host);
    503       1.1       cgd 	else
    504       1.1       cgd 		msgtail("to %s\n", tape);
    505      1.21     lukem 	msg("Label: %s\n", labelstr);
    506       1.1       cgd 
    507      1.25  perseant 	ufsib = fs_parametrize();
    508      1.25  perseant 
    509       1.1       cgd 	dev_bshift = ffs(dev_bsize) - 1;
    510       1.1       cgd 	if (dev_bsize != (1 << dev_bshift))
    511      1.26    briggs 		quit("dev_bsize (%ld) is not a power of 2", dev_bsize);
    512       1.1       cgd 	tp_bshift = ffs(TP_BSIZE) - 1;
    513       1.1       cgd 	if (TP_BSIZE != (1 << tp_bshift))
    514       1.1       cgd 		quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
    515      1.25  perseant 	maxino = fs_maxino();
    516       1.3   mycroft 	mapsize = roundup(howmany(maxino, NBBY), TP_BSIZE);
    517      1.33     lukem 	usedinomap = (char *)xcalloc((unsigned) mapsize, sizeof(char));
    518      1.33     lukem 	dumpdirmap = (char *)xcalloc((unsigned) mapsize, sizeof(char));
    519      1.33     lukem 	dumpinomap = (char *)xcalloc((unsigned) mapsize, sizeof(char));
    520       1.1       cgd 	tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
    521       1.1       cgd 
    522      1.18    bouyer 	nonodump = iswap32(spcl.c_level) < honorlevel;
    523       1.3   mycroft 
    524      1.22    bouyer 	initcache(readcache, readblksize);
    525      1.45     lukem 
    526      1.14     lukem 	(void)signal(SIGINFO, statussig);
    527      1.14     lukem 
    528       1.1       cgd 	msg("mapping (Pass I) [regular files]\n");
    529      1.33     lukem 	anydirskipped = mapfiles(maxino, &tapesize, mountpoint,
    530      1.33     lukem 	    (dirc ? argv : NULL));
    531       1.1       cgd 
    532       1.1       cgd 	msg("mapping (Pass II) [directories]\n");
    533       1.1       cgd 	while (anydirskipped) {
    534       1.1       cgd 		anydirskipped = mapdirs(maxino, &tapesize);
    535       1.1       cgd 	}
    536       1.1       cgd 
    537      1.49     lukem 	if (pipeout || unlimited) {
    538       1.1       cgd 		tapesize += 10;	/* 10 trailer blocks */
    539      1.55      fvdl 		msg("estimated %llu tape blocks.\n",
    540      1.55      fvdl 		    (unsigned long long)tapesize);
    541       1.3   mycroft 	} else {
    542       1.3   mycroft 		double fetapes;
    543       1.3   mycroft 
    544       1.1       cgd 		if (blocksperfile)
    545       1.3   mycroft 			fetapes = (double) tapesize / blocksperfile;
    546       1.1       cgd 		else if (cartridge) {
    547       1.1       cgd 			/* Estimate number of tapes, assuming streaming stops at
    548       1.1       cgd 			   the end of each block written, and not in mid-block.
    549       1.1       cgd 			   Assume no erroneous blocks; this can be compensated
    550       1.1       cgd 			   for with an artificially low tape size. */
    551      1.45     lukem 			fetapes =
    552      1.48     lukem 			(	  (double) tapesize	/* blocks */
    553       1.1       cgd 				* TP_BSIZE	/* bytes/block */
    554       1.1       cgd 				* (1.0/density)	/* 0.1" / byte */
    555       1.1       cgd 			  +
    556      1.48     lukem 				  (double) tapesize	/* blocks */
    557       1.1       cgd 				* (1.0/ntrec)	/* streaming-stops per block */
    558       1.1       cgd 				* 15.48		/* 0.1" / streaming-stop */
    559       1.1       cgd 			) * (1.0 / tsize );	/* tape / 0.1" */
    560       1.1       cgd 		} else {
    561       1.1       cgd 			/* Estimate number of tapes, for old fashioned 9-track
    562       1.1       cgd 			   tape */
    563       1.1       cgd 			int tenthsperirg = (density == 625) ? 3 : 7;
    564       1.1       cgd 			fetapes =
    565       1.1       cgd 			(	  tapesize	/* blocks */
    566       1.1       cgd 				* TP_BSIZE	/* bytes / block */
    567       1.1       cgd 				* (1.0/density)	/* 0.1" / byte */
    568       1.1       cgd 			  +
    569       1.1       cgd 				  tapesize	/* blocks */
    570       1.1       cgd 				* (1.0/ntrec)	/* IRG's / block */
    571       1.1       cgd 				* tenthsperirg	/* 0.1" / IRG */
    572       1.1       cgd 			) * (1.0 / tsize );	/* tape / 0.1" */
    573       1.1       cgd 		}
    574       1.1       cgd 		etapes = fetapes;		/* truncating assignment */
    575       1.1       cgd 		etapes++;
    576       1.1       cgd 		/* count the dumped inodes map on each additional tape */
    577       1.1       cgd 		tapesize += (etapes - 1) *
    578       1.1       cgd 			(howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
    579       1.1       cgd 		tapesize += etapes + 10;	/* headers + 10 trailer blks */
    580      1.55      fvdl 		msg("estimated %llu tape blocks on %3.2f tape(s).\n",
    581      1.55      fvdl 		    (unsigned long long)tapesize, fetapes);
    582       1.3   mycroft 	}
    583      1.17     lukem 	/*
    584      1.17     lukem 	 * If the user only wants an estimate of the number of
    585      1.17     lukem 	 * tapes, exit now.
    586      1.17     lukem 	 */
    587      1.17     lukem 	if (just_estimate)
    588      1.48     lukem 		exit(X_FINOK);
    589       1.1       cgd 
    590       1.1       cgd 	/*
    591       1.3   mycroft 	 * Allocate tape buffer.
    592       1.1       cgd 	 */
    593       1.1       cgd 	if (!alloctape())
    594       1.1       cgd 		quit("can't allocate tape buffers - try a smaller blocking factor.\n");
    595       1.1       cgd 
    596       1.1       cgd 	startnewtape(1);
    597       1.3   mycroft 	(void)time((time_t *)&(tstart_writing));
    598      1.10     lukem 	xferrate = 0;
    599       1.3   mycroft 	dumpmap(usedinomap, TS_CLRI, maxino - 1);
    600       1.1       cgd 
    601       1.1       cgd 	msg("dumping (Pass III) [directories]\n");
    602       1.3   mycroft 	dirty = 0;		/* XXX just to get gcc to shut up */
    603       1.3   mycroft 	for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
    604       1.3   mycroft 		if (((ino - 1) % NBBY) == 0)	/* map is offset by 1 */
    605       1.1       cgd 			dirty = *map++;
    606       1.1       cgd 		else
    607       1.1       cgd 			dirty >>= 1;
    608       1.1       cgd 		if ((dirty & 1) == 0)
    609       1.1       cgd 			continue;
    610       1.1       cgd 		/*
    611       1.1       cgd 		 * Skip directory inodes deleted and maybe reallocated
    612       1.1       cgd 		 */
    613       1.1       cgd 		dp = getino(ino);
    614      1.55      fvdl 		if ((DIP(dp, mode) & IFMT) != IFDIR)
    615       1.1       cgd 			continue;
    616       1.3   mycroft 		(void)dumpino(dp, ino);
    617       1.1       cgd 	}
    618       1.1       cgd 
    619       1.1       cgd 	msg("dumping (Pass IV) [regular files]\n");
    620       1.3   mycroft 	for (map = dumpinomap, ino = 1; ino < maxino; ino++) {
    621       1.3   mycroft 		int mode;
    622       1.3   mycroft 
    623       1.3   mycroft 		if (((ino - 1) % NBBY) == 0)	/* map is offset by 1 */
    624       1.1       cgd 			dirty = *map++;
    625       1.1       cgd 		else
    626       1.1       cgd 			dirty >>= 1;
    627       1.1       cgd 		if ((dirty & 1) == 0)
    628       1.1       cgd 			continue;
    629       1.1       cgd 		/*
    630       1.1       cgd 		 * Skip inodes deleted and reallocated as directories.
    631       1.1       cgd 		 */
    632       1.1       cgd 		dp = getino(ino);
    633      1.55      fvdl 		mode = DIP(dp, mode) & IFMT;
    634       1.3   mycroft 		if (mode == IFDIR)
    635       1.1       cgd 			continue;
    636       1.3   mycroft 		(void)dumpino(dp, ino);
    637       1.1       cgd 	}
    638       1.1       cgd 
    639      1.18    bouyer 	spcl.c_type = iswap32(TS_END);
    640       1.1       cgd 	for (i = 0; i < ntrec; i++)
    641       1.3   mycroft 		writeheader(maxino - 1);
    642       1.1       cgd 	if (pipeout)
    643      1.26    briggs 		msg("%d tape blocks\n",iswap32(spcl.c_tapea));
    644       1.1       cgd 	else
    645      1.26    briggs 		msg("%d tape blocks on %d volume%s\n",
    646      1.18    bouyer 		    iswap32(spcl.c_tapea), iswap32(spcl.c_volume),
    647      1.18    bouyer 		    (iswap32(spcl.c_volume) == 1) ? "" : "s");
    648      1.10     lukem 	tnow = do_stats();
    649      1.18    bouyer 	date = iswap32(spcl.c_date);
    650      1.10     lukem 	msg("Date of this level %c dump: %s", level,
    651      1.18    bouyer 		spcl.c_date == 0 ? "the epoch\n" : ctime(&date));
    652      1.10     lukem 	msg("Date this dump completed:  %s", ctime(&tnow));
    653      1.26    briggs 	msg("Average transfer rate: %d KB/s\n", xferrate / tapeno);
    654       1.1       cgd 	putdumptime();
    655      1.29      tron 	trewind(0);
    656      1.48     lukem 	broadcast("DUMP IS DONE!\a\a\n");
    657      1.62  perseant #ifdef DUMP_LFS
    658      1.62  perseant 	lfs_wrap_go();
    659      1.62  perseant #endif /* DUMP_LFS */
    660       1.1       cgd 	msg("DUMP IS DONE\n");
    661       1.1       cgd 	Exit(X_FINOK);
    662       1.1       cgd 	/* NOTREACHED */
    663      1.15     lukem 	exit(X_FINOK);		/* XXX: to satisfy gcc */
    664       1.1       cgd }
    665       1.1       cgd 
    666       1.5   mycroft static void
    667      1.31     lukem usage(void)
    668       1.5   mycroft {
    669      1.49     lukem 	const char *prog = getprogname();
    670       1.5   mycroft 
    671      1.49     lukem 	(void)fprintf(stderr,
    672      1.67  christos "usage: %s [-0123456789aceFinStuX] [-B records] [-b blocksize]\n"
    673      1.49     lukem "            [-d density] [-f file] [-h level] [-k read-blocksize]\n"
    674      1.67  christos "            [-L label] [-l timeout] [-r cachesize] [-s feet]\n"
    675      1.58   hannken "            [-T date] [-x snap-backup] files-to-dump\n"
    676      1.49     lukem "       %s [-W | -w]\n", prog, prog);
    677      1.48     lukem 	exit(X_STARTUP);
    678       1.5   mycroft }
    679       1.5   mycroft 
    680       1.3   mycroft /*
    681       1.3   mycroft  * Pick up a numeric argument.  It must be nonnegative and in the given
    682       1.3   mycroft  * range (except that a vmax of 0 means unlimited).
    683       1.3   mycroft  */
    684       1.3   mycroft static long
    685      1.59  christos numarg(const char *meaning, long vmin, long vmax)
    686       1.3   mycroft {
    687       1.5   mycroft 	char *p;
    688       1.3   mycroft 	long val;
    689       1.3   mycroft 
    690       1.5   mycroft 	val = strtol(optarg, &p, 10);
    691       1.5   mycroft 	if (*p)
    692      1.48     lukem 		errx(X_STARTUP, "illegal %s -- %s", meaning, optarg);
    693       1.3   mycroft 	if (val < vmin || (vmax && val > vmax))
    694      1.48     lukem 		errx(X_STARTUP, "%s must be between %ld and %ld",
    695      1.48     lukem 		    meaning, vmin, vmax);
    696       1.3   mycroft 	return (val);
    697       1.3   mycroft }
    698       1.3   mycroft 
    699       1.1       cgd void
    700      1.32     lukem sig(int signo)
    701       1.1       cgd {
    702      1.32     lukem 
    703       1.1       cgd 	switch(signo) {
    704       1.1       cgd 	case SIGALRM:
    705       1.1       cgd 	case SIGBUS:
    706       1.1       cgd 	case SIGFPE:
    707       1.1       cgd 	case SIGHUP:
    708       1.1       cgd 	case SIGTERM:
    709       1.1       cgd 	case SIGTRAP:
    710       1.1       cgd 		if (pipeout)
    711       1.1       cgd 			quit("Signal on pipe: cannot recover\n");
    712      1.35       mrg 		msg("Rewriting attempted as response to signal %s.\n", sys_siglist[signo]);
    713       1.3   mycroft 		(void)fflush(stderr);
    714       1.3   mycroft 		(void)fflush(stdout);
    715       1.1       cgd 		close_rewind();
    716       1.3   mycroft 		exit(X_REWRITE);
    717       1.1       cgd 		/* NOTREACHED */
    718       1.1       cgd 	case SIGSEGV:
    719       1.1       cgd 		msg("SIGSEGV: ABORTING!\n");
    720       1.3   mycroft 		(void)signal(SIGSEGV, SIG_DFL);
    721       1.3   mycroft 		(void)kill(0, SIGSEGV);
    722       1.1       cgd 		/* NOTREACHED */
    723       1.1       cgd 	}
    724       1.1       cgd }
    725       1.1       cgd 
    726       1.5   mycroft /*
    727       1.5   mycroft  * obsolete --
    728       1.5   mycroft  *	Change set of key letters and ordered arguments into something
    729       1.5   mycroft  *	getopt(3) will like.
    730       1.5   mycroft  */
    731       1.5   mycroft static void
    732      1.32     lukem obsolete(int *argcp, char **argvp[])
    733       1.1       cgd {
    734       1.5   mycroft 	int argc, flags;
    735       1.5   mycroft 	char *ap, **argv, *flagsp, **nargv, *p;
    736       1.5   mycroft 
    737       1.5   mycroft 	/* Setup. */
    738       1.5   mycroft 	argv = *argvp;
    739       1.5   mycroft 	argc = *argcp;
    740       1.5   mycroft 
    741       1.5   mycroft 	/* Return if no arguments or first argument has leading dash. */
    742       1.5   mycroft 	ap = argv[1];
    743       1.5   mycroft 	if (argc == 1 || *ap == '-')
    744       1.5   mycroft 		return;
    745       1.5   mycroft 
    746       1.5   mycroft 	/* Allocate space for new arguments. */
    747      1.33     lukem 	*argvp = nargv = xmalloc((argc + 1) * sizeof(char *));
    748      1.33     lukem 	p = flagsp = xmalloc(strlen(ap) + 2);
    749       1.5   mycroft 
    750       1.5   mycroft 	*nargv++ = *argv;
    751       1.5   mycroft 	argv += 2;
    752       1.5   mycroft 
    753       1.5   mycroft 	for (flags = 0; *ap; ++ap) {
    754       1.5   mycroft 		switch (*ap) {
    755       1.5   mycroft 		case 'B':
    756       1.5   mycroft 		case 'b':
    757       1.5   mycroft 		case 'd':
    758       1.5   mycroft 		case 'f':
    759       1.5   mycroft 		case 'h':
    760       1.5   mycroft 		case 's':
    761       1.5   mycroft 		case 'T':
    762      1.58   hannken 		case 'x':
    763       1.5   mycroft 			if (*argv == NULL) {
    764       1.5   mycroft 				warnx("option requires an argument -- %c", *ap);
    765       1.5   mycroft 				usage();
    766       1.5   mycroft 			}
    767      1.33     lukem 			nargv[0] = xmalloc(strlen(*argv) + 2 + 1);
    768       1.5   mycroft 			nargv[0][0] = '-';
    769       1.5   mycroft 			nargv[0][1] = *ap;
    770      1.17     lukem 			(void)strcpy(&nargv[0][2], *argv); /* XXX safe strcpy */
    771       1.5   mycroft 			++argv;
    772       1.5   mycroft 			++nargv;
    773       1.5   mycroft 			break;
    774       1.5   mycroft 		default:
    775       1.5   mycroft 			if (!flags) {
    776       1.5   mycroft 				*p++ = '-';
    777       1.5   mycroft 				flags = 1;
    778       1.5   mycroft 			}
    779       1.5   mycroft 			*p++ = *ap;
    780       1.5   mycroft 			break;
    781       1.5   mycroft 		}
    782       1.5   mycroft 	}
    783       1.1       cgd 
    784       1.5   mycroft 	/* Terminate flags. */
    785       1.5   mycroft 	if (flags) {
    786       1.5   mycroft 		*p = '\0';
    787       1.5   mycroft 		*nargv++ = flagsp;
    788      1.60  christos 	} else
    789      1.60  christos 		free(flagsp);
    790       1.5   mycroft 
    791       1.5   mycroft 	/* Copy remaining arguments. */
    792      1.14     lukem 	while ((*nargv++ = *argv++) != NULL)
    793      1.14     lukem 		;
    794       1.5   mycroft 
    795       1.5   mycroft 	/* Update argument count. */
    796       1.5   mycroft 	*argcp = nargv - *argvp - 1;
    797      1.33     lukem }
    798      1.33     lukem 
    799      1.33     lukem 
    800      1.33     lukem void *
    801      1.33     lukem xcalloc(size_t number, size_t size)
    802      1.33     lukem {
    803      1.33     lukem 	void *p;
    804      1.33     lukem 
    805      1.33     lukem 	p = calloc(number, size);
    806      1.33     lukem 	if (p == NULL)
    807      1.33     lukem 		quit("%s\n", strerror(errno));
    808      1.33     lukem 	return (p);
    809      1.33     lukem }
    810      1.33     lukem 
    811      1.33     lukem void *
    812      1.33     lukem xmalloc(size_t size)
    813      1.33     lukem {
    814      1.33     lukem 	void *p;
    815      1.33     lukem 
    816      1.33     lukem 	p = malloc(size);
    817      1.33     lukem 	if (p == NULL)
    818      1.33     lukem 		quit("%s\n", strerror(errno));
    819      1.33     lukem 	return (p);
    820      1.33     lukem }
    821      1.33     lukem 
    822      1.33     lukem char *
    823      1.33     lukem xstrdup(const char *str)
    824      1.33     lukem {
    825      1.33     lukem 	char *p;
    826      1.33     lukem 
    827      1.33     lukem 	p = strdup(str);
    828      1.33     lukem 	if (p == NULL)
    829      1.33     lukem 		quit("%s\n", strerror(errno));
    830      1.33     lukem 	return (p);
    831       1.1       cgd }
    832