1 
2 #include <sys/param.h>
3 #include <sys/time.h>
4 #include <sys/uio.h>
5 #include <sys/vnode.h>
6 #include <sys/stat.h>
7 #include <sys/mount.h>
8 
9 #include <ufs/ufs/dinode.h>
10 #include <ufs/lfs/lfs.h>
11 #include <ufs/lfs/lfs_extern.h>
12 
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <unistd.h>
16 #include "clean.h"
17 
18 /*
19  * fs_getmntinfo:
20  *
21  *    This function will get information on all mounted file systems
22  * of a given type.
23  */
24 int
25 fs_getmntinfo(buf, type)
26 	struct	statfs	**buf;
27 	int	type;
28 {
29 	int	i;
30 	int	count;
31 	int	tcount;
32 	struct	statfs	*tstatfsp;
33 
34 	tcount = getmntinfo(&tstatfsp, 0);
35 
36 	if (tcount < 0) {
37 		perror ("fs_getmntinfo: getmntinfo failed");
38 		return -1;
39 	}
40 
41 	for (count = 0, i = 0 ; i < tcount ; i ++)
42 		if (type == 0 || tstatfsp[i].f_type == type)
43 			++ count;
44 
45 	if (count > 0) {
46 		*buf = (struct statfs *)
47 			malloc(count*sizeof(struct statfs));
48 		if (*buf == 0) { perror ("fs_getmntinfo: out of space"); exit (1); }
49 		for (i = 0, count = 0 ; i < tcount ; i ++) {
50 			if (type == 0 || tstatfsp[i].f_type == type) {
51 				(*buf)[count] = tstatfsp[i];
52 				++count;
53 			}
54 		}
55 		return count;
56 	}
57 	return 0;
58 }
59 
60 /*
61  * get_fs_info:
62  *
63  * get all the information available on a file system
64  */
65 int
66 get_fs_info (lstatfsp, fspp, count)
67 	struct  statfs  *lstatfsp;	/* IN: array of statfs structs */
68 	FS_INFO **fspp;			/* OUT: resulting array of FS_INFOs */
69 	int	count;			/* IN: number of file systems */
70 {
71 	int	i;
72 	caddr_t	ifp;
73 	FS_INFO	*fsp;
74 
75 	*fspp = (FS_INFO *)malloc(count * sizeof(FS_INFO));
76 
77 	for (i = 0 ; i < count ; i++) {
78 		fsp = *fspp + i;
79 		statfsp = lstatfsp + i;
80 		lfsp = (struct lfs *)malloc (LFS_SBPAD);
81 		if (get_superblock (fsp, lfsp) < 0) {
82 			perror("get_fs_info: get_superblock failed");
83 			return -1;
84 		}
85 		fsp->fi_daddr_shift = lfsp->lfs_bshift - lfsp->lfs_fsbtodb;
86 		if (get_ifile (fsp) < 0) {
87 			perror("get_fs_info: get_ifile failed");
88 			return -1;
89 		}
90 	}
91 	return 0;
92 }
93 
94 /* this is needed temporarily, because of the bug in mmap'ed files */
95 void
96 free_fs_info (fsp, count)
97 	FS_INFO *fsp;	/* IN: array of fs_infos we will dispose of */
98 	int	count;	/* IN: number of file systems */
99 {
100 	int	i;
101 	caddr_t	fsp_base = (caddr_t)fsp;
102 
103 	for (i = 0 ; i < count ; i++, fsp++) {
104 		/* free superblock */
105 		free (lfsp);
106 		/* sdp points to the beginning of the ifile area */
107 #ifndef MMAP_WORKS
108 		free (cip);
109 #else
110 		if (munmap (cip, ifile_length) < 0) {
111 			perror("free_fs_info: munmap failed\n");
112 		}
113 #endif /* MMAP_WORKS */
114 	}
115 
116 	free (fsp_base);
117 }
118 
119 /*
120  * get_superblock:
121  *    gets the superblock from disk (possibly in face of errors)
122  */
123 int
124 get_superblock (fsp, sbp)
125 	FS_INFO *fsp;	/* IN: array of fs_infos we will dispose of */
126 	struct	lfs	*sbp;
127 {
128         int 	fid;
129 	char	mntfromname[MNAMELEN+1];
130 
131 	strcpy(mntfromname, "/dev/r");
132 	strcat(mntfromname, statfsp->f_mntfromname+5);
133 
134 	if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
135 		perror("get_superblock: bad open");
136 		return -1;
137 	}
138 
139 	if(lseek (fid, LFS_LABELPAD, SEEK_SET) != LFS_LABELPAD) {
140 		perror("get_superblock: bad seek");
141 		return -1;
142 	}
143 	if(read (fid, (char *)sbp, LFS_SBPAD) != LFS_SBPAD) {
144 		perror("get_superblock: bad read");
145 		return -1;
146 	}
147 	close (fid);
148 
149 	return 0;
150 }
151 
152 /*
153  * get_ifile:
154  *    This function will map the ifile into memory.  It returns
155  * NULL on failure.
156  */
157 int
158 get_ifile (fsp)
159 	FS_INFO	*fsp;
160 {
161 	int	fid;
162 	int	count;
163 	caddr_t	ifp = NULL;
164 	char    *ifile_name;
165 	struct	stat file_stat;
166 
167 	ifile_name = (char *)
168 		malloc(strlen(statfsp->f_mntonname)+strlen(IFILE_NAME)+2);
169 	strcpy(ifile_name, statfsp->f_mntonname);
170 	strcat(ifile_name, "/");
171 	strcat(ifile_name, IFILE_NAME);
172 
173 	if ((fid = open(ifile_name, O_RDWR, (mode_t)0)) < 0) {
174 		perror("get_ifile: bad open");
175 		return -1;
176 	}
177 
178 	if(fstat (fid, &file_stat)) {
179 		perror("get_ifile: fstat failed");
180 		return -1;
181 	}
182 	ifile_length = file_stat.st_size;
183 
184 	/* get the ifile */
185 #ifndef MMAP_WORKS
186 	ifp = (caddr_t)malloc (ifile_length);
187 	if (ifp == 0) {
188 		perror ("get_ifile: malloc failed, out of memory?");
189 		return -1;
190 	}
191 	count = read (fid, ifp, ifile_length);
192 
193 	if (count != ifile_length) {
194 		perror("get_ifile: bad ifile read");
195 		return -1;
196 	}
197 #else	/* MMAP_WORKS */
198 	ifp = mmap ((caddr_t)0, ifile_length, PROT_READ|PROT_WRITE,
199 		MAP_FILE|MAP_SHARED, fid, (off_t)0);
200 	if (ifp < 0) {
201 		perror("get_ifile: mmap failed");
202 		return NULL;
203 	}
204 #endif	/* MMAP_WORKS */
205 
206 	close (fid);
207 
208 	cip = (CLEANERINFO*)ifp;
209 	segusep = (SEGUSE*)(ifp + CLEANSIZE(lfsp));
210 	ifilep  = (IFILE*)(ifp + CLEANSIZE(lfsp) + SEGTABSIZE(lfsp));
211 	/* # of bytes in ifile table */
212 	ifile_count = ifile_length - (CLEANSIZE(lfsp) + SEGTABSIZE(lfsp));
213 	/* # of ifile entries in ifile table */
214 	ifile_count = (ifile_count / lfsp->lfs_bsize) * lfsp->lfs_ifpb;
215 	free (ifile_name);
216 	return 0;
217 }
218 
219 
220 /*
221  * segmapv:
222  *
223  *   This function will scan a segment and return a list of
224  * <inode, blocknum> pairs which indicate which blocks were
225  * contained as live data within the segment at some point
226  * (it may have "died" since then).  Any given pair will be
227  * listed at most once.
228  */
229 int
230 lfs_segmapv(fsp, seg, seg_buf, blocks, bcount, inodes, icount)
231 	FS_INFO *fsp;		/* pointer to super block */
232 	int	seg;		/* the segment id */
233 	caddr_t	seg_buf;	/* the buffer containing the segment's data */
234 				/* OUT: array of block_info for live blocks */
235 	BLOCK_INFO	**blocks;
236 	int	*bcount;	/* OUT: number of active blocks in segment */
237 				/* OUT: array of inode_info for live inodes */
238 	INODE_INFO	**inodes;
239 	int	*icount;	/* OUT: number of active inodes in segment */
240 {
241 	caddr_t	s;
242 	caddr_t	endofseg;
243 	int	nextsum;
244 	u_long	sb_off;
245 	time_t	timestamp;
246 
247 	*bcount = 0;
248 	*blocks = (BLOCK_INFO *)malloc (sizeof(BLOCK_INFO));
249 
250 	*icount = 0;
251 	*inodes = (INODE_INFO *)malloc(sizeof(INODE_INFO));
252 
253 	sb_off = (SEGUSE_ENTRY(lfsp, segusep, seg)->su_flags & SEGUSE_SUPERBLOCK) ?
254 		LFS_SBPAD : 0;
255 
256 	for (s = seg_buf + sb_off, endofseg = seg_buf + seg_size(lfsp),
257 	     timestamp = 0 ;
258 	     s < endofseg ;
259 	     s += pseg_size (fsp, (SEGSUM*)s)) {
260 		BLOCK_INFO	*pblocks;
261 		int		pbcount;
262 		INODE_INFO	*pinodes;
263 		int		picount;
264 
265 #ifdef VERBOSE
266 		printf("lfs_segmapv: seg_buf = 0x%x, pseg_buf = 0x%x, offset = %lu (0x%x), pseg = \n\t",
267 			(u_int)seg_buf, (u_int)s,
268 			(u_int)s - (u_int)seg_buf - (u_int)sb_off,
269 			(u_int)s - (u_int)seg_buf - (u_int)sb_off);
270 /* this can cause core dumps when printing an invalid segsum
271  *		print_SEGSUM ((SEGSUM*)s);
272  *		printf("\n");
273  *		printf("pseg_size = %lu\n", pseg_size(fsp, (SEGSUM*)s));
274  */
275 		fflush(stdout);
276 #endif /* VERBOSE */
277 
278 		/* we have hit the end of the valid data */
279 		if (! pseg_valid (fsp, (SEGSUM*)s)) break;
280 
281 		/* we have gone back in time and hit old data */
282 		if (timestamp > ((SEGSUM*)s)->ss_create) break;
283 
284 		timestamp = ((SEGSUM*)s)->ss_create;
285 
286 		/* get the block and inode list */
287 		pseg_blocks (fsp, seg, (SEGSUM*)s, seg_buf,
288 			&pblocks, &pbcount);
289 		pseg_bjoin  (fsp, blocks, bcount, pblocks, pbcount);
290 
291 		pseg_inodes (fsp, seg, (SEGSUM*)s, seg_buf,
292 			&pinodes, &picount);
293 		pseg_ijoin  (fsp, inodes, icount, pinodes, picount);
294 
295 		/* free the temporary tables */
296 		free (pblocks);
297 		free (pinodes);
298 	}
299 
300 }
301 
302 /*
303  * this will parse a partial segment and create a vector of block_info's
304  * for live data and a vector of inode_info's for live inodes.  It will
305  * not include blocks or inodes from files with new version numbers.
306  */
307 void
308 pseg_blocks (fsp, seg, s, seg_buf, blocks, count)
309 	FS_INFO *fsp;		/* pointer to super block */
310 	int	seg;		/* the segment id */
311 	SEGSUM	*s;		/* (unvalidated) segsum pointer */
312 	caddr_t	seg_buf;	/* the buffer containing the segment's data */
313 				/* OUT: array of block_info for live blocks */
314 	BLOCK_INFO	**blocks;
315 	int	*count;		/* OUT: number of active blocks in segment */
316 {
317 	FINFO	**finfos;
318 	int	finfoc;
319 	int	blockc;
320 	int	i;
321 	int	j;
322 	int	ninob;		/* number of inode blocks passed */
323 	daddr_t	seg_daddr;
324 	daddr_t	*cur_iaddrp;	/* pointer to current inode block */
325 	u_long	offset;		/* the offset (in bytes) within the segment */
326 
327 	*count = 0;
328 	*blocks = NULL;
329 
330 	pseg_finfos (fsp, s, &finfos, &finfoc);
331 
332 #ifdef VERBOSE
333 	for(i=0;i<finfoc;i++){print_FINFO(finfos[i]);printf("\n");fflush(stdout);}
334 	printf("pseg_blocks: finfoc = %d\n", finfoc);fflush(stdout);
335 #endif
336 
337 	/* count how many blocks are held by live FINFO's */
338 	for (i = 0, blockc = 0 ; i < finfoc ; ++i)
339 		if (finfos[i]->fi_version ==
340 		    IFILE_ENTRY(lfsp, ifilep, finfos[i]->fi_ino)->if_version)
341 			blockc += finfos[i]->fi_nblocks;
342 
343 	if (finfoc == 0 || blockc == 0) return;
344 
345 	ninob = 0;
346 	offset = LFS_SUMMARY_SIZE + ((u_int)s - (u_int)seg_buf) +
347 		s->ss_next * datobyte(fsp, 1<<lfsp->lfs_bshift);
348 	cur_iaddrp = (daddr_t*)(s->ss_ninos == 0 ? 0 :
349 	    (char *)s + LFS_SUMMARY_SIZE - sizeof(daddr_t));
350 	seg_daddr = sntoda(lfsp, seg);
351 	*blocks = (BLOCK_INFO *)malloc (blockc*sizeof(BLOCK_INFO));
352 
353 	for (i = 0 ; i < finfoc ; i ++) {
354 		FINFO		*f = finfos[i];
355 
356 		if (f->fi_version != IFILE_ENTRY(lfsp, ifilep, f->fi_ino)->if_version)
357 			continue;
358 
359 #ifdef VERBOSE
360 		printf("finfo %d = ", i);
361 		print_FINFO(f);
362 		printf("\n");
363 		fflush(stdout);
364 		printf("IFILE entry for file %d = ", f->fi_ino);
365 		print_IFILE (IFILE_ENTRY(lfsp, ifilep, f->fi_ino));
366 		printf("\n");
367 		fflush(stdout);
368 #endif
369 		for (j = 0 ; j < finfos[i]->fi_nblocks ; j ++) {
370 			BLOCK_INFO	*b = &(*blocks)[*count];
371 
372 			/*
373 			 * XXX:
374 			 * this changes if we have variable size blocks
375 			 */
376 			for (;cur_iaddrp &&
377 			    seg_daddr + bytetoda(fsp, offset) == *cur_iaddrp;
378 			    offset += datobyte(fsp, 1<<lfsp->lfs_bshift)) {
379 				if (ninob <= (s->ss_ninos + INOPB(lfsp) - 1)
380 				    / INOPB(lfsp)) {
381 					++ninob;
382 					--cur_iaddrp;
383 				} else
384 					cur_iaddrp = NULL;
385 			}
386 			b->bi_inode = f->fi_ino;
387 			b->bi_lbn = f->fi_blocks[j];
388 			b->bi_daddr = seg_daddr + bytetoda(fsp, offset);
389 			b->bi_segcreate = s->ss_create;
390 			b->bi_bp = seg_buf + offset;
391 
392 			(*count) ++;
393 			offset += blocksize(fsp, b->bi_lbn);
394 #ifdef VERBOSE
395 			printf("\tb[%d] = ", j);
396 			print_BLOCK_INFO(b);
397 			printf("\n");
398 			fflush(stdout);
399 #endif
400 		}
401 	}
402 	free (finfos);
403 }
404 
405 void
406 pseg_inodes (fsp, seg, s, seg_buf, inodes, count)
407 	FS_INFO *fsp;		/* pointer to super block */
408 	int	seg;		/* the segment id */
409 	SEGSUM	*s;		/* (unvalidated) segsum pointer */
410 	caddr_t	seg_buf;	/* the buffer containing the segment's data */
411 				/* OUT: array of inode_info for live inodes */
412 	INODE_INFO	**inodes;
413 	int	*count;		/* OUT: number of active inodes in segment */
414 {
415 	int	i;
416 	ino_t	inum;
417 	daddr_t	*daddrp, i_daddr, seg_daddr;
418 	struct	dinode	*di;
419 
420 	*count = 0;
421 	*inodes = NULL;
422 
423 	if (s->ss_ninos <= 0) return;
424 
425 	*inodes = (INODE_INFO *)malloc (s->ss_ninos * sizeof(INODE_INFO));
426 
427 	seg_daddr = sntoda(lfsp, seg);
428 
429 #ifdef VERBOSE
430 	printf("pseg_inodes:\n");
431 	print_SEGSUM(s);
432 	printf("\n");
433 	fflush(stdout);
434 #endif
435 
436 	daddrp = (daddr_t *)((caddr_t)s + LFS_SUMMARY_SIZE);
437 
438 	for (i = 0 ; i < s->ss_ninos ; ++i) {
439 
440 		if (i % INOPB(lfsp) == 0) {
441 			i_daddr = *--daddrp;
442 			if (datosn(lfsp, i_daddr) != seg ||
443 			    datobyte(fsp, i_daddr - seg_daddr) > seg_size(lfsp)) {
444 				printf("pseg_inodes: bad i_daddr\n");
445 				print_SEGSUM(s);
446 				printf("\n");
447 				fflush(stdout);
448 				printf("i_daddr = %d, seg_daddr = %d, offset = %d, pseg_size = %d\n",
449 				    i_daddr, seg_daddr, i_daddr - seg_daddr,
450 				    pseg_size(fsp, (SEGSUM*)s));
451 				fflush(stdout);
452 			}
453 			di = (struct dinode *)
454 				(seg_buf + datobyte(fsp, i_daddr - seg_daddr));
455 		} else
456 			++di;
457 
458 		inum = di->di_inum;
459 
460 		if (IFILE_ENTRY(lfsp, ifilep, inum)->if_daddr == i_daddr) {
461 			(*inodes)[*count].ii_inode = inum;
462 			(*inodes)[*count].ii_daddr = i_daddr;
463 			(*inodes)[*count].ii_segcreate = s->ss_create;
464 			(*inodes)[*count].ii_dinode = di;
465 
466 			(*count) ++;
467 		}
468 	}
469 }
470 
471 /* return the size of the partial segment in bytes. */
472 u_long
473 pseg_size (fsp, s)
474 	FS_INFO *fsp;   /* pointer to super block */
475 	SEGSUM	*s;	/* segsum pointer */
476 {
477 	int	i;
478 	int	j;
479 	FINFO	**finfos;
480 	int	finfoc;
481 	u_long	size = LFS_SUMMARY_SIZE;
482 
483 	pseg_finfos (fsp, s, &finfos, &finfoc);
484 	for (i = 0 ; i < finfoc ; i ++)
485 	for (j = 0 ; j < finfos[i]->fi_nblocks ; j ++)
486 		size += blocksize(fsp, finfos[i]->fi_blocks[j]);
487 
488 	/* inodes are packed INOPB inodes per block */
489 	/* there can be unused space in an inode block */
490 	size += datobyte(fsp, fsbtodb(lfsp,1)*((s->ss_ninos+INOPB(lfsp)-1)/INOPB(lfsp)));
491 
492 	return size;
493 }
494 
495 /*
496  * join block list b with list a (eliminating duplicates), leaving result
497  * in list a.
498  */
499 void
500 pseg_bjoin (fsp, ablocks, acount, bblocks, bcount)
501 	FS_INFO *fsp;   /* pointer to file system info */
502 				/* INOUT: array of live blocks block_info */
503 	BLOCK_INFO	**ablocks;
504 	int	*acount;	/* INOUT: number of active blocks */
505 				/* IN: array of live blocks block_info */
506 	BLOCK_INFO	*bblocks;
507 	int	bcount;	/* IN: number of active blocks */
508 {
509 	int	i;
510 	int	j;
511 	BLOCK_INFO	*abp;
512 	BLOCK_INFO	*bbp;
513 
514 #ifdef VERBOSE
515 	printf("pseg_bjoin: *acount = %d, bcount = %d\n", *acount, bcount);
516 /**/
517 	printf("ablocks = \n");
518 	for(i=0;i<*acount;i++){print_BLOCK_INFO((*ablocks)+i); printf("\n");}
519 /**/
520 	printf("bblocks = \n");
521 	for(i=0;i<bcount;i++){print_BLOCK_INFO(bblocks+i); printf("\n");}
522 /**/
523 	fflush(stdout);
524 /**/
525 #endif
526 
527 	for (i = 0, bbp = bblocks ; i < bcount ; ++i, ++bbp) {
528 		for (j = 0, abp = *ablocks ; j < *acount ; ++j, ++abp) {
529 			if (abp->bi_inode == bbp->bi_inode
530 				&& abp->bi_lbn == bbp->bi_lbn) {
531 				/* the data is for the same file and logical block */
532 				if (abp->bi_segcreate < bbp->bi_segcreate)
533 					*abp = *bbp;
534 				break;
535 			}
536 		}
537 		if (j == *acount) {
538 			/* this is a block we haven't seen before */
539 			*ablocks = (BLOCK_INFO*)
540 				realloc (*ablocks, sizeof(BLOCK_INFO)*(*acount + 1));
541 			(*ablocks)[*acount] = *bbp;
542 			(*acount) ++;
543 		}
544 	}
545 }
546 
547 /*
548  * join block list b with list a (eliminating duplicates), leaving result
549  * in list a.
550  */
551 void
552 pseg_ijoin (fsp, ainodes, acount, binodes, bcount)
553 	FS_INFO *fsp;   /* pointer to file system info */
554 				/* INOUT: array of live inodes inode_info */
555 	INODE_INFO	**ainodes;
556 	int	*acount;	/* INOUT: number of active inodes */
557 				/* IN: array of live inodes inode_info */
558 	INODE_INFO	*binodes;
559 	int	bcount;		/* IN: number of active inodes */
560 {
561 	int	i;
562 	int	j;
563 	daddr_t	daddr;
564 	INODE_INFO	*aip;
565 	INODE_INFO	*bip;
566 
567 	/* we assume that we have no duplicate live inodes on "a" and "b" */
568 
569 	/* eliminate dead inodes from "a" */
570 	for (i = 0, aip = *ainodes ; i < *acount ; ++aip ) {
571 		daddr = IFILE_ENTRY(lfsp, ifilep, aip->ii_inode)->if_daddr;
572 		if (daddr != aip->ii_daddr)
573 			*aip = (*ainodes)[--(*acount)];
574 		else 	i++;
575 	}
576 
577 	/* eliminate dead inodes from "b" */
578 	for (i = 0, bip = binodes ; i < bcount ; ++bip) {
579 		daddr = IFILE_ENTRY(lfsp, ifilep, bip->ii_inode)->if_daddr;
580 		if (daddr != bip->ii_daddr) {
581 			/* don't really need to do this, only we don't want
582 			   to lose any inodes, just in case */
583 			INODE_INFO	tmp;
584 			tmp = *bip;
585 			*bip = binodes[bcount];
586 			binodes[bcount] = tmp;
587 			bcount --;
588 		}
589 		else	i++;
590 	}
591 	/* append "b" to "a" */
592 	if (bcount > 0) {
593 		*ainodes = (INODE_INFO *)realloc ((void *)*ainodes,
594 			(*acount + bcount + 1)*sizeof(INODE_INFO));
595 		for (i = 0 ; i < bcount ; i ++)
596 			(*ainodes)[(*acount)++] = binodes[i];
597 	}
598 }
599 
600 /* is the segsum block valid? return TRUE if it is, FALSE otherwise */
601 int
602 segsum_valid (fsp, ssp)
603 	FS_INFO *fsp;   /* pointer to file system info */
604 	SEGSUM	*ssp;	/* pointer to segment summary block */
605 {
606 	u_long	sumsum;
607 
608 	/* check segsum block checksum */
609 	sumsum = cksum(&ssp->ss_datasum,
610 	    LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum));
611 
612 	if (sumsum != ssp->ss_sumsum) return FALSE;
613 
614 	return TRUE;
615 }
616 
617 /*
618  * pseg_valid:
619  *
620  * returns 1 if the partial segment is valid, and 0 if it is invalid.
621  * it uses the checksums to verify validity.
622  */
623 int
624 pseg_valid (fsp, ssp)
625 	FS_INFO *fsp;   /* pointer to file system info */
626 	SEGSUM	*ssp;	/* pointer to segment summary block */
627 {
628 	u_long	datasum;
629 	u_long	size;
630 	int	nblocks;
631 	int	i;
632 	u_long	*datap;
633 	caddr_t	p;
634 
635 	/* check segsum block checksum */
636 	if (segsum_valid (fsp, ssp) == FALSE) return FALSE;
637 
638 	return TRUE;
639 
640 	/* check data/inode block(s) checksum too... */
641 	size = pseg_size (fsp, ssp);
642 	nblocks = size/fsbtodb(lfsp, 1);
643 	datap = (u_long*)malloc(sizeof(u_long)*nblocks);
644 	p = (caddr_t)ssp + LFS_SUMMARY_SIZE;
645 	for (i = 0 ; i < nblocks ; i ++) {
646 		datap[i] = *((u_long *)p);
647 		p += lfsp->lfs_bsize;
648 	}
649 	datasum = cksum ((void *)datap, nblocks*sizeof(u_long));
650 	if (datasum != ssp->ss_datasum) return FALSE;
651 
652 	return TRUE;
653 }
654 
655 /* get array of FINFO pointers for partial segment */
656 void
657 pseg_finfos (fsp, ssp, finfos, count)
658 	FS_INFO	*fsp;   /* pointer to file system info */
659 	SEGSUM	*ssp;	/* pointer to segment summary block */
660 	FINFO	***finfos;	/* OUT: return an array of FINFO pointers */
661 	int	*count;		/* OUT: return size of array */
662 {
663 	caddr_t	p = (caddr_t)ssp + sizeof(SEGSUM);
664 	int	i;
665 	FINFO	*fip;
666 
667 	*count = 0;
668 	*finfos = NULL;
669 
670 	if (ssp->ss_nfinfo > 0)
671 		*finfos = (FINFO**)malloc (ssp->ss_nfinfo*sizeof(FINFO*));
672 
673 	for (i = 0 ; i < ssp->ss_nfinfo ; i ++) {
674 		fip = (FINFO *)p;
675 		(*finfos)[*count] = fip;
676 		(*count) ++;
677 		p += finfo_size (fip);
678 	}
679 }
680 
681 /*
682  * blocksize:
683  *
684  * returns the size (in bytes) of a (logical) block.
685  * this is used because lfs uses different block sizes, depending
686  * on the logical # of the block.  Lfs uses various sizes so
687  * it doesn't need fragments.
688  */
689 u_long
690 blocksize (fsp, index)
691 	FS_INFO *fsp;   /* pointer to file system info */
692 	int	index;	/* logical block # w/in file */
693 {
694 	return lfsp->lfs_bsize;	/* XXX: blocksize might depend on
695 					the logical block number */
696 }
697 
698 /*
699  * finfo_size
700  *
701  * returns the size in bytes of an FINFO structure
702  */
703 u_long
704 finfo_size (finfop)
705 	FINFO	*finfop;
706 {
707 	return sizeof(FINFO) + sizeof(long)*(finfop->fi_nblocks-1);
708 }
709 
710 
711 /* #define MMAP_SEGMENT */
712 /*
713  * read a segment into a memory buffer
714  */
715 int
716 mmap_segment (fsp, segment, seg_buf)
717 	FS_INFO	*fsp;		/* file system information */
718 	int	segment;	/* the index of the segment to be cleaned */
719 	caddr_t	*seg_buf;	/* pointer to buffer area */
720 {
721 	off_t	seg_daddr;	/* base disk address of segment */
722 	int	fid;		/* fildes for file system device */
723 	char	mntfromname[MNAMELEN+2];
724 
725 	/* get the disk address of the beginning of the segment */
726 	seg_daddr = sntoda(lfsp, segment);
727 
728 	strcpy(mntfromname, "/dev/r");
729 	strcat(mntfromname, statfsp->f_mntfromname+5);
730 
731 	if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
732 		perror("mmap_segment: bad open");
733 		return -1;
734 	}
735 
736 #ifdef MMAP_SEGMENT
737 	*seg_buf = mmap ((caddr_t)0, seg_size(lfsp), PROT_READ,
738 		MAP_FILE, fid, (off_t)datobyte(fsp, seg_daddr));
739 	if ((long)*seg_buf < 0) {
740 		perror("mmap_segment: mmap failed");
741 		return NULL;
742 	}
743 #else /* MMAP_SEGMENT */
744 	printf("mmap_segment: seg_daddr = %lu, seg_size = %lu, seg_offset = %lu\n",
745 		seg_daddr, seg_size(lfsp), datobyte(fsp, seg_daddr));
746 	/* malloc the space for the buffer */
747 	*seg_buf = (caddr_t)malloc(seg_size(lfsp));
748 
749 	/* read the segment data into the buffer */
750 	if (datobyte(fsp, seg_daddr) != lseek (fid, datobyte(fsp, seg_daddr), SEEK_SET)) {
751 		perror ("mmap_segment: bad lseek");
752 		return -1;
753 	}
754 
755 	if (seg_size(lfsp) != read (fid, *seg_buf, seg_size(lfsp))) {
756 		perror ("mmap_segment: bad read");
757 		return -1;
758 	}
759 #endif /* MMAP_SEGMENT */
760 	close (fid);
761 
762 	return 0;
763 }
764 
765 void
766 munmap_segment (fsp, seg_buf)
767 	FS_INFO	*fsp;		/* file system information */
768 	caddr_t	seg_buf;	/* pointer to buffer area */
769 {
770 #ifdef MMAP_SEGMENT
771 	munmap (seg_buf, seg_size(lfsp));
772 #else /* MMAP_SEGMENT */
773 	free (seg_buf);
774 #endif /* MMAP_SEGMENT */
775 }
776 
777 
778 /*
779  * USEFUL DEBUGGING TOOLS:
780  */
781 
782 void
783 print_IFILE (p)
784 	IFILE	*p;
785 {
786 	if (p) {
787 		if (p->if_daddr == 0)
788 			printf("{free, if_version=%lu, if_nextfree=%lu}",
789 				p->if_version, p->if_nextfree);
790 		else
791 			printf("{if_version=%lu, if_daddr=%lu}",
792 				p->if_version, p->if_daddr);
793 	}
794 	else printf("0x0");
795 	fflush(stdout);
796 }
797 
798 void
799 print_SEGUSE (p)
800 	SEGUSE	*p;
801 {
802 	if (p) {
803 		printf("{su_nbytes=%lu, su_flags=%c%c%c, su_lastmod=",
804 			p->su_nbytes,
805 			((p->su_flags & SEGUSE_DIRTY) ? 'D' : 'C'),
806 			((p->su_flags & SEGUSE_ACTIVE) ? 'A' : ' '),
807 			((p->su_flags & SEGUSE_SUPERBLOCK) ? 'S' : ' '));
808 			print_time_t(p->su_lastmod);
809 			printf("}");
810 	}
811 	else
812 		printf("0x0");
813 	fflush(stdout);
814 }
815 
816 void
817 print_CLEANERINFO (p)
818 	CLEANERINFO	*p;
819 {
820 	if (p) printf("{clean=%lu, dirty=%lu}", p->clean, p->dirty);
821 	else printf("0x0");
822 	fflush(stdout);
823 }
824 
825 void
826 print_SEGSUM (p)
827 	SEGSUM	*p;
828 {
829 	if (p) {
830 		printf("{ss_sumsum=%lu, ss_datasum=%lu, ss_next=%lu, ",
831 			p->ss_sumsum, p->ss_datasum, p->ss_next);
832 		printf("ss_create=%lu, ss_nfinfo=%lu, ss_ninos=%lu",
833 			p->ss_create, p->ss_nfinfo, p->ss_ninos);
834 		printf("}");
835 	}
836 	else printf("0x0");
837 	fflush(stdout);
838 }
839 
840 void
841 print_time_t (t)
842 	time_t	t;
843 {
844 	char temp[128];
845 	int len;
846 
847 	strcpy (temp, ctime(&t));
848 	len = strlen(temp);
849 	if (temp[len-1] == '\n') temp[len-1] = 0;
850 	printf("%s", temp);
851 	fflush(stdout);
852 }
853 
854 void
855 print_FINFO (p)
856 	FINFO	*p;
857 {
858 	int i;
859 
860 	if (p) {
861 		printf("{fi_nblocks=%lu, fi_version=%lu, fi_ino=%lu, fi_blocks={",
862 			p->fi_nblocks, p->fi_version, p->fi_ino);
863 		for (i = 0 ; i < p->fi_nblocks ; i ++) {
864 			if (i > 0) printf(", ");
865 			printf("%ld", p->fi_blocks[i]);
866 		}
867 		printf("}}");
868 	} else printf("0x0");
869 	fflush(stdout);
870 }
871 
872 void
873 print_BLOCK_INFO (p)
874 	BLOCK_INFO	*p;
875 {
876 	if (p) {
877 		printf("{bi_inode=%lu, bi_lbn=%ld, bi_daddr=%lu, bi_segcreate=",
878 			p->bi_inode, p->bi_lbn, p->bi_daddr);
879 		print_time_t(p->bi_segcreate);
880 		printf(", bi_bp = 0x%x}", p->bi_bp);
881 	}
882 	else
883 		printf("0x0");
884 	fflush(stdout);
885 }
886 
887 void
888 print_INODE_INFO (p)
889 	INODE_INFO	*p;
890 {
891 	if (p) {
892 		printf("{ii_inode=%lu, ii_daddr=%lu, ii_segcreate=",
893 			p->ii_inode, p->ii_daddr);
894 		print_time_t (p->ii_segcreate);
895 		printf(", ii_dinode=0x%x}", p->ii_dinode);
896 	}
897 	else
898 		printf("0x0");
899 	fflush(stdout);
900 }
901 
902 void
903 print_lfs (p)
904 	struct	lfs	*p;
905 {
906 	int	i;
907 
908 	if (p) {
909 		printf("{\n");
910 		printf("\tlfs_magic=0x%x\n", p->lfs_magic);
911 		printf("\tlfs_version=%lu\n", p->lfs_version);
912 		printf("\tlfs_size=%lu\n", p->lfs_size);
913 		printf("\tlfs_ssize=%lu\n", p->lfs_ssize);
914 		printf("\tlfs_dsize=%lu\n", p->lfs_dsize);
915 		printf("\tlfs_bsize=%lu\n", p->lfs_bsize);
916 		printf("\tlfs_fsize=%lu\n", p->lfs_fsize);
917 		printf("\tlfs_frag=%lu\n", p->lfs_frag);
918 		/* checkpoint region */
919 		printf("\tlfs_free=%lu\n", p->lfs_free);
920 		printf("\tlfs_bfree=%lu\n", p->lfs_bfree);
921 		printf("\tlfs_nfiles=%lu\n", p->lfs_nfiles);
922 		printf("\tlfs_idaddr=%lu\n", p->lfs_idaddr);
923 		printf("\tlfs_ifile=%lu\n", p->lfs_ifile);
924 		printf("\tlfs_lastseg=%lu\n", p->lfs_lastseg);
925 		printf("\tlfs_nextseg=%lu\n", p->lfs_nextseg);
926 		printf("\tlfs_curseg=%lu\n", p->lfs_curseg);
927 		printf("\tlfs_offset=%lu\n", p->lfs_offset);
928 		printf("\tlfs_tstamp=%lu\n", p->lfs_tstamp);
929 		/* configuration parameters */
930 		printf("\tlfs_minfree=%lu\n", p->lfs_minfree);
931 		/* these fields can be computed from the others */
932 		printf("\tlfs_dbpseg=%lu\n", p->lfs_dbpseg);
933 		printf("\tlfs_inopb=%lu\n", p->lfs_inopb);
934 		printf("\tlfs_ifpb=%lu\n", p->lfs_ifpb);
935 		printf("\tlfs_sepb=%lu\n", p->lfs_sepb);
936 		printf("\tlfs_nindir=%lu\n", p->lfs_nindir);
937 		printf("\tlfs_nseg=%lu\n", p->lfs_nseg);
938 		printf("\tlfs_nspf=%lu\n", p->lfs_nspf);
939 		printf("\tlfs_cleansz=%lu\n", p->lfs_cleansz);
940 		printf("\tlfs_segtabsz=%lu\n", p->lfs_segtabsz);
941 
942 		printf("\tlfs_segmask=%lu\n", p->lfs_segmask);
943 		printf("\tlfs_segshift=%lu\n", p->lfs_segshift);
944 		printf("\tlfs_bmask=%lu\n", p->lfs_bmask);
945 		printf("\tlfs_bshift=%lu\n", p->lfs_bshift);
946 		printf("\tlfs_ffmask=%lu\n", p->lfs_ffmask);
947 		printf("\tlfs_ffshift=%lu\n", p->lfs_ffshift);
948 		printf("\tlfs_fbmask=%lu\n", p->lfs_fbmask);
949 		printf("\tlfs_fbshift=%lu\n", p->lfs_fbshift);
950 		printf("\tlfs_fsbtodb=%lu\n", p->lfs_fsbtodb);
951 		/* superblock offsets */
952 		printf("\tlfs_sboffs={");
953 		for (i = 0 ; i < LFS_MAXNUMSB ; i ++) {
954 			if (i > 0) printf(", ");
955 			printf("%lu", p->lfs_sboffs[i]);
956 		}
957 		printf("}\n");
958 
959 		printf("}");
960 	}
961 	else
962 		printf("0x0");
963 	fflush(stdout);
964 }
965