1 /* $NetBSD: fsirand.c,v 1.33 2022/11/17 06:40:39 chs 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.33 2022/11/17 06:40:39 chs 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 __dead 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 static 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 case FS_UFS2EA_MAGIC: 99 is_ufs2 = 1; 100 /* FALLTHROUGH */ 101 case FS_UFS1_MAGIC: 102 break; 103 case FS_UFS2_MAGIC_SWAPPED: 104 case FS_UFS2EA_MAGIC_SWAPPED: 105 is_ufs2 = 1; 106 /* FALLTHROUGH */ 107 case FS_UFS1_MAGIC_SWAPPED: 108 needswap = 1; 109 ffs_sb_swap(fs, fs); 110 break; 111 default: 112 continue; 113 } 114 115 if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2) 116 continue; 117 break; 118 } 119 120 if (fs->fs_ncg < 1) 121 errx(1, "%s: bad ncg in superblock", name); 122 123 if (fs->fs_sbsize > SBLOCKSIZE) 124 errx(1, "%s: superblock too large", name); 125 } 126 127 128 /* 129 * fixinodes(): 130 * Randomize the inode generation numbers 131 */ 132 static void 133 fixinodes(int fd, struct fs *fs, struct disklabel *lab, int pflag, long xorval) 134 { 135 int inopb = FFS_INOPB(fs); 136 int size; 137 caddr_t buf; 138 struct ufs1_dinode *dp1 = NULL; 139 struct ufs2_dinode *dp2 = NULL; 140 int i; 141 142 size = is_ufs2 ? inopb * sizeof (struct ufs2_dinode) : 143 inopb * sizeof (struct ufs1_dinode); 144 145 if ((buf = malloc(size)) == NULL) 146 err(1, "Out of memory"); 147 148 if (is_ufs2) 149 dp2 = (struct ufs2_dinode *)buf; 150 else 151 dp1 = (struct ufs1_dinode *)buf; 152 153 for (ino = 0, imax = fs->fs_ipg * fs->fs_ncg; ino < imax;) { 154 off_t sp; 155 sp = (off_t) FFS_FSBTODB(fs, ino_to_fsba(fs, ino)) * 156 (off_t) lab->d_secsize; 157 158 if (lseek(fd, sp, SEEK_SET) == (off_t) -1) 159 err(1, "Seeking to inode %d failed", ino); 160 161 if (read(fd, buf, size) != size) 162 err(1, "Reading inodes %d+%d failed", ino, inopb); 163 164 for (i = 0; i < inopb; i++) { 165 if (is_ufs2) { 166 if (pflag) 167 printf("inode %10d gen 0x%08x\n", 168 ino, 169 ufs_rw32(dp2[i].di_gen, needswap)); 170 else 171 dp2[i].di_gen = 172 ufs_rw32((arc4random() & INT32_MAX)^ xorval, 173 needswap); 174 } else { 175 if (pflag) 176 printf("inode %10d gen 0x%08x\n", 177 ino, 178 ufs_rw32(dp1[i].di_gen, needswap)); 179 else 180 dp1[i].di_gen = 181 ufs_rw32((arc4random() & INT32_MAX) ^ xorval, 182 needswap); 183 } 184 if (++ino > imax) 185 errx(1, "Exceeded number of inodes"); 186 } 187 188 if (pflag) 189 continue; 190 191 if (lseek(fd, sp, SEEK_SET) == (off_t) -1) 192 err(1, "Seeking to inode %d failed", ino); 193 194 if (write(fd, buf, size) != size) 195 err(1, "Writing inodes %d+%d failed", ino, inopb); 196 } 197 free(buf); 198 } 199 200 /* 201 * statussig(): 202 * display current status 203 */ 204 static void 205 statussig(int dummy) 206 { 207 char msgbuf[256]; 208 int len, deltat; 209 time_t tnow; 210 211 (void)time(&tnow); 212 len = snprintf(msgbuf, sizeof(msgbuf), 213 "fsirand: completed inode %d of %d (%3.2f%%)", 214 ino, imax, (ino * 100.0) / imax); 215 if (imax - ino) { 216 deltat = tstart - tnow + (1.0 * (tnow - tstart)) / ino * imax; 217 len += snprintf(msgbuf + len, sizeof(msgbuf) - len, 218 ", finished in %d:%02d\n", deltat / 60, deltat % 60); 219 } else { 220 len += snprintf(msgbuf + len, sizeof(msgbuf) - len, "\n"); 221 } 222 write(STDERR_FILENO, msgbuf, len); 223 } 224 225 int 226 main(int argc, char *argv[]) 227 { 228 const char *special; 229 char buf[SBLOCKSIZE], device[MAXPATHLEN]; 230 struct fs *fs = (struct fs *) buf; 231 struct disklabel lab; 232 long xorval; 233 char *ep; 234 int fd, c, Fflag, pflag, openflags; 235 236 xorval = 0; 237 Fflag = pflag = 0; 238 239 while ((c = getopt(argc, argv, "Fpx:")) != -1) 240 switch (c) { 241 case 'F': 242 Fflag++; 243 break; 244 case 'p': 245 pflag++; 246 break; 247 case 'x': 248 errno = 0; 249 xorval = strtol(optarg, &ep, 0); 250 if ((xorval == LONG_MIN || xorval == LONG_MAX) && 251 errno == ERANGE) 252 err(1, "Out of range constant"); 253 if (*ep) 254 errx(1, "Bad constant"); 255 break; 256 default: 257 usage(); 258 } 259 260 argv += optind; 261 argc -= optind; 262 263 if (argc != 1) 264 usage(); 265 266 special = argv[0]; 267 openflags = pflag ? O_RDONLY : O_RDWR; 268 if (Fflag) 269 fd = open(special, openflags); 270 else { 271 fd = opendisk(special, openflags, device, sizeof(device), 0); 272 special = device; 273 } 274 if (fd == -1) 275 err(1, "Cannot open `%s'", special); 276 277 if (Fflag) { 278 memset(&lab, 0, sizeof(lab)); 279 lab.d_secsize = DEV_BSIZE; /* XXX */ 280 } else { 281 if (ioctl(fd, DIOCGDINFO, &lab) == -1) 282 err(1, "%s: cannot get disklabel information", special); 283 } 284 285 time(&tstart); 286 (void)signal(SIGINFO, statussig); 287 getsblock(fd, special, fs); 288 fixinodes(fd, fs, &lab, pflag, xorval); 289 290 (void) close(fd); 291 return 0; 292 } 293