xref: /openbsd-src/sbin/dump/traverse.c (revision f6e4162f05818bbc182b2d0e7e8682ece0079a77)
1*f6e4162fSjsg /*	$OpenBSD: traverse.c,v 1.43 2024/09/15 07:14:58 jsg Exp $	*/
22904a520Smillert /*	$NetBSD: traverse.c,v 1.17 1997/06/05 11:13:27 lukem Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*-
5df930be7Sderaadt  * Copyright (c) 1980, 1988, 1991, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt  * modification, are permitted provided that the following conditions
10df930be7Sderaadt  * are met:
11df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
161ef0d710Smillert  * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
18df930be7Sderaadt  *    without specific prior written permission.
19df930be7Sderaadt  *
20df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt  * SUCH DAMAGE.
31df930be7Sderaadt  */
32df930be7Sderaadt 
3378eb0b7eSderaadt #include <sys/param.h>	/* MAXBSIZE DEV_BSIZE dbtob */
34df930be7Sderaadt #include <sys/time.h>
35df930be7Sderaadt #include <sys/stat.h>
36b39ffb6cSkrw #include <sys/disklabel.h>
37df930be7Sderaadt #include <ufs/ffs/fs.h>
38df930be7Sderaadt #include <ufs/ufs/dir.h>
39df930be7Sderaadt #include <ufs/ufs/dinode.h>
40df930be7Sderaadt 
41df930be7Sderaadt #include <protocols/dumprestore.h>
42df930be7Sderaadt 
43df930be7Sderaadt #include <ctype.h>
442904a520Smillert #include <errno.h>
452904a520Smillert #include <fts.h>
46df930be7Sderaadt #include <stdio.h>
470155e653Smillert #include <stdlib.h>
48df930be7Sderaadt #include <string.h>
49df930be7Sderaadt #include <unistd.h>
50b9fc9a72Sderaadt #include <limits.h>
51df930be7Sderaadt 
52df930be7Sderaadt #include "dump.h"
53df930be7Sderaadt 
54b39ffb6cSkrw extern struct disklabel lab;
55b39ffb6cSkrw 
560155e653Smillert union dinode {
570155e653Smillert 	struct ufs1_dinode dp1;
580155e653Smillert 	struct ufs2_dinode dp2;
590155e653Smillert };
600155e653Smillert #define	DIP(dp, field) \
610155e653Smillert 	((sblock->fs_magic == FS_UFS1_MAGIC) ? \
620155e653Smillert 	(dp)->dp1.field : (dp)->dp2.field)
630155e653Smillert 
64df930be7Sderaadt #define	HASDUMPEDFILE	0x1
65df930be7Sderaadt #define	HASSUBDIRS	0x2
66df930be7Sderaadt 
670603cbefSnaddy static	int dirindir(ino_t, daddr_t, int, off_t *, int64_t *, int);
681abdbfdeSderaadt static	void dmpindir(ino_t, daddr_t, int, off_t *);
690603cbefSnaddy static	int searchdir(ino_t, daddr_t, long, off_t, int64_t *, int);
70e07939ebSderaadt void	fs_mapinodes(ino_t maxino, off_t *tapesize, int *anydirskipped);
71df930be7Sderaadt 
72df930be7Sderaadt /*
73df930be7Sderaadt  * This is an estimation of the number of TP_BSIZE blocks in the file.
74df930be7Sderaadt  * It estimates the number of blocks in files with holes by assuming
75df930be7Sderaadt  * that all of the blocks accounted for by di_blocks are data blocks
76df930be7Sderaadt  * (when some of the blocks are usually used for indirect pointers);
77df930be7Sderaadt  * hence the estimate may be high.
78df930be7Sderaadt  */
790603cbefSnaddy int64_t
800155e653Smillert blockest(union dinode *dp)
81df930be7Sderaadt {
820603cbefSnaddy 	int64_t blkest, sizeest;
83df930be7Sderaadt 
84df930be7Sderaadt 	/*
85df930be7Sderaadt 	 * dp->di_size is the size of the file in bytes.
86df930be7Sderaadt 	 * dp->di_blocks stores the number of sectors actually in the file.
87df930be7Sderaadt 	 * If there are more sectors than the size would indicate, this just
88df930be7Sderaadt 	 *	means that there are indirect blocks in the file or unused
89df930be7Sderaadt 	 *	sectors in the last file block; we can safely ignore these
90df930be7Sderaadt 	 *	(blkest = sizeest below).
91df930be7Sderaadt 	 * If the file is bigger than the number of sectors would indicate,
92df930be7Sderaadt 	 *	then the file has holes in it.	In this case we must use the
93df930be7Sderaadt 	 *	block count to estimate the number of data blocks used, but
94df930be7Sderaadt 	 *	we use the actual size for estimating the number of indirect
95df930be7Sderaadt 	 *	dump blocks (sizeest vs. blkest in the indirect block
96df930be7Sderaadt 	 *	calculation).
97df930be7Sderaadt 	 */
980603cbefSnaddy 	blkest = howmany(dbtob((int64_t)DIP(dp, di_blocks)), TP_BSIZE);
990603cbefSnaddy 	sizeest = howmany((int64_t)DIP(dp, di_size), TP_BSIZE);
100df930be7Sderaadt 	if (blkest > sizeest)
101df930be7Sderaadt 		blkest = sizeest;
1020155e653Smillert 	if (DIP(dp, di_size) > sblock->fs_bsize * NDADDR) {
103df930be7Sderaadt 		/* calculate the number of indirect blocks on the dump tape */
104df930be7Sderaadt 		blkest +=
105df930be7Sderaadt 			howmany(sizeest - NDADDR * sblock->fs_bsize / TP_BSIZE,
106df930be7Sderaadt 			TP_NINDIR);
107df930be7Sderaadt 	}
108df930be7Sderaadt 	return (blkest + 1);
109df930be7Sderaadt }
110df930be7Sderaadt 
111583aebd5Szhuk /* true if "nodump" flag has no effect here, i.e. dumping allowed */
112583aebd5Szhuk #define CHECKNODUMP(dp) \
113583aebd5Szhuk 	(nonodump || (DIP((dp), di_flags) & UF_NODUMP) != UF_NODUMP)
114df930be7Sderaadt 
115df930be7Sderaadt /*
1162904a520Smillert  * Determine if given inode should be dumped
117df930be7Sderaadt  */
1182904a520Smillert void
1190603cbefSnaddy mapfileino(ino_t ino, int64_t *tapesize, int *dirskipped)
120df930be7Sderaadt {
1212904a520Smillert 	int mode;
1220155e653Smillert 	union dinode *dp;
123df930be7Sderaadt 
1240155e653Smillert 	dp = getino(ino, &mode);
1250155e653Smillert 	if (mode == 0)
1262904a520Smillert 		return;
127df930be7Sderaadt 	SETINO(ino, usedinomap);
128df930be7Sderaadt 	if (mode == IFDIR)
129df930be7Sderaadt 		SETINO(ino, dumpdirmap);
130583aebd5Szhuk 	if (CHECKNODUMP(dp) &&
131583aebd5Szhuk 	    (DIP(dp, di_mtime) >= spcl.c_ddate ||
132583aebd5Szhuk 	     DIP(dp, di_ctime) >= spcl.c_ddate)) {
133df930be7Sderaadt 		SETINO(ino, dumpinomap);
134df930be7Sderaadt 		if (mode != IFREG && mode != IFDIR && mode != IFLNK)
135df930be7Sderaadt 			*tapesize += 1;
136df930be7Sderaadt 		else
137df930be7Sderaadt 			*tapesize += blockest(dp);
1382904a520Smillert 		return;
139df930be7Sderaadt 	}
140583aebd5Szhuk 	if (mode == IFDIR) {
141583aebd5Szhuk 		if (!CHECKNODUMP(dp))
142583aebd5Szhuk 			CLRINO(ino, usedinomap);
1432904a520Smillert 		*dirskipped = 1;
1442904a520Smillert 	}
145583aebd5Szhuk }
1462904a520Smillert 
1470155e653Smillert void
1480603cbefSnaddy fs_mapinodes(ino_t maxino, int64_t *tapesize, int *anydirskipped)
1490155e653Smillert {
1500155e653Smillert 	int i, cg, inosused;
1510155e653Smillert 	struct cg *cgp;
1520155e653Smillert 	ino_t ino;
1530155e653Smillert 
1540155e653Smillert 	if ((cgp = malloc(sblock->fs_cgsize)) == NULL)
1550155e653Smillert 		quit("fs_mapinodes: cannot allocate memory.\n");
1560155e653Smillert 
1570155e653Smillert 	for (cg = 0; cg < sblock->fs_ncg; cg++) {
158d16fc9bbSguenther 		ino = cg * (ino_t)sblock->fs_ipg;
1590155e653Smillert 		bread(fsbtodb(sblock, cgtod(sblock, cg)), (char *)cgp,
1600155e653Smillert 		    sblock->fs_cgsize);
1610155e653Smillert 		if (sblock->fs_magic == FS_UFS2_MAGIC)
1620155e653Smillert 			inosused = cgp->cg_initediblk;
1630155e653Smillert 		else
1640155e653Smillert 			inosused = sblock->fs_ipg;
1650155e653Smillert 		for (i = 0; i < inosused; i++, ino++) {
1660155e653Smillert 			if (ino < ROOTINO)
1670155e653Smillert 				continue;
1680155e653Smillert 			mapfileino(ino, tapesize, anydirskipped);
1690155e653Smillert 		}
1700155e653Smillert 	}
1710155e653Smillert 
1720155e653Smillert 	free(cgp);
1730155e653Smillert }
1740155e653Smillert 
1752904a520Smillert /*
1762904a520Smillert  * Dump pass 1.
1772904a520Smillert  *
1782904a520Smillert  * Walk the inode list for a filesystem to find all allocated inodes
1792904a520Smillert  * that have been modified since the previous dump time. Also, find all
1802904a520Smillert  * the directories in the filesystem.
1812904a520Smillert  */
1822904a520Smillert int
1830603cbefSnaddy mapfiles(ino_t maxino, int64_t *tapesize, char *disk, char * const *dirv)
1842904a520Smillert {
1852904a520Smillert 	int anydirskipped = 0;
1862904a520Smillert 
1872904a520Smillert 	if (dirv != NULL) {
188b9fc9a72Sderaadt 		char	 curdir[PATH_MAX];
1892904a520Smillert 		FTS	*dirh;
1902904a520Smillert 		FTSENT	*entry;
1912904a520Smillert 		int	 d;
1922904a520Smillert 
1932904a520Smillert 		if (getcwd(curdir, sizeof(curdir)) == NULL) {
1942904a520Smillert 			msg("Can't determine cwd: %s\n", strerror(errno));
1952904a520Smillert 			dumpabort(0);
1962904a520Smillert 		}
1972904a520Smillert 		if ((dirh = fts_open(dirv, FTS_PHYSICAL|FTS_SEEDOT|FTS_XDEV,
19853fedb49Sderaadt 		    NULL)) == NULL) {
1992904a520Smillert 			msg("fts_open failed: %s\n", strerror(errno));
2002904a520Smillert 			dumpabort(0);
2012904a520Smillert 		}
2022904a520Smillert 		while ((entry = fts_read(dirh)) != NULL) {
2032904a520Smillert 			switch (entry->fts_info) {
2042904a520Smillert 			case FTS_DNR:		/* an error */
2052904a520Smillert 			case FTS_ERR:
2062904a520Smillert 			case FTS_NS:
2072904a520Smillert 				msg("Can't fts_read %s: %s\n", entry->fts_path,
2082904a520Smillert 				    strerror(errno));
209a4e7dc73Sray 				/* FALLTHROUGH */
2102904a520Smillert 			case FTS_DP:		/* already seen dir */
2112904a520Smillert 				continue;
2122904a520Smillert 			}
2132904a520Smillert 			mapfileino(entry->fts_statp->st_ino, tapesize,
2142904a520Smillert 			    &anydirskipped);
2152904a520Smillert 		}
2164760cb14Sotto 		if (errno) {
2174760cb14Sotto 			msg("fts_read failed: %s\n", strerror(errno));
2184760cb14Sotto 			dumpabort(0);
2194760cb14Sotto 		}
2202904a520Smillert 		(void)fts_close(dirh);
2212904a520Smillert 
2222904a520Smillert 		/*
2232904a520Smillert 		 * Add any parent directories
2242904a520Smillert 		 */
2252904a520Smillert 		for (d = 0 ; dirv[d] != NULL ; d++) {
226b9fc9a72Sderaadt 			char path[PATH_MAX];
2272904a520Smillert 
2282904a520Smillert 			if (dirv[d][0] != '/')
2292904a520Smillert 				(void)snprintf(path, sizeof(path), "%s/%s",
2302904a520Smillert 				    curdir, dirv[d]);
2312904a520Smillert 			else
2322904a520Smillert 				(void)snprintf(path, sizeof(path), "%s",
2332904a520Smillert 				    dirv[d]);
2342904a520Smillert 			while (strcmp(path, disk) != 0) {
2352904a520Smillert 				char *p;
2362904a520Smillert 				struct stat sb;
2372904a520Smillert 
2382904a520Smillert 				if (*path == '\0')
2392904a520Smillert 					break;
2402904a520Smillert 				if ((p = strrchr(path, '/')) == NULL)
2412904a520Smillert 					break;
2422904a520Smillert 				if (p == path)
2432904a520Smillert 					break;
2442904a520Smillert 				*p = '\0';
2452904a520Smillert 				if (stat(path, &sb) == -1) {
2462904a520Smillert 					msg("Can't stat %s: %s\n", path,
2472904a520Smillert 					    strerror(errno));
2482904a520Smillert 					break;
2492904a520Smillert 				}
2502904a520Smillert 				mapfileino(sb.st_ino, tapesize, &anydirskipped);
2512904a520Smillert 			}
2522904a520Smillert 		}
2532904a520Smillert 
2542904a520Smillert 		/*
2552904a520Smillert 		 * Ensure that the root inode actually appears in the
2562904a520Smillert 		 * file list for a subdir
2572904a520Smillert 		 */
2582904a520Smillert 		mapfileino(ROOTINO, tapesize, &anydirskipped);
2592904a520Smillert 	} else {
2600155e653Smillert 		fs_mapinodes(maxino, tapesize, &anydirskipped);
261df930be7Sderaadt 	}
262df930be7Sderaadt 	/*
263df930be7Sderaadt 	 * Restore gets very upset if the root is not dumped,
264df930be7Sderaadt 	 * so ensure that it always is dumped.
265df930be7Sderaadt 	 */
266df930be7Sderaadt 	SETINO(ROOTINO, dumpinomap);
267df930be7Sderaadt 	return (anydirskipped);
268df930be7Sderaadt }
269df930be7Sderaadt 
270df930be7Sderaadt /*
271df930be7Sderaadt  * Dump pass 2.
272df930be7Sderaadt  *
273df930be7Sderaadt  * Scan each directory on the filesystem to see if it has any modified
274df930be7Sderaadt  * files in it. If it does, and has not already been added to the dump
275df930be7Sderaadt  * list (because it was itself modified), then add it. If a directory
276df930be7Sderaadt  * has not been modified itself, contains no modified files and has no
277df930be7Sderaadt  * subdirectories, then it can be deleted from the dump list and from
278df930be7Sderaadt  * the list of directories. By deleting it from the list of directories,
279df930be7Sderaadt  * its parent may now qualify for the same treatment on this or a later
280df930be7Sderaadt  * pass using this algorithm.
281df930be7Sderaadt  */
282df930be7Sderaadt int
2830603cbefSnaddy mapdirs(ino_t maxino, int64_t *tapesize)
284df930be7Sderaadt {
2850155e653Smillert 	union dinode *dp;
286583aebd5Szhuk 	int i, isdir, nodump;
287e073c79dSmpech 	char *map;
288e073c79dSmpech 	ino_t ino;
2890155e653Smillert 	union dinode di;
290c5f0f3a2Smickey 	off_t filesize;
291df930be7Sderaadt 	int ret, change = 0;
292df930be7Sderaadt 
293df930be7Sderaadt 	isdir = 0;		/* XXX just to get gcc to shut up */
294df930be7Sderaadt 	for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
295df930be7Sderaadt 		if (((ino - 1) % NBBY) == 0)	/* map is offset by 1 */
296df930be7Sderaadt 			isdir = *map++;
297df930be7Sderaadt 		else
298df930be7Sderaadt 			isdir >>= 1;
299583aebd5Szhuk                 /*
300583aebd5Szhuk 		 * If a directory has been removed from usedinomap, it
301583aebd5Szhuk 		 * either has the nodump flag set, or has inherited
302583aebd5Szhuk 		 * it.  Although a directory can't be in dumpinomap if
303583aebd5Szhuk 		 * it isn't in usedinomap, we have to go through it to
304583aebd5Szhuk 		 * propagate the nodump flag.
305583aebd5Szhuk 		 */
306583aebd5Szhuk 		nodump = !nonodump && !TSTINO(ino, usedinomap);
307583aebd5Szhuk 		if ((isdir & 1) == 0 || (TSTINO(ino, dumpinomap) && !nodump))
308df930be7Sderaadt 			continue;
3090155e653Smillert 		dp = getino(ino, &i);
3100155e653Smillert 		/*
3110155e653Smillert 		 * inode buf may change in searchdir().
3120155e653Smillert 		 */
3130155e653Smillert 		if (sblock->fs_magic == FS_UFS1_MAGIC)
3140155e653Smillert 			di.dp1 = dp->dp1;
3150155e653Smillert 		else
3160155e653Smillert 			di.dp2 = dp->dp2;
3170155e653Smillert 		filesize = (off_t)DIP(dp, di_size);
318df930be7Sderaadt 		for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) {
3190155e653Smillert 			if (DIP(&di, di_db[i]) != 0)
3200155e653Smillert 				ret |= searchdir(ino, DIP(&di, di_db[i]),
3210155e653Smillert 				    sblksize(sblock, DIP(dp, di_size), i),
322583aebd5Szhuk 				    filesize, tapesize, nodump);
323df930be7Sderaadt 			if (ret & HASDUMPEDFILE)
324df930be7Sderaadt 				filesize = 0;
325df930be7Sderaadt 			else
326df930be7Sderaadt 				filesize -= sblock->fs_bsize;
327df930be7Sderaadt 		}
328df930be7Sderaadt 		for (i = 0; filesize > 0 && i < NIADDR; i++) {
3290155e653Smillert 			if (DIP(&di, di_ib[i]) == 0)
330df930be7Sderaadt 				continue;
331583aebd5Szhuk 			ret |= dirindir(ino, DIP(&di, di_ib[i]), i, &filesize,
332583aebd5Szhuk 			    tapesize, nodump);
333df930be7Sderaadt 		}
334df930be7Sderaadt 		if (ret & HASDUMPEDFILE) {
335df930be7Sderaadt 			SETINO(ino, dumpinomap);
336df930be7Sderaadt 			*tapesize += blockest(dp);
337df930be7Sderaadt 			change = 1;
338df930be7Sderaadt 			continue;
339df930be7Sderaadt 		}
340583aebd5Szhuk                 if (nodump) {
341583aebd5Szhuk                         if (ret & HASSUBDIRS)
342583aebd5Szhuk                                 change = 1;     /* subdirs inherit nodump */
343583aebd5Szhuk                         CLRINO(ino, dumpdirmap);
344583aebd5Szhuk                 } else if ((ret & HASSUBDIRS) == 0) {
345df930be7Sderaadt 			if (!TSTINO(ino, dumpinomap)) {
346df930be7Sderaadt 				CLRINO(ino, dumpdirmap);
347df930be7Sderaadt 				change = 1;
348df930be7Sderaadt 			}
349df930be7Sderaadt 		}
350df930be7Sderaadt 	}
351df930be7Sderaadt 	return (change);
352df930be7Sderaadt }
353df930be7Sderaadt 
354df930be7Sderaadt /*
355df930be7Sderaadt  * Read indirect blocks, and pass the data blocks to be searched
356df930be7Sderaadt  * as directories. Quit as soon as any entry is found that will
357df930be7Sderaadt  * require the directory to be dumped.
358df930be7Sderaadt  */
359df930be7Sderaadt static int
3601abdbfdeSderaadt dirindir(ino_t ino, daddr_t blkno, int ind_level, off_t *filesize,
3610603cbefSnaddy     int64_t *tapesize, int nodump)
362df930be7Sderaadt {
363df930be7Sderaadt 	int ret = 0;
364e073c79dSmpech 	int i;
365e78b6070Sotto 	char idblk[MAXBSIZE];
366df930be7Sderaadt 
3670155e653Smillert 	bread(fsbtodb(sblock, blkno), idblk, (int)sblock->fs_bsize);
368df930be7Sderaadt 	if (ind_level <= 0) {
369df930be7Sderaadt 		for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
3700155e653Smillert 			if (sblock->fs_magic == FS_UFS1_MAGIC)
3710155e653Smillert 				blkno = ((int32_t *)idblk)[i];
3720155e653Smillert 			else
3730155e653Smillert 				blkno = ((int64_t *)idblk)[i];
374df930be7Sderaadt 			if (blkno != 0)
375df930be7Sderaadt 				ret |= searchdir(ino, blkno, sblock->fs_bsize,
376583aebd5Szhuk 					*filesize, tapesize, nodump);
377df930be7Sderaadt 			if (ret & HASDUMPEDFILE)
378df930be7Sderaadt 				*filesize = 0;
379df930be7Sderaadt 			else
380df930be7Sderaadt 				*filesize -= sblock->fs_bsize;
381df930be7Sderaadt 		}
382df930be7Sderaadt 		return (ret);
383df930be7Sderaadt 	}
384df930be7Sderaadt 	ind_level--;
385df930be7Sderaadt 	for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
3860155e653Smillert 		if (sblock->fs_magic == FS_UFS1_MAGIC)
3870155e653Smillert 			blkno = ((int32_t *)idblk)[i];
3880155e653Smillert 		else
3890155e653Smillert 			blkno = ((int64_t *)idblk)[i];
390df930be7Sderaadt 		if (blkno != 0)
391583aebd5Szhuk 			ret |= dirindir(ino, blkno, ind_level, filesize,
392583aebd5Szhuk 			    tapesize, nodump);
393df930be7Sderaadt 	}
394df930be7Sderaadt 	return (ret);
395df930be7Sderaadt }
396df930be7Sderaadt 
397df930be7Sderaadt /*
398df930be7Sderaadt  * Scan a disk block containing directory information looking to see if
399df930be7Sderaadt  * any of the entries are on the dump list and to see if the directory
400df930be7Sderaadt  * contains any subdirectories.
401df930be7Sderaadt  */
402df930be7Sderaadt static int
4031abdbfdeSderaadt searchdir(ino_t ino, daddr_t blkno, long size, off_t filesize,
4040603cbefSnaddy     int64_t *tapesize, int nodump)
405df930be7Sderaadt {
406e073c79dSmpech 	struct direct *dp;
407583aebd5Szhuk 	union dinode *ip;
408c5f0f3a2Smickey 	long loc;
4090155e653Smillert 	static caddr_t dblk;
410583aebd5Szhuk 	int mode, ret = 0;
411df930be7Sderaadt 
4120155e653Smillert 	if (dblk == NULL && (dblk = malloc(sblock->fs_bsize)) == NULL)
4130155e653Smillert 		quit("searchdir: cannot allocate indirect memory.\n");
414df930be7Sderaadt 	bread(fsbtodb(sblock, blkno), dblk, (int)size);
415df930be7Sderaadt 	if (filesize < size)
416df930be7Sderaadt 		size = filesize;
417df930be7Sderaadt 	for (loc = 0; loc < size; ) {
418df930be7Sderaadt 		dp = (struct direct *)(dblk + loc);
419df930be7Sderaadt 		if (dp->d_reclen == 0) {
420d0f688a9Sderaadt 			msg("corrupted directory, inumber %llu\n",
421d0f688a9Sderaadt 			    (unsigned long long)ino);
422df930be7Sderaadt 			break;
423df930be7Sderaadt 		}
424df930be7Sderaadt 		loc += dp->d_reclen;
425df930be7Sderaadt 		if (dp->d_ino == 0)
426df930be7Sderaadt 			continue;
427df930be7Sderaadt 		if (dp->d_name[0] == '.') {
428df930be7Sderaadt 			if (dp->d_name[1] == '\0')
429df930be7Sderaadt 				continue;
430df930be7Sderaadt 			if (dp->d_name[1] == '.' && dp->d_name[2] == '\0')
431df930be7Sderaadt 				continue;
432df930be7Sderaadt 		}
433583aebd5Szhuk 		if (nodump) {
434583aebd5Szhuk                         ip = getino(dp->d_ino, &mode);
435583aebd5Szhuk                         if (TSTINO(dp->d_ino, dumpinomap)) {
436583aebd5Szhuk                                 CLRINO(dp->d_ino, dumpinomap);
437583aebd5Szhuk                                 *tapesize -= blockest(ip);
438583aebd5Szhuk                         }
439583aebd5Szhuk                         /*
440583aebd5Szhuk                          * Add back to dumpdirmap and remove from usedinomap
441583aebd5Szhuk                          * to propagate nodump.
442583aebd5Szhuk                          */
443583aebd5Szhuk                         if (mode == IFDIR) {
444583aebd5Szhuk                                 SETINO(dp->d_ino, dumpdirmap);
445583aebd5Szhuk                                 CLRINO(dp->d_ino, usedinomap);
446583aebd5Szhuk                                 ret |= HASSUBDIRS;
447583aebd5Szhuk                         }
448583aebd5Szhuk 		} else {
449df930be7Sderaadt 			if (TSTINO(dp->d_ino, dumpinomap)) {
450df930be7Sderaadt 				ret |= HASDUMPEDFILE;
451df930be7Sderaadt 				if (ret & HASSUBDIRS)
452df930be7Sderaadt 					break;
453df930be7Sderaadt 			}
454df930be7Sderaadt 			if (TSTINO(dp->d_ino, dumpdirmap)) {
455df930be7Sderaadt 				ret |= HASSUBDIRS;
456df930be7Sderaadt 				if (ret & HASDUMPEDFILE)
457df930be7Sderaadt 					break;
458df930be7Sderaadt 			}
459df930be7Sderaadt 		}
460583aebd5Szhuk 	}
461df930be7Sderaadt 	return (ret);
462df930be7Sderaadt }
463df930be7Sderaadt 
464df930be7Sderaadt /*
465df930be7Sderaadt  * Dump passes 3 and 4.
466df930be7Sderaadt  *
467df930be7Sderaadt  * Dump the contents of an inode to tape.
468df930be7Sderaadt  */
469df930be7Sderaadt void
4700155e653Smillert dumpino(union dinode *dp, ino_t ino)
471df930be7Sderaadt {
472df930be7Sderaadt 	int ind_level, cnt;
473c5f0f3a2Smickey 	off_t size;
474df930be7Sderaadt 	char buf[TP_BSIZE];
475df930be7Sderaadt 
476df930be7Sderaadt 	if (newtape) {
477df930be7Sderaadt 		newtape = 0;
478df930be7Sderaadt 		dumpmap(dumpinomap, TS_BITS, ino);
479df930be7Sderaadt 	}
480df930be7Sderaadt 	CLRINO(ino, dumpinomap);
4810155e653Smillert 	if (sblock->fs_magic == FS_UFS1_MAGIC) {
4820155e653Smillert 		spcl.c_mode = dp->dp1.di_mode;
4830155e653Smillert 		spcl.c_size = dp->dp1.di_size;
484a7131aaeSmillert 		spcl.c_old_atime = (time_t)dp->dp1.di_atime;
485a7131aaeSmillert 		spcl.c_atime = dp->dp1.di_atime;
4860155e653Smillert 		spcl.c_atimensec = dp->dp1.di_atimensec;
487a7131aaeSmillert 		spcl.c_old_mtime = (time_t)dp->dp1.di_mtime;
488a7131aaeSmillert 		spcl.c_mtime = dp->dp1.di_mtime;
4890155e653Smillert 		spcl.c_mtimensec = dp->dp1.di_mtimensec;
4900155e653Smillert 		spcl.c_birthtime = 0;
4910155e653Smillert 		spcl.c_birthtimensec = 0;
4920155e653Smillert 		spcl.c_rdev = dp->dp1.di_rdev;
4930155e653Smillert 		spcl.c_file_flags = dp->dp1.di_flags;
4940155e653Smillert 		spcl.c_uid = dp->dp1.di_uid;
4950155e653Smillert 		spcl.c_gid = dp->dp1.di_gid;
4960155e653Smillert 	} else {
4970155e653Smillert 		spcl.c_mode = dp->dp2.di_mode;
4980155e653Smillert 		spcl.c_size = dp->dp2.di_size;
499a7131aaeSmillert 		spcl.c_atime = dp->dp2.di_atime;
5000155e653Smillert 		spcl.c_atimensec = dp->dp2.di_atimensec;
501a7131aaeSmillert 		spcl.c_mtime = dp->dp2.di_mtime;
5020155e653Smillert 		spcl.c_mtimensec = dp->dp2.di_mtimensec;
503a7131aaeSmillert 		spcl.c_birthtime = dp->dp2.di_birthtime;
5040155e653Smillert 		spcl.c_birthtimensec = dp->dp2.di_birthnsec;
5050155e653Smillert 		spcl.c_rdev = dp->dp2.di_rdev;
5060155e653Smillert 		spcl.c_file_flags = dp->dp2.di_flags;
5070155e653Smillert 		spcl.c_uid = dp->dp2.di_uid;
5080155e653Smillert 		spcl.c_gid = dp->dp2.di_gid;
5090155e653Smillert 	}
510df930be7Sderaadt 	spcl.c_type = TS_INODE;
511df930be7Sderaadt 	spcl.c_count = 0;
5120155e653Smillert 	switch (DIP(dp, di_mode) & S_IFMT) {
513df930be7Sderaadt 
514df930be7Sderaadt 	case 0:
515df930be7Sderaadt 		/*
516df930be7Sderaadt 		 * Freed inode.
517df930be7Sderaadt 		 */
518df930be7Sderaadt 		return;
519df930be7Sderaadt 
520df930be7Sderaadt 	case IFLNK:
521df930be7Sderaadt 		/*
522df930be7Sderaadt 		 * Check for short symbolic link.
523df930be7Sderaadt 		 */
5240155e653Smillert 		if (DIP(dp, di_size) > 0 &&
525da5362d5Sguenther 		    DIP(dp, di_size) < sblock->fs_maxsymlinklen) {
5260155e653Smillert 			void *shortlink;
5270155e653Smillert 
528df930be7Sderaadt 			spcl.c_addr[0] = 1;
529df930be7Sderaadt 			spcl.c_count = 1;
530df930be7Sderaadt 			writeheader(ino);
5310155e653Smillert 			if (sblock->fs_magic == FS_UFS1_MAGIC)
5320155e653Smillert 				shortlink = dp->dp1.di_shortlink;
5330155e653Smillert 			else
5340155e653Smillert 				shortlink = dp->dp2.di_shortlink;
5350155e653Smillert 			memcpy(buf, shortlink, DIP(dp, di_size));
5360155e653Smillert 			buf[DIP(dp, di_size)] = '\0';
537df930be7Sderaadt 			writerec(buf, 0);
538df930be7Sderaadt 			return;
539df930be7Sderaadt 		}
540a4e7dc73Sray 		/* FALLTHROUGH */
541df930be7Sderaadt 
542df930be7Sderaadt 	case IFDIR:
543df930be7Sderaadt 	case IFREG:
5440155e653Smillert 		if (DIP(dp, di_size) > 0)
545df930be7Sderaadt 			break;
546a4e7dc73Sray 		/* FALLTHROUGH */
547df930be7Sderaadt 
548df930be7Sderaadt 	case IFIFO:
549df930be7Sderaadt 	case IFSOCK:
550df930be7Sderaadt 	case IFCHR:
551df930be7Sderaadt 	case IFBLK:
552df930be7Sderaadt 		writeheader(ino);
553df930be7Sderaadt 		return;
554df930be7Sderaadt 
555df930be7Sderaadt 	default:
5560155e653Smillert 		msg("Warning: undefined file type 0%o\n",
5570155e653Smillert 		    DIP(dp, di_mode) & IFMT);
558df930be7Sderaadt 		return;
559df930be7Sderaadt 	}
5600155e653Smillert 	if (DIP(dp, di_size) > NDADDR * sblock->fs_bsize)
561df930be7Sderaadt 		cnt = NDADDR * sblock->fs_frag;
562df930be7Sderaadt 	else
5630155e653Smillert 		cnt = howmany(DIP(dp, di_size), sblock->fs_fsize);
5640155e653Smillert 	if (sblock->fs_magic == FS_UFS1_MAGIC)
5650155e653Smillert 		ufs1_blksout(&dp->dp1.di_db[0], cnt, ino);
5660155e653Smillert 	else
5670155e653Smillert 		ufs2_blksout(&dp->dp2.di_db[0], cnt, ino);
5680155e653Smillert 	if ((size = DIP(dp, di_size) - NDADDR * sblock->fs_bsize) <= 0)
569df930be7Sderaadt 		return;
570df930be7Sderaadt 	for (ind_level = 0; ind_level < NIADDR; ind_level++) {
5710155e653Smillert 		dmpindir(ino, DIP(dp, di_ib[ind_level]), ind_level, &size);
572df930be7Sderaadt 		if (size <= 0)
573df930be7Sderaadt 			return;
574df930be7Sderaadt 	}
575df930be7Sderaadt }
576df930be7Sderaadt 
577df930be7Sderaadt /*
578df930be7Sderaadt  * Read indirect blocks, and pass the data blocks to be dumped.
579df930be7Sderaadt  */
580df930be7Sderaadt static void
5811abdbfdeSderaadt dmpindir(ino_t ino, daddr_t  blk, int ind_level, off_t *size)
582df930be7Sderaadt {
583df930be7Sderaadt 	int i, cnt;
584e78b6070Sotto 	char idblk[MAXBSIZE];
585df930be7Sderaadt 
586df930be7Sderaadt 	if (blk != 0)
5870155e653Smillert 		bread(fsbtodb(sblock, blk), idblk, (int) sblock->fs_bsize);
588df930be7Sderaadt 	else
589df930be7Sderaadt 		memset(idblk, 0, (int)sblock->fs_bsize);
590df930be7Sderaadt 	if (ind_level <= 0) {
591df930be7Sderaadt 		if (*size < NINDIR(sblock) * sblock->fs_bsize)
592df930be7Sderaadt 			cnt = howmany(*size, sblock->fs_fsize);
593df930be7Sderaadt 		else
594df930be7Sderaadt 			cnt = NINDIR(sblock) * sblock->fs_frag;
595df930be7Sderaadt 		*size -= NINDIR(sblock) * sblock->fs_bsize;
5960155e653Smillert 		if (sblock->fs_magic == FS_UFS1_MAGIC)
5970155e653Smillert 			ufs1_blksout((int32_t *)idblk, cnt, ino);
5980155e653Smillert 		else
5990155e653Smillert 			ufs2_blksout((int64_t *)idblk, cnt, ino);
600df930be7Sderaadt 		return;
601df930be7Sderaadt 	}
602df930be7Sderaadt 	ind_level--;
603df930be7Sderaadt 	for (i = 0; i < NINDIR(sblock); i++) {
6040155e653Smillert 		if (sblock->fs_magic == FS_UFS1_MAGIC)
6050155e653Smillert 			dmpindir(ino, ((int32_t *)idblk)[i], ind_level,
6060155e653Smillert 			    size);
6070155e653Smillert 		else
6080155e653Smillert 			dmpindir(ino, ((int64_t *)idblk)[i], ind_level,
6090155e653Smillert 			    size);
610df930be7Sderaadt 		if (*size <= 0)
611df930be7Sderaadt 			return;
612df930be7Sderaadt 	}
613df930be7Sderaadt }
614df930be7Sderaadt 
615df930be7Sderaadt /*
616df930be7Sderaadt  * Collect up the data into tape record sized buffers and output them.
617df930be7Sderaadt  */
618df930be7Sderaadt void
6190155e653Smillert ufs1_blksout(int32_t *blkp, int frags, ino_t ino)
620df930be7Sderaadt {
6210155e653Smillert 	int32_t *bp;
6220155e653Smillert 	int i, j, count, blks, tbperdb;
6230155e653Smillert 
6240155e653Smillert 	blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
6250155e653Smillert 	tbperdb = sblock->fs_bsize >> tp_bshift;
6260155e653Smillert 	for (i = 0; i < blks; i += TP_NINDIR) {
6270155e653Smillert 		if (i + TP_NINDIR > blks)
6280155e653Smillert 			count = blks;
6290155e653Smillert 		else
6300155e653Smillert 			count = i + TP_NINDIR;
6310155e653Smillert 		for (j = i; j < count; j++)
6320155e653Smillert 			if (blkp[j / tbperdb] != 0)
6330155e653Smillert 				spcl.c_addr[j - i] = 1;
6340155e653Smillert 			else
6350155e653Smillert 				spcl.c_addr[j - i] = 0;
6360155e653Smillert 		spcl.c_count = count - i;
6370155e653Smillert 		writeheader(ino);
6380155e653Smillert 		bp = &blkp[i / tbperdb];
6390155e653Smillert 		for (j = i; j < count; j += tbperdb, bp++)
6400155e653Smillert 			if (*bp != 0) {
6410155e653Smillert 				if (j + tbperdb <= count)
6420155e653Smillert 					dumpblock(*bp, (int)sblock->fs_bsize);
6430155e653Smillert 				else
6440155e653Smillert 					dumpblock(*bp, (count - j) * TP_BSIZE);
6450155e653Smillert 			}
6460155e653Smillert 		spcl.c_type = TS_ADDR;
6470155e653Smillert 	}
6480155e653Smillert }
6490155e653Smillert 
6500155e653Smillert /*
6510155e653Smillert  * Collect up the data into tape record sized buffers and output them.
6520155e653Smillert  */
6530155e653Smillert void
6541abdbfdeSderaadt ufs2_blksout(daddr_t *blkp, int frags, ino_t ino)
6550155e653Smillert {
6561abdbfdeSderaadt 	daddr_t *bp;
657df930be7Sderaadt 	int i, j, count, blks, tbperdb;
658df930be7Sderaadt 
659df930be7Sderaadt 	blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
660df930be7Sderaadt 	tbperdb = sblock->fs_bsize >> tp_bshift;
661df930be7Sderaadt 	for (i = 0; i < blks; i += TP_NINDIR) {
662df930be7Sderaadt 		if (i + TP_NINDIR > blks)
663df930be7Sderaadt 			count = blks;
664df930be7Sderaadt 		else
665df930be7Sderaadt 			count = i + TP_NINDIR;
666df930be7Sderaadt 		for (j = i; j < count; j++)
667df930be7Sderaadt 			if (blkp[j / tbperdb] != 0)
668df930be7Sderaadt 				spcl.c_addr[j - i] = 1;
669df930be7Sderaadt 			else
670df930be7Sderaadt 				spcl.c_addr[j - i] = 0;
671df930be7Sderaadt 		spcl.c_count = count - i;
672df930be7Sderaadt 		writeheader(ino);
673df930be7Sderaadt 		bp = &blkp[i / tbperdb];
674df930be7Sderaadt 		for (j = i; j < count; j += tbperdb, bp++)
6758ac1cfb4Sderaadt 			if (*bp != 0) {
676df930be7Sderaadt 				if (j + tbperdb <= count)
677df930be7Sderaadt 					dumpblock(*bp, (int)sblock->fs_bsize);
678df930be7Sderaadt 				else
679df930be7Sderaadt 					dumpblock(*bp, (count - j) * TP_BSIZE);
6808ac1cfb4Sderaadt 			}
681df930be7Sderaadt 		spcl.c_type = TS_ADDR;
682df930be7Sderaadt 	}
683df930be7Sderaadt }
684df930be7Sderaadt 
685df930be7Sderaadt /*
686df930be7Sderaadt  * Dump a map to the tape.
687df930be7Sderaadt  */
688df930be7Sderaadt void
689c969aecdStb dumpmap(char *map, int type, ino_t ino)
690df930be7Sderaadt {
691e073c79dSmpech 	int i;
692df930be7Sderaadt 	char *cp;
693df930be7Sderaadt 
694df930be7Sderaadt 	spcl.c_type = type;
695df930be7Sderaadt 	spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE);
696df930be7Sderaadt 	writeheader(ino);
697df930be7Sderaadt 	for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE)
698df930be7Sderaadt 		writerec(cp, 0);
699df930be7Sderaadt }
700df930be7Sderaadt 
701df930be7Sderaadt /*
702df930be7Sderaadt  * Write a header record to the dump tape.
703df930be7Sderaadt  */
704df930be7Sderaadt void
705c969aecdStb writeheader(ino_t ino)
706df930be7Sderaadt {
707e073c79dSmpech 	int32_t sum, cnt, *lp;
708df930be7Sderaadt 
709df930be7Sderaadt 	spcl.c_inumber = ino;
7100155e653Smillert 	if (sblock->fs_magic == FS_UFS2_MAGIC) {
7110155e653Smillert 		spcl.c_magic = FS_UFS2_MAGIC;
7120155e653Smillert 	} else {
713df930be7Sderaadt 		spcl.c_magic = NFS_MAGIC;
7140155e653Smillert 		spcl.c_old_date = (int32_t)spcl.c_date;
7150155e653Smillert 		spcl.c_old_ddate = (int32_t)spcl.c_ddate;
7160155e653Smillert 		spcl.c_old_tapea = (int32_t)spcl.c_tapea;
7170155e653Smillert 		spcl.c_old_firstrec = (int32_t)spcl.c_firstrec;
7180155e653Smillert 	}
719df930be7Sderaadt 	spcl.c_checksum = 0;
720d739c122Sderaadt 	lp = (int32_t *)&spcl;
721df930be7Sderaadt 	sum = 0;
722d739c122Sderaadt 	cnt = sizeof(union u_spcl) / (4 * sizeof(int32_t));
723df930be7Sderaadt 	while (--cnt >= 0) {
724df930be7Sderaadt 		sum += *lp++;
725df930be7Sderaadt 		sum += *lp++;
726df930be7Sderaadt 		sum += *lp++;
727df930be7Sderaadt 		sum += *lp++;
728df930be7Sderaadt 	}
729df930be7Sderaadt 	spcl.c_checksum = CHECKSUM - sum;
730df930be7Sderaadt 	writerec((char *)&spcl, 1);
731df930be7Sderaadt }
732df930be7Sderaadt 
7330155e653Smillert union dinode *
7340155e653Smillert getino(ino_t inum, int *modep)
735df930be7Sderaadt {
7360155e653Smillert 	static ino_t minino, maxino;
7370155e653Smillert 	static void *inoblock;
7380155e653Smillert 	struct ufs1_dinode *dp1;
7390155e653Smillert 	struct ufs2_dinode *dp2;
740df930be7Sderaadt 
7410155e653Smillert 	if (inoblock == NULL && (inoblock = malloc(sblock->fs_bsize)) == NULL)
7420155e653Smillert 		quit("cannot allocate inode memory.\n");
743df930be7Sderaadt 	curino = inum;
744df930be7Sderaadt 	if (inum >= minino && inum < maxino)
7450155e653Smillert 		goto gotit;
7460155e653Smillert 	bread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), inoblock,
747df930be7Sderaadt 	    (int)sblock->fs_bsize);
748df930be7Sderaadt 	minino = inum - (inum % INOPB(sblock));
749df930be7Sderaadt 	maxino = minino + INOPB(sblock);
7500155e653Smillert gotit:
7510155e653Smillert 	if (sblock->fs_magic == FS_UFS1_MAGIC) {
7520155e653Smillert 		dp1 = &((struct ufs1_dinode *)inoblock)[inum - minino];
7530155e653Smillert 		*modep = (dp1->di_mode & IFMT);
7540155e653Smillert 		return ((union dinode *)dp1);
7550155e653Smillert 	}
7560155e653Smillert 	dp2 = &((struct ufs2_dinode *)inoblock)[inum - minino];
7570155e653Smillert 	*modep = (dp2->di_mode & IFMT);
7580155e653Smillert 	return ((union dinode *)dp2);
759df930be7Sderaadt }
760df930be7Sderaadt 
761df930be7Sderaadt /*
762df930be7Sderaadt  * Read a chunk of data from the disk.
763df930be7Sderaadt  * Try to recover from hard errors by reading in sector sized pieces.
764df930be7Sderaadt  * Error recovery is attempted at most BREADEMAX times before seeking
765df930be7Sderaadt  * consent from the operator to continue.
766df930be7Sderaadt  */
767df930be7Sderaadt int	breaderrors = 0;
768df930be7Sderaadt #define	BREADEMAX 32
769df930be7Sderaadt 
770df930be7Sderaadt void
7711abdbfdeSderaadt bread(daddr_t blkno, char *buf, int size)
772df930be7Sderaadt {
773892d6e70Skrw 	static char *mybuf = NULL;
774892d6e70Skrw 	char *mybufp, *bufp, *np;
775892d6e70Skrw 	static size_t mybufsz = 0;
776171a3685Skrw 	off_t offset;
777df930be7Sderaadt 	int cnt, i;
778892d6e70Skrw 	u_int64_t secno, seccount;
779892d6e70Skrw 	u_int32_t secoff, secsize = lab.d_secsize;
780df930be7Sderaadt 
781892d6e70Skrw 	/*
782892d6e70Skrw 	 * We must read an integral number of sectors large enough to contain
783892d6e70Skrw 	 * all the requested data. The read must begin at a sector.
784892d6e70Skrw 	 */
785892d6e70Skrw 	if (DL_BLKOFFSET(&lab, blkno) == 0 && size % secsize == 0) {
786892d6e70Skrw 		secno = DL_BLKTOSEC(&lab, blkno);
787892d6e70Skrw 		secoff = 0;
788892d6e70Skrw 		seccount = size / secsize;
789892d6e70Skrw 		bufp = buf;
790892d6e70Skrw 	} else {
791892d6e70Skrw 		secno = DL_BLKTOSEC(&lab, blkno);
792892d6e70Skrw 		secoff = DL_BLKOFFSET(&lab, blkno);
793892d6e70Skrw 		seccount = DL_BLKTOSEC(&lab, (size + secoff) / DEV_BSIZE);
794892d6e70Skrw 		if (seccount * secsize < (size + secoff))
795892d6e70Skrw 			seccount++;
796892d6e70Skrw 		if (mybufsz < seccount * secsize) {
797892d6e70Skrw 			np = reallocarray(mybuf, seccount, secsize);
798892d6e70Skrw 			if (np == NULL) {
799892d6e70Skrw 				msg("No memory to read %llu %u-byte sectors",
800892d6e70Skrw 				    seccount, secsize);
801892d6e70Skrw 				dumpabort(0);
802892d6e70Skrw 			}
803892d6e70Skrw 			mybufsz = seccount * secsize;
804892d6e70Skrw 			mybuf = np;
805892d6e70Skrw 		}
806892d6e70Skrw 		bufp = mybuf;
807892d6e70Skrw 	}
808892d6e70Skrw 
809892d6e70Skrw 	offset = secno * secsize;
810171a3685Skrw 
811df930be7Sderaadt loop:
812892d6e70Skrw 	if ((cnt = pread(diskfd, bufp, seccount * secsize, offset)) ==
813892d6e70Skrw 	    seccount * secsize)
814892d6e70Skrw 		goto done;
815171a3685Skrw 	if (blkno + (size / DEV_BSIZE) >
816af12d456Skrw 	    fsbtodb(sblock, sblock->fs_ffs1_size)) {
817df930be7Sderaadt 		/*
818df930be7Sderaadt 		 * Trying to read the final fragment.
819df930be7Sderaadt 		 *
820df930be7Sderaadt 		 * NB - dump only works in TP_BSIZE blocks, hence
821171a3685Skrw 		 * rounds `DEV_BSIZE' fragments up to TP_BSIZE pieces.
822df930be7Sderaadt 		 * It should be smarter about not actually trying to
823df930be7Sderaadt 		 * read more than it can get, but for the time being
824df930be7Sderaadt 		 * we punt and scale back the read only when it gets
825df930be7Sderaadt 		 * us into trouble. (mkm 9/25/83)
826df930be7Sderaadt 		 */
827b39ffb6cSkrw 		size -= secsize;
828892d6e70Skrw 		seccount--;
829df930be7Sderaadt 		goto loop;
830df930be7Sderaadt 	}
831df930be7Sderaadt 	if (cnt == -1)
8320155e653Smillert 		msg("read error from %s: %s: [block %lld]: count=%d\n",
83361945d51Skrw 		    disk, strerror(errno), (long long)blkno, size);
834df930be7Sderaadt 	else
835af12d456Skrw 		msg("short read error from %s: [block %lld]: count=%d, "
83661945d51Skrw 		    "got=%d\n", disk, (long long)blkno, size, cnt);
837df930be7Sderaadt 	if (++breaderrors > BREADEMAX) {
83861351727Scloder 		msg("More than %d block read errors from %s\n",
839df930be7Sderaadt 			BREADEMAX, disk);
840df930be7Sderaadt 		broadcast("DUMP IS AILING!\n");
841df930be7Sderaadt 		msg("This is an unrecoverable error.\n");
842df930be7Sderaadt 		if (!query("Do you want to attempt to continue?")){
843df930be7Sderaadt 			dumpabort(0);
844df930be7Sderaadt 			/*NOTREACHED*/
845df930be7Sderaadt 		} else
846df930be7Sderaadt 			breaderrors = 0;
847df930be7Sderaadt 	}
848df930be7Sderaadt 	/*
849df930be7Sderaadt 	 * Zero buffer, then try to read each sector of buffer separately.
850df930be7Sderaadt 	 */
851892d6e70Skrw 	if (bufp == mybuf)
852892d6e70Skrw 		memset(bufp, 0, mybufsz);
853892d6e70Skrw 	else
854892d6e70Skrw 		memset(bufp, 0, size);
855892d6e70Skrw 	for (i = 0, mybufp = bufp; i < size; i += secsize, mybufp += secsize) {
856892d6e70Skrw 		if ((cnt = pread(diskfd, mybufp, secsize, offset + i)) ==
857b39ffb6cSkrw 		    secsize)
858df930be7Sderaadt 			continue;
859df930be7Sderaadt 		if (cnt == -1) {
86091475891Skrw 			msg("read error from %s: %s: [block %lld]: "
861b39ffb6cSkrw 			    "count=%u\n", disk, strerror(errno),
862b39ffb6cSkrw 			    (long long)(offset + i) / DEV_BSIZE, secsize);
863df930be7Sderaadt 			continue;
864df930be7Sderaadt 		}
86591475891Skrw 		msg("short read error from %s: [block %lld]: count=%u, "
866171a3685Skrw 		    "got=%d\n", disk, (long long)(offset + i) / DEV_BSIZE,
867b39ffb6cSkrw 		    secsize, cnt);
868df930be7Sderaadt 	}
869892d6e70Skrw 
870892d6e70Skrw done:
871892d6e70Skrw 	/* If necessary, copy out data that was read. */
872892d6e70Skrw 	if (bufp == mybuf)
873892d6e70Skrw 		memcpy(buf, bufp + secoff, size);
874df930be7Sderaadt }
875