1 /* $OpenBSD: fsirand.c,v 1.9 1997/02/28 00:46:33 millert Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Todd C. Miller. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 23 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 24 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 30 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #ifndef lint 34 static char rcsid[] = "$OpenBSD: fsirand.c,v 1.9 1997/02/28 00:46:33 millert Exp $"; 35 #endif /* not lint */ 36 37 #include <sys/types.h> 38 #include <sys/disklabel.h> 39 #include <sys/ioctl.h> 40 #include <sys/param.h> 41 #include <sys/time.h> 42 #include <sys/resource.h> 43 44 #include <ufs/ffs/fs.h> 45 #include <ufs/ufs/dinode.h> 46 47 #include <err.h> 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <time.h> 54 #include <unistd.h> 55 56 static void usage __P((int)); 57 int fsirand __P((char *)); 58 59 int printonly = 0, force = 0, ignorelabel = 0; 60 61 int 62 main(argc, argv) 63 int argc; 64 char *argv[]; 65 { 66 int n, ex = 0; 67 struct rlimit rl; 68 69 while ((n = getopt(argc, argv, "bfp")) != -1) { 70 switch (n) { 71 case 'b': 72 ignorelabel++; 73 break; 74 case 'p': 75 printonly++; 76 break; 77 case 'f': 78 force++; 79 break; 80 default: 81 usage(1); 82 } 83 } 84 if (argc - optind < 1) 85 usage(1); 86 87 srandomdev(); 88 89 /* Increase our data size to the max */ 90 if (getrlimit(RLIMIT_DATA, &rl) == 0) { 91 rl.rlim_cur = rl.rlim_max; 92 if (setrlimit(RLIMIT_DATA, &rl) < 0) 93 warn("Can't get resource limit to max data size"); 94 } else 95 warn("Can't get resource limit for data size"); 96 97 for (n = optind; n < argc; n++) { 98 if (argc - optind != 1) 99 (void)puts(argv[n]); 100 ex += fsirand(argv[n]); 101 if (n < argc - 1) 102 putchar('\n'); 103 } 104 105 exit(ex); 106 } 107 108 int 109 fsirand(device) 110 char *device; 111 { 112 static struct dinode *inodebuf; 113 static size_t oldibufsize; 114 size_t ibufsize; 115 struct fs *sblock; 116 ino_t inumber, maxino; 117 daddr_t dblk; 118 char sbuf[SBSIZE], sbuftmp[SBSIZE]; 119 int devfd, n, cg; 120 u_int32_t bsize = DEV_BSIZE; 121 struct disklabel label; 122 123 if ((devfd = open(device, printonly ? O_RDONLY : O_RDWR)) < 0) { 124 warn("Can't open %s", device); 125 return (1); 126 } 127 128 /* Get block size (usually 512) from disklabel if possible */ 129 if (!ignorelabel) { 130 if (ioctl(devfd, DIOCGDINFO, &label) < 0) 131 warn("Can't read disklabel, using sector size of %d", 132 bsize); 133 else 134 bsize = label.d_secsize; 135 } 136 137 /* Read in master superblock */ 138 (void)memset(&sbuf, 0, sizeof(sbuf)); 139 sblock = (struct fs *)&sbuf; 140 if (lseek(devfd, SBOFF, SEEK_SET) == -1) { 141 warn("Can't seek to superblock (%qd) on %s", SBOFF, device); 142 return (1); 143 } 144 if ((n = read(devfd, (void *)sblock, SBSIZE)) != SBSIZE) { 145 warnx("Can't read superblock on %s: %s", device, 146 (n < SBSIZE) ? "short read" : strerror(errno)); 147 return (1); 148 } 149 maxino = sblock->fs_ncg * sblock->fs_ipg; 150 151 /* Simple sanity checks on the superblock */ 152 if (sblock->fs_magic != FS_MAGIC) { 153 warnx("Bad magic number in superblock"); 154 return (1); 155 } 156 if (sblock->fs_sbsize > SBSIZE) { 157 warnx("Superblock size is preposterous"); 158 return (1); 159 } 160 if (sblock->fs_postblformat == FS_42POSTBLFMT) { 161 warnx("Filesystem format is too old, sorry"); 162 return (1); 163 } 164 if (!force && !printonly && sblock->fs_clean != 1) { 165 warnx("Filesystem is not clean, fsck %s first.", device); 166 return (1); 167 } 168 169 /* Make sure backup superblocks are sane. */ 170 sblock = (struct fs *)&sbuftmp; 171 for (cg = 0; cg < sblock->fs_ncg; cg++) { 172 dblk = fsbtodb(sblock, cgsblock(sblock, cg)); 173 if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { 174 warn("Can't seek to %qd", (off_t)dblk * bsize); 175 return (1); 176 } else if ((n = write(devfd, (void *)sblock, SBSIZE)) != SBSIZE) { 177 warn("Can't read backup superblock %d on %s: %s", 178 cg + 1, device, (n < SBSIZE) ? "short write" 179 : strerror(errno)); 180 return (1); 181 } 182 if (sblock->fs_magic != FS_MAGIC) { 183 warnx("Bad magic number in backup superblock %d on %s", 184 cg + 1, device); 185 return (1); 186 } 187 if (sblock->fs_sbsize > SBSIZE) { 188 warnx("Size of backup superblock %d on %s is preposterous", 189 cg + 1, device); 190 return (1); 191 } 192 } 193 sblock = (struct fs *)&sbuf; 194 195 /* XXX - should really cap buffer at 512kb or so */ 196 ibufsize = sizeof(struct dinode) * sblock->fs_ipg; 197 if (oldibufsize < ibufsize) { 198 if ((inodebuf = realloc(inodebuf, ibufsize)) == NULL) 199 errx(1, "Can't allocate memory for inode buffer"); 200 oldibufsize = ibufsize; 201 } 202 203 if (printonly && (sblock->fs_id[0] || sblock->fs_id[1])) { 204 if (sblock->fs_inodefmt >= FS_44INODEFMT && sblock->fs_id[0]) 205 (void)printf("%s was randomized on %s", device, 206 ctime((const time_t *)&(sblock->fs_id[0]))); 207 (void)printf("fsid: %x %x\n", sblock->fs_id[0], 208 sblock->fs_id[1]); 209 } 210 211 /* Randomize fs_id unless old 4.2BSD filesystem */ 212 if ((sblock->fs_inodefmt >= FS_44INODEFMT) && !printonly) { 213 /* Randomize fs_id and write out new sblock and backups */ 214 sblock->fs_id[0] = (u_int32_t)time(NULL); 215 sblock->fs_id[1] = random(); 216 217 if (lseek(devfd, SBOFF, SEEK_SET) == -1) { 218 warn("Can't seek to superblock (%qd) on %s", SBOFF, 219 device); 220 return (1); 221 } 222 if ((n = write(devfd, (void *)sblock, SBSIZE)) != SBSIZE) { 223 warn("Can't read superblock on %s: %s", device, 224 (n < SBSIZE) ? "short write" : strerror(errno)); 225 return (1); 226 } 227 } 228 229 /* For each cylinder group, randomize inodes and update backup sblock */ 230 for (cg = 0, inumber = 0; cg < sblock->fs_ncg; cg++) { 231 /* Update superblock if appropriate */ 232 if ((sblock->fs_inodefmt >= FS_44INODEFMT) && !printonly) { 233 dblk = fsbtodb(sblock, cgsblock(sblock, cg)); 234 if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { 235 warn("Can't seek to %qd", (off_t)dblk * bsize); 236 return (1); 237 } else if ((n = write(devfd, (void *)sblock, SBSIZE)) != SBSIZE) { 238 warn("Can't read backup superblock %d on %s: %s", 239 cg + 1, device, (n < SBSIZE) ? "short write" 240 : strerror(errno)); 241 return (1); 242 } 243 } 244 245 /* Read in inodes, then print or randomize generation nums */ 246 dblk = fsbtodb(sblock, ino_to_fsba(sblock, inumber)); 247 if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { 248 warn("Can't seek to %qd", (off_t)dblk * bsize); 249 return (1); 250 } else if ((n = read(devfd, inodebuf, ibufsize)) != ibufsize) { 251 warnx("Can't read inodes: %s", 252 (n < ibufsize) ? "short read" : strerror(errno)); 253 return (1); 254 } 255 256 for (n = 0; n < sblock->fs_ipg; n++, inumber++) { 257 if (inumber >= ROOTINO) { 258 if (printonly) 259 (void)printf("ino %d gen %x\n", inumber, 260 inodebuf[n].di_gen); 261 else 262 inodebuf[n].di_gen = random(); 263 } 264 } 265 266 /* Write out modified inodes */ 267 if (!printonly) { 268 if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) { 269 warn("Can't seek to %qd", 270 (off_t)dblk * bsize); 271 return (1); 272 } else if ((n = write(devfd, inodebuf, ibufsize)) != 273 ibufsize) { 274 warnx("Can't write inodes: %s", 275 (n != ibufsize) ? "short write" : 276 strerror(errno)); 277 return (1); 278 } 279 } 280 } 281 (void)close(devfd); 282 283 return(0); 284 } 285 286 static void 287 usage(ex) 288 int ex; 289 { 290 (void)fprintf(stderr, 291 "usage: fsirand [ -b ] [ -f ] [ -p ] special [special ...]\n"); 292 exit(ex); 293 } 294