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 29#include <sys/param.h> 30#include <sys/disk.h> 31#include <sys/queue.h> 32#include <sys/stat.h> 33#include <err.h> 34#include <errno.h> 35#include <fcntl.h> 36#include <md5.h> 37#include <stdint.h> 38#include <stdio.h> 39#include <string.h> 40#include <stdarg.h> 41#include <stddef.h> 42#include <stdlib.h> 43#include <unistd.h> 44 45#define NBBY 8 46 47int 48pager_output(const char *line) 49{ 50 51 fprintf(stderr, "%s", line); 52 return (0); 53} 54 55uint64_t 56ldi_get_size(void *priv) 57{ 58 struct stat sb; 59 int fd; 60 61 fd = *(int *)priv; 62 if (fstat(fd, &sb) != 0) 63 return (0); 64 if (S_ISCHR(sb.st_mode) && ioctl(fd, DIOCGMEDIASIZE, &sb.st_size) != 0) 65 return (0); 66 return (sb.st_size); 67} 68 69#define ZFS_TEST 70#define printf(...) fprintf(stderr, __VA_ARGS__) 71#include "libzfs.h" 72#include "zfsimpl.c" 73#undef printf 74 75static int 76vdev_read(vdev_t *vdev, void *priv, off_t off, void *buf, size_t bytes) 77{ 78 int fd = *(int *)priv; 79 80 if (pread(fd, buf, bytes, off) != bytes) 81 return (-1); 82 return (0); 83} 84 85static int 86zfs_read(spa_t *spa, dnode_phys_t *dn, void *buf, size_t size, off_t off) 87{ 88 const znode_phys_t *zp = (const znode_phys_t *) dn->dn_bonus; 89 size_t n; 90 int rc; 91 92 n = size; 93 if (off + n > zp->zp_size) 94 n = zp->zp_size - off; 95 96 rc = dnode_read(spa, dn, off, buf, n); 97 if (rc != 0) 98 return (-rc); 99 100 return (n); 101} 102 103int 104main(int argc, char** argv) 105{ 106 char buf[512], hash[33]; 107 MD5_CTX ctx; 108 struct stat sb; 109 struct zfsmount zfsmnt; 110 dnode_phys_t dn; 111#if 0 112 uint64_t rootobj; 113#endif 114 spa_t *spa; 115 off_t off; 116 ssize_t n; 117 int i, failures, *fd; 118 119 zfs_init(); 120 if (argc == 1) { 121 static char *av[] = { 122 "zfsboottest", 123 "/dev/gpt/system0", 124 "/dev/gpt/system1", 125 "-", 126 "/boot/loader", 127 "/boot/support.4th", 128 "/boot/kernel/kernel", 129 NULL, 130 }; 131 argc = sizeof(av) / sizeof(av[0]) - 1; 132 argv = av; 133 } 134 for (i = 1; i < argc; i++) { 135 if (strcmp(argv[i], "-") == 0) 136 break; 137 } 138 fd = malloc(sizeof(fd[0]) * (i - 1)); 139 if (fd == NULL) 140 errx(1, "Unable to allocate memory."); 141 for (i = 1; i < argc; i++) { 142 if (strcmp(argv[i], "-") == 0) 143 break; 144 fd[i - 1] = open(argv[i], O_RDONLY); 145 if (fd[i - 1] == -1) { 146 warn("open(%s) failed", argv[i]); 147 continue; 148 } 149 if (vdev_probe(vdev_read, NULL, &fd[i - 1], NULL) != 0) { 150 warnx("vdev_probe(%s) failed", argv[i]); 151 close(fd[i - 1]); 152 } 153 } 154 155 STAILQ_FOREACH(spa, &zfs_pools, spa_link) { 156 if (zfs_spa_init(spa)) { 157 fprintf(stderr, "can't init pool %s\n", spa->spa_name); 158 exit(1); 159 } 160 } 161 162 spa_all_status(); 163 164 spa = STAILQ_FIRST(&zfs_pools); 165 if (spa == NULL) { 166 fprintf(stderr, "no pools\n"); 167 exit(1); 168 } 169 170#if 0 171 uint64_t rootobj; 172 if (zfs_get_root(spa, &rootobj)) { 173 fprintf(stderr, "can't get root\n"); 174 exit(1); 175 } 176 177 if (zfs_mount(spa, rootobj, &zfsmnt)) { 178#else 179 if (zfs_mount(spa, 0, &zfsmnt)) { 180 fprintf(stderr, "can't mount\n"); 181 exit(1); 182#endif 183 } 184 185 printf("\n"); 186 for (++i, failures = 0; i < argc; i++) { 187 if (zfs_lookup(&zfsmnt, argv[i], &dn)) { 188 fprintf(stderr, "%s: can't lookup\n", argv[i]); 189 failures++; 190 continue; 191 } 192 193 if (zfs_dnode_stat(spa, &dn, &sb)) { 194 fprintf(stderr, "%s: can't stat\n", argv[i]); 195 failures++; 196 continue; 197 } 198 199 off = 0; 200 MD5Init(&ctx); 201 do { 202 n = sb.st_size - off; 203 n = n > sizeof(buf) ? sizeof(buf) : n; 204 n = zfs_read(spa, &dn, buf, n, off); 205 if (n < 0) { 206 fprintf(stderr, "%s: zfs_read failed\n", 207 argv[i]); 208 failures++; 209 break; 210 } 211 MD5Update(&ctx, buf, n); 212 off += n; 213 } while (off < sb.st_size); 214 if (off < sb.st_size) 215 continue; 216 MD5End(&ctx, hash); 217 printf("%s %s\n", hash, argv[i]); 218 } 219 220 return (failures == 0 ? 0 : 1); 221} 222