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 42 read_ondisk(FILE *fp) 43 { 44 return (read_buf(fp, 0, sizeof(struct hammer_volume_ondisk))); 45 } 46 47 static int 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* 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 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 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 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 238 fsvtyp_hammer(const char *blkdevs, char *label, size_t size) 239 { 240 return (__fsvtyp_hammer(blkdevs, label, size, 0)); 241 } 242 243 int 244 fsvtyp_hammer_partial(const char *blkdevs, char *label, size_t size) 245 { 246 return (__fsvtyp_hammer(blkdevs, label, size, 1)); 247 } 248