Home | History | Annotate | Line # | Download | only in scan_ffs
scan_ffs.c revision 1.3
      1 /*	$NetBSD: scan_ffs.c,v 1.3 2005/06/15 20:03:03 christos Exp $	*/
      2 /*	$OpenBSD: scan_ffs.c,v 1.11 2004/02/16 19:13:03 deraadt Exp$	*/
      3 
      4 /*
      5  * Copyright (c) 2005 Juan Romero Pardines
      6  * Copyright (c) 1998 Niklas Hallqvist, Tobias Weingartner
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 /*
     31  * Currently it can detect:
     32  * 	o FFSv1 with fragsize/blocksize: 512/4096, 1024/8192, 2048/16384.
     33  *	o FFSv2 with fragsize/blocksize: 512/4096, 1024/8192, 2048/16384,
     34  *	  				 4096/32768, 8192/65536.
     35  * TODO:
     36  *	o Detect FFSv1 partitions with fsize/bsize > 2048/16384.
     37  *	o Detect FFSv2 partitions with fsize/bsize > 8192/65536.
     38  */
     39 
     40 #include <sys/cdefs.h>
     41 #ifndef lint
     42 __RCSID("$NetBSD: scan_ffs.c,v 1.3 2005/06/15 20:03:03 christos Exp $");
     43 #endif /* not lint */
     44 
     45 #include <sys/types.h>
     46 #include <sys/param.h>
     47 
     48 #include <sys/disklabel.h>
     49 #include <sys/dkio.h>
     50 #include <sys/ioctl.h>
     51 #include <sys/fcntl.h>
     52 #include <ufs/ffs/fs.h>
     53 #include <unistd.h>
     54 #include <stdlib.h>
     55 #include <stdio.h>
     56 #include <string.h>
     57 #include <err.h>
     58 #include <util.h>
     59 
     60 enum { NADA, VERBOSE, LABELS };
     61 
     62 #define SBCOUNT	64 /* XXX should be configurable */
     63 
     64 static void	printpart(int, int, int);
     65 static void	ufsmagic(int);
     66 static void	usage(void) __attribute__((__noreturn__));
     67 static int	checkfstype(void);
     68 static int	ufsscan(int, daddr_t, daddr_t, int);
     69 
     70 static char	lastmount[MAXMNTLEN];
     71 static char	device[MAXPATHLEN];
     72 
     73 static int 	eflag = 0;
     74 static int	flags = 0;
     75 
     76 static daddr_t	blk, lastblk;
     77 
     78 static struct fs *sb;
     79 
     80 static const char *fstypes[] = { "NONE", "FFSv1", "FFSv2" };
     81 
     82 #define FSTYPE_NONE	0
     83 #define FSTYPE_FFSV1	1
     84 #define FSTYPE_FFSV2	2
     85 
     86 static int
     87 checkfstype(void)
     88 {
     89 	switch (sb->fs_magic) {
     90 		case FS_UFS1_MAGIC:
     91 		case FS_UFS1_MAGIC_SWAPPED:
     92 			sb->fs_size = sb->fs_old_size;
     93 			return FSTYPE_FFSV1;
     94 		case FS_UFS2_MAGIC:
     95 		case FS_UFS2_MAGIC_SWAPPED:
     96 			return FSTYPE_FFSV2;
     97 		default:
     98 			return FSTYPE_NONE;
     99 	}
    100 }
    101 
    102 static void
    103 printpart(int flag, int ffsize, int n)
    104 {
    105 
    106 	int fstype = checkfstype();
    107 
    108 	switch (flag) {
    109 	case VERBOSE:
    110 		(void)printf("block: %" PRIu64 "id %x,%x size %" PRIu64 "\n",
    111 		    blk + (n / 512), sb->fs_id[0], sb->fs_id[1], sb->fs_size);
    112 		break;
    113 	case LABELS:
    114 		(void)printf("X:  %9" PRIu64,
    115 		    (uint64_t)((off_t)sb->fs_size * sb->fs_fsize / 512));
    116 		switch (fstype) {
    117 		case FSTYPE_FFSV1:
    118 			(void)printf(" %9" PRIu64,
    119 			    blk + (n / 512) - (2 * SBLOCKSIZE / 512));
    120 			break;
    121 		case FSTYPE_FFSV2:
    122 			(void)printf(" %9" PRIu64,
    123 			    blk + (n / 512) -
    124 			    (ffsize * SBLOCKSIZE / 512 + 128));
    125 			break;
    126 		default:
    127 			break;
    128 		}
    129 		(void)printf(" 4.2BSD %6d %5d%4d # %s [%s]\n",
    130 			sb->fs_fsize, sb->fs_bsize,
    131 			sb->fs_old_cpg, lastmount, fstypes[fstype]);
    132 		break;
    133 	default:
    134 		printf("%s ", fstypes[fstype]);
    135 		switch (fstype) {
    136 		case FSTYPE_FFSV1:
    137 			(void)printf("at %" PRIu64,
    138 			    blk + (n / 512) - (2 * SBLOCKSIZE / 512));
    139 			break;
    140 		case FSTYPE_FFSV2:
    141 			(void)printf("at %" PRIu64,
    142 			    blk + (n / 512) -
    143 			    (ffsize * SBLOCKSIZE / 512 + 128));
    144 			break;
    145 		default:
    146 			break;
    147 		}
    148 		(void)printf(" size %" PRIu64 ", last mounted on %s\n",
    149 		    (uint64_t)((off_t)sb->fs_size * sb->fs_fsize / 512),
    150 		    lastmount);
    151 		break;
    152 	}
    153 }
    154 
    155 static void
    156 ufsmagic(int n)
    157 {
    158 	int fstype = checkfstype();
    159 	size_t i;
    160 
    161 	/*
    162 	 * FIXME:
    163 	 * It cannot find FFSv1 partitions with fsize/bsize > 2048/16384,
    164 	 * same problem found in the original program that comes from
    165 	 * OpenBSD (scan_ffs(1)).
    166 	 */
    167 	if (flags & VERBOSE)
    168 		printpart(VERBOSE, NADA, n);
    169 	switch (fstype) {
    170 	case FSTYPE_FFSV1:
    171 		if (((blk + (n / 512)) - lastblk) == (SBLOCKSIZE / 512)) {
    172 			if (flags & LABELS)
    173 				printpart(LABELS, NADA, n);
    174 			else
    175 				printpart(NADA, NADA, n);
    176 		}
    177 		break;
    178 	case FSTYPE_FFSV2:
    179 		/*
    180 		 * That checks for FFSv2 partitions with fragsize/blocksize:
    181 		 * 512/4096, 1024/8192, 2048/16384, 4096/32768 and 8192/65536.
    182 		 * Really enough for now.
    183 		 */
    184 		for (i = 1; i < 16; i <<= 1)
    185 			if (((blk + (n / 512)) - lastblk) ==
    186 			    (i * SBLOCKSIZE / 512)) {
    187 				if (flags & LABELS)
    188 					printpart(LABELS, i, n);
    189 				else
    190 					printpart(NADA, i, n);
    191 			}
    192 	}
    193 }
    194 
    195 static int
    196 ufsscan(int fd, daddr_t beg, daddr_t end, int fflags)
    197 {
    198 
    199 	u_int8_t buf[SBLOCKSIZE * SBCOUNT];
    200 	int n, fstype;
    201 
    202 	lastblk = -1;
    203 	(void)memset(lastmount, 0, MAXMNTLEN);
    204 
    205 	if (fflags & LABELS)
    206 		(void)printf(
    207 		    "#        size    offset fstype [fsize bsize cpg]\n");
    208 
    209 	for (blk = beg; blk <= ((end < 0) ? blk: end);
    210 		blk += (SBCOUNT * SBLOCKSIZE / 512)) {
    211 		(void)memset(buf, 0, sizeof(buf));
    212 
    213 		if (lseek(fd, (off_t)blk * 512, SEEK_SET) == (off_t)-1)
    214 			err(1, "lseek");
    215 
    216 		if (read(fd, buf, sizeof(buf)) == -1)
    217 			err(1, "read");
    218 
    219 		for (n = 0; n < (SBLOCKSIZE * SBCOUNT); n += 512) {
    220 			sb = (struct fs *)(void *)&buf[n];
    221 			if ((fstype = checkfstype()) == FSTYPE_NONE)
    222 				continue;
    223 			ufsmagic(n);
    224 			/* Update last potential FS SBs seen */
    225 			lastblk = blk + (n / 512);
    226 			(void)memcpy(lastmount, sb->fs_fsmnt, MAXMNTLEN);
    227 		}
    228 	}
    229 	return EXIT_SUCCESS;
    230 }
    231 
    232 
    233 static void
    234 usage(void)
    235 {
    236 	(void)fprintf(stderr,
    237 		"Usage: %s [-lv] [-s start] [-e end] device", getprogname());
    238 	exit(EXIT_FAILURE);
    239 }
    240 
    241 
    242 int
    243 main(int argc, char **argv)
    244 {
    245 	int ch, fd;
    246 	daddr_t end = -1, beg = 0;
    247 	struct disklabel dl;
    248 
    249 	setprogname(argv[0]);
    250 
    251 	while ((ch = getopt(argc, argv, "e:ls:v")) != -1)
    252 		switch(ch) {
    253 		case 'e':
    254 			eflag = 1;
    255 			end = atoi(optarg);
    256 			break;
    257 		case 'l':
    258 			flags |= LABELS;
    259 			break;
    260 		case 's':
    261 			beg = atoi(optarg);
    262 			break;
    263 		case 'v':
    264 			flags |= VERBOSE;
    265 			break;
    266 		default:
    267 			usage();
    268 			/* NOTREACHED */
    269 		}
    270 
    271 	argc -= optind;
    272 	argv += optind;
    273 
    274 	if (argc != 1)
    275 		usage();
    276 
    277 	fd = opendisk(argv[0], O_RDONLY, device, sizeof(device), 0);
    278 
    279 	if (fd == -1)
    280 		err(1, "Cannot open `%s'", device);
    281 		/* NOTREACHED */
    282 
    283 	if (ioctl(fd, DIOCGDINFO, &dl) == -1) {
    284 		warn("Couldn't retrieve disklabel");
    285 		(void)memset(&dl, 0, sizeof(dl));
    286 		dl.d_secperunit = 0x7fffffff;
    287 	} else {
    288 		(void)printf("Disk: %s\n", dl.d_typename);
    289 		(void)printf("Total sectors on disk: %" PRIu32 "\n\n",
    290 		    dl.d_secperunit);
    291 	}
    292 
    293 	if (!eflag)
    294 		end = dl.d_secperunit; /* default to max sectors */
    295 
    296 	return ufsscan(fd, beg, end, flags);
    297 }
    298