| 1 |  |  | /*	$OpenBSD: fsirand.c,v 1.39 2016/08/14 22:35:54 guenther Exp $	*/ | 
    
    | 2 |  |  |  | 
    
    | 3 |  |  | /* | 
    
    | 4 |  |  |  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> | 
    
    | 5 |  |  |  * | 
    
    | 6 |  |  |  * Permission to use, copy, modify, and distribute this software for any | 
    
    | 7 |  |  |  * purpose with or without fee is hereby granted, provided that the above | 
    
    | 8 |  |  |  * copyright notice and this permission notice appear in all copies. | 
    
    | 9 |  |  |  * | 
    
    | 10 |  |  |  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 
    
    | 11 |  |  |  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 
    
    | 12 |  |  |  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 
    
    | 13 |  |  |  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 
    
    | 14 |  |  |  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 
    
    | 15 |  |  |  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 
    
    | 16 |  |  |  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 
    
    | 17 |  |  |  */ | 
    
    | 18 |  |  |  | 
    
    | 19 |  |  | #include <sys/param.h>	/* DEV_BSIZE */ | 
    
    | 20 |  |  | #include <sys/disklabel.h> | 
    
    | 21 |  |  | #include <sys/ioctl.h> | 
    
    | 22 |  |  | #include <sys/dkio.h> | 
    
    | 23 |  |  | #include <sys/resource.h> | 
    
    | 24 |  |  | #include <sys/time.h> | 
    
    | 25 |  |  |  | 
    
    | 26 |  |  | #include <ufs/ffs/fs.h> | 
    
    | 27 |  |  | #include <ufs/ufs/dinode.h> | 
    
    | 28 |  |  |  | 
    
    | 29 |  |  | #include <err.h> | 
    
    | 30 |  |  | #include <errno.h> | 
    
    | 31 |  |  | #include <fcntl.h> | 
    
    | 32 |  |  | #include <stdio.h> | 
    
    | 33 |  |  | #include <stdlib.h> | 
    
    | 34 |  |  | #include <string.h> | 
    
    | 35 |  |  | #include <unistd.h> | 
    
    | 36 |  |  | #include <util.h> | 
    
    | 37 |  |  |  | 
    
    | 38 |  |  | void usage(int); | 
    
    | 39 |  |  | int fsirand(char *); | 
    
    | 40 |  |  |  | 
    
    | 41 |  |  | extern char *__progname; | 
    
    | 42 |  |  |  | 
    
    | 43 |  |  | int printonly = 0, force = 0, ignorelabel = 0; | 
    
    | 44 |  |  |  | 
    
    | 45 |  |  | /* | 
    
    | 46 |  |  |  * Possible locations for the superblock. | 
    
    | 47 |  |  |  */ | 
    
    | 48 |  |  | static const int sbtry[] = SBLOCKSEARCH; | 
    
    | 49 |  |  |  | 
    
    | 50 |  |  | int | 
    
    | 51 |  |  | main(int argc, char *argv[]) | 
    
    | 52 |  |  | { | 
    
    | 53 |  |  | 	int n, ex = 0; | 
    
    | 54 |  |  | 	struct rlimit rl; | 
    
    | 55 |  |  |  | 
    
    | 56 |  |  | 	while ((n = getopt(argc, argv, "bfp")) != -1) { | 
    
    | 57 |  |  | 		switch (n) { | 
    
    | 58 |  |  | 		case 'b': | 
    
    | 59 |  |  | 			ignorelabel = 1; | 
    
    | 60 |  |  | 			break; | 
    
    | 61 |  |  | 		case 'p': | 
    
    | 62 |  |  | 			printonly = 1; | 
    
    | 63 |  |  | 			break; | 
    
    | 64 |  |  | 		case 'f': | 
    
    | 65 |  |  | 			force = 1; | 
    
    | 66 |  |  | 			break; | 
    
    | 67 |  |  | 		default: | 
    
    | 68 |  |  | 			usage(1); | 
    
    | 69 |  |  | 		} | 
    
    | 70 |  |  | 	} | 
    
    | 71 |  |  | 	if (argc - optind < 1) | 
    
    | 72 |  |  | 		usage(1); | 
    
    | 73 |  |  |  | 
    
    | 74 |  |  | 	/* Increase our data size to the max */ | 
    
    | 75 |  |  | 	if (getrlimit(RLIMIT_DATA, &rl) == 0) { | 
    
    | 76 |  |  | 		rl.rlim_cur = rl.rlim_max; | 
    
    | 77 |  |  | 		if (setrlimit(RLIMIT_DATA, &rl) < 0) | 
    
    | 78 |  |  | 			warn("Can't set resource limit to max data size"); | 
    
    | 79 |  |  | 	} else | 
    
    | 80 |  |  | 		warn("Can't get resource limit for data size"); | 
    
    | 81 |  |  |  | 
    
    | 82 |  |  | 	for (n = optind; n < argc; n++) { | 
    
    | 83 |  |  | 		if (argc - optind != 1) | 
    
    | 84 |  |  | 			(void)puts(argv[n]); | 
    
    | 85 |  |  | 		ex += fsirand(argv[n]); | 
    
    | 86 |  |  | 		if (n < argc - 1) | 
    
    | 87 |  |  | 			putchar('\n'); | 
    
    | 88 |  |  | 	} | 
    
    | 89 |  |  |  | 
    
    | 90 |  |  | 	exit(ex); | 
    
    | 91 |  |  | } | 
    
    | 92 |  |  |  | 
    
    | 93 |  |  | int | 
    
    | 94 |  |  | fsirand(char *device) | 
    
    | 95 |  |  | { | 
    
    | 96 |  |  | 	struct ufs1_dinode *dp1 = NULL; | 
    
    | 97 |  |  | 	struct ufs2_dinode *dp2 = NULL; | 
    
    | 98 |  |  | 	static char *inodebuf; | 
    
    | 99 |  |  | 	size_t ibufsize, isize; | 
    
    | 100 |  |  | 	struct fs *sblock, *tmpsblock; | 
    
    | 101 |  |  | 	ino_t inumber; | 
    
    | 102 |  |  | 	daddr_t sblockloc, dblk; | 
    
    | 103 |  |  | 	char sbuf[SBSIZE], sbuftmp[SBSIZE]; | 
    
    | 104 |  |  | 	int devfd, n, cg, i; | 
    
    | 105 |  |  | 	char *devpath, *ib; | 
    
    | 106 |  |  | 	u_int32_t bsize = DEV_BSIZE; | 
    
    | 107 |  |  | 	struct disklabel label; | 
    
    | 108 |  |  |  | 
    
    | 109 |  |  | 	if ((devfd = opendev(device, printonly ? O_RDONLY : O_RDWR, | 
    
    | 110 |  |  | 	    0, &devpath)) < 0) { | 
    
    | 111 |  |  | 		warn("Can't open %s", devpath); | 
    
    | 112 |  |  | 		return (1); | 
    
    | 113 |  |  | 	} | 
    
    | 114 |  |  |  | 
    
    | 115 |  |  | 	/* Get block size (usually 512) from disklabel if possible */ | 
    
    | 116 |  |  | 	if (!ignorelabel) { | 
    
    | 117 |  |  | 		if (ioctl(devfd, DIOCGDINFO, &label) < 0) | 
    
    | 118 |  |  | 			warn("Can't read disklabel, using sector size of %d", | 
    
    | 119 |  |  | 			    bsize); | 
    
    | 120 |  |  | 		else | 
    
    | 121 |  |  | 			bsize = label.d_secsize; | 
    
    | 122 |  |  | 	} | 
    
    | 123 |  |  |  | 
    
    | 124 |  |  | 	if (pledge("stdio flock rpath cpath wpath", NULL) == -1) | 
    
    | 125 |  |  | 		err(1, "pledge"); | 
    
    | 126 |  |  |  | 
    
    | 127 |  |  | 	/* Read in master superblock */ | 
    
    | 128 |  |  | 	(void)memset(&sbuf, 0, sizeof(sbuf)); | 
    
    | 129 |  |  | 	sblock = (struct fs *)&sbuf; | 
    
    | 130 |  |  |  | 
    
    | 131 |  |  | 	for (i = 0; sbtry[i] != -1; i++) { | 
    
    | 132 |  |  | 		sblockloc = sbtry[i]; | 
    
    | 133 |  |  |  | 
    
    | 134 |  |  | 		if (lseek(devfd, sblockloc, SEEK_SET) == -1) { | 
    
    | 135 |  |  | 			warn("Can't seek to superblock (%lld) on %s", | 
    
    | 136 |  |  | 			    (long long)sblockloc, devpath); | 
    
    | 137 |  |  | 			return (1); | 
    
    | 138 |  |  | 		} | 
    
    | 139 |  |  |  | 
    
    | 140 |  |  | 		if ((n = read(devfd, sblock, SBSIZE)) != SBSIZE) { | 
    
    | 141 |  |  | 			warnx("Can't read superblock on %s: %s", devpath, | 
    
    | 142 |  |  | 			    (n < SBSIZE) ? "short read" : strerror(errno)); | 
    
    | 143 |  |  | 			return (1); | 
    
    | 144 |  |  | 		} | 
    
    | 145 |  |  |  | 
    
    | 146 |  |  | 		/* Find a suitable superblock */ | 
    
    | 147 |  |  | 		if (sblock->fs_magic != FS_UFS1_MAGIC && | 
    
    | 148 |  |  | 		    sblock->fs_magic != FS_UFS2_MAGIC) | 
    
    | 149 |  |  | 			continue; /* Not a superblock */ | 
    
    | 150 |  |  |  | 
    
    | 151 |  |  | 		if (sblock->fs_magic == FS_UFS2_MAGIC && | 
    
    | 152 |  |  | 		    sblock->fs_sblockloc != sbtry[i]) | 
    
    | 153 |  |  | 		    	continue; /* Not a superblock */ | 
    
    | 154 |  |  |  | 
    
    | 155 |  |  | 		break; | 
    
    | 156 |  |  | 	} | 
    
    | 157 |  |  |  | 
    
    | 158 |  |  | 	if (sbtry[i] == -1) { | 
    
    | 159 |  |  | 		warnx("Cannot find file system superblock"); | 
    
    | 160 |  |  | 		return (1); | 
    
    | 161 |  |  | 	} | 
    
    | 162 |  |  |  | 
    
    | 163 |  |  | 	/* Simple sanity checks on the superblock */ | 
    
    | 164 |  |  | 	if (sblock->fs_sbsize > SBSIZE) { | 
    
    | 165 |  |  | 		warnx("Superblock size is preposterous"); | 
    
    | 166 |  |  | 		return (1); | 
    
    | 167 |  |  | 	} | 
    
    | 168 |  |  |  | 
    
    | 169 |  |  | 	if (sblock->fs_postblformat == FS_42POSTBLFMT) { | 
    
    | 170 |  |  | 		warnx("Filesystem format is too old, sorry"); | 
    
    | 171 |  |  | 		return (1); | 
    
    | 172 |  |  | 	} | 
    
    | 173 |  |  |  | 
    
    | 174 |  |  | 	if (!force && !printonly && sblock->fs_clean != FS_ISCLEAN) { | 
    
    | 175 |  |  | 		warnx("Filesystem is not clean, fsck %s first.", devpath); | 
    
    | 176 |  |  | 		return (1); | 
    
    | 177 |  |  | 	} | 
    
    | 178 |  |  |  | 
    
    | 179 |  |  | 	/* Make sure backup superblocks are sane. */ | 
    
    | 180 |  |  | 	tmpsblock = (struct fs *)&sbuftmp; | 
    
    | 181 |  |  | 	for (cg = 0; cg < sblock->fs_ncg; cg++) { | 
    
    | 182 |  |  | 		dblk = fsbtodb(sblock, cgsblock(sblock, cg)); | 
    
    | 183 |  |  | 		if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { | 
    
    | 184 |  |  | 			warn("Can't seek to %lld", (long long)dblk * bsize); | 
    
    | 185 |  |  | 			return (1); | 
    
    | 186 |  |  | 		} else if ((n = read(devfd, tmpsblock, SBSIZE)) != SBSIZE) { | 
    
    | 187 |  |  | 			warn("Can't read backup superblock %d on %s: %s", | 
    
    | 188 |  |  | 			    cg + 1, devpath, (n < SBSIZE) ? "short read" | 
    
    | 189 |  |  | 			    : strerror(errno)); | 
    
    | 190 |  |  | 			return (1); | 
    
    | 191 |  |  | 		} | 
    
    | 192 |  |  | 		if (tmpsblock->fs_magic != FS_UFS1_MAGIC && | 
    
    | 193 |  |  | 		    tmpsblock->fs_magic != FS_UFS2_MAGIC) { | 
    
    | 194 |  |  | 			warnx("Bad magic number in backup superblock %d on %s", | 
    
    | 195 |  |  | 			    cg + 1, devpath); | 
    
    | 196 |  |  | 			return (1); | 
    
    | 197 |  |  | 		} | 
    
    | 198 |  |  | 		if (tmpsblock->fs_sbsize > SBSIZE) { | 
    
    | 199 |  |  | 			warnx("Size of backup superblock %d on %s is preposterous", | 
    
    | 200 |  |  | 			    cg + 1, devpath); | 
    
    | 201 |  |  | 			return (1); | 
    
    | 202 |  |  | 		} | 
    
    | 203 |  |  | 	} | 
    
    | 204 |  |  |  | 
    
    | 205 |  |  | 	/* XXX - should really cap buffer at 512kb or so */ | 
    
    | 206 |  |  | 	if (sblock->fs_magic == FS_UFS1_MAGIC) | 
    
    | 207 |  |  | 		isize = sizeof(struct ufs1_dinode); | 
    
    | 208 |  |  | 	else | 
    
    | 209 |  |  | 		isize = sizeof(struct ufs2_dinode); | 
    
    | 210 |  |  |  | 
    
    | 211 |  |  | 	if ((ib = reallocarray(inodebuf, sblock->fs_ipg, isize)) == NULL) | 
    
    | 212 |  |  | 		errx(1, "Can't allocate memory for inode buffer"); | 
    
    | 213 |  |  | 	inodebuf = ib; | 
    
    | 214 |  |  | 	ibufsize = sblock->fs_ipg * isize; | 
    
    | 215 |  |  |  | 
    
    | 216 |  |  | 	if (printonly && (sblock->fs_id[0] || sblock->fs_id[1])) { | 
    
    | 217 |  |  | 		if (sblock->fs_inodefmt >= FS_44INODEFMT && sblock->fs_id[0]) { | 
    
    | 218 |  |  | 			time_t t = sblock->fs_id[0];	/* XXX 2038 */ | 
    
    | 219 |  |  | 			(void)printf("%s was randomized on %s", devpath, | 
    
    | 220 |  |  | 			    ctime(&t)); | 
    
    | 221 |  |  | 		} | 
    
    | 222 |  |  | 		(void)printf("fsid: %x %x\n", sblock->fs_id[0], | 
    
    | 223 |  |  | 		    sblock->fs_id[1]); | 
    
    | 224 |  |  | 	} | 
    
    | 225 |  |  |  | 
    
    | 226 |  |  | 	/* Randomize fs_id unless old 4.2BSD filesystem */ | 
    
    | 227 |  |  | 	if ((sblock->fs_inodefmt >= FS_44INODEFMT) && !printonly) { | 
    
    | 228 |  |  | 		/* Randomize fs_id and write out new sblock and backups */ | 
    
    | 229 |  |  | 		sblock->fs_id[0] = (u_int32_t)time(NULL); | 
    
    | 230 |  |  | 		sblock->fs_id[1] = arc4random(); | 
    
    | 231 |  |  |  | 
    
    | 232 |  |  | 		if (lseek(devfd, SBOFF, SEEK_SET) == -1) { | 
    
    | 233 |  |  | 			warn("Can't seek to superblock (%lld) on %s", | 
    
    | 234 |  |  | 			    (long long)SBOFF, devpath); | 
    
    | 235 |  |  | 			return (1); | 
    
    | 236 |  |  | 		} | 
    
    | 237 |  |  | 		if ((n = write(devfd, sblock, SBSIZE)) != SBSIZE) { | 
    
    | 238 |  |  | 			warn("Can't write superblock on %s: %s", devpath, | 
    
    | 239 |  |  | 			    (n < SBSIZE) ? "short write" : strerror(errno)); | 
    
    | 240 |  |  | 			return (1); | 
    
    | 241 |  |  | 		} | 
    
    | 242 |  |  | 	} | 
    
    | 243 |  |  |  | 
    
    | 244 |  |  | 	/* For each cylinder group, randomize inodes and update backup sblock */ | 
    
    | 245 |  |  | 	for (cg = 0, inumber = 0; cg < sblock->fs_ncg; cg++) { | 
    
    | 246 |  |  | 		/* Update superblock if appropriate */ | 
    
    | 247 |  |  | 		if ((sblock->fs_inodefmt >= FS_44INODEFMT) && !printonly) { | 
    
    | 248 |  |  | 			dblk = fsbtodb(sblock, cgsblock(sblock, cg)); | 
    
    | 249 |  |  | 			if (lseek(devfd, (off_t)dblk * bsize, | 
    
    | 250 |  |  | 			    SEEK_SET) < 0) { | 
    
    | 251 |  |  | 				warn("Can't seek to %lld", | 
    
    | 252 |  |  | 				    (long long)dblk * bsize); | 
    
    | 253 |  |  | 				return (1); | 
    
    | 254 |  |  | 			} else if ((n = write(devfd, sblock, SBSIZE)) != | 
    
    | 255 |  |  | 			    SBSIZE) { | 
    
    | 256 |  |  | 				warn("Can't read backup superblock %d on %s: %s", | 
    
    | 257 |  |  | 				    cg + 1, devpath, (n < SBSIZE) ? "short write" | 
    
    | 258 |  |  | 				    : strerror(errno)); | 
    
    | 259 |  |  | 				return (1); | 
    
    | 260 |  |  | 			} | 
    
    | 261 |  |  | 		} | 
    
    | 262 |  |  |  | 
    
    | 263 |  |  | 		/* Read in inodes, then print or randomize generation nums */ | 
    
    | 264 |  |  | 		dblk = fsbtodb(sblock, ino_to_fsba(sblock, inumber)); | 
    
    | 265 |  |  | 		if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { | 
    
    | 266 |  |  | 			warn("Can't seek to %lld", (long long)dblk * bsize); | 
    
    | 267 |  |  | 			return (1); | 
    
    | 268 |  |  | 		} else if ((n = read(devfd, inodebuf, ibufsize)) != ibufsize) { | 
    
    | 269 |  |  | 			warnx("Can't read inodes: %s", | 
    
    | 270 |  |  | 			    (n < ibufsize) ? "short read" : strerror(errno)); | 
    
    | 271 |  |  | 			return (1); | 
    
    | 272 |  |  | 		} | 
    
    | 273 |  |  |  | 
    
    | 274 |  |  | 		for (n = 0; n < sblock->fs_ipg; n++, inumber++) { | 
    
    | 275 |  |  | 			if (sblock->fs_magic == FS_UFS1_MAGIC) | 
    
    | 276 |  |  | 				dp1 = &((struct ufs1_dinode *)inodebuf)[n]; | 
    
    | 277 |  |  | 			else | 
    
    | 278 |  |  | 				dp2 = &((struct ufs2_dinode *)inodebuf)[n]; | 
    
    | 279 |  |  | 			if (inumber >= ROOTINO) { | 
    
    | 280 |  |  | 				if (printonly) | 
    
    | 281 |  |  | 					(void)printf("ino %llu gen %x\n", | 
    
    | 282 |  |  | 					    (unsigned long long)inumber, | 
    
    | 283 |  |  | 					    sblock->fs_magic == FS_UFS1_MAGIC ? | 
    
    | 284 |  |  | 					    dp1->di_gen : dp2->di_gen); | 
    
    | 285 |  |  | 				else if (sblock->fs_magic == FS_UFS1_MAGIC) | 
    
    | 286 |  |  | 					dp1->di_gen = arc4random(); | 
    
    | 287 |  |  | 				else | 
    
    | 288 |  |  | 					dp2->di_gen = arc4random(); | 
    
    | 289 |  |  | 			} | 
    
    | 290 |  |  | 		} | 
    
    | 291 |  |  |  | 
    
    | 292 |  |  | 		/* Write out modified inodes */ | 
    
    | 293 |  |  | 		if (!printonly) { | 
    
    | 294 |  |  | 			if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { | 
    
    | 295 |  |  | 				warn("Can't seek to %lld", | 
    
    | 296 |  |  | 				    (long long)dblk * bsize); | 
    
    | 297 |  |  | 				return (1); | 
    
    | 298 |  |  | 			} else if ((n = write(devfd, inodebuf, ibufsize)) != | 
    
    | 299 |  |  | 				 ibufsize) { | 
    
    | 300 |  |  | 				warnx("Can't write inodes: %s", | 
    
    | 301 |  |  | 				    (n != ibufsize) ? "short write" : | 
    
    | 302 |  |  | 				    strerror(errno)); | 
    
    | 303 |  |  | 				return (1); | 
    
    | 304 |  |  | 			} | 
    
    | 305 |  |  | 		} | 
    
    | 306 |  |  | 	} | 
    
    | 307 |  |  | 	(void)close(devfd); | 
    
    | 308 |  |  |  | 
    
    | 309 |  |  | 	return(0); | 
    
    | 310 |  |  | } | 
    
    | 311 |  |  |  | 
    
    | 312 |  |  | void | 
    
    | 313 |  |  | usage(int ex) | 
    
    | 314 |  |  | { | 
    
    | 315 |  |  | 	(void)fprintf(stderr, "usage: %s [-bfp] special ...\n", | 
    
    | 316 |  |  | 	    __progname); | 
    
    | 317 |  |  | 	exit(ex); | 
    
    | 318 |  |  | } |