1/*	$OpenBSD: fsirand.c,v 1.9 1997/02/28 00:46:33 millert Exp $	*/
2
3/*-
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by Todd C. Miller.
20 * 4. The name of the author may not be used to endorse or promote products
21 *    derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
26 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <sys/param.h>
36#include <sys/resource.h>
37
38#include <ufs/ufs/dinode.h>
39#include <ufs/ffs/fs.h>
40
41#include <err.h>
42#include <errno.h>
43#include <fcntl.h>
44#include <libufs.h>
45#include <stdio.h>
46#include <stdint.h>
47#include <stdlib.h>
48#include <string.h>
49#include <time.h>
50#include <unistd.h>
51
52static void usage(void) __dead2;
53int fsirand(char *);
54
55static int printonly = 0, force = 0, ignorelabel = 0;
56
57int
58main(int argc, char *argv[])
59{
60	int n, ex = 0;
61	struct rlimit rl;
62
63	while ((n = getopt(argc, argv, "bfp")) != -1) {
64		switch (n) {
65		case 'b':
66			ignorelabel++;
67			break;
68		case 'p':
69			printonly++;
70			break;
71		case 'f':
72			force++;
73			break;
74		default:
75			usage();
76		}
77	}
78	if (argc - optind < 1)
79		usage();
80
81	/* Increase our data size to the max */
82	if (getrlimit(RLIMIT_DATA, &rl) == 0) {
83		rl.rlim_cur = rl.rlim_max;
84		if (setrlimit(RLIMIT_DATA, &rl) < 0)
85			warn("can't get resource limit to max data size");
86	} else
87		warn("can't get resource limit for data size");
88
89	for (n = optind; n < argc; n++) {
90		if (argc - optind != 1)
91			(void)puts(argv[n]);
92		ex += fsirand(argv[n]);
93		if (n < argc - 1)
94			putchar('\n');
95	}
96
97	exit(ex);
98}
99
100int
101fsirand(char *device)
102{
103	struct ufs1_dinode *dp1;
104	struct ufs2_dinode *dp2;
105	caddr_t inodebuf;
106	ssize_t ibufsize;
107	struct fs *sblock;
108	ino_t inumber;
109	ufs2_daddr_t dblk;
110	int devfd, n, cg;
111	u_int32_t bsize = DEV_BSIZE;
112
113	if ((devfd = open(device, printonly ? O_RDONLY : O_RDWR)) < 0) {
114		warn("can't open %s", device);
115		return (1);
116	}
117
118	dp1 = NULL;
119	dp2 = NULL;
120
121	/* Read in master superblock */
122	if ((errno = sbget(devfd, &sblock, UFS_STDSB, UFS_NOCSUM)) != 0) {
123		switch (errno) {
124		case ENOENT:
125			warnx("Cannot find file system superblock");
126			return (1);
127		default:
128			warn("Unable to read file system superblock");
129			return (1);
130		}
131	}
132	/*
133	 * Check for unclean filesystem.
134	 */
135	if (sblock->fs_clean == 0 ||
136	    (sblock->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) != 0)
137		errx(1, "%s is not clean - run fsck.\n", device);
138
139	if (sblock->fs_magic == FS_UFS1_MAGIC &&
140	    sblock->fs_old_inodefmt < FS_44INODEFMT) {
141		warnx("file system format is too old, sorry");
142		return (1);
143	}
144	if (!force && !printonly && sblock->fs_clean != 1) {
145		warnx("file system is not clean, fsck %s first", device);
146		return (1);
147	}
148
149	/* XXX - should really cap buffer at 512kb or so */
150	if (sblock->fs_magic == FS_UFS1_MAGIC)
151		ibufsize = sizeof(struct ufs1_dinode) * sblock->fs_ipg;
152	else
153		ibufsize = sizeof(struct ufs2_dinode) * sblock->fs_ipg;
154	if ((inodebuf = malloc(ibufsize)) == NULL)
155		errx(1, "can't allocate memory for inode buffer");
156
157	if (printonly && (sblock->fs_id[0] || sblock->fs_id[1])) {
158		if (sblock->fs_id[0])
159			(void)printf("%s was randomized on %s", device,
160			    ctime((void *)&(sblock->fs_id[0])));
161		(void)printf("fsid: %x %x\n", sblock->fs_id[0],
162			    sblock->fs_id[1]);
163	}
164
165	/* Randomize fs_id unless old 4.2BSD file system */
166	if (!printonly) {
167		/* Randomize fs_id and write out new sblock and backups */
168		sblock->fs_id[0] = (u_int32_t)time(NULL);
169		sblock->fs_id[1] = arc4random();
170		if (sbput(devfd, sblock, sblock->fs_ncg) != 0) {
171			warn("could not write updated superblock");
172			return (1);
173		}
174	}
175
176	/* For each cylinder group, randomize inodes and update backup sblock */
177	for (cg = 0, inumber = UFS_ROOTINO; cg < (int)sblock->fs_ncg; cg++) {
178		/* Read in inodes, then print or randomize generation nums */
179		dblk = fsbtodb(sblock, ino_to_fsba(sblock, inumber));
180		if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) {
181			warn("can't seek to %jd", (intmax_t)dblk * bsize);
182			return (1);
183		} else if ((n = read(devfd, inodebuf, ibufsize)) != ibufsize) {
184			warnx("can't read inodes: %s",
185			     (n < ibufsize) ? "short read" : strerror(errno));
186			return (1);
187		}
188
189		dp1 = (struct ufs1_dinode *)(void *)inodebuf;
190		dp2 = (struct ufs2_dinode *)(void *)inodebuf;
191		for (n = cg > 0 ? 0 : UFS_ROOTINO;
192		     n < (int)sblock->fs_ipg;
193		     n++, inumber++) {
194			if (printonly) {
195				(void)printf("ino %ju gen %08x\n",
196				    (uintmax_t)inumber,
197				    sblock->fs_magic == FS_UFS1_MAGIC ?
198				    dp1->di_gen : dp2->di_gen);
199			} else if (sblock->fs_magic == FS_UFS1_MAGIC) {
200				dp1->di_gen = arc4random();
201				dp1++;
202			} else {
203				dp2->di_gen = arc4random();
204				ffs_update_dinode_ckhash(sblock, dp2);
205				dp2++;
206			}
207		}
208
209		/* Write out modified inodes */
210		if (!printonly) {
211			if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) < 0) {
212				warn("can't seek to %jd",
213				    (intmax_t)dblk * bsize);
214				return (1);
215			} else if ((n = write(devfd, inodebuf, ibufsize)) !=
216				 ibufsize) {
217				warnx("can't write inodes: %s",
218				     (n != ibufsize) ? "short write" :
219				     strerror(errno));
220				return (1);
221			}
222		}
223	}
224	(void)close(devfd);
225
226	return(0);
227}
228
229static void
230usage(void)
231{
232	(void)fprintf(stderr,
233		"usage: fsirand [-b] [-f] [-p] special [special ...]\n");
234	exit(1);
235}
236