1185029Spjd/*- 2185029Spjd * Copyright (c) 2007 Doug Rabson 3185029Spjd * All rights reserved. 4185029Spjd * 5185029Spjd * Redistribution and use in source and binary forms, with or without 6185029Spjd * modification, are permitted provided that the following conditions 7185029Spjd * are met: 8185029Spjd * 1. Redistributions of source code must retain the above copyright 9185029Spjd * notice, this list of conditions and the following disclaimer. 10185029Spjd * 2. Redistributions in binary form must reproduce the above copyright 11185029Spjd * notice, this list of conditions and the following disclaimer in the 12185029Spjd * documentation and/or other materials provided with the distribution. 13185029Spjd * 14185029Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15185029Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16185029Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17185029Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18185029Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19185029Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20185029Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21185029Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22185029Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23185029Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24185029Spjd * SUCH DAMAGE. 25185029Spjd * 26185029Spjd * $FreeBSD$ 27185029Spjd */ 28185029Spjd 29185029Spjd#include <sys/cdefs.h> 30185029Spjd__FBSDID("$FreeBSD$"); 31185029Spjd 32185029Spjd/* 33185029Spjd * Stand-alone file reading package. 34185029Spjd */ 35185029Spjd 36239068Sae#include <sys/disk.h> 37185029Spjd#include <sys/param.h> 38185029Spjd#include <sys/time.h> 39185029Spjd#include <sys/queue.h> 40239068Sae#include <part.h> 41185029Spjd#include <stddef.h> 42185029Spjd#include <stdarg.h> 43185029Spjd#include <string.h> 44185029Spjd#include <stand.h> 45185029Spjd#include <bootstrap.h> 46185029Spjd 47235329Savg#include "libzfs.h" 48235329Savg 49185029Spjd#include "zfsimpl.c" 50185029Spjd 51293802Sallanjude/* Define the range of indexes to be populated with ZFS Boot Environments */ 52293802Sallanjude#define ZFS_BE_FIRST 4 53293802Sallanjude#define ZFS_BE_LAST 8 54293802Sallanjude 55185029Spjdstatic int zfs_open(const char *path, struct open_file *f); 56185029Spjdstatic int zfs_write(struct open_file *f, void *buf, size_t size, size_t *resid); 57185029Spjdstatic int zfs_close(struct open_file *f); 58185029Spjdstatic int zfs_read(struct open_file *f, void *buf, size_t size, size_t *resid); 59185029Spjdstatic off_t zfs_seek(struct open_file *f, off_t offset, int where); 60185029Spjdstatic int zfs_stat(struct open_file *f, struct stat *sb); 61185029Spjdstatic int zfs_readdir(struct open_file *f, struct dirent *d); 62185029Spjd 63185029Spjdstruct devsw zfs_dev; 64185029Spjd 65185029Spjdstruct fs_ops zfs_fsops = { 66185029Spjd "zfs", 67185029Spjd zfs_open, 68185029Spjd zfs_close, 69185029Spjd zfs_read, 70185029Spjd zfs_write, 71185029Spjd zfs_seek, 72185029Spjd zfs_stat, 73185029Spjd zfs_readdir 74185029Spjd}; 75185029Spjd 76185029Spjd/* 77185029Spjd * In-core open file. 78185029Spjd */ 79185029Spjdstruct file { 80185029Spjd off_t f_seekp; /* seek pointer */ 81185029Spjd dnode_phys_t f_dnode; 82185029Spjd uint64_t f_zap_type; /* zap type for readdir */ 83185029Spjd uint64_t f_num_leafs; /* number of fzap leaf blocks */ 84185029Spjd zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */ 85185029Spjd}; 86185029Spjd 87293802Sallanjudestatic int zfs_env_index; 88293802Sallanjudestatic int zfs_env_count; 89293802Sallanjude 90293802SallanjudeSLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = SLIST_HEAD_INITIALIZER(zfs_be_head); 91293802Sallanjudestruct zfs_be_list *zfs_be_headp; 92293802Sallanjudestruct zfs_be_entry { 93293802Sallanjude const char *name; 94293802Sallanjude SLIST_ENTRY(zfs_be_entry) entries; 95293802Sallanjude} *zfs_be, *zfs_be_tmp; 96293802Sallanjude 97185029Spjd/* 98185029Spjd * Open a file. 99185029Spjd */ 100185029Spjdstatic int 101185029Spjdzfs_open(const char *upath, struct open_file *f) 102185029Spjd{ 103235329Savg struct zfsmount *mount = (struct zfsmount *)f->f_devdata; 104185029Spjd struct file *fp; 105185029Spjd int rc; 106185029Spjd 107235394Savg if (f->f_dev != &zfs_dev) 108185029Spjd return (EINVAL); 109185029Spjd 110185029Spjd /* allocate file system specific data structure */ 111185029Spjd fp = malloc(sizeof(struct file)); 112185029Spjd bzero(fp, sizeof(struct file)); 113185029Spjd f->f_fsdata = (void *)fp; 114185029Spjd 115235329Savg rc = zfs_lookup(mount, upath, &fp->f_dnode); 116185029Spjd fp->f_seekp = 0; 117185029Spjd if (rc) { 118185029Spjd f->f_fsdata = NULL; 119185029Spjd free(fp); 120185029Spjd } 121185029Spjd return (rc); 122185029Spjd} 123185029Spjd 124185029Spjdstatic int 125185029Spjdzfs_close(struct open_file *f) 126185029Spjd{ 127185029Spjd struct file *fp = (struct file *)f->f_fsdata; 128185029Spjd 129185029Spjd dnode_cache_obj = 0; 130185029Spjd f->f_fsdata = (void *)0; 131185029Spjd if (fp == (struct file *)0) 132185029Spjd return (0); 133185029Spjd 134185029Spjd free(fp); 135185029Spjd return (0); 136185029Spjd} 137185029Spjd 138185029Spjd/* 139185029Spjd * Copy a portion of a file into kernel memory. 140185029Spjd * Cross block boundaries when necessary. 141185029Spjd */ 142185029Spjdstatic int 143185029Spjdzfs_read(struct open_file *f, void *start, size_t size, size_t *resid /* out */) 144185029Spjd{ 145235390Savg const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; 146185029Spjd struct file *fp = (struct file *)f->f_fsdata; 147219089Spjd struct stat sb; 148185029Spjd size_t n; 149185029Spjd int rc; 150185029Spjd 151219089Spjd rc = zfs_stat(f, &sb); 152219089Spjd if (rc) 153219089Spjd return (rc); 154185029Spjd n = size; 155219089Spjd if (fp->f_seekp + n > sb.st_size) 156219089Spjd n = sb.st_size - fp->f_seekp; 157294716Ssmh 158185029Spjd rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n); 159185029Spjd if (rc) 160185029Spjd return (rc); 161185029Spjd 162185029Spjd if (0) { 163185029Spjd int i; 164185029Spjd for (i = 0; i < n; i++) 165185029Spjd putchar(((char*) start)[i]); 166185029Spjd } 167185029Spjd fp->f_seekp += n; 168185029Spjd if (resid) 169185029Spjd *resid = size - n; 170185029Spjd 171185029Spjd return (0); 172185029Spjd} 173185029Spjd 174185029Spjd/* 175185029Spjd * Don't be silly - the bootstrap has no business writing anything. 176185029Spjd */ 177185029Spjdstatic int 178185029Spjdzfs_write(struct open_file *f, void *start, size_t size, size_t *resid /* out */) 179185029Spjd{ 180185029Spjd 181185029Spjd return (EROFS); 182185029Spjd} 183185029Spjd 184185029Spjdstatic off_t 185185029Spjdzfs_seek(struct open_file *f, off_t offset, int where) 186185029Spjd{ 187185029Spjd struct file *fp = (struct file *)f->f_fsdata; 188185029Spjd 189185029Spjd switch (where) { 190185029Spjd case SEEK_SET: 191185029Spjd fp->f_seekp = offset; 192185029Spjd break; 193185029Spjd case SEEK_CUR: 194185029Spjd fp->f_seekp += offset; 195185029Spjd break; 196185029Spjd case SEEK_END: 197219089Spjd { 198219089Spjd struct stat sb; 199219089Spjd int error; 200219089Spjd 201219089Spjd error = zfs_stat(f, &sb); 202219089Spjd if (error != 0) { 203219089Spjd errno = error; 204219089Spjd return (-1); 205219089Spjd } 206219089Spjd fp->f_seekp = sb.st_size - offset; 207185029Spjd break; 208219089Spjd } 209185029Spjd default: 210185029Spjd errno = EINVAL; 211185029Spjd return (-1); 212185029Spjd } 213185029Spjd return (fp->f_seekp); 214185029Spjd} 215185029Spjd 216185029Spjdstatic int 217185029Spjdzfs_stat(struct open_file *f, struct stat *sb) 218185029Spjd{ 219235390Savg const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; 220185029Spjd struct file *fp = (struct file *)f->f_fsdata; 221185029Spjd 222219089Spjd return (zfs_dnode_stat(spa, &fp->f_dnode, sb)); 223185029Spjd} 224185029Spjd 225185029Spjdstatic int 226185029Spjdzfs_readdir(struct open_file *f, struct dirent *d) 227185029Spjd{ 228235390Savg const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa; 229185029Spjd struct file *fp = (struct file *)f->f_fsdata; 230185029Spjd mzap_ent_phys_t mze; 231219089Spjd struct stat sb; 232185029Spjd size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT; 233185029Spjd int rc; 234185029Spjd 235219089Spjd rc = zfs_stat(f, &sb); 236219089Spjd if (rc) 237219089Spjd return (rc); 238219089Spjd if (!S_ISDIR(sb.st_mode)) 239185029Spjd return (ENOTDIR); 240185029Spjd 241185029Spjd /* 242185029Spjd * If this is the first read, get the zap type. 243185029Spjd */ 244185029Spjd if (fp->f_seekp == 0) { 245185029Spjd rc = dnode_read(spa, &fp->f_dnode, 246185029Spjd 0, &fp->f_zap_type, sizeof(fp->f_zap_type)); 247185029Spjd if (rc) 248185029Spjd return (rc); 249185029Spjd 250185029Spjd if (fp->f_zap_type == ZBT_MICRO) { 251185029Spjd fp->f_seekp = offsetof(mzap_phys_t, mz_chunk); 252185029Spjd } else { 253185029Spjd rc = dnode_read(spa, &fp->f_dnode, 254185029Spjd offsetof(zap_phys_t, zap_num_leafs), 255185029Spjd &fp->f_num_leafs, 256185029Spjd sizeof(fp->f_num_leafs)); 257185029Spjd if (rc) 258185029Spjd return (rc); 259185029Spjd 260185029Spjd fp->f_seekp = bsize; 261185029Spjd fp->f_zap_leaf = (zap_leaf_phys_t *)malloc(bsize); 262185029Spjd rc = dnode_read(spa, &fp->f_dnode, 263185029Spjd fp->f_seekp, 264185029Spjd fp->f_zap_leaf, 265185029Spjd bsize); 266185029Spjd if (rc) 267185029Spjd return (rc); 268185029Spjd } 269185029Spjd } 270185029Spjd 271185029Spjd if (fp->f_zap_type == ZBT_MICRO) { 272185029Spjd mzap_next: 273185029Spjd if (fp->f_seekp >= bsize) 274185029Spjd return (ENOENT); 275185029Spjd 276185029Spjd rc = dnode_read(spa, &fp->f_dnode, 277185029Spjd fp->f_seekp, &mze, sizeof(mze)); 278208669Savg if (rc) 279208669Savg return (rc); 280185029Spjd fp->f_seekp += sizeof(mze); 281185029Spjd 282185029Spjd if (!mze.mze_name[0]) 283185029Spjd goto mzap_next; 284185029Spjd 285185029Spjd d->d_fileno = ZFS_DIRENT_OBJ(mze.mze_value); 286185029Spjd d->d_type = ZFS_DIRENT_TYPE(mze.mze_value); 287185029Spjd strcpy(d->d_name, mze.mze_name); 288185029Spjd d->d_namlen = strlen(d->d_name); 289185029Spjd return (0); 290185029Spjd } else { 291185029Spjd zap_leaf_t zl; 292185029Spjd zap_leaf_chunk_t *zc, *nc; 293185029Spjd int chunk; 294185029Spjd size_t namelen; 295185029Spjd char *p; 296185029Spjd uint64_t value; 297185029Spjd 298185029Spjd /* 299185029Spjd * Initialise this so we can use the ZAP size 300185029Spjd * calculating macros. 301185029Spjd */ 302185029Spjd zl.l_bs = ilog2(bsize); 303185029Spjd zl.l_phys = fp->f_zap_leaf; 304185029Spjd 305185029Spjd /* 306185029Spjd * Figure out which chunk we are currently looking at 307185029Spjd * and consider seeking to the next leaf. We use the 308185029Spjd * low bits of f_seekp as a simple chunk index. 309185029Spjd */ 310185029Spjd fzap_next: 311185029Spjd chunk = fp->f_seekp & (bsize - 1); 312185029Spjd if (chunk == ZAP_LEAF_NUMCHUNKS(&zl)) { 313185029Spjd fp->f_seekp = (fp->f_seekp & ~(bsize - 1)) + bsize; 314185029Spjd chunk = 0; 315185029Spjd 316185029Spjd /* 317185029Spjd * Check for EOF and read the new leaf. 318185029Spjd */ 319185029Spjd if (fp->f_seekp >= bsize * fp->f_num_leafs) 320185029Spjd return (ENOENT); 321185029Spjd 322185029Spjd rc = dnode_read(spa, &fp->f_dnode, 323185029Spjd fp->f_seekp, 324185029Spjd fp->f_zap_leaf, 325185029Spjd bsize); 326185029Spjd if (rc) 327185029Spjd return (rc); 328185029Spjd } 329185029Spjd 330185029Spjd zc = &ZAP_LEAF_CHUNK(&zl, chunk); 331185029Spjd fp->f_seekp++; 332185029Spjd if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) 333185029Spjd goto fzap_next; 334185029Spjd 335240346Savg namelen = zc->l_entry.le_name_numints; 336185029Spjd if (namelen > sizeof(d->d_name)) 337185029Spjd namelen = sizeof(d->d_name); 338185029Spjd 339185029Spjd /* 340185029Spjd * Paste the name back together. 341185029Spjd */ 342185029Spjd nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk); 343185029Spjd p = d->d_name; 344185029Spjd while (namelen > 0) { 345185029Spjd int len; 346185029Spjd len = namelen; 347185029Spjd if (len > ZAP_LEAF_ARRAY_BYTES) 348185029Spjd len = ZAP_LEAF_ARRAY_BYTES; 349185029Spjd memcpy(p, nc->l_array.la_array, len); 350185029Spjd p += len; 351185029Spjd namelen -= len; 352185029Spjd nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next); 353185029Spjd } 354185029Spjd d->d_name[sizeof(d->d_name) - 1] = 0; 355185029Spjd 356185029Spjd /* 357185029Spjd * Assume the first eight bytes of the value are 358185029Spjd * a uint64_t. 359185029Spjd */ 360185029Spjd value = fzap_leaf_value(&zl, zc); 361185029Spjd 362185029Spjd d->d_fileno = ZFS_DIRENT_OBJ(value); 363185029Spjd d->d_type = ZFS_DIRENT_TYPE(value); 364185029Spjd d->d_namlen = strlen(d->d_name); 365185029Spjd 366185029Spjd return (0); 367185029Spjd } 368185029Spjd} 369185029Spjd 370185029Spjdstatic int 371185029Spjdvdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t size) 372185029Spjd{ 373185029Spjd int fd; 374185029Spjd 375185029Spjd fd = (uintptr_t) priv; 376185029Spjd lseek(fd, offset, SEEK_SET); 377185029Spjd if (read(fd, buf, size) == size) { 378185029Spjd return 0; 379185029Spjd } else { 380185029Spjd return (EIO); 381185029Spjd } 382185029Spjd} 383185029Spjd 384235329Savgstatic int 385235329Savgzfs_dev_init(void) 386185029Spjd{ 387241289Savg spa_t *spa; 388241289Savg spa_t *next; 389241289Savg spa_t *prev; 390241289Savg 391235329Savg zfs_init(); 392235329Savg if (archsw.arch_zfs_probe == NULL) 393235329Savg return (ENXIO); 394235329Savg archsw.arch_zfs_probe(); 395241289Savg 396241289Savg prev = NULL; 397241289Savg spa = STAILQ_FIRST(&zfs_pools); 398241289Savg while (spa != NULL) { 399241289Savg next = STAILQ_NEXT(spa, spa_link); 400241289Savg if (zfs_spa_init(spa)) { 401241289Savg if (prev == NULL) 402241289Savg STAILQ_REMOVE_HEAD(&zfs_pools, spa_link); 403241289Savg else 404241289Savg STAILQ_REMOVE_AFTER(&zfs_pools, prev, spa_link); 405241289Savg } else 406241289Savg prev = spa; 407241289Savg spa = next; 408241289Savg } 409235329Savg return (0); 410185029Spjd} 411185029Spjd 412239068Saestruct zfs_probe_args { 413239068Sae int fd; 414239068Sae const char *devname; 415239068Sae uint64_t *pool_guid; 416239068Sae uint16_t secsz; 417239068Sae}; 418239068Sae 419239068Saestatic int 420239068Saezfs_diskread(void *arg, void *buf, size_t blocks, off_t offset) 421239068Sae{ 422239068Sae struct zfs_probe_args *ppa; 423239068Sae 424239068Sae ppa = (struct zfs_probe_args *)arg; 425239068Sae return (vdev_read(NULL, (void *)(uintptr_t)ppa->fd, 426239068Sae offset * ppa->secsz, buf, blocks * ppa->secsz)); 427239068Sae} 428239068Sae 429239068Saestatic int 430239068Saezfs_probe(int fd, uint64_t *pool_guid) 431239068Sae{ 432239068Sae spa_t *spa; 433239068Sae int ret; 434239068Sae 435239068Sae ret = vdev_probe(vdev_read, (void *)(uintptr_t)fd, &spa); 436239068Sae if (ret == 0 && pool_guid != NULL) 437239068Sae *pool_guid = spa->spa_guid; 438239068Sae return (ret); 439239068Sae} 440239068Sae 441239068Saestatic void 442239068Saezfs_probe_partition(void *arg, const char *partname, 443239068Sae const struct ptable_entry *part) 444239068Sae{ 445239068Sae struct zfs_probe_args *ppa, pa; 446239068Sae struct ptable *table; 447239068Sae char devname[32]; 448239068Sae int ret; 449239068Sae 450239068Sae /* Probe only freebsd-zfs and freebsd partitions */ 451239068Sae if (part->type != PART_FREEBSD && 452239068Sae part->type != PART_FREEBSD_ZFS) 453239068Sae return; 454239068Sae 455239068Sae ppa = (struct zfs_probe_args *)arg; 456239068Sae strncpy(devname, ppa->devname, strlen(ppa->devname) - 1); 457239292Sae devname[strlen(ppa->devname) - 1] = '\0'; 458239068Sae sprintf(devname, "%s%s:", devname, partname); 459239068Sae pa.fd = open(devname, O_RDONLY); 460239068Sae if (pa.fd == -1) 461239068Sae return; 462239068Sae ret = zfs_probe(pa.fd, ppa->pool_guid); 463239068Sae if (ret == 0) 464239068Sae return; 465239068Sae /* Do we have BSD label here? */ 466239068Sae if (part->type == PART_FREEBSD) { 467239068Sae pa.devname = devname; 468239068Sae pa.pool_guid = ppa->pool_guid; 469239068Sae pa.secsz = ppa->secsz; 470239068Sae table = ptable_open(&pa, part->end - part->start + 1, 471239068Sae ppa->secsz, zfs_diskread); 472239068Sae if (table != NULL) { 473239068Sae ptable_iterate(table, &pa, zfs_probe_partition); 474239068Sae ptable_close(table); 475239068Sae } 476239068Sae } 477239068Sae close(pa.fd); 478239068Sae} 479239068Sae 480235329Savgint 481235329Savgzfs_probe_dev(const char *devname, uint64_t *pool_guid) 482185029Spjd{ 483239068Sae struct ptable *table; 484239068Sae struct zfs_probe_args pa; 485239068Sae off_t mediasz; 486235329Savg int ret; 487185029Spjd 488239068Sae pa.fd = open(devname, O_RDONLY); 489239068Sae if (pa.fd == -1) 490235329Savg return (ENXIO); 491239068Sae /* Probe the whole disk */ 492239068Sae ret = zfs_probe(pa.fd, pool_guid); 493239068Sae if (ret == 0) 494239068Sae return (0); 495239068Sae /* Probe each partition */ 496239068Sae ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz); 497239068Sae if (ret == 0) 498239068Sae ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz); 499239068Sae if (ret == 0) { 500239068Sae pa.devname = devname; 501239068Sae pa.pool_guid = pool_guid; 502239068Sae table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz, 503239068Sae zfs_diskread); 504239068Sae if (table != NULL) { 505239068Sae ptable_iterate(table, &pa, zfs_probe_partition); 506239068Sae ptable_close(table); 507239068Sae } 508239068Sae } 509239068Sae close(pa.fd); 510294716Ssmh return (ret); 511185029Spjd} 512185029Spjd 513185029Spjd/* 514185029Spjd * Print information about ZFS pools 515185029Spjd */ 516185029Spjdstatic void 517185029Spjdzfs_dev_print(int verbose) 518185029Spjd{ 519185029Spjd spa_t *spa; 520185029Spjd char line[80]; 521185029Spjd 522185029Spjd if (verbose) { 523185029Spjd spa_all_status(); 524185029Spjd return; 525185029Spjd } 526185029Spjd STAILQ_FOREACH(spa, &zfs_pools, spa_link) { 527235329Savg sprintf(line, " zfs:%s\n", spa->spa_name); 528185029Spjd pager_output(line); 529185029Spjd } 530185029Spjd} 531185029Spjd 532185029Spjd/* 533185029Spjd * Attempt to open the pool described by (dev) for use by (f). 534185029Spjd */ 535235329Savgstatic int 536235364Savgzfs_dev_open(struct open_file *f, ...) 537235329Savg{ 538235364Savg va_list args; 539235364Savg struct zfs_devdesc *dev; 540235329Savg struct zfsmount *mount; 541235364Savg spa_t *spa; 542235329Savg int rv; 543235329Savg 544235364Savg va_start(args, f); 545235364Savg dev = va_arg(args, struct zfs_devdesc *); 546235364Savg va_end(args); 547235364Savg 548241282Savg if (dev->pool_guid == 0) 549241282Savg spa = STAILQ_FIRST(&zfs_pools); 550241282Savg else 551241282Savg spa = spa_find_by_guid(dev->pool_guid); 552235364Savg if (!spa) 553235364Savg return (ENXIO); 554235329Savg mount = malloc(sizeof(*mount)); 555235364Savg rv = zfs_mount(spa, dev->root_guid, mount); 556235329Savg if (rv != 0) { 557235329Savg free(mount); 558235329Savg return (rv); 559235329Savg } 560235329Savg if (mount->objset.os_type != DMU_OST_ZFS) { 561235361Savg printf("Unexpected object set type %ju\n", 562235361Savg (uintmax_t)mount->objset.os_type); 563235329Savg free(mount); 564235329Savg return (EIO); 565235329Savg } 566235329Savg f->f_devdata = mount; 567235329Savg free(dev); 568235329Savg return (0); 569235329Savg} 570235329Savg 571241290Savgstatic int 572185029Spjdzfs_dev_close(struct open_file *f) 573185029Spjd{ 574185029Spjd 575235329Savg free(f->f_devdata); 576185029Spjd f->f_devdata = NULL; 577185029Spjd return (0); 578185029Spjd} 579185029Spjd 580241290Savgstatic int 581185029Spjdzfs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize) 582185029Spjd{ 583185029Spjd 584185029Spjd return (ENOSYS); 585185029Spjd} 586185029Spjd 587185029Spjdstruct devsw zfs_dev = { 588235329Savg .dv_name = "zfs", 589235329Savg .dv_type = DEVT_ZFS, 590185029Spjd .dv_init = zfs_dev_init, 591235329Savg .dv_strategy = zfs_dev_strategy, 592235329Savg .dv_open = zfs_dev_open, 593235329Savg .dv_close = zfs_dev_close, 594185029Spjd .dv_ioctl = noioctl, 595185029Spjd .dv_print = zfs_dev_print, 596185029Spjd .dv_cleanup = NULL 597185029Spjd}; 598235329Savg 599235329Savgint 600235329Savgzfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path) 601235329Savg{ 602235329Savg static char rootname[ZFS_MAXNAMELEN]; 603235329Savg static char poolname[ZFS_MAXNAMELEN]; 604235329Savg spa_t *spa; 605235329Savg const char *end; 606235329Savg const char *np; 607235329Savg const char *sep; 608235329Savg int rv; 609235329Savg 610235329Savg np = devspec; 611235329Savg if (*np != ':') 612235329Savg return (EINVAL); 613235329Savg np++; 614235329Savg end = strchr(np, ':'); 615235329Savg if (end == NULL) 616235329Savg return (EINVAL); 617235329Savg sep = strchr(np, '/'); 618235329Savg if (sep == NULL || sep >= end) 619235329Savg sep = end; 620235329Savg memcpy(poolname, np, sep - np); 621235329Savg poolname[sep - np] = '\0'; 622235329Savg if (sep < end) { 623235329Savg sep++; 624235329Savg memcpy(rootname, sep, end - sep); 625235329Savg rootname[end - sep] = '\0'; 626235329Savg } 627235329Savg else 628235329Savg rootname[0] = '\0'; 629235329Savg 630235329Savg spa = spa_find_by_name(poolname); 631235329Savg if (!spa) 632235329Savg return (ENXIO); 633235329Savg dev->pool_guid = spa->spa_guid; 634241292Savg rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid); 635241292Savg if (rv != 0) 636241292Savg return (rv); 637235329Savg if (path != NULL) 638235329Savg *path = (*end == '\0') ? end : end + 1; 639235329Savg dev->d_dev = &zfs_dev; 640235329Savg dev->d_type = zfs_dev.dv_type; 641235329Savg return (0); 642235329Savg} 643235329Savg 644235329Savgchar * 645235329Savgzfs_fmtdev(void *vdev) 646235329Savg{ 647235329Savg static char rootname[ZFS_MAXNAMELEN]; 648235329Savg static char buf[2 * ZFS_MAXNAMELEN + 8]; 649235329Savg struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev; 650235329Savg spa_t *spa; 651235329Savg 652235329Savg buf[0] = '\0'; 653235329Savg if (dev->d_type != DEVT_ZFS) 654235329Savg return (buf); 655235329Savg 656241292Savg if (dev->pool_guid == 0) { 657241282Savg spa = STAILQ_FIRST(&zfs_pools); 658241292Savg dev->pool_guid = spa->spa_guid; 659241292Savg } else 660241282Savg spa = spa_find_by_guid(dev->pool_guid); 661235329Savg if (spa == NULL) { 662235329Savg printf("ZFS: can't find pool by guid\n"); 663235329Savg return (buf); 664235329Savg } 665235329Savg if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) { 666235329Savg printf("ZFS: can't find root filesystem\n"); 667235329Savg return (buf); 668235329Savg } 669235329Savg if (zfs_rlookup(spa, dev->root_guid, rootname)) { 670235329Savg printf("ZFS: can't find filesystem by guid\n"); 671235329Savg return (buf); 672235329Savg } 673235329Savg 674235329Savg if (rootname[0] == '\0') 675235329Savg sprintf(buf, "%s:%s:", dev->d_dev->dv_name, spa->spa_name); 676235329Savg else 677235329Savg sprintf(buf, "%s:%s/%s:", dev->d_dev->dv_name, spa->spa_name, 678235329Savg rootname); 679235329Savg return (buf); 680235329Savg} 681241283Savg 682241283Savgint 683241283Savgzfs_list(const char *name) 684241283Savg{ 685241283Savg static char poolname[ZFS_MAXNAMELEN]; 686241283Savg uint64_t objid; 687241283Savg spa_t *spa; 688241283Savg const char *dsname; 689241283Savg int len; 690241283Savg int rv; 691241283Savg 692241283Savg len = strlen(name); 693241283Savg dsname = strchr(name, '/'); 694241283Savg if (dsname != NULL) { 695241283Savg len = dsname - name; 696241283Savg dsname++; 697241292Savg } else 698241292Savg dsname = ""; 699241283Savg memcpy(poolname, name, len); 700241283Savg poolname[len] = '\0'; 701241283Savg 702241283Savg spa = spa_find_by_name(poolname); 703241283Savg if (!spa) 704241283Savg return (ENXIO); 705241292Savg rv = zfs_lookup_dataset(spa, dsname, &objid); 706241283Savg if (rv != 0) 707241283Savg return (rv); 708293802Sallanjude 709293802Sallanjude return (zfs_list_dataset(spa, objid)); 710293802Sallanjude} 711293802Sallanjude 712295475Sallanjudevoid 713295475Sallanjudeinit_zfs_bootenv(char *currdev) 714295475Sallanjude{ 715295475Sallanjude char *beroot; 716295475Sallanjude 717295475Sallanjude if (strlen(currdev) == 0) 718295475Sallanjude return; 719295475Sallanjude if(strncmp(currdev, "zfs:", 4) != 0) 720295475Sallanjude return; 721295475Sallanjude /* Remove the trailing : */ 722295475Sallanjude currdev[strlen(currdev) - 1] = '\0'; 723295475Sallanjude setenv("zfs_be_active", currdev, 1); 724295475Sallanjude setenv("zfs_be_currpage", "1", 1); 725295475Sallanjude /* Forward past zfs: */ 726295475Sallanjude currdev = strchr(currdev, ':'); 727295475Sallanjude currdev++; 728295475Sallanjude /* Remove the last element (current bootenv) */ 729295475Sallanjude beroot = strrchr(currdev, '/'); 730295475Sallanjude if (beroot != NULL) 731295475Sallanjude beroot[0] = '\0'; 732295475Sallanjude beroot = currdev; 733295475Sallanjude setenv("zfs_be_root", beroot, 1); 734295475Sallanjude} 735295475Sallanjude 736293802Sallanjudeint 737293802Sallanjudezfs_bootenv(const char *name) 738293802Sallanjude{ 739293802Sallanjude static char poolname[ZFS_MAXNAMELEN], *dsname, *root; 740293802Sallanjude char becount[4]; 741293802Sallanjude uint64_t objid; 742293802Sallanjude spa_t *spa; 743293802Sallanjude int len, rv, pages, perpage, currpage; 744293802Sallanjude 745293802Sallanjude if (name == NULL) 746293802Sallanjude return (EINVAL); 747293802Sallanjude if ((root = getenv("zfs_be_root")) == NULL) 748293802Sallanjude return (EINVAL); 749293802Sallanjude 750293802Sallanjude if (strcmp(name, root) != 0) { 751293802Sallanjude if (setenv("zfs_be_root", name, 1) != 0) 752293802Sallanjude return (ENOMEM); 753293802Sallanjude } 754293802Sallanjude 755293802Sallanjude SLIST_INIT(&zfs_be_head); 756293802Sallanjude zfs_env_count = 0; 757293802Sallanjude len = strlen(name); 758293802Sallanjude dsname = strchr(name, '/'); 759293802Sallanjude if (dsname != NULL) { 760293802Sallanjude len = dsname - name; 761293802Sallanjude dsname++; 762293802Sallanjude } else 763293802Sallanjude dsname = ""; 764293802Sallanjude memcpy(poolname, name, len); 765293802Sallanjude poolname[len] = '\0'; 766293802Sallanjude 767293802Sallanjude spa = spa_find_by_name(poolname); 768293802Sallanjude if (!spa) 769293802Sallanjude return (ENXIO); 770293802Sallanjude rv = zfs_lookup_dataset(spa, dsname, &objid); 771293802Sallanjude if (rv != 0) 772293802Sallanjude return (rv); 773293802Sallanjude rv = zfs_callback_dataset(spa, objid, zfs_belist_add); 774293802Sallanjude 775293802Sallanjude /* Calculate and store the number of pages of BEs */ 776293802Sallanjude perpage = (ZFS_BE_LAST - ZFS_BE_FIRST + 1); 777293802Sallanjude pages = (zfs_env_count / perpage) + ((zfs_env_count % perpage) > 0 ? 1 : 0); 778293802Sallanjude snprintf(becount, 4, "%d", pages); 779293802Sallanjude if (setenv("zfs_be_pages", becount, 1) != 0) 780293802Sallanjude return (ENOMEM); 781293802Sallanjude 782293802Sallanjude /* Roll over the page counter if it has exceeded the maximum */ 783293802Sallanjude currpage = strtol(getenv("zfs_be_currpage"), NULL, 10); 784293802Sallanjude if (currpage > pages) { 785293802Sallanjude if (setenv("zfs_be_currpage", "1", 1) != 0) 786293802Sallanjude return (ENOMEM); 787293802Sallanjude } 788293802Sallanjude 789293802Sallanjude /* Populate the menu environment variables */ 790293802Sallanjude zfs_set_env(); 791293802Sallanjude 792293802Sallanjude /* Clean up the SLIST of ZFS BEs */ 793293802Sallanjude while (!SLIST_EMPTY(&zfs_be_head)) { 794293802Sallanjude zfs_be = SLIST_FIRST(&zfs_be_head); 795293802Sallanjude SLIST_REMOVE_HEAD(&zfs_be_head, entries); 796293802Sallanjude free(zfs_be); 797293802Sallanjude } 798293802Sallanjude 799241292Savg return (rv); 800241283Savg} 801293802Sallanjude 802293802Sallanjudeint 803293802Sallanjudezfs_belist_add(const char *name) 804293802Sallanjude{ 805293802Sallanjude 806295475Sallanjude /* Skip special datasets that start with a $ character */ 807295475Sallanjude if (strncmp(name, "$", 1) == 0) { 808295475Sallanjude return (0); 809295475Sallanjude } 810293802Sallanjude /* Add the boot environment to the head of the SLIST */ 811293802Sallanjude zfs_be = malloc(sizeof(struct zfs_be_entry)); 812295475Sallanjude if (zfs_be == NULL) { 813295475Sallanjude return (ENOMEM); 814295475Sallanjude } 815293802Sallanjude zfs_be->name = name; 816293802Sallanjude SLIST_INSERT_HEAD(&zfs_be_head, zfs_be, entries); 817293802Sallanjude zfs_env_count++; 818293802Sallanjude 819293802Sallanjude return (0); 820293802Sallanjude} 821293802Sallanjude 822293802Sallanjudeint 823293802Sallanjudezfs_set_env(void) 824293802Sallanjude{ 825293802Sallanjude char envname[32], envval[256]; 826293802Sallanjude char *beroot, *pagenum; 827293802Sallanjude int rv, page, ctr; 828293802Sallanjude 829293802Sallanjude beroot = getenv("zfs_be_root"); 830293802Sallanjude if (beroot == NULL) { 831293802Sallanjude return (1); 832293802Sallanjude } 833293802Sallanjude 834293802Sallanjude pagenum = getenv("zfs_be_currpage"); 835293802Sallanjude if (pagenum != NULL) { 836293802Sallanjude page = strtol(pagenum, NULL, 10); 837293802Sallanjude } else { 838293802Sallanjude page = 1; 839293802Sallanjude } 840293802Sallanjude 841293802Sallanjude ctr = 1; 842293802Sallanjude rv = 0; 843293802Sallanjude zfs_env_index = ZFS_BE_FIRST; 844293802Sallanjude SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) { 845293802Sallanjude /* Skip to the requested page number */ 846293802Sallanjude if (ctr <= ((ZFS_BE_LAST - ZFS_BE_FIRST + 1) * (page - 1))) { 847293802Sallanjude ctr++; 848293802Sallanjude continue; 849293802Sallanjude } 850293802Sallanjude 851293802Sallanjude snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); 852293802Sallanjude snprintf(envval, sizeof(envval), "%s", zfs_be->name); 853293802Sallanjude rv = setenv(envname, envval, 1); 854293802Sallanjude if (rv != 0) { 855293802Sallanjude break; 856293802Sallanjude } 857293802Sallanjude 858293802Sallanjude snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index); 859293802Sallanjude rv = setenv(envname, envval, 1); 860293802Sallanjude if (rv != 0){ 861293802Sallanjude break; 862293802Sallanjude } 863293802Sallanjude 864293802Sallanjude snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index); 865293802Sallanjude rv = setenv(envname, "set_bootenv", 1); 866293802Sallanjude if (rv != 0){ 867293802Sallanjude break; 868293802Sallanjude } 869293802Sallanjude 870293802Sallanjude snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index); 871293802Sallanjude snprintf(envval, sizeof(envval), "zfs:%s/%s", beroot, zfs_be->name); 872293802Sallanjude rv = setenv(envname, envval, 1); 873293802Sallanjude if (rv != 0){ 874293802Sallanjude break; 875293802Sallanjude } 876293802Sallanjude 877293802Sallanjude zfs_env_index++; 878293802Sallanjude if (zfs_env_index > ZFS_BE_LAST) { 879293802Sallanjude break; 880293802Sallanjude } 881293802Sallanjude 882293802Sallanjude } 883293802Sallanjude 884293802Sallanjude for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) { 885293802Sallanjude snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); 886293802Sallanjude (void)unsetenv(envname); 887293802Sallanjude snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index); 888293802Sallanjude (void)unsetenv(envname); 889293802Sallanjude snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index); 890293802Sallanjude (void)unsetenv(envname); 891293802Sallanjude snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index); 892293802Sallanjude (void)unsetenv(envname); 893293802Sallanjude } 894293802Sallanjude 895293802Sallanjude return (rv); 896293802Sallanjude}