diff options
Diffstat (limited to 'sys/geom/label')
| -rw-r--r-- | sys/geom/label/g_label.c | 586 | ||||
| -rw-r--r-- | sys/geom/label/g_label.h | 110 | ||||
| -rw-r--r-- | sys/geom/label/g_label_disk_ident.c | 84 | ||||
| -rw-r--r-- | sys/geom/label/g_label_ext2fs.c | 104 | ||||
| -rw-r--r-- | sys/geom/label/g_label_flashmap.c | 72 | ||||
| -rw-r--r-- | sys/geom/label/g_label_gpt.c | 166 | ||||
| -rw-r--r-- | sys/geom/label/g_label_iso9660.c | 78 | ||||
| -rw-r--r-- | sys/geom/label/g_label_msdosfs.c | 225 | ||||
| -rw-r--r-- | sys/geom/label/g_label_msdosfs.h | 140 | ||||
| -rw-r--r-- | sys/geom/label/g_label_ntfs.c | 185 | ||||
| -rw-r--r-- | sys/geom/label/g_label_swaplinux.c | 91 | ||||
| -rw-r--r-- | sys/geom/label/g_label_ufs.c | 206 | 
12 files changed, 2047 insertions, 0 deletions
| diff --git a/sys/geom/label/g_label.c b/sys/geom/label/g_label.c new file mode 100644 index 000000000000..faefbd7c2ef6 --- /dev/null +++ b/sys/geom/label/g_label.c @@ -0,0 +1,586 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include "opt_geom.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/bio.h> +#include <sys/ctype.h> +#include <sys/malloc.h> +#include <sys/libkern.h> +#include <sys/sbuf.h> +#include <sys/stddef.h> +#include <sys/sysctl.h> +#include <geom/geom.h> +#include <geom/geom_dbg.h> +#include <geom/geom_slice.h> +#include <geom/label/g_label.h> + +FEATURE(geom_label, "GEOM labeling support"); + +SYSCTL_DECL(_kern_geom); +SYSCTL_NODE(_kern_geom, OID_AUTO, label, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, +    "GEOM_LABEL stuff"); +u_int g_label_debug = 0; +SYSCTL_UINT(_kern_geom_label, OID_AUTO, debug, CTLFLAG_RWTUN, &g_label_debug, 0, +    "Debug level"); + +static int g_label_destroy_geom(struct gctl_req *req, struct g_class *mp, +    struct g_geom *gp); +static int g_label_destroy(struct g_geom *gp, boolean_t force); +static struct g_geom *g_label_taste(struct g_class *mp, struct g_provider *pp, +    int flags __unused); +static void g_label_generic_taste(struct g_consumer *, char *, size_t); +static void g_label_config(struct gctl_req *req, struct g_class *mp, +    const char *verb); + +#define	G_LABEL_DIRPREFIX	"label/" + +struct g_class g_label_class = { +	.name = G_LABEL_CLASS_NAME, +	.version = G_VERSION, +	.ctlreq = g_label_config, +	.taste = g_label_taste, +	.destroy_geom = g_label_destroy_geom +}; + +static struct g_label_desc g_label_generic = { +        .ld_taste = g_label_generic_taste, +        .ld_dirprefix = G_LABEL_DIRPREFIX, +        .ld_enabled = 1 +}; + +/* + * To add a new file system where you want to look for volume labels, + * you have to: + * 1. Add a file g_label_<file system>.c which implements labels recognition. + * 2. Add an 'extern const struct g_label_desc g_label_<file system>;' into + *    g_label.h file. + * 3. Add an element to the table below '&g_label_<file system>,'. + * 4. Add your file to sys/conf/files. + * 5. Add your file to sys/modules/geom/geom_label/Makefile. + * 6. Add your file system to manual page sbin/geom/class/label/glabel.8. + */ +const struct g_label_desc *g_labels[] = { +	&g_label_gpt, +	&g_label_gpt_uuid, +#ifdef GEOM_LABEL +	&g_label_ufs_id, +	&g_label_ufs_volume, +	&g_label_iso9660, +	&g_label_msdosfs, +	&g_label_ext2fs, +	&g_label_ntfs, +	&g_label_disk_ident, +	&g_label_flashmap, +	&g_label_swaplinux, +#endif +	&g_label_generic, +	NULL +}; + +void +g_label_rtrim(char *label, size_t size) +{ +	ptrdiff_t i; + +	for (i = size - 1; i >= 0; i--) { +		if (label[i] == '\0') +			continue; +		else if (label[i] == ' ') +			label[i] = '\0'; +		else +			break; +	} +} + +static int +g_label_destroy_geom(struct gctl_req *req __unused, struct g_class *mp, +    struct g_geom *gp __unused) +{ + +	/* +	 * XXX: Unloading a class which is using geom_slice:1.56 is currently +	 * XXX: broken, so we deny unloading when we have geoms. +	 */ +	return (EOPNOTSUPP); +} + +static void +g_label_orphan(struct g_consumer *cp) +{ + +	G_LABEL_DEBUG(1, "Label %s removed.", +	    LIST_FIRST(&cp->geom->provider)->name); +	g_slice_orphan(cp); +} + +static void +g_label_spoiled(struct g_consumer *cp) +{ + +	G_LABEL_DEBUG(1, "Label %s removed.", +	    LIST_FIRST(&cp->geom->provider)->name); +	g_slice_spoiled(cp); +} + +static void +g_label_resize(struct g_consumer *cp) +{ + +	G_LABEL_DEBUG(1, "Label %s resized.", +	    LIST_FIRST(&cp->geom->provider)->name); + +	g_slice_config(cp->geom, 0, G_SLICE_CONFIG_FORCE, (off_t)0, +	    cp->provider->mediasize, cp->provider->sectorsize, "notused"); +} + +static int +g_label_is_name_ok(const char *label) +{ +	const char *s; + +	/* Check if the label starts from ../ */ +	if (strncmp(label, "../", 3) == 0) +		return (0); +	/* Check if the label contains /../ */ +	if (strstr(label, "/../") != NULL) +		return (0); +	/* Check if the label ends at ../ */ +	if ((s = strstr(label, "/..")) != NULL && s[3] == '\0') +		return (0); +	return (1); +} + +static void +g_label_mangle_name(char *label, size_t size) +{ +	struct sbuf *sb; +	const u_char *c; +	size_t len, i; + +	/* Trim trailing whitespace. */ +	len = strlen(label); +	for (i = len; i > 0; i--) { +		if (isspace(label[i - 1])) +			label[i - 1] = '\0'; +		else +			break; +	} +	if (*label == '\0') +		return; + +	sb = sbuf_new(NULL, NULL, size, SBUF_FIXEDLEN); +	for (c = label; *c != '\0'; c++) { +		/* Trim leading whitespace. */ +		if (isspace(*c) && sbuf_len(sb) == 0) +			continue; +		if (!isprint(*c) || isspace(*c) || *c =='"' || *c == '%') +			sbuf_printf(sb, "%%%02X", *c); +		else +			sbuf_putc(sb, *c); +	} +	if (sbuf_finish(sb) != 0) +		label[0] = '\0'; +	else +		strlcpy(label, sbuf_data(sb), size); +	sbuf_delete(sb); +} + +static struct g_geom * +g_label_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, +    const char *label, const char *dirprefix, off_t mediasize) +{ +	struct g_geom *gp; +	struct g_provider *pp2; +	struct g_consumer *cp; +	char name[64]; + +	g_topology_assert(); + +	if (!g_label_is_name_ok(label)) { +		G_LABEL_DEBUG(0, "%s contains suspicious label, skipping.", +		    pp->name); +		G_LABEL_DEBUG(1, "%s suspicious label is: %s", pp->name, label); +		if (req != NULL) +			gctl_error(req, "Label name %s is invalid.", label); +		return (NULL); +	} +	gp = NULL; +	cp = NULL; +	if (snprintf(name, sizeof(name), "%s%s", dirprefix, label) >= sizeof(name)) { +		if (req != NULL) +			gctl_error(req, "Label name %s is too long.", label); +		return (NULL); +	} +	LIST_FOREACH(gp, &mp->geom, geom) { +		pp2 = LIST_FIRST(&gp->provider); +		if (pp2 == NULL) +			continue; +		if ((pp2->flags & G_PF_ORPHAN) != 0) +			continue; +		if (strcmp(pp2->name, name) == 0) { +			G_LABEL_DEBUG(1, "Label %s(%s) already exists (%s).", +			    label, name, pp->name); +			if (req != NULL) { +				gctl_error(req, "Provider %s already exists.", +				    name); +			} +			return (NULL); +		} +	} +	gp = g_slice_new(mp, 1, pp, &cp, NULL, 0, NULL); +	if (gp == NULL) { +		G_LABEL_DEBUG(0, "Cannot create slice %s.", label); +		if (req != NULL) +			gctl_error(req, "Cannot create slice %s.", label); +		return (NULL); +	} +	gp->orphan = g_label_orphan; +	gp->spoiled = g_label_spoiled; +	gp->resize = g_label_resize; +	g_access(cp, -1, 0, 0); +	g_slice_config(gp, 0, G_SLICE_CONFIG_SET, (off_t)0, mediasize, +	    pp->sectorsize, "%s", name); +	G_LABEL_DEBUG(1, "Label for provider %s is %s.", pp->name, name); +	return (gp); +} + +static int +g_label_destroy(struct g_geom *gp, boolean_t force) +{ +	struct g_provider *pp; + +	g_topology_assert(); +	pp = LIST_FIRST(&gp->provider); +	if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { +		if (force) { +			G_LABEL_DEBUG(0, "Provider %s is still open, so it " +			    "can't be definitely removed.", pp->name); +		} else { +			G_LABEL_DEBUG(1, +			    "Provider %s is still open (r%dw%de%d).", pp->name, +			    pp->acr, pp->acw, pp->ace); +			return (EBUSY); +		} +	} else if (pp != NULL) +		G_LABEL_DEBUG(1, "Label %s removed.", pp->name); +	g_slice_spoiled(LIST_FIRST(&gp->consumer)); +	return (0); +} + +static int +g_label_read_metadata(struct g_consumer *cp, struct g_label_metadata *md) +{ +	struct g_provider *pp; +	u_char *buf; +	int error; + +	pp = cp->provider; +	if (pp->sectorsize < sizeof(*md)) +		return (EINVAL); +	buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, +	    &error); +	if (buf == NULL) +		return (error); +	/* Decode metadata. */ +	label_metadata_decode(buf, md); +	g_free(buf); + +	return (0); +} + +static void +g_label_orphan_taste(struct g_consumer *cp __unused) +{ + +	KASSERT(1 == 0, ("%s called?", __func__)); +} + +static void +g_label_start_taste(struct bio *bp __unused) +{ + +	KASSERT(1 == 0, ("%s called?", __func__)); +} + +static int +g_label_access_taste(struct g_provider *pp __unused, int dr __unused, +    int dw __unused, int de __unused) +{ + +	KASSERT(1 == 0, ("%s called", __func__)); +	return (EOPNOTSUPP); +} + +static void +g_label_generic_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_provider *pp; +	struct g_label_metadata md; + +	g_topology_assert_not(); +	label[0] = '\0'; +	pp = cp->provider; + +	if (g_label_read_metadata(cp, &md) != 0) +		return; + +	if (strcmp(md.md_magic, G_LABEL_MAGIC) != 0) +		return; + +	if (md.md_version > G_LABEL_VERSION) { +		printf("geom_label.ko module is too old to handle %s.\n", +			pp->name); +		return; +	} +	/* +	 * Backward compatibility: there was no md_provsize field in +	 * earlier versions of metadata, so only check if we have it. +	 */ +	if (md.md_version >= 2 && md.md_provsize != pp->mediasize) +		return; + +	strlcpy(label, md.md_label, size); +} + +static struct g_geom * +g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) +{ +	struct g_consumer *cp; +	struct g_geom *gp; +	off_t mediasize; +	int i; + +	g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); +	g_topology_assert(); + +	G_LABEL_DEBUG(2, "Tasting %s.", pp->name); + +	/* Skip providers that are already open for writing. */ +	if (pp->acw > 0) +		return (NULL); + +	/* Skip broken disks that don't set their sector size */ +	if (pp->sectorsize == 0) +		return (NULL); + +	if (strcmp(pp->geom->class->name, mp->name) == 0) +		return (NULL); + +	gp = g_new_geom(mp, "label:taste"); +	gp->start = g_label_start_taste; +	gp->access = g_label_access_taste; +	gp->orphan = g_label_orphan_taste; +	cp = g_new_consumer(gp); +	cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; +	if (g_attach(cp, pp) != 0) +		goto end2; +	if (g_access(cp, 1, 0, 0) != 0) +		goto end; +	for (i = 0; g_labels[i] != NULL; i++) { +		char label[128]; + +		if (g_labels[i]->ld_enabled == 0) +			continue; +		g_topology_unlock(); +		g_labels[i]->ld_taste(cp, label, sizeof(label)); +		g_label_mangle_name(label, sizeof(label)); +		g_topology_lock(); +		if (label[0] == '\0') +			continue; +		if (g_labels[i] != &g_label_generic) { +			mediasize = pp->mediasize; +		} else { +			mediasize = pp->mediasize - pp->sectorsize; +		} +		g_label_create(NULL, mp, pp, label, +		    g_labels[i]->ld_dirprefix, mediasize); +	} +	g_access(cp, -1, 0, 0); +end: +	g_detach(cp); +end2: +	g_destroy_consumer(cp); +	g_destroy_geom(gp); +	return (NULL); +} + +static void +g_label_ctl_create(struct gctl_req *req, struct g_class *mp) +{ +	struct g_provider *pp; +	const char *name; +	int *nargs; + +	g_topology_assert(); + +	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); +	if (nargs == NULL) { +		gctl_error(req, "No '%s' argument", "nargs"); +		return; +	} +	if (*nargs != 2) { +		gctl_error(req, "Invalid number of arguments."); +		return; +	} +	/* +	 * arg1 is the name of provider. +	 */ +	pp = gctl_get_provider(req, "arg1"); +	if (pp == NULL) +		return; +	/* +	 * arg0 is the label. +	 */ +	name = gctl_get_asciiparam(req, "arg0"); +	if (name == NULL) { +		gctl_error(req, "No 'arg%d' argument", 0); +		return; +	} +	g_label_create(req, mp, pp, name, G_LABEL_DIRPREFIX, pp->mediasize); +} + +static const char * +g_label_skip_dir(const char *name) +{ +	u_int i; + +	if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) +		name += strlen(_PATH_DEV); +	for (i = 0; g_labels[i] != NULL; i++) { +		if (strncmp(name, g_labels[i]->ld_dirprefix, +		    strlen(g_labels[i]->ld_dirprefix)) == 0) { +			name += strlen(g_labels[i]->ld_dirprefix); +			break; +		} +	} +	return (name); +} + +static struct g_geom * +g_label_find_geom(struct g_class *mp, const char *name) +{ +	struct g_geom *gp; +	struct g_provider *pp; +	const char *pname; + +	name = g_label_skip_dir(name); +	LIST_FOREACH(gp, &mp->geom, geom) { +		pp = LIST_FIRST(&gp->provider); +		pname = g_label_skip_dir(pp->name); +		if (strcmp(pname, name) == 0) +			return (gp); +	} +	return (NULL); +} + +static void +g_label_ctl_destroy(struct gctl_req *req, struct g_class *mp) +{ +	int *nargs, *force, error, i; +	struct g_geom *gp; +	const char *name; +	char param[16]; + +	g_topology_assert(); + +	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); +	if (nargs == NULL) { +		gctl_error(req, "No '%s' argument", "nargs"); +		return; +	} +	if (*nargs <= 0) { +		gctl_error(req, "Missing device(s)."); +		return; +	} +	force = gctl_get_paraml(req, "force", sizeof(*force)); +	if (force == NULL) { +		gctl_error(req, "No 'force' argument"); +		return; +	} + +	for (i = 0; i < *nargs; i++) { +		snprintf(param, sizeof(param), "arg%d", i); +		name = gctl_get_asciiparam(req, param); +		if (name == NULL) { +			gctl_error(req, "No 'arg%d' argument", i); +			return; +		} +		gp = g_label_find_geom(mp, name); +		if (gp == NULL) { +			G_LABEL_DEBUG(1, "Label %s is invalid.", name); +			gctl_error(req, "Label %s is invalid.", name); +			return; +		} +		error = g_label_destroy(gp, *force); +		if (error != 0) { +			gctl_error(req, "Cannot destroy label %s (error=%d).", +			    LIST_FIRST(&gp->provider)->name, error); +			return; +		} +	} +} + +static void +g_label_config(struct gctl_req *req, struct g_class *mp, const char *verb) +{ +	uint32_t *version; + +	g_topology_assert(); + +	version = gctl_get_paraml(req, "version", sizeof(*version)); +	if (version == NULL) { +		gctl_error(req, "No '%s' argument.", "version"); +		return; +	} +	if (*version != G_LABEL_VERSION) { +		gctl_error(req, "Userland and kernel parts are out of sync."); +		return; +	} + +	if (strcmp(verb, "create") == 0) { +		g_label_ctl_create(req, mp); +		return; +	} else if (strcmp(verb, "destroy") == 0 || +	    strcmp(verb, "stop") == 0) { +		g_label_ctl_destroy(req, mp); +		return; +	} + +	gctl_error(req, "Unknown verb."); +} + +DECLARE_GEOM_CLASS(g_label_class, g_label); +MODULE_VERSION(geom_label, 0); diff --git a/sys/geom/label/g_label.h b/sys/geom/label/g_label.h new file mode 100644 index 000000000000..0d8951f7c99d --- /dev/null +++ b/sys/geom/label/g_label.h @@ -0,0 +1,110 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef	_G_LABEL_H_ +#define	_G_LABEL_H_ + +#include <sys/endian.h> +#ifdef _KERNEL +#include <sys/sysctl.h> +#endif + +#define	G_LABEL_CLASS_NAME	"LABEL" + +#define	G_LABEL_MAGIC		"GEOM::LABEL" +/* + * Version history: + * 1 - Initial version number. + * 2 - Added md_provsize field to metadata. + */ +#define	G_LABEL_VERSION		2 + +#ifdef _KERNEL +extern u_int g_label_debug; + +#define G_LABEL_DEBUG(lvl, ...) \ +    _GEOM_DEBUG("GEOM_LABEL", g_label_debug, (lvl), NULL, __VA_ARGS__) + +SYSCTL_DECL(_kern_geom_label); + +#define	G_LABEL_INIT(kind, label, descr) 				\ +	SYSCTL_NODE(_kern_geom_label, OID_AUTO, kind,			\ +	    CTLFLAG_RD | CTLFLAG_MPSAFE,				\ +	    NULL, "");							\ +	SYSCTL_INT(_kern_geom_label_##kind, OID_AUTO, enable, 		\ +	    CTLFLAG_RWTUN, &label.ld_enabled, 1, descr) + +typedef void g_label_taste_t (struct g_consumer *cp, char *label, size_t size); + +struct g_label_desc { +	g_label_taste_t	*ld_taste; +	char		*ld_dirprefix; +	int		 ld_enabled; +}; + +/* Supported labels. */ +extern struct g_label_desc g_label_ufs_id; +extern struct g_label_desc g_label_ufs_volume; +extern struct g_label_desc g_label_iso9660; +extern struct g_label_desc g_label_msdosfs; +extern struct g_label_desc g_label_ext2fs; +extern struct g_label_desc g_label_ntfs; +extern struct g_label_desc g_label_gpt; +extern struct g_label_desc g_label_gpt_uuid; +extern struct g_label_desc g_label_disk_ident; +extern struct g_label_desc g_label_flashmap; +extern struct g_label_desc g_label_swaplinux; + +extern void g_label_rtrim(char *label, size_t size); +#endif	/* _KERNEL */ + +struct g_label_metadata { +	char		md_magic[16];	/* Magic value. */ +	uint32_t	md_version;	/* Version number. */ +	char		md_label[16];	/* Label. */ +	uint64_t	md_provsize;	/* Provider's size. */ +}; +static __inline void +label_metadata_encode(const struct g_label_metadata *md, u_char *data) +{ + +	bcopy(md->md_magic, data, sizeof(md->md_magic)); +	le32enc(data + 16, md->md_version); +	bcopy(md->md_label, data + 20, sizeof(md->md_label)); +	le64enc(data + 36, md->md_provsize); +} +static __inline void +label_metadata_decode(const u_char *data, struct g_label_metadata *md) +{ + +	bcopy(data, md->md_magic, sizeof(md->md_magic)); +	md->md_version = le32dec(data + 16); +	bcopy(data + 20, md->md_label, sizeof(md->md_label)); +	md->md_provsize = le64dec(data + 36); +} +#endif	/* _G_LABEL_H_ */ diff --git a/sys/geom/label/g_label_disk_ident.c b/sys/geom/label/g_label_disk_ident.c new file mode 100644 index 000000000000..880ce53565ce --- /dev/null +++ b/sys/geom/label/g_label_disk_ident.c @@ -0,0 +1,84 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2012 Ivan Voras <ivoras@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#include <geom/geom.h> +#include <geom/geom_disk.h> +#include <geom/label/g_label.h> +#include <geom/multipath/g_multipath.h> + +static char* classes_pass[] = { G_DISK_CLASS_NAME, G_MULTIPATH_CLASS_NAME, +    NULL }; + +static void +g_label_disk_ident_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_class *cls; +	char ident[DISK_IDENT_SIZE]; +	int ident_len, found, i; + +	g_topology_assert_not(); +	label[0] = '\0'; + +	cls = cp->provider->geom->class; + +	/*  +	 * Get the GEOM::ident string, and construct a label in the format +	 * "CLASS_NAME-ident" +	 */ +	ident_len = sizeof(ident); +	if (g_io_getattr("GEOM::ident", cp, &ident_len, ident) == 0) { +		if (ident_len == 0 || ident[0] == '\0') +			return; +		for (i = 0, found = 0; classes_pass[i] != NULL; i++) +			if (strcmp(classes_pass[i], cls->name) == 0) { +				found = 1; +				break; +			} +		if (!found) +			return; +		/* +		 * We can safely ignore the result of snprintf(): the label +		 * will simply be truncated, which at most is only annoying. +		 */ +		(void)snprintf(label, size, "%s-%s", cls->name, ident); +	} +} + +struct g_label_desc g_label_disk_ident = { +	.ld_taste = g_label_disk_ident_taste, +	.ld_dirprefix = "diskid/", +	.ld_enabled = 1 +}; + +G_LABEL_INIT(disk_ident, g_label_disk_ident, "Create device nodes for drives " +    "which export a disk identification string"); diff --git a/sys/geom/label/g_label_ext2fs.c b/sys/geom/label/g_label_ext2fs.c new file mode 100644 index 000000000000..b72cfcd03509 --- /dev/null +++ b/sys/geom/label/g_label_ext2fs.c @@ -0,0 +1,104 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2005 Stanislav Sedov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#include <geom/geom.h> +#include <geom/geom_dbg.h> +#include <geom/label/g_label.h> + +#define EXT2FS_SB_OFFSET	1024 +#define EXT2_SUPER_MAGIC	0xef53 +#define EXT2_DYNAMIC_REV	1 + +typedef struct e2sb { +	uint8_t		fake1[56]; +	uint16_t	s_magic; +	uint8_t		fake2[18]; +	uint32_t	s_rev_level; +	uint8_t		fake3[40]; +	char		s_volume_name[16]; +} e2sb_t; + +static void +g_label_ext2fs_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_provider *pp; +	e2sb_t *fs; +	char *s_volume_name; + +	g_topology_assert_not(); +	pp = cp->provider; +	label[0] = '\0'; + +	KASSERT(pp->sectorsize != 0, ("Tasting a disk with 0 sectorsize")); +	if (pp->sectorsize < sizeof(*fs)) +		return; +	if ((EXT2FS_SB_OFFSET % pp->sectorsize) != 0) +		return; + +	fs = g_read_data(cp, EXT2FS_SB_OFFSET, pp->sectorsize, NULL); +	if (fs == NULL) +		return; + +	/* Check for magic and versio n*/ +	if (fs->s_magic == EXT2_SUPER_MAGIC && +	    fs->s_rev_level == EXT2_DYNAMIC_REV) { +		G_LABEL_DEBUG(1, "ext2fs file system detected on %s.", +		    pp->name); +	} else { +		goto exit_free; +	} + +	s_volume_name = fs->s_volume_name; +	/* Terminate label */ +	s_volume_name[sizeof(fs->s_volume_name) - 1] = '\0'; + +	if (s_volume_name[0] == '/') +		s_volume_name += 1; + +	/* Check for volume label */ +	if (s_volume_name[0] == '\0') +		goto exit_free; + +	strlcpy(label, s_volume_name, size); + +exit_free: +	g_free(fs); +} + +struct g_label_desc g_label_ext2fs = { +	.ld_taste = g_label_ext2fs_taste, +	.ld_dirprefix = "ext2fs/", +	.ld_enabled = 1 +}; + +G_LABEL_INIT(ext2fs, g_label_ext2fs, "Create device nodes for EXT2FS volumes"); diff --git a/sys/geom/label/g_label_flashmap.c b/sys/geom/label/g_label_flashmap.c new file mode 100644 index 000000000000..cc3bd98bcf6f --- /dev/null +++ b/sys/geom/label/g_label_flashmap.c @@ -0,0 +1,72 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Ian Lepore <ian@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/slicer.h> + +#include <geom/geom.h> +#include <geom/geom_flashmap.h> +#include <geom/geom_slice.h> +#include <geom/label/g_label.h> + +static void +g_label_flashmap_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_flashmap *gfp; +	struct g_slicer *gsp; +	struct g_provider *pp; + +	g_topology_assert_not(); + +	pp = cp->provider; +	label[0] = '\0'; + +	/* We taste only partitions handled by flashmap */ +	if (strncmp(pp->geom->class->name, FLASHMAP_CLASS_NAME, +	    sizeof(FLASHMAP_CLASS_NAME)) != 0) +		return; + +	gsp = (struct g_slicer *)pp->geom->softc; +	gfp = (struct g_flashmap *)gsp->softc; + +	/* If it's handled by flashmap it should have a label, but be safe. */ +	if (gfp->labels[pp->index] == NULL) +		return; + +	strlcpy(label, gfp->labels[pp->index], size); +} + +struct g_label_desc g_label_flashmap = { +	.ld_taste = g_label_flashmap_taste, +	.ld_dirprefix = "flash/", +	.ld_enabled = 1 +}; + +G_LABEL_INIT(flashmap, g_label_flashmap, "Create device nodes for Flashmap labels"); diff --git a/sys/geom/label/g_label_gpt.c b/sys/geom/label/g_label_gpt.c new file mode 100644 index 000000000000..742e6d39e50d --- /dev/null +++ b/sys/geom/label/g_label_gpt.c @@ -0,0 +1,166 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2008 Marius Nuennerich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/kobj.h> +#include <sys/gpt.h> +#include <sys/sbuf.h> + +#include <geom/geom.h> +#include <geom/label/g_label.h> +#include <geom/part/g_part.h> + +#define	PART_CLASS_NAME	"PART" +#define	SCHEME_NAME	"GPT" + +/* XXX: Also defined in geom/part/g_part_gpt.c */ +struct g_part_gpt_entry { +	struct g_part_entry     base; +	struct gpt_ent          ent; +}; + +/* XXX: Shamelessly stolen from g_part_gpt.c */ +static void +sbuf_nprintf_utf16(struct sbuf *sb, uint16_t *str, size_t len) +{ +	u_int bo; +	uint32_t ch; +	uint16_t c; + +	bo = LITTLE_ENDIAN;	/* GPT is little-endian */ +	while (len > 0 && *str != 0) { +		ch = (bo == BIG_ENDIAN) ? be16toh(*str) : le16toh(*str); +		str++, len--; +		if ((ch & 0xf800) == 0xd800) { +			if (len > 0) { +				c = (bo == BIG_ENDIAN) ? be16toh(*str) +				    : le16toh(*str); +				str++, len--; +			} else +				c = 0xfffd; +			if ((ch & 0x400) == 0 && (c & 0xfc00) == 0xdc00) { +				ch = ((ch & 0x3ff) << 10) + (c & 0x3ff); +				ch += 0x10000; +			} else +				ch = 0xfffd; +		} else if (ch == 0xfffe) { /* BOM (U+FEFF) swapped. */ +			bo = (bo == BIG_ENDIAN) ? LITTLE_ENDIAN : BIG_ENDIAN; +			continue; +		} else if (ch == 0xfeff) /* BOM (U+FEFF) unswapped. */ +			continue; + +		/* Write the Unicode character in UTF-8 */ +		if (ch < 0x80) +			sbuf_printf(sb, "%c", ch); +		else if (ch < 0x800) +			sbuf_printf(sb, "%c%c", 0xc0 | (ch >> 6), +			    0x80 | (ch & 0x3f)); +		else if (ch < 0x10000) +			sbuf_printf(sb, "%c%c%c", 0xe0 | (ch >> 12), +			    0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); +		else if (ch < 0x200000) +			sbuf_printf(sb, "%c%c%c%c", 0xf0 | (ch >> 18), +			    0x80 | ((ch >> 12) & 0x3f), +			    0x80 | ((ch >> 6) & 0x3f), 0x80 | (ch & 0x3f)); +	} +} + +static void +g_label_gpt_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_provider *pp; +	struct g_part_table *tp; +	struct g_part_gpt_entry *part_gpt_entry; +	struct sbuf *lbl; + +	g_topology_assert_not(); +	pp = cp->provider; +	tp = (struct g_part_table *)pp->geom->softc; +	label[0] = '\0'; + +	/* We taste only partitions handled by GPART */ +	if (strncmp(pp->geom->class->name, PART_CLASS_NAME, sizeof(PART_CLASS_NAME))) +		return; +	/* and only GPT */ +	if (strncmp(tp->gpt_scheme->name, SCHEME_NAME, sizeof(SCHEME_NAME))) +		return; + +	part_gpt_entry = (struct g_part_gpt_entry *)pp->private; + +	/* +	 * Create sbuf with biggest possible size. +	 * We need max. 4 bytes for every 2-byte utf16 char. +	 */ +	lbl = sbuf_new(NULL, NULL, sizeof(part_gpt_entry->ent.ent_name) << 1, SBUF_FIXEDLEN); +	/* Size is the number of characters, not bytes */ +	sbuf_nprintf_utf16(lbl, part_gpt_entry->ent.ent_name, sizeof(part_gpt_entry->ent.ent_name) >> 1); +	sbuf_finish(lbl); +	strlcpy(label, sbuf_data(lbl), size); +	sbuf_delete(lbl); +} + +static void +g_label_gpt_uuid_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_provider *pp; +	struct g_part_table *tp; +	struct g_part_gpt_entry *part_gpt_entry; + +	g_topology_assert_not(); +	pp = cp->provider; +	tp = (struct g_part_table *)pp->geom->softc; +	label[0] = '\0'; + +	/* We taste only partitions handled by GPART */ +	if (strncmp(pp->geom->class->name, PART_CLASS_NAME, sizeof(PART_CLASS_NAME))) +		return; +	/* and only GPT */ +	if (strncmp(tp->gpt_scheme->name, SCHEME_NAME, sizeof(SCHEME_NAME))) +		return; + +	part_gpt_entry = (struct g_part_gpt_entry *)pp->private; +	snprintf_uuid(label, size, &part_gpt_entry->ent.ent_uuid); +} + +struct g_label_desc g_label_gpt = { +	.ld_taste = g_label_gpt_taste, +	.ld_dirprefix = "gpt/", +	.ld_enabled = 1 +}; + +struct g_label_desc g_label_gpt_uuid = { +	.ld_taste = g_label_gpt_uuid_taste, +	.ld_dirprefix = "gptid/", +	.ld_enabled = 1 +}; + +G_LABEL_INIT(gpt, g_label_gpt, "Create device nodes for GPT labels"); +G_LABEL_INIT(gptid, g_label_gpt_uuid, "Create device nodes for GPT UUIDs"); diff --git a/sys/geom/label/g_label_iso9660.c b/sys/geom/label/g_label_iso9660.c new file mode 100644 index 000000000000..031295fb3fb5 --- /dev/null +++ b/sys/geom/label/g_label_iso9660.c @@ -0,0 +1,78 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#include <geom/geom.h> +#include <geom/geom_dbg.h> +#include <geom/label/g_label.h> + +#define	ISO9660_MAGIC	"\x01" "CD001" "\x01\x00" +#define	ISO9660_OFFSET	0x8000 +#define	VOLUME_LEN	32 + +static void +g_label_iso9660_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_provider *pp; +	char *sector, *volume; + +	g_topology_assert_not(); +	pp = cp->provider; +	label[0] = '\0'; + +	KASSERT(pp->sectorsize != 0, ("Tasting a disk with 0 sectorsize")); +	if (pp->sectorsize < 0x28 + VOLUME_LEN) +		return; +	if ((ISO9660_OFFSET % pp->sectorsize) != 0) +		return; +	sector = g_read_data(cp, ISO9660_OFFSET, pp->sectorsize, NULL); +	if (sector == NULL) +		return; +	if (bcmp(sector, ISO9660_MAGIC, sizeof(ISO9660_MAGIC) - 1) != 0) { +		g_free(sector); +		return; +	} +	G_LABEL_DEBUG(1, "ISO9660 file system detected on %s.", pp->name); +	volume = sector + 0x28; +	bzero(label, size); +	strlcpy(label, volume, MIN(size, VOLUME_LEN)); +	g_free(sector); +	g_label_rtrim(label, size); +} + +struct g_label_desc g_label_iso9660 = { +	.ld_taste = g_label_iso9660_taste, +	.ld_dirprefix = "iso9660/", +	.ld_enabled = 1 +}; + +G_LABEL_INIT(iso9660, g_label_iso9660, "Create device nodes for ISO9660 volume names"); diff --git a/sys/geom/label/g_label_msdosfs.c b/sys/geom/label/g_label_msdosfs.c new file mode 100644 index 000000000000..74ece5568e76 --- /dev/null +++ b/sys/geom/label/g_label_msdosfs.c @@ -0,0 +1,225 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * Copyright (c) 2006 Tobias Reifenberger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#include <geom/geom.h> +#include <geom/geom_dbg.h> +#include <geom/label/g_label.h> +#include <geom/label/g_label_msdosfs.h> + +#define LABEL_NO_NAME		"NO NAME    " + +static void +g_label_msdosfs_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_provider *pp; +	FAT_BSBPB *pfat_bsbpb; +	FAT32_BSBPB *pfat32_bsbpb; +	FAT_DES *pfat_entry; +	uint8_t *sector0, *sector; +	size_t copysize; + +	g_topology_assert_not(); +	pp = cp->provider; +	sector0 = NULL; +	sector = NULL; +	bzero(label, size); + +	/* Check if the sector size of the medium is a valid FAT sector size. */ +	switch(pp->sectorsize) { +	case 512: +	case 1024: +	case 2048: +	case 4096: +		break; +	default: +		G_LABEL_DEBUG(1, "MSDOSFS: %s: sector size %d not compatible.", +		    pp->name, pp->sectorsize); +		return; +	} + +	/* Load 1st sector with boot sector and boot parameter block. */ +	sector0 = (uint8_t *)g_read_data(cp, 0, pp->sectorsize, NULL); +	if (sector0 == NULL) +		return; + +	/* Check for the FAT boot sector signature. */ +	if (sector0[510] != 0x55 || sector0[511] != 0xaa) { +		G_LABEL_DEBUG(1, "MSDOSFS: %s: no FAT signature found.", +		    pp->name); +		goto error; +	} + +	/* +	 * Test if this is really a FAT volume and determine the FAT type. +	 */ + +	pfat_bsbpb = (FAT_BSBPB *)sector0; +	pfat32_bsbpb = (FAT32_BSBPB *)sector0; + +	if (UINT16BYTES(pfat_bsbpb->BPB_FATSz16) != 0) { +		/* +		 * If the BPB_FATSz16 field is not zero and the string "FAT" is +		 * at the right place, this should be a FAT12 or FAT16 volume. +		 */ +		if (strncmp(pfat_bsbpb->BS_FilSysType, "FAT", 3) != 0) { +			G_LABEL_DEBUG(1, +			    "MSDOSFS: %s: FAT12/16 volume not valid.", +			    pp->name); +			goto error; +		} +		G_LABEL_DEBUG(1, "MSDOSFS: %s: FAT12/FAT16 volume detected.", +		    pp->name); + +		/* A volume with no name should have "NO NAME    " as label. */ +		if (strncmp(pfat_bsbpb->BS_VolLab, LABEL_NO_NAME, +		    sizeof(pfat_bsbpb->BS_VolLab)) == 0) { +			G_LABEL_DEBUG(1, +			    "MSDOSFS: %s: FAT12/16 volume has no name.", +			    pp->name); +			goto error; +		} +		copysize = MIN(size - 1, sizeof(pfat_bsbpb->BS_VolLab)); +		memcpy(label, pfat_bsbpb->BS_VolLab, copysize); +		label[copysize] = '\0'; +	} else if (UINT32BYTES(pfat32_bsbpb->BPB_FATSz32) != 0) { +		uint32_t fat_FirstDataSector, fat_BytesPerSector, offset; + +		/* +		 * If the BPB_FATSz32 field is not zero and the string "FAT" is +		 * at the right place, this should be a FAT32 volume. +		 */ +		if (strncmp(pfat32_bsbpb->BS_FilSysType, "FAT", 3) != 0) { +			G_LABEL_DEBUG(1, "MSDOSFS: %s: FAT32 volume not valid.", +			    pp->name); +			goto error; +		} +		G_LABEL_DEBUG(1, "MSDOSFS: %s: FAT32 volume detected.", +		    pp->name); + +		/* +		 * If the volume label is not "NO NAME    " we're done. +		 */ +		if (strncmp(pfat32_bsbpb->BS_VolLab, LABEL_NO_NAME, +		    sizeof(pfat32_bsbpb->BS_VolLab)) != 0) { +			copysize = MIN(size - 1, +			    sizeof(pfat32_bsbpb->BS_VolLab)); +			memcpy(label, pfat32_bsbpb->BS_VolLab, copysize); +			label[copysize] = '\0'; +			goto endofchecks; +		} + +		/* +		 * If the volume label "NO NAME    " is in the boot sector, the +		 * label of FAT32 volumes may be stored as a special entry in +		 * the root directory. +		 */ +		fat_FirstDataSector = +		    UINT16BYTES(pfat32_bsbpb->BPB_RsvdSecCnt) + +		    (pfat32_bsbpb->BPB_NumFATs * +		     UINT32BYTES(pfat32_bsbpb->BPB_FATSz32)); +		fat_BytesPerSector = UINT16BYTES(pfat32_bsbpb->BPB_BytsPerSec); + +		G_LABEL_DEBUG(2, +		    "MSDOSFS: FAT_FirstDataSector=0x%x, FAT_BytesPerSector=%d", +		    fat_FirstDataSector, fat_BytesPerSector); +		if (fat_BytesPerSector == 0 || +		    fat_BytesPerSector % pp->sectorsize != 0) { +			G_LABEL_DEBUG(1, "MSDOSFS: %s: corrupted BPB", +			    pp->name); +			goto error; +		} + +		for (offset = fat_BytesPerSector * fat_FirstDataSector;; +		    offset += fat_BytesPerSector) { +			sector = (uint8_t *)g_read_data(cp, offset, +			    fat_BytesPerSector, NULL); +			if (sector == NULL) +				goto error; + +			pfat_entry = (FAT_DES *)sector; +			do { +				/* No more entries available. */ +				if (pfat_entry->DIR_Name[0] == 0) { +					G_LABEL_DEBUG(1, "MSDOSFS: %s: " +					    "FAT32 volume has no name.", +					    pp->name); +					goto error; +				} + +				/* Skip empty or long name entries. */ +				if (pfat_entry->DIR_Name[0] == 0xe5 || +				    (pfat_entry->DIR_Attr & +				     FAT_DES_ATTR_LONG_NAME) == +				    FAT_DES_ATTR_LONG_NAME) { +					continue; +				} + +				/* +				 * The name of the entry is the volume label if +				 * ATTR_VOLUME_ID is set. +				 */ +				if (pfat_entry->DIR_Attr & +				    FAT_DES_ATTR_VOLUME_ID) { +					copysize = MIN(size - 1, +					    sizeof(pfat_entry->DIR_Name)); +					memcpy(label, pfat_entry->DIR_Name, +					    copysize); +					label[copysize] = '\0'; +					goto endofchecks; +				} +			} while((uint8_t *)(++pfat_entry) < +			    (uint8_t *)(sector + fat_BytesPerSector)); +			g_free(sector); +		} +	} else { +		G_LABEL_DEBUG(1, "MSDOSFS: %s: no FAT volume detected.", +		    pp->name); +		goto error; +	} + +endofchecks: +	g_label_rtrim(label, size); + +error: +	g_free(sector0); +	g_free(sector); +} + +struct g_label_desc g_label_msdosfs = { +	.ld_taste = g_label_msdosfs_taste, +	.ld_dirprefix = "msdosfs/", +	.ld_enabled = 1 +}; + +G_LABEL_INIT(msdosfs, g_label_msdosfs, "Create device nodes for MSDOSFS volumes"); diff --git a/sys/geom/label/g_label_msdosfs.h b/sys/geom/label/g_label_msdosfs.h new file mode 100644 index 000000000000..8c83c9862f84 --- /dev/null +++ b/sys/geom/label/g_label_msdosfs.h @@ -0,0 +1,140 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2006 Tobias Reifenberger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> + +/* + * Conversion macros for little endian encoded unsigned integers + * in byte streams to the local unsigned integer format. + */ +#define UINT16BYTES(p) ((uint32_t)((p)[0] + (256*(p)[1]))) +#define UINT32BYTES(p) ((uint32_t)((p)[0] + (256*(p)[1]) +		\ +	    (65536*(p)[2]) + (16777216*(p)[3]))) + +/* + * All following structures are according to: + * + * Microsoft Extensible Firmware Initiative FAT32 File System Specification + * FAT: General Overview of On-Disk Format + * Version 1.03, December 6, 2000 + * Microsoft Corporation + */ + +/* + * FAT boot sector and boot parameter block for + * FAT12 and FAT16 volumes + */ +typedef struct fat_bsbpb { +	/* common fields */ +	uint8_t BS_jmpBoot[3]; +	uint8_t BS_OEMName[8]; +	uint8_t BPB_BytsPerSec[2]; +	uint8_t BPB_SecPerClus; +	uint8_t BPB_RsvdSecCnt[2]; +	uint8_t BPB_NumFATs; +	uint8_t BPB_RootEntCnt[2]; +	uint8_t BPB_TotSec16[2]; +	uint8_t BPB_Media; +	uint8_t BPB_FATSz16[2]; +	uint8_t BPB_SecPerTrack[2]; +	uint8_t BPB_NumHeads[2]; +	uint8_t BPB_HiddSec[4]; +	uint8_t BPB_TotSec32[4]; +	/* FAT12/FAT16 only fields */ +	uint8_t BS_DrvNum; +	uint8_t BS_Reserved1; +	uint8_t BS_BootSig; +	uint8_t BS_VolID[4]; +	uint8_t BS_VolLab[11]; +	uint8_t BS_FilSysType[8]; +} FAT_BSBPB; /* 62 bytes */ + +/* + * FAT boot sector and boot parameter block for + * FAT32 volumes + */ +typedef struct fat32_bsbpb { +	/* common fields */ +	uint8_t BS_jmpBoot[3]; +	uint8_t BS_OEMName[8]; +	uint8_t BPB_BytsPerSec[2]; +	uint8_t BPB_SecPerClus; +	uint8_t BPB_RsvdSecCnt[2]; +	uint8_t BPB_NumFATs; +	uint8_t BPB_RootEntCnt[2]; +	uint8_t BPB_TotSec16[2]; +	uint8_t BPB_Media; +	uint8_t BPB_FATSz16[2]; +	uint8_t BPB_SecPerTrack[2]; +	uint8_t BPB_NumHeads[2]; +	uint8_t BPB_HiddSec[4]; +	uint8_t BPB_TotSec32[4]; +	/* FAT32 only fields */ +	uint8_t BPB_FATSz32[4]; +	uint8_t BPB_ExtFlags[2]; +	uint8_t BPB_FSVer[2]; +	uint8_t BPB_RootClus[4]; +	uint8_t BPB_FSInfo[2]; +	uint8_t BPB_BkBootSec[2]; +	uint8_t BPB_Reserved[12]; +	uint8_t BS_DrvNum; +	uint8_t BS_Reserved1; +	uint8_t BS_BootSig; +	uint8_t BS_VolID[4]; +	uint8_t BS_VolLab[11]; +	uint8_t BS_FilSysType[8]; +} FAT32_BSBPB; /* 90 bytes */ + +/* + * FAT directory entry structure + */ +#define	FAT_DES_ATTR_READ_ONLY	0x01 +#define	FAT_DES_ATTR_HIDDEN	0x02 +#define	FAT_DES_ATTR_SYSTEM	0x04 +#define	FAT_DES_ATTR_VOLUME_ID	0x08 +#define	FAT_DES_ATTR_DIRECTORY	0x10 +#define	FAT_DES_ATTR_ARCHIVE	0x20 +#define	FAT_DES_ATTR_LONG_NAME	(FAT_DES_ATTR_READ_ONLY |		\ +				 FAT_DES_ATTR_HIDDEN |			\ +				 FAT_DES_ATTR_SYSTEM |			\ +				 FAT_DES_ATTR_VOLUME_ID) + +typedef struct fat_des { +	uint8_t DIR_Name[11]; +	uint8_t DIR_Attr; +	uint8_t DIR_NTRes; +	uint8_t DIR_CrtTimeTenth; +	uint8_t DIR_CrtTime[2]; +	uint8_t DIR_CrtDate[2]; +	uint8_t DIR_LstAccDate[2]; +	uint8_t DIR_FstClusHI[2]; +	uint8_t DIR_WrtTime[2]; +	uint8_t DIR_WrtDate[2]; +	uint8_t DIR_FstClusLO[2]; +	uint8_t DIR_FileSize[4]; +} FAT_DES; diff --git a/sys/geom/label/g_label_ntfs.c b/sys/geom/label/g_label_ntfs.c new file mode 100644 index 000000000000..ad43dbe38d1b --- /dev/null +++ b/sys/geom/label/g_label_ntfs.c @@ -0,0 +1,185 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2005 Takanori Watanabe + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#include <geom/geom.h> +#include <geom/label/g_label.h> + +#define	NTFS_A_VOLUMENAME	0x60 +#define	NTFS_FILEMAGIC		((uint32_t)(0x454C4946)) +#define	NTFS_VOLUMEINO		3 + +struct ntfs_attr { +	uint32_t	a_type; +	uint32_t	reclen; +	uint8_t		a_flag; +	uint8_t		a_namelen; +	uint8_t		a_nameoff; +	uint8_t		reserved1; +	uint8_t		a_compression; +	uint8_t		reserved2; +	uint16_t	a_index; +	uint16_t	a_datalen; +	uint16_t	reserved3; +	uint16_t	a_dataoff; +	uint16_t	a_indexed; +} __packed; + +struct ntfs_filerec { +	uint32_t	fr_hdrmagic; +	uint16_t	fr_hdrfoff; +	uint16_t	fr_hdrfnum; +	uint8_t		reserved[8]; +	uint16_t	fr_seqnum; +	uint16_t	fr_nlink; +	uint16_t	fr_attroff; +	uint16_t	fr_flags; +	uint32_t	fr_size; +	uint32_t	fr_allocated; +	uint64_t	fr_mainrec; +	uint16_t	fr_attrnum; +} __packed; + +struct ntfs_bootfile { +	uint8_t		reserved1[3]; +	uint8_t		bf_sysid[8]; +	uint16_t	bf_bps; +	uint8_t		bf_spc; +	uint8_t		reserved2[7]; +	uint8_t		bf_media; +	uint8_t		reserved3[2]; +	uint16_t	bf_spt; +	uint16_t	bf_heads; +	uint8_t		reserver4[12]; +	uint64_t	bf_spv; +	uint64_t	bf_mftcn; +	uint64_t	bf_mftmirrcn; +	int8_t		bf_mftrecsz; +	uint32_t	bf_ibsz; +	uint32_t	bf_volsn; +} __packed; + +static void +g_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_provider *pp; +	struct ntfs_bootfile *bf; +	struct ntfs_filerec *fr; +	struct ntfs_attr *atr; +	off_t voloff; +	size_t recoff; +	char *filerecp; +	int8_t mftrecsz; +	char vnchar; +	int recsize, j; + +	g_topology_assert_not(); + +	label[0] = '\0'; +	pp = cp->provider; +	bf = NULL; +	filerecp = NULL; + +	if (pp->sectorsize < sizeof(*bf)) +		goto done; + +	bf = g_read_data(cp, 0, pp->sectorsize, NULL); +	if (bf == NULL || strncmp(bf->bf_sysid, "NTFS    ", 8) != 0) +		goto done; + +	mftrecsz = bf->bf_mftrecsz; +	recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) : +	    (1 << -mftrecsz); +	if (recsize <= 0 || recsize > maxphys || recsize % pp->sectorsize != 0) +		goto done; + +	voloff = bf->bf_mftcn * bf->bf_spc * bf->bf_bps + +	    recsize * NTFS_VOLUMEINO; +	if (voloff % pp->sectorsize != 0) +		goto done; + +	filerecp = g_read_data(cp, voloff, recsize, NULL); +	if (filerecp == NULL) +		goto done; +	fr = (struct ntfs_filerec *)filerecp; +	if (fr->fr_hdrmagic != NTFS_FILEMAGIC) +		goto done; + +	for (recoff = fr->fr_attroff; +	    recoff <= recsize - 2 * sizeof(uint32_t); +	    recoff += atr->reclen) { +		atr = (struct ntfs_attr *)(filerecp + recoff); +		if (atr->a_type == -1) +			break; +		if (atr->reclen < sizeof(*atr)) +			break; +		if (recsize - recoff < atr->reclen) +			break; +		if (atr->a_type == NTFS_A_VOLUMENAME) { +			if (atr->a_dataoff > atr->reclen || +			    atr->a_datalen > atr->reclen - atr->a_dataoff) +				break; + +			/* +			 * UNICODE to ASCII. +			 * Should we need to use iconv(9)? +			 */ +			if (atr->a_datalen >= size * 2 || +			    atr->a_datalen % 2 != 0) +				break; +			for (j = 0; j < atr->a_datalen; j++) { +				vnchar = ((char *)atr)[atr->a_dataoff + j]; +				if (j & 1) { +					if (vnchar) { +						label[0] = 0; +						goto done; +					} +				} else { +					label[j / 2] = vnchar; +				} +			} +			label[j / 2] = 0; +			break; +		} +	} +done: +	g_free(bf); +	g_free(filerecp); +} + +struct g_label_desc g_label_ntfs = { +	.ld_taste = g_label_ntfs_taste, +	.ld_dirprefix = "ntfs/", +	.ld_enabled = 1 +}; + +G_LABEL_INIT(ntfs, g_label_ntfs, "Create device nodes for NTFS volumes"); diff --git a/sys/geom/label/g_label_swaplinux.c b/sys/geom/label/g_label_swaplinux.c new file mode 100644 index 000000000000..5994ad93fd6f --- /dev/null +++ b/sys/geom/label/g_label_swaplinux.c @@ -0,0 +1,91 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> + +#include <geom/geom.h> +#include <geom/geom_dbg.h> +#include <geom/label/g_label.h> + +/* + * Taken from + * https://github.com/util-linux/util-linux/blob/master/include/swapheader.h + */ + +#define SWAP_VERSION 1 +#define SWAP_UUID_LENGTH 16 +#define SWAP_LABEL_LENGTH 16 +#define SWAP_SIGNATURE "SWAPSPACE2" +#define SWAP_SIGNATURE_SZ (sizeof(SWAP_SIGNATURE) - 1) + +struct swap_header_v1_2 { +	char	      bootbits[1024];    /* Space for disklabel etc. */ +	uint32_t      version; +	uint32_t      last_page; +	uint32_t      nr_badpages; +	unsigned char uuid[SWAP_UUID_LENGTH]; +	char	      volume_name[SWAP_LABEL_LENGTH]; +	uint32_t      padding[117]; +	uint32_t      badpages[1]; +}; + +typedef union { +	struct swap_header_v1_2	header; +	struct { +		uint8_t reserved[PAGE_SIZE - SWAP_SIGNATURE_SZ]; +		char	signature[SWAP_SIGNATURE_SZ]; +	} tail; +} swhdr_t; + +#define sw_version	header.version +#define sw_volume_name	header.volume_name +#define sw_signature	tail.signature + +static void +g_label_swaplinux_taste(struct g_consumer *cp, char *label, size_t size) +{ +	struct g_provider *pp; +	swhdr_t *hdr; + +	g_topology_assert_not(); +	pp = cp->provider; +	label[0] = '\0'; + +	KASSERT(pp->sectorsize != 0, ("Tasting a disk with 0 sectorsize")); +	if ((PAGE_SIZE % pp->sectorsize) != 0) +		return; + +	hdr = (swhdr_t *)g_read_data(cp, 0, PAGE_SIZE, NULL); +	if (hdr == NULL) +		return; + +	/* Check version and magic string */ +	if (hdr->sw_version == SWAP_VERSION && +	    !memcmp(hdr->sw_signature, SWAP_SIGNATURE, SWAP_SIGNATURE_SZ)) +		G_LABEL_DEBUG(1, "linux swap detected on %s.", pp->name); +	else +		goto exit_free; + +	/* Check for volume label */ +	if (hdr->sw_volume_name[0] == '\0') +		goto exit_free; + +	/* Terminate label */ +	hdr->sw_volume_name[sizeof(hdr->sw_volume_name) - 1] = '\0'; +	strlcpy(label, hdr->sw_volume_name, size); + +exit_free: +	g_free(hdr); +} + +struct g_label_desc g_label_swaplinux = { +	.ld_taste = g_label_swaplinux_taste, +	.ld_dirprefix = "swaplinux/", +	.ld_enabled = 1 +}; + +G_LABEL_INIT(swaplinux, g_label_swaplinux, "Create device nodes for Linux swap"); diff --git a/sys/geom/label/g_label_ufs.c b/sys/geom/label/g_label_ufs.c new file mode 100644 index 000000000000..9361af7a136b --- /dev/null +++ b/sys/geom/label/g_label_ufs.c @@ -0,0 +1,206 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2002, 2003 Gordon Tetlow + * Copyright (c) 2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/disklabel.h> +#include <sys/malloc.h> +#include <sys/vnode.h> + +#include <ufs/ufs/dinode.h> +#include <ufs/ffs/fs.h> +#include <ufs/ufs/quota.h> +#include <ufs/ufs/extattr.h> +#include <ufs/ffs/ffs_extern.h> + +#include <geom/geom.h> +#include <geom/geom_dbg.h> +#include <geom/label/g_label.h> + +#define	G_LABEL_UFS_VOLUME	0 +#define	G_LABEL_UFS_ID		1 + +/* + * G_LABEL_UFS_CMP returns true if difference between provider mediasize + * and filesystem size is less than G_LABEL_UFS_MAXDIFF sectors + */ +#define	G_LABEL_UFS_CMP(prov, fsys, size) 				   \ +	( abs( ((fsys)->size) - ( (prov)->mediasize / (fsys)->fs_fsize ))  \ +				< G_LABEL_UFS_MAXDIFF ) +#define	G_LABEL_UFS_MAXDIFF	0x100 + +/* + * For providers that look like disklabels we need to check if the file system + * size is almost equal to the provider's size, because sysinstall(8) used to + * bogusly put the first partition at offset 0 instead of 16, and glabel/ufs + * would find a file system on the slice instead of the partition. + * + * In addition, media size can be a bit bigger than file system size. For + * instance, mkuzip can append bytes to align data to large sector size (it + * improves compression rates). + */ +static bool +g_label_ufs_ignore_bsdlabel_slice(struct g_consumer *cp, +    struct fs *fs) +{ +	struct g_provider *pp; +	u_char *buf; +	uint32_t magic1, magic2; +	int error; + +	pp = cp->provider; + +	/* +	 * If the expected provider size for the filesystem matches the +	 * real provider size then don't ignore this filesystem. +	 */ +	if (G_LABEL_UFS_CMP(pp, fs, fs_providersize)) +		return (false); + +	/* +	 * If the filesystem size matches the real provider size then +	 * don't ignore this filesystem. +	 */ +	if (fs->fs_magic == FS_UFS1_MAGIC ? +	    G_LABEL_UFS_CMP(pp, fs, fs_old_size) : +	    G_LABEL_UFS_CMP(pp, fs, fs_size)) +		return (false); + +	/* +	 * Provider is bigger than expected; probe to see if there's a +	 * disklabel. Adapted from g_part_bsd_probe. +	 */ + +	/* Check if the superblock overlaps where the disklabel lives. */ +	if (fs->fs_sblockloc < pp->sectorsize * 2) +		return (false); + +	/* Sanity-check the provider. */ +	if (pp->sectorsize < sizeof(struct disklabel) || +	    pp->mediasize < BBSIZE) +		return (false); +	if (BBSIZE % pp->sectorsize) +		return (false); + +	/* Check that there's a disklabel. */ +	buf = g_read_data(cp, pp->sectorsize, pp->sectorsize, &error); +	if (buf == NULL) +		return (false); +	magic1 = le32dec(buf + 0); +	magic2 = le32dec(buf + 132); +	g_free(buf); +	if (magic1 == DISKMAGIC && magic2 == DISKMAGIC) +		return (true); + +	return (false); +} + +/* + * Try to find a superblock on the provider. If successful, look for a volume + * label and create an appropriate provider based on that. + */ +static void +g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int what) +{ +	struct g_provider *pp; +	struct fs *fs; + +	g_topology_assert_not(); +	pp = cp->provider; +	label[0] = '\0'; + +	fs = NULL; +	KASSERT(pp->sectorsize != 0, ("Tasting a disk with 0 sectorsize")); +	if (SBLOCKSIZE % pp->sectorsize != 0 || ffs_sbget(cp, &fs, UFS_STDSB, +	    UFS_NOHASHFAIL | UFS_NOCSUM | UFS_NOMSG, M_GEOM, g_use_g_read_data) +	    != 0) { +		KASSERT(fs == NULL, +		    ("g_label_ufs_taste_common: non-NULL fs %p\n", fs)); +		return; +	} + +	/* Check for magic. */ +	if (fs->fs_magic == FS_UFS1_MAGIC && fs->fs_fsize > 0) { +		/* Valid UFS1. */ +	} else if (fs->fs_magic == FS_UFS2_MAGIC && fs->fs_fsize > 0) { +		/* Valid UFS2. */ +	} else { +		goto out; +	} +	/* Check if this should be ignored for compatibility. */ +	if (g_label_ufs_ignore_bsdlabel_slice(cp, fs)) +		goto out; +	G_LABEL_DEBUG(1, "%s file system detected on %s.", +	    fs->fs_magic == FS_UFS1_MAGIC ? "UFS1" : "UFS2", pp->name); +	switch (what) { +	case G_LABEL_UFS_VOLUME: +		/* Check for volume label */ +		if (fs->fs_volname[0] != '\0') +			strlcpy(label, fs->fs_volname, size); +		break; +	case G_LABEL_UFS_ID: +		if (fs->fs_id[0] != 0 || fs->fs_id[1] != 0) +			snprintf(label, size, "%08x%08x", fs->fs_id[0], +			    fs->fs_id[1]); +		break; +	} +out: +	g_free(fs); +} + +static void +g_label_ufs_volume_taste(struct g_consumer *cp, char *label, size_t size) +{ + +	g_label_ufs_taste_common(cp, label, size, G_LABEL_UFS_VOLUME); +} + +static void +g_label_ufs_id_taste(struct g_consumer *cp, char *label, size_t size) +{ + +	g_label_ufs_taste_common(cp, label, size, G_LABEL_UFS_ID); +} + +struct g_label_desc g_label_ufs_volume = { +	.ld_taste = g_label_ufs_volume_taste, +	.ld_dirprefix = "ufs/", +	.ld_enabled = 1 +}; + +struct g_label_desc g_label_ufs_id = { +	.ld_taste = g_label_ufs_id_taste, +	.ld_dirprefix = "ufsid/", +	.ld_enabled = 1 +}; + +G_LABEL_INIT(ufsid, g_label_ufs_id, "Create device nodes for UFS file system IDs"); +G_LABEL_INIT(ufs, g_label_ufs_volume, "Create device nodes for UFS volume names"); + +MODULE_DEPEND(g_label, ufs, 1, 1, 1); | 
