summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2015-12-30 16:21:07 -0200
committerRenato Botelho <renato@netgate.com>2015-12-30 16:21:07 -0200
commitd8ff3484131f428fcc0727cd504acb5050a36490 (patch)
tree8adfbb5b779f497e621d29277fcbe1536012eeb0
parent0319542cc712df59c57f014b4f925f516bcb5b4b (diff)
parentecf8336fcdf81e2aeb30a7ab82841dd7299ceb98 (diff)
downloadFreeBSD-src-d8ff3484131f428fcc0727cd504acb5050a36490.zip
FreeBSD-src-d8ff3484131f428fcc0727cd504acb5050a36490.tar.gz
Merge remote-tracking branch 'origin/stable/10' into devel
-rw-r--r--.arcconfig6
-rw-r--r--.arclint25
-rw-r--r--Makefile.inc132
-rw-r--r--contrib/netbsd-tests/lib/libc/gen/t_assert.c23
-rwxr-xr-xcontrib/netbsd-tests/lib/libc/ssp/t_ssp.sh1
-rw-r--r--contrib/netbsd-tests/usr.bin/grep/d_binary.out2
-rwxr-xr-xcontrib/netbsd-tests/usr.bin/grep/t_grep.sh13
-rw-r--r--etc/defaults/periodic.conf4
-rw-r--r--etc/mtree/BSD.tests.dist4
-rw-r--r--gnu/usr.bin/binutils/ld/Makefile1
-rw-r--r--lib/libc/net/map_v4v6.c16
-rw-r--r--lib/libc/tests/Makefile2
-rw-r--r--lib/libc/tests/nss/Makefile22
-rw-r--r--lib/libc/tests/nss/getaddrinfo_test.c556
-rw-r--r--lib/libc/tests/nss/getgr_test.c541
-rw-r--r--lib/libc/tests/nss/gethostby_test.c1506
-rw-r--r--lib/libc/tests/nss/getproto_test.c556
-rw-r--r--lib/libc/tests/nss/getpw_test.c530
-rw-r--r--lib/libc/tests/nss/getrpc_test.c560
-rw-r--r--lib/libc/tests/nss/getserv_test.c570
-rw-r--r--lib/libc/tests/nss/getusershell_test.c225
-rw-r--r--lib/libc/tests/nss/testutil.h333
-rw-r--r--lib/libc/tests/resolv/Makefile15
-rw-r--r--lib/libc/tests/resolv/mach46
-rw-r--r--lib/libc/tests/resolv/resolv_test.c331
-rw-r--r--release/Makefile13
-rw-r--r--release/Makefile.vm2
-rw-r--r--share/mk/bsd.own.mk9
-rw-r--r--sys/dev/isp/isp.c565
-rw-r--r--sys/dev/isp/isp_freebsd.c20
-rw-r--r--sys/dev/isp/isp_freebsd.h56
-rw-r--r--sys/dev/isp/isp_library.c327
-rw-r--r--sys/dev/isp/isp_library.h15
-rw-r--r--sys/dev/isp/isp_pci.c294
-rw-r--r--sys/dev/isp/isp_sbus.c120
-rw-r--r--sys/dev/isp/isp_target.c4
-rw-r--r--sys/dev/isp/ispmbox.h2
-rw-r--r--sys/dev/isp/ispvar.h29
-rw-r--r--sys/dev/pci/pci.c52
-rw-r--r--sys/dev/pci/pci_if.m24
-rw-r--r--sys/dev/pci/pci_private.h6
-rw-r--r--sys/dev/pci/pcivar.h25
-rw-r--r--sys/dev/virtio/balloon/virtio_balloon.c4
-rw-r--r--sys/dev/xen/balloon/balloon.c89
-rw-r--r--sys/fs/devfs/devfs_vnops.c21
-rw-r--r--sys/fs/nfs/nfsport.h7
-rw-r--r--sys/fs/nfsclient/nfs_clnode.c5
-rw-r--r--sys/fs/nfsclient/nfs_clport.c2
-rw-r--r--sys/kern/imgact_elf.c3
-rw-r--r--sys/kern/vfs_subr.c475
-rw-r--r--sys/ofed/include/linux/pci.h4
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c6
-rwxr-xr-xtests/sys/file/flock_test.sh5
-rwxr-xr-xtools/regression/mac/mac_portacl/misc.sh44
-rwxr-xr-xtools/regression/mac/mac_portacl/nobody.t4
-rwxr-xr-xtools/regression/mac/mac_portacl/root.t4
-rw-r--r--usr.sbin/crunch/crunchide/exec_elf32.c1
-rw-r--r--usr.sbin/sysrc/sysrc181
-rw-r--r--usr.sbin/sysrc/sysrc.869
-rw-r--r--usr.sbin/uhsoctl/uhsoctl.c1
61 files changed, 7354 insertions, 1056 deletions
diff --git a/.arcconfig b/.arcconfig
new file mode 100644
index 0000000..54153b9
--- /dev/null
+++ b/.arcconfig
@@ -0,0 +1,6 @@
+{
+ "project.name": "S",
+ "repository.callsign" : "S",
+ "phabricator.uri" : "https://reviews.freebsd.org/",
+ "history.immutable" : true
+}
diff --git a/.arclint b/.arclint
new file mode 100644
index 0000000..31bda09
--- /dev/null
+++ b/.arclint
@@ -0,0 +1,25 @@
+{
+ "exclude": "(contrib|crypto)",
+ "linters": {
+ "python": {
+ "type": "pep8",
+ "include": "(\\.py$)"
+ },
+ "spelling": {
+ "type": "spelling"
+ },
+ "chmod": {
+ "type": "chmod"
+ },
+ "merge-conflict": {
+ "type": "merge-conflict"
+ },
+ "filename": {
+ "type": "filename"
+ },
+ "json": {
+ "type": "json",
+ "include": "(\\.arclint|\\.json$)"
+ }
+ }
+}
diff --git a/Makefile.inc1 b/Makefile.inc1
index 8c1b8ac..de4b434 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -913,13 +913,13 @@ packageworld:
.for dist in base ${EXTRA_DISTRIBUTIONS}
.if defined(NO_ROOT)
${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \
- tar cvJf ${DESTDIR}/${DISTDIR}/${dist}.txz \
- --exclude usr/lib/debug \
- @${DESTDIR}/${DISTDIR}/${dist}.meta
+ tar cvf - --exclude usr/lib/debug \
+ @${DESTDIR}/${DISTDIR}/${dist}.meta | \
+ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}.txz
.else
${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \
- tar cvJf ${DESTDIR}/${DISTDIR}/${dist}.txz \
- --exclude usr/lib/debug .
+ tar cvf - --exclude usr/lib/debug . | \
+ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}.txz
.endif
.endfor
@@ -927,12 +927,12 @@ packageworld:
. for dist in base ${EXTRA_DISTRIBUTIONS}
. if defined(NO_ROOT)
${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \
- tar cvJf ${DESTDIR}/${DISTDIR}/${dist}.debug.txz \
- @${DESTDIR}/${DISTDIR}/${dist}.debug.meta
+ tar cvf - @${DESTDIR}/${DISTDIR}/${dist}.debug.meta | \
+ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}.debug.txz
. else
${_+_}cd ${DESTDIR}/${DISTDIR}/${dist}; \
- tar cvJfL ${DESTDIR}/${DISTDIR}/${dist}.debug.txz \
- usr/lib/debug
+ tar cvLf - usr/lib/debug | \
+ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/${dist}-debug.txz
. endif
. endfor
.endif
@@ -1141,19 +1141,21 @@ distributekernel distributekernel.debug:
packagekernel:
.if defined(NO_ROOT)
cd ${DESTDIR}/${DISTDIR}/kernel; \
- tar cvJf ${DESTDIR}/${DISTDIR}/kernel.txz \
- @${DESTDIR}/${DISTDIR}/kernel.meta
+ tar cvf - @${DESTDIR}/${DISTDIR}/kernel.meta | \
+ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.txz
.for _kernel in ${BUILDKERNELS:S/${INSTALLKERNEL}//}
cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \
- tar cvJf ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.txz \
- @${DESTDIR}/${DISTDIR}/kernel.${_kernel}.meta
+ tar cvf - @${DESTDIR}/${DISTDIR}/kernel.${_kernel}.meta | \
+ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.txz
.endfor
.else
cd ${DESTDIR}/${DISTDIR}/kernel; \
- tar cvJf ${DESTDIR}/${DISTDIR}/kernel.txz .
+ tar cvf - . | \
+ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.txz
.for _kernel in ${BUILDKERNELS:S/${INSTALLKERNEL}//}
cd ${DESTDIR}/${DISTDIR}/kernel.${_kernel}; \
- tar cvJf ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.txz .
+ tar cvf - . | \
+ ${XZ_CMD} > ${DESTDIR}/${DISTDIR}/kernel.${_kernel}.txz
.endfor
.endif
diff --git a/contrib/netbsd-tests/lib/libc/gen/t_assert.c b/contrib/netbsd-tests/lib/libc/gen/t_assert.c
index 140417a..a09c130 100644
--- a/contrib/netbsd-tests/lib/libc/gen/t_assert.c
+++ b/contrib/netbsd-tests/lib/libc/gen/t_assert.c
@@ -40,6 +40,23 @@ __RCSID("$NetBSD: t_assert.c,v 1.2 2011/06/14 05:28:00 jruoho Exp $");
#include <string.h>
#include <unistd.h>
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+static void
+disable_corefile(void)
+{
+ struct rlimit limits;
+
+ limits.rlim_cur = 0;
+ limits.rlim_max = 0;
+
+ ATF_REQUIRE(setrlimit(RLIMIT_CORE, &limits) == 0);
+}
+#endif
+
static void handler(int);
static void
@@ -65,6 +82,9 @@ ATF_TC_BODY(assert_false, tc)
if (pid == 0) {
+#ifdef __FreeBSD__
+ disable_corefile();
+#endif
(void)closefrom(0);
(void)memset(&sa, 0, sizeof(struct sigaction));
@@ -102,6 +122,9 @@ ATF_TC_BODY(assert_true, tc)
if (pid == 0) {
+#ifdef __FreeBSD__
+ disable_corefile();
+#endif
(void)closefrom(0);
(void)memset(&sa, 0, sizeof(struct sigaction));
diff --git a/contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh b/contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh
index 04adc67..2986ccf 100755
--- a/contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh
+++ b/contrib/netbsd-tests/lib/libc/ssp/t_ssp.sh
@@ -35,6 +35,7 @@ h_fail()
{
echo "Executing command [ $2$1 ]"
# Begin FreeBSD
+ ulimit -c 0
if true; then
eval $2 atf_check -s signal -o ignore -e ignore $1
else
diff --git a/contrib/netbsd-tests/usr.bin/grep/d_binary.out b/contrib/netbsd-tests/usr.bin/grep/d_binary.out
index ce03056..f0ef988 100644
--- a/contrib/netbsd-tests/usr.bin/grep/d_binary.out
+++ b/contrib/netbsd-tests/usr.bin/grep/d_binary.out
@@ -1 +1 @@
-Binary file /bin/sh matches
+Binary file test.file matches
diff --git a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh
index f2d70f0..7e53016 100755
--- a/contrib/netbsd-tests/usr.bin/grep/t_grep.sh
+++ b/contrib/netbsd-tests/usr.bin/grep/t_grep.sh
@@ -43,7 +43,20 @@ binary_head()
}
binary_body()
{
+ # Begin FreeBSD
+ #
+ # Generate stable output instead of depending on uname to match the
+ # branded OS name of /bin/sh
+ if true; then
+ dd if=/dev/zero count=1 of=test.file
+ echo -n "foobar" >> test.file
+ atf_check -o file:"$(atf_get_srcdir)/d_binary.out" grep foobar test.file
+ else
+ # End FreeBSD
atf_check -o file:"$(atf_get_srcdir)/d_binary.out" grep $(uname) /bin/sh
+ # Begin FreeBSD
+ fi
+ # End FreeBSD
}
atf_test_case recurse
diff --git a/etc/defaults/periodic.conf b/etc/defaults/periodic.conf
index 14f1a08..d97bd93 100644
--- a/etc/defaults/periodic.conf
+++ b/etc/defaults/periodic.conf
@@ -319,8 +319,8 @@ if [ -z "${source_periodic_confs_defined}" ]; then
"use \$$var instead." >&2
case "$value" in
[Yy][Ee][Ss])
- $var=YES
- $periodvar=daily
+ eval $var=YES
+ eval $periodvar=daily
;;
*)
eval $var=\"$value\"
diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist
index 41e8421..f189ea9 100644
--- a/etc/mtree/BSD.tests.dist
+++ b/etc/mtree/BSD.tests.dist
@@ -109,10 +109,14 @@
..
..
..
+ nss
+ ..
regex
data
..
..
+ resolv
+ ..
rpc
..
ssp
diff --git a/gnu/usr.bin/binutils/ld/Makefile b/gnu/usr.bin/binutils/ld/Makefile
index 9e2acd8..58a6848 100644
--- a/gnu/usr.bin/binutils/ld/Makefile
+++ b/gnu/usr.bin/binutils/ld/Makefile
@@ -52,6 +52,7 @@ CLEANFILES+= ldemul-list.h stringify.sed
FILES= ${LDSCRIPTS:S|^|ldscripts/|}
FILESDIR= ${SCRIPTDIR}
+LINKS= ${BINDIR}/ld ${BINDIR}/ld.bfd
HOST= ${TARGET_TUPLE}
LIBSEARCHPATH= \"=/lib\":\"=/usr/lib\"
diff --git a/lib/libc/net/map_v4v6.c b/lib/libc/net/map_v4v6.c
index dbc7e70..871cfda 100644
--- a/lib/libc/net/map_v4v6.c
+++ b/lib/libc/net/map_v4v6.c
@@ -77,19 +77,11 @@ typedef union {
void
_map_v4v6_address(const char *src, char *dst)
{
- u_char *p = (u_char *)dst;
- char tmp[NS_INADDRSZ];
- int i;
-
- /* Stash a temporary copy so our caller can update in place. */
- memcpy(tmp, src, NS_INADDRSZ);
+ /* Our caller may update in place. */
+ memmove(&dst[12], src, NS_INADDRSZ);
/* Mark this ipv6 addr as a mapped ipv4. */
- for (i = 0; i < 10; i++)
- *p++ = 0x00;
- *p++ = 0xff;
- *p++ = 0xff;
- /* Retrieve the saved copy and we're done. */
- memcpy((void*)p, tmp, NS_INADDRSZ);
+ memset(&dst[10], 0xff, 2);
+ memset(&dst[0], 0, 10);
}
void
diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile
index bf5bf25..15db4fd 100644
--- a/lib/libc/tests/Makefile
+++ b/lib/libc/tests/Makefile
@@ -12,7 +12,9 @@ TESTS_SUBDIRS+= gen
TESTS_SUBDIRS+= hash
TESTS_SUBDIRS+= inet
TESTS_SUBDIRS+= net
+TESTS_SUBDIRS+= nss
TESTS_SUBDIRS+= regex
+TESTS_SUBDIRS+= resolv
TESTS_SUBDIRS+= rpc
TESTS_SUBDIRS+= stdio
TESTS_SUBDIRS+= stdlib
diff --git a/lib/libc/tests/nss/Makefile b/lib/libc/tests/nss/Makefile
new file mode 100644
index 0000000..1b777c2
--- /dev/null
+++ b/lib/libc/tests/nss/Makefile
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libc/nss
+BINDIR= ${TESTSDIR}
+
+.PATH: ${.CURDIR:H}/resolv
+
+FILES+= mach
+
+CFLAGS+= -I${SRCTOP}/tests
+
+ATF_TESTS_C+= getaddrinfo_test
+ATF_TESTS_C+= getgr_test
+ATF_TESTS_C+= gethostby_test
+TEST_METADATA.gethostby_test= timeout="1200"
+ATF_TESTS_C+= getpw_test
+ATF_TESTS_C+= getproto_test
+ATF_TESTS_C+= getrpc_test
+ATF_TESTS_C+= getserv_test
+ATF_TESTS_C+= getusershell_test
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/nss/getaddrinfo_test.c b/lib/libc/tests/nss/getaddrinfo_test.c
new file mode 100644
index 0000000..0c9704f
--- /dev/null
+++ b/lib/libc/tests/nss/getaddrinfo_test.c
@@ -0,0 +1,556 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "freebsd_test_suite/macros.h"
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETADDRINFO,
+ TEST_BUILD_SNAPSHOT
+};
+
+static struct addrinfo hints;
+static enum test_methods method = TEST_GETADDRINFO;
+
+DECLARE_TEST_DATA(addrinfo)
+DECLARE_TEST_FILE_SNAPSHOT(addrinfo)
+DECLARE_2PASS_TEST(addrinfo)
+
+static void clone_addrinfo(struct addrinfo *, struct addrinfo const *);
+static int compare_addrinfo(struct addrinfo *, struct addrinfo *, void *);
+static void dump_addrinfo(struct addrinfo *);
+
+static void sdump_addrinfo(struct addrinfo *, char *, size_t);
+
+IMPLEMENT_TEST_DATA(addrinfo)
+IMPLEMENT_TEST_FILE_SNAPSHOT(addrinfo)
+IMPLEMENT_2PASS_TEST(addrinfo)
+
+static void
+clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src)
+{
+
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ memcpy(dest, src, sizeof(struct addrinfo));
+ if (src->ai_canonname != NULL)
+ dest->ai_canonname = strdup(src->ai_canonname);
+
+ if (src->ai_addr != NULL) {
+ dest->ai_addr = malloc(src->ai_addrlen);
+ ATF_REQUIRE(dest->ai_addr != NULL);
+ memcpy(dest->ai_addr, src->ai_addr, src->ai_addrlen);
+ }
+
+ if (src->ai_next != NULL) {
+ dest->ai_next = malloc(sizeof(struct addrinfo));
+ ATF_REQUIRE(dest->ai_next != NULL);
+ clone_addrinfo(dest->ai_next, src->ai_next);
+ }
+}
+
+static int
+compare_addrinfo_(struct addrinfo *ai1, struct addrinfo *ai2)
+{
+
+ if ((ai1 == NULL) || (ai2 == NULL))
+ return (-1);
+
+ if (ai1->ai_flags != ai2->ai_flags ||
+ ai1->ai_family != ai2->ai_family ||
+ ai1->ai_socktype != ai2->ai_socktype ||
+ ai1->ai_protocol != ai2->ai_protocol ||
+ ai1->ai_addrlen != ai2->ai_addrlen ||
+ ((ai1->ai_addr == NULL || ai2->ai_addr == NULL) &&
+ ai1->ai_addr != ai2->ai_addr) ||
+ ((ai1->ai_canonname == NULL || ai2->ai_canonname == NULL) &&
+ ai1->ai_canonname != ai2->ai_canonname))
+ return (-1);
+
+ if (ai1->ai_canonname != NULL &&
+ strcmp(ai1->ai_canonname, ai2->ai_canonname) != 0)
+ return (-1);
+
+ if (ai1->ai_addr != NULL &&
+ memcmp(ai1->ai_addr, ai2->ai_addr, ai1->ai_addrlen) != 0)
+ return (-1);
+
+ if (ai1->ai_next == NULL && ai2->ai_next == NULL)
+ return (0);
+ else
+ return (compare_addrinfo_(ai1->ai_next, ai2->ai_next));
+}
+
+static int
+compare_addrinfo(struct addrinfo *ai1, struct addrinfo *ai2, void *mdata)
+{
+ int rv;
+
+ printf("testing equality of 2 addrinfo structures\n");
+
+ rv = compare_addrinfo_(ai1, ai2);
+
+ if (rv == 0)
+ printf("equal\n");
+ else {
+ dump_addrinfo(ai1);
+ dump_addrinfo(ai2);
+ printf("not equal\n");
+ }
+
+ return (rv);
+}
+
+void
+free_addrinfo(struct addrinfo *ai)
+{
+ if (ai == NULL)
+ return;
+
+ free(ai->ai_addr);
+ free(ai->ai_canonname);
+ free_addrinfo(ai->ai_next);
+}
+
+void
+sdump_addrinfo(struct addrinfo *ai, char *buffer, size_t buflen)
+{
+ int written, i;
+
+ written = snprintf(buffer, buflen, "%d %d %d %d %d ",
+ ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol,
+ ai->ai_addrlen);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ written = snprintf(buffer, buflen, "%s ",
+ ai->ai_canonname == NULL ? "(null)" : ai->ai_canonname);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (ai->ai_addr == NULL) {
+ written = snprintf(buffer, buflen, "(null)");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ } else {
+ for (i = 0; i < ai->ai_addrlen; i++) {
+ written = snprintf(buffer, buflen,
+ i + 1 != ai->ai_addrlen ? "%d." : "%d",
+ ((unsigned char *)ai->ai_addr)[i]);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ }
+
+ if (ai->ai_next != NULL) {
+ written = snprintf(buffer, buflen, ":");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ sdump_addrinfo(ai->ai_next, buffer, buflen);
+ }
+}
+
+void
+dump_addrinfo(struct addrinfo *result)
+{
+ if (result != NULL) {
+ char buffer[2048];
+ sdump_addrinfo(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+addrinfo_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
+{
+ char *s, *ps, *ts;
+
+ ps = addr;
+ while ((s = strsep(&ps, ".")) != NULL) {
+ if (len == 0)
+ return (-1);
+
+ *result = (unsigned char)strtol(s, &ts, 10);
+ ++result;
+ if (*ts != '\0')
+ return (-1);
+
+ --len;
+ }
+ if (len != 0)
+ return (-1);
+ else
+ return (0);
+}
+
+static int
+addrinfo_read_snapshot_ai(struct addrinfo *ai, char *line)
+{
+ char *s, *ps, *ts;
+ int i, rv, *pi;
+
+ rv = 0;
+ i = 0;
+ ps = line;
+ memset(ai, 0, sizeof(struct addrinfo));
+ while ((s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ pi = &ai->ai_flags + i;
+ *pi = (int)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 4:
+ ai->ai_addrlen = (socklen_t)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 5:
+ if (strcmp(s, "(null)") != 0) {
+ ai->ai_canonname = strdup(s);
+ ATF_REQUIRE(ai->ai_canonname != NULL);
+ }
+ break;
+ case 6:
+ if (strcmp(s, "(null)") != 0) {
+ ai->ai_addr = calloc(1, ai->ai_addrlen);
+ ATF_REQUIRE(ai->ai_addr != NULL);
+ rv = addrinfo_read_snapshot_addr(s,
+ (unsigned char *)ai->ai_addr,
+ ai->ai_addrlen);
+
+ if (rv != 0)
+ goto fin;
+ }
+ break;
+ default:
+ /* NOTE: should not be reachable */
+ rv = -1;
+ goto fin;
+ }
+
+ ++i;
+ }
+
+fin:
+ if (i != 7 || rv != 0) {
+ free_addrinfo(ai);
+ ai = NULL;
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+addrinfo_read_snapshot_func(struct addrinfo *ai, char *line)
+{
+ struct addrinfo *ai2;
+ char *s, *ps;
+ int i, rv;
+
+ printf("1 line read from snapshot:\n%s\n", line);
+
+ rv = 0;
+ i = 0;
+ ps = line;
+
+ s = strsep(&ps, ":");
+ if (s == NULL)
+ return (-1);
+
+ rv = addrinfo_read_snapshot_ai(ai, s);
+ if (rv != 0)
+ return (-1);
+
+ ai2 = ai;
+ while ((s = strsep(&ps, ":")) != NULL) {
+ ai2->ai_next = calloc(1, sizeof(struct addrinfo));
+ ATF_REQUIRE(ai2->ai_next != NULL);
+
+ rv = addrinfo_read_snapshot_ai(ai2->ai_next, s);
+ if (rv != 0) {
+ free_addrinfo(ai);
+ ai = NULL;
+ return (-1);
+ }
+
+ ai2 = ai2->ai_next;
+ }
+
+ return (0);
+}
+
+static int
+addrinfo_test_correctness(struct addrinfo *ai, void *mdata)
+{
+
+ printf("testing correctness with the following data:\n");
+ dump_addrinfo(ai);
+
+ if (ai == NULL)
+ goto errfin;
+
+ if (!(ai->ai_family >= 0 && ai->ai_family < AF_MAX))
+ goto errfin;
+
+ if (ai->ai_socktype != 0 && ai->ai_socktype != SOCK_STREAM &&
+ ai->ai_socktype != SOCK_DGRAM && ai->ai_socktype != SOCK_RAW)
+ goto errfin;
+
+ if (ai->ai_protocol != 0 && ai->ai_protocol != IPPROTO_UDP &&
+ ai->ai_protocol != IPPROTO_TCP)
+ goto errfin;
+
+ if ((ai->ai_flags & ~(AI_CANONNAME | AI_NUMERICHOST | AI_PASSIVE)) != 0)
+ goto errfin;
+
+ if (ai->ai_addrlen != ai->ai_addr->sa_len ||
+ ai->ai_family != ai->ai_addr->sa_family)
+ goto errfin;
+
+ printf("correct\n");
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+static int
+addrinfo_read_hostlist_func(struct addrinfo *ai, char *line)
+{
+ struct addrinfo *result;
+ int rv;
+
+ printf("resolving %s: ", line);
+ rv = getaddrinfo(line, NULL, &hints, &result);
+ if (rv == 0) {
+ printf("found\n");
+
+ rv = addrinfo_test_correctness(result, NULL);
+ if (rv != 0) {
+ freeaddrinfo(result);
+ result = NULL;
+ return (rv);
+ }
+
+ clone_addrinfo(ai, result);
+ freeaddrinfo(result);
+ result = NULL;
+ } else {
+ printf("not found\n");
+
+ memset(ai, 0, sizeof(struct addrinfo));
+ }
+ return (0);
+}
+
+void
+run_tests(char *hostlist_file, char *snapshot_file, int ai_family)
+{
+ struct addrinfo_test_data td, td_snap;
+ int rv;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = ai_family;
+ hints.ai_flags = AI_CANONNAME;
+
+ if (snapshot_file != NULL)
+ method = TEST_BUILD_SNAPSHOT;
+
+ TEST_DATA_INIT(addrinfo, &td, clone_addrinfo, free_addrinfo);
+ TEST_DATA_INIT(addrinfo, &td_snap, clone_addrinfo, free_addrinfo);
+
+ ATF_REQUIRE_MSG(access(hostlist_file, R_OK) == 0,
+ "can't access the hostlist file %s\n", hostlist_file);
+
+ printf("building host lists from %s\n", hostlist_file);
+
+ rv = TEST_SNAPSHOT_FILE_READ(addrinfo, hostlist_file, &td,
+ addrinfo_read_hostlist_func);
+ if (rv != 0)
+ goto fin;
+
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the snapshot "
+ "file %s\n", snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file,
+ &td_snap, addrinfo_read_snapshot_func);
+ if (rv != 0) {
+ printf("error reading snapshot file: %s\n",
+ strerror(errno));
+ goto fin;
+ }
+ }
+ }
+
+ switch (method) {
+ case TEST_GETADDRINFO:
+ if (snapshot_file != NULL)
+ ATF_CHECK(DO_2PASS_TEST(addrinfo, &td, &td_snap,
+ compare_addrinfo, NULL) == 0);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL) {
+ ATF_CHECK(TEST_SNAPSHOT_FILE_WRITE(addrinfo,
+ snapshot_file, &td, sdump_addrinfo) == 0);
+ }
+ break;
+ default:
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(addrinfo, &td_snap);
+ TEST_DATA_DESTROY(addrinfo, &td);
+
+ free(hostlist_file);
+ free(snapshot_file);
+}
+
+#define HOSTLIST_FILE "mach"
+#define RUN_TESTS(tc, snapshot_file, ai_family) do { \
+ char *_hostlist_file; \
+ char *_snapshot_file; \
+ ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \
+ atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \
+ if (snapshot_file == NULL) \
+ _snapshot_file = NULL; \
+ else { \
+ _snapshot_file = strdup(snapshot_file); \
+ ATF_REQUIRE(_snapshot_file != NULL); \
+ } \
+ run_tests(_hostlist_file, _snapshot_file, ai_family); \
+} while(0)
+
+ATF_TC_WITHOUT_HEAD(pf_unspec);
+ATF_TC_BODY(pf_unspec, tc)
+{
+
+ RUN_TESTS(tc, NULL, AF_UNSPEC);
+}
+
+ATF_TC_WITHOUT_HEAD(pf_unspec_with_snapshot);
+ATF_TC_BODY(pf_unspec_with_snapshot, tc)
+{
+
+ RUN_TESTS(tc, "snapshot_ai", AF_UNSPEC);
+}
+
+ATF_TC_WITHOUT_HEAD(pf_inet);
+ATF_TC_BODY(pf_inet, tc)
+{
+
+ ATF_REQUIRE_FEATURE("inet");
+ RUN_TESTS(tc, NULL, AF_INET);
+}
+
+ATF_TC_WITHOUT_HEAD(pf_inet_with_snapshot);
+ATF_TC_BODY(pf_inet_with_snapshot, tc)
+{
+
+ ATF_REQUIRE_FEATURE("inet");
+ RUN_TESTS(tc, "snapshot_ai4", AF_INET);
+}
+
+ATF_TC_WITHOUT_HEAD(pf_inet6);
+ATF_TC_BODY(pf_inet6, tc)
+{
+
+ ATF_REQUIRE_FEATURE("inet6");
+ RUN_TESTS(tc, NULL, AF_INET6);
+}
+
+ATF_TC_WITHOUT_HEAD(pf_inet6_with_snapshot);
+ATF_TC_BODY(pf_inet6_with_snapshot, tc)
+{
+
+ ATF_REQUIRE_FEATURE("inet6");
+ RUN_TESTS(tc, "snapshot_ai6", AF_INET6);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, pf_unspec);
+ ATF_TP_ADD_TC(tp, pf_unspec_with_snapshot);
+ ATF_TP_ADD_TC(tp, pf_inet);
+ ATF_TP_ADD_TC(tp, pf_inet_with_snapshot);
+ ATF_TP_ADD_TC(tp, pf_inet6);
+ ATF_TP_ADD_TC(tp, pf_inet6_with_snapshot);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getgr_test.c b/lib/libc/tests/nss/getgr_test.c
new file mode 100644
index 0000000..d9851ef
--- /dev/null
+++ b/lib/libc/tests/nss/getgr_test.c
@@ -0,0 +1,541 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETGRENT = 1,
+ TEST_GETGRNAM = 2,
+ TEST_GETGRGID = 4,
+ TEST_GETGRENT_2PASS = 8,
+ TEST_BUILD_SNAPSHOT = 16,
+};
+
+static enum test_methods method = TEST_BUILD_SNAPSHOT;
+
+DECLARE_TEST_DATA(group)
+DECLARE_TEST_FILE_SNAPSHOT(group)
+DECLARE_1PASS_TEST(group)
+DECLARE_2PASS_TEST(group)
+
+static void clone_group(struct group *, struct group const *);
+static int compare_group(struct group *, struct group *, void *);
+static void dump_group(struct group *);
+static void free_group(struct group *);
+
+static void sdump_group(struct group *, char *, size_t);
+static int group_read_snapshot_func(struct group *, char *);
+
+static int group_check_ambiguity(struct group_test_data *,
+ struct group *);
+static int group_fill_test_data(struct group_test_data *);
+static int group_test_correctness(struct group *, void *);
+static int group_test_getgrnam(struct group *, void *);
+static int group_test_getgrgid(struct group *, void *);
+static int group_test_getgrent(struct group *, void *);
+
+IMPLEMENT_TEST_DATA(group)
+IMPLEMENT_TEST_FILE_SNAPSHOT(group)
+IMPLEMENT_1PASS_TEST(group)
+IMPLEMENT_2PASS_TEST(group)
+
+static void
+clone_group(struct group *dest, struct group const *src)
+{
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ char **cp;
+ int members_num;
+
+ memset(dest, 0, sizeof(struct group));
+
+ if (src->gr_name != NULL) {
+ dest->gr_name = strdup(src->gr_name);
+ ATF_REQUIRE(dest->gr_name != NULL);
+ }
+
+ if (src->gr_passwd != NULL) {
+ dest->gr_passwd = strdup(src->gr_passwd);
+ ATF_REQUIRE(dest->gr_passwd != NULL);
+ }
+ dest->gr_gid = src->gr_gid;
+
+ if (src->gr_mem != NULL) {
+ members_num = 0;
+ for (cp = src->gr_mem; *cp; ++cp)
+ ++members_num;
+
+ dest->gr_mem = calloc(1, (members_num + 1) * sizeof(char *));
+ ATF_REQUIRE(dest->gr_mem != NULL);
+
+ for (cp = src->gr_mem; *cp; ++cp) {
+ dest->gr_mem[cp - src->gr_mem] = strdup(*cp);
+ ATF_REQUIRE(dest->gr_mem[cp - src->gr_mem] != NULL);
+ }
+ }
+}
+
+static void
+free_group(struct group *grp)
+{
+ char **cp;
+
+ ATF_REQUIRE(grp != NULL);
+
+ free(grp->gr_name);
+ free(grp->gr_passwd);
+
+ for (cp = grp->gr_mem; *cp; ++cp)
+ free(*cp);
+ free(grp->gr_mem);
+}
+
+static int
+compare_group(struct group *grp1, struct group *grp2, void *mdata)
+{
+ char **c1, **c2;
+
+ if (grp1 == grp2)
+ return (0);
+
+ if (grp1 == NULL || grp2 == NULL)
+ goto errfin;
+
+ if (strcmp(grp1->gr_name, grp2->gr_name) != 0 ||
+ strcmp(grp1->gr_passwd, grp2->gr_passwd) != 0 ||
+ grp1->gr_gid != grp2->gr_gid)
+ goto errfin;
+
+ c1 = grp1->gr_mem;
+ c2 = grp2->gr_mem;
+
+ if (grp1->gr_mem == NULL || grp2->gr_mem == NULL)
+ goto errfin;
+
+ for (; *c1 && *c2; ++c1, ++c2)
+ if (strcmp(*c1, *c2) != 0)
+ goto errfin;
+
+ if (*c1 != '\0' || *c2 != '\0')
+ goto errfin;
+
+ return 0;
+
+errfin:
+ if (mdata == NULL) {
+ printf("following structures are not equal:\n");
+ dump_group(grp1);
+ dump_group(grp2);
+ }
+
+ return (-1);
+}
+
+static void
+sdump_group(struct group *grp, char *buffer, size_t buflen)
+{
+ char **cp;
+ int written;
+
+ written = snprintf(buffer, buflen, "%s %s %d",
+ grp->gr_name, grp->gr_passwd, grp->gr_gid);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (grp->gr_mem != NULL) {
+ if (*(grp->gr_mem) != '\0') {
+ for (cp = grp->gr_mem; *cp; ++cp) {
+ written = snprintf(buffer, buflen, " %s",*cp);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ } else
+ snprintf(buffer, buflen, " nomem");
+ } else
+ snprintf(buffer, buflen, " (null)");
+}
+
+static int
+group_read_snapshot_func(struct group *grp, char *line)
+{
+ StringList *sl;
+ char *s, *ps, *ts;
+ int i;
+
+ printf("1 line read from snapshot:\n%s\n", line);
+
+ i = 0;
+ sl = NULL;
+ ps = line;
+ memset(grp, 0, sizeof(struct group));
+ while ((s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ grp->gr_name = strdup(s);
+ ATF_REQUIRE(grp->gr_name != NULL);
+ break;
+
+ case 1:
+ grp->gr_passwd = strdup(s);
+ ATF_REQUIRE(grp->gr_passwd != NULL);
+ break;
+
+ case 2:
+ grp->gr_gid = (gid_t)strtol(s, &ts, 10);
+ if (*ts != '\0') {
+ free(grp->gr_name);
+ free(grp->gr_passwd);
+ grp->gr_name = NULL;
+ grp->gr_passwd = NULL;
+ return (-1);
+ }
+ break;
+
+ default:
+ if (sl == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl = sl_init();
+ ATF_REQUIRE(sl != NULL);
+
+ if (strcmp(s, "nomem") != 0) {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ } else {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ break;
+ }
+ ++i;
+ }
+
+ if (i < 3) {
+ free(grp->gr_name);
+ free(grp->gr_passwd);
+ memset(grp, 0, sizeof(struct group));
+ return (-1);
+ }
+
+ sl_add(sl, NULL);
+ grp->gr_mem = sl->sl_str;
+
+ /* NOTE: is it a dirty hack or not? */
+ free(sl);
+ return (0);
+}
+
+static void
+dump_group(struct group *result)
+{
+ if (result != NULL) {
+ char buffer[1024];
+ sdump_group(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+group_fill_test_data(struct group_test_data *td)
+{
+ struct group *grp;
+
+ setgroupent(1);
+ while ((grp = getgrent()) != NULL) {
+ if (group_test_correctness(grp, NULL) == 0)
+ TEST_DATA_APPEND(group, td, grp);
+ else
+ return (-1);
+ }
+ endgrent();
+
+ return (0);
+}
+
+static int
+group_test_correctness(struct group *grp, void *mdata)
+{
+ printf("testing correctness with the following data:\n");
+ dump_group(grp);
+
+ if (grp == NULL)
+ goto errfin;
+
+ if (grp->gr_name == NULL)
+ goto errfin;
+
+ if (grp->gr_passwd == NULL)
+ goto errfin;
+
+ if (grp->gr_mem == NULL)
+ goto errfin;
+
+ printf("correct\n");
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+/* group_check_ambiguity() is needed here because when doing the getgrent()
+ * calls sequence, records from different nsswitch sources can be different,
+ * though having the same pw_name/pw_uid */
+static int
+group_check_ambiguity(struct group_test_data *td, struct group *pwd)
+{
+
+ return (TEST_DATA_FIND(group, td, pwd, compare_group,
+ NULL) != NULL ? 0 : -1);
+}
+
+static int
+group_test_getgrnam(struct group *grp_model, void *mdata)
+{
+ struct group *grp;
+
+ printf("testing getgrnam() with the following data:\n");
+ dump_group(grp_model);
+
+ grp = getgrnam(grp_model->gr_name);
+ if (group_test_correctness(grp, NULL) != 0)
+ goto errfin;
+
+ if (compare_group(grp, grp_model, NULL) != 0 &&
+ group_check_ambiguity((struct group_test_data *)mdata, grp) != 0)
+ goto errfin;
+
+ return (0);
+
+errfin:
+ return (-1);
+}
+
+static int
+group_test_getgrgid(struct group *grp_model, void *mdata)
+{
+ struct group *grp;
+
+ printf("testing getgrgid() with the following data...\n");
+ dump_group(grp_model);
+
+ grp = getgrgid(grp_model->gr_gid);
+ if (group_test_correctness(grp, NULL) != 0 ||
+ (compare_group(grp, grp_model, NULL) != 0 &&
+ group_check_ambiguity((struct group_test_data *)mdata, grp) != 0)) {
+ return (-1);
+ } else {
+ return (0);
+ }
+}
+
+static int
+group_test_getgrent(struct group *grp, void *mdata)
+{
+ /* Only correctness can be checked when doing 1-pass test for
+ * getgrent(). */
+ return (group_test_correctness(grp, NULL));
+}
+
+static int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct group_test_data td, td_snap, td_2pass;
+ int rv;
+
+ TEST_DATA_INIT(group, &td, clone_group, free_group);
+ TEST_DATA_INIT(group, &td_snap, clone_group, free_group);
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the file %s\n",
+ snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ if (method == TEST_BUILD_SNAPSHOT) {
+ rv = 0;
+ goto fin;
+ }
+
+ TEST_SNAPSHOT_FILE_READ(group, snapshot_file,
+ &td_snap, group_read_snapshot_func);
+ }
+ }
+
+ rv = group_fill_test_data(&td);
+ if (rv == -1)
+ return (-1);
+ switch (method) {
+ case TEST_GETGRNAM:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(group, &td,
+ group_test_getgrnam, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(group, &td_snap,
+ group_test_getgrnam, (void *)&td_snap);
+ break;
+ case TEST_GETGRGID:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(group, &td,
+ group_test_getgrgid, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(group, &td_snap,
+ group_test_getgrgid, (void *)&td_snap);
+ break;
+ case TEST_GETGRENT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(group, &td, group_test_getgrent,
+ (void *)&td);
+ else
+ rv = DO_2PASS_TEST(group, &td, &td_snap,
+ compare_group, NULL);
+ break;
+ case TEST_GETGRENT_2PASS:
+ TEST_DATA_INIT(group, &td_2pass, clone_group, free_group);
+ rv = group_fill_test_data(&td_2pass);
+ if (rv != -1)
+ rv = DO_2PASS_TEST(group, &td, &td_2pass,
+ compare_group, NULL);
+ TEST_DATA_DESTROY(group, &td_2pass);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL)
+ rv = TEST_SNAPSHOT_FILE_WRITE(group, snapshot_file, &td,
+ sdump_group);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(group, &td_snap);
+ TEST_DATA_DESTROY(group, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_grp"
+
+ATF_TC_BODY(getgrent, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrent_with_snapshot);
+ATF_TC_BODY(getgrent_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrent_with_two_pass);
+ATF_TC_BODY(getgrent_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT_2PASS) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrgid);
+ATF_TC_BODY(getgrgid, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRGID) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrgid_with_snapshot);
+ATF_TC_BODY(getgrgid_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRGID) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrnam);
+ATF_TC_BODY(getgrnam, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRNAM) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrnam_with_snapshot);
+ATF_TC_BODY(getgrnam_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRNAM) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getgrent);
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, getgrent);
+ ATF_TP_ADD_TC(tp, getgrent_with_snapshot);
+ ATF_TP_ADD_TC(tp, getgrent_with_two_pass);
+ ATF_TP_ADD_TC(tp, getgrgid);
+ ATF_TP_ADD_TC(tp, getgrgid_with_snapshot);
+ ATF_TP_ADD_TC(tp, getgrnam);
+ ATF_TP_ADD_TC(tp, getgrnam_with_snapshot);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/gethostby_test.c b/lib/libc/tests/nss/gethostby_test.c
new file mode 100644
index 0000000..bdeafbc
--- /dev/null
+++ b/lib/libc/tests/nss/gethostby_test.c
@@ -0,0 +1,1506 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "freebsd_test_suite/macros.h"
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETHOSTBYNAME2,
+ TEST_GETHOSTBYADDR,
+ TEST_GETHOSTBYNAME2_GETADDRINFO,
+ TEST_GETHOSTBYADDR_GETNAMEINFO,
+ TEST_BUILD_SNAPSHOT,
+ TEST_BUILD_ADDR_SNAPSHOT
+};
+
+static int ipnode_flags = 0;
+static int af_type = AF_INET;
+static bool use_ipnode_functions;
+
+DECLARE_TEST_DATA(hostent)
+DECLARE_TEST_FILE_SNAPSHOT(hostent)
+DECLARE_1PASS_TEST(hostent)
+DECLARE_2PASS_TEST(hostent)
+
+/* These stubs will use gethostby***() or getipnodeby***() functions,
+ * depending on the use_ipnode_functions global variable value */
+static struct hostent *__gethostbyname2(const char *, int);
+static struct hostent *__gethostbyaddr(const void *, socklen_t, int);
+static void __freehostent(struct hostent *);
+
+static void clone_hostent(struct hostent *, struct hostent const *);
+static int compare_hostent(struct hostent *, struct hostent *, void *);
+static void dump_hostent(struct hostent *);
+static void free_hostent(struct hostent *);
+
+static int is_hostent_equal(struct hostent *, struct addrinfo *);
+
+static void sdump_hostent(struct hostent *, char *, size_t);
+static int hostent_read_hostlist_func(struct hostent *, char *);
+static int hostent_read_snapshot_addr(char *, unsigned char *, size_t);
+static int hostent_read_snapshot_func(struct hostent *, char *);
+
+static int hostent_test_correctness(struct hostent *, void *);
+static int hostent_test_gethostbyaddr(struct hostent *, void *);
+static int hostent_test_getaddrinfo_eq(struct hostent *, void *);
+static int hostent_test_getnameinfo_eq(struct hostent *, void *);
+
+static void usage(void) __attribute__((__noreturn__));
+
+IMPLEMENT_TEST_DATA(hostent)
+IMPLEMENT_TEST_FILE_SNAPSHOT(hostent)
+IMPLEMENT_1PASS_TEST(hostent)
+IMPLEMENT_2PASS_TEST(hostent)
+
+static struct hostent *
+__gethostbyname2(const char *name, int af)
+{
+ struct hostent *he;
+ int error;
+
+ if (use_ipnode_functions) {
+ error = 0;
+ he = getipnodebyname(name, af, ipnode_flags, &error);
+ if (he == NULL)
+ errno = error;
+ } else
+ he = gethostbyname2(name, af);
+
+ return (he);
+}
+
+static struct hostent *
+__gethostbyaddr(const void *addr, socklen_t len, int af)
+{
+ struct hostent *he;
+ int error;
+
+ if (use_ipnode_functions) {
+ error = 0;
+ he = getipnodebyaddr(addr, len, af, &error);
+ if (he == NULL)
+ errno = error;
+ } else
+ he = gethostbyaddr(addr, len, af);
+
+ return (he);
+}
+
+static void
+__freehostent(struct hostent *he)
+{
+
+ /* NOTE: checking for he != NULL - just in case */
+ if (use_ipnode_functions && he != NULL)
+ freehostent(he);
+}
+
+static void
+clone_hostent(struct hostent *dest, struct hostent const *src)
+{
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ char **cp;
+ int aliases_num;
+ int addrs_num;
+ size_t offset;
+
+ memset(dest, 0, sizeof(struct hostent));
+
+ if (src->h_name != NULL) {
+ dest->h_name = strdup(src->h_name);
+ ATF_REQUIRE(dest->h_name != NULL);
+ }
+
+ dest->h_addrtype = src->h_addrtype;
+ dest->h_length = src->h_length;
+
+ if (src->h_aliases != NULL) {
+ aliases_num = 0;
+ for (cp = src->h_aliases; *cp; ++cp)
+ ++aliases_num;
+
+ dest->h_aliases = calloc(1, (aliases_num + 1) *
+ sizeof(char *));
+ ATF_REQUIRE(dest->h_aliases != NULL);
+
+ for (cp = src->h_aliases; *cp; ++cp) {
+ dest->h_aliases[cp - src->h_aliases] = strdup(*cp);
+ ATF_REQUIRE(dest->h_aliases[cp - src->h_aliases] != NULL);
+ }
+ }
+
+ if (src->h_addr_list != NULL) {
+ addrs_num = 0;
+ for (cp = src->h_addr_list; *cp; ++cp)
+ ++addrs_num;
+
+ dest->h_addr_list = calloc(1, (addrs_num + 1) * sizeof(char *));
+ ATF_REQUIRE(dest->h_addr_list != NULL);
+
+ for (cp = src->h_addr_list; *cp; ++cp) {
+ offset = cp - src->h_addr_list;
+ dest->h_addr_list[offset] = malloc(src->h_length);
+ ATF_REQUIRE(dest->h_addr_list[offset] != NULL);
+ memcpy(dest->h_addr_list[offset],
+ src->h_addr_list[offset], src->h_length);
+ }
+ }
+}
+
+static void
+free_hostent(struct hostent *ht)
+{
+ char **cp;
+
+ ATF_REQUIRE(ht != NULL);
+
+ free(ht->h_name);
+
+ if (ht->h_aliases != NULL) {
+ for (cp = ht->h_aliases; *cp; ++cp)
+ free(*cp);
+ free(ht->h_aliases);
+ }
+
+ if (ht->h_addr_list != NULL) {
+ for (cp = ht->h_addr_list; *cp; ++cp)
+ free(*cp);
+ free(ht->h_addr_list);
+ }
+}
+
+static int
+compare_hostent(struct hostent *ht1, struct hostent *ht2, void *mdata)
+{
+ char **c1, **c2, **ct, **cb;
+ int b;
+
+ if (ht1 == ht2)
+ return 0;
+
+ if (ht1 == NULL || ht2 == NULL)
+ goto errfin;
+
+ if (ht1->h_name == NULL || ht2->h_name == NULL)
+ goto errfin;
+
+ if (ht1->h_addrtype != ht2->h_addrtype ||
+ ht1->h_length != ht2->h_length ||
+ strcmp(ht1->h_name, ht2->h_name) != 0)
+ goto errfin;
+
+ c1 = ht1->h_aliases;
+ c2 = ht2->h_aliases;
+
+ if ((ht1->h_aliases == NULL || ht2->h_aliases == NULL) &&
+ ht1->h_aliases != ht2->h_aliases)
+ goto errfin;
+
+ if (c1 != NULL && c2 != NULL) {
+ cb = c1;
+ for (;*c1; ++c1) {
+ b = 0;
+ for (ct = c2; *ct; ++ct) {
+ if (strcmp(*c1, *ct) == 0) {
+ b = 1;
+ break;
+ }
+ }
+ if (b == 0) {
+ printf("h1 aliases item can't be found in h2 "
+ "aliases\n");
+ goto errfin;
+ }
+ }
+
+ c1 = cb;
+ for (;*c2; ++c2) {
+ b = 0;
+ for (ct = c1; *ct; ++ct) {
+ if (strcmp(*c2, *ct) == 0) {
+ b = 1;
+ break;
+ }
+ }
+ if (b == 0) {
+ printf("h2 aliases item can't be found in h1 "
+ "aliases\n");
+ goto errfin;
+ }
+ }
+ }
+
+ c1 = ht1->h_addr_list;
+ c2 = ht2->h_addr_list;
+
+ if ((ht1->h_addr_list == NULL || ht2->h_addr_list== NULL) &&
+ ht1->h_addr_list != ht2->h_addr_list)
+ goto errfin;
+
+ if (c1 != NULL && c2 != NULL) {
+ cb = c1;
+ for (; *c1; ++c1) {
+ b = 0;
+ for (ct = c2; *ct; ++ct) {
+ if (memcmp(*c1, *ct, ht1->h_length) == 0) {
+ b = 1;
+ break;
+ }
+ }
+ if (b == 0) {
+ printf("h1 addresses item can't be found in "
+ "h2 addresses\n");
+ goto errfin;
+ }
+ }
+
+ c1 = cb;
+ for (; *c2; ++c2) {
+ b = 0;
+ for (ct = c1; *ct; ++ct) {
+ if (memcmp(*c2, *ct, ht1->h_length) == 0) {
+ b = 1;
+ break;
+ }
+ }
+ if (b == 0) {
+ printf("h2 addresses item can't be found in "
+ "h1 addresses\n");
+ goto errfin;
+ }
+ }
+ }
+
+ return 0;
+
+errfin:
+ if (mdata == NULL) {
+ printf("following structures are not equal:\n");
+ dump_hostent(ht1);
+ dump_hostent(ht2);
+ }
+
+ return (-1);
+}
+
+static int
+check_addrinfo_for_name(struct addrinfo *ai, char const *name)
+{
+ struct addrinfo *ai2;
+
+ for (ai2 = ai; ai2 != NULL; ai2 = ai2->ai_next) {
+ if (strcmp(ai2->ai_canonname, name) == 0)
+ return (0);
+ }
+
+ return (-1);
+}
+
+static int
+check_addrinfo_for_addr(struct addrinfo *ai, char const *addr,
+ socklen_t addrlen, int af)
+{
+ struct addrinfo *ai2;
+
+ for (ai2 = ai; ai2 != NULL; ai2 = ai2->ai_next) {
+ if (af != ai2->ai_family)
+ continue;
+
+ switch (af) {
+ case AF_INET:
+ if (memcmp(addr,
+ (void *)&((struct sockaddr_in *)ai2->ai_addr)->sin_addr,
+ MIN(addrlen, ai2->ai_addrlen)) == 0)
+ return (0);
+ break;
+ case AF_INET6:
+ if (memcmp(addr,
+ (void *)&((struct sockaddr_in6 *)ai2->ai_addr)->sin6_addr,
+ MIN(addrlen, ai2->ai_addrlen)) == 0)
+ return (0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return (-1);
+}
+
+static int
+is_hostent_equal(struct hostent *he, struct addrinfo *ai)
+{
+ char **cp;
+ int rv;
+
+#ifdef DEBUG
+ printf("checking equality of he and ai\n");
+#endif
+
+ rv = check_addrinfo_for_name(ai, he->h_name);
+ if (rv != 0) {
+ printf("not equal - he->h_name couldn't be found\n");
+ return (rv);
+ }
+
+ for (cp = he->h_addr_list; *cp; ++cp) {
+ rv = check_addrinfo_for_addr(ai, *cp, he->h_length,
+ he->h_addrtype);
+ if (rv != 0) {
+ printf("not equal - one of he->h_addr_list couldn't be found\n");
+ return (rv);
+ }
+ }
+
+#ifdef DEBUG
+ printf("equal\n");
+#endif
+
+ return (0);
+}
+
+static void
+sdump_hostent(struct hostent *ht, char *buffer, size_t buflen)
+{
+ char **cp;
+ size_t i;
+ int written;
+
+ written = snprintf(buffer, buflen, "%s %d %d",
+ ht->h_name, ht->h_addrtype, ht->h_length);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (ht->h_aliases != NULL) {
+ if (*(ht->h_aliases) != NULL) {
+ for (cp = ht->h_aliases; *cp; ++cp) {
+ written = snprintf(buffer, buflen, " %s",*cp);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ } else {
+ written = snprintf(buffer, buflen, " noaliases");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ }
+ } else {
+ written = snprintf(buffer, buflen, " (null)");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ }
+
+ written = snprintf(buffer, buflen, " : ");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (ht->h_addr_list != NULL) {
+ if (*(ht->h_addr_list) != NULL) {
+ for (cp = ht->h_addr_list; *cp; ++cp) {
+ for (i = 0; i < ht->h_length; ++i ) {
+ written = snprintf(buffer, buflen,
+ i + 1 != ht->h_length ? "%d." : "%d",
+ (unsigned char)(*cp)[i]);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+
+ if (*(cp + 1) ) {
+ written = snprintf(buffer, buflen, " ");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ }
+ }
+ } else {
+ written = snprintf(buffer, buflen, " noaddrs");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ }
+ } else {
+ written = snprintf(buffer, buflen, " (null)");
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+ }
+}
+
+static int
+hostent_read_hostlist_func(struct hostent *he, char *line)
+{
+ struct hostent *result;
+ int rv;
+
+#ifdef DEBUG
+ printf("resolving %s: ", line);
+#endif
+ result = __gethostbyname2(line, af_type);
+ if (result != NULL) {
+#ifdef DEBUG
+ printf("found\n");
+#endif
+
+ rv = hostent_test_correctness(result, NULL);
+ if (rv != 0) {
+ __freehostent(result);
+ return (rv);
+ }
+
+ clone_hostent(he, result);
+ __freehostent(result);
+ } else {
+#ifdef DEBUG
+ printf("not found\n");
+#endif
+ memset(he, 0, sizeof(struct hostent));
+ he->h_name = strdup(line);
+ ATF_REQUIRE(he->h_name != NULL);
+ }
+ return (0);
+}
+
+static int
+hostent_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
+{
+ char *s, *ps, *ts;
+
+ ps = addr;
+ while ( (s = strsep(&ps, ".")) != NULL) {
+ if (len == 0)
+ return (-1);
+
+ *result = (unsigned char)strtol(s, &ts, 10);
+ ++result;
+ if (*ts != '\0')
+ return (-1);
+
+ --len;
+ }
+ if (len != 0)
+ return (-1);
+ else
+ return (0);
+}
+
+static int
+hostent_read_snapshot_func(struct hostent *ht, char *line)
+{
+ StringList *sl1, *sl2;
+ char *s, *ps, *ts;
+ int i, rv;
+
+#ifdef DEBUG
+ printf("1 line read from snapshot:\n%s\n", line);
+#endif
+
+ rv = 0;
+ i = 0;
+ sl1 = sl2 = NULL;
+ ps = line;
+ memset(ht, 0, sizeof(struct hostent));
+ while ((s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ ht->h_name = strdup(s);
+ ATF_REQUIRE(ht->h_name != NULL);
+ break;
+
+ case 1:
+ ht->h_addrtype = (int)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+
+ case 2:
+ ht->h_length = (int)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+
+ case 3:
+ if (sl1 == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl1 = sl_init();
+ ATF_REQUIRE(sl1 != NULL);
+
+ if (strcmp(s, "noaliases") != 0) {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl1, ts);
+ }
+ } else {
+ if (strcmp(s, ":") == 0)
+ ++i;
+ else {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl1, ts);
+ }
+ }
+ break;
+
+ case 4:
+ if (sl2 == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl2 = sl_init();
+ ATF_REQUIRE(sl2 != NULL);
+
+ if (strcmp(s, "noaddrs") != 0) {
+ ts = calloc(1, ht->h_length);
+ ATF_REQUIRE(ts != NULL);
+ rv = hostent_read_snapshot_addr(s,
+ (unsigned char *)ts,
+ ht->h_length);
+ sl_add(sl2, ts);
+ if (rv != 0)
+ goto fin;
+ }
+ } else {
+ ts = calloc(1, ht->h_length);
+ ATF_REQUIRE(ts != NULL);
+ rv = hostent_read_snapshot_addr(s,
+ (unsigned char *)ts, ht->h_length);
+ sl_add(sl2, ts);
+ if (rv != 0)
+ goto fin;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (i != 3 && i != 4)
+ ++i;
+ }
+
+fin:
+ if (sl1 != NULL) {
+ sl_add(sl1, NULL);
+ ht->h_aliases = sl1->sl_str;
+ }
+ if (sl2 != NULL) {
+ sl_add(sl2, NULL);
+ ht->h_addr_list = sl2->sl_str;
+ }
+
+ if ((i != 4) || (rv != 0)) {
+ free_hostent(ht);
+ memset(ht, 0, sizeof(struct hostent));
+ return (-1);
+ }
+
+ /* NOTE: is it a dirty hack or not? */
+ free(sl1);
+ free(sl2);
+ return (0);
+}
+
+static void
+dump_hostent(struct hostent *result)
+{
+ if (result != NULL) {
+ char buffer[1024];
+ sdump_hostent(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+hostent_test_correctness(struct hostent *ht, void *mdata)
+{
+
+#ifdef DEBUG
+ printf("testing correctness with the following data:\n");
+ dump_hostent(ht);
+#endif
+
+ if (ht == NULL)
+ goto errfin;
+
+ if (ht->h_name == NULL)
+ goto errfin;
+
+ if (!((ht->h_addrtype >= 0) && (ht->h_addrtype < AF_MAX)))
+ goto errfin;
+
+ if ((ht->h_length != sizeof(struct in_addr)) &&
+ (ht->h_length != sizeof(struct in6_addr)))
+ goto errfin;
+
+ if (ht->h_aliases == NULL)
+ goto errfin;
+
+ if (ht->h_addr_list == NULL)
+ goto errfin;
+
+#ifdef DEBUG
+ printf("correct\n");
+#endif
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+static int
+hostent_test_gethostbyaddr(struct hostent *he, void *mdata)
+{
+ struct hostent *result;
+ struct hostent_test_data *addr_test_data;
+ int rv;
+
+ addr_test_data = (struct hostent_test_data *)mdata;
+
+ /* We should omit unresolved hostents */
+ if (he->h_addr_list != NULL) {
+ char **cp;
+ for (cp = he->h_addr_list; *cp; ++cp) {
+#ifdef DEBUG
+ printf("doing reverse lookup for %s\n", he->h_name);
+#endif
+
+ result = __gethostbyaddr(*cp, he->h_length,
+ he->h_addrtype);
+ if (result == NULL) {
+#ifdef DEBUG
+ printf("%s: warning: reverse lookup failed "
+ "for %s: %s\n", __func__, he->h_name,
+ strerror(errno));
+#endif
+ continue;
+ }
+ rv = hostent_test_correctness(result, NULL);
+ if (rv != 0) {
+ __freehostent(result);
+ return (rv);
+ }
+
+ if (addr_test_data != NULL)
+ TEST_DATA_APPEND(hostent, addr_test_data,
+ result);
+
+ __freehostent(result);
+ }
+ }
+
+ return (0);
+}
+
+static int
+hostent_test_getaddrinfo_eq(struct hostent *he, void *mdata)
+{
+ struct addrinfo *ai, hints;
+ int rv;
+
+ ai = NULL;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = af_type;
+ hints.ai_flags = AI_CANONNAME;
+
+ printf("using getaddrinfo() to resolve %s\n", he->h_name);
+
+ /* struct hostent *he was not resolved */
+ if (he->h_addr_list == NULL) {
+ /* We can be sure that he->h_name is not NULL */
+ rv = getaddrinfo(he->h_name, NULL, &hints, &ai);
+ if (rv == 0) {
+ printf("not ok - shouldn't have been resolved\n");
+ return (-1);
+ }
+ } else {
+ rv = getaddrinfo(he->h_name, NULL, &hints, &ai);
+ if (rv != 0) {
+ printf("not ok - should have been resolved\n");
+ return (-1);
+ }
+
+ rv = is_hostent_equal(he, ai);
+ if (rv != 0) {
+ printf("not ok - addrinfo and hostent are not equal\n");
+ return (-1);
+ }
+
+ }
+
+ return (0);
+}
+
+static int
+hostent_test_getnameinfo_eq(struct hostent *he, void *mdata)
+{
+ char **cp;
+ char buffer[NI_MAXHOST];
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ struct sockaddr *saddr;
+ struct hostent *result;
+ int i, rv;
+
+ if (he->h_addr_list == NULL)
+ return (0);
+
+ for (cp = he->h_addr_list; *cp; ++cp) {
+#ifdef DEBUG
+ printf("doing reverse lookup for %s\n", he->h_name);
+#endif
+ result = __gethostbyaddr(*cp, he->h_length,
+ he->h_addrtype);
+ if (result != NULL) {
+ rv = hostent_test_correctness(result, NULL);
+ if (rv != 0) {
+ __freehostent(result);
+ return (rv);
+ }
+ } else
+ printf("%s: warning: reverse lookup failed "
+ "for %s: %s\n", __func__, he->h_name,
+ strerror(errno));
+
+ switch (he->h_addrtype) {
+ case AF_INET:
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_len = sizeof(struct sockaddr_in);
+ sin.sin_family = AF_INET;
+ memcpy(&sin.sin_addr, *cp, he->h_length);
+
+ saddr = (struct sockaddr *)&sin;
+ break;
+ case AF_INET6:
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+ memcpy(&sin6.sin6_addr, *cp, he->h_length);
+
+ saddr = (struct sockaddr *)&sin6;
+ break;
+ default:
+ printf("warning: %d family is unsupported\n",
+ he->h_addrtype);
+ continue;
+ }
+
+ ATF_REQUIRE(saddr != NULL);
+ rv = getnameinfo(saddr, saddr->sa_len, buffer,
+ sizeof(buffer), NULL, 0, NI_NAMEREQD);
+
+ if (rv != 0 && result != NULL) {
+ printf("getnameinfo() didn't make the reverse "
+ "lookup, when it should have (%s)\n",
+ gai_strerror(rv));
+ return (rv);
+ }
+
+ if (rv == 0 && result == NULL) {
+ printf("getnameinfo() made the "
+ "reverse lookup, when it shouldn't have\n");
+ return (rv);
+ }
+
+ if (rv != 0 && result == NULL) {
+#ifdef DEBUG
+ printf("both getnameinfo() and ***byaddr() failed as "
+ "expected\n");
+#endif
+ continue;
+ }
+
+#ifdef DEBUG
+ printf("comparing %s with %s\n", result->h_name,
+ buffer);
+#endif
+
+ /*
+ * An address might reverse resolve to hostname alias or the
+ * official hostname, e.g. moon.vub.ac.be.
+ */
+ bool found_a_match;
+
+ if (strcmp(result->h_name, buffer) == 0) {
+ found_a_match = true;
+#ifdef DEBUG
+ printf("matched official hostname\n");
+#endif
+ } else {
+ for (i = 0; i < nitems(result->h_aliases); i++) {
+ printf("[%d] resolved: %s\n", i,
+ result->h_aliases[i]);
+ if (strcmp(result->h_aliases[i],
+ buffer) == 0) {
+ printf("matched hostname alias\n");
+ found_a_match = true;
+ break;
+ }
+ }
+ }
+ __freehostent(result);
+
+ if (found_a_match) {
+#ifdef DEBUG
+ printf("getnameinfo() and ***byaddr() results are "
+ "equal\n");
+#endif
+ } else {
+ printf("getnameinfo() and ***byaddr() results are not "
+ "equal for %s\n", he->h_name);
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+int
+run_tests(const char *hostlist_file, const char *snapshot_file, int af_type,
+ enum test_methods method, bool use_ipv6_mapping)
+{
+ struct hostent_test_data td, td_addr, td_snap;
+ res_state statp;
+ int rv = -2;
+
+ switch (af_type) {
+ case AF_INET:
+ ATF_REQUIRE_FEATURE("inet");
+ ATF_REQUIRE(!use_ipv6_mapping);
+ break;
+ case AF_INET6:
+ ATF_REQUIRE_FEATURE("inet6");
+ break;
+ default:
+ atf_tc_fail("unhandled address family: %d", af_type);
+ break;
+ }
+
+ if (!use_ipnode_functions) {
+ statp = __res_state();
+ if (statp == NULL || ((statp->options & RES_INIT) == 0 &&
+ res_ninit(statp) == -1)) {
+ printf("error: can't init res_state\n");
+
+ return (-1);
+ }
+
+ if (use_ipv6_mapping)
+ statp->options |= RES_USE_INET6;
+ else
+ statp->options &= ~RES_USE_INET6;
+ }
+
+ TEST_DATA_INIT(hostent, &td, clone_hostent, free_hostent);
+ TEST_DATA_INIT(hostent, &td_addr, clone_hostent, free_hostent);
+ TEST_DATA_INIT(hostent, &td_snap, clone_hostent, free_hostent);
+
+ if (access(hostlist_file, R_OK) != 0) {
+ printf("can't access the hostlist file %s\n", hostlist_file);
+ rv = -1;
+ goto fin;
+ }
+
+#ifdef DEBUG
+ printf("building host lists from %s\n", hostlist_file);
+#endif
+
+ rv = TEST_SNAPSHOT_FILE_READ(hostent, hostlist_file, &td,
+ hostent_read_hostlist_func);
+ if (rv != 0) {
+ printf("failed to read the host list file: %s\n",
+ hostlist_file);
+ goto fin;
+ }
+
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT) {
+ if (method != TEST_GETHOSTBYADDR)
+ method = TEST_BUILD_SNAPSHOT;
+ else
+ method = TEST_BUILD_ADDR_SNAPSHOT;
+ } else {
+ printf("can't access the snapshot file %s\n",
+ snapshot_file);
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ rv = TEST_SNAPSHOT_FILE_READ(hostent, snapshot_file,
+ &td_snap, hostent_read_snapshot_func);
+ if (rv != 0) {
+ printf("error reading snapshot file\n");
+ goto fin;
+ }
+ }
+ }
+
+ switch (method) {
+ case TEST_GETHOSTBYNAME2:
+ if (snapshot_file != NULL)
+ rv = DO_2PASS_TEST(hostent, &td, &td_snap,
+ compare_hostent, NULL);
+ break;
+ case TEST_GETHOSTBYADDR:
+ rv = DO_1PASS_TEST(hostent, &td,
+ hostent_test_gethostbyaddr, (void *)&td_addr);
+ if (rv != 0)
+ goto fin;
+
+ if (snapshot_file != NULL)
+ rv = DO_2PASS_TEST(hostent, &td_addr, &td_snap,
+ compare_hostent, NULL);
+ break;
+ case TEST_GETHOSTBYNAME2_GETADDRINFO:
+ rv = DO_1PASS_TEST(hostent, &td,
+ hostent_test_getaddrinfo_eq, NULL);
+ break;
+ case TEST_GETHOSTBYADDR_GETNAMEINFO:
+ rv = DO_1PASS_TEST(hostent, &td,
+ hostent_test_getnameinfo_eq, NULL);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL) {
+ rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file,
+ &td, sdump_hostent);
+ }
+ break;
+ case TEST_BUILD_ADDR_SNAPSHOT:
+ if (snapshot_file != NULL) {
+ rv = DO_1PASS_TEST(hostent, &td,
+ hostent_test_gethostbyaddr, (void *)&td_addr);
+ if (rv != 0)
+ goto fin;
+ rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file,
+ &td_addr, sdump_hostent);
+ }
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(hostent, &td_snap);
+ TEST_DATA_DESTROY(hostent, &td_addr);
+ TEST_DATA_DESTROY(hostent, &td);
+
+ return (rv);
+}
+
+#define HOSTLIST_FILE "mach"
+
+#define _RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \
+do { \
+ char *_hostlist_file; \
+ char *_snapshot_file; \
+ ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \
+ atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \
+ if (snapshot_file == NULL) \
+ _snapshot_file = NULL; \
+ else { \
+ _snapshot_file = strdup(snapshot_file); \
+ ATF_REQUIRE(_snapshot_file != NULL); \
+ } \
+ ATF_REQUIRE(run_tests(_hostlist_file, _snapshot_file, af_type, \
+ method, use_ipv6_mapping) == 0); \
+} while(0)
+
+#define RUN_HOST_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \
+do { \
+ use_ipnode_functions = false; \
+ _RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping); \
+} while(0)
+
+#define RUN_IPNODE_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \
+do { \
+ use_ipnode_functions = true; \
+ _RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping); \
+} while(0)
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv4);
+ATF_TC_BODY(gethostbyaddr_ipv4, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv4_with_snapshot);
+ATF_TC_BODY(gethostbyaddr_ipv4_with_snapshot, tc)
+{
+
+ RUN_HOST_TESTS(tc, "snapshot_htaddr4", AF_INET, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6);
+ATF_TC_BODY(gethostbyaddr_ipv6, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_AI_V4MAPPED);
+ATF_TC_BODY(gethostbyaddr_ipv6_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_with_snapshot);
+ATF_TC_BODY(gethostbyaddr_ipv6_with_snapshot, tc)
+{
+
+ RUN_HOST_TESTS(tc, "snapshot_htaddr6", AF_INET6, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED);
+ATF_TC_BODY(gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_HOST_TESTS(tc, "snapshot_htaddr6map", AF_INET6, TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_getaddrinfo_ipv4);
+ATF_TC_BODY(gethostbyname2_getaddrinfo_ipv4, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_getaddrinfo_ipv6);
+ATF_TC_BODY(gethostbyname2_getaddrinfo_ipv6, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_getnameinfo_ipv4);
+ATF_TC_BODY(gethostbyaddr_getnameinfo_ipv4, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyaddr_getnameinfo_ipv6);
+ATF_TC_BODY(gethostbyaddr_getnameinfo_ipv6, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv4);
+ATF_TC_BODY(gethostbyname2_ipv4, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv4_with_snapshot);
+ATF_TC_BODY(gethostbyname2_ipv4_with_snapshot, tc)
+{
+
+ RUN_HOST_TESTS(tc, "snapshot_htname4", AF_INET, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6);
+ATF_TC_BODY(gethostbyname2_ipv6, tc)
+{
+
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_AI_V4MAPPED);
+ATF_TC_BODY(gethostbyname2_ipv6_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_with_snapshot);
+ATF_TC_BODY(gethostbyname2_ipv6_with_snapshot, tc)
+{
+
+ RUN_HOST_TESTS(tc, "snapshot_htname6", AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED);
+ATF_TC_BODY(gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_HOST_TESTS(tc, "snapshot_htname6map", AF_INET6, TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv4);
+ATF_TC_BODY(getipnodebyaddr_ipv4, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv4_with_snapshot);
+ATF_TC_BODY(getipnodebyaddr_ipv4_with_snapshot, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodeaddr4", AF_INET, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_getnameinfo_ipv4);
+ATF_TC_BODY(getipnodebyaddr_getnameinfo_ipv4, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6);
+ATF_TC_BODY(getipnodebyaddr_ipv6, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED);
+ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG);
+ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL);
+ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot);
+ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodeaddr6", AF_INET6, TEST_GETHOSTBYADDR, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED);
+ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodeaddr6_AI_V4MAPPED", AF_INET6,
+ TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG);
+ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodeaddr6_AI_V4MAPPED_CFG", AF_INET6,
+ TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
+ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodeaddr6_AI_V4MAPPED_CFG_AI_ALL", AF_INET6,
+ TEST_GETHOSTBYADDR, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyaddr_getnameinfo_ipv6);
+ATF_TC_BODY(getipnodebyaddr_getnameinfo_ipv6, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4);
+ATF_TC_BODY(getipnodebyname_ipv4, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_with_snapshot);
+ATF_TC_BODY(getipnodebyname_ipv4_with_snapshot, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodename4", AF_INET, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv4_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodename4_AI_ADDRCONFIG", AF_INET,
+ TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_getaddrinfo_ipv4);
+ATF_TC_BODY(getipnodebyname_getaddrinfo_ipv4, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6);
+ATF_TC_BODY(getipnodebyname_ipv6, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodename6", AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv6_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED);
+ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG);
+ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL);
+ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodename6_AI_V4MAPPED", AF_INET6,
+ TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodename6_AI_V4MAPPED_CFG", AF_INET6,
+ TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodename6_AI_V4MAPPED_CFG_AI_ADDRCONFIG", AF_INET6,
+ TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL, tc)
+{
+
+ ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
+ RUN_IPNODE_TESTS(tc,
+ "snapshot_ipnodename6_AI_V4MAPPED_CFG_AI_ALL", AF_INET6,
+ TEST_GETHOSTBYNAME2, true);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG);
+ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG, tc)
+{
+
+ ipnode_flags = AI_ADDRCONFIG;
+ RUN_IPNODE_TESTS(tc, "snapshot_ipnodename6_AI_ADDRCONFIG", AF_INET6,
+ TEST_GETHOSTBYNAME2, false);
+}
+
+ATF_TC_WITHOUT_HEAD(getipnodebyname_getaddrinfo_ipv6);
+ATF_TC_BODY(getipnodebyname_getaddrinfo_ipv6, tc)
+{
+
+ RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ /* gethostbyaddr */
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv4);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv4_with_snapshot);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_AI_V4MAPPED); /* XXX */
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_with_snapshot);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_getnameinfo_ipv4);
+ ATF_TP_ADD_TC(tp, gethostbyaddr_getnameinfo_ipv6);
+
+ /* gethostbyname2 */
+ ATF_TP_ADD_TC(tp, gethostbyname2_getaddrinfo_ipv4);
+ ATF_TP_ADD_TC(tp, gethostbyname2_getaddrinfo_ipv6);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv4);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv4_with_snapshot);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv6);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_with_snapshot);
+ ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED);
+
+ /* getipnodebyaddr */
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv4);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv4_with_snapshot);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_getnameinfo_ipv4);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED_CFG);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
+ ATF_TP_ADD_TC(tp, getipnodebyaddr_getnameinfo_ipv6);
+
+ /* getipnodebyname */
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv4);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_with_snapshot);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_getaddrinfo_ipv4);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
+ ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG);
+ ATF_TP_ADD_TC(tp, getipnodebyname_getaddrinfo_ipv6);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getproto_test.c b/lib/libc/tests/nss/getproto_test.c
new file mode 100644
index 0000000..fdb6804
--- /dev/null
+++ b/lib/libc/tests/nss/getproto_test.c
@@ -0,0 +1,556 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETPROTOENT,
+ TEST_GETPROTOBYNAME,
+ TEST_GETPROTOBYNUMBER,
+ TEST_GETPROTOENT_2PASS,
+ TEST_BUILD_SNAPSHOT
+};
+
+DECLARE_TEST_DATA(protoent)
+DECLARE_TEST_FILE_SNAPSHOT(protoent)
+DECLARE_1PASS_TEST(protoent)
+DECLARE_2PASS_TEST(protoent)
+
+static void clone_protoent(struct protoent *, struct protoent const *);
+static int compare_protoent(struct protoent *, struct protoent *, void *);
+static void dump_protoent(struct protoent *);
+static void free_protoent(struct protoent *);
+
+static void sdump_protoent(struct protoent *, char *, size_t);
+static int protoent_read_snapshot_func(struct protoent *, char *);
+
+static int protoent_check_ambiguity(struct protoent_test_data *,
+ struct protoent *);
+static int protoent_fill_test_data(struct protoent_test_data *);
+static int protoent_test_correctness(struct protoent *, void *);
+static int protoent_test_getprotobyname(struct protoent *, void *);
+static int protoent_test_getprotobynumber(struct protoent *, void *);
+static int protoent_test_getprotoent(struct protoent *, void *);
+
+IMPLEMENT_TEST_DATA(protoent)
+IMPLEMENT_TEST_FILE_SNAPSHOT(protoent)
+IMPLEMENT_1PASS_TEST(protoent)
+IMPLEMENT_2PASS_TEST(protoent)
+
+static void
+clone_protoent(struct protoent *dest, struct protoent const *src)
+{
+ assert(dest != NULL);
+ assert(src != NULL);
+
+ char **cp;
+ int aliases_num;
+
+ memset(dest, 0, sizeof(struct protoent));
+
+ if (src->p_name != NULL) {
+ dest->p_name = strdup(src->p_name);
+ assert(dest->p_name != NULL);
+ }
+
+ dest->p_proto = src->p_proto;
+
+ if (src->p_aliases != NULL) {
+ aliases_num = 0;
+ for (cp = src->p_aliases; *cp; ++cp)
+ ++aliases_num;
+
+ dest->p_aliases = calloc(1, (aliases_num+1) * sizeof(char *));
+ assert(dest->p_aliases != NULL);
+
+ for (cp = src->p_aliases; *cp; ++cp) {
+ dest->p_aliases[cp - src->p_aliases] = strdup(*cp);
+ assert(dest->p_aliases[cp - src->p_aliases] != NULL);
+ }
+ }
+}
+
+static void
+free_protoent(struct protoent *pe)
+{
+ char **cp;
+
+ assert(pe != NULL);
+
+ free(pe->p_name);
+
+ for (cp = pe->p_aliases; *cp; ++cp)
+ free(*cp);
+ free(pe->p_aliases);
+}
+
+static int
+compare_protoent(struct protoent *pe1, struct protoent *pe2, void *mdata)
+{
+ char **c1, **c2;
+
+ if (pe1 == pe2)
+ return 0;
+
+ if ((pe1 == NULL) || (pe2 == NULL))
+ goto errfin;
+
+ if ((strcmp(pe1->p_name, pe2->p_name) != 0) ||
+ (pe1->p_proto != pe2->p_proto))
+ goto errfin;
+
+ c1 = pe1->p_aliases;
+ c2 = pe2->p_aliases;
+
+ if ((pe1->p_aliases == NULL) || (pe2->p_aliases == NULL))
+ goto errfin;
+
+ for (;*c1 && *c2; ++c1, ++c2)
+ if (strcmp(*c1, *c2) != 0)
+ goto errfin;
+
+ if ((*c1 != '\0') || (*c2 != '\0'))
+ goto errfin;
+
+ return 0;
+
+errfin:
+ if (mdata == NULL) {
+ printf("following structures are not equal:\n");
+ dump_protoent(pe1);
+ dump_protoent(pe2);
+ }
+
+ return (-1);
+}
+
+static void
+sdump_protoent(struct protoent *pe, char *buffer, size_t buflen)
+{
+ char **cp;
+ int written;
+
+ written = snprintf(buffer, buflen, "%s %d",
+ pe->p_name, pe->p_proto);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (pe->p_aliases != NULL) {
+ if (*(pe->p_aliases) != '\0') {
+ for (cp = pe->p_aliases; *cp; ++cp) {
+ written = snprintf(buffer, buflen, " %s",*cp);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ } else
+ snprintf(buffer, buflen, " noaliases");
+ } else
+ snprintf(buffer, buflen, " (null)");
+}
+
+static int
+protoent_read_snapshot_func(struct protoent *pe, char *line)
+{
+ StringList *sl;
+ char *s, *ps, *ts;
+ int i;
+
+ printf("1 line read from snapshot:\n%s\n", line);
+
+ i = 0;
+ sl = NULL;
+ ps = line;
+ memset(pe, 0, sizeof(struct protoent));
+ while ( (s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ pe->p_name = strdup(s);
+ assert(pe->p_name != NULL);
+ break;
+
+ case 1:
+ pe->p_proto = (int)strtol(s, &ts, 10);
+ if (*ts != '\0') {
+ free(pe->p_name);
+ return (-1);
+ }
+ break;
+
+ default:
+ if (sl == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl = sl_init();
+ assert(sl != NULL);
+
+ if (strcmp(s, "noaliases") != 0) {
+ ts = strdup(s);
+ assert(ts != NULL);
+ sl_add(sl, ts);
+ }
+ } else {
+ ts = strdup(s);
+ assert(ts != NULL);
+ sl_add(sl, ts);
+ }
+ break;
+ }
+ ++i;
+ }
+
+ if (i < 3) {
+ free(pe->p_name);
+ memset(pe, 0, sizeof(struct protoent));
+ return (-1);
+ }
+
+ sl_add(sl, NULL);
+ pe->p_aliases = sl->sl_str;
+
+ /* NOTE: is it a dirty hack or not? */
+ free(sl);
+ return (0);
+}
+
+static void
+dump_protoent(struct protoent *result)
+{
+ if (result != NULL) {
+ char buffer[1024];
+ sdump_protoent(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+protoent_fill_test_data(struct protoent_test_data *td)
+{
+ struct protoent *pe;
+
+ setprotoent(1);
+ while ((pe = getprotoent()) != NULL) {
+ if (protoent_test_correctness(pe, NULL) == 0)
+ TEST_DATA_APPEND(protoent, td, pe);
+ else
+ return (-1);
+ }
+ endprotoent();
+
+ return (0);
+}
+
+static int
+protoent_test_correctness(struct protoent *pe, void *mdata)
+{
+ printf("testing correctness with the following data:\n");
+ dump_protoent(pe);
+
+ if (pe == NULL)
+ goto errfin;
+
+ if (pe->p_name == NULL)
+ goto errfin;
+
+ if (pe->p_proto < 0)
+ goto errfin;
+
+ if (pe->p_aliases == NULL)
+ goto errfin;
+
+ printf("correct\n");
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+/* protoent_check_ambiguity() is needed when one port+proto is associated with
+ * more than one peice (these cases are usually marked as PROBLEM in
+ * /etc/peices. This functions is needed also when one peice+proto is
+ * associated with several ports. We have to check all the protoent structures
+ * to make sure that pe really exists and correct */
+static int
+protoent_check_ambiguity(struct protoent_test_data *td, struct protoent *pe)
+{
+
+ return (TEST_DATA_FIND(protoent, td, pe, compare_protoent,
+ NULL) != NULL ? 0 : -1);
+}
+
+static int
+protoent_test_getprotobyname(struct protoent *pe_model, void *mdata)
+{
+ char **alias;
+ struct protoent *pe;
+
+ printf("testing getprotobyname() with the following data:\n");
+ dump_protoent(pe_model);
+
+ pe = getprotobyname(pe_model->p_name);
+ if (protoent_test_correctness(pe, NULL) != 0)
+ goto errfin;
+
+ if ((compare_protoent(pe, pe_model, NULL) != 0) &&
+ (protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
+ !=0))
+ goto errfin;
+
+ for (alias = pe_model->p_aliases; *alias; ++alias) {
+ pe = getprotobyname(*alias);
+
+ if (protoent_test_correctness(pe, NULL) != 0)
+ goto errfin;
+
+ if ((compare_protoent(pe, pe_model, NULL) != 0) &&
+ (protoent_check_ambiguity(
+ (struct protoent_test_data *)mdata, pe) != 0))
+ goto errfin;
+ }
+
+ printf("ok\n");
+ return (0);
+
+errfin:
+ printf("not ok\n");
+
+ return (-1);
+}
+
+static int
+protoent_test_getprotobynumber(struct protoent *pe_model, void *mdata)
+{
+ struct protoent *pe;
+
+ printf("testing getprotobyport() with the following data...\n");
+ dump_protoent(pe_model);
+
+ pe = getprotobynumber(pe_model->p_proto);
+ if ((protoent_test_correctness(pe, NULL) != 0) ||
+ ((compare_protoent(pe, pe_model, NULL) != 0) &&
+ (protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
+ != 0))) {
+ printf("not ok\n");
+ return (-1);
+ } else {
+ printf("ok\n");
+ return (0);
+ }
+}
+
+static int
+protoent_test_getprotoent(struct protoent *pe, void *mdata)
+{
+ /* Only correctness can be checked when doing 1-pass test for
+ * getprotoent(). */
+ return (protoent_test_correctness(pe, NULL));
+}
+
+int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct protoent_test_data td, td_snap, td_2pass;
+ int rv;
+
+ TEST_DATA_INIT(protoent, &td, clone_protoent, free_protoent);
+ TEST_DATA_INIT(protoent, &td_snap, clone_protoent, free_protoent);
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the file %s\n",
+ snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ if (method == TEST_BUILD_SNAPSHOT) {
+ rv = 0;
+ goto fin;
+ }
+
+ TEST_SNAPSHOT_FILE_READ(protoent, snapshot_file,
+ &td_snap, protoent_read_snapshot_func);
+ }
+ }
+
+ rv = protoent_fill_test_data(&td);
+ if (rv == -1)
+ return (-1);
+ switch (method) {
+ case TEST_GETPROTOBYNAME:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(protoent, &td,
+ protoent_test_getprotobyname, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(protoent, &td_snap,
+ protoent_test_getprotobyname, (void *)&td_snap);
+ break;
+ case TEST_GETPROTOBYNUMBER:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(protoent, &td,
+ protoent_test_getprotobynumber, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(protoent, &td_snap,
+ protoent_test_getprotobynumber, (void *)&td_snap);
+ break;
+ case TEST_GETPROTOENT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(protoent, &td,
+ protoent_test_getprotoent, (void *)&td);
+ else
+ rv = DO_2PASS_TEST(protoent, &td, &td_snap,
+ compare_protoent, NULL);
+ break;
+ case TEST_GETPROTOENT_2PASS:
+ TEST_DATA_INIT(protoent, &td_2pass, clone_protoent,
+ free_protoent);
+ rv = protoent_fill_test_data(&td_2pass);
+ if (rv != -1)
+ rv = DO_2PASS_TEST(protoent, &td, &td_2pass,
+ compare_protoent, NULL);
+ TEST_DATA_DESTROY(protoent, &td_2pass);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL)
+ rv = TEST_SNAPSHOT_FILE_WRITE(protoent, snapshot_file,
+ &td, sdump_protoent);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(protoent, &td_snap);
+ TEST_DATA_DESTROY(protoent, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_proto"
+
+ATF_TC_WITHOUT_HEAD(build_snapshot);
+ATF_TC_BODY(build_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotoent);
+ATF_TC_BODY(getprotoent, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotoent_with_snapshot);
+ATF_TC_BODY(getprotoent_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotoent_with_two_pass);
+ATF_TC_BODY(getprotoent_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOENT_2PASS) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotobyname);
+ATF_TC_BODY(getprotobyname, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotobyname_with_snapshot);
+ATF_TC_BODY(getprotobyname_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotobynumber);
+ATF_TC_BODY(getprotobynumber, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOBYNUMBER) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getprotobynumber_with_snapshot);
+ATF_TC_BODY(getprotobynumber_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOBYNUMBER) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, build_snapshot);
+ ATF_TP_ADD_TC(tp, getprotoent);
+ ATF_TP_ADD_TC(tp, getprotoent_with_snapshot);
+ ATF_TP_ADD_TC(tp, getprotoent_with_two_pass);
+ ATF_TP_ADD_TC(tp, getprotobyname);
+ ATF_TP_ADD_TC(tp, getprotobyname_with_snapshot);
+ ATF_TP_ADD_TC(tp, getprotobynumber);
+ ATF_TP_ADD_TC(tp, getprotobynumber_with_snapshot);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getpw_test.c b/lib/libc/tests/nss/getpw_test.c
new file mode 100644
index 0000000..98f890f
--- /dev/null
+++ b/lib/libc/tests/nss/getpw_test.c
@@ -0,0 +1,530 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETPWENT,
+ TEST_GETPWNAM,
+ TEST_GETPWUID,
+ TEST_GETPWENT_2PASS,
+ TEST_BUILD_SNAPSHOT
+};
+
+static enum test_methods method = TEST_BUILD_SNAPSHOT;
+
+DECLARE_TEST_DATA(passwd)
+DECLARE_TEST_FILE_SNAPSHOT(passwd)
+DECLARE_1PASS_TEST(passwd)
+DECLARE_2PASS_TEST(passwd)
+
+static void clone_passwd(struct passwd *, struct passwd const *);
+static int compare_passwd(struct passwd *, struct passwd *, void *);
+static void free_passwd(struct passwd *);
+
+static void sdump_passwd(struct passwd *, char *, size_t);
+static void dump_passwd(struct passwd *);
+
+static int passwd_read_snapshot_func(struct passwd *, char *);
+
+static int passwd_check_ambiguity(struct passwd_test_data *, struct passwd *);
+static int passwd_fill_test_data(struct passwd_test_data *);
+static int passwd_test_correctness(struct passwd *, void *);
+static int passwd_test_getpwnam(struct passwd *, void *);
+static int passwd_test_getpwuid(struct passwd *, void *);
+static int passwd_test_getpwent(struct passwd *, void *);
+
+IMPLEMENT_TEST_DATA(passwd)
+IMPLEMENT_TEST_FILE_SNAPSHOT(passwd)
+IMPLEMENT_1PASS_TEST(passwd)
+IMPLEMENT_2PASS_TEST(passwd)
+
+static void
+clone_passwd(struct passwd *dest, struct passwd const *src)
+{
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ memcpy(dest, src, sizeof(struct passwd));
+ if (src->pw_name != NULL)
+ dest->pw_name = strdup(src->pw_name);
+ if (src->pw_passwd != NULL)
+ dest->pw_passwd = strdup(src->pw_passwd);
+ if (src->pw_class != NULL)
+ dest->pw_class = strdup(src->pw_class);
+ if (src->pw_gecos != NULL)
+ dest->pw_gecos = strdup(src->pw_gecos);
+ if (src->pw_dir != NULL)
+ dest->pw_dir = strdup(src->pw_dir);
+ if (src->pw_shell != NULL)
+ dest->pw_shell = strdup(dest->pw_shell);
+}
+
+static int
+compare_passwd(struct passwd *pwd1, struct passwd *pwd2, void *mdata)
+{
+ ATF_REQUIRE(pwd1 != NULL);
+ ATF_REQUIRE(pwd2 != NULL);
+
+ if (pwd1 == pwd2)
+ return (0);
+
+ if (pwd1->pw_uid != pwd2->pw_uid ||
+ pwd1->pw_gid != pwd2->pw_gid ||
+ pwd1->pw_change != pwd2->pw_change ||
+ pwd1->pw_expire != pwd2->pw_expire ||
+ pwd1->pw_fields != pwd2->pw_fields ||
+ strcmp(pwd1->pw_name, pwd2->pw_name) != 0 ||
+ strcmp(pwd1->pw_passwd, pwd2->pw_passwd) != 0 ||
+ strcmp(pwd1->pw_class, pwd2->pw_class) != 0 ||
+ strcmp(pwd1->pw_gecos, pwd2->pw_gecos) != 0 ||
+ strcmp(pwd1->pw_dir, pwd2->pw_dir) != 0 ||
+ strcmp(pwd1->pw_shell, pwd2->pw_shell) != 0)
+ return (-1);
+ else
+ return (0);
+}
+
+static void
+free_passwd(struct passwd *pwd)
+{
+ free(pwd->pw_name);
+ free(pwd->pw_passwd);
+ free(pwd->pw_class);
+ free(pwd->pw_gecos);
+ free(pwd->pw_dir);
+ free(pwd->pw_shell);
+}
+
+static void
+sdump_passwd(struct passwd *pwd, char *buffer, size_t buflen)
+{
+ snprintf(buffer, buflen, "%s:%s:%d:%d:%jd:%s:%s:%s:%s:%jd:%d",
+ pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid,
+ (uintmax_t)pwd->pw_change, pwd->pw_class, pwd->pw_gecos,
+ pwd->pw_dir, pwd->pw_shell, (uintmax_t)pwd->pw_expire,
+ pwd->pw_fields);
+}
+
+static void
+dump_passwd(struct passwd *pwd)
+{
+ if (pwd != NULL) {
+ char buffer[2048];
+ sdump_passwd(pwd, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+passwd_read_snapshot_func(struct passwd *pwd, char *line)
+{
+ char *s, *ps, *ts;
+ int i;
+
+#ifdef DEBUG
+ printf("1 line read from snapshot:\n%s\n", line);
+#endif
+
+ i = 0;
+ ps = line;
+ memset(pwd, 0, sizeof(struct passwd));
+ while ((s = strsep(&ps, ":")) != NULL) {
+ switch (i) {
+ case 0:
+ pwd->pw_name = strdup(s);
+ ATF_REQUIRE(pwd->pw_name != NULL);
+ break;
+ case 1:
+ pwd->pw_passwd = strdup(s);
+ ATF_REQUIRE(pwd->pw_passwd != NULL);
+ break;
+ case 2:
+ pwd->pw_uid = (uid_t)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 3:
+ pwd->pw_gid = (gid_t)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 4:
+ pwd->pw_change = (time_t)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 5:
+ pwd->pw_class = strdup(s);
+ ATF_REQUIRE(pwd->pw_class != NULL);
+ break;
+ case 6:
+ pwd->pw_gecos = strdup(s);
+ ATF_REQUIRE(pwd->pw_gecos != NULL);
+ break;
+ case 7:
+ pwd->pw_dir = strdup(s);
+ ATF_REQUIRE(pwd->pw_dir != NULL);
+ break;
+ case 8:
+ pwd->pw_shell = strdup(s);
+ ATF_REQUIRE(pwd->pw_shell != NULL);
+ break;
+ case 9:
+ pwd->pw_expire = (time_t)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ case 10:
+ pwd->pw_fields = (int)strtol(s, &ts, 10);
+ if (*ts != '\0')
+ goto fin;
+ break;
+ default:
+ break;
+ }
+ ++i;
+ }
+
+fin:
+ if (i != 11) {
+ free_passwd(pwd);
+ memset(pwd, 0, sizeof(struct passwd));
+ return (-1);
+ }
+
+ return (0);
+}
+
+static int
+passwd_fill_test_data(struct passwd_test_data *td)
+{
+ struct passwd *pwd;
+
+ setpassent(1);
+ while ((pwd = getpwent()) != NULL) {
+ if (passwd_test_correctness(pwd, NULL) == 0)
+ TEST_DATA_APPEND(passwd, td, pwd);
+ else
+ return (-1);
+ }
+ endpwent();
+
+ return (0);
+}
+
+static int
+passwd_test_correctness(struct passwd *pwd, void *mdata)
+{
+
+#ifdef DEBUG
+ printf("testing correctness with the following data:\n");
+ dump_passwd(pwd);
+#endif
+
+ if (pwd == NULL)
+ return (-1);
+
+ if (pwd->pw_name == NULL)
+ goto errfin;
+
+ if (pwd->pw_passwd == NULL)
+ goto errfin;
+
+ if (pwd->pw_class == NULL)
+ goto errfin;
+
+ if (pwd->pw_gecos == NULL)
+ goto errfin;
+
+ if (pwd->pw_dir == NULL)
+ goto errfin;
+
+ if (pwd->pw_shell == NULL)
+ goto errfin;
+
+#ifdef DEBUG
+ printf("correct\n");
+#endif
+
+ return (0);
+errfin:
+#ifdef DEBUG
+ printf("incorrect\n");
+#endif
+
+ return (-1);
+}
+
+/* passwd_check_ambiguity() is needed here because when doing the getpwent()
+ * calls sequence, records from different nsswitch sources can be different,
+ * though having the same pw_name/pw_uid */
+static int
+passwd_check_ambiguity(struct passwd_test_data *td, struct passwd *pwd)
+{
+
+ return (TEST_DATA_FIND(passwd, td, pwd, compare_passwd,
+ NULL) != NULL ? 0 : -1);
+}
+
+static int
+passwd_test_getpwnam(struct passwd *pwd_model, void *mdata)
+{
+ struct passwd *pwd;
+
+#ifdef DEBUG
+ printf("testing getpwnam() with the following data:\n");
+ dump_passwd(pwd_model);
+#endif
+
+ pwd = getpwnam(pwd_model->pw_name);
+ if (passwd_test_correctness(pwd, NULL) != 0)
+ goto errfin;
+
+ if ((compare_passwd(pwd, pwd_model, NULL) != 0) &&
+ (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd)
+ !=0))
+ goto errfin;
+
+#ifdef DEBUG
+ printf("ok\n");
+#endif
+ return (0);
+
+errfin:
+#ifdef DEBUG
+ printf("not ok\n");
+#endif
+ return (-1);
+}
+
+static int
+passwd_test_getpwuid(struct passwd *pwd_model, void *mdata)
+{
+ struct passwd *pwd;
+
+#ifdef DEBUG
+ printf("testing getpwuid() with the following data...\n");
+ dump_passwd(pwd_model);
+#endif
+
+ pwd = getpwuid(pwd_model->pw_uid);
+ if ((passwd_test_correctness(pwd, NULL) != 0) ||
+ ((compare_passwd(pwd, pwd_model, NULL) != 0) &&
+ (passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd)
+ != 0))) {
+#ifdef DEBUG
+ printf("not ok\n");
+#endif
+ return (-1);
+ } else {
+#ifdef DEBUG
+ printf("ok\n");
+#endif
+ return (0);
+ }
+}
+
+static int
+passwd_test_getpwent(struct passwd *pwd, void *mdata)
+{
+ /* Only correctness can be checked when doing 1-pass test for
+ * getpwent(). */
+ return (passwd_test_correctness(pwd, NULL));
+}
+
+static int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct passwd_test_data td, td_snap, td_2pass;
+ int rv;
+
+ TEST_DATA_INIT(passwd, &td, clone_passwd, free_passwd);
+ TEST_DATA_INIT(passwd, &td_snap, clone_passwd, free_passwd);
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the file %s\n",
+ snapshot_file);
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ if (method == TEST_BUILD_SNAPSHOT) {
+ rv = 0;
+ goto fin;
+ }
+
+ TEST_SNAPSHOT_FILE_READ(passwd, snapshot_file,
+ &td_snap, passwd_read_snapshot_func);
+ }
+ }
+
+ rv = passwd_fill_test_data(&td);
+ if (rv == -1)
+ return (-1);
+
+ switch (method) {
+ case TEST_GETPWNAM:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(passwd, &td,
+ passwd_test_getpwnam, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(passwd, &td_snap,
+ passwd_test_getpwnam, (void *)&td_snap);
+ break;
+ case TEST_GETPWUID:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(passwd, &td,
+ passwd_test_getpwuid, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(passwd, &td_snap,
+ passwd_test_getpwuid, (void *)&td_snap);
+ break;
+ case TEST_GETPWENT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(passwd, &td, passwd_test_getpwent,
+ (void *)&td);
+ else
+ rv = DO_2PASS_TEST(passwd, &td, &td_snap,
+ compare_passwd, NULL);
+ break;
+ case TEST_GETPWENT_2PASS:
+ TEST_DATA_INIT(passwd, &td_2pass, clone_passwd, free_passwd);
+ rv = passwd_fill_test_data(&td_2pass);
+ if (rv != -1)
+ rv = DO_2PASS_TEST(passwd, &td, &td_2pass,
+ compare_passwd, NULL);
+ TEST_DATA_DESTROY(passwd, &td_2pass);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL)
+ rv = TEST_SNAPSHOT_FILE_WRITE(passwd, snapshot_file,
+ &td, sdump_passwd);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(passwd, &td_snap);
+ TEST_DATA_DESTROY(passwd, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_pwd"
+
+ATF_TC_WITHOUT_HEAD(build_snapshot);
+ATF_TC_BODY(build_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwent);
+ATF_TC_BODY(getpwent, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwent_with_snapshot);
+ATF_TC_BODY(getpwent_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwent_with_two_pass);
+ATF_TC_BODY(getpwent_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT_2PASS) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwnam);
+ATF_TC_BODY(getpwnam, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWNAM) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwnam_with_snapshot);
+ATF_TC_BODY(getpwnam_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWNAM) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwuid);
+ATF_TC_BODY(getpwuid, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWUID) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getpwuid_with_snapshot);
+ATF_TC_BODY(getpwuid_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWUID) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, build_snapshot);
+ ATF_TP_ADD_TC(tp, getpwent);
+ ATF_TP_ADD_TC(tp, getpwent_with_snapshot);
+ ATF_TP_ADD_TC(tp, getpwent_with_two_pass);
+ ATF_TP_ADD_TC(tp, getpwnam);
+ ATF_TP_ADD_TC(tp, getpwnam_with_snapshot);
+ ATF_TP_ADD_TC(tp, getpwuid);
+ ATF_TP_ADD_TC(tp, getpwuid_with_snapshot);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getrpc_test.c b/lib/libc/tests/nss/getrpc_test.c
new file mode 100644
index 0000000..89de986
--- /dev/null
+++ b/lib/libc/tests/nss/getrpc_test.c
@@ -0,0 +1,560 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETRPCENT,
+ TEST_GETRPCBYNAME,
+ TEST_GETRPCBYNUMBER,
+ TEST_GETRPCENT_2PASS,
+ TEST_BUILD_SNAPSHOT
+};
+
+DECLARE_TEST_DATA(rpcent)
+DECLARE_TEST_FILE_SNAPSHOT(rpcent)
+DECLARE_1PASS_TEST(rpcent)
+DECLARE_2PASS_TEST(rpcent)
+
+static void clone_rpcent(struct rpcent *, struct rpcent const *);
+static int compare_rpcent(struct rpcent *, struct rpcent *, void *);
+static void dump_rpcent(struct rpcent *);
+static void free_rpcent(struct rpcent *);
+
+static void sdump_rpcent(struct rpcent *, char *, size_t);
+static int rpcent_read_snapshot_func(struct rpcent *, char *);
+
+static int rpcent_check_ambiguity(struct rpcent_test_data *,
+ struct rpcent *);
+static int rpcent_fill_test_data(struct rpcent_test_data *);
+static int rpcent_test_correctness(struct rpcent *, void *);
+static int rpcent_test_getrpcbyname(struct rpcent *, void *);
+static int rpcent_test_getrpcbynumber(struct rpcent *, void *);
+static int rpcent_test_getrpcent(struct rpcent *, void *);
+
+static void usage(void) __attribute__((__noreturn__));
+
+IMPLEMENT_TEST_DATA(rpcent)
+IMPLEMENT_TEST_FILE_SNAPSHOT(rpcent)
+IMPLEMENT_1PASS_TEST(rpcent)
+IMPLEMENT_2PASS_TEST(rpcent)
+
+static void
+clone_rpcent(struct rpcent *dest, struct rpcent const *src)
+{
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ char **cp;
+ int aliases_num;
+
+ memset(dest, 0, sizeof(struct rpcent));
+
+ if (src->r_name != NULL) {
+ dest->r_name = strdup(src->r_name);
+ ATF_REQUIRE(dest->r_name != NULL);
+ }
+
+ dest->r_number = src->r_number;
+
+ if (src->r_aliases != NULL) {
+ aliases_num = 0;
+ for (cp = src->r_aliases; *cp; ++cp)
+ ++aliases_num;
+
+ dest->r_aliases = calloc(1, (aliases_num + 1) * sizeof(char *));
+ ATF_REQUIRE(dest->r_aliases != NULL);
+
+ for (cp = src->r_aliases; *cp; ++cp) {
+ dest->r_aliases[cp - src->r_aliases] = strdup(*cp);
+ ATF_REQUIRE(dest->r_aliases[cp - src->r_aliases] != NULL);
+ }
+ }
+}
+
+static void
+free_rpcent(struct rpcent *rpc)
+{
+ char **cp;
+
+ ATF_REQUIRE(rpc != NULL);
+
+ free(rpc->r_name);
+
+ for (cp = rpc->r_aliases; *cp; ++cp)
+ free(*cp);
+ free(rpc->r_aliases);
+}
+
+static int
+compare_rpcent(struct rpcent *rpc1, struct rpcent *rpc2, void *mdata)
+{
+ char **c1, **c2;
+
+ if (rpc1 == rpc2)
+ return 0;
+
+ if ((rpc1 == NULL) || (rpc2 == NULL))
+ goto errfin;
+
+ if ((strcmp(rpc1->r_name, rpc2->r_name) != 0) ||
+ (rpc1->r_number != rpc2->r_number))
+ goto errfin;
+
+ c1 = rpc1->r_aliases;
+ c2 = rpc2->r_aliases;
+
+ if ((rpc1->r_aliases == NULL) || (rpc2->r_aliases == NULL))
+ goto errfin;
+
+ for (;*c1 && *c2; ++c1, ++c2)
+ if (strcmp(*c1, *c2) != 0)
+ goto errfin;
+
+ if ((*c1 != '\0') || (*c2 != '\0'))
+ goto errfin;
+
+ return 0;
+
+errfin:
+ if (mdata == NULL) {
+ printf("following structures are not equal:\n");
+ dump_rpcent(rpc1);
+ dump_rpcent(rpc2);
+ }
+
+ return (-1);
+}
+
+static void
+sdump_rpcent(struct rpcent *rpc, char *buffer, size_t buflen)
+{
+ char **cp;
+ int written;
+
+ written = snprintf(buffer, buflen, "%s %d",
+ rpc->r_name, rpc->r_number);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (rpc->r_aliases != NULL) {
+ if (*(rpc->r_aliases) != '\0') {
+ for (cp = rpc->r_aliases; *cp; ++cp) {
+ written = snprintf(buffer, buflen, " %s",*cp);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ } else
+ snprintf(buffer, buflen, " noaliases");
+ } else
+ snprintf(buffer, buflen, " (null)");
+}
+
+static int
+rpcent_read_snapshot_func(struct rpcent *rpc, char *line)
+{
+ StringList *sl;
+ char *s, *ps, *ts;
+ int i;
+
+ printf("1 line read from snapshot:\n%s\n", line);
+
+ i = 0;
+ sl = NULL;
+ ps = line;
+ memset(rpc, 0, sizeof(struct rpcent));
+ while ((s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ rpc->r_name = strdup(s);
+ ATF_REQUIRE(rpc->r_name != NULL);
+ break;
+
+ case 1:
+ rpc->r_number = (int)strtol(s, &ts, 10);
+ if (*ts != '\0') {
+ free(rpc->r_name);
+ return (-1);
+ }
+ break;
+
+ default:
+ if (sl == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl = sl_init();
+ ATF_REQUIRE(sl != NULL);
+
+ if (strcmp(s, "noaliases") != 0) {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ } else {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ break;
+ }
+ i++;
+ }
+
+ if (i < 3) {
+ free(rpc->r_name);
+ memset(rpc, 0, sizeof(struct rpcent));
+ return (-1);
+ }
+
+ sl_add(sl, NULL);
+ rpc->r_aliases = sl->sl_str;
+
+ /* NOTE: is it a dirty hack or not? */
+ free(sl);
+ return (0);
+}
+
+static void
+dump_rpcent(struct rpcent *result)
+{
+ if (result != NULL) {
+ char buffer[1024];
+ sdump_rpcent(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+rpcent_fill_test_data(struct rpcent_test_data *td)
+{
+ struct rpcent *rpc;
+
+ setrpcent(1);
+ while ((rpc = getrpcent()) != NULL) {
+ if (rpcent_test_correctness(rpc, NULL) == 0)
+ TEST_DATA_APPEND(rpcent, td, rpc);
+ else
+ return (-1);
+ }
+ endrpcent();
+
+ return (0);
+}
+
+static int
+rpcent_test_correctness(struct rpcent *rpc, void *mdata)
+{
+
+ printf("testing correctness with the following data:\n");
+ dump_rpcent(rpc);
+
+ if (rpc == NULL)
+ goto errfin;
+
+ if (rpc->r_name == NULL)
+ goto errfin;
+
+ if (rpc->r_number < 0)
+ goto errfin;
+
+ if (rpc->r_aliases == NULL)
+ goto errfin;
+
+ printf("correct\n");
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+/* rpcent_check_ambiguity() is needed when one port+rpc is associated with
+ * more than one peice (these cases are usually marked as PROBLEM in
+ * /etc/peices. This functions is needed also when one peice+rpc is
+ * associated with several ports. We have to check all the rpcent structures
+ * to make sure that rpc really exists and correct */
+static int
+rpcent_check_ambiguity(struct rpcent_test_data *td, struct rpcent *rpc)
+{
+
+ return (TEST_DATA_FIND(rpcent, td, rpc, compare_rpcent,
+ NULL) != NULL ? 0 : -1);
+}
+
+static int
+rpcent_test_getrpcbyname(struct rpcent *rpc_model, void *mdata)
+{
+ char **alias;
+ struct rpcent *rpc;
+
+ printf("testing getrpcbyname() with the following data:\n");
+ dump_rpcent(rpc_model);
+
+ rpc = getrpcbyname(rpc_model->r_name);
+ if (rpcent_test_correctness(rpc, NULL) != 0)
+ goto errfin;
+
+ if ((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
+ (rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc)
+ !=0))
+ goto errfin;
+
+ for (alias = rpc_model->r_aliases; *alias; ++alias) {
+ rpc = getrpcbyname(*alias);
+
+ if (rpcent_test_correctness(rpc, NULL) != 0)
+ goto errfin;
+
+ if ((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
+ (rpcent_check_ambiguity(
+ (struct rpcent_test_data *)mdata, rpc) != 0))
+ goto errfin;
+ }
+
+ printf("ok\n");
+ return (0);
+
+errfin:
+ printf("not ok\n");
+
+ return (-1);
+}
+
+static int
+rpcent_test_getrpcbynumber(struct rpcent *rpc_model, void *mdata)
+{
+ struct rpcent *rpc;
+
+ printf("testing getrpcbyport() with the following data...\n");
+ dump_rpcent(rpc_model);
+
+ rpc = getrpcbynumber(rpc_model->r_number);
+ if (rpcent_test_correctness(rpc, NULL) != 0 ||
+ (compare_rpcent(rpc, rpc_model, NULL) != 0 &&
+ rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc)
+ != 0)) {
+ printf("not ok\n");
+ return (-1);
+ } else {
+ printf("ok\n");
+ return (0);
+ }
+}
+
+static int
+rpcent_test_getrpcent(struct rpcent *rpc, void *mdata)
+{
+
+ /*
+ * Only correctness can be checked when doing 1-pass test for
+ * getrpcent().
+ */
+ return (rpcent_test_correctness(rpc, NULL));
+}
+
+int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct rpcent_test_data td, td_snap, td_2pass;
+ int rv;
+
+ TEST_DATA_INIT(rpcent, &td, clone_rpcent, free_rpcent);
+ TEST_DATA_INIT(rpcent, &td_snap, clone_rpcent, free_rpcent);
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the file %s\n",
+ snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ if (method == TEST_BUILD_SNAPSHOT) {
+ rv = 0;
+ goto fin;
+ }
+
+ TEST_SNAPSHOT_FILE_READ(rpcent, snapshot_file,
+ &td_snap, rpcent_read_snapshot_func);
+ }
+ }
+
+ rv = rpcent_fill_test_data(&td);
+ if (rv == -1)
+ return (-1);
+ switch (method) {
+ case TEST_GETRPCBYNAME:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(rpcent, &td,
+ rpcent_test_getrpcbyname, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(rpcent, &td_snap,
+ rpcent_test_getrpcbyname, (void *)&td_snap);
+ break;
+ case TEST_GETRPCBYNUMBER:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(rpcent, &td,
+ rpcent_test_getrpcbynumber, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(rpcent, &td_snap,
+ rpcent_test_getrpcbynumber, (void *)&td_snap);
+ break;
+ case TEST_GETRPCENT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(rpcent, &td, rpcent_test_getrpcent,
+ (void *)&td);
+ else
+ rv = DO_2PASS_TEST(rpcent, &td, &td_snap,
+ compare_rpcent, NULL);
+ break;
+ case TEST_GETRPCENT_2PASS:
+ TEST_DATA_INIT(rpcent, &td_2pass, clone_rpcent, free_rpcent);
+ rv = rpcent_fill_test_data(&td_2pass);
+ if (rv != -1)
+ rv = DO_2PASS_TEST(rpcent, &td, &td_2pass,
+ compare_rpcent, NULL);
+ TEST_DATA_DESTROY(rpcent, &td_2pass);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL)
+ rv = TEST_SNAPSHOT_FILE_WRITE(rpcent, snapshot_file, &td,
+ sdump_rpcent);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(rpcent, &td_snap);
+ TEST_DATA_DESTROY(rpcent, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_rpc"
+
+ATF_TC_WITHOUT_HEAD(build_snapshot);
+ATF_TC_BODY(build_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbyname);
+ATF_TC_BODY(getrpcbyname, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbyname_with_snapshot);
+ATF_TC_BODY(getrpcbyname_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbynumber);
+ATF_TC_BODY(getrpcbynumber, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNUMBER) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbynumber_with_snapshot);
+ATF_TC_BODY(getrpcbynumber_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCBYNUMBER) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbyent);
+ATF_TC_BODY(getrpcbyent, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbyent_with_snapshot);
+ATF_TC_BODY(getrpcbyent_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getrpcbyent_with_two_pass);
+ATF_TC_BODY(getrpcbyent_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT_2PASS) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, build_snapshot);
+ ATF_TP_ADD_TC(tp, getrpcbyname);
+ ATF_TP_ADD_TC(tp, getrpcbyname_with_snapshot);
+ ATF_TP_ADD_TC(tp, getrpcbynumber);
+ ATF_TP_ADD_TC(tp, getrpcbynumber_with_snapshot);
+ ATF_TP_ADD_TC(tp, getrpcbyent);
+ ATF_TP_ADD_TC(tp, getrpcbyent_with_snapshot);
+ ATF_TP_ADD_TC(tp, getrpcbyent_with_two_pass);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getserv_test.c b/lib/libc/tests/nss/getserv_test.c
new file mode 100644
index 0000000..29c1dfa
--- /dev/null
+++ b/lib/libc/tests/nss/getserv_test.c
@@ -0,0 +1,570 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETSERVENT,
+ TEST_GETSERVBYNAME,
+ TEST_GETSERVBYPORT,
+ TEST_GETSERVENT_2PASS,
+ TEST_BUILD_SNAPSHOT
+};
+
+DECLARE_TEST_DATA(servent)
+DECLARE_TEST_FILE_SNAPSHOT(servent)
+DECLARE_1PASS_TEST(servent)
+DECLARE_2PASS_TEST(servent)
+
+static void clone_servent(struct servent *, struct servent const *);
+static int compare_servent(struct servent *, struct servent *, void *);
+static void dump_servent(struct servent *);
+static void free_servent(struct servent *);
+
+static void sdump_servent(struct servent *, char *, size_t);
+static int servent_read_snapshot_func(struct servent *, char *);
+
+static int servent_check_ambiguity(struct servent_test_data *,
+ struct servent *);
+static int servent_fill_test_data(struct servent_test_data *);
+static int servent_test_correctness(struct servent *, void *);
+static int servent_test_getservbyname(struct servent *, void *);
+static int servent_test_getservbyport(struct servent *, void *);
+static int servent_test_getservent(struct servent *, void *);
+
+IMPLEMENT_TEST_DATA(servent)
+IMPLEMENT_TEST_FILE_SNAPSHOT(servent)
+IMPLEMENT_1PASS_TEST(servent)
+IMPLEMENT_2PASS_TEST(servent)
+
+static void
+clone_servent(struct servent *dest, struct servent const *src)
+{
+ ATF_REQUIRE(dest != NULL);
+ ATF_REQUIRE(src != NULL);
+
+ char **cp;
+ int aliases_num;
+
+ memset(dest, 0, sizeof(struct servent));
+
+ if (src->s_name != NULL) {
+ dest->s_name = strdup(src->s_name);
+ ATF_REQUIRE(dest->s_name != NULL);
+ }
+
+ if (src->s_proto != NULL) {
+ dest->s_proto = strdup(src->s_proto);
+ ATF_REQUIRE(dest->s_proto != NULL);
+ }
+ dest->s_port = src->s_port;
+
+ if (src->s_aliases != NULL) {
+ aliases_num = 0;
+ for (cp = src->s_aliases; *cp; ++cp)
+ ++aliases_num;
+
+ dest->s_aliases = calloc(1, (aliases_num + 1) * sizeof(char *));
+ ATF_REQUIRE(dest->s_aliases != NULL);
+
+ for (cp = src->s_aliases; *cp; ++cp) {
+ dest->s_aliases[cp - src->s_aliases] = strdup(*cp);
+ ATF_REQUIRE(dest->s_aliases[cp - src->s_aliases] != NULL);
+ }
+ }
+}
+
+static void
+free_servent(struct servent *serv)
+{
+ char **cp;
+
+ ATF_REQUIRE(serv != NULL);
+
+ free(serv->s_name);
+ free(serv->s_proto);
+
+ for (cp = serv->s_aliases; *cp; ++cp)
+ free(*cp);
+ free(serv->s_aliases);
+}
+
+static int
+compare_servent(struct servent *serv1, struct servent *serv2, void *mdata)
+{
+ char **c1, **c2;
+
+ if (serv1 == serv2)
+ return 0;
+
+ if ((serv1 == NULL) || (serv2 == NULL))
+ goto errfin;
+
+ if ((strcmp(serv1->s_name, serv2->s_name) != 0) ||
+ (strcmp(serv1->s_proto, serv2->s_proto) != 0) ||
+ (serv1->s_port != serv2->s_port))
+ goto errfin;
+
+ c1 = serv1->s_aliases;
+ c2 = serv2->s_aliases;
+
+ if ((serv1->s_aliases == NULL) || (serv2->s_aliases == NULL))
+ goto errfin;
+
+ for (;*c1 && *c2; ++c1, ++c2)
+ if (strcmp(*c1, *c2) != 0)
+ goto errfin;
+
+ if ((*c1 != '\0') || (*c2 != '\0'))
+ goto errfin;
+
+ return 0;
+
+errfin:
+ if (mdata == NULL) {
+ printf("following structures are not equal:\n");
+ dump_servent(serv1);
+ dump_servent(serv2);
+ }
+
+ return (-1);
+}
+
+static void
+sdump_servent(struct servent *serv, char *buffer, size_t buflen)
+{
+ char **cp;
+ int written;
+
+ written = snprintf(buffer, buflen, "%s %d %s",
+ serv->s_name, ntohs(serv->s_port), serv->s_proto);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (serv->s_aliases != NULL) {
+ if (*(serv->s_aliases) != '\0') {
+ for (cp = serv->s_aliases; *cp; ++cp) {
+ written = snprintf(buffer, buflen, " %s",*cp);
+ buffer += written;
+ if (written > buflen)
+ return;
+ buflen -= written;
+
+ if (buflen == 0)
+ return;
+ }
+ } else
+ snprintf(buffer, buflen, " noaliases");
+ } else
+ snprintf(buffer, buflen, " (null)");
+}
+
+static int
+servent_read_snapshot_func(struct servent *serv, char *line)
+{
+ StringList *sl;
+ char *s, *ps, *ts;
+ int i;
+
+ printf("1 line read from snapshot:\n%s\n", line);
+
+ i = 0;
+ sl = NULL;
+ ps = line;
+ memset(serv, 0, sizeof(struct servent));
+ while ( (s = strsep(&ps, " ")) != NULL) {
+ switch (i) {
+ case 0:
+ serv->s_name = strdup(s);
+ ATF_REQUIRE(serv->s_name != NULL);
+ break;
+
+ case 1:
+ serv->s_port = htons(
+ (int)strtol(s, &ts, 10));
+ if (*ts != '\0') {
+ free(serv->s_name);
+ return (-1);
+ }
+ break;
+
+ case 2:
+ serv->s_proto = strdup(s);
+ ATF_REQUIRE(serv->s_proto != NULL);
+ break;
+
+ default:
+ if (sl == NULL) {
+ if (strcmp(s, "(null)") == 0)
+ return (0);
+
+ sl = sl_init();
+ ATF_REQUIRE(sl != NULL);
+
+ if (strcmp(s, "noaliases") != 0) {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ } else {
+ ts = strdup(s);
+ ATF_REQUIRE(ts != NULL);
+ sl_add(sl, ts);
+ }
+ break;
+ }
+ ++i;
+ }
+
+ if (i < 3) {
+ free(serv->s_name);
+ free(serv->s_proto);
+ memset(serv, 0, sizeof(struct servent));
+ return (-1);
+ }
+
+ sl_add(sl, NULL);
+ serv->s_aliases = sl->sl_str;
+
+ /* NOTE: is it a dirty hack or not? */
+ free(sl);
+ return (0);
+}
+
+static void
+dump_servent(struct servent *result)
+{
+ if (result != NULL) {
+ char buffer[1024];
+ sdump_servent(result, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+servent_fill_test_data(struct servent_test_data *td)
+{
+ struct servent *serv;
+
+ setservent(1);
+ while ((serv = getservent()) != NULL) {
+ if (servent_test_correctness(serv, NULL) == 0)
+ TEST_DATA_APPEND(servent, td, serv);
+ else
+ return (-1);
+ }
+ endservent();
+
+ return (0);
+}
+
+static int
+servent_test_correctness(struct servent *serv, void *mdata)
+{
+ printf("testing correctness with the following data:\n");
+ dump_servent(serv);
+
+ if (serv == NULL)
+ goto errfin;
+
+ if (serv->s_name == NULL)
+ goto errfin;
+
+ if (serv->s_proto == NULL)
+ goto errfin;
+
+ if (ntohs(serv->s_port < 0))
+ goto errfin;
+
+ if (serv->s_aliases == NULL)
+ goto errfin;
+
+ printf("correct\n");
+
+ return (0);
+errfin:
+ printf("incorrect\n");
+
+ return (-1);
+}
+
+/* servent_check_ambiguity() is needed when one port+proto is associated with
+ * more than one service (these cases are usually marked as PROBLEM in
+ * /etc/services. This functions is needed also when one service+proto is
+ * associated with several ports. We have to check all the servent structures
+ * to make sure that serv really exists and correct */
+static int
+servent_check_ambiguity(struct servent_test_data *td, struct servent *serv)
+{
+
+ return (TEST_DATA_FIND(servent, td, serv, compare_servent,
+ NULL) != NULL ? 0 : -1);
+}
+
+static int
+servent_test_getservbyname(struct servent *serv_model, void *mdata)
+{
+ char **alias;
+ struct servent *serv;
+
+ printf("testing getservbyname() with the following data:\n");
+ dump_servent(serv_model);
+
+ serv = getservbyname(serv_model->s_name, serv_model->s_proto);
+ if (servent_test_correctness(serv, NULL) != 0)
+ goto errfin;
+
+ if ((compare_servent(serv, serv_model, NULL) != 0) &&
+ (servent_check_ambiguity((struct servent_test_data *)mdata, serv)
+ !=0))
+ goto errfin;
+
+ for (alias = serv_model->s_aliases; *alias; ++alias) {
+ serv = getservbyname(*alias, serv_model->s_proto);
+
+ if (servent_test_correctness(serv, NULL) != 0)
+ goto errfin;
+
+ if ((compare_servent(serv, serv_model, NULL) != 0) &&
+ (servent_check_ambiguity(
+ (struct servent_test_data *)mdata, serv) != 0))
+ goto errfin;
+ }
+
+ printf("ok\n");
+ return (0);
+
+errfin:
+ printf("not ok\n");
+
+ return (-1);
+}
+
+static int
+servent_test_getservbyport(struct servent *serv_model, void *mdata)
+{
+ struct servent *serv;
+
+ printf("testing getservbyport() with the following data...\n");
+ dump_servent(serv_model);
+
+ serv = getservbyport(serv_model->s_port, serv_model->s_proto);
+ if ((servent_test_correctness(serv, NULL) != 0) ||
+ ((compare_servent(serv, serv_model, NULL) != 0) &&
+ (servent_check_ambiguity((struct servent_test_data *)mdata, serv)
+ != 0))) {
+ printf("not ok\n");
+ return (-1);
+ } else {
+ printf("ok\n");
+ return (0);
+ }
+}
+
+static int
+servent_test_getservent(struct servent *serv, void *mdata)
+{
+ /* Only correctness can be checked when doing 1-pass test for
+ * getservent(). */
+ return (servent_test_correctness(serv, NULL));
+}
+
+int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct servent_test_data td, td_snap, td_2pass;
+ int rv;
+
+ TEST_DATA_INIT(servent, &td, clone_servent, free_servent);
+ TEST_DATA_INIT(servent, &td_snap, clone_servent, free_servent);
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the file %s\n",
+ snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ if (method == TEST_BUILD_SNAPSHOT) {
+ rv = 0;
+ goto fin;
+ }
+
+ TEST_SNAPSHOT_FILE_READ(servent, snapshot_file,
+ &td_snap, servent_read_snapshot_func);
+ }
+ }
+
+ rv = servent_fill_test_data(&td);
+ if (rv == -1)
+ return (-1);
+ switch (method) {
+ case TEST_GETSERVBYNAME:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(servent, &td,
+ servent_test_getservbyname, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(servent, &td_snap,
+ servent_test_getservbyname, (void *)&td_snap);
+ break;
+ case TEST_GETSERVBYPORT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(servent, &td,
+ servent_test_getservbyport, (void *)&td);
+ else
+ rv = DO_1PASS_TEST(servent, &td_snap,
+ servent_test_getservbyport, (void *)&td_snap);
+ break;
+ case TEST_GETSERVENT:
+ if (snapshot_file == NULL)
+ rv = DO_1PASS_TEST(servent, &td, servent_test_getservent,
+ (void *)&td);
+ else
+ rv = DO_2PASS_TEST(servent, &td, &td_snap,
+ compare_servent, NULL);
+ break;
+ case TEST_GETSERVENT_2PASS:
+ TEST_DATA_INIT(servent, &td_2pass, clone_servent, free_servent);
+ rv = servent_fill_test_data(&td_2pass);
+ if (rv != -1)
+ rv = DO_2PASS_TEST(servent, &td, &td_2pass,
+ compare_servent, NULL);
+ TEST_DATA_DESTROY(servent, &td_2pass);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL)
+ rv = TEST_SNAPSHOT_FILE_WRITE(servent, snapshot_file, &td,
+ sdump_servent);
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(servent, &td_snap);
+ TEST_DATA_DESTROY(servent, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_serv"
+
+ATF_TC_WITHOUT_HEAD(build_snapshot);
+ATF_TC_BODY(build_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyname);
+ATF_TC_BODY(getservbyname, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyname_with_snapshot);
+ATF_TC_BODY(getservbyname_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVBYNAME) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyport);
+ATF_TC_BODY(getservbyport, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYPORT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyport_with_snapshot);
+ATF_TC_BODY(getservbyport_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVBYPORT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyent);
+ATF_TC_BODY(getservbyent, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyent_with_snapshot);
+ATF_TC_BODY(getservbyent_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVENT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getservbyent_with_two_pass);
+ATF_TC_BODY(getservbyent_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT_2PASS) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, build_snapshot);
+ ATF_TP_ADD_TC(tp, getservbyent);
+ ATF_TP_ADD_TC(tp, getservbyent_with_snapshot);
+ ATF_TP_ADD_TC(tp, getservbyent_with_two_pass);
+ ATF_TP_ADD_TC(tp, getservbyname);
+ ATF_TP_ADD_TC(tp, getservbyname_with_snapshot);
+ ATF_TP_ADD_TC(tp, getservbyport);
+ ATF_TP_ADD_TC(tp, getservbyport_with_snapshot);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/getusershell_test.c b/lib/libc/tests/nss/getusershell_test.c
new file mode 100644
index 0000000..ccd8cf9
--- /dev/null
+++ b/lib/libc/tests/nss/getusershell_test.c
@@ -0,0 +1,225 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "testutil.h"
+
+enum test_methods {
+ TEST_GETUSERSHELL,
+ TEST_BUILD_SNAPSHOT
+};
+
+struct usershell {
+ char *path;
+};
+
+static enum test_methods method = TEST_GETUSERSHELL;
+
+DECLARE_TEST_DATA(usershell)
+DECLARE_TEST_FILE_SNAPSHOT(usershell)
+DECLARE_2PASS_TEST(usershell)
+
+static void clone_usershell(struct usershell *, struct usershell const *);
+static int compare_usershell(struct usershell *, struct usershell *, void *);
+static void free_usershell(struct usershell *);
+
+static void sdump_usershell(struct usershell *, char *, size_t);
+static void dump_usershell(struct usershell *);
+
+IMPLEMENT_TEST_DATA(usershell)
+IMPLEMENT_TEST_FILE_SNAPSHOT(usershell)
+IMPLEMENT_2PASS_TEST(usershell)
+
+static void
+clone_usershell(struct usershell *dest, struct usershell const *src)
+{
+ assert(dest != NULL);
+ assert(src != NULL);
+
+ if (src->path != NULL) {
+ dest->path = strdup(src->path);
+ assert(dest->path != NULL);
+ }
+}
+
+static int
+compare_usershell(struct usershell *us1, struct usershell *us2, void *mdata)
+{
+ int rv;
+
+ assert(us1 != NULL);
+ assert(us2 != NULL);
+
+ dump_usershell(us1);
+ dump_usershell(us2);
+
+ if (us1 == us2)
+ return (0);
+
+ rv = strcmp(us1->path, us2->path);
+ if (rv != 0) {
+ printf("following structures are not equal:\n");
+ dump_usershell(us1);
+ dump_usershell(us2);
+ }
+
+ return (rv);
+}
+
+static void
+free_usershell(struct usershell *us)
+{
+ free(us->path);
+}
+
+static void
+sdump_usershell(struct usershell *us, char *buffer, size_t buflen)
+{
+ snprintf(buffer, buflen, "%s", us->path);
+}
+
+static void
+dump_usershell(struct usershell *us)
+{
+ if (us != NULL) {
+ char buffer[2048];
+ sdump_usershell(us, buffer, sizeof(buffer));
+ printf("%s\n", buffer);
+ } else
+ printf("(null)\n");
+}
+
+static int
+usershell_read_snapshot_func(struct usershell *us, char *line)
+{
+
+ us->path = strdup(line);
+ ATF_REQUIRE(us->path != NULL);
+
+ return (0);
+}
+
+int
+run_tests(const char *snapshot_file, enum test_methods method)
+{
+ struct usershell_test_data td, td_snap;
+ struct usershell ushell;
+ int rv;
+
+ rv = 0;
+
+ TEST_DATA_INIT(usershell, &td, clone_usershell, free_usershell);
+ TEST_DATA_INIT(usershell, &td_snap, clone_usershell, free_usershell);
+
+ setusershell();
+ while ((ushell.path = getusershell()) != NULL) {
+ printf("usershell found:\n");
+ dump_usershell(&ushell);
+ TEST_DATA_APPEND(usershell, &td, &ushell);
+ }
+ endusershell();
+
+ if (snapshot_file != NULL) {
+ if (access(snapshot_file, W_OK | R_OK) != 0) {
+ if (errno == ENOENT)
+ method = TEST_BUILD_SNAPSHOT;
+ else {
+ printf("can't access the snapshot file %s\n",
+ snapshot_file);
+
+ rv = -1;
+ goto fin;
+ }
+ } else {
+ rv = TEST_SNAPSHOT_FILE_READ(usershell, snapshot_file,
+ &td_snap, usershell_read_snapshot_func);
+ if (rv != 0) {
+ printf("error reading snapshot file\n");
+ goto fin;
+ }
+ }
+ }
+
+ switch (method) {
+ case TEST_GETUSERSHELL:
+ rv = DO_2PASS_TEST(usershell, &td, &td_snap,
+ compare_usershell, NULL);
+ break;
+ case TEST_BUILD_SNAPSHOT:
+ if (snapshot_file != NULL) {
+ rv = TEST_SNAPSHOT_FILE_WRITE(usershell, snapshot_file,
+ &td, sdump_usershell);
+ }
+ break;
+ default:
+ rv = 0;
+ break;
+ }
+
+fin:
+ TEST_DATA_DESTROY(usershell, &td_snap);
+ TEST_DATA_DESTROY(usershell, &td);
+
+ return (rv);
+}
+
+#define SNAPSHOT_FILE "snapshot_usershell"
+
+ATF_TC_WITHOUT_HEAD(getusershell_with_snapshot);
+ATF_TC_BODY(getusershell_with_snapshot, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(getusershell_with_two_pass);
+ATF_TC_BODY(getusershell_with_two_pass, tc)
+{
+
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
+ ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETUSERSHELL) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, getusershell_with_snapshot);
+ ATF_TP_ADD_TC(tp, getusershell_with_two_pass);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/nss/testutil.h b/lib/libc/tests/nss/testutil.h
new file mode 100644
index 0000000..39c4f41
--- /dev/null
+++ b/lib/libc/tests/nss/testutil.h
@@ -0,0 +1,333 @@
+/*-
+ * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/queue.h>
+
+#define DECLARE_TEST_DATA(ent) \
+struct ent##_entry { \
+ struct ent data; \
+ STAILQ_ENTRY(ent##_entry) entries; \
+}; \
+ \
+struct ent##_test_data { \
+ void (*clone_func)(struct ent *, struct ent const *); \
+ void (*free_func)(struct ent *); \
+ \
+ STAILQ_HEAD(ent_head, ent##_entry) snapshot_data; \
+}; \
+ \
+void __##ent##_test_data_init(struct ent##_test_data *, \
+ void (*)(struct ent *, struct ent const *), \
+ void (*freef)(struct ent *)); \
+void __##ent##_test_data_destroy(struct ent##_test_data *); \
+ \
+void __##ent##_test_data_append(struct ent##_test_data *, struct ent *data);\
+int __##ent##_test_data_foreach(struct ent##_test_data *, \
+ int (*)(struct ent *, void *), void *); \
+int __##ent##_test_data_compare(struct ent##_test_data *, \
+ struct ent##_test_data *, int (*)(struct ent *, struct ent *, \
+ void *), void *); \
+struct ent *__##ent##_test_data_find(struct ent##_test_data *, struct ent *,\
+ int (*)(struct ent *, struct ent *, void *), void *); \
+void __##ent##_test_data_clear(struct ent##_test_data *);
+
+#define TEST_DATA_INIT(ent, td, clonef, freef)\
+ __##ent##_test_data_init(td, clonef, freef)
+#define TEST_DATA_DESTROY(ent, td) __##ent##_test_data_destroy(td)
+#define TEST_DATA_APPEND(ent, td, d) __##ent##_test_data_append(td, d)
+#define TEST_DATA_FOREACH(ent, td, f, mdata)\
+ __##ent##_test_data_foreach(td, f, mdata)
+#define TEST_DATA_COMPARE(ent, td1, td2, fcmp, mdata)\
+ __##ent##_test_data_compare(td1, td2, fcmp, mdata);
+#define TEST_DATA_FIND(ent, td, d, fcmp, mdata)\
+ __##ent##_test_data_find(td, d, fcmp, mdata)
+#define TEST_DATA_CLEAR(ent, td) __##ent##_test_data_clear(td)
+
+#define IMPLEMENT_TEST_DATA(ent) \
+void \
+__##ent##_test_data_init(struct ent##_test_data *td, \
+ void (*clonef)(struct ent *, struct ent const *), \
+ void (*freef)(struct ent *)) \
+{ \
+ ATF_REQUIRE(td != NULL); \
+ ATF_REQUIRE(clonef != NULL); \
+ ATF_REQUIRE(freef != NULL); \
+ \
+ memset(td, 0, sizeof(*td)); \
+ td->clone_func = clonef; \
+ td->free_func = freef; \
+ STAILQ_INIT(&td->snapshot_data); \
+} \
+ \
+void \
+__##ent##_test_data_destroy(struct ent##_test_data *td) \
+{ \
+ __##ent##_test_data_clear(td); \
+} \
+ \
+void \
+__##ent##_test_data_append(struct ent##_test_data *td, struct ent *app_data)\
+{ \
+ struct ent##_entry *e; \
+ \
+ ATF_REQUIRE(td != NULL); \
+ ATF_REQUIRE(app_data != NULL); \
+ \
+ e = (struct ent##_entry *)malloc(sizeof(struct ent##_entry)); \
+ ATF_REQUIRE(e != NULL); \
+ memset(e, 0, sizeof(struct ent##_entry)); \
+ \
+ td->clone_func(&e->data, app_data); \
+ STAILQ_INSERT_TAIL(&td->snapshot_data, e, entries); \
+} \
+ \
+int \
+__##ent##_test_data_foreach(struct ent##_test_data *td, \
+ int (*forf)(struct ent *, void *), void *mdata) \
+{ \
+ struct ent##_entry *e; \
+ int rv; \
+ \
+ ATF_REQUIRE(td != NULL); \
+ ATF_REQUIRE(forf != NULL); \
+ \
+ rv = 0; \
+ STAILQ_FOREACH(e, &td->snapshot_data, entries) { \
+ rv = forf(&e->data, mdata); \
+ if (rv != 0) \
+ break; \
+ } \
+ \
+ return (rv); \
+} \
+ \
+int \
+__##ent##_test_data_compare(struct ent##_test_data *td1, struct ent##_test_data *td2,\
+ int (*cmp_func)(struct ent *, struct ent *, void *), void *mdata)\
+{ \
+ struct ent##_entry *e1, *e2; \
+ int rv; \
+ \
+ ATF_REQUIRE(td1 != NULL); \
+ ATF_REQUIRE(td2 != NULL); \
+ ATF_REQUIRE(cmp_func != NULL); \
+ \
+ e1 = STAILQ_FIRST(&td1->snapshot_data); \
+ e2 = STAILQ_FIRST(&td2->snapshot_data); \
+ \
+ rv = 0; \
+ do { \
+ if ((e1 == NULL) || (e2 == NULL)) { \
+ if (e1 == e2) \
+ return (0); \
+ else \
+ return (-1); \
+ } \
+ \
+ rv = cmp_func(&e1->data, &e2->data, mdata); \
+ e1 = STAILQ_NEXT(e1, entries); \
+ e2 = STAILQ_NEXT(e2, entries); \
+ } while (rv == 0); \
+ \
+ return (rv); \
+} \
+ \
+struct ent * \
+__##ent##_test_data_find(struct ent##_test_data *td, struct ent *data, \
+ int (*cmp)(struct ent *, struct ent *, void *), void *mdata) \
+{ \
+ struct ent##_entry *e; \
+ struct ent *result; \
+ \
+ ATF_REQUIRE(td != NULL); \
+ ATF_REQUIRE(cmp != NULL); \
+ \
+ result = NULL; \
+ STAILQ_FOREACH(e, &td->snapshot_data, entries) { \
+ if (cmp(&e->data, data, mdata) == 0) { \
+ result = &e->data; \
+ break; \
+ } \
+ } \
+ \
+ return (result); \
+} \
+ \
+ \
+void \
+__##ent##_test_data_clear(struct ent##_test_data *td) \
+{ \
+ struct ent##_entry *e; \
+ ATF_REQUIRE(td != NULL); \
+ \
+ while (!STAILQ_EMPTY(&td->snapshot_data)) { \
+ e = STAILQ_FIRST(&td->snapshot_data); \
+ STAILQ_REMOVE_HEAD(&td->snapshot_data, entries); \
+ \
+ td->free_func(&e->data); \
+ free(e); \
+ e = NULL; \
+ } \
+}
+
+#define DECLARE_TEST_FILE_SNAPSHOT(ent) \
+struct ent##_snp_param { \
+ FILE *fp; \
+ void (*sdump_func)(struct ent *, char *, size_t); \
+}; \
+ \
+int __##ent##_snapshot_write_func(struct ent *, void *); \
+int __##ent##_snapshot_write(char const *, struct ent##_test_data *, \
+ void (*)(struct ent *, char *, size_t)); \
+int __##ent##_snapshot_read(char const *, struct ent##_test_data *, \
+ int (*)(struct ent *, char *));
+
+#define TEST_SNAPSHOT_FILE_WRITE(ent, fname, td, f) \
+ __##ent##_snapshot_write(fname, td, f)
+#define TEST_SNAPSHOT_FILE_READ(ent, fname, td, f) \
+ __##ent##_snapshot_read(fname, td, f)
+
+#define IMPLEMENT_TEST_FILE_SNAPSHOT(ent) \
+int \
+__##ent##_snapshot_write_func(struct ent *data, void *mdata) \
+{ \
+ char buffer[1024]; \
+ struct ent##_snp_param *param; \
+ \
+ ATF_REQUIRE(data != NULL); \
+ \
+ param = (struct ent##_snp_param *)mdata; \
+ param->sdump_func(data, buffer, sizeof(buffer)); \
+ fputs(buffer, param->fp); \
+ fputc('\n', param->fp); \
+ \
+ return (0); \
+} \
+ \
+int \
+__##ent##_snapshot_write(char const *fname, struct ent##_test_data *td, \
+ void (*sdump_func)(struct ent *, char *, size_t)) \
+{ \
+ struct ent##_snp_param param; \
+ \
+ ATF_REQUIRE(fname != NULL); \
+ ATF_REQUIRE(td != NULL); \
+ \
+ param.fp = fopen(fname, "w"); \
+ if (param.fp == NULL) \
+ return (-1); \
+ \
+ param.sdump_func = sdump_func; \
+ __##ent##_test_data_foreach(td, __##ent##_snapshot_write_func, &param);\
+ fclose(param.fp); \
+ \
+ return (0); \
+} \
+ \
+int \
+__##ent##_snapshot_read(char const *fname, struct ent##_test_data *td, \
+ int (*read_func)(struct ent *, char *)) \
+{ \
+ char buffer[1024]; \
+ struct ent data; \
+ char *s; \
+ FILE *fi; \
+ size_t len; \
+ int rv; \
+ \
+ ATF_REQUIRE(fname != NULL); \
+ ATF_REQUIRE(td != NULL); \
+ \
+ fi = fopen(fname, "r"); \
+ if (fi == NULL) \
+ return (-1); \
+ \
+ rv = 0; \
+ memset(buffer, 0, sizeof(buffer)); \
+ while (!feof(fi)) { \
+ s = fgets(buffer, sizeof(buffer), fi); \
+ if (s != NULL && s[0] != '#') { \
+ len = strlen(s); \
+ if (len == 0) \
+ continue; \
+ if (buffer[len - 1] == '\n') \
+ buffer[len -1] = '\0'; \
+ \
+ rv = read_func(&data, s); \
+ if (rv == 0) { \
+ __##ent##_test_data_append(td, &data); \
+ td->free_func(&data); \
+ } else \
+ goto fin; \
+ } \
+ } \
+ \
+fin: \
+ fclose(fi); \
+ return (rv); \
+}
+
+#define DECLARE_1PASS_TEST(ent) \
+int __##ent##_1pass_test(struct ent##_test_data *, \
+ int (*)(struct ent *, void *), \
+ void *);
+
+#define DO_1PASS_TEST(ent, td, f, mdata) \
+ __##ent##_1pass_test(td, f, mdata)
+
+#define IMPLEMENT_1PASS_TEST(ent) \
+int \
+__##ent##_1pass_test(struct ent##_test_data *td, \
+ int (*tf)(struct ent *, void *), \
+ void *mdata) \
+{ \
+ int rv; \
+ rv = __##ent##_test_data_foreach(td, tf, mdata); \
+ \
+ return (rv); \
+}
+
+#define DECLARE_2PASS_TEST(ent) \
+int __##ent##_2pass_test(struct ent##_test_data *, \
+ struct ent##_test_data *, \
+ int (*)(struct ent *, struct ent *, void *), void *);
+
+#define DO_2PASS_TEST(ent, td1, td2, f, mdata) \
+ __##ent##_2pass_test(td1, td2, f, mdata)
+
+#define IMPLEMENT_2PASS_TEST(ent) \
+int \
+__##ent##_2pass_test(struct ent##_test_data *td1, \
+ struct ent##_test_data *td2, \
+ int (*cmp_func)(struct ent *, struct ent *, void *), \
+ void *cmp_mdata) \
+{ \
+ int rv; \
+ \
+ rv = __##ent##_test_data_compare(td1, td2, cmp_func, cmp_mdata); \
+ return (rv); \
+}
diff --git a/lib/libc/tests/resolv/Makefile b/lib/libc/tests/resolv/Makefile
new file mode 100644
index 0000000..c6d9900
--- /dev/null
+++ b/lib/libc/tests/resolv/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libc/resolv
+BINDIR= ${TESTSDIR}
+
+FILES+= mach
+
+ATF_TESTS_C+= resolv_test
+
+# Note: this test relies on being dynamically linked. You will get a
+# spurious PASS for a statically linked test.
+DPADD.resolv_test+= ${LIBPTHREAD}
+LDADD.resolv_test+= -lpthread
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/resolv/mach b/lib/libc/tests/resolv/mach
new file mode 100644
index 0000000..4b47ebb
--- /dev/null
+++ b/lib/libc/tests/resolv/mach
@@ -0,0 +1,46 @@
+# $FreeBSD$
+localhost
+anoncvs.cirr.com
+anoncvs.netbsd.se
+antioche.antioche.eu.org
+centaurus.4web.cz
+chur.math.ntnu.no
+console.netbsd.org
+cvs.netbsd.org
+cvsup.netbsd.se
+ftp.chg.ru
+ftp.estpak.ee
+ftp.fsn.hu
+ftp.funet.fi
+ftp.netbsd.org
+ftp.nluug.nl
+ftp.plig.org
+ftp.uni-erlangen.de
+ftp.xgate.co.kr
+gd.tuwien.ac.at
+gort.ludd.luth.se
+irc.warped.net
+knug.youn.co.kr
+mail.jp.netbsd.org
+mail.netbsd.org
+melanoma.cs.rmit.edu.au
+mirror.aarnet.edu.au
+moon.vub.ac.be
+net.bsd.cz
+netbsd.3miasto.net
+netbsd.4ka.mipt.ru
+netbsd.csie.nctu.edu.tw
+netbsd.enderunix.org
+netbsd.ftp.fu-berlin.de
+netbsd.pair.com
+netbsdiso.interoute.net.uk
+netbsdwww.cs.rmit.edu.au
+netbsdwww.interoute.net.uk
+ns.netbsd.org
+skeleton.phys.spbu.ru
+www.en.netbsd.de
+www.netbsd.cl
+www.netbsd.nl
+www.netbsd.org
+www.netbsd.ro
+zeppo.rediris.es
diff --git a/lib/libc/tests/resolv/resolv_test.c b/lib/libc/tests/resolv/resolv_test.c
new file mode 100644
index 0000000..74e89b1
--- /dev/null
+++ b/lib/libc/tests/resolv/resolv_test.c
@@ -0,0 +1,331 @@
+/* $NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $ */
+
+/*-
+ * Copyright (c) 2004 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/* $FreeBSD$ */
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: resolv.c,v 1.6 2004/05/23 16:59:11 christos Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stringlist.h>
+
+#include <atf-c.h>
+
+#define NTHREADS 10
+#define NHOSTS 100
+#define WS " \t\n\r"
+
+enum method {
+ METHOD_GETADDRINFO,
+ METHOD_GETHOSTBY,
+ METHOD_GETIPNODEBY
+};
+
+static StringList *hosts = NULL;
+static enum method method = METHOD_GETADDRINFO;
+static int *ask = NULL;
+static int *got = NULL;
+
+static void load(const char *);
+static void resolvone(int);
+static void *resolvloop(void *);
+static void run(int *);
+
+static pthread_mutex_t stats = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+load(const char *fname)
+{
+ FILE *fp;
+ size_t len;
+ char *line;
+
+ if ((fp = fopen(fname, "r")) == NULL)
+ ATF_REQUIRE(fp != NULL);
+ while ((line = fgetln(fp, &len)) != NULL) {
+ char c = line[len];
+ char *ptr;
+ line[len] = '\0';
+ for (ptr = strtok(line, WS); ptr; ptr = strtok(NULL, WS)) {
+ if (ptr == '\0' || ptr[0] == '#')
+ continue;
+ sl_add(hosts, strdup(ptr));
+ }
+ line[len] = c;
+ }
+
+ (void)fclose(fp);
+}
+
+static int
+resolv_getaddrinfo(pthread_t self, char *host, int port)
+{
+ char portstr[6], buf[1024], hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+ struct addrinfo hints, *res;
+ int error, len;
+
+ snprintf(portstr, sizeof(portstr), "%d", port);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(host, portstr, &hints, &res);
+ len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
+ self, host, error ? "not found" : "ok");
+ (void)write(STDOUT_FILENO, buf, len);
+ if (error == 0) {
+ memset(hbuf, 0, sizeof(hbuf));
+ memset(pbuf, 0, sizeof(pbuf));
+ getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf),
+ pbuf, sizeof(pbuf), 0);
+ len = snprintf(buf, sizeof(buf),
+ "%p: reverse %s %s\n", self, hbuf, pbuf);
+ (void)write(STDOUT_FILENO, buf, len);
+ }
+ if (error == 0)
+ freeaddrinfo(res);
+ return error;
+}
+
+static int
+resolv_gethostby(pthread_t self, char *host)
+{
+ char buf[1024];
+ struct hostent *hp, *hp2;
+ int len;
+
+ hp = gethostbyname(host);
+ len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
+ self, host, (hp == NULL) ? "not found" : "ok");
+ (void)write(STDOUT_FILENO, buf, len);
+ if (hp) {
+ memcpy(buf, hp->h_addr, hp->h_length);
+ hp2 = gethostbyaddr(buf, hp->h_length, hp->h_addrtype);
+ if (hp2) {
+ len = snprintf(buf, sizeof(buf),
+ "%p: reverse %s\n", self, hp2->h_name);
+ (void)write(STDOUT_FILENO, buf, len);
+ }
+ }
+ return hp ? 0 : -1;
+}
+
+static int
+resolv_getipnodeby(pthread_t self, char *host)
+{
+ char buf[1024];
+ struct hostent *hp, *hp2;
+ int len, h_error;
+
+ hp = getipnodebyname(host, AF_INET, 0, &h_error);
+ len = snprintf(buf, sizeof(buf), "%p: host %s %s\n",
+ self, host, (hp == NULL) ? "not found" : "ok");
+ (void)write(STDOUT_FILENO, buf, len);
+ if (hp) {
+ memcpy(buf, hp->h_addr, hp->h_length);
+ hp2 = getipnodebyaddr(buf, hp->h_length, hp->h_addrtype,
+ &h_error);
+ if (hp2) {
+ len = snprintf(buf, sizeof(buf),
+ "%p: reverse %s\n", self, hp2->h_name);
+ (void)write(STDOUT_FILENO, buf, len);
+ }
+ if (hp2)
+ freehostent(hp2);
+ }
+ if (hp)
+ freehostent(hp);
+ return hp ? 0 : -1;
+}
+
+static void
+resolvone(int n)
+{
+ char buf[1024];
+ pthread_t self = pthread_self();
+ size_t i = (random() & 0x0fffffff) % hosts->sl_cur;
+ char *host = hosts->sl_str[i];
+ struct addrinfo hints, *res;
+ int error, len;
+
+ len = snprintf(buf, sizeof(buf), "%p: %d resolving %s %d\n",
+ self, n, host, (int)i);
+ (void)write(STDOUT_FILENO, buf, len);
+ switch (method) {
+ case METHOD_GETADDRINFO:
+ error = resolv_getaddrinfo(self, host, i);
+ break;
+ case METHOD_GETHOSTBY:
+ error = resolv_gethostby(self, host);
+ break;
+ case METHOD_GETIPNODEBY:
+ error = resolv_getipnodeby(self, host);
+ break;
+ default:
+ break;
+ }
+ pthread_mutex_lock(&stats);
+ ask[i]++;
+ got[i] += error == 0;
+ pthread_mutex_unlock(&stats);
+}
+
+static void *
+resolvloop(void *p)
+{
+ int *nhosts = (int *)p;
+ if (*nhosts == 0)
+ return NULL;
+ do
+ resolvone(*nhosts);
+ while (--(*nhosts));
+ return NULL;
+}
+
+static void
+run(int *nhosts)
+{
+ pthread_t self;
+ int rc;
+
+ self = pthread_self();
+ rc = pthread_create(&self, NULL, resolvloop, nhosts);
+ ATF_REQUIRE_MSG(rc == 0, "pthread_create failed: %s", strerror(rc));
+}
+
+static int
+run_tests(const char *hostlist_file, enum method method)
+{
+ int nthreads = NTHREADS;
+ int nhosts = NHOSTS;
+ int i, c, done, *nleft;
+ hosts = sl_init();
+
+ srandom(1234);
+
+ load(hostlist_file);
+
+ ATF_REQUIRE_MSG(0 < hosts->sl_cur, "0 hosts in %s", hostlist_file);
+
+ nleft = malloc(nthreads * sizeof(int));
+ ATF_REQUIRE(nleft != NULL);
+
+ ask = calloc(hosts->sl_cur, sizeof(int));
+ ATF_REQUIRE(ask != NULL);
+
+ got = calloc(hosts->sl_cur, sizeof(int));
+ ATF_REQUIRE(got != NULL);
+
+ for (i = 0; i < nthreads; i++) {
+ nleft[i] = nhosts;
+ run(&nleft[i]);
+ }
+
+ for (done = 0; !done;) {
+ done = 1;
+ for (i = 0; i < nthreads; i++) {
+ if (nleft[i] != 0) {
+ done = 0;
+ break;
+ }
+ }
+ sleep(1);
+ }
+ c = 0;
+ for (i = 0; i < hosts->sl_cur; i++) {
+ if (ask[i] != got[i] && got[i] != 0) {
+ printf("Error: host %s ask %d got %d\n",
+ hosts->sl_str[i], ask[i], got[i]);
+ c++;
+ }
+ }
+ free(nleft);
+ free(ask);
+ free(got);
+ sl_free(hosts, 1);
+ return c;
+}
+
+#define HOSTLIST_FILE "mach"
+
+#define RUN_TESTS(tc, method) \
+do { \
+ char *_hostlist_file; \
+ ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \
+ atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \
+ ATF_REQUIRE(run_tests(_hostlist_file, method) == 0); \
+} while(0)
+
+ATF_TC(getaddrinfo_test);
+ATF_TC_HEAD(getaddrinfo_test, tc) {
+ atf_tc_set_md_var(tc, "timeout", "450");
+}
+ATF_TC_BODY(getaddrinfo_test, tc)
+{
+
+ RUN_TESTS(tc, METHOD_GETADDRINFO);
+}
+
+ATF_TC(gethostby_test);
+ATF_TC_HEAD(gethostby_test, tc) {
+ atf_tc_set_md_var(tc, "timeout", "450");
+}
+ATF_TC_BODY(gethostby_test, tc)
+{
+
+ RUN_TESTS(tc, METHOD_GETHOSTBY);
+}
+
+ATF_TC(getipnodeby_test);
+ATF_TC_HEAD(getipnodeby_test, tc) {
+
+ atf_tc_set_md_var(tc, "timeout", "450");
+}
+ATF_TC_BODY(getipnodeby_test, tc)
+{
+
+ RUN_TESTS(tc, METHOD_GETIPNODEBY);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, getaddrinfo_test);
+ ATF_TP_ADD_TC(tp, gethostby_test);
+ ATF_TP_ADD_TC(tp, getipnodeby_test);
+
+ return (atf_no_error());
+}
diff --git a/release/Makefile b/release/Makefile
index 4cd82c3..976f651 100644
--- a/release/Makefile
+++ b/release/Makefile
@@ -40,7 +40,6 @@ WORLDDIR?= ${.CURDIR}/..
PORTSDIR?= /usr/ports
DOCDIR?= /usr/doc
RELNOTES_LANG?= en_US.ISO8859-1
-XZCMD?= /usr/bin/xz
.if !defined(TARGET) || empty(TARGET)
TARGET= ${MACHINE}
@@ -161,16 +160,18 @@ kernel.txz:
src.txz:
mkdir -p ${DISTDIR}/usr
ln -fs ${WORLDDIR} ${DISTDIR}/usr/src
- cd ${DISTDIR} && tar cLvJf ${.OBJDIR}/src.txz --exclude .svn --exclude .zfs \
- --exclude .git --exclude @ --exclude usr/src/release/dist usr/src
+ cd ${DISTDIR} && tar cLvf - --exclude .svn --exclude .zfs \
+ --exclude .git --exclude @ --exclude usr/src/release/dist usr/src | \
+ ${XZ_CMD} > ${.OBJDIR}/src.txz
ports.txz:
mkdir -p ${DISTDIR}/usr
ln -fs ${PORTSDIR} ${DISTDIR}/usr/ports
- cd ${DISTDIR} && tar cLvJf ${.OBJDIR}/ports.txz \
+ cd ${DISTDIR} && tar cLvf - \
--exclude .git --exclude .svn \
--exclude usr/ports/distfiles --exclude usr/ports/packages \
- --exclude 'usr/ports/INDEX*' --exclude work usr/ports
+ --exclude 'usr/ports/INDEX*' --exclude work usr/ports | \
+ ${XZ_CMD} > ${.OBJDIR}/ports.txz
reldoc:
cd ${.CURDIR}/doc && ${MAKE} all install clean 'FORMATS=html txt' \
@@ -333,7 +334,7 @@ release-install:
.for I in ${IMAGES}
cp -p ${I} ${DESTDIR}/${OSRELEASE}-${I}
. if defined(WITH_COMPRESSED_IMAGES) && !empty(WITH_COMPRESSED_IMAGES)
- ${XZCMD} -k ${DESTDIR}/${OSRELEASE}-${I}
+ ${XZ_CMD} -k ${DESTDIR}/${OSRELEASE}-${I}
. endif
.endfor
cd ${DESTDIR} && sha512 ${OSRELEASE}* > ${DESTDIR}/CHECKSUM.SHA512
diff --git a/release/Makefile.vm b/release/Makefile.vm
index f4de633..902442f 100644
--- a/release/Makefile.vm
+++ b/release/Makefile.vm
@@ -137,7 +137,7 @@ vm-install:
. if defined(WITH_COMPRESSED_VMIMAGES) && !empty(WITH_COMPRESSED_VMIMAGES)
. for FORMAT in ${VMFORMATS}
# Don't keep the originals. There is a copy in ${.OBJDIR} if needed.
- ${XZCMD} ${DESTDIR}/vmimages/${OSRELEASE}.${FORMAT}
+ ${XZ_CMD} ${DESTDIR}/vmimages/${OSRELEASE}.${FORMAT}
. endfor
. endif
cd ${DESTDIR}/vmimages && sha512 ${OSRELEASE}* > \
diff --git a/share/mk/bsd.own.mk b/share/mk/bsd.own.mk
index 4792bad..ef200d8 100644
--- a/share/mk/bsd.own.mk
+++ b/share/mk/bsd.own.mk
@@ -213,6 +213,15 @@ STRIP?= -s
COMPRESS_CMD?= gzip -cn
COMPRESS_EXT?= .gz
+# Set XZ_THREADS to 1 to disable multi-threading.
+XZ_THREADS?= 0
+
+.if !empty(XZ_THREADS)
+XZ_CMD?= xz -T ${XZ_THREADS}
+.else
+XZ_CMD?= xz
+.endif
+
.if !defined(_WITHOUT_SRCCONF)
#
# Define MK_* variables (which are either "yes" or "no") for users
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c
index d394011..d5c393b 100644
--- a/sys/dev/isp/isp.c
+++ b/sys/dev/isp/isp.c
@@ -108,12 +108,12 @@ static void isp_fibre_init(ispsoftc_t *);
static void isp_fibre_init_2400(ispsoftc_t *);
static void isp_clear_portdb(ispsoftc_t *, int);
static void isp_mark_portdb(ispsoftc_t *, int);
-static int isp_plogx(ispsoftc_t *, int, uint16_t, uint32_t, int, int);
+static int isp_plogx(ispsoftc_t *, int, uint16_t, uint32_t, int);
static int isp_port_login(ispsoftc_t *, uint16_t, uint32_t);
static int isp_port_logout(ispsoftc_t *, uint16_t, uint32_t);
-static int isp_getpdb(ispsoftc_t *, int, uint16_t, isp_pdb_t *, int);
-static int isp_gethandles(ispsoftc_t *, int, uint16_t *, int *, int, int);
-static void isp_dump_chip_portdb(ispsoftc_t *, int, int);
+static int isp_getpdb(ispsoftc_t *, int, uint16_t, isp_pdb_t *);
+static int isp_gethandles(ispsoftc_t *, int, uint16_t *, int *, int);
+static void isp_dump_chip_portdb(ispsoftc_t *, int);
static uint64_t isp_get_wwn(ispsoftc_t *, int, int, int);
static int isp_fclink_test(ispsoftc_t *, int, int);
static int isp_pdb_sync(ispsoftc_t *, int);
@@ -2142,19 +2142,41 @@ isp_fibre_init_2400(ispsoftc_t *isp)
if ((icbp->icb_fwoptions3 & ICB2400_OPT3_RSPSZ_MASK) == 0) {
icbp->icb_fwoptions3 |= ICB2400_OPT3_RSPSZ_24;
}
- icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_AUTO;
if (isp->isp_confopts & ISP_CFG_1GB) {
+ icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK;
icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_1GB;
} else if (isp->isp_confopts & ISP_CFG_2GB) {
+ icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK;
icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_2GB;
} else if (isp->isp_confopts & ISP_CFG_4GB) {
+ icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK;
icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_4GB;
} else if (isp->isp_confopts & ISP_CFG_8GB) {
+ icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK;
icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_8GB;
} else if (isp->isp_confopts & ISP_CFG_16GB) {
+ icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK;
icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_16GB;
} else {
- icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_AUTO;
+ switch (icbp->icb_fwoptions3 & ICB2400_OPT3_RATE_MASK) {
+ case ICB2400_OPT3_RATE_4GB:
+ case ICB2400_OPT3_RATE_8GB:
+ case ICB2400_OPT3_RATE_16GB:
+ case ICB2400_OPT3_RATE_AUTO:
+ break;
+ case ICB2400_OPT3_RATE_2GB:
+ if (isp->isp_type <= ISP_HA_FC_2500)
+ break;
+ /*FALLTHROUGH*/
+ case ICB2400_OPT3_RATE_1GB:
+ if (isp->isp_type <= ISP_HA_FC_2400)
+ break;
+ /*FALLTHROUGH*/
+ default:
+ icbp->icb_fwoptions3 &= ~ICB2400_OPT3_RATE_MASK;
+ icbp->icb_fwoptions3 |= ICB2400_OPT3_RATE_AUTO;
+ break;
+ }
}
icbp->icb_logintime = ICB_LOGIN_TOV;
@@ -2322,6 +2344,161 @@ isp_fibre_init_2400(ispsoftc_t *isp)
isp->isp_state = ISP_RUNSTATE;
}
+static int
+isp_fc_enable_vp(ispsoftc_t *isp, int chan)
+{
+ fcparam *fcp = FCPARAM(isp, chan);
+ vp_modify_t vp;
+ void *reqp;
+ uint8_t resp[QENTRY_LEN];
+
+ /* Build a VP MODIFY command in memory */
+ ISP_MEMZERO(&vp, sizeof(vp));
+ vp.vp_mod_hdr.rqs_entry_type = RQSTYPE_VP_MODIFY;
+ vp.vp_mod_hdr.rqs_entry_count = 1;
+ vp.vp_mod_cnt = 1;
+ vp.vp_mod_idx0 = chan;
+ vp.vp_mod_cmd = VP_MODIFY_ENA;
+ vp.vp_mod_ports[0].options = ICB2400_VPOPT_ENABLED |
+ ICB2400_VPOPT_ENA_SNSLOGIN;
+ if (fcp->role & ISP_ROLE_INITIATOR)
+ vp.vp_mod_ports[0].options |= ICB2400_VPOPT_INI_ENABLE;
+ if ((fcp->role & ISP_ROLE_TARGET) == 0)
+ vp.vp_mod_ports[0].options |= ICB2400_VPOPT_TGT_DISABLE;
+ if (fcp->isp_loopid < LOCAL_LOOP_LIM) {
+ vp.vp_mod_ports[0].loopid = fcp->isp_loopid;
+ if (isp->isp_confopts & ISP_CFG_OWNLOOPID)
+ vp.vp_mod_ports[0].options |= ICB2400_VPOPT_HARD_ADDRESS;
+ else
+ vp.vp_mod_ports[0].options |= ICB2400_VPOPT_PREV_ADDRESS;
+ }
+ MAKE_NODE_NAME_FROM_WWN(vp.vp_mod_ports[0].wwpn, fcp->isp_wwpn);
+ MAKE_NODE_NAME_FROM_WWN(vp.vp_mod_ports[0].wwnn, fcp->isp_wwnn);
+
+ /* Prepare space for response in memory */
+ memset(resp, 0xff, sizeof(resp));
+ vp.vp_mod_hdl = isp_allocate_handle(isp, resp, ISP_HANDLE_CTRL);
+ if (vp.vp_mod_hdl == 0) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_MODIFY of Chan %d out of handles", __func__, chan);
+ return (EIO);
+ }
+
+ /* Send request and wait for response. */
+ reqp = isp_getrqentry(isp);
+ if (reqp == NULL) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_MODIFY of Chan %d out of rqent", __func__, chan);
+ isp_destroy_handle(isp, vp.vp_mod_hdl);
+ return (EIO);
+ }
+ isp_put_vp_modify(isp, &vp, (vp_modify_t *)reqp);
+ ISP_SYNC_REQUEST(isp);
+ if (msleep(resp, &isp->isp_lock, 0, "VP_MODIFY", 5*hz) == EWOULDBLOCK) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_MODIFY of Chan %d timed out", __func__, chan);
+ isp_destroy_handle(isp, vp.vp_mod_hdl);
+ return (EIO);
+ }
+ isp_get_vp_modify(isp, (vp_modify_t *)resp, &vp);
+
+ if (vp.vp_mod_hdr.rqs_flags != 0 || vp.vp_mod_status != VP_STS_OK) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_MODIFY of Chan %d failed with flags %x status %d",
+ __func__, chan, vp.vp_mod_hdr.rqs_flags, vp.vp_mod_status);
+ return (EIO);
+ }
+ return (0);
+}
+
+static int
+isp_fc_disable_vp(ispsoftc_t *isp, int chan)
+{
+ vp_ctrl_info_t vp;
+ void *reqp;
+ uint8_t resp[QENTRY_LEN];
+
+ /* Build a VP CTRL command in memory */
+ ISP_MEMZERO(&vp, sizeof(vp));
+ vp.vp_ctrl_hdr.rqs_entry_type = RQSTYPE_VP_CTRL;
+ vp.vp_ctrl_hdr.rqs_entry_count = 1;
+ if (ISP_CAP_VP0(isp)) {
+ vp.vp_ctrl_status = 1;
+ } else {
+ vp.vp_ctrl_status = 0;
+ chan--; /* VP0 can not be controlled in this case. */
+ }
+ vp.vp_ctrl_command = VP_CTRL_CMD_DISABLE_VP_LOGO_ALL;
+ vp.vp_ctrl_vp_count = 1;
+ vp.vp_ctrl_idmap[chan / 16] |= (1 << chan % 16);
+
+ /* Prepare space for response in memory */
+ memset(resp, 0xff, sizeof(resp));
+ vp.vp_ctrl_handle = isp_allocate_handle(isp, resp, ISP_HANDLE_CTRL);
+ if (vp.vp_ctrl_handle == 0) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_CTRL of Chan %d out of handles", __func__, chan);
+ return (EIO);
+ }
+
+ /* Send request and wait for response. */
+ reqp = isp_getrqentry(isp);
+ if (reqp == NULL) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_CTRL of Chan %d out of rqent", __func__, chan);
+ isp_destroy_handle(isp, vp.vp_ctrl_handle);
+ return (EIO);
+ }
+ isp_put_vp_ctrl_info(isp, &vp, (vp_ctrl_info_t *)reqp);
+ ISP_SYNC_REQUEST(isp);
+ if (msleep(resp, &isp->isp_lock, 0, "VP_CTRL", 5*hz) == EWOULDBLOCK) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_CTRL of Chan %d timed out", __func__, chan);
+ isp_destroy_handle(isp, vp.vp_ctrl_handle);
+ return (EIO);
+ }
+ isp_get_vp_ctrl_info(isp, (vp_ctrl_info_t *)resp, &vp);
+
+ if (vp.vp_ctrl_hdr.rqs_flags != 0 || vp.vp_ctrl_status != 0) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_CTRL of Chan %d failed with flags %x status %d %d",
+ __func__, chan, vp.vp_ctrl_hdr.rqs_flags,
+ vp.vp_ctrl_status, vp.vp_ctrl_index_fail);
+ return (EIO);
+ }
+ return (0);
+}
+
+static int
+isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role)
+{
+ fcparam *fcp = FCPARAM(isp, chan);
+ int i, was, res = 0;
+
+ if (chan >= isp->isp_nchan) {
+ isp_prt(isp, ISP_LOGWARN, "%s: bad channel %d", __func__, chan);
+ return (ENXIO);
+ }
+ if (fcp->role == new_role)
+ return (0);
+ for (was = 0, i = 0; i < isp->isp_nchan; i++) {
+ if (FCPARAM(isp, i)->role != ISP_ROLE_NONE)
+ was++;
+ }
+ if (was == 0 || (was == 1 && fcp->role != ISP_ROLE_NONE)) {
+ fcp->role = new_role;
+ return (isp_reinit(isp, 0));
+ }
+ if (fcp->role != ISP_ROLE_NONE) {
+ res = isp_fc_disable_vp(isp, chan);
+ isp_clear_portdb(isp, chan);
+ }
+ fcp->role = new_role;
+ if (fcp->role != ISP_ROLE_NONE)
+ res = isp_fc_enable_vp(isp, chan);
+ return (res);
+}
+
static void
isp_clear_portdb(ispsoftc_t *isp, int chan)
{
@@ -2373,13 +2550,11 @@ isp_mark_portdb(ispsoftc_t *isp, int chan)
* or via FABRIC LOGIN/FABRIC LOGOUT for other cards.
*/
static int
-isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags, int gs)
+isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags)
{
- mbreg_t mbs;
- uint8_t q[QENTRY_LEN];
- isp_plogx_t *plp;
- fcparam *fcp;
- uint8_t *scp;
+ isp_plogx_t pl;
+ void *reqp;
+ uint8_t resp[QENTRY_LEN];
uint32_t sst, parm1;
int rval, lev;
const char *msg;
@@ -2399,63 +2574,58 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags
}
}
- ISP_MEMZERO(q, QENTRY_LEN);
- plp = (isp_plogx_t *) q;
- plp->plogx_header.rqs_entry_count = 1;
- plp->plogx_header.rqs_entry_type = RQSTYPE_LOGIN;
- plp->plogx_handle = 0xffffffff;
- plp->plogx_nphdl = handle;
- plp->plogx_vphdl = chan;
- plp->plogx_portlo = portid;
- plp->plogx_rspsz_porthi = (portid >> 16) & 0xff;
- plp->plogx_flags = flags;
+ ISP_MEMZERO(&pl, sizeof(pl));
+ pl.plogx_header.rqs_entry_count = 1;
+ pl.plogx_header.rqs_entry_type = RQSTYPE_LOGIN;
+ pl.plogx_nphdl = handle;
+ pl.plogx_vphdl = chan;
+ pl.plogx_portlo = portid;
+ pl.plogx_rspsz_porthi = (portid >> 16) & 0xff;
+ pl.plogx_flags = flags;
- if (isp->isp_dblev & ISP_LOGDEBUG1) {
- isp_print_bytes(isp, "IOCB LOGX", QENTRY_LEN, plp);
- }
-
- if (gs == 0) {
- if (FC_SCRATCH_ACQUIRE(isp, chan)) {
- isp_prt(isp, ISP_LOGERR, sacq);
- return (-1);
- }
+ /* Prepare space for response in memory */
+ memset(resp, 0xff, sizeof(resp));
+ pl.plogx_handle = isp_allocate_handle(isp, resp, ISP_HANDLE_CTRL);
+ if (pl.plogx_handle == 0) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: PLOGX of Chan %d out of handles", __func__, chan);
+ return (-1);
}
- fcp = FCPARAM(isp, chan);
- scp = fcp->isp_scratch;
- isp_put_plogx(isp, plp, (isp_plogx_t *) scp);
- MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 500000);
- mbs.param[1] = QENTRY_LEN;
- mbs.param[2] = DMA_WD1(fcp->isp_scdma);
- mbs.param[3] = DMA_WD0(fcp->isp_scdma);
- mbs.param[6] = DMA_WD3(fcp->isp_scdma);
- mbs.param[7] = DMA_WD2(fcp->isp_scdma);
- MEMORYBARRIER(isp, SYNC_SFORDEV, 0, QENTRY_LEN, chan);
- isp_mboxcmd(isp, &mbs);
- if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- rval = mbs.param[0];
- goto out;
+ /* Send request and wait for response. */
+ reqp = isp_getrqentry(isp);
+ if (reqp == NULL) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: PLOGX of Chan %d out of rqent", __func__, chan);
+ isp_destroy_handle(isp, pl.plogx_handle);
+ return (-1);
}
- MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan);
- scp += QENTRY_LEN;
- isp_get_plogx(isp, (isp_plogx_t *) scp, plp);
- if (isp->isp_dblev & ISP_LOGDEBUG1) {
- isp_print_bytes(isp, "IOCB LOGX response", QENTRY_LEN, plp);
+ if (isp->isp_dblev & ISP_LOGDEBUG1)
+ isp_print_bytes(isp, "IOCB LOGX", QENTRY_LEN, &pl);
+ isp_put_plogx(isp, &pl, (isp_plogx_t *)reqp);
+ ISP_SYNC_REQUEST(isp);
+ if (msleep(resp, &isp->isp_lock, 0, "PLOGX", 3 * ICB_LOGIN_TOV * hz)
+ == EWOULDBLOCK) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: PLOGX of Chan %d timed out", __func__, chan);
+ isp_destroy_handle(isp, pl.plogx_handle);
+ return (-1);
}
+ isp_get_plogx(isp, (isp_plogx_t *)resp, &pl);
+ if (isp->isp_dblev & ISP_LOGDEBUG1)
+ isp_print_bytes(isp, "IOCB LOGX response", QENTRY_LEN, &pl);
- if (plp->plogx_status == PLOGX_STATUS_OK) {
- rval = 0;
- goto out;
- } else if (plp->plogx_status != PLOGX_STATUS_IOCBERR) {
+ if (pl.plogx_status == PLOGX_STATUS_OK) {
+ return (0);
+ } else if (pl.plogx_status != PLOGX_STATUS_IOCBERR) {
isp_prt(isp, ISP_LOGWARN,
"status 0x%x on port login IOCB channel %d",
- plp->plogx_status, chan);
- rval = -1;
- goto out;
+ pl.plogx_status, chan);
+ return (-1);
}
- sst = plp->plogx_ioparm[0].lo16 | (plp->plogx_ioparm[0].hi16 << 16);
- parm1 = plp->plogx_ioparm[1].lo16 | (plp->plogx_ioparm[1].hi16 << 16);
+ sst = pl.plogx_ioparm[0].lo16 | (pl.plogx_ioparm[0].hi16 << 16);
+ parm1 = pl.plogx_ioparm[1].lo16 | (pl.plogx_ioparm[1].hi16 << 16);
rval = -1;
lev = ISP_LOGERR;
@@ -2516,17 +2686,13 @@ isp_plogx(ispsoftc_t *isp, int chan, uint16_t handle, uint32_t portid, int flags
msg = "no FLOGI_ACC";
break;
default:
- ISP_SNPRINTF(buf, sizeof (buf), "status %x from %x", plp->plogx_status, flags);
+ ISP_SNPRINTF(buf, sizeof (buf), "status %x from %x", pl.plogx_status, flags);
msg = buf;
break;
}
if (msg) {
isp_prt(isp, ISP_LOGERR, "Chan %d PLOGX PortID 0x%06x to N-Port handle 0x%x: %s", chan, portid, handle, msg);
}
-out:
- if (gs == 0) {
- FC_SCRATCH_RELEASE(isp, chan);
- }
return (rval);
}
@@ -2596,7 +2762,7 @@ isp_port_logout(ispsoftc_t *isp, uint16_t handle, uint32_t portid)
}
static int
-isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock)
+isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb)
{
fcparam *fcp = FCPARAM(isp, chan);
mbreg_t mbs;
@@ -2620,18 +2786,14 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock)
mbs.param[3] = DMA_WD0(fcp->isp_scdma);
mbs.param[6] = DMA_WD3(fcp->isp_scdma);
mbs.param[7] = DMA_WD2(fcp->isp_scdma);
- if (dolock) {
- if (FC_SCRATCH_ACQUIRE(isp, chan)) {
- isp_prt(isp, ISP_LOGERR, sacq);
- return (-1);
- }
+ if (FC_SCRATCH_ACQUIRE(isp, chan)) {
+ isp_prt(isp, ISP_LOGERR, sacq);
+ return (-1);
}
MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (un), chan);
isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- if (dolock) {
- FC_SCRATCH_RELEASE(isp, chan);
- }
+ FC_SCRATCH_RELEASE(isp, chan);
return (mbs.param[0] | (mbs.param[1] << 16));
}
if (IS_24XX(isp)) {
@@ -2647,9 +2809,7 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock)
un.bill.pdb_curstate);
if (un.bill.pdb_curstate < PDB2400_STATE_PLOGI_DONE || un.bill.pdb_curstate > PDB2400_STATE_LOGGED_IN) {
mbs.param[0] = MBOX_NOT_LOGGED_IN;
- if (dolock) {
- FC_SCRATCH_RELEASE(isp, chan);
- }
+ FC_SCRATCH_RELEASE(isp, chan);
return (mbs.param[0]);
}
} else {
@@ -2662,15 +2822,12 @@ isp_getpdb(ispsoftc_t *isp, int chan, uint16_t id, isp_pdb_t *pdb, int dolock)
isp_prt(isp, ISP_LOGDEBUG1,
"Chan %d handle 0x%x Port 0x%06x", chan, id, pdb->portid);
}
- if (dolock) {
- FC_SCRATCH_RELEASE(isp, chan);
- }
+ FC_SCRATCH_RELEASE(isp, chan);
return (0);
}
static int
-isp_gethandles(ispsoftc_t *isp, int chan, uint16_t *handles, int *num,
- int dolock, int loop)
+isp_gethandles(ispsoftc_t *isp, int chan, uint16_t *handles, int *num, int loop)
{
fcparam *fcp = FCPARAM(isp, chan);
mbreg_t mbs;
@@ -2696,18 +2853,14 @@ isp_gethandles(ispsoftc_t *isp, int chan, uint16_t *handles, int *num,
mbs.param[3] = DMA_WD3(fcp->isp_scdma);
mbs.param[6] = DMA_WD2(fcp->isp_scdma);
}
- if (dolock) {
- if (FC_SCRATCH_ACQUIRE(isp, chan)) {
- isp_prt(isp, ISP_LOGERR, sacq);
- return (-1);
- }
+ if (FC_SCRATCH_ACQUIRE(isp, chan)) {
+ isp_prt(isp, ISP_LOGERR, sacq);
+ return (-1);
}
MEMORYBARRIER(isp, SYNC_SFORDEV, 0, ISP_FC_SCRLEN, chan);
isp_mboxcmd(isp, &mbs);
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- if (dolock) {
- FC_SCRATCH_RELEASE(isp, chan);
- }
+ FC_SCRATCH_RELEASE(isp, chan);
return (mbs.param[0] | (mbs.param[1] << 16));
}
elp1 = fcp->isp_scratch;
@@ -2735,13 +2888,12 @@ isp_gethandles(ispsoftc_t *isp, int chan, uint16_t *handles, int *num,
handles[j++] = h;
}
*num = j;
- if (dolock)
- FC_SCRATCH_RELEASE(isp, chan);
+ FC_SCRATCH_RELEASE(isp, chan);
return (0);
}
static void
-isp_dump_chip_portdb(ispsoftc_t *isp, int chan, int dolock)
+isp_dump_chip_portdb(ispsoftc_t *isp, int chan)
{
isp_pdb_t pdb;
uint16_t lim, nphdl;
@@ -2753,7 +2905,7 @@ isp_dump_chip_portdb(ispsoftc_t *isp, int chan, int dolock)
lim = NPH_MAX;
}
for (nphdl = 0; nphdl != lim; nphdl++) {
- if (isp_getpdb(isp, chan, nphdl, &pdb, dolock)) {
+ if (isp_getpdb(isp, chan, nphdl, &pdb)) {
continue;
}
isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGINFO, "Chan %d Handle 0x%04x "
@@ -2903,7 +3055,7 @@ isp_fclink_test(ispsoftc_t *isp, int chan, int usdelay)
if (fcp->isp_topo == TOPO_F_PORT || fcp->isp_topo == TOPO_FL_PORT) {
nphdl = IS_24XX(isp) ? NPH_FL_ID : FL_ID;
- r = isp_getpdb(isp, chan, nphdl, &pdb, 1);
+ r = isp_getpdb(isp, chan, nphdl, &pdb);
if (r != 0 || pdb.portid == 0) {
if (IS_2100(isp)) {
fcp->isp_topo = TOPO_NL_PORT;
@@ -3018,7 +3170,7 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
lp->portid,
PLOGX_FLG_CMD_LOGO |
PLOGX_FLG_IMPLICIT |
- PLOGX_FLG_FREE_NPHDL, 0);
+ PLOGX_FLG_FREE_NPHDL);
}
/*
* Note that we might come out of this with our state
@@ -3145,7 +3297,7 @@ isp_fix_portids(ispsoftc_t *isp, int chan)
if (VALID_PORT(lp->portid))
continue;
- r = isp_getpdb(isp, chan, lp->handle, &pdb, 1);
+ r = isp_getpdb(isp, chan, lp->handle, &pdb);
if (fcp->isp_loopstate < LOOP_SCANNING_LOOP)
return;
if (r != 0) {
@@ -3174,7 +3326,7 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
fcparam *fcp = FCPARAM(isp, chan);
int idx, lim, r;
isp_pdb_t pdb;
- uint16_t handles[LOCAL_LOOP_LIM];
+ uint16_t *handles;
uint16_t handle;
if (fcp->isp_loopstate < LOOP_LTEST_DONE)
@@ -3196,8 +3348,9 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
return (0);
}
- lim = LOCAL_LOOP_LIM;
- r = isp_gethandles(isp, chan, handles, &lim, 1, 1);
+ handles = (uint16_t *)fcp->isp_scanscratch;
+ lim = ISP_FC_SCRLEN / 2;
+ r = isp_gethandles(isp, chan, handles, &lim, 1);
if (r != 0) {
isp_prt(isp, ISP_LOG_SANCFG,
"Chan %d Getting list of handles failed with %x", chan, r);
@@ -3247,7 +3400,7 @@ abort:
/*
* Get the port database entity for this index.
*/
- r = isp_getpdb(isp, chan, handle, &pdb, 1);
+ r = isp_getpdb(isp, chan, handle, &pdb);
if (fcp->isp_loopstate < LOOP_SCANNING_LOOP)
goto abort;
if (r != 0) {
@@ -3276,20 +3429,10 @@ abort:
*
* For the 24XX card, we have to use CT-Pass through run via the Execute IOCB
* mailbox command.
- *
- * The net result is to leave the list of Port IDs setting untranslated in
- * offset IGPOFF of the FC scratch area, whereupon we'll canonicalize it to
- * host order at OGPOFF.
*/
-
-/*
- * Take half of our scratch area to store Port IDs
- */
-#define GIDLEN (ISP_FC_SCRLEN >> 1)
+#define GIDLEN (ISP_FC_SCRLEN - (3 * QENTRY_LEN))
#define NGENT ((GIDLEN - 16) >> 2)
-#define IGPOFF (0)
-#define OGPOFF (ISP_FC_SCRLEN >> 1)
#define XTXOFF (ISP_FC_SCRLEN - (3 * QENTRY_LEN)) /* CT request */
#define CTXOFF (ISP_FC_SCRLEN - (2 * QENTRY_LEN)) /* Request IOCB */
#define ZTXOFF (ISP_FC_SCRLEN - (1 * QENTRY_LEN)) /* Response IOCB */
@@ -3306,21 +3449,25 @@ isp_gid_ft_sns(ispsoftc_t *isp, int chan)
uint8_t *scp = fcp->isp_scratch;
mbreg_t mbs;
- isp_prt(isp, ISP_LOGDEBUG0, "Chan %d scanning fabric (GID_FT) via SNS", chan);
+ isp_prt(isp, ISP_LOGDEBUG0, "Chan %d requesting GID_FT via SNS", chan);
+ if (FC_SCRATCH_ACQUIRE(isp, chan)) {
+ isp_prt(isp, ISP_LOGERR, sacq);
+ return (-1);
+ }
ISP_MEMZERO(rq, SNS_GID_FT_REQ_SIZE);
rq->snscb_rblen = GIDLEN >> 1;
- rq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma + IGPOFF);
- rq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma + IGPOFF);
- rq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma + IGPOFF);
- rq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma + IGPOFF);
+ rq->snscb_addr[RQRSP_ADDR0015] = DMA_WD0(fcp->isp_scdma);
+ rq->snscb_addr[RQRSP_ADDR1631] = DMA_WD1(fcp->isp_scdma);
+ rq->snscb_addr[RQRSP_ADDR3247] = DMA_WD2(fcp->isp_scdma);
+ rq->snscb_addr[RQRSP_ADDR4863] = DMA_WD3(fcp->isp_scdma);
rq->snscb_sblen = 6;
rq->snscb_cmd = SNS_GID_FT;
rq->snscb_mword_div_2 = NGENT;
rq->snscb_fc4_type = FC4_SCSI;
isp_put_gid_ft_request(isp, rq, (sns_gid_ft_req_t *)&scp[CTXOFF]);
- MEMORYBARRIER(isp, SYNC_SFORDEV, 0, SNS_GID_FT_REQ_SIZE, chan);
+ MEMORYBARRIER(isp, SYNC_SFORDEV, CTXOFF, SNS_GID_FT_REQ_SIZE, chan);
MBSINIT(&mbs, MBOX_SEND_SNS, MBLOGALL, 10000000);
mbs.param[0] = MBOX_SEND_SNS;
@@ -3337,6 +3484,12 @@ isp_gid_ft_sns(ispsoftc_t *isp, int chan)
return (-1);
}
}
+ MEMORYBARRIER(isp, SYNC_SFORCPU, 0, GIDLEN, chan);
+ if (isp->isp_dblev & ISP_LOGDEBUG1)
+ isp_print_bytes(isp, "CT response", GIDLEN, scp);
+ isp_get_gid_ft_response(isp, (sns_gid_ft_rsp_t *)scp,
+ (sns_gid_ft_rsp_t *)fcp->isp_scanscratch, NGENT);
+ FC_SCRATCH_RELEASE(isp, chan);
return (0);
}
@@ -3355,7 +3508,11 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan)
uint32_t *rp;
uint8_t *scp = fcp->isp_scratch;
- isp_prt(isp, ISP_LOGDEBUG0, "Chan %d scanning fabric (GID_FT) via CT", chan);
+ isp_prt(isp, ISP_LOGDEBUG0, "Chan %d requesting GID_FT via CT", chan);
+ if (FC_SCRATCH_ACQUIRE(isp, chan)) {
+ isp_prt(isp, ISP_LOGERR, sacq);
+ return (-1);
+ }
/*
* Build a Passthrough IOCB in memory.
@@ -3368,15 +3525,15 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan)
pt->ctp_nphdl = fcp->isp_sns_hdl;
pt->ctp_cmd_cnt = 1;
pt->ctp_vpidx = ISP_GET_VPIDX(isp, chan);
- pt->ctp_time = 30;
+ pt->ctp_time = 10;
pt->ctp_rsp_cnt = 1;
pt->ctp_rsp_bcnt = GIDLEN;
pt->ctp_cmd_bcnt = sizeof (*ct) + sizeof (uint32_t);
pt->ctp_dataseg[0].ds_base = DMA_LO32(fcp->isp_scdma+XTXOFF);
pt->ctp_dataseg[0].ds_basehi = DMA_HI32(fcp->isp_scdma+XTXOFF);
pt->ctp_dataseg[0].ds_count = sizeof (*ct) + sizeof (uint32_t);
- pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma+IGPOFF);
- pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF);
+ pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma);
+ pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma);
pt->ctp_dataseg[1].ds_count = GIDLEN;
if (isp->isp_dblev & ISP_LOGDEBUG1) {
isp_print_bytes(isp, "ct IOCB", QENTRY_LEN, pt);
@@ -3404,7 +3561,8 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan)
sizeof (*ct) + sizeof (uint32_t), &scp[XTXOFF]);
}
ISP_MEMZERO(&scp[ZTXOFF], QENTRY_LEN);
- MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 500000);
+ MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL,
+ MBCMD_DEFAULT_TIMEOUT + pt->ctp_time * 1000000);
mbs.param[1] = QENTRY_LEN;
mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF);
mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF);
@@ -3415,7 +3573,7 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan)
if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
return (-1);
}
- MEMORYBARRIER(isp, SYNC_SFORCPU, ZTXOFF, QENTRY_LEN, chan);
+ MEMORYBARRIER(isp, SYNC_SFORCPU, 0, ISP_FC_SCRLEN, chan);
pt = &un.plocal;
isp_get_ct_pt(isp, (isp_ct_pt_t *) &scp[ZTXOFF], pt);
if (isp->isp_dblev & ISP_LOGDEBUG1) {
@@ -3424,14 +3582,15 @@ isp_gid_ft_ct_passthru(ispsoftc_t *isp, int chan)
if (pt->ctp_status && pt->ctp_status != RQCS_DATA_UNDERRUN) {
isp_prt(isp, ISP_LOGWARN,
- "Chan %d ISP GID FT CT Passthrough returned 0x%x",
+ "Chan %d GID_FT CT Passthrough returned 0x%x",
chan, pt->ctp_status);
return (-1);
}
- MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN, chan);
- if (isp->isp_dblev & ISP_LOGDEBUG1) {
- isp_print_bytes(isp, "CT response", GIDLEN, &scp[IGPOFF]);
- }
+ if (isp->isp_dblev & ISP_LOGDEBUG1)
+ isp_print_bytes(isp, "CT response", GIDLEN, scp);
+ isp_get_gid_ft_response(isp, (sns_gid_ft_rsp_t *)scp,
+ (sns_gid_ft_rsp_t *)fcp->isp_scanscratch, NGENT);
+ FC_SCRATCH_RELEASE(isp, chan);
return (0);
}
@@ -3444,7 +3603,7 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
uint16_t nphdl;
isp_pdb_t pdb;
int portidx, portlim, r;
- sns_gid_ft_rsp_t *rs0, *rs1;
+ sns_gid_ft_rsp_t *rs;
if (fcp->isp_loopstate < LOOP_LSCAN_DONE)
return (-1);
@@ -3460,13 +3619,6 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
return (0);
}
- if (FC_SCRATCH_ACQUIRE(isp, chan)) {
- isp_prt(isp, ISP_LOGERR, sacq);
-fail:
- isp_prt(isp, ISP_LOG_SANCFG,
- "Chan %d FC fabric scan done (bad)", chan);
- return (-1);
- }
if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC) {
abort:
FC_SCRATCH_RELEASE(isp, chan);
@@ -3479,14 +3631,16 @@ abort:
* Make sure we still are logged into the fabric controller.
*/
nphdl = IS_24XX(isp) ? NPH_FL_ID : FL_ID;
- r = isp_getpdb(isp, chan, nphdl, &pdb, 0);
+ r = isp_getpdb(isp, chan, nphdl, &pdb);
if ((r & 0xffff) == MBOX_NOT_LOGGED_IN) {
- isp_dump_chip_portdb(isp, chan, 0);
+ isp_dump_chip_portdb(isp, chan);
}
if (r) {
fcp->isp_loopstate = LOOP_LTEST_DONE;
- FC_SCRATCH_RELEASE(isp, chan);
- goto fail;
+fail:
+ isp_prt(isp, ISP_LOG_SANCFG,
+ "Chan %d FC fabric scan done (bad)", chan);
+ return (-1);
}
/* Get list of port IDs from SNS. */
@@ -3498,42 +3652,36 @@ abort:
goto abort;
if (r > 0) {
fcp->isp_loopstate = LOOP_FSCAN_DONE;
- FC_SCRATCH_RELEASE(isp, chan);
return (-1);
} else if (r < 0) {
fcp->isp_loopstate = LOOP_LTEST_DONE; /* try again */
- FC_SCRATCH_RELEASE(isp, chan);
return (-1);
}
- MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN, chan);
- rs0 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+IGPOFF);
- rs1 = (sns_gid_ft_rsp_t *) ((uint8_t *)fcp->isp_scratch+OGPOFF);
- isp_get_gid_ft_response(isp, rs0, rs1, NGENT);
+ rs = (sns_gid_ft_rsp_t *) fcp->isp_scanscratch;
if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC)
goto abort;
- if (rs1->snscb_cthdr.ct_cmd_resp != LS_ACC) {
+ if (rs->snscb_cthdr.ct_cmd_resp != LS_ACC) {
int level;
- if (rs1->snscb_cthdr.ct_reason == 9 && rs1->snscb_cthdr.ct_explanation == 7) {
+ if (rs->snscb_cthdr.ct_reason == 9 && rs->snscb_cthdr.ct_explanation == 7) {
level = ISP_LOG_SANCFG;
} else {
level = ISP_LOGWARN;
}
isp_prt(isp, level, "Chan %d Fabric Nameserver rejected GID_FT"
" (Reason=0x%x Expl=0x%x)", chan,
- rs1->snscb_cthdr.ct_reason,
- rs1->snscb_cthdr.ct_explanation);
- FC_SCRATCH_RELEASE(isp, chan);
+ rs->snscb_cthdr.ct_reason,
+ rs->snscb_cthdr.ct_explanation);
fcp->isp_loopstate = LOOP_FSCAN_DONE;
return (-1);
}
/* Check our buffer was big enough to get the full list. */
for (portidx = 0; portidx < NGENT-1; portidx++) {
- if (rs1->snscb_ports[portidx].control & 0x80)
+ if (rs->snscb_ports[portidx].control & 0x80)
break;
}
- if ((rs1->snscb_ports[portidx].control & 0x80) == 0) {
+ if ((rs->snscb_ports[portidx].control & 0x80) == 0) {
isp_prt(isp, ISP_LOGWARN,
"fabric too big for scratch area: increase ISP_FC_SCRLEN");
}
@@ -3546,24 +3694,24 @@ abort:
int npidx;
portid =
- ((rs1->snscb_ports[portidx].portid[0]) << 16) |
- ((rs1->snscb_ports[portidx].portid[1]) << 8) |
- ((rs1->snscb_ports[portidx].portid[2]));
+ ((rs->snscb_ports[portidx].portid[0]) << 16) |
+ ((rs->snscb_ports[portidx].portid[1]) << 8) |
+ ((rs->snscb_ports[portidx].portid[2]));
for (npidx = portidx + 1; npidx < portlim; npidx++) {
uint32_t new_portid =
- ((rs1->snscb_ports[npidx].portid[0]) << 16) |
- ((rs1->snscb_ports[npidx].portid[1]) << 8) |
- ((rs1->snscb_ports[npidx].portid[2]));
+ ((rs->snscb_ports[npidx].portid[0]) << 16) |
+ ((rs->snscb_ports[npidx].portid[1]) << 8) |
+ ((rs->snscb_ports[npidx].portid[2]));
if (new_portid == portid) {
break;
}
}
if (npidx < portlim) {
- rs1->snscb_ports[npidx].portid[0] = 0;
- rs1->snscb_ports[npidx].portid[1] = 0;
- rs1->snscb_ports[npidx].portid[2] = 0;
+ rs->snscb_ports[npidx].portid[0] = 0;
+ rs->snscb_ports[npidx].portid[1] = 0;
+ rs->snscb_ports[npidx].portid[2] = 0;
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d removing duplicate PortID 0x%06x entry from list", chan, portid);
}
}
@@ -3584,9 +3732,9 @@ abort:
*/
isp_mark_portdb(isp, chan);
for (portidx = 0; portidx < portlim; portidx++) {
- portid = ((rs1->snscb_ports[portidx].portid[0]) << 16) |
- ((rs1->snscb_ports[portidx].portid[1]) << 8) |
- ((rs1->snscb_ports[portidx].portid[2]));
+ portid = ((rs->snscb_ports[portidx].portid[0]) << 16) |
+ ((rs->snscb_ports[portidx].portid[1]) << 8) |
+ ((rs->snscb_ports[portidx].portid[2]));
isp_prt(isp, ISP_LOG_SANCFG,
"Chan %d Checking fabric port 0x%06x", chan, portid);
if (portid == 0) {
@@ -3608,7 +3756,6 @@ abort:
"Chan %d Port 0x%06x@0x%04x [%d] is not probational (0x%x)",
chan, lp->portid, lp->handle,
FC_PORTDB_TGT(isp, chan, lp), lp->state);
- FC_SCRATCH_RELEASE(isp, chan);
isp_dump_portdb(isp, chan);
goto fail;
}
@@ -3628,7 +3775,7 @@ abort:
* database entry for somebody further along to
* decide what to do (policy choice).
*/
- r = isp_getpdb(isp, chan, lp->handle, &pdb, 0);
+ r = isp_getpdb(isp, chan, lp->handle, &pdb);
if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC)
goto abort;
if (r != 0) {
@@ -3662,7 +3809,6 @@ relogin:
if (fcp->isp_loopstate < LOOP_SCANNING_FABRIC)
goto abort;
- FC_SCRATCH_RELEASE(isp, chan);
fcp->isp_loopstate = LOOP_FSCAN_DONE;
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC fabric scan done", chan);
return (0);
@@ -3689,7 +3835,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint1
return (-1);
/* Check if this handle is free. */
- r = isp_getpdb(isp, chan, handle, p, 0);
+ r = isp_getpdb(isp, chan, handle, p);
if (r == 0) {
if (p->portid != portid) {
/* This handle is busy, try next one. */
@@ -3704,7 +3850,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint1
/*
* Now try and log into the device
*/
- r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1);
+ r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI);
if (r == 0) {
break;
} else if ((r & 0xffff) == MBOX_PORT_ID_USED) {
@@ -3713,12 +3859,12 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint1
* handle. We need to break that association. We used to try and just substitute the handle, but then
* failed to get any data via isp_getpdb (below).
*/
- if (isp_plogx(isp, chan, r >> 16, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL, 1)) {
+ if (isp_plogx(isp, chan, r >> 16, portid, PLOGX_FLG_CMD_LOGO | PLOGX_FLG_IMPLICIT | PLOGX_FLG_FREE_NPHDL)) {
isp_prt(isp, ISP_LOGERR, "baw... logout of %x failed", r >> 16);
}
if (FCPARAM(isp, chan)->isp_loopstate != LOOP_SCANNING_FABRIC)
return (-1);
- r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI, 1);
+ r = isp_plogx(isp, chan, handle, portid, PLOGX_FLG_CMD_PLOGI);
if (r != 0)
i = lim;
break;
@@ -3742,7 +3888,7 @@ isp_login_device(ispsoftc_t *isp, int chan, uint32_t portid, isp_pdb_t *p, uint1
* so we can crosscheck that it is still what we think it
* is and that we also have the role it plays
*/
- r = isp_getpdb(isp, chan, handle, p, 0);
+ r = isp_getpdb(isp, chan, handle, p);
if (r != 0) {
isp_prt(isp, ISP_LOGERR, "Chan %d new device 0x%06x@0x%x disappeared", chan, portid, handle);
return (-1);
@@ -3839,15 +3985,15 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp, int chan)
pt->ctp_nphdl = fcp->isp_sns_hdl;
pt->ctp_cmd_cnt = 1;
pt->ctp_vpidx = ISP_GET_VPIDX(isp, chan);
- pt->ctp_time = 1;
+ pt->ctp_time = 4;
pt->ctp_rsp_cnt = 1;
pt->ctp_rsp_bcnt = sizeof (ct_hdr_t);
pt->ctp_cmd_bcnt = sizeof (rft_id_t);
pt->ctp_dataseg[0].ds_base = DMA_LO32(fcp->isp_scdma+XTXOFF);
pt->ctp_dataseg[0].ds_basehi = DMA_HI32(fcp->isp_scdma+XTXOFF);
pt->ctp_dataseg[0].ds_count = sizeof (rft_id_t);
- pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma+IGPOFF);
- pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF);
+ pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma);
+ pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma);
pt->ctp_dataseg[1].ds_count = sizeof (ct_hdr_t);
isp_put_ct_pt(isp, pt, (isp_ct_pt_t *) &scp[CTXOFF]);
if (isp->isp_dblev & ISP_LOGDEBUG1) {
@@ -3878,7 +4024,8 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp, int chan)
ISP_MEMZERO(&scp[ZTXOFF], sizeof (ct_hdr_t));
- MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 1000000);
+ MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL,
+ MBCMD_DEFAULT_TIMEOUT + pt->ctp_time * 1000000);
mbs.param[1] = QENTRY_LEN;
mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF);
mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF);
@@ -3904,7 +4051,7 @@ isp_register_fc4_type_24xx(ispsoftc_t *isp, int chan)
return (1);
}
- isp_get_ct_hdr(isp, (ct_hdr_t *) &scp[IGPOFF], ct);
+ isp_get_ct_hdr(isp, (ct_hdr_t *) scp, ct);
FC_SCRATCH_RELEASE(isp, chan);
if (ct->ct_cmd_resp == LS_RJT) {
@@ -3950,15 +4097,15 @@ isp_register_fc4_features_24xx(ispsoftc_t *isp, int chan)
pt->ctp_nphdl = fcp->isp_sns_hdl;
pt->ctp_cmd_cnt = 1;
pt->ctp_vpidx = ISP_GET_VPIDX(isp, chan);
- pt->ctp_time = 1;
+ pt->ctp_time = 4;
pt->ctp_rsp_cnt = 1;
pt->ctp_rsp_bcnt = sizeof (ct_hdr_t);
pt->ctp_cmd_bcnt = sizeof (rff_id_t);
pt->ctp_dataseg[0].ds_base = DMA_LO32(fcp->isp_scdma+XTXOFF);
pt->ctp_dataseg[0].ds_basehi = DMA_HI32(fcp->isp_scdma+XTXOFF);
pt->ctp_dataseg[0].ds_count = sizeof (rff_id_t);
- pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma+IGPOFF);
- pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma+IGPOFF);
+ pt->ctp_dataseg[1].ds_base = DMA_LO32(fcp->isp_scdma);
+ pt->ctp_dataseg[1].ds_basehi = DMA_HI32(fcp->isp_scdma);
pt->ctp_dataseg[1].ds_count = sizeof (ct_hdr_t);
isp_put_ct_pt(isp, pt, (isp_ct_pt_t *) &scp[CTXOFF]);
if (isp->isp_dblev & ISP_LOGDEBUG1) {
@@ -3994,7 +4141,8 @@ isp_register_fc4_features_24xx(ispsoftc_t *isp, int chan)
ISP_MEMZERO(&scp[ZTXOFF], sizeof (ct_hdr_t));
- MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 1000000);
+ MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL,
+ MBCMD_DEFAULT_TIMEOUT + pt->ctp_time * 1000000);
mbs.param[1] = QENTRY_LEN;
mbs.param[2] = DMA_WD1(fcp->isp_scdma + CTXOFF);
mbs.param[3] = DMA_WD0(fcp->isp_scdma + CTXOFF);
@@ -4020,7 +4168,7 @@ isp_register_fc4_features_24xx(ispsoftc_t *isp, int chan)
return (1);
}
- isp_get_ct_hdr(isp, (ct_hdr_t *) &scp[IGPOFF], ct);
+ isp_get_ct_hdr(isp, (ct_hdr_t *) scp, ct);
FC_SCRATCH_RELEASE(isp, chan);
if (ct->ct_cmd_resp == LS_RJT) {
@@ -4090,7 +4238,7 @@ int
isp_start(XS_T *xs)
{
ispsoftc_t *isp;
- uint32_t handle, cdblen;
+ uint32_t cdblen;
uint8_t local[QENTRY_LEN];
ispreq_t *reqp;
void *cdbp, *qep;
@@ -4381,21 +4529,18 @@ isp_start(XS_T *xs)
}
ISP_MEMCPY(cdbp, XS_CDBP(xs), cdblen);
- *tptr = XS_TIME(xs) / 1000;
- if (*tptr == 0 && XS_TIME(xs)) {
- *tptr = 1;
- }
+ *tptr = (XS_TIME(xs) + 999) / 1000;
if (IS_24XX(isp) && *tptr > 0x1999) {
*tptr = 0x1999;
}
- if (isp_allocate_xs(isp, xs, &handle)) {
+ /* Whew. Thankfully the same for type 7 requests */
+ reqp->req_handle = isp_allocate_handle(isp, xs, ISP_HANDLE_INITIATOR);
+ if (reqp->req_handle == 0) {
isp_prt(isp, ISP_LOG_WARN1, "out of xflist pointers");
XS_SETERR(xs, HBA_BOTCH);
return (CMD_EAGAIN);
}
- /* Whew. Thankfully the same for type 7 requests */
- reqp->req_handle = handle;
/*
* Set up DMA and/or do any platform dependent swizzling of the request entry
@@ -4405,7 +4550,7 @@ isp_start(XS_T *xs)
*/
dmaresult = ISP_DMASETUP(isp, xs, reqp);
if (dmaresult != CMD_QUEUED) {
- isp_destroy_handle(isp, handle);
+ isp_destroy_handle(isp, reqp->req_handle);
/*
* dmasetup sets actual error in packet, and
* return what we were given to return.
@@ -4490,13 +4635,14 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, ...)
tmf->tmf_header.rqs_entry_count = 1;
tmf->tmf_nphdl = lp->handle;
tmf->tmf_delay = 2;
- tmf->tmf_timeout = 2;
+ tmf->tmf_timeout = 4;
tmf->tmf_flags = ISP24XX_TMF_TARGET_RESET;
tmf->tmf_tidlo = lp->portid;
tmf->tmf_tidhi = lp->portid >> 16;
tmf->tmf_vpidx = ISP_GET_VPIDX(isp, chan);
isp_prt(isp, ISP_LOGALL, "Chan %d Reset N-Port Handle 0x%04x @ Port 0x%06x", chan, lp->handle, lp->portid);
- MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000);
+ MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL,
+ MBCMD_DEFAULT_TIMEOUT + tmf->tmf_timeout * 1000000);
mbs.param[1] = QENTRY_LEN;
mbs.param[2] = DMA_WD1(fcp->isp_scdma);
mbs.param[3] = DMA_WD0(fcp->isp_scdma);
@@ -4710,7 +4856,7 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, ...)
tgt = va_arg(ap, int);
pdb = va_arg(ap, isp_pdb_t *);
va_end(ap);
- return (isp_getpdb(isp, chan, tgt, pdb, 1));
+ return (isp_getpdb(isp, chan, tgt, pdb));
}
break;
@@ -4758,11 +4904,11 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, ...)
va_end(ap);
if ((p->flags & PLOGX_FLG_CMD_MASK) != PLOGX_FLG_CMD_PLOGI || (p->handle != NIL_HANDLE)) {
- return (isp_plogx(isp, p->channel, p->handle, p->portid, p->flags, 0));
+ return (isp_plogx(isp, p->channel, p->handle, p->portid, p->flags));
}
do {
isp_next_handle(isp, &p->handle);
- r = isp_plogx(isp, p->channel, p->handle, p->portid, p->flags, 0);
+ r = isp_plogx(isp, p->channel, p->handle, p->portid, p->flags);
if ((r & 0xffff) == MBOX_PORT_ID_USED) {
p->handle = r >> 16;
r = 0;
@@ -5133,12 +5279,6 @@ again:
}
}
- if (!ISP_VALID_HANDLE(isp, sp->req_handle)) {
- isp_prt(isp, ISP_LOGERR, "bad request handle 0x%x (iocb type 0x%x)", sp->req_handle, etype);
- ISP_MEMZERO(hp, QENTRY_LEN); /* PERF */
- last_etype = etype;
- continue;
- }
xs = isp_find_xs(isp, sp->req_handle);
if (xs == NULL) {
uint8_t ts = completion_status & 0xff;
@@ -5952,6 +6092,8 @@ isp_handle_other_response(ispsoftc_t *isp, int type, isphdr_t *hp, uint32_t *opt
{
isp_ridacq_t rid;
int chan, c;
+ uint32_t hdl;
+ void *ptr;
switch (type) {
case RQSTYPE_STATUS_CONT:
@@ -5993,6 +6135,17 @@ isp_handle_other_response(ispsoftc_t *isp, int type, isphdr_t *hp, uint32_t *opt
}
}
return (1);
+ case RQSTYPE_VP_MODIFY:
+ case RQSTYPE_VP_CTRL:
+ case RQSTYPE_LOGIN:
+ ISP_IOXGET_32(isp, (uint32_t *)(hp + 1), hdl);
+ ptr = isp_find_xs(isp, hdl);
+ if (ptr != NULL) {
+ isp_destroy_handle(isp, hdl);
+ memcpy(ptr, hp, QENTRY_LEN);
+ wakeup(ptr);
+ }
+ return (1);
case RQSTYPE_ATIO:
case RQSTYPE_CTIO:
case RQSTYPE_ENABLE_LUN:
@@ -6879,7 +7032,7 @@ static const uint32_t mbpfc[] = {
ISP_FC_OPMAP(0x01, 0x07), /* 0x1f: MBOX_GET_FIRMWARE_STATUS */
ISP_FC_OPMAP_HALF(0x2, 0x01, 0x7e, 0xcf), /* 0x20: MBOX_GET_LOOP_ID */
ISP_FC_OPMAP(0x00, 0x00), /* 0x21: */
- ISP_FC_OPMAP(0x01, 0x07), /* 0x22: MBOX_GET_RETRY_COUNT */
+ ISP_FC_OPMAP(0x03, 0x4b), /* 0x22: MBOX_GET_TIMEOUT_PARAMS */
ISP_FC_OPMAP(0x00, 0x00), /* 0x23: */
ISP_FC_OPMAP(0x00, 0x00), /* 0x24: */
ISP_FC_OPMAP(0x00, 0x00), /* 0x25: */
@@ -6895,7 +7048,7 @@ static const uint32_t mbpfc[] = {
ISP_FC_OPMAP(0x00, 0x00), /* 0x2f: */
ISP_FC_OPMAP(0x00, 0x00), /* 0x30: */
ISP_FC_OPMAP(0x00, 0x00), /* 0x31: */
- ISP_FC_OPMAP(0x07, 0x07), /* 0x32: MBOX_SET_RETRY_COUNT */
+ ISP_FC_OPMAP(0x4b, 0x4b), /* 0x32: MBOX_SET_TIMEOUT_PARAMS */
ISP_FC_OPMAP(0x00, 0x00), /* 0x33: */
ISP_FC_OPMAP(0x00, 0x00), /* 0x34: */
ISP_FC_OPMAP(0x00, 0x00), /* 0x35: */
@@ -7632,6 +7785,7 @@ isp_setdfltfcparm(ispsoftc_t *isp, int chan)
fcp->isp_fwoptions |= ICB2400_OPT1_FULL_DUPLEX;
}
fcp->isp_fwoptions |= ICB2400_OPT1_BOTH_WWNS;
+ fcp->isp_zfwoptions |= ICB2400_OPT3_RATE_AUTO;
} else {
fcp->isp_fwoptions |= ICBOPT_FAIRNESS;
fcp->isp_fwoptions |= ICBOPT_PDBCHANGE_AE;
@@ -7644,6 +7798,7 @@ isp_setdfltfcparm(ispsoftc_t *isp, int chan)
* extended options from NVRAM
*/
fcp->isp_fwoptions &= ~ICBOPT_EXTENDED;
+ fcp->isp_zfwoptions |= ICBZOPT_RATE_AUTO;
}
diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c
index c533d69..cbf1262 100644
--- a/sys/dev/isp/isp_freebsd.c
+++ b/sys/dev/isp/isp_freebsd.c
@@ -632,7 +632,7 @@ ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td)
tmf->tmf_header.rqs_entry_count = 1;
tmf->tmf_nphdl = lp->handle;
tmf->tmf_delay = 2;
- tmf->tmf_timeout = 2;
+ tmf->tmf_timeout = 4;
tmf->tmf_tidlo = lp->portid;
tmf->tmf_tidhi = lp->portid >> 16;
tmf->tmf_vpidx = ISP_GET_VPIDX(isp, chan);
@@ -668,7 +668,8 @@ ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td)
ISP_UNLOCK(isp);
break;
}
- MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 5000000);
+ MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL,
+ MBCMD_DEFAULT_TIMEOUT + tmf->tmf_timeout * 1000000);
mbs.param[1] = QENTRY_LEN;
mbs.param[2] = DMA_WD1(fcp->isp_scdma);
mbs.param[3] = DMA_WD0(fcp->isp_scdma);
@@ -1403,7 +1404,7 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how)
cto->ct_iid_hi = atp->portid >> 16;
cto->ct_oxid = atp->oxid;
cto->ct_vpidx = ISP_GET_VPIDX(isp, XS_CHANNEL(ccb));
- cto->ct_timeout = 120;
+ cto->ct_timeout = (XS_TIME(ccb) + 999) / 1000;
cto->ct_flags = atp->tattr << CT7_TASK_ATTR_SHIFT;
/*
@@ -1555,7 +1556,7 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how)
cto->ct_lun = ccb->ccb_h.target_lun;
}
}
- cto->ct_timeout = 10;
+ cto->ct_timeout = (XS_TIME(ccb) + 999) / 1000;
cto->ct_rxid = cso->tag_id;
/*
@@ -1693,7 +1694,8 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how)
TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe);
break;
}
- if (isp_allocate_xs_tgt(isp, ccb, &handle)) {
+ handle = isp_allocate_handle(isp, ccb, ISP_HANDLE_TARGET);
+ if (handle == 0) {
ISP_PATH_PRT(isp, ISP_LOGWARN, ccb->ccb_h.path, "No XFLIST pointers for %s\n", __func__);
TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe);
isp_free_pcmd(isp, ccb);
@@ -1722,7 +1724,7 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how)
dmaresult = ISP_DMASETUP(isp, cso, (ispreq_t *) local);
if (dmaresult != CMD_QUEUED) {
- isp_destroy_tgt_handle(isp, handle);
+ isp_destroy_handle(isp, handle);
isp_free_pcmd(isp, ccb);
if (dmaresult == CMD_EAGAIN) {
TAILQ_INSERT_HEAD(&tptr->waitq, &ccb->ccb_h, periph_links.tqe);
@@ -2379,12 +2381,12 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
uint32_t handle, moved_data = 0, data_requested;
handle = ((ct2_entry_t *)arg)->ct_syshandle;
- ccb = isp_find_xs_tgt(isp, handle);
+ ccb = isp_find_xs(isp, handle);
if (ccb == NULL) {
isp_print_bytes(isp, "null ccb in isp_handle_platform_ctio", QENTRY_LEN, arg);
return;
}
- isp_destroy_tgt_handle(isp, handle);
+ isp_destroy_handle(isp, handle);
data_requested = PISP_PCMD(ccb)->datalen;
isp_free_pcmd(isp, ccb);
if (isp->isp_nactive) {
@@ -3320,7 +3322,7 @@ isp_loop_dead(ispsoftc_t *isp, int chan)
for (i = 0; i < isp->isp_maxcmds; i++) {
struct ccb_scsiio *xs;
- if (!ISP_VALID_HANDLE(isp, isp->isp_xflist[i].handle)) {
+ if (ISP_H2HT(isp->isp_xflist[i].handle) != ISP_HANDLE_INITIATOR) {
continue;
}
if ((xs = isp->isp_xflist[i].cmd) == NULL) {
diff --git a/sys/dev/isp/isp_freebsd.h b/sys/dev/isp/isp_freebsd.h
index 9a9093a..7702ee6 100644
--- a/sys/dev/isp/isp_freebsd.h
+++ b/sys/dev/isp/isp_freebsd.h
@@ -225,8 +225,7 @@ struct isp_fc {
struct cam_path *path;
struct ispsoftc *isp;
struct proc *kproc;
- bus_dma_tag_t tdmat;
- bus_dmamap_t tdmap;
+ bus_dmamap_t scmap;
uint64_t def_wwpn;
uint64_t def_wwnn;
time_t loop_down_time;
@@ -285,13 +284,18 @@ struct isposinfo {
const struct firmware * fw;
/*
- * DMA related sdtuff
+ * DMA related stuff
*/
struct resource * regs;
struct resource * regs2;
bus_dma_tag_t dmat;
- bus_dma_tag_t cdmat;
- bus_dmamap_t cdmap;
+ bus_dma_tag_t reqdmat;
+ bus_dma_tag_t respdmat;
+ bus_dma_tag_t atiodmat;
+ bus_dma_tag_t scdmat;
+ bus_dmamap_t reqmap;
+ bus_dmamap_t respmap;
+ bus_dmamap_t atiomap;
/*
* Command and transaction related related stuff
@@ -406,62 +410,60 @@ struct isposinfo {
#define MEMORYBARRIER(isp, type, offset, size, chan) \
switch (type) { \
+case SYNC_REQUEST: \
+ bus_dmamap_sync(isp->isp_osinfo.reqdmat, \
+ isp->isp_osinfo.reqmap, BUS_DMASYNC_PREWRITE); \
+ break; \
+case SYNC_RESULT: \
+ bus_dmamap_sync(isp->isp_osinfo.respdmat, \
+ isp->isp_osinfo.respmap, BUS_DMASYNC_POSTREAD); \
+ break; \
case SYNC_SFORDEV: \
{ \
struct isp_fc *fc = ISP_FC_PC(isp, chan); \
- bus_dmamap_sync(fc->tdmat, fc->tdmap, \
+ bus_dmamap_sync(isp->isp_osinfo.scdmat, fc->scmap, \
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); \
break; \
} \
-case SYNC_REQUEST: \
- bus_dmamap_sync(isp->isp_osinfo.cdmat, \
- isp->isp_osinfo.cdmap, \
- BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); \
- break; \
case SYNC_SFORCPU: \
{ \
struct isp_fc *fc = ISP_FC_PC(isp, chan); \
- bus_dmamap_sync(fc->tdmat, fc->tdmap, \
+ bus_dmamap_sync(isp->isp_osinfo.scdmat, fc->scmap, \
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); \
break; \
} \
-case SYNC_RESULT: \
- bus_dmamap_sync(isp->isp_osinfo.cdmat, \
- isp->isp_osinfo.cdmap, \
- BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); \
- break; \
case SYNC_REG: \
bus_barrier(isp->isp_osinfo.regs, offset, size, \
BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); \
break; \
+case SYNC_ATIOQ: \
+ bus_dmamap_sync(isp->isp_osinfo.atiodmat, \
+ isp->isp_osinfo.atiomap, BUS_DMASYNC_POSTREAD); \
+ break; \
default: \
break; \
}
#define MEMORYBARRIERW(isp, type, offset, size, chan) \
switch (type) { \
+case SYNC_REQUEST: \
+ bus_dmamap_sync(isp->isp_osinfo.reqdmat, \
+ isp->isp_osinfo.reqmap, BUS_DMASYNC_PREWRITE); \
+ break; \
case SYNC_SFORDEV: \
{ \
struct isp_fc *fc = ISP_FC_PC(isp, chan); \
- bus_dmamap_sync(fc->tdmat, fc->tdmap, \
+ bus_dmamap_sync(isp->isp_osinfo.scdmat, fc->scmap, \
BUS_DMASYNC_PREWRITE); \
break; \
} \
-case SYNC_REQUEST: \
- bus_dmamap_sync(isp->isp_osinfo.cdmat, \
- isp->isp_osinfo.cdmap, BUS_DMASYNC_PREWRITE); \
- break; \
case SYNC_SFORCPU: \
{ \
struct isp_fc *fc = ISP_FC_PC(isp, chan); \
- bus_dmamap_sync(fc->tdmat, fc->tdmap, \
+ bus_dmamap_sync(isp->isp_osinfo.scdmat, fc->scmap, \
BUS_DMASYNC_POSTWRITE); \
break; \
} \
-case SYNC_RESULT: \
- bus_dmamap_sync(isp->isp_osinfo.cdmat, \
- isp->isp_osinfo.cdmap, BUS_DMASYNC_POSTWRITE); \
- break; \
case SYNC_REG: \
bus_barrier(isp->isp_osinfo.regs, offset, size, \
BUS_SPACE_BARRIER_WRITE); \
diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c
index ec99244..78c7f6f 100644
--- a/sys/dev/isp/isp_library.c
+++ b/sys/dev/isp/isp_library.c
@@ -247,28 +247,26 @@ copy_and_sync:
return (CMD_QUEUED);
}
-int
-isp_allocate_xs(ispsoftc_t *isp, XS_T *xs, uint32_t *handlep)
+uint32_t
+isp_allocate_handle(ispsoftc_t *isp, void *xs, int type)
{
isp_hdl_t *hdp;
hdp = isp->isp_xffree;
- if (hdp == NULL) {
- return (-1);
- }
+ if (hdp == NULL)
+ return (ISP_HANDLE_FREE);
isp->isp_xffree = hdp->cmd;
hdp->cmd = xs;
hdp->handle = (hdp - isp->isp_xflist);
- hdp->handle |= (ISP_HANDLE_INITIATOR << ISP_HANDLE_USAGE_SHIFT);
+ hdp->handle |= (type << ISP_HANDLE_USAGE_SHIFT);
hdp->handle |= (isp->isp_seqno++ << ISP_HANDLE_SEQ_SHIFT);
- *handlep = hdp->handle;
- return (0);
+ return (hdp->handle);
}
-XS_T *
+void *
isp_find_xs(ispsoftc_t *isp, uint32_t handle)
{
- if (!ISP_VALID_INI_HANDLE(isp, handle)) {
+ if (!ISP_VALID_HANDLE(isp, handle)) {
isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle);
return (NULL);
}
@@ -276,7 +274,7 @@ isp_find_xs(ispsoftc_t *isp, uint32_t handle)
}
uint32_t
-isp_find_handle(ispsoftc_t *isp, XS_T *xs)
+isp_find_handle(ispsoftc_t *isp, void *xs)
{
uint32_t i, foundhdl = ISP_HANDLE_FREE;
@@ -292,21 +290,10 @@ isp_find_handle(ispsoftc_t *isp, XS_T *xs)
return (foundhdl);
}
-uint32_t
-isp_handle_index(ispsoftc_t *isp, uint32_t handle)
-{
- if (!ISP_VALID_HANDLE(isp, handle)) {
- isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle);
- return (ISP_BAD_HANDLE_INDEX);
- } else {
- return (handle & ISP_HANDLE_CMD_MASK);
- }
-}
-
void
isp_destroy_handle(ispsoftc_t *isp, uint32_t handle)
{
- if (!ISP_VALID_INI_HANDLE(isp, handle)) {
+ if (!ISP_VALID_HANDLE(isp, handle)) {
isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle);
} else {
isp->isp_xflist[(handle & ISP_HANDLE_CMD_MASK)].handle = ISP_HANDLE_FREE;
@@ -573,168 +560,6 @@ isp_fc_toponame(fcparam *fcp)
}
}
-static int
-isp_fc_enable_vp(ispsoftc_t *isp, int chan)
-{
- fcparam *fcp = FCPARAM(isp, chan);
- mbreg_t mbs;
- vp_modify_t *vp;
- uint8_t qe[QENTRY_LEN], *scp;
-
- ISP_MEMZERO(qe, QENTRY_LEN);
- if (FC_SCRATCH_ACQUIRE(isp, chan)) {
- return (EBUSY);
- }
- scp = fcp->isp_scratch;
-
- /*
- * Build a VP MODIFY command in memory
- */
- vp = (vp_modify_t *) qe;
- vp->vp_mod_hdr.rqs_entry_type = RQSTYPE_VP_MODIFY;
- vp->vp_mod_hdr.rqs_entry_count = 1;
- vp->vp_mod_cnt = 1;
- vp->vp_mod_idx0 = chan;
- vp->vp_mod_cmd = VP_MODIFY_ENA;
- vp->vp_mod_ports[0].options = ICB2400_VPOPT_ENABLED |
- ICB2400_VPOPT_ENA_SNSLOGIN;
- if (fcp->role & ISP_ROLE_INITIATOR) {
- vp->vp_mod_ports[0].options |= ICB2400_VPOPT_INI_ENABLE;
- }
- if ((fcp->role & ISP_ROLE_TARGET) == 0) {
- vp->vp_mod_ports[0].options |= ICB2400_VPOPT_TGT_DISABLE;
- }
- if (fcp->isp_loopid < LOCAL_LOOP_LIM) {
- vp->vp_mod_ports[0].loopid = fcp->isp_loopid;
- if (isp->isp_confopts & ISP_CFG_OWNLOOPID)
- vp->vp_mod_ports[0].options |=
- ICB2400_VPOPT_HARD_ADDRESS;
- else
- vp->vp_mod_ports[0].options |=
- ICB2400_VPOPT_PREV_ADDRESS;
- }
- MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwpn, fcp->isp_wwpn);
- MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwnn, fcp->isp_wwnn);
- isp_put_vp_modify(isp, vp, (vp_modify_t *) scp);
-
- /*
- * Build a EXEC IOCB A64 command that points to the VP MODIFY command
- */
- MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0);
- mbs.param[1] = QENTRY_LEN;
- mbs.param[2] = DMA_WD1(fcp->isp_scdma);
- mbs.param[3] = DMA_WD0(fcp->isp_scdma);
- mbs.param[6] = DMA_WD3(fcp->isp_scdma);
- mbs.param[7] = DMA_WD2(fcp->isp_scdma);
- MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan);
- isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
- if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- FC_SCRATCH_RELEASE(isp, chan);
- return (EIO);
- }
- MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan);
- isp_get_vp_modify(isp, (vp_modify_t *)&scp[QENTRY_LEN], vp);
-
- FC_SCRATCH_RELEASE(isp, chan);
-
- if (vp->vp_mod_status != VP_STS_OK) {
- isp_prt(isp, ISP_LOGERR, "%s: VP_MODIFY of Chan %d failed with status %d", __func__, chan, vp->vp_mod_status);
- return (EIO);
- }
- return (0);
-}
-
-static int
-isp_fc_disable_vp(ispsoftc_t *isp, int chan)
-{
- fcparam *fcp = FCPARAM(isp, chan);
- mbreg_t mbs;
- vp_ctrl_info_t *vp;
- uint8_t qe[QENTRY_LEN], *scp;
-
- ISP_MEMZERO(qe, QENTRY_LEN);
- if (FC_SCRATCH_ACQUIRE(isp, chan)) {
- return (EBUSY);
- }
- scp = fcp->isp_scratch;
-
- /*
- * Build a VP CTRL command in memory
- */
- vp = (vp_ctrl_info_t *) qe;
- vp->vp_ctrl_hdr.rqs_entry_type = RQSTYPE_VP_CTRL;
- vp->vp_ctrl_hdr.rqs_entry_count = 1;
- if (ISP_CAP_VP0(isp)) {
- vp->vp_ctrl_status = 1;
- } else {
- vp->vp_ctrl_status = 0;
- chan--; /* VP0 can not be controlled in this case. */
- }
- vp->vp_ctrl_command = VP_CTRL_CMD_DISABLE_VP_LOGO_ALL;
- vp->vp_ctrl_vp_count = 1;
- vp->vp_ctrl_idmap[chan / 16] |= (1 << chan % 16);
- isp_put_vp_ctrl_info(isp, vp, (vp_ctrl_info_t *) scp);
-
- /*
- * Build a EXEC IOCB A64 command that points to the VP CTRL command
- */
- MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0);
- mbs.param[1] = QENTRY_LEN;
- mbs.param[2] = DMA_WD1(fcp->isp_scdma);
- mbs.param[3] = DMA_WD0(fcp->isp_scdma);
- mbs.param[6] = DMA_WD3(fcp->isp_scdma);
- mbs.param[7] = DMA_WD2(fcp->isp_scdma);
- MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan);
- isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
- if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- FC_SCRATCH_RELEASE(isp, chan);
- return (EIO);
- }
- MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan);
- isp_get_vp_ctrl_info(isp, (vp_ctrl_info_t *)&scp[QENTRY_LEN], vp);
-
- FC_SCRATCH_RELEASE(isp, chan);
-
- if (vp->vp_ctrl_status != 0) {
- isp_prt(isp, ISP_LOGERR,
- "%s: VP_CTRL of Chan %d failed with status %d %d",
- __func__, chan, vp->vp_ctrl_status, vp->vp_ctrl_index_fail);
- return (EIO);
- }
- return (0);
-}
-
-/*
- * Change Roles
- */
-int
-isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role)
-{
- fcparam *fcp = FCPARAM(isp, chan);
- int i, was, res = 0;
-
- if (chan >= isp->isp_nchan) {
- isp_prt(isp, ISP_LOGWARN, "%s: bad channel %d", __func__, chan);
- return (ENXIO);
- }
- if (fcp->role == new_role)
- return (0);
- for (was = 0, i = 0; i < isp->isp_nchan; i++) {
- if (FCPARAM(isp, i)->role != ISP_ROLE_NONE)
- was++;
- }
- if (was == 0 || (was == 1 && fcp->role != ISP_ROLE_NONE)) {
- fcp->role = new_role;
- return (isp_reinit(isp, 0));
- }
- if (fcp->role != ISP_ROLE_NONE)
- res = isp_fc_disable_vp(isp, chan);
- fcp->role = new_role;
- if (fcp->role != ISP_ROLE_NONE)
- res = isp_fc_enable_vp(isp, chan);
- return (res);
-}
-
void
isp_clear_commands(ispsoftc_t *isp)
{
@@ -745,46 +570,49 @@ isp_clear_commands(ispsoftc_t *isp)
#endif
for (tmp = 0; isp->isp_xflist && tmp < isp->isp_maxcmds; tmp++) {
- XS_T *xs;
hdp = &isp->isp_xflist[tmp];
- if (hdp->handle == ISP_HANDLE_FREE) {
- continue;
- }
- xs = hdp->cmd;
- if (XS_XFRLEN(xs)) {
- ISP_DMAFREE(isp, xs, hdp->handle);
- XS_SET_RESID(xs, XS_XFRLEN(xs));
- } else {
- XS_SET_RESID(xs, 0);
+ switch (ISP_H2HT(hdp->handle)) {
+ case ISP_HANDLE_INITIATOR: {
+ XS_T *xs = hdp->cmd;
+ if (XS_XFRLEN(xs)) {
+ ISP_DMAFREE(isp, xs, hdp->handle);
+ XS_SET_RESID(xs, XS_XFRLEN(xs));
+ } else {
+ XS_SET_RESID(xs, 0);
+ }
+ isp_destroy_handle(isp, hdp->handle);
+ XS_SETERR(xs, HBA_BUSRESET);
+ isp_done(xs);
+ break;
}
- hdp->handle = 0;
- hdp->cmd = NULL;
- XS_SETERR(xs, HBA_BUSRESET);
- isp_done(xs);
- }
#ifdef ISP_TARGET_MODE
- for (tmp = 0; isp->isp_tgtlist && tmp < isp->isp_maxcmds; tmp++) {
- uint8_t local[QENTRY_LEN];
- hdp = &isp->isp_tgtlist[tmp];
- if (hdp->handle == ISP_HANDLE_FREE) {
- continue;
+ case ISP_HANDLE_TARGET: {
+ uint8_t local[QENTRY_LEN];
+ ISP_DMAFREE(isp, hdp->cmd, hdp->handle);
+ ISP_MEMZERO(local, QENTRY_LEN);
+ if (IS_24XX(isp)) {
+ ct7_entry_t *ctio = (ct7_entry_t *) local;
+ ctio->ct_syshandle = hdp->handle;
+ ctio->ct_nphdl = CT_HBA_RESET;
+ ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
+ } else {
+ ct2_entry_t *ctio = (ct2_entry_t *) local;
+ ctio->ct_syshandle = hdp->handle;
+ ctio->ct_status = CT_HBA_RESET;
+ ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
+ }
+ isp_async(isp, ISPASYNC_TARGET_ACTION, local);
+ break;
}
- ISP_DMAFREE(isp, hdp->cmd, hdp->handle);
- ISP_MEMZERO(local, QENTRY_LEN);
- if (IS_24XX(isp)) {
- ct7_entry_t *ctio = (ct7_entry_t *) local;
- ctio->ct_syshandle = hdp->handle;
- ctio->ct_nphdl = CT_HBA_RESET;
- ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
- } else {
- ct2_entry_t *ctio = (ct2_entry_t *) local;
- ctio->ct_syshandle = hdp->handle;
- ctio->ct_status = CT_HBA_RESET;
- ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
+#endif
+ case ISP_HANDLE_CTRL:
+ wakeup(hdp->cmd);
+ isp_destroy_handle(isp, hdp->handle);
+ break;
}
- isp_async(isp, ISPASYNC_TARGET_ACTION, local);
}
+#ifdef ISP_TARGET_MODE
for (tmp = 0; tmp < isp->isp_nchan; tmp++) {
ISP_MEMZERO(&notify, sizeof (isp_notify_t));
notify.nt_ncode = NT_HBA_RESET;
@@ -2385,69 +2213,6 @@ isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_
return (CMD_QUEUED);
}
-int
-isp_allocate_xs_tgt(ispsoftc_t *isp, void *xs, uint32_t *handlep)
-{
- isp_hdl_t *hdp;
-
- hdp = isp->isp_tgtfree;
- if (hdp == NULL) {
- return (-1);
- }
- isp->isp_tgtfree = hdp->cmd;
- hdp->cmd = xs;
- hdp->handle = (hdp - isp->isp_tgtlist);
- hdp->handle |= (ISP_HANDLE_TARGET << ISP_HANDLE_USAGE_SHIFT);
- /*
- * Target handles for SCSI cards are only 16 bits, so
- * sequence number protection will be ommitted.
- */
- if (IS_FC(isp)) {
- hdp->handle |= (isp->isp_seqno++ << ISP_HANDLE_SEQ_SHIFT);
- }
- *handlep = hdp->handle;
- return (0);
-}
-
-void *
-isp_find_xs_tgt(ispsoftc_t *isp, uint32_t handle)
-{
- if (!ISP_VALID_TGT_HANDLE(isp, handle)) {
- isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle);
- return (NULL);
- }
- return (isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)].cmd);
-}
-
-uint32_t
-isp_find_tgt_handle(ispsoftc_t *isp, void *xs)
-{
- uint32_t i, foundhdl = ISP_HANDLE_FREE;
-
- if (xs != NULL) {
- for (i = 0; i < isp->isp_maxcmds; i++) {
- if (isp->isp_tgtlist[i].cmd != xs) {
- continue;
- }
- foundhdl = isp->isp_tgtlist[i].handle;
- break;
- }
- }
- return (foundhdl);
-}
-
-void
-isp_destroy_tgt_handle(ispsoftc_t *isp, uint32_t handle)
-{
- if (!ISP_VALID_TGT_HANDLE(isp, handle)) {
- isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle);
- } else {
- isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)].handle = ISP_HANDLE_FREE;
- isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)].cmd = isp->isp_tgtfree;
- isp->isp_tgtfree = &isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)];
- }
-}
-
#endif
/*
diff --git a/sys/dev/isp/isp_library.h b/sys/dev/isp/isp_library.h
index efe4e0e..922a98b 100644
--- a/sys/dev/isp/isp_library.h
+++ b/sys/dev/isp/isp_library.h
@@ -43,10 +43,9 @@ int isp_send_cmd(ispsoftc_t *, void *, void *, uint32_t, uint32_t, isp_ddir_t, i
*
* These handles are associate with a command.
*/
-int isp_allocate_xs(ispsoftc_t *, XS_T *, uint32_t *);
-XS_T * isp_find_xs(ispsoftc_t *, uint32_t);
-uint32_t isp_find_handle(ispsoftc_t *, XS_T *);
-uint32_t isp_handle_index(ispsoftc_t *, uint32_t);
+uint32_t isp_allocate_handle(ispsoftc_t *, void *, int);
+void *isp_find_xs(ispsoftc_t *, uint32_t);
+uint32_t isp_find_handle(ispsoftc_t *, void *);
void isp_destroy_handle(ispsoftc_t *, uint32_t);
/*
@@ -72,9 +71,6 @@ const char *isp_fc_fw_statename(int);
const char *isp_fc_loop_statename(int);
const char *isp_fc_toponame(fcparam *);
-int isp_fc_change_role(ispsoftc_t *, int, int);
-
-
/*
* Cleanup
*/
@@ -165,11 +161,6 @@ void isp_put_fcp_rsp_iu(ispsoftc_t *isp, fcp_rsp_iu_t *, fcp_rsp_iu_t *);
#endif
int isp_send_tgt_cmd(ispsoftc_t *, void *, void *, uint32_t, uint32_t, isp_ddir_t, void *, uint32_t);
-
-int isp_allocate_xs_tgt(ispsoftc_t *, void *, uint32_t *);
-void *isp_find_xs_tgt(ispsoftc_t *, uint32_t);
-uint32_t isp_find_tgt_handle(ispsoftc_t *, void *);
-void isp_destroy_tgt_handle(ispsoftc_t *, uint32_t);
#endif
int isp_find_pdb_empty(ispsoftc_t *, int, fcportdb_t **);
int isp_find_pdb_by_wwpn(ispsoftc_t *, int, uint64_t, fcportdb_t **);
diff --git a/sys/dev/isp/isp_pci.c b/sys/dev/isp/isp_pci.c
index e5ea359..11386ee 100644
--- a/sys/dev/isp/isp_pci.c
+++ b/sys/dev/isp/isp_pci.c
@@ -1539,78 +1539,17 @@ isp_pci_wr_reg_2600(ispsoftc_t *isp, int regoff, uint32_t val)
struct imush {
- ispsoftc_t *isp;
- caddr_t vbase;
- int chan;
+ bus_addr_t maddr;
int error;
};
-static void imc(void *, bus_dma_segment_t *, int, int);
-static void imc1(void *, bus_dma_segment_t *, int, int);
-
static void
imc(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
struct imush *imushp = (struct imush *) arg;
- isp_ecmd_t *ecmd;
-
- if (error) {
- imushp->error = error;
- return;
- }
- if (nseg != 1) {
- imushp->error = EINVAL;
- return;
- }
- isp_prt(imushp->isp, ISP_LOGDEBUG0, "request/result area @ 0x%jx/0x%jx", (uintmax_t) segs->ds_addr, (uintmax_t) segs->ds_len);
-
- imushp->isp->isp_rquest = imushp->vbase;
- imushp->isp->isp_rquest_dma = segs->ds_addr;
- segs->ds_addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(imushp->isp));
- imushp->vbase += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(imushp->isp));
-
- imushp->isp->isp_result_dma = segs->ds_addr;
- imushp->isp->isp_result = imushp->vbase;
- segs->ds_addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(imushp->isp));
- imushp->vbase += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(imushp->isp));
-
- if (imushp->isp->isp_type >= ISP_HA_FC_2200) {
- imushp->isp->isp_osinfo.ecmd_dma = segs->ds_addr;
- imushp->isp->isp_osinfo.ecmd_free = (isp_ecmd_t *)imushp->vbase;
- imushp->isp->isp_osinfo.ecmd_base = imushp->isp->isp_osinfo.ecmd_free;
- for (ecmd = imushp->isp->isp_osinfo.ecmd_free; ecmd < &imushp->isp->isp_osinfo.ecmd_free[N_XCMDS]; ecmd++) {
- if (ecmd == &imushp->isp->isp_osinfo.ecmd_free[N_XCMDS - 1]) {
- ecmd->next = NULL;
- } else {
- ecmd->next = ecmd + 1;
- }
- }
- }
-#ifdef ISP_TARGET_MODE
- segs->ds_addr += (N_XCMDS * XCMD_SIZE);
- imushp->vbase += (N_XCMDS * XCMD_SIZE);
- if (IS_24XX(imushp->isp)) {
- imushp->isp->isp_atioq_dma = segs->ds_addr;
- imushp->isp->isp_atioq = imushp->vbase;
- }
-#endif
-}
-static void
-imc1(void *arg, bus_dma_segment_t *segs, int nseg, int error)
-{
- struct imush *imushp = (struct imush *) arg;
- if (error) {
- imushp->error = error;
- return;
- }
- if (nseg != 1) {
- imushp->error = EINVAL;
- return;
- }
- isp_prt(imushp->isp, ISP_LOGDEBUG0, "scdma @ 0x%jx/0x%jx", (uintmax_t) segs->ds_addr, (uintmax_t) segs->ds_len);
- FCPARAM(imushp->isp, imushp->chan)->isp_scdma = segs->ds_addr;
- FCPARAM(imushp->isp, imushp->chan)->isp_scratch = imushp->vbase;
+ if (!(imushp->error = error))
+ imushp->maddr = segs[0].ds_addr;
}
static int
@@ -1623,6 +1562,7 @@ isp_pci_mbxdma(ispsoftc_t *isp)
bus_addr_t llim; /* low limit of unavailable dma */
bus_addr_t hlim; /* high limit of unavailable dma */
struct imush im;
+ isp_ecmd_t *ecmd;
/*
* Already been here? If so, leave...
@@ -1684,97 +1624,129 @@ isp_pci_mbxdma(ispsoftc_t *isp)
isp->isp_xflist[len].cmd = &isp->isp_xflist[len+1];
}
isp->isp_xffree = isp->isp_xflist;
-#ifdef ISP_TARGET_MODE
- len = sizeof (isp_hdl_t) * isp->isp_maxcmds;
- isp->isp_tgtlist = (isp_hdl_t *) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
- if (isp->isp_tgtlist == NULL) {
- free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
- free(isp->isp_xflist, M_DEVBUF);
- ISP_LOCK(isp);
- isp_prt(isp, ISP_LOGERR, "cannot alloc tgtlist array");
- return (1);
- }
- for (len = 0; len < isp->isp_maxcmds - 1; len++) {
- isp->isp_tgtlist[len].cmd = &isp->isp_tgtlist[len+1];
- }
- isp->isp_tgtfree = isp->isp_tgtlist;
-#endif
/*
- * Allocate and map the request and result queues (and ATIO queue
- * if we're a 2400 supporting target mode), and a region for
- * external dma addressable command/status structures (23XX and
- * later).
+ * Allocate and map the request queue and a region for external
+ * DMA addressable command/status structures (22XX and later).
*/
len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
- len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
-#ifdef ISP_TARGET_MODE
- if (IS_24XX(isp)) {
- len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
- }
-#endif
- if (isp->isp_type >= ISP_HA_FC_2200) {
+ if (isp->isp_type >= ISP_HA_FC_2200)
len += (N_XCMDS * XCMD_SIZE);
+ if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ len, 1, len, 0, &isp->isp_osinfo.reqdmat)) {
+ isp_prt(isp, ISP_LOGERR, "cannot create request DMA tag");
+ goto bad1;
+ }
+ if (bus_dmamem_alloc(isp->isp_osinfo.reqdmat, (void **)&base,
+ BUS_DMA_COHERENT, &isp->isp_osinfo.reqmap) != 0) {
+ isp_prt(isp, ISP_LOGERR, "cannot allocate request DMA memory");
+ bus_dma_tag_destroy(isp->isp_osinfo.reqdmat);
+ goto bad1;
+ }
+ isp->isp_rquest = base;
+ im.error = 0;
+ if (bus_dmamap_load(isp->isp_osinfo.reqdmat, isp->isp_osinfo.reqmap,
+ base, len, imc, &im, 0) || im.error) {
+ isp_prt(isp, ISP_LOGERR, "error loading request DMA map %d", im.error);
+ goto bad1;
+ }
+ isp_prt(isp, ISP_LOGDEBUG0, "request area @ 0x%jx/0x%jx",
+ (uintmax_t)im.maddr, (uintmax_t)len);
+ isp->isp_rquest_dma = im.maddr;
+ base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
+ im.maddr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
+ if (isp->isp_type >= ISP_HA_FC_2200) {
+ isp->isp_osinfo.ecmd_dma = im.maddr;
+ isp->isp_osinfo.ecmd_free = (isp_ecmd_t *)base;
+ isp->isp_osinfo.ecmd_base = isp->isp_osinfo.ecmd_free;
+ for (ecmd = isp->isp_osinfo.ecmd_free;
+ ecmd < &isp->isp_osinfo.ecmd_free[N_XCMDS]; ecmd++) {
+ if (ecmd == &isp->isp_osinfo.ecmd_free[N_XCMDS - 1])
+ ecmd->next = NULL;
+ else
+ ecmd->next = ecmd + 1;
+ }
}
/*
- * Create a tag for the control spaces. We don't always need this
- * to be 32 bits, but we do this for simplicity and speed's sake.
+ * Allocate and map the result queue.
*/
- if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, len, 1, slim, 0, &isp->isp_osinfo.cdmat)) {
- isp_prt(isp, ISP_LOGERR, "cannot create a dma tag for control spaces");
- free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
- free(isp->isp_xflist, M_DEVBUF);
-#ifdef ISP_TARGET_MODE
- free(isp->isp_tgtlist, M_DEVBUF);
-#endif
- ISP_LOCK(isp);
- return (1);
+ len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
+ if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ len, 1, len, 0, &isp->isp_osinfo.respdmat)) {
+ isp_prt(isp, ISP_LOGERR, "cannot create response DMA tag");
+ goto bad1;
+ }
+ if (bus_dmamem_alloc(isp->isp_osinfo.respdmat, (void **)&base,
+ BUS_DMA_COHERENT, &isp->isp_osinfo.respmap) != 0) {
+ isp_prt(isp, ISP_LOGERR, "cannot allocate response DMA memory");
+ bus_dma_tag_destroy(isp->isp_osinfo.respdmat);
+ goto bad1;
+ }
+ isp->isp_result = base;
+ im.error = 0;
+ if (bus_dmamap_load(isp->isp_osinfo.respdmat, isp->isp_osinfo.respmap,
+ base, len, imc, &im, 0) || im.error) {
+ isp_prt(isp, ISP_LOGERR, "error loading response DMA map %d", im.error);
+ goto bad1;
}
+ isp_prt(isp, ISP_LOGDEBUG0, "response area @ 0x%jx/0x%jx",
+ (uintmax_t)im.maddr, (uintmax_t)len);
+ isp->isp_result_dma = im.maddr;
- if (bus_dmamem_alloc(isp->isp_osinfo.cdmat, (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &isp->isp_osinfo.cdmap) != 0) {
- isp_prt(isp, ISP_LOGERR, "cannot allocate %d bytes of CCB memory", len);
- bus_dma_tag_destroy(isp->isp_osinfo.cdmat);
- free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
- free(isp->isp_xflist, M_DEVBUF);
#ifdef ISP_TARGET_MODE
- free(isp->isp_tgtlist, M_DEVBUF);
-#endif
- ISP_LOCK(isp);
- return (1);
- }
-
- im.isp = isp;
- im.chan = 0;
- im.vbase = base;
- im.error = 0;
-
- bus_dmamap_load(isp->isp_osinfo.cdmat, isp->isp_osinfo.cdmap, base, len, imc, &im, 0);
- if (im.error) {
- isp_prt(isp, ISP_LOGERR, "error %d loading dma map for control areas", im.error);
- goto bad;
+ /*
+ * Allocate and map ATIO queue on 24xx with target mode.
+ */
+ if (IS_24XX(isp)) {
+ len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
+ if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, slim,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ len, 1, len, 0, &isp->isp_osinfo.atiodmat)) {
+ isp_prt(isp, ISP_LOGERR, "cannot create ATIO DMA tag");
+ goto bad1;
+ }
+ if (bus_dmamem_alloc(isp->isp_osinfo.atiodmat, (void **)&base,
+ BUS_DMA_COHERENT, &isp->isp_osinfo.atiomap) != 0) {
+ isp_prt(isp, ISP_LOGERR, "cannot allocate ATIO DMA memory");
+ bus_dma_tag_destroy(isp->isp_osinfo.atiodmat);
+ goto bad1;
+ }
+ isp->isp_atioq = base;
+ im.error = 0;
+ if (bus_dmamap_load(isp->isp_osinfo.atiodmat, isp->isp_osinfo.atiomap,
+ base, len, imc, &im, 0) || im.error) {
+ isp_prt(isp, ISP_LOGERR, "error loading ATIO DMA map %d", im.error);
+ goto bad;
+ }
+ isp_prt(isp, ISP_LOGDEBUG0, "ATIO area @ 0x%jx/0x%jx",
+ (uintmax_t)im.maddr, (uintmax_t)len);
+ isp->isp_atioq_dma = im.maddr;
}
+#endif
if (IS_FC(isp)) {
+ if (isp_dma_tag_create(isp->isp_osinfo.dmat, 64, slim,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ ISP_FC_SCRLEN, 1, ISP_FC_SCRLEN, 0, &isp->isp_osinfo.scdmat)) {
+ goto bad;
+ }
for (cmap = 0; cmap < isp->isp_nchan; cmap++) {
struct isp_fc *fc = ISP_FC_PC(isp, cmap);
- if (isp_dma_tag_create(isp->isp_osinfo.dmat, 64, slim, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, ISP_FC_SCRLEN, 1, slim, 0, &fc->tdmat)) {
- goto bad;
- }
- if (bus_dmamem_alloc(fc->tdmat, (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &fc->tdmap) != 0) {
- bus_dma_tag_destroy(fc->tdmat);
+ if (bus_dmamem_alloc(isp->isp_osinfo.scdmat,
+ (void **)&base, BUS_DMA_COHERENT, &fc->scmap) != 0)
goto bad;
- }
- im.isp = isp;
- im.chan = cmap;
- im.vbase = base;
+ FCPARAM(isp, cmap)->isp_scratch = base;
im.error = 0;
- bus_dmamap_load(fc->tdmat, fc->tdmap, base, ISP_FC_SCRLEN, imc1, &im, 0);
- if (im.error) {
- bus_dmamem_free(fc->tdmat, base, fc->tdmap);
- bus_dma_tag_destroy(fc->tdmat);
+ if (bus_dmamap_load(isp->isp_osinfo.scdmat, fc->scmap,
+ base, ISP_FC_SCRLEN, imc, &im, 0) || im.error) {
+ bus_dmamem_free(isp->isp_osinfo.scdmat,
+ base, fc->scmap);
goto bad;
}
+ FCPARAM(isp, cmap)->isp_scdma = im.maddr;
if (!IS_2100(isp)) {
for (i = 0; i < INITIAL_NEXUS_COUNT; i++) {
struct isp_nexus *n = malloc(sizeof (struct isp_nexus), M_DEVBUF, M_NOWAIT | M_ZERO);
@@ -1815,22 +1787,52 @@ isp_pci_mbxdma(ispsoftc_t *isp)
return (0);
bad:
- while (--cmap >= 0) {
- struct isp_fc *fc = ISP_FC_PC(isp, cmap);
- bus_dmamem_free(fc->tdmat, base, fc->tdmap);
- bus_dma_tag_destroy(fc->tdmat);
- while (fc->nexus_free_list) {
- struct isp_nexus *n = fc->nexus_free_list;
- fc->nexus_free_list = n->next;
- free(n, M_DEVBUF);
+ if (IS_FC(isp)) {
+ while (--cmap >= 0) {
+ struct isp_fc *fc = ISP_FC_PC(isp, cmap);
+ bus_dmamap_unload(isp->isp_osinfo.scdmat, fc->scmap);
+ bus_dmamem_free(isp->isp_osinfo.scdmat, base, fc->scmap);
+ while (fc->nexus_free_list) {
+ struct isp_nexus *n = fc->nexus_free_list;
+ fc->nexus_free_list = n->next;
+ free(n, M_DEVBUF);
+ }
}
+ bus_dma_tag_destroy(isp->isp_osinfo.scdmat);
+ }
+bad1:
+ if (isp->isp_rquest_dma != 0) {
+ bus_dmamap_unload(isp->isp_osinfo.reqdmat,
+ isp->isp_osinfo.reqmap);
+ }
+ if (isp->isp_rquest != NULL) {
+ bus_dmamem_free(isp->isp_osinfo.reqdmat, isp->isp_rquest,
+ isp->isp_osinfo.reqmap);
+ bus_dma_tag_destroy(isp->isp_osinfo.reqdmat);
+ }
+ if (isp->isp_result_dma != 0) {
+ bus_dmamap_unload(isp->isp_osinfo.respdmat,
+ isp->isp_osinfo.respmap);
+ }
+ if (isp->isp_result != NULL) {
+ bus_dmamem_free(isp->isp_osinfo.respdmat, isp->isp_result,
+ isp->isp_osinfo.respmap);
+ bus_dma_tag_destroy(isp->isp_osinfo.respdmat);
}
- bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap);
- bus_dma_tag_destroy(isp->isp_osinfo.cdmat);
- free(isp->isp_xflist, M_DEVBUF);
#ifdef ISP_TARGET_MODE
- free(isp->isp_tgtlist, M_DEVBUF);
+ if (IS_24XX(isp)) {
+ if (isp->isp_atioq_dma != 0) {
+ bus_dmamap_unload(isp->isp_osinfo.atiodmat,
+ isp->isp_osinfo.atiomap);
+ }
+ if (isp->isp_atioq != NULL) {
+ bus_dmamem_free(isp->isp_osinfo.reqdmat, isp->isp_atioq,
+ isp->isp_osinfo.atiomap);
+ bus_dma_tag_destroy(isp->isp_osinfo.atiodmat);
+ }
+ }
#endif
+ free(isp->isp_xflist, M_DEVBUF);
free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
isp->isp_rquest = NULL;
ISP_LOCK(isp);
diff --git a/sys/dev/isp/isp_sbus.c b/sys/dev/isp/isp_sbus.c
index 2abfc64..f1ca83c 100644
--- a/sys/dev/isp/isp_sbus.c
+++ b/sys/dev/isp/isp_sbus.c
@@ -413,7 +413,7 @@ isp_sbus_wr_reg(ispsoftc_t *isp, int regoff, uint32_t val)
}
struct imush {
- ispsoftc_t *isp;
+ bus_addr_t maddr;
int error;
};
@@ -423,16 +423,9 @@ static void
imc(void *arg, bus_dma_segment_t *segs, int nseg, int error)
{
struct imush *imushp = (struct imush *) arg;
- if (error) {
- imushp->error = error;
- } else {
- ispsoftc_t *isp =imushp->isp;
- bus_addr_t addr = segs->ds_addr;
- isp->isp_rquest_dma = addr;
- addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
- isp->isp_result_dma = addr;
- }
+ if (!(imushp->error = error))
+ imushp->maddr = segs[0].ds_addr;
}
static int
@@ -479,40 +472,62 @@ isp_sbus_mbxdma(ispsoftc_t *isp)
BUS_SPACE_MAXADDR_32BIT, NULL, NULL, BUS_SPACE_MAXSIZE_32BIT,
ISP_NSEG_MAX, BUS_SPACE_MAXADDR_24BIT, 0, &isp->isp_osinfo.dmat)) {
isp_prt(isp, ISP_LOGERR, "could not create master dma tag");
- free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
- free(isp->isp_xflist, M_DEVBUF);
- ISP_LOCK(isp);
- return(1);
+ goto bad;
}
/*
- * Allocate and map the request, result queues, plus FC scratch area.
+ * Allocate and map the request queue.
*/
len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
- len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
-
- if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN,
- BUS_SPACE_MAXADDR_24BIT+1, BUS_SPACE_MAXADDR_32BIT,
- BUS_SPACE_MAXADDR_32BIT, NULL, NULL, len, 1,
- BUS_SPACE_MAXADDR_24BIT, 0, &isp->isp_osinfo.cdmat)) {
- isp_prt(isp, ISP_LOGERR,
- "cannot create a dma tag for control spaces");
- free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
- free(isp->isp_xflist, M_DEVBUF);
- ISP_LOCK(isp);
- return (1);
+ if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, BUS_SPACE_MAXADDR_24BIT+1,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ len, 1, len, 0, &isp->isp_osinfo.reqdmat)) {
+ isp_prt(isp, ISP_LOGERR, "cannot create request DMA tag");
+ goto bad;
+ }
+ if (bus_dmamem_alloc(isp->isp_osinfo.reqdmat, (void **)&base,
+ BUS_DMA_COHERENT, &isp->isp_osinfo.reqmap) != 0) {
+ isp_prt(isp, ISP_LOGERR, "cannot allocate request DMA memory");
+ bus_dma_tag_destroy(isp->isp_osinfo.reqdmat);
+ goto bad;
+ }
+ im.error = 0;
+ if (bus_dmamap_load(isp->isp_osinfo.reqdmat, isp->isp_osinfo.reqmap,
+ base, len, imc, &im, 0) || im.error) {
+ isp_prt(isp, ISP_LOGERR, "error loading request DMA map %d", im.error);
+ goto bad;
}
+ isp_prt(isp, ISP_LOGDEBUG0, "request area @ 0x%jx/0x%jx",
+ (uintmax_t)im.maddr, (uintmax_t)len);
+ isp->isp_rquest = base;
+ isp->isp_rquest_dma = im.maddr;
- if (bus_dmamem_alloc(isp->isp_osinfo.cdmat, (void **)&base, BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
- &isp->isp_osinfo.cdmap) != 0) {
- isp_prt(isp, ISP_LOGERR,
- "cannot allocate %d bytes of CCB memory", len);
- bus_dma_tag_destroy(isp->isp_osinfo.cdmat);
- free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
- free(isp->isp_xflist, M_DEVBUF);
- ISP_LOCK(isp);
- return (1);
+ /*
+ * Allocate and map the result queue.
+ */
+ len = ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
+ if (isp_dma_tag_create(isp->isp_osinfo.dmat, QENTRY_LEN, BUS_SPACE_MAXADDR_24BIT+1,
+ BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
+ len, 1, len, 0, &isp->isp_osinfo.respdmat)) {
+ isp_prt(isp, ISP_LOGERR, "cannot create response DMA tag");
+ goto bad;
}
+ if (bus_dmamem_alloc(isp->isp_osinfo.respdmat, (void **)&base,
+ BUS_DMA_COHERENT, &isp->isp_osinfo.respmap) != 0) {
+ isp_prt(isp, ISP_LOGERR, "cannot allocate response DMA memory");
+ bus_dma_tag_destroy(isp->isp_osinfo.respdmat);
+ goto bad;
+ }
+ im.error = 0;
+ if (bus_dmamap_load(isp->isp_osinfo.respdmat, isp->isp_osinfo.respmap,
+ base, len, imc, &im, 0) || im.error) {
+ isp_prt(isp, ISP_LOGERR, "error loading response DMA map %d", im.error);
+ goto bad;
+ }
+ isp_prt(isp, ISP_LOGDEBUG0, "response area @ 0x%jx/0x%jx",
+ (uintmax_t)im.maddr, (uintmax_t)len);
+ isp->isp_result = base;
+ isp->isp_result_dma = im.maddr;
for (i = 0; i < isp->isp_maxcmds; i++) {
struct isp_pcmd *pcmd = &isp->isp_osinfo.pcmd_pool[i];
@@ -534,25 +549,28 @@ isp_sbus_mbxdma(ispsoftc_t *isp)
}
}
isp->isp_osinfo.pcmd_free = &isp->isp_osinfo.pcmd_pool[0];
-
- im.isp = isp;
- im.error = 0;
- bus_dmamap_load(isp->isp_osinfo.cdmat, isp->isp_osinfo.cdmap, base, len, imc, &im, 0);
- if (im.error) {
- isp_prt(isp, ISP_LOGERR,
- "error %d loading dma map for control areas", im.error);
- goto bad;
- }
-
- isp->isp_rquest = base;
- base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
- isp->isp_result = base;
ISP_LOCK(isp);
return (0);
bad:
- bus_dmamem_free(isp->isp_osinfo.cdmat, base, isp->isp_osinfo.cdmap);
- bus_dma_tag_destroy(isp->isp_osinfo.cdmat);
+ if (isp->isp_rquest_dma != 0) {
+ bus_dmamap_unload(isp->isp_osinfo.reqdmat,
+ isp->isp_osinfo.reqmap);
+ }
+ if (isp->isp_rquest != NULL) {
+ bus_dmamem_free(isp->isp_osinfo.reqdmat, isp->isp_rquest,
+ isp->isp_osinfo.reqmap);
+ bus_dma_tag_destroy(isp->isp_osinfo.reqdmat);
+ }
+ if (isp->isp_result_dma != 0) {
+ bus_dmamap_unload(isp->isp_osinfo.respdmat,
+ isp->isp_osinfo.respmap);
+ }
+ if (isp->isp_result != NULL) {
+ bus_dmamem_free(isp->isp_osinfo.respdmat, isp->isp_result,
+ isp->isp_osinfo.respmap);
+ bus_dma_tag_destroy(isp->isp_osinfo.respdmat);
+ }
free(isp->isp_xflist, M_DEVBUF);
free(isp->isp_osinfo.pcmd_pool, M_DEVBUF);
isp->isp_rquest = NULL;
diff --git a/sys/dev/isp/isp_target.c b/sys/dev/isp/isp_target.c
index c6e48fe..c6af888 100644
--- a/sys/dev/isp/isp_target.c
+++ b/sys/dev/isp/isp_target.c
@@ -1094,7 +1094,7 @@ isp_handle_ctio2(ispsoftc_t *isp, ct2_entry_t *ct)
char *fmsg = NULL;
if (ct->ct_syshandle) {
- xs = isp_find_xs_tgt(isp, ct->ct_syshandle);
+ xs = isp_find_xs(isp, ct->ct_syshandle);
if (xs == NULL) {
pl = ISP_LOGALL;
}
@@ -1249,7 +1249,7 @@ isp_handle_ctio7(ispsoftc_t *isp, ct7_entry_t *ct)
char *fmsg = NULL;
if (ct->ct_syshandle) {
- xs = isp_find_xs_tgt(isp, ct->ct_syshandle);
+ xs = isp_find_xs(isp, ct->ct_syshandle);
if (xs == NULL) {
pl = ISP_LOGALL;
}
diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h
index a89228b..5a1306f 100644
--- a/sys/dev/isp/ispmbox.h
+++ b/sys/dev/isp/ispmbox.h
@@ -1086,7 +1086,7 @@ typedef struct {
#define ICB_DFLT_RDELAY 5
#define ICB_DFLT_RCOUNT 3
-#define ICB_LOGIN_TOV 30
+#define ICB_LOGIN_TOV 10
#define ICB_LUN_ENABLE_TOV 15
diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h
index 0c42642..a7184e2 100644
--- a/sys/dev/isp/ispvar.h
+++ b/sys/dev/isp/ispvar.h
@@ -77,7 +77,7 @@ struct ispmdvec {
*/
#define MAX_TARGETS 16
#ifndef MAX_FC_TARG
-#define MAX_FC_TARG 256
+#define MAX_FC_TARG 1024
#endif
#define ISP_MAX_TARGETS(isp) (IS_FC(isp)? MAX_FC_TARG : MAX_TARGETS)
#define ISP_MAX_LUNS(isp) (isp)->isp_maxluns
@@ -315,21 +315,16 @@ typedef struct {
# define ISP_HANDLE_NONE 0
# define ISP_HANDLE_INITIATOR 1
# define ISP_HANDLE_TARGET 2
+# define ISP_HANDLE_CTRL 3
#define ISP_HANDLE_SEQ_MASK 0xffff0000
#define ISP_HANDLE_SEQ_SHIFT 16
#define ISP_H2SEQ(hdl) ((hdl & ISP_HANDLE_SEQ_MASK) >> ISP_HANDLE_SEQ_SHIFT)
-#define ISP_VALID_INI_HANDLE(c, hdl) \
- (ISP_H2HT(hdl) == ISP_HANDLE_INITIATOR && (hdl & ISP_HANDLE_CMD_MASK) < (c)->isp_maxcmds && \
- ISP_H2SEQ(hdl) == ISP_H2SEQ((c)->isp_xflist[hdl & ISP_HANDLE_CMD_MASK].handle))
-#ifdef ISP_TARGET_MODE
-#define ISP_VALID_TGT_HANDLE(c, hdl) \
- (ISP_H2HT(hdl) == ISP_HANDLE_TARGET && (hdl & ISP_HANDLE_CMD_MASK) < (c)->isp_maxcmds && \
- ISP_H2SEQ(hdl) == ISP_H2SEQ((c)->isp_tgtlist[hdl & ISP_HANDLE_CMD_MASK].handle))
#define ISP_VALID_HANDLE(c, hdl) \
- (ISP_VALID_INI_HANDLE((c), hdl) || ISP_VALID_TGT_HANDLE((c), hdl))
-#else
-#define ISP_VALID_HANDLE ISP_VALID_INI_HANDLE
-#endif
+ ((ISP_H2HT(hdl) == ISP_HANDLE_INITIATOR || \
+ ISP_H2HT(hdl) == ISP_HANDLE_TARGET || \
+ ISP_H2HT(hdl) == ISP_HANDLE_CTRL) && \
+ ((hdl) & ISP_HANDLE_CMD_MASK) < (c)->isp_maxcmds && \
+ (hdl) == ((c)->isp_xflist[(hdl) & ISP_HANDLE_CMD_MASK].handle))
#define ISP_BAD_HANDLE_INDEX 0xffffffff
@@ -477,6 +472,8 @@ typedef struct {
*/
void * isp_scratch;
XS_DMA_ADDR_T isp_scdma;
+
+ uint8_t isp_scanscratch[ISP_FC_SCRLEN];
} fcparam;
#define FW_CONFIG_WAIT 0
@@ -598,14 +595,6 @@ struct ispsoftc {
isp_hdl_t *isp_xflist;
isp_hdl_t *isp_xffree;
-#ifdef ISP_TARGET_MODE
- /*
- * Active target commands are stored here, indexed by handle functions.
- */
- isp_hdl_t *isp_tgtlist;
- isp_hdl_t *isp_tgtfree;
-#endif
-
/*
* request/result queue pointers and DMA handles for them.
*/
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index fb9a202..a9c33ae 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -110,11 +110,6 @@ static int pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg,
int reg, uint32_t data);
#endif
static void pci_read_vpd(device_t pcib, pcicfgregs *cfg);
-static void pci_disable_msi(device_t dev);
-static void pci_enable_msi(device_t dev, uint64_t address,
- uint16_t data);
-static void pci_enable_msix(device_t dev, u_int index,
- uint64_t address, uint32_t data);
static void pci_mask_msix(device_t dev, u_int index);
static void pci_unmask_msix(device_t dev, u_int index);
static int pci_msi_blacklisted(void);
@@ -180,11 +175,15 @@ static device_method_t pci_methods[] = {
DEVMETHOD(pci_find_htcap, pci_find_htcap_method),
DEVMETHOD(pci_alloc_msi, pci_alloc_msi_method),
DEVMETHOD(pci_alloc_msix, pci_alloc_msix_method),
+ DEVMETHOD(pci_enable_msi, pci_enable_msi_method),
+ DEVMETHOD(pci_enable_msix, pci_enable_msix_method),
+ DEVMETHOD(pci_disable_msi, pci_disable_msi_method),
DEVMETHOD(pci_remap_msix, pci_remap_msix_method),
DEVMETHOD(pci_release_msi, pci_release_msi_method),
DEVMETHOD(pci_msi_count, pci_msi_count_method),
DEVMETHOD(pci_msix_count, pci_msix_count_method),
DEVMETHOD(pci_get_rid, pci_get_rid_method),
+ DEVMETHOD(pci_child_added, pci_child_added_method),
DEVMETHOD_END
};
@@ -1374,9 +1373,10 @@ pci_find_extcap_method(device_t dev, device_t child, int capability,
* Support for MSI-X message interrupts.
*/
void
-pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data)
+pci_enable_msix_method(device_t dev, device_t child, u_int index,
+ uint64_t address, uint32_t data)
{
- struct pci_devinfo *dinfo = device_get_ivars(dev);
+ struct pci_devinfo *dinfo = device_get_ivars(child);
struct pcicfg_msix *msix = &dinfo->cfg.msix;
uint32_t offset;
@@ -1387,7 +1387,7 @@ pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data)
bus_write_4(msix->msix_table_res, offset + 8, data);
/* Enable MSI -> HT mapping. */
- pci_ht_map_msi(dev, address);
+ pci_ht_map_msi(child, address);
}
void
@@ -1956,45 +1956,46 @@ pcie_adjust_config(device_t dev, int reg, uint32_t mask, uint32_t value,
* Support for MSI message signalled interrupts.
*/
void
-pci_enable_msi(device_t dev, uint64_t address, uint16_t data)
+pci_enable_msi_method(device_t dev, device_t child, uint64_t address,
+ uint16_t data)
{
- struct pci_devinfo *dinfo = device_get_ivars(dev);
+ struct pci_devinfo *dinfo = device_get_ivars(child);
struct pcicfg_msi *msi = &dinfo->cfg.msi;
/* Write data and address values. */
- pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR,
+ pci_write_config(child, msi->msi_location + PCIR_MSI_ADDR,
address & 0xffffffff, 4);
if (msi->msi_ctrl & PCIM_MSICTRL_64BIT) {
- pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR_HIGH,
+ pci_write_config(child, msi->msi_location + PCIR_MSI_ADDR_HIGH,
address >> 32, 4);
- pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA_64BIT,
+ pci_write_config(child, msi->msi_location + PCIR_MSI_DATA_64BIT,
data, 2);
} else
- pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA, data,
+ pci_write_config(child, msi->msi_location + PCIR_MSI_DATA, data,
2);
/* Enable MSI in the control register. */
msi->msi_ctrl |= PCIM_MSICTRL_MSI_ENABLE;
- pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl,
- 2);
+ pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL,
+ msi->msi_ctrl, 2);
/* Enable MSI -> HT mapping. */
- pci_ht_map_msi(dev, address);
+ pci_ht_map_msi(child, address);
}
void
-pci_disable_msi(device_t dev)
+pci_disable_msi_method(device_t dev, device_t child)
{
- struct pci_devinfo *dinfo = device_get_ivars(dev);
+ struct pci_devinfo *dinfo = device_get_ivars(child);
struct pcicfg_msi *msi = &dinfo->cfg.msi;
/* Disable MSI -> HT mapping. */
- pci_ht_map_msi(dev, 0);
+ pci_ht_map_msi(child, 0);
/* Disable MSI in the control register. */
msi->msi_ctrl &= ~PCIM_MSICTRL_MSI_ENABLE;
- pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl,
- 2);
+ pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL,
+ msi->msi_ctrl, 2);
}
/*
@@ -3604,6 +3605,13 @@ pci_add_child(device_t bus, struct pci_devinfo *dinfo)
pci_cfg_restore(dinfo->cfg.dev, dinfo);
pci_print_verbose(dinfo);
pci_add_resources(bus, dinfo->cfg.dev, 0, 0);
+ pci_child_added(dinfo->cfg.dev);
+}
+
+void
+pci_child_added_method(device_t dev, device_t child)
+{
+
}
static int
diff --git a/sys/dev/pci/pci_if.m b/sys/dev/pci/pci_if.m
index 82864eb..227d362 100644
--- a/sys/dev/pci/pci_if.m
+++ b/sys/dev/pci/pci_if.m
@@ -138,6 +138,26 @@ METHOD int alloc_msix {
int *count;
};
+METHOD void enable_msi {
+ device_t dev;
+ device_t child;
+ uint64_t address;
+ uint16_t data;
+};
+
+METHOD void enable_msix {
+ device_t dev;
+ device_t child;
+ u_int index;
+ uint64_t address;
+ uint32_t data;
+};
+
+METHOD void disable_msi {
+ device_t dev;
+ device_t child;
+};
+
METHOD int remap_msix {
device_t dev;
device_t child;
@@ -165,3 +185,7 @@ METHOD uint16_t get_rid {
device_t child;
};
+METHOD void child_added {
+ device_t dev;
+ device_t child;
+};
diff --git a/sys/dev/pci/pci_private.h b/sys/dev/pci/pci_private.h
index 0223ee8..5a90ce9 100644
--- a/sys/dev/pci/pci_private.h
+++ b/sys/dev/pci/pci_private.h
@@ -90,6 +90,11 @@ int pci_find_htcap_method(device_t dev, device_t child,
int capability, int *capreg);
int pci_alloc_msi_method(device_t dev, device_t child, int *count);
int pci_alloc_msix_method(device_t dev, device_t child, int *count);
+void pci_enable_msi_method(device_t dev, device_t child,
+ uint64_t address, uint16_t data);
+void pci_enable_msix_method(device_t dev, device_t child,
+ u_int index, uint64_t address, uint32_t data);
+void pci_disable_msi_method(device_t dev, device_t child);
int pci_remap_msix_method(device_t dev, device_t child,
int count, const u_int *vectors);
int pci_release_msi_method(device_t dev, device_t child);
@@ -120,6 +125,7 @@ int pci_assign_interrupt_method(device_t dev, device_t child);
int pci_resume(device_t dev);
int pci_suspend(device_t dev);
bus_dma_tag_t pci_get_dma_tag(device_t bus, device_t dev);
+void pci_child_added_method(device_t dev, device_t child);
/** Restore the config register state. The state must be previously
* saved with pci_cfg_save. However, the pci bus driver takes care of
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index 4b570d0..2bb26bd 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -458,6 +458,24 @@ pci_alloc_msix(device_t dev, int *count)
return (PCI_ALLOC_MSIX(device_get_parent(dev), dev, count));
}
+static __inline void
+pci_enable_msi(device_t dev, uint64_t address, uint16_t data)
+{
+ PCI_ENABLE_MSI(device_get_parent(dev), dev, address, data);
+}
+
+static __inline void
+pci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data)
+{
+ PCI_ENABLE_MSIX(device_get_parent(dev), dev, index, address, data);
+}
+
+static __inline void
+pci_disable_msi(device_t dev)
+{
+ PCI_DISABLE_MSI(device_get_parent(dev), dev);
+}
+
static __inline int
pci_remap_msix(device_t dev, int count, const u_int *vectors)
{
@@ -488,6 +506,13 @@ pci_get_rid(device_t dev)
return (PCI_GET_RID(device_get_parent(dev), dev));
}
+static __inline void
+pci_child_added(device_t dev)
+{
+
+ return (PCI_CHILD_ADDED(device_get_parent(dev), dev));
+}
+
device_t pci_find_bsf(uint8_t, uint8_t, uint8_t);
device_t pci_find_dbsf(uint32_t, uint8_t, uint8_t, uint8_t);
device_t pci_find_device(uint16_t, uint16_t);
diff --git a/sys/dev/virtio/balloon/virtio_balloon.c b/sys/dev/virtio/balloon/virtio_balloon.c
index a90a653..6d00ef3 100644
--- a/sys/dev/virtio/balloon/virtio_balloon.c
+++ b/sys/dev/virtio/balloon/virtio_balloon.c
@@ -438,8 +438,7 @@ vtballoon_alloc_page(struct vtballoon_softc *sc)
{
vm_page_t m;
- m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_WIRED |
- VM_ALLOC_NOOBJ);
+ m = vm_page_alloc(NULL, 0, VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ);
if (m != NULL)
sc->vtballoon_current_npages++;
@@ -450,7 +449,6 @@ static void
vtballoon_free_page(struct vtballoon_softc *sc, vm_page_t m)
{
- vm_page_unwire(m, 0);
vm_page_free(m);
sc->vtballoon_current_npages--;
}
diff --git a/sys/dev/xen/balloon/balloon.c b/sys/dev/xen/balloon/balloon.c
index 2df9c8b..6503a00 100644
--- a/sys/dev/xen/balloon/balloon.c
+++ b/sys/dev/xen/balloon/balloon.c
@@ -94,13 +94,8 @@ SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, low_mem, CTLFLAG_RD,
SYSCTL_ULONG(_dev_xen_balloon, OID_AUTO, high_mem, CTLFLAG_RD,
&bs.balloon_high, 0, "High-mem balloon");
-struct balloon_entry {
- vm_page_t page;
- STAILQ_ENTRY(balloon_entry) list;
-};
-
/* List of ballooned pages, threaded through the mem_map array. */
-static STAILQ_HEAD(,balloon_entry) ballooned_pages;
+static TAILQ_HEAD(,vm_page) ballooned_pages;
/* Main work function, always executed in process context. */
static void balloon_process(void *unused);
@@ -110,47 +105,6 @@ static void balloon_process(void *unused);
#define WPRINTK(fmt, args...) \
printk(KERN_WARNING "xen_mem: " fmt, ##args)
-/* balloon_append: add the given page to the balloon. */
-static int
-balloon_append(vm_page_t page)
-{
- struct balloon_entry *entry;
-
- mtx_assert(&balloon_mutex, MA_OWNED);
-
- entry = malloc(sizeof(struct balloon_entry), M_BALLOON, M_NOWAIT);
- if (!entry)
- return (ENOMEM);
- entry->page = page;
- STAILQ_INSERT_HEAD(&ballooned_pages, entry, list);
- bs.balloon_low++;
-
- return (0);
-}
-
-/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
-static vm_page_t
-balloon_retrieve(void)
-{
- vm_page_t page;
- struct balloon_entry *entry;
-
- mtx_assert(&balloon_mutex, MA_OWNED);
-
- if (STAILQ_EMPTY(&ballooned_pages))
- return (NULL);
-
- entry = STAILQ_FIRST(&ballooned_pages);
- STAILQ_REMOVE_HEAD(&ballooned_pages, list);
-
- page = entry->page;
- free(entry, M_BALLOON);
-
- bs.balloon_low--;
-
- return (page);
-}
-
static unsigned long
current_target(void)
{
@@ -203,7 +157,6 @@ static int
increase_reservation(unsigned long nr_pages)
{
unsigned long pfn, i;
- struct balloon_entry *entry;
vm_page_t page;
long rc;
struct xen_memory_reservation reservation = {
@@ -217,10 +170,9 @@ increase_reservation(unsigned long nr_pages)
if (nr_pages > nitems(frame_list))
nr_pages = nitems(frame_list);
- for (entry = STAILQ_FIRST(&ballooned_pages), i = 0;
- i < nr_pages; i++, entry = STAILQ_NEXT(entry, list)) {
- KASSERT(entry, ("ballooned_pages list corrupt"));
- page = entry->page;
+ for (page = TAILQ_FIRST(&ballooned_pages), i = 0;
+ i < nr_pages; i++, page = TAILQ_NEXT(page, plinks.q)) {
+ KASSERT(page != NULL, ("ballooned_pages list corrupt"));
frame_list[i] = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT);
}
@@ -245,8 +197,10 @@ increase_reservation(unsigned long nr_pages)
}
for (i = 0; i < nr_pages; i++) {
- page = balloon_retrieve();
- KASSERT(page, ("balloon_retrieve failed"));
+ page = TAILQ_FIRST(&ballooned_pages);
+ KASSERT(page != NULL, ("Unable to get ballooned page"));
+ TAILQ_REMOVE(&ballooned_pages, page, plinks.q);
+ bs.balloon_low--;
pfn = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT);
KASSERT((xen_feature(XENFEAT_auto_translated_physmap) ||
@@ -255,7 +209,6 @@ increase_reservation(unsigned long nr_pages)
set_phys_to_machine(pfn, frame_list[i]);
- vm_page_unwire(page, 0);
vm_page_free(page);
}
@@ -286,24 +239,29 @@ decrease_reservation(unsigned long nr_pages)
for (i = 0; i < nr_pages; i++) {
if ((page = vm_page_alloc(NULL, 0,
VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ |
- VM_ALLOC_WIRED | VM_ALLOC_ZERO)) == NULL) {
+ VM_ALLOC_ZERO)) == NULL) {
nr_pages = i;
need_sleep = 1;
break;
}
+ if ((page->flags & PG_ZERO) == 0) {
+ /*
+ * Zero the page, or else we might be leaking
+ * important data to other domains on the same
+ * host. Xen doesn't scrub ballooned out memory
+ * pages, the guest is in charge of making
+ * sure that no information is leaked.
+ */
+ pmap_zero_page(page);
+ }
+
pfn = (VM_PAGE_TO_PHYS(page) >> PAGE_SHIFT);
frame_list[i] = PFNTOMFN(pfn);
set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
- if (balloon_append(page) != 0) {
- vm_page_unwire(page, 0);
- vm_page_free(page);
-
- nr_pages = i;
- need_sleep = 1;
- break;
- }
+ TAILQ_INSERT_HEAD(&ballooned_pages, page, plinks.q);
+ bs.balloon_low++;
}
set_xen_guest_handle(reservation.extent_start, frame_list);
@@ -438,7 +396,8 @@ balloon_init(void *arg)
/* Initialise the balloon with excess memory space. */
for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
page = PHYS_TO_VM_PAGE(pfn << PAGE_SHIFT);
- balloon_append(page);
+ TAILQ_INSERT_HEAD(&ballooned_pages, page, plinks.q);
+ bs.balloon_low++;
}
#undef max_pfn
#endif
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index 17a336f..816a340 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -1533,11 +1533,15 @@ devfs_setattr(struct vop_setattr_args *ap)
return (EINVAL);
}
+ error = devfs_populate_vp(vp);
+ if (error != 0)
+ return (error);
+
de = vp->v_data;
if (vp->v_type == VDIR)
de = de->de_dir;
- error = c = 0;
+ c = 0;
if (vap->va_uid == (uid_t)VNOVAL)
uid = de->de_uid;
else
@@ -1550,8 +1554,8 @@ devfs_setattr(struct vop_setattr_args *ap)
if ((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid ||
(gid != de->de_gid && !groupmember(gid, ap->a_cred))) {
error = priv_check(td, PRIV_VFS_CHOWN);
- if (error)
- return (error);
+ if (error != 0)
+ goto ret;
}
de->de_uid = uid;
de->de_gid = gid;
@@ -1561,8 +1565,8 @@ devfs_setattr(struct vop_setattr_args *ap)
if (vap->va_mode != (mode_t)VNOVAL) {
if (ap->a_cred->cr_uid != de->de_uid) {
error = priv_check(td, PRIV_VFS_ADMIN);
- if (error)
- return (error);
+ if (error != 0)
+ goto ret;
}
de->de_mode = vap->va_mode;
c = 1;
@@ -1571,7 +1575,7 @@ devfs_setattr(struct vop_setattr_args *ap)
if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
error = vn_utimes_perm(vp, vap, ap->a_cred, td);
if (error != 0)
- return (error);
+ goto ret;
if (vap->va_atime.tv_sec != VNOVAL) {
if (vp->v_type == VCHR)
vp->v_rdev->si_atime = vap->va_atime;
@@ -1593,7 +1597,10 @@ devfs_setattr(struct vop_setattr_args *ap)
else
vfs_timestamp(&de->de_mtime);
}
- return (0);
+
+ret:
+ sx_xunlock(&VFSTODEVFS(vp->v_mount)->dm_lock);
+ return (error);
}
#ifdef MAC
diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h
index b46aef7..eea9df0 100644
--- a/sys/fs/nfs/nfsport.h
+++ b/sys/fs/nfs/nfsport.h
@@ -981,6 +981,13 @@ struct nfsreq {
#define NFSVNO_DELEGOK(v) (1)
#endif
+/*
+ * Name used by getnewvnode() to describe filesystem, "newnfs".
+ * For perfomance reasons it is useful to have the same string
+ * used in both places that call getnewvnode().
+ */
+extern const char nfs_vnode_tag[];
+
#endif /* _KERNEL */
#endif /* _NFS_NFSPORT_H */
diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c
index 0cd503c..263185f 100644
--- a/sys/fs/nfsclient/nfs_clnode.c
+++ b/sys/fs/nfsclient/nfs_clnode.c
@@ -66,6 +66,8 @@ MALLOC_DECLARE(M_NEWNFSREQ);
uma_zone_t newnfsnode_zone;
+const char nfs_vnode_tag[] = "newnfs";
+
static void nfs_freesillyrename(void *arg, __unused int pending);
void
@@ -124,7 +126,7 @@ ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp,
}
np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO);
- error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp);
+ error = getnewvnode(nfs_vnode_tag, mntp, &newnfs_vnodeops, &nvp);
if (error) {
uma_zfree(newnfsnode_zone, np);
return (error);
@@ -332,4 +334,3 @@ ncl_invalcaches(struct vnode *vp)
KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
mtx_unlock(&np->n_mtx);
}
-
diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c
index 8c2e84b..f6919ab 100644
--- a/sys/fs/nfsclient/nfs_clport.c
+++ b/sys/fs/nfsclient/nfs_clport.c
@@ -199,7 +199,7 @@ nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp,
}
np = uma_zalloc(newnfsnode_zone, M_WAITOK | M_ZERO);
- error = getnewvnode("newnfs", mntp, &newnfs_vnodeops, &nvp);
+ error = getnewvnode(nfs_vnode_tag, mntp, &newnfs_vnodeops, &nvp);
if (error) {
uma_zfree(newnfsnode_zone, np);
FREE((caddr_t)nfhp, M_NFSFH);
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 520cc8b..eaa3ee1 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -993,7 +993,8 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
}
vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY);
if (error != 0) {
- uprintf("ELF interpreter %s not found\n", interp);
+ uprintf("ELF interpreter %s not found, error %d\n",
+ interp, error);
goto ret;
}
} else
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 2df1e25..bad816b 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -145,24 +145,51 @@ int vttoif_tab[10] = {
static TAILQ_HEAD(freelst, vnode) vnode_free_list;
/*
- * Free vnode target. Free vnodes may simply be files which have been stat'd
- * but not read. This is somewhat common, and a small cache of such files
- * should be kept to avoid recreation costs.
+ * "Free" vnode target. Free vnodes are rarely completely free, but are
+ * just ones that are cheap to recycle. Usually they are for files which
+ * have been stat'd but not read; these usually have inode and namecache
+ * data attached to them. This target is the preferred minimum size of a
+ * sub-cache consisting mostly of such files. The system balances the size
+ * of this sub-cache with its complement to try to prevent either from
+ * thrashing while the other is relatively inactive. The targets express
+ * a preference for the best balance.
+ *
+ * "Above" this target there are 2 further targets (watermarks) related
+ * to recyling of free vnodes. In the best-operating case, the cache is
+ * exactly full, the free list has size between vlowat and vhiwat above the
+ * free target, and recycling from it and normal use maintains this state.
+ * Sometimes the free list is below vlowat or even empty, but this state
+ * is even better for immediate use provided the cache is not full.
+ * Otherwise, vnlru_proc() runs to reclaim enough vnodes (usually non-free
+ * ones) to reach one of these states. The watermarks are currently hard-
+ * coded as 4% and 9% of the available space higher. These and the default
+ * of 25% for wantfreevnodes are too large if the memory size is large.
+ * E.g., 9% of 75% of MAXVNODES is more than 566000 vnodes to reclaim
+ * whenever vnlru_proc() becomes active.
*/
static u_long wantfreevnodes;
-SYSCTL_ULONG(_vfs, OID_AUTO, wantfreevnodes, CTLFLAG_RW, &wantfreevnodes, 0, "");
-/* Number of vnodes in the free list. */
+SYSCTL_ULONG(_vfs, OID_AUTO, wantfreevnodes, CTLFLAG_RW,
+ &wantfreevnodes, 0, "Target for minimum number of \"free\" vnodes");
static u_long freevnodes;
-SYSCTL_ULONG(_vfs, OID_AUTO, freevnodes, CTLFLAG_RD, &freevnodes, 0,
- "Number of vnodes in the free list");
+SYSCTL_ULONG(_vfs, OID_AUTO, freevnodes, CTLFLAG_RD,
+ &freevnodes, 0, "Number of \"free\" vnodes");
+/*
+ * The vfs.vlru_allow_cache_src sysctl variable is no longer used but
+ * the sysctl remains to provide ABI compatibility. The new code frees
+ * namecache sources as the last chance to satisfy the highest watermark,
+ * instead of selecting the source vnodes randomly. This provides good
+ * enough behaviour to keep vn_fullpath() working in most situations.
+ * The filesystem layout with deep trees, where the depricated knob was
+ * required, is thus handled automatically.
+ */
static int vlru_allow_cache_src;
SYSCTL_INT(_vfs, OID_AUTO, vlru_allow_cache_src, CTLFLAG_RW,
- &vlru_allow_cache_src, 0, "Allow vlru to reclaim source vnode");
+ &vlru_allow_cache_src, 0, "Placeholder for API compatibility (unused)");
static u_long recycles_count;
SYSCTL_ULONG(_vfs, OID_AUTO, recycles, CTLFLAG_RD, &recycles_count, 0,
- "Number of vnodes recycled to avoid exceding kern.maxvnodes");
+ "Number of vnodes recycled to meet vnode cache targets");
/*
* Various variables used for debugging the new implementation of
@@ -272,14 +299,13 @@ static int syncer_worklist_len;
static enum { SYNCER_RUNNING, SYNCER_SHUTTING_DOWN, SYNCER_FINAL_DELAY }
syncer_state;
-/*
- * Number of vnodes we want to exist at any one time. This is mostly used
- * to size hash tables in vnode-related code. It is normally not used in
- * getnewvnode(), as wantfreevnodes is normally nonzero.)
- *
- * XXX desiredvnodes is historical cruft and should not exist.
- */
+/* Target for maximum number of vnodes. */
int desiredvnodes;
+static int gapvnodes; /* gap between wanted and desired */
+static int vhiwat; /* enough extras after expansion */
+static int vlowat; /* minimal extras before expansion */
+static int vstir; /* nonzero to stir non-free vnodes */
+static volatile int vsmalltrigger = 8; /* pref to keep if > this many pages */
static int
sysctl_update_desiredvnodes(SYSCTL_HANDLER_ARGS)
@@ -290,6 +316,8 @@ sysctl_update_desiredvnodes(SYSCTL_HANDLER_ARGS)
if ((error = sysctl_handle_int(oidp, arg1, arg2, req)) != 0)
return (error);
if (old_desiredvnodes != desiredvnodes) {
+ wantfreevnodes = desiredvnodes / 4;
+ /* XXX locking seems to be incomplete. */
vfs_hash_changesize(desiredvnodes);
cache_changesize(desiredvnodes);
}
@@ -298,9 +326,9 @@ sysctl_update_desiredvnodes(SYSCTL_HANDLER_ARGS)
SYSCTL_PROC(_kern, KERN_MAXVNODES, maxvnodes,
CTLTYPE_INT | CTLFLAG_MPSAFE | CTLFLAG_RW, &desiredvnodes, 0,
- sysctl_update_desiredvnodes, "I", "Maximum number of vnodes");
+ sysctl_update_desiredvnodes, "I", "Target for maximum number of vnodes");
SYSCTL_ULONG(_kern, OID_AUTO, minvnodes, CTLFLAG_RW,
- &wantfreevnodes, 0, "Minimum number of vnodes (legacy)");
+ &wantfreevnodes, 0, "Old name for vfs.wantfreevnodes (legacy)");
static int vnlru_nowhere;
SYSCTL_INT(_debug, OID_AUTO, vnlru_nowhere, CTLFLAG_RW,
&vnlru_nowhere, 0, "Number of times the vnlru process ran without success");
@@ -331,11 +359,71 @@ PCTRIE_DEFINE(BUF, buf, b_lblkno, buf_trie_alloc, buf_trie_free);
*
* Reevaluate the following cap on the number of vnodes after the physical
* memory size exceeds 512GB. In the limit, as the physical memory size
- * grows, the ratio of physical pages to vnodes approaches sixteen to one.
+ * grows, the ratio of the memory size in KB to to vnodes approaches 64:1.
*/
#ifndef MAXVNODES_MAX
-#define MAXVNODES_MAX (512 * (1024 * 1024 * 1024 / (int)PAGE_SIZE / 16))
+#define MAXVNODES_MAX (512 * 1024 * 1024 / 64) /* 8M */
#endif
+
+/*
+ * Initialize a vnode as it first enters the zone.
+ */
+static int
+vnode_init(void *mem, int size, int flags)
+{
+ struct vnode *vp;
+ struct bufobj *bo;
+
+ vp = mem;
+ bzero(vp, size);
+ /*
+ * Setup locks.
+ */
+ vp->v_vnlock = &vp->v_lock;
+ mtx_init(&vp->v_interlock, "vnode interlock", NULL, MTX_DEF);
+ /*
+ * By default, don't allow shared locks unless filesystems opt-in.
+ */
+ lockinit(vp->v_vnlock, PVFS, "vnode", VLKTIMEOUT,
+ LK_NOSHARE | LK_IS_VNODE);
+ /*
+ * Initialize bufobj.
+ */
+ bo = &vp->v_bufobj;
+ bo->__bo_vnode = vp;
+ rw_init(BO_LOCKPTR(bo), "bufobj interlock");
+ bo->bo_private = vp;
+ TAILQ_INIT(&bo->bo_clean.bv_hd);
+ TAILQ_INIT(&bo->bo_dirty.bv_hd);
+ /*
+ * Initialize namecache.
+ */
+ LIST_INIT(&vp->v_cache_src);
+ TAILQ_INIT(&vp->v_cache_dst);
+ /*
+ * Initialize rangelocks.
+ */
+ rangelock_init(&vp->v_rl);
+ return (0);
+}
+
+/*
+ * Free a vnode when it is cleared from the zone.
+ */
+static void
+vnode_fini(void *mem, int size)
+{
+ struct vnode *vp;
+ struct bufobj *bo;
+
+ vp = mem;
+ rangelock_destroy(&vp->v_rl);
+ lockdestroy(vp->v_vnlock);
+ mtx_destroy(&vp->v_interlock);
+ bo = &vp->v_bufobj;
+ rw_destroy(BO_LOCKPTR(bo));
+}
+
static void
vntblinit(void *dummy __unused)
{
@@ -345,15 +433,16 @@ vntblinit(void *dummy __unused)
/*
* Desiredvnodes is a function of the physical memory size and the
* kernel's heap size. Generally speaking, it scales with the
- * physical memory size. The ratio of desiredvnodes to physical pages
- * is one to four until desiredvnodes exceeds 98,304. Thereafter, the
- * marginal ratio of desiredvnodes to physical pages is one to
- * sixteen. However, desiredvnodes is limited by the kernel's heap
+ * physical memory size. The ratio of desiredvnodes to the physical
+ * memory size is 1:16 until desiredvnodes exceeds 98,304.
+ * Thereafter, the
+ * marginal ratio of desiredvnodes to the physical memory size is
+ * 1:64. However, desiredvnodes is limited by the kernel's heap
* size. The memory required by desiredvnodes vnodes and vm objects
- * may not exceed one seventh of the kernel's heap size.
+ * must not exceed 1/7th of the kernel's heap size.
*/
- physvnodes = maxproc + cnt.v_page_count / 16 + 3 * min(98304 * 4,
- cnt.v_page_count) / 16;
+ physvnodes = maxproc + pgtok(cnt.v_page_count) / 64 +
+ 3 * min(98304 * 16, pgtok(cnt.v_page_count)) / 64;
virtvnodes = vm_kmem_size / (7 * (sizeof(struct vm_object) +
sizeof(struct vnode)));
desiredvnodes = min(physvnodes, virtvnodes);
@@ -368,7 +457,7 @@ vntblinit(void *dummy __unused)
TAILQ_INIT(&vnode_free_list);
mtx_init(&vnode_free_list_mtx, "vnode_free_list", NULL, MTX_DEF);
vnode_zone = uma_zcreate("VNODE", sizeof (struct vnode), NULL, NULL,
- NULL, NULL, UMA_ALIGN_PTR, 0);
+ vnode_init, vnode_fini, UMA_ALIGN_PTR, 0);
vnodepoll_zone = uma_zcreate("VNODEPOLL", sizeof (struct vpollinfo),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
/*
@@ -742,35 +831,41 @@ vattr_null(struct vattr *vap)
* you set kern.maxvnodes to. Do not set kern.maxvnodes too low.
*/
static int
-vlrureclaim(struct mount *mp)
+vlrureclaim(struct mount *mp, int reclaim_nc_src, int trigger)
{
struct vnode *vp;
- int done;
- int trigger;
- int usevnodes;
- int count;
+ int count, done, target;
- /*
- * Calculate the trigger point, don't allow user
- * screwups to blow us up. This prevents us from
- * recycling vnodes with lots of resident pages. We
- * aren't trying to free memory, we are trying to
- * free vnodes.
- */
- usevnodes = desiredvnodes;
- if (usevnodes <= 0)
- usevnodes = 1;
- trigger = cnt.v_page_count * 2 / usevnodes;
done = 0;
vn_start_write(NULL, &mp, V_WAIT);
MNT_ILOCK(mp);
- count = mp->mnt_nvnodelistsize / 10 + 1;
- while (count != 0) {
+ count = mp->mnt_nvnodelistsize;
+ target = count * (int64_t)gapvnodes / imax(desiredvnodes, 1);
+ target = target / 10 + 1;
+ while (count != 0 && done < target) {
vp = TAILQ_FIRST(&mp->mnt_nvnodelist);
while (vp != NULL && vp->v_type == VMARKER)
vp = TAILQ_NEXT(vp, v_nmntvnodes);
if (vp == NULL)
break;
+ /*
+ * XXX LRU is completely broken for non-free vnodes. First
+ * by calling here in mountpoint order, then by moving
+ * unselected vnodes to the end here, and most grossly by
+ * removing the vlruvp() function that was supposed to
+ * maintain the order. (This function was born broken
+ * since syncer problems prevented it doing anything.) The
+ * order is closer to LRC (C = Created).
+ *
+ * LRU reclaiming of vnodes seems to have last worked in
+ * FreeBSD-3 where LRU wasn't mentioned under any spelling.
+ * Then there was no hold count, and inactive vnodes were
+ * simply put on the free list in LRU order. The separate
+ * lists also break LRU. We prefer to reclaim from the
+ * free list for technical reasons. This tends to thrash
+ * the free list to keep very unrecently used held vnodes.
+ * The problem is mitigated by keeping the free list large.
+ */
TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
TAILQ_INSERT_TAIL(&mp->mnt_nvnodelist, vp, v_nmntvnodes);
--count;
@@ -779,10 +874,12 @@ vlrureclaim(struct mount *mp)
/*
* If it's been deconstructed already, it's still
* referenced, or it exceeds the trigger, skip it.
+ * Also skip free vnodes. We are trying to make space
+ * to expand the free list, not reduce it.
*/
if (vp->v_usecount ||
- (!vlru_allow_cache_src &&
- !LIST_EMPTY(&(vp)->v_cache_src)) ||
+ (!reclaim_nc_src && !LIST_EMPTY(&vp->v_cache_src)) ||
+ ((vp->v_iflag & VI_FREE) != 0) ||
(vp->v_iflag & VI_DOOMED) != 0 || (vp->v_object != NULL &&
vp->v_object->resident_page_count > trigger)) {
VI_UNLOCK(vp);
@@ -808,8 +905,8 @@ vlrureclaim(struct mount *mp)
* vnode lock before our VOP_LOCK() call fails.
*/
if (vp->v_usecount ||
- (!vlru_allow_cache_src &&
- !LIST_EMPTY(&(vp)->v_cache_src)) ||
+ (!reclaim_nc_src && !LIST_EMPTY(&vp->v_cache_src)) ||
+ (vp->v_iflag & VI_FREE) != 0 ||
(vp->v_object != NULL &&
vp->v_object->resident_page_count > trigger)) {
VOP_UNLOCK(vp, LK_INTERLOCK);
@@ -842,7 +939,7 @@ relock_mnt:
}
/*
- * Attempt to keep the free list at wantfreevnodes length.
+ * Attempt to reduce the free list by the requested amount.
*/
static void
vnlru_free(int count)
@@ -899,6 +996,24 @@ vnlru_free(int count)
mtx_lock(&vnode_free_list_mtx);
}
}
+
+/* XXX some names and initialization are bad for limits and watermarks. */
+static int
+vspace(void)
+{
+ int space;
+
+ gapvnodes = imax(desiredvnodes - wantfreevnodes, 100);
+ vhiwat = gapvnodes / 11; /* 9% -- just under the 10% in vlrureclaim() */
+ vlowat = vhiwat / 2;
+ if (numvnodes > desiredvnodes)
+ return (0);
+ space = desiredvnodes - numvnodes;
+ if (freevnodes > wantfreevnodes)
+ space += freevnodes - wantfreevnodes;
+ return (space);
+}
+
/*
* Attempt to recycle vnodes in a context that is always safe to block.
* Calling vlrurecycle() from the bowels of filesystem code has some
@@ -911,18 +1026,36 @@ static void
vnlru_proc(void)
{
struct mount *mp, *nmp;
- int done;
- struct proc *p = vnlruproc;
+ unsigned long ofreevnodes, onumvnodes;
+ int done, force, reclaim_nc_src, trigger, usevnodes;
- EVENTHANDLER_REGISTER(shutdown_pre_sync, kproc_shutdown, p,
+ EVENTHANDLER_REGISTER(shutdown_pre_sync, kproc_shutdown, vnlruproc,
SHUTDOWN_PRI_FIRST);
+ force = 0;
for (;;) {
- kproc_suspend_check(p);
+ kproc_suspend_check(vnlruproc);
mtx_lock(&vnode_free_list_mtx);
- if (freevnodes > wantfreevnodes)
- vnlru_free(freevnodes - wantfreevnodes);
- if (numvnodes <= desiredvnodes * 9 / 10) {
+ /*
+ * If numvnodes is too large (due to desiredvnodes being
+ * adjusted using its sysctl, or emergency growth), first
+ * try to reduce it by discarding from the free list.
+ */
+ if (numvnodes > desiredvnodes && freevnodes > 0)
+ vnlru_free(ulmin(numvnodes - desiredvnodes,
+ freevnodes));
+ /*
+ * Sleep if the vnode cache is in a good state. This is
+ * when it is not over-full and has space for about a 4%
+ * or 9% expansion (by growing its size or inexcessively
+ * reducing its free list). Otherwise, try to reclaim
+ * space for a 10% expansion.
+ */
+ if (vstir && force == 0) {
+ force = 1;
+ vstir = 0;
+ }
+ if (vspace() >= vlowat && force == 0) {
vnlruproc_sig = 0;
wakeup(&vnlruproc_sig);
msleep(vnlruproc, &vnode_free_list_mtx,
@@ -931,30 +1064,66 @@ vnlru_proc(void)
}
mtx_unlock(&vnode_free_list_mtx);
done = 0;
+ ofreevnodes = freevnodes;
+ onumvnodes = numvnodes;
+ /*
+ * Calculate parameters for recycling. These are the same
+ * throughout the loop to give some semblance of fairness.
+ * The trigger point is to avoid recycling vnodes with lots
+ * of resident pages. We aren't trying to free memory; we
+ * are trying to recycle or at least free vnodes.
+ */
+ if (numvnodes <= desiredvnodes)
+ usevnodes = numvnodes - freevnodes;
+ else
+ usevnodes = numvnodes;
+ if (usevnodes <= 0)
+ usevnodes = 1;
+ /*
+ * The trigger value is is chosen to give a conservatively
+ * large value to ensure that it alone doesn't prevent
+ * making progress. The value can easily be so large that
+ * it is effectively infinite in some congested and
+ * misconfigured cases, and this is necessary. Normally
+ * it is about 8 to 100 (pages), which is quite large.
+ */
+ trigger = cnt.v_page_count * 2 / usevnodes;
+ if (force < 2)
+ trigger = vsmalltrigger;
+ reclaim_nc_src = force >= 3;
mtx_lock(&mountlist_mtx);
for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
if (vfs_busy(mp, MBF_NOWAIT | MBF_MNTLSTLOCK)) {
nmp = TAILQ_NEXT(mp, mnt_list);
continue;
}
- done += vlrureclaim(mp);
+ done += vlrureclaim(mp, reclaim_nc_src, trigger);
mtx_lock(&mountlist_mtx);
nmp = TAILQ_NEXT(mp, mnt_list);
vfs_unbusy(mp);
}
mtx_unlock(&mountlist_mtx);
+ if (onumvnodes > desiredvnodes && numvnodes <= desiredvnodes)
+ uma_reclaim();
if (done == 0) {
-#if 0
- /* These messages are temporary debugging aids */
- if (vnlru_nowhere < 5)
- printf("vnlru process getting nowhere..\n");
- else if (vnlru_nowhere == 5)
- printf("vnlru process messages stopped.\n");
-#endif
+ if (force == 0 || force == 1) {
+ force = 2;
+ continue;
+ }
+ if (force == 2) {
+ force = 3;
+ continue;
+ }
+ force = 0;
vnlru_nowhere++;
tsleep(vnlruproc, PPAUSE, "vlrup", hz * 3);
} else
kern_yield(PRI_USER);
+ /*
+ * After becoming active to expand above low water, keep
+ * active until above high water.
+ */
+ force = vspace() < vhiwat;
}
}
@@ -1028,22 +1197,31 @@ vtryrecycle(struct vnode *vp)
return (0);
}
+static void
+vcheckspace(void)
+{
+
+ if (vspace() < vlowat && vnlruproc_sig == 0) {
+ vnlruproc_sig = 1;
+ wakeup(vnlruproc);
+ }
+}
+
/*
- * Wait for available vnodes.
+ * Wait if necessary for space for a new vnode.
*/
static int
getnewvnode_wait(int suspended)
{
mtx_assert(&vnode_free_list_mtx, MA_OWNED);
- if (numvnodes > desiredvnodes) {
+ if (numvnodes >= desiredvnodes) {
if (suspended) {
/*
- * File system is beeing suspended, we cannot risk a
- * deadlock here, so allocate new vnode anyway.
+ * The file system is being suspended. We cannot
+ * risk a deadlock here, so allow allocation of
+ * another vnode even if this would give too many.
*/
- if (freevnodes > wantfreevnodes)
- vnlru_free(freevnodes - wantfreevnodes);
return (0);
}
if (vnlruproc_sig == 0) {
@@ -1053,18 +1231,34 @@ getnewvnode_wait(int suspended)
msleep(&vnlruproc_sig, &vnode_free_list_mtx, PVFS,
"vlruwk", hz);
}
- return (numvnodes > desiredvnodes ? ENFILE : 0);
+ /* Post-adjust like the pre-adjust in getnewvnode(). */
+ if (numvnodes + 1 > desiredvnodes && freevnodes > 1)
+ vnlru_free(1);
+ return (numvnodes >= desiredvnodes ? ENFILE : 0);
}
+/*
+ * This hack is fragile, and probably not needed any more now that the
+ * watermark handling works.
+ */
void
getnewvnode_reserve(u_int count)
{
struct thread *td;
+ /* Pre-adjust like the pre-adjust in getnewvnode(), with any count. */
+ /* XXX no longer so quick, but this part is not racy. */
+ mtx_lock(&vnode_free_list_mtx);
+ if (numvnodes + count > desiredvnodes && freevnodes > wantfreevnodes)
+ vnlru_free(ulmin(numvnodes + count - desiredvnodes,
+ freevnodes - wantfreevnodes));
+ mtx_unlock(&vnode_free_list_mtx);
+
td = curthread;
/* First try to be quick and racy. */
if (atomic_fetchadd_long(&numvnodes, count) + count <= desiredvnodes) {
td->td_vp_reserv += count;
+ vcheckspace(); /* XXX no longer so quick, but more racy */
return;
} else
atomic_subtract_long(&numvnodes, count);
@@ -1077,9 +1271,18 @@ getnewvnode_reserve(u_int count)
atomic_add_long(&numvnodes, 1);
}
}
+ vcheckspace();
mtx_unlock(&vnode_free_list_mtx);
}
+/*
+ * This hack is fragile, especially if desiredvnodes or wantvnodes are
+ * misconfgured or changed significantly. Reducing desiredvnodes below
+ * the reserved amount should cause bizarre behaviour like reducing it
+ * below the number of active vnodes -- the system will try to reduce
+ * numvnodes to match, but should fail, so the subtraction below should
+ * not overflow.
+ */
void
getnewvnode_drop_reserve(void)
{
@@ -1098,8 +1301,9 @@ getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops,
struct vnode **vpp)
{
struct vnode *vp;
- struct bufobj *bo;
struct thread *td;
+ struct lock_object *lo;
+ static int cyclecount;
int error;
CTR3(KTR_VFS, "%s: mp %p with tag %s", __func__, mp, tag);
@@ -1110,57 +1314,77 @@ getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops,
goto alloc;
}
mtx_lock(&vnode_free_list_mtx);
+ if (numvnodes < desiredvnodes)
+ cyclecount = 0;
+ else if (cyclecount++ >= freevnodes) {
+ cyclecount = 0;
+ vstir = 1;
+ }
/*
- * Lend our context to reclaim vnodes if they've exceeded the max.
+ * Grow the vnode cache if it will not be above its target max
+ * after growing. Otherwise, if the free list is nonempty, try
+ * to reclaim 1 item from it before growing the cache (possibly
+ * above its target max if the reclamation failed or is delayed).
+ * Otherwise, wait for some space. In all cases, schedule
+ * vnlru_proc() if we are getting short of space. The watermarks
+ * should be chosen so that we never wait or even reclaim from
+ * the free list to below its target minimum.
*/
- if (freevnodes > wantfreevnodes)
+ if (numvnodes + 1 <= desiredvnodes)
+ ;
+ else if (freevnodes > 0)
vnlru_free(1);
- error = getnewvnode_wait(mp != NULL && (mp->mnt_kern_flag &
- MNTK_SUSPEND));
+ else {
+ error = getnewvnode_wait(mp != NULL && (mp->mnt_kern_flag &
+ MNTK_SUSPEND));
#if 0 /* XXX Not all VFS_VGET/ffs_vget callers check returns. */
- if (error != 0) {
- mtx_unlock(&vnode_free_list_mtx);
- return (error);
- }
+ if (error != 0) {
+ mtx_unlock(&vnode_free_list_mtx);
+ return (error);
+ }
#endif
+ }
+ vcheckspace();
atomic_add_long(&numvnodes, 1);
mtx_unlock(&vnode_free_list_mtx);
alloc:
atomic_add_long(&vnodes_created, 1);
- vp = (struct vnode *) uma_zalloc(vnode_zone, M_WAITOK|M_ZERO);
- /*
- * Setup locks.
- */
- vp->v_vnlock = &vp->v_lock;
- mtx_init(&vp->v_interlock, "vnode interlock", NULL, MTX_DEF);
- /*
- * By default, don't allow shared locks unless filesystems
- * opt-in.
- */
- lockinit(vp->v_vnlock, PVFS, tag, VLKTIMEOUT, LK_NOSHARE | LK_IS_VNODE);
+ vp = (struct vnode *) uma_zalloc(vnode_zone, M_WAITOK);
/*
- * Initialize bufobj.
+ * Locks are given the generic name "vnode" when created.
+ * Follow the historic practice of using the filesystem
+ * name when they allocated, e.g., "zfs", "ufs", "nfs, etc.
+ *
+ * Locks live in a witness group keyed on their name. Thus,
+ * when a lock is renamed, it must also move from the witness
+ * group of its old name to the witness group of its new name.
+ *
+ * The change only needs to be made when the vnode moves
+ * from one filesystem type to another. We ensure that each
+ * filesystem use a single static name pointer for its tag so
+ * that we can compare pointers rather than doing a strcmp().
*/
- bo = &vp->v_bufobj;
- bo->__bo_vnode = vp;
- rw_init(BO_LOCKPTR(bo), "bufobj interlock");
- bo->bo_ops = &buf_ops_bio;
- bo->bo_private = vp;
- TAILQ_INIT(&bo->bo_clean.bv_hd);
- TAILQ_INIT(&bo->bo_dirty.bv_hd);
+ lo = &vp->v_vnlock->lock_object;
+ if (lo->lo_name != tag) {
+ lo->lo_name = tag;
+ WITNESS_DESTROY(lo);
+ WITNESS_INIT(lo, tag);
+ }
/*
- * Initialize namecache.
+ * By default, don't allow shared locks unless filesystems opt-in.
*/
- LIST_INIT(&vp->v_cache_src);
- TAILQ_INIT(&vp->v_cache_dst);
+ vp->v_vnlock->lock_object.lo_flags |= LK_NOSHARE;
/*
* Finalize various vnode identity bits.
*/
+ KASSERT(vp->v_object == NULL, ("stale v_object %p", vp));
+ KASSERT(vp->v_lockf == NULL, ("stale v_lockf %p", vp));
+ KASSERT(vp->v_pollinfo == NULL, ("stale v_pollinfo %p", vp));
vp->v_type = VNON;
vp->v_tag = tag;
vp->v_op = vops;
v_incr_usecount(vp);
- vp->v_data = NULL;
+ vp->v_bufobj.bo_ops = &buf_ops_bio;
#ifdef MAC
mac_vnode_init(vp);
if (mp != NULL && (mp->mnt_flag & MNT_MULTILABEL) == 0)
@@ -1169,11 +1393,10 @@ alloc:
printf("NULL mp in getnewvnode()\n");
#endif
if (mp != NULL) {
- bo->bo_bsize = mp->mnt_stat.f_iosize;
+ vp->v_bufobj.bo_bsize = mp->mnt_stat.f_iosize;
if ((mp->mnt_kern_flag & MNTK_NOKNOTE) != 0)
vp->v_vflag |= VV_NOKNOTE;
}
- rangelock_init(&vp->v_rl);
/*
* For the filesystems which do not use vfs_hash_insert(),
@@ -2399,7 +2622,7 @@ vholdl(struct vnode *vp)
mtx_lock(&vnode_free_list_mtx);
TAILQ_REMOVE(&vnode_free_list, vp, v_actfreelist);
freevnodes--;
- vp->v_iflag &= ~(VI_FREE|VI_AGE);
+ vp->v_iflag &= ~VI_FREE;
KASSERT((vp->v_iflag & VI_ACTIVE) == 0,
("Activating already active vnode"));
vp->v_iflag |= VI_ACTIVE;
@@ -2467,15 +2690,9 @@ vdropl(struct vnode *vp)
v_actfreelist);
mp->mnt_activevnodelistsize--;
}
- if (vp->v_iflag & VI_AGE) {
- TAILQ_INSERT_HEAD(&vnode_free_list, vp,
- v_actfreelist);
- } else {
- TAILQ_INSERT_TAIL(&vnode_free_list, vp,
- v_actfreelist);
- }
+ TAILQ_INSERT_TAIL(&vnode_free_list, vp,
+ v_actfreelist);
freevnodes++;
- vp->v_iflag &= ~VI_AGE;
vp->v_iflag |= VI_FREE;
mtx_unlock(&vnode_free_list_mtx);
} else {
@@ -2486,6 +2703,12 @@ vdropl(struct vnode *vp)
}
/*
* The vnode has been marked for destruction, so free it.
+ *
+ * The vnode will be returned to the zone where it will
+ * normally remain until it is needed for another vnode. We
+ * need to cleanup (or verify that the cleanup has already
+ * been done) any residual data left from its current use
+ * so as not to contaminate the freshly allocated vnode.
*/
CTR2(KTR_VFS, "%s: destroying the vnode %p", __func__, vp);
atomic_subtract_long(&numvnodes, 1);
@@ -2506,20 +2729,25 @@ vdropl(struct vnode *vp)
VNASSERT(TAILQ_EMPTY(&vp->v_cache_dst), vp, ("vp has namecache dst"));
VNASSERT(LIST_EMPTY(&vp->v_cache_src), vp, ("vp has namecache src"));
VNASSERT(vp->v_cache_dd == NULL, vp, ("vp has namecache for .."));
+ VNASSERT(TAILQ_EMPTY(&vp->v_rl.rl_waiters), vp,
+ ("Dangling rangelock waiters"));
VI_UNLOCK(vp);
#ifdef MAC
mac_vnode_destroy(vp);
#endif
- if (vp->v_pollinfo != NULL)
+ if (vp->v_pollinfo != NULL) {
destroy_vpollinfo(vp->v_pollinfo);
+ vp->v_pollinfo = NULL;
+ }
#ifdef INVARIANTS
/* XXX Elsewhere we detect an already freed vnode via NULL v_op. */
vp->v_op = NULL;
#endif
- rangelock_destroy(&vp->v_rl);
- lockdestroy(vp->v_vnlock);
- mtx_destroy(&vp->v_interlock);
- rw_destroy(BO_LOCKPTR(bo));
+ bzero(&vp->v_un, sizeof(vp->v_un));
+ vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
+ vp->v_iflag = 0;
+ vp->v_vflag = 0;
+ bo->bo_flag = 0;
uma_zfree(vnode_zone, vp);
}
@@ -2884,6 +3112,7 @@ vgonel(struct vnode *vp)
* Clear the advisory locks and wake up waiting threads.
*/
(void)VOP_ADVLOCKPURGE(vp);
+ vp->v_lockf = NULL;
/*
* Delete from old mount point vnode list.
*/
@@ -2986,8 +3215,6 @@ vn_printf(struct vnode *vp, const char *fmt, ...)
}
if (vp->v_iflag & VI_MOUNT)
strlcat(buf, "|VI_MOUNT", sizeof(buf));
- if (vp->v_iflag & VI_AGE)
- strlcat(buf, "|VI_AGE", sizeof(buf));
if (vp->v_iflag & VI_DOOMED)
strlcat(buf, "|VI_DOOMED", sizeof(buf));
if (vp->v_iflag & VI_FREE)
@@ -2998,7 +3225,7 @@ vn_printf(struct vnode *vp, const char *fmt, ...)
strlcat(buf, "|VI_DOINGINACT", sizeof(buf));
if (vp->v_iflag & VI_OWEINACT)
strlcat(buf, "|VI_OWEINACT", sizeof(buf));
- flags = vp->v_iflag & ~(VI_MOUNT | VI_AGE | VI_DOOMED | VI_FREE |
+ flags = vp->v_iflag & ~(VI_MOUNT | VI_DOOMED | VI_FREE |
VI_ACTIVE | VI_DOINGINACT | VI_OWEINACT);
if (flags != 0) {
snprintf(buf2, sizeof(buf2), "|VI(0x%lx)", flags);
diff --git a/sys/ofed/include/linux/pci.h b/sys/ofed/include/linux/pci.h
index a2f02b5..2e6eef4 100644
--- a/sys/ofed/include/linux/pci.h
+++ b/sys/ofed/include/linux/pci.h
@@ -566,7 +566,11 @@ struct msix_entry {
/*
* Enable msix, positive errors indicate actual number of available
* vectors. Negative errors are failures.
+ *
+ * NB: define added to prevent this definition of pci_enable_msix from
+ * clashing with the native FreeBSD version.
*/
+#define pci_enable_msix linux_pci_enable_msix
static inline int
pci_enable_msix(struct pci_dev *pdev, struct msix_entry *entries, int nreq)
{
diff --git a/sys/sys/param.h b/sys/sys/param.h
index 3acaad7..e58c77e 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1002504 /* Master, propagated to newvers */
+#define __FreeBSD_version 1002505 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 26c0286..1c7b9db 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -1670,10 +1670,8 @@ ffs_vgetf(mp, ino, flags, vpp, ffs_flags)
ip = uma_zalloc(uma_inode, M_WAITOK | M_ZERO);
/* Allocate a new vnode/inode. */
- if (fs->fs_magic == FS_UFS1_MAGIC)
- error = getnewvnode("ufs", mp, &ffs_vnodeops1, &vp);
- else
- error = getnewvnode("ufs", mp, &ffs_vnodeops2, &vp);
+ error = getnewvnode("ufs", mp, fs->fs_magic == FS_UFS1_MAGIC ?
+ &ffs_vnodeops1 : &ffs_vnodeops2, &vp);
if (error) {
*vpp = NULL;
uma_zfree(uma_inode, ip);
diff --git a/tests/sys/file/flock_test.sh b/tests/sys/file/flock_test.sh
index ac3e799..ffd3d18 100755
--- a/tests/sys/file/flock_test.sh
+++ b/tests/sys/file/flock_test.sh
@@ -48,10 +48,11 @@ for n in `seq 1 $last_testcase`; do
todomsg=" # TODO: racy testcase (doesn't handle EINTR properly)"
fi
- $(dirname $0)/flock_helper . $n | grep -q SUCCEED
- if [ $? -eq 0 ]; then
+ output=$($(dirname $0)/flock_helper . $n)
+ if echo "$output" | grep -q SUCCEED; then
echo "ok $n$todomsg"
else
echo "not ok $n$todomsg"
+ echo "$output" >&2
fi
done
diff --git a/tools/regression/mac/mac_portacl/misc.sh b/tools/regression/mac/mac_portacl/misc.sh
index a1f152b..5a9e67b 100755
--- a/tools/regression/mac/mac_portacl/misc.sh
+++ b/tools/regression/mac/mac_portacl/misc.sh
@@ -6,10 +6,18 @@ if [ $? -ne 0 ]; then
echo "1..0 # SKIP MAC_PORTACL is unavailable."
exit 0
fi
+if [ $(id -u) -ne 0 ]; then
+ echo "1..0 # SKIP testcases must be run as root"
+ exit 0
+fi
ntest=1
check_bind() {
+ local host idtype name proto port udpflag
+
+ host="127.0.0.1"
+
idtype=${1}
name=${2}
proto=${3}
@@ -17,10 +25,10 @@ check_bind() {
[ "${proto}" = "udp" ] && udpflag="-u"
- out=`(
+ out=$(
case "${idtype}" in
uid|gid)
- ( echo -n | su -m ${name} -c "nc ${udpflag} -o -l 127.0.0.1 $port" 2>&1 ) &
+ ( echo -n | su -m ${name} -c "nc ${udpflag} -l -w 10 $host $port" 2>&1 ) &
;;
jail)
kill $$
@@ -29,9 +37,9 @@ check_bind() {
kill $$
esac
sleep 0.3
- echo | nc ${udpflag} -o 127.0.0.1 $port >/dev/null 2>&1
+ echo | nc ${udpflag} -w 10 $host $port >/dev/null 2>&1
wait
- )`
+ )
case "${out}" in
"nc: Permission denied"*|"nc: Operation not permitted"*)
echo fl
@@ -46,6 +54,8 @@ check_bind() {
}
bind_test() {
+ local expect_without_rule expect_with_rule idtype name proto port
+
expect_without_rule=${1}
expect_with_rule=${2}
idtype=${3}
@@ -54,40 +64,40 @@ bind_test() {
port=${6}
sysctl security.mac.portacl.rules= >/dev/null
- out=`check_bind ${idtype} ${name} ${proto} ${port}`
+ out=$(check_bind ${idtype} ${name} ${proto} ${port})
if [ "${out}" = "${expect_without_rule}" ]; then
echo "ok ${ntest}"
elif [ "${out}" = "ok" -o "${out}" = "fl" ]; then
- echo "not ok ${ntest}"
+ echo "not ok ${ntest} # '${out}' != '${expect_without_rule}'"
else
- echo "not ok ${ntest} # ${out}"
+ echo "not ok ${ntest} # unexpected output: '${out}'"
fi
- ntest=$((ntest+1))
+ : $(( ntest += 1 ))
if [ "${idtype}" = "uid" ]; then
- idstr=`id -u ${name}`
+ idstr=$(id -u ${name})
elif [ "${idtype}" = "gid" ]; then
- idstr=`id -g ${name}`
+ idstr=$(id -g ${name})
else
idstr=${name}
fi
sysctl security.mac.portacl.rules=${idtype}:${idstr}:${proto}:${port} >/dev/null
- out=`check_bind ${idtype} ${name} ${proto} ${port}`
+ out=$(check_bind ${idtype} ${name} ${proto} ${port})
if [ "${out}" = "${expect_with_rule}" ]; then
echo "ok ${ntest}"
elif [ "${out}" = "ok" -o "${out}" = "fl" ]; then
- echo "not ok ${ntest}"
+ echo "not ok ${ntest} # '${out}' != '${expect_with_rule}'"
else
- echo "not ok ${ntest} # ${out}"
+ echo "not ok ${ntest} # unexpected output: '${out}'"
fi
- ntest=$((ntest+1))
+ : $(( ntest += 1 ))
sysctl security.mac.portacl.rules= >/dev/null
}
-reserved_high=`sysctl -n net.inet.ip.portrange.reservedhigh`
-suser_exempt=`sysctl -n security.mac.portacl.suser_exempt`
-port_high=`sysctl -n security.mac.portacl.port_high`
+reserved_high=$(sysctl -n net.inet.ip.portrange.reservedhigh)
+suser_exempt=$(sysctl -n security.mac.portacl.suser_exempt)
+port_high=$(sysctl -n security.mac.portacl.port_high)
restore_settings() {
sysctl -n net.inet.ip.portrange.reservedhigh=${reserved_high} >/dev/null
diff --git a/tools/regression/mac/mac_portacl/nobody.t b/tools/regression/mac/mac_portacl/nobody.t
index c0754eb..7d8dbd6 100755
--- a/tools/regression/mac/mac_portacl/nobody.t
+++ b/tools/regression/mac/mac_portacl/nobody.t
@@ -10,6 +10,8 @@ echo "1..64"
# behaviour.
# mac_portacl has no impact on ports <= net.inet.ip.portrange.reservedhigh.
+trap restore_settings EXIT INT TERM
+
sysctl security.mac.portacl.suser_exempt=1 >/dev/null
sysctl net.inet.ip.portrange.reservedhigh=78 >/dev/null
@@ -63,5 +65,3 @@ bind_test fl ok gid nobody tcp 77
bind_test ok ok gid nobody tcp 7777
bind_test fl ok gid nobody udp 77
bind_test ok ok gid nobody udp 7777
-
-restore_settings
diff --git a/tools/regression/mac/mac_portacl/root.t b/tools/regression/mac/mac_portacl/root.t
index 626bdfa..9ed452f 100755
--- a/tools/regression/mac/mac_portacl/root.t
+++ b/tools/regression/mac/mac_portacl/root.t
@@ -8,6 +8,8 @@ echo "1..48"
# Verify if security.mac.portacl.suser_exempt=1 really exempts super-user.
+trap restore_settings EXIT INT TERM
+
sysctl security.mac.portacl.suser_exempt=1 >/dev/null
bind_test ok ok uid root tcp 77
@@ -47,5 +49,3 @@ bind_test fl ok gid root tcp 77
bind_test fl ok gid root tcp 7777
bind_test fl ok gid root udp 77
bind_test fl ok gid root udp 7777
-
-restore_settings
diff --git a/usr.sbin/crunch/crunchide/exec_elf32.c b/usr.sbin/crunch/crunchide/exec_elf32.c
index 52a340c..efbc60a 100644
--- a/usr.sbin/crunch/crunchide/exec_elf32.c
+++ b/usr.sbin/crunch/crunchide/exec_elf32.c
@@ -183,6 +183,7 @@ ELFNAMEEND(check)(int fd, const char *fn)
#endif
case EM_AARCH64: break;
case EM_ARM: break;
+ case EM_IA_64: break;
case EM_MIPS: break;
case /* EM_MIPS_RS3_LE */ EM_MIPS_RS4_BE: break;
case EM_PPC: break;
diff --git a/usr.sbin/sysrc/sysrc b/usr.sbin/sysrc/sysrc
index 2a24551..e384dff 100644
--- a/usr.sbin/sysrc/sysrc
+++ b/usr.sbin/sysrc/sysrc
@@ -40,18 +40,23 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
#
# Version information
#
-SYSRC_VERSION="6.5 Sep-1,2015"
+SYSRC_VERSION="7.0 Sep-13,2015"
#
# Options
#
CHECK_ONLY=
+DEFAULT=
DELETE=
DESCRIBE=
+EXISTING_ONLY=
IGNORE_UNKNOWNS=
JAIL=
+LIST_SERVICE_CONFS=
+LIST_CONFS=
QUIET=
ROOTDIR=
+SERVICE=
SHOW_ALL=
SHOW_EQUALS=
SHOW_FILE=
@@ -80,7 +85,8 @@ die()
#
usage()
{
- f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm"
+ f_err "Usage: %s [OPTIONS] %s\n" "$pgm" \
+ "{name[[+|-]=value] ... | -a | -A | -l | -L [name ...]}"
f_err "Try \`%s --help' for more information.\n" "$pgm"
die
}
@@ -95,6 +101,8 @@ help()
local envfmt="\t%-17s%s\n"
f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm"
+ f_err "Usage: %s [OPTIONS] -a | -A\n" "$pgm"
+ f_err "Usage: %s [OPTIONS] -l | -L [name ...]\n" "$pgm"
f_err "OPTIONS:\n"
f_err "$optfmt" "-a" \
@@ -113,6 +121,8 @@ help()
"Print query results as \`var=value' (useful for producing"
f_err "$optfmt" "" \
"output to be fed back in). Ignored if \`-n' is specified."
+ f_err "$optfmt" "-E" \
+ "Existing files only with \`-[lL]' or when changing a setting."
f_err "$optfmt" "-f file" \
"Operate on the specified file(s) instead of rc_conf_files."
f_err "$optfmt" "" \
@@ -129,12 +139,20 @@ help()
"The jid or name of the jail to operate within (overrides"
f_err "$optfmt" "" \
"\`-R dir'; requires jexec(8))."
+ f_err "$optfmt" "-l" \
+ "List configuration files used at startup on stdout and exit."
+ f_err "$optfmt" "-L" \
+ "List all configuration files including rc.conf.d entries."
f_err "$optfmt" "-n" \
"Show only variable values, not their names."
f_err "$optfmt" "-N" \
"Show only variable names, not their values."
f_err "$optfmt" "-q" \
"Quiet. Disable verbose and hide certain errors."
+ f_err "$optfmt" "-s name" \
+ "Process additional \`rc.conf.d' entries for service name."
+ f_err "$optfmt" "" \
+ "Ignored if \`-f file' is given."
f_err "$optfmt" "-R dir" \
"Operate within the root directory \`dir' rather than \`/'."
f_err "$optfmt" "-v" \
@@ -245,27 +263,33 @@ unset arg
#
# Process command-line flags
#
-while getopts aAcdDef:Fhij:nNqR:vxX flag; do
+while getopts aAcdDeEf:Fhij:lLnNqR:s:vxX flag; do
case "$flag" in
a) SHOW_ALL=${SHOW_ALL:-1} ;;
A) SHOW_ALL=2 ;;
c) CHECK_ONLY=1 ;;
d) DESCRIBE=1 ;;
- D) RC_CONFS= ;;
+ D) DEFAULT=1 RC_CONFS= ;;
e) SHOW_EQUALS=1 ;;
- f) RC_CONFS="$RC_CONFS${RC_CONFS:+ }$OPTARG" ;;
+ E) EXISTING_ONLY=1 ;;
+ f) DEFAULT= RC_CONFS="$RC_CONFS${RC_CONFS:+ }$OPTARG" ;;
F) SHOW_FILE=1 ;;
h) usage ;; # NOTREACHED
i) IGNORE_UNKNOWNS=1 ;;
j) [ "$OPTARG" ] ||
die "%s: Missing or null argument to \`-j' flag" "$pgm"
JAIL="$OPTARG" ;;
+ l) LIST_CONFS=1 ;;
+ L) LIST_SERVICE_CONFS=1 ;;
n) SHOW_NAME= ;;
N) SHOW_VALUE= ;;
q) QUIET=1 VERBOSE= ;;
R) [ "$OPTARG" ] ||
die "%s: Missing or null argument to \`-R' flag" "$pgm"
ROOTDIR="$OPTARG" ;;
+ s) [ "$OPTARG" ] ||
+ die "%s: Missing or null argument to \`-s' flag" "$pgm"
+ SERVICE="$OPTARG" ;;
v) VERBOSE=1 QUIET= ;;
x) DELETE=${DELETE:-1} ;;
X) DELETE=2 ;;
@@ -275,6 +299,129 @@ done
shift $(( $OPTIND - 1 ))
#
+# Process `-L' flag
+#
+if [ "$LIST_SERVICE_CONFS" ]; then
+ list=
+
+ #
+ # List rc_conf_files if no service names given
+ #
+ files=
+ [ $# -eq 0 ] && files=$( f_sysrc_get rc_conf_files )
+ for file in $files; do
+ if [ "$EXISTING_ONLY" ]; then
+ [ -e "$file" -a ! -d "$file" ] || continue
+ fi
+ case "$list" in
+ "$file"|*" $file"|"$file "*|*" $file "*) continue ;;
+ esac
+ list="$list $file"
+ done
+ list="${list# }"
+ if [ $# -eq 0 ]; then
+ if [ "$VERBOSE" ]; then
+ echo rc_conf_files: $list
+ elif [ "$SHOW_EQUALS" ]; then
+ echo "rc_conf_files=\"$list\""
+ fi
+ fi
+
+ #
+ # List rc.conf.d entries
+ #
+ retval=$SUCCESS
+ for service in ${*:-$( service -l )}; do
+ slist=
+ f_sysrc_service_configs $service files || retval=$? continue
+ for file in $files; do
+ if [ "$EXISTING_ONLY" ]; then
+ [ -e "$file" -a ! -d "$file" ] || continue
+ fi
+ if [ ! "$VERBOSE" -a ! "$SHOW_EQUALS" ]; then
+ case "$list" in
+ "$file"|*" $file"|"$file "*|*" $file "*)
+ continue ;;
+ esac
+ fi
+ slist="$slist $file"
+ done
+ slist="${slist# }"
+ if [ $# -gt 0 ]; then
+ [ "$slist" ] || retval=$?
+ fi
+ if [ "$VERBOSE" ]; then
+ [ "$slist" ] && echo "$service: $slist"
+ continue
+ elif [ "$SHOW_EQUALS" ]; then
+ [ "$slist" ] && echo "$service=\"$slist\""
+ continue
+ fi
+ list="$list${slist:+ }$slist"
+ done
+ if [ ! "$VERBOSE" -a ! "$SHOW_EQUALS" ]; then
+ if [ $# -eq 0 -o ! "$QUIET" ]; then
+ list="${list# }"
+ [ "$list" ] && echo $list
+ fi
+ fi
+
+ exit $retval
+fi
+
+#
+# Process `-s name' argument
+#
+if [ "$SERVICE" -a ! "${RC_CONFS+set}" ]; then
+ if f_sysrc_service_configs "$SERVICE" RC_CONFS; then
+ rc_conf_files=$( f_sysrc_get rc_conf_files )
+ RC_CONFS="$rc_conf_files${RC_CONFS:+ }$RC_CONFS"
+ unset rc_conf_files
+ else
+ unset RC_CONFS
+ fi
+fi
+
+#
+# Process `-E' option flag
+#
+if [ "$EXISTING_ONLY" ]; then
+ #
+ # To get f_sysrc_*() to ignore missing rc_conf_files, we have to use
+ # RC_CONFS to override the unpreened value. If RC_CONFS already has a
+ # value (`-D', `-f file', `-s name', or inherited from parent), use it.
+ # Otherwise, include filtered contents of rc_conf_files.
+ #
+ RC_CONFS=$(
+ if [ "${RC_CONFS+set}" ]; then
+ set -- $RC_CONFS
+ else
+ set -- $( f_sysrc_get rc_conf_files )
+ fi
+ while [ $# -gt 0 ]; do
+ [ -f "$1" ] && echo -n " $1"
+ shift
+ done
+ )
+ RC_CONFS="${RC_CONFS# }"
+fi
+
+#
+# Process `-l' option flag
+#
+if [ "$LIST_CONFS" ]; then
+ [ $# -eq 0 ] || usage
+ if [ "$DEFAULT" ]; then
+ echo "$RC_DEFAULTS"
+ elif [ "${RC_CONFS+set}" ]; then
+ echo "$RC_CONFS"
+ else
+ f_sysrc_get rc_conf_files
+ fi
+ exit $SUCCESS
+fi
+
+#
# [More] Sanity checks (e.g., "sysrc --")
#
[ $# -eq 0 -a ! "$SHOW_ALL" ] && usage # NOTREACHED
@@ -344,6 +491,10 @@ if [ "$JAIL" -o "$ROOTDIR" ]; then
$( [ "$SHOW_ALL" = "1" ] && echo \ -a )
$( [ "$SHOW_ALL" = "2" ] && echo \ -A )
${CHECK_ONLY:+-c}
+ ${DEFAULT:+-D}
+ ${EXISTING_ONLY:+-E}
+ ${LIST_CONFS:+-l}
+ ${LIST_SERVICE_CONFS:+-L}
${DESCRIBE:+-d}
${SHOW_EQUALS:+-e}
${IGNORE_UNKNOWNS:+-i}
@@ -351,6 +502,11 @@ if [ "$JAIL" -o "$ROOTDIR" ]; then
$( [ "$SHOW_VALUE" ] || echo \ -N )
$( [ "$SHOW_FILE" ] && echo \ -F )
"
+ if [ "$SERVICE" ]; then
+ escape "$SERVICE" _SERVICE
+ args="$args -s '$_SERVICE'"
+ unset _SERVICE
+ fi
if [ "${RC_CONFS+set}" ]; then
escape "$RC_CONFS" _RC_CONFS
args="$args -f '$_RC_CONFS'"
@@ -454,9 +610,10 @@ if [ "$SHOW_ALL" ]; then
#
IFS="$IFS|"
EXCEPT="IFS|EXCEPT|PATH|RC_DEFAULTS|OPTIND|DESCRIBE|SEP"
- EXCEPT="$EXCEPT|DELETE|SHOW_ALL|SHOW_EQUALS|SHOW_NAME"
- EXCEPT="$EXCEPT|SHOW_VALUE|SHOW_FILE|VERBOSE|RC_CONFS"
- EXCEPT="$EXCEPT|pgm|SUCCESS|FAILURE|CHECK_ONLY"
+ EXCEPT="$EXCEPT|DELETE|SHOW_ALL|SHOW_EQUALS|SHOW_NAME|DEFAULT"
+ EXCEPT="$EXCEPT|SHOW_VALUE|SHOW_FILE|VERBOSE|RC_CONFS|SERVICE"
+ EXCEPT="$EXCEPT|pgm|SUCCESS|FAILURE|CHECK_ONLY|EXISTING_ONLY"
+ EXCEPT="$EXCEPT|LIST_CONFS|LIST_SERVICE_CONFS"
EXCEPT="$EXCEPT|f_sysrc_desc_awk|f_sysrc_delete_awk"
#
@@ -479,7 +636,13 @@ if [ "$SHOW_ALL" ]; then
# explicit value, modifying the default behavior of
# source_rc_confs().
#
- [ "${RC_CONFS+set}" ] && rc_conf_files="$RC_CONFS"
+ if [ "${RC_CONFS+set}" ]; then
+ [ "$SHOW_ALL" = "1" -a "$SERVICE" -a \
+ ! "$DEFAULT" ] || rc_conf_files=
+ rc_conf_files="$rc_conf_files $RC_CONFS"
+ rc_conf_files="${rc_conf_files# }"
+ rc_conf_files="${rc_conf_files% }"
+ fi
source_rc_confs
diff --git a/usr.sbin/sysrc/sysrc.8 b/usr.sbin/sysrc/sysrc.8
index 2634e31..1047e15 100644
--- a/usr.sbin/sysrc/sysrc.8
+++ b/usr.sbin/sysrc/sysrc.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 2, 2015
+.Dd September 12, 2015
.Dt SYSRC 8
.Os
.Sh NAME
@@ -32,16 +32,27 @@
.Nd safely edit system rc files
.Sh SYNOPSIS
.Nm
-.Op Fl cdDeFhinNqvx
+.Op Fl cdDeEFhinNqvx
+.Op Fl s Ar name
.Op Fl f Ar file
.Op Fl j Ar jail | Fl R Ar dir
.Ar name Ns Op Ns Oo +|- Oc Ns = Ns Ar value
.Ar ...
.Nm
-.Op Fl cdDeFhinNqvx
+.Op Fl cdDeEFhinNqvx
+.Op Fl s Ar name
.Op Fl f Ar file
.Op Fl j Ar jail | Fl R Ar dir
.Fl a | A
+.Nm
+.Op Fl E
+.Op Fl s Ar name
+.Op Fl f Ar file
+.Fl l
+.Nm
+.Op Fl eEqv
+.Fl L
+.Op Ar name ...
.Sh DESCRIPTION
The
.Nm
@@ -81,6 +92,13 @@ Ignored if either
or
.Ql Fl F
is specified.
+.It Fl E
+When given
+.Sq Fl l
+or
+.Sq Fl L
+to list configuration files, only list those that exist.
+When changing a setting, prefer to modify existing files.
.It Fl f Ar file
Operate on the specified file(s) instead of the files obtained by reading the
.Sq rc_conf_files
@@ -105,6 +123,17 @@ or name of the
.Ar jail
to operate within
.Pq overrides So Fl R Ar dir Sc ; requires Xr jexec 8 .
+.It Fl l
+List configuration files used at startup on stdout and exit.
+.It Fl L
+List all configuration files including rc.conf.d entries on stdout and exit.
+Can be combined with
+.Sq Fl v
+or
+.Sq Fl e
+to show service names.
+.Nm
+exits with success if all named services are installed, failure otherwise.
.It Fl n
Show only variable values, not their names.
.It Fl N
@@ -112,11 +141,40 @@ Show only variable names, not their values.
.It Fl q
Quiet.
Disable verbose and hide certain errors.
+When combined with
+.Sq Fl L
+and one or more
+.Li Ar name
+arguments, provide only exit status and no output.
.It Fl R Ar dir
Operate within the root directory
.Sq Ar dir
rather than
.Sq / .
+.It Fl s Ar name
+If an
+.Li rc.d
+script of
+.Ar name
+exists
+.Po
+in
+.Dq /etc/rc.d
+or
+.Li local_startup
+directories
+.Pc ,
+process its
+.Dq rc.conf.d
+entries as potential overrides to
+.Sq rc_conf_files .
+See
+.Xr rc.subr 8
+for additional information on
+.Dq rc.conf.d .
+Can be combined with
+.Sq Fl l
+to list configuration files used by service at startup.
.It Fl v
Verbose.
Print the pathname of the specific
@@ -336,6 +394,10 @@ and
.It Pa /etc/defaults/rc.conf
.It Pa /etc/rc.conf
.It Pa /etc/rc.conf.local
+.It Pa /etc/rc.conf.d/name
+.It Pa /etc/rc.conf.d/name/*
+.It Pa /usr/local/etc/rc.conf.d/name
+.It Pa /usr/local/etc/rc.conf.d/name/*
.El
.Sh EXAMPLES
Below are some simple examples of how
@@ -397,6 +459,7 @@ cloned_interfaces+"alternate"
.Sh SEE ALSO
.Xr jls 1 ,
.Xr rc.conf 5 ,
+.Xr rc.subr 8 ,
.Xr jail 8 ,
.Xr jexec 8 ,
.Xr rc 8 ,
diff --git a/usr.sbin/uhsoctl/uhsoctl.c b/usr.sbin/uhsoctl/uhsoctl.c
index 21b6220..92efed8 100644
--- a/usr.sbin/uhsoctl/uhsoctl.c
+++ b/usr.sbin/uhsoctl/uhsoctl.c
@@ -453,6 +453,7 @@ set_nameservers(struct ctx *ctx, const char *respath, int ns, ...)
free(ctx->ns[i]);
}
free(ctx->ns);
+ ctx->ns = NULL;
}
fd = open(respath, O_RDWR | O_CREAT | O_NOFOLLOW, 0666);
OpenPOWER on IntegriCloud