xref: /dragonfly/usr.sbin/fstyp/hammer.c (revision 25dcc235)
1 /*-
2  * Copyright (c) 2016-2019 The DragonFly Project
3  * Copyright (c) 2016-2019 Tomohiro Kusumi <tkusumi@netbsd.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <err.h>
32 #include <assert.h>
33 #include <uuid.h>
34 #include <vfs/hammer/hammer_disk.h>
35 
36 #include "fstyp.h"
37 
38 static hammer_volume_ondisk_t
39 read_ondisk(FILE *fp)
40 {
41 	hammer_volume_ondisk_t ondisk;
42 
43 	ondisk = read_buf(fp, 0, sizeof(*ondisk));
44 	if (ondisk == NULL)
45 		err(1, "failed to read ondisk");
46 
47 	return (ondisk);
48 }
49 
50 static int
51 test_ondisk(const hammer_volume_ondisk_t ondisk)
52 {
53 	static int count = 0;
54 	static hammer_uuid_t fsid, fstype;
55 	static char label[64];
56 
57 	if (ondisk->vol_signature != HAMMER_FSBUF_VOLUME &&
58 	    ondisk->vol_signature != HAMMER_FSBUF_VOLUME_REV)
59 		return (1);
60 	if (ondisk->vol_rootvol != HAMMER_ROOT_VOLNO)
61 		return (2);
62 	if (ondisk->vol_no < 0 || ondisk->vol_no > HAMMER_MAX_VOLUMES - 1)
63 		return (3);
64 	if (ondisk->vol_count < 1 || ondisk->vol_count > HAMMER_MAX_VOLUMES)
65 		return (4);
66 
67 	if (count == 0) {
68 		count = ondisk->vol_count;
69 		assert(count != 0);
70 		memcpy(&fsid, &ondisk->vol_fsid, sizeof(fsid));
71 		memcpy(&fstype, &ondisk->vol_fstype, sizeof(fstype));
72 		strlcpy(label, ondisk->vol_label, sizeof(label));
73 	} else {
74 		if (ondisk->vol_count != count)
75 			return (5);
76 		if (!uuid_equal(&ondisk->vol_fsid, &fsid, NULL))
77 			return (6);
78 		if (!uuid_equal(&ondisk->vol_fstype, &fstype, NULL))
79 			return (7);
80 		if (strcmp(ondisk->vol_label, label))
81 			return (8);
82 	}
83 
84 	return (0);
85 }
86 
87 static const char*
88 extract_device_name(const char *devpath)
89 {
90 	const char *p;
91 
92 	p = strrchr(devpath, '/');
93 	if (p) {
94 		p++;
95 		if (*p == 0)
96 			p = NULL;
97 	} else {
98 		p = devpath;
99 	}
100 	return (p);
101 }
102 
103 int
104 fstyp_hammer(FILE *fp, char *label, size_t size, const char *devpath)
105 {
106 	hammer_volume_ondisk_t ondisk;
107 	int error = 1;
108 #ifdef HAS_DEVPATH
109 	const char *p;
110 #endif
111 	ondisk = read_ondisk(fp);
112 	if (ondisk->vol_no != HAMMER_ROOT_VOLNO)
113 		goto fail;
114 	if (ondisk->vol_count != 1)
115 		goto fail;
116 	if (test_ondisk(ondisk))
117 		goto fail;
118 
119 	/*
120 	 * fstyp_function in DragonFly takes an additional devpath argument
121 	 * which doesn't exist in FreeBSD and NetBSD.
122 	 */
123 #ifdef HAS_DEVPATH
124 	/* Add device name to help support multiple autofs -media mounts. */
125 	p = extract_device_name(devpath);
126 	if (p)
127 		snprintf(label, size, "%s_%s", ondisk->vol_label, p);
128 	else
129 		strlcpy(label, ondisk->vol_label, size);
130 #else
131 	strlcpy(label, ondisk->vol_label, size);
132 #endif
133 	error = 0;
134 fail:
135 	free(ondisk);
136 	return (error);
137 }
138 
139 static int
140 test_volume(const char *volpath)
141 {
142 	hammer_volume_ondisk_t ondisk = NULL;
143 	FILE *fp;
144 	int volno = -1;
145 
146 	if ((fp = fopen(volpath, "r")) == NULL)
147 		goto fail;
148 
149 	ondisk = read_ondisk(fp);
150 	fclose(fp);
151 	if (test_ondisk(ondisk))
152 		goto fail;
153 
154 	volno = ondisk->vol_no;
155 fail:
156 	free(ondisk);
157 	return (volno);
158 }
159 
160 static int
161 __fsvtyp_hammer(const char *blkdevs, char *label, size_t size, int partial)
162 {
163 	hammer_volume_ondisk_t ondisk = NULL;
164 	FILE *fp;
165 	char *dup = NULL, *p, *volpath, *rootvolpath, x[HAMMER_MAX_VOLUMES];
166 	int i, volno, error = 1;
167 
168 	if (!blkdevs)
169 		goto fail;
170 
171 	memset(x, 0, sizeof(x));
172 	dup = strdup(blkdevs);
173 	p = dup;
174 
175 	volpath = NULL;
176 	rootvolpath = NULL;
177 	volno = -1;
178 	while (p) {
179 		volpath = p;
180 		if ((p = strchr(p, ':')) != NULL)
181 			*p++ = '\0';
182 		if ((volno = test_volume(volpath)) == -1)
183 			break;
184 		assert(volno >= 0);
185 		assert(volno < HAMMER_MAX_VOLUMES);
186 		x[volno]++;
187 		if (volno == HAMMER_ROOT_VOLNO)
188 			rootvolpath = volpath;
189 	}
190 
191 	/* If no rootvolpath, proceed only if partial mode with volpath. */
192 	if (rootvolpath)
193 		volpath = rootvolpath;
194 	else if (!partial || !volpath)
195 		goto fail;
196 	if ((fp = fopen(volpath, "r")) == NULL)
197 		goto fail;
198 	ondisk = read_ondisk(fp);
199 	fclose(fp);
200 
201 	if (volno == -1)
202 		goto fail;
203 	if (partial)
204 		goto success;
205 
206 	for (i = 0; i < HAMMER_MAX_VOLUMES; i++)
207 		if (x[i] > 1)
208 			goto fail;
209 	for (i = 0; i < HAMMER_MAX_VOLUMES; i++)
210 		if (x[i] == 0)
211 			break;
212 	if (ondisk->vol_count != i)
213 		goto fail;
214 	for (; i < HAMMER_MAX_VOLUMES; i++)
215 		if (x[i] != 0)
216 			goto fail;
217 success:
218 	/* Add device name to help support multiple autofs -media mounts. */
219 	p = (char*)extract_device_name(volpath);
220 	if (p)
221 		snprintf(label, size, "%s_%s", ondisk->vol_label, p);
222 	else
223 		strlcpy(label, ondisk->vol_label, size);
224 	error = 0;
225 fail:
226 	free(ondisk);
227 	free(dup);
228 	return (error);
229 }
230 
231 int
232 fsvtyp_hammer(const char *blkdevs, char *label, size_t size)
233 {
234 	return (__fsvtyp_hammer(blkdevs, label, size, 0));
235 }
236 
237 int
238 fsvtyp_hammer_partial(const char *blkdevs, char *label, size_t size)
239 {
240 	return (__fsvtyp_hammer(blkdevs, label, size, 1));
241 }
242