xref: /netbsd-src/sbin/fsirand/fsirand.c (revision 87ba0e2a319653af510fae24a6d2975d3589735b)
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