Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F109054457
D3167.id7318.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D3167.id7318.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]="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
Details
Attached
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)
Attached To
Mode
D3167: Autogenerate list of ZFS Boot Environments in the beastie menu
Attached
Detach File
Event Timeline
Log In to Comment