1030fdd8aSTomohiro Kusumi /*- 226cca7e2STomohiro Kusumi * Copyright (c) 2017-2019 The DragonFly Project 396fbde7aSTomohiro Kusumi * Copyright (c) 2017-2019 Tomohiro Kusumi <tkusumi@netbsd.org> 4030fdd8aSTomohiro Kusumi * All rights reserved. 5030fdd8aSTomohiro Kusumi * 6030fdd8aSTomohiro Kusumi * Redistribution and use in source and binary forms, with or without 7030fdd8aSTomohiro Kusumi * modification, are permitted provided that the following conditions 8030fdd8aSTomohiro Kusumi * are met: 9030fdd8aSTomohiro Kusumi * 1. Redistributions of source code must retain the above copyright 10030fdd8aSTomohiro Kusumi * notice, this list of conditions and the following disclaimer. 11030fdd8aSTomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright 12030fdd8aSTomohiro Kusumi * notice, this list of conditions and the following disclaimer in the 13030fdd8aSTomohiro Kusumi * documentation and/or other materials provided with the distribution. 14030fdd8aSTomohiro Kusumi * 15030fdd8aSTomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 16030fdd8aSTomohiro Kusumi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17030fdd8aSTomohiro Kusumi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18030fdd8aSTomohiro Kusumi * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 19030fdd8aSTomohiro Kusumi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20030fdd8aSTomohiro Kusumi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21030fdd8aSTomohiro Kusumi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22030fdd8aSTomohiro Kusumi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23030fdd8aSTomohiro Kusumi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24030fdd8aSTomohiro Kusumi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25030fdd8aSTomohiro Kusumi * SUCH DAMAGE. 26030fdd8aSTomohiro Kusumi */ 27030fdd8aSTomohiro Kusumi 28030fdd8aSTomohiro Kusumi #include <stdio.h> 29030fdd8aSTomohiro Kusumi #include <stdlib.h> 3065d969b4STomohiro Kusumi #include <stdbool.h> 31030fdd8aSTomohiro Kusumi #include <string.h> 32030fdd8aSTomohiro Kusumi #include <err.h> 3365d969b4STomohiro Kusumi #include <assert.h> 34030fdd8aSTomohiro Kusumi #include <vfs/hammer2/hammer2_disk.h> 35030fdd8aSTomohiro Kusumi 36030fdd8aSTomohiro Kusumi #include "fstyp.h" 37030fdd8aSTomohiro Kusumi 38030fdd8aSTomohiro Kusumi static hammer2_volume_data_t* 39c8efd889STomohiro Kusumi read_voldata(FILE *fp) 40030fdd8aSTomohiro Kusumi { 41030fdd8aSTomohiro Kusumi hammer2_volume_data_t *voldata; 42030fdd8aSTomohiro Kusumi 43030fdd8aSTomohiro Kusumi voldata = read_buf(fp, 0, sizeof(*voldata)); 44030fdd8aSTomohiro Kusumi if (voldata == NULL) 45030fdd8aSTomohiro Kusumi err(1, "failed to read volume data"); 46030fdd8aSTomohiro Kusumi 47030fdd8aSTomohiro Kusumi return (voldata); 48030fdd8aSTomohiro Kusumi } 49030fdd8aSTomohiro Kusumi 50030fdd8aSTomohiro Kusumi static int 51c8efd889STomohiro Kusumi test_voldata(const hammer2_volume_data_t *voldata) 52030fdd8aSTomohiro Kusumi { 53030fdd8aSTomohiro Kusumi if (voldata->magic != HAMMER2_VOLUME_ID_HBO && 54030fdd8aSTomohiro Kusumi voldata->magic != HAMMER2_VOLUME_ID_ABO) 55030fdd8aSTomohiro Kusumi return (1); 56030fdd8aSTomohiro Kusumi 57030fdd8aSTomohiro Kusumi return (0); 58030fdd8aSTomohiro Kusumi } 59030fdd8aSTomohiro Kusumi 6065d969b4STomohiro Kusumi static hammer2_media_data_t* 61c8efd889STomohiro Kusumi read_media(FILE *fp, const hammer2_blockref_t *bref, size_t *media_bytes) 6265d969b4STomohiro Kusumi { 6365d969b4STomohiro Kusumi hammer2_media_data_t *media; 6465d969b4STomohiro Kusumi hammer2_off_t io_off, io_base; 6565d969b4STomohiro Kusumi size_t bytes, io_bytes, boff; 6665d969b4STomohiro Kusumi 6765d969b4STomohiro Kusumi bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX); 6865d969b4STomohiro Kusumi if (bytes) 6965d969b4STomohiro Kusumi bytes = (size_t)1 << bytes; 7065d969b4STomohiro Kusumi *media_bytes = bytes; 7165d969b4STomohiro Kusumi 7265d969b4STomohiro Kusumi if (!bytes) { 73841ef9e9STomohiro Kusumi warnx("blockref has no data"); 7465d969b4STomohiro Kusumi return (NULL); 7565d969b4STomohiro Kusumi } 7665d969b4STomohiro Kusumi 7765d969b4STomohiro Kusumi io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; 7865d969b4STomohiro Kusumi io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1); 7965d969b4STomohiro Kusumi boff = io_off - io_base; 8065d969b4STomohiro Kusumi 8165d969b4STomohiro Kusumi io_bytes = HAMMER2_MINIOSIZE; 8265d969b4STomohiro Kusumi while (io_bytes + boff < bytes) 8365d969b4STomohiro Kusumi io_bytes <<= 1; 8465d969b4STomohiro Kusumi 8565d969b4STomohiro Kusumi if (io_bytes > sizeof(hammer2_media_data_t)) { 86841ef9e9STomohiro Kusumi warnx("invalid I/O bytes"); 8765d969b4STomohiro Kusumi return (NULL); 8865d969b4STomohiro Kusumi } 8965d969b4STomohiro Kusumi 9065d969b4STomohiro Kusumi if (fseek(fp, io_base, SEEK_SET) == -1) { 91841ef9e9STomohiro Kusumi warnx("failed to seek media"); 9265d969b4STomohiro Kusumi return (NULL); 9365d969b4STomohiro Kusumi } 9465d969b4STomohiro Kusumi media = read_buf(fp, io_base, io_bytes); 9565d969b4STomohiro Kusumi if (media == NULL) { 96841ef9e9STomohiro Kusumi warnx("failed to read media"); 9765d969b4STomohiro Kusumi return (NULL); 9865d969b4STomohiro Kusumi } 9965d969b4STomohiro Kusumi if (boff) 10065d969b4STomohiro Kusumi memcpy(media, (char *)media + boff, bytes); 10165d969b4STomohiro Kusumi 10265d969b4STomohiro Kusumi return (media); 10365d969b4STomohiro Kusumi } 10465d969b4STomohiro Kusumi 10526cca7e2STomohiro Kusumi static int 106c8efd889STomohiro Kusumi find_pfs(FILE *fp, const hammer2_blockref_t *bref, const char *pfs, bool *res) 10765d969b4STomohiro Kusumi { 10865d969b4STomohiro Kusumi hammer2_media_data_t *media; 10965d969b4STomohiro Kusumi hammer2_inode_data_t ipdata; 11065d969b4STomohiro Kusumi hammer2_blockref_t *bscan; 11165d969b4STomohiro Kusumi size_t bytes; 11265d969b4STomohiro Kusumi int i, bcount; 11365d969b4STomohiro Kusumi 114c8efd889STomohiro Kusumi media = read_media(fp, bref, &bytes); 11565d969b4STomohiro Kusumi if (media == NULL) 11665d969b4STomohiro Kusumi return (-1); 11765d969b4STomohiro Kusumi 11865d969b4STomohiro Kusumi switch (bref->type) { 11965d969b4STomohiro Kusumi case HAMMER2_BREF_TYPE_INODE: 12065d969b4STomohiro Kusumi ipdata = media->ipdata; 121*029e6489STomohiro Kusumi if (ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) { 12265d969b4STomohiro Kusumi bscan = &ipdata.u.blockset.blockref[0]; 12365d969b4STomohiro Kusumi bcount = HAMMER2_SET_COUNT; 12465d969b4STomohiro Kusumi } else { 12565d969b4STomohiro Kusumi bscan = NULL; 12665d969b4STomohiro Kusumi bcount = 0; 12765d969b4STomohiro Kusumi if (ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) { 12863dc3af7STomohiro Kusumi if (memchr(ipdata.filename, 0, 12963dc3af7STomohiro Kusumi sizeof(ipdata.filename))) { 1304a4aa420STomohiro Kusumi if (!strcmp( 1314a4aa420STomohiro Kusumi (const char*)ipdata.filename, pfs)) 13265d969b4STomohiro Kusumi *res = true; 13363dc3af7STomohiro Kusumi } else { 134e3e33cadSTomohiro Kusumi if (strlen(pfs) > 0 && 135e3e33cadSTomohiro Kusumi !memcmp(ipdata.filename, pfs, 13663dc3af7STomohiro Kusumi strlen(pfs))) 13763dc3af7STomohiro Kusumi *res = true; 13863dc3af7STomohiro Kusumi } 13965d969b4STomohiro Kusumi } else 14065d969b4STomohiro Kusumi assert(0); 14165d969b4STomohiro Kusumi } 14265d969b4STomohiro Kusumi break; 14365d969b4STomohiro Kusumi case HAMMER2_BREF_TYPE_INDIRECT: 14465d969b4STomohiro Kusumi bscan = &media->npdata[0]; 14565d969b4STomohiro Kusumi bcount = bytes / sizeof(hammer2_blockref_t); 14665d969b4STomohiro Kusumi break; 14765d969b4STomohiro Kusumi default: 14865d969b4STomohiro Kusumi bscan = NULL; 14965d969b4STomohiro Kusumi bcount = 0; 15065d969b4STomohiro Kusumi break; 15165d969b4STomohiro Kusumi } 15265d969b4STomohiro Kusumi 15365d969b4STomohiro Kusumi for (i = 0; i < bcount; ++i) { 15465d969b4STomohiro Kusumi if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) { 155c8efd889STomohiro Kusumi if (find_pfs(fp, &bscan[i], pfs, res) == -1) { 15665d969b4STomohiro Kusumi free(media); 15765d969b4STomohiro Kusumi return (-1); 15865d969b4STomohiro Kusumi } 15965d969b4STomohiro Kusumi } 16065d969b4STomohiro Kusumi } 16165d969b4STomohiro Kusumi free(media); 16265d969b4STomohiro Kusumi 16365d969b4STomohiro Kusumi return (0); 16465d969b4STomohiro Kusumi } 16565d969b4STomohiro Kusumi 1662f9f168aSTomohiro Kusumi static char* 1672f9f168aSTomohiro Kusumi extract_device_name(const char *devpath) 1682f9f168aSTomohiro Kusumi { 169e3e33cadSTomohiro Kusumi char *p, *head; 170e3e33cadSTomohiro Kusumi 171e3e33cadSTomohiro Kusumi if (!devpath) 172e3e33cadSTomohiro Kusumi return NULL; 173e3e33cadSTomohiro Kusumi 174e3e33cadSTomohiro Kusumi p = strdup(devpath); 175e3e33cadSTomohiro Kusumi head = p; 1762f9f168aSTomohiro Kusumi 1772f9f168aSTomohiro Kusumi p = strchr(p, '@'); 1782f9f168aSTomohiro Kusumi if (p) 1792f9f168aSTomohiro Kusumi *p = 0; 1802f9f168aSTomohiro Kusumi 1812f9f168aSTomohiro Kusumi p = strrchr(head, '/'); 1822f9f168aSTomohiro Kusumi if (p) { 1832f9f168aSTomohiro Kusumi p++; 1842f9f168aSTomohiro Kusumi if (*p == 0) { 1852f9f168aSTomohiro Kusumi free(head); 1862f9f168aSTomohiro Kusumi return NULL; 1872f9f168aSTomohiro Kusumi } 1882f9f168aSTomohiro Kusumi p = strdup(p); 1892f9f168aSTomohiro Kusumi free(head); 1902f9f168aSTomohiro Kusumi return p; 1912f9f168aSTomohiro Kusumi } 1922f9f168aSTomohiro Kusumi 1932f9f168aSTomohiro Kusumi return head; 1942f9f168aSTomohiro Kusumi } 1952f9f168aSTomohiro Kusumi 19665d969b4STomohiro Kusumi static int 197c8efd889STomohiro Kusumi read_label(FILE *fp, char *label, size_t size, const char *devpath) 19826cca7e2STomohiro Kusumi { 19926cca7e2STomohiro Kusumi hammer2_blockref_t broot, best, *bref; 2009ed43ec3STomohiro Kusumi hammer2_media_data_t *vols[HAMMER2_NUM_VOLHDRS], *media; 20165d969b4STomohiro Kusumi size_t bytes; 20265d969b4STomohiro Kusumi bool res = false; 203841ef9e9STomohiro Kusumi int i, best_i, error = 1; 20465d969b4STomohiro Kusumi const char *pfs; 2052f9f168aSTomohiro Kusumi char *devname; 20626cca7e2STomohiro Kusumi 20726cca7e2STomohiro Kusumi best_i = -1; 20826cca7e2STomohiro Kusumi memset(&best, 0, sizeof(best)); 20926cca7e2STomohiro Kusumi 21026cca7e2STomohiro Kusumi for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) { 21126cca7e2STomohiro Kusumi memset(&broot, 0, sizeof(broot)); 21226cca7e2STomohiro Kusumi broot.type = HAMMER2_BREF_TYPE_VOLUME; 21326cca7e2STomohiro Kusumi broot.data_off = (i * HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX; 21426cca7e2STomohiro Kusumi vols[i] = read_buf(fp, broot.data_off & ~HAMMER2_OFF_MASK_RADIX, 21526cca7e2STomohiro Kusumi sizeof(*vols[i])); 21626cca7e2STomohiro Kusumi broot.mirror_tid = vols[i]->voldata.mirror_tid; 21726cca7e2STomohiro Kusumi if (best_i < 0 || best.mirror_tid < broot.mirror_tid) { 21826cca7e2STomohiro Kusumi best_i = i; 21926cca7e2STomohiro Kusumi best = broot; 22026cca7e2STomohiro Kusumi } 22126cca7e2STomohiro Kusumi } 22226cca7e2STomohiro Kusumi 22326cca7e2STomohiro Kusumi bref = &vols[best_i]->voldata.sroot_blockset.blockref[0]; 22426cca7e2STomohiro Kusumi if (bref->type != HAMMER2_BREF_TYPE_INODE) { 225841ef9e9STomohiro Kusumi warnx("blockref type is not inode"); 226841ef9e9STomohiro Kusumi goto fail; 22726cca7e2STomohiro Kusumi } 22826cca7e2STomohiro Kusumi 229c8efd889STomohiro Kusumi media = read_media(fp, bref, &bytes); 23065d969b4STomohiro Kusumi if (media == NULL) { 231841ef9e9STomohiro Kusumi goto fail; 23226cca7e2STomohiro Kusumi } 23326cca7e2STomohiro Kusumi 234e3e33cadSTomohiro Kusumi /* 235e3e33cadSTomohiro Kusumi * fstyp_function in DragonFly takes an additional devpath argument 236e3e33cadSTomohiro Kusumi * which doesn't exist in FreeBSD and NetBSD. 237e3e33cadSTomohiro Kusumi */ 238e3e33cadSTomohiro Kusumi #ifdef HAS_DEVPATH 23965d969b4STomohiro Kusumi pfs = strchr(devpath, '@'); 24065d969b4STomohiro Kusumi if (!pfs) { 24165d969b4STomohiro Kusumi assert(strlen(devpath)); 24265d969b4STomohiro Kusumi switch (devpath[strlen(devpath) - 1]) { 24365d969b4STomohiro Kusumi case 'a': 24465d969b4STomohiro Kusumi pfs = "BOOT"; 24565d969b4STomohiro Kusumi break; 24665d969b4STomohiro Kusumi case 'd': 24765d969b4STomohiro Kusumi pfs = "ROOT"; 24865d969b4STomohiro Kusumi break; 24965d969b4STomohiro Kusumi default: 25065d969b4STomohiro Kusumi pfs = "DATA"; 25165d969b4STomohiro Kusumi break; 25226cca7e2STomohiro Kusumi } 25365d969b4STomohiro Kusumi } else 25465d969b4STomohiro Kusumi pfs++; 25526cca7e2STomohiro Kusumi 25663dc3af7STomohiro Kusumi if (strlen(pfs) > HAMMER2_INODE_MAXNAME) { 257841ef9e9STomohiro Kusumi goto fail; 25863dc3af7STomohiro Kusumi } 2592f9f168aSTomohiro Kusumi devname = extract_device_name(devpath); 260e3e33cadSTomohiro Kusumi #else 261e3e33cadSTomohiro Kusumi pfs = ""; 262e3e33cadSTomohiro Kusumi devname = extract_device_name(NULL); 263e3e33cadSTomohiro Kusumi assert(!devname); 264e3e33cadSTomohiro Kusumi #endif 2652f9f168aSTomohiro Kusumi 2662f9f168aSTomohiro Kusumi /* Add device name to help support multiple autofs -media mounts. */ 2672f9f168aSTomohiro Kusumi if (find_pfs(fp, bref, pfs, &res) == 0 && res) { 2682f9f168aSTomohiro Kusumi if (devname) 2692f9f168aSTomohiro Kusumi snprintf(label, size, "%s_%s", pfs, devname); 2702f9f168aSTomohiro Kusumi else 2713b3b0bfeSTomohiro Kusumi strlcpy(label, pfs, size); 2722f9f168aSTomohiro Kusumi } else { 27396b636c4STomohiro Kusumi memset(label, 0, size); 27496b636c4STomohiro Kusumi memcpy(label, media->ipdata.filename, 27596b636c4STomohiro Kusumi sizeof(media->ipdata.filename)); 27696b636c4STomohiro Kusumi if (devname) { 27796b636c4STomohiro Kusumi strlcat(label, "_", size); 27896b636c4STomohiro Kusumi strlcat(label, devname, size); 27996b636c4STomohiro Kusumi } 2802f9f168aSTomohiro Kusumi } 2812f9f168aSTomohiro Kusumi if (devname) 2822f9f168aSTomohiro Kusumi free(devname); 28326cca7e2STomohiro Kusumi free(media); 284841ef9e9STomohiro Kusumi error = 0; 285841ef9e9STomohiro Kusumi fail: 28626cca7e2STomohiro Kusumi for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) 28726cca7e2STomohiro Kusumi free(vols[i]); 28826cca7e2STomohiro Kusumi 28926cca7e2STomohiro Kusumi return (error); 29026cca7e2STomohiro Kusumi } 29126cca7e2STomohiro Kusumi 292030fdd8aSTomohiro Kusumi int 29365d969b4STomohiro Kusumi fstyp_hammer2(FILE *fp, char *label, size_t size, const char *devpath) 294030fdd8aSTomohiro Kusumi { 295030fdd8aSTomohiro Kusumi hammer2_volume_data_t *voldata; 296030fdd8aSTomohiro Kusumi int error = 1; 297030fdd8aSTomohiro Kusumi 298c8efd889STomohiro Kusumi voldata = read_voldata(fp); 299c8efd889STomohiro Kusumi if (test_voldata(voldata)) 300841ef9e9STomohiro Kusumi goto fail; 301030fdd8aSTomohiro Kusumi 302c8efd889STomohiro Kusumi error = read_label(fp, label, size, devpath); 303841ef9e9STomohiro Kusumi fail: 304030fdd8aSTomohiro Kusumi free(voldata); 305030fdd8aSTomohiro Kusumi return (error); 306030fdd8aSTomohiro Kusumi } 307