SUBDIRS = zfs zpool zdb zhack zinject zstreamdump ztest zpios
SUBDIRS += mount_zfs fsck_zfs zvol_id vdev_id arcstat dbufstat zed
-SUBDIRS += arc_summary raidz_test
+SUBDIRS += arc_summary raidz_test zgenhostid
--- /dev/null
+dist_bin_SCRIPTS = zgenhostid
--- /dev/null
+#!/bin/bash
+
+# Emulate genhostid(1) available on RHEL/CENTOS, for use on distros
+# which do not provide that utility.
+#
+# Usage:
+# zgenhostid
+# zgenhostid <value>
+#
+# If /etc/hostid already exists and is size > 0, the script exits immediately
+# and changes nothing. Unlike genhostid, this generates an error message.
+#
+# The first form generates a random hostid and stores it in /etc/hostid.
+# The second form checks that the provided value is between 0x1 and 0xFFFFFFFF
+# and if so, stores it in /etc/hostid. This form is not supported by
+# genhostid(1).
+
+hostid_file=/etc/hostid
+
+function usage {
+ echo "$0 [value]"
+ echo "If $hostid_file is not present, store a hostid in it." >&2
+ echo "The optional value must be an 8-digit hex number between" >&2
+ echo "1 and 2^32-1. If no value is provided, a random one will" >&2
+ echo "be generated. The value must be unique among your systems." >&2
+}
+
+# hostid(1) ignores contents of /etc/hostid if size < 4 bytes. It would
+# be better if this checked size >= 4 bytes but it the method must be
+# widely portable.
+if [ -s $hostid_file ]; then
+ echo "$hostid_file already exists. No change made." >&2
+ exit 1
+fi
+
+if [ -n "$1" ]; then
+ host_id=$1
+else
+ # $RANDOM goes from 0..32k-1
+ number=$((((RANDOM % 4) * 32768 + RANDOM) * 32768 + RANDOM))
+ host_id=$(printf "%08x" $number)
+fi
+
+if egrep -o '^0{8}$' <<< $host_id >/dev/null 2>&1; then
+ usage
+ exit 2
+fi
+
+if ! egrep -o '^[a-fA-F0-9]{8}$' <<< $host_id >/dev/null 2>&1; then
+ usage
+ exit 3
+fi
+
+a=${host_id:6:2}
+b=${host_id:4:2}
+c=${host_id:2:2}
+d=${host_id:0:2}
+
+echo -ne \\x$a\\x$b\\x$c\\x$d > $hostid_file
+
+exit 0
break;
case ZPOOL_STATUS_HOSTID_REQUIRED:
(void) printf(gettext(" action: Set a unique system "
- "hostid with the genhostid(1) command.\n"));
+ "hostid with the zgenhostid(8) command.\n"));
break;
default:
(void) printf(gettext(" action: The pool cannot be "
(void) fprintf(stderr, gettext("Cannot import '%s': "
"pool has the multihost property on and the\n"
"system's hostid is not set. Set a unique hostid "
- "with the genhostid(1) command.\n"), name);
+ "with the zgenhostid(8) command.\n"), name);
} else {
char *hostname = "<unknown>";
uint64_t timestamp = 0;
cmd/arc_summary/Makefile
cmd/zed/Makefile
cmd/raidz_test/Makefile
+ cmd/zgenhostid/Makefile
contrib/Makefile
contrib/bash_completion.d/Makefile
contrib/dracut/Makefile
"the multihost property on and "
"the\nsystem's hostid is not set. "
"Set a unique system hostid with "
- "the genhostid(1) command.\n"));
+ "the zgenhostid(8) command.\n"));
}
(void) zfs_error_aux(hdl, aux);
vdev_id.8 \
zdb.8 \
zfs.8 \
+ zgenhostid.8
zinject.8 \
zpool.8 \
zstreamdump.8
--- /dev/null
+.\"
+.\" 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.
+.\"
+.Dd July 24, 2017
+.Dt ZGENHOSTID 8 SMM
+.Os Linux
+.Sh NAME
+.Nm zgenhostid
+.Nd generate and store a hostid in
+.Em /etc/hostid
+.Sh SYNOPSIS
+.Nm
+.Op Ar hostid
+.Sh DESCRIPTION
+If
+.Em /etc/hostid
+does not exist, create it and store a hostid in it. If the user provides
+.Op Ar hostid
+on the command line, store that value. Otherwise, randomly generate a
+value to store.
+.Pp
+This emulates the
+.Xr genhostid 1
+utility and is provided for use on systems which do not include the utility.
+.Pp
+.Sh OPTIONS
+.Op Ar hostid
+Specifies the value to be placed in
+.Em /etc/hostid .
+It must be a number with a value between 1 and 2^32-1. This value
+.Sy must
+be unique among your systems. It must be expressed in hexadecimal and be
+exactly 8 digits long.
+.Sh EXAMPLES
+.Bl -tag -width Ds
+.It Generate a random hostid and store it
+.Bd -literal
+# zgenhostid
+.Ed
+.It Record the libc-generated hostid in Em /etc/hostid
+.Bd -literal
+# zgenhostid $(hostid)
+.Ed
+.It Record a custom hostid (0xdeadbeef) in Em etc/hostid
+.Bd -literal
+# zgenhostid deadbeef
+.Ed
+.El
+.Sh SEE ALSO
+.Xr spl-module-parameters 5 ,
+.Xr genhostid 1 ,
+.Xr hostid 1
man page. In order to enable this property each host must set a unique hostid.
See
.Xr genhostid 1
-and
+.Xr zgenhostid 8
.Xr spl-module-paramters 5
for additional details. The default value is
.Sy off .
arcstat.py
dbufstat.py
zed
+ zgenhostid
zstreamdump'
export ZFSTEST_FILES='chg_usr_exec
{
typeset hostid=$1
- a=${hostid:6:2}
- b=${hostid:4:2}
- c=${hostid:2:2}
- d=${hostid:0:2}
-
- printf "\\x$a\\x$b\\x$c\\x$d" >$HOSTID_FILE
+ zgenhostid $1
if [ $(hostid) != "$hostid" ]; then
return 1
log_must mkdir -p $dir
log_must truncate -s $MINVDEVSIZE $dir/vdev1 $dir/vdev2
+ log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID1
log_must zpool create -f $pool mirror $dir/vdev1 $dir/vdev2
log_must zpool set multihost=on $pool
log_must zpool export $pool
+ log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
log_note "Starting ztest in the background as hostid $HOSTID1"
typeset pool=$1
typeset hostid=$2
+ log_must mmp_clear_hostid
log_must mmp_set_hostid $hostid
log_must zpool export $pool
log_must zpool import $pool
MMP_IMPORTED_MSG="The pool can be imported"
log_must check_pool_import $MMP_POOL "-d $MMP_DIR" "action" $MMP_IMPORTED_MSG
+log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
MMP_IMPORTED_MSG="The pool was last accessed by another system."
log_must check_pool_import $MMP_POOL "-d $MMP_DIR" "status" $MMP_IMPORTED_MSG
for opt in "" "-f"; do
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
log_must zpool export $TESTPOOL
+ log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
log_must import_no_activity_check $TESTPOOL $opt
done
for opt in "" "-f"; do
log_must mmp_pool_set_hostid $TESTPOOL $HOSTID1
log_must zpool export $TESTPOOL
+ log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
log_must import_no_activity_check $TESTPOOL $opt
done
# 3. Verify multihost=off and hostids differ (no activity check)
log_must zpool export -F $TESTPOOL
+log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
log_mustnot import_no_activity_check $TESTPOOL ""
log_must import_no_activity_check $TESTPOOL "-f"
# 6. Verify multihost=on and hostids differ (activity check)
log_must zpool export -F $TESTPOOL
+log_must mmp_clear_hostid
log_must mmp_set_hostid $HOSTID2
log_mustnot import_activity_check $TESTPOOL ""
log_must import_activity_check $TESTPOOL "-f"