1104442Swollman/*
2104442Swollman * This program, created 2002-10-03 by Garrett A. Wollman
3104442Swollman * <wollman@FreeBSD.org>, is in the public domain.  Use at your own risk.
4104442Swollman *
5104442Swollman * $FreeBSD$
6104442Swollman */
7104442Swollman
8158297Ssobomax#ifdef __FreeBSD__
9104442Swollman#include <sys/param.h>
10104442Swollman
11104442Swollman#include <ufs/ufs/dinode.h>
12104442Swollman#include <ufs/ffs/fs.h>
13158297Ssobomax#else
14158297Ssobomax#include "mini_ufs.h"
15158297Ssobomax#endif
16104442Swollman
17104442Swollman#include <err.h>
18104442Swollman#include <fcntl.h>
19104442Swollman#include <inttypes.h>
20104442Swollman#include <stdio.h>
21104442Swollman#include <stdlib.h>
22104442Swollman#include <string.h>
23104442Swollman#include <unistd.h>
24104442Swollman
25104442Swollmanstatic union {
26104442Swollman	char buf[SBLOCKSIZE];
27104442Swollman	struct fs sblock;
28104442Swollman} u;
29104442Swollman
30104442Swollmanint
31104442Swollmanmain(int argc, char **argv)
32104442Swollman{
33158526Ssobomax	off_t end, last1, last2;
34104442Swollman	size_t len;
35104442Swollman	ssize_t justread;
36104442Swollman	int fd;
37158526Ssobomax	char *ch;
38158526Ssobomax	char c;
39158526Ssobomax	intmax_t offset;
40104442Swollman
41162720Sru	offset = 0;
42158526Ssobomax	while ((c = getopt(argc, argv, "o:")) != -1) {
43158526Ssobomax		switch (c) {
44158526Ssobomax		case 'o':
45158526Ssobomax			if (optarg[0] == '\0')
46158526Ssobomax				errx(1, "usage");
47158526Ssobomax			offset = strtoimax(optarg, &ch, 10);
48158526Ssobomax			if (*ch != '\0' || offset < 0)
49158526Ssobomax				errx(1, "usage");
50158526Ssobomax			offset -= offset % DEV_BSIZE;
51158526Ssobomax			break;
52158526Ssobomax
53158526Ssobomax		default:
54158526Ssobomax			errx(1, "usage");
55158526Ssobomax		}
56158526Ssobomax	}
57158526Ssobomax	argc -= optind;
58158526Ssobomax	argv += optind;
59158526Ssobomax
60158526Ssobomax	if (argc != 1)
61104442Swollman		errx(1, "usage");
62104442Swollman
63158526Ssobomax	fd = open(argv[0], O_RDONLY, 0);
64104442Swollman	if (fd < 0)
65158526Ssobomax		err(1, "%s", argv[0]);
66104442Swollman
67158526Ssobomax	if (offset != 0) {
68158526Ssobomax		end = lseek(fd, offset, SEEK_SET);
69158526Ssobomax		if (end == -1)
70158526Ssobomax			err(1, "%s", argv[0]);
71158526Ssobomax	} else {
72158526Ssobomax		end = 0;
73158526Ssobomax	}
74158526Ssobomax	len = 0;
75158526Ssobomax	last1 = last2 = -1;
76158526Ssobomax
77104442Swollman	while (1) {
78104442Swollman		justread = read(fd, &u.buf[len], DEV_BSIZE);
79104442Swollman		if (justread != DEV_BSIZE) {
80104442Swollman			if (justread == 0) {
81104442Swollman				printf("reached end-of-file at %jd\n",
82104442Swollman				       (intmax_t)end);
83104442Swollman				exit (0);
84104442Swollman			}
85104442Swollman			if (justread < 0)
86104442Swollman				err(1, "read");
87104442Swollman			errx(1, "short read %jd (wanted %d) at %jd",
88104442Swollman			     (intmax_t)justread, DEV_BSIZE, (intmax_t)end);
89104442Swollman		}
90104442Swollman		len += DEV_BSIZE;
91104442Swollman		end += DEV_BSIZE;
92104442Swollman		if (len >= sizeof(struct fs)) {
93158526Ssobomax			offset = end - len;
94104442Swollman
95104442Swollman			if (u.sblock.fs_magic == FS_UFS1_MAGIC) {
96104442Swollman				intmax_t fsbegin = offset - SBLOCK_UFS1;
97104442Swollman				printf("Found UFS1 superblock at offset %jd, "
98104442Swollman				       "block %jd\n", offset,
99104442Swollman				       offset / DEV_BSIZE);
100104442Swollman				printf("Filesystem might begin at offset %jd, "
101104442Swollman				       "block %jd\n", fsbegin,
102104442Swollman				       fsbegin / DEV_BSIZE);
103158526Ssobomax				if (last1 >= 0) {
104104442Swollman					printf("%jd blocks from last guess\n",
105158526Ssobomax					       fsbegin / DEV_BSIZE - last1);
106104442Swollman				}
107158526Ssobomax				last1 = fsbegin / DEV_BSIZE;
108158526Ssobomax				len -= DEV_BSIZE;
109158526Ssobomax				memmove(u.buf, &u.buf[DEV_BSIZE], len);
110104442Swollman			} else if (u.sblock.fs_magic == FS_UFS2_MAGIC) {
111158297Ssobomax				intmax_t fsbegin = offset - SBLOCK_UFS2;
112104442Swollman				printf("Found UFS2 superblock at offset %jd, "
113104442Swollman				       "block %jd\n", offset,
114104442Swollman				       offset / DEV_BSIZE);
115104442Swollman				printf("Filesystem might begin at offset %jd, "
116104442Swollman				       "block %jd\n", fsbegin,
117104442Swollman				       fsbegin / DEV_BSIZE);
118158526Ssobomax				if (last2 >= 0) {
119104442Swollman					printf("%jd blocks from last guess\n",
120158526Ssobomax					       fsbegin / DEV_BSIZE - last2);
121104442Swollman				}
122158526Ssobomax				last2 = fsbegin / DEV_BSIZE;
123158526Ssobomax				len -= DEV_BSIZE;
124158526Ssobomax				memmove(u.buf, &u.buf[DEV_BSIZE], len);
125104442Swollman			}
126104442Swollman		}
127104442Swollman		if (len >= SBLOCKSIZE) {
128104442Swollman			memmove(u.buf, &u.buf[DEV_BSIZE],
129104442Swollman				SBLOCKSIZE - DEV_BSIZE);
130104442Swollman			len -= DEV_BSIZE;
131104442Swollman		}
132104442Swollman	}
133104442Swollman}
134