summaryrefslogtreecommitdiff
path: root/usr/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/test')
-rw-r--r--usr/src/test/Readme.smartos80
-rw-r--r--usr/src/test/libc-tests/runfiles/default.run2
-rw-r--r--usr/src/test/libc-tests/tests/Makefile1
-rw-r--r--usr/src/test/libc-tests/tests/env-OS-4089.c73
-rw-r--r--usr/src/test/libc-tests/tests/random/Makefile10
-rw-r--r--usr/src/test/os-tests/cmd/ostest.ksh9
-rw-r--r--usr/src/test/os-tests/runfiles/Makefile5
-rw-r--r--usr/src/test/os-tests/runfiles/default.run (renamed from usr/src/test/os-tests/runfiles/delphix.run)7
-rw-r--r--usr/src/test/os-tests/runfiles/openindiana.run28
-rw-r--r--usr/src/test/os-tests/tests/Makefile2
-rw-r--r--usr/src/test/os-tests/tests/file-locking/Makefile77
-rw-r--r--usr/src/test/os-tests/tests/file-locking/acquire-lock.c161
-rw-r--r--usr/src/test/os-tests/tests/file-locking/runtests.c677
-rw-r--r--usr/src/test/os-tests/tests/file-locking/util.c175
-rw-r--r--usr/src/test/os-tests/tests/file-locking/util.h49
-rw-r--r--usr/src/test/os-tests/tests/tmpfs/Makefile52
-rw-r--r--usr/src/test/os-tests/tests/tmpfs/tmpfs_badmount.ksh114
-rw-r--r--usr/src/test/os-tests/tests/tmpfs/tmpfs_enospc.ksh74
-rw-r--r--usr/src/test/os-tests/tests/tmpfs/tmpfs_full.c94
-rw-r--r--usr/src/test/test-runner/cmd/Makefile4
-rw-r--r--usr/src/test/test-runner/cmd/run.py2
-rw-r--r--usr/src/test/util-tests/runfiles/default.run5
-rw-r--r--usr/src/test/util-tests/tests/Makefile3
-rw-r--r--usr/src/test/util-tests/tests/bunyan/Makefile68
-rw-r--r--usr/src/test/util-tests/tests/bunyan/btest.c312
-rw-r--r--usr/src/test/util-tests/tests/bunyan/bunyan.ksh (renamed from usr/src/test/os-tests/runfiles/omnios.run)22
-rw-r--r--usr/src/test/util-tests/tests/dladm/Makefile2
-rw-r--r--usr/src/test/util-tests/tests/dladm/vnic-mtu.ksh116
-rw-r--r--usr/src/test/util-tests/tests/libnvpair_json/Makefile21
-rw-r--r--usr/src/test/util-tests/tests/libnvpair_json/json_08_large_data.ksh37
-rw-r--r--usr/src/test/util-tests/tests/mergeq/Makefile64
-rw-r--r--usr/src/test/util-tests/tests/mergeq/mqt.c217
-rw-r--r--usr/src/test/util-tests/tests/workq/Makefile64
-rw-r--r--usr/src/test/util-tests/tests/workq/wqt.c196
34 files changed, 2749 insertions, 74 deletions
diff --git a/usr/src/test/Readme.smartos b/usr/src/test/Readme.smartos
new file mode 100644
index 0000000000..12a430c4d5
--- /dev/null
+++ b/usr/src/test/Readme.smartos
@@ -0,0 +1,80 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016, Joyent, Inc.
+#
+
+I) Introduction
+
+The procedure to run the illumos tests under SmartOS is unlike that for
+other distributions because of the zone-centric nature of the distribution,
+and because there is no built-in package management for the global zone.
+
+This Readme assumes you will run the tests in the global zone, as root.
+Although it is possible to run some of the tests within a non-global zone, as a
+user configured within that zone, that approach is not described here.
+
+Some test suites, such as the ZFS tests, assume there are available disks to
+use for the test run. This configuration is not currently available on a
+standard SmartOS installation, where all of the disks are already setup in the
+"zones" zpool, so these tests are not runnable at this time. The ZFS tests
+also are required to run as a non-root user, and that is non-standard for a
+SmartOS global zone, where any user created is lost on reboot.
+
+II) Setup to Run the Tests
+
+1) The tests currently require python26 to run, so you need to install this in
+ the global zone. The easiest way to do this is with pkgsrc using the
+ following procedure:
+
+ a) Get a copy of the following bootstrap tarball onto the test machine:
+ https://pkgsrc.joyent.com/packages/SmartOS/bootstrap/bootstrap-2014Q4-multiarch.tar.gz
+
+ b) Install the bootstrap tarball:
+ # gzcat bootstrap-2014Q4-multiarch.tar.gz | (cd /; tar -xpf -)
+
+ c) Install python26:
+ pkgin in python26
+
+2) You need to get the tests from your build machine onto the test machine's
+ global zone. This can be done in whatever way is easiest for you. Here is
+ one simple way:
+
+ a) On your build machine, in your fully built smartos-live proto area,
+ create a tarball of the test directory:
+ % cd proto/opt
+ % tar czf ../opt.tgz *
+
+
+ b) Copy the tarball from the build machine to the test machine running
+ SmartOS (the next step assumes you placed the tarball into the /zones
+ directory).
+
+3) In the global zone on your test machine, install the tests.
+
+ # cd /opt
+ # tar xf /zones/opt.tgz
+
+III) Run the Tests
+
+Now that setup is complete, you can run the tests using the normal procedure.
+For example:
+
+ # /opt/util-tests/bin/utiltest
+or
+ # /opt/os-tests/bin/ostest
+
+IV) Running New Tests
+
+During development, if you are creating or updating new tests, you can repeat
+steps 2 and 3 as often as necessary to make the new tests available on the test
+machine.
diff --git a/usr/src/test/libc-tests/runfiles/default.run b/usr/src/test/libc-tests/runfiles/default.run
index 5880329fd1..88b46eeba9 100644
--- a/usr/src/test/libc-tests/runfiles/default.run
+++ b/usr/src/test/libc-tests/runfiles/default.run
@@ -63,6 +63,8 @@ outputdir = /var/tmp/test_results
[/opt/libc-tests/tests/call_once.32]
[/opt/libc-tests/tests/call_once.64]
[/opt/libc-tests/tests/catopen]
+[/opt/libc-tests/tests/env-OS-4089.32]
+[/opt/libc-tests/tests/env-OS-4089.64]
[/opt/libc-tests/tests/env-7076.32]
[/opt/libc-tests/tests/env-7076.64]
[/opt/libc-tests/tests/endian.32]
diff --git a/usr/src/test/libc-tests/tests/Makefile b/usr/src/test/libc-tests/tests/Makefile
index a259d28c89..c99d09502d 100644
--- a/usr/src/test/libc-tests/tests/Makefile
+++ b/usr/src/test/libc-tests/tests/Makefile
@@ -29,6 +29,7 @@ SUBDIRS = \
wctype
PROGS = \
+ env-OS-4089 \
aligned_alloc \
c11_threads \
c11_tss \
diff --git a/usr/src/test/libc-tests/tests/env-OS-4089.c b/usr/src/test/libc-tests/tests/env-OS-4089.c
new file mode 100644
index 0000000000..0f52201c79
--- /dev/null
+++ b/usr/src/test/libc-tests/tests/env-OS-4089.c
@@ -0,0 +1,73 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Regression test for OS-4089 where doing a putenv() call without an '=' sign
+ * may lead to a segmentation fault when doing a getenv() depending on the
+ * circumstances of the environment's layout. Verify putenv() mimics
+ * unsetenv().
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/debug.h>
+
+int
+main(void)
+{
+ if (putenv("FOO=bar") != 0) {
+ fprintf(stderr, "failed to put FOO into the environment: %s\n",
+ strerror(errno));
+ return (1);
+ }
+
+ if (getenv("FOO") == NULL) {
+ fprintf(stderr, "failed to retrieve FOO from the "
+ "environment!\n");
+ return (1);
+ }
+
+ VERIFY0(unsetenv("FOO"));
+
+ if (getenv("FOO") != NULL) {
+ fprintf(stderr, "Somehow retrieved FOO from the "
+ "environment after unsetenv()!\n");
+ return (1);
+ }
+
+ if (putenv("FOO=bar") != 0) {
+ fprintf(stderr, "failed to put FOO into the environment: %s\n",
+ strerror(errno));
+ return (1);
+ }
+
+ if (getenv("FOO") == NULL) {
+ fprintf(stderr, "failed to retrieve FOO from the "
+ "environment!\n");
+ return (1);
+ }
+
+ VERIFY0(putenv("FOO"));
+
+ if (getenv("FOO") != NULL) {
+ fprintf(stderr, "Somehow retrieved FOO from the "
+ "environment after putenv()!\n");
+ return (1);
+ }
+
+ return (0);
+}
diff --git a/usr/src/test/libc-tests/tests/random/Makefile b/usr/src/test/libc-tests/tests/random/Makefile
index ed480dacb9..c1a1a18e1f 100644
--- a/usr/src/test/libc-tests/tests/random/Makefile
+++ b/usr/src/test/libc-tests/tests/random/Makefile
@@ -17,7 +17,6 @@ include $(SRC)/Makefile.master
ROOTOPTPKG = $(ROOT)/opt/libc-tests
TESTDIR = $(ROOTOPTPKG)/tests/random
-ROOTBINDIR = $(ROOTOPTPKG)/bin
PROGS = arc4random \
arc4random_prefork \
@@ -74,17 +73,12 @@ arc4random_preforksig: arc4random_forksig.c
$(POST_PROCESS)
chacha: chacha_tv.c
- $(COMPILE.c) -DKEYSTREAM_ONLY -I$(SRC)/common/crypto/chacha -o chacha.o -c $(SRC)/common/crypto/chacha/chacha.c
+ $(COMPILE.c) -DKEYSTREAM_ONLY -I$(SRC)/common/crypto/chacha \
+ -o chacha.o -c $(SRC)/common/crypto/chacha/chacha.c
$(COMPILE.c) -I$(SRC)/common/crypto/chacha -o chacha_tv.o -c chacha_tv.c
$(LINK.c) -o $@ chacha_tv.o chacha.o $(LDLIBS)
$(POST_PROCESS)
-$(ROOTBINDIR):
- $(INS.dir)
-
-$(ROOTBINDIR)/%: %
- $(INS.file)
-
$(TESTDIR):
$(INS.dir)
diff --git a/usr/src/test/os-tests/cmd/ostest.ksh b/usr/src/test/os-tests/cmd/ostest.ksh
index afa944b613..d30e7fe6eb 100644
--- a/usr/src/test/os-tests/cmd/ostest.ksh
+++ b/usr/src/test/os-tests/cmd/ostest.ksh
@@ -14,6 +14,7 @@
#
# Copyright (c) 2012 by Delphix. All rights reserved.
# Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2016, Joyent, Inc.
#
export OS_TESTS="/opt/os-tests"
@@ -28,12 +29,8 @@ function fail
function find_runfile
{
typeset distro=
- if [[ -d /opt/delphix && -h /etc/delphix/version ]]; then
- distro=delphix
- elif [[ 0 -ne $(grep -c OpenIndiana /etc/release 2>/dev/null) ]]; then
- distro=openindiana
- elif [[ 0 -ne $(grep -c OmniOS /etc/release 2>/dev/null) ]]; then
- distro=omnios
+ if [[ -f $OS_TESTS/runfiles/default.run ]]; then
+ distro=default
fi
[[ -n $distro ]] && echo $OS_TESTS/runfiles/$distro.run
diff --git a/usr/src/test/os-tests/runfiles/Makefile b/usr/src/test/os-tests/runfiles/Makefile
index 619c9b812a..a4346ca2c9 100644
--- a/usr/src/test/os-tests/runfiles/Makefile
+++ b/usr/src/test/os-tests/runfiles/Makefile
@@ -12,13 +12,12 @@
#
# Copyright (c) 2012 by Delphix. All rights reserved.
# Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
+# Copyright 2016, Joyent, Inc.
#
include $(SRC)/Makefile.master
-SRCS = delphix.run \
- omnios.run \
- openindiana.run
+SRCS = default.run
ROOTOPTPKG = $(ROOT)/opt/os-tests
RUNFILES = $(ROOTOPTPKG)/runfiles
diff --git a/usr/src/test/os-tests/runfiles/delphix.run b/usr/src/test/os-tests/runfiles/default.run
index 4e73ebc8b3..13ac29f437 100644
--- a/usr/src/test/os-tests/runfiles/delphix.run
+++ b/usr/src/test/os-tests/runfiles/default.run
@@ -26,3 +26,10 @@ user = root
[/opt/os-tests/tests/sigqueue]
tests = ['sigqueue_queue_size']
+
+[/opt/os-tests/tests/tmpfs]
+user = root
+tests = ['tmpfs_badmount', 'tmpfs_enospc']
+
+[/opt/os-tests/tests/file-locking]
+tests = ['runtests.32', 'runtests.64']
diff --git a/usr/src/test/os-tests/runfiles/openindiana.run b/usr/src/test/os-tests/runfiles/openindiana.run
deleted file mode 100644
index 4e73ebc8b3..0000000000
--- a/usr/src/test/os-tests/runfiles/openindiana.run
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# This file and its contents are supplied under the terms of the
-# Common Development and Distribution License ("CDDL"), version 1.0.
-# You may only use this file in accordance with the terms of version
-# 1.0 of the CDDL.
-#
-# A full copy of the text of the CDDL should have accompanied this
-# source. A copy of the CDDL is also available via the Internet at
-# http://www.illumos.org/license/CDDL.
-#
-
-#
-# Copyright (c) 2012 by Delphix. All rights reserved.
-#
-
-[DEFAULT]
-pre =
-verbose = False
-quiet = False
-timeout = 60
-post =
-outputdir = /var/tmp/test_results
-
-[/opt/os-tests/tests/poll_test]
-user = root
-
-[/opt/os-tests/tests/sigqueue]
-tests = ['sigqueue_queue_size']
diff --git a/usr/src/test/os-tests/tests/Makefile b/usr/src/test/os-tests/tests/Makefile
index cd4104500c..2c65f957fe 100644
--- a/usr/src/test/os-tests/tests/Makefile
+++ b/usr/src/test/os-tests/tests/Makefile
@@ -13,6 +13,6 @@
# Copyright (c) 2012 by Delphix. All rights reserved.
#
-SUBDIRS = poll sigqueue spoof-ras
+SUBDIRS = poll sigqueue spoof-ras tmpfs file-locking
include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/os-tests/tests/file-locking/Makefile b/usr/src/test/os-tests/tests/file-locking/Makefile
new file mode 100644
index 0000000000..60601b5fee
--- /dev/null
+++ b/usr/src/test/os-tests/tests/file-locking/Makefile
@@ -0,0 +1,77 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+UTILS = util.c
+
+PROGS = \
+ runtests \
+ acquire-lock
+
+C99MODE = -xc99=%all
+
+SRCS = $(PROGS:%=%.c) $(UTILS)
+PROGS32 = $(PROGS:%=%.32)
+PROGS64 = $(PROGS:%=%.64)
+
+runtests.32 := LDLIBS += -lgen
+runtests.64 := LDLIBS64 += -lgen
+
+ROOTOPTDIR = $(ROOT)/opt/os-tests/tests/file-locking
+ROOTOPTPROGS = $(PROGS32:%=$(ROOTOPTDIR)/%) \
+ $(PROGS64:%=$(ROOTOPTDIR)/%)
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+install: $(ROOTOPTPROGS)
+
+all: $(PROGS32) $(PROGS64)
+
+lint: lint_SRCS
+
+clean:
+ -rm $(PROGS32) $(PROGS64)
+
+$(ROOTOPTPROGS): $(PROGS32) $(PROGS64) $(ROOTOPTDIR)
+
+$(ROOTOPTDIR):
+ $(INS.dir)
+
+$(ROOTOPTDIR)/%: %
+ $(INS.file)
+
+$(ROOTOPTDIR)/%: %.ksh
+ $(INS.rename)
+
+%.64: %.c
+ $(LINK64.c) -o $@ $< $(UTILS) $(LDLIBS64)
+ $(POST_PROCESS)
+
+%.32: %.c
+ $(LINK.c) -o $@ $< $(UTILS) $(LDLIBS)
+ $(POST_PROCESS)
+
+clobber:
+ $(RM) $(PROGS32) $(PROGS64)
+
+FRC:
diff --git a/usr/src/test/os-tests/tests/file-locking/acquire-lock.c b/usr/src/test/os-tests/tests/file-locking/acquire-lock.c
new file mode 100644
index 0000000000..c66dfdddc2
--- /dev/null
+++ b/usr/src/test/os-tests/tests/file-locking/acquire-lock.c
@@ -0,0 +1,161 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Acquire the specified kind of lock with the specified parameters. After
+ * acquiring the lock, a byte will be written to stdout. The program will
+ * then wait for a byte to be written to stdin before exiting.
+ *
+ * Usage: <posix|ofd|flock> <shared|exclusive> <path>
+ */
+
+#include "util.h"
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/file.h>
+#include <unistd.h>
+
+
+static void acq_fcntl(int, int, int);
+static void acq_flock(int fd, int mode);
+static void acq_run(int, lock_style_t, boolean_t);
+
+
+static void
+acq_fcntl(int fd, int cmd, int mode)
+{
+ struct flock fl;
+ int ret, i;
+
+ /*
+ * Acquire the lock, and then try reacquiring it several times. Once we
+ * have acquired the lock, trying to acquire it again should succeed,
+ * and shouldn't upgrade, downgrade or free the lock.
+ */
+ for (i = 0; i < 3; i++) {
+ flock_reinit(&fl, mode);
+ flock_log("Acquiring lock (fcntl)...\n");
+ ret = fcntl(fd, cmd, &fl);
+ if (ret == -1) {
+ err(EXIT_FAILURE, "fcntl failed");
+ }
+ }
+
+
+ /* Let the parent know we have the lock and wait */
+ flock_log("Waiting (fcntl)...\n");
+ flock_alert(1);
+ flock_block(0);
+
+ /* Now unlock */
+ flock_reinit(&fl, F_UNLCK);
+ flock_log("Releasing lock (fcntl)...\n");
+ ret = fcntl(fd, cmd, &fl);
+ if (ret == -1) {
+ err(EXIT_FAILURE, "fcntl failed");
+ }
+}
+
+
+static void
+acq_flock(int fd, int mode)
+{
+ int ret, i;
+
+ /*
+ * Acquire the lock, and then try reacquiring it several times. Once we
+ * have acquired the lock, trying to acquire it again should succeed,
+ * and shouldn't upgrade, downgrade or free the lock.
+ */
+ for (i = 0; i < 3; i++) {
+ flock_log("Acquiring lock (flock)...\n");
+ ret = flock(fd, mode);
+ if (ret == -1) {
+ err(EXIT_FAILURE, "flock failed");
+ }
+ }
+
+ /* Wait to be okayed to unlock */
+ flock_log("Waiting (flock)...\n");
+ flock_alert(1);
+ flock_block(0);
+
+ /* Release lock */
+ flock_log("Releasing lock (flock)...\n");
+ ret = flock(fd, LOCK_UN);
+ if (ret == -1) {
+ err(EXIT_FAILURE, "flock failed");
+ }
+}
+
+
+static void
+acq_run(int fd, lock_style_t style, boolean_t is_exclusive)
+{
+ switch (style) {
+ case LSTYLE_POSIX:
+ acq_fcntl(fd, F_SETLKW, is_exclusive ? F_WRLCK : F_RDLCK);
+ break;
+ case LSTYLE_OFD:
+ acq_fcntl(fd, F_OFD_SETLKW, is_exclusive ? F_WRLCK : F_RDLCK);
+ break;
+ case LSTYLE_FLOCK:
+ acq_flock(fd, is_exclusive ? LOCK_EX : LOCK_SH);
+ break;
+ default:
+ abort();
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ char *modestr, *path;
+ lock_style_t style;
+ boolean_t is_exclusive;
+ int fd;
+
+ if (argc < 4) {
+ errx(EXIT_FAILURE, BAD_ARGS_MESSAGE, argc - 1);
+ }
+
+ modestr = argv[2];
+ path = argv[3];
+
+ style = flock_styleenum(argv[1]);
+
+ if (strcmp(modestr, "shared") == 0) {
+ is_exclusive = B_FALSE;
+ } else if (strcmp(modestr, "exclusive") == 0) {
+ is_exclusive = B_TRUE;
+ } else {
+ errx(EXIT_FAILURE, BAD_MODE_MESSAGE);
+ }
+
+ boolean_t rdonly = style == LSTYLE_FLOCK || !is_exclusive;
+ fd = open(path, rdonly ? O_RDONLY : O_WRONLY);
+ if (fd == -1) {
+ err(EXIT_FAILURE, "Failed to open %s", path);
+ }
+
+ acq_run(fd, style, is_exclusive);
+
+ return (0);
+}
diff --git a/usr/src/test/os-tests/tests/file-locking/runtests.c b/usr/src/test/os-tests/tests/file-locking/runtests.c
new file mode 100644
index 0000000000..0a1a4d9976
--- /dev/null
+++ b/usr/src/test/os-tests/tests/file-locking/runtests.c
@@ -0,0 +1,677 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Validate various fcntl(2) and flock(3C) operations.
+ */
+
+#include "util.h"
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/debug.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+
+#define LOCKFILE_FMT "/tmp/.lockfile-%s-%ld"
+#define LOCKDIR_FMT "/tmp/.lockdir-%s-%ld"
+
+typedef struct lockinfo {
+ char *lf_name;
+ char *lf_path;
+ int lf_fd;
+} lockinfo_t;
+
+
+static void assert_write_locked_by(lockinfo_t *, pid_t);
+static void assert_read_locked_by(lockinfo_t *, pid_t);
+static void assert_unlocked(lockinfo_t *);
+static void assert_all_unlocked(void);
+
+static int flock_copyfil(lockinfo_t *, lockinfo_t *);
+static int flock_mkfil(lockinfo_t *);
+static int flock_mkdir(lockinfo_t *);
+static void flock_rminfo(lockinfo_t *);
+
+static void flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl);
+static void flock_run(lock_style_t, boolean_t, lockinfo_t *,
+ pid_t *, int[]);
+static int flock_wait(pid_t pid);
+static void flock_cleanup_child(pid_t, int []);
+
+static void flock_test_invalid(lockinfo_t *, int, short, short,
+ off_t, off_t);
+static void flock_test_exclusive(lock_style_t, lock_style_t,
+ lockinfo_t *, lockinfo_t *, boolean_t);
+static void flock_test_shared(lock_style_t, lock_style_t, lockinfo_t *,
+ lockinfo_t *, boolean_t);
+static void flock_test_upgrade_downgrade(void);
+
+static char *acqprog = NULL;
+
+static lockinfo_t flock_fileA = { "a", NULL, -1 };
+static lockinfo_t flock_fileB = { "b", NULL, -1 };
+static lockinfo_t flock_dirA = { "a", NULL, -1 };
+static lockinfo_t flock_dirB = { "b", NULL, -1 };
+
+
+static short cmds[8] = {
+ F_SETLK, F_SETLKW, F_GETLK,
+ F_OFD_SETLK, F_OFD_SETLKW, F_OFD_GETLK,
+ F_FLOCK, F_FLOCKW
+};
+
+
+static void
+flock_kill(pid_t pid)
+{
+ while (kill(pid, SIGKILL) == -1) {
+ if (errno == EINTR)
+ continue;
+
+ err(EXIT_FAILURE, "kill failed");
+ }
+}
+
+
+static void
+flock_fcntl(lockinfo_t *lf, int cmd, struct flock *fl)
+{
+ if (fcntl(lf->lf_fd, cmd, fl) == -1) {
+ err(EXIT_FAILURE, "fcntl failed");
+ }
+}
+
+
+static void
+assert_write_locked_by(lockinfo_t *lf, pid_t pid)
+{
+ struct flock fl;
+
+ flock_reinit(&fl, F_WRLCK);
+ flock_fcntl(lf, F_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
+
+ flock_reinit(&fl, F_WRLCK);
+ flock_fcntl(lf, F_OFD_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
+
+ flock_reinit(&fl, F_RDLCK);
+ flock_fcntl(lf, F_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
+
+ flock_reinit(&fl, F_RDLCK);
+ flock_fcntl(lf, F_OFD_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_WRLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
+}
+
+
+static void
+assert_read_locked_by(lockinfo_t *lf, pid_t pid)
+{
+ struct flock fl;
+
+ flock_reinit(&fl, F_WRLCK);
+ flock_fcntl(lf, F_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_RDLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
+
+ flock_reinit(&fl, F_WRLCK);
+ flock_fcntl(lf, F_OFD_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_RDLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, pid, pid_t);
+
+ flock_reinit(&fl, F_RDLCK);
+ flock_fcntl(lf, F_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
+
+ flock_reinit(&fl, F_RDLCK);
+ flock_fcntl(lf, F_OFD_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
+}
+
+static void
+assert_unlocked(lockinfo_t *lf)
+{
+ struct flock fl;
+
+ flock_reinit(&fl, F_WRLCK);
+ flock_fcntl(lf, F_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
+
+ flock_reinit(&fl, F_WRLCK);
+ flock_fcntl(lf, F_OFD_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
+
+ flock_reinit(&fl, F_RDLCK);
+ flock_fcntl(lf, F_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
+
+ flock_reinit(&fl, F_RDLCK);
+ flock_fcntl(lf, F_OFD_GETLK, &fl);
+ VERIFY3_IMPL(fl.l_type, ==, F_UNLCK, short);
+ VERIFY3_IMPL(fl.l_sysid, ==, 0, int);
+ VERIFY3_IMPL(fl.l_pid, ==, 0, pid_t);
+}
+
+
+static void
+assert_all_unlocked(void)
+{
+ assert_unlocked(&flock_fileA);
+ assert_unlocked(&flock_fileB);
+ assert_unlocked(&flock_dirA);
+ assert_unlocked(&flock_dirB);
+}
+
+
+static int
+flock_copyfil(lockinfo_t *src, lockinfo_t *dst)
+{
+ dst->lf_name = NULL;
+ dst->lf_path = NULL;
+ if ((dst->lf_fd = open(src->lf_path, O_RDWR)) == -1) {
+ warn("Failed to open %s", src->lf_path);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+static int
+flock_mkfil(lockinfo_t *lf)
+{
+ if (asprintf(&lf->lf_path, LOCKFILE_FMT, lf->lf_name, getpid()) < 0) {
+ warnx("Failed to generate lockfile name");
+ return (-1);
+ }
+
+ if ((lf->lf_fd = open(lf->lf_path, O_RDWR|O_CREAT, 0600)) == -1) {
+ warn("Failed to open %s", lf->lf_path);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+static int
+flock_mkdir(lockinfo_t *lf)
+{
+ if (asprintf(&lf->lf_path, LOCKDIR_FMT, lf->lf_name, getpid()) < 0) {
+ warnx("Failed to generate lockfile name");
+ return (-1);
+ }
+
+ if (mkdir(lf->lf_path, 0700) == -1) {
+ warn("Failed to make %s", lf->lf_path);
+ return (-1);
+ }
+
+ if ((lf->lf_fd = open(lf->lf_path, O_RDONLY)) == -1) {
+ warn("Failed to open %s", lf->lf_path);
+ return (-1);
+ }
+
+ return (0);
+}
+
+
+static void
+flock_rminfo(lockinfo_t *lf)
+{
+ if (lf->lf_fd != -1) {
+ (void) close(lf->lf_fd);
+ }
+ if (lf->lf_path != NULL) {
+ (void) unlink(lf->lf_path);
+ free(lf->lf_path);
+ }
+}
+
+
+static void
+flock_run(lock_style_t style, boolean_t is_exclusive, lockinfo_t *lf,
+ pid_t *pid, int fds[])
+{
+ char *stylestr = flock_stylestr(style);
+ char *modestr = is_exclusive ? "exclusive" : "shared";
+ char *argv[5] = { acqprog, stylestr, modestr, lf->lf_path, NULL };
+ int ret = pipe(fds);
+ if (ret == -1) {
+ err(EXIT_FAILURE, "pipe failed");
+ }
+
+ *pid = fork();
+ if (*pid == (pid_t)-1) {
+ err(EXIT_FAILURE, "fork failed");
+ } else if (*pid == (pid_t)0) {
+ /* Set up pipe for communicating with child */
+ ret = dup2(fds[1], 0);
+ if (ret == -1) {
+ err(EXIT_FAILURE, "dup2 failed");
+ }
+ ret = dup2(fds[1], 1);
+ if (ret == -1) {
+ err(EXIT_FAILURE, "dup2 failed");
+ }
+ closefrom(3);
+
+ (void) execv(acqprog, argv);
+ err(EXIT_FAILURE, "Failed to execute %s", acqprog);
+ }
+}
+
+
+static int
+flock_wait(pid_t pid)
+{
+ int childstat = 0;
+
+ while (waitpid(pid, &childstat, 0) == -1) {
+ if (errno == EINTR)
+ continue;
+
+ err(EXIT_FAILURE, "Failed to wait on child");
+ }
+
+ if (WIFEXITED(childstat)) {
+ return (WEXITSTATUS(childstat));
+ } else if (WIFSIGNALED(childstat)) {
+ return (1);
+ } else {
+ abort();
+ return (1);
+ }
+}
+
+
+static void
+flock_cleanup_child(pid_t pid, int fds[])
+{
+ (void) flock_wait(pid);
+ (void) close(fds[0]);
+ (void) close(fds[1]);
+}
+
+
+static void
+flock_test_upgrade_downgrade(void)
+{
+ lockinfo_t afd1, afd2, afd3;
+ pid_t pid;
+ int fds[2];
+
+ VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0);
+ VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0);
+ VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0);
+
+ flock_log("Acquiring shared locks 1, 2 and 3...");
+ VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0);
+ VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0);
+ VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0);
+ assert_read_locked_by(&flock_fileA, -1);
+ flock_log(" ok\n");
+
+ flock_log("Upgrading lock 3 should fail w/ EWOULDBLOCK...");
+ VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
+ VERIFY3U(errno, ==, EWOULDBLOCK);
+ assert_read_locked_by(&flock_fileA, -1);
+ flock_log(" ok\n");
+
+ flock_log("Upgrading 3 should succeed after releasing locks 1 & 2...");
+ VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0);
+ VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0);
+ VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
+ assert_write_locked_by(&flock_fileA, -1);
+ flock_log(" ok\n");
+
+
+ flock_log("Starting up child, then downgrading lock 3 to shared...");
+ flock_run(LSTYLE_FLOCK, B_FALSE, &flock_fileA, &pid, fds);
+ VERIFY3_IMPL(flock_nodata(fds[0]), ==, B_TRUE, boolean_t);
+ VERIFY3S(flock(afd3.lf_fd, LOCK_SH), ==, 0);
+ flock_block(fds[0]);
+ assert_read_locked_by(&flock_fileA, -1);
+ flock_log(" ok\n");
+
+ flock_log("Releasing child and upgrading...");
+ flock_alert(fds[0]);
+ flock_cleanup_child(pid, fds);
+ assert_read_locked_by(&flock_fileA, -1);
+ VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
+ assert_write_locked_by(&flock_fileA, -1);
+ flock_log(" ok\n");
+
+ flock_log("Releasing lock 3...");
+ VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0);
+ flock_rminfo(&afd1);
+ flock_rminfo(&afd2);
+ flock_rminfo(&afd3);
+ assert_all_unlocked();
+ flock_log(" ok\n");
+}
+
+
+static void
+flock_test_invalid(lockinfo_t *lf, int cmd, short l_type, short l_whence,
+ off_t l_start, off_t l_len)
+{
+ struct flock fl = {
+ .l_type = l_type,
+ .l_whence = l_whence,
+ .l_start = l_start,
+ .l_len = l_len
+ };
+
+ flock_log("fcntl(fd, %s, { %hd, %hd, %ld, %ld, ... })...",
+ flock_cmdname(cmd), l_type, l_whence, l_start, l_len);
+ VERIFY3S(fcntl(lf->lf_fd, cmd, &fl), ==, -1);
+ VERIFY3U(errno, ==, EINVAL);
+ flock_log(" ok\n");
+}
+
+
+static void
+flock_test_exclusive(lock_style_t styleA, lock_style_t styleB,
+ lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn)
+{
+ pid_t pidA, pidB;
+ int fdsA[2], fdsB[2];
+
+ flock_log("Running %s + %s tests (%s)...",
+ flock_stylename(styleA), flock_stylename(styleB),
+ kill_firstborn ? "kill child" : "child exits");
+
+ /* Create child, and wait for it to acquire the lock */
+ flock_run(styleA, B_TRUE, lock1, &pidA, fdsA);
+ flock_block(fdsA[0]);
+
+ /* Create second child, which shouldn't acquire & signal */
+ flock_run(styleB, B_TRUE, lock1, &pidB, fdsB);
+ VERIFY3_IMPL(flock_nodata(fdsB[0]), ==, B_TRUE, boolean_t);
+
+ /* lock1 is blocked for reading and writing */
+ assert_write_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1);
+ assert_unlocked(lock2);
+
+ /* Tell pidA to exit */
+ if (kill_firstborn) {
+ flock_kill(pidA);
+ } else {
+ flock_alert(fdsA[0]);
+ }
+ flock_cleanup_child(pidA, fdsA);
+
+ /* Wait for pidB to signal us */
+ flock_block(fdsB[0]);
+
+ /* lock1 is blocked for reading and writing */
+ assert_write_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1);
+ assert_unlocked(lock2);
+
+ /* Tell pidB to exit */
+ flock_alert(fdsB[0]);
+
+ flock_cleanup_child(pidB, fdsB);
+
+ /*
+ * Tests after child has released lock
+ */
+ assert_all_unlocked();
+
+ flock_log(" ok\n");
+}
+
+
+static void
+flock_test_shared(lock_style_t styleA, lock_style_t styleB,
+ lockinfo_t *lock1, lockinfo_t *lock2, boolean_t kill_firstborn)
+{
+ pid_t pidA, pidB;
+ int fdsA[2], fdsB[2];
+
+ flock_log("Running %s + %s tests (%s)...",
+ flock_stylename(styleA), flock_stylename(styleB),
+ kill_firstborn ? "kill child" : "child exits");
+
+ /* Create children, and wait for it to acquire the lock */
+ flock_run(styleB, B_FALSE, lock1, &pidB, fdsB);
+ flock_block(fdsB[0]);
+ flock_run(styleA, B_FALSE, lock1, &pidA, fdsA);
+ flock_block(fdsA[0]);
+
+ /* testfileA is only blocked for writing */
+ assert_read_locked_by(lock1, styleA == LSTYLE_POSIX ? pidA : -1);
+ assert_unlocked(lock2);
+
+ /* Tell pidA to exit */
+ if (kill_firstborn) {
+ flock_kill(pidA);
+ } else {
+ flock_alert(fdsA[0]);
+ }
+ flock_cleanup_child(pidA, fdsA);
+
+ /* testfileA is still blocked for writing by pidB */
+ assert_read_locked_by(lock1, styleB == LSTYLE_POSIX ? pidB : -1);
+ assert_unlocked(lock2);
+
+ /* Tell pidB to exit */
+ flock_alert(fdsB[0]);
+ flock_cleanup_child(pidB, fdsB);
+
+ assert_all_unlocked();
+
+ flock_log(" ok\n");
+}
+
+
+static void
+flock_test_ofd_sameproc(void)
+{
+ lockinfo_t afd1, afd2, afd3;
+
+ VERIFY3S(flock_copyfil(&flock_fileA, &afd1), ==, 0);
+ VERIFY3S(flock_copyfil(&flock_fileA, &afd2), ==, 0);
+ VERIFY3S(flock_copyfil(&flock_fileA, &afd3), ==, 0);
+
+ flock_log("Acquiring first two shared locks...");
+ VERIFY3S(flock(afd1.lf_fd, LOCK_SH), ==, 0);
+ VERIFY3S(flock(afd2.lf_fd, LOCK_SH), ==, 0);
+ assert_read_locked_by(&flock_fileA, -1);
+ flock_log(" ok\n");
+
+ flock_log("Acquiring an exclusive lock should fail w/ EWOULDBLOCK...");
+ VERIFY3S(flock(afd3.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
+ VERIFY3U(errno, ==, EWOULDBLOCK);
+ flock_log(" ok\n");
+
+ flock_log("Releasing to acquire an exclusive lock...");
+ VERIFY3S(flock(afd1.lf_fd, LOCK_UN), ==, 0);
+ VERIFY3S(flock(afd2.lf_fd, LOCK_UN), ==, 0);
+ flock_log(" ok\n");
+
+ flock_log("Acquiring an exclusive lock...");
+ VERIFY3S(flock(afd3.lf_fd, LOCK_EX), ==, 0);
+ assert_write_locked_by(&flock_fileA, -1);
+ flock_log(" ok\n");
+
+ flock_log("Acquiring a shared lock should fail w/ EWOULDBLOCK...");
+ VERIFY3S(flock(afd1.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
+ VERIFY3U(errno, ==, EWOULDBLOCK);
+ VERIFY3S(flock(afd2.lf_fd, LOCK_EX|LOCK_NB), ==, -1);
+ VERIFY3U(errno, ==, EWOULDBLOCK);
+ flock_log(" ok\n");
+
+ flock_log("Releasing exclusive lock...");
+ VERIFY3S(flock(afd3.lf_fd, LOCK_UN), ==, 0);
+ assert_all_unlocked();
+ flock_log(" ok\n");
+
+ flock_rminfo(&afd1);
+ flock_rminfo(&afd2);
+ flock_rminfo(&afd3);
+}
+
+
+static void
+flock_runtests(void)
+{
+ lock_style_t first, second;
+ int i;
+
+ flock_log("# Exclusive lock tests\n");
+ for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) {
+ for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) {
+ flock_test_exclusive(first, second,
+ &flock_fileA, &flock_fileB, B_TRUE);
+ flock_test_exclusive(first, second,
+ &flock_fileA, &flock_fileB, B_FALSE);
+ }
+ }
+
+ flock_log("# Shared lock tests\n");
+ for (first = (lock_style_t)0; first < LSTYLE_LAST; first++) {
+ for (second = (lock_style_t)0; second < LSTYLE_LAST; second++) {
+ flock_test_shared(first, second,
+ &flock_fileA, &flock_fileB, B_TRUE);
+ flock_test_shared(first, second,
+ &flock_fileA, &flock_fileB, B_FALSE);
+ }
+ }
+
+ flock_log("# flock(3C) directory lock tests\n");
+ flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK,
+ &flock_dirA, &flock_dirB, B_TRUE);
+ flock_test_exclusive(LSTYLE_FLOCK, LSTYLE_FLOCK,
+ &flock_dirA, &flock_dirB, B_FALSE);
+ flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK,
+ &flock_dirA, &flock_dirB, B_TRUE);
+ flock_test_shared(LSTYLE_FLOCK, LSTYLE_FLOCK,
+ &flock_dirA, &flock_dirB, B_FALSE);
+
+
+ flock_log("# Invalid fcntl(2) parameters tests\n");
+ for (i = 0; i < sizeof (cmds) / sizeof (short); i++) {
+ flock_test_invalid(&flock_fileA, cmds[i], 200, 0, 0, 0);
+ flock_test_invalid(&flock_fileA, cmds[i], -1, 0, 0, 0);
+ }
+ for (i = 3; i < sizeof (cmds) / sizeof (short); i++) {
+ flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 1, 0, 0);
+ flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 1, 0);
+ flock_test_invalid(&flock_fileA, cmds[i], F_WRLCK, 0, 0, 1);
+ }
+
+ flock_log("# Testing that multiple OFD locks work in a process\n");
+ flock_test_ofd_sameproc();
+
+ flock_log("# Testing flock(3C) upgrade/downgrade tests\n");
+ flock_test_upgrade_downgrade();
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ char *basestr, *suffix, *dirstr, *dirpath;
+ pid_t testrunner;
+ int exval;
+
+ LOG = B_TRUE;
+
+ if (argc < 1) {
+ errx(EXIT_FAILURE, "Can't find program name!");
+ }
+
+ dirstr = strdup(argv[0]);
+ dirpath = dirname(dirstr);
+ basestr = strdup(argv[0]);
+ suffix = basename(basestr);
+
+ while (*suffix != '.' && *suffix != '\0') {
+ suffix += 1;
+ }
+
+ if (asprintf(&acqprog, "%s/acquire-lock%s", dirpath, suffix) < 0) {
+ errx(EXIT_FAILURE,
+ "Can't generate lock acquisition program name!");
+ }
+
+ if (access(acqprog, X_OK) != 0) {
+ err(EXIT_FAILURE,
+ "Can't run lock acquisition program %s", acqprog);
+ }
+
+ /* Create several lockfiles for testing */
+ if (flock_mkfil(&flock_fileA) != 0 ||
+ flock_mkfil(&flock_fileB) != 0 ||
+ flock_mkdir(&flock_dirA) != 0 ||
+ flock_mkdir(&flock_dirB) != 0) {
+ exval = 1;
+ goto cleanup;
+ }
+
+ /*
+ * We run the tests in a child process so that when tests fail
+ * we can still clean up our temporary files.
+ */
+ testrunner = fork();
+ if (testrunner == (pid_t)-1) {
+ err(EXIT_FAILURE, "Unable to fork to run tests");
+ } else if (testrunner == (pid_t)0) {
+ flock_runtests();
+ return (0);
+ }
+
+ exval = flock_wait(testrunner);
+
+cleanup:
+ free(basestr);
+ free(dirstr);
+ flock_rminfo(&flock_fileA);
+ flock_rminfo(&flock_fileB);
+ flock_rminfo(&flock_dirA);
+ flock_rminfo(&flock_dirB);
+ return (exval);
+}
diff --git a/usr/src/test/os-tests/tests/file-locking/util.c b/usr/src/test/os-tests/tests/file-locking/util.c
new file mode 100644
index 0000000000..ad171840ae
--- /dev/null
+++ b/usr/src/test/os-tests/tests/file-locking/util.c
@@ -0,0 +1,175 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Utility functions for use in both acquire-lock and runtests.
+ */
+
+#include "util.h"
+#include <err.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+
+boolean_t LOG = B_FALSE;
+
+
+void
+flock_log(const char *format, ...)
+{
+ va_list ap;
+ if (!LOG) {
+ return;
+ }
+
+ va_start(ap, format);
+ (void) vfprintf(stderr, format, ap);
+ va_end(ap);
+}
+
+
+boolean_t
+flock_nodata(int fd)
+{
+ struct pollfd pfd = { fd, POLLIN, 0 };
+ int ret = poll(&pfd, 1, 1000);
+
+ if (ret == -1) {
+ err(EXIT_FAILURE, "poll failed");
+ }
+
+ return (ret == 0);
+}
+
+
+void
+flock_block(int fd)
+{
+ char buf[1];
+ int ret = 0;
+ while (ret < 1) {
+ ret = read(fd, buf, 1);
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ err(EXIT_FAILURE, "read failed");
+ }
+ }
+}
+
+
+void
+flock_alert(int fd)
+{
+ int ret = 0;
+ while (ret < 1) {
+ ret = write(fd, "1", 1);
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ err(EXIT_FAILURE, "write failed");
+ }
+ }
+}
+
+
+lock_style_t
+flock_styleenum(char *stylestr)
+{
+ if (strcmp(stylestr, "posix") == 0) {
+ return (LSTYLE_POSIX);
+ } else if (strcmp(stylestr, "ofd") == 0) {
+ return (LSTYLE_OFD);
+ } else if (strcmp(stylestr, "flock") == 0) {
+ return (LSTYLE_FLOCK);
+ } else {
+ errx(EXIT_FAILURE, BAD_LOCK_MESSAGE);
+ return (LSTYLE_LAST);
+ }
+}
+
+
+char *
+flock_stylestr(lock_style_t style)
+{
+ switch (style) {
+ case LSTYLE_POSIX:
+ return ("posix");
+ case LSTYLE_OFD:
+ return ("ofd");
+ case LSTYLE_FLOCK:
+ return ("flock");
+ default:
+ abort();
+ return ("<unreachable>");
+ }
+}
+
+
+char *
+flock_stylename(lock_style_t style)
+{
+ switch (style) {
+ case LSTYLE_POSIX:
+ return ("fcntl(2) POSIX");
+ case LSTYLE_OFD:
+ return ("fcntl(2) OFD");
+ case LSTYLE_FLOCK:
+ return ("flock(3C)");
+ default:
+ abort();
+ return ("<unreachable>");
+ }
+}
+
+
+void
+flock_reinit(struct flock *flp, int ltype)
+{
+ bzero(flp, sizeof (*flp));
+ flp->l_type = ltype;
+}
+
+
+char *
+flock_cmdname(int cmd)
+{
+ switch (cmd) {
+ case F_SETLK:
+ return ("F_SETLK");
+ case F_OFD_SETLK:
+ return ("F_OFD_SETLK");
+ case F_SETLKW:
+ return ("F_SETLKW");
+ case F_OFD_SETLKW:
+ return ("F_OFD_SETLKW");
+ case F_GETLK:
+ return ("F_GETLK");
+ case F_OFD_GETLK:
+ return ("F_OFD_GETLK");
+ case F_FLOCK:
+ return ("F_FLOCK");
+ case F_FLOCKW:
+ return ("F_FLOCKW");
+ default:
+ abort();
+ return ("<unreachable>");
+ }
+}
diff --git a/usr/src/test/os-tests/tests/file-locking/util.h b/usr/src/test/os-tests/tests/file-locking/util.h
new file mode 100644
index 0000000000..b6d2b57d8a
--- /dev/null
+++ b/usr/src/test/os-tests/tests/file-locking/util.h
@@ -0,0 +1,49 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+#ifndef FLOCK_TEST_UTIL_H
+#define FLOCK_TEST_UTIL_H
+
+#include <fcntl.h>
+#include <sys/types.h>
+
+#define BAD_ARGS_MESSAGE "Expected to receive 3 arguments, but found %d."
+#define BAD_MODE_MESSAGE "Lock mode must be one of " \
+ "\"shared\" or \"exclusive\""
+#define BAD_LOCK_MESSAGE "Lock style must be one of " \
+ "\"posix\", \"ofd\", or \"exclusive\""
+
+typedef enum lock_style {
+ LSTYLE_POSIX,
+ LSTYLE_OFD,
+ LSTYLE_FLOCK,
+ LSTYLE_LAST
+} lock_style_t;
+
+extern boolean_t LOG;
+
+extern boolean_t flock_nodata(int);
+
+extern void flock_block(int);
+extern void flock_alert(int);
+extern void flock_log(const char *, ...);
+extern void flock_reinit(struct flock *, int);
+
+extern char *flock_cmdname(int);
+extern char *flock_stylename(lock_style_t);
+extern char *flock_stylestr(lock_style_t);
+extern lock_style_t flock_styleenum(char *);
+
+#endif /* FLOCK_TEST_UTIL_H */
diff --git a/usr/src/test/os-tests/tests/tmpfs/Makefile b/usr/src/test/os-tests/tests/tmpfs/Makefile
new file mode 100644
index 0000000000..d6515b38fa
--- /dev/null
+++ b/usr/src/test/os-tests/tests/tmpfs/Makefile
@@ -0,0 +1,52 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/os-tests
+TESTDIR = $(ROOTOPTPKG)/tests/tmpfs
+
+PROGS = tmpfs_full
+SCRIPTS = tmpfs_badmount \
+ tmpfs_enospc
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+CMDS = $(PROGS:%=$(TESTDIR)/%) $(SCRIPTS:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+all: $(PROGS)
+
+install: all $(CMDS)
+
+lint:
+
+clobber: clean
+ -$(RM) $(PROGS)
+
+clean:
+ -$(RM) *.o
+
+$(CMDS): $(TESTDIR) $(PROGS)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %.ksh
+ $(INS.rename)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/test/os-tests/tests/tmpfs/tmpfs_badmount.ksh b/usr/src/test/os-tests/tests/tmpfs/tmpfs_badmount.ksh
new file mode 100644
index 0000000000..7e2c4a6095
--- /dev/null
+++ b/usr/src/test/os-tests/tests/tmpfs/tmpfs_badmount.ksh
@@ -0,0 +1,114 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+#
+# Test various options to try and mount a tmpfs. Aside from the first to
+# verify that we can mount tmpfs at all, these should all fail.
+#
+
+tb_arg0=$(basename $0)
+tb_mountpoint="/var/tmp/$0.$$"
+tb_mount=/usr/sbin/mount
+tb_umount=/usr/sbin/umount
+
+function fatal
+{
+ rmdir $tb_mountpoint
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="test failed"
+ echo "$tb_arg0: test failed $msg" >&2
+ exit 1
+}
+
+function check_mount
+{
+ mkdir -p $tb_mountpoint || fatal \
+ "failed to make mountpoint $tb_mountpoint"
+ $tb_mount -F tmpfs swap $tb_mountpoint || fatal \
+ "failed to mount tmpfs, check user perms"
+ $tb_umount $tb_mountpoint || fatal \
+ "failed to unmount test point"
+}
+
+function test_one
+{
+ typeset opts=$1
+
+ [[ -z "$opts" ]] && fatal "missing required opts"
+ $tb_mount -F tmpfs -o $opts swap $tb_mountpoint 2>/dev/null
+ if [[ $? -eq 0 ]]; then
+ $tb_umount $tb_mountpoint
+ fatal "successfully mounted with opts $opts, expected failure"
+ fi
+}
+
+check_mount
+
+#
+# Test invalid percentages.
+#
+test_one "size=-5%"
+test_one "size=200%"
+test_one "size=55.55555%"
+test_one "size=100.0%"
+test_one "size=bad%"
+test_one "size=30g%"
+test_one "size=%"
+test_one "size=%wat"
+
+#
+# Test invalid sizes. Only kmg are valid prefixes.
+#
+test_one "size=hello;world"
+test_one "size=0xnope"
+test_one "size=3.14g"
+test_one "size=3;14"
+test_one "size=thisisanormalsize"
+test_one "size="
+test_one "size=100mtry"
+
+#
+# Now, we need to try and trigger a bunch of overflow. We're going to do
+# this assuming we're on a 64-bit kernel (which will always overflow a
+# 32-bit kernel).
+#
+test_one "size=20000000000000000000"
+test_one "size=1ggggggggggggggggggg"
+test_one "size=1mmmmmmmmmmmmmmmmmmm"
+test_one "size=1kkkkkkkkkkkkkkkkkkk"
+test_one "size=1kkkkkkkkkkkkkkkkkkk"
+test_one "size=18014398509481983k"
+test_one "size=17592186044416m"
+test_one "size=17179869185g"
+test_one "size=17179869184g"
+
+#
+# Let's throw a couple bad modes around while we're here.
+#
+test_one "mode=17777"
+test_one "mode=27777"
+test_one "mode=37777"
+test_one "mode=47777"
+test_one "mode=57777"
+test_one "mode=67777"
+test_one "mode=77777"
+test_one "mode=87777"
+test_one "mode=97777"
+test_one "mode=asdf"
+test_one "mode=deadbeef"
+test_one "mode=kefka"
+
+rmdir $tb_mountpoint
diff --git a/usr/src/test/os-tests/tests/tmpfs/tmpfs_enospc.ksh b/usr/src/test/os-tests/tests/tmpfs/tmpfs_enospc.ksh
new file mode 100644
index 0000000000..a285f306e2
--- /dev/null
+++ b/usr/src/test/os-tests/tests/tmpfs/tmpfs_enospc.ksh
@@ -0,0 +1,74 @@
+#!/usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2016 Joyent, Inc.
+#
+
+#
+# Verify that if we fill up a tmpfs that we can't then perform
+# additional things to it that would result in the creation or use of
+# kernel memory.
+#
+
+te_arg0=$(basename $0)
+te_root=$(dirname $0)
+te_bin=$te_root/tmpfs_full
+te_mountpoint="/var/tmp/$0.$$"
+te_mount=/usr/sbin/mount
+te_umount=/usr/sbin/umount
+te_testfile=1m
+te_mounted=
+te_exit=1
+
+function fatal
+{
+ [[ -n "$te_mounted" ]] && $te_umount $te_mountpoint
+ rmdir $te_mountpoint
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="test failed"
+ echo "$te_arg0: test failed $msg" >&2
+ exit 1
+}
+
+function setup
+{
+ typeset ofile=$te_mountpoint/$te_testfile
+
+ mkdir -p $te_mountpoint || fatal \
+ "failed to make mountpoint $te_mountpoint"
+ $te_mount -F tmpfs swap $te_mountpoint || fatal \
+ "failed to mount tmpfs, check user perms"
+ te_mounted=1
+ dd if=/dev/zero of=$ofile bs=1M count=1 2>/dev/null || fatal \
+ "failed to create a 1 MB file"
+ $te_mount -F tmpfs -o remount,size=512k swap $te_mountpoint ||
+ fatal "failed to remount tmpfs"
+}
+
+function run_test
+{
+ $te_bin $te_mountpoint $te_testfile || fatal "$te_bin failed"
+}
+
+function cleanup
+{
+ te_mounted=
+ $te_umount $te_mountpoint || fatal "failed to unmount $te_mountpoint"
+ rmdir $te_mountpoint || fatal "failed to remove $te_mountpoint"
+}
+
+setup
+run_test
+cleanup
+
+exit 0
diff --git a/usr/src/test/os-tests/tests/tmpfs/tmpfs_full.c b/usr/src/test/os-tests/tests/tmpfs/tmpfs_full.c
new file mode 100644
index 0000000000..6c6037710b
--- /dev/null
+++ b/usr/src/test/os-tests/tests/tmpfs/tmpfs_full.c
@@ -0,0 +1,94 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2016 Joyent, Inc.
+ */
+
+/*
+ * Given a path to a tmpfs that has already been marked as full, attempt to
+ * perform certain activities on it, all of which should fail with ENOSPC.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <strings.h>
+#include <sys/debug.h>
+#include <unistd.h>
+
+int
+main(int argc, const char *argv[])
+{
+ int fd, ret;
+ struct statvfs vfs;
+
+ if (argc != 3) {
+ fprintf(stderr, "test failed: missing path or file\n");
+ return (1);
+ }
+
+ if ((fd = open(argv[1], O_RDONLY)) < 0) {
+ fprintf(stderr, "test failed: failed to open root %s: %s\n",
+ argv[1], strerror(errno));
+ return (1);
+ }
+
+ if (fstatvfs(fd, &vfs) != 0) {
+ fprintf(stderr, "test failed: failed to stat vfs for %s: %s\n",
+ argv[1], strerror(errno));
+ return (1);
+ }
+
+ if (strncmp("tmpfs", vfs.f_basetype, FSTYPSZ) != 0) {
+ fprintf(stderr, "test failed: asked to run on non-tmpfs\n");
+ return (1);
+ }
+
+ /*
+ * Once a few additional bugs in tmpfs are fixed, we should double check
+ * and make sure that the free space here is actually zero before
+ * continuing.
+ */
+
+ /*
+ * Go through operations that would create nodes and make sure that they
+ * all fail.
+ */
+
+ ret = openat(fd, "Mnemosyne", O_RDWR | O_CREAT, 0755);
+ VERIFY3S(ret, ==, -1);
+ VERIFY3S(errno, ==, ENOSPC);
+
+ ret = mkdirat(fd, "Euterpe", 0775);
+ VERIFY3S(ret, ==, -1);
+ VERIFY3S(errno, ==, ENOSPC);
+
+ ret = symlinkat("/dev/null", fd, "Melpomene");
+ VERIFY3S(ret, ==, -1);
+ VERIFY3S(errno, ==, ENOSPC);
+
+ ret = linkat(fd, argv[2], fd, "Urania", 0);
+ VERIFY3S(ret, ==, -1);
+ VERIFY3S(errno, ==, ENOSPC);
+
+ /*
+ * Make sure we can't create open extended attributes.
+ */
+ ret = openat(fd, "Lethe", O_RDWR | O_CREAT | O_XATTR);
+ VERIFY3S(ret, ==, -1);
+ VERIFY3S(errno, ==, ENOSPC);
+
+ return (0);
+}
diff --git a/usr/src/test/test-runner/cmd/Makefile b/usr/src/test/test-runner/cmd/Makefile
index 33e7a61275..948aea9ed8 100644
--- a/usr/src/test/test-runner/cmd/Makefile
+++ b/usr/src/test/test-runner/cmd/Makefile
@@ -34,4 +34,6 @@ $(ROOTBIN):
$(INS.dir)
$(ROOTBIN)/%: %.py
- $(INS.rename)
+ $(RM) $@
+ $(SED.py) $< > $@
+ $(CHMOD) 0555 $@
diff --git a/usr/src/test/test-runner/cmd/run.py b/usr/src/test/test-runner/cmd/run.py
index 81e53b210f..4054b12087 100644
--- a/usr/src/test/test-runner/cmd/run.py
+++ b/usr/src/test/test-runner/cmd/run.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2.6
+#!ON_PYTHON_26
#
# This file and its contents are supplied under the terms of the
diff --git a/usr/src/test/util-tests/runfiles/default.run b/usr/src/test/util-tests/runfiles/default.run
index 3f7498e23b..dcdbf43f95 100644
--- a/usr/src/test/util-tests/runfiles/default.run
+++ b/usr/src/test/util-tests/runfiles/default.run
@@ -24,9 +24,14 @@ outputdir = /var/tmp/test_results
[/opt/util-tests/tests/printf_test]
[/opt/util-tests/tests/allowed-ips]
+[/opt/util-tests/tests/vnic-mtu]
+[/opt/util-tests/tests/bunyan]
[/opt/util-tests/tests/xargs_test]
+[/opt/util-tests/tests/mqt]
+[/opt/util-tests/tests/wqt]
+
[/opt/util-tests/tests/libnvpair_json]
tests = ['json_00_blank', 'json_01_boolean', 'json_02_numbers',
'json_03_empty_arrays', 'json_04_number_arrays', 'json_05_strings',
diff --git a/usr/src/test/util-tests/tests/Makefile b/usr/src/test/util-tests/tests/Makefile
index 4709c7adcd..739b79893f 100644
--- a/usr/src/test/util-tests/tests/Makefile
+++ b/usr/src/test/util-tests/tests/Makefile
@@ -14,7 +14,6 @@
# Copyright 2014 Garrett D'Amore <garrett@damore.org>
#
-SUBDIRS = dladm printf xargs
-SUBDIRS = dladm libnvpair_json printf xargs
+SUBDIRS = dladm libnvpair_json printf xargs mergeq workq
include $(SRC)/test/Makefile.com
diff --git a/usr/src/test/util-tests/tests/bunyan/Makefile b/usr/src/test/util-tests/tests/bunyan/Makefile
new file mode 100644
index 0000000000..5f58bf1614
--- /dev/null
+++ b/usr/src/test/util-tests/tests/bunyan/Makefile
@@ -0,0 +1,68 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/util-tests
+TESTDIR = $(ROOTOPTPKG)/tests/bunyan
+TESTBIN = $(ROOTOPTPKG)/bin
+
+PROG = btest
+
+SCRIPTS = \
+ bunyan
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/test/Makefile.com
+
+OBJS = $(PROG:%=%.o)
+SRCS = $(OBJS:%.o=%.c)
+
+CMDS = $(PROG:%=$(TESTBIN)/%) $(SCRIPTS:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+DIRS = $(TESTDIR) $(TESTBIN)
+
+LDLIBS += -lbunyan
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+install: all $(CMDS)
+
+lint:
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+ -$(RM) $(OBJS)
+
+$(CMDS): $(DIRS)
+
+$(DIRS):
+ $(INS.dir)
+
+$(TESTDIR)/%: %.ksh
+ $(INS.rename)
+
+$(TESTDIR)/%: %
+ $(INS.file)
+
+$(TESTBIN)/%: %
+ $(INS.file)
diff --git a/usr/src/test/util-tests/tests/bunyan/btest.c b/usr/src/test/util-tests/tests/bunyan/btest.c
new file mode 100644
index 0000000000..5239e91f1e
--- /dev/null
+++ b/usr/src/test/util-tests/tests/bunyan/btest.c
@@ -0,0 +1,312 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2014, Joyent, Inc.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <bunyan.h>
+#include <netinet/in.h>
+#include <strings.h>
+
+static void
+create_handles(void)
+{
+ bunyan_logger_t *a, *b, *c;
+
+ assert(bunyan_init("foo", &a) == 0);
+ assert(bunyan_init("foo", &b) == 0);
+ assert(bunyan_init("foo", &c) == 0);
+ bunyan_fini(a);
+ bunyan_fini(b);
+ bunyan_fini(c);
+}
+
+static void
+create_stream(void)
+{
+ bunyan_logger_t *a;
+
+ assert(bunyan_init("foo", &a) == 0);
+ assert(bunyan_stream_add(a, "bar", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_stream_add(a, "baz", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_stream_add(a, "bar", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == EEXIST);
+ assert(bunyan_stream_add(a, "baz", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == EEXIST);
+ assert(bunyan_stream_remove(a, "baz") == 0);
+ assert(bunyan_stream_remove(a, "baz") == ENOENT);
+ assert(bunyan_stream_remove(a, "foobaz") == ENOENT);
+ assert(bunyan_stream_remove(a, "blah") == ENOENT);
+ assert(bunyan_stream_add(a, "bar", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == EEXIST);
+ assert(bunyan_stream_add(a, "baz", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_stream_add(a, "debug", BUNYAN_L_DEBUG,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_stream_add(a, "info", BUNYAN_L_INFO,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_stream_add(a, "warn", BUNYAN_L_WARN,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_stream_add(a, "error", BUNYAN_L_ERROR,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_stream_add(a, "fatal", BUNYAN_L_FATAL,
+ bunyan_stream_fd, (void *)1) == 0);
+
+ bunyan_fini(a);
+}
+
+static void
+create_key(void)
+{
+ bunyan_logger_t *a;
+ struct in_addr v4;
+ struct in6_addr v6;
+
+ assert(bunyan_init("foo", &a) == 0);
+ assert(bunyan_key_remove(a, "blah") == ENOENT);
+ assert(bunyan_key_add(a, BUNYAN_T_END) == 0);
+
+ assert(bunyan_key_add(a, BUNYAN_T_STRING, "s", "foo",
+ BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4,
+ BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE,
+ BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969,
+ BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323,
+ BUNYAN_T_DOUBLE, "d", 3.14,
+ BUNYAN_T_INT64STR, "i64s", (uint64_t)12345,
+ BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0);
+
+ assert(bunyan_key_remove(a, "s") == 0);
+ assert(bunyan_key_remove(a, "s") == ENOENT);
+ assert(bunyan_key_remove(a, "p") == 0);
+ assert(bunyan_key_remove(a, "p") == ENOENT);
+ assert(bunyan_key_remove(a, "v4") == 0);
+ assert(bunyan_key_remove(a, "v4") == ENOENT);
+ assert(bunyan_key_remove(a, "v6") == 0);
+ assert(bunyan_key_remove(a, "v6") == ENOENT);
+ assert(bunyan_key_remove(a, "b") == 0);
+ assert(bunyan_key_remove(a, "b") == ENOENT);
+ assert(bunyan_key_remove(a, "i32") == 0);
+ assert(bunyan_key_remove(a, "i32") == ENOENT);
+ assert(bunyan_key_remove(a, "i64") == 0);
+ assert(bunyan_key_remove(a, "i64") == ENOENT);
+ assert(bunyan_key_remove(a, "u32") == 0);
+ assert(bunyan_key_remove(a, "u32") == ENOENT);
+ assert(bunyan_key_remove(a, "u64") == 0);
+ assert(bunyan_key_remove(a, "u64") == ENOENT);
+ assert(bunyan_key_remove(a, "d") == 0);
+ assert(bunyan_key_remove(a, "d") == ENOENT);
+ assert(bunyan_key_remove(a, "i64s") == 0);
+ assert(bunyan_key_remove(a, "i64s") == ENOENT);
+ assert(bunyan_key_remove(a, "u64s") == 0);
+ assert(bunyan_key_remove(a, "u64s") == ENOENT);
+
+ bunyan_fini(a);
+}
+
+static void
+bad_level(void)
+{
+ bunyan_logger_t *a;
+
+ assert(bunyan_init("bad level", &a) == 0);
+ assert(bunyan_stream_add(a, "bar", BUNYAN_L_TRACE - 1,
+ bunyan_stream_fd, (void *)1) == EINVAL);
+ assert(bunyan_stream_add(a, "bar", BUNYAN_L_TRACE + 1,
+ bunyan_stream_fd, (void *)1) == EINVAL);
+ assert(bunyan_stream_add(a, "bar", BUNYAN_L_DEBUG - 1,
+ bunyan_stream_fd, (void *)1) == EINVAL);
+ assert(bunyan_stream_add(a, "bar", BUNYAN_L_INFO + 1,
+ bunyan_stream_fd, (void *)1) == EINVAL);
+ assert(bunyan_stream_add(a, "bar", BUNYAN_L_WARN - 1,
+ bunyan_stream_fd, (void *)1) == EINVAL);
+ assert(bunyan_stream_add(a, "bar", BUNYAN_L_ERROR + 1,
+ bunyan_stream_fd, (void *)1) == EINVAL);
+ assert(bunyan_stream_add(a, "bar", BUNYAN_L_FATAL - 1,
+ bunyan_stream_fd, (void *)1) == EINVAL);
+ assert(bunyan_stream_add(a, "bar", -5,
+ bunyan_stream_fd, (void *)1) == EINVAL);
+
+ bunyan_fini(a);
+}
+
+static void
+basic_log(void)
+{
+ bunyan_logger_t *a;
+
+ assert(bunyan_init("basic", &a) == 0);
+ assert(bunyan_stream_add(a, "foo", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_trace(a, "trace", BUNYAN_T_END) == 0);
+ assert(bunyan_debug(a, "debug", BUNYAN_T_END) == 0);
+ assert(bunyan_info(a, "info", BUNYAN_T_END) == 0);
+ assert(bunyan_warn(a, "warn", BUNYAN_T_END) == 0);
+ assert(bunyan_error(a, "error", BUNYAN_T_END) == 0);
+ assert(bunyan_fatal(a, "fatal", BUNYAN_T_END) == 0);
+
+ bunyan_fini(a);
+}
+
+static void
+crazy_log(void)
+{
+ bunyan_logger_t *a;
+ struct in_addr v4;
+ struct in6_addr v6;
+
+ bzero(&v4, sizeof (struct in_addr));
+ bzero(&v6, sizeof (struct in6_addr));
+
+ assert(bunyan_init("basic", &a) == 0);
+ assert(bunyan_stream_add(a, "foo", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_trace(a, "trace", BUNYAN_T_STRING, "s", "foo",
+ BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4,
+ BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE,
+ BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969,
+ BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323,
+ BUNYAN_T_DOUBLE, "d", 3.14,
+ BUNYAN_T_INT64STR, "i64s", (uint64_t)12345,
+ BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0);
+ assert(bunyan_debug(a, "debug", BUNYAN_T_STRING, "s", "foo",
+ BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4,
+ BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE,
+ BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969,
+ BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323,
+ BUNYAN_T_DOUBLE, "d", 3.14,
+ BUNYAN_T_INT64STR, "i64s", (uint64_t)12345,
+ BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0);
+ assert(bunyan_info(a, "info", BUNYAN_T_STRING, "s", "foo",
+ BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4,
+ BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE,
+ BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969,
+ BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323,
+ BUNYAN_T_DOUBLE, "d", 3.14,
+ BUNYAN_T_INT64STR, "i64s", (uint64_t)12345,
+ BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0);
+ assert(bunyan_warn(a, "warn", BUNYAN_T_STRING, "s", "foo",
+ BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4,
+ BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE,
+ BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969,
+ BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323,
+ BUNYAN_T_DOUBLE, "d", 3.14,
+ BUNYAN_T_INT64STR, "i64s", (uint64_t)12345,
+ BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0);
+ assert(bunyan_error(a, "error", BUNYAN_T_STRING, "s", "foo",
+ BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4,
+ BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE,
+ BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969,
+ BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323,
+ BUNYAN_T_DOUBLE, "d", 3.14,
+ BUNYAN_T_INT64STR, "i64s", (uint64_t)12345,
+ BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0);
+ assert(bunyan_fatal(a, "fatal", BUNYAN_T_STRING, "s", "foo",
+ BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4,
+ BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE,
+ BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969,
+ BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323,
+ BUNYAN_T_DOUBLE, "d", 3.14,
+ BUNYAN_T_INT64STR, "i64s", (uint64_t)12345,
+ BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0);
+
+ bunyan_fini(a);
+}
+
+static void
+child_log(void)
+{
+ bunyan_logger_t *a, *child;
+ struct in_addr v4;
+ struct in6_addr v6;
+
+ bzero(&v4, sizeof (struct in_addr));
+ bzero(&v6, sizeof (struct in6_addr));
+
+ assert(bunyan_init("child", &a) == 0);
+ assert(bunyan_stream_add(a, "foo", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_child(a, &child, BUNYAN_T_STRING, "s", "foo",
+ BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4,
+ BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE,
+ BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969,
+ BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323,
+ BUNYAN_T_DOUBLE, "d", 3.14,
+ BUNYAN_T_INT64STR, "i64s", (uint64_t)12345,
+ BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0);
+
+ bunyan_fini(a);
+ assert(bunyan_trace(child, "trace", BUNYAN_T_END) == 0);
+ assert(bunyan_debug(child, "debug", BUNYAN_T_END) == 0);
+ assert(bunyan_info(child, "info", BUNYAN_T_END) == 0);
+ assert(bunyan_warn(child, "warn", BUNYAN_T_END) == 0);
+ assert(bunyan_error(child, "error", BUNYAN_T_END) == 0);
+ assert(bunyan_fatal(child, "fatal", BUNYAN_T_END) == 0);
+
+ bunyan_fini(child);
+}
+
+static void
+crazy_child(void)
+{
+ bunyan_logger_t *a, *child;
+ struct in_addr v4;
+ struct in6_addr v6;
+
+ bzero(&v4, sizeof (struct in_addr));
+ bzero(&v6, sizeof (struct in6_addr));
+
+ assert(bunyan_init("crazy child", &a) == 0);
+ assert(bunyan_stream_add(a, "foo", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_key_add(a, BUNYAN_T_STRING, "s", "foo",
+ BUNYAN_T_POINTER, "p", (void *)a, BUNYAN_T_IP, "v4", &v4,
+ BUNYAN_T_IP6, "v6", &v6, BUNYAN_T_BOOLEAN, "b", B_TRUE,
+ BUNYAN_T_INT32, "i32", 69, BUNYAN_T_INT64, "i64", (uint64_t)6969,
+ BUNYAN_T_UINT32, "u32", 23, BUNYAN_T_UINT64, "u64", (uint64_t)2323,
+ BUNYAN_T_DOUBLE, "d", 3.14,
+ BUNYAN_T_INT64STR, "i64s", (uint64_t)12345,
+ BUNYAN_T_UINT64STR, "u64s", (uint64_t)54321, BUNYAN_T_END) == 0);
+ assert(bunyan_child(a, &child, BUNYAN_T_END) == 0);
+ bunyan_fini(a);
+
+ assert(bunyan_stream_remove(child, "foo") == 0);
+ assert(bunyan_stream_add(child, "bar", BUNYAN_L_TRACE,
+ bunyan_stream_fd, (void *)1) == 0);
+ assert(bunyan_key_remove(child, "u64s") == 0);
+ assert(bunyan_trace(child, "trace", BUNYAN_T_END) == 0);
+ assert(bunyan_debug(child, "debug", BUNYAN_T_END) == 0);
+ assert(bunyan_info(child, "info", BUNYAN_T_END) == 0);
+ assert(bunyan_warn(child, "warn", BUNYAN_T_END) == 0);
+ assert(bunyan_error(child, "error", BUNYAN_T_END) == 0);
+ assert(bunyan_fatal(child, "fatal", BUNYAN_T_END) == 0);
+
+ bunyan_fini(child);
+}
+
+int
+main(void)
+{
+ create_handles();
+ create_stream();
+ create_key();
+ bad_level();
+ basic_log();
+ crazy_log();
+ child_log();
+ crazy_child();
+
+ return (0);
+}
diff --git a/usr/src/test/os-tests/runfiles/omnios.run b/usr/src/test/util-tests/tests/bunyan/bunyan.ksh
index 4e73ebc8b3..4ec0f4bd62 100644
--- a/usr/src/test/os-tests/runfiles/omnios.run
+++ b/usr/src/test/util-tests/tests/bunyan/bunyan.ksh
@@ -1,3 +1,4 @@
+#! /usr/bin/ksh
#
# This file and its contents are supplied under the terms of the
# Common Development and Distribution License ("CDDL"), version 1.0.
@@ -10,19 +11,16 @@
#
#
-# Copyright (c) 2012 by Delphix. All rights reserved.
+# Copyright (c) 2014, Joyent, Inc.
#
-[DEFAULT]
-pre =
-verbose = False
-quiet = False
-timeout = 60
-post =
-outputdir = /var/tmp/test_results
+#
+# Simple wrapper for the classic test.out
+#
+
+set -o errexit
-[/opt/os-tests/tests/poll_test]
-user = root
+btest_root=$(dirname $0)/../..
+btest_bin=$btest_root/bin/btest
-[/opt/os-tests/tests/sigqueue]
-tests = ['sigqueue_queue_size']
+LD_PRELOAD=libumem.so UMEM_DEBUG=default $btest_bin >/dev/null
diff --git a/usr/src/test/util-tests/tests/dladm/Makefile b/usr/src/test/util-tests/tests/dladm/Makefile
index df3997656c..a71332b016 100644
--- a/usr/src/test/util-tests/tests/dladm/Makefile
+++ b/usr/src/test/util-tests/tests/dladm/Makefile
@@ -17,7 +17,7 @@ include $(SRC)/cmd/Makefile.cmd
include $(SRC)/test/Makefile.com
ROOTOPTPKG = $(ROOT)/opt/util-tests/tests
-PROG = allowed-ips
+PROG = allowed-ips vnic-mtu
ROOTPROG = $(PROG:%=$(ROOTOPTPKG)/%)
diff --git a/usr/src/test/util-tests/tests/dladm/vnic-mtu.ksh b/usr/src/test/util-tests/tests/dladm/vnic-mtu.ksh
new file mode 100644
index 0000000000..49daa74f3b
--- /dev/null
+++ b/usr/src/test/util-tests/tests/dladm/vnic-mtu.ksh
@@ -0,0 +1,116 @@
+#!/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+#
+# The purpose of this is to test the MTU property on VNICs, using both
+# temporary and persistent properties. To do this, we create an
+# Etherstub and then create various VNICs on top of it.
+#
+
+vm_arg0="$(basename $0)"
+vm_stub="teststub$$"
+vm_vnic="testvnic$$"
+
+VM_MTU_MIN=576
+VM_MTU_MAX=9000
+
+fatal()
+{
+ typeset msg="$*"
+ [[ -z "$msg" ]] && msg="failed"
+ echo "TEST_FAIL: $vm_arg0: $msg" >&2
+
+ # Try to clean up just in case
+ dladm delete-vnic $vm_vnic 2>/dev/null
+ dladm delete-etherstub $vm_stub 2>/dev/null
+ exit 1
+}
+
+#
+# Validate that the MTU of the datalink dev has the MTU that we expect
+#
+validate_mtu()
+{
+ typeset dev=$1
+ typeset mtu=$2
+ typeset val
+
+ [[ -z "$dev" ]] && fatal "missing required device"
+ [[ -z "$mtu" ]] && fatal "missing required mtu"
+ val=$(dladm show-linkprop -c -p mtu -o value $dev)
+ [[ $? -eq 0 ]] || fatal "failed to get MTU for $dev"
+ (( $val == $mtu )) || fatal \
+ "mtu mismatch on $dev: expected $mtu, got $val"
+}
+
+delete_stub()
+{
+ dladm delete-etherstub $vm_stub || fatal \
+ "failed to delete stub $vm_stub"
+}
+
+create_stub()
+{
+ dladm create-etherstub $vm_stub || fatal \
+ "failed to create stub"
+ validate_mtu $vm_stub $VM_MTU_MAX
+}
+
+delete_vnic()
+{
+ dladm delete-vnic $vm_vnic || fatal "failed to delete vnic $vm_vnic"
+}
+
+test_vnic_pass()
+{
+ typeset mtu=$1
+ typeset flags=$2
+
+ [[ -z "$mtu" ]] && fatal "missing required mtu"
+ dladm create-vnic $flags -l $vm_stub -p mtu=$mtu $vm_vnic || fatal \
+ "failed tocreate vnic: $vm_vnic"
+ validate_mtu "$vm_vnic" "$mtu"
+ delete_vnic
+}
+
+test_vnic_fail()
+{
+ typeset mtu=$1
+ typeset flags=$2
+
+ [[ -z "$mtu" ]] && fatal "missing required mtu"
+ dladm create-vnic $flags -l $vm_stub -p mtu=$mtu \
+ $vm_vnic 2>/dev/null && fatal \
+ "created vnic with mtu $mtu, but failure expected"
+}
+
+test_pass()
+{
+ typeset flags=$1
+
+ create_stub
+ test_vnic_pass 1500 $flags
+ test_vnic_pass 1400 $flags
+ test_vnic_pass $VM_MTU_MIN $flags
+ test_vnic_pass $VM_MTU_MAX $flags
+ test_vnic_fail $((($VM_MTU_MIN - 1))) $flags
+ test_vnic_fail $((($VM_MTU_MAX + 1))) $flags
+ delete_stub
+}
+
+test_pass "-t"
+test_pass
+echo "TEST PASS: $vm_arg0"
diff --git a/usr/src/test/util-tests/tests/libnvpair_json/Makefile b/usr/src/test/util-tests/tests/libnvpair_json/Makefile
index d1d3585b02..3b48e0b630 100644
--- a/usr/src/test/util-tests/tests/libnvpair_json/Makefile
+++ b/usr/src/test/util-tests/tests/libnvpair_json/Makefile
@@ -10,14 +10,14 @@
#
#
-# Copyright (c) 2014 Joyent, Inc.
+# Copyright 2015 Joyent, Inc.
#
include $(SRC)/Makefile.master
ROOTOPTPKG = $(ROOT)/opt/util-tests
TESTDIR = $(ROOTOPTPKG)/tests/libnvpair_json
-ROOTBINDIR = $(ROOTOPTPKG)/bin
+TESTBIN = $(ROOTOPTPKG)/bin
PROG = print_json
@@ -38,9 +38,11 @@ include $(SRC)/test/Makefile.com
OBJS = $(PROG:%=%.o)
SRCS = $(OBJS:%.o=%.c)
-CMDS = $(PROG:%=$(ROOTBINDIR)/%) $(SCRIPTS:%=$(TESTDIR)/%)
+CMDS = $(PROG:%=$(TESTBIN)/%) $(SCRIPTS:%=$(TESTDIR)/%)
$(CMDS) := FILEMODE = 0555
+DIRS = $(TESTDIR) $(TESTBIN)
+
LDLIBS += -lnvpair
LINTFLAGS += -erroff=E_FUNC_ARG_UNUSED
@@ -61,16 +63,13 @@ clobber: clean
clean:
-$(RM) $(OBJS)
-$(CMDS): $(TESTDIR) $(PROG)
+$(CMDS): $(DIRS)
-$(ROOTBINDIR):
- $(INS.dir)
-
-$(ROOTBINDIR)/%: %
- $(INS.file)
-
-$(TESTDIR):
+$(DIRS):
$(INS.dir)
$(TESTDIR)/%: %.ksh
$(INS.rename)
+
+$(TESTBIN)/%: %
+ $(INS.file)
diff --git a/usr/src/test/util-tests/tests/libnvpair_json/json_08_large_data.ksh b/usr/src/test/util-tests/tests/libnvpair_json/json_08_large_data.ksh
new file mode 100644
index 0000000000..ca19e10d06
--- /dev/null
+++ b/usr/src/test/util-tests/tests/libnvpair_json/json_08_large_data.ksh
@@ -0,0 +1,37 @@
+#!/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015, Joyent, Inc.
+#
+
+DIR=$(dirname $(whence $0))
+. ${DIR}/json_common
+
+BASELINE="$(cat <<EOF
+{\
+"o":[\
+$(for i in {1..50}; do
+ printf '"%s",' 'some_very_big_string_that_takes_up_space'
+done)\
+"end"\
+]\
+}
+EOF)"
+
+OUTPUT="$(${DIR}/../../bin/print_json <<-EOF
+add_string_array "o" $(for i in {1..50}; do
+ printf '"%s" ' 'some_very_big_string_that_takes_up_space'
+done)"end";
+EOF)"
+
+complete
diff --git a/usr/src/test/util-tests/tests/mergeq/Makefile b/usr/src/test/util-tests/tests/mergeq/Makefile
new file mode 100644
index 0000000000..ef6c6abb99
--- /dev/null
+++ b/usr/src/test/util-tests/tests/mergeq/Makefile
@@ -0,0 +1,64 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/util-tests
+TESTDIR = $(ROOTOPTPKG)/tests/mergeq
+
+PROG = mqt
+OBJS = mqt.o mergeq.o
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/cmd/Makefile.ctf
+include $(SRC)/test/Makefile.com
+
+CMDS = $(PROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+CPPFLAGS += -I$(SRC)/lib/mergeq -D_REENTRANT
+LDLIBS += -lumem
+
+all: $(PROG)
+
+install: all $(CMDS)
+
+lint: lint_SRCS
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+ -$(RM) $(OBJS)
+
+%.o: %.c
+ $(COMPILE.c) -o $@ -c $<
+ $(POST_PROCESS_O)
+
+%.o: $(SRC)/lib/mergeq/%.c
+ $(COMPILE.c) -o $@ -c $<
+ $(POST_PROCESS_O)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/test/util-tests/tests/mergeq/mqt.c b/usr/src/test/util-tests/tests/mergeq/mqt.c
new file mode 100644
index 0000000000..e61e9173d2
--- /dev/null
+++ b/usr/src/test/util-tests/tests/mergeq/mqt.c
@@ -0,0 +1,217 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * mergeq testing routines
+ */
+
+#include <mergeq.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+const char *
+_umem_debug_init()
+{
+ return ("default,verbose");
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents");
+}
+
+void *
+mergeq_alloc(size_t size)
+{
+ return (malloc(size));
+}
+
+/*ARGSUSED*/
+void
+mergeq_free(void *buf, size_t size)
+{
+ free(buf);
+}
+
+static int
+mqt_int(void *first, void *second, void **outp, void *arg)
+{
+ uintptr_t a, b, c;
+ a = (uintptr_t)first;
+ b = (uintptr_t)second;
+ c = a + b;
+ *outp = (void *)c;
+
+ return (0);
+}
+
+static int
+mqt_append(void *first, void *second, void **outp, void *arg)
+{
+ char *out;
+
+ /* Yes, this leaks, don't worry about it for the test */
+ if (asprintf(&out, "%s%s", first, second) != -1) {
+ *outp = out;
+ return (0);
+ }
+ return (-1);
+}
+
+static int
+mqt_fatal(void *first, void *second, void **outp, void *arg)
+{
+ return (-1);
+}
+
+/*
+ * Test structures and cases. We really want mq_args to be a flexible array
+ * member, but then we cant initialize it. Thus we set a fixed size number of
+ * entries.
+ */
+typedef struct mq_test {
+ const char *mq_desc; /* test description/name */
+ mergeq_proc_f *mq_proc; /* processing function */
+ int mq_rval; /* mergeq_merge return value */
+ int mq_uerr; /* user error, if any */
+ boolean_t mq_strcmp; /* use strcmp rather than == */
+ void *mq_result; /* expected result */
+ void **mq_args; /* argument array */
+} mq_test_t;
+
+static void *mqt_empty_args[] = { NULL };
+static void *mqt_single_args[] = { (void *)42, NULL };
+static void *mqt_double_args[] = { (void *)42, (void *)27, NULL };
+static void *mqt_wrap_args[] = {
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, NULL
+};
+static void *mqt_grow_args[] = {
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, NULL
+};
+static void *mqt_order_args[] = { "l", "e", "g", "e", "n", "d", " ", "o", "f",
+ " ", "z", "e", "l", "d", "a", NULL };
+
+
+static mq_test_t mq_tests[] = {
+ { "empty", mqt_int, 0, 0, B_FALSE, NULL, mqt_empty_args },
+ { "single", mqt_int, 0, 0, B_FALSE, (void *)42, mqt_single_args },
+ { "double", mqt_int, 0, 0, B_FALSE, (void *)69, mqt_double_args },
+ { "wrap", mqt_int, 0, 0, B_FALSE, (void *)64, mqt_wrap_args },
+ { "grow", mqt_int, 0, 0, B_FALSE, (void *)92, mqt_grow_args },
+ { "fatal", mqt_fatal, MERGEQ_UERROR, -1, B_FALSE, NULL,
+ mqt_double_args },
+ { "order", mqt_append, 0, 0, B_TRUE, "alegend of zeld", mqt_order_args }
+};
+
+#define NMQ_TESTS (sizeof (mq_tests) / sizeof (mq_test_t))
+
+static void
+mq_test_run(mergeq_t *mqp, mq_test_t *mqt)
+{
+ int ret, err;
+ void **itemp = mqt->mq_args;
+ void *out;
+
+ while (*itemp != NULL) {
+ if ((ret = mergeq_add(mqp, *itemp)) != 0) {
+ (void) fprintf(stderr,
+ "test %s: failed to add item: %s\n",
+ mqt->mq_desc, strerror(errno));
+ exit(1);
+ }
+ itemp++;
+ }
+
+ ret = mergeq_merge(mqp, mqt->mq_proc, NULL, &out, &err);
+ if (ret != mqt->mq_rval) {
+ (void) fprintf(stderr, "test %s: got incorrect rval. "
+ "Expected %d, got %d\n", mqt->mq_desc, mqt->mq_rval, ret);
+ exit(1);
+ }
+
+ if (ret == MERGEQ_UERROR && err != mqt->mq_uerr) {
+ (void) fprintf(stderr, "test %s: got incorrect user error. "
+ "Expected %d, got %d\n", mqt->mq_desc, mqt->mq_uerr, err);
+ exit(1);
+ }
+
+ if (ret == 0) {
+ if (mqt->mq_strcmp == B_TRUE &&
+ strcmp(out, mqt->mq_result) != 0) {
+ (void) fprintf(stderr, "test %s: got unexpected "
+ "result: %s, expected %s\n", mqt->mq_desc, out,
+ mqt->mq_result);
+ exit(1);
+ } else if (mqt->mq_strcmp == B_FALSE && out != mqt->mq_result) {
+ (void) fprintf(stderr, "test %s: got unexpected "
+ "result: %p, expected %p\n", mqt->mq_desc, out,
+ mqt->mq_result);
+ exit(1);
+ }
+ }
+}
+
+int
+main(void)
+{
+ int ret, i, t;
+ mergeq_t *mqp;
+ int nthreads[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, -1 };
+
+ for (t = 0; nthreads[t] != -1; t++) {
+ printf("Beginning tests with %d threads\n", nthreads[t]);
+ if ((ret = mergeq_init(&mqp, nthreads[t])) != 0) {
+ fprintf(stderr, "failed to init mergeq: %s\n",
+ strerror(errno));
+ return (1);
+ }
+
+ for (i = 0; i < NMQ_TESTS; i++) {
+ mq_test_run(mqp, &mq_tests[i]);
+ }
+
+ mergeq_fini(mqp);
+ }
+
+ return (0);
+}
diff --git a/usr/src/test/util-tests/tests/workq/Makefile b/usr/src/test/util-tests/tests/workq/Makefile
new file mode 100644
index 0000000000..ab5455fd86
--- /dev/null
+++ b/usr/src/test/util-tests/tests/workq/Makefile
@@ -0,0 +1,64 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Joyent, Inc.
+#
+
+include $(SRC)/Makefile.master
+
+ROOTOPTPKG = $(ROOT)/opt/util-tests
+TESTDIR = $(ROOTOPTPKG)/tests/mergeq
+
+PROG = wqt
+OBJS = wqt.o workq.o
+
+include $(SRC)/cmd/Makefile.cmd
+include $(SRC)/cmd/Makefile.ctf
+include $(SRC)/test/Makefile.com
+
+CMDS = $(PROG:%=$(TESTDIR)/%)
+$(CMDS) := FILEMODE = 0555
+
+CPPFLAGS += -I$(SRC)/lib/mergeq -D_REENTRANT
+LDLIBS += -lumem
+
+all: $(PROG)
+
+install: all $(CMDS)
+
+lint: lint_SRCS
+
+clobber: clean
+ -$(RM) $(PROG)
+
+clean:
+ -$(RM) $(OBJS)
+
+%.o: %.c
+ $(COMPILE.c) -o $@ -c $<
+ $(POST_PROCESS_O)
+
+%.o: $(SRC)/lib/mergeq/%.c
+ $(COMPILE.c) -o $@ -c $<
+ $(POST_PROCESS_O)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+$(CMDS): $(TESTDIR) $(PROG)
+
+$(TESTDIR):
+ $(INS.dir)
+
+$(TESTDIR)/%: %
+ $(INS.file)
diff --git a/usr/src/test/util-tests/tests/workq/wqt.c b/usr/src/test/util-tests/tests/workq/wqt.c
new file mode 100644
index 0000000000..bda0b4a9e5
--- /dev/null
+++ b/usr/src/test/util-tests/tests/workq/wqt.c
@@ -0,0 +1,196 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Joyent, Inc.
+ */
+
+/*
+ * workq testing routines
+ *
+ * What we want to guarantee is that every function is executed exactly once. To
+ * that end we have the callback function basically increment a global in the
+ * test around a mutex.
+ */
+
+#include <workq.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <thread.h>
+#include <synch.h>
+
+mutex_t wqt_lock = ERRORCHECKMUTEX;
+uintptr_t wqt_count;
+
+const char *
+_umem_debug_init()
+{
+ return ("default,verbose");
+}
+
+const char *
+_umem_logging_init(void)
+{
+ return ("fail,contents");
+}
+
+void *
+workq_alloc(size_t size)
+{
+ return (malloc(size));
+}
+
+/*ARGSUSED*/
+void
+workq_free(void *buf, size_t size)
+{
+ free(buf);
+}
+
+/*ARGSUSED*/
+int
+wqt_fatal(void *item, void *arg)
+{
+ return (-1);
+}
+
+int
+wqt_add(void *item, void *arg)
+{
+ uintptr_t a = (uintptr_t)item;
+
+ mutex_enter(&wqt_lock);
+ wqt_count += a;
+ mutex_exit(&wqt_lock);
+
+ return (0);
+}
+
+typedef struct wq_test {
+ const char *wq_desc; /* test description/name */
+ workq_proc_f *wq_proc; /* processing function */
+ int wq_rval; /* workq_work return value */
+ int wq_uerr; /* user error, if any */
+ uintptr_t wq_sum; /* expected sum */
+ void **wq_args; /* argument array */
+} wq_test_t;
+
+static void *wqt_empty_args[] = { NULL };
+static void *wqt_single_args[] = { (void *)42, NULL };
+static void *wqt_double_args[] = { (void *)42, (void *)27, NULL };
+static void *wqt_wrap_args[] = {
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, NULL
+};
+static void *wqt_grow_args[] = {
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1,
+ (void *)1, (void *)1, NULL
+};
+
+static wq_test_t wq_tests[] = {
+ { "empty", wqt_add, 0, 0, NULL, wqt_empty_args },
+ { "single", wqt_add, 0, 0, 42, wqt_single_args },
+ { "double", wqt_add, 0, 0, 69, wqt_double_args },
+ { "wrap", wqt_add, 0, 0, 64, wqt_wrap_args },
+ { "grow", wqt_add, 0, 0, 92, wqt_grow_args },
+ { "fatal", wqt_fatal, WORKQ_UERROR, -1, -1, wqt_double_args }
+};
+
+#define NWQ_TESTS (sizeof (wq_tests) / sizeof (wq_test_t))
+
+static void
+wq_test_run(workq_t *wqp, wq_test_t *wqt)
+{
+ int ret, err;
+ void **itemp = wqt->wq_args;
+
+ while (*itemp != NULL) {
+ if ((ret = workq_add(wqp, *itemp)) != 0) {
+ (void) fprintf(stderr, "test %s: failed to add item: "
+ "%s\n", wqt->wq_desc, strerror(errno));
+ exit(1);
+ }
+ itemp++;
+ }
+
+ wqt_count = 0;
+ ret = workq_work(wqp, wqt->wq_proc, NULL, &err);
+ if (ret != wqt->wq_rval) {
+ (void) fprintf(stderr, "test %s: got incorrect rval. "
+ "Expected %d, got %d (%d)\n", wqt->wq_desc, wqt->wq_rval,
+ ret, errno);
+ exit(1);
+ }
+
+ if (ret == WORKQ_UERROR && err != wqt->wq_uerr) {
+ (void) fprintf(stderr, "test %s: got incorrect user error. "
+ "Expected %d, got %d\n", wqt->wq_desc, wqt->wq_uerr, err);
+ exit(1);
+ }
+
+ if (ret == 0 && wqt_count != wqt->wq_sum) {
+ (void) fprintf(stderr, "test %s: got unexpected "
+ "result: %d, expected %d\n", wqt->wq_desc, wqt_count,
+ wqt->wq_sum);
+ exit(1);
+ }
+}
+
+int
+main(void)
+{
+ int ret, i, t;
+ workq_t *wqp;
+ int nthreads[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, -1 };
+
+ for (t = 0; nthreads[t] != -1; t++) {
+ printf("Beginning tests with %d threads\n", nthreads[t]);
+ if ((ret = workq_init(&wqp, nthreads[t])) != 0) {
+ fprintf(stderr, "failed to init workq: %s\n",
+ strerror(errno));
+ return (1);
+ }
+
+ for (i = 0; i < NWQ_TESTS; i++) {
+ wq_test_run(wqp, &wq_tests[i]);
+ }
+
+ workq_fini(wqp);
+ }
+
+
+ return (0);
+}