diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 5df206293..90893a857 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -117,6 +117,7 @@ static int zfs_do_load_key(int argc, char **argv); static int zfs_do_unload_key(int argc, char **argv); static int zfs_do_change_key(int argc, char **argv); static int zfs_do_project(int argc, char **argv); +static int zfs_do_version(int argc, char **argv); /* * Enable a reasonable set of defaults for libumem debugging on DEBUG builds. @@ -171,6 +172,7 @@ typedef enum { HELP_LOAD_KEY, HELP_UNLOAD_KEY, HELP_CHANGE_KEY, + HELP_VERSION } zfs_help_t; typedef struct zfs_command { @@ -189,6 +191,8 @@ typedef struct zfs_command { * the generic usage message. */ static zfs_command_t command_table[] = { + { "version", zfs_do_version, HELP_VERSION }, + { NULL }, { "create", zfs_do_create, HELP_CREATE }, { "destroy", zfs_do_destroy, HELP_DESTROY }, { NULL }, @@ -379,6 +383,8 @@ get_usage(zfs_help_t idx) "\t [-o keylocation=] [-o pbkfd2iters=]\n" "\t \n" "\tchange-key -i [-l] \n")); + case HELP_VERSION: + return (gettext("\tversion\n")); } abort(); @@ -8059,6 +8065,18 @@ zfs_do_project(int argc, char **argv) return (ret); } +/* + * Display version message + */ +static int +zfs_do_version(int argc, char **argv) +{ + if (zfs_version_print() == -1) + return (1); + + return (0); +} + int main(int argc, char **argv) { @@ -8114,6 +8132,12 @@ main(int argc, char **argv) (strcmp(cmdname, "--help") == 0)) usage(B_TRUE); + /* + * Special case '-V|--version' + */ + if ((strcmp(cmdname, "-V") == 0) || (strcmp(cmdname, "--version") == 0)) + return (zfs_do_version(argc, argv)); + if ((g_zfs = libzfs_init()) == NULL) { (void) fprintf(stderr, "%s", libzfs_error_init(errno)); return (1); diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index f4670fd62..c167324ce 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -115,6 +115,8 @@ static int zpool_do_set(int, char **); static int zpool_do_sync(int, char **); +static int zpool_do_version(int, char **); + /* * These libumem hooks provide a reasonable set of defaults for the allocator's * debugging facilities. @@ -164,7 +166,8 @@ typedef enum { HELP_SPLIT, HELP_SYNC, HELP_REGUID, - HELP_REOPEN + HELP_REOPEN, + HELP_VERSION } zpool_help_t; @@ -263,6 +266,8 @@ typedef struct zpool_command { * the generic usage message. */ static zpool_command_t command_table[] = { + { "version", zpool_do_version, HELP_VERSION }, + { NULL }, { "create", zpool_do_create, HELP_CREATE }, { "destroy", zpool_do_destroy, HELP_DESTROY }, { NULL }, @@ -404,6 +409,8 @@ get_usage(zpool_help_t idx) return (gettext("\treguid \n")); case HELP_SYNC: return (gettext("\tsync [pool] ...\n")); + case HELP_VERSION: + return (gettext("\tversion\n")); } abort(); @@ -9222,6 +9229,18 @@ find_command_idx(char *command, int *idx) return (1); } +/* + * Display version message + */ +static int +zpool_do_version(int argc, char **argv) +{ + if (zfs_version_print() == -1) + return (1); + + return (0); +} + int main(int argc, char **argv) { @@ -9252,6 +9271,12 @@ main(int argc, char **argv) if ((strcmp(cmdname, "-?") == 0) || strcmp(cmdname, "--help") == 0) usage(B_TRUE); + /* + * Special case '-V|--version' + */ + if ((strcmp(cmdname, "-V") == 0) || (strcmp(cmdname, "--version") == 0)) + return (zpool_do_version(argc, argv)); + if ((g_zfs = libzfs_init()) == NULL) { (void) fprintf(stderr, "%s", libzfs_error_init(errno)); return (1); diff --git a/include/libzfs.h b/include/libzfs.h index b604f1194..8d79fe69e 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -815,6 +815,13 @@ void libzfs_free_str_array(char **strs, int count); int libzfs_envvar_is_set(char *envvar); +/* + * Utility functions for zfs version + */ +extern void zfs_version_userland(char *, int); +extern int zfs_version_kernel(char *, int); +extern int zfs_version_print(void); + /* * Given a device or file, determine if it is part of a pool. */ diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index 23dcb11bd..b988d8f31 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -54,6 +54,7 @@ #include "zfeature_common.h" #include #include +#include int libzfs_errno(libzfs_handle_t *hdl) @@ -1940,3 +1941,66 @@ zprop_iter(zprop_func func, void *cb, boolean_t show_all, boolean_t ordered, { return (zprop_iter_common(func, cb, show_all, ordered, type)); } + +/* + * Fill given version buffer with zfs userland version + */ +void +zfs_version_userland(char *version, int len) +{ + (void) strlcpy(version, ZFS_META_ALIAS, len); +} + +/* + * Fill given version buffer with zfs kernel version read from ZFS_SYSFS_DIR + * Returns 0 on success, and -1 on error (with errno set) + */ +int +zfs_version_kernel(char *version, int len) +{ + int _errno; + int fd; + int rlen; + + if ((fd = open(ZFS_SYSFS_DIR "/version", O_RDONLY)) == -1) + return (-1); + + if ((rlen = read(fd, version, len)) == -1) { + version[0] = '\0'; + _errno = errno; + (void) close(fd); + errno = _errno; + return (-1); + } + + version[rlen-1] = '\0'; /* discard '\n' */ + + if (close(fd) == -1) + return (-1); + + return (0); +} + +/* + * Prints both zfs userland and kernel versions + * Returns 0 on success, and -1 on error (with errno set) + */ +int +zfs_version_print(void) +{ + char zver_userland[128]; + char zver_kernel[128]; + + if (zfs_version_kernel(zver_kernel, sizeof (zver_kernel)) == -1) { + fprintf(stderr, "zfs_version_kernel() failed: %s\n", + strerror(errno)); + return (-1); + } + + zfs_version_userland(zver_userland, sizeof (zver_userland)); + + (void) printf("%s\n", zver_userland); + (void) printf("zfs-kmod-%s\n", zver_kernel); + + return (0); +} diff --git a/man/man8/zfs.8 b/man/man8/zfs.8 index 36ab9353f..69036d04c 100644 --- a/man/man8/zfs.8 +++ b/man/man8/zfs.8 @@ -38,7 +38,7 @@ .Nd configures ZFS file systems .Sh SYNOPSIS .Nm -.Fl ? +.Fl ?V .Nm .Cm create .Op Fl p @@ -327,6 +327,8 @@ .Fl i .Op Fl l .Ar filesystem +.Nm +.Cm version .Sh DESCRIPTION The .Nm @@ -2453,6 +2455,13 @@ original form. Displays a help message. .It Xo .Nm +.Fl V, -version +.Xc +An alias for the +.Nm zfs Cm version +subcommand. +.It Xo +.Nm .Cm create .Op Fl p .Oo Fl o Ar property Ns = Ns Ar value Oc Ns ... @@ -4624,6 +4633,13 @@ Indicates that zfs should make inherit the key of its parent. Note that this command can only be run on an encryption root that has an encrypted parent. .El +.It Xo +.Nm +.Cm version +.Xc +Displays the software version of the +.Nm +userland utility and the zfs kernel module. .El .Sh EXIT STATUS The diff --git a/man/man8/zpool.8 b/man/man8/zpool.8 index ebdb72251..e644f7e6a 100644 --- a/man/man8/zpool.8 +++ b/man/man8/zpool.8 @@ -35,7 +35,7 @@ .Nd configure ZFS storage pools .Sh SYNOPSIS .Nm -.Fl ? +.Fl ?V .Nm .Cm add .Op Fl fgLnP @@ -210,6 +210,8 @@ .Cm upgrade .Op Fl V Ar version .Fl a Ns | Ns Ar pool Ns ... +.Nm +.Cm version .Sh DESCRIPTION The .Nm @@ -933,6 +935,13 @@ The following subcommands are supported: Displays a help message. .It Xo .Nm +.Fl V, -version +.Xc +An alias for the +.Nm zpool Cm version +subcommand. +.It Xo +.Nm .Cm add .Op Fl fgLnP .Oo Fl o Ar property Ns = Ns Ar value Oc @@ -2465,6 +2474,13 @@ flag is specified, no features will be enabled on the pool. This option can only be used to increase the version number up to the last supported legacy version number. .El +.It Xo +.Nm +.Cm version +.Xc +Displays the software version of the +.Nm +userland utility and the zfs kernel module. .El .Sh EXIT STATUS The following exit values are returned: