1/*
2 * This program, created 2002-10-03 by Garrett A. Wollman
3 * <wollman@FreeBSD.org>, is in the public domain.  Use at your own risk.
4 *
5 * $FreeBSD$
6 */
7
8#ifdef __FreeBSD__
9#include <sys/param.h>
10
11#include <ufs/ufs/dinode.h>
12#include <ufs/ffs/fs.h>
13#else
14#include "mini_ufs.h"
15#endif
16
17#include <err.h>
18#include <fcntl.h>
19#include <inttypes.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24
25static union {
26	char buf[SBLOCKSIZE];
27	struct fs sblock;
28} u;
29
30int
31main(int argc, char **argv)
32{
33	off_t end, last1, last2;
34	size_t len;
35	ssize_t justread;
36	int fd;
37	char *ch;
38	char c;
39	intmax_t offset;
40
41	offset = 0;
42	while ((c = getopt(argc, argv, "o:")) != -1) {
43		switch (c) {
44		case 'o':
45			if (optarg[0] == '\0')
46				errx(1, "usage");
47			offset = strtoimax(optarg, &ch, 10);
48			if (*ch != '\0' || offset < 0)
49				errx(1, "usage");
50			offset -= offset % DEV_BSIZE;
51			break;
52
53		default:
54			errx(1, "usage");
55		}
56	}
57	argc -= optind;
58	argv += optind;
59
60	if (argc != 1)
61		errx(1, "usage");
62
63	fd = open(argv[0], O_RDONLY, 0);
64	if (fd < 0)
65		err(1, "%s", argv[0]);
66
67	if (offset != 0) {
68		end = lseek(fd, offset, SEEK_SET);
69		if (end == -1)
70			err(1, "%s", argv[0]);
71	} else {
72		end = 0;
73	}
74	len = 0;
75	last1 = last2 = -1;
76
77	while (1) {
78		justread = read(fd, &u.buf[len], DEV_BSIZE);
79		if (justread != DEV_BSIZE) {
80			if (justread == 0) {
81				printf("reached end-of-file at %jd\n",
82				       (intmax_t)end);
83				exit (0);
84			}
85			if (justread < 0)
86				err(1, "read");
87			errx(1, "short read %jd (wanted %d) at %jd",
88			     (intmax_t)justread, DEV_BSIZE, (intmax_t)end);
89		}
90		len += DEV_BSIZE;
91		end += DEV_BSIZE;
92		if (len >= sizeof(struct fs)) {
93			offset = end - len;
94
95			if (u.sblock.fs_magic == FS_UFS1_MAGIC) {
96				intmax_t fsbegin = offset - SBLOCK_UFS1;
97				printf("Found UFS1 superblock at offset %jd, "
98				       "block %jd\n", offset,
99				       offset / DEV_BSIZE);
100				printf("Filesystem might begin at offset %jd, "
101				       "block %jd\n", fsbegin,
102				       fsbegin / DEV_BSIZE);
103				if (last1 >= 0) {
104					printf("%jd blocks from last guess\n",
105					       fsbegin / DEV_BSIZE - last1);
106				}
107				last1 = fsbegin / DEV_BSIZE;
108				len -= DEV_BSIZE;
109				memmove(u.buf, &u.buf[DEV_BSIZE], len);
110			} else if (u.sblock.fs_magic == FS_UFS2_MAGIC) {
111				intmax_t fsbegin = offset - SBLOCK_UFS2;
112				printf("Found UFS2 superblock at offset %jd, "
113				       "block %jd\n", offset,
114				       offset / DEV_BSIZE);
115				printf("Filesystem might begin at offset %jd, "
116				       "block %jd\n", fsbegin,
117				       fsbegin / DEV_BSIZE);
118				if (last2 >= 0) {
119					printf("%jd blocks from last guess\n",
120					       fsbegin / DEV_BSIZE - last2);
121				}
122				last2 = fsbegin / DEV_BSIZE;
123				len -= DEV_BSIZE;
124				memmove(u.buf, &u.buf[DEV_BSIZE], len);
125			}
126		}
127		if (len >= SBLOCKSIZE) {
128			memmove(u.buf, &u.buf[DEV_BSIZE],
129				SBLOCKSIZE - DEV_BSIZE);
130			len -= DEV_BSIZE;
131		}
132	}
133}
134