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