Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F109304797
D3167.id7212.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D3167.id7212.diff
View Options
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]="Back to Main Menu [Backspace]"
+set bootenvmenu_command[1]="1 goto_menu"
+set bootenvmenu_keycode[1]=8
+set bootenvansi_caption[1]="Back to Main Menu ^[1m[Backspace]^[37m"
+
+set bootenvmenu_caption[2]="Choice: "
+set bootenvmenu_command[2]="true"
+set bootenvmenu_keycode[2]=27
+set bootenvansi_caption[2]="^[1m${bootenvmenu_caption[2]}^[37m"
+
+set bemenu_current="Choice: "
+set beansi_current="^[1m${bemenu_current}^[37m"
+: init_bootenv ( -- )
+ s" set menu_caption[2]=${bemenu_current}${vfs.root.mountfrom}" evaluate
+ s" set ansi_caption[2]=${beansi_current}${vfs.root.mountfrom}" evaluate
+;
+
+set bootenvmenu_init="init_bootenv"
+unset bootenvmenu_caption[2]
+unset bootenvansi_caption[2]
+
+: 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" read-conf /boot/defaults/loader.conf" evaluate
+ s" read-conf /boot/loader.conf" evaluate
+ s" unload" evaluate
+ init_bootenv
+ menu-redraw
+ TRUE
+;
+
+set bootenvmenu_caption[3]="[A]ctive: ${vfs.root.mountfrom}"
+set bootenvansi_caption[3]="^[1mA^[37mctive: ${vfs.root.mountfrom}"
+set bootenvmenu_keycode[3]=97
+set bootenvmenu_command[3]="set_bootenv"
+set bootenv_root[3]="${zfs_be_active}"
+
+set bootenvmenu_options=4
+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
@@ -360,6 +390,27 @@
}
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
/* ISA bus access functions for PnP. */
Index: sys/boot/zfs/libzfs.h
===================================================================
--- sys/boot/zfs/libzfs.h
+++ sys/boot/zfs/libzfs.h
@@ -62,6 +62,8 @@
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_set_env(const char *name);
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
@@ -80,6 +80,8 @@
zap_leaf_phys_t *f_zap_leaf; /* zap leaf buffer */
};
+static int zfs_env_index = 0;
+
/*
* Open a file.
*/
@@ -694,3 +696,93 @@
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;
+ char *index_str;
+ int len;
+ int rv;
+
+ setenv("zfs_beroot", name, 1);
+
+ zfs_env_index = 4;
+ 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_set_env);
+ if (rv != 0)
+ return (rv);
+ index_str = malloc(20);
+ snprintf(index_str, 20, "%d", zfs_env_index - 1);
+ rv = setenv("bootenv_count", index_str, 1);
+ return (rv);
+}
+
+int
+zfs_set_env(const char *name)
+{
+ char *envname = NULL, *envval = NULL, *beroot;
+ int rv, i;
+
+ beroot = getenv("zfs_beroot");
+ if (beroot == NULL)
+ return (1);
+
+ envname = malloc(32);
+ envval = malloc(256);
+ /* Don't overflow the menu, shuffle entries down to show the newest */
+ if (zfs_env_index == 9) {
+ for (i = 4; i < 8; i++) {
+ snprintf(envname, 32, "bootenvmenu_caption[%d]", i);
+ snprintf(envval, 32, "bootenvmenu_caption[%d]", i + 1);
+ setenv(envname, getenv(envval), 1);
+
+ snprintf(envname, 32, "bootenvansi_caption[%d]", i);
+ snprintf(envval, 32, "bootenvansi_caption[%d]", i + 1);
+ setenv(envname, getenv(envval), 1);
+
+ snprintf(envname, 32, "bootenv_root[%d]", i);
+ snprintf(envval, 32, "bootenv_root[%d]", i + 1);
+ setenv(envname, getenv(envval), 1);
+ }
+ zfs_env_index = 8;
+ }
+
+ snprintf(envname, 32, "bootenvmenu_caption[%d]", zfs_env_index);
+ snprintf(envval, 256, "%s", name);
+ rv = setenv(envname, envval, 1);
+
+ snprintf(envname, 32, "bootenvansi_caption[%d]", zfs_env_index);
+ rv = setenv(envname, envval, 1);
+
+ snprintf(envname, 32, "bootenvmenu_command[%d]", zfs_env_index);
+ rv = setenv(envname, "set_bootenv", 1);
+
+ snprintf(envname, 32, "bootenv_root[%d]", zfs_env_index);
+ snprintf(envval, 256, "zfs:%s/%s", beroot, name);
+ rv = setenv(envname, envval, 1);
+
+ if (zfs_env_index <= 8)
+ zfs_env_index++;
+ free(envname);
+ free(envval);
+ 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,19 @@
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 +1593,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 +1864,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
Details
Attached
Mime Type
text/plain
Expires
Tue, Feb 4, 8:00 AM (7 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16450205
Default Alt Text
D3167.id7212.diff (9 KB)
Attached To
Mode
D3167: Autogenerate list of ZFS Boot Environments in the beastie menu
Attached
Detach File
Event Timeline
Log In to Comment