Changeset View
Changeset View
Standalone View
Standalone View
sbin/zfsbootcfg/zfsbootcfg.c
Show All 27 Lines | |||||
#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 <string.h> | #include <string.h> | ||||
#include <sys/nvpair.h> | |||||
#include <kenv.h> | #include <kenv.h> | ||||
#include <libzfs.h> | #include <libzfs.h> | ||||
/* Keep in sync with zfsboot.c. */ | /* Keep in sync with zfsboot.c. */ | ||||
#define MAX_COMMAND_LEN 512 | #define MAX_COMMAND_LEN 512 | ||||
int | int main(int argc, char * const *argv) | ||||
imp: nit: int should be on a line by itself...
| |||||
install_bootonce(libzfs_handle_t *hdl, uint64_t pool_guid, nvlist_t *nv, | |||||
const char * const data) | |||||
{ | { | ||||
nvlist_t **child; | char buf[MAX_COMMAND_LEN], *name = NULL; | ||||
uint_t children = 0; | const char *key, *value; | ||||
uint64_t guid; | libzfs_handle_t *hdl; | ||||
zpool_handle_t *zphdl; | |||||
nvlist_t *nv; | |||||
nvpair_t *nvp; | |||||
int rv; | int rv; | ||||
int len; | |||||
bool print = false; | |||||
(void) nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, | key = "command"; | ||||
&children); | value = NULL; | ||||
print = 0; | |||||
for (int c = 0; c < children; c++) { | while ((rv = getopt(argc, argv, "k:v:pz:")) != -1) { | ||||
rv = install_bootonce(hdl, pool_guid, child[c], data); | switch (rv) { | ||||
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… | |||||
case 'k': | |||||
key = optarg; | |||||
break; | |||||
case 'v': | |||||
value = optarg; | |||||
break; | |||||
case 'p': | |||||
print = true; | |||||
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) { | if ((hdl = libzfs_init()) == NULL) { | ||||
(void) fprintf(stderr, "internal error: failed to " | (void) fprintf(stderr, "internal error: failed to " | ||||
"initialize ZFS library\n"); | "initialize ZFS library\n"); | ||||
return (1); | return (1); | ||||
} | } | ||||
libzfs_print_on_error(hdl, B_TRUE); | |||||
zphdl = zpool_open(hdl, name); | zphdl = zpool_open(hdl, name); | ||||
if (zphdl == NULL) { | if (zphdl == NULL) { | ||||
perror("can't open pool"); | perror("can't open pool"); | ||||
libzfs_fini(hdl); | libzfs_fini(hdl); | ||||
return (1); | return (1); | ||||
} | } | ||||
pool_guid = zpool_get_prop_int(zphdl, ZPOOL_PROP_GUID, NULL); | if (value != NULL) { | ||||
len = strlen(value); | |||||
if (len >= MAX_COMMAND_LEN) { | |||||
fprintf(stderr, "options string is too long\n"); | |||||
} else { | |||||
rv = zpool_get_bootenv(zphdl, &nv); | |||||
if (rv != 0) | |||||
nv = fnvlist_alloc(); | |||||
config = zpool_get_config(zphdl, NULL); | if (value[0] == '\0') | ||||
if (config == NULL) { | fnvlist_remove(nv, key); | ||||
perror("can't get pool config"); | else | ||||
zpool_close(zphdl); | fnvlist_add_string(nv, key, value); | ||||
libzfs_fini(hdl); | |||||
return (1); | rv = zpool_set_bootenv(zphdl, nv); | ||||
if (rv == 0) | |||||
printf("zfs next boot options are successfully written\n"); | |||||
else | |||||
printf("error: %d\n", rv); | |||||
fnvlist_free(nv); | |||||
} | } | ||||
} | |||||
if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) { | if (print) { | ||||
perror("failed to get vdev tree"); | rv = zpool_get_bootenv(zphdl, &nv); | ||||
zpool_close(zphdl); | if (rv == 0) { | ||||
libzfs_fini(hdl); | nvlist_print(stdout, nv); | ||||
return (1); | |||||
} | } | ||||
fnvlist_free(nv); | |||||
} | |||||
rv = install_bootonce(hdl, pool_guid, nv, argv[1]); | |||||
zpool_close(zphdl); | zpool_close(zphdl); | ||||
libzfs_fini(hdl); | 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...