9423 loader: zfs_bootfs() needs to use config pool txg for boot device
[unleashed.git] / usr / src / boot / sys / boot / zfs / zfs.c
blob9a4b94417805c3e61e3be1f4de5a21ef0b10c847
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.
27 #include <sys/cdefs.h>
30 * Stand-alone file reading package.
33 #include <sys/disk.h>
34 #include <sys/param.h>
35 #include <sys/time.h>
36 #include <sys/queue.h>
37 #include <part.h>
38 #include <stddef.h>
39 #include <stdarg.h>
40 #include <string.h>
41 #include <stand.h>
42 #include <bootstrap.h>
44 #include "libzfs.h"
46 #include "zfsimpl.c"
48 /* Define the range of indexes to be populated with ZFS Boot Environments */
49 #define ZFS_BE_FIRST 4
50 #define ZFS_BE_LAST 8
52 static int zfs_open(const char *path, struct open_file *f);
53 static int zfs_close(struct open_file *f);
54 static int zfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
55 static off_t zfs_seek(struct open_file *f, off_t offset, int where);
56 static int zfs_stat(struct open_file *f, struct stat *sb);
57 static int zfs_readdir(struct open_file *f, struct dirent *d);
59 struct devsw zfs_dev;
61 struct fs_ops zfs_fsops = {
62 "zfs",
63 zfs_open,
64 zfs_close,
65 zfs_read,
66 null_write,
67 zfs_seek,
68 zfs_stat,
69 zfs_readdir
73 * In-core open file.
75 struct file {
76 off_t f_seekp; /* seek pointer */
77 dnode_phys_t f_dnode;
78 uint64_t f_zap_type; /* zap type for readdir */
79 uint64_t f_num_leafs; /* number of fzap leaf blocks */
80 zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */
83 #ifdef __FreeBSD__
84 static int zfs_env_index;
85 static int zfs_env_count;
86 #endif
88 SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = SLIST_HEAD_INITIALIZER(zfs_be_head);
89 struct zfs_be_list *zfs_be_headp;
90 struct zfs_be_entry {
91 const char *name;
92 SLIST_ENTRY(zfs_be_entry) entries;
93 } *zfs_be, *zfs_be_tmp;
96 * Open a file.
98 static int
99 zfs_open(const char *upath, struct open_file *f)
101 struct zfsmount *mount = (struct zfsmount *)f->f_devdata;
102 struct file *fp;
103 int rc;
105 if (f->f_dev != &zfs_dev)
106 return (EINVAL);
108 /* allocate file system specific data structure */
109 fp = malloc(sizeof(struct file));
110 bzero(fp, sizeof(struct file));
111 f->f_fsdata = (void *)fp;
113 rc = zfs_lookup(mount, upath, &fp->f_dnode);
114 fp->f_seekp = 0;
115 if (rc) {
116 f->f_fsdata = NULL;
117 free(fp);
119 return (rc);
122 static int
123 zfs_close(struct open_file *f)
125 struct file *fp = (struct file *)f->f_fsdata;
127 dnode_cache_obj = 0;
128 f->f_fsdata = (void *)0;
129 if (fp == (struct file *)0)
130 return (0);
132 free(fp);
133 return (0);
137 * Copy a portion of a file into kernel memory.
138 * Cross block boundaries when necessary.
140 static int
141 zfs_read(struct open_file *f, void *start, size_t size, size_t *resid /* out */)
143 const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
144 struct file *fp = (struct file *)f->f_fsdata;
145 struct stat sb;
146 size_t n;
147 int rc;
149 rc = zfs_stat(f, &sb);
150 if (rc)
151 return (rc);
152 n = size;
153 if (fp->f_seekp + n > sb.st_size)
154 n = sb.st_size - fp->f_seekp;
156 rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n);
157 if (rc)
158 return (rc);
160 if (0) {
161 int i;
162 for (i = 0; i < n; i++)
163 putchar(((char*) start)[i]);
165 fp->f_seekp += n;
166 if (resid)
167 *resid = size - n;
169 return (0);
172 static off_t
173 zfs_seek(struct open_file *f, off_t offset, int where)
175 struct file *fp = (struct file *)f->f_fsdata;
177 switch (where) {
178 case SEEK_SET:
179 fp->f_seekp = offset;
180 break;
181 case SEEK_CUR:
182 fp->f_seekp += offset;
183 break;
184 case SEEK_END:
186 struct stat sb;
187 int error;
189 error = zfs_stat(f, &sb);
190 if (error != 0) {
191 errno = error;
192 return (-1);
194 fp->f_seekp = sb.st_size - offset;
195 break;
197 default:
198 errno = EINVAL;
199 return (-1);
201 return (fp->f_seekp);
204 static int
205 zfs_stat(struct open_file *f, struct stat *sb)
207 const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
208 struct file *fp = (struct file *)f->f_fsdata;
210 return (zfs_dnode_stat(spa, &fp->f_dnode, sb));
213 static int
214 zfs_readdir(struct open_file *f, struct dirent *d)
216 const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
217 struct file *fp = (struct file *)f->f_fsdata;
218 mzap_ent_phys_t mze;
219 struct stat sb;
220 size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT;
221 int rc;
223 rc = zfs_stat(f, &sb);
224 if (rc)
225 return (rc);
226 if (!S_ISDIR(sb.st_mode))
227 return (ENOTDIR);
230 * If this is the first read, get the zap type.
232 if (fp->f_seekp == 0) {
233 rc = dnode_read(spa, &fp->f_dnode,
234 0, &fp->f_zap_type, sizeof(fp->f_zap_type));
235 if (rc)
236 return (rc);
238 if (fp->f_zap_type == ZBT_MICRO) {
239 fp->f_seekp = offsetof(mzap_phys_t, mz_chunk);
240 } else {
241 rc = dnode_read(spa, &fp->f_dnode,
242 offsetof(zap_phys_t, zap_num_leafs),
243 &fp->f_num_leafs,
244 sizeof(fp->f_num_leafs));
245 if (rc)
246 return (rc);
248 fp->f_seekp = bsize;
249 fp->f_zap_leaf = (zap_leaf_phys_t *)malloc(bsize);
250 rc = dnode_read(spa, &fp->f_dnode,
251 fp->f_seekp,
252 fp->f_zap_leaf,
253 bsize);
254 if (rc)
255 return (rc);
259 if (fp->f_zap_type == ZBT_MICRO) {
260 mzap_next:
261 if (fp->f_seekp >= bsize)
262 return (ENOENT);
264 rc = dnode_read(spa, &fp->f_dnode,
265 fp->f_seekp, &mze, sizeof(mze));
266 if (rc)
267 return (rc);
268 fp->f_seekp += sizeof(mze);
270 if (!mze.mze_name[0])
271 goto mzap_next;
273 d->d_fileno = ZFS_DIRENT_OBJ(mze.mze_value);
274 d->d_type = ZFS_DIRENT_TYPE(mze.mze_value);
275 strcpy(d->d_name, mze.mze_name);
276 d->d_namlen = strlen(d->d_name);
277 return (0);
278 } else {
279 zap_leaf_t zl;
280 zap_leaf_chunk_t *zc, *nc;
281 int chunk;
282 size_t namelen;
283 char *p;
284 uint64_t value;
287 * Initialise this so we can use the ZAP size
288 * calculating macros.
290 zl.l_bs = ilog2(bsize);
291 zl.l_phys = fp->f_zap_leaf;
294 * Figure out which chunk we are currently looking at
295 * and consider seeking to the next leaf. We use the
296 * low bits of f_seekp as a simple chunk index.
298 fzap_next:
299 chunk = fp->f_seekp & (bsize - 1);
300 if (chunk == ZAP_LEAF_NUMCHUNKS(&zl)) {
301 fp->f_seekp = (fp->f_seekp & ~(bsize - 1)) + bsize;
302 chunk = 0;
305 * Check for EOF and read the new leaf.
307 if (fp->f_seekp >= bsize * fp->f_num_leafs)
308 return (ENOENT);
310 rc = dnode_read(spa, &fp->f_dnode,
311 fp->f_seekp,
312 fp->f_zap_leaf,
313 bsize);
314 if (rc)
315 return (rc);
318 zc = &ZAP_LEAF_CHUNK(&zl, chunk);
319 fp->f_seekp++;
320 if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY)
321 goto fzap_next;
323 namelen = zc->l_entry.le_name_numints;
324 if (namelen > sizeof(d->d_name))
325 namelen = sizeof(d->d_name);
328 * Paste the name back together.
330 nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk);
331 p = d->d_name;
332 while (namelen > 0) {
333 int len;
334 len = namelen;
335 if (len > ZAP_LEAF_ARRAY_BYTES)
336 len = ZAP_LEAF_ARRAY_BYTES;
337 memcpy(p, nc->l_array.la_array, len);
338 p += len;
339 namelen -= len;
340 nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next);
342 d->d_name[sizeof(d->d_name) - 1] = 0;
345 * Assume the first eight bytes of the value are
346 * a uint64_t.
348 value = fzap_leaf_value(&zl, zc);
350 d->d_fileno = ZFS_DIRENT_OBJ(value);
351 d->d_type = ZFS_DIRENT_TYPE(value);
352 d->d_namlen = strlen(d->d_name);
354 return (0);
358 static int
359 vdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t bytes)
361 int fd, ret;
362 size_t res, size, remainder, rb_size, blksz;
363 unsigned secsz;
364 off_t off;
365 char *bouncebuf, *rb_buf;
367 fd = (uintptr_t) priv;
368 bouncebuf = NULL;
370 ret = ioctl(fd, DIOCGSECTORSIZE, &secsz);
371 if (ret != 0)
372 return (ret);
374 off = offset / secsz;
375 remainder = offset % secsz;
376 if (lseek(fd, off * secsz, SEEK_SET) == -1)
377 return (errno);
379 rb_buf = buf;
380 rb_size = bytes;
381 size = roundup2(bytes + remainder, secsz);
382 blksz = size;
383 if (remainder != 0 || size != bytes) {
384 bouncebuf = zfs_alloc(secsz);
385 if (bouncebuf == NULL) {
386 printf("vdev_read: out of memory\n");
387 return (ENOMEM);
389 rb_buf = bouncebuf;
390 blksz = rb_size - remainder;
393 while (bytes > 0) {
394 res = read(fd, rb_buf, rb_size);
395 if (res != rb_size) {
396 ret = EIO;
397 goto error;
399 if (bytes < blksz)
400 blksz = bytes;
401 if (bouncebuf != NULL)
402 memcpy(buf, rb_buf + remainder, blksz);
403 buf = (void *)((uintptr_t)buf + blksz);
404 bytes -= blksz;
405 remainder = 0;
406 blksz = rb_size;
409 ret = 0;
410 error:
411 if (bouncebuf != NULL)
412 zfs_free(bouncebuf, secsz);
413 return (ret);
416 static int
417 zfs_dev_init(void)
419 spa_t *spa;
420 spa_t *next;
421 spa_t *prev;
423 zfs_init();
424 if (archsw.arch_zfs_probe == NULL)
425 return (ENXIO);
426 archsw.arch_zfs_probe();
428 prev = NULL;
429 spa = STAILQ_FIRST(&zfs_pools);
430 while (spa != NULL) {
431 next = STAILQ_NEXT(spa, spa_link);
432 if (zfs_spa_init(spa)) {
433 if (prev == NULL)
434 STAILQ_REMOVE_HEAD(&zfs_pools, spa_link);
435 else
436 STAILQ_REMOVE_AFTER(&zfs_pools, prev, spa_link);
437 } else
438 prev = spa;
439 spa = next;
441 return (0);
444 struct zfs_probe_args {
445 int fd;
446 const char *devname;
447 uint64_t *pool_guid;
448 u_int secsz;
451 static int
452 zfs_diskread(void *arg, void *buf, size_t blocks, uint64_t offset)
454 struct zfs_probe_args *ppa;
456 ppa = (struct zfs_probe_args *)arg;
457 return (vdev_read(NULL, (void *)(uintptr_t)ppa->fd,
458 offset * ppa->secsz, buf, blocks * ppa->secsz));
461 static int
462 zfs_probe(int fd, uint64_t *pool_guid)
464 spa_t *spa;
465 int ret;
467 ret = vdev_probe(vdev_read, (void *)(uintptr_t)fd, &spa);
468 if (ret == 0 && pool_guid != NULL)
469 *pool_guid = spa->spa_guid;
470 return (ret);
473 static int
474 zfs_probe_partition(void *arg, const char *partname,
475 const struct ptable_entry *part)
477 struct zfs_probe_args *ppa, pa;
478 struct ptable *table;
479 char devname[32];
480 int ret = 0;
482 /* filter out partitions *not* used by zfs */
483 switch (part->type) {
484 case PART_RESERVED: /* efi reserverd */
485 case PART_VTOC_BOOT: /* vtoc boot area */
486 case PART_VTOC_SWAP:
487 return (ret);
488 default:
489 break;
491 ppa = (struct zfs_probe_args *)arg;
492 strncpy(devname, ppa->devname, strlen(ppa->devname) - 1);
493 devname[strlen(ppa->devname) - 1] = '\0';
494 sprintf(devname, "%s%s:", devname, partname);
495 pa.fd = open(devname, O_RDONLY);
496 if (pa.fd == -1)
497 return (ret);
498 ret = zfs_probe(pa.fd, ppa->pool_guid);
499 if (ret == 0)
500 return (ret);
501 if (part->type == PART_SOLARIS2) {
502 pa.devname = devname;
503 pa.pool_guid = ppa->pool_guid;
504 pa.secsz = ppa->secsz;
505 table = ptable_open(&pa, part->end - part->start + 1,
506 ppa->secsz, zfs_diskread);
507 if (table != NULL) {
508 enum ptable_type pt = ptable_gettype(table);
510 if (pt == PTABLE_VTOC8 || pt == PTABLE_VTOC)
511 ptable_iterate(table, &pa, zfs_probe_partition);
512 ptable_close(table);
515 close(pa.fd);
516 return (0);
520 zfs_probe_dev(const char *devname, uint64_t *pool_guid)
522 struct ptable *table;
523 struct zfs_probe_args pa;
524 uint64_t mediasz;
525 int ret;
527 if (pool_guid)
528 *pool_guid = 0;
529 pa.fd = open(devname, O_RDONLY);
530 if (pa.fd == -1)
531 return (ENXIO);
532 /* Probe the whole disk */
533 ret = zfs_probe(pa.fd, pool_guid);
534 if (ret == 0)
535 return (0);
537 /* Probe each partition */
538 ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz);
539 if (ret == 0)
540 ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz);
541 if (ret == 0) {
542 pa.devname = devname;
543 pa.pool_guid = pool_guid;
544 table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz,
545 zfs_diskread);
546 if (table != NULL) {
547 ptable_iterate(table, &pa, zfs_probe_partition);
548 ptable_close(table);
551 close(pa.fd);
552 if (pool_guid && *pool_guid == 0)
553 ret = ENXIO;
554 return (ret);
558 * Print information about ZFS pools
560 static int
561 zfs_dev_print(int verbose)
563 spa_t *spa;
564 char line[80];
565 int ret = 0;
567 if (STAILQ_EMPTY(&zfs_pools))
568 return (0);
570 printf("%s devices:", zfs_dev.dv_name);
571 if ((ret = pager_output("\n")) != 0)
572 return (ret);
574 if (verbose) {
575 return (spa_all_status());
577 STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
578 sprintf(line, " zfs:%s\n", spa->spa_name);
579 ret = pager_output(line);
580 if (ret != 0)
581 break;
583 return (ret);
587 * Attempt to open the pool described by (dev) for use by (f).
589 static int
590 zfs_dev_open(struct open_file *f, ...)
592 va_list args;
593 struct zfs_devdesc *dev;
594 struct zfsmount *mount;
595 spa_t *spa;
596 int rv;
598 va_start(args, f);
599 dev = va_arg(args, struct zfs_devdesc *);
600 va_end(args);
602 if (dev->pool_guid == 0)
603 spa = STAILQ_FIRST(&zfs_pools);
604 else
605 spa = spa_find_by_guid(dev->pool_guid);
606 if (!spa)
607 return (ENXIO);
608 mount = malloc(sizeof(*mount));
609 rv = zfs_mount(spa, dev->root_guid, mount);
610 if (rv != 0) {
611 free(mount);
612 return (rv);
614 if (mount->objset.os_type != DMU_OST_ZFS) {
615 printf("Unexpected object set type %ju\n",
616 (uintmax_t)mount->objset.os_type);
617 free(mount);
618 return (EIO);
620 f->f_devdata = mount;
621 free(dev);
622 return (0);
625 static int
626 zfs_dev_close(struct open_file *f)
629 free(f->f_devdata);
630 f->f_devdata = NULL;
631 return (0);
634 static int
635 zfs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
636 char *buf, size_t *rsize)
639 return (ENOSYS);
642 struct devsw zfs_dev = {
643 .dv_name = "zfs",
644 .dv_type = DEVT_ZFS,
645 .dv_init = zfs_dev_init,
646 .dv_strategy = zfs_dev_strategy,
647 .dv_open = zfs_dev_open,
648 .dv_close = zfs_dev_close,
649 .dv_ioctl = noioctl,
650 .dv_print = zfs_dev_print,
651 .dv_cleanup = NULL
655 zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path)
657 static char rootname[ZFS_MAXNAMELEN];
658 static char poolname[ZFS_MAXNAMELEN];
659 spa_t *spa;
660 const char *end;
661 const char *np;
662 const char *sep;
663 int rv;
665 np = devspec;
666 if (*np != ':')
667 return (EINVAL);
668 np++;
669 end = strchr(np, ':');
670 if (end == NULL)
671 return (EINVAL);
672 sep = strchr(np, '/');
673 if (sep == NULL || sep >= end)
674 sep = end;
675 memcpy(poolname, np, sep - np);
676 poolname[sep - np] = '\0';
677 if (sep < end) {
678 sep++;
679 memcpy(rootname, sep, end - sep);
680 rootname[end - sep] = '\0';
682 else
683 rootname[0] = '\0';
685 spa = spa_find_by_name(poolname);
686 if (!spa)
687 return (ENXIO);
688 dev->pool_guid = spa->spa_guid;
689 rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid);
690 if (rv != 0)
691 return (rv);
692 if (path != NULL)
693 *path = (*end == '\0') ? end : end + 1;
694 dev->d_dev = &zfs_dev;
695 dev->d_type = zfs_dev.dv_type;
696 return (0);
699 char *
700 zfs_bootfs(void *zdev)
702 static char rootname[ZFS_MAXNAMELEN];
703 static char buf[2 * ZFS_MAXNAMELEN];
704 struct zfs_devdesc *dev = (struct zfs_devdesc *)zdev;
705 uint64_t objnum;
706 spa_t *spa;
707 int n;
709 buf[0] = '\0';
710 if (dev->d_type != DEVT_ZFS)
711 return (buf);
713 spa = spa_find_by_guid(dev->pool_guid);
714 if (spa == NULL) {
715 printf("ZFS: can't find pool by guid\n");
716 return (buf);
718 if (zfs_rlookup(spa, dev->root_guid, rootname)) {
719 printf("ZFS: can't find filesystem by guid\n");
720 return (buf);
722 if (zfs_lookup_dataset(spa, rootname, &objnum)) {
723 printf("ZFS: can't find filesystem by name\n");
724 return (buf);
727 /* Set the environment. */
728 snprintf(buf, sizeof (buf), "%s/%llu", spa->spa_name,
729 (unsigned long long)objnum);
730 setenv("zfs-bootfs", buf, 1);
731 if (spa->spa_boot_vdev->v_phys_path != NULL)
732 setenv("bootpath", spa->spa_boot_vdev->v_phys_path, 1);
733 if (spa->spa_boot_vdev->v_devid != NULL)
734 setenv("diskdevid", spa->spa_boot_vdev->v_devid, 1);
737 * Build the command line string. Once our kernel will read
738 * the environment and we can stop caring about old kernels,
739 * we can remove this part.
741 snprintf(buf, sizeof(buf), "zfs-bootfs=%s/%llu", spa->spa_name,
742 (unsigned long long)objnum);
743 n = strlen(buf);
744 if (spa->spa_boot_vdev->v_phys_path != NULL) {
745 snprintf(buf+n, sizeof (buf) - n, ",bootpath=\"%s\"",
746 spa->spa_boot_vdev->v_phys_path);
747 n = strlen(buf);
749 if (spa->spa_boot_vdev->v_devid != NULL) {
750 snprintf(buf+n, sizeof (buf) - n, ",diskdevid=\"%s\"",
751 spa->spa_boot_vdev->v_devid);
753 return (buf);
756 char *
757 zfs_fmtdev(void *vdev)
759 static char rootname[ZFS_MAXNAMELEN];
760 static char buf[2 * ZFS_MAXNAMELEN + 8];
761 struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
762 spa_t *spa;
764 buf[0] = '\0';
765 if (dev->d_type != DEVT_ZFS)
766 return (buf);
768 if (dev->pool_guid == 0) {
769 spa = STAILQ_FIRST(&zfs_pools);
770 dev->pool_guid = spa->spa_guid;
771 } else
772 spa = spa_find_by_guid(dev->pool_guid);
773 if (spa == NULL) {
774 printf("ZFS: can't find pool by guid\n");
775 return (buf);
777 if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) {
778 printf("ZFS: can't find root filesystem\n");
779 return (buf);
781 if (zfs_rlookup(spa, dev->root_guid, rootname)) {
782 printf("ZFS: can't find filesystem by guid\n");
783 return (buf);
786 if (rootname[0] == '\0')
787 sprintf(buf, "%s:%s:", dev->d_dev->dv_name, spa->spa_name);
788 else
789 sprintf(buf, "%s:%s/%s:", dev->d_dev->dv_name, spa->spa_name,
790 rootname);
791 return (buf);
795 zfs_list(const char *name)
797 static char poolname[ZFS_MAXNAMELEN];
798 uint64_t objid;
799 spa_t *spa;
800 const char *dsname;
801 int len;
802 int rv;
804 len = strlen(name);
805 dsname = strchr(name, '/');
806 if (dsname != NULL) {
807 len = dsname - name;
808 dsname++;
809 } else
810 dsname = "";
811 memcpy(poolname, name, len);
812 poolname[len] = '\0';
814 spa = spa_find_by_name(poolname);
815 if (!spa)
816 return (ENXIO);
817 rv = zfs_lookup_dataset(spa, dsname, &objid);
818 if (rv != 0)
819 return (rv);
821 return (zfs_list_dataset(spa, objid));
824 #ifdef __FreeBSD__
825 void
826 init_zfs_bootenv(char *currdev)
828 char *beroot;
830 if (strlen(currdev) == 0)
831 return;
832 if(strncmp(currdev, "zfs:", 4) != 0)
833 return;
834 /* Remove the trailing : */
835 currdev[strlen(currdev) - 1] = '\0';
836 setenv("zfs_be_active", currdev, 1);
837 setenv("zfs_be_currpage", "1", 1);
838 /* Forward past zfs: */
839 currdev = strchr(currdev, ':');
840 currdev++;
841 /* Remove the last element (current bootenv) */
842 beroot = strrchr(currdev, '/');
843 if (beroot != NULL)
844 beroot[0] = '\0';
845 beroot = currdev;
846 setenv("zfs_be_root", beroot, 1);
850 zfs_bootenv(const char *name)
852 static char poolname[ZFS_MAXNAMELEN], *dsname, *root;
853 char becount[4];
854 uint64_t objid;
855 spa_t *spa;
856 int len, rv, pages, perpage, currpage;
858 if (name == NULL)
859 return (EINVAL);
860 if ((root = getenv("zfs_be_root")) == NULL)
861 return (EINVAL);
863 if (strcmp(name, root) != 0) {
864 if (setenv("zfs_be_root", name, 1) != 0)
865 return (ENOMEM);
868 SLIST_INIT(&zfs_be_head);
869 zfs_env_count = 0;
870 len = strlen(name);
871 dsname = strchr(name, '/');
872 if (dsname != NULL) {
873 len = dsname - name;
874 dsname++;
875 } else
876 dsname = "";
877 memcpy(poolname, name, len);
878 poolname[len] = '\0';
880 spa = spa_find_by_name(poolname);
881 if (!spa)
882 return (ENXIO);
883 rv = zfs_lookup_dataset(spa, dsname, &objid);
884 if (rv != 0)
885 return (rv);
886 rv = zfs_callback_dataset(spa, objid, zfs_belist_add);
888 /* Calculate and store the number of pages of BEs */
889 perpage = (ZFS_BE_LAST - ZFS_BE_FIRST + 1);
890 pages = (zfs_env_count / perpage) + ((zfs_env_count % perpage) > 0 ? 1 : 0);
891 snprintf(becount, 4, "%d", pages);
892 if (setenv("zfs_be_pages", becount, 1) != 0)
893 return (ENOMEM);
895 /* Roll over the page counter if it has exceeded the maximum */
896 currpage = strtol(getenv("zfs_be_currpage"), NULL, 10);
897 if (currpage > pages) {
898 if (setenv("zfs_be_currpage", "1", 1) != 0)
899 return (ENOMEM);
902 /* Populate the menu environment variables */
903 zfs_set_env();
905 /* Clean up the SLIST of ZFS BEs */
906 while (!SLIST_EMPTY(&zfs_be_head)) {
907 zfs_be = SLIST_FIRST(&zfs_be_head);
908 SLIST_REMOVE_HEAD(&zfs_be_head, entries);
909 free(zfs_be);
912 return (rv);
916 zfs_belist_add(const char *name, uint64_t value __unused)
919 /* Skip special datasets that start with a $ character */
920 if (strncmp(name, "$", 1) == 0) {
921 return (0);
923 /* Add the boot environment to the head of the SLIST */
924 zfs_be = malloc(sizeof(struct zfs_be_entry));
925 if (zfs_be == NULL) {
926 return (ENOMEM);
928 zfs_be->name = name;
929 SLIST_INSERT_HEAD(&zfs_be_head, zfs_be, entries);
930 zfs_env_count++;
932 return (0);
936 zfs_set_env(void)
938 char envname[32], envval[256];
939 char *beroot, *pagenum;
940 int rv, page, ctr;
942 beroot = getenv("zfs_be_root");
943 if (beroot == NULL) {
944 return (1);
947 pagenum = getenv("zfs_be_currpage");
948 if (pagenum != NULL) {
949 page = strtol(pagenum, NULL, 10);
950 } else {
951 page = 1;
954 ctr = 1;
955 rv = 0;
956 zfs_env_index = ZFS_BE_FIRST;
957 SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) {
958 /* Skip to the requested page number */
959 if (ctr <= ((ZFS_BE_LAST - ZFS_BE_FIRST + 1) * (page - 1))) {
960 ctr++;
961 continue;
964 snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index);
965 snprintf(envval, sizeof(envval), "%s", zfs_be->name);
966 rv = setenv(envname, envval, 1);
967 if (rv != 0) {
968 break;
971 snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index);
972 rv = setenv(envname, envval, 1);
973 if (rv != 0){
974 break;
977 snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index);
978 rv = setenv(envname, "set_bootenv", 1);
979 if (rv != 0){
980 break;
983 snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index);
984 snprintf(envval, sizeof(envval), "zfs:%s/%s", beroot, zfs_be->name);
985 rv = setenv(envname, envval, 1);
986 if (rv != 0){
987 break;
990 zfs_env_index++;
991 if (zfs_env_index > ZFS_BE_LAST) {
992 break;
997 for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) {
998 snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index);
999 (void)unsetenv(envname);
1000 snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index);
1001 (void)unsetenv(envname);
1002 snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index);
1003 (void)unsetenv(envname);
1004 snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index);
1005 (void)unsetenv(envname);
1008 return (rv);
1010 #endif