1509798eaSPedro F. Giffuni /*- 2509798eaSPedro F. Giffuni * Copyright (c) 2017-2019 The DragonFly Project 3*9d529ed8SPedro 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> 36*9d529ed8SPedro F. Giffuni #include <stdbool.h> 37509798eaSPedro F. Giffuni #include <string.h> 38509798eaSPedro F. Giffuni #include <err.h> 39*9d529ed8SPedro 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* 48*9d529ed8SPedro 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 60*9d529ed8SPedro 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 69*9d529ed8SPedro F. Giffuni static hammer2_media_data_t* 70*9d529ed8SPedro F. Giffuni read_media(FILE *fp, const hammer2_blockref_t *bref, size_t *media_bytes) 71*9d529ed8SPedro F. Giffuni { 72*9d529ed8SPedro F. Giffuni hammer2_media_data_t *media; 73*9d529ed8SPedro F. Giffuni hammer2_off_t io_off, io_base; 74*9d529ed8SPedro F. Giffuni size_t bytes, io_bytes, boff; 75*9d529ed8SPedro F. Giffuni 76*9d529ed8SPedro F. Giffuni bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX); 77*9d529ed8SPedro F. Giffuni if (bytes) 78*9d529ed8SPedro F. Giffuni bytes = (size_t)1 << bytes; 79*9d529ed8SPedro F. Giffuni *media_bytes = bytes; 80*9d529ed8SPedro F. Giffuni 81*9d529ed8SPedro F. Giffuni if (!bytes) { 82*9d529ed8SPedro F. Giffuni warnx("blockref has no data"); 83*9d529ed8SPedro F. Giffuni return (NULL); 84*9d529ed8SPedro F. Giffuni } 85*9d529ed8SPedro F. Giffuni 86*9d529ed8SPedro F. Giffuni io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; 87*9d529ed8SPedro F. Giffuni io_base = io_off & ~(hammer2_off_t)(HAMMER2_MINIOSIZE - 1); 88*9d529ed8SPedro F. Giffuni boff = io_off - io_base; 89*9d529ed8SPedro F. Giffuni 90*9d529ed8SPedro F. Giffuni io_bytes = HAMMER2_MINIOSIZE; 91*9d529ed8SPedro F. Giffuni while (io_bytes + boff < bytes) 92*9d529ed8SPedro F. Giffuni io_bytes <<= 1; 93*9d529ed8SPedro F. Giffuni 94*9d529ed8SPedro F. Giffuni if (io_bytes > sizeof(hammer2_media_data_t)) { 95*9d529ed8SPedro F. Giffuni warnx("invalid I/O bytes"); 96*9d529ed8SPedro F. Giffuni return (NULL); 97*9d529ed8SPedro F. Giffuni } 98*9d529ed8SPedro F. Giffuni 99*9d529ed8SPedro F. Giffuni if (fseek(fp, io_base, SEEK_SET) == -1) { 100*9d529ed8SPedro F. Giffuni warnx("failed to seek media"); 101*9d529ed8SPedro F. Giffuni return (NULL); 102*9d529ed8SPedro F. Giffuni } 103*9d529ed8SPedro F. Giffuni media = read_buf(fp, io_base, io_bytes); 104*9d529ed8SPedro F. Giffuni if (media == NULL) { 105*9d529ed8SPedro F. Giffuni warnx("failed to read media"); 106*9d529ed8SPedro F. Giffuni return (NULL); 107*9d529ed8SPedro F. Giffuni } 108*9d529ed8SPedro F. Giffuni if (boff) 109*9d529ed8SPedro F. Giffuni memcpy(media, (char *)media + boff, bytes); 110*9d529ed8SPedro F. Giffuni 111*9d529ed8SPedro F. Giffuni return (media); 112*9d529ed8SPedro F. Giffuni } 113*9d529ed8SPedro F. Giffuni 114509798eaSPedro F. Giffuni static int 115*9d529ed8SPedro F. Giffuni find_pfs(FILE *fp, const hammer2_blockref_t *bref, const char *pfs, bool *res) 116*9d529ed8SPedro F. Giffuni { 117*9d529ed8SPedro F. Giffuni hammer2_media_data_t *media; 118*9d529ed8SPedro F. Giffuni hammer2_inode_data_t ipdata; 119*9d529ed8SPedro F. Giffuni hammer2_blockref_t *bscan; 120*9d529ed8SPedro F. Giffuni size_t bytes; 121*9d529ed8SPedro F. Giffuni int i, bcount; 122*9d529ed8SPedro F. Giffuni 123*9d529ed8SPedro F. Giffuni media = read_media(fp, bref, &bytes); 124*9d529ed8SPedro F. Giffuni if (media == NULL) 125*9d529ed8SPedro F. Giffuni return (-1); 126*9d529ed8SPedro F. Giffuni 127*9d529ed8SPedro F. Giffuni switch (bref->type) { 128*9d529ed8SPedro F. Giffuni case HAMMER2_BREF_TYPE_INODE: 129*9d529ed8SPedro F. Giffuni ipdata = media->ipdata; 130*9d529ed8SPedro F. Giffuni if (ipdata.meta.pfs_type & HAMMER2_PFSTYPE_SUPROOT) { 131*9d529ed8SPedro F. Giffuni bscan = &ipdata.u.blockset.blockref[0]; 132*9d529ed8SPedro F. Giffuni bcount = HAMMER2_SET_COUNT; 133*9d529ed8SPedro F. Giffuni } else { 134*9d529ed8SPedro F. Giffuni bscan = NULL; 135*9d529ed8SPedro F. Giffuni bcount = 0; 136*9d529ed8SPedro F. Giffuni if (ipdata.meta.op_flags & HAMMER2_OPFLAG_PFSROOT) { 137*9d529ed8SPedro F. Giffuni if (memchr(ipdata.filename, 0, 138*9d529ed8SPedro F. Giffuni sizeof(ipdata.filename))) { 139*9d529ed8SPedro F. Giffuni if (!strcmp( 140*9d529ed8SPedro F. Giffuni (const char*)ipdata.filename, pfs)) 141*9d529ed8SPedro F. Giffuni *res = true; 142*9d529ed8SPedro F. Giffuni } else { 143*9d529ed8SPedro F. Giffuni if (strlen(pfs) > 0 && 144*9d529ed8SPedro F. Giffuni !memcmp(ipdata.filename, pfs, 145*9d529ed8SPedro F. Giffuni strlen(pfs))) 146*9d529ed8SPedro F. Giffuni *res = true; 147*9d529ed8SPedro F. Giffuni } 148*9d529ed8SPedro F. Giffuni } else 149*9d529ed8SPedro F. Giffuni assert(0); 150*9d529ed8SPedro F. Giffuni } 151*9d529ed8SPedro F. Giffuni break; 152*9d529ed8SPedro F. Giffuni case HAMMER2_BREF_TYPE_INDIRECT: 153*9d529ed8SPedro F. Giffuni bscan = &media->npdata[0]; 154*9d529ed8SPedro F. Giffuni bcount = bytes / sizeof(hammer2_blockref_t); 155*9d529ed8SPedro F. Giffuni break; 156*9d529ed8SPedro F. Giffuni default: 157*9d529ed8SPedro F. Giffuni bscan = NULL; 158*9d529ed8SPedro F. Giffuni bcount = 0; 159*9d529ed8SPedro F. Giffuni break; 160*9d529ed8SPedro F. Giffuni } 161*9d529ed8SPedro F. Giffuni 162*9d529ed8SPedro F. Giffuni for (i = 0; i < bcount; ++i) { 163*9d529ed8SPedro F. Giffuni if (bscan[i].type != HAMMER2_BREF_TYPE_EMPTY) { 164*9d529ed8SPedro F. Giffuni if (find_pfs(fp, &bscan[i], pfs, res) == -1) { 165*9d529ed8SPedro F. Giffuni free(media); 166*9d529ed8SPedro F. Giffuni return (-1); 167*9d529ed8SPedro F. Giffuni } 168*9d529ed8SPedro F. Giffuni } 169*9d529ed8SPedro F. Giffuni } 170*9d529ed8SPedro F. Giffuni free(media); 171*9d529ed8SPedro F. Giffuni 172*9d529ed8SPedro F. Giffuni return (0); 173*9d529ed8SPedro F. Giffuni } 174*9d529ed8SPedro F. Giffuni 175*9d529ed8SPedro F. Giffuni static char* 176*9d529ed8SPedro F. Giffuni extract_device_name(const char *devpath) 177*9d529ed8SPedro F. Giffuni { 178*9d529ed8SPedro F. Giffuni char *p, *head; 179*9d529ed8SPedro F. Giffuni 180*9d529ed8SPedro F. Giffuni if (!devpath) 181*9d529ed8SPedro F. Giffuni return NULL; 182*9d529ed8SPedro F. Giffuni 183*9d529ed8SPedro F. Giffuni p = strdup(devpath); 184*9d529ed8SPedro F. Giffuni head = p; 185*9d529ed8SPedro F. Giffuni 186*9d529ed8SPedro F. Giffuni p = strchr(p, '@'); 187*9d529ed8SPedro F. Giffuni if (p) 188*9d529ed8SPedro F. Giffuni *p = 0; 189*9d529ed8SPedro F. Giffuni 190*9d529ed8SPedro F. Giffuni p = strrchr(head, '/'); 191*9d529ed8SPedro F. Giffuni if (p) { 192*9d529ed8SPedro F. Giffuni p++; 193*9d529ed8SPedro F. Giffuni if (*p == 0) { 194*9d529ed8SPedro F. Giffuni free(head); 195*9d529ed8SPedro F. Giffuni return NULL; 196*9d529ed8SPedro F. Giffuni } 197*9d529ed8SPedro F. Giffuni p = strdup(p); 198*9d529ed8SPedro F. Giffuni free(head); 199*9d529ed8SPedro F. Giffuni return p; 200*9d529ed8SPedro F. Giffuni } 201*9d529ed8SPedro F. Giffuni 202*9d529ed8SPedro F. Giffuni return head; 203*9d529ed8SPedro F. Giffuni } 204*9d529ed8SPedro F. Giffuni 205*9d529ed8SPedro F. Giffuni static int 206*9d529ed8SPedro 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; 210*9d529ed8SPedro F. Giffuni size_t bytes; 211*9d529ed8SPedro F. Giffuni bool res = false; 212*9d529ed8SPedro F. Giffuni int i, best_i, error = 1; 213*9d529ed8SPedro F. Giffuni const char *pfs; 214*9d529ed8SPedro 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) { 234*9d529ed8SPedro F. Giffuni warnx("blockref type is not inode"); 235*9d529ed8SPedro F. Giffuni goto fail; 236509798eaSPedro F. Giffuni } 237509798eaSPedro F. Giffuni 238*9d529ed8SPedro F. Giffuni media = read_media(fp, bref, &bytes); 239*9d529ed8SPedro F. Giffuni if (media == NULL) { 240*9d529ed8SPedro F. Giffuni goto fail; 241509798eaSPedro F. Giffuni } 242509798eaSPedro F. Giffuni 243*9d529ed8SPedro F. Giffuni pfs = ""; 244*9d529ed8SPedro F. Giffuni devname = extract_device_name(NULL); 245*9d529ed8SPedro F. Giffuni assert(!devname); /* Currently always NULL in FreeBSD. */ 246509798eaSPedro F. Giffuni 247*9d529ed8SPedro F. Giffuni /* Add device name to help support multiple autofs -media mounts. */ 248*9d529ed8SPedro F. Giffuni if (find_pfs(fp, bref, pfs, &res) == 0 && res) { 249*9d529ed8SPedro F. Giffuni if (devname) 250*9d529ed8SPedro F. Giffuni snprintf(label, size, "%s_%s", pfs, devname); 251*9d529ed8SPedro F. Giffuni else 252*9d529ed8SPedro F. Giffuni strlcpy(label, pfs, size); 253*9d529ed8SPedro F. Giffuni } else { 254*9d529ed8SPedro F. Giffuni memset(label, 0, size); 255*9d529ed8SPedro F. Giffuni memcpy(label, media->ipdata.filename, 256*9d529ed8SPedro F. Giffuni sizeof(media->ipdata.filename)); 257*9d529ed8SPedro F. Giffuni if (devname) { 258*9d529ed8SPedro F. Giffuni strlcat(label, "_", size); 259*9d529ed8SPedro F. Giffuni strlcat(label, devname, size); 260509798eaSPedro F. Giffuni } 261*9d529ed8SPedro F. Giffuni } 262*9d529ed8SPedro F. Giffuni if (devname) 263*9d529ed8SPedro F. Giffuni free(devname); 264509798eaSPedro F. Giffuni free(media); 265*9d529ed8SPedro F. Giffuni error = 0; 266*9d529ed8SPedro 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 279*9d529ed8SPedro F. Giffuni voldata = read_voldata(fp); 280*9d529ed8SPedro F. Giffuni if (test_voldata(voldata)) 281*9d529ed8SPedro F. Giffuni goto fail; 282509798eaSPedro F. Giffuni 283*9d529ed8SPedro F. Giffuni error = read_label(fp, label, size); 284*9d529ed8SPedro F. Giffuni fail: 285509798eaSPedro F. Giffuni free(voldata); 286509798eaSPedro F. Giffuni return (error); 287509798eaSPedro F. Giffuni } 288