1 /*-
2  * Copyright (c) 2010 Doug Rabson
3  * Copyright (c) 2011 Andriy Gapon
4  * Copyright (c) 2011 Pawel Jakub Dawidek <pawel@dawidek.net>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 /* $FreeBSD$ */
29 
30 #include <sys/param.h>
31 #include <sys/disk.h>
32 #include <sys/queue.h>
33 #include <sys/stat.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <md5.h>
38 #include <stdint.h>
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdarg.h>
42 #include <stddef.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 
46 #define NBBY 8
47 
48 int
49 pager_output(const char *line)
50 {
51 
52 	fprintf(stderr, "%s", line);
53 	return (0);
54 }
55 
56 uint64_t
57 ldi_get_size(void *priv)
58 {
59 	struct stat sb;
60 	int fd;
61 
62 	fd = *(int *)priv;
63 	if (fstat(fd, &sb) != 0)
64 		return (0);
65 	if (S_ISCHR(sb.st_mode) && ioctl(fd, DIOCGMEDIASIZE, &sb.st_size) != 0)
66 		return (0);
67 	return (sb.st_size);
68 }
69 
70 #define ZFS_TEST
71 #define	printf(...)	 fprintf(stderr, __VA_ARGS__)
72 #include "libzfs.h"
73 #include "zfsimpl.c"
74 #undef printf
75 
76 static int
77 vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes)
78 {
79 	int fd = *(int *)priv;
80 
81 	if (pread(fd, buf, bytes, off) != bytes)
82 		return (-1);
83 	return (0);
84 }
85 
86 static int
87 zfs_read(spa_t *spa, dnode_phys_t *dn, void *buf, size_t size, off_t off)
88 {
89 	const znode_phys_t *zp = (const znode_phys_t *) dn->dn_bonus;
90 	size_t n;
91 	int rc;
92 
93 	n = size;
94 	if (off + n > zp->zp_size)
95 		n = zp->zp_size - off;
96 
97 	rc = dnode_read(spa, dn, off, buf, n);
98 	if (rc != 0)
99 		return (-rc);
100 
101 	return (n);
102 }
103 
104 int
105 main(int argc, char** argv)
106 {
107 	char buf[512], hash[33];
108 	MD5_CTX ctx;
109 	struct stat sb;
110 	struct zfsmount zfsmnt;
111 	dnode_phys_t dn;
112 #if 0
113 	uint64_t rootobj;
114 #endif
115 	spa_t *spa;
116 	off_t off;
117 	ssize_t n;
118 	int i, failures, *fd;
119 
120 	zfs_init();
121 	if (argc == 1) {
122 		static char *av[] = {
123 			"zfsboottest",
124 			"/dev/gpt/system0",
125 			"/dev/gpt/system1",
126 			"-",
127 			"/boot/loader",
128 			"/boot/support.4th",
129 			"/boot/kernel/kernel",
130 			NULL,
131 		};
132 		argc = sizeof(av) / sizeof(av[0]) - 1;
133 		argv = av;
134 	}
135 	for (i = 1; i < argc; i++) {
136 		if (strcmp(argv[i], "-") == 0)
137 			break;
138 	}
139 	fd = malloc(sizeof(fd[0]) * (i - 1));
140 	if (fd == NULL)
141 		errx(1, "Unable to allocate memory.");
142 	for (i = 1; i < argc; i++) {
143 		if (strcmp(argv[i], "-") == 0)
144 			break;
145 		fd[i - 1] = open(argv[i], O_RDONLY);
146 		if (fd[i - 1] == -1) {
147 			warn("open(%s) failed", argv[i]);
148 			continue;
149 		}
150 		if (vdev_probe(vdev_read, &fd[i - 1], NULL) != 0) {
151 			warnx("vdev_probe(%s) failed", argv[i]);
152 			close(fd[i - 1]);
153 		}
154 	}
155 
156 	STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
157 		if (zfs_spa_init(spa)) {
158 			fprintf(stderr, "can't init pool %s\n", spa->spa_name);
159 			exit(1);
160 		}
161 	}
162 
163 	spa_all_status();
164 
165 	spa = STAILQ_FIRST(&zfs_pools);
166 	if (spa == NULL) {
167 		fprintf(stderr, "no pools\n");
168 		exit(1);
169 	}
170 
171 #if 0
172 	uint64_t rootobj;
173 	if (zfs_get_root(spa, &rootobj)) {
174 		fprintf(stderr, "can't get root\n");
175 		exit(1);
176 	}
177 
178 	if (zfs_mount(spa, rootobj, &zfsmnt)) {
179 #else
180 	if (zfs_mount(spa, 0, &zfsmnt)) {
181 		fprintf(stderr, "can't mount\n");
182 		exit(1);
183 #endif
184 	}
185 
186 	printf("\n");
187 	for (++i, failures = 0; i < argc; i++) {
188 		if (zfs_lookup(&zfsmnt, argv[i], &dn)) {
189 			fprintf(stderr, "%s: can't lookup\n", argv[i]);
190 			failures++;
191 			continue;
192 		}
193 
194 		if (zfs_dnode_stat(spa, &dn, &sb)) {
195 			fprintf(stderr, "%s: can't stat\n", argv[i]);
196 			failures++;
197 			continue;
198 		}
199 
200 		off = 0;
201 		MD5Init(&ctx);
202 		do {
203 			n = sb.st_size - off;
204 			n = n > sizeof(buf) ? sizeof(buf) : n;
205 			n = zfs_read(spa, &dn, buf, n, off);
206 			if (n < 0) {
207 				fprintf(stderr, "%s: zfs_read failed\n",
208 				    argv[i]);
209 				failures++;
210 				break;
211 			}
212 			MD5Update(&ctx, buf, n);
213 			off += n;
214 		} while (off < sb.st_size);
215 		if (off < sb.st_size)
216 			continue;
217 		MD5End(&ctx, hash);
218 		printf("%s %s\n", hash, argv[i]);
219 	}
220 
221 	return (failures == 0 ? 0 : 1);
222 }
223