1*87ba0e2aSchs /* $NetBSD: fsirand.c,v 1.33 2022/11/17 06:40:39 chs Exp $ */
24de05221Schristos
3ccc59bf1Schristos /*-
4ccc59bf1Schristos * Copyright (c) 1997 The NetBSD Foundation, Inc.
5ccc59bf1Schristos * All rights reserved.
6ccc59bf1Schristos *
7ccc59bf1Schristos * This code is derived from software contributed to The NetBSD Foundation
8ccc59bf1Schristos * by Christos Zoulas.
94de05221Schristos *
104de05221Schristos * Redistribution and use in source and binary forms, with or without
114de05221Schristos * modification, are permitted provided that the following conditions
124de05221Schristos * are met:
134de05221Schristos * 1. Redistributions of source code must retain the above copyright
144de05221Schristos * notice, this list of conditions and the following disclaimer.
154de05221Schristos * 2. Redistributions in binary form must reproduce the above copyright
164de05221Schristos * notice, this list of conditions and the following disclaimer in the
174de05221Schristos * documentation and/or other materials provided with the distribution.
184de05221Schristos *
19ccc59bf1Schristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20ccc59bf1Schristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21ccc59bf1Schristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22ccc59bf1Schristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23ccc59bf1Schristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ccc59bf1Schristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ccc59bf1Schristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ccc59bf1Schristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ccc59bf1Schristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ccc59bf1Schristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ccc59bf1Schristos * POSSIBILITY OF SUCH DAMAGE.
304de05221Schristos */
314de05221Schristos
325fa4ef04Slukem #include <sys/cdefs.h>
334de05221Schristos #ifndef lint
34*87ba0e2aSchs __RCSID("$NetBSD: fsirand.c,v 1.33 2022/11/17 06:40:39 chs Exp $");
354de05221Schristos #endif /* lint */
364de05221Schristos
372fa188aaSlukem #include <sys/param.h>
382fa188aaSlukem #include <sys/time.h>
392fa188aaSlukem #include <sys/vnode.h>
402fa188aaSlukem #include <sys/disklabel.h>
412fa188aaSlukem #include <sys/ioctl.h>
422fa188aaSlukem
434de05221Schristos #include <ctype.h>
444de05221Schristos #include <err.h>
45664a532eSlukem #include <errno.h>
46664a532eSlukem #include <fcntl.h>
47664a532eSlukem #include <stdio.h>
484de05221Schristos #include <stdlib.h>
49664a532eSlukem #include <string.h>
504de05221Schristos #include <unistd.h>
512fa188aaSlukem #include <util.h>
52628f1591Sdrochner #include <signal.h>
534de05221Schristos
54c0892a30Sbouyer #include <ufs/ufs/ufs_bswap.h>
554de05221Schristos
56ed7fcecaSlukem #include <ufs/ufs/dinode.h>
574de05221Schristos #include <ufs/ffs/fs.h>
58c0892a30Sbouyer #include <ufs/ffs/ffs_extern.h>
594de05221Schristos
608e008989Sjoerg __dead static void usage(void);
612fa188aaSlukem static void getsblock(int, const char *, struct fs *);
6284fb1263Slukem static void fixinodes(int, struct fs *, struct disklabel *, int, long);
63664a532eSlukem static void statussig(int);
644de05221Schristos
6542614ed3Sfvdl int needswap, ino, imax, is_ufs2;
668e008989Sjoerg static time_t tstart;
67664a532eSlukem
684de05221Schristos static void
usage(void)6984fb1263Slukem usage(void)
704de05221Schristos {
718a986b2eScgd
72664a532eSlukem (void) fprintf(stderr,
73b635f565Sjmmv "usage: %s [-F] [-p] [-x <constant>] <special>\n",
748a986b2eScgd getprogname());
754de05221Schristos exit(1);
764de05221Schristos }
774de05221Schristos
784de05221Schristos
7942614ed3Sfvdl static const off_t sblock_try[] = SBLOCKSEARCH;
8042614ed3Sfvdl
8184fb1263Slukem /*
8284fb1263Slukem * getsblock():
834de05221Schristos * Return the superblock
844de05221Schristos */
854de05221Schristos static void
getsblock(int fd,const char * name,struct fs * fs)862fa188aaSlukem getsblock(int fd, const char *name, struct fs *fs)
874de05221Schristos {
8842614ed3Sfvdl int i;
894de05221Schristos
903d7fa497Sdsl for (i = 0; ; i++) {
913d7fa497Sdsl if (sblock_try[i] == -1)
923d7fa497Sdsl errx(1, "%s: can't find superblock", name);
933d7fa497Sdsl if (pread(fd, fs, SBLOCKSIZE, sblock_try[i]) != SBLOCKSIZE)
9442614ed3Sfvdl continue;
9542614ed3Sfvdl
9642614ed3Sfvdl switch(fs->fs_magic) {
9742614ed3Sfvdl case FS_UFS2_MAGIC:
98*87ba0e2aSchs case FS_UFS2EA_MAGIC:
9942614ed3Sfvdl is_ufs2 = 1;
10042614ed3Sfvdl /* FALLTHROUGH */
10142614ed3Sfvdl case FS_UFS1_MAGIC:
1023d7fa497Sdsl break;
10342614ed3Sfvdl case FS_UFS2_MAGIC_SWAPPED:
104*87ba0e2aSchs case FS_UFS2EA_MAGIC_SWAPPED:
10542614ed3Sfvdl is_ufs2 = 1;
10642614ed3Sfvdl /* FALLTHROUGH */
10742614ed3Sfvdl case FS_UFS1_MAGIC_SWAPPED:
108c0892a30Sbouyer needswap = 1;
1093d7fa497Sdsl ffs_sb_swap(fs, fs);
1103d7fa497Sdsl break;
11142614ed3Sfvdl default:
11242614ed3Sfvdl continue;
113029a64ccSross }
11442614ed3Sfvdl
1153d7fa497Sdsl if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2)
1163d7fa497Sdsl continue;
1173d7fa497Sdsl break;
1183d7fa497Sdsl }
1194de05221Schristos
1204de05221Schristos if (fs->fs_ncg < 1)
1212fa188aaSlukem errx(1, "%s: bad ncg in superblock", name);
1224de05221Schristos
12342614ed3Sfvdl if (fs->fs_sbsize > SBLOCKSIZE)
1242fa188aaSlukem errx(1, "%s: superblock too large", name);
1254de05221Schristos }
1264de05221Schristos
127664a532eSlukem
12884fb1263Slukem /*
12984fb1263Slukem * fixinodes():
1304de05221Schristos * Randomize the inode generation numbers
1314de05221Schristos */
1324de05221Schristos static void
fixinodes(int fd,struct fs * fs,struct disklabel * lab,int pflag,long xorval)13384fb1263Slukem fixinodes(int fd, struct fs *fs, struct disklabel *lab, int pflag, long xorval)
1344de05221Schristos {
135f1333577Sdholland int inopb = FFS_INOPB(fs);
13642614ed3Sfvdl int size;
137377b6539Sthorpej caddr_t buf;
1389a1b8a3bSlukem struct ufs1_dinode *dp1 = NULL;
1399a1b8a3bSlukem struct ufs2_dinode *dp2 = NULL;
140664a532eSlukem int i;
1414de05221Schristos
14242614ed3Sfvdl size = is_ufs2 ? inopb * sizeof (struct ufs2_dinode) :
14342614ed3Sfvdl inopb * sizeof (struct ufs1_dinode);
14442614ed3Sfvdl
145377b6539Sthorpej if ((buf = malloc(size)) == NULL)
1464de05221Schristos err(1, "Out of memory");
1474de05221Schristos
14842614ed3Sfvdl if (is_ufs2)
14942614ed3Sfvdl dp2 = (struct ufs2_dinode *)buf;
15042614ed3Sfvdl else
15142614ed3Sfvdl dp1 = (struct ufs1_dinode *)buf;
15242614ed3Sfvdl
1534de05221Schristos for (ino = 0, imax = fs->fs_ipg * fs->fs_ncg; ino < imax;) {
1548f6e4a4bSmycroft off_t sp;
1552737439dSdholland sp = (off_t) FFS_FSBTODB(fs, ino_to_fsba(fs, ino)) *
1568f6e4a4bSmycroft (off_t) lab->d_secsize;
1574de05221Schristos
1584de05221Schristos if (lseek(fd, sp, SEEK_SET) == (off_t) -1)
1594de05221Schristos err(1, "Seeking to inode %d failed", ino);
1604de05221Schristos
161377b6539Sthorpej if (read(fd, buf, size) != size)
1624de05221Schristos err(1, "Reading inodes %d+%d failed", ino, inopb);
1634de05221Schristos
164377b6539Sthorpej for (i = 0; i < inopb; i++) {
16542614ed3Sfvdl if (is_ufs2) {
1664de05221Schristos if (pflag)
16742614ed3Sfvdl printf("inode %10d gen 0x%08x\n",
16842614ed3Sfvdl ino,
16942614ed3Sfvdl ufs_rw32(dp2[i].di_gen, needswap));
1704de05221Schristos else
17142614ed3Sfvdl dp2[i].di_gen =
172e2c411ceSitojun ufs_rw32((arc4random() & INT32_MAX)^ xorval,
17384fb1263Slukem needswap);
17442614ed3Sfvdl } else {
17542614ed3Sfvdl if (pflag)
17642614ed3Sfvdl printf("inode %10d gen 0x%08x\n",
17742614ed3Sfvdl ino,
17842614ed3Sfvdl ufs_rw32(dp1[i].di_gen, needswap));
17942614ed3Sfvdl else
18042614ed3Sfvdl dp1[i].di_gen =
181e2c411ceSitojun ufs_rw32((arc4random() & INT32_MAX) ^ xorval,
18242614ed3Sfvdl needswap);
18342614ed3Sfvdl }
1844de05221Schristos if (++ino > imax)
1854de05221Schristos errx(1, "Exceeded number of inodes");
1864de05221Schristos }
1874de05221Schristos
1884de05221Schristos if (pflag)
1894de05221Schristos continue;
1904de05221Schristos
1914de05221Schristos if (lseek(fd, sp, SEEK_SET) == (off_t) -1)
1924de05221Schristos err(1, "Seeking to inode %d failed", ino);
1934de05221Schristos
194377b6539Sthorpej if (write(fd, buf, size) != size)
1954de05221Schristos err(1, "Writing inodes %d+%d failed", ino, inopb);
1964de05221Schristos }
197377b6539Sthorpej free(buf);
1984de05221Schristos }
1994de05221Schristos
200664a532eSlukem /*
201664a532eSlukem * statussig():
202664a532eSlukem * display current status
203664a532eSlukem */
2048e008989Sjoerg static void
statussig(int dummy)205664a532eSlukem statussig(int dummy)
206664a532eSlukem {
207664a532eSlukem char msgbuf[256];
208664a532eSlukem int len, deltat;
2093e4993b3Schristos time_t tnow;
210664a532eSlukem
211664a532eSlukem (void)time(&tnow);
212664a532eSlukem len = snprintf(msgbuf, sizeof(msgbuf),
213664a532eSlukem "fsirand: completed inode %d of %d (%3.2f%%)",
214664a532eSlukem ino, imax, (ino * 100.0) / imax);
215664a532eSlukem if (imax - ino) {
216664a532eSlukem deltat = tstart - tnow + (1.0 * (tnow - tstart)) / ino * imax;
217664a532eSlukem len += snprintf(msgbuf + len, sizeof(msgbuf) - len,
218664a532eSlukem ", finished in %d:%02d\n", deltat / 60, deltat % 60);
219664a532eSlukem } else {
220664a532eSlukem len += snprintf(msgbuf + len, sizeof(msgbuf) - len, "\n");
221664a532eSlukem }
222664a532eSlukem write(STDERR_FILENO, msgbuf, len);
223664a532eSlukem }
224664a532eSlukem
2254de05221Schristos int
main(int argc,char * argv[])22684fb1263Slukem main(int argc, char *argv[])
2274de05221Schristos {
2282fa188aaSlukem const char *special;
22942614ed3Sfvdl char buf[SBLOCKSIZE], device[MAXPATHLEN];
2304de05221Schristos struct fs *fs = (struct fs *) buf;
2314de05221Schristos struct disklabel lab;
2322fa188aaSlukem long xorval;
2334de05221Schristos char *ep;
2342fa188aaSlukem int fd, c, Fflag, pflag, openflags;
2354de05221Schristos
2362fa188aaSlukem xorval = 0;
237664a532eSlukem Fflag = pflag = 0;
2384de05221Schristos
239664a532eSlukem while ((c = getopt(argc, argv, "Fpx:")) != -1)
2404de05221Schristos switch (c) {
241664a532eSlukem case 'F':
242664a532eSlukem Fflag++;
243664a532eSlukem break;
2444de05221Schristos case 'p':
2454de05221Schristos pflag++;
2464de05221Schristos break;
2474de05221Schristos case 'x':
24885828b64Slukem errno = 0;
2494de05221Schristos xorval = strtol(optarg, &ep, 0);
2503474a69fSkleink if ((xorval == LONG_MIN || xorval == LONG_MAX) &&
2514de05221Schristos errno == ERANGE)
2524de05221Schristos err(1, "Out of range constant");
2534de05221Schristos if (*ep)
2544de05221Schristos errx(1, "Bad constant");
2554de05221Schristos break;
2564de05221Schristos default:
2574de05221Schristos usage();
2584de05221Schristos }
2594de05221Schristos
2604de05221Schristos argv += optind;
2614de05221Schristos argc -= optind;
2624de05221Schristos
2634de05221Schristos if (argc != 1)
2644de05221Schristos usage();
2654de05221Schristos
2662fa188aaSlukem special = argv[0];
2672fa188aaSlukem openflags = pflag ? O_RDONLY : O_RDWR;
2682fa188aaSlukem if (Fflag)
2692fa188aaSlukem fd = open(special, openflags);
2702fa188aaSlukem else {
2712fa188aaSlukem fd = opendisk(special, openflags, device, sizeof(device), 0);
2722fa188aaSlukem special = device;
2732fa188aaSlukem }
2742fa188aaSlukem if (fd == -1)
2752fa188aaSlukem err(1, "Cannot open `%s'", special);
2764de05221Schristos
277664a532eSlukem if (Fflag) {
278664a532eSlukem memset(&lab, 0, sizeof(lab));
279664a532eSlukem lab.d_secsize = DEV_BSIZE; /* XXX */
2802fa188aaSlukem } else {
2814de05221Schristos if (ioctl(fd, DIOCGDINFO, &lab) == -1)
2822fa188aaSlukem err(1, "%s: cannot get disklabel information", special);
2832fa188aaSlukem }
2844de05221Schristos
285664a532eSlukem time(&tstart);
286664a532eSlukem (void)signal(SIGINFO, statussig);
2872fa188aaSlukem getsblock(fd, special, fs);
2884de05221Schristos fixinodes(fd, fs, &lab, pflag, xorval);
2894de05221Schristos
2904de05221Schristos (void) close(fd);
2914de05221Schristos return 0;
2924de05221Schristos }
293