xref: /dragonfly/usr.sbin/fstyp/hammer2.c (revision 11dd095c)
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