]> granicus.if.org Git - zfs/commitdiff
zpool iostat/status -c improvements
authorGiuseppe Di Natale <dinatale2@users.noreply.github.com>
Mon, 5 Jun 2017 17:52:15 +0000 (13:52 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 5 Jun 2017 17:52:15 +0000 (10:52 -0700)
Users can now provide their own scripts to be run
with 'zpool iostat/status -c'. User scripts should be
placed in ~/.zpool.d to be included in zpool's
default search path.

Provide a script which can be used with
'zpool iostat|status -c' that will return the type of
device (hdd, sdd, file).

Provide a script to get various values from smartctl
when using 'zpool iostat/status -c'.

Allow users to define the ZPOOL_SCRIPTS_PATH
environment variable which can be used to override
the default 'zpool iostat/status -c' search path.

Allow the ZPOOL_SCRIPTS_ENABLED environment
variable to enable or disable 'zpool status/iostat -c'
functionality.

Use the new smart script to provide the serial command.

Install /etc/sudoers.d/zfs file which contains the sudoer
rule for smartctl as a sample.

Allow 'zpool iostat/status -c' tests to run in tree.

Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Closes #6121
Closes #6153

43 files changed:
cmd/zpool/Makefile.am
cmd/zpool/zpool.d/ata_err [new symlink]
cmd/zpool/zpool.d/cmd_to [new symlink]
cmd/zpool/zpool.d/defect [new symlink]
cmd/zpool/zpool.d/health [new symlink]
cmd/zpool/zpool.d/hours_on [new symlink]
cmd/zpool/zpool.d/lsblk
cmd/zpool/zpool.d/media [new file with mode: 0755]
cmd/zpool/zpool.d/nonmed [new symlink]
cmd/zpool/zpool.d/off_ucor [new symlink]
cmd/zpool/zpool.d/pend_sec [new symlink]
cmd/zpool/zpool.d/pwr_cyc [new symlink]
cmd/zpool/zpool.d/r_proc [new symlink]
cmd/zpool/zpool.d/r_ucor [new symlink]
cmd/zpool/zpool.d/realloc [new symlink]
cmd/zpool/zpool.d/rep_ucor [new symlink]
cmd/zpool/zpool.d/serial
cmd/zpool/zpool.d/ses
cmd/zpool/zpool.d/smart [new file with mode: 0755]
cmd/zpool/zpool.d/smartx [new symlink]
cmd/zpool/zpool.d/temp [new symlink]
cmd/zpool/zpool.d/w_proc [new symlink]
cmd/zpool/zpool.d/w_ucor [new symlink]
cmd/zpool/zpool_iter.c
cmd/zpool/zpool_main.c
cmd/zpool/zpool_util.h
configure.ac
etc/Makefile.am
etc/sudoers.d/Makefile.am [new file with mode: 0644]
etc/sudoers.d/zfs [new file with mode: 0644]
man/man8/zpool.8
rpm/generic/zfs.spec.in
scripts/zfs-helpers.sh
tests/runfiles/linux.run
tests/zfs-tests/tests/functional/cli_root/zpool_status/Makefile.am
tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_-c_disable.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_-c_homedir.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_-c_searchpath.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/cli_user/zpool_iostat/Makefile.am
tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_-c_disable.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_-c_homedir.ksh [new file with mode: 0755]
tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_-c_searchpath.ksh [new file with mode: 0755]
zfs-script-config.sh.in

index f905fb73db2223852ccd2a938e60c312d7636133..6eff1d143202824a1155a9ec0f575a5f00e9d7f1 100644 (file)
@@ -36,12 +36,31 @@ dist_zpoolexec_SCRIPTS = \
        zpool.d/label \
        zpool.d/locate_led \
        zpool.d/lsblk \
+       zpool.d/media \
        zpool.d/model \
        zpool.d/serial \
        zpool.d/ses \
        zpool.d/size \
        zpool.d/slaves \
        zpool.d/slot \
+       zpool.d/smart \
+       zpool.d/smartx \
+       zpool.d/temp \
+       zpool.d/health \
+       zpool.d/r_proc \
+       zpool.d/w_proc \
+       zpool.d/r_ucor \
+       zpool.d/w_ucor \
+       zpool.d/nonmed \
+       zpool.d/defect \
+       zpool.d/hours_on \
+       zpool.d/realloc \
+       zpool.d/rep_ucor \
+       zpool.d/cmd_to \
+       zpool.d/pend_sec \
+       zpool.d/off_ucor \
+       zpool.d/ata_err \
+       zpool.d/pwr_cyc \
        zpool.d/upath \
        zpool.d/vendor
 
@@ -55,12 +74,31 @@ zpoolconfdefaults = \
        label \
        locate_led \
        lsblk \
+       media \
        model \
        serial \
        ses \
        size \
        slaves \
        slot \
+       smart \
+       smartx \
+       temp \
+       health \
+       r_proc \
+       w_proc \
+       r_ucor \
+       w_ucor \
+       nonmed \
+       defect \
+       hours_on \
+       realloc \
+       rep_ucor \
+       cmd_to \
+       pend_sec \
+       off_ucor \
+       ata_err \
+       pwr_cyc \
        upath \
        vendor
 
diff --git a/cmd/zpool/zpool.d/ata_err b/cmd/zpool/zpool.d/ata_err
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/cmd_to b/cmd/zpool/zpool.d/cmd_to
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/defect b/cmd/zpool/zpool.d/defect
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/health b/cmd/zpool/zpool.d/health
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/hours_on b/cmd/zpool/zpool.d/hours_on
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
index fc0394a3d3a9a930978a71ed187b5e57f5427e1e..1cdef40494fed80ce693db18dc52824f72fac209 100755 (executable)
 #   DISC-ZERO  discard zeroes data
 #
 # If the script is run as just 'lsblk' then print out disk size, vendor,
-# model number and serial number.
+# and model number.
 
 
 helpstr="
 label: Show filesystem label.
 model: Show disk model number.
-serial:        Show disk serial number.
 size:  Show the disk capacity.
 vendor:        Show the disk vendor.
-lsblk: Show the disk size, vendor, model number, and serial number."
+lsblk: Show the disk size, vendor, and model number."
 
 script=$(basename "$0")
 
@@ -57,7 +56,7 @@ if [ "$1" = "-h" ] ; then
 fi
 
 if [ "$script" = "lsblk" ] ; then
-       list="size vendor model serial"
+       list="size vendor model"
 else
        list=$(echo "$script" | tr '[:upper:]' '[:lower:]')
 fi
diff --git a/cmd/zpool/zpool.d/media b/cmd/zpool/zpool.d/media
new file mode 100755 (executable)
index 0000000..05bc159
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# Print out the type of device
+#
+
+if [ "$1" = "-h" ] ; then
+       echo "Show whether a vdev is a file, hdd, or ssd."
+       exit
+fi
+
+if [ -b "$VDEV_UPATH" ]; then
+       device=$(basename "$VDEV_UPATH")
+       val=$(cat "/sys/block/$device/queue/rotational" 2>/dev/null)
+       if [ "$val" = "0" ]; then
+               MEDIA="ssd"
+       fi
+
+       if [ "$val" = "1" ]; then
+               MEDIA="hdd"
+       fi
+else
+       if [ -f "$VDEV_UPATH" ]; then
+               MEDIA="file"
+       fi
+fi
+
+echo "media=$MEDIA"
diff --git a/cmd/zpool/zpool.d/nonmed b/cmd/zpool/zpool.d/nonmed
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/off_ucor b/cmd/zpool/zpool.d/off_ucor
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/pend_sec b/cmd/zpool/zpool.d/pend_sec
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/pwr_cyc b/cmd/zpool/zpool.d/pwr_cyc
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/r_proc b/cmd/zpool/zpool.d/r_proc
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/r_ucor b/cmd/zpool/zpool.d/r_ucor
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/realloc b/cmd/zpool/zpool.d/realloc
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/rep_ucor b/cmd/zpool/zpool.d/rep_ucor
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
index 7d1e766add99843d6d05654c39f007722bf97135..94f22861f0cebd5e326c1989dcd22d910d0cb585 120000 (symlink)
@@ -1 +1 @@
-lsblk
\ No newline at end of file
+smart
\ No newline at end of file
index 10d5dcfd35bdd090a7876ffcea0f78aba438aebf..f6b7520dfb6cd3a5c565348cf885e6cba8489173 100755 (executable)
@@ -6,10 +6,10 @@
 helpstr="
 enc:           Show disk enclosure w:x:y:z value.
 slot:          Show disk slot number as reported by the enclosure.
-encdev:                Show the /dev/sg* device for the enclosure associated with the disk slot.
-fault_led:     Show the value of the disk enclosure slot fault LED.
-locate_led:    Show the value of the disk enclosure slot locate LED.
-ses:           Show disk's enclosure, enclosure dev, slot number, and fault/locate LED values."
+encdev:                Show /dev/sg* device associated with the enclosure disk slot.
+fault_led:     Show value of the disk enclosure slot fault LED.
+locate_led:    Show value of the disk enclosure slot locate LED.
+ses:           Show disk's enc, enc device, slot, and fault/locate LED values."
 
 script=$(basename "$0")
 if [ "$1" = "-h" ] ; then
diff --git a/cmd/zpool/zpool.d/smart b/cmd/zpool/zpool.d/smart
new file mode 100755 (executable)
index 0000000..3721f30
--- /dev/null
@@ -0,0 +1,123 @@
+#!/bin/sh
+#
+# Show SMART stats
+#
+
+helpstr="
+smart:         Show SMART temperature and error stats (specific to drive type)
+smartx:                Show SMART extended drive stats (specific to drive type).
+temp:          Show SMART drive temperature in celsius (all drives).
+health:                Show reported SMART status (all drives).
+r_proc:                Show SMART read GBytes processed over drive lifetime (SAS).
+w_proc:                Show SMART write GBytes processed over drive lifetime (SAS).
+r_ucor:                Show SMART read uncorrectable errors (SAS).
+w_ucor:                Show SMART write uncorrectable errors (SAS).
+nonmed:                Show SMART non-medium errors (SAS).
+defect:                Show SMART grown defect list (SAS).
+hours_on:      Show number of hours drive powered on (all drives).
+realloc:       Show SMART reallocated sectors count (ATA).
+rep_ucor:      Show SMART reported uncorrectable count (ATA).
+cmd_to:                Show SMART command timeout count (ATA).
+pend_sec:      Show SMART current pending sector count (ATA).
+off_ucor:      Show SMART offline uncorrectable errors (ATA).
+ata_err:       Show SMART ATA errors (ATA).
+pwr_cyc:       Show SMART power cycle count (ATA).
+serial:                Show disk serial number.
+"
+
+script=$(basename "$0")
+
+if [ "$1" = "-h" ] ; then
+        echo "$helpstr" | grep "$script:" | tr -s '\t' | cut -f 2-
+        exit
+fi
+
+smartctl_path=$(which smartctl)
+
+if [ -b "$VDEV_UPATH" ] && [ -x "$smartctl_path" ]; then
+       raw_out=$(eval "sudo $smartctl_path -a $VDEV_UPATH")
+
+       # Are we a SAS or ATA drive?  Look for the right line in smartctl:
+       #
+       # SAS:
+       #       Transport protocol:   SAS
+       #
+       # SATA:
+       #       ATA Version is:   8
+       #
+       type=$(echo "$raw_out" | grep -m 1 -Eo '^ATA|SAS$')
+       out=$(echo "$raw_out" | awk '
+# SAS specific
+/read:/{print "rrd="$4"\nr_cor="$5"\nr_proc="$7"\nr_ucor="$8}
+/write:/{print "rwr="$4"\nw_cor="$5"\nw_proc="$7"\nw_ucor="$8}
+/Non-medium error count/{print "nonmed="$4}
+/Elements in grown defect list/{print "defect="$6}
+
+# SAS common
+/Drive Temperature:/{print "temp="$4}
+# Status can be a long string, substitute spaces for '_'
+/SMART Health Status:/{printf "health="; for(i=4;i<=NF-1;i++){printf "%s_", $i}; printf "%s\n", $i}
+/number of hours powered up/{print "hours_on="$7}
+/Serial number:/{print "serial="$3}
+
+# SATA specific
+/Reallocated_Sector_Ct/{print "realloc="$10}
+/Reported_Uncorrect/{print "rep_ucor="$10}
+/Command_Timeout/{print "cmd_to="$10}
+/Current_Pending_Sector/{print "pend_sec="$10}
+/Offline_Uncorrectable/{print "off_ucor="$10}
+/ATA Error Count:/{print "ata_err="$4}
+/Power_Cycle_Count/{print "pwr_cyc="$10}
+
+# SATA common
+/Temperature_Celsius/{print "temp="$10}
+/SMART overall-health self-assessment test result:/{print "health="$6}
+/Power_On_Hours/{print "hours_on="$10}
+/Serial Number:/{print "serial="$3}
+
+END {ORS="\n"; print ""}
+');
+fi
+
+# if type is not set by now, either we don't have a block device
+# or smartctl failed. Either way, default to ATA and set out to
+# nothing
+if [ -z "$type" ]; then
+       type="ATA"
+       out=
+fi
+
+case $script in
+smart)
+       # Print temperature plus common predictors of drive failure
+       if [ "$type" = "SAS" ] ; then
+               scripts="temp|health|r_ucor|w_ucor"
+       elif [ "$type" = "ATA" ] ; then
+               scripts="temp|health|ata_err|realloc|rep_ucor|cmd_to|pend_sec|off_ucor"
+       fi
+       ;;
+smartx)
+       # Print some other interesting stats
+       if [ "$type" = "SAS" ] ; then
+               scripts="hours_on|defect|nonmed|r_proc|w_proc"
+       elif [ "$type" = "ATA" ] ; then
+               scripts="hours_on|pwr_cyc"
+       fi
+       ;;
+*)
+       scripts="$script"
+esac
+
+with_vals=$(echo "$out" | grep -E "$scripts")
+if [ ! -z "$with_vals" ]; then
+       echo "$with_vals"
+       without_vals=$(echo "$scripts" | tr "|" "\n" |
+               grep -v -E "$(echo "$with_vals" |
+               awk -F "=" '{print $1}')" | awk '{print $0"="}')
+else
+       without_vals=$(echo "$scripts" | tr "|" "\n" | awk '{print $0"="}')
+fi
+
+if [ ! -z "$without_vals" ]; then
+       echo "$without_vals"
+fi
diff --git a/cmd/zpool/zpool.d/smartx b/cmd/zpool/zpool.d/smartx
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/temp b/cmd/zpool/zpool.d/temp
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/w_proc b/cmd/zpool/zpool.d/w_proc
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
diff --git a/cmd/zpool/zpool.d/w_ucor b/cmd/zpool/zpool.d/w_ucor
new file mode 120000 (symlink)
index 0000000..94f2286
--- /dev/null
@@ -0,0 +1 @@
+smart
\ No newline at end of file
index 94777f076c6f81269a81b960e3839c211e15819a..abb1b179881f856875b2cd4ef1d8029f9f644040 100644 (file)
@@ -521,28 +521,66 @@ out:
                        free(env[i]);
 }
 
+/*
+ * Generate the search path for zpool iostat/status -c scripts.
+ * The string returned must be freed.
+ */
+char *
+zpool_get_cmd_search_path(void)
+{
+       const char *env;
+       char *sp = NULL;
+
+       env = getenv("ZPOOL_SCRIPTS_PATH");
+       if (env != NULL)
+               return (strdup(env));
+
+       env = getenv("HOME");
+       if (env != NULL) {
+               if (asprintf(&sp, "%s/.zpool.d:%s",
+                   env, ZPOOL_SCRIPTS_DIR) != -1) {
+                       return (sp);
+               }
+       }
+
+       if (asprintf(&sp, "%s", ZPOOL_SCRIPTS_DIR) != -1)
+               return (sp);
+
+       return (NULL);
+}
+
 /* Thread function run for each vdev */
 static void
 vdev_run_cmd_thread(void *cb_cmd_data)
 {
        vdev_cmd_data_t *data = cb_cmd_data;
-       const char *sep = ",";
-       char *cmd = NULL, *cmddup, *rest;
-       char fullpath[MAXPATHLEN];
+       char *cmd = NULL, *cmddup, *cmdrest;
 
        cmddup = strdup(data->cmd);
        if (cmddup == NULL)
                return;
 
-       rest = cmddup;
-       while ((cmd = strtok_r(rest, sep, &rest))) {
-               if (snprintf(fullpath, sizeof (fullpath), "%s/%s",
-                   ZPOOL_SCRIPTS_DIR, cmd) == -1)
+       cmdrest = cmddup;
+       while ((cmd = strtok_r(cmdrest, ",", &cmdrest))) {
+               char *dir = NULL, *sp, *sprest;
+               char fullpath[MAXPATHLEN];
+
+               sp = zpool_get_cmd_search_path();
+               if (sp == NULL)
                        continue;
 
-               /* Does the script exist in our zpool scripts dir? */
-               if (access(fullpath, X_OK) == 0)
-                       vdev_run_cmd(data, fullpath);
+               sprest = sp;
+               while ((dir = strtok_r(sprest, ":", &sprest))) {
+                       if (snprintf(fullpath, sizeof (fullpath),
+                           "%s/%s", dir, cmd) == -1)
+                               continue;
+
+                       if (access(fullpath, X_OK) == 0) {
+                               vdev_run_cmd(data, fullpath);
+                               break;
+                       }
+               }
+               free(sp);
        }
        free(cmddup);
 }
index f99145da9632f46bdc7361da4f9ebf59dedf5463..5fccd754b4fb8928a223ac8b06e223af9479e2db 100644 (file)
@@ -4190,25 +4190,22 @@ print_zpool_script_help(char *name, char *path)
        libzfs_free_str_array(lines, lines_cnt);
 }
 
-
 /*
- * Go though the list of all the zpool status/iostat -c scripts, run their
+ * Go though the zpool status/iostat -c scripts in the user's path, run their
  * help option (-h), and print out the results.
  */
 static void
-print_zpool_script_list(void)
+print_zpool_dir_scripts(char *dirpath)
 {
        DIR *dir;
        struct dirent *ent;
        char fullpath[MAXPATHLEN];
        struct stat dir_stat;
 
-       if ((dir = opendir(ZPOOL_SCRIPTS_DIR)) != NULL) {
-               printf("\n");
+       if ((dir = opendir(dirpath)) != NULL) {
                /* print all the files and directories within directory */
                while ((ent = readdir(dir)) != NULL) {
-                       sprintf(fullpath, "%s/%s", ZPOOL_SCRIPTS_DIR,
-                           ent->d_name);
+                       sprintf(fullpath, "%s/%s", dirpath, ent->d_name);
 
                        /* Print the scripts */
                        if (stat(fullpath, &dir_stat) == 0)
@@ -4217,14 +4214,33 @@ print_zpool_script_list(void)
                                        print_zpool_script_help(ent->d_name,
                                            fullpath);
                }
-               printf("\n");
                closedir(dir);
-       } else {
-               fprintf(stderr, gettext("Can't open %s scripts dir\n"),
-                   ZPOOL_SCRIPTS_DIR);
        }
 }
 
+/*
+ * Print out help text for all zpool status/iostat -c scripts.
+ */
+static void
+print_zpool_script_list(char *subcommand)
+{
+       char *dir, *sp;
+
+       printf(gettext("Available 'zpool %s -c' commands:\n"), subcommand);
+
+       sp = zpool_get_cmd_search_path();
+       if (sp == NULL)
+               return;
+
+       dir = strtok(sp, ":");
+       while (dir != NULL) {
+               print_zpool_dir_scripts(dir);
+               dir = strtok(NULL, ":");
+       }
+
+       free(sp);
+}
+
 /*
  * zpool iostat [[-c [script1,script2,...]] [-lq]|[-rw]] [-ghHLpPvy] [-n name]
  *              [-T d|u] [[ pool ...]|[pool vdev ...]|[vdev ...]]
@@ -4285,6 +4301,15 @@ zpool_do_iostat(int argc, char **argv)
                                    gettext("Can't set -c flag twice\n"));
                                exit(1);
                        }
+
+                       if (getenv("ZPOOL_SCRIPTS_ENABLED") != NULL &&
+                           !libzfs_envvar_is_set("ZPOOL_SCRIPTS_ENABLED")) {
+                               fprintf(stderr, gettext(
+                                   "Can't run -c, disabled by "
+                                   "ZPOOL_SCRIPTS_ENABLED.\n"));
+                               exit(1);
+                       }
+
                        if ((getuid() <= 0 || geteuid() <= 0) &&
                            !libzfs_envvar_is_set("ZPOOL_SCRIPTS_AS_ROOT")) {
                                fprintf(stderr, gettext(
@@ -4336,10 +4361,7 @@ zpool_do_iostat(int argc, char **argv)
                        break;
                case '?':
                        if (optopt == 'c') {
-                               fprintf(stderr, gettext(
-                                   "Current scripts in %s:\n"),
-                                   ZPOOL_SCRIPTS_DIR);
-                               print_zpool_script_list();
+                               print_zpool_script_list("iostat");
                                exit(0);
                        } else {
                                fprintf(stderr,
@@ -6427,6 +6449,15 @@ zpool_do_status(int argc, char **argv)
                                    gettext("Can't set -c flag twice\n"));
                                exit(1);
                        }
+
+                       if (getenv("ZPOOL_SCRIPTS_ENABLED") != NULL &&
+                           !libzfs_envvar_is_set("ZPOOL_SCRIPTS_ENABLED")) {
+                               fprintf(stderr, gettext(
+                                   "Can't run -c, disabled by "
+                                   "ZPOOL_SCRIPTS_ENABLED.\n"));
+                               exit(1);
+                       }
+
                        if ((getuid() <= 0 || geteuid() <= 0) &&
                            !libzfs_envvar_is_set("ZPOOL_SCRIPTS_AS_ROOT")) {
                                fprintf(stderr, gettext(
@@ -6459,10 +6490,7 @@ zpool_do_status(int argc, char **argv)
                        break;
                case '?':
                        if (optopt == 'c') {
-                               fprintf(stderr, gettext(
-                                   "Current scripts in %s:\n"),
-                                   ZPOOL_SCRIPTS_DIR);
-                               print_zpool_script_list();
+                               print_zpool_script_list("status");
                                exit(0);
                        } else {
                                fprintf(stderr,
index ab7662cfa7b7fcd611926faf88bdc00aa2af537f..aef2cff27d29e0aaa322f3a9ab8acb366ed4e770 100644 (file)
@@ -44,6 +44,11 @@ uint_t num_logs(nvlist_t *nv);
 uint64_t array64_max(uint64_t array[], unsigned int len);
 int isnumber(char *str);
 
+/*
+ * Misc utility functions
+ */
+char *zpool_get_cmd_search_path(void);
+
 /*
  * Virtual device functions
  */
index 06b6662fd0edad8bdfee5cdb756ba57ed8dd72a4..c52d72e3dd846283785d8f8e955ba55cda60e56b 100644 (file)
@@ -65,6 +65,7 @@ AC_CONFIG_FILES([
        etc/zfs/Makefile
        etc/systemd/Makefile
        etc/systemd/system/Makefile
+       etc/sudoers.d/Makefile
        etc/modules-load.d/Makefile
        man/Makefile
        man/man1/Makefile
index a62678b4e561492faa50c23bc0258ed1607118fe..28b955106e5f84a0d75776872c731671511c6edf 100644 (file)
@@ -1,2 +1,2 @@
-SUBDIRS = zfs $(ZFS_INIT_SYSTEMD) $(ZFS_INIT_SYSV) $(ZFS_MODULE_LOAD)
-DIST_SUBDIRS = init.d zfs systemd modules-load.d
+SUBDIRS = zfs sudoers.d $(ZFS_INIT_SYSTEMD) $(ZFS_INIT_SYSV) $(ZFS_MODULE_LOAD)
+DIST_SUBDIRS = init.d zfs systemd modules-load.d sudoers.d
diff --git a/etc/sudoers.d/Makefile.am b/etc/sudoers.d/Makefile.am
new file mode 100644 (file)
index 0000000..ca9186a
--- /dev/null
@@ -0,0 +1,5 @@
+sudoersddir = $(sysconfdir)/sudoers.d
+sudoersd_DATA = zfs
+
+EXTRA_DIST = \
+       $(top_srcdir)/etc/sudoers.d/zfs
diff --git a/etc/sudoers.d/zfs b/etc/sudoers.d/zfs
new file mode 100644 (file)
index 0000000..f66ebad
--- /dev/null
@@ -0,0 +1,8 @@
+##
+## Allow any user to run `zpool iostat/status -c smart` in order
+## to read basic SMART health statistics for a pool.
+##
+## CAUTION: Any syntax error introduced here will break sudo.
+##
+
+# ALL ALL = (root) NOPASSWD: /usr/sbin/smartctl -a /dev/[hsv]d[a-z0-9]*
index ff3db440dad52f9df1b048389a55169ece138b2d..190b9dfc0fde7caef46efb92028ba80adc62b359 100644 (file)
@@ -1550,14 +1550,13 @@ Run a script (or scripts) on each vdev and include the output in zpool iostat
 .sp
 The \fB-c\fR option allows you to run script(s) for each vdev and display the
 output in zpool iostat.  For security reasons, a user can only execute scripts
-found in the /<etc>/zfs/zpool.d directory as an unprivileged user.  However, a
-privileged user can run \fB-c\fR if they have the ZPOOL_SCRIPTS_AS_ROOT
-environment variable set.  If a script requires the use of a privileged
-command (like smartctl) then it's recommended you allow the user access to it in
-/etc/sudoers.  For example, to allow user "zfsuser" access to "smartctl -a", add
-the following to /etc/sudoers:
-
-zfsuser ALL=NOPASSWD: /usr/sbin/smartctl -a /dev/sd[a-z]*, NOEXEC: /usr/sbin/smartctl -a /dev/sd[a-z]*`
+as an unprivileged user.  By default, a user may run a script from ~/.zpool.d
+or /etc/zfs/zpool.d.  The default search path can be overriden by setting
+the \fBZPOOL_SCRIPTS_PATH\fR environment variable.  A privileged user can run
+\fB-c\fR if they have the \fBZPOOL_SCRIPTS_AS_ROOT\fR environment variable set.
+If a script requires the use of a privileged command (like \fBsmartctl(8)\fR)
+then it's recommended you allow the user access to it in /etc/sudoers or add
+the user to the /etc/sudoers.d/zfs file.
 
 If \fB-c\fR is passed without a script name, it prints a list of all scripts.
 \fB-c\fR also sets verbose mode (\fB-v\fR).
@@ -2148,15 +2147,14 @@ If a scrub or resilver is in progress, this command reports the percentage done
 Run a script (or scripts) on each vdev and include the output in zpool status
 .sp
 The \fB-c\fR option allows you to run script(s) for each vdev and display the
-output in zpool iostat.  For security reasons, a user can only execute scripts
-found in the /<etc>/zfs/zpool.d directory as an unprivileged user.  However, a
-privileged user can run \fB-c\fR if they have the ZPOOL_SCRIPTS_AS_ROOT
-environment variable set.  If a script requires the use of a privileged
-command (like smartctl) then it's recommended you allow the user access to it in
-/etc/sudoers.  For example, to allow user "zfsuser" access to "smartctl -a", add
-the following to /etc/sudoers:
-
-zfsuser ALL=NOPASSWD: /usr/sbin/smartctl -a /dev/sd[a-z]*, NOEXEC: /usr/sbin/smartctl -a /dev/sd[a-z]*`
+output in zpool status.  For security reasons, a user can only execute scripts
+as an unprivileged user.  By default, a user may run a script from ~/.zpool.d
+or /etc/zfs/zpool.d.  The default search path can be overriden by setting
+the \fBZPOOL_SCRIPTS_PATH\fR environment variable.  A privileged user can run
+\fB-c\fR if they have the \fBZPOOL_SCRIPTS_AS_ROOT\fR environment variable set.
+If a script requires the use of a privileged command (like \fBsmartctl(8)\fR)
+then it's recommended you allow the user access to it in /etc/sudoers or add
+the user to the /etc/sudoers.d/zfs file.
 
 If \fB-c\fR is passed without a script name, it prints a list of all scripts.
 
@@ -2727,6 +2725,16 @@ them on \fBzpool create\fR or \fBzpool add\fR by setting ZFS_VDEV_DEVID_OPT_OUT.
 .B "ZPOOL_SCRIPTS_AS_ROOT"
 Allow a privilaged user to run the \fBzpool status/iostat\fR with the \fB-c\fR
 option.  Normally, only unprivilaged users are allowed to run \fB-c\fR.
+.TP
+.B "ZPOOL_SCRIPTS_PATH"
+The search path for scripts when running \fBzpool status/iostat\fR with the \fB-c\fR
+option. This is a colon-separated list of directories and overrides the default
+~/.zpool.d and /etc/zfs/zpool.d search paths.
+.TP
+.B "ZPOOL_SCRIPTS_ENABLED"
+Allow a user to run \fBzpool status/iostat\fR with the \fB-c\fR option. If
+ZPOOL_SCRIPTS_ENABLED is not set, it is assumed that the user is allowed to
+run \fBzpool status/iostat -c\fR.
 
 .SH SEE ALSO
 .sp
index 2ad4b693c1b511b95c694862c7026243411c7453..c62d76346e40ff740cbe4daff2b9a6ef69a24f16 100644 (file)
@@ -181,6 +181,7 @@ Requires:       bc
 Requires:       ksh
 Requires:      fio
 Requires:      acl
+Requires:      sudo
 Requires:      sysstat
 
 %description test
@@ -290,6 +291,7 @@ exit 0
 %config(noreplace) %{_initconfdir}/zfs
 %endif
 %config(noreplace) %{_sysconfdir}/%{name}
+%attr(440, root, root) %config(noreplace) %{_sysconfdir}/sudoers.d/*
 
 %files -n libzpool2
 %{_libdir}/libzpool.so.*
index 0354cc0ed0538cd2873d4f19f0250355027c4743..d2da575f483dfd28ec9d94f73e819a811d1f2542 100755 (executable)
@@ -14,6 +14,7 @@
 #   --with-mounthelperdir=DIR  install mount.zfs in dir [/sbin]
 #   --with-udevdir=DIR         install udev helpers [default=check]
 #   --with-udevruledir=DIR     install udev rules [default=UDEVDIR/rules.d]
+#   --sysconfdir=DIR           install zfs configuration files [PREFIX/etc]
 #
 
 basedir="$(dirname $0)"
@@ -96,6 +97,7 @@ if [ "$VERBOSE" ]; then
        echo "udevdir:          $udevdir"
        echo "udevruledir:      $udevruledir"
        echo "mounthelperdir:   $mounthelperdir"
+       echo "sysconfdir:       $sysconfdir"
        echo "DRYRUN:           $DRYRUN"
        echo
 fi
@@ -114,6 +116,7 @@ install() {
                msg "ln -s $src $dst"
 
                if [ ! "$DRYRUN" ]; then
+                       mkdir -p $(dirname $dst) &>/dev/null
                        ln -s $src $dst
                fi
        fi
@@ -125,6 +128,7 @@ remove() {
        if [ -h $dst ]; then
                msg "rm $dst"
                rm $dst
+               rmdir $(dirname $dst) &>/dev/null
        fi
 }
 
@@ -136,6 +140,7 @@ if [ ${INSTALL} ]; then
        install $UDEVRULEDIR/60-zvol.rules $udevruledir/60-zvol.rules
        install $UDEVRULEDIR/69-vdev.rules $udevruledir/69-vdev.rules
        install $UDEVRULEDIR/90-zfs.rules $udevruledir/90-zfs.rules
+       install $CMDDIR/zpool/zpool.d $sysconfdir/zfs/zpool.d
 else
        remove $mounthelperdir/mount.zfs
        remove $mounthelperdir/fsck.zfs
@@ -144,6 +149,7 @@ else
        remove $udevruledir/60-zvol.rules
        remove $udevruledir/69-vdev.rules
        remove $udevruledir/90-zfs.rules
+       remove $sysconfdir/zfs/zpool.d
 fi
 
 exit 0
index 674684f1fdc0283886ec36113946f8622cd81714..115b9b025f856e805e41ae1a6bbe6256c7f101bb 100644 (file)
@@ -279,7 +279,9 @@ pre =
 post =
 
 [tests/functional/cli_root/zpool_status]
-tests = ['zpool_status_001_pos', 'zpool_status_002_pos','zpool_status_003_pos']
+tests = ['zpool_status_001_pos', 'zpool_status_002_pos','zpool_status_003_pos',
+    'zpool_status_-c_disable', 'zpool_status_-c_homedir',
+    'zpool_status_-c_searchpath']
 user =
 
 [tests/functional/cli_root/zpool_sync]
@@ -318,7 +320,8 @@ user =
 [tests/functional/cli_user/zpool_iostat]
 tests = ['zpool_iostat_001_neg', 'zpool_iostat_002_pos',
     'zpool_iostat_003_neg', 'zpool_iostat_004_pos',
-    'zpool_iostat_005_pos']
+    'zpool_iostat_005_pos', 'zpool_iostat_-c_disable',
+    'zpool_iostat_-c_homedir', 'zpool_iostat_-c_searchpath']
 user =
 
 [tests/functional/cli_user/zpool_list]
index 747ec1dfa22280d262e438c6810f70ba53c63f84..aab4de0e7c89c1ad50808001b77414dc29168e86 100644 (file)
@@ -4,4 +4,7 @@ dist_pkgdata_SCRIPTS = \
        cleanup.ksh \
        zpool_status_001_pos.ksh \
        zpool_status_002_pos.ksh \
-       zpool_status_003_pos.ksh
+       zpool_status_003_pos.ksh \
+       zpool_status_-c_disable.ksh \
+       zpool_status_-c_homedir.ksh \
+       zpool_status_-c_searchpath.ksh
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_-c_disable.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_-c_disable.ksh
new file mode 100755 (executable)
index 0000000..c8105fb
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2017 by Lawrence Livermore National Security, LLC.
+#
+
+# DESCRIPTION:
+#      Verify zpool status command mode (-c) respects ZPOOL_SCRIPTS_ENABLED.
+#
+# STRATEGY:
+#      1. Set ZPOOL_SCRIPTS_ENABLED to 0, disabling zpool status -c
+#      2. zpool status -c must not run successfully
+#      3. Set ZPOOL_SCRIPTS_ENABLED to 1, enabling zpool status -c
+#      4. zpool status -c must run successfully
+#      5. Unset ZPOOL_SCRIPTS_ENABLED, enabling zpool status -c
+#      6. zpool status -c must run successfully
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/include/zpool_script.shlib
+
+verify_runnable "both"
+
+log_assert "zpool status -c properly handles ZPOOL_SCRIPTS_ENABLED"
+
+export ZPOOL_SCRIPTS_ENABLED=0
+log_mustnot zpool status -c media
+
+export ZPOOL_SCRIPTS_ENABLED=1
+log_must zpool status -c media
+
+unset ZPOOL_SCRIPTS_ENABLED
+log_must zpool status -c media
+
+log_pass "zpool status -c properly handles ZPOOL_SCRIPTS_ENABLED passed"
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_-c_homedir.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_-c_homedir.ksh
new file mode 100755 (executable)
index 0000000..4cc3deb
--- /dev/null
@@ -0,0 +1,76 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2017 by Lawrence Livermore National Security, LLC.
+#
+
+# DESCRIPTION:
+#      Verify zpool status command mode (-c) works with scripts in user's
+#      home directory.
+#
+# STRATEGY:
+#      1. Change HOME to /var/tmp
+#      2. Make a simple script that echos a key value pair
+#         in /var/tmp/.zpool.d
+#      3. Make sure it can be run with -c
+#      4. Remove the script we created
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/include/zpool_script.shlib
+
+verify_runnable "both"
+
+# In tree testing sets this variable, we need to unset it
+# to restore zpool's search path.
+unset ZPOOL_SCRIPTS_PATH
+
+# change HOME
+export HOME="$TEST_BASE_DIR"
+typeset USER_SCRIPT_FULL="$HOME/.zpool.d/userscript"
+
+function cleanup
+{
+       log_must rm -rf "$HOME/.zpool.d"
+}
+
+log_assert "zpool status -c can run scripts from ~/.zpool.d"
+
+if [ -e "$USER_SCRIPT_FULL" ]; then
+       log_fail "$USER_SCRIPT_FULL already exists."
+fi
+
+log_onexit cleanup
+
+# create simple script
+log_must mkdir -p "$HOME/.zpool.d"
+cat > "$USER_SCRIPT_FULL" << EOF
+#!/bin/sh
+echo "USRCOL=USRVAL"
+EOF
+log_must chmod +x "$USER_SCRIPT_FULL"
+
+# test that we can run the script
+typeset USER_SCRIPT=$(basename "$USER_SCRIPT_FULL")
+test_zpool_script "$USER_SCRIPT" "$TESTPOOL" "zpool status -P -c"
+
+log_pass "zpool status -c can run scripts from ~/.zpool.d passed"
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_-c_searchpath.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_status/zpool_status_-c_searchpath.ksh
new file mode 100755 (executable)
index 0000000..a075b9a
--- /dev/null
@@ -0,0 +1,88 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2017 by Lawrence Livermore National Security, LLC.
+#
+
+# DESCRIPTION:
+#      Verify zpool status command mode (-c) works with ZPOOL_SCRIPTS_PATH
+# defined.
+#
+# STRATEGY:
+#      1. Set ZPOOL_SCRIPTS_PATH to contain a couple of non-default dirs
+#      2. Make a simple script that echos a key value pair in each dir
+#      3. Make sure scripts can be run with -c
+#      4. Remove the scripts we created
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/include/zpool_script.shlib
+
+verify_runnable "both"
+
+typeset SCRIPT_1="$TEST_BASE_DIR/scripts1/test1"
+typeset SCRIPT_2="$TEST_BASE_DIR/scripts2/test2"
+
+function cleanup
+{
+       log_must rm -rf $(dirname "$SCRIPT_1")
+       log_must rm -rf $(dirname "$SCRIPT_2")
+}
+
+log_assert "zpool status -c can run scripts from custom search path"
+
+if [ -e "$SCRIPT_1" ]; then
+       log_fail "$SCRIPT_1 already exists."
+fi
+
+if [ -e "$SCRIPT_2" ]; then
+       log_fail "$SCRIPT_2 already exists."
+fi
+
+log_onexit cleanup
+
+# change zpool status search path
+export ZPOOL_SCRIPTS_PATH="$(dirname $SCRIPT_1):$(dirname $SCRIPT_2)"
+
+# create simple script in each dir
+log_must mkdir -p $(dirname "$SCRIPT_1")
+cat > "$SCRIPT_1" << EOF
+#!/bin/sh
+echo "USRCOL1=USRVAL1"
+EOF
+log_must chmod +x "$SCRIPT_1"
+
+log_must mkdir -p $(dirname "$SCRIPT_2")
+cat > "$SCRIPT_2" << EOF
+#!/bin/sh
+echo "USRCOL2=USRVAL2"
+EOF
+log_must chmod +x "$SCRIPT_2"
+
+# test that we can run the scripts
+typeset CMD_1=$(basename "$SCRIPT_1")
+typeset CMD_2=$(basename "$SCRIPT_2")
+test_zpool_script "$CMD_1" "$TESTPOOL" "zpool status -P -c"
+test_zpool_script "$CMD_2" "$TESTPOOL" "zpool status -P -c"
+test_zpool_script "$CMD_2,$CMD_1" "$TESTPOOL" "zpool status -P -c"
+
+log_pass "zpool status -c can run scripts from custom search path passed"
index cadf9439a9e15c67e15a36f45bf48f078087a00e..5ee30eafc35822d94712efde6d7e38fbafb3ddc1 100644 (file)
@@ -6,4 +6,7 @@ dist_pkgdata_SCRIPTS = \
        zpool_iostat_002_pos.ksh \
        zpool_iostat_003_neg.ksh \
        zpool_iostat_004_pos.ksh \
-       zpool_iostat_005_pos.ksh
+       zpool_iostat_005_pos.ksh \
+       zpool_iostat_-c_disable.ksh \
+       zpool_iostat_-c_searchpath.ksh \
+       zpool_iostat_-c_homedir.ksh
diff --git a/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_-c_disable.ksh b/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_-c_disable.ksh
new file mode 100755 (executable)
index 0000000..0d64eb0
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2017 by Lawrence Livermore National Security, LLC.
+#
+
+# DESCRIPTION:
+#      Verify zpool iostat command mode (-c) respects ZPOOL_SCRIPTS_ENABLED.
+#
+# STRATEGY:
+#      1. Set ZPOOL_SCRIPTS_ENABLED to 0, disabling zpool iostat -c
+#      2. zpool iostat -c must not run successfully
+#      3. Set ZPOOL_SCRIPTS_ENABLED to 1, enabling zpool iostat -c
+#      4. zpool iostat -c must run successfully
+#      5. Unset ZPOOL_SCRIPTS_ENABLED, enabling zpool iostat -c
+#      6. zpool iostat -c must run successfully
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/include/zpool_script.shlib
+
+verify_runnable "both"
+
+log_assert "zpool iostat -c properly handles ZPOOL_SCRIPTS_ENABLED"
+
+export ZPOOL_SCRIPTS_ENABLED=0
+log_mustnot zpool iostat -c media
+
+export ZPOOL_SCRIPTS_ENABLED=1
+log_must zpool iostat -c media
+
+unset ZPOOL_SCRIPTS_ENABLED
+log_must zpool iostat -c media
+
+log_pass "zpool iostat -c properly handles ZPOOL_SCRIPTS_ENABLED passed"
diff --git a/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_-c_homedir.ksh b/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_-c_homedir.ksh
new file mode 100755 (executable)
index 0000000..5cb50fd
--- /dev/null
@@ -0,0 +1,76 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2017 by Lawrence Livermore National Security, LLC.
+#
+
+# DESCRIPTION:
+#      Verify zpool iostat command mode (-c) works with scripts in user's
+#      home directory.
+#
+# STRATEGY:
+#      1. Change HOME to /var/tmp
+#      2. Make a simple script that echos a key value pair
+#         in /var/tmp/.zpool.d
+#      3. Make sure it can be run with -c
+#      4. Remove the script we created
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/include/zpool_script.shlib
+
+verify_runnable "both"
+
+# In tree testing sets this variable, we need to unset it
+# to restore zpool's search path.
+unset ZPOOL_SCRIPTS_PATH
+
+# change HOME
+export HOME="$TEST_BASE_DIR"
+typeset USER_SCRIPT_FULL="$HOME/.zpool.d/userscript"
+
+function cleanup
+{
+       log_must rm -rf "$HOME/.zpool.d"
+}
+
+log_assert "zpool iostat -c can run scripts from ~/.zpool.d"
+
+if [ -e "$USER_SCRIPT_FULL" ]; then
+       log_fail "$USER_SCRIPT_FULL already exists."
+fi
+
+log_onexit cleanup
+
+# create simple script
+log_must mkdir -p "$HOME/.zpool.d"
+cat > "$USER_SCRIPT_FULL" << EOF
+#!/bin/sh
+echo "USRCOL=USRVAL"
+EOF
+log_must chmod +x "$USER_SCRIPT_FULL"
+
+# test that we can run the script
+typeset USER_SCRIPT=$(basename "$USER_SCRIPT_FULL")
+test_zpool_script "$USER_SCRIPT" "$TESTPOOL" "zpool iostat -P -c"
+
+log_pass "zpool iostat -c can run scripts from ~/.zpool.d passed"
diff --git a/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_-c_searchpath.ksh b/tests/zfs-tests/tests/functional/cli_user/zpool_iostat/zpool_iostat_-c_searchpath.ksh
new file mode 100755 (executable)
index 0000000..1197ea2
--- /dev/null
@@ -0,0 +1,88 @@
+#!/bin/ksh -p
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2017 by Lawrence Livermore National Security, LLC.
+#
+
+# DESCRIPTION:
+#      Verify zpool iostat command mode (-c) works with ZPOOL_SCRIPTS_PATH
+# defined.
+#
+# STRATEGY:
+#      1. Set ZPOOL_SCRIPTS_PATH to contain a couple of non-default dirs
+#      2. Make a simple script that echos a key value pair in each dir
+#      3. Make sure scripts can be run with -c
+#      4. Remove the scripts we created
+
+. $STF_SUITE/include/libtest.shlib
+. $STF_SUITE/include/zpool_script.shlib
+
+verify_runnable "both"
+
+typeset SCRIPT_1="$TEST_BASE_DIR/scripts1/test1"
+typeset SCRIPT_2="$TEST_BASE_DIR/scripts2/test2"
+
+function cleanup
+{
+       log_must rm -rf $(dirname "$SCRIPT_1")
+       log_must rm -rf $(dirname "$SCRIPT_2")
+}
+
+log_assert "zpool iostat -c can run scripts from custom search path"
+
+if [ -e "$SCRIPT_1" ]; then
+       log_fail "$SCRIPT_1 already exists."
+fi
+
+if [ -e "$SCRIPT_2" ]; then
+       log_fail "$SCRIPT_2 already exists."
+fi
+
+log_onexit cleanup
+
+# change zpool iostat search path
+export ZPOOL_SCRIPTS_PATH="$(dirname $SCRIPT_1):$(dirname $SCRIPT_2)"
+
+# create simple script in each dir
+log_must mkdir -p $(dirname "$SCRIPT_1")
+cat > "$SCRIPT_1" << EOF
+#!/bin/sh
+echo "USRCOL1=USRVAL1"
+EOF
+log_must chmod +x "$SCRIPT_1"
+
+log_must mkdir -p $(dirname "$SCRIPT_2")
+cat > "$SCRIPT_2" << EOF
+#!/bin/sh
+echo "USRCOL2=USRVAL2"
+EOF
+log_must chmod +x "$SCRIPT_2"
+
+# test that we can run the scripts
+typeset CMD_1=$(basename "$SCRIPT_1")
+typeset CMD_2=$(basename "$SCRIPT_2")
+test_zpool_script "$CMD_1" "$TESTPOOL" "zpool iostat -P -c"
+test_zpool_script "$CMD_2" "$TESTPOOL" "zpool iostat -P -c"
+test_zpool_script "$CMD_2,$CMD_1" "$TESTPOOL" "zpool iostat -P -c"
+
+log_pass "zpool iostat -c can run scripts from custom search path passed"
index 593b4d00e023a91b474f14b9b0329d2ef539ac92..f1006b3f7f83a26e6b33c028d55a2f6b3e6911e5 100644 (file)
@@ -24,6 +24,7 @@ export UDEVRULEDIR=${BUILDDIR}/udev/rules.d
 export ZEDLET_ETC_DIR=${SRCDIR}/cmd/zed/zed.d
 export ZEDLET_LIBEXEC_DIR=${SRCDIR}/cmd/zed/zed.d
 export ZPOOL_SCRIPT_DIR=${SRCDIR}/cmd/zpool/zpool.d
+export ZPOOL_SCRIPTS_PATH=${SRCDIR}/cmd/zpool/zpool.d
 
 export ZDB=${CMDDIR}/zdb/zdb
 export ZFS=${CMDDIR}/zfs/zfs