Changeset View
Changeset View
Standalone View
Standalone View
sbin/zfsbootcfg/zfsbootcfg.c
Show All 26 Lines | |||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <limits.h> | #include <limits.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <stdbool.h> | |||||
#include <string.h> | #include <string.h> | ||||
#include <kenv.h> | #include <kenv.h> | ||||
#include <unistd.h> | |||||
#include <libzfs.h> | #include <libzfsbootenv.h> | ||||
/* Keep in sync with zfsboot.c. */ | #ifndef ZFS_MAXNAMELEN | ||||
#define MAX_COMMAND_LEN 512 | #define ZFS_MAXNAMELEN 256 | ||||
#endif | |||||
int | int | ||||
install_bootonce(libzfs_handle_t *hdl, uint64_t pool_guid, nvlist_t *nv, | main(int argc, char * const *argv) | ||||
imp: nit: int should be on a line by itself...
| |||||
const char * const data) | |||||
{ | { | ||||
nvlist_t **child; | char buf[ZFS_MAXNAMELEN], *name; | ||||
uint_t children = 0; | const char *key, *value, *type; | ||||
uint64_t guid; | |||||
int rv; | int rv; | ||||
bool print; | |||||
(void) nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, | name = NULL; | ||||
&children); | key = NULL; | ||||
type = NULL; | |||||
for (int c = 0; c < children; c++) { | value = NULL; | ||||
rv = install_bootonce(hdl, pool_guid, child[c], data); | print = false; | ||||
Done Inline ActionsI think for backwards compatibility, we need to make print the default if 0 args are specified so running just 'zfsbootcfg' prints the currently selected bootenv (this is what it did before our changes) allanjude: I think for backwards compatibility, we need to make print the default if 0 args are specified… | |||||
Done Inline ActionsActually it did not, it did require argc == 2 and only wrote the argument string to pad2:) but the idea is still OK tsoome: Actually it did not, it did require argc == 2 and only wrote the argument string to pad2:) but… | |||||
while ((rv = getopt(argc, argv, "k:pt:v:z:")) != -1) { | |||||
switch (rv) { | |||||
case 'k': | |||||
key = optarg; | |||||
break; | |||||
case 'p': | |||||
print = true; | |||||
break; | |||||
case 't': | |||||
type = optarg; | |||||
break; | |||||
case 'v': | |||||
value = optarg; | |||||
break; | |||||
case 'z': | |||||
name = optarg; | |||||
break; | |||||
} | } | ||||
if (children > 0) | |||||
return (rv); | |||||
if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) != 0) { | |||||
perror("can't get vdev guid"); | |||||
return (1); | |||||
} | } | ||||
if (zpool_nextboot(hdl, pool_guid, guid, data) != 0) { | |||||
perror("ZFS_IOC_NEXTBOOT failed"); | |||||
return (1); | |||||
} | |||||
return (0); | |||||
} | |||||
int main(int argc, const char * const *argv) | argc -= optind; | ||||
{ | argv += optind; | ||||
char buf[32], *name; | |||||
libzfs_handle_t *hdl; | |||||
zpool_handle_t *zphdl; | |||||
uint64_t pool_guid; | |||||
nvlist_t *nv, *config; | |||||
int rv; | |||||
int len; | |||||
if (argc != 2) { | if (argc == 1) | ||||
value = argv[0]; | |||||
if (argc > 1) { | |||||
fprintf(stderr, "usage: zfsbootcfg <boot.config(5) options>\n"); | fprintf(stderr, "usage: zfsbootcfg <boot.config(5) options>\n"); | ||||
return (1); | return (1); | ||||
} | } | ||||
len = strlen(argv[1]); | if (name == NULL) { | ||||
if (len >= MAX_COMMAND_LEN) { | rv = kenv(KENV_GET, "vfs.root.mountfrom", buf, sizeof(buf)); | ||||
fprintf(stderr, "options string is too long\n"); | if (rv <= 0) { | ||||
return (1); | |||||
} | |||||
if (kenv(KENV_GET, "vfs.root.mountfrom", buf, sizeof(buf)) <= 0) { | |||||
perror("can't get vfs.root.mountfrom"); | perror("can't get vfs.root.mountfrom"); | ||||
return (1); | return (1); | ||||
} | } | ||||
if (strncmp(buf, "zfs:", 4) == 0) { | if (strncmp(buf, "zfs:", 4) == 0) { | ||||
name = strchr(buf + 4, '/'); | name = strchr(buf + 4, '/'); | ||||
if (name != NULL) | if (name != NULL) | ||||
*name = '\0'; | *name = '\0'; | ||||
name = buf + 4; | name = buf + 4; | ||||
} else { | } else { | ||||
perror("not a zfs root"); | perror("not a zfs root"); | ||||
return (1); | return (1); | ||||
} | } | ||||
if ((hdl = libzfs_init()) == NULL) { | |||||
(void) fprintf(stderr, "internal error: failed to " | |||||
"initialize ZFS library\n"); | |||||
return (1); | |||||
} | } | ||||
zphdl = zpool_open(hdl, name); | rv = 0; | ||||
if (zphdl == NULL) { | if (key != NULL || value != NULL) { | ||||
perror("can't open pool"); | if (type == NULL) | ||||
libzfs_fini(hdl); | type = "DATA_TYPE_STRING"; | ||||
return (1); | |||||
} | |||||
pool_guid = zpool_get_prop_int(zphdl, ZPOOL_PROP_GUID, NULL); | if (key == NULL || strcmp(key, "command") == 0) | ||||
rv = lzbe_set_boot_device(name, value); | |||||
else | |||||
rv = lzbe_set_pair(name, key, type, value); | |||||
config = zpool_get_config(zphdl, NULL); | if (rv == 0) | ||||
if (config == NULL) { | printf("zfs bootenv is successfully written\n"); | ||||
perror("can't get pool config"); | else | ||||
zpool_close(zphdl); | printf("error: %d\n", rv); | ||||
libzfs_fini(hdl); | } else { | ||||
return (1); | char *ptr; | ||||
if (lzbe_get_boot_device(name, &ptr) == 0) { | |||||
printf("zfs:%s:\n", ptr); | |||||
free(ptr); | |||||
} | } | ||||
} | |||||
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) { | if (print) { | ||||
perror("failed to get vdev tree"); | rv = lzbe_bootenv_print(name, stdout); | ||||
zpool_close(zphdl); | |||||
libzfs_fini(hdl); | |||||
return (1); | |||||
} | } | ||||
rv = install_bootonce(hdl, pool_guid, nv, argv[1]); | |||||
zpool_close(zphdl); | |||||
libzfs_fini(hdl); | |||||
if (rv == 0) | |||||
printf("zfs next boot options are successfully written\n"); | |||||
return (rv); | return (rv); | ||||
} | } |
nit: int should be on a line by itself...