1509798eaSPedro F. Giffuni /*- 2509798eaSPedro F. Giffuni * Copyright (c) 2017-2019 The DragonFly Project 39d529ed8SPedro F. Giffuni * Copyright (c) 2017-2019 Tomohiro Kusumi <tkusumi@netbsd.org> 4509798eaSPedro F. Giffuni * All rights reserved. 5509798eaSPedro F. Giffuni * 6509798eaSPedro F. Giffuni * This software was developed by Edward Tomasz Napierala under sponsorship 7509798eaSPedro F. Giffuni * from the FreeBSD Foundation. 8509798eaSPedro F. Giffuni * 9509798eaSPedro F. Giffuni * Redistribution and use in source and binary forms, with or without 10509798eaSPedro F. Giffuni * modification, are permitted provided that the following conditions 11509798eaSPedro F. Giffuni * are met: 12509798eaSPedro F. Giffuni * 1. Redistributions of source code must retain the above copyright 13509798eaSPedro F. Giffuni * notice, this list of conditions and the following disclaimer. 14509798eaSPedro F. Giffuni * 2. Redistributions in binary form must reproduce the above copyright 15509798eaSPedro F. Giffuni * notice, this list of conditions and the following disclaimer in the 16509798eaSPedro F. Giffuni * documentation and/or other materials provided with the distribution. 17509798eaSPedro F. Giffuni * 18509798eaSPedro F. Giffuni * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19509798eaSPedro F. Giffuni * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20509798eaSPedro F. Giffuni * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21509798eaSPedro F. Giffuni * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22509798eaSPedro F. Giffuni * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23509798eaSPedro F. Giffuni * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24509798eaSPedro F. Giffuni * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25509798eaSPedro F. Giffuni * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26509798eaSPedro F. Giffuni * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27509798eaSPedro F. Giffuni * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28509798eaSPedro F. Giffuni * SUCH DAMAGE. 29509798eaSPedro F. Giffuni */ 30509798eaSPedro F. Giffuni 31509798eaSPedro F. Giffuni #include <sys/cdefs.h> 32509798eaSPedro F. Giffuni __FBSDID("$FreeBSD$"); 33509798eaSPedro F. Giffuni 34509798eaSPedro F. Giffuni #include <stdio.h> 35509798eaSPedro F. Giffuni #include <stdlib.h> 369d529ed8SPedro F. Giffuni #include <stdbool.h> 37509798eaSPedro F. Giffuni #include <string.h> 38509798eaSPedro F. Giffuni #include <err.h> 399d529ed8SPedro F. Giffuni #include <assert.h> 40509798eaSPedro F. Giffuni 41509798eaSPedro F. Giffuni #include <sys/types.h> 42509798eaSPedro F. Giffuni 43509798eaSPedro F. Giffuni #include "hammer2_disk.h" 44509798eaSPedro F. Giffuni 45509798eaSPedro F. Giffuni #include "fstyp.h" 46509798eaSPedro F. Giffuni 47509798eaSPedro F. Giffuni static hammer2_volume_data_t* 489d529ed8SPedro F. Giffuni read_voldata(FILE *fp) 49509798eaSPedro F. Giffuni { 50509798eaSPedro F. Giffuni hammer2_volume_data_t *voldata; 51509798eaSPedro F. Giffuni 52509798eaSPedro F. Giffuni voldata = read_buf(fp, 0, sizeof(*voldata)); 53509798eaSPedro F. Giffuni if (voldata == NULL) 54509798eaSPedro F. Giffuni err(1, "failed to read volume data"); 55509798eaSPedro F. Giffuni 56509798eaSPedro F. Giffuni return (voldata); 57509798eaSPedro F. Giffuni } 58509798eaSPedro F. Giffuni 59509798eaSPedro F. Giffuni static int 609d529ed8SPedro F. Giffuni test_voldata(const hammer2_volume_data_t *voldata) 61509798eaSPedro F. Giffuni { 62509798eaSPedro F. Giffuni if (voldata->magic != HAMMER2_VOLUME_ID_HBO && 63509798eaSPedro F. Giffuni voldata->magic != HAMMER2_VOLUME_ID_ABO) 64509798eaSPedro F. Giffuni return (1); 65509798eaSPedro F. Giffuni 66509798eaSPedro F. Giffuni return (0); 67509798eaSPedro F. Giffuni } 68509798eaSPedro F. Giffuni 699d529ed8SPedro F. Giffuni static hammer2_media_data_t* 709d529ed8SPedro F. Giffuni read_media(FILE *fp, const hammer2_blockref_t *bref, size_t *media_bytes) 719d529ed8SPedro F. Giffuni { 729d529ed8SPedro F. Giffuni hammer2_media_data_t *media; 739d529ed8SPedro F. Giffuni hammer2_off_t io_off, io_base; 749d529ed8SPedro F. Giffuni size_t bytes, io_bytes, boff; 759d529ed8SPedro F. Giffuni 769d529ed8SPedro F. Giffuni bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX); 779d529ed8SPedro F. Giffuni if (bytes) 789d529ed8SPedro F. Giffuni bytes = (size_t)1 << bytes; 799d529ed8SPedro F. Giffuni *media_bytes = bytes; 809d529ed8SPedro F. Giffuni 819d529ed8SPedro F. Giffuni if (!bytes) { 829d529ed8SPedro F. Giffuni warnx("blockref has no data"); 839d529ed8SPedro F. Giffuni return (NULL); 849d529ed8SPedro F. Giffuni } 859d529ed8SPedro F. Giffuni 869d529ed8SPedro F. Giffuni io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; 879d529ed8SPedro F. Giffuni io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1); 889d529ed8SPedro F. Giffuni boff = io_off - io_base; 899d529ed8SPedro F. Giffuni 909d529ed8SPedro F. Giffuni io_bytes = HAMMER2_MINIOSIZE; 919d529ed8SPedro F. Giffuni while (io_bytes + boff < bytes) 929d529ed8SPedro F. Giffuni io_bytes <<= 1; 939d529ed8SPedro F. Giffuni 949d529ed8SPedro F. Giffuni if (io_bytes > sizeof(hammer2_media_data_t)) { 959d529ed8SPedro F. Giffuni warnx("invalid I/O bytes"); 969d529ed8SPedro F. Giffuni return (NULL); 979d529ed8SPedro F. Giffuni } 989d529ed8SPedro F. Giffuni 999d529ed8SPedro F. Giffuni if (fseek(fp, io_base, SEEK_SET) == -1) { 1009d529ed8SPedro F. Giffuni warnx("failed to seek media"); 1019d529ed8SPedro F. Giffuni return (NULL); 1029d529ed8SPedro F. Giffuni } 1039d529ed8SPedro F. Giffuni media = read_buf(fp, io_base, io_bytes); 1049d529ed8SPedro F. Giffuni if (media == NULL) { 1059d529ed8SPedro F. Giffuni warnx("failed to read media"); 1069d529ed8SPedro F. Giffuni return (NULL); 1079d529ed8SPedro F. Giffuni } 1089d529ed8SPedro F. Giffuni if (boff) 1099d529ed8SPedro F. Giffuni memcpy(media, (char *)media + boff, bytes); 1109d529ed8SPedro F. Giffuni 1119d529ed8SPedro F. Giffuni return (media); 1129d529ed8SPedro F. Giffuni } 1139d529ed8SPedro F. Giffuni 114509798eaSPedro F. Giffuni static int 1159d529ed8SPedro F. Giffuni find_pfs(FILE *fp, const hammer2_blockref_t *bref, const char *pfs, bool *res) 1169d529ed8SPedro F. Giffuni { 1179d529ed8SPedro F. Giffuni hammer2_media_data_t *media; 1189d529ed8SPedro F. Giffuni hammer2_inode_data_t ipdata; 1199d529ed8SPedro F. Giffuni hammer2_blockref_t *bscan; 1209d529ed8SPedro F. Giffuni size_t bytes; 1219d529ed8SPedro F. Giffuni int i, bcount; 1229d529ed8SPedro F. Giffuni 1239d529ed8SPedro F. Giffuni media = read_media(fp, bref, &bytes); 1249d529ed8SPedro F. Giffuni if (media == NULL) 1259d529ed8SPedro F. Giffuni return (-1); 1269d529ed8SPedro F. Giffuni 1279d529ed8SPedro F. Giffuni switch (bref->type) { 1289d529ed8SPedro F. Giffuni case HAMMER2_BREF_TYPE_INODE: 1299d529ed8SPedro F. Giffuni ipdata = media->ipdata; 130*0d2913adSPedro F. Giffuni if (ipdata.meta.pfs_type == HAMMER2_PFSTYPE_SUPROOT) { 1319d529ed8SPedro F. Giffuni bscan = &ipdata.u.blockset.blockref[0]; 1329d529ed8SPedro F. Giffuni bcount = HAMMER2_SET_COUNT; 1339d529ed8SPedro F. Giffuni } else { 1349d529ed8SPedro F. Giffuni bscan = NULL; 1359d529ed8SPedro F. Giffuni bcount = 0; 1369d529ed8SPedro F. Giffuni if (ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) { 1379d529ed8SPedro F. Giffuni if (memchr(ipdata.filename, 0, 1389d529ed8SPedro F. Giffuni sizeof(ipdata.filename))) { 1399d529ed8SPedro F. Giffuni if (!strcmp( 1409d529ed8SPedro F. Giffuni (const char*)ipdata.filename, pfs)) 1419d529ed8SPedro F. Giffuni *res = true; 1429d529ed8SPedro F. Giffuni } else { 1439d529ed8SPedro F. Giffuni if (strlen(pfs) > 0 && 1449d529ed8SPedro F. Giffuni !memcmp(ipdata.filename, pfs, 1459d529ed8SPedro F. Giffuni strlen(pfs))) 1469d529ed8SPedro F. Giffuni *res = true; 1479d529ed8SPedro F. Giffuni } 1489d529ed8SPedro F. Giffuni } else 1499d529ed8SPedro F. Giffuni assert(0); 1509d529ed8SPedro F. Giffuni } 1519d529ed8SPedro F. Giffuni break; 1529d529ed8SPedro F. Giffuni case HAMMER2_BREF_TYPE_INDIRECT: 1539d529ed8SPedro F. Giffuni bscan = &media->npdata[0]; 1549d529ed8SPedro F. Giffuni bcount = bytes / sizeof(hammer2_blockref_t); 1559d529ed8SPedro F. Giffuni break; 1569d529ed8SPedro F. Giffuni default: 1579d529ed8SPedro F. Giffuni bscan = NULL; 1589d529ed8SPedro F. Giffuni bcount = 0; 1599d529ed8SPedro F. Giffuni break; 1609d529ed8SPedro F. Giffuni } 1619d529ed8SPedro F. Giffuni 1629d529ed8SPedro F. Giffuni for (i = 0; i < bcount; ++i) { 1639d529ed8SPedro F. Giffuni if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) { 1649d529ed8SPedro F. Giffuni if (find_pfs(fp, &bscan[i], pfs, res) == -1) { 1659d529ed8SPedro F. Giffuni free(media); 1669d529ed8SPedro F. Giffuni return (-1); 1679d529ed8SPedro F. Giffuni } 1689d529ed8SPedro F. Giffuni } 1699d529ed8SPedro F. Giffuni } 1709d529ed8SPedro F. Giffuni free(media); 1719d529ed8SPedro F. Giffuni 1729d529ed8SPedro F. Giffuni return (0); 1739d529ed8SPedro F. Giffuni } 1749d529ed8SPedro F. Giffuni 1759d529ed8SPedro F. Giffuni static char* 1769d529ed8SPedro F. Giffuni extract_device_name(const char *devpath) 1779d529ed8SPedro F. Giffuni { 1789d529ed8SPedro F. Giffuni char *p, *head; 1799d529ed8SPedro F. Giffuni 1809d529ed8SPedro F. Giffuni if (!devpath) 1819d529ed8SPedro F. Giffuni return NULL; 1829d529ed8SPedro F. Giffuni 1839d529ed8SPedro F. Giffuni p = strdup(devpath); 1849d529ed8SPedro F. Giffuni head = p; 1859d529ed8SPedro F. Giffuni 1869d529ed8SPedro F. Giffuni p = strchr(p, '@'); 1879d529ed8SPedro F. Giffuni if (p) 1889d529ed8SPedro F. Giffuni *p = 0; 1899d529ed8SPedro F. Giffuni 1909d529ed8SPedro F. Giffuni p = strrchr(head, '/'); 1919d529ed8SPedro F. Giffuni if (p) { 1929d529ed8SPedro F. Giffuni p++; 1939d529ed8SPedro F. Giffuni if (*p == 0) { 1949d529ed8SPedro F. Giffuni free(head); 1959d529ed8SPedro F. Giffuni return NULL; 1969d529ed8SPedro F. Giffuni } 1979d529ed8SPedro F. Giffuni p = strdup(p); 1989d529ed8SPedro F. Giffuni free(head); 1999d529ed8SPedro F. Giffuni return p; 2009d529ed8SPedro F. Giffuni } 2019d529ed8SPedro F. Giffuni 2029d529ed8SPedro F. Giffuni return head; 2039d529ed8SPedro F. Giffuni } 2049d529ed8SPedro F. Giffuni 2059d529ed8SPedro F. Giffuni static int 2069d529ed8SPedro F. Giffuni read_label(FILE *fp, char *label, size_t size) 207509798eaSPedro F. Giffuni { 208509798eaSPedro F. Giffuni hammer2_blockref_t broot, best, *bref; 209509798eaSPedro F. Giffuni hammer2_media_data_t *vols[HAMMER2_NUM_VOLHDRS], *media; 2109d529ed8SPedro F. Giffuni size_t bytes; 2119d529ed8SPedro F. Giffuni bool res = false; 2129d529ed8SPedro F. Giffuni int i, best_i, error = 1; 2139d529ed8SPedro F. Giffuni const char *pfs; 2149d529ed8SPedro F. Giffuni char *devname; 215509798eaSPedro F. Giffuni 216509798eaSPedro F. Giffuni best_i = -1; 217509798eaSPedro F. Giffuni memset(&best, 0, sizeof(best)); 218509798eaSPedro F. Giffuni 219509798eaSPedro F. Giffuni for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) { 220509798eaSPedro F. Giffuni memset(&broot, 0, sizeof(broot)); 221509798eaSPedro F. Giffuni broot.type = HAMMER2_BREF_TYPE_VOLUME; 222509798eaSPedro F. Giffuni broot.data_off = (i * HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX; 223509798eaSPedro F. Giffuni vols[i] = read_buf(fp, broot.data_off & ~HAMMER2_OFF_MASK_RADIX, 224509798eaSPedro F. Giffuni sizeof(*vols[i])); 225509798eaSPedro F. Giffuni broot.mirror_tid = vols[i]->voldata.mirror_tid; 226509798eaSPedro F. Giffuni if (best_i < 0 || best.mirror_tid < broot.mirror_tid) { 227509798eaSPedro F. Giffuni best_i = i; 228509798eaSPedro F. Giffuni best = broot; 229509798eaSPedro F. Giffuni } 230509798eaSPedro F. Giffuni } 231509798eaSPedro F. Giffuni 232509798eaSPedro F. Giffuni bref = &vols[best_i]->voldata.sroot_blockset.blockref[0]; 233509798eaSPedro F. Giffuni if (bref->type != HAMMER2_BREF_TYPE_INODE) { 2349d529ed8SPedro F. Giffuni warnx("blockref type is not inode"); 2359d529ed8SPedro F. Giffuni goto fail; 236509798eaSPedro F. Giffuni } 237509798eaSPedro F. Giffuni 2389d529ed8SPedro F. Giffuni media = read_media(fp, bref, &bytes); 2399d529ed8SPedro F. Giffuni if (media == NULL) { 2409d529ed8SPedro F. Giffuni goto fail; 241509798eaSPedro F. Giffuni } 242509798eaSPedro F. Giffuni 2439d529ed8SPedro F. Giffuni pfs = ""; 2449d529ed8SPedro F. Giffuni devname = extract_device_name(NULL); 2459d529ed8SPedro F. Giffuni assert(!devname); /* Currently always NULL in FreeBSD. */ 246509798eaSPedro F. Giffuni 2479d529ed8SPedro F. Giffuni /* Add device name to help support multiple autofs -media mounts. */ 2489d529ed8SPedro F. Giffuni if (find_pfs(fp, bref, pfs, &res) == 0 && res) { 2499d529ed8SPedro F. Giffuni if (devname) 2509d529ed8SPedro F. Giffuni snprintf(label, size, "%s_%s", pfs, devname); 2519d529ed8SPedro F. Giffuni else 2529d529ed8SPedro F. Giffuni strlcpy(label, pfs, size); 2539d529ed8SPedro F. Giffuni } else { 2549d529ed8SPedro F. Giffuni memset(label, 0, size); 2559d529ed8SPedro F. Giffuni memcpy(label, media->ipdata.filename, 2569d529ed8SPedro F. Giffuni sizeof(media->ipdata.filename)); 2579d529ed8SPedro F. Giffuni if (devname) { 2589d529ed8SPedro F. Giffuni strlcat(label, "_", size); 2599d529ed8SPedro F. Giffuni strlcat(label, devname, size); 260509798eaSPedro F. Giffuni } 2619d529ed8SPedro F. Giffuni } 2629d529ed8SPedro F. Giffuni if (devname) 2639d529ed8SPedro F. Giffuni free(devname); 264509798eaSPedro F. Giffuni free(media); 2659d529ed8SPedro F. Giffuni error = 0; 2669d529ed8SPedro F. Giffuni fail: 267509798eaSPedro F. Giffuni for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) 268509798eaSPedro F. Giffuni free(vols[i]); 269509798eaSPedro F. Giffuni 270509798eaSPedro F. Giffuni return (error); 271509798eaSPedro F. Giffuni } 272509798eaSPedro F. Giffuni 273509798eaSPedro F. Giffuni int 274509798eaSPedro F. Giffuni fstyp_hammer2(FILE *fp, char *label, size_t size) 275509798eaSPedro F. Giffuni { 276509798eaSPedro F. Giffuni hammer2_volume_data_t *voldata; 277509798eaSPedro F. Giffuni int error = 1; 278509798eaSPedro F. Giffuni 2799d529ed8SPedro F. Giffuni voldata = read_voldata(fp); 2809d529ed8SPedro F. Giffuni if (test_voldata(voldata)) 2819d529ed8SPedro F. Giffuni goto fail; 282509798eaSPedro F. Giffuni 2839d529ed8SPedro F. Giffuni error = read_label(fp, label, size); 2849d529ed8SPedro F. Giffuni fail: 285509798eaSPedro F. Giffuni free(voldata); 286509798eaSPedro F. Giffuni return (error); 287509798eaSPedro F. Giffuni } 288