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