diff options
author | Mariusz Zaborski <oshogbo@FreeBSD.org> | 2020-08-18 19:48:04 +0000 |
---|---|---|
committer | Mariusz Zaborski <oshogbo@FreeBSD.org> | 2020-08-18 19:48:04 +0000 |
commit | 277f38abffc6a8160b5044128b5b2c620fbb970c (patch) | |
tree | 3bab41fe37fb14ef05b8dfb2b0b1235a2a47ffce /stand | |
parent | ad7a0eb189e2aba52f2dcc6b47642a84365b90dd (diff) | |
download | src-277f38abffc6a8160b5044128b5b2c620fbb970c.tar.gz src-277f38abffc6a8160b5044128b5b2c620fbb970c.zip |
Notes
Diffstat (limited to 'stand')
-rw-r--r-- | stand/efi/loader/main.c | 2 | ||||
-rw-r--r-- | stand/i386/loader/main.c | 2 | ||||
-rw-r--r-- | stand/libsa/zfs/libzfs.h | 2 | ||||
-rw-r--r-- | stand/libsa/zfs/zfs.c | 138 | ||||
-rw-r--r-- | stand/libsa/zfs/zfsimpl.c | 72 | ||||
-rw-r--r-- | stand/lua/core.lua | 47 | ||||
-rw-r--r-- | stand/lua/menu.lua | 30 |
7 files changed, 212 insertions, 81 deletions
diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c index 8ba03141c95b..e81a01de8b1e 100644 --- a/stand/efi/loader/main.c +++ b/stand/efi/loader/main.c @@ -269,7 +269,7 @@ probe_zfs_currdev(uint64_t guid) currdev.root_guid = 0; set_currdev_devdesc((struct devdesc *)&currdev); devname = efi_fmtdev(&currdev); - init_zfs_bootenv(devname); + init_zfs_boot_options(devname); rv = sanity_check_currdev(); if (rv) { diff --git a/stand/i386/loader/main.c b/stand/i386/loader/main.c index 377075f100ee..d7c23ba807ad 100644 --- a/stand/i386/loader/main.c +++ b/stand/i386/loader/main.c @@ -363,7 +363,7 @@ extract_currdev(void) #ifdef LOADER_ZFS_SUPPORT if (new_currdev.dd.d_dev->dv_type == DEVT_ZFS) - init_zfs_bootenv(zfs_fmtdev(&new_currdev)); + init_zfs_boot_options(zfs_fmtdev(&new_currdev)); #endif env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev), diff --git a/stand/libsa/zfs/libzfs.h b/stand/libsa/zfs/libzfs.h index a5df0c1b8255..e9eb717f0cb0 100644 --- a/stand/libsa/zfs/libzfs.h +++ b/stand/libsa/zfs/libzfs.h @@ -123,7 +123,7 @@ int zfs_nextboot(void *vdev, char *buf, size_t size); int zfs_probe_dev(const char *devname, uint64_t *pool_guid); int zfs_list(const char *name); uint64_t ldi_get_size(void *); -void init_zfs_bootenv(const char *currdev); +void init_zfs_boot_options(const char *currdev); int zfs_bootenv(const char *name); int zfs_belist_add(const char *name, uint64_t __unused); int zfs_set_env(void); diff --git a/stand/libsa/zfs/zfs.c b/stand/libsa/zfs/zfs.c index fd7b6cbfdeba..6bceb1ee5270 100644 --- a/stand/libsa/zfs/zfs.c +++ b/stand/libsa/zfs/zfs.c @@ -60,7 +60,10 @@ static off_t zfs_seek(struct open_file *f, off_t offset, int where); static int zfs_stat(struct open_file *f, struct stat *sb); static int zfs_readdir(struct open_file *f, struct dirent *d); -static void zfs_bootenv_initial(const char *); +static void zfs_bootenv_initial(const char *envname, spa_t *spa, + const char *name, const char *dsname, int checkpoint); +static void zfs_checkpoints_initial(spa_t *spa, const char *name, + const char *dsname); struct devsw zfs_dev; @@ -1077,15 +1080,15 @@ zfs_fmtdev(void *vdev) return (buf); } -int -zfs_list(const char *name) +static int +split_devname(const char *name, char *poolname, size_t size, + const char **dsnamep) { - static char poolname[ZFS_MAXNAMELEN]; - uint64_t objid; - spa_t *spa; - const char *dsname; - int len; - int rv; + const char *dsname; + size_t len; + + ASSERT(name != NULL); + ASSERT(poolname != NULL); len = strlen(name); dsname = strchr(name, '/'); @@ -1094,8 +1097,29 @@ zfs_list(const char *name) dsname++; } else dsname = ""; - memcpy(poolname, name, len); - poolname[len] = '\0'; + + if (len + 1 > size) + return (EINVAL); + + strlcpy(poolname, name, len + 1); + + if (dsnamep != NULL) + *dsnamep = dsname; + + return (0); +} + +int +zfs_list(const char *name) +{ + static char poolname[ZFS_MAXNAMELEN]; + uint64_t objid; + spa_t *spa; + const char *dsname; + int rv; + + if (split_devname(name, poolname, sizeof(poolname), &dsname) != 0) + return (EINVAL); spa = spa_find_by_name(poolname); if (!spa) @@ -1108,10 +1132,13 @@ zfs_list(const char *name) } void -init_zfs_bootenv(const char *currdev_in) +init_zfs_boot_options(const char *currdev_in) { + char poolname[ZFS_MAXNAMELEN]; char *beroot, *currdev; + spa_t *spa; int currdev_len; + const char *dsname; currdev = NULL; currdev_len = strlen(currdev_in); @@ -1124,6 +1151,7 @@ init_zfs_bootenv(const char *currdev_in) return; /* Remove the trailing : */ currdev[currdev_len - 1] = '\0'; + setenv("zfs_be_active", currdev, 1); setenv("zfs_be_currpage", "1", 1); /* Remove the last element (current bootenv) */ @@ -1132,49 +1160,71 @@ init_zfs_bootenv(const char *currdev_in) beroot[0] = '\0'; beroot = strchr(currdev, ':') + 1; setenv("zfs_be_root", beroot, 1); - zfs_bootenv_initial(beroot); + + if (split_devname(beroot, poolname, sizeof(poolname), &dsname) != 0) + return; + + spa = spa_find_by_name(poolname); + if (spa == NULL) + return; + + zfs_bootenv_initial("bootenvs", spa, beroot, dsname, 0); + zfs_checkpoints_initial(spa, beroot, dsname); + free(currdev); } static void -zfs_bootenv_initial(const char *name) +zfs_checkpoints_initial(spa_t *spa, const char *name, const char *dsname) { - char poolname[ZFS_MAXNAMELEN], *dsname; - char envname[32], envval[256]; + char envname[32]; + + if (spa->spa_uberblock_checkpoint.ub_checkpoint_txg != 0) { + snprintf(envname, sizeof(envname), "zpool_checkpoint"); + setenv(envname, name, 1); + + spa->spa_uberblock = &spa->spa_uberblock_checkpoint; + spa->spa_mos = &spa->spa_mos_checkpoint; + + zfs_bootenv_initial("bootenvs_check", spa, name, dsname, 1); + + spa->spa_uberblock = &spa->spa_uberblock_master; + spa->spa_mos = &spa->spa_mos_master; + } +} + +static void +zfs_bootenv_initial(const char *envprefix, spa_t *spa, const char *rootname, + const char *dsname, int checkpoint) +{ + char envname[32], envval[256]; uint64_t objid; - spa_t *spa; - int bootenvs_idx, len, rv; + int bootenvs_idx, rv; SLIST_INIT(&zfs_be_head); zfs_env_count = 0; - len = strlen(name); - dsname = strchr(name, '/'); - if (dsname != NULL) { - len = dsname - name; - dsname++; - } else - dsname = ""; - strlcpy(poolname, name, len + 1); - spa = spa_find_by_name(poolname); - if (spa == NULL) - return; + rv = zfs_lookup_dataset(spa, dsname, &objid); if (rv != 0) return; + rv = zfs_callback_dataset(spa, objid, zfs_belist_add); bootenvs_idx = 0; /* Populate the initial environment variables */ SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) { /* Enumerate all bootenvs for general usage */ - snprintf(envname, sizeof(envname), "bootenvs[%d]", bootenvs_idx); - snprintf(envval, sizeof(envval), "zfs:%s/%s", name, zfs_be->name); + snprintf(envname, sizeof(envname), "%s[%d]", + envprefix, bootenvs_idx); + snprintf(envval, sizeof(envval), "zfs:%s%s/%s", + checkpoint ? "!" : "", rootname, zfs_be->name); rv = setenv(envname, envval, 1); if (rv != 0) break; bootenvs_idx++; } + snprintf(envname, sizeof(envname), "%s_count", envprefix); snprintf(envval, sizeof(envval), "%d", bootenvs_idx); - setenv("bootenvs_count", envval, 1); + setenv(envname, envval, 1); /* Clean up the SLIST of ZFS BEs */ while (!SLIST_EMPTY(&zfs_be_head)) { @@ -1183,19 +1233,17 @@ zfs_bootenv_initial(const char *name) free(zfs_be->name); free(zfs_be); } - - return; - } int zfs_bootenv(const char *name) { - static char poolname[ZFS_MAXNAMELEN], *dsname, *root; + char poolname[ZFS_MAXNAMELEN], *root; + const char *dsname; char becount[4]; uint64_t objid; spa_t *spa; - int len, rv, pages, perpage, currpage; + int rv, pages, perpage, currpage; if (name == NULL) return (EINVAL); @@ -1209,15 +1257,9 @@ zfs_bootenv(const char *name) SLIST_INIT(&zfs_be_head); zfs_env_count = 0; - len = strlen(name); - dsname = strchr(name, '/'); - if (dsname != NULL) { - len = dsname - name; - dsname++; - } else - dsname = ""; - memcpy(poolname, name, len); - poolname[len] = '\0'; + + if (split_devname(name, poolname, sizeof(poolname), &dsname) != 0) + return (EINVAL); spa = spa_find_by_name(poolname); if (!spa) @@ -1307,7 +1349,7 @@ zfs_set_env(void) ctr++; continue; } - + snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); snprintf(envval, sizeof(envval), "%s", zfs_be->name); rv = setenv(envname, envval, 1); @@ -1340,7 +1382,7 @@ zfs_set_env(void) } } - + for (; zfs_env_index <= ZFS_BE_LAST; zfs_env_index++) { snprintf(envname, sizeof(envname), "bootenvmenu_caption[%d]", zfs_env_index); (void)unsetenv(envname); diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c index 0e97e06245b3..152c0459c2be 100644 --- a/stand/libsa/zfs/zfsimpl.c +++ b/stand/libsa/zfs/zfsimpl.c @@ -699,7 +699,7 @@ vdev_indirect_read(vdev_t *vdev, const blkptr_t *bp, void *buf, vic = &vdev->vdev_indirect_config; vdev->v_mapping = vdev_indirect_mapping_open(spa, - &spa->spa_mos, vic->vic_mapping_object); + spa->spa_mos, vic->vic_mapping_object); } vdev_indirect_remap(vdev, offset, bytes, &zio); @@ -1347,6 +1347,8 @@ spa_create(uint64_t guid, const char *name) free(spa); return (NULL); } + spa->spa_uberblock = &spa->spa_uberblock_master; + spa->spa_mos = &spa->spa_mos_master; spa->spa_guid = guid; spa->spa_root_vdev = vdev_create(guid, NULL); if (spa->spa_root_vdev == NULL) { @@ -1883,7 +1885,7 @@ vdev_probe(vdev_phys_read_t *_read, void *read_priv, spa_t **spap) * the best uberblock and then we can actually access * the contents of the pool. */ - vdev_uberblock_load(vdev, &spa->spa_uberblock); + vdev_uberblock_load(vdev, spa->spa_uberblock); if (spap != NULL) *spap = spa; @@ -2409,8 +2411,9 @@ fzap_lookup(const spa_t *spa, const dnode_phys_t *dnode, zap_phys_t *zh, if (zh->zap_magic != ZAP_MAGIC) return (EIO); - if ((rc = fzap_check_size(integer_size, num_integers)) != 0) + if ((rc = fzap_check_size(integer_size, num_integers)) != 0) { return (rc); + } z.zap_block_shift = ilog2(bsize); z.zap_phys = zh; @@ -2766,7 +2769,7 @@ zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result) p = &name[sizeof(name) - 1]; *p = '\0'; - if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { + if (objset_get_dnode(spa, spa->spa_mos, objnum, &dataset)) { printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); return (EIO); } @@ -2774,7 +2777,7 @@ zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result) dir_obj = ds->ds_dir_obj; for (;;) { - if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir) != 0) + if (objset_get_dnode(spa, spa->spa_mos, dir_obj, &dir) != 0) return (EIO); dd = (dsl_dir_phys_t *)&dir.dn_bonus; @@ -2783,12 +2786,12 @@ zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result) if (parent_obj == 0) break; - if (objset_get_dnode(spa, &spa->spa_mos, parent_obj, + if (objset_get_dnode(spa, spa->spa_mos, parent_obj, &parent) != 0) return (EIO); dd = (dsl_dir_phys_t *)&parent.dn_bonus; child_dir_zapobj = dd->dd_child_dir_zapobj; - if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, + if (objset_get_dnode(spa, spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) return (EIO); if (zap_rlookup(spa, &child_dir_zap, component, dir_obj) != 0) @@ -2820,7 +2823,7 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum) dsl_dir_phys_t *dd; const char *p, *q; - if (objset_get_dnode(spa, &spa->spa_mos, + if (objset_get_dnode(spa, spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, &dir)) return (EIO); if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof (dir_obj), @@ -2829,7 +2832,7 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum) p = name; for (;;) { - if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) + if (objset_get_dnode(spa, spa->spa_mos, dir_obj, &dir)) return (EIO); dd = (dsl_dir_phys_t *)&dir.dn_bonus; @@ -2850,7 +2853,7 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum) } child_dir_zapobj = dd->dd_child_dir_zapobj; - if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, + if (objset_get_dnode(spa, spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) return (EIO); @@ -2873,21 +2876,21 @@ zfs_list_dataset(const spa_t *spa, uint64_t objnum/*, int pos, char *entry*/) dsl_dataset_phys_t *ds; dsl_dir_phys_t *dd; - if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { + if (objset_get_dnode(spa, spa->spa_mos, objnum, &dataset)) { printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); return (EIO); } ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; dir_obj = ds->ds_dir_obj; - if (objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir)) { + if (objset_get_dnode(spa, spa->spa_mos, dir_obj, &dir)) { printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); return (EIO); } dd = (dsl_dir_phys_t *)&dir.dn_bonus; child_dir_zapobj = dd->dd_child_dir_zapobj; - if (objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, + if (objset_get_dnode(spa, spa->spa_mos, child_dir_zapobj, &child_dir_zap) != 0) { printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); return (EIO); @@ -2908,7 +2911,7 @@ zfs_callback_dataset(const spa_t *spa, uint64_t objnum, size_t size; int err; - err = objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset); + err = objset_get_dnode(spa, spa->spa_mos, objnum, &dataset); if (err != 0) { printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); return (err); @@ -2916,7 +2919,7 @@ zfs_callback_dataset(const spa_t *spa, uint64_t objnum, ds = (dsl_dataset_phys_t *)&dataset.dn_bonus; dir_obj = ds->ds_dir_obj; - err = objset_get_dnode(spa, &spa->spa_mos, dir_obj, &dir); + err = objset_get_dnode(spa, spa->spa_mos, dir_obj, &dir); if (err != 0) { printf("ZFS: can't find dirobj %ju\n", (uintmax_t)dir_obj); return (err); @@ -2924,7 +2927,7 @@ zfs_callback_dataset(const spa_t *spa, uint64_t objnum, dd = (dsl_dir_phys_t *)&dir.dn_bonus; child_dir_zapobj = dd->dd_child_dir_zapobj; - err = objset_get_dnode(spa, &spa->spa_mos, child_dir_zapobj, + err = objset_get_dnode(spa, spa->spa_mos, child_dir_zapobj, &child_dir_zap); if (err != 0) { printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj); @@ -2962,7 +2965,7 @@ zfs_mount_dataset(const spa_t *spa, uint64_t objnum, objset_phys_t *objset) dnode_phys_t dataset; dsl_dataset_phys_t *ds; - if (objset_get_dnode(spa, &spa->spa_mos, objnum, &dataset)) { + if (objset_get_dnode(spa, spa->spa_mos, objnum, &dataset)) { printf("ZFS: can't find dataset %ju\n", (uintmax_t)objnum); return (EIO); } @@ -2992,7 +2995,7 @@ zfs_get_root(const spa_t *spa, uint64_t *objid) /* * Start with the MOS directory object. */ - if (objset_get_dnode(spa, &spa->spa_mos, + if (objset_get_dnode(spa, spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, &dir)) { printf("ZFS: can't read MOS object directory\n"); return (EIO); @@ -3003,7 +3006,7 @@ zfs_get_root(const spa_t *spa, uint64_t *objid) */ if (zap_lookup(spa, &dir, DMU_POOL_PROPS, sizeof(props), 1, &props) == 0 && - objset_get_dnode(spa, &spa->spa_mos, props, &propdir) == 0 && + objset_get_dnode(spa, spa->spa_mos, props, &propdir) == 0 && zap_lookup(spa, &propdir, "bootfs", sizeof(bootfs), 1, &bootfs) == 0 && bootfs != 0) { *objid = bootfs; @@ -3014,7 +3017,7 @@ zfs_get_root(const spa_t *spa, uint64_t *objid) */ if (zap_lookup(spa, &dir, DMU_POOL_ROOT_DATASET, sizeof(root), 1, &root) || - objset_get_dnode(spa, &spa->spa_mos, root, &dir)) { + objset_get_dnode(spa, spa->spa_mos, root, &dir)) { printf("ZFS: can't find root dsl_dir\n"); return (EIO); } @@ -3085,7 +3088,7 @@ check_mos_features(const spa_t *spa) size_t size; int rc; - if ((rc = objset_get_dnode(spa, &spa->spa_mos, DMU_OT_OBJECT_DIRECTORY, + if ((rc = objset_get_dnode(spa, spa->spa_mos, DMU_OT_OBJECT_DIRECTORY, &dir)) != 0) return (rc); if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ, @@ -3097,7 +3100,7 @@ check_mos_features(const spa_t *spa) return (0); } - if ((rc = objset_get_dnode(spa, &spa->spa_mos, objnum, &dir)) != 0) + if ((rc = objset_get_dnode(spa, spa->spa_mos, objnum, &dir)) != 0) return (rc); if (dir.dn_type != DMU_OTN_ZAP_METADATA) @@ -3131,7 +3134,7 @@ load_nvlist(spa_t *spa, uint64_t obj, nvlist_t **value) unsigned char *nv; *value = NULL; - if ((rc = objset_get_dnode(spa, &spa->spa_mos, obj, &dir)) != 0) + if ((rc = objset_get_dnode(spa, spa->spa_mos, obj, &dir)) != 0) return (rc); if (dir.dn_type != DMU_OT_PACKED_NVLIST && dir.dn_bonustype != DMU_OT_PACKED_NVLIST_SIZE) { @@ -3160,22 +3163,23 @@ load_nvlist(spa_t *spa, uint64_t obj, nvlist_t **value) static int zfs_spa_init(spa_t *spa) { + struct uberblock checkpoint; dnode_phys_t dir; uint64_t config_object; nvlist_t *nvlist; int rc; - if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) { + if (zio_read(spa, &spa->spa_uberblock->ub_rootbp, spa->spa_mos)) { printf("ZFS: can't read MOS of pool %s\n", spa->spa_name); return (EIO); } - if (spa->spa_mos.os_type != DMU_OST_META) { + if (spa->spa_mos->os_type != DMU_OST_META) { printf("ZFS: corrupted MOS of pool %s\n", spa->spa_name); return (EIO); } - if (objset_get_dnode(spa, &spa->spa_mos, DMU_POOL_DIRECTORY_OBJECT, - &dir)) { + if (objset_get_dnode(spa, &spa->spa_mos_master, + DMU_POOL_DIRECTORY_OBJECT, &dir)) { printf("ZFS: failed to read pool %s directory object\n", spa->spa_name); return (EIO); @@ -3200,6 +3204,20 @@ zfs_spa_init(spa_t *spa) rc = load_nvlist(spa, config_object, &nvlist); if (rc != 0) return (rc); + + rc = zap_lookup(spa, &dir, DMU_POOL_ZPOOL_CHECKPOINT, + sizeof(uint64_t), sizeof(checkpoint) / sizeof(uint64_t), + &checkpoint); + if (rc == 0 && checkpoint.ub_checkpoint_txg != 0) { + memcpy(&spa->spa_uberblock_checkpoint, &checkpoint, + sizeof(checkpoint)); + if (zio_read(spa, &spa->spa_uberblock_checkpoint.ub_rootbp, + &spa->spa_mos_checkpoint)) { + printf("ZFS: can not read checkpoint data.\n"); + return (EIO); + } + } + /* * Update vdevs from MOS config. Note, we do skip encoding bytes * here. See also vdev_label_read_config(). diff --git a/stand/lua/core.lua b/stand/lua/core.lua index 448215d97d03..c56443e98733 100644 --- a/stand/lua/core.lua +++ b/stand/lua/core.lua @@ -38,6 +38,8 @@ local default_safe_mode = false local default_single_user = false local default_verbose = false +local bootenv_list = "bootenvs" + local function composeLoaderCmd(cmd_name, argstr) if argstr ~= nil then cmd_name = cmd_name .. " " .. argstr @@ -270,7 +272,7 @@ function core.bootenvDefault() end function core.bootenvList() - local bootenv_count = tonumber(loader.getenv("bootenvs_count")) + local bootenv_count = tonumber(loader.getenv(bootenv_list .. "_count")) local bootenvs = {} local curenv local envcount = 0 @@ -281,7 +283,12 @@ function core.bootenvList() end -- Currently selected bootenv is always first/default - curenv = core.bootenvDefault() + -- On the rewinded list the bootenv may not exists + if core.isRewinded() then + curenv = core.bootenvDefaultRewinded() + else + curenv = core.bootenvDefault() + end if curenv ~= nil then envcount = envcount + 1 bootenvs[envcount] = curenv @@ -289,7 +296,7 @@ function core.bootenvList() end for curenv_idx = 0, bootenv_count - 1 do - curenv = loader.getenv("bootenvs[" .. curenv_idx .. "]") + curenv = loader.getenv(bootenv_list .. "[" .. curenv_idx .. "]") if curenv ~= nil and unique[curenv] == nil then envcount = envcount + 1 bootenvs[envcount] = curenv @@ -299,6 +306,40 @@ function core.bootenvList() return bootenvs end +function core.isCheckpointed() + return loader.getenv("zpool_checkpoint") ~= nil +end + +function core.bootenvDefaultRewinded() + local defname = "zfs:!" .. string.sub(core.bootenvDefault(), 5) + local bootenv_count = tonumber("bootenvs_check_count") + + if bootenv_count == nil or bootenv_count <= 0 then + return defname + end + + for curenv_idx = 0, bootenv_count - 1 do + curenv = loader.getenv("bootenvs_check[" .. curenv_idx .. "]") + if curenv == defname then + return defname + end + end + + return loader.getenv("bootenvs_check[0]") +end + +function core.isRewinded() + return bootenv_list == "bootenvs_check" +end + +function core.changeRewindCheckpoint() + if core.isRewinded() then + bootenv_list = "bootenvs" + else + bootenv_list = "bootenvs_check" + end +end + function core.setDefaults() core.setACPI(core.getACPIPresent(true)) core.setSafeMode(default_safe_mode) diff --git a/stand/lua/menu.lua b/stand/lua/menu.lua index 32f414f7fbfa..103ec9c00050 100644 --- a/stand/lua/menu.lua +++ b/stand/lua/menu.lua @@ -132,6 +132,9 @@ menu.boot_environments = { }, { entry_type = core.MENU_ENTRY, + visible = function() + return core.isRewinded() == false + end, name = function() return color.highlight("b") .. "ootfs: " .. core.bootenvDefault() @@ -250,6 +253,7 @@ menu.welcome = { }, menu_entries.kernel_options, menu_entries.boot_options, + menu_entries.zpool_checkpoints, menu_entries.boot_envs, menu_entries.chainload, } @@ -334,6 +338,32 @@ menu.welcome = { submenu = menu.boot_options, alias = {"o", "O"}, }, + zpool_checkpoints = { + entry_type = core.MENU_ENTRY, + name = function() + rewind = "No" + if core.isRewinded() then + rewind = "Yes" + end + return "Rewind ZFS " .. color.highlight("C") .. + "heckpoint: " .. rewind + end, + func = function() + core.changeRewindCheckpoint() + if core.isRewinded() then + bootenvSet( + core.bootenvDefaultRewinded()) + else + bootenvSet(core.bootenvDefault()) + end + config.setCarouselIndex("be_active", 1) + end, + visible = function() + return core.isZFSBoot() and + core.isCheckpointed() + end, + alias = {"c", "C"}, + }, boot_envs = { entry_type = core.MENU_SUBMENU, visible = function() |