diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/conf/NOTES | 1 | ||||
-rw-r--r-- | sys/conf/files | 4 | ||||
-rw-r--r-- | sys/conf/options | 1 | ||||
-rw-r--r-- | sys/geom/label/g_label.c | 405 | ||||
-rw-r--r-- | sys/geom/label/g_label.h | 97 | ||||
-rw-r--r-- | sys/geom/label/g_label_iso9660.c | 80 | ||||
-rw-r--r-- | sys/geom/label/g_label_msdosfs.c | 101 | ||||
-rw-r--r-- | sys/geom/label/g_label_ufs.c | 102 | ||||
-rw-r--r-- | sys/modules/geom/Makefile | 1 | ||||
-rw-r--r-- | sys/modules/geom/geom_label/Makefile | 11 |
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> |