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 <vfs/hammer/hammer_disk.h> 34 35 #include "fstyp.h" 36 37 static hammer_volume_ondisk_t 38 read_ondisk(FILE *fp) 39 { 40 hammer_volume_ondisk_t ondisk; 41 42 ondisk = read_buf(fp, 0, sizeof(*ondisk)); 43 if (ondisk == NULL) 44 err(1, "failed to read ondisk"); 45 46 return (ondisk); 47 } 48 49 static int 50 test_ondisk(const hammer_volume_ondisk_t ondisk) 51 { 52 static int count = 0; 53 static hammer_uuid_t fsid, fstype; 54 static char label[64]; 55 56 if (ondisk->vol_signature != HAMMER_FSBUF_VOLUME && 57 ondisk->vol_signature != HAMMER_FSBUF_VOLUME_REV) 58 return (1); 59 if (ondisk->vol_rootvol != HAMMER_ROOT_VOLNO) 60 return (2); 61 if (ondisk->vol_no < 0 || ondisk->vol_no > HAMMER_MAX_VOLUMES - 1) 62 return (3); 63 if (ondisk->vol_count < 1 || ondisk->vol_count > HAMMER_MAX_VOLUMES) 64 return (4); 65 66 if (count == 0) { 67 count = ondisk->vol_count; 68 assert(count != 0); 69 memcpy(&fsid, &ondisk->vol_fsid, sizeof(fsid)); 70 memcpy(&fstype, &ondisk->vol_fstype, sizeof(fstype)); 71 strlcpy(label, ondisk->vol_label, sizeof(label)); 72 } else { 73 if (ondisk->vol_count != count) 74 return (5); 75 if (memcmp(&ondisk->vol_fsid, &fsid, sizeof(fsid))) 76 return (6); 77 if (memcmp(&ondisk->vol_fstype, &fstype, sizeof(fstype))) 78 return (7); 79 if (strcmp(ondisk->vol_label, label)) 80 return (8); 81 } 82 83 return (0); 84 } 85 86 int 87 fstyp_hammer(FILE *fp, char *label, size_t size, const char *devpath) 88 { 89 hammer_volume_ondisk_t ondisk; 90 int error = 1; 91 #ifdef HAS_DEVPATH 92 const char *p; 93 #endif 94 ondisk = read_ondisk(fp); 95 if (ondisk->vol_no != HAMMER_ROOT_VOLNO) 96 goto fail; 97 if (ondisk->vol_count != 1) 98 goto fail; 99 if (test_ondisk(ondisk)) 100 goto fail; 101 102 /* 103 * fstyp_function in DragonFly takes an additional devpath argument 104 * which doesn't exist in FreeBSD and NetBSD. 105 */ 106 #ifdef HAS_DEVPATH 107 /* Add device name to help support multiple autofs -media mounts. */ 108 p = strrchr(devpath, '/'); 109 if (p) { 110 p++; 111 if (*p == 0) 112 strlcpy(label, ondisk->vol_label, size); 113 else 114 snprintf(label, size, "%s_%s", ondisk->vol_label, p); 115 } else 116 snprintf(label, size, "%s_%s", ondisk->vol_label, devpath); 117 #else 118 strlcpy(label, ondisk->vol_label, size); 119 #endif 120 error = 0; 121 fail: 122 free(ondisk); 123 return (error); 124 } 125 126 static int 127 test_volume(const char *volpath) 128 { 129 hammer_volume_ondisk_t ondisk; 130 FILE *fp; 131 int volno = -1; 132 133 if ((fp = fopen(volpath, "r")) == NULL) 134 err(1, "failed to open %s", volpath); 135 136 ondisk = read_ondisk(fp); 137 fclose(fp); 138 if (test_ondisk(ondisk)) 139 goto fail; 140 141 volno = ondisk->vol_no; 142 fail: 143 free(ondisk); 144 return (volno); 145 } 146 147 static int 148 __fsvtyp_hammer(const char *blkdevs, char *label, size_t size, int partial) 149 { 150 hammer_volume_ondisk_t ondisk = NULL; 151 FILE *fp; 152 char *dup, *p, *volpath, x[HAMMER_MAX_VOLUMES]; 153 int i, volno, error = 1; 154 155 if (!blkdevs) 156 goto fail; 157 158 memset(x, 0, sizeof(x)); 159 dup = strdup(blkdevs); 160 p = dup; 161 162 volpath = NULL; 163 volno = -1; 164 while (p) { 165 volpath = p; 166 if ((p = strchr(p, ':')) != NULL) 167 *p++ = '\0'; 168 if ((volno = test_volume(volpath)) == -1) 169 break; 170 assert(volno >= 0); 171 assert(volno < HAMMER_MAX_VOLUMES); 172 x[volno]++; 173 } 174 175 if (!volpath) 176 err(1, "invalid path %s", blkdevs); 177 if ((fp = fopen(volpath, "r")) == NULL) 178 err(1, "failed to open %s", volpath); 179 ondisk = read_ondisk(fp); 180 fclose(fp); 181 182 free(dup); 183 184 if (volno == -1) 185 goto fail; 186 if (partial) 187 goto success; 188 189 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) 190 if (x[i] > 1) 191 goto fail; 192 for (i = 0; i < HAMMER_MAX_VOLUMES; i++) 193 if (x[i] == 0) 194 break; 195 if (ondisk->vol_count != i) 196 goto fail; 197 for (; i < HAMMER_MAX_VOLUMES; i++) 198 if (x[i] != 0) 199 goto fail; 200 success: 201 /* XXX autofs -media mount can't handle multiple mounts */ 202 strlcpy(label, ondisk->vol_label, size); 203 error = 0; 204 fail: 205 free(ondisk); 206 return (error); 207 } 208 209 int 210 fsvtyp_hammer(const char *blkdevs, char *label, size_t size) 211 { 212 return (__fsvtyp_hammer(blkdevs, label, size, 0)); 213 } 214 215 int 216 fsvtyp_hammer_partial(const char *blkdevs, char *label, size_t size) 217 { 218 return (__fsvtyp_hammer(blkdevs, label, size, 1)); 219 } 220