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