1030fdd8aSTomohiro Kusumi /*-
226cca7e2STomohiro Kusumi * Copyright (c) 2017-2019 The DragonFly Project
396fbde7aSTomohiro Kusumi * Copyright (c) 2017-2019 Tomohiro Kusumi <tkusumi@netbsd.org>
4030fdd8aSTomohiro Kusumi * All rights reserved.
5030fdd8aSTomohiro Kusumi *
6030fdd8aSTomohiro Kusumi * Redistribution and use in source and binary forms, with or without
7030fdd8aSTomohiro Kusumi * modification, are permitted provided that the following conditions
8030fdd8aSTomohiro Kusumi * are met:
9030fdd8aSTomohiro Kusumi * 1. Redistributions of source code must retain the above copyright
10030fdd8aSTomohiro Kusumi * notice, this list of conditions and the following disclaimer.
11030fdd8aSTomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright
12030fdd8aSTomohiro Kusumi * notice, this list of conditions and the following disclaimer in the
13030fdd8aSTomohiro Kusumi * documentation and/or other materials provided with the distribution.
14030fdd8aSTomohiro Kusumi *
15030fdd8aSTomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16030fdd8aSTomohiro Kusumi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17030fdd8aSTomohiro Kusumi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18030fdd8aSTomohiro Kusumi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19030fdd8aSTomohiro Kusumi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20030fdd8aSTomohiro Kusumi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21030fdd8aSTomohiro Kusumi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22030fdd8aSTomohiro Kusumi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23030fdd8aSTomohiro Kusumi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24030fdd8aSTomohiro Kusumi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25030fdd8aSTomohiro Kusumi * SUCH DAMAGE.
26030fdd8aSTomohiro Kusumi */
27030fdd8aSTomohiro Kusumi
28030fdd8aSTomohiro Kusumi #include <stdio.h>
29030fdd8aSTomohiro Kusumi #include <stdlib.h>
3065d969b4STomohiro Kusumi #include <stdbool.h>
31030fdd8aSTomohiro Kusumi #include <string.h>
32030fdd8aSTomohiro Kusumi #include <err.h>
3365d969b4STomohiro Kusumi #include <assert.h>
340b738157STomohiro Kusumi #include <uuid.h>
35030fdd8aSTomohiro Kusumi #include <vfs/hammer2/hammer2_disk.h>
36030fdd8aSTomohiro Kusumi
37030fdd8aSTomohiro Kusumi #include "fstyp.h"
38030fdd8aSTomohiro Kusumi
39064b66eaSTomohiro Kusumi static ssize_t
get_file_size(FILE * fp)40064b66eaSTomohiro Kusumi get_file_size(FILE *fp)
41064b66eaSTomohiro Kusumi {
42064b66eaSTomohiro Kusumi ssize_t siz;
43064b66eaSTomohiro Kusumi
44064b66eaSTomohiro Kusumi if (fseek(fp, 0, SEEK_END) == -1) {
45064b66eaSTomohiro Kusumi warnx("hammer2: failed to seek media end");
46064b66eaSTomohiro Kusumi return (-1);
47064b66eaSTomohiro Kusumi }
48064b66eaSTomohiro Kusumi
49064b66eaSTomohiro Kusumi siz = ftell(fp);
50064b66eaSTomohiro Kusumi if (siz == -1) {
51064b66eaSTomohiro Kusumi warnx("hammer2: failed to tell media end");
52064b66eaSTomohiro Kusumi return (-1);
53064b66eaSTomohiro Kusumi }
54064b66eaSTomohiro Kusumi
55064b66eaSTomohiro Kusumi return (siz);
56064b66eaSTomohiro Kusumi }
57064b66eaSTomohiro Kusumi
580b738157STomohiro Kusumi static hammer2_volume_data_t *
read_voldata(FILE * fp,int i)590b738157STomohiro Kusumi read_voldata(FILE *fp, int i)
600b738157STomohiro Kusumi {
610b738157STomohiro Kusumi if (i < 0 || i >= HAMMER2_NUM_VOLHDRS)
620b738157STomohiro Kusumi return (NULL);
630b738157STomohiro Kusumi
640b738157STomohiro Kusumi if (i * HAMMER2_ZONE_BYTES64 >= get_file_size(fp))
650b738157STomohiro Kusumi return (NULL);
660b738157STomohiro Kusumi
670b738157STomohiro Kusumi return (read_buf(fp, i * HAMMER2_ZONE_BYTES64,
680b738157STomohiro Kusumi sizeof(hammer2_volume_data_t)));
690b738157STomohiro Kusumi }
700b738157STomohiro Kusumi
71d07d7d69STomohiro Kusumi static int
test_voldata(FILE * fp)72d07d7d69STomohiro Kusumi test_voldata(FILE *fp)
73030fdd8aSTomohiro Kusumi {
74030fdd8aSTomohiro Kusumi hammer2_volume_data_t *voldata;
750b738157STomohiro Kusumi int i;
760b738157STomohiro Kusumi static int count = 0;
770b738157STomohiro Kusumi static uuid_t fsid, fstype;
78030fdd8aSTomohiro Kusumi
79064b66eaSTomohiro Kusumi for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) {
80064b66eaSTomohiro Kusumi if (i * HAMMER2_ZONE_BYTES64 >= get_file_size(fp))
81d07d7d69STomohiro Kusumi break;
820b738157STomohiro Kusumi voldata = read_voldata(fp, i);
83064b66eaSTomohiro Kusumi if (voldata == NULL) {
84064b66eaSTomohiro Kusumi warnx("hammer2: failed to read volume data");
85064b66eaSTomohiro Kusumi return (1);
86064b66eaSTomohiro Kusumi }
87030fdd8aSTomohiro Kusumi if (voldata->magic != HAMMER2_VOLUME_ID_HBO &&
880b738157STomohiro Kusumi voldata->magic != HAMMER2_VOLUME_ID_ABO) {
890b738157STomohiro Kusumi free(voldata);
90030fdd8aSTomohiro Kusumi return (1);
910b738157STomohiro Kusumi }
920b738157STomohiro Kusumi if (voldata->volu_id > HAMMER2_MAX_VOLUMES - 1) {
930b738157STomohiro Kusumi free(voldata);
940b738157STomohiro Kusumi return (1);
950b738157STomohiro Kusumi }
960b738157STomohiro Kusumi if (voldata->nvolumes > HAMMER2_MAX_VOLUMES) {
970b738157STomohiro Kusumi free(voldata);
980b738157STomohiro Kusumi return (1);
990b738157STomohiro Kusumi }
1000b738157STomohiro Kusumi
1010b738157STomohiro Kusumi if (count == 0) {
1020b738157STomohiro Kusumi count = voldata->nvolumes;
1030b738157STomohiro Kusumi memcpy(&fsid, &voldata->fsid, sizeof(fsid));
1040b738157STomohiro Kusumi memcpy(&fstype, &voldata->fstype, sizeof(fstype));
1050b738157STomohiro Kusumi } else {
1060b738157STomohiro Kusumi if (voldata->nvolumes != count) {
1070b738157STomohiro Kusumi free(voldata);
1080b738157STomohiro Kusumi return (1);
1090b738157STomohiro Kusumi }
1100b738157STomohiro Kusumi if (!uuid_equal(&fsid, &voldata->fsid, NULL)) {
1110b738157STomohiro Kusumi free(voldata);
1120b738157STomohiro Kusumi return (1);
1130b738157STomohiro Kusumi }
1140b738157STomohiro Kusumi if (!uuid_equal(&fstype, &voldata->fstype, NULL)) {
1150b738157STomohiro Kusumi free(voldata);
1160b738157STomohiro Kusumi return (1);
1170b738157STomohiro Kusumi }
1180b738157STomohiro Kusumi }
1190b738157STomohiro Kusumi free(voldata);
1200b738157STomohiro Kusumi }
121030fdd8aSTomohiro Kusumi
122030fdd8aSTomohiro Kusumi return (0);
123030fdd8aSTomohiro Kusumi }
124030fdd8aSTomohiro Kusumi
12565d969b4STomohiro Kusumi static hammer2_media_data_t*
read_media(FILE * fp,const hammer2_blockref_t * bref,size_t * media_bytes)126c8efd889STomohiro Kusumi read_media(FILE *fp, const hammer2_blockref_t *bref, size_t *media_bytes)
12765d969b4STomohiro Kusumi {
12865d969b4STomohiro Kusumi hammer2_media_data_t *media;
12965d969b4STomohiro Kusumi hammer2_off_t io_off, io_base;
1300b738157STomohiro Kusumi size_t bytes, io_bytes, boff, fbytes;
13165d969b4STomohiro Kusumi
13265d969b4STomohiro Kusumi bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX);
13365d969b4STomohiro Kusumi if (bytes)
13465d969b4STomohiro Kusumi bytes = (size_t)1 << bytes;
13565d969b4STomohiro Kusumi *media_bytes = bytes;
13665d969b4STomohiro Kusumi
13765d969b4STomohiro Kusumi if (!bytes) {
138064b66eaSTomohiro Kusumi warnx("hammer2: blockref has no data");
13965d969b4STomohiro Kusumi return (NULL);
14065d969b4STomohiro Kusumi }
14165d969b4STomohiro Kusumi
14265d969b4STomohiro Kusumi io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX;
1435dade8cfSTomohiro Kusumi io_base = io_off & ~(hammer2_off_t)(HAMMER2_LBUFSIZE - 1);
14465d969b4STomohiro Kusumi boff = io_off - io_base;
14565d969b4STomohiro Kusumi
1465dade8cfSTomohiro Kusumi io_bytes = HAMMER2_LBUFSIZE;
14765d969b4STomohiro Kusumi while (io_bytes + boff < bytes)
14865d969b4STomohiro Kusumi io_bytes <<= 1;
14965d969b4STomohiro Kusumi
15065d969b4STomohiro Kusumi if (io_bytes > sizeof(hammer2_media_data_t)) {
151064b66eaSTomohiro Kusumi warnx("hammer2: invalid I/O bytes");
15265d969b4STomohiro Kusumi return (NULL);
15365d969b4STomohiro Kusumi }
15465d969b4STomohiro Kusumi
1550b738157STomohiro Kusumi /*
1560b738157STomohiro Kusumi * XXX fp is currently always root volume, so read fails if io_base is
1570b738157STomohiro Kusumi * beyond root volume limit. Fail with a message before read_buf() then.
1580b738157STomohiro Kusumi */
1590b738157STomohiro Kusumi fbytes = get_file_size(fp);
1600b738157STomohiro Kusumi if (fbytes == -1) {
1610b738157STomohiro Kusumi warnx("hammer2: failed to get media size");
1620b738157STomohiro Kusumi return (NULL);
1630b738157STomohiro Kusumi }
1640b738157STomohiro Kusumi if (io_base >= fbytes) {
1650b738157STomohiro Kusumi warnx("hammer2: XXX read beyond HAMMER2 root volume limit unsupported");
1660b738157STomohiro Kusumi return (NULL);
1670b738157STomohiro Kusumi }
1680b738157STomohiro Kusumi
16965d969b4STomohiro Kusumi if (fseek(fp, io_base, SEEK_SET) == -1) {
170064b66eaSTomohiro Kusumi warnx("hammer2: failed to seek media");
17165d969b4STomohiro Kusumi return (NULL);
17265d969b4STomohiro Kusumi }
17365d969b4STomohiro Kusumi media = read_buf(fp, io_base, io_bytes);
17465d969b4STomohiro Kusumi if (media == NULL) {
175064b66eaSTomohiro Kusumi warnx("hammer2: failed to read media");
17665d969b4STomohiro Kusumi return (NULL);
17765d969b4STomohiro Kusumi }
17865d969b4STomohiro Kusumi if (boff)
17965d969b4STomohiro Kusumi memcpy(media, (char *)media + boff, bytes);
18065d969b4STomohiro Kusumi
18165d969b4STomohiro Kusumi return (media);
18265d969b4STomohiro Kusumi }
18365d969b4STomohiro Kusumi
18426cca7e2STomohiro Kusumi static int
find_pfs(FILE * fp,const hammer2_blockref_t * bref,const char * pfs,bool * res)185c8efd889STomohiro Kusumi find_pfs(FILE *fp, const hammer2_blockref_t *bref, const char *pfs, bool *res)
18665d969b4STomohiro Kusumi {
18765d969b4STomohiro Kusumi hammer2_media_data_t *media;
18865d969b4STomohiro Kusumi hammer2_inode_data_t ipdata;
18965d969b4STomohiro Kusumi hammer2_blockref_t *bscan;
19065d969b4STomohiro Kusumi size_t bytes;
19165d969b4STomohiro Kusumi int i, bcount;
19265d969b4STomohiro Kusumi
193c8efd889STomohiro Kusumi media = read_media(fp, bref, &bytes);
19465d969b4STomohiro Kusumi if (media == NULL)
19565d969b4STomohiro Kusumi return (-1);
19665d969b4STomohiro Kusumi
19765d969b4STomohiro Kusumi switch (bref->type) {
19865d969b4STomohiro Kusumi case HAMMER2_BREF_TYPE_INODE:
19965d969b4STomohiro Kusumi ipdata = media->ipdata;
200029e6489STomohiro Kusumi if (ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) {
20165d969b4STomohiro Kusumi bscan = &ipdata.u.blockset.blockref[0];
20265d969b4STomohiro Kusumi bcount = HAMMER2_SET_COUNT;
20365d969b4STomohiro Kusumi } else {
20465d969b4STomohiro Kusumi bscan = NULL;
20565d969b4STomohiro Kusumi bcount = 0;
20665d969b4STomohiro Kusumi if (ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) {
20763dc3af7STomohiro Kusumi if (memchr(ipdata.filename, 0,
20863dc3af7STomohiro Kusumi sizeof(ipdata.filename))) {
2094a4aa420STomohiro Kusumi if (!strcmp(
2104a4aa420STomohiro Kusumi (const char*)ipdata.filename, pfs))
21165d969b4STomohiro Kusumi *res = true;
21263dc3af7STomohiro Kusumi } else {
213e3e33cadSTomohiro Kusumi if (strlen(pfs) > 0 &&
214e3e33cadSTomohiro Kusumi !memcmp(ipdata.filename, pfs,
21563dc3af7STomohiro Kusumi strlen(pfs)))
21663dc3af7STomohiro Kusumi *res = true;
21763dc3af7STomohiro Kusumi }
218aed08990STomohiro Kusumi } else {
219aed08990STomohiro Kusumi free(media);
2205721f2ecSTomohiro Kusumi return (-1);
22165d969b4STomohiro Kusumi }
222aed08990STomohiro Kusumi }
22365d969b4STomohiro Kusumi break;
22465d969b4STomohiro Kusumi case HAMMER2_BREF_TYPE_INDIRECT:
22565d969b4STomohiro Kusumi bscan = &media->npdata[0];
22665d969b4STomohiro Kusumi bcount = bytes / sizeof(hammer2_blockref_t);
22765d969b4STomohiro Kusumi break;
22865d969b4STomohiro Kusumi default:
22965d969b4STomohiro Kusumi bscan = NULL;
23065d969b4STomohiro Kusumi bcount = 0;
23165d969b4STomohiro Kusumi break;
23265d969b4STomohiro Kusumi }
23365d969b4STomohiro Kusumi
23465d969b4STomohiro Kusumi for (i = 0; i < bcount; ++i) {
23565d969b4STomohiro Kusumi if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) {
236c8efd889STomohiro Kusumi if (find_pfs(fp, &bscan[i], pfs, res) == -1) {
23765d969b4STomohiro Kusumi free(media);
23865d969b4STomohiro Kusumi return (-1);
23965d969b4STomohiro Kusumi }
24065d969b4STomohiro Kusumi }
24165d969b4STomohiro Kusumi }
24265d969b4STomohiro Kusumi free(media);
24365d969b4STomohiro Kusumi
24465d969b4STomohiro Kusumi return (0);
24565d969b4STomohiro Kusumi }
24665d969b4STomohiro Kusumi
2472f9f168aSTomohiro Kusumi static char*
extract_device_name(const char * devpath)2482f9f168aSTomohiro Kusumi extract_device_name(const char *devpath)
2492f9f168aSTomohiro Kusumi {
250e3e33cadSTomohiro Kusumi char *p, *head;
251e3e33cadSTomohiro Kusumi
252e3e33cadSTomohiro Kusumi if (!devpath)
253c51f15daSTomohiro Kusumi return (NULL);
254e3e33cadSTomohiro Kusumi
255e3e33cadSTomohiro Kusumi p = strdup(devpath);
256e3e33cadSTomohiro Kusumi head = p;
2572f9f168aSTomohiro Kusumi
2582f9f168aSTomohiro Kusumi p = strchr(p, '@');
2592f9f168aSTomohiro Kusumi if (p)
2602f9f168aSTomohiro Kusumi *p = 0;
2612f9f168aSTomohiro Kusumi
2622f9f168aSTomohiro Kusumi p = strrchr(head, '/');
2632f9f168aSTomohiro Kusumi if (p) {
2642f9f168aSTomohiro Kusumi p++;
2652f9f168aSTomohiro Kusumi if (*p == 0) {
2662f9f168aSTomohiro Kusumi free(head);
267c51f15daSTomohiro Kusumi return (NULL);
2682f9f168aSTomohiro Kusumi }
2692f9f168aSTomohiro Kusumi p = strdup(p);
2702f9f168aSTomohiro Kusumi free(head);
271c51f15daSTomohiro Kusumi return (p);
2722f9f168aSTomohiro Kusumi }
2732f9f168aSTomohiro Kusumi
274c51f15daSTomohiro Kusumi return (head);
2752f9f168aSTomohiro Kusumi }
2762f9f168aSTomohiro Kusumi
27765d969b4STomohiro Kusumi static int
read_label(FILE * fp,char * label,size_t size,const char * devpath)278c8efd889STomohiro Kusumi read_label(FILE *fp, char *label, size_t size, const char *devpath)
27926cca7e2STomohiro Kusumi {
28026cca7e2STomohiro Kusumi hammer2_blockref_t broot, best, *bref;
2819ed43ec3STomohiro Kusumi hammer2_media_data_t *vols[HAMMER2_NUM_VOLHDRS], *media;
28265d969b4STomohiro Kusumi size_t bytes;
28365d969b4STomohiro Kusumi bool res = false;
284841ef9e9STomohiro Kusumi int i, best_i, error = 1;
28565d969b4STomohiro Kusumi const char *pfs;
2862f9f168aSTomohiro Kusumi char *devname;
28726cca7e2STomohiro Kusumi
28826cca7e2STomohiro Kusumi best_i = -1;
289064b66eaSTomohiro Kusumi memset(vols, 0, sizeof(vols));
29026cca7e2STomohiro Kusumi memset(&best, 0, sizeof(best));
29126cca7e2STomohiro Kusumi
29226cca7e2STomohiro Kusumi for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) {
293064b66eaSTomohiro Kusumi if (i * HAMMER2_ZONE_BYTES64 >= get_file_size(fp))
294064b66eaSTomohiro Kusumi break;
29526cca7e2STomohiro Kusumi memset(&broot, 0, sizeof(broot));
29626cca7e2STomohiro Kusumi broot.type = HAMMER2_BREF_TYPE_VOLUME;
29726cca7e2STomohiro Kusumi broot.data_off = (i * HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX;
2980b738157STomohiro Kusumi vols[i] = (void*)read_voldata(fp, i);
299064b66eaSTomohiro Kusumi if (vols[i] == NULL) {
300064b66eaSTomohiro Kusumi warnx("hammer2: failed to read volume data");
301064b66eaSTomohiro Kusumi goto fail;
302064b66eaSTomohiro Kusumi }
30326cca7e2STomohiro Kusumi broot.mirror_tid = vols[i]->voldata.mirror_tid;
30426cca7e2STomohiro Kusumi if (best_i < 0 || best.mirror_tid < broot.mirror_tid) {
30526cca7e2STomohiro Kusumi best_i = i;
30626cca7e2STomohiro Kusumi best = broot;
30726cca7e2STomohiro Kusumi }
30826cca7e2STomohiro Kusumi }
30926cca7e2STomohiro Kusumi
31026cca7e2STomohiro Kusumi bref = &vols[best_i]->voldata.sroot_blockset.blockref[0];
31126cca7e2STomohiro Kusumi if (bref->type != HAMMER2_BREF_TYPE_INODE) {
3120b738157STomohiro Kusumi /* Don't print error as devpath could be non-root volume. */
313841ef9e9STomohiro Kusumi goto fail;
31426cca7e2STomohiro Kusumi }
31526cca7e2STomohiro Kusumi
316c8efd889STomohiro Kusumi media = read_media(fp, bref, &bytes);
31765d969b4STomohiro Kusumi if (media == NULL) {
318841ef9e9STomohiro Kusumi goto fail;
31926cca7e2STomohiro Kusumi }
32026cca7e2STomohiro Kusumi
321e3e33cadSTomohiro Kusumi /*
322e3e33cadSTomohiro Kusumi * fstyp_function in DragonFly takes an additional devpath argument
323e3e33cadSTomohiro Kusumi * which doesn't exist in FreeBSD and NetBSD.
324e3e33cadSTomohiro Kusumi */
325e3e33cadSTomohiro Kusumi #ifdef HAS_DEVPATH
32665d969b4STomohiro Kusumi pfs = strchr(devpath, '@');
32765d969b4STomohiro Kusumi if (!pfs) {
32865d969b4STomohiro Kusumi assert(strlen(devpath));
32965d969b4STomohiro Kusumi switch (devpath[strlen(devpath) - 1]) {
33065d969b4STomohiro Kusumi case 'a':
33165d969b4STomohiro Kusumi pfs = "BOOT";
33265d969b4STomohiro Kusumi break;
33365d969b4STomohiro Kusumi case 'd':
33465d969b4STomohiro Kusumi pfs = "ROOT";
33565d969b4STomohiro Kusumi break;
33665d969b4STomohiro Kusumi default:
33765d969b4STomohiro Kusumi pfs = "DATA";
33865d969b4STomohiro Kusumi break;
33926cca7e2STomohiro Kusumi }
34065d969b4STomohiro Kusumi } else
34165d969b4STomohiro Kusumi pfs++;
34226cca7e2STomohiro Kusumi
34363dc3af7STomohiro Kusumi if (strlen(pfs) > HAMMER2_INODE_MAXNAME) {
344841ef9e9STomohiro Kusumi goto fail;
34563dc3af7STomohiro Kusumi }
3462f9f168aSTomohiro Kusumi devname = extract_device_name(devpath);
347e3e33cadSTomohiro Kusumi #else
348e3e33cadSTomohiro Kusumi pfs = "";
349e3e33cadSTomohiro Kusumi devname = extract_device_name(NULL);
350e3e33cadSTomohiro Kusumi assert(!devname);
351e3e33cadSTomohiro Kusumi #endif
3522f9f168aSTomohiro Kusumi
3532f9f168aSTomohiro Kusumi /* Add device name to help support multiple autofs -media mounts. */
3542f9f168aSTomohiro Kusumi if (find_pfs(fp, bref, pfs, &res) == 0 && res) {
3552f9f168aSTomohiro Kusumi if (devname)
3562f9f168aSTomohiro Kusumi snprintf(label, size, "%s_%s", pfs, devname);
3572f9f168aSTomohiro Kusumi else
3583b3b0bfeSTomohiro Kusumi strlcpy(label, pfs, size);
3592f9f168aSTomohiro Kusumi } else {
36096b636c4STomohiro Kusumi memset(label, 0, size);
36196b636c4STomohiro Kusumi memcpy(label, media->ipdata.filename,
36296b636c4STomohiro Kusumi sizeof(media->ipdata.filename));
36396b636c4STomohiro Kusumi if (devname) {
36496b636c4STomohiro Kusumi strlcat(label, "_", size);
36596b636c4STomohiro Kusumi strlcat(label, devname, size);
36696b636c4STomohiro Kusumi }
3672f9f168aSTomohiro Kusumi }
3682f9f168aSTomohiro Kusumi if (devname)
3692f9f168aSTomohiro Kusumi free(devname);
37026cca7e2STomohiro Kusumi free(media);
371841ef9e9STomohiro Kusumi error = 0;
372841ef9e9STomohiro Kusumi fail:
37326cca7e2STomohiro Kusumi for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++)
37426cca7e2STomohiro Kusumi free(vols[i]);
37526cca7e2STomohiro Kusumi
37626cca7e2STomohiro Kusumi return (error);
37726cca7e2STomohiro Kusumi }
37826cca7e2STomohiro Kusumi
379030fdd8aSTomohiro Kusumi int
fstyp_hammer2(FILE * fp,char * label,size_t size,const char * devpath)38065d969b4STomohiro Kusumi fstyp_hammer2(FILE *fp, char *label, size_t size, const char *devpath)
381030fdd8aSTomohiro Kusumi {
3820b738157STomohiro Kusumi hammer2_volume_data_t *voldata = read_voldata(fp, 0);
3830b738157STomohiro Kusumi int error = 1;
384030fdd8aSTomohiro Kusumi
3850b738157STomohiro Kusumi if (voldata->volu_id != HAMMER2_ROOT_VOLUME)
3860b738157STomohiro Kusumi goto fail;
3870b738157STomohiro Kusumi if (voldata->nvolumes != 0)
3880b738157STomohiro Kusumi goto fail;
3890b738157STomohiro Kusumi if (test_voldata(fp))
3900b738157STomohiro Kusumi goto fail;
3910b738157STomohiro Kusumi
3920b738157STomohiro Kusumi error = read_label(fp, label, size, devpath);
3930b738157STomohiro Kusumi fail:
3940b738157STomohiro Kusumi free(voldata);
3950b738157STomohiro Kusumi return (error);
3960b738157STomohiro Kusumi }
3970b738157STomohiro Kusumi
3980b738157STomohiro Kusumi static int
__fsvtyp_hammer2(const char * blkdevs,char * label,size_t size,int partial)3990b738157STomohiro Kusumi __fsvtyp_hammer2(const char *blkdevs, char *label, size_t size, int partial)
4000b738157STomohiro Kusumi {
4010b738157STomohiro Kusumi hammer2_volume_data_t *voldata = NULL;
4020b738157STomohiro Kusumi FILE *fp = NULL;
4030b738157STomohiro Kusumi char *dup = NULL, *target_label = NULL, *p, *volpath, *rootvolpath;
4040b738157STomohiro Kusumi char x[HAMMER2_MAX_VOLUMES];
4050b738157STomohiro Kusumi int i, volid, error = 1;
4060b738157STomohiro Kusumi
4070b738157STomohiro Kusumi if (!blkdevs)
4080b738157STomohiro Kusumi goto fail;
4090b738157STomohiro Kusumi
4100b738157STomohiro Kusumi memset(x, 0, sizeof(x));
4110b738157STomohiro Kusumi p = dup = strdup(blkdevs);
4120b738157STomohiro Kusumi if ((p = strchr(p, '@')) != NULL) {
4130b738157STomohiro Kusumi *p++ = '\0';
4140b738157STomohiro Kusumi target_label = p;
4150b738157STomohiro Kusumi }
4160b738157STomohiro Kusumi p = dup;
4170b738157STomohiro Kusumi
4180b738157STomohiro Kusumi volpath = NULL;
4190b738157STomohiro Kusumi rootvolpath = NULL;
4200b738157STomohiro Kusumi volid = -1;
4210b738157STomohiro Kusumi while (p) {
4220b738157STomohiro Kusumi volpath = p;
4230b738157STomohiro Kusumi if ((p = strchr(p, ':')) != NULL)
4240b738157STomohiro Kusumi *p++ = '\0';
4250b738157STomohiro Kusumi if ((fp = fopen(volpath, "r")) == NULL) {
4260b738157STomohiro Kusumi warnx("hammer2: failed to open %s", volpath);
4270b738157STomohiro Kusumi goto fail;
4280b738157STomohiro Kusumi }
4290b738157STomohiro Kusumi if (test_voldata(fp))
4300b738157STomohiro Kusumi break;
4310b738157STomohiro Kusumi voldata = read_voldata(fp, 0);
4320b738157STomohiro Kusumi fclose(fp);
4330b738157STomohiro Kusumi if (voldata == NULL) {
4340b738157STomohiro Kusumi warnx("hammer2: failed to read volume data");
4350b738157STomohiro Kusumi goto fail;
4360b738157STomohiro Kusumi }
4370b738157STomohiro Kusumi volid = voldata->volu_id;
4380b738157STomohiro Kusumi free(voldata);
4390b738157STomohiro Kusumi voldata = NULL;
4405721f2ecSTomohiro Kusumi if (volid < 0 || volid >= HAMMER2_MAX_VOLUMES)
4415721f2ecSTomohiro Kusumi goto fail;
4420b738157STomohiro Kusumi x[volid]++;
4430b738157STomohiro Kusumi if (volid == HAMMER2_ROOT_VOLUME)
4440b738157STomohiro Kusumi rootvolpath = volpath;
4450b738157STomohiro Kusumi }
4460b738157STomohiro Kusumi
4470b738157STomohiro Kusumi /* If no rootvolpath, proceed only if partial mode with volpath. */
4480b738157STomohiro Kusumi if (rootvolpath)
4490b738157STomohiro Kusumi volpath = rootvolpath;
4500b738157STomohiro Kusumi else if (!partial || !volpath)
4510b738157STomohiro Kusumi goto fail;
4520b738157STomohiro Kusumi if ((fp = fopen(volpath, "r")) == NULL) {
4530b738157STomohiro Kusumi warnx("hammer2: failed to open %s", volpath);
4540b738157STomohiro Kusumi goto fail;
4550b738157STomohiro Kusumi }
4560b738157STomohiro Kusumi voldata = read_voldata(fp, 0);
4570b738157STomohiro Kusumi if (voldata == NULL) {
4580b738157STomohiro Kusumi warnx("hammer2: failed to read volume data");
4590b738157STomohiro Kusumi goto fail;
4600b738157STomohiro Kusumi }
4610b738157STomohiro Kusumi
4620b738157STomohiro Kusumi if (volid == -1)
4630b738157STomohiro Kusumi goto fail;
4640b738157STomohiro Kusumi if (partial)
4650b738157STomohiro Kusumi goto success;
4660b738157STomohiro Kusumi
4670b738157STomohiro Kusumi for (i = 0; i < HAMMER2_MAX_VOLUMES; i++)
4680b738157STomohiro Kusumi if (x[i] > 1)
4690b738157STomohiro Kusumi goto fail;
4700b738157STomohiro Kusumi for (i = 0; i < HAMMER2_MAX_VOLUMES; i++)
4710b738157STomohiro Kusumi if (x[i] == 0)
4720b738157STomohiro Kusumi break;
4730b738157STomohiro Kusumi if (voldata->nvolumes != i)
4740b738157STomohiro Kusumi goto fail;
4750b738157STomohiro Kusumi for (; i < HAMMER2_MAX_VOLUMES; i++)
4760b738157STomohiro Kusumi if (x[i] != 0)
4770b738157STomohiro Kusumi goto fail;
4780b738157STomohiro Kusumi success:
4790b738157STomohiro Kusumi /* Reconstruct @label format path using only root volume. */
4800b738157STomohiro Kusumi if (target_label) {
481*11dd095cSTomohiro Kusumi size_t siz = strlen(volpath) + strlen(target_label) + 2;
4820b738157STomohiro Kusumi p = calloc(1, siz);
4830b738157STomohiro Kusumi snprintf(p, siz, "%s@%s", volpath, target_label);
4840b738157STomohiro Kusumi volpath = p;
4850b738157STomohiro Kusumi }
4860b738157STomohiro Kusumi error = read_label(fp, label, size, volpath);
4870b738157STomohiro Kusumi if (target_label)
4880b738157STomohiro Kusumi free(p);
4890b738157STomohiro Kusumi /* If in partial mode, read label but ignore error. */
4900b738157STomohiro Kusumi if (partial)
4910b738157STomohiro Kusumi error = 0;
4920b738157STomohiro Kusumi fail:
4930b738157STomohiro Kusumi if (fp)
4940b738157STomohiro Kusumi fclose(fp);
4950b738157STomohiro Kusumi free(voldata);
4960b738157STomohiro Kusumi free(dup);
4970b738157STomohiro Kusumi return (error);
4980b738157STomohiro Kusumi }
4990b738157STomohiro Kusumi
5000b738157STomohiro Kusumi int
fsvtyp_hammer2(const char * blkdevs,char * label,size_t size)5010b738157STomohiro Kusumi fsvtyp_hammer2(const char *blkdevs, char *label, size_t size)
5020b738157STomohiro Kusumi {
5030b738157STomohiro Kusumi return (__fsvtyp_hammer2(blkdevs, label, size, 0));
5040b738157STomohiro Kusumi }
5050b738157STomohiro Kusumi
5060b738157STomohiro Kusumi int
fsvtyp_hammer2_partial(const char * blkdevs,char * label,size_t size)5070b738157STomohiro Kusumi fsvtyp_hammer2_partial(const char *blkdevs, char *label, size_t size)
5080b738157STomohiro Kusumi {
5090b738157STomohiro Kusumi return (__fsvtyp_hammer2(blkdevs, label, size, 1));
510030fdd8aSTomohiro Kusumi }
511