Page MenuHomeFreeBSD

D3167.id7318.diff
No OneTemporary

D3167.id7318.diff

Index: sys/boot/forth/menu.rc
===================================================================
--- sys/boot/forth/menu.rc
+++ sys/boot/forth/menu.rc
@@ -65,6 +65,11 @@
set mainmenu_keycode[6]=111
set mainansi_caption[6]="Configure Boot ^[1mO^[mptions..."
+set mainmenu_caption[7]="Select Boot [E]nvironment..."
+set mainmenu_command[7]="3 goto_menu"
+set mainmenu_keycode[7]=101
+set mainansi_caption[7]="Select Boot ^[1mE^[37mnvironment..."
+
\
\ BOOT OPTIONS MENU
\
@@ -116,6 +121,53 @@
set optionsansi_caption[6]="^[1mV^[merbose..... ^[34;1mOff^[m"
set optionstoggled_ansi[6]="^[1mV^[merbose..... ^[32;7mOn^[m"
+\
+\ BOOT ENVIRONMENT MENU
+\
+
+set menuset_name3="bootenv"
+
+set bootenvmenu_caption[1]="Selected: "
+set bootenvmenu_command[1]="1 goto_menu"
+set bootenvmenu_keycode[1]=8
+set bootenvansi_caption[1]="^[1mSelected: ^[37m"
+
+set bemenu_current="Selected: "
+set beansi_current="^[1m${bemenu_current}^[37m"
+: init_bootenv ( -- )
+ s" set menu_caption[1]=${bemenu_current}${vfs.root.mountfrom}" evaluate
+ s" set ansi_caption[1]=${beansi_current}${vfs.root.mountfrom}" evaluate
+;
+
+set bootenvmenu_init="init_bootenv"
+unset bootenvmenu_caption[1]
+unset bootenvansi_caption[1]
+
+: set_bootenv ( N -- N TRUE )
+ dup s" set vfs.root.mountfrom=${bootenv_root[E]}" 38 +c! evaluate
+ s" set currdev=${vfs.root.mountfrom}:" evaluate
+ s" /boot/defaults/loader.conf" read-conf
+ s" /boot/loader.conf" read-conf
+ s" unload" evaluate
+ init_bootenv
+ clear \ Clear the screen (in screen.4th)
+ print_version \ print version string (bottom-right; see version.4th)
+ draw-beastie \ Draw FreeBSD logo at right (in beastie.4th)
+ draw-brand \ Draw brand.4th logo at top (in brand.4th)
+ menu-init \ Initialize menu and draw bounding box (in menu.4th)
+ menu-redraw \ Redraw menu (in menu.4th)
+ TRUE
+;
+
+set bootenvmenu_caption[2]="[A]ctive: ${vfs.root.mountfrom}"
+set bootenvansi_caption[2]="^[1mA^[37mctive: ${vfs.root.mountfrom}"
+set bootenvmenu_keycode[2]=97
+set bootenvmenu_command[2]="set_bootenv"
+set bootenv_root[2]="${zfs_be_active}"
+
+set bootenvmenu_options=3
+set bootenvmenu_optionstext="Boot Environments:"
+
\ Enable automatic booting (add ``autoboot_delay=N'' to loader.conf(5) to
\ customize the timeout; default is 10-seconds)
\
Index: sys/boot/i386/loader/main.c
===================================================================
--- sys/boot/i386/loader/main.c
+++ sys/boot/i386/loader/main.c
@@ -69,6 +69,7 @@
static void isa_outb(int port, int value);
void exit(int code);
#ifdef LOADER_ZFS_SUPPORT
+static void list_zfs_bootenv(char *currdev);
static void i386_zfs_probe(void);
#endif
@@ -299,12 +300,41 @@
new_currdev.d_unit = 0;
}
+#ifdef LOADER_ZFS_SUPPORT
+ list_zfs_bootenv(zfs_fmtdev(&new_currdev));
+#endif
+
env_setenv("currdev", EV_VOLATILE, i386_fmtdev(&new_currdev),
i386_setcurrdev, env_nounset);
env_setenv("loaddev", EV_VOLATILE, i386_fmtdev(&new_currdev), env_noset,
env_nounset);
}
+#ifdef LOADER_ZFS_SUPPORT
+static void
+list_zfs_bootenv(char *currdev)
+{
+ char *beroot;
+
+ /* Remove the trailing : */
+ currdev[strlen(currdev) - 1] = '\0';
+ setenv("zfs_be_active", currdev, 1);
+ /* Do not overwrite if already set */
+ setenv("vfs.root.mountfrom", currdev, 0);
+ /* Forward past zfs: */
+ currdev = strchr(currdev, ':');
+ currdev++;
+ /* Remove the last element (current bootenv) */
+ beroot = strrchr(currdev, '/');
+ beroot[0] = '\0';
+
+ beroot = currdev;
+
+ if (beroot && beroot[0] != '\0')
+ zfs_bootenv(beroot);
+}
+#endif
+
COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
static int
@@ -358,6 +388,29 @@
command_errmsg = strerror(err);
return (CMD_ERROR);
}
+
+ return (CMD_OK);
+}
+
+COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments",
+ command_reloadbe);
+
+static int
+command_reloadbe(int argc, char *argv[])
+{
+ int err;
+
+ if (argc != 2) {
+ command_errmsg = "wrong number of arguments";
+ return (CMD_ERROR);
+ }
+
+ err = zfs_bootenv(argv[1]);
+ if (err != 0) {
+ command_errmsg = strerror(err);
+ return (CMD_ERROR);
+ }
+
return (CMD_OK);
}
#endif
Index: sys/boot/zfs/libzfs.h
===================================================================
--- sys/boot/zfs/libzfs.h
+++ sys/boot/zfs/libzfs.h
@@ -62,6 +62,9 @@
char *zfs_fmtdev(void *vdev);
int zfs_probe_dev(const char *devname, uint64_t *pool_guid);
int zfs_list(const char *name);
+int zfs_bootenv(const char *name);
+int zfs_belist_add(const char *name);
+int zfs_set_env(void);
extern struct devsw zfs_dev;
extern struct fs_ops zfs_fsops;
Index: sys/boot/zfs/zfs.c
===================================================================
--- sys/boot/zfs/zfs.c
+++ sys/boot/zfs/zfs.c
@@ -48,6 +48,10 @@
#include "zfsimpl.c"
+/* Define the range of indexes to be populated with ZFS Boot Environments */
+#define ZFS_BE_FIRST 3
+#define ZFS_BE_LAST 8
+
static int zfs_open(const char *path, struct open_file *f);
static int zfs_write(struct open_file *f, void *buf, size_t size, size_t *resid);
static int zfs_close(struct open_file *f);
@@ -80,6 +84,15 @@
zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */
};
+static int zfs_env_index;
+
+SLIST_HEAD(zfs_be_list, zfs_be_entry) zfs_be_head = SLIST_HEAD_INITIALIZER(zfs_be_head);
+struct zfs_be_list *zfs_be_headp;
+struct zfs_be_entry {
+ const char *name;
+ SLIST_ENTRY(zfs_be_entry) entries;
+} *zfs_be, *zfs_be_tmp;
+
/*
* Open a file.
*/
@@ -692,5 +705,107 @@
if (rv != 0)
return (rv);
rv = zfs_list_dataset(spa, objid);
+
+ return (rv);
+}
+
+int
+zfs_bootenv(const char *name)
+{
+ static char poolname[ZFS_MAXNAMELEN];
+ uint64_t objid;
+ spa_t *spa;
+ const char *dsname;
+ int len;
+ int rv;
+
+ setenv("zfs_beroot", name, 1);
+
+ SLIST_INIT(&zfs_be_head);
+ zfs_env_index = ZFS_BE_FIRST;
+
+ len = strlen(name);
+ dsname = strchr(name, '/');
+ if (dsname != NULL) {
+ len = dsname - name;
+ dsname++;
+ } else
+ dsname = "";
+ memcpy(poolname, name, len);
+ poolname[len] = '\0';
+
+ spa = spa_find_by_name(poolname);
+ if (!spa)
+ return (ENXIO);
+ rv = zfs_lookup_dataset(spa, dsname, &objid);
+ if (rv != 0)
+ return (rv);
+ rv = zfs_callback_dataset(spa, objid, zfs_belist_add);
+
+ /* Populate the environment */
+ zfs_set_env();
+
+ /* Clean up the SLIST of ZFS BEs */
+ while (!SLIST_EMPTY(&zfs_be_head)) {
+ zfs_be = SLIST_FIRST(&zfs_be_head);
+ SLIST_REMOVE_HEAD(&zfs_be_head, entries);
+ free(zfs_be);
+ }
+
return (rv);
}
+
+int
+zfs_belist_add(const char *name)
+{
+
+ /* Add the boot environment to the head of the SLIST */
+ zfs_be = malloc(sizeof(struct zfs_be_entry));
+ zfs_be->name = name;
+ SLIST_INSERT_HEAD(&zfs_be_head, zfs_be, entries);
+
+ return 0;
+}
+
+int
+zfs_set_env(void)
+{
+ char envname[32], envval[256];
+ char *beroot;
+ int rv;
+
+ beroot = getenv("zfs_beroot");
+ if (beroot == NULL)
+ return (1);
+
+ SLIST_FOREACH_SAFE(zfs_be, &zfs_be_head, entries, zfs_be_tmp) {
+ snprintf(envname, 32, "bootenvmenu_caption[%d]", zfs_env_index);
+ snprintf(envval, 256, "%s", zfs_be->name);
+ rv = setenv(envname, envval, 1);
+ if (rv)
+ return (rv);
+
+ snprintf(envname, 32, "bootenvansi_caption[%d]", zfs_env_index);
+ rv = setenv(envname, envval, 1);
+ if (rv)
+ return (rv);
+
+ snprintf(envname, 32, "bootenvmenu_command[%d]", zfs_env_index);
+ rv = setenv(envname, "set_bootenv", 1);
+ if (rv)
+ return (rv);
+
+ snprintf(envname, 32, "bootenv_root[%d]", zfs_env_index);
+ snprintf(envval, 256, "zfs:%s/%s", beroot, zfs_be->name);
+ rv = setenv(envname, envval, 1);
+ if (rv)
+ return (rv);
+
+ if (zfs_env_index >= ZFS_BE_LAST)
+ break;
+
+ zfs_env_index++;
+ }
+
+ return (rv);
+}
\ No newline at end of file
Index: sys/boot/zfs/zfsimpl.c
===================================================================
--- sys/boot/zfs/zfsimpl.c
+++ sys/boot/zfs/zfsimpl.c
@@ -1473,7 +1473,7 @@
* the directory contents.
*/
static int
-mzap_list(const dnode_phys_t *dnode)
+mzap_list(const dnode_phys_t *dnode, int (*callback)(const char *))
{
const mzap_phys_t *mz;
const mzap_ent_phys_t *mze;
@@ -1492,7 +1492,7 @@
mze = &mz->mz_chunk[i];
if (mze->mze_name[0])
//printf("%-32s 0x%jx\n", mze->mze_name, (uintmax_t)mze->mze_value);
- printf("%s\n", mze->mze_name);
+ callback(mze->mze_name);
}
return (0);
@@ -1503,7 +1503,7 @@
* the directory header.
*/
static int
-fzap_list(const spa_t *spa, const dnode_phys_t *dnode)
+fzap_list(const spa_t *spa, const dnode_phys_t *dnode, int (*callback)(const char *))
{
int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT;
zap_phys_t zh = *(zap_phys_t *) zap_scratch;
@@ -1566,13 +1566,21 @@
value = fzap_leaf_value(&zl, zc);
//printf("%s 0x%jx\n", name, (uintmax_t)value);
- printf("%s\n", name);
+ callback((const char *)name);
}
}
return (0);
}
+static int zfs_printf(const char *name)
+{
+
+ printf("%s\n", name);
+
+ return (0);
+}
+
/*
* List a zap directory.
*/
@@ -1587,9 +1595,9 @@
zap_type = *(uint64_t *) zap_scratch;
if (zap_type == ZBT_MICRO)
- return mzap_list(dnode);
+ return mzap_list(dnode, zfs_printf);
else
- return fzap_list(spa, dnode);
+ return fzap_list(spa, dnode, zfs_printf);
}
static int
@@ -1858,6 +1866,43 @@
return (zap_list(spa, &child_dir_zap) != 0);
}
+
+int
+zfs_callback_dataset(const spa_t *spa, uint64_t objnum, int (*callback)(const char *name))
+{
+ uint64_t dir_obj, child_dir_zapobj, zap_type;
+ dnode_phys_t child_dir_zap, dir, dataset;
+ dsl_dataset_phys_t *ds;
+ dsl_dir_phys_t *dd;
+
+ 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)) {
+ 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, &child_dir_zap) != 0) {
+ printf("ZFS: can't find child zap %ju\n", (uintmax_t)dir_obj);
+ return (EIO);
+ }
+
+ if (dnode_read(spa, &child_dir_zap, 0, zap_scratch, child_dir_zap.dn_datablkszsec * 512))
+ return (EIO);
+
+ zap_type = *(uint64_t *) zap_scratch;
+ if (zap_type == ZBT_MICRO)
+ return mzap_list(&child_dir_zap, callback);
+ else
+ return fzap_list(spa, &child_dir_zap, callback);
+}
#endif
/*

File Metadata

Mime Type
text/plain
Expires
Sat, Feb 1, 5:09 AM (11 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16376078
Default Alt Text
D3167.id7318.diff (10 KB)

Event Timeline