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