Revert "mtree(8): Replace our mtree(8) with NetBSD's version."
[dragonfly.git] / sbin / hammer2 / cmd_info.c
blob50b03e6c0fff3384a05f4e2f9de58d161e00194e
1 /*
2 * Copyright (c) 2015 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@dragonflybsd.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 #include "hammer2.h"
36 static void h2disk_check(const char *devpath,
37 void (*callback1)(const char *, hammer2_blockref_t *, int));
38 static void h2pfs_check(int fd, hammer2_blockref_t *bref,
39 void (*callback2)(const char *, hammer2_blockref_t *, int));
41 static void info_callback1(const char *, hammer2_blockref_t *, int);
42 static void info_callback2(const char *, hammer2_blockref_t *, int);
44 int
45 cmd_info(int ac, const char **av)
47 struct dirent *den;
48 char *devpath;
49 DIR *dir;
50 int i;
52 for (i = 0; i < ac; ++i)
53 h2disk_check(av[i], info_callback1);
54 if (ac == 0 && (dir = opendir("/dev/serno")) != NULL) {
55 while ((den = readdir(dir)) != NULL) {
56 const char *ptr;
57 int slice;
58 char part;
60 ptr = strrchr(den->d_name, '.');
61 if (ptr && sscanf(ptr, ".s%d%c", &slice, &part) == 2) {
62 asprintf(&devpath, "/dev/serno/%s",
63 den->d_name);
64 h2disk_check(devpath, info_callback1);
65 free(devpath);
68 closedir(dir);
70 return 0;
73 static
74 void
75 info_callback1(const char *path, hammer2_blockref_t *bref, int fd)
77 printf("%s:\n", path);
78 h2pfs_check(fd, bref, info_callback2);
81 static
82 void
83 info_callback2(const char *pfsname,
84 hammer2_blockref_t *bref __unused, int fd __unused)
86 printf(" %s\n", pfsname);
89 static void mount_callback1(const char *, hammer2_blockref_t *, int);
90 static void mount_callback2(const char *, hammer2_blockref_t *, int);
91 static void cmd_mountall_alarm(int signo);
93 static volatile sig_atomic_t DidAlarm;
95 int
96 cmd_mountall(int ac, const char **av)
98 struct dirent *den;
99 char *devpath;
100 DIR *dir;
101 int i;
102 pid_t pid;
104 for (i = 0; i < ac; ++i)
105 h2disk_check(av[i], mount_callback1);
106 if (ac == 0 && (dir = opendir("/dev/serno")) != NULL) {
107 while ((den = readdir(dir)) != NULL) {
108 const char *ptr;
109 int slice;
110 char part;
112 ptr = strrchr(den->d_name, '.');
113 if (ptr && sscanf(ptr, ".s%d%c", &slice, &part) == 2) {
114 asprintf(&devpath, "/dev/serno/%s",
115 den->d_name);
116 h2disk_check(devpath, mount_callback1);
117 free(devpath);
120 closedir(dir);
122 signal(SIGALRM, cmd_mountall_alarm);
123 for (;;) {
124 alarm(15);
125 pid = wait3(NULL, 0, NULL);
126 if (pid < 0 && errno == ECHILD)
127 break;
128 if (pid < 0 && DidAlarm) {
129 printf("Timeout waiting for mounts to complete\n");
130 break;
133 alarm(0);
135 return 0;
138 static
139 void
140 cmd_mountall_alarm(int signo __unused)
142 DidAlarm = 1;
145 static const char *mount_path;
146 static const char *mount_comp;
148 static
149 void
150 mount_callback1(const char *devpath, hammer2_blockref_t *bref, int fd)
152 mount_path = devpath;
153 mount_comp = strrchr(devpath, '/');
154 if (mount_comp) {
155 ++mount_comp;
156 h2pfs_check(fd, bref, mount_callback2);
160 static
161 void
162 mount_callback2(const char *pfsname,
163 hammer2_blockref_t *bref __unused, int fd)
165 char *tmp_path;
166 char *label;
167 int tfd;
169 if (strcmp(pfsname, "LOCAL") == 0) {
170 if ((tfd = open("/dev/null", O_RDONLY)) >= 0) {
171 dup2(tfd, fd);
172 close(tfd);
173 } else {
174 perror("open(/dev/null)");
175 exit(1);
177 asprintf(&tmp_path, "/var/hammer2/LOCAL.%s", mount_comp);
178 asprintf(&label, "%s@LOCAL", mount_path);
179 mkdir("/var/hammer2", 0700);
180 mkdir(tmp_path, 0700);
181 printf("mount %s\n", tmp_path);
182 if (fork() == 0) {
183 execl("/sbin/mount_hammer2",
184 "mount",
185 label,
186 tmp_path,
187 NULL);
189 free(label);
190 free(tmp_path);
195 * Support
197 static
198 void
199 h2disk_check(const char *devpath,
200 void (*callback1)(const char *, hammer2_blockref_t *, int))
202 hammer2_blockref_t broot;
203 hammer2_blockref_t best;
204 hammer2_media_data_t media;
205 struct partinfo partinfo;
206 int fd;
207 int i;
208 int best_i;
210 fd = open(devpath, O_RDONLY);
211 if (fd < 0) {
212 fprintf(stderr, "Unable to open \"%s\"\n", devpath);
213 return;
215 if (ioctl(fd, DIOCGPART, &partinfo) == -1) {
216 fprintf(stderr, "DIOCGPART failed on \"%s\"\n", devpath);
217 goto done;
219 if (partinfo.fstype != FS_HAMMER2)
220 goto done;
223 * Find the best volume header.
225 best_i = -1;
226 bzero(&best, sizeof(best));
227 for (i = 0; i < 4; ++i) {
228 bzero(&broot, sizeof(broot));
229 broot.type = HAMMER2_BREF_TYPE_VOLUME;
230 broot.data_off = (i * HAMMER2_ZONE_BYTES64) |
231 HAMMER2_PBUFRADIX;
232 lseek(fd, broot.data_off & ~HAMMER2_OFF_MASK_RADIX, 0);
233 if (read(fd, &media, HAMMER2_PBUFSIZE) ==
234 (ssize_t)HAMMER2_PBUFSIZE &&
235 media.voldata.magic == HAMMER2_VOLUME_ID_HBO) {
236 broot.mirror_tid = media.voldata.mirror_tid;
237 if (best_i < 0 || best.mirror_tid < broot.mirror_tid) {
238 best_i = i;
239 best = broot;
243 if (best_i >= 0)
244 callback1(devpath, &best, fd);
245 done:
246 close(fd);
249 static
250 void
251 h2pfs_check(int fd, hammer2_blockref_t *bref,
252 void (*callback2)(const char *, hammer2_blockref_t *, int))
254 hammer2_media_data_t media;
255 hammer2_blockref_t *bscan;
256 int bcount;
257 int i;
258 size_t bytes;
259 uint32_t cv;
260 uint64_t cv64;
262 bytes = (size_t)1 << (bref->data_off & HAMMER2_OFF_MASK_RADIX);
265 hammer2_off_t io_off;
266 hammer2_off_t io_base;
267 size_t io_bytes;
268 size_t boff;
270 io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX;
271 io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1);
272 io_bytes = bytes;
273 boff = io_off - io_base;
275 io_bytes = HAMMER2_MINIOSIZE;
276 while (io_bytes + boff < bytes)
277 io_bytes <<= 1;
279 if (io_bytes > sizeof(media)) {
280 printf("(bad block size %zd)\n", bytes);
281 return;
283 if (bref->type != HAMMER2_BREF_TYPE_DATA) {
284 lseek(fd, io_base, 0);
285 if (read(fd, &media, io_bytes) != (ssize_t)io_bytes) {
286 printf("(media read failed)\n");
287 return;
289 if (boff)
290 bcopy((char *)&media + boff, &media, bytes);
294 bscan = NULL;
295 bcount = 0;
298 * Check data integrity in verbose mode, otherwise we are just doing
299 * a quick meta-data scan. Meta-data integrity is always checked.
300 * (Also see the check above that ensures the media data is loaded,
301 * otherwise there's no data to check!).
303 if (bref->type != HAMMER2_BREF_TYPE_DATA || VerboseOpt >= 1) {
304 switch(HAMMER2_DEC_CHECK(bref->methods)) {
305 case HAMMER2_CHECK_NONE:
306 break;
307 case HAMMER2_CHECK_DISABLED:
308 break;
309 case HAMMER2_CHECK_ISCSI32:
310 cv = hammer2_icrc32(&media, bytes);
311 if (bref->check.iscsi32.value != cv) {
312 printf("\t(icrc failed %02x:%08x/%08x)\n",
313 bref->methods,
314 bref->check.iscsi32.value,
315 cv);
317 break;
318 case HAMMER2_CHECK_XXHASH64:
319 cv64 = XXH64(&media, bytes, XXH_HAMMER2_SEED);
320 if (bref->check.xxhash64.value != cv64) {
321 printf("\t(xxhash failed %02x:%016jx/%016jx)\n",
322 bref->methods,
323 bref->check.xxhash64.value,
324 cv64);
326 break;
327 case HAMMER2_CHECK_SHA192:
328 break;
329 case HAMMER2_CHECK_FREEMAP:
330 cv = hammer2_icrc32(&media, bytes);
331 if (bref->check.freemap.icrc32 != cv) {
332 printf("\t(fcrc %02x:%08x/%08x)\n",
333 bref->methods,
334 bref->check.freemap.icrc32,
335 cv);
337 break;
341 switch(bref->type) {
342 case HAMMER2_BREF_TYPE_EMPTY:
343 break;
344 case HAMMER2_BREF_TYPE_INODE:
345 if (media.ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) {
346 if ((media.ipdata.meta.op_flags &
347 HAMMER2_OPFLAG_DIRECTDATA) == 0) {
348 bscan = &media.ipdata.u.blockset.blockref[0];
349 bcount = HAMMER2_SET_COUNT;
351 } else
352 if (media.ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) {
353 callback2(media.ipdata.filename, bref, fd);
354 bscan = NULL;
355 bcount = 0;
356 } else {
357 bscan = NULL;
358 bcount = 0;
360 break;
361 case HAMMER2_BREF_TYPE_INDIRECT:
362 bscan = &media.npdata[0];
363 bcount = bytes / sizeof(hammer2_blockref_t);
364 break;
365 case HAMMER2_BREF_TYPE_DATA:
366 break;
367 case HAMMER2_BREF_TYPE_VOLUME:
368 bscan = &media.voldata.sroot_blockset.blockref[0];
369 bcount = HAMMER2_SET_COUNT;
370 break;
371 default:
372 break;
374 for (i = 0; i < bcount; ++i) {
375 if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY)
376 h2pfs_check(fd, &bscan[i], callback2);