summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/NOTES1
-rw-r--r--sys/conf/files4
-rw-r--r--sys/conf/options1
-rw-r--r--sys/geom/label/g_label.c405
-rw-r--r--sys/geom/label/g_label.h97
-rw-r--r--sys/geom/label/g_label_iso9660.c80
-rw-r--r--sys/geom/label/g_label_msdosfs.c101
-rw-r--r--sys/geom/label/g_label_ufs.c102
-rw-r--r--sys/modules/geom/Makefile1
-rw-r--r--sys/modules/geom/geom_label/Makefile11
10 files changed, 803 insertions, 0 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 2191e57..2607142 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -125,6 +125,7 @@ options GEOM_CONCAT # Disk concatenation.
options GEOM_FOX # Redundant path mitigation
options GEOM_GATE # Userland services.
options GEOM_GPT # GPT partitioning
+options GEOM_LABEL # Providers labelization.
options GEOM_MBR # DOS/MBR partitioning
options GEOM_NOP # Test class.
options GEOM_PC98 # NEC PC9800 partitioning
diff --git a/sys/conf/files b/sys/conf/files
index 10c2df7..a25b963 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -940,6 +940,10 @@ crypto/rijndael/rijndael-api-fst.c optional geom_bde
crypto/sha2/sha2.c optional geom_bde
geom/concat/g_concat.c optional geom_concat
geom/gate/g_gate.c optional geom_gate
+geom/label/g_label.c optional geom_label
+geom/label/g_label_iso9660.c optional geom_label
+geom/label/g_label_msdosfs.c optional geom_label
+geom/label/g_label_ufs.c optional geom_label
geom/nop/g_nop.c optional geom_nop
geom/stripe/g_stripe.c optional geom_stripe
geom/geom_aes.c optional geom_aes
diff --git a/sys/conf/options b/sys/conf/options
index 1c6c146..d086703 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -71,6 +71,7 @@ GEOM_CONCAT opt_geom.h
GEOM_FOX opt_geom.h
GEOM_GATE opt_geom.h
GEOM_GPT opt_geom.h
+GEOM_LABEL opt_geom.h
GEOM_MBR opt_geom.h
GEOM_MIRROR opt_geom.h
GEOM_NOP opt_geom.h
diff --git a/sys/geom/label/g_label.c b/sys/geom/label/g_label.c
new file mode 100644
index 0000000..2aa9754
--- /dev/null
+++ b/sys/geom/label/g_label.c
@@ -0,0 +1,405 @@
+/*-
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#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/sysctl.h>
+#include <sys/malloc.h>
+#include <geom/geom.h>
+#include <geom/geom_slice.h>
+#include <geom/label/g_label.h>
+
+
+SYSCTL_DECL(_kern_geom);
+SYSCTL_NODE(_kern_geom, OID_AUTO, label, CTLFLAG_RW, 0, "GEOM_LABEL stuff");
+u_int g_label_debug = 0;
+SYSCTL_UINT(_kern_geom_label, OID_AUTO, debug, CTLFLAG_RW, &g_label_debug, 0,
+ "Debug level");
+
+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_config(struct gctl_req *req, struct g_class *mp,
+ const char *verb);
+
+struct g_class g_label_class = {
+ .name = G_LABEL_CLASS_NAME,
+ .ctlreq = g_label_config,
+ .taste = g_label_taste
+};
+
+/*
+ * To add a new file system where you want to look for volume labels,
+ * you have to:
+ * 1. Add a file which implements looking for volume labels.
+ * 2. Add an 'extern const struct g_label_desc g_label_<your file system>;'.
+ * 3. Add an element to the table below '&g_label_<your_file_system>,'.
+ */
+const struct g_label_desc *g_labels[] = {
+ &g_label_ufs,
+ &g_label_iso9660,
+ &g_label_msdosfs,
+ NULL
+};
+
+
+static void
+g_label_orphan(struct g_consumer *cp __unused)
+{
+
+ KASSERT(1 == 0, ("%s called?", __func__));
+}
+
+static void
+g_label_start(struct bio *bp __unused)
+{
+
+ KASSERT(1 == 0, ("%s called?", __func__));
+}
+
+static int
+g_label_access(struct g_provider *pp __unused, int dr __unused, int dw __unused,
+ int de __unused)
+{
+
+ KASSERT(1 == 0, ("%s called", __func__));
+ return (EOPNOTSUPP);
+}
+
+static struct g_geom *
+g_label_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp,
+ const char *label, const char *dir, off_t mediasize)
+{
+ struct g_geom *gp;
+ struct g_provider *pp2;
+ struct g_consumer *cp;
+ char name[64];
+
+ g_topology_assert();
+
+ gp = NULL;
+ cp = NULL;
+ snprintf(name, sizeof(name), "%s/%s", dir, label);
+ LIST_FOREACH(gp, &mp->geom, geom) {
+ pp2 = LIST_FIRST(&gp->provider);
+ if (pp2 == NULL)
+ 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);
+ }
+ g_access(cp, -1, 0, 0);
+ g_slice_config(gp, 0, G_SLICE_CONFIG_SET, (off_t)0, mediasize,
+ pp->sectorsize, name);
+ G_LABEL_DEBUG(0, "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 {
+ G_LABEL_DEBUG(0, "Label %s removed.",
+ LIST_FIRST(&gp->provider)->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;
+
+ g_topology_assert();
+
+ pp = cp->provider;
+ g_topology_unlock();
+ buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
+ &error);
+ g_topology_lock();
+ if (buf == NULL)
+ return (error);
+ /* Decode metadata. */
+ label_metadata_decode(buf, md);
+ g_free(buf);
+
+ return (0);
+}
+
+static struct g_geom *
+g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
+{
+ struct g_label_metadata md;
+ struct g_consumer *cp;
+ struct g_geom *gp;
+ int error, i;
+
+ g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
+ g_topology_assert();
+
+ G_LABEL_DEBUG(3, "Tasting %s.", pp->name);
+
+ if (strcmp(pp->geom->class->name, mp->name) == 0)
+ return (NULL);
+
+ gp = g_new_geomf(mp, "label:taste");
+ gp->start = g_label_start;
+ gp->access = g_label_access;
+ gp->orphan = g_label_orphan;
+ cp = g_new_consumer(gp);
+ g_attach(cp, pp);
+ error = g_access(cp, 1, 0, 0);
+ if (error != 0)
+ return (NULL);
+
+ do {
+ error = g_label_read_metadata(cp, &md);
+ if (error != 0)
+ break;
+ if (strcmp(md.md_magic, G_LABEL_MAGIC) != 0)
+ break;
+ if (md.md_version > G_LABEL_VERSION) {
+ printf("geom_label.ko module is too old to handle %s.\n",
+ pp->name);
+ break;
+ }
+ g_label_create(NULL, mp, pp, md.md_label, G_LABEL_DIR,
+ pp->mediasize - pp->sectorsize);
+ } while (0);
+ for (i = 0; g_labels[i] != NULL; i++) {
+ char label[64];
+
+ g_topology_unlock();
+ g_labels[i]->ld_taste(cp, label, sizeof(label));
+ g_topology_lock();
+ if (label[0] == '\0')
+ continue;
+ g_label_create(NULL, mp, pp, label, g_labels[i]->ld_dir,
+ pp->mediasize);
+ }
+
+ g_access(cp, -1, 0, 0);
+ g_wither_geom(gp, ENXIO);
+
+ 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 argument.");
+ return;
+ }
+ /*
+ * arg1 is the name of provider.
+ */
+ name = gctl_get_asciiparam(req, "arg1");
+ if (name == NULL) {
+ gctl_error(req, "No 'arg%d' argument", 1);
+ return;
+ }
+ if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
+ name += strlen("/dev/");
+ pp = g_provider_by_name(name);
+ if (pp == NULL) {
+ G_LABEL_DEBUG(1, "Provider %s is invalid.", name);
+ gctl_error(req, "Provider %s is invalid.", name);
+ 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_DIR, pp->mediasize);
+}
+
+static const char *
+g_label_skip_dir(const char *name)
+{
+ char path[64];
+ u_int i;
+
+ if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
+ name += strlen("/dev/");
+ if (strncmp(name, G_LABEL_DIR "/", strlen(G_LABEL_DIR "/")) == 0)
+ name += strlen(G_LABEL_DIR "/");
+ for (i = 0; g_labels[i] != NULL; i++) {
+ snprintf(path, sizeof(path), "%s/", g_labels[i]->ld_dir);
+ if (strncmp(name, path, strlen(path)) == 0) {
+ name += strlen(path);
+ 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) {
+ g_label_ctl_destroy(req, mp);
+ return;
+ }
+
+ gctl_error(req, "Unknown verb.");
+}
+
+DECLARE_GEOM_CLASS(g_label_class, g_label);
diff --git a/sys/geom/label/g_label.h b/sys/geom/label/g_label.h
new file mode 100644
index 0000000..011cc5e
--- /dev/null
+++ b/sys/geom/label/g_label.h
@@ -0,0 +1,97 @@
+/*-
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _G_LABEL_H_
+#define _G_LABEL_H_
+
+#include <sys/endian.h>
+
+#define G_LABEL_CLASS_NAME "LABEL"
+
+#define G_LABEL_MAGIC "GEOM::LABEL"
+#define G_LABEL_VERSION 0
+#define G_LABEL_DIR "label"
+
+#ifdef _KERNEL
+extern u_int g_label_debug;
+
+#define G_LABEL_DEBUG(lvl, ...) do { \
+ if (g_label_debug >= (lvl)) { \
+ printf("GEOM_LABEL"); \
+ if (g_label_debug > 0) \
+ printf("[%u]", lvl); \
+ printf(": "); \
+ printf(__VA_ARGS__); \
+ printf("\n"); \
+ } \
+} while (0)
+#define G_LABEL_LOGREQ(bp, ...) do { \
+ if (g_label_debug >= 2) { \
+ printf("GEOM_LABEL[2]: "); \
+ printf(__VA_ARGS__); \
+ printf(" "); \
+ g_print_bio(bp); \
+ printf("\n"); \
+ } \
+} while (0)
+
+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_dir;
+};
+
+/* Supported labels. */
+extern const struct g_label_desc g_label_ufs;
+extern const struct g_label_desc g_label_iso9660;
+extern const struct g_label_desc g_label_msdosfs;
+#endif /* _KERNEL */
+
+struct g_label_metadata {
+ char md_magic[16]; /* Magic value. */
+ uint32_t md_version; /* Version number. */
+ char md_label[16]; /* Label. */
+};
+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));
+}
+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));
+}
+#endif /* _G_LABEL_H_ */
diff --git a/sys/geom/label/g_label_iso9660.c b/sys/geom/label/g_label_iso9660.c
new file mode 100644
index 0000000..34d9252
--- /dev/null
+++ b/sys/geom/label/g_label_iso9660.c
@@ -0,0 +1,80 @@
+/*-
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#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 G_LABEL_ISO9660_DIR "iso9660"
+
+#define ISO9660_MAGIC "\x01" "CD001" "\x01\x00"
+#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;
+ int i, error;
+
+ g_topology_assert_not();
+ pp = cp->provider;
+ label[0] = '\0';
+
+ sector = (char *)g_read_data(cp, 0x8000, pp->sectorsize, &error);
+ if (sector == NULL || error != 0)
+ 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);
+ for (i = size - 1; i > 0; i--) {
+ if (label[i] == '\0')
+ continue;
+ else if (label[i] == ' ')
+ label[i] = '\0';
+ else
+ break;
+ }
+}
+
+const struct g_label_desc g_label_iso9660 = {
+ .ld_taste = g_label_iso9660_taste,
+ .ld_dir = G_LABEL_ISO9660_DIR
+};
diff --git a/sys/geom/label/g_label_msdosfs.c b/sys/geom/label/g_label_msdosfs.c
new file mode 100644
index 0000000..ff0d7c3
--- /dev/null
+++ b/sys/geom/label/g_label_msdosfs.c
@@ -0,0 +1,101 @@
+/*-
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#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 G_LABEL_MSDOSFS_DIR "msdosfs"
+
+#define FAT12 "FAT12 "
+#define FAT16 "FAT16 "
+#define FAT32 "FAT32 "
+#define VOLUME_LEN 11
+#define NO_NAME "NO NAME "
+
+
+static void
+g_label_msdosfs_taste(struct g_consumer *cp, char *label, size_t size)
+{
+ struct g_provider *pp;
+ char *sector, *volume;
+ int i, error;
+
+ g_topology_assert_not();
+ pp = cp->provider;
+ label[0] = '\0';
+
+ sector = (char *)g_read_data(cp, 0, pp->sectorsize, &error);
+ if (sector == NULL || error != 0)
+ return;
+ if (strncmp(sector + 0x36, FAT12, strlen(FAT12)) == 0) {
+ G_LABEL_DEBUG(1, "MSDOS (FAT12) file system detected on %s.",
+ pp->name);
+ volume = sector + 0x2b;
+ } else if (strncmp(sector + 0x36, FAT16, strlen(FAT16)) == 0) {
+ G_LABEL_DEBUG(1, "MSDOS (FAT16) file system detected on %s.",
+ pp->name);
+ volume = sector + 0x2b;
+ } else if (strncmp(sector + 0x52, FAT32, strlen(FAT32)) == 0) {
+ G_LABEL_DEBUG(1, "MSDOS (FAT32) file system detected on %s.",
+ pp->name);
+ volume = sector + 0x47;
+ } else {
+ g_free(sector);
+ return;
+ }
+ if (strncmp(volume, NO_NAME, VOLUME_LEN) == 0) {
+ g_free(sector);
+ return;
+ }
+ if (volume[0] == '\0') {
+ g_free(sector);
+ return;
+ }
+ bzero(label, size);
+ strlcpy(label, volume, MIN(size, VOLUME_LEN));
+ g_free(sector);
+ for (i = size - 1; i > 0; i--) {
+ if (label[i] == '\0')
+ continue;
+ else if (label[i] == ' ')
+ label[i] = '\0';
+ else
+ break;
+ }
+}
+
+const struct g_label_desc g_label_msdosfs = {
+ .ld_taste = g_label_msdosfs_taste,
+ .ld_dir = G_LABEL_MSDOSFS_DIR
+};
diff --git a/sys/geom/label/g_label_ufs.c b/sys/geom/label/g_label_ufs.c
new file mode 100644
index 0000000..dc188f7
--- /dev/null
+++ b/sys/geom/label/g_label_ufs.c
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 2002, 2003 Gordon Tetlow
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+
+#include <geom/geom.h>
+#include <geom/label/g_label.h>
+
+#define G_LABEL_UFS_DIR "ufs"
+
+static const int superblocks[] = SBLOCKSEARCH;
+
+static void
+g_label_ufs_taste(struct g_consumer *cp, char *label, size_t size)
+{
+ struct g_provider *pp;
+ int error, sb, superblock;
+ struct fs *fs;
+
+ g_topology_assert_not();
+ pp = cp->provider;
+ label[0] = '\0';
+ /*
+ * Walk through the standard places that superblocks hide and look
+ * for UFS magic. If we find magic, then check that the size in the
+ * superblock corresponds to the size of the underlying provider.
+ * Finally, look for a volume label and create an appropriate
+ * provider based on that.
+ */
+ for (sb = 0; (superblock = superblocks[sb]) != -1; sb++) {
+ fs = (struct fs *)g_read_data(cp, superblock, SBLOCKSIZE,
+ &error);
+ if (fs == NULL || error != 0)
+ continue;
+ /* Check for magic and make sure things are the right size */
+ if (fs->fs_magic == FS_UFS1_MAGIC) {
+ G_LABEL_DEBUG(1, "UFS1 file system detected on %s.",
+ pp->name);
+ if (fs->fs_old_size * fs->fs_fsize !=
+ (int32_t)pp->mediasize) {
+ g_free(fs);
+ continue;
+ }
+ } else if (fs->fs_magic == FS_UFS2_MAGIC) {
+ G_LABEL_DEBUG(1, "UFS2 file system detected on %s.",
+ pp->name);
+ if (fs->fs_size * fs->fs_fsize !=
+ (int64_t)pp->mediasize) {
+ g_free(fs);
+ continue;
+ }
+ } else {
+ g_free(fs);
+ continue;
+ }
+ /* Check for volume label */
+ if (fs->fs_volname[0] == '\0') {
+ g_free(fs);
+ continue;
+ }
+ strlcpy(label, fs->fs_volname, size);
+ g_free(fs);
+ break;
+ }
+}
+
+const struct g_label_desc g_label_ufs = {
+ .ld_taste = g_label_ufs_taste,
+ .ld_dir = G_LABEL_UFS_DIR
+};
diff --git a/sys/modules/geom/Makefile b/sys/modules/geom/Makefile
index 039ae29..880c082 100644
--- a/sys/modules/geom/Makefile
+++ b/sys/modules/geom/Makefile
@@ -8,6 +8,7 @@ SUBDIR= geom_apple \
geom_fox \
geom_gate \
geom_gpt \
+ geom_label \
geom_mbr \
geom_nop \
geom_pc98 \
diff --git a/sys/modules/geom/geom_label/Makefile b/sys/modules/geom/geom_label/Makefile
new file mode 100644
index 0000000..839a48e
--- /dev/null
+++ b/sys/modules/geom/geom_label/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../../geom/label
+
+KMOD= geom_label
+SRCS= g_label.c
+SRCS+= g_label_iso9660.c
+SRCS+= g_label_msdosfs.c
+SRCS+= g_label_ufs.c
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud