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
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
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
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);
45 cmd_info(int ac
, const char **av
)
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
) {
60 ptr
= strrchr(den
->d_name
, '.');
61 if (ptr
&& sscanf(ptr
, ".s%d%c", &slice
, &part
) == 2) {
62 asprintf(&devpath
, "/dev/serno/%s",
64 h2disk_check(devpath
, info_callback1
);
75 info_callback1(const char *path
, hammer2_blockref_t
*bref
, int fd
)
77 printf("%s:\n", path
);
78 h2pfs_check(fd
, bref
, info_callback2
);
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
;
96 cmd_mountall(int ac
, const char **av
)
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
) {
112 ptr
= strrchr(den
->d_name
, '.');
113 if (ptr
&& sscanf(ptr
, ".s%d%c", &slice
, &part
) == 2) {
114 asprintf(&devpath
, "/dev/serno/%s",
116 h2disk_check(devpath
, mount_callback1
);
122 signal(SIGALRM
, cmd_mountall_alarm
);
125 pid
= wait3(NULL
, 0, NULL
);
126 if (pid
< 0 && errno
== ECHILD
)
128 if (pid
< 0 && DidAlarm
) {
129 printf("Timeout waiting for mounts to complete\n");
140 cmd_mountall_alarm(int signo __unused
)
145 static const char *mount_path
;
146 static const char *mount_comp
;
150 mount_callback1(const char *devpath
, hammer2_blockref_t
*bref
, int fd
)
152 mount_path
= devpath
;
153 mount_comp
= strrchr(devpath
, '/');
156 h2pfs_check(fd
, bref
, mount_callback2
);
162 mount_callback2(const char *pfsname
,
163 hammer2_blockref_t
*bref __unused
, int fd
)
169 if (strcmp(pfsname
, "LOCAL") == 0) {
170 if ((tfd
= open("/dev/null", O_RDONLY
)) >= 0) {
174 perror("open(/dev/null)");
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
);
183 execl("/sbin/mount_hammer2",
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
;
210 fd
= open(devpath
, O_RDONLY
);
212 fprintf(stderr
, "Unable to open \"%s\"\n", devpath
);
215 if (ioctl(fd
, DIOCGPART
, &partinfo
) == -1) {
216 fprintf(stderr
, "DIOCGPART failed on \"%s\"\n", devpath
);
219 if (partinfo
.fstype
!= FS_HAMMER2
)
223 * Find the best volume header.
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
) |
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
) {
244 callback1(devpath
, &best
, fd
);
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
;
262 bytes
= (size_t)1 << (bref
->data_off
& HAMMER2_OFF_MASK_RADIX
);
265 hammer2_off_t io_off
;
266 hammer2_off_t io_base
;
270 io_off
= bref
->data_off
& ~HAMMER2_OFF_MASK_RADIX
;
271 io_base
= io_off
& ~(hammer2_off_t
)(HAMMER2_MINIOSIZE
- 1);
273 boff
= io_off
- io_base
;
275 io_bytes
= HAMMER2_MINIOSIZE
;
276 while (io_bytes
+ boff
< bytes
)
279 if (io_bytes
> sizeof(media
)) {
280 printf("(bad block size %zd)\n", bytes
);
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");
290 bcopy((char *)&media
+ boff
, &media
, bytes
);
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
:
307 case HAMMER2_CHECK_DISABLED
:
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",
314 bref
->check
.iscsi32
.value
,
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",
323 bref
->check
.xxhash64
.value
,
327 case HAMMER2_CHECK_SHA192
:
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",
334 bref
->check
.freemap
.icrc32
,
342 case HAMMER2_BREF_TYPE_EMPTY
:
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
;
352 if (media
.ipdata
.meta
.op_flags
& HAMMER2_OPFLAG_PFSROOT
) {
353 callback2(media
.ipdata
.filename
, bref
, fd
);
361 case HAMMER2_BREF_TYPE_INDIRECT
:
362 bscan
= &media
.npdata
[0];
363 bcount
= bytes
/ sizeof(hammer2_blockref_t
);
365 case HAMMER2_BREF_TYPE_DATA
:
367 case HAMMER2_BREF_TYPE_VOLUME
:
368 bscan
= &media
.voldata
.sroot_blockset
.blockref
[0];
369 bcount
= HAMMER2_SET_COUNT
;
374 for (i
= 0; i
< bcount
; ++i
) {
375 if (bscan
[i
].type
!= HAMMER2_BREF_TYPE_EMPTY
)
376 h2pfs_check(fd
, &bscan
[i
], callback2
);