Index: head/usr.sbin/fstyp/hammer.c =================================================================== --- head/usr.sbin/fstyp/hammer.c (revision 357630) +++ head/usr.sbin/fstyp/hammer.c (revision 357631) @@ -1,198 +1,208 @@ /*- - * Copyright (c) 2016 The DragonFly Project + * Copyright (c) 2016-2019 The DragonFly Project + * Copyright (c) 2016-2019 Tomohiro Kusumi * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include "hammer_disk.h" #include "fstyp.h" static hammer_volume_ondisk_t -__read_ondisk(FILE *fp) +read_ondisk(FILE *fp) { hammer_volume_ondisk_t ondisk; ondisk = read_buf(fp, 0, sizeof(*ondisk)); if (ondisk == NULL) err(1, "failed to read ondisk"); return (ondisk); } static int -__test_ondisk(const hammer_volume_ondisk_t ondisk) +test_ondisk(const hammer_volume_ondisk_t ondisk) { static int count = 0; static hammer_uuid_t fsid, fstype; static char label[64]; if (ondisk->vol_signature != HAMMER_FSBUF_VOLUME && ondisk->vol_signature != HAMMER_FSBUF_VOLUME_REV) return (1); if (ondisk->vol_rootvol != HAMMER_ROOT_VOLNO) return (2); if (ondisk->vol_no < 0 || ondisk->vol_no > HAMMER_MAX_VOLUMES - 1) return (3); if (ondisk->vol_count < 1 || ondisk->vol_count > HAMMER_MAX_VOLUMES) return (4); if (count == 0) { count = ondisk->vol_count; assert(count != 0); memcpy(&fsid, &ondisk->vol_fsid, sizeof(fsid)); memcpy(&fstype, &ondisk->vol_fstype, sizeof(fstype)); strlcpy(label, ondisk->vol_label, sizeof(label)); } else { if (ondisk->vol_count != count) return (5); if (memcmp(&ondisk->vol_fsid, &fsid, sizeof(fsid))) return (6); if (memcmp(&ondisk->vol_fstype, &fstype, sizeof(fstype))) return (7); if (strcmp(ondisk->vol_label, label)) return (8); } return (0); } int fstyp_hammer(FILE *fp, char *label, size_t size) { hammer_volume_ondisk_t ondisk; int error = 1; - ondisk = __read_ondisk(fp); + ondisk = read_ondisk(fp); if (ondisk->vol_no != HAMMER_ROOT_VOLNO) - goto done; + goto fail; if (ondisk->vol_count != 1) - goto done; - if (__test_ondisk(ondisk)) - goto done; + goto fail; + if (test_ondisk(ondisk)) + goto fail; strlcpy(label, ondisk->vol_label, size); error = 0; -done: +fail: free(ondisk); return (error); } static int -__test_volume(const char *volpath) +test_volume(const char *volpath) { hammer_volume_ondisk_t ondisk; FILE *fp; int volno = -1; if ((fp = fopen(volpath, "r")) == NULL) err(1, "failed to open %s", volpath); - ondisk = __read_ondisk(fp); + ondisk = read_ondisk(fp); fclose(fp); - if (__test_ondisk(ondisk)) - goto done; + if (test_ondisk(ondisk)) + goto fail; volno = ondisk->vol_no; -done: +fail: free(ondisk); return (volno); } static int __fsvtyp_hammer(const char *blkdevs, char *label, size_t size, int partial) { - hammer_volume_ondisk_t ondisk; + hammer_volume_ondisk_t ondisk = NULL; FILE *fp; char *dup, *p, *volpath, x[HAMMER_MAX_VOLUMES]; int i, volno, error = 1; + if (!blkdevs) + goto fail; + memset(x, 0, sizeof(x)); dup = strdup(blkdevs); p = dup; + volpath = NULL; + volno = -1; while (p) { volpath = p; if ((p = strchr(p, ':')) != NULL) *p++ = '\0'; - if ((volno = __test_volume(volpath)) == -1) + if ((volno = test_volume(volpath)) == -1) break; + assert(volno >= 0); + assert(volno < HAMMER_MAX_VOLUMES); x[volno]++; } + if (!volpath) + err(1, "invalid path %s", blkdevs); if ((fp = fopen(volpath, "r")) == NULL) err(1, "failed to open %s", volpath); - ondisk = __read_ondisk(fp); + ondisk = read_ondisk(fp); fclose(fp); free(dup); if (volno == -1) - goto done; + goto fail; if (partial) goto success; for (i = 0; i < HAMMER_MAX_VOLUMES; i++) if (x[i] > 1) - goto done; + goto fail; for (i = 0; i < HAMMER_MAX_VOLUMES; i++) if (x[i] == 0) break; if (ondisk->vol_count != i) - goto done; + goto fail; for (; i < HAMMER_MAX_VOLUMES; i++) if (x[i] != 0) - goto done; + goto fail; success: strlcpy(label, ondisk->vol_label, size); error = 0; -done: +fail: free(ondisk); return (error); } int fsvtyp_hammer(const char *blkdevs, char *label, size_t size) { return (__fsvtyp_hammer(blkdevs, label, size, 0)); } int fsvtyp_hammer_partial(const char *blkdevs, char *label, size_t size) { return (__fsvtyp_hammer(blkdevs, label, size, 1)); } Index: head/usr.sbin/fstyp/hammer2.c =================================================================== --- head/usr.sbin/fstyp/hammer2.c (revision 357630) +++ head/usr.sbin/fstyp/hammer2.c (revision 357631) @@ -1,147 +1,287 @@ /*- * Copyright (c) 2017-2019 The DragonFly Project + * Copyright (c) 2017-2019 Tomohiro Kusumi * All rights reserved. * * This software was developed by Edward Tomasz Napierala under sponsorship * from the FreeBSD Foundation. * * 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 __FBSDID("$FreeBSD$"); #include #include +#include #include #include +#include #include #include "hammer2_disk.h" #include "fstyp.h" static hammer2_volume_data_t* -__read_voldata(FILE *fp) +read_voldata(FILE *fp) { hammer2_volume_data_t *voldata; voldata = read_buf(fp, 0, sizeof(*voldata)); if (voldata == NULL) err(1, "failed to read volume data"); return (voldata); } static int -__test_voldata(const hammer2_volume_data_t *voldata) +test_voldata(const hammer2_volume_data_t *voldata) { if (voldata->magic != HAMMER2_VOLUME_ID_HBO && voldata->magic != HAMMER2_VOLUME_ID_ABO) return (1); return (0); } +static hammer2_media_data_t* +read_media(FILE *fp, const hammer2_blockref_t *bref, size_t *media_bytes) +{ + hammer2_media_data_t *media; + hammer2_off_t io_off, io_base; + size_t bytes, io_bytes, boff; + + bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX); + if (bytes) + bytes = (size_t)1 << bytes; + *media_bytes = bytes; + + if (!bytes) { + warnx("blockref has no data"); + return (NULL); + } + + io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; + io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1); + boff = io_off - io_base; + + io_bytes = HAMMER2_MINIOSIZE; + while (io_bytes + boff < bytes) + io_bytes <<= 1; + + if (io_bytes > sizeof(hammer2_media_data_t)) { + warnx("invalid I/O bytes"); + return (NULL); + } + + if (fseek(fp, io_base, SEEK_SET) == -1) { + warnx("failed to seek media"); + return (NULL); + } + media = read_buf(fp, io_base, io_bytes); + if (media == NULL) { + warnx("failed to read media"); + return (NULL); + } + if (boff) + memcpy(media, (char *)media + boff, bytes); + + return (media); +} + static int -__read_label(FILE *fp, char *label, size_t size) +find_pfs(FILE *fp, const hammer2_blockref_t *bref, const char *pfs, bool *res) { + hammer2_media_data_t *media; + hammer2_inode_data_t ipdata; + hammer2_blockref_t *bscan; + size_t bytes; + int i, bcount; + + media = read_media(fp, bref, &bytes); + if (media == NULL) + return (-1); + + switch (bref->type) { + case HAMMER2_BREF_TYPE_INODE: + ipdata = media->ipdata; + if (ipdata.meta.pfs_type & HAMMER2_PFSTYPE_SUPROOT) { + bscan = &ipdata.u.blockset.blockref[0]; + bcount = HAMMER2_SET_COUNT; + } else { + bscan = NULL; + bcount = 0; + if (ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) { + if (memchr(ipdata.filename, 0, + sizeof(ipdata.filename))) { + if (!strcmp( + (const char*)ipdata.filename, pfs)) + *res = true; + } else { + if (strlen(pfs) > 0 && + !memcmp(ipdata.filename, pfs, + strlen(pfs))) + *res = true; + } + } else + assert(0); + } + break; + case HAMMER2_BREF_TYPE_INDIRECT: + bscan = &media->npdata[0]; + bcount = bytes / sizeof(hammer2_blockref_t); + break; + default: + bscan = NULL; + bcount = 0; + break; + } + + for (i = 0; i < bcount; ++i) { + if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) { + if (find_pfs(fp, &bscan[i], pfs, res) == -1) { + free(media); + return (-1); + } + } + } + free(media); + + return (0); +} + +static char* +extract_device_name(const char *devpath) +{ + char *p, *head; + + if (!devpath) + return NULL; + + p = strdup(devpath); + head = p; + + p = strchr(p, '@'); + if (p) + *p = 0; + + p = strrchr(head, '/'); + if (p) { + p++; + if (*p == 0) { + free(head); + return NULL; + } + p = strdup(p); + free(head); + return p; + } + + return head; +} + +static int +read_label(FILE *fp, char *label, size_t size) +{ hammer2_blockref_t broot, best, *bref; hammer2_media_data_t *vols[HAMMER2_NUM_VOLHDRS], *media; - hammer2_off_t io_off, io_base; - size_t bytes, io_bytes, boff; - int i, best_i, error = 0; + size_t bytes; + bool res = false; + int i, best_i, error = 1; + const char *pfs; + char *devname; best_i = -1; memset(&best, 0, sizeof(best)); for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) { memset(&broot, 0, sizeof(broot)); broot.type = HAMMER2_BREF_TYPE_VOLUME; broot.data_off = (i * HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX; vols[i] = read_buf(fp, broot.data_off & ~HAMMER2_OFF_MASK_RADIX, sizeof(*vols[i])); broot.mirror_tid = vols[i]->voldata.mirror_tid; if (best_i < 0 || best.mirror_tid < broot.mirror_tid) { best_i = i; best = broot; } } bref = &vols[best_i]->voldata.sroot_blockset.blockref[0]; if (bref->type != HAMMER2_BREF_TYPE_INODE) { - warnx("Superroot blockref type is not inode"); - error = 2; - goto done; + warnx("blockref type is not inode"); + goto fail; } - bytes = bref->data_off & HAMMER2_OFF_MASK_RADIX; - if (bytes) - bytes = (size_t)1 << bytes; - if (bytes != sizeof(hammer2_inode_data_t)) { - warnx("Superroot blockref size does not match inode size"); - error = 3; - goto done; + media = read_media(fp, bref, &bytes); + if (media == NULL) { + goto fail; } - io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; - io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1); - boff = io_off - io_base; + pfs = ""; + devname = extract_device_name(NULL); + assert(!devname); /* Currently always NULL in FreeBSD. */ - io_bytes = HAMMER2_MINIOSIZE; - while (io_bytes + boff < bytes) - io_bytes <<= 1; - if (io_bytes > sizeof(*media)) { - warnx("Invalid I/O bytes"); - error = 4; - goto done; + /* Add device name to help support multiple autofs -media mounts. */ + if (find_pfs(fp, bref, pfs, &res) == 0 && res) { + if (devname) + snprintf(label, size, "%s_%s", pfs, devname); + else + strlcpy(label, pfs, size); + } else { + memset(label, 0, size); + memcpy(label, media->ipdata.filename, + sizeof(media->ipdata.filename)); + if (devname) { + strlcat(label, "_", size); + strlcat(label, devname, size); + } } - - media = read_buf(fp, io_base, io_bytes); - if (boff) - memcpy(media, (char*)media + boff, bytes); - - strlcpy(label, (char*)media->ipdata.filename, size); + if (devname) + free(devname); free(media); -done: + error = 0; +fail: for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) free(vols[i]); return (error); } int fstyp_hammer2(FILE *fp, char *label, size_t size) { hammer2_volume_data_t *voldata; int error = 1; - voldata = __read_voldata(fp); - if (__test_voldata(voldata)) - goto done; + voldata = read_voldata(fp); + if (test_voldata(voldata)) + goto fail; - error = __read_label(fp, label, size); -done: + error = read_label(fp, label, size); +fail: free(voldata); return (error); }