1 /* $NetBSD: fsirand.c,v 1.28 2008/04/28 20:23:08 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __RCSID("$NetBSD: fsirand.c,v 1.28 2008/04/28 20:23:08 martin Exp $"); 35 #endif /* lint */ 36 37 #include <sys/param.h> 38 #include <sys/time.h> 39 #include <sys/vnode.h> 40 #include <sys/disklabel.h> 41 #include <sys/ioctl.h> 42 43 #include <ctype.h> 44 #include <err.h> 45 #include <errno.h> 46 #include <fcntl.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 #include <util.h> 52 #include <signal.h> 53 54 #include <ufs/ufs/ufs_bswap.h> 55 56 #include <ufs/ufs/dinode.h> 57 #include <ufs/ffs/fs.h> 58 #include <ufs/ffs/ffs_extern.h> 59 60 static void usage(void); 61 static void getsblock(int, const char *, struct fs *); 62 static void fixinodes(int, struct fs *, struct disklabel *, int, long); 63 static void statussig(int); 64 65 int needswap, ino, imax, is_ufs2; 66 time_t tstart; 67 68 static void 69 usage(void) 70 { 71 72 (void) fprintf(stderr, 73 "usage: %s [-F] [-p] [-x <constant>] <special>\n", 74 getprogname()); 75 exit(1); 76 } 77 78 79 static const off_t sblock_try[] = SBLOCKSEARCH; 80 81 /* 82 * getsblock(): 83 * Return the superblock 84 */ 85 static void 86 getsblock(int fd, const char *name, struct fs *fs) 87 { 88 int i; 89 90 for (i = 0; ; i++) { 91 if (sblock_try[i] == -1) 92 errx(1, "%s: can't find superblock", name); 93 if (pread(fd, fs, SBLOCKSIZE, sblock_try[i]) != SBLOCKSIZE) 94 continue; 95 96 switch(fs->fs_magic) { 97 case FS_UFS2_MAGIC: 98 is_ufs2 = 1; 99 /* FALLTHROUGH */ 100 case FS_UFS1_MAGIC: 101 break; 102 case FS_UFS2_MAGIC_SWAPPED: 103 is_ufs2 = 1; 104 /* FALLTHROUGH */ 105 case FS_UFS1_MAGIC_SWAPPED: 106 needswap = 1; 107 ffs_sb_swap(fs, fs); 108 break; 109 default: 110 continue; 111 } 112 113 if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2) 114 continue; 115 break; 116 } 117 118 if (fs->fs_ncg < 1) 119 errx(1, "%s: bad ncg in superblock", name); 120 121 if (fs->fs_sbsize > SBLOCKSIZE) 122 errx(1, "%s: superblock too large", name); 123 } 124 125 126 /* 127 * fixinodes(): 128 * Randomize the inode generation numbers 129 */ 130 static void 131 fixinodes(int fd, struct fs *fs, struct disklabel *lab, int pflag, long xorval) 132 { 133 int inopb = INOPB(fs); 134 int size; 135 caddr_t buf; 136 struct ufs1_dinode *dp1 = NULL; 137 struct ufs2_dinode *dp2 = NULL; 138 int i; 139 140 size = is_ufs2 ? inopb * sizeof (struct ufs2_dinode) : 141 inopb * sizeof (struct ufs1_dinode); 142 143 if ((buf = malloc(size)) == NULL) 144 err(1, "Out of memory"); 145 146 if (is_ufs2) 147 dp2 = (struct ufs2_dinode *)buf; 148 else 149 dp1 = (struct ufs1_dinode *)buf; 150 151 for (ino = 0, imax = fs->fs_ipg * fs->fs_ncg; ino < imax;) { 152 off_t sp; 153 sp = (off_t) fsbtodb(fs, ino_to_fsba(fs, ino)) * 154 (off_t) lab->d_secsize; 155 156 if (lseek(fd, sp, SEEK_SET) == (off_t) -1) 157 err(1, "Seeking to inode %d failed", ino); 158 159 if (read(fd, buf, size) != size) 160 err(1, "Reading inodes %d+%d failed", ino, inopb); 161 162 for (i = 0; i < inopb; i++) { 163 if (is_ufs2) { 164 if (pflag) 165 printf("inode %10d gen 0x%08x\n", 166 ino, 167 ufs_rw32(dp2[i].di_gen, needswap)); 168 else 169 dp2[i].di_gen = 170 ufs_rw32((arc4random() & INT32_MAX)^ xorval, 171 needswap); 172 } else { 173 if (pflag) 174 printf("inode %10d gen 0x%08x\n", 175 ino, 176 ufs_rw32(dp1[i].di_gen, needswap)); 177 else 178 dp1[i].di_gen = 179 ufs_rw32((arc4random() & INT32_MAX) ^ xorval, 180 needswap); 181 } 182 if (++ino > imax) 183 errx(1, "Exceeded number of inodes"); 184 } 185 186 if (pflag) 187 continue; 188 189 if (lseek(fd, sp, SEEK_SET) == (off_t) -1) 190 err(1, "Seeking to inode %d failed", ino); 191 192 if (write(fd, buf, size) != size) 193 err(1, "Writing inodes %d+%d failed", ino, inopb); 194 } 195 free(buf); 196 } 197 198 /* 199 * statussig(): 200 * display current status 201 */ 202 void 203 statussig(int dummy) 204 { 205 char msgbuf[256]; 206 int len, deltat; 207 time_t tnow, elapsed; 208 209 (void)time(&tnow); 210 elapsed = tnow - tstart; 211 len = snprintf(msgbuf, sizeof(msgbuf), 212 "fsirand: completed inode %d of %d (%3.2f%%)", 213 ino, imax, (ino * 100.0) / imax); 214 if (imax - ino) { 215 deltat = tstart - tnow + (1.0 * (tnow - tstart)) / ino * imax; 216 len += snprintf(msgbuf + len, sizeof(msgbuf) - len, 217 ", finished in %d:%02d\n", deltat / 60, deltat % 60); 218 } else { 219 len += snprintf(msgbuf + len, sizeof(msgbuf) - len, "\n"); 220 } 221 write(STDERR_FILENO, msgbuf, len); 222 } 223 224 int 225 main(int argc, char *argv[]) 226 { 227 const char *special; 228 char buf[SBLOCKSIZE], device[MAXPATHLEN]; 229 struct fs *fs = (struct fs *) buf; 230 struct disklabel lab; 231 long xorval; 232 char *ep; 233 int fd, c, Fflag, pflag, openflags; 234 235 xorval = 0; 236 Fflag = pflag = 0; 237 238 while ((c = getopt(argc, argv, "Fpx:")) != -1) 239 switch (c) { 240 case 'F': 241 Fflag++; 242 break; 243 case 'p': 244 pflag++; 245 break; 246 case 'x': 247 errno = 0; 248 xorval = strtol(optarg, &ep, 0); 249 if ((xorval == LONG_MIN || xorval == LONG_MAX) && 250 errno == ERANGE) 251 err(1, "Out of range constant"); 252 if (*ep) 253 errx(1, "Bad constant"); 254 break; 255 default: 256 usage(); 257 } 258 259 argv += optind; 260 argc -= optind; 261 262 if (argc != 1) 263 usage(); 264 265 special = argv[0]; 266 openflags = pflag ? O_RDONLY : O_RDWR; 267 if (Fflag) 268 fd = open(special, openflags); 269 else { 270 fd = opendisk(special, openflags, device, sizeof(device), 0); 271 special = device; 272 } 273 if (fd == -1) 274 err(1, "Cannot open `%s'", special); 275 276 if (Fflag) { 277 memset(&lab, 0, sizeof(lab)); 278 lab.d_secsize = DEV_BSIZE; /* XXX */ 279 } else { 280 if (ioctl(fd, DIOCGDINFO, &lab) == -1) 281 err(1, "%s: cannot get disklabel information", special); 282 } 283 284 time(&tstart); 285 (void)signal(SIGINFO, statussig); 286 getsblock(fd, special, fs); 287 fixinodes(fd, fs, &lab, pflag, xorval); 288 289 (void) close(fd); 290 return 0; 291 } 292