8646 loader: replace EFI part devices.
[unleashed.git] / usr / src / boot / sys / boot / zfs / zfs.c
blobadfa9caf5a333276615c62550b65a530ed9ece8b
1 /*-
2 * Copyright (c) 2007 Doug Rabson
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
26 * $FreeBSD$
29 #include <sys/cdefs.h>
32 * Stand-alone file reading package.
35 #include <sys/disk.h>
36 #include <sys/param.h>
37 #include <sys/time.h>
38 #include <sys/queue.h>
39 #include <part.h>
40 #include <stddef.h>
41 #include <stdarg.h>
42 #include <string.h>
43 #include <stand.h>
44 #include <bootstrap.h>
46 #include "libzfs.h"
48 #include "zfsimpl.c"
50 /* Define the range of indexes to be populated with ZFS Boot Environments */
51 #define ZFS_BE_FIRST 4
52 #define ZFS_BE_LAST 8
54 static int zfs_open(const char *path, struct open_file *f);
55 static int zfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
56 static int zfs_close(struct open_file *f);
57 static int zfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
58 static off_t zfs_seek(struct open_file *f, off_t offset, int where);
59 static int zfs_stat(struct open_file *f, struct stat *sb);
60 static int zfs_readdir(struct open_file *f, struct dirent *d);
62 struct devsw zfs_dev;
64 struct fs_ops zfs_fsops = {
65 "zfs",
66 zfs_open,
67 zfs_close,
68 zfs_read,
69 zfs_write,
70 zfs_seek,
71 zfs_stat,
72 zfs_readdir
76 * In-core open file.
78 struct file {
79 off_t f_seekp; /* seek pointer */
80 dnode_phys_t f_dnode;
81 uint64_t f_zap_type; /* zap type for readdir */
82 uint64_t f_num_leafs; /* number of fzap leaf blocks */
83 zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */
86 #ifdef __FreeBSD__
87 static int zfs_env_index;
88 static int zfs_env_count;
89 #endif
91 SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = SLIST_HEAD_INITIALIZER(zfs_be_head);
92 struct zfs_be_list *zfs_be_headp;
93 struct zfs_be_entry {
94 const char *name;
95 SLIST_ENTRY(zfs_be_entry) entries;
96 } *zfs_be, *zfs_be_tmp;
99 * Open a file.
101 static int
102 zfs_open(const char *upath, struct open_file *f)
104 struct zfsmount *mount = (struct zfsmount *)f->f_devdata;
105 struct file *fp;
106 int rc;
108 if (f->f_dev != &zfs_dev)
109 return (EINVAL);
111 /* allocate file system specific data structure */
112 fp = malloc(sizeof(struct file));
113 bzero(fp, sizeof(struct file));
114 f->f_fsdata = (void *)fp;
116 rc = zfs_lookup(mount, upath, &fp->f_dnode);
117 fp->f_seekp = 0;
118 if (rc) {
119 f->f_fsdata = NULL;
120 free(fp);
122 return (rc);
125 static int
126 zfs_close(struct open_file *f)
128 struct file *fp = (struct file *)f->f_fsdata;
130 dnode_cache_obj = 0;
131 f->f_fsdata = (void *)0;
132 if (fp == (struct file *)0)
133 return (0);
135 free(fp);
136 return (0);
140 * Copy a portion of a file into kernel memory.
141 * Cross block boundaries when necessary.
143 static int
144 zfs_read(struct open_file *f, void *start, size_t size, size_t *resid /* out */)
146 const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
147 struct file *fp = (struct file *)f->f_fsdata;
148 struct stat sb;
149 size_t n;
150 int rc;
152 rc = zfs_stat(f, &sb);
153 if (rc)
154 return (rc);
155 n = size;
156 if (fp->f_seekp + n > sb.st_size)
157 n = sb.st_size - fp->f_seekp;
159 rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n);
160 if (rc)
161 return (rc);
163 if (0) {
164 int i;
165 for (i = 0; i < n; i++)
166 putchar(((char*) start)[i]);
168 fp->f_seekp += n;
169 if (resid)
170 *resid = size - n;
172 return (0);
176 * Don't be silly - the bootstrap has no business writing anything.
178 static int
179 zfs_write(struct open_file *f, void *start, size_t size, size_t *resid /* out */)
182 return (EROFS);
185 static off_t
186 zfs_seek(struct open_file *f, off_t offset, int where)
188 struct file *fp = (struct file *)f->f_fsdata;
190 switch (where) {
191 case SEEK_SET:
192 fp->f_seekp = offset;
193 break;
194 case SEEK_CUR:
195 fp->f_seekp += offset;
196 break;
197 case SEEK_END:
199 struct stat sb;
200 int error;
202 error = zfs_stat(f, &sb);
203 if (error != 0) {
204 errno = error;
205 return (-1);
207 fp->f_seekp = sb.st_size - offset;
208 break;
210 default:
211 errno = EINVAL;
212 return (-1);
214 return (fp->f_seekp);
217 static int
218 zfs_stat(struct open_file *f, struct stat *sb)
220 const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
221 struct file *fp = (struct file *)f->f_fsdata;
223 return (zfs_dnode_stat(spa, &fp->f_dnode, sb));
226 static int
227 zfs_readdir(struct open_file *f, struct dirent *d)
229 const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
230 struct file *fp = (struct file *)f->f_fsdata;
231 mzap_ent_phys_t mze;
232 struct stat sb;
233 size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT;
234 int rc;
236 rc = zfs_stat(f, &sb);
237 if (rc)
238 return (rc);
239 if (!S_ISDIR(sb.st_mode))
240 return (ENOTDIR);
243 * If this is the first read, get the zap type.
245 if (fp->f_seekp == 0) {
246 rc = dnode_read(spa, &fp->f_dnode,
247 0, &fp->f_zap_type, sizeof(fp->f_zap_type));
248 if (rc)
249 return (rc);
251 if (fp->f_zap_type == ZBT_MICRO) {
252 fp->f_seekp = offsetof(mzap_phys_t, mz_chunk);
253 } else {
254 rc = dnode_read(spa, &fp->f_dnode,
255 offsetof(zap_phys_t, zap_num_leafs),
256 &fp->f_num_leafs,
257 sizeof(fp->f_num_leafs));
258 if (rc)
259 return (rc);
261 fp->f_seekp = bsize;
262 fp->f_zap_leaf = (zap_leaf_phys_t *)malloc(bsize);
263 rc = dnode_read(spa, &fp->f_dnode,
264 fp->f_seekp,
265 fp->f_zap_leaf,
266 bsize);
267 if (rc)
268 return (rc);
272 if (fp->f_zap_type == ZBT_MICRO) {
273 mzap_next:
274 if (fp->f_seekp >= bsize)
275 return (ENOENT);
277 rc = dnode_read(spa, &fp->f_dnode,
278 fp->f_seekp, &mze, sizeof(mze));
279 if (rc)
280 return (rc);
281 fp->f_seekp += sizeof(mze);
283 if (!mze.mze_name[0])
284 goto mzap_next;
286 d->d_fileno = ZFS_DIRENT_OBJ(mze.mze_value);
287 d->d_type = ZFS_DIRENT_TYPE(mze.mze_value);
288 strcpy(d->d_name, mze.mze_name);
289 d->d_namlen = strlen(d->d_name);
290 return (0);
291 } else {
292 zap_leaf_t zl;
293 zap_leaf_chunk_t *zc, *nc;
294 int chunk;
295 size_t namelen;
296 char *p;
297 uint64_t value;
300 * Initialise this so we can use the ZAP size
301 * calculating macros.
303 zl.l_bs = ilog2(bsize);
304 zl.l_phys = fp->f_zap_leaf;
307 * Figure out which chunk we are currently looking at
308 * and consider seeking to the next leaf. We use the
309 * low bits of f_seekp as a simple chunk index.
311 fzap_next:
312 chunk = fp->f_seekp & (bsize - 1);
313 if (chunk == ZAP_LEAF_NUMCHUNKS(&zl)) {
314 fp->f_seekp = (fp->f_seekp & ~(bsize - 1)) + bsize;
315 chunk = 0;
318 * Check for EOF and read the new leaf.
320 if (fp->f_seekp >= bsize * fp->f_num_leafs)
321 return (ENOENT);
323 rc = dnode_read(spa, &fp->f_dnode,
324 fp->f_seekp,
325 fp->f_zap_leaf,
326 bsize);
327 if (rc)
328 return (rc);
331 zc = &ZAP_LEAF_CHUNK(&zl, chunk);
332 fp->f_seekp++;
333 if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY)
334 goto fzap_next;
336 namelen = zc->l_entry.le_name_numints;
337 if (namelen > sizeof(d->d_name))
338 namelen = sizeof(d->d_name);
341 * Paste the name back together.
343 nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk);
344 p = d->d_name;
345 while (namelen > 0) {
346 int len;
347 len = namelen;
348 if (len > ZAP_LEAF_ARRAY_BYTES)
349 len = ZAP_LEAF_ARRAY_BYTES;
350 memcpy(p, nc->l_array.la_array, len);
351 p += len;
352 namelen -= len;
353 nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next);
355 d->d_name[sizeof(d->d_name) - 1] = 0;
358 * Assume the first eight bytes of the value are
359 * a uint64_t.
361 value = fzap_leaf_value(&zl, zc);
363 d->d_fileno = ZFS_DIRENT_OBJ(value);
364 d->d_type = ZFS_DIRENT_TYPE(value);
365 d->d_namlen = strlen(d->d_name);
367 return (0);
371 static int
372 vdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t size)
374 int fd;
376 fd = (uintptr_t) priv;
377 lseek(fd, offset, SEEK_SET);
378 if (read(fd, buf, size) == size) {
379 return 0;
380 } else {
381 return (EIO);
385 static int
386 zfs_dev_init(void)
388 spa_t *spa;
389 spa_t *next;
390 spa_t *prev;
392 zfs_init();
393 if (archsw.arch_zfs_probe == NULL)
394 return (ENXIO);
395 archsw.arch_zfs_probe();
397 prev = NULL;
398 spa = STAILQ_FIRST(&zfs_pools);
399 while (spa != NULL) {
400 next = STAILQ_NEXT(spa, spa_link);
401 if (zfs_spa_init(spa)) {
402 if (prev == NULL)
403 STAILQ_REMOVE_HEAD(&zfs_pools, spa_link);
404 else
405 STAILQ_REMOVE_AFTER(&zfs_pools, prev, spa_link);
406 } else
407 prev = spa;
408 spa = next;
410 return (0);
413 struct zfs_probe_args {
414 int fd;
415 const char *devname;
416 uint64_t *pool_guid;
417 u_int secsz;
420 static int
421 zfs_diskread(void *arg, void *buf, size_t blocks, uint64_t offset)
423 struct zfs_probe_args *ppa;
425 ppa = (struct zfs_probe_args *)arg;
426 return (vdev_read(NULL, (void *)(uintptr_t)ppa->fd,
427 offset * ppa->secsz, buf, blocks * ppa->secsz));
430 static int
431 zfs_probe(int fd, uint64_t *pool_guid)
433 spa_t *spa;
434 int ret;
436 ret = vdev_probe(vdev_read, (void *)(uintptr_t)fd, &spa);
437 if (ret == 0 && pool_guid != NULL)
438 *pool_guid = spa->spa_guid;
439 return (ret);
442 static int
443 zfs_probe_partition(void *arg, const char *partname,
444 const struct ptable_entry *part)
446 struct zfs_probe_args *ppa, pa;
447 struct ptable *table;
448 char devname[32];
449 int ret = 0;
451 /* filter out partitions *not* used by zfs */
452 switch (part->type) {
453 case PART_RESERVED: /* efi reserverd */
454 case PART_VTOC_BOOT: /* vtoc boot area */
455 case PART_VTOC_SWAP:
456 return (ret);
457 default:
458 break;;
460 ppa = (struct zfs_probe_args *)arg;
461 strncpy(devname, ppa->devname, strlen(ppa->devname) - 1);
462 devname[strlen(ppa->devname) - 1] = '\0';
463 sprintf(devname, "%s%s:", devname, partname);
464 pa.fd = open(devname, O_RDONLY);
465 if (pa.fd == -1)
466 return (ret);
467 ret = zfs_probe(pa.fd, ppa->pool_guid);
468 if (ret == 0)
469 return (ret);
470 if (part->type == PART_SOLARIS2) {
471 pa.devname = devname;
472 pa.pool_guid = ppa->pool_guid;
473 pa.secsz = ppa->secsz;
474 table = ptable_open(&pa, part->end - part->start + 1,
475 ppa->secsz, zfs_diskread);
476 if (table != NULL) {
477 ptable_iterate(table, &pa, zfs_probe_partition);
478 ptable_close(table);
481 close(pa.fd);
482 return (0);
486 zfs_probe_dev(const char *devname, uint64_t *pool_guid)
488 struct ptable *table;
489 struct zfs_probe_args pa;
490 uint64_t mediasz;
491 int ret;
493 if (pool_guid)
494 *pool_guid = 0;
495 pa.fd = open(devname, O_RDONLY);
496 if (pa.fd == -1)
497 return (ENXIO);
498 /* Probe the whole disk */
499 ret = zfs_probe(pa.fd, pool_guid);
500 if (ret == 0)
501 return (0);
503 /* Probe each partition */
504 ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz);
505 if (ret == 0)
506 ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz);
507 if (ret == 0) {
508 pa.devname = devname;
509 pa.pool_guid = pool_guid;
510 table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz,
511 zfs_diskread);
512 if (table != NULL) {
513 ptable_iterate(table, &pa, zfs_probe_partition);
514 ptable_close(table);
517 close(pa.fd);
518 if (pool_guid && *pool_guid == 0)
519 ret = ENXIO;
520 return (ret);
524 * Print information about ZFS pools
526 static int
527 zfs_dev_print(int verbose)
529 spa_t *spa;
530 char line[80];
531 int ret = 0;
533 if (STAILQ_EMPTY(&zfs_pools))
534 return (0);
536 printf("%s devices:", zfs_dev.dv_name);
537 if ((ret = pager_output("\n")) != 0)
538 return (ret);
540 if (verbose) {
541 return (spa_all_status());
543 STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
544 sprintf(line, " zfs:%s\n", spa->spa_name);
545 ret = pager_output(line);
546 if (ret != 0)
547 break;
549 return (ret);
553 * Attempt to open the pool described by (dev) for use by (f).
555 static int
556 zfs_dev_open(struct open_file *f, ...)
558 va_list args;
559 struct zfs_devdesc *dev;
560 struct zfsmount *mount;
561 spa_t *spa;
562 int rv;
564 va_start(args, f);
565 dev = va_arg(args, struct zfs_devdesc *);
566 va_end(args);
568 if (dev->pool_guid == 0)
569 spa = STAILQ_FIRST(&zfs_pools);
570 else
571 spa = spa_find_by_guid(dev->pool_guid);
572 if (!spa)
573 return (ENXIO);
574 mount = malloc(sizeof(*mount));
575 rv = zfs_mount(spa, dev->root_guid, mount);
576 if (rv != 0) {
577 free(mount);
578 return (rv);
580 if (mount->objset.os_type != DMU_OST_ZFS) {
581 printf("Unexpected object set type %ju\n",
582 (uintmax_t)mount->objset.os_type);
583 free(mount);
584 return (EIO);
586 f->f_devdata = mount;
587 free(dev);
588 return (0);
591 static int
592 zfs_dev_close(struct open_file *f)
595 free(f->f_devdata);
596 f->f_devdata = NULL;
597 return (0);
600 static int
601 zfs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
602 char *buf, size_t *rsize)
605 return (ENOSYS);
608 struct devsw zfs_dev = {
609 .dv_name = "zfs",
610 .dv_type = DEVT_ZFS,
611 .dv_init = zfs_dev_init,
612 .dv_strategy = zfs_dev_strategy,
613 .dv_open = zfs_dev_open,
614 .dv_close = zfs_dev_close,
615 .dv_ioctl = noioctl,
616 .dv_print = zfs_dev_print,
617 .dv_cleanup = NULL
621 zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path)
623 static char rootname[ZFS_MAXNAMELEN];
624 static char poolname[ZFS_MAXNAMELEN];
625 spa_t *spa;
626 const char *end;
627 const char *np;
628 const char *sep;
629 int rv;
631 np = devspec;
632 if (*np != ':')
633 return (EINVAL);
634 np++;
635 end = strchr(np, ':');
636 if (end == NULL)
637 return (EINVAL);
638 sep = strchr(np, '/');
639 if (sep == NULL || sep >= end)
640 sep = end;
641 memcpy(poolname, np, sep - np);
642 poolname[sep - np] = '\0';
643 if (sep < end) {
644 sep++;
645 memcpy(rootname, sep, end - sep);
646 rootname[end - sep] = '\0';
648 else
649 rootname[0] = '\0';
651 spa = spa_find_by_name(poolname);
652 if (!spa)
653 return (ENXIO);
654 dev->pool_guid = spa->spa_guid;
655 rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid);
656 if (rv != 0)
657 return (rv);
658 if (path != NULL)
659 *path = (*end == '\0') ? end : end + 1;
660 dev->d_dev = &zfs_dev;
661 dev->d_type = zfs_dev.dv_type;
662 return (0);
665 char *
666 zfs_bootfs(void *zdev)
668 static char rootname[ZFS_MAXNAMELEN];
669 static char buf[2 * ZFS_MAXNAMELEN];
670 struct zfs_devdesc *dev = (struct zfs_devdesc *)zdev;
671 uint64_t objnum;
672 spa_t *spa;
673 vdev_t *vdev;
674 vdev_t *kid;
675 int n;
677 buf[0] = '\0';
678 if (dev->d_type != DEVT_ZFS)
679 return (buf);
681 spa = spa_find_by_guid(dev->pool_guid);
682 if (spa == NULL) {
683 printf("ZFS: can't find pool by guid\n");
684 return (buf);
686 if (zfs_rlookup(spa, dev->root_guid, rootname)) {
687 printf("ZFS: can't find filesystem by guid\n");
688 return (buf);
690 if (zfs_lookup_dataset(spa, rootname, &objnum)) {
691 printf("ZFS: can't find filesystem by name\n");
692 return (buf);
695 STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) {
696 STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) {
697 /* use this kid? */
698 if (kid->v_state == VDEV_STATE_HEALTHY &&
699 kid->v_phys_path != NULL) {
700 break;
703 if (kid != NULL) {
704 vdev = kid;
705 break;
707 if (vdev->v_state == VDEV_STATE_HEALTHY &&
708 vdev->v_phys_path != NULL) {
709 break;
714 * since this pool was used to read in the kernel and boot archive,
715 * there has to be at least one healthy vdev, therefore vdev
716 * can not be NULL.
718 /* Set the environment. */
719 snprintf(buf, sizeof (buf), "%s/%llu", spa->spa_name,
720 (unsigned long long)objnum);
721 setenv("zfs-bootfs", buf, 1);
722 if (vdev->v_phys_path != NULL)
723 setenv("bootpath", vdev->v_phys_path, 1);
724 if (vdev->v_devid != NULL)
725 setenv("diskdevid", vdev->v_devid, 1);
728 * Build the command line string. Once our kernel will read
729 * the environment and we can stop caring about old kernels,
730 * we can remove this part.
732 snprintf(buf, sizeof(buf), "zfs-bootfs=%s/%llu", spa->spa_name,
733 (unsigned long long)objnum);
734 n = strlen(buf);
735 if (vdev->v_phys_path != NULL) {
736 snprintf(buf+n, sizeof (buf) - n, ",bootpath=\"%s\"",
737 vdev->v_phys_path);
738 n = strlen(buf);
740 if (vdev->v_devid != NULL) {
741 snprintf(buf+n, sizeof (buf) - n, ",diskdevid=\"%s\"",
742 vdev->v_devid);
744 return (buf);
747 char *
748 zfs_fmtdev(void *vdev)
750 static char rootname[ZFS_MAXNAMELEN];
751 static char buf[2 * ZFS_MAXNAMELEN + 8];
752 struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
753 spa_t *spa;
755 buf[0] = '\0';
756 if (dev->d_type != DEVT_ZFS)
757 return (buf);
759 if (dev->pool_guid == 0) {
760 spa = STAILQ_FIRST(&zfs_pools);
761 dev->pool_guid = spa->spa_guid;
762 } else
763 spa = spa_find_by_guid(dev->pool_guid);
764 if (spa == NULL) {
765 printf("ZFS: can't find pool by guid\n");
766 return (buf);
768 if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) {
769 printf("ZFS: can't find root filesystem\n");
770 return (buf);
772 if (zfs_rlookup(spa, dev->root_guid, rootname)) {
773 printf("ZFS: can't find filesystem by guid\n");
774 return (buf);
777 if (rootname[0] == '\0')
778 sprintf(buf, "%s:%s:", dev->d_dev->dv_name, spa->spa_name);
779 else
780 sprintf(buf, "%s:%s/%s:", dev->d_dev->dv_name, spa->spa_name,
781 rootname);
782 return (buf);
786 zfs_list(const char *name)
788 static char poolname[ZFS_MAXNAMELEN];
789 uint64_t objid;
790 spa_t *spa;
791 const char *dsname;
792 int len;
793 int rv;
795 len = strlen(name);
796 dsname = strchr(name, '/');
797 if (dsname != NULL) {
798 len = dsname - name;
799 dsname++;
800 } else
801 dsname = "";
802 memcpy(poolname, name, len);
803 poolname[len] = '\0';
805 spa = spa_find_by_name(poolname);
806 if (!spa)
807 return (ENXIO);
808 rv = zfs_lookup_dataset(spa, dsname, &objid);
809 if (rv != 0)
810 return (rv);
812 return (zfs_list_dataset(spa, objid));
815 #ifdef __FreeBSD__
816 void
817 init_zfs_bootenv(char *currdev)
819 char *beroot;
821 if (strlen(currdev) == 0)
822 return;
823 if(strncmp(currdev, "zfs:", 4) != 0)
824 return;
825 /* Remove the trailing : */
826 currdev[strlen(currdev) - 1] = '\0';
827 setenv("zfs_be_active", currdev, 1);
828 setenv("zfs_be_currpage", "1", 1);
829 /* Forward past zfs: */
830 currdev = strchr(currdev, ':');
831 currdev++;
832 /* Remove the last element (current bootenv) */
833 beroot = strrchr(currdev, '/');
834 if (beroot != NULL)
835 beroot[0] = '\0';
836 beroot = currdev;
837 setenv("zfs_be_root", beroot, 1);
841 zfs_bootenv(const char *name)
843 static char poolname[ZFS_MAXNAMELEN], *dsname, *root;
844 char becount[4];
845 uint64_t objid;
846 spa_t *spa;
847 int len, rv, pages, perpage, currpage;
849 if (name == NULL)
850 return (EINVAL);
851 if ((root = getenv("zfs_be_root")) == NULL)
852 return (EINVAL);
854 if (strcmp(name, root) != 0) {
855 if (setenv("zfs_be_root", name, 1) != 0)
856 return (ENOMEM);
859 SLIST_INIT(&zfs_be_head);
860 zfs_env_count = 0;
861 len = strlen(name);
862 dsname = strchr(name, '/');
863 if (dsname != NULL) {
864 len = dsname - name;
865 dsname++;
866 } else
867 dsname = "";
868 memcpy(poolname, name, len);
869 poolname[len] = '\0';
871 spa = spa_find_by_name(poolname);
872 if (!spa)
873 return (ENXIO);
874 rv = zfs_lookup_dataset(spa, dsname, &objid);
875 if (rv != 0)
876 return (rv);
877 rv = zfs_callback_dataset(spa, objid, zfs_belist_add);
879 /* Calculate and store the number of pages of BEs */
880 perpage = (ZFS_BE_LAST - ZFS_BE_FIRST + 1);
881 pages = (zfs_env_count / perpage) + ((zfs_env_count % perpage) > 0 ? 1 : 0);
882 snprintf(becount, 4, "%d", pages);
883 if (setenv("zfs_be_pages", becount, 1) != 0)
884 return (ENOMEM);
886 /* Roll over the page counter if it has exceeded the maximum */
887 currpage = strtol(getenv("zfs_be_currpage"), NULL, 10);
888 if (currpage > pages) {
889 if (setenv("zfs_be_currpage", "1", 1) != 0)
890 return (ENOMEM);
893 /* Populate the menu environment variables */
894 zfs_set_env();
896 /* Clean up the SLIST of ZFS BEs */
897 while (!SLIST_EMPTY(&zfs_be_head)) {
898 zfs_be = SLIST_FIRST(&zfs_be_head);
899 SLIST_REMOVE_HEAD(&zfs_be_head, entries);
900 free(zfs_be);
903 return (rv);
907 zfs_belist_add(const char *name, uint64_t value __unused)
910 /* Skip special datasets that start with a $ character */
911 if (strncmp(name, "$", 1) == 0) {
912 return (0);
914 /* Add the boot environment to the head of the SLIST */
915 zfs_be = malloc(sizeof(struct zfs_be_entry));
916 if (zfs_be == NULL) {
917 return (ENOMEM);
919 zfs_be->name = name;
920 SLIST_INSERT_HEAD(&zfs_be_head, zfs_be, entries);
921 zfs_env_count++;
923 return (0);
927 zfs_set_env(void)
929 char envname[32], envval[256];
930 char *beroot, *pagenum;
931 int rv, page, ctr;
933 beroot = getenv("zfs_be_root");
934 if (beroot == NULL) {
935 return (1);
938 pagenum = getenv("zfs_be_currpage");
939 if (pagenum != NULL) {
940 page = strtol(pagenum, NULL, 10);
941 } else {
942 page = 1;
945 ctr = 1;
946 rv = 0;
947 zfs_env_index = ZFS_BE_FIRST;
948 SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) {
949 /* Skip to the requested page number */
950 if (ctr <= ((ZFS_BE_LAST - ZFS_BE_FIRST + 1) * (page - 1))) {
951 ctr++;
952 continue;
955 snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index);
956 snprintf(envval, sizeof(envval), "%s", zfs_be->name);
957 rv = setenv(envname, envval, 1);
958 if (rv != 0) {
959 break;
962 snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index);
963 rv = setenv(envname, envval, 1);
964 if (rv != 0){
965 break;
968 snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index);
969 rv = setenv(envname, "set_bootenv", 1);
970 if (rv != 0){
971 break;
974 snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index);
975 snprintf(envval, sizeof(envval), "zfs:%s/%s", beroot, zfs_be->name);
976 rv = setenv(envname, envval, 1);
977 if (rv != 0){
978 break;
981 zfs_env_index++;
982 if (zfs_env_index > ZFS_BE_LAST) {
983 break;
988 for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) {
989 snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index);
990 (void)unsetenv(envname);
991 snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index);
992 (void)unsetenv(envname);
993 snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index);
994 (void)unsetenv(envname);
995 snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index);
996 (void)unsetenv(envname);
999 return (rv);
1001 #endif