Home | History | Annotate | Line # | Download | only in fstyp
      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 (at) 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