1*a7b9eedcSflorian /* $OpenBSD: fsirand.c,v 1.44 2024/05/09 08:35:40 florian Exp $ */
282982fb4Smillert
382982fb4Smillert /*
4bf198cc6Smillert * Copyright (c) 1997 Todd C. Miller <millert@openbsd.org>
582982fb4Smillert *
606f01696Smillert * Permission to use, copy, modify, and distribute this software for any
706f01696Smillert * purpose with or without fee is hereby granted, provided that the above
806f01696Smillert * copyright notice and this permission notice appear in all copies.
982982fb4Smillert *
10328f1f07Smillert * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11328f1f07Smillert * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12328f1f07Smillert * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13328f1f07Smillert * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14328f1f07Smillert * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15328f1f07Smillert * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16328f1f07Smillert * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1782982fb4Smillert */
1882982fb4Smillert
1978eb0b7eSderaadt #include <sys/param.h> /* DEV_BSIZE */
20c1084f3dSmillert #include <sys/disklabel.h>
21c1084f3dSmillert #include <sys/ioctl.h>
2291f4f7d8Sdlg #include <sys/dkio.h>
2331051779Smillert #include <sys/resource.h>
24c1084f3dSmillert #include <sys/time.h>
2582982fb4Smillert
2682982fb4Smillert #include <ufs/ffs/fs.h>
2782982fb4Smillert #include <ufs/ufs/dinode.h>
2882982fb4Smillert
2982982fb4Smillert #include <err.h>
3082982fb4Smillert #include <errno.h>
3182982fb4Smillert #include <fcntl.h>
3282982fb4Smillert #include <stdio.h>
3382982fb4Smillert #include <stdlib.h>
3482982fb4Smillert #include <string.h>
3582982fb4Smillert #include <unistd.h>
3682982fb4Smillert #include <util.h>
3782982fb4Smillert
38c72b5b24Smillert void usage(int);
39c72b5b24Smillert int fsirand(char *);
4082982fb4Smillert
4182982fb4Smillert extern char *__progname;
4282982fb4Smillert
43c1084f3dSmillert int printonly = 0, force = 0, ignorelabel = 0;
4474a56d56Smillert
450833e960Spedro /*
460833e960Spedro * Possible locations for the superblock.
470833e960Spedro */
480833e960Spedro static const int sbtry[] = SBLOCKSEARCH;
490833e960Spedro
5082982fb4Smillert int
main(int argc,char * argv[])51bc52e260Sderaadt main(int argc, char *argv[])
5282982fb4Smillert {
53c1084f3dSmillert int n, ex = 0;
5431051779Smillert struct rlimit rl;
5582982fb4Smillert
56c1084f3dSmillert while ((n = getopt(argc, argv, "bfp")) != -1) {
5782982fb4Smillert switch (n) {
58c1084f3dSmillert case 'b':
593579491dSderaadt ignorelabel = 1;
60c1084f3dSmillert break;
6182982fb4Smillert case 'p':
623579491dSderaadt printonly = 1;
6382982fb4Smillert break;
6482982fb4Smillert case 'f':
653579491dSderaadt force = 1;
6682982fb4Smillert break;
6782982fb4Smillert default:
6882982fb4Smillert usage(1);
6982982fb4Smillert }
7082982fb4Smillert }
7174a56d56Smillert if (argc - optind < 1)
7282982fb4Smillert usage(1);
7382982fb4Smillert
7438780ef0Smillert /* Increase our data size to the max */
7538780ef0Smillert if (getrlimit(RLIMIT_DATA, &rl) == 0) {
7631051779Smillert rl.rlim_cur = rl.rlim_max;
77df69c215Sderaadt if (setrlimit(RLIMIT_DATA, &rl) == -1)
7866c75fc7Smillert warn("Can't set resource limit to max data size");
7938780ef0Smillert } else
8038780ef0Smillert warn("Can't get resource limit for data size");
8131051779Smillert
8274a56d56Smillert for (n = optind; n < argc; n++) {
83c4059a45Smillert if (argc - optind != 1)
84c4059a45Smillert (void)puts(argv[n]);
85c1084f3dSmillert ex += fsirand(argv[n]);
8674a56d56Smillert if (n < argc - 1)
8774a56d56Smillert putchar('\n');
8874a56d56Smillert }
8974a56d56Smillert
90c1084f3dSmillert exit(ex);
9174a56d56Smillert }
9274a56d56Smillert
93c1084f3dSmillert int
fsirand(char * device)94bc52e260Sderaadt fsirand(char *device)
9574a56d56Smillert {
960833e960Spedro struct ufs1_dinode *dp1 = NULL;
970833e960Spedro struct ufs2_dinode *dp2 = NULL;
980833e960Spedro static char *inodebuf;
99d4f470b6Sderaadt size_t ibufsize, isize;
100a547488bSmillert struct fs *sblock, *tmpsblock;
101ea2f7659Sderaadt ino_t inumber;
1021abdbfdeSderaadt daddr_t sblockloc, dblk;
103c1084f3dSmillert char sbuf[SBSIZE], sbuftmp[SBSIZE];
104abbb3558Sotto int devfd, n, i;
105abbb3558Sotto u_int cg;
106d4f470b6Sderaadt char *devpath, *ib;
107c1084f3dSmillert u_int32_t bsize = DEV_BSIZE;
108c1084f3dSmillert struct disklabel label;
10974a56d56Smillert
11074a56d56Smillert if ((devfd = opendev(device, printonly ? O_RDONLY : O_RDWR,
111df69c215Sderaadt 0, &devpath)) == -1) {
112c1084f3dSmillert warn("Can't open %s", devpath);
113c1084f3dSmillert return (1);
114c1084f3dSmillert }
11574a56d56Smillert
116c1084f3dSmillert /* Get block size (usually 512) from disklabel if possible */
117c1084f3dSmillert if (!ignorelabel) {
118df69c215Sderaadt if (ioctl(devfd, DIOCGDINFO, &label) == -1)
119c1084f3dSmillert warn("Can't read disklabel, using sector size of %d",
120c1084f3dSmillert bsize);
121c1084f3dSmillert else
122c1084f3dSmillert bsize = label.d_secsize;
123c1084f3dSmillert }
124c1084f3dSmillert
1257f8d1e1eSderaadt if (pledge("stdio", NULL) == -1)
1267f8d1e1eSderaadt err(1, "pledge");
1277f8d1e1eSderaadt
128c1084f3dSmillert /* Read in master superblock */
12982982fb4Smillert (void)memset(&sbuf, 0, sizeof(sbuf));
13082982fb4Smillert sblock = (struct fs *)&sbuf;
1310833e960Spedro
1320833e960Spedro for (i = 0; sbtry[i] != -1; i++) {
1330833e960Spedro sblockloc = sbtry[i];
1340833e960Spedro
135a7ca0864Sguenther if (lseek(devfd, sblockloc, SEEK_SET) == -1) {
136a7ca0864Sguenther warn("Can't seek to superblock (%lld) on %s",
137a7ca0864Sguenther (long long)sblockloc, devpath);
138c1084f3dSmillert return (1);
139c1084f3dSmillert }
1400833e960Spedro
141a7ca0864Sguenther if ((n = read(devfd, sblock, SBSIZE)) != SBSIZE) {
142c1084f3dSmillert warnx("Can't read superblock on %s: %s", devpath,
14382982fb4Smillert (n < SBSIZE) ? "short read" : strerror(errno));
144c1084f3dSmillert return (1);
145c1084f3dSmillert }
14682982fb4Smillert
1470833e960Spedro /* Find a suitable superblock */
1480833e960Spedro if (sblock->fs_magic != FS_UFS1_MAGIC &&
1490833e960Spedro sblock->fs_magic != FS_UFS2_MAGIC)
1500833e960Spedro continue; /* Not a superblock */
1510833e960Spedro
152c348d7c6Sotto /*
153c348d7c6Sotto * Do not look for an FFS1 file system at SBLOCK_UFS2.
154c348d7c6Sotto * Doing so will find the wrong super-block for file
155c348d7c6Sotto * systems with 64k block size.
156c348d7c6Sotto */
157c348d7c6Sotto if (sblock->fs_magic == FS_UFS1_MAGIC &&
158c348d7c6Sotto sbtry[i] == SBLOCK_UFS2)
159c348d7c6Sotto continue;
160c348d7c6Sotto
1610833e960Spedro if (sblock->fs_magic == FS_UFS2_MAGIC &&
1620833e960Spedro sblock->fs_sblockloc != sbtry[i])
1630833e960Spedro continue; /* Not a superblock */
1640833e960Spedro
1650833e960Spedro break;
1660833e960Spedro }
1670833e960Spedro
1680833e960Spedro if (sbtry[i] == -1) {
1690833e960Spedro warnx("Cannot find file system superblock");
170c1084f3dSmillert return (1);
171c1084f3dSmillert }
1720833e960Spedro
1730833e960Spedro /* Simple sanity checks on the superblock */
174c1084f3dSmillert if (sblock->fs_sbsize > SBSIZE) {
175c1084f3dSmillert warnx("Superblock size is preposterous");
176c1084f3dSmillert return (1);
177c1084f3dSmillert }
1780833e960Spedro
179c1084f3dSmillert if (sblock->fs_postblformat == FS_42POSTBLFMT) {
180c1084f3dSmillert warnx("Filesystem format is too old, sorry");
181c1084f3dSmillert return (1);
182c1084f3dSmillert }
1830833e960Spedro
184c1084f3dSmillert if (!force && !printonly && sblock->fs_clean != FS_ISCLEAN) {
185c1084f3dSmillert warnx("Filesystem is not clean, fsck %s first.", devpath);
186c1084f3dSmillert return (1);
187c1084f3dSmillert }
18882982fb4Smillert
189c1084f3dSmillert /* Make sure backup superblocks are sane. */
190a547488bSmillert tmpsblock = (struct fs *)&sbuftmp;
191c1084f3dSmillert for (cg = 0; cg < sblock->fs_ncg; cg++) {
192c1084f3dSmillert dblk = fsbtodb(sblock, cgsblock(sblock, cg));
193df69c215Sderaadt if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) == -1) {
194a7ca0864Sguenther warn("Can't seek to %lld", (long long)dblk * bsize);
195c1084f3dSmillert return (1);
196a7ca0864Sguenther } else if ((n = read(devfd, tmpsblock, SBSIZE)) != SBSIZE) {
197c1084f3dSmillert warn("Can't read backup superblock %d on %s: %s",
198b64f3f39Smillert cg + 1, devpath, (n < SBSIZE) ? "short read"
199c1084f3dSmillert : strerror(errno));
200c1084f3dSmillert return (1);
201c1084f3dSmillert }
2020833e960Spedro if (tmpsblock->fs_magic != FS_UFS1_MAGIC &&
2030833e960Spedro tmpsblock->fs_magic != FS_UFS2_MAGIC) {
204c1084f3dSmillert warnx("Bad magic number in backup superblock %d on %s",
205c1084f3dSmillert cg + 1, devpath);
206c1084f3dSmillert return (1);
207c1084f3dSmillert }
208a547488bSmillert if (tmpsblock->fs_sbsize > SBSIZE) {
209c1084f3dSmillert warnx("Size of backup superblock %d on %s is preposterous",
210c1084f3dSmillert cg + 1, devpath);
211c1084f3dSmillert return (1);
212c1084f3dSmillert }
213c1084f3dSmillert }
214c1084f3dSmillert
215c1084f3dSmillert /* XXX - should really cap buffer at 512kb or so */
2160833e960Spedro if (sblock->fs_magic == FS_UFS1_MAGIC)
217d4f470b6Sderaadt isize = sizeof(struct ufs1_dinode);
2180833e960Spedro else
219d4f470b6Sderaadt isize = sizeof(struct ufs2_dinode);
2200612d09dSderaadt
221d4f470b6Sderaadt if ((ib = reallocarray(inodebuf, sblock->fs_ipg, isize)) == NULL)
222c322e0a2Smillert errx(1, "Can't allocate memory for inode buffer");
2230612d09dSderaadt inodebuf = ib;
224d4f470b6Sderaadt ibufsize = sblock->fs_ipg * isize;
225c322e0a2Smillert
226c1084f3dSmillert if (printonly && (sblock->fs_id[0] || sblock->fs_id[1])) {
227f6bd394bSderaadt if (sblock->fs_inodefmt >= FS_44INODEFMT && sblock->fs_id[0]) {
228f6bd394bSderaadt time_t t = sblock->fs_id[0]; /* XXX 2038 */
229*a7b9eedcSflorian char *ct = ctime(&t);
230*a7b9eedcSflorian if (ct)
231c1084f3dSmillert (void)printf("%s was randomized on %s", devpath,
232*a7b9eedcSflorian ct);
233*a7b9eedcSflorian else
234*a7b9eedcSflorian (void)printf("%s was randomized on %lld\n",
235*a7b9eedcSflorian devpath, t);
236f6bd394bSderaadt }
237c1084f3dSmillert (void)printf("fsid: %x %x\n", sblock->fs_id[0],
238c1084f3dSmillert sblock->fs_id[1]);
239c1084f3dSmillert }
240c1084f3dSmillert
241c1084f3dSmillert /* Randomize fs_id unless old 4.2BSD filesystem */
242c1084f3dSmillert if ((sblock->fs_inodefmt >= FS_44INODEFMT) && !printonly) {
243c1084f3dSmillert /* Randomize fs_id and write out new sblock and backups */
244c1084f3dSmillert sblock->fs_id[0] = (u_int32_t)time(NULL);
245c1084f3dSmillert sblock->fs_id[1] = arc4random();
246c1084f3dSmillert
247a7ca0864Sguenther if (lseek(devfd, SBOFF, SEEK_SET) == -1) {
248a7ca0864Sguenther warn("Can't seek to superblock (%lld) on %s",
249a7ca0864Sguenther (long long)SBOFF, devpath);
250c1084f3dSmillert return (1);
251c1084f3dSmillert }
252a7ca0864Sguenther if ((n = write(devfd, sblock, SBSIZE)) != SBSIZE) {
253b64f3f39Smillert warn("Can't write superblock on %s: %s", devpath,
254c1084f3dSmillert (n < SBSIZE) ? "short write" : strerror(errno));
255c1084f3dSmillert return (1);
256c1084f3dSmillert }
257c1084f3dSmillert }
258c1084f3dSmillert
259c1084f3dSmillert /* For each cylinder group, randomize inodes and update backup sblock */
260c1084f3dSmillert for (cg = 0, inumber = 0; cg < sblock->fs_ncg; cg++) {
261c1084f3dSmillert /* Update superblock if appropriate */
262c1084f3dSmillert if ((sblock->fs_inodefmt >= FS_44INODEFMT) && !printonly) {
263c1084f3dSmillert dblk = fsbtodb(sblock, cgsblock(sblock, cg));
264a7ca0864Sguenther if (lseek(devfd, (off_t)dblk * bsize,
265df69c215Sderaadt SEEK_SET) == -1) {
266a7ca0864Sguenther warn("Can't seek to %lld",
267a7ca0864Sguenther (long long)dblk * bsize);
268c1084f3dSmillert return (1);
269a7ca0864Sguenther } else if ((n = write(devfd, sblock, SBSIZE)) !=
270bc52e260Sderaadt SBSIZE) {
271c1084f3dSmillert warn("Can't read backup superblock %d on %s: %s",
272c1084f3dSmillert cg + 1, devpath, (n < SBSIZE) ? "short write"
273c1084f3dSmillert : strerror(errno));
274c1084f3dSmillert return (1);
275c1084f3dSmillert }
276c1084f3dSmillert }
277c1084f3dSmillert
27874a56d56Smillert /* Read in inodes, then print or randomize generation nums */
27974a56d56Smillert dblk = fsbtodb(sblock, ino_to_fsba(sblock, inumber));
280df69c215Sderaadt if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) == -1) {
281a7ca0864Sguenther warn("Can't seek to %lld", (long long)dblk * bsize);
282c1084f3dSmillert return (1);
28374a56d56Smillert } else if ((n = read(devfd, inodebuf, ibufsize)) != ibufsize) {
28474a56d56Smillert warnx("Can't read inodes: %s",
28574a56d56Smillert (n < ibufsize) ? "short read" : strerror(errno));
286c1084f3dSmillert return (1);
28774a56d56Smillert }
28874a56d56Smillert
28974a56d56Smillert for (n = 0; n < sblock->fs_ipg; n++, inumber++) {
2900833e960Spedro if (sblock->fs_magic == FS_UFS1_MAGIC)
2910833e960Spedro dp1 = &((struct ufs1_dinode *)inodebuf)[n];
2920833e960Spedro else
2930833e960Spedro dp2 = &((struct ufs2_dinode *)inodebuf)[n];
294c322e0a2Smillert if (inumber >= ROOTINO) {
295c322e0a2Smillert if (printonly)
2961e74350aSderaadt (void)printf("ino %llu gen %x\n",
2971e74350aSderaadt (unsigned long long)inumber,
2980833e960Spedro sblock->fs_magic == FS_UFS1_MAGIC ?
2990833e960Spedro dp1->di_gen : dp2->di_gen);
3000833e960Spedro else if (sblock->fs_magic == FS_UFS1_MAGIC)
3010833e960Spedro dp1->di_gen = arc4random();
302c322e0a2Smillert else
3030833e960Spedro dp2->di_gen = arc4random();
304c322e0a2Smillert }
30574a56d56Smillert }
30674a56d56Smillert
30774a56d56Smillert /* Write out modified inodes */
308c322e0a2Smillert if (!printonly) {
309df69c215Sderaadt if (lseek(devfd, (off_t)dblk * bsize, SEEK_SET) == -1) {
310a7ca0864Sguenther warn("Can't seek to %lld",
311a7ca0864Sguenther (long long)dblk * bsize);
312c1084f3dSmillert return (1);
31374a56d56Smillert } else if ((n = write(devfd, inodebuf, ibufsize)) !=
31474a56d56Smillert ibufsize) {
315c1084f3dSmillert warnx("Can't write inodes: %s",
31674a56d56Smillert (n != ibufsize) ? "short write" :
317c322e0a2Smillert strerror(errno));
318c1084f3dSmillert return (1);
319c322e0a2Smillert }
320c322e0a2Smillert }
32174a56d56Smillert }
32274a56d56Smillert (void)close(devfd);
323c1084f3dSmillert
324c1084f3dSmillert return(0);
325c322e0a2Smillert }
326c322e0a2Smillert
327c322e0a2Smillert void
usage(int ex)328bc52e260Sderaadt usage(int ex)
32982982fb4Smillert {
3302d50a4f4Sjmc (void)fprintf(stderr, "usage: %s [-bfp] special ...\n",
33174a56d56Smillert __progname);
33282982fb4Smillert exit(ex);
33382982fb4Smillert }
334