xref: /freebsd/usr.sbin/fstyp/hammer.c (revision da0c0e0121574a1d82f417cc7e245ecd5506325c)
1509798eaSPedro F. Giffuni /*-
29d529ed8SPedro F. Giffuni  * Copyright (c) 2016-2019 The DragonFly Project
39d529ed8SPedro F. Giffuni  * Copyright (c) 2016-2019 Tomohiro Kusumi <tkusumi@netbsd.org>
4509798eaSPedro F. Giffuni  * All rights reserved.
5509798eaSPedro F. Giffuni  *
6509798eaSPedro F. Giffuni  * This software was developed by Edward Tomasz Napierala under sponsorship
7509798eaSPedro F. Giffuni  * from the FreeBSD Foundation.
8509798eaSPedro F. Giffuni  *
9509798eaSPedro F. Giffuni  * Redistribution and use in source and binary forms, with or without
10509798eaSPedro F. Giffuni  * modification, are permitted provided that the following conditions
11509798eaSPedro F. Giffuni  * are met:
12509798eaSPedro F. Giffuni  * 1. Redistributions of source code must retain the above copyright
13509798eaSPedro F. Giffuni  *    notice, this list of conditions and the following disclaimer.
14509798eaSPedro F. Giffuni  * 2. Redistributions in binary form must reproduce the above copyright
15509798eaSPedro F. Giffuni  *    notice, this list of conditions and the following disclaimer in the
16509798eaSPedro F. Giffuni  *    documentation and/or other materials provided with the distribution.
17509798eaSPedro F. Giffuni  *
18509798eaSPedro F. Giffuni  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19509798eaSPedro F. Giffuni  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20509798eaSPedro F. Giffuni  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21509798eaSPedro F. Giffuni  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22509798eaSPedro F. Giffuni  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23509798eaSPedro F. Giffuni  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24509798eaSPedro F. Giffuni  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25509798eaSPedro F. Giffuni  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26509798eaSPedro F. Giffuni  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27509798eaSPedro F. Giffuni  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28509798eaSPedro F. Giffuni  * SUCH DAMAGE.
29509798eaSPedro F. Giffuni  */
30509798eaSPedro F. Giffuni 
31509798eaSPedro F. Giffuni #include <sys/cdefs.h>
32509798eaSPedro F. Giffuni __FBSDID("$FreeBSD$");
33509798eaSPedro F. Giffuni 
34509798eaSPedro F. Giffuni #include <stdio.h>
35509798eaSPedro F. Giffuni #include <stdlib.h>
36509798eaSPedro F. Giffuni #include <string.h>
37509798eaSPedro F. Giffuni #include <err.h>
38509798eaSPedro F. Giffuni #include <assert.h>
39509798eaSPedro F. Giffuni 
40509798eaSPedro F. Giffuni #include <sys/types.h>
41509798eaSPedro F. Giffuni 
42509798eaSPedro F. Giffuni #include "hammer_disk.h"
43509798eaSPedro F. Giffuni 
44509798eaSPedro F. Giffuni #include "fstyp.h"
45509798eaSPedro F. Giffuni 
46*da0c0e01SPiotr Pawel Stefaniak extern int fsvtyp_hammer(const char *blkdevs, char *label, size_t size);
47*da0c0e01SPiotr Pawel Stefaniak extern int fsvtyp_hammer_partial(const char *blkdevs, char *label, size_t size);
48*da0c0e01SPiotr Pawel Stefaniak 
49509798eaSPedro F. Giffuni static hammer_volume_ondisk_t
509d529ed8SPedro F. Giffuni read_ondisk(FILE *fp)
51509798eaSPedro F. Giffuni {
52509798eaSPedro F. Giffuni 	hammer_volume_ondisk_t ondisk;
53509798eaSPedro F. Giffuni 
54509798eaSPedro F. Giffuni 	ondisk = read_buf(fp, 0, sizeof(*ondisk));
55509798eaSPedro F. Giffuni 	if (ondisk == NULL)
56509798eaSPedro F. Giffuni 		err(1, "failed to read ondisk");
57509798eaSPedro F. Giffuni 
58509798eaSPedro F. Giffuni 	return (ondisk);
59509798eaSPedro F. Giffuni }
60509798eaSPedro F. Giffuni 
61509798eaSPedro F. Giffuni static int
629d529ed8SPedro F. Giffuni test_ondisk(const hammer_volume_ondisk_t ondisk)
63509798eaSPedro F. Giffuni {
64509798eaSPedro F. Giffuni 	static int count = 0;
65509798eaSPedro F. Giffuni 	static hammer_uuid_t fsid, fstype;
66509798eaSPedro F. Giffuni 	static char label[64];
67509798eaSPedro F. Giffuni 
68509798eaSPedro F. Giffuni 	if (ondisk->vol_signature != HAMMER_FSBUF_VOLUME &&
69509798eaSPedro F. Giffuni 	    ondisk->vol_signature != HAMMER_FSBUF_VOLUME_REV)
70509798eaSPedro F. Giffuni 		return (1);
71509798eaSPedro F. Giffuni 	if (ondisk->vol_rootvol != HAMMER_ROOT_VOLNO)
72509798eaSPedro F. Giffuni 		return (2);
73509798eaSPedro F. Giffuni 	if (ondisk->vol_no < 0 || ondisk->vol_no > HAMMER_MAX_VOLUMES - 1)
74509798eaSPedro F. Giffuni 		return (3);
75509798eaSPedro F. Giffuni 	if (ondisk->vol_count < 1 || ondisk->vol_count > HAMMER_MAX_VOLUMES)
76509798eaSPedro F. Giffuni 		return (4);
77509798eaSPedro F. Giffuni 
78509798eaSPedro F. Giffuni 	if (count == 0) {
79509798eaSPedro F. Giffuni 		count = ondisk->vol_count;
80509798eaSPedro F. Giffuni 		assert(count != 0);
81509798eaSPedro F. Giffuni 		memcpy(&fsid, &ondisk->vol_fsid, sizeof(fsid));
82509798eaSPedro F. Giffuni 		memcpy(&fstype, &ondisk->vol_fstype, sizeof(fstype));
830ab52bd3SEric van Gyzen 		strlcpy(label, ondisk->vol_label, sizeof(label));
84509798eaSPedro F. Giffuni 	} else {
85509798eaSPedro F. Giffuni 		if (ondisk->vol_count != count)
86509798eaSPedro F. Giffuni 			return (5);
87509798eaSPedro F. Giffuni 		if (memcmp(&ondisk->vol_fsid, &fsid, sizeof(fsid)))
88509798eaSPedro F. Giffuni 			return (6);
89509798eaSPedro F. Giffuni 		if (memcmp(&ondisk->vol_fstype, &fstype, sizeof(fstype)))
90509798eaSPedro F. Giffuni 			return (7);
910ab52bd3SEric van Gyzen 		if (strcmp(ondisk->vol_label, label))
92509798eaSPedro F. Giffuni 			return (8);
93509798eaSPedro F. Giffuni 	}
94509798eaSPedro F. Giffuni 
95509798eaSPedro F. Giffuni 	return (0);
96509798eaSPedro F. Giffuni }
97509798eaSPedro F. Giffuni 
98509798eaSPedro F. Giffuni int
99509798eaSPedro F. Giffuni fstyp_hammer(FILE *fp, char *label, size_t size)
100509798eaSPedro F. Giffuni {
101509798eaSPedro F. Giffuni 	hammer_volume_ondisk_t ondisk;
102509798eaSPedro F. Giffuni 	int error = 1;
103509798eaSPedro F. Giffuni 
1049d529ed8SPedro F. Giffuni 	ondisk = read_ondisk(fp);
105509798eaSPedro F. Giffuni 	if (ondisk->vol_no != HAMMER_ROOT_VOLNO)
1069d529ed8SPedro F. Giffuni 		goto fail;
107509798eaSPedro F. Giffuni 	if (ondisk->vol_count != 1)
1089d529ed8SPedro F. Giffuni 		goto fail;
1099d529ed8SPedro F. Giffuni 	if (test_ondisk(ondisk))
1109d529ed8SPedro F. Giffuni 		goto fail;
111509798eaSPedro F. Giffuni 
112509798eaSPedro F. Giffuni 	strlcpy(label, ondisk->vol_label, size);
113509798eaSPedro F. Giffuni 	error = 0;
1149d529ed8SPedro F. Giffuni fail:
115509798eaSPedro F. Giffuni 	free(ondisk);
116509798eaSPedro F. Giffuni 	return (error);
117509798eaSPedro F. Giffuni }
118509798eaSPedro F. Giffuni 
119509798eaSPedro F. Giffuni static int
1209d529ed8SPedro F. Giffuni test_volume(const char *volpath)
121509798eaSPedro F. Giffuni {
122509798eaSPedro F. Giffuni 	hammer_volume_ondisk_t ondisk;
123509798eaSPedro F. Giffuni 	FILE *fp;
124509798eaSPedro F. Giffuni 	int volno = -1;
125509798eaSPedro F. Giffuni 
126509798eaSPedro F. Giffuni 	if ((fp = fopen(volpath, "r")) == NULL)
127509798eaSPedro F. Giffuni 		err(1, "failed to open %s", volpath);
128509798eaSPedro F. Giffuni 
1299d529ed8SPedro F. Giffuni 	ondisk = read_ondisk(fp);
130509798eaSPedro F. Giffuni 	fclose(fp);
1319d529ed8SPedro F. Giffuni 	if (test_ondisk(ondisk))
1329d529ed8SPedro F. Giffuni 		goto fail;
133509798eaSPedro F. Giffuni 
134509798eaSPedro F. Giffuni 	volno = ondisk->vol_no;
1359d529ed8SPedro F. Giffuni fail:
136509798eaSPedro F. Giffuni 	free(ondisk);
137509798eaSPedro F. Giffuni 	return (volno);
138509798eaSPedro F. Giffuni }
139509798eaSPedro F. Giffuni 
140509798eaSPedro F. Giffuni static int
141509798eaSPedro F. Giffuni __fsvtyp_hammer(const char *blkdevs, char *label, size_t size, int partial)
142509798eaSPedro F. Giffuni {
1439d529ed8SPedro F. Giffuni 	hammer_volume_ondisk_t ondisk = NULL;
144509798eaSPedro F. Giffuni 	FILE *fp;
145509798eaSPedro F. Giffuni 	char *dup, *p, *volpath, x[HAMMER_MAX_VOLUMES];
146509798eaSPedro F. Giffuni 	int i, volno, error = 1;
147509798eaSPedro F. Giffuni 
1489d529ed8SPedro F. Giffuni 	if (!blkdevs)
1499d529ed8SPedro F. Giffuni 		goto fail;
1509d529ed8SPedro F. Giffuni 
151509798eaSPedro F. Giffuni 	memset(x, 0, sizeof(x));
152509798eaSPedro F. Giffuni 	dup = strdup(blkdevs);
153509798eaSPedro F. Giffuni 	p = dup;
154509798eaSPedro F. Giffuni 
1559d529ed8SPedro F. Giffuni 	volpath = NULL;
1569d529ed8SPedro F. Giffuni 	volno = -1;
157509798eaSPedro F. Giffuni 	while (p) {
158509798eaSPedro F. Giffuni 		volpath = p;
159509798eaSPedro F. Giffuni 		if ((p = strchr(p, ':')) != NULL)
160509798eaSPedro F. Giffuni 			*p++ = '\0';
1619d529ed8SPedro F. Giffuni 		if ((volno = test_volume(volpath)) == -1)
162509798eaSPedro F. Giffuni 			break;
1639d529ed8SPedro F. Giffuni 		assert(volno >= 0);
1649d529ed8SPedro F. Giffuni 		assert(volno < HAMMER_MAX_VOLUMES);
165509798eaSPedro F. Giffuni 		x[volno]++;
166509798eaSPedro F. Giffuni 	}
167509798eaSPedro F. Giffuni 
1689d529ed8SPedro F. Giffuni 	if (!volpath)
1699d529ed8SPedro F. Giffuni 		err(1, "invalid path %s", blkdevs);
170509798eaSPedro F. Giffuni 	if ((fp = fopen(volpath, "r")) == NULL)
171509798eaSPedro F. Giffuni 		err(1, "failed to open %s", volpath);
1729d529ed8SPedro F. Giffuni 	ondisk = read_ondisk(fp);
173509798eaSPedro F. Giffuni 	fclose(fp);
174509798eaSPedro F. Giffuni 
175509798eaSPedro F. Giffuni 	free(dup);
176509798eaSPedro F. Giffuni 
177509798eaSPedro F. Giffuni 	if (volno == -1)
1789d529ed8SPedro F. Giffuni 		goto fail;
179509798eaSPedro F. Giffuni 	if (partial)
180509798eaSPedro F. Giffuni 		goto success;
181509798eaSPedro F. Giffuni 
182509798eaSPedro F. Giffuni 	for (i = 0; i < HAMMER_MAX_VOLUMES; i++)
183509798eaSPedro F. Giffuni 		if (x[i] > 1)
1849d529ed8SPedro F. Giffuni 			goto fail;
185509798eaSPedro F. Giffuni 	for (i = 0; i < HAMMER_MAX_VOLUMES; i++)
186509798eaSPedro F. Giffuni 		if (x[i] == 0)
187509798eaSPedro F. Giffuni 			break;
188509798eaSPedro F. Giffuni 	if (ondisk->vol_count != i)
1899d529ed8SPedro F. Giffuni 		goto fail;
190509798eaSPedro F. Giffuni 	for (; i < HAMMER_MAX_VOLUMES; i++)
191509798eaSPedro F. Giffuni 		if (x[i] != 0)
1929d529ed8SPedro F. Giffuni 			goto fail;
193509798eaSPedro F. Giffuni success:
194509798eaSPedro F. Giffuni 	strlcpy(label, ondisk->vol_label, size);
195509798eaSPedro F. Giffuni 	error = 0;
1969d529ed8SPedro F. Giffuni fail:
197509798eaSPedro F. Giffuni 	free(ondisk);
198509798eaSPedro F. Giffuni 	return (error);
199509798eaSPedro F. Giffuni }
200509798eaSPedro F. Giffuni 
201509798eaSPedro F. Giffuni int
202509798eaSPedro F. Giffuni fsvtyp_hammer(const char *blkdevs, char *label, size_t size)
203509798eaSPedro F. Giffuni {
204509798eaSPedro F. Giffuni 	return (__fsvtyp_hammer(blkdevs, label, size, 0));
205509798eaSPedro F. Giffuni }
206509798eaSPedro F. Giffuni 
207509798eaSPedro F. Giffuni int
208509798eaSPedro F. Giffuni fsvtyp_hammer_partial(const char *blkdevs, char *label, size_t size)
209509798eaSPedro F. Giffuni {
210509798eaSPedro F. Giffuni 	return (__fsvtyp_hammer(blkdevs, label, size, 1));
211509798eaSPedro F. Giffuni }
212