1 /*
2 * Copyright (c) 2007 Doug Rabson
3 * All rights reserved.
4 *
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.
13 *
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.
25 */
26
27 #include <sys/cdefs.h>
28
29 /*
30 * Stand-alone file reading package.
31 */
32
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>
43
44 #include "libzfs.h"
45
46 #include "zfsimpl.c"
47
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
51
52 static int zfs_open(const char *path, struct open_file *f);
53 static int zfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
54 static int zfs_close(struct open_file *f);
55 static int zfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
56 static off_t zfs_seek(struct open_file *f, off_t offset, int where);
57 static int zfs_stat(struct open_file *f, struct stat *sb);
58 static int zfs_readdir(struct open_file *f, struct dirent *d);
59
60 struct devsw zfs_dev;
61
62 struct fs_ops zfs_fsops = {
63 "zfs",
64 zfs_open,
65 zfs_close,
66 zfs_read,
67 zfs_write,
68 zfs_seek,
69 zfs_stat,
70 zfs_readdir
71 };
72
73 /*
74 * In-core open file.
75 */
76 struct file {
77 off_t f_seekp; /* seek pointer */
78 dnode_phys_t f_dnode;
79 uint64_t f_zap_type; /* zap type for readdir */
80 uint64_t f_num_leafs; /* number of fzap leaf blocks */
81 zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */
82 };
83
84 #ifdef __FreeBSD__
85 static int zfs_env_index;
86 static int zfs_env_count;
87 #endif
88
89 SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = SLIST_HEAD_INITIALIZER(zfs_be_head);
90 struct zfs_be_list *zfs_be_headp;
91 struct zfs_be_entry {
92 const char *name;
93 SLIST_ENTRY(zfs_be_entry) entries;
94 } *zfs_be, *zfs_be_tmp;
95
96 /*
97 * Open a file.
98 */
99 static int
zfs_open(const char * upath,struct open_file * f)100 zfs_open(const char *upath, struct open_file *f)
101 {
102 struct zfsmount *mount = (struct zfsmount *)f->f_devdata;
103 struct file *fp;
104 int rc;
105
106 if (f->f_dev != &zfs_dev)
107 return (EINVAL);
108
109 /* allocate file system specific data structure */
110 fp = malloc(sizeof(struct file));
111 bzero(fp, sizeof(struct file));
112 f->f_fsdata = (void *)fp;
113
114 rc = zfs_lookup(mount, upath, &fp->f_dnode);
115 fp->f_seekp = 0;
116 if (rc) {
117 f->f_fsdata = NULL;
118 free(fp);
119 }
120 return (rc);
121 }
122
123 static int
zfs_close(struct open_file * f)124 zfs_close(struct open_file *f)
125 {
126 struct file *fp = (struct file *)f->f_fsdata;
127
128 dnode_cache_obj = 0;
129 f->f_fsdata = (void *)0;
130 if (fp == (struct file *)0)
131 return (0);
132
133 free(fp);
134 return (0);
135 }
136
137 /*
138 * Copy a portion of a file into kernel memory.
139 * Cross block boundaries when necessary.
140 */
141 static int
zfs_read(struct open_file * f,void * start,size_t size,size_t * resid)142 zfs_read(struct open_file *f, void *start, size_t size, size_t *resid /* out */)
143 {
144 const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
145 struct file *fp = (struct file *)f->f_fsdata;
146 struct stat sb;
147 size_t n;
148 int rc;
149
150 rc = zfs_stat(f, &sb);
151 if (rc)
152 return (rc);
153 n = size;
154 if (fp->f_seekp + n > sb.st_size)
155 n = sb.st_size - fp->f_seekp;
156
157 rc = dnode_read(spa, &fp->f_dnode, fp->f_seekp, start, n);
158 if (rc)
159 return (rc);
160
161 if (0) {
162 int i;
163 for (i = 0; i < n; i++)
164 putchar(((char*) start)[i]);
165 }
166 fp->f_seekp += n;
167 if (resid)
168 *resid = size - n;
169
170 return (0);
171 }
172
173 /*
174 * Don't be silly - the bootstrap has no business writing anything.
175 */
176 static int
zfs_write(struct open_file * f,void * start,size_t size,size_t * resid)177 zfs_write(struct open_file *f, void *start, size_t size, size_t *resid /* out */)
178 {
179
180 return (EROFS);
181 }
182
183 static off_t
zfs_seek(struct open_file * f,off_t offset,int where)184 zfs_seek(struct open_file *f, off_t offset, int where)
185 {
186 struct file *fp = (struct file *)f->f_fsdata;
187
188 switch (where) {
189 case SEEK_SET:
190 fp->f_seekp = offset;
191 break;
192 case SEEK_CUR:
193 fp->f_seekp += offset;
194 break;
195 case SEEK_END:
196 {
197 struct stat sb;
198 int error;
199
200 error = zfs_stat(f, &sb);
201 if (error != 0) {
202 errno = error;
203 return (-1);
204 }
205 fp->f_seekp = sb.st_size - offset;
206 break;
207 }
208 default:
209 errno = EINVAL;
210 return (-1);
211 }
212 return (fp->f_seekp);
213 }
214
215 static int
zfs_stat(struct open_file * f,struct stat * sb)216 zfs_stat(struct open_file *f, struct stat *sb)
217 {
218 const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
219 struct file *fp = (struct file *)f->f_fsdata;
220
221 return (zfs_dnode_stat(spa, &fp->f_dnode, sb));
222 }
223
224 static int
zfs_readdir(struct open_file * f,struct dirent * d)225 zfs_readdir(struct open_file *f, struct dirent *d)
226 {
227 const spa_t *spa = ((struct zfsmount *)f->f_devdata)->spa;
228 struct file *fp = (struct file *)f->f_fsdata;
229 mzap_ent_phys_t mze;
230 struct stat sb;
231 size_t bsize = fp->f_dnode.dn_datablkszsec << SPA_MINBLOCKSHIFT;
232 int rc;
233
234 rc = zfs_stat(f, &sb);
235 if (rc)
236 return (rc);
237 if (!S_ISDIR(sb.st_mode))
238 return (ENOTDIR);
239
240 /*
241 * If this is the first read, get the zap type.
242 */
243 if (fp->f_seekp == 0) {
244 rc = dnode_read(spa, &fp->f_dnode,
245 0, &fp->f_zap_type, sizeof(fp->f_zap_type));
246 if (rc)
247 return (rc);
248
249 if (fp->f_zap_type == ZBT_MICRO) {
250 fp->f_seekp = offsetof(mzap_phys_t, mz_chunk);
251 } else {
252 rc = dnode_read(spa, &fp->f_dnode,
253 offsetof(zap_phys_t, zap_num_leafs),
254 &fp->f_num_leafs,
255 sizeof(fp->f_num_leafs));
256 if (rc)
257 return (rc);
258
259 fp->f_seekp = bsize;
260 fp->f_zap_leaf = (zap_leaf_phys_t *)malloc(bsize);
261 rc = dnode_read(spa, &fp->f_dnode,
262 fp->f_seekp,
263 fp->f_zap_leaf,
264 bsize);
265 if (rc)
266 return (rc);
267 }
268 }
269
270 if (fp->f_zap_type == ZBT_MICRO) {
271 mzap_next:
272 if (fp->f_seekp >= bsize)
273 return (ENOENT);
274
275 rc = dnode_read(spa, &fp->f_dnode,
276 fp->f_seekp, &mze, sizeof(mze));
277 if (rc)
278 return (rc);
279 fp->f_seekp += sizeof(mze);
280
281 if (!mze.mze_name[0])
282 goto mzap_next;
283
284 d->d_fileno = ZFS_DIRENT_OBJ(mze.mze_value);
285 d->d_type = ZFS_DIRENT_TYPE(mze.mze_value);
286 strcpy(d->d_name, mze.mze_name);
287 d->d_namlen = strlen(d->d_name);
288 return (0);
289 } else {
290 zap_leaf_t zl;
291 zap_leaf_chunk_t *zc, *nc;
292 int chunk;
293 size_t namelen;
294 char *p;
295 uint64_t value;
296
297 /*
298 * Initialise this so we can use the ZAP size
299 * calculating macros.
300 */
301 zl.l_bs = ilog2(bsize);
302 zl.l_phys = fp->f_zap_leaf;
303
304 /*
305 * Figure out which chunk we are currently looking at
306 * and consider seeking to the next leaf. We use the
307 * low bits of f_seekp as a simple chunk index.
308 */
309 fzap_next:
310 chunk = fp->f_seekp & (bsize - 1);
311 if (chunk == ZAP_LEAF_NUMCHUNKS(&zl)) {
312 fp->f_seekp = (fp->f_seekp & ~(bsize - 1)) + bsize;
313 chunk = 0;
314
315 /*
316 * Check for EOF and read the new leaf.
317 */
318 if (fp->f_seekp >= bsize * fp->f_num_leafs)
319 return (ENOENT);
320
321 rc = dnode_read(spa, &fp->f_dnode,
322 fp->f_seekp,
323 fp->f_zap_leaf,
324 bsize);
325 if (rc)
326 return (rc);
327 }
328
329 zc = &ZAP_LEAF_CHUNK(&zl, chunk);
330 fp->f_seekp++;
331 if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY)
332 goto fzap_next;
333
334 namelen = zc->l_entry.le_name_numints;
335 if (namelen > sizeof(d->d_name))
336 namelen = sizeof(d->d_name);
337
338 /*
339 * Paste the name back together.
340 */
341 nc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_name_chunk);
342 p = d->d_name;
343 while (namelen > 0) {
344 int len;
345 len = namelen;
346 if (len > ZAP_LEAF_ARRAY_BYTES)
347 len = ZAP_LEAF_ARRAY_BYTES;
348 memcpy(p, nc->l_array.la_array, len);
349 p += len;
350 namelen -= len;
351 nc = &ZAP_LEAF_CHUNK(&zl, nc->l_array.la_next);
352 }
353 d->d_name[sizeof(d->d_name) - 1] = 0;
354
355 /*
356 * Assume the first eight bytes of the value are
357 * a uint64_t.
358 */
359 value = fzap_leaf_value(&zl, zc);
360
361 d->d_fileno = ZFS_DIRENT_OBJ(value);
362 d->d_type = ZFS_DIRENT_TYPE(value);
363 d->d_namlen = strlen(d->d_name);
364
365 return (0);
366 }
367 }
368
369 static int
vdev_read(vdev_t * vdev,void * priv,off_t offset,void * buf,size_t bytes)370 vdev_read(vdev_t *vdev, void *priv, off_t offset, void *buf, size_t bytes)
371 {
372 int fd, ret;
373 size_t res, size, remainder, rb_size, blksz;
374 unsigned secsz;
375 off_t off;
376 char *bouncebuf, *rb_buf;
377
378 fd = (uintptr_t) priv;
379 bouncebuf = NULL;
380
381 ret = ioctl(fd, DIOCGSECTORSIZE, &secsz);
382 if (ret != 0)
383 return (ret);
384
385 off = offset / secsz;
386 remainder = offset % secsz;
387 if (lseek(fd, off * secsz, SEEK_SET) == -1)
388 return (errno);
389
390 rb_buf = buf;
391 rb_size = bytes;
392 size = roundup2(bytes + remainder, secsz);
393 blksz = size;
394 if (remainder != 0 || size != bytes) {
395 bouncebuf = zfs_alloc(secsz);
396 if (bouncebuf == NULL) {
397 printf("vdev_read: out of memory\n");
398 return (ENOMEM);
399 }
400 rb_buf = bouncebuf;
401 blksz = rb_size - remainder;
402 }
403
404 while (bytes > 0) {
405 res = read(fd, rb_buf, rb_size);
406 if (res != rb_size) {
407 ret = EIO;
408 goto error;
409 }
410 if (bytes < blksz)
411 blksz = bytes;
412 if (bouncebuf != NULL)
413 memcpy(buf, rb_buf + remainder, blksz);
414 buf = (void *)((uintptr_t)buf + blksz);
415 bytes -= blksz;
416 remainder = 0;
417 blksz = rb_size;
418 }
419
420 ret = 0;
421 error:
422 if (bouncebuf != NULL)
423 zfs_free(bouncebuf, secsz);
424 return (ret);
425 }
426
427 static int
zfs_dev_init(void)428 zfs_dev_init(void)
429 {
430 spa_t *spa;
431 spa_t *next;
432 spa_t *prev;
433
434 zfs_init();
435 if (archsw.arch_zfs_probe == NULL)
436 return (ENXIO);
437 archsw.arch_zfs_probe();
438
439 prev = NULL;
440 spa = STAILQ_FIRST(&zfs_pools);
441 while (spa != NULL) {
442 next = STAILQ_NEXT(spa, spa_link);
443 if (zfs_spa_init(spa)) {
444 if (prev == NULL)
445 STAILQ_REMOVE_HEAD(&zfs_pools, spa_link);
446 else
447 STAILQ_REMOVE_AFTER(&zfs_pools, prev, spa_link);
448 } else
449 prev = spa;
450 spa = next;
451 }
452 return (0);
453 }
454
455 struct zfs_probe_args {
456 int fd;
457 const char *devname;
458 uint64_t *pool_guid;
459 u_int secsz;
460 };
461
462 static int
zfs_diskread(void * arg,void * buf,size_t blocks,uint64_t offset)463 zfs_diskread(void *arg, void *buf, size_t blocks, uint64_t offset)
464 {
465 struct zfs_probe_args *ppa;
466
467 ppa = (struct zfs_probe_args *)arg;
468 return (vdev_read(NULL, (void *)(uintptr_t)ppa->fd,
469 offset * ppa->secsz, buf, blocks * ppa->secsz));
470 }
471
472 static int
zfs_probe(int fd,uint64_t * pool_guid)473 zfs_probe(int fd, uint64_t *pool_guid)
474 {
475 spa_t *spa;
476 int ret;
477
478 ret = vdev_probe(vdev_read, (void *)(uintptr_t)fd, &spa);
479 if (ret == 0 && pool_guid != NULL)
480 *pool_guid = spa->spa_guid;
481 return (ret);
482 }
483
484 static int
zfs_probe_partition(void * arg,const char * partname,const struct ptable_entry * part)485 zfs_probe_partition(void *arg, const char *partname,
486 const struct ptable_entry *part)
487 {
488 struct zfs_probe_args *ppa, pa;
489 struct ptable *table;
490 char devname[32];
491 int ret = 0;
492
493 /* filter out partitions *not* used by zfs */
494 switch (part->type) {
495 case PART_RESERVED: /* efi reserverd */
496 case PART_VTOC_BOOT: /* vtoc boot area */
497 case PART_VTOC_SWAP:
498 return (ret);
499 default:
500 break;;
501 }
502 ppa = (struct zfs_probe_args *)arg;
503 strncpy(devname, ppa->devname, strlen(ppa->devname) - 1);
504 devname[strlen(ppa->devname) - 1] = '\0';
505 sprintf(devname, "%s%s:", devname, partname);
506 pa.fd = open(devname, O_RDONLY);
507 if (pa.fd == -1)
508 return (ret);
509 ret = zfs_probe(pa.fd, ppa->pool_guid);
510 if (ret == 0)
511 return (ret);
512 if (part->type == PART_SOLARIS2) {
513 pa.devname = devname;
514 pa.pool_guid = ppa->pool_guid;
515 pa.secsz = ppa->secsz;
516 table = ptable_open(&pa, part->end - part->start + 1,
517 ppa->secsz, zfs_diskread);
518 if (table != NULL) {
519 ptable_iterate(table, &pa, zfs_probe_partition);
520 ptable_close(table);
521 }
522 }
523 close(pa.fd);
524 return (0);
525 }
526
527 int
zfs_probe_dev(const char * devname,uint64_t * pool_guid)528 zfs_probe_dev(const char *devname, uint64_t *pool_guid)
529 {
530 struct ptable *table;
531 struct zfs_probe_args pa;
532 uint64_t mediasz;
533 int ret;
534
535 if (pool_guid)
536 *pool_guid = 0;
537 pa.fd = open(devname, O_RDONLY);
538 if (pa.fd == -1)
539 return (ENXIO);
540 /* Probe the whole disk */
541 ret = zfs_probe(pa.fd, pool_guid);
542 if (ret == 0)
543 return (0);
544
545 /* Probe each partition */
546 ret = ioctl(pa.fd, DIOCGMEDIASIZE, &mediasz);
547 if (ret == 0)
548 ret = ioctl(pa.fd, DIOCGSECTORSIZE, &pa.secsz);
549 if (ret == 0) {
550 pa.devname = devname;
551 pa.pool_guid = pool_guid;
552 table = ptable_open(&pa, mediasz / pa.secsz, pa.secsz,
553 zfs_diskread);
554 if (table != NULL) {
555 ptable_iterate(table, &pa, zfs_probe_partition);
556 ptable_close(table);
557 }
558 }
559 close(pa.fd);
560 if (pool_guid && *pool_guid == 0)
561 ret = ENXIO;
562 return (ret);
563 }
564
565 /*
566 * Print information about ZFS pools
567 */
568 static int
zfs_dev_print(int verbose)569 zfs_dev_print(int verbose)
570 {
571 spa_t *spa;
572 char line[80];
573 int ret = 0;
574
575 if (STAILQ_EMPTY(&zfs_pools))
576 return (0);
577
578 printf("%s devices:", zfs_dev.dv_name);
579 if ((ret = pager_output("\n")) != 0)
580 return (ret);
581
582 if (verbose) {
583 return (spa_all_status());
584 }
585 STAILQ_FOREACH(spa, &zfs_pools, spa_link) {
586 sprintf(line, " zfs:%s\n", spa->spa_name);
587 ret = pager_output(line);
588 if (ret != 0)
589 break;
590 }
591 return (ret);
592 }
593
594 /*
595 * Attempt to open the pool described by (dev) for use by (f).
596 */
597 static int
zfs_dev_open(struct open_file * f,...)598 zfs_dev_open(struct open_file *f, ...)
599 {
600 va_list args;
601 struct zfs_devdesc *dev;
602 struct zfsmount *mount;
603 spa_t *spa;
604 int rv;
605
606 va_start(args, f);
607 dev = va_arg(args, struct zfs_devdesc *);
608 va_end(args);
609
610 if (dev->pool_guid == 0)
611 spa = STAILQ_FIRST(&zfs_pools);
612 else
613 spa = spa_find_by_guid(dev->pool_guid);
614 if (!spa)
615 return (ENXIO);
616 mount = malloc(sizeof(*mount));
617 rv = zfs_mount(spa, dev->root_guid, mount);
618 if (rv != 0) {
619 free(mount);
620 return (rv);
621 }
622 if (mount->objset.os_type != DMU_OST_ZFS) {
623 printf("Unexpected object set type %ju\n",
624 (uintmax_t)mount->objset.os_type);
625 free(mount);
626 return (EIO);
627 }
628 f->f_devdata = mount;
629 free(dev);
630 return (0);
631 }
632
633 static int
zfs_dev_close(struct open_file * f)634 zfs_dev_close(struct open_file *f)
635 {
636
637 free(f->f_devdata);
638 f->f_devdata = NULL;
639 return (0);
640 }
641
642 static int
zfs_dev_strategy(void * devdata,int rw,daddr_t dblk,size_t size,char * buf,size_t * rsize)643 zfs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
644 char *buf, size_t *rsize)
645 {
646
647 return (ENOSYS);
648 }
649
650 struct devsw zfs_dev = {
651 .dv_name = "zfs",
652 .dv_type = DEVT_ZFS,
653 .dv_init = zfs_dev_init,
654 .dv_strategy = zfs_dev_strategy,
655 .dv_open = zfs_dev_open,
656 .dv_close = zfs_dev_close,
657 .dv_ioctl = noioctl,
658 .dv_print = zfs_dev_print,
659 .dv_cleanup = NULL
660 };
661
662 int
zfs_parsedev(struct zfs_devdesc * dev,const char * devspec,const char ** path)663 zfs_parsedev(struct zfs_devdesc *dev, const char *devspec, const char **path)
664 {
665 static char rootname[ZFS_MAXNAMELEN];
666 static char poolname[ZFS_MAXNAMELEN];
667 spa_t *spa;
668 const char *end;
669 const char *np;
670 const char *sep;
671 int rv;
672
673 np = devspec;
674 if (*np != ':')
675 return (EINVAL);
676 np++;
677 end = strchr(np, ':');
678 if (end == NULL)
679 return (EINVAL);
680 sep = strchr(np, '/');
681 if (sep == NULL || sep >= end)
682 sep = end;
683 memcpy(poolname, np, sep - np);
684 poolname[sep - np] = '\0';
685 if (sep < end) {
686 sep++;
687 memcpy(rootname, sep, end - sep);
688 rootname[end - sep] = '\0';
689 }
690 else
691 rootname[0] = '\0';
692
693 spa = spa_find_by_name(poolname);
694 if (!spa)
695 return (ENXIO);
696 dev->pool_guid = spa->spa_guid;
697 rv = zfs_lookup_dataset(spa, rootname, &dev->root_guid);
698 if (rv != 0)
699 return (rv);
700 if (path != NULL)
701 *path = (*end == '\0') ? end : end + 1;
702 dev->d_dev = &zfs_dev;
703 dev->d_type = zfs_dev.dv_type;
704 return (0);
705 }
706
707 char *
zfs_bootfs(void * zdev)708 zfs_bootfs(void *zdev)
709 {
710 static char rootname[ZFS_MAXNAMELEN];
711 static char buf[2 * ZFS_MAXNAMELEN];
712 struct zfs_devdesc *dev = (struct zfs_devdesc *)zdev;
713 uint64_t objnum;
714 spa_t *spa;
715 vdev_t *vdev;
716 vdev_t *kid;
717 int n;
718
719 buf[0] = '\0';
720 if (dev->d_type != DEVT_ZFS)
721 return (buf);
722
723 spa = spa_find_by_guid(dev->pool_guid);
724 if (spa == NULL) {
725 printf("ZFS: can't find pool by guid\n");
726 return (buf);
727 }
728 if (zfs_rlookup(spa, dev->root_guid, rootname)) {
729 printf("ZFS: can't find filesystem by guid\n");
730 return (buf);
731 }
732 if (zfs_lookup_dataset(spa, rootname, &objnum)) {
733 printf("ZFS: can't find filesystem by name\n");
734 return (buf);
735 }
736
737 STAILQ_FOREACH(vdev, &spa->spa_vdevs, v_childlink) {
738 STAILQ_FOREACH(kid, &vdev->v_children, v_childlink) {
739 /* use this kid? */
740 if (kid->v_state == VDEV_STATE_HEALTHY &&
741 kid->v_phys_path != NULL) {
742 break;
743 }
744 }
745 if (kid != NULL) {
746 vdev = kid;
747 break;
748 }
749 if (vdev->v_state == VDEV_STATE_HEALTHY &&
750 vdev->v_phys_path != NULL) {
751 break;
752 }
753 }
754
755 /*
756 * since this pool was used to read in the kernel and boot archive,
757 * there has to be at least one healthy vdev, therefore vdev
758 * can not be NULL.
759 */
760 /* Set the environment. */
761 snprintf(buf, sizeof (buf), "%s/%llu", spa->spa_name,
762 (unsigned long long)objnum);
763 setenv("zfs-bootfs", buf, 1);
764 if (vdev->v_phys_path != NULL)
765 setenv("bootpath", vdev->v_phys_path, 1);
766 if (vdev->v_devid != NULL)
767 setenv("diskdevid", vdev->v_devid, 1);
768
769 /*
770 * Build the command line string. Once our kernel will read
771 * the environment and we can stop caring about old kernels,
772 * we can remove this part.
773 */
774 snprintf(buf, sizeof(buf), "zfs-bootfs=%s/%llu", spa->spa_name,
775 (unsigned long long)objnum);
776 n = strlen(buf);
777 if (vdev->v_phys_path != NULL) {
778 snprintf(buf+n, sizeof (buf) - n, ",bootpath=\"%s\"",
779 vdev->v_phys_path);
780 n = strlen(buf);
781 }
782 if (vdev->v_devid != NULL) {
783 snprintf(buf+n, sizeof (buf) - n, ",diskdevid=\"%s\"",
784 vdev->v_devid);
785 }
786 return (buf);
787 }
788
789 char *
zfs_fmtdev(void * vdev)790 zfs_fmtdev(void *vdev)
791 {
792 static char rootname[ZFS_MAXNAMELEN];
793 static char buf[2 * ZFS_MAXNAMELEN + 8];
794 struct zfs_devdesc *dev = (struct zfs_devdesc *)vdev;
795 spa_t *spa;
796
797 buf[0] = '\0';
798 if (dev->d_type != DEVT_ZFS)
799 return (buf);
800
801 if (dev->pool_guid == 0) {
802 spa = STAILQ_FIRST(&zfs_pools);
803 dev->pool_guid = spa->spa_guid;
804 } else
805 spa = spa_find_by_guid(dev->pool_guid);
806 if (spa == NULL) {
807 printf("ZFS: can't find pool by guid\n");
808 return (buf);
809 }
810 if (dev->root_guid == 0 && zfs_get_root(spa, &dev->root_guid)) {
811 printf("ZFS: can't find root filesystem\n");
812 return (buf);
813 }
814 if (zfs_rlookup(spa, dev->root_guid, rootname)) {
815 printf("ZFS: can't find filesystem by guid\n");
816 return (buf);
817 }
818
819 if (rootname[0] == '\0')
820 sprintf(buf, "%s:%s:", dev->d_dev->dv_name, spa->spa_name);
821 else
822 sprintf(buf, "%s:%s/%s:", dev->d_dev->dv_name, spa->spa_name,
823 rootname);
824 return (buf);
825 }
826
827 int
zfs_list(const char * name)828 zfs_list(const char *name)
829 {
830 static char poolname[ZFS_MAXNAMELEN];
831 uint64_t objid;
832 spa_t *spa;
833 const char *dsname;
834 int len;
835 int rv;
836
837 len = strlen(name);
838 dsname = strchr(name, '/');
839 if (dsname != NULL) {
840 len = dsname - name;
841 dsname++;
842 } else
843 dsname = "";
844 memcpy(poolname, name, len);
845 poolname[len] = '\0';
846
847 spa = spa_find_by_name(poolname);
848 if (!spa)
849 return (ENXIO);
850 rv = zfs_lookup_dataset(spa, dsname, &objid);
851 if (rv != 0)
852 return (rv);
853
854 return (zfs_list_dataset(spa, objid));
855 }
856
857 #ifdef __FreeBSD__
858 void
init_zfs_bootenv(char * currdev)859 init_zfs_bootenv(char *currdev)
860 {
861 char *beroot;
862
863 if (strlen(currdev) == 0)
864 return;
865 if(strncmp(currdev, "zfs:", 4) != 0)
866 return;
867 /* Remove the trailing : */
868 currdev[strlen(currdev) - 1] = '\0';
869 setenv("zfs_be_active", currdev, 1);
870 setenv("zfs_be_currpage", "1", 1);
871 /* Forward past zfs: */
872 currdev = strchr(currdev, ':');
873 currdev++;
874 /* Remove the last element (current bootenv) */
875 beroot = strrchr(currdev, '/');
876 if (beroot != NULL)
877 beroot[0] = '\0';
878 beroot = currdev;
879 setenv("zfs_be_root", beroot, 1);
880 }
881
882 int
zfs_bootenv(const char * name)883 zfs_bootenv(const char *name)
884 {
885 static char poolname[ZFS_MAXNAMELEN], *dsname, *root;
886 char becount[4];
887 uint64_t objid;
888 spa_t *spa;
889 int len, rv, pages, perpage, currpage;
890
891 if (name == NULL)
892 return (EINVAL);
893 if ((root = getenv("zfs_be_root")) == NULL)
894 return (EINVAL);
895
896 if (strcmp(name, root) != 0) {
897 if (setenv("zfs_be_root", name, 1) != 0)
898 return (ENOMEM);
899 }
900
901 SLIST_INIT(&zfs_be_head);
902 zfs_env_count = 0;
903 len = strlen(name);
904 dsname = strchr(name, '/');
905 if (dsname != NULL) {
906 len = dsname - name;
907 dsname++;
908 } else
909 dsname = "";
910 memcpy(poolname, name, len);
911 poolname[len] = '\0';
912
913 spa = spa_find_by_name(poolname);
914 if (!spa)
915 return (ENXIO);
916 rv = zfs_lookup_dataset(spa, dsname, &objid);
917 if (rv != 0)
918 return (rv);
919 rv = zfs_callback_dataset(spa, objid, zfs_belist_add);
920
921 /* Calculate and store the number of pages of BEs */
922 perpage = (ZFS_BE_LAST - ZFS_BE_FIRST + 1);
923 pages = (zfs_env_count / perpage) + ((zfs_env_count % perpage) > 0 ? 1 : 0);
924 snprintf(becount, 4, "%d", pages);
925 if (setenv("zfs_be_pages", becount, 1) != 0)
926 return (ENOMEM);
927
928 /* Roll over the page counter if it has exceeded the maximum */
929 currpage = strtol(getenv("zfs_be_currpage"), NULL, 10);
930 if (currpage > pages) {
931 if (setenv("zfs_be_currpage", "1", 1) != 0)
932 return (ENOMEM);
933 }
934
935 /* Populate the menu environment variables */
936 zfs_set_env();
937
938 /* Clean up the SLIST of ZFS BEs */
939 while (!SLIST_EMPTY(&zfs_be_head)) {
940 zfs_be = SLIST_FIRST(&zfs_be_head);
941 SLIST_REMOVE_HEAD(&zfs_be_head, entries);
942 free(zfs_be);
943 }
944
945 return (rv);
946 }
947
948 int
zfs_belist_add(const char * name,uint64_t value __unused)949 zfs_belist_add(const char *name, uint64_t value __unused)
950 {
951
952 /* Skip special datasets that start with a $ character */
953 if (strncmp(name, "$", 1) == 0) {
954 return (0);
955 }
956 /* Add the boot environment to the head of the SLIST */
957 zfs_be = malloc(sizeof(struct zfs_be_entry));
958 if (zfs_be == NULL) {
959 return (ENOMEM);
960 }
961 zfs_be->name = name;
962 SLIST_INSERT_HEAD(&zfs_be_head, zfs_be, entries);
963 zfs_env_count++;
964
965 return (0);
966 }
967
968 int
zfs_set_env(void)969 zfs_set_env(void)
970 {
971 char envname[32], envval[256];
972 char *beroot, *pagenum;
973 int rv, page, ctr;
974
975 beroot = getenv("zfs_be_root");
976 if (beroot == NULL) {
977 return (1);
978 }
979
980 pagenum = getenv("zfs_be_currpage");
981 if (pagenum != NULL) {
982 page = strtol(pagenum, NULL, 10);
983 } else {
984 page = 1;
985 }
986
987 ctr = 1;
988 rv = 0;
989 zfs_env_index = ZFS_BE_FIRST;
990 SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) {
991 /* Skip to the requested page number */
992 if (ctr <= ((ZFS_BE_LAST - ZFS_BE_FIRST + 1) * (page - 1))) {
993 ctr++;
994 continue;
995 }
996
997 snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index);
998 snprintf(envval, sizeof(envval), "%s", zfs_be->name);
999 rv = setenv(envname, envval, 1);
1000 if (rv != 0) {
1001 break;
1002 }
1003
1004 snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index);
1005 rv = setenv(envname, envval, 1);
1006 if (rv != 0){
1007 break;
1008 }
1009
1010 snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index);
1011 rv = setenv(envname, "set_bootenv", 1);
1012 if (rv != 0){
1013 break;
1014 }
1015
1016 snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index);
1017 snprintf(envval, sizeof(envval), "zfs:%s/%s", beroot, zfs_be->name);
1018 rv = setenv(envname, envval, 1);
1019 if (rv != 0){
1020 break;
1021 }
1022
1023 zfs_env_index++;
1024 if (zfs_env_index > ZFS_BE_LAST) {
1025 break;
1026 }
1027
1028 }
1029
1030 for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) {
1031 snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index);
1032 (void)unsetenv(envname);
1033 snprintf(envname, sizeof(envname), "bootenvansi_caption[%d]", zfs_env_index);
1034 (void)unsetenv(envname);
1035 snprintf(envname, sizeof(envname), "bootenvmenu_command[%d]", zfs_env_index);
1036 (void)unsetenv(envname);
1037 snprintf(envname, sizeof(envname), "bootenv_root[%d]", zfs_env_index);
1038 (void)unsetenv(envname);
1039 }
1040
1041 return (rv);
1042 }
1043 #endif
1044