diff options
67 files changed, 3603 insertions, 890 deletions
| @@ -22,11 +22,9 @@  /tests/client/full-t  /tests/client/prompt-t  /tests/client/rekey-t -/tests/data/.placeholder -/tests/data/test.keytab -/tests/data/test.password -/tests/data/test.principal -/tests/data/test.krbtype +/tests/config/keytab +/tests/config/password +/tests/config/principal  /tests/portable/asprintf-t  /tests/portable/mkstemp-t  /tests/portable/setenv-t diff --git a/Makefile.am b/Makefile.am index 0e1d99c..772a71e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,7 +26,6 @@ PERL_FILES = perl/Wallet/ACL.pm perl/Wallet/ACL/Base.pm			   \  	perl/t/schema.t perl/t/server.t perl/t/verifier-netdb.t		   \  	perl/t/verifier.t -AUTOMAKE_OPTIONS = foreign subdir-objects  ACLOCAL_AMFLAGS = -I m4  EXTRA_DIST = .gitignore LICENSE autogen client/wallet.pod		   \  	client/wallet-rekey.pod config/allow-extract config/keytab	   \ @@ -97,18 +96,22 @@ dist_pkgdata_DATA = perl/sql/Wallet-Schema-0.07-0.08-MySQL.sql	\  #  #     -Wconversion      http://bugs.debian.org/488884 (htons warnings)  # -# Last checked against gcc 4.4 (2010-08-15). -WARNINGS = -g -O -Wall -Wextra -Wendif-labels -Wformat=2 -Winit-self \ -	-Wswitch-enum -Wdeclaration-after-statement -Wshadow -Wpointer-arith \ -	-Wbad-function-cast -Wwrite-strings -Wstrict-prototypes \ -	-Wmissing-prototypes -Wnested-externs -Werror +# Last checked against gcc 4.6.1 (2011-05-04).  -D_FORTIFY_SOURCE=2 enables +# warn_unused_result attribute markings on glibc functions on Linux, which +# catches a few more issues. +WARNINGS = -g -O -D_FORTIFY_SOURCE=2 -Wall -Wextra -Wendif-labels	    \ +	-Wformat=2 -Winit-self -Wswitch-enum -Wdeclaration-after-statement  \ +	-Wshadow -Wpointer-arith -Wbad-function-cast -Wcast-align	    \ +	-Wwrite-strings -Wjump-misses-init -Wlogical-op			    \ +	-Wstrict-prototypes -Wmissing-prototypes -Wredundant-decls	    \ +	-Wnested-externs -Werror  warnings:  	$(MAKE) V=0 CFLAGS='$(WARNINGS)'  	$(MAKE) V=0 CFLAGS='$(WARNINGS)' $(check_PROGRAMS)  # Remove some additional files. -DISTCLEANFILES = perl/Makefile tests/data/.placeholder +DISTCLEANFILES = perl/Makefile  MAINTAINERCLEANFILES = Makefile.in aclocal.m4 build-aux/compile		     \  	build-aux/depcomp build-aux/install-sh build-aux/missing	     \  	client/wallet.1 config.h.in config.h.in~ configure		     \ @@ -163,7 +166,8 @@ check_LIBRARIES = tests/tap/libtap.a  tests_tap_libtap_a_CPPFLAGS = -I$(abs_top_srcdir)/tests $(KRB5_CPPFLAGS)  tests_tap_libtap_a_SOURCES = tests/tap/basic.c tests/tap/basic.h	\  	tests/tap/kerberos.c tests/tap/kerberos.h tests/tap/messages.c	\ -	tests/tap/messages.h tests/tap/process.c tests/tap/process.h +	tests/tap/messages.h tests/tap/process.c tests/tap/process.h	\ +	tests/tap/string.c tests/tap/string.h  # All of the test programs.  tests_portable_asprintf_t_SOURCES = tests/portable/asprintf-t.c \ @@ -27,6 +27,49 @@ wallet 1.0 (unreleased)      Add docs/objects-and-schemes, which provides a brief summary of the      current supported object types and ACL schemes. +    Update to rra-c-util 4.8: + +    * Look for krb5-config in /usr/kerberos/bin after the user's PATH. +    * Kerberos library probing fixes without transitive shared libraries. +    * Fix Autoconf warnings when probing for AIX's bundled Kerberos. +    * Avoid using krb5-config if --with-{krb5,gssapi}-{include,lib} given. +    * Correctly remove -I/usr/include from Kerberos and GSS-API flags. +    * Build on systems where krb5/krb5.h exists but krb5.h does not. +    * Pass --deps to krb5-config unless --enable-reduced-depends was used. +    * Do not use krb5-config results unless gssapi is supported. +    * Fix probing for Heimdal's libroken to work with older versions. +    * Update warning flags for GCC 4.6.1. +    * Update utility library and test suite for newer GCC warnings. +    * Fix broken GCC attribute markers causing compilation problems. +    * Suppress warnings on compilers that support gcc's __attribute__. +    * Add notices to all files copied over from rra-c-util. +    * Fix warnings when reporting memory allocation failure in messages.c. +    * Fix message utility library compiler warnings on 64-bit systems. +    * Include strings.h for additional POSIX functions where found. +    * Use an atexit handler to clean up after Kerberos tests. +    * Kerberos test configuration now goes in tests/config. +    * The principal of the test keytab is determined automatically. +    * Simplify the test suite calls for Kerberos and remctl tests. +    * Check for a missing ssize_t. +    * Improve the xstrndup utility function. +    * Checked asprintf variants are now void functions and cannot fail. +    * Fix use of long long in portable/mkstemp.c. +    * Fix test suite portability to Solaris. +    * Substantial improvements to the POD syntax and spelling checks. + +    Update to C TAP Harness 1.12: + +    * Fix compliation of runtests with more aggressive warnings. +    * Add a more complete usage message and a -h command-line flag. +    * Flush stderr before printing output from tests. +    * Better handle running shell tests without BUILD and SOURCE set. +    * Fix runtests to honor -s even if BUILD and -b aren't given. +    * runtests now frees all allocated resources on exit. +    * Only use feature-test macros when requested or built with gcc -ansi. +    * Drop is_double from the C TAP library to avoid requiring -lm. +    * Avoid using local in the shell libtap.sh library. +    * Suppress warnings on compilers that support gcc's __attribute__. +  wallet 0.12 (2010-08-25)      New client program wallet-rekey that, given a list of keytabs on the @@ -223,7 +223,7 @@ TESTING    support in the server, however, you will need to do some preparatory    work before running the test suite.  Review the files: -      tests/data/README +      tests/config/README        perl/t/data/README    and follow the instructions in those files to enable the full test diff --git a/configure.ac b/configure.ac index ffd7eeb..a79e42d 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,8 @@ AC_INIT([wallet], [0.12], [rra@stanford.edu])  AC_CONFIG_AUX_DIR([build-aux])  AC_CONFIG_LIBOBJ_DIR([portable])  AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE([1.11 check-news silent-rules]) +AM_INIT_AUTOMAKE([1.11 check-news dist-xz foreign silent-rules subdir-objects +    -Wall -Wno-override -Werror])  AM_MAINTAINER_MODE  AC_PROG_CC @@ -22,6 +23,18 @@ AM_PROG_CC_C_O  AC_PROG_INSTALL  AC_PROG_RANLIB +AC_ARG_WITH([wallet-server], +    [AC_HELP_STRING([--with-wallet-server=HOST], [Default wallet server])], +    [AS_IF([test x"$withval" != xno && test x"$withval" != xyes], +        [AC_DEFINE_UNQUOTED([WALLET_SERVER], ["$withval"], +            [Define to the default server host name.])])]) +AC_ARG_WITH([wallet-port], +    [AC_HELP_STRING([--with-wallet-port=PORT], +        [Default wallet server port])], +    [AS_IF([test x"$withval" != xno && test x"$withval" != xyes], +        [AC_DEFINE_UNQUOTED([WALLET_PORT], [$withval], +            [Define to the default server port.])])]) +  RRA_LIB_REMCTL  RRA_LIB_KRB5  RRA_LIB_KRB5_SWITCH @@ -30,8 +43,9 @@ AC_CHECK_FUNCS([krb5_get_init_creds_opt_alloc \      krb5_principal_get_realm])  AC_CHECK_FUNCS([krb5_get_init_creds_opt_free],      [RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS]) +AC_CHECK_DECLS([krb5_kt_free_entry], [], [], [RRA_INCLUDES_KRB5])  AC_CHECK_DECLS([krb5_kt_free_entry]) -AC_CHECK_MEMBERS([krb5_keytab_entry.keyblock], , , [#include <krb5.h>]) +AC_CHECK_MEMBERS([krb5_keytab_entry.keyblock], [], [], [RRA_INCLUDES_KRB5])  RRA_LIB_KRB5_RESTORE  AC_HEADER_STDBOOL @@ -40,31 +54,18 @@ AC_CHECK_DECLS([snprintf, vsnprintf])  RRA_C_C99_VAMACROS  RRA_C_GNU_VAMACROS  AC_TYPE_LONG_LONG_INT +AC_CHECK_TYPES([ssize_t], [], [], +    [#include <sys/types.h>])  RRA_FUNC_SNPRINTF  AC_CHECK_FUNCS([setrlimit])  AC_REPLACE_FUNCS([asprintf mkstemp setenv strlcat strlcpy]) -AC_ARG_WITH([wallet-server], -    [AC_HELP_STRING([--with-wallet-server=HOST], [Default wallet server])], -    [AS_IF([test x"$withval" != xno && test x"$withval" != xyes], -        [AC_DEFINE_UNQUOTED([WALLET_SERVER], ["$withval"], -            [Define to the default server host name.])])]) -AC_ARG_WITH([wallet-port], -    [AC_HELP_STRING([--with-wallet-port=PORT], -        [Default wallet server port])], -    [AS_IF([test x"$withval" != xno && test x"$withval" != xyes], -        [AC_DEFINE_UNQUOTED([WALLET_PORT], [$withval], -            [Define to the default server port.])])]) -  AC_ARG_VAR([REMCTLD], [Path to the remctld binary])  AC_PATH_PROG([REMCTLD], [remctld], , [$PATH:/usr/sbin:/usr/local/sbin])  AS_IF([test x"$REMCTLD" != x],      [AC_DEFINE_UNQUOTED([PATH_REMCTLD], ["$REMCTLD"],          [Define to the full path to remctld to run remctl tests.])]) -dnl Create the tests/data directory for builds outside the source directory. -AC_CONFIG_COMMANDS([tests/data/.placeholder], [touch tests/data/.placeholder]) -  AC_CONFIG_HEADER([config.h])  AC_CONFIG_FILES([Makefile perl/Makefile.PL])  AC_CONFIG_FILES([tests/client/basic-t], [chmod +x tests/client/basic-t]) diff --git a/m4/gssapi.m4 b/m4/gssapi.m4 index 0a657ff..c596609 100644 --- a/m4/gssapi.m4 +++ b/m4/gssapi.m4 @@ -3,7 +3,8 @@ dnl  dnl Finds the compiler and linker flags for linking with GSS-API libraries.  dnl Provides the --with-gssapi, --with-gssapi-include, and --with-gssapi-lib  dnl configure option to specify a non-standard path to the GSS-API libraries. -dnl Uses krb5-config where available unless reduced dependencies is requested. +dnl Uses krb5-config where available unless reduced dependencies is requested +dnl or --with-gssapi-include or --with-gssapi-lib are given.  dnl  dnl Provides the macro RRA_LIB_GSSAPI and sets the substitution variables  dnl GSSAPI_CPPFLAGS, GSSAPI_LDFLAGS, and GSSAPI_LIBS.  Also provides @@ -11,13 +12,34 @@ dnl RRA_LIB_GSSAPI_SWITCH to set CPPFLAGS, LDFLAGS, and LIBS to include the  dnl GSS-API libraries, saving the ecurrent values, and RRA_LIB_GSSAPI_RESTORE  dnl to restore those settings to before the last RRA_LIB_GSSAPI_SWITCH.  dnl -dnl Depends on RRA_ENABLE_REDUCED_DEPENDS and RRA_SET_LDFLAGS. +dnl Also provides RRA_INCLUDES_KRB5, which are the headers to include when +dnl probing the Kerberos library properties. +dnl +dnl Depends on RRA_KRB5_CONFIG, RRA_ENABLE_REDUCED_DEPENDS, and +dnl RRA_SET_LDFLAGS. +dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>.  dnl  dnl Written by Russ Allbery <rra@stanford.edu> -dnl Copyright 2005, 2006, 2007, 2008, 2009 -dnl     Board of Trustees, Leland Stanford Jr. University +dnl Copyright 2005, 2006, 2007, 2008, 2009, 2011, 2012 +dnl     The Board of Trustees of the Leland Stanford Junior University  dnl -dnl See LICENSE for licensing terms. +dnl This file is free software; the authors give unlimited permission to copy +dnl and/or distribute it, with or without modifications, as long as this +dnl notice is preserved. + +dnl Headers to include when probing for Kerberos library properties. +AC_DEFUN([RRA_INCLUDES_GSSAPI], [[ +#ifdef HAVE_GSSAPI_GSSAPI_H +# include <gssapi/gssapi.h> +#else +# include <gssapi.h> +#endif +#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H +# include <gssapi/gssapi_krb5.h> +#endif +]])  dnl Save the current CPPFLAGS, LDFLAGS, and LIBS settings and switch to  dnl versions that include the GSS-API flags.  Used as a wrapper, with @@ -68,18 +90,18 @@ AC_DEFUN([_RRA_LIB_GSSAPI_MANUAL],  [RRA_LIB_GSSAPI_SWITCH   rra_gssapi_extra=   LIBS= - AC_SEARCH_LIBS([res_search], [resolv], , + AC_SEARCH_LIBS([res_search], [resolv], [],      [AC_SEARCH_LIBS([__res_search], [resolv])])   AC_SEARCH_LIBS([gethostbyname], [nsl]) - AC_SEARCH_LIBS([socket], [socket], , -    [AC_CHECK_LIB([nsl], [socket], [LIBS="-lnsl -lsocket $LIBS"], , + AC_SEARCH_LIBS([socket], [socket], [], +    [AC_CHECK_LIB([nsl], [socket], [LIBS="-lnsl -lsocket $LIBS"], [],          [-lsocket])])   AC_SEARCH_LIBS([crypt], [crypt]) + AC_SEARCH_LIBS([roken_concat], [roken])   rra_gssapi_extra="$LIBS"   LIBS="$rra_gssapi_save_LIBS"   AC_CHECK_LIB([gssapi], [gss_import_name], -    [GSSAPI_LIBS="-lgssapi -lkrb5 -lasn1 -lroken -lcrypto -lcom_err" -     GSSAPI_LIBS="$GSSAPI_LIBS $rra_gssapi_extra"], +    [GSSAPI_LIBS="-lgssapi -lkrb5 -lasn1 -lcrypto -lcom_err $rra_gssapi_extra"],      [AC_CHECK_LIB([krb5support], [krb5int_getspecific],          [rra_gssapi_extra="-lkrb5support $rra_gssapi_extra"],          [AC_CHECK_LIB([pthreads], [pthread_setspecific], @@ -88,7 +110,7 @@ AC_DEFUN([_RRA_LIB_GSSAPI_MANUAL],                  [rra_gssapi_pthread="-lpthread"])])           AC_CHECK_LIB([krb5support], [krb5int_setspecific],              [rra_gssapi_extra="-lkrb5support $rra_gssapi_extra" -             rra_gssapi_extra="$rra_gssapi_extra $rra_gssapi_pthread"], , +             rra_gssapi_extra="$rra_gssapi_extra $rra_gssapi_pthread"], [],              [$rra_gssapi_pthread])])       AC_CHECK_LIB([com_err], [error_message],          [rra_gssapi_extra="-lcom_err $rra_gssapi_extra"]) @@ -101,7 +123,7 @@ AC_DEFUN([_RRA_LIB_GSSAPI_MANUAL],              [GSSAPI_LIBS="-lgss"],              [AC_MSG_ERROR([cannot find usable GSS-API library])])],          [$rra_gssapi_extra])], -    [-lkrb5 -lasn1 -lroken -lcrypto -lcom_err $rra_gssapi_extra]) +    [-lkrb5 -lasn1 -lcrypto -lcom_err $rra_gssapi_extra])   RRA_LIB_GSSAPI_RESTORE])  dnl Sanity-check the results of krb5-config and be sure we can really link a @@ -116,6 +138,44 @@ AC_DEFUN([_RRA_LIB_GSSAPI_CHECK],       _RRA_LIB_GSSAPI_PATHS       _RRA_LIB_GSSAPI_MANUAL])]) +dnl Determine GSS-API compiler and linker flags from krb5-config. +AC_DEFUN([_RRA_LIB_GSSAPI_CONFIG], +[RRA_KRB5_CONFIG([${rra_gssapi_root}], [gssapi], [GSSAPI], +    [_RRA_LIB_GSSAPI_CHECK], +    [_RRA_LIB_GSSAPI_PATHS +     _RRA_LIB_GSSAPI_MANUAL])]) + +dnl Check for a header using a file existence check rather than using +dnl AC_CHECK_HEADERS.  This is used if there were arguments to configure +dnl specifying the GSS-API library path, since we may have one header in the +dnl default include path and another under our explicitly-configured GSS-API +dnl location. +AC_DEFUN([_RRA_LIB_GSSAPI_CHECK_HEADER], +[AC_MSG_CHECKING([for $1]) + AS_IF([test -f "${rra_gssapi_incroot}/$1"], +    [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1]), [1], +        [Define to 1 if you have the <$1> header file.]) +     AC_MSG_RESULT([yes])], +    [AC_MSG_RESULT([no])])]) + +dnl Determine the GSS-API header location and probe for some other +dnl characteristics of the libraries.  We use a file existence check rather +dnl than letting the compiler probe for the right header location +AC_DEFUN([_RRA_LIB_GSSAPI_EXTRA], +[rra_gssapi_incroot= + AS_IF([test x"$rra_gssapi_includedir" != x], +    [rra_gssapi_incroot="$rra_gssapi_includedir"], +    [AS_IF([test x"$rra_gssapi_root" != x], +        [rra_gssapi_incroot="${rra_gssapi_root}/include"])]) + AS_IF([test x"$rra_gssapi_incroot" = x], +    [AC_CHECK_HEADERS([gssapi/gssapi.h gssapi/gssapi_krb5.h])], +    [_RRA_LIB_GSSAPI_CHECK_HEADER([gssapi/gssapi.h]) +     _RRA_LIB_GSSAPI_CHECK_HEADER([gssapi/gssapi_krb5.h])]) + AC_CHECK_DECL([GSS_C_NT_USER_NAME], +    [AC_DEFINE([HAVE_GSS_RFC_OIDS], 1, +       [Define to 1 if the GSS-API library uses RFC-compliant OIDs.])], [], +    [RRA_INCLUDES_GSSAPI])]) +  dnl The main macro.  AC_DEFUN([RRA_LIB_GSSAPI],  [AC_REQUIRE([RRA_ENABLE_REDUCED_DEPENDS]) @@ -148,24 +208,12 @@ AC_DEFUN([RRA_LIB_GSSAPI],   AS_IF([test x"$rra_reduced_depends" = xtrue],      [_RRA_LIB_GSSAPI_PATHS       _RRA_LIB_GSSAPI_REDUCED], -    [AC_ARG_VAR([KRB5_CONFIG], [Path to krb5-config]) -     AS_IF([test x"$rra_gssapi_root" != x && test -z "$KRB5_CONFIG"], -         [AS_IF([test -x "${rra_gssapi_root}/bin/krb5-config"], -             [KRB5_CONFIG="${rra_gssapi_root}/bin/krb5-config"])], -         [AC_PATH_PROG([KRB5_CONFIG], [krb5-config])]) -     AS_IF([test x"$KRB5_CONFIG" != x && test -x "$KRB5_CONFIG"], -         [AC_CACHE_CHECK([for gssapi support in krb5-config], -             [rra_cv_lib_gssapi_config], -             [AS_IF(["$KRB5_CONFIG" 2>&1 | grep gssapi >/dev/null 2>&1], -                 [rra_cv_lib_gssapi_config=yes], -                 [rra_cv_lib_gssapi_config=no])]) -          AS_IF([test "$rra_cv_lib_gssapi_config" = yes], -              [GSSAPI_CPPFLAGS=`"$KRB5_CONFIG" --cflags gssapi 2>/dev/null` -               GSSAPI_LIBS=`"$KRB5_CONFIG" --libs gssapi 2>/dev/null`], -              [GSSAPI_CPPFLAGS=`"$KRB5_CONFIG" --cflags 2>/dev/null` -               GSSAPI_LIBS=`"$KRB5_CONFIG" --libs 2>/dev/null`]) -          GSSAPI_CPPFLAGS=`echo "$GSSAPI_CPPFLAGS" \ -              | sed 's%-I/usr/include ?%%'` -          _RRA_LIB_GSSAPI_CHECK], -         [_RRA_LIB_GSSAPI_PATHS -          _RRA_LIB_GSSAPI_MANUAL])])]) +    [AS_IF([test x"$rra_gssapi_includedir" = x \ +            && test x"$rra_gssapi_libdir" = x], +        [_RRA_LIB_GSSAPI_CONFIG], +        [_RRA_LIB_GSSAPI_PATHS +         _RRA_LIB_GSSAPI_MANUAL])]) + + RRA_LIB_GSSAPI_SWITCH + _RRA_LIB_GSSAPI_EXTRA + RRA_LIB_GSSAPI_RESTORE]) diff --git a/m4/krb5-config.m4 b/m4/krb5-config.m4 new file mode 100644 index 0000000..d73085f --- /dev/null +++ b/m4/krb5-config.m4 @@ -0,0 +1,101 @@ +dnl Use krb5-config to get link paths for Kerberos libraries. +dnl +dnl Provides one macro, RRA_KRB5_CONFIG, which attempts to get compiler and +dnl linker flags for a library via krb5-config and sets the appropriate shell +dnl variables.  Defines the Autoconf variable PATH_KRB5_CONFIG, which can be +dnl used to find the default path to krb5-config. +dnl +dnl Depends on RRA_ENABLE_REDUCED_DEPENDS. +dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl +dnl Written by Russ Allbery <rra@stanford.edu> +dnl Copyright 2011, 2012 +dnl     The Board of Trustees of the Leland Stanford Junior University +dnl +dnl This file is free software; the authors give unlimited permission to copy +dnl and/or distribute it, with or without modifications, as long as this +dnl notice is preserved. + +dnl Check for krb5-config in the user's path and set PATH_KRB5_CONFIG.  This +dnl is moved into a separate macro so that it can be loaded via AC_REQUIRE, +dnl meaning it will only be run once even if we link with multiple krb5-config +dnl libraries. +AC_DEFUN([_RRA_KRB5_CONFIG_PATH], +[AC_ARG_VAR([PATH_KRB5_CONFIG], [Path to krb5-config]) + AC_PATH_PROG([PATH_KRB5_CONFIG], [krb5-config], [], +    [${PATH}:/usr/kerberos/bin])]) + +dnl Check whether the --deps flag is supported by krb5-config.  Takes the path +dnl to krb5-config to use.  Note that this path is not embedded in the cache +dnl variable, so this macro implicitly assumes that we will always use the +dnl same krb5-config program. +AC_DEFUN([_RRA_KRB5_CONFIG_DEPS], +[AC_REQUIRE([_RRA_KRB5_CONFIG_PATH]) + AC_CACHE_CHECK([for --deps support in krb5-config], +    [rra_cv_krb5_config_deps], +    [AS_IF(["$1" 2>&1 | grep deps >/dev/null 2>&1], +        [rra_cv_krb5_config_deps=yes], +        [rra_cv_krb5_config_deps=no])])]) + +dnl Obtain the library flags for a particular library using krb5-config. +dnl Takes the path to the krb5-config program to use, the argument to +dnl krb5-config to use, and the variable prefix under which to store the +dnl library flags. +AC_DEFUN([_RRA_KRB5_CONFIG_LIBS], +[AC_REQUIRE([_RRA_KRB5_CONFIG_PATH]) + AC_REQUIRE([RRA_ENABLE_REDUCED_DEPENDS]) + _RRA_KRB5_CONFIG_DEPS([$1]) + AS_IF([test x"$rra_reduced_depends" = xfalse \ +        && test x"$rra_cv_krb5_config_deps" = xyes], +    [$3[]_LIBS=`"$1" --deps --libs $2 2>/dev/null`], +    [$3[]_LIBS=`"$1" --libs $2 2>/dev/null`])]) + +dnl Attempt to find the flags for a library using krb5-config.  Takes the +dnl following arguments (in order): +dnl +dnl 1. The root directory for the library in question, generally from an +dnl    Autoconf --with flag.  Used by preference as the path to krb5-config. +dnl +dnl 2. The argument to krb5-config to retrieve flags for this particular +dnl    library. +dnl +dnl 3. The variable prefix to use when setting CPPFLAGS and LIBS variables +dnl    based on the result of krb5-config. +dnl +dnl 4. Further actions to take if krb5-config was found and supported that +dnl    library type. +dnl +dnl 5. Further actions to take if krb5-config could not be used to get flags +dnl    for that library type. +dnl +dnl Special-case a krb5-config argument of krb5 and run krb5-config without an +dnl argument if that option was requested and not supported.  Old versions of +dnl krb5-config didn't take an argument to specify the library type, but +dnl always returned the flags for libkrb5. +AC_DEFUN([RRA_KRB5_CONFIG], +[AC_REQUIRE([_RRA_KRB5_CONFIG_PATH]) + rra_krb5_config_$3= + rra_krb5_config_$3[]_ok= + AS_IF([test x"$1" != x && test -x "$1/bin/krb5-config"], +    [rra_krb5_config_$3="$1/bin/krb5-config"], +    [rra_krb5_config_$3="$PATH_KRB5_CONFIG"]) + AS_IF([test x"$rra_krb5_config_$3" != x && test -x "$rra_krb5_config_$3"], +    [AC_CACHE_CHECK([for $2 support in krb5-config], [rra_cv_lib_$3[]_config], +         [AS_IF(["$rra_krb5_config_$3" 2>&1 | grep $2 >/dev/null 2>&1], +             [rra_cv_lib_$3[]_config=yes], +             [rra_cv_lib_$3[]_config=no])]) +     AS_IF([test "$rra_cv_lib_$3[]_config" = yes], +        [$3[]_CPPFLAGS=`"$rra_krb5_config_$3" --cflags $2 2>/dev/null` +         _RRA_KRB5_CONFIG_LIBS([$rra_krb5_config_$3], [$2], [$3]) +         rra_krb5_config_$3[]_ok=yes], +        [AS_IF([test x"$2" = xkrb5], +            [$3[]_CPPFLAGS=`"$rra_krb5_config_$3" --cflags 2>/dev/null` +             $3[]_LIBS=`"$rra_krb5_config_$3" --libs $2 2>/dev/null` +             rra_krb5_config_$3[]_ok=yes])])]) + AS_IF([test x"$rra_krb5_config_$3[]_ok" = xyes], +    [$3[]_CPPFLAGS=`echo "$$3[]_CPPFLAGS" | sed 's%-I/usr/include %%'` +     $3[]_CPPFLAGS=`echo "$$3[]_CPPFLAGS" | sed 's%-I/usr/include$%%'` +     $4], +    [$5])]) @@ -1,17 +1,18 @@ -dnl Find the compiler and linker flags for Kerberos v5. +dnl Find the compiler and linker flags for Kerberos.  dnl -dnl Finds the compiler and linker flags for linking with Kerberos v5 -dnl libraries.  Provides the --with-krb5, --with-krb5-include, and -dnl --with-krb5-lib configure options to specify non-standard paths to the -dnl Kerberos libraries.  Uses krb5-config where available unless reduced -dnl dependencies is requested. +dnl Finds the compiler and linker flags for linking with Kerberos libraries. +dnl Provides the --with-krb5, --with-krb5-include, and --with-krb5-lib +dnl configure options to specify non-standard paths to the Kerberos libraries. +dnl Uses krb5-config where available unless reduced dependencies is requested +dnl or --with-krb5-include or --with-krb5-lib are given.  dnl  dnl Provides the macro RRA_LIB_KRB5 and sets the substitution variables  dnl KRB5_CPPFLAGS, KRB5_LDFLAGS, and KRB5_LIBS.  Also provides  dnl RRA_LIB_KRB5_SWITCH to set CPPFLAGS, LDFLAGS, and LIBS to include the  dnl Kerberos libraries, saving the current values first, and  dnl RRA_LIB_KRB5_RESTORE to restore those settings to before the last -dnl RRA_LIB_KRB5_SWITCH. +dnl RRA_LIB_KRB5_SWITCH.  HAVE_KERBEROS will always be defined if RRA_LIB_KRB5 +dnl is used.  dnl  dnl If KRB5_CPPFLAGS, KRB5_LDFLAGS, or KRB5_LIBS are set before calling these  dnl macros, their values will be added to whatever the macros discover. @@ -32,14 +33,31 @@ dnl Also provides RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS, which checks  dnl whether krb5_get_init_creds_opt_free takes one argument or two.  Defines  dnl HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS if it takes two arguments.  dnl +dnl Also provides RRA_INCLUDES_KRB5, which are the headers to include when +dnl probing the Kerberos library properties. +dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl  dnl Written by Russ Allbery <rra@stanford.edu> -dnl Copyright 2005, 2006, 2007, 2008, 2009, 2010 -dnl     Board of Trustees, Leland Stanford Jr. University +dnl Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011 +dnl     The Board of Trustees of the Leland Stanford Junior University  dnl -dnl See LICENSE for licensing terms. +dnl This file is free software; the authors give unlimited permission to copy +dnl and/or distribute it, with or without modifications, as long as this +dnl notice is preserved. + +dnl Headers to include when probing for Kerberos library properties. +AC_DEFUN([RRA_INCLUDES_KRB5], [[ +#if HAVE_KRB5_H +# include <krb5.h> +#else +# include <krb5/krb5.h> +#endif +]])  dnl Save the current CPPFLAGS, LDFLAGS, and LIBS settings and switch to -dnl versions that include the Kerberos v5 flags.  Used as a wrapper, with +dnl versions that include the Kerberos flags.  Used as a wrapper, with  dnl RRA_LIB_KRB5_RESTORE, around tests.  AC_DEFUN([RRA_LIB_KRB5_SWITCH],  [rra_krb5_save_CPPFLAGS="$CPPFLAGS" @@ -69,44 +87,62 @@ AC_DEFUN([_RRA_LIB_KRB5_PATHS],          [AS_IF([test x"$rra_krb5_root" != x/usr],              [KRB5_CPPFLAGS="-I${rra_krb5_root}/include"])])])]) -dnl Does the appropriate library checks for reduced-dependency Kerberos v5 +dnl Check for a header using a file existence check rather than using +dnl AC_CHECK_HEADERS.  This is used if there were arguments to configure +dnl specifying the Kerberos header path, since we may have one header in the +dnl default include path and another under our explicitly-configured Kerberos +dnl location. +AC_DEFUN([_RRA_LIB_KRB5_CHECK_HEADER], +[AC_MSG_CHECKING([for $1]) + AS_IF([test -f "${rra_krb5_incroot}/$1"], +    [AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$1]), [1], +        [Define to 1 if you have the <$1> header file.]) +     AC_MSG_RESULT([yes])], +    [AC_MSG_RESULT([no])])]) + +dnl Does the appropriate library checks for reduced-dependency Kerberos  dnl linkage.  The single argument, if true, says to fail if Kerberos could not  dnl be found.  AC_DEFUN([_RRA_LIB_KRB5_REDUCED],  [RRA_LIB_KRB5_SWITCH   AC_CHECK_LIB([krb5], [krb5_init_context], [KRB5_LIBS="-lkrb5"],       [AS_IF([test x"$1" = xtrue], -         [AC_MSG_ERROR([cannot find usable Kerberos v5 library])])]) +         [AC_MSG_ERROR([cannot find usable Kerberos library])])])   LIBS="$KRB5_LIBS $LIBS" + AS_IF([test x"$rra_krb5_incroot" = x], +     [AC_CHECK_HEADERS([krb5.h krb5/krb5.h])], +     [_RRA_LIB_KRB5_CHECK_HEADER([krb5.h]) +      _RRA_LIB_KRB5_CHECK_HEADER([krb5/krb5.h])])   AC_CHECK_FUNCS([krb5_get_error_message],       [AC_CHECK_FUNCS([krb5_free_error_message])], -     [AC_CHECK_FUNCS([krb5_get_error_string], , -         [AC_CHECK_FUNCS([krb5_get_err_txt], , +     [AC_CHECK_FUNCS([krb5_get_error_string], [], +         [AC_CHECK_FUNCS([krb5_get_err_txt], [],               [AC_CHECK_LIB([ksvc], [krb5_svc_get_msg],                   [KRB5_LIBS="$KRB5_LIBS -lksvc"                    AC_DEFINE([HAVE_KRB5_SVC_GET_MSG], [1]) -                  AC_CHECK_HEADERS([ibm_svc/krb5_svc.h])], +                  AC_CHECK_HEADERS([ibm_svc/krb5_svc.h], [], [], +                     [RRA_INCLUDES_KRB5])],                   [AC_CHECK_LIB([com_err], [com_err],                       [KRB5_LIBS="$KRB5_LIBS -lcom_err"],                       [AC_MSG_ERROR([cannot find usable com_err library])])                    AC_CHECK_HEADERS([et/com_err.h])])])])])   RRA_LIB_KRB5_RESTORE]) -dnl Does the appropriate library checks for Kerberos v5 linkage when we don't +dnl Does the appropriate library checks for Kerberos linkage when we don't  dnl have krb5-config or reduced dependencies.  The single argument, if true,  dnl says to fail if Kerberos could not be found.  AC_DEFUN([_RRA_LIB_KRB5_MANUAL],  [RRA_LIB_KRB5_SWITCH   rra_krb5_extra=   LIBS= - AC_SEARCH_LIBS([res_search], [resolv], , + AC_SEARCH_LIBS([res_search], [resolv], [],      [AC_SEARCH_LIBS([__res_search], [resolv])])   AC_SEARCH_LIBS([gethostbyname], [nsl]) - AC_SEARCH_LIBS([socket], [socket], , -    [AC_CHECK_LIB([nsl], [socket], [LIBS="-lnsl -lsocket $LIBS"], , + AC_SEARCH_LIBS([socket], [socket], [], +    [AC_CHECK_LIB([nsl], [socket], [LIBS="-lnsl -lsocket $LIBS"], [],          [-lsocket])])   AC_SEARCH_LIBS([crypt], [crypt]) - AC_SEARCH_LIBS([rk_simple_execve], [roken]) + AC_SEARCH_LIBS([roken_concat], [roken])   rra_krb5_extra="$LIBS"   LIBS="$rra_krb5_save_LIBS"   AC_CHECK_LIB([krb5], [krb5_init_context], @@ -119,28 +155,34 @@ AC_DEFUN([_RRA_LIB_KRB5_MANUAL],                  [rra_krb5_pthread="-lpthread"])])           AC_CHECK_LIB([krb5support], [krb5int_setspecific],              [rra_krb5_extra="-lkrb5support $rra_krb5_extra $rra_krb5_pthread"], -            , [$rra_krb5_pthread])]) +            [], [$rra_krb5_pthread $rra_krb5_extra])], +        [$rra_krb5_extra])       AC_CHECK_LIB([com_err], [error_message], -        [rra_krb5_extra="-lcom_err $rra_krb5_extra"]) +        [rra_krb5_extra="-lcom_err $rra_krb5_extra"], [], [$rra_krb5_extra])       AC_CHECK_LIB([ksvc], [krb5_svc_get_msg], -        [rra_krb5_extra="-lksvc $rra_krb5_extra"]) +        [rra_krb5_extra="-lksvc $rra_krb5_extra"], [], [$rra_krb5_extra])       AC_CHECK_LIB([k5crypto], [krb5int_hash_md5], -        [rra_krb5_extra="-lk5crypto $rra_krb5_extra"]) +        [rra_krb5_extra="-lk5crypto $rra_krb5_extra"], [], [$rra_krb5_extra])       AC_CHECK_LIB([k5profile], [profile_get_values], -        [rra_krb5_extra="-lk5profile $rra_krb5_extra"]) +        [rra_krb5_extra="-lk5profile $rra_krb5_extra"], [], [$rra_krb5_extra])       AC_CHECK_LIB([krb5], [krb5_cc_default],          [KRB5_LIBS="-lkrb5 $rra_krb5_extra"],          [AS_IF([test x"$1" = xtrue], -            [AC_MSG_ERROR([cannot find usable Kerberos v5 library])])], +            [AC_MSG_ERROR([cannot find usable Kerberos library])])],          [$rra_krb5_extra])],      [-lasn1 -lcom_err -lcrypto $rra_krb5_extra])   LIBS="$KRB5_LIBS $LIBS" + AS_IF([test x"$rra_krb5_incroot" = x], +     [AC_CHECK_HEADERS([krb5.h krb5/krb5.h])], +     [_RRA_LIB_KRB5_CHECK_HEADER([krb5.h]) +      _RRA_LIB_KRB5_CHECK_HEADER([krb5/krb5.h])])   AC_CHECK_FUNCS([krb5_get_error_message],       [AC_CHECK_FUNCS([krb5_free_error_message])], -     [AC_CHECK_FUNCS([krb5_get_error_string], , -         [AC_CHECK_FUNCS([krb5_get_err_txt], , +     [AC_CHECK_FUNCS([krb5_get_error_string], [], +         [AC_CHECK_FUNCS([krb5_get_err_txt], [],               [AC_CHECK_FUNCS([krb5_svc_get_msg], -                 [AC_CHECK_HEADERS([ibm_svc/krb5_svc.h])], +                 [AC_CHECK_HEADERS([ibm_svc/krb5_svc.h], [], [], +                     [RRA_INCLUDES_KRB5])],                   [AC_CHECK_HEADERS([et/com_err.h])])])])])   RRA_LIB_KRB5_RESTORE]) @@ -158,49 +200,49 @@ AC_DEFUN([_RRA_LIB_KRB5_CHECK],       _RRA_LIB_KRB5_PATHS       _RRA_LIB_KRB5_MANUAL([$1])])]) +dnl Determine Kerberos compiler and linker flags from krb5-config.  Does the +dnl additional probing we need to do to uncover error handling features, and +dnl falls back on the manual checks. +AC_DEFUN([_RRA_LIB_KRB5_CONFIG], +[RRA_KRB5_CONFIG([${rra_krb5_root}], [krb5], [KRB5], +    [_RRA_LIB_KRB5_CHECK([$1]) +     RRA_LIB_KRB5_SWITCH +     AS_IF([test x"$rra_krb5_incroot" = x], +         [AC_CHECK_HEADERS([krb5.h krb5/krb5.h])], +         [_RRA_LIB_KRB5_CHECK_HEADER([krb5.h]) +          _RRA_LIB_KRB5_CHECK_HEADER([krb5/krb5.h])]) +     AC_CHECK_FUNCS([krb5_get_error_message], +         [AC_CHECK_FUNCS([krb5_free_error_message])], +         [AC_CHECK_FUNCS([krb5_get_error_string], [], +             [AC_CHECK_FUNCS([krb5_get_err_txt], [], +                 [AC_CHECK_FUNCS([krb5_svc_get_msg], +                     [AC_CHECK_HEADERS([ibm_svc/krb5_svc.h], [], [], +                         [RRA_INCLUDES_KRB5])], +                     [AC_CHECK_HEADERS([et/com_err.h])])])])]) +     RRA_LIB_KRB5_RESTORE], +    [_RRA_LIB_KRB5_PATHS +     _RRA_LIB_KRB5_MANUAL([$1])])]) +  dnl The core of the library checking, shared between RRA_LIB_KRB5 and  dnl RRA_LIB_KRB5_OPTIONAL.  The single argument, if "true", says to fail if -dnl Kerberos could not be found. +dnl Kerberos could not be found.  Set up rra_krb5_incroot for later header +dnl checking.  AC_DEFUN([_RRA_LIB_KRB5_INTERNAL],  [AC_REQUIRE([RRA_ENABLE_REDUCED_DEPENDS]) + rra_krb5_incroot= + AS_IF([test x"$rra_krb5_includedir" != x], +    [rra_krb5_incroot="$rra_krb5_includedir"], +    [AS_IF([test x"$rra_krb5_root" != x], +        [rra_krb5_incroot="${rra_krb5_root}/include"])])   AS_IF([test x"$rra_reduced_depends" = xtrue],      [_RRA_LIB_KRB5_PATHS       _RRA_LIB_KRB5_REDUCED([$1])], -    [AC_ARG_VAR([KRB5_CONFIG], [Path to krb5-config]) -     AS_IF([test x"$rra_krb5_root" != x && test -z "$KRB5_CONFIG"], -         [AS_IF([test -x "${rra_krb5_root}/bin/krb5-config"], -             [KRB5_CONFIG="${rra_krb5_root}/bin/krb5-config"])], -         [AC_PATH_PROG([KRB5_CONFIG], [krb5-config])]) -     AS_IF([test x"$KRB5_CONFIG" != x && test -x "$KRB5_CONFIG"], -         [AC_CACHE_CHECK([for krb5 support in krb5-config], -             [rra_cv_lib_krb5_config], -             [AS_IF(["$KRB5_CONFIG" 2>&1 | grep krb5 >/dev/null 2>&1], -                 [rra_cv_lib_krb5_config=yes], -                 [rra_cv_lib_krb5_config=no])]) -          AS_IF([test x"$rra_cv_lib_krb5_config" = xyes], -              [KRB5_CPPFLAGS=`"$KRB5_CONFIG" --cflags krb5 2>/dev/null` -               KRB5_LIBS=`"$KRB5_CONFIG" --libs krb5 2>/dev/null`], -              [KRB5_CPPFLAGS=`"$KRB5_CONFIG" --cflags 2>/dev/null` -               KRB5_LIBS=`"$KRB5_CONFIG" --libs 2>/dev/null`]) -          KRB5_CPPFLAGS=`echo "$KRB5_CPPFLAGS" | sed 's%-I/usr/include ?%%'` -          _RRA_LIB_KRB5_CHECK([$1]) -          RRA_LIB_KRB5_SWITCH -          AC_CHECK_FUNCS([krb5_get_error_message], -              [AC_CHECK_FUNCS([krb5_free_error_message])], -              [AC_CHECK_FUNCS([krb5_get_error_string], , -                  [AC_CHECK_FUNCS([krb5_get_err_txt], , -                      [AC_CHECK_FUNCS([krb5_svc_get_msg], -                          [AC_CHECK_HEADERS([ibm_svc/krb5_svc.h])], -                          [AC_CHECK_HEADERS([et/com_err.h])])])])]) -          RRA_LIB_KRB5_RESTORE], -         [_RRA_LIB_KRB5_PATHS -          _RRA_LIB_KRB5_MANUAL([$1])])]) +    [AS_IF([test x"$rra_krb5_includedir" = x && test x"$rra_krb5_libdir" = x], +        [_RRA_LIB_KRB5_CONFIG([$1])], +        [_RRA_LIB_KRB5_PATHS +         _RRA_LIB_KRB5_MANUAL([$1])])])   rra_krb5_uses_com_err=false - case "$LIBS" in - *-lcom_err*) -     rra_krb5_uses_com_err=true -     ;; - esac + AS_CASE([$LIBS], [*-lcom_err*], [rra_krb5_uses_com_err=true])   AM_CONDITIONAL([KRB5_USES_COM_ERR], [test x"$rra_krb5_uses_com_err" = xtrue])])  dnl The main macro for packages with mandatory Kerberos support. @@ -208,26 +250,28 @@ AC_DEFUN([RRA_LIB_KRB5],  [rra_krb5_root=   rra_krb5_libdir=   rra_krb5_includedir= + rra_use_kerberos=true   AC_SUBST([KRB5_CPPFLAGS])   AC_SUBST([KRB5_LDFLAGS])   AC_SUBST([KRB5_LIBS])   AC_ARG_WITH([krb5],      [AS_HELP_STRING([--with-krb5=DIR], -        [Location of Kerberos v5 headers and libraries])], +        [Location of Kerberos headers and libraries])],      [AS_IF([test x"$withval" != xyes && test x"$withval" != xno],          [rra_krb5_root="$withval"])])   AC_ARG_WITH([krb5-include],      [AS_HELP_STRING([--with-krb5-include=DIR], -        [Location of Kerberos v5 headers])], +        [Location of Kerberos headers])],      [AS_IF([test x"$withval" != xyes && test x"$withval" != xno],          [rra_krb5_includedir="$withval"])])   AC_ARG_WITH([krb5-lib],      [AS_HELP_STRING([--with-krb5-lib=DIR], -        [Location of Kerberos v5 libraries])], +        [Location of Kerberos libraries])],      [AS_IF([test x"$withval" != xyes && test x"$withval" != xno],          [rra_krb5_libdir="$withval"])]) - _RRA_LIB_KRB5_INTERNAL([true])]) + _RRA_LIB_KRB5_INTERNAL([true]) + AC_DEFINE([HAVE_KERBEROS], 1, [Define to enable Kerberos features.])])  dnl The main macro for packages with optional Kerberos support.  AC_DEFUN([RRA_LIB_KRB5_OPTIONAL], @@ -241,29 +285,41 @@ AC_DEFUN([RRA_LIB_KRB5_OPTIONAL],   AC_ARG_WITH([krb5],      [AS_HELP_STRING([--with-krb5@<:@=DIR@:>@], -        [Location of Kerberos v5 headers and libraries])], +        [Location of Kerberos headers and libraries])],      [AS_IF([test x"$withval" = xno],          [rra_use_kerberos=false],          [AS_IF([test x"$withval" != xyes], [rra_krb5_root="$withval"])           rra_use_kerberos=true])])   AC_ARG_WITH([krb5-include],      [AS_HELP_STRING([--with-krb5-include=DIR], -        [Location of Kerberos v5 headers])], +        [Location of Kerberos headers])],      [AS_IF([test x"$withval" != xyes && test x"$withval" != xno],          [rra_krb5_includedir="$withval"])])   AC_ARG_WITH([krb5-lib],      [AS_HELP_STRING([--with-krb5-lib=DIR], -        [Location of Kerberos v5 libraries])], +        [Location of Kerberos libraries])],      [AS_IF([test x"$withval" != xyes && test x"$withval" != xno],          [rra_krb5_libdir="$withval"])])   AS_IF([test x"$rra_use_kerberos" != xfalse],       [AS_IF([test x"$rra_use_kerberos" = xtrue],           [_RRA_LIB_KRB5_INTERNAL([true])], -         [_RRA_LIB_KRB5_INTERNAL([false])])]) +         [_RRA_LIB_KRB5_INTERNAL([false])])], +     [AM_CONDITIONAL([KRB5_USES_COM_ERR], [false])])   AS_IF([test x"$KRB5_LIBS" != x],      [AC_DEFINE([HAVE_KERBEROS], 1, [Define to enable Kerberos features.])])]) +dnl Source used by RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS. +AC_DEFUN([_RRA_FUNC_KRB5_OPT_FREE_ARGS_SOURCE], [RRA_INCLUDES_KRB5] [[ +int +main(void) +{ +    krb5_get_init_creds_opt *opts; +    krb5_context c; +    krb5_get_init_creds_opt_free(c, opts); +} +]]) +  dnl Check whether krb5_get_init_creds_opt_free takes one argument or two.  dnl Early Heimdal used to take a single argument.  Defines  dnl HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS if it takes two arguments. @@ -272,9 +328,7 @@ dnl Should be called with RRA_LIB_KRB5_SWITCH active.  AC_DEFUN([RRA_FUNC_KRB5_GET_INIT_CREDS_OPT_FREE_ARGS],  [AC_CACHE_CHECK([if krb5_get_init_creds_opt_free takes two arguments],      [rra_cv_func_krb5_get_init_creds_opt_free_args], -    [AC_TRY_COMPILE([#include <krb5.h>], -        [krb5_get_init_creds_opt *opts; krb5_context c; -         krb5_get_init_creds_opt_free(c, opts);], +    [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_RRA_FUNC_KRB5_OPT_FREE_ARGS_SOURCE])],          [rra_cv_func_krb5_get_init_creds_opt_free_args=yes],          [rra_cv_func_krb5_get_init_creds_opt_free_args=no])])   AS_IF([test $rra_cv_func_krb5_get_init_creds_opt_free_args = yes], diff --git a/m4/lib-depends.m4 b/m4/lib-depends.m4 index 039e245..b5185f3 100644 --- a/m4/lib-depends.m4 +++ b/m4/lib-depends.m4 @@ -9,11 +9,16 @@ dnl  dnl This macro doesn't do much but is defined separately so that other macros  dnl can require it with AC_REQUIRE.  dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl  dnl Written by Russ Allbery <rra@stanford.edu>  dnl Copyright 2005, 2006, 2007 -dnl     Board of Trustees, Leland Stanford Jr. University +dnl     The Board of Trustees of the Leland Stanford Junior University  dnl -dnl See LICENSE for licensing terms. +dnl This file is free software; the authors give unlimited permission to copy +dnl and/or distribute it, with or without modifications, as long as this +dnl notice is preserved.  AC_DEFUN([RRA_ENABLE_REDUCED_DEPENDS],  [rra_reduced_depends=false diff --git a/m4/lib-pathname.m4 b/m4/lib-pathname.m4 index fc326a0..fd5a5a1 100644 --- a/m4/lib-pathname.m4 +++ b/m4/lib-pathname.m4 @@ -12,10 +12,16 @@ dnl  dnl This file also provides the Autoconf macro RRA_SET_LIBDIR, which sets the  dnl libdir variable to PREFIX/lib{,32,64} as appropriate.  dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl  dnl Written by Russ Allbery <rra@stanford.edu> -dnl Copyright 2008, 2009 Board of Trustees, Leland Stanford Jr. University +dnl Copyright 2008, 2009 +dnl     The Board of Trustees of the Leland Stanford Junior University  dnl -dnl See LICENSE for licensing terms. +dnl This file is free software; the authors give unlimited permission to copy +dnl and/or distribute it, with or without modifications, as long as this +dnl notice is preserved.  dnl Probe for the alternate library name that we should attempt on this  dnl architecture, given the size of an int, and set rra_lib_arch_name to that diff --git a/m4/remctl.m4 b/m4/remctl.m4 index bb3a56f..588404f 100644 --- a/m4/remctl.m4 +++ b/m4/remctl.m4 @@ -10,15 +10,28 @@ dnl REMCTL_CPPFLAGS, REMCTL_LDFLAGS, and REMCTL_LIBS.  Also provides  dnl RRA_LIB_REMCTL_SWITCH to set CPPFLAGS, LDFLAGS, and LIBS to include the  dnl remctl libraries, saving the current values first, and  dnl RRA_LIB_REMCTL_RESTORE to restore those settings to before the last -dnl RRA_LIB_REMCTL_SWITCH. +dnl RRA_LIB_REMCTL_SWITCH.  HAVE_REMCTL will always be defined if +dnl RRA_LIB_REMCTL is used. +dnl +dnl Provides the RRA_LIB_REMCTL_OPTIONAL macro, which should be used if +dnl Kerberos support is optional.  This macro will still always est the +dnl substitution variables, but they'll be empty unless --with-remctl is +dnl given.  HAVE_REMCTL will be defined if --with-remctl is given and +dnl $rra_use_remctl will be set to "true".  dnl  dnl Depends on RRA_ENABLE_REDUCED_DEPENDS, RRA_SET_LDFLAGS, and  dnl RRA_LIB_GSSAPI.  dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl  dnl Written by Russ Allbery <rra@stanford.edu> -dnl Copyright 2008, 2009 Board of Trustees, Leland Stanford Jr. University +dnl Copyright 2008, 2009, 2011 +dnl     The Board of Trustees of the Leland Stanford Junior University  dnl -dnl See LICENSE for licensing terms. +dnl This file is free software; the authors give unlimited permission to copy +dnl and/or distribute it, with or without modifications, as long as this +dnl notice is preserved.  dnl Save the current CPPFLAGS, LDFLAGS, and LIBS settings and switch to  dnl versions that include the remctl flags.  Used as a wrapper, with @@ -55,16 +68,34 @@ dnl Sanity-check the results of the remctl library search to be sure we can  dnl really link a remctl program.  AC_DEFUN([_RRA_LIB_REMCTL_CHECK],  [RRA_LIB_REMCTL_SWITCH - AC_CHECK_FUNC([remctl_open], , -    [AC_MSG_FAILURE([unable to link with remctl library])]) + AC_CHECK_FUNC([remctl_open], [], +    [AS_IF([test x"$1" = xtrue], +        [AC_MSG_FAILURE([unable to link with remctl library])]) +     REMCTL_CPPFLAGS= +     REMCTL_LDFLAGS= +     REMCTL_LIBS=])   RRA_LIB_REMCTL_RESTORE]) -dnl The main macro. -AC_DEFUN([RRA_LIB_REMCTL], +dnl The core of the library checking, shared between RRA_LIB_REMCTL and +dnl RRA_LIB_REMCTL_OPTIONAL.  The single argument, if "true", says to fail if +dnl remctl could not be found. +AC_DEFUN([_RRA_LIB_REMCTL_INTERNAL],  [AC_REQUIRE([RRA_ENABLE_REDUCED_DEPENDS]) - rra_remctl_root= + _RRA_LIB_REMCTL_PATHS + AS_IF([test x"$rra_reduced_depends" = xtrue], +    [REMCTL_LIBS="-lremctl"], +    [RRA_LIB_GSSAPI +     REMCTL_CPPFLAGS="$REMCTL_CPPFLAGS $GSSAPI_CPPFLAGS" +     REMCTL_LDFLAGS="$REMCTL_LDFLAGS $GSSAPI_LDFLAGS" +     REMCTL_LIBS="-lremctl $GSSAPI_LIBS"]) + _RRA_LIB_REMCTL_CHECK([$1])]) + +dnl The main macro for packages with mandatory remctl support. +AC_DEFUN([RRA_LIB_REMCTL], +[rra_remctl_root=   rra_remctl_libdir=   rra_remctl_includedir= + rra_use_remctl=true   REMCTL_CPPFLAGS=   REMCTL_LDFLAGS=   REMCTL_LIBS= @@ -87,12 +118,43 @@ AC_DEFUN([RRA_LIB_REMCTL],          [Location of remctl libraries])],      [AS_IF([test x"$withval" != xyes && test x"$withval" != xno],          [rra_remctl_libdir="$withval"])]) + _RRA_LIB_REMCTL_INTERNAL([true]) + AC_DEFINE([HAVE_REMCTL], 1, [Define to enable remctl features.])]) - _RRA_LIB_REMCTL_PATHS - AS_IF([test x"$rra_reduced_depends" = xtrue], -    [REMCTL_LIBS="-lremctl"], -    [RRA_LIB_GSSAPI -     REMCTL_CPPFLAGS="$REMCTL_CPPFLAGS $GSSAPI_CPPFLAGS" -     REMCTL_LDFLAGS="$REMCTL_LDFLAGS $GSSAPI_LDFLAGS" -     REMCTL_LIBS="-lremctl $GSSAPI_LIBS"]) - _RRA_LIB_REMCTL_CHECK]) +dnl The main macro for packages with optional remctl support. +AC_DEFUN([RRA_LIB_REMCTL_OPTIONAL], +[rra_remctl_root= + rra_remctl_libdir= + rra_remctl_includedir= + rra_use_remctl= + REMCTL_CPPFLAGS= + REMCTL_LDFLAGS= + REMCTL_LIBS= + AC_SUBST([REMCTL_CPPFLAGS]) + AC_SUBST([REMCTL_LDFLAGS]) + AC_SUBST([REMCTL_LIBS]) + + AC_ARG_WITH([remctl], +    [AS_HELP_STRING([--with-remctl@<:@=DIR@:>@], +        [Location of remctl headers and libraries])], +    [AS_IF([test x"$withval" = xno], +        [rra_use_remctl=false], +        [AS_IF([test x"$withval" != xyes], [rra_remctl_root="$withval"]) +         rra_use_remctl=true])]) + AC_ARG_WITH([remctl-include], +    [AS_HELP_STRING([--with-remctl-include=DIR], +        [Location of remctl headers])], +    [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], +        [rra_remctl_includedir="$withval"])]) + AC_ARG_WITH([remctl-lib], +    [AS_HELP_STRING([--with-remctl-lib=DIR], +        [Location of remctl libraries])], +    [AS_IF([test x"$withval" != xyes && test x"$withval" != xno], +        [rra_remctl_libdir="$withval"])]) + AS_IF([test x"$rra_use_remctl" != xfalse], +    [AS_IF([test x"$rra_use_remctl" = xtrue], +        [_RRA_LIB_REMCTL_INTERNAL([true])], +        [_RRA_LIB_REMCTL_INTERNAL([false])])]) + AS_IF([test x"$REMCTL_LIBS" != x], +    [rra_use_remctl=true +     AC_DEFINE([HAVE_REMCTL], 1, [Define to enable remctl features.])])]) diff --git a/m4/snprintf.m4 b/m4/snprintf.m4 index d933f55..cd585ef 100644 --- a/m4/snprintf.m4 +++ b/m4/snprintf.m4 @@ -9,11 +9,16 @@ dnl  dnl Provides RRA_FUNC_SNPRINTF, which adds snprintf.o to LIBOBJS unless a  dnl fully working snprintf is found.  dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl  dnl Written by Russ Allbery <rra@stanford.edu>  dnl Copyright 2006, 2008, 2009 -dnl     Board of Trustees, Leland Stanford Jr. University +dnl     The Board of Trustees of the Leland Stanford Junior University  dnl -dnl See LICENSE for licensing terms. +dnl This file is free software; the authors give unlimited permission to copy +dnl and/or distribute it, with or without modifications, as long as this +dnl notice is preserved.  dnl Source used by RRA_FUNC_SNPRINTF.  AC_DEFUN([_RRA_FUNC_SNPRINTF_SOURCE], [[ diff --git a/m4/vamacros.m4 b/m4/vamacros.m4 index 855bb40..af98f6a 100644 --- a/m4/vamacros.m4 +++ b/m4/vamacros.m4 @@ -13,11 +13,16 @@ dnl    #define macro(args...) fprintf(stderr, args)  dnl  dnl They set HAVE_C99_VAMACROS or HAVE_GNU_VAMACROS as appropriate.  dnl +dnl The canonical version of this file is maintained in the rra-c-util +dnl package, available at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +dnl  dnl Written by Russ Allbery <rra@stanford.edu>  dnl Copyright 2006, 2008, 2009 -dnl     Board of Trustees, Leland Stanford Jr. University +dnl     The Board of Trustees of the Leland Stanford Junior University  dnl -dnl See LICENSE for licensing terms. +dnl This file is free software; the authors give unlimited permission to copy +dnl and/or distribute it, with or without modifications, as long as this +dnl notice is preserved.  AC_DEFUN([_RRA_C_C99_VAMACROS_SOURCE], [[  #include <stdio.h> diff --git a/portable/asprintf.c b/portable/asprintf.c index 4219a19..0093070 100644 --- a/portable/asprintf.c +++ b/portable/asprintf.c @@ -4,8 +4,18 @@   * Provides the same functionality as the standard GNU library routines   * asprintf and vasprintf for those platforms that don't have them.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> diff --git a/portable/dummy.c b/portable/dummy.c index 8a0d54d..50052ec 100644 --- a/portable/dummy.c +++ b/portable/dummy.c @@ -5,8 +5,18 @@   * supply, Automake builds an empty library and then calls ar with nonsensical   * arguments.  Ensure that libportable always contains at least one symbol.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  /* Prototype to avoid gcc warnings. */ diff --git a/portable/krb5-extra.c b/portable/krb5-extra.c index 89ccbde..849842c 100644 --- a/portable/krb5-extra.c +++ b/portable/krb5-extra.c @@ -6,8 +6,18 @@   * Everything in this file will be protected by #ifndef.  If the native   * Kerberos libraries are fully capable, this file will be skipped.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> diff --git a/portable/krb5.h b/portable/krb5.h index 3b5700b..b418ae7 100644 --- a/portable/krb5.h +++ b/portable/krb5.h @@ -16,8 +16,18 @@   * prefers the generic krb5_xfree().  In this case, this header provides   * krb5_free_unparsed_name() for both APIs since it's the most specific call.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #ifndef PORTABLE_KRB5_H @@ -32,7 +42,11 @@  #endif  #include <portable/macros.h> -#include <krb5.h> +#ifdef HAVE_KRB5_H +# include <krb5.h> +#else +# include <krb5/krb5.h> +#endif  #include <stdlib.h>  BEGIN_DECLS @@ -75,7 +89,7 @@ krb5_error_code krb5_get_init_creds_opt_alloc(krb5_context,  /* Heimdal-specific. */  #ifndef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_DEFAULT_FLAGS -#define krb5_get_init_creds_opt_set_default_flags(c, p, r, o) /* empty */ +# define krb5_get_init_creds_opt_set_default_flags(c, p, r, o) /* empty */  #endif  /* diff --git a/portable/macros.h b/portable/macros.h index 8d5adbd..b33d064 100644 --- a/portable/macros.h +++ b/portable/macros.h @@ -1,8 +1,18 @@  /*   * Portability macros used in include files.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #ifndef PORTABLE_MACROS_H @@ -20,6 +30,29 @@  #endif  /* + * We use __alloc_size__, but it was only available in fairly recent versions + * of GCC.  Suppress warnings about the unknown attribute if GCC is too old. + * We know that we're GCC at this point, so we can use the GCC variadic macro + * extension, which will still work with versions of GCC too old to have C99 + * variadic macro support. + */ +#if !defined(__attribute__) && !defined(__alloc_size__) +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) +#  define __alloc_size__(spec, args...) /* empty */ +# endif +#endif + +/* + * LLVM and Clang pretend to be GCC but don't support all of the __attribute__ + * settings that GCC does.  For them, suppress warnings about unknown + * attributes on declarations.  This unfortunately will affect the entire + * compilation context, but there's no push and pop available. + */ +#if !defined(__attribute__) && (defined(__llvm__) || defined(__clang__)) +# pragma GCC diagnostic ignored "-Wattributes" +#endif + +/*   * BEGIN_DECLS is used at the beginning of declarations so that C++   * compilers don't mangle their names.  END_DECLS is used at the end.   */ diff --git a/portable/mkstemp.c b/portable/mkstemp.c index dd2a485..8668db1 100644 --- a/portable/mkstemp.c +++ b/portable/mkstemp.c @@ -4,8 +4,18 @@   * Provides the same functionality as the library function mkstemp for those   * systems that don't have it.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> @@ -27,7 +37,7 @@ int test_mkstemp(char *);  #endif  /* Pick the longest available integer type. */ -#if HAVE_LONG_LONG +#if HAVE_LONG_LONG_INT  typedef unsigned long long long_int_type;  #else  typedef unsigned long long_int_type; diff --git a/portable/setenv.c b/portable/setenv.c index d66ddcd..fd2b10c 100644 --- a/portable/setenv.c +++ b/portable/setenv.c @@ -4,8 +4,18 @@   * Provides the same functionality as the standard library routine setenv for   * those platforms that don't have it.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> @@ -31,10 +41,9 @@ setenv(const char *name, const char *value, int overwrite)      /*       * Allocate memory for the environment string.  We intentionally don't use -     * concat here, or the xmalloc family of allocation routines, since the -     * intention is to provide a replacement for the standard library function -     * which sets errno and returns in the event of a memory allocation -     * failure. +     * the xmalloc family of allocation routines here, since the intention is +     * to provide a replacement for the standard library function that sets +     * errno and returns in the event of a memory allocation failure.       */      size = strlen(name) + 1 + strlen(value) + 1;      envstring = malloc(size); diff --git a/portable/snprintf.c b/portable/snprintf.c index ab3121c..91c8491 100644 --- a/portable/snprintf.c +++ b/portable/snprintf.c @@ -8,6 +8,9 @@   * Please do not reformat or otherwise change this file more than necessary so   * that later merges with the original source are easy.  Bug fixes and   * improvements should be sent back to the original author. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.   */  /* diff --git a/portable/stdbool.h b/portable/stdbool.h index bfbf4c4..045436f 100644 --- a/portable/stdbool.h +++ b/portable/stdbool.h @@ -5,13 +5,31 @@   * following the C99 specification, on hosts that don't have stdbool.h.  This   * logic is based heavily on the example in the Autoconf manual.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #ifndef PORTABLE_STDBOOL_H  #define PORTABLE_STDBOOL_H 1 +/* + * Allow inclusion of config.h to be skipped, since sometimes we have to use a + * stripped-down version of config.h with a different name. + */ +#ifndef CONFIG_H_INCLUDED +# include <config.h> +#endif +  #if HAVE_STDBOOL_H  # include <stdbool.h>  #else diff --git a/portable/strlcat.c b/portable/strlcat.c index f696db3..3bee4ee 100644 --- a/portable/strlcat.c +++ b/portable/strlcat.c @@ -9,8 +9,18 @@   * space available in the destination buffer, not just the amount of space   * remaining.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> diff --git a/portable/strlcpy.c b/portable/strlcpy.c index 596e968..df75fd8 100644 --- a/portable/strlcpy.c +++ b/portable/strlcpy.c @@ -8,8 +8,18 @@   * total space required is returned.  The destination string is not nul-filled   * like strncpy does, just nul-terminated.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> diff --git a/portable/system.h b/portable/system.h index 461601b..d1ccc94 100644 --- a/portable/system.h +++ b/portable/system.h @@ -13,13 +13,24 @@   *     #include <stddef.h>   *     #include <stdint.h>   *     #include <string.h> + *     #include <strings.h>   *     #include <unistd.h>   *   * Missing functions are provided via #define or prototyped if available from   * the portable helper library.  Also provides some standard #defines.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #ifndef PORTABLE_SYSTEM_H @@ -38,6 +49,9 @@  #include <stdlib.h>  #include <sys/types.h>  #include <string.h> +#if HAVE_STRINGS_H +# include <strings.h> +#endif  #if HAVE_INTTYPES_H  # include <inttypes.h>  #endif @@ -56,6 +70,38 @@  /* Get the bool type. */  #include <portable/stdbool.h> +/* Windows provides snprintf under a different name. */ +#ifdef _WIN32 +# define snprintf _snprintf +#endif + +/* Windows does not define ssize_t. */ +#ifndef HAVE_SSIZE_T +typedef ptrdiff_t ssize_t; +#endif + +/* + * POSIX requires that these be defined in <unistd.h>.  If one of them has + * been defined, all the rest almost certainly have. + */ +#ifndef STDIN_FILENO +# define STDIN_FILENO  0 +# define STDOUT_FILENO 1 +# define STDERR_FILENO 2 +#endif + +/* + * C99 requires va_copy.  Older versions of GCC provide __va_copy.  Per the + * Autoconf manual, memcpy is a generally portable fallback. + */ +#ifndef va_copy +# ifdef __va_copy +#  define va_copy(d, s) __va_copy((d), (s)) +# else +#  define va_copy(d, s) memcpy(&(d), &(s), sizeof(va_list)) +# endif +#endif +  BEGIN_DECLS  /* Default to a hidden visibility for all portability functions. */ @@ -96,31 +142,4 @@ extern size_t strlcpy(char *, const char *, size_t);  END_DECLS -/* Windows provides snprintf under a different name. */ -#ifdef _WIN32 -# define snprintf _snprintf -#endif - -/* - * POSIX requires that these be defined in <unistd.h>.  If one of them has - * been defined, all the rest almost certainly have. - */ -#ifndef STDIN_FILENO -# define STDIN_FILENO  0 -# define STDOUT_FILENO 1 -# define STDERR_FILENO 2 -#endif - -/* - * C99 requires va_copy.  Older versions of GCC provide __va_copy.  Per the - * Autoconf manual, memcpy is a generally portable fallback. - */ -#ifndef va_copy -# ifdef __va_copy -#  define va_copy(d, s) __va_copy((d), (s)) -# else -#  define va_copy(d, s) memcpy(&(d), &(s), sizeof(va_list)) -# endif -#endif -  #endif /* !PORTABLE_SYSTEM_H */ diff --git a/portable/uio.h b/portable/uio.h index 3c9e840..3bd1f96 100644 --- a/portable/uio.h +++ b/portable/uio.h @@ -5,8 +5,18 @@   * (primarily Windows).  Currently, the corresponding readv and writev   * functions are not provided or prototyped here.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #ifndef PORTABLE_UIO_H diff --git a/tests/client/full-t.in b/tests/client/full-t.in index ce2789d..680e78f 100644 --- a/tests/client/full-t.in +++ b/tests/client/full-t.in @@ -56,19 +56,19 @@ chdir "$ENV{SOURCE}" or die "Cannot chdir to $ENV{SOURCE}: $!\n";  SKIP: {      skip 'no keytab configuration', $total -        unless -f "$ENV{BUILD}/data/test.keytab"; +        unless -f "$ENV{BUILD}/config/keytab";      my $remctld = '@REMCTLD@';      skip 'remctld not found', $total unless $remctld;      # Spawn remctld and get local tickets.  Don't destroy the user's Kerberos      # ticket cache.      unlink ('krb5cc_test', 'test-pid'); -    my $principal = contents ("$ENV{BUILD}/data/test.principal"); +    my $principal = contents ("$ENV{BUILD}/config/principal");      remctld_spawn ($remctld, $principal, -                   "$ENV{BUILD}/data/test.keytab", +                   "$ENV{BUILD}/config/keytab",                     "$ENV{SOURCE}/data/full.conf");      $ENV{KRB5CCNAME} = 'krb5cc_test'; -    getcreds ("$ENV{BUILD}/data/test.keytab", $principal); +    getcreds ("$ENV{BUILD}/config/keytab", $principal);      # Use Wallet::Admin to set up the database.      db_setup; diff --git a/tests/client/prompt-t.in b/tests/client/prompt-t.in index 1d8b079..682cd70 100644 --- a/tests/client/prompt-t.in +++ b/tests/client/prompt-t.in @@ -21,11 +21,11 @@ chdir "$ENV{SOURCE}" or die "Cannot chdir to $ENV{SOURCE}: $!\n";  SKIP: {      skip 'no password configuration', $total -        unless -f "$ENV{BUILD}/data/test.password"; +        unless -f "$ENV{BUILD}/config/password";      my $remctld = '@REMCTLD@';      skip 'remctld not found', $total unless $remctld;      eval { require Expect }; -    skip 'Exepct module not found', $total if $@; +    skip 'Expect module not found', $total if $@;      # Disable sending of wallet's output to our standard output.  Do this      # twice to avoid Perl warnings. @@ -34,14 +34,14 @@ SKIP: {      # Spawn remctld and set up with a different ticket cache.      unlink ('krb5cc_test', 'test-pid'); -    my $principal = contents ("$ENV{BUILD}/data/test.principal"); -    remctld_spawn ($remctld, $principal, "$ENV{BUILD}/data/test.keytab", +    my $principal = contents ("$ENV{BUILD}/config/principal"); +    remctld_spawn ($remctld, $principal, "$ENV{BUILD}/config/keytab",                     "$ENV{SOURCE}/data/basic.conf");      $ENV{KRB5CCNAME} = 'krb5cc_test';      # Read in the principal and password. -    open (PASS, '<', "$ENV{BUILD}/data/test.password") -        or die "Cannot open $ENV{BUILD}/data/test.password: $!\n"; +    open (PASS, '<', "$ENV{BUILD}/config/password") +        or die "Cannot open $ENV{BUILD}/config/password: $!\n";      my $user = <PASS>;      my $password = <PASS>;      close PASS; diff --git a/tests/config/README b/tests/config/README new file mode 100644 index 0000000..2992a11 --- /dev/null +++ b/tests/config/README @@ -0,0 +1,24 @@ +This directory contains configuration required to run the complete wallet +test suite.  If there is no configuration in this directory, some of the +tests will be skipped.  To enable the full test suite, create the +following files: + +keytab + +    A valid Kerberos keytab for a principal, preferrably in your local +    realm.  This will be used to test network interactions that require +    Kerberos authentication. + +principal + +    The name of the Kerberos principal whose keys are stored in keytab. + +password + +    This file should contain two lines.  The first line is the +    fully-qualified principal (including the realm) of a Kerberos +    principal to use for testing authentication.  The second line is +    the password for that principal.  The realm of the principal must +    be configured in your system krb5.conf file or in DNS configuration +    picked up by your Kerberos libraries and must be in the same realm as +    the keytab above or have valid cross-realm trust to it. diff --git a/tests/data/perl.conf b/tests/data/perl.conf new file mode 100644 index 0000000..eaf7443 --- /dev/null +++ b/tests/data/perl.conf @@ -0,0 +1,6 @@ +# Configuration for Perl tests.  -*- perl -*- + +# No special configuration yet. + +# File must end with this line. +1; diff --git a/tests/docs/pod-spelling-t b/tests/docs/pod-spelling-t index eaa7dd6..e1a95cd 100755 --- a/tests/docs/pod-spelling-t +++ b/tests/docs/pod-spelling-t @@ -1,80 +1,52 @@  #!/usr/bin/perl  # -# Check for spelling errors in POD documentation +# Checks all POD files in the tree for spelling errors using Test::Spelling. +# This test is disabled unless RRA_MAINTAINER_TESTS is set, since spelling +# dictionaries vary too much between environments.  # -# Checks all POD files in the tree for spelling problems using Pod::Spell and -# either aspell or ispell.  aspell is preferred.  This test is disabled unless -# RRA_MAINTAINER_TESTS is set, since spelling dictionaries vary too much -# between environments. +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.  # -# Copyright 2008, 2009 Russ Allbery <rra@stanford.edu> +# Written by Russ Allbery <rra@stanford.edu> +# Copyright 2012, 2013 +#     The Board of Trustees of the Leland Stanford Junior University  # -# See LICENSE for licensing terms. +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +use 5.006;  use strict; -use Test::More; +use warnings; -# Skip all spelling tests unless the maintainer environment variable is set. -plan skip_all => 'spelling tests only run for maintainer' -    unless $ENV{RRA_MAINTAINER_TESTS}; +use lib "$ENV{SOURCE}/tap/perl"; + +use Test::More; +use Test::RRA qw(skip_unless_maintainer use_prereq); +use Test::RRA::Automake qw(automake_setup perl_dirs); -# Load required Perl modules. -eval 'use Test::Pod 1.00'; -plan skip_all => 'Test::Pod 1.00 required for testing POD' if $@; -eval 'use Pod::Spell'; -plan skip_all => 'Pod::Spell required to test POD spelling' if $@; +# Only run this test for the maintainer. +skip_unless_maintainer('Spelling tests'); -# Locate a spell-checker.  hunspell is not currently supported due to its lack -# of support for contractions (at least in the version in Debian). -my @spell; -my %options = (aspell => [ qw(-d en_US --home-dir=./ list) ], -               ispell => [ qw(-d american -l -p /dev/null) ]); -SEARCH: for my $program (qw/aspell ispell/) { -    for my $dir (split ':', $ENV{PATH}) { -        if (-x "$dir/$program") { -            @spell = ("$dir/$program", @{ $options{$program} }); -        } -        last SEARCH if @spell; -    } -} -plan skip_all => 'aspell or ispell required to test POD spelling' -    unless @spell; +# Load prerequisite modules. +use_prereq('Test::Spelling'); -# Prerequisites are satisfied, so we're going to do some testing.  Figure out -# what POD files we have and from that develop our plan. -$| = 1; -my @pod = map { -    my $pod = "$ENV{SOURCE}/../" . $_; -    $pod =~ s,[^/.][^/]*/../,,g; -    $pod; -} qw(client/wallet.pod client/wallet-rekey.pod server/keytab-backend -     server/wallet-admin server/wallet-backend server/wallet-report); -plan tests => scalar @pod; +# Set up Automake testing. +automake_setup(); -# Finally, do the checks. -for my $pod (@pod) { -    my $child = open (CHILD, '-|'); -    if (not defined $child) { -        BAIL_OUT ("cannot fork: $!"); -    } elsif ($child == 0) { -        my $pid = open (SPELL, '|-', @spell) -            or BAIL_OUT ("cannot run @spell: $!"); -        open (POD, '<', $pod) or BAIL_OUT ("cannot open $pod: $!"); -        my $parser = Pod::Spell->new; -        $parser->parse_from_filehandle (\*POD, \*SPELL); -        close POD; -        close SPELL; -        exit ($? >> 8); -    } else { -        my @words = <CHILD>; -        close CHILD; -      SKIP: { -            skip "@spell failed for $pod", 1 unless $? == 0; -            for (@words) { -                s/^\s+//; -                s/\s+$//; -            } -            is ("@words", '', $pod); -        } -    } -} +# Run the tests. +all_pod_files_spelling_ok(perl_dirs()); diff --git a/tests/docs/pod-t b/tests/docs/pod-t index e25ade2..2743287 100755 --- a/tests/docs/pod-t +++ b/tests/docs/pod-t @@ -1,22 +1,48 @@  #!/usr/bin/perl -w  # -# Test POD formatting for documentation. +# Check all POD documents in the tree, except for any embedded Perl module +# distribution, for POD formatting errors. +# +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.  #  # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2008, 2010 Board of Trustees, Leland Stanford Jr. University +# Copyright 2012, 2013 +#     The Board of Trustees of the Leland Stanford Junior University +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions:  # -# See LICENSE for licensing terms. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +use 5.006;  use strict; +use warnings; + +use lib "$ENV{SOURCE}/tap/perl"; +  use Test::More; -eval 'use Test::Pod 1.00'; -plan skip_all => 'Test::Pod 1.00 required for testing POD' if $@; +use Test::RRA qw(use_prereq); +use Test::RRA::Automake qw(automake_setup perl_dirs); + +# Load prerequisite modules. +use_prereq('Test::Pod'); + +# Set up Automake testing. +automake_setup(); -my @files = qw(client/wallet.pod client/wallet-rekey.pod server/keytab-backend -               server/wallet-admin server/wallet-backend -               server/wallet-report); -my $total = scalar (@files); -plan tests => $total; -for my $file (@files) { -    pod_file_ok ("$ENV{SOURCE}/../$file", $file); -} +# Run the tests. +all_pod_files_ok(perl_dirs()); diff --git a/tests/portable/asprintf-t.c b/tests/portable/asprintf-t.c index 04fbd1b..4513a85 100644 --- a/tests/portable/asprintf-t.c +++ b/tests/portable/asprintf-t.c @@ -1,11 +1,18 @@  /*   * asprintf and vasprintf test suite.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * Copyright 2006, 2008, 2009 - *     Board of Trustees, Leland Stanford Jr. University   * - * See LICENSE for licensing terms. + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> diff --git a/tests/portable/mkstemp-t.c b/tests/portable/mkstemp-t.c index 54701f7..98c708e 100644 --- a/tests/portable/mkstemp-t.c +++ b/tests/portable/mkstemp-t.c @@ -1,11 +1,18 @@  /*   * mkstemp test suite.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * Copyright 2002, 2004, 2008, 2009 - *     Board of Trustees, Leland Stanford Jr. University   * - * See LICENSE for licensing terms. + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> diff --git a/tests/portable/setenv-t.c b/tests/portable/setenv-t.c index 5bc59ce..a1aecb5 100644 --- a/tests/portable/setenv-t.c +++ b/tests/portable/setenv-t.c @@ -1,14 +1,18 @@  /*   * setenv test suite.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * Copyright 2009 Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz   * - * See LICENSE for licensing terms. + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> diff --git a/tests/portable/snprintf-t.c b/tests/portable/snprintf-t.c index 4b64f5b..927de96 100644 --- a/tests/portable/snprintf-t.c +++ b/tests/portable/snprintf-t.c @@ -1,14 +1,20 @@  /*   * snprintf test suite.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * Copyright 2009, 2010 Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz + * Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 + *     Russ Allbery <rra@stanford.edu> + * Copyright 2009, 2010 + *     The Board of Trustees of the Leland Stanford Junior University + * Copyright 1995 Patrick Powell + * Copyright 2001 Hrvoje Niksic   * - * See LICENSE for licensing terms. + * This code is based on code written by Patrick Powell (papowell@astart.com) + * It may be used for any purpose as long as this notice remains intact + * on all source code distributions   */  #include <config.h> diff --git a/tests/portable/strlcat-t.c b/tests/portable/strlcat-t.c index e02c277..54d0d40 100644 --- a/tests/portable/strlcat-t.c +++ b/tests/portable/strlcat-t.c @@ -1,14 +1,18 @@  /*   * strlcat test suite.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * Copyright 2009 Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz   * - * See LICENSE for licensing terms. + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> diff --git a/tests/portable/strlcpy-t.c b/tests/portable/strlcpy-t.c index ba224ba..26aa8f2 100644 --- a/tests/portable/strlcpy-t.c +++ b/tests/portable/strlcpy-t.c @@ -1,14 +1,18 @@  /*   * strlcpy test suite.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * Copyright 2009 Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz   * - * See LICENSE for licensing terms. + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #include <config.h> diff --git a/tests/runtests.c b/tests/runtests.c index ab77629..4249875 100644 --- a/tests/runtests.c +++ b/tests/runtests.c @@ -3,14 +3,15 @@   *   * Usage:   * - *      runtests <test-list> + *      runtests [-b <build-dir>] [-s <source-dir>] <test-list> + *      runtests -o [-b <build-dir>] [-s <source-dir>] <test>   * - * Expects a list of executables located in the given file, one line per - * executable.  For each one, runs it as part of a test suite, reporting - * results.  Test output should start with a line containing the number of - * tests (numbered from 1 to this number), optionally preceded by "1..", - * although that line may be given anywhere in the output.  Each additional - * line should be in the following format: + * In the first case, expects a list of executables located in the given file, + * one line per executable.  For each one, runs it as part of a test suite, + * reporting results.  Test output should start with a line containing the + * number of tests (numbered from 1 to this number), optionally preceded by + * "1..", although that line may be given anywhere in the output.  Each + * additional line should be in the following format:   *   *      ok <number>   *      not ok <number> @@ -39,10 +40,21 @@   * This is a subset of TAP as documented in Test::Harness::TAP or   * TAP::Parser::Grammar, which comes with Perl.   * + * If the -o option is given, instead run a single test and display all of its + * output.  This is intended for use with failing tests so that the person + * running the test suite can get more details about what failed. + * + * If built with the C preprocessor symbols SOURCE and BUILD defined, C TAP + * Harness will export those values in the environment so that tests can find + * the source and build directory and will look for tests under both + * directories.  These paths can also be set with the -b and -s command-line + * options, which will override anything set at build time. + *   * Any bug reports, bug fixes, and improvements are very much welcome and - * should be sent to the e-mail address below. + * should be sent to the e-mail address below.  This program is part of C TAP + * Harness <http://www.eyrie.org/~eagle/software/c-tap-harness/>.   * - * Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009, 2010 + * Copyright 2000, 2001, 2004, 2006, 2007, 2008, 2009, 2010, 2011   *     Russ Allbery <rra@stanford.edu>   *   * Permission is hereby granted, free of charge, to any person obtaining a @@ -64,6 +76,13 @@   * DEALINGS IN THE SOFTWARE.  */ +/* Required for fdopen(), getopt(), and putenv(). */ +#if defined(__STRICT_ANSI__) || defined(PEDANTIC) +# ifndef _XOPEN_SOURCE +#  define _XOPEN_SOURCE 500 +# endif +#endif +  #include <ctype.h>  #include <errno.h>  #include <fcntl.h> @@ -71,6 +90,7 @@  #include <stdio.h>  #include <stdlib.h>  #include <string.h> +#include <strings.h>  #include <sys/stat.h>  #include <sys/time.h>  #include <sys/types.h> @@ -133,10 +153,10 @@ struct testset {      unsigned long skipped;      /* Count of skipped tests (passed). */      unsigned long allocated;    /* The size of the results table. */      enum test_status *results;  /* Table of results by test number. */ -    int aborted;                /* Whether the set as aborted. */ +    unsigned int aborted;       /* Whether the set as aborted. */      int reported;               /* Whether the results were reported. */      int status;                 /* The exit status of the test. */ -    int all_skipped;            /* Whether all tests were skipped. */ +    unsigned int all_skipped;   /* Whether all tests were skipped. */      char *reason;               /* Why all tests were skipped. */  }; @@ -147,6 +167,23 @@ struct testlist {  };  /* + * Usage message.  Should be used as a printf format with two arguments: the + * path to runtests, given twice. + */ +static const char usage_message[] = "\ +Usage: %s [-b <build-dir>] [-s <source-dir>] <test-list>\n\ +       %s -o [-b <build-dir>] [-s <source-dir>] <test>\n\ +\n\ +Options:\n\ +    -b <build-dir>      Set the build directory to <build-dir>\n\ +    -o                  Run a single test rather than a list of tests\n\ +    -s <source-dir>     Set the source directory to <source-dir>\n\ +\n\ +runtests normally runs each test listed in a file whose path is given as\n\ +its command-line argument.  With the -o option, it instead runs a single\n\ +test and shows its complete output.\n"; + +/*   * Header used for test output.  %s is replaced by the file name of the list   * of tests.   */ @@ -367,7 +404,9 @@ test_plan(const char *line, struct testset *ts)       * Get the count, check it for validity, and initialize the struct.  If we       * have something of the form "1..0 # skip foo", the whole file was       * skipped; record that.  If we do skip the whole file, zero out all of -     * our statistics, since they're no longer relevant. +     * our statistics, since they're no longer relevant.  strtol is called +     * with a second argument to advance the line pointer past the count to +     * make it simpler to detect the # skip case.       */      n = strtol(line, (char **) &line, 10);      if (n == 0) { @@ -437,6 +476,7 @@ test_checkline(const char *line, struct testset *ts)      char *end;      long number;      unsigned long i, current; +    int outlen;      /* Before anything, check for a test abort. */      bail = strstr(line, "Bail out!"); @@ -557,7 +597,8 @@ test_checkline(const char *line, struct testset *ts)      ts->results[current - 1] = status;      test_backspace(ts);      if (isatty(STDOUT_FILENO)) { -        ts->length = printf("%lu/%lu", current, ts->count); +        outlen = printf("%lu/%lu", current, ts->count); +        ts->length = (outlen >= 0) ? outlen : 0;          fflush(stdout);      }  } @@ -565,23 +606,20 @@ test_checkline(const char *line, struct testset *ts)  /*   * Print out a range of test numbers, returning the number of characters it - * took up.  Add a comma and a space before the range if chars indicates that + * took up.  Takes the first number, the last number, the number of characters + * already printed on the line, and the limit of number of characters the line + * can hold.  Add a comma and a space before the range if chars indicates that   * something has already been printed on the line, and print ... instead if   * chars plus the space needed would go over the limit (use a limit of 0 to - * disable this. + * disable this).   */  static unsigned int  test_print_range(unsigned long first, unsigned long last, unsigned int chars,                   unsigned int limit)  {      unsigned int needed = 0; -    unsigned int out = 0;      unsigned long n; -    if (chars > 0) { -        needed += 2; -        if (!limit || chars <= limit) out += printf(", "); -    }      for (n = first; n > 0; n /= 10)          needed++;      if (last > first) { @@ -589,15 +627,26 @@ test_print_range(unsigned long first, unsigned long last, unsigned int chars,              needed++;          needed++;      } -    if (limit && chars + needed > limit) { -        if (chars <= limit) -            out += printf("..."); +    if (chars > 0) +        needed += 2; +    if (limit > 0 && chars + needed > limit) { +        needed = 0; +        if (chars <= limit) { +            if (chars > 0) { +                printf(", "); +                needed += 2; +            } +            printf("..."); +            needed += 3; +        }      } else { +        if (chars > 0) +            printf(", ");          if (last > first) -            out += printf("%lu-", first); -        out += printf("%lu", last); +            printf("%lu-", first); +        printf("%lu", last);      } -    return out; +    return needed;  } @@ -825,14 +874,14 @@ test_fail_summary(const struct testlist *fails)                      last = i + 1;                  else {                      if (first != 0) -                        chars += test_print_range(first, last, chars, 20); +                        chars += test_print_range(first, last, chars, 19);                      first = i + 1;                      last = i + 1;                  }              }          }          if (first != 0) -            test_print_range(first, last, chars, 20); +            test_print_range(first, last, chars, 19);          putchar('\n');          free(ts->file);          free(ts->path); @@ -861,10 +910,17 @@ find_test(const char *name, struct testset *ts, const char *source,            const char *build)  {      char *path; -    const char *bases[] = { ".", build, source, NULL }; +    const char *bases[4];      unsigned int i; -    for (i = 0; bases[i] != NULL; i++) { +    bases[0] = "."; +    bases[1] = build; +    bases[2] = source; +    bases[3] = NULL; + +    for (i = 0; i < 3; i++) { +        if (bases[i] == NULL) +            continue;          path = xmalloc(strlen(bases[i]) + strlen(name) + 4);          sprintf(path, "%s/%s-t", bases[i], name);          if (access(path, X_OK) != 0) @@ -993,6 +1049,7 @@ test_batch(const char *testlist, const char *source, const char *build)          failed += ts.failed;      }      total -= skipped; +    fclose(tests);      /* Stop the timer and get our child resource statistics. */      gettimeofday(&end, NULL); @@ -1060,17 +1117,23 @@ int  main(int argc, char *argv[])  {      int option; +    int status = 0;      int single = 0; -    char *setting; +    char *source_env = NULL; +    char *build_env = NULL;      const char *list;      const char *source = SOURCE;      const char *build = BUILD; -    while ((option = getopt(argc, argv, "b:os:")) != EOF) { +    while ((option = getopt(argc, argv, "b:hos:")) != EOF) {          switch (option) {          case 'b':              build = optarg;              break; +        case 'h': +            printf(usage_message, argv[0], argv[0]); +            exit(0); +            break;          case 'o':              single = 1;              break; @@ -1081,36 +1144,46 @@ main(int argc, char *argv[])              exit(1);          }      } -    argc -= optind; -    argv += optind; -    if (argc != 1) { -        fprintf(stderr, "Usage: runtests <test-list>\n"); +    if (argc - optind != 1) { +        fprintf(stderr, usage_message, argv[0], argv[0]);          exit(1);      } +    argc -= optind; +    argv += optind;      if (source != NULL) { -        setting = xmalloc(strlen("SOURCE=") + strlen(source) + 1); -        sprintf(setting, "SOURCE=%s", source); -        if (putenv(setting) != 0) +        source_env = xmalloc(strlen("SOURCE=") + strlen(source) + 1); +        sprintf(source_env, "SOURCE=%s", source); +        if (putenv(source_env) != 0)              sysdie("cannot set SOURCE in the environment");      }      if (build != NULL) { -        setting = xmalloc(strlen("BUILD=") + strlen(build) + 1); -        sprintf(setting, "BUILD=%s", build); -        if (putenv(setting) != 0) +        build_env = xmalloc(strlen("BUILD=") + strlen(build) + 1); +        sprintf(build_env, "BUILD=%s", build); +        if (putenv(build_env) != 0)              sysdie("cannot set BUILD in the environment");      } -    if (single) { +    if (single)          test_single(argv[0], source, build); -        exit(0); -    } else { +    else {          list = strrchr(argv[0], '/');          if (list == NULL)              list = argv[0];          else              list++;          printf(banner, list); -        exit(test_batch(argv[0], source, build) ? 0 : 1); +        status = test_batch(argv[0], source, build) ? 0 : 1; +    } + +    /* For valgrind cleanliness. */ +    if (source_env != NULL) { +        putenv((char *) "SOURCE="); +        free(source_env); +    } +    if (build_env != NULL) { +        putenv((char *) "BUILD="); +        free(build_env);      } +    exit(status);  } diff --git a/tests/tap/basic.c b/tests/tap/basic.c index 829f91a..e8196fc 100644 --- a/tests/tap/basic.c +++ b/tests/tap/basic.c @@ -1,22 +1,38 @@  /*   * Some utility routines for writing tests.   * - * Herein are a variety of utility routines for writing tests.  All routines - * of the form ok() or is*() take a test number and some number of appropriate - * arguments, check to be sure the results match the expected output using the - * arguments, and print out something appropriate for that test number.  Other - * utility routines help in constructing more complex tests, skipping tests, - * or setting up the TAP output format. + * Here are a variety of utility routines for writing tests compatible with + * the TAP protocol.  All routines of the form ok() or is*() take a test + * number and some number of appropriate arguments, check to be sure the + * results match the expected output using the arguments, and print out + * something appropriate for that test number.  Other utility routines help in + * constructing more complex tests, skipping tests, reporting errors, setting + * up the TAP output format, or finding things in the test environment.   * - * Copyright 2009, 2010 Russ Allbery <rra@stanford.edu> - * Copyright 2006, 2007, 2008 - *     Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz + * This file is part of C TAP Harness.  The current version plus supporting + * documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.   * - * See LICENSE for licensing terms. + * Copyright 2009, 2010, 2011, 2012 Russ Allbery <rra@stanford.edu> + * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012 + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #include <errno.h> @@ -24,12 +40,21 @@  #include <stdio.h>  #include <stdlib.h>  #include <string.h> +#ifdef _WIN32 +# include <direct.h> +#else +# include <sys/stat.h> +#endif  #include <sys/types.h> -#include <sys/time.h> -#include <sys/wait.h>  #include <unistd.h> -#include <tap/basic.h> +#include <tests/tap/basic.h> + +/* Windows provides mkdir and rmdir under different names. */ +#ifdef _WIN32 +# define mkdir(p, m) _mkdir(p) +# define rmdir(p)    _rmdir(p) +#endif  /*   * The test count.  Always contains the number that will be used for the next @@ -57,7 +82,9 @@ static int _lazy = 0;  /*   * Our exit handler.  Called on completion of the test to report a summary of - * results provided we're still in the original process. + * results provided we're still in the original process.  This also handles + * printing out the plan if we used plan_lazy(), although that's suppressed if + * we never ran a test (due to an early bail, for example).   */  static void  finish(void) @@ -66,8 +93,9 @@ finish(void)      if (_planned == 0 && !_lazy)          return; +    fflush(stderr);      if (_process != 0 && getpid() == _process) { -        if (_lazy) { +        if (_lazy && highest > 0) {              printf("1..%lu\n", highest);              _planned = highest;          } @@ -98,6 +126,7 @@ plan(unsigned long count)      if (setvbuf(stdout, NULL, _IOLBF, BUFSIZ) != 0)          fprintf(stderr, "# cannot set stdout to line buffered: %s\n",                  strerror(errno)); +    fflush(stderr);      printf("1..%lu\n", count);      testnum = 1;      _planned = count; @@ -130,6 +159,7 @@ plan_lazy(void)  void  skip_all(const char *format, ...)  { +    fflush(stderr);      printf("1..0 # skip");      if (format != NULL) {          va_list args; @@ -162,6 +192,7 @@ print_desc(const char *format, va_list args)  void  ok(int success, const char *format, ...)  { +    fflush(stderr);      printf("%sok %lu", success ? "" : "not ", testnum++);      if (!success)          _failed++; @@ -182,6 +213,7 @@ ok(int success, const char *format, ...)  void  okv(int success, const char *format, va_list args)  { +    fflush(stderr);      printf("%sok %lu", success ? "" : "not ", testnum++);      if (!success)          _failed++; @@ -197,6 +229,7 @@ okv(int success, const char *format, va_list args)  void  skip(const char *reason, ...)  { +    fflush(stderr);      printf("ok %lu # skip", testnum++);      if (reason != NULL) {          va_list args; @@ -218,6 +251,7 @@ ok_block(unsigned long count, int status, const char *format, ...)  {      unsigned long i; +    fflush(stderr);      for (i = 0; i < count; i++) {          printf("%sok %lu", status ? "" : "not ", testnum++);          if (!status) @@ -242,6 +276,7 @@ skip_block(unsigned long count, const char *reason, ...)  {      unsigned long i; +    fflush(stderr);      for (i = 0; i < count; i++) {          printf("ok %lu # skip", testnum++);          if (reason != NULL) { @@ -264,6 +299,7 @@ skip_block(unsigned long count, const char *reason, ...)  void  is_int(long wanted, long seen, const char *format, ...)  { +    fflush(stderr);      if (wanted == seen)          printf("ok %lu", testnum++);      else { @@ -293,6 +329,7 @@ is_string(const char *wanted, const char *seen, const char *format, ...)          wanted = "(null)";      if (seen == NULL)          seen = "(null)"; +    fflush(stderr);      if (strcmp(wanted, seen) == 0)          printf("ok %lu", testnum++);      else { @@ -312,37 +349,13 @@ is_string(const char *wanted, const char *seen, const char *format, ...)  /* - * Takes an expected double and a seen double and assumes the test passes if - * those two numbers match. - */ -void -is_double(double wanted, double seen, const char *format, ...) -{ -    if (wanted == seen) -        printf("ok %lu", testnum++); -    else { -        printf("# wanted: %g\n#   seen: %g\n", wanted, seen); -        printf("not ok %lu", testnum++); -        _failed++; -    } -    if (format != NULL) { -        va_list args; - -        va_start(args, format); -        print_desc(format, args); -        va_end(args); -    } -    putchar('\n'); -} - - -/*   * Takes an expected unsigned long and a seen unsigned long and assumes the   * test passes if the two numbers match.  Otherwise, reports them in hex.   */  void  is_hex(unsigned long wanted, unsigned long seen, const char *format, ...)  { +    fflush(stderr);      if (wanted == seen)          printf("ok %lu", testnum++);      else { @@ -370,6 +383,7 @@ bail(const char *format, ...)  {      va_list args; +    fflush(stderr);      fflush(stdout);      printf("Bail out! ");      va_start(args, format); @@ -389,6 +403,7 @@ sysbail(const char *format, ...)      va_list args;      int oerrno = errno; +    fflush(stderr);      fflush(stdout);      printf("Bail out! ");      va_start(args, format); @@ -407,6 +422,7 @@ diag(const char *format, ...)  {      va_list args; +    fflush(stderr);      fflush(stdout);      printf("# ");      va_start(args, format); @@ -425,6 +441,7 @@ sysdiag(const char *format, ...)      va_list args;      int oerrno = errno; +    fflush(stderr);      fflush(stdout);      printf("# ");      va_start(args, format); @@ -435,6 +452,92 @@ sysdiag(const char *format, ...)  /* + * Allocate cleared memory, reporting a fatal error with bail on failure. + */ +void * +bcalloc(size_t n, size_t size) +{ +    void *p; + +    p = calloc(n, size); +    if (p == NULL) +        sysbail("failed to calloc %lu", (unsigned long)(n * size)); +    return p; +} + + +/* + * Allocate memory, reporting a fatal error with bail on failure. + */ +void * +bmalloc(size_t size) +{ +    void *p; + +    p = malloc(size); +    if (p == NULL) +        sysbail("failed to malloc %lu", (unsigned long) size); +    return p; +} + + +/* + * Reallocate memory, reporting a fatal error with bail on failure. + */ +void * +brealloc(void *p, size_t size) +{ +    p = realloc(p, size); +    if (p == NULL) +        sysbail("failed to realloc %lu bytes", (unsigned long) size); +    return p; +} + + +/* + * Copy a string, reporting a fatal error with bail on failure. + */ +char * +bstrdup(const char *s) +{ +    char *p; +    size_t len; + +    len = strlen(s) + 1; +    p = malloc(len); +    if (p == NULL) +        sysbail("failed to strdup %lu bytes", (unsigned long) len); +    memcpy(p, s, len); +    return p; +} + + +/* + * Copy up to n characters of a string, reporting a fatal error with bail on + * failure.  Don't use the system strndup function, since it may not exist and + * the TAP library doesn't assume any portability support. + */ +char * +bstrndup(const char *s, size_t n) +{ +    const char *p; +    char *copy; +    size_t length; + +    /* Don't assume that the source string is nul-terminated. */ +    for (p = s; (size_t) (p - s) < n && *p != '\0'; p++) +        ; +    length = p - s; +    copy = malloc(length + 1); +    if (p == NULL) +        sysbail("failed to strndup %lu bytes", (unsigned long) length); +    memcpy(copy, s, length); +    copy[length] = '\0'; +    return copy; +} + + +/*   * Locate a test file.  Given the partial path to a file, look under BUILD and   * then SOURCE for the file and return the full path to the file.  Returns   * NULL if the file doesn't exist.  A non-NULL return should be freed with @@ -458,9 +561,7 @@ test_file_path(const char *file)          if (base == NULL)              continue;          length = strlen(base) + 1 + strlen(file) + 1; -        path = malloc(length); -        if (path == NULL) -            sysbail("cannot allocate memory"); +        path = bmalloc(length);          sprintf(path, "%s/%s", base, file);          if (access(path, R_OK) == 0)              break; @@ -482,3 +583,47 @@ test_file_path_free(char *path)      if (path != NULL)          free(path);  } + + +/* + * Create a temporary directory, tmp, under BUILD if set and the current + * directory if it does not.  Returns the path to the temporary directory in + * newly allocated memory, and calls bail on any failure.  The return value + * should be freed with test_tmpdir_free. + * + * This function uses sprintf because it attempts to be independent of all + * other portability layers.  The use immediately after a memory allocation + * should be safe without using snprintf or strlcpy/strlcat. + */ +char * +test_tmpdir(void) +{ +    const char *build; +    char *path = NULL; +    size_t length; + +    build = getenv("BUILD"); +    if (build == NULL) +        build = "."; +    length = strlen(build) + strlen("/tmp") + 1; +    path = bmalloc(length); +    sprintf(path, "%s/tmp", build); +    if (access(path, X_OK) < 0) +        if (mkdir(path, 0777) < 0) +            sysbail("error creating temporary directory %s", path); +    return path; +} + + +/* + * Free a path returned from test_tmpdir() and attempt to remove the + * directory.  If we can't delete the directory, don't worry; something else + * that hasn't yet cleaned up may still be using it. + */ +void +test_tmpdir_free(char *path) +{ +    rmdir(path); +    if (path != NULL) +        free(path); +} diff --git a/tests/tap/basic.h b/tests/tap/basic.h index 9602db4..fa4adaf 100644 --- a/tests/tap/basic.h +++ b/tests/tap/basic.h @@ -1,47 +1,38 @@  /*   * Basic utility routines for the TAP protocol.   * - * Copyright 2009, 2010 Russ Allbery <rra@stanford.edu> - * Copyright 2006, 2007, 2008 - *     Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz + * This file is part of C TAP Harness.  The current version plus supporting + * documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>.   * - * See LICENSE for licensing terms. + * Copyright 2009, 2010, 2011, 2012 Russ Allbery <rra@stanford.edu> + * Copyright 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2011, 2012 + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #ifndef TAP_BASIC_H  #define TAP_BASIC_H 1 +#include <tests/tap/macros.h>  #include <stdarg.h>             /* va_list */ -#include <sys/types.h>          /* pid_t */ - -/* - * __attribute__ is available in gcc 2.5 and later, but only with gcc 2.7 - * could you use the __format__ form of the attributes, which is what we use - * (to avoid confusion with other macros). - */ -#ifndef __attribute__ -# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) -#  define __attribute__(spec)   /* empty */ -# endif -#endif - -/* - * BEGIN_DECLS is used at the beginning of declarations so that C++ - * compilers don't mangle their names.  END_DECLS is used at the end. - */ -#undef BEGIN_DECLS -#undef END_DECLS -#ifdef __cplusplus -# define BEGIN_DECLS    extern "C" { -# define END_DECLS      } -#else -# define BEGIN_DECLS    /* empty */ -# define END_DECLS      /* empty */ -#endif +#include <sys/types.h>          /* size_t */  /*   * Used for iterating through arrays.  ARRAY_SIZE returns the number of @@ -93,8 +84,6 @@ void skip_block(unsigned long count, const char *reason, ...)  /* Check an expected value against a seen value. */  void is_int(long wanted, long seen, const char *format, ...)      __attribute__((__format__(printf, 3, 4))); -void is_double(double wanted, double seen, const char *format, ...) -    __attribute__((__format__(printf, 3, 4)));  void is_string(const char *wanted, const char *seen, const char *format, ...)      __attribute__((__format__(printf, 3, 4)));  void is_hex(unsigned long wanted, unsigned long seen, const char *format, ...) @@ -112,6 +101,18 @@ void diag(const char *format, ...)  void sysdiag(const char *format, ...)      __attribute__((__nonnull__, __format__(printf, 1, 2))); +/* Allocate memory, reporting a fatal error with bail on failure. */ +void *bcalloc(size_t, size_t) +    __attribute__((__alloc_size__(1, 2), __malloc__)); +void *bmalloc(size_t) +    __attribute__((__alloc_size__(1), __malloc__)); +void *brealloc(void *, size_t) +    __attribute__((__alloc_size__(2), __malloc__)); +char *bstrdup(const char *) +    __attribute__((__malloc__, __nonnull__)); +char *bstrndup(const char *, size_t) +    __attribute__((__malloc__, __nonnull__)); +  /*   * Find a test file under BUILD or SOURCE, returning the full path.  The   * returned path should be freed with test_file_path_free(). @@ -120,6 +121,14 @@ char *test_file_path(const char *file)      __attribute__((__malloc__, __nonnull__));  void test_file_path_free(char *path); +/* + * Create a temporary directory relative to BUILD and return the path.  The + * returned path should be freed with test_tmpdir_free. + */ +char *test_tmpdir(void) +    __attribute__((__malloc__)); +void test_tmpdir_free(char *path); +  END_DECLS  #endif /* TAP_BASIC_H */ diff --git a/tests/tap/kerberos.c b/tests/tap/kerberos.c index a17d980..474cf4f 100644 --- a/tests/tap/kerberos.c +++ b/tests/tap/kerberos.c @@ -1,47 +1,90 @@  /*   * Utility functions for tests that use Kerberos.   * - * Currently only provides kerberos_setup(), which assumes a particular set of - * data files in either the SOURCE or BUILD directories and, using those, - * obtains Kerberos credentials, sets up a ticket cache, and sets the - * environment variable pointing to the Kerberos keytab to use for testing. + * The core function is kerberos_setup, which loads Kerberos test + * configuration and returns a struct of information.  It also supports + * obtaining initial tickets from the configured keytab and setting up + * KRB5CCNAME and KRB5_KTNAME if a Kerberos keytab is present.  Also included + * are utility functions for setting up a krb5.conf file and reporting + * Kerberos errors or warnings during testing.   * - * Copyright 2006, 2007, 2009, 2010 - *     Board of Trustees, Leland Stanford Jr. University + * Some of the functionality here is only available if the Kerberos libraries + * are available.   * - * See LICENSE for licensing terms. + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Written by Russ Allbery <rra@stanford.edu> + * Copyright 2006, 2007, 2009, 2010, 2011, 2012 + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #include <config.h> -#include <portable/krb5.h> +#ifdef HAVE_KERBEROS +# include <portable/krb5.h> +#endif  #include <portable/system.h> +#include <sys/stat.h> +  #include <tests/tap/basic.h>  #include <tests/tap/kerberos.h> -#include <util/concat.h> -#include <util/xmalloc.h> +#include <tests/tap/process.h> +#include <tests/tap/string.h> + +/* + * Disable the requirement that format strings be literals, since it's easier + * to handle the possible patterns for kinit commands as an array. + */ +#pragma GCC diagnostic ignored "-Wformat-nonliteral"  /* - * Obtain Kerberos tickets for the principal specified in test.principal using - * the keytab specified in test.keytab, both of which are presumed to be in - * tests/data in either the build or the source tree. - * - * Returns the contents of test.principal in newly allocated memory or NULL if - * Kerberos tests are apparently not configured.  If Kerberos tests are - * configured but something else fails, calls bail(). + * These variables hold the allocated configuration struct, the environment to + * point to a different Kerberos ticket cache, keytab, and configuration file, + * and the temporary directories used.  We store them so that we can free them + * on exit for cleaner valgrind output, making it easier to find real memory + * leaks in the tested programs. + */ +static struct kerberos_config *config = NULL; +static char *krb5ccname = NULL; +static char *krb5_ktname = NULL; +static char *krb5_config = NULL; +static char *tmpdir_ticket = NULL; +static char *tmpdir_conf = NULL; + + +/* + * Obtain Kerberos tickets and fill in the principal config entry.   * - * The error handling here is not great.  We should have a bail_krb5 that uses - * the same logic as messages-krb5.c, which hasn't yet been imported into - * rra-c-util. + * There are two implementations of this function, one if we have native + * Kerberos libraries available and one if we don't.  Uses keytab to obtain + * credentials, and fills in the cache member of the provided config struct.   */ -char * -kerberos_setup(void) +#ifdef HAVE_KERBEROS + +static void +kerberos_kinit(void)  { -    char *path, *krbtgt; -    const char *build, *realm; -    FILE *file; -    char principal[BUFSIZ]; +    char *name, *krbtgt;      krb5_error_code code;      krb5_context ctx;      krb5_ccache ccache; @@ -49,89 +92,397 @@ kerberos_setup(void)      krb5_keytab keytab;      krb5_get_init_creds_opt *opts;      krb5_creds creds; +    const char *realm; -    /* Read the principal name and find the keytab file. */ -    path = test_file_path("data/test.principal"); -    if (path == NULL) -        return NULL; -    file = fopen(path, "r"); -    if (file == NULL) { -        free(path); -        return NULL; -    } -    if (fgets(principal, sizeof(principal), file) == NULL) { -        fclose(file); -        bail("cannot read %s", path); -    } -    fclose(file); -    if (principal[strlen(principal) - 1] != '\n') -        bail("no newline in %s", path); -    free(path); -    principal[strlen(principal) - 1] = '\0'; -    path = test_file_path("data/test.keytab"); -    if (path == NULL) -        return NULL; - -    /* Set the KRB5CCNAME and KRB5_KTNAME environment variables. */ -    build = getenv("BUILD"); -    if (build == NULL) -        build = "."; -    putenv(concat("KRB5CCNAME=", build, "/data/test.cache", (char *) 0)); -    putenv(concat("KRB5_KTNAME=", path, (char *) 0)); - -    /* Now do the Kerberos initialization. */ +    /* +     * Determine the principal corresponding to that keytab.  We copy the +     * memory to ensure that it's allocated in the right memory domain on +     * systems where that may matter (like Windows). +     */      code = krb5_init_context(&ctx);      if (code != 0) -        bail("error initializing Kerberos"); +        bail_krb5(ctx, code, "error initializing Kerberos"); +    kprinc = kerberos_keytab_principal(ctx, config->keytab); +    code = krb5_unparse_name(ctx, kprinc, &name); +    if (code != 0) +        bail_krb5(ctx, code, "error unparsing name"); +    krb5_free_principal(ctx, kprinc); +    config->principal = bstrdup(name); +    krb5_free_unparsed_name(ctx, name); + +    /* Now do the Kerberos initialization. */      code = krb5_cc_default(ctx, &ccache);      if (code != 0) -        bail("error setting ticket cache"); -    code = krb5_parse_name(ctx, principal, &kprinc); +        bail_krb5(ctx, code, "error setting ticket cache"); +    code = krb5_parse_name(ctx, config->principal, &kprinc);      if (code != 0) -        bail("error parsing principal %s", principal); +        bail_krb5(ctx, code, "error parsing principal %s", config->principal);      realm = krb5_principal_get_realm(ctx, kprinc); -    krbtgt = concat("krbtgt/", realm, "@", realm, (char *) 0); -    code = krb5_kt_resolve(ctx, path, &keytab); +    basprintf(&krbtgt, "krbtgt/%s@%s", realm, realm); +    code = krb5_kt_resolve(ctx, config->keytab, &keytab);      if (code != 0) -        bail("cannot open keytab %s", path); +        bail_krb5(ctx, code, "cannot open keytab %s", config->keytab);      code = krb5_get_init_creds_opt_alloc(ctx, &opts);      if (code != 0) -        bail("cannot allocate credential options"); +        bail_krb5(ctx, code, "cannot allocate credential options");      krb5_get_init_creds_opt_set_default_flags(ctx, NULL, realm, opts);      krb5_get_init_creds_opt_set_forwardable(opts, 0);      krb5_get_init_creds_opt_set_proxiable(opts, 0);      code = krb5_get_init_creds_keytab(ctx, &creds, kprinc, keytab, 0, krbtgt,                                        opts);      if (code != 0) -        bail("cannot get Kerberos tickets"); +        bail_krb5(ctx, code, "cannot get Kerberos tickets");      code = krb5_cc_initialize(ctx, ccache, kprinc);      if (code != 0) -        bail("error initializing ticket cache"); +        bail_krb5(ctx, code, "error initializing ticket cache");      code = krb5_cc_store_cred(ctx, ccache, &creds);      if (code != 0) -        bail("error storing credentials"); +        bail_krb5(ctx, code, "error storing credentials");      krb5_cc_close(ctx, ccache);      krb5_free_cred_contents(ctx, &creds);      krb5_kt_close(ctx, keytab);      krb5_free_principal(ctx, kprinc); +    krb5_get_init_creds_opt_free(ctx, opts);      krb5_free_context(ctx);      free(krbtgt); -    free(path); +} -    return xstrdup(principal); +#else /* !HAVE_KERBEROS */ + +static void +kerberos_kinit(void) +{ +    static const char * const format[] = { +        "kinit --no-afslog -k -t %s %s >/dev/null 2>&1 </dev/null", +        "kinit -k -t %s %s >/dev/null 2>&1 </dev/null", +        "kinit -t %s %s >/dev/null 2>&1 </dev/null", +        "kinit -k -K %s %s >/dev/null 2>&1 </dev/null" +    }; +    FILE *file; +    char *path; +    char principal[BUFSIZ], *command; +    size_t i; +    int status; + +    /* Read the principal corresponding to the keytab. */ +    path = test_file_path("config/principal"); +    if (path == NULL) { +        test_file_path_free(config->keytab); +        config->keytab = NULL; +        return; +    } +    file = fopen(path, "r"); +    if (file == NULL) { +        test_file_path_free(path); +        return; +    } +    test_file_path_free(path); +    if (fgets(principal, sizeof(principal), file) == NULL) +        bail("cannot read %s", path); +    fclose(file); +    if (principal[strlen(principal) - 1] != '\n') +        bail("no newline in %s", path); +    principal[strlen(principal) - 1] = '\0'; +    config->principal = bstrdup(principal); + +    /* Now do the Kerberos initialization. */ +    for (i = 0; i < ARRAY_SIZE(format); i++) { +        basprintf(&command, format[i], config->keytab, principal); +        status = system(command); +        free(command); +        if (status != -1 && WEXITSTATUS(status) == 0) +            break; +    } +    if (status == -1 || WEXITSTATUS(status) != 0) +        bail("cannot get Kerberos tickets");  } +#endif /* !HAVE_KERBEROS */ +  /* - * Clean up at the end of a test.  Currently, all this does is remove the - * ticket cache. + * Clean up at the end of a test.  This removes the ticket cache and resets + * and frees the memory allocated for the environment variables so that + * valgrind output on test suites is cleaner.   */  void  kerberos_cleanup(void)  {      char *path; -    path = concatpath(getenv("BUILD"), "data/test.cache"); -    unlink(path); -    free(path); +    if (tmpdir_ticket != NULL) { +        basprintf(&path, "%s/krb5cc_test", tmpdir_ticket); +        unlink(path); +        free(path); +        test_tmpdir_free(tmpdir_ticket); +        tmpdir_ticket = NULL; +    } +    if (config != NULL) { +        if (config->keytab != NULL) { +            test_file_path_free(config->keytab); +            free(config->principal); +            free(config->cache); +        } +        if (config->userprinc != NULL) { +            free(config->userprinc); +            free(config->username); +            free(config->password); +        } +        free(config); +        config = NULL; +    } +    if (krb5ccname != NULL) { +        putenv((char *) "KRB5CCNAME="); +        free(krb5ccname); +        krb5ccname = NULL; +    } +    if (krb5_ktname != NULL) { +        putenv((char *) "KRB5_KTNAME="); +        free(krb5_ktname); +        krb5_ktname = NULL; +    } +} + + +/* + * Obtain Kerberos tickets for the principal specified in config/principal + * using the keytab specified in config/keytab, both of which are presumed to + * be in tests in either the build or the source tree.  Also sets KRB5_KTNAME + * and KRB5CCNAME. + * + * Returns the contents of config/principal in newly allocated memory or NULL + * if Kerberos tests are apparently not configured.  If Kerberos tests are + * configured but something else fails, calls bail. + */ +struct kerberos_config * +kerberos_setup(enum kerberos_needs needs) +{ +    char *path; +    char buffer[BUFSIZ]; +    FILE *file = NULL; + +    /* If we were called before, clean up after the previous run. */ +    if (config != NULL) +        kerberos_cleanup(); +    config = bcalloc(1, sizeof(struct kerberos_config)); + +    /* +     * If we have a config/keytab file, set the KRB5CCNAME and KRB5_KTNAME +     * environment variables and obtain initial tickets. +     */ +    config->keytab = test_file_path("config/keytab"); +    if (config->keytab == NULL) { +        if (needs == TAP_KRB_NEEDS_KEYTAB || needs == TAP_KRB_NEEDS_BOTH) +            skip_all("Kerberos tests not configured"); +    } else { +        tmpdir_ticket = test_tmpdir(); +        basprintf(&config->cache, "%s/krb5cc_test", tmpdir_ticket); +        basprintf(&krb5ccname, "KRB5CCNAME=%s/krb5cc_test", tmpdir_ticket); +        basprintf(&krb5_ktname, "KRB5_KTNAME=%s", config->keytab); +        putenv(krb5ccname); +        putenv(krb5_ktname); +        kerberos_kinit(); +    } + +    /* +     * If we have a config/password file, read it and fill out the relevant +     * members of our config struct. +     */ +    path = test_file_path("config/password"); +    if (path != NULL) +        file = fopen(path, "r"); +    if (file == NULL) { +        if (needs == TAP_KRB_NEEDS_PASSWORD || needs == TAP_KRB_NEEDS_BOTH) +            skip_all("Kerberos tests not configured"); +    } else { +        if (fgets(buffer, sizeof(buffer), file) == NULL) +            bail("cannot read %s", path); +        if (buffer[strlen(buffer) - 1] != '\n') +            bail("no newline in %s", path); +        buffer[strlen(buffer) - 1] = '\0'; +        config->userprinc = bstrdup(buffer); +        if (fgets(buffer, sizeof(buffer), file) == NULL) +            bail("cannot read password from %s", path); +        fclose(file); +        if (buffer[strlen(buffer) - 1] != '\n') +            bail("password too long in %s", path); +        buffer[strlen(buffer) - 1] = '\0'; +        config->password = bstrdup(buffer); + +        /* +         * Strip the realm from the principal and set realm and username. +         * This is not strictly correct; it doesn't cope with escaped @-signs +         * or enterprise names. +         */ +        config->username = bstrdup(config->userprinc); +        config->realm = strchr(config->username, '@'); +        if (config->realm == NULL) +            bail("test principal has no realm"); +        *config->realm = '\0'; +        config->realm++; +    } +    if (path != NULL) +        test_file_path_free(path); + +    /* +     * Register the cleanup function as an atexit handler so that the caller +     * doesn't have to worry about cleanup. +     */ +    if (atexit(kerberos_cleanup) != 0) +        sysdiag("cannot register cleanup function"); + +    /* Return the configuration. */ +    return config; +} + + +/* + * Clean up the krb5.conf file generated by kerberos_generate_conf and free + * the memory used to set the environment variable.  This doesn't fail if the + * file and variable are already gone, allowing it to be harmlessly run + * multiple times. + * + * Normally called via an atexit handler. + */ +void +kerberos_cleanup_conf(void) +{ +    char *path; + +    if (tmpdir_conf != NULL) { +        basprintf(&path, "%s/krb5.conf", tmpdir_conf); +        unlink(path); +        free(path); +        test_tmpdir_free(tmpdir_conf); +        tmpdir_conf = NULL; +    } +    putenv((char *) "KRB5_CONFIG="); +    if (krb5_config != NULL) { +        free(krb5_config); +        krb5_config = NULL; +    }  } + + +/* + * Generate a krb5.conf file for testing and set KRB5_CONFIG to point to it. + * The [appdefaults] section will be stripped out and the default realm will + * be set to the realm specified, if not NULL.  This will use config/krb5.conf + * in preference, so users can configure the tests by creating that file if + * the system file isn't suitable. + * + * Depends on data/generate-krb5-conf being present in the test suite. + */ +void +kerberos_generate_conf(const char *realm) +{ +    char *path; +    const char *argv[3]; + +    if (tmpdir_conf != NULL) +        kerberos_cleanup_conf(); +    path = test_file_path("data/generate-krb5-conf"); +    if (path == NULL) +        bail("cannot find generate-krb5-conf"); +    argv[0] = path; +    argv[1] = realm; +    argv[2] = NULL; +    run_setup(argv); +    test_file_path_free(path); +    tmpdir_conf = test_tmpdir(); +    basprintf(&krb5_config, "KRB5_CONFIG=%s/krb5.conf", tmpdir_conf); +    putenv(krb5_config); +    if (atexit(kerberos_cleanup_conf) != 0) +        sysdiag("cannot register cleanup function"); +} + + +/* + * The remaining functions in this file are only available if Kerberos + * libraries are available. + */ +#ifdef HAVE_KERBEROS + + +/* + * Report a Kerberos error and bail out. + */ +void +bail_krb5(krb5_context ctx, krb5_error_code code, const char *format, ...) +{ +    const char *k5_msg = NULL; +    char *message; +    va_list args; + +    if (ctx != NULL) +        k5_msg = krb5_get_error_message(ctx, code); +    va_start(args, format); +    bvasprintf(&message, format, args); +    va_end(args); +    if (k5_msg == NULL) +        bail("%s", message); +    else +        bail("%s: %s", message, k5_msg); +} + + +/* + * Report a Kerberos error as a diagnostic to stderr. + */ +void +diag_krb5(krb5_context ctx, krb5_error_code code, const char *format, ...) +{ +    const char *k5_msg = NULL; +    char *message; +    va_list args; + +    if (ctx != NULL) +        k5_msg = krb5_get_error_message(ctx, code); +    va_start(args, format); +    bvasprintf(&message, format, args); +    va_end(args); +    if (k5_msg == NULL) +        diag("%s", message); +    else +        diag("%s: %s", message, k5_msg); +    free(message); +    if (k5_msg != NULL) +        krb5_free_error_message(ctx, k5_msg); +} + + +/* + * Find the principal of the first entry of a keytab and return it.  The + * caller is responsible for freeing the result with krb5_free_principal. + * Exit on error. + */ +krb5_principal +kerberos_keytab_principal(krb5_context ctx, const char *path) +{ +    krb5_keytab keytab; +    krb5_kt_cursor cursor; +    krb5_keytab_entry entry; +    krb5_principal princ; +    krb5_error_code status; + +    status = krb5_kt_resolve(ctx, path, &keytab); +    if (status != 0) +        bail_krb5(ctx, status, "error opening %s", path); +    status = krb5_kt_start_seq_get(ctx, keytab, &cursor); +    if (status != 0) +        bail_krb5(ctx, status, "error reading %s", path); +    status = krb5_kt_next_entry(ctx, keytab, &entry, &cursor); +    if (status == 0) { +        status = krb5_copy_principal(ctx, entry.principal, &princ); +        if (status != 0) +            bail_krb5(ctx, status, "error copying principal from %s", path); +        krb5_kt_free_entry(ctx, &entry); +    } +    if (status != 0) +        bail("no principal found in keytab file %s", path); +    krb5_kt_end_seq_get(ctx, keytab, &cursor); +    krb5_kt_close(ctx, keytab); +    return princ; +} + +#endif /* HAVE_KERBEROS */ diff --git a/tests/tap/kerberos.h b/tests/tap/kerberos.h index 1c64f70..31b6343 100644 --- a/tests/tap/kerberos.h +++ b/tests/tap/kerberos.h @@ -1,32 +1,125 @@  /*   * Utility functions for tests that use Kerberos.   * - * Copyright 2006, 2007, 2009 - *     Board of Trustees, Leland Stanford Jr. University + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.   * - * See LICENSE for licensing terms. + * Written by Russ Allbery <rra@stanford.edu> + * Copyright 2006, 2007, 2009, 2011, 2012 + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #ifndef TAP_KERBEROS_H  #define TAP_KERBEROS_H 1  #include <config.h> -#include <portable/macros.h> +#include <tests/tap/macros.h> + +#ifdef HAVE_KERBEROS +# include <portable/krb5.h> +#endif + +/* Holds the information parsed from the Kerberos test configuration. */ +struct kerberos_config { +    char *keytab;               /* Path to the keytab. */ +    char *principal;            /* Principal whose keys are in the keytab. */ +    char *cache;                /* Path to the Kerberos ticket cache. */ +    char *userprinc;            /* The fully-qualified principal. */ +    char *username;             /* The local (non-realm) part of principal. */ +    char *realm;                /* The realm part of the principal. */ +    char *password;             /* The password. */ +}; + +/* + * Whether to skip all tests (by calling skip_all) in kerberos_setup if + * certain configuration information isn't available. + */ +enum kerberos_needs { +    TAP_KRB_NEEDS_NONE, +    TAP_KRB_NEEDS_KEYTAB, +    TAP_KRB_NEEDS_PASSWORD, +    TAP_KRB_NEEDS_BOTH +};  BEGIN_DECLS  /* - * Set up Kerberos, returning the test principal in newly allocated memory if - * we were successful.  If there is no principal in tests/data/test.principal - * or no keytab in tests/data/test.keytab, return NULL.  Otherwise, on - * failure, calls bail(). + * Set up Kerberos, returning the test configuration information.  This + * obtains Kerberos tickets from config/keytab, if one is present, and stores + * them in a Kerberos ticket cache, sets KRB5_KTNAME and KRB5CCNAME.  It also + * loads the principal and password from config/password, if it exists, and + * stores the principal, password, username, and realm in the returned struct. + * + * If there is no config/keytab file, KRB5_KTNAME and KRB5CCNAME won't be set + * and the keytab field will be NULL.  If there is no config/password file, + * the principal field will be NULL.  If the files exist but loading them + * fails, or authentication fails, kerberos_setup calls bail. + * + * kerberos_cleanup will be set up to run from an atexit handler.  This means + * that any child processes that should not remove the Kerberos ticket cache + * should call _exit instead of exit.  The principal will be automatically + * freed when kerberos_cleanup is called or if kerberos_setup is called again. + * The caller doesn't need to worry about it.   */ -char *kerberos_setup(void) +struct kerberos_config *kerberos_setup(enum kerberos_needs)      __attribute__((__malloc__)); - -/* Clean up at the end of a test. */  void kerberos_cleanup(void); +/* + * Generate a krb5.conf file for testing and set KRB5_CONFIG to point to it. + * The [appdefaults] section will be stripped out and the default realm will + * be set to the realm specified, if not NULL.  This will use config/krb5.conf + * in preference, so users can configure the tests by creating that file if + * the system file isn't suitable. + * + * Depends on data/generate-krb5-conf being present in the test suite. + * + * kerberos_cleanup_conf will clean up after this function, but usually + * doesn't need to be called directly since it's registered as an atexit + * handler. + */ +void kerberos_generate_conf(const char *realm); +void kerberos_cleanup_conf(void); + +/* Thes interfaces are only available with native Kerberos support. */ +#ifdef HAVE_KERBEROS + +/* Bail out with an error, appending the Kerberos error message. */ +void bail_krb5(krb5_context, krb5_error_code, const char *format, ...) +    __attribute__((__noreturn__, __nonnull__, __format__(printf, 3, 4))); + +/* Report a diagnostic with Kerberos error to stderr prefixed with #. */ +void diag_krb5(krb5_context, krb5_error_code, const char *format, ...) +    __attribute__((__nonnull__, __format__(printf, 3, 4))); + +/* + * Given a Kerberos context and the path to a keytab, retrieve the principal + * for the first entry in the keytab and return it.  Calls bail on failure. + * The returned principal should be freed with krb5_free_principal. + */ +krb5_principal kerberos_keytab_principal(krb5_context, const char *path) +    __attribute__((__nonnull__)); + +#endif /* HAVE_KERBEROS */ +  END_DECLS  #endif /* !TAP_MESSAGES_H */ diff --git a/tests/tap/kerberos.sh b/tests/tap/kerberos.sh index 904cae5..d2f174d 100644 --- a/tests/tap/kerberos.sh +++ b/tests/tap/kerberos.sh @@ -1,30 +1,61 @@  # Shell function library to initialize Kerberos credentials  # +# Note that while many of the functions in this library could benefit from +# using "local" to avoid possibly hammering global variables, Solaris /bin/sh +# doesn't support local and this library aspires to be portable to Solaris +# Bourne shell.  Instead, all private variables are prefixed with "tap_". +# +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +#  # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2009, 2010 Board of Trustees, Leland Stanford Jr. University +# Copyright 2009, 2010, 2011, 2012 +#     The Board of Trustees of the Leland Stanford Junior University +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software.  # -# See LICENSE for licensing terms. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +# We use test_tmpdir. +. "${SOURCE}/tap/libtap.sh"  # Set up Kerberos, including the ticket cache environment variable.  Bail out  # if not successful, return 0 if successful, and return 1 if Kerberos is not  # configured.  Sets the global principal variable to the principal to use.  kerberos_setup () { -    local keytab -    keytab=`test_file_path data/test.keytab` -    principal=`test_file_path data/test.principal` +    tap_keytab=`test_file_path config/keytab` +    principal=`test_file_path config/principal`      principal=`cat "$principal" 2>/dev/null` -    if [ -z "$keytab" ] || [ -z "$principal" ] ; then +    if [ -z "$tap_keytab" ] || [ -z "$principal" ] ; then          return 1      fi -    KRB5CCNAME="$BUILD/data/test.cache"; export KRB5CCNAME -    kinit -k -t "$keytab" "$principal" >/dev/null </dev/null +    KRB5CCNAME=`test_tmpdir`/krb5cc_test; export KRB5CCNAME +    kinit --no-afslog -k -t "$tap_keytab" "$principal" >/dev/null </dev/null      status=$?      if [ $status != 0 ] ; then -        kinit -t "$keytab" "$principal" >/dev/null </dev/null +        kinit -k -t "$tap_keytab" "$principal" >/dev/null </dev/null +        status=$? +    fi +    if [ $status != 0 ] ; then +        kinit -t "$tap_keytab" "$principal" >/dev/null </dev/null          status=$?      fi      if [ $status != 0 ] ; then -        kinit -k -K "$keytab" "$principal" >/dev/null </dev/null +        kinit -k -K "$tap_keytab" "$principal" >/dev/null </dev/null          status=$?      fi      if [ $status != 0 ] ; then @@ -35,7 +66,8 @@ kerberos_setup () {  # Clean up at the end of a test.  Currently only removes the ticket cache.  kerberos_cleanup () { -    rm -f "$BUILD/data/test.cache" +    tap_tmp=`test_tmpdir` +    rm -f "$tap_tmp"/krb5cc_test  }  # List the contents of a keytab with enctypes and keys.  This adjusts for the @@ -44,11 +76,13 @@ kerberos_cleanup () {  # may just hang.  Takes the keytab to list and the file into which to save the  # output, and strips off the header containing the file name.  ktutil_list () { -    if klist -keK "$1" > ktutil-tmp 2>/dev/null ; then +    tap_tmp=`test_tmpdir` +    if klist -keK "$1" > "$tap_tmp"/ktutil-tmp 2>/dev/null ; then          :      else -        ktutil -k "$1" list --keys > ktutil-tmp < /dev/null 2>/dev/null +        ktutil -k "$1" list --keys > "$tap_tmp"/ktutil-tmp </dev/null \ +            2>/dev/null      fi -    sed -e '/Keytab name:/d' -e "/^[^ ]*:/d" ktutil-tmp > "$2" -    rm -f ktutil-tmp +    sed -e '/Keytab name:/d' -e "/^[^ ]*:/d" "$tap_tmp"/ktutil-tmp > "$2" +    rm -f "$tap_tmp"/ktutil-tmp  } diff --git a/tests/tap/libtap.sh b/tests/tap/libtap.sh index a9b46d4..f9347d8 100644 --- a/tests/tap/libtap.sh +++ b/tests/tap/libtap.sh @@ -1,10 +1,36 @@  # Shell function library for test cases.  # +# Note that while many of the functions in this library could benefit from +# using "local" to avoid possibly hammering global variables, Solaris /bin/sh +# doesn't support local and this library aspires to be portable to Solaris +# Bourne shell.  Instead, all private variables are prefixed with "tap_". +# +# This file provides a TAP-compatible shell function library useful for +# writing test cases.  It is part of C TAP Harness, which can be found at +# <http://www.eyrie.org/~eagle/software/c-tap-harness/>. +#  # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2009, 2010 Russ Allbery <rra@stanford.edu> -# Copyright 2006, 2007, 2008 Board of Trustees, Leland Stanford Jr. University +# Copyright 2009, 2010, 2011, 2012 Russ Allbery <rra@stanford.edu> +# Copyright 2006, 2007, 2008 +#     The Board of Trustees of the Leland Stanford Junior University +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions:  # -# See LICENSE for licensing terms. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE.  # Print out the number of test cases we expect to run.  plan () { @@ -25,33 +51,35 @@ plan_lazy () {  # Report the test status on exit.  finish () { -    local highest looks -    highest=`expr "$count" - 1` +    tap_highest=`expr "$count" - 1`      if [ "$planned" = 0 ] ; then -        echo "1..$highest" -        planned="$highest" +        echo "1..$tap_highest" +        planned="$tap_highest"      fi -    looks='# Looks like you' +    tap_looks='# Looks like you'      if [ "$planned" -gt 0 ] ; then -        if [ "$planned" -gt "$highest" ] ; then +        if [ "$planned" -gt "$tap_highest" ] ; then              if [ "$planned" -gt 1 ] ; then -                echo "$looks planned $planned tests but only ran $highest" +                echo "$tap_looks planned $planned tests but only ran" \ +                    "$tap_highest"              else -                echo "$looks planned $planned test but only ran $highest" +                echo "$tap_looks planned $planned test but only ran" \ +                    "$tap_highest"              fi -        elif [ "$planned" -lt "$highest" ] ; then -            local extra -            extra=`expr "$highest" - "$planned"` +        elif [ "$planned" -lt "$tap_highest" ] ; then +            tap_extra=`expr "$tap_highest" - "$planned"`              if [ "$planned" -gt 1 ] ; then -                echo "$looks planned $planned tests but ran $extra extra" +                echo "$tap_looks planned $planned tests but ran" \ +                    "$tap_extra extra"              else -                echo "$looks planned $planned test but ran $extra extra" +                echo "$tap_looks planned $planned test but ran" \ +                    "$tap_extra extra"              fi          elif [ "$failed" -gt 0 ] ; then              if [ "$failed" -gt 1 ] ; then -                echo "$looks failed $failed tests of $planned" +                echo "$tap_looks failed $failed tests of $planned"              else -                echo "$looks failed $failed test of $planned" +                echo "$tap_looks failed $failed test of $planned"              fi          elif [ "$planned" -gt 1 ] ; then              echo "# All $planned tests successful or skipped" @@ -63,10 +91,9 @@ finish () {  # Skip the entire test suite.  Should be run instead of plan.  skip_all () { -    local desc -    desc="$1" -    if [ -n "$desc" ] ; then -        echo "1..0 # skip $desc" +    tap_desc="$1" +    if [ -n "$tap_desc" ] ; then +        echo "1..0 # skip $tap_desc"      else          echo "1..0 # skip"      fi @@ -77,16 +104,15 @@ skip_all () {  # command is successful, false otherwise.  The count starts at 1 and is  # updated each time ok is printed.  ok () { -    local desc -    desc="$1" -    if [ -n "$desc" ] ; then -        desc=" - $desc" +    tap_desc="$1" +    if [ -n "$tap_desc" ] ; then +        tap_desc=" - $tap_desc"      fi      shift      if "$@" ; then -        echo ok $count$desc +        echo ok "$count$tap_desc"      else -        echo not ok $count$desc +        echo not ok "$count$tap_desc"          failed=`expr $failed + 1`      fi      count=`expr $count + 1` @@ -101,58 +127,80 @@ skip () {  # Report the same status on a whole set of tests.  Takes the count of tests,  # the description, and then the command to run to determine the status.  ok_block () { -    local end i desc -    i=$count -    end=`expr $count + $1` -    shift -    desc="$1" +    tap_i=$count +    tap_end=`expr $count + $1`      shift -    while [ "$i" -lt "$end" ] ; do -        ok "$desc" "$@" -        i=`expr $i + 1` +    while [ "$tap_i" -lt "$tap_end" ] ; do +        ok "$@" +        tap_i=`expr $tap_i + 1`      done  }  # Skip a whole set of tests.  Takes the count and then the reason for skipping  # the test.  skip_block () { -    local i end -    i=$count -    end=`expr $count + $1` +    tap_i=$count +    tap_end=`expr $count + $1`      shift -    while [ "$i" -lt "$end" ] ; do +    while [ "$tap_i" -lt "$tap_end" ] ; do          skip "$@" -        i=`expr $i + 1` +        tap_i=`expr $tap_i + 1`      done  } +# Portable variant of printf '%s\n' "$*".  In the majority of cases, this +# function is slower than printf, because the latter is often implemented +# as a builtin command.  The value of the variable IFS is ignored. +# +# This macro must not be called via backticks inside double quotes, since this +# will result in bizarre escaping behavior and lots of extra backslashes on +# Solaris. +puts () { +    cat << EOH +$@ +EOH +} +  # Run a program expected to succeed, and print ok if it does and produces the  # correct output.  Takes the description, expected exit status, the expected -# output, the command to run, and then any arguments for that command.  Strip -# a colon and everything after it off the output if the expected status is -# non-zero, since this is probably a system-specific error message. +# output, the command to run, and then any arguments for that command. +# Standard output and standard error are combined when analyzing the output of +# the command. +# +# If the command may contain system-specific error messages in its output, +# add strip_colon_error before the command to post-process its output.  ok_program () { -    local desc w_status w_output output status -    desc="$1" +    tap_desc="$1"      shift -    w_status="$1" +    tap_w_status="$1"      shift -    w_output="$1" +    tap_w_output="$1"      shift -    output=`"$@" 2>&1` -    status=$? -    if [ "$w_status" -ne 0 ] ; then -        output=`echo "$output" | sed 's/^\([^:]* [^:]*\):.*/\1/'` -    fi -    if [ $status = $w_status ] && [ x"$output" = x"$w_output" ] ; then -        ok "$desc" true +    tap_output=`"$@" 2>&1` +    tap_status=$? +    if [ $tap_status = $tap_w_status ] \ +        && [ x"$tap_output" = x"$tap_w_output" ] ; then +        ok "$tap_desc" true      else -        echo "#  saw: ($status) $output" -        echo "#  not: ($w_status) $w_output" -        ok "$desc" false +        echo "#  saw: ($tap_status) $tap_output" +        echo "#  not: ($tap_w_status) $tap_w_output" +        ok "$tap_desc" false      fi  } +# Strip a colon and everything after it off the output of a command, as long +# as that colon comes after at least one whitespace character.  (This is done +# to avoid stripping the name of the program from the start of an error +# message.)  This is used to remove system-specific error messages (coming +# from strerror, for example). +strip_colon_error() { +    tap_output=`"$@" 2>&1` +    tap_status=$? +    tap_output=`puts "$tap_output" | sed 's/^\([^ ]* [^:]*\):.*/\1/'` +    puts "$tap_output" +    return $tap_status +} +  # Bail out with an error message.  bail () {      echo 'Bail out!' "$@" @@ -167,12 +215,32 @@ diag () {  # Search for the given file first in $BUILD and then in $SOURCE and echo the  # path where the file was found, or the empty string if the file wasn't  # found. +# +# This macro uses puts, so don't run it using backticks inside double quotes +# or bizarre quoting behavior will happen with Solaris sh.  test_file_path () { -    if [ -f "$BUILD/$1" ] ; then -        echo "$BUILD/$1" -    elif [ -f "$SOURCE/$1" ] ; then -        echo "$SOURCE/$1" +    if [ -n "$BUILD" ] && [ -f "$BUILD/$1" ] ; then +        puts "$BUILD/$1" +    elif [ -n "$SOURCE" ] && [ -f "$SOURCE/$1" ] ; then +        puts "$SOURCE/$1"      else          echo ''      fi  } + +# Create $BUILD/tmp for use by tests for storing temporary files and return +# the path (via standard output). +# +# This macro uses puts, so don't run it using backticks inside double quotes +# or bizarre quoting behavior will happen with Solaris sh. +test_tmpdir () { +    if [ -z "$BUILD" ] ; then +        tap_tmpdir="./tmp" +    else +        tap_tmpdir="$BUILD"/tmp +    fi +    if [ ! -d "$tap_tmpdir" ] ; then +        mkdir "$tap_tmpdir" || bail "Error creating $tap_tmpdir" +    fi +    puts "$tap_tmpdir" +} diff --git a/tests/tap/macros.h b/tests/tap/macros.h new file mode 100644 index 0000000..33fee42 --- /dev/null +++ b/tests/tap/macros.h @@ -0,0 +1,88 @@ +/* + * Helpful macros for TAP header files. + * + * This is not, strictly speaking, related to TAP, but any TAP add-on is + * probably going to need these macros, so define them in one place so that + * everyone can pull them in. + * + * This file is part of C TAP Harness.  The current version plus supporting + * documentation is at <http://www.eyrie.org/~eagle/software/c-tap-harness/>. + * + * Copyright 2008, 2012 Russ Allbery <rra@stanford.edu> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef TAP_MACROS_H +#define TAP_MACROS_H 1 + +/* + * __attribute__ is available in gcc 2.5 and later, but only with gcc 2.7 + * could you use the __format__ form of the attributes, which is what we use + * (to avoid confusion with other macros), and only with gcc 2.96 can you use + * the attribute __malloc__.  2.96 is very old, so don't bother trying to get + * the other attributes to work with GCC versions between 2.7 and 2.96. + */ +#ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) +#  define __attribute__(spec)   /* empty */ +# endif +#endif + +/* + * We use __alloc_size__, but it was only available in fairly recent versions + * of GCC.  Suppress warnings about the unknown attribute if GCC is too old. + * We know that we're GCC at this point, so we can use the GCC variadic macro + * extension, which will still work with versions of GCC too old to have C99 + * variadic macro support. + */ +#if !defined(__attribute__) && !defined(__alloc_size__) +# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) +#  define __alloc_size__(spec, args...) /* empty */ +# endif +#endif + +/* + * LLVM and Clang pretend to be GCC but don't support all of the __attribute__ + * settings that GCC does.  For them, suppress warnings about unknown + * attributes on declarations.  This unfortunately will affect the entire + * compilation context, but there's no push and pop available. + */ +#if !defined(__attribute__) && (defined(__llvm__) || defined(__clang__)) +# pragma GCC diagnostic ignored "-Wattributes" +#endif + +/* Used for unused parameters to silence gcc warnings. */ +#define UNUSED __attribute__((__unused__)) + +/* + * BEGIN_DECLS is used at the beginning of declarations so that C++ + * compilers don't mangle their names.  END_DECLS is used at the end. + */ +#undef BEGIN_DECLS +#undef END_DECLS +#ifdef __cplusplus +# define BEGIN_DECLS    extern "C" { +# define END_DECLS      } +#else +# define BEGIN_DECLS    /* empty */ +# define END_DECLS      /* empty */ +#endif + +#endif /* TAP_MACROS_H */ diff --git a/tests/tap/messages.c b/tests/tap/messages.c index 3bb9a1a..abc2c49 100644 --- a/tests/tap/messages.c +++ b/tests/tap/messages.c @@ -5,24 +5,39 @@   * into a buffer that can be inspected later, allowing testing of error   * handling.   * - * Copyright 2006, 2007, 2009 - *     Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.   * - * See LICENSE for licensing terms. + * Copyright 2002, 2004, 2005 Russ Allbery <rra@stanford.edu> + * Copyright 2006, 2007, 2009, 2012 + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #include <config.h>  #include <portable/system.h> +#include <tests/tap/macros.h>  #include <tests/tap/messages.h> -#include <util/concat.h> -#include <util/macros.h> +#include <tests/tap/string.h>  #include <util/messages.h> -#include <util/xmalloc.h>  /* A global buffer into which message_log_buffer stores error messages. */  char *errors = NULL; @@ -33,18 +48,18 @@ char *errors = NULL;   * error_capture.   */  static void -message_log_buffer(int len, const char *fmt, va_list args, int error UNUSED) +message_log_buffer(int len UNUSED, const char *fmt, va_list args, +                   int error UNUSED)  {      char *message; -    message = xmalloc(len + 1); -    vsnprintf(message, len + 1, fmt, args); -    if (errors == NULL) { -        errors = concat(message, "\n", (char *) 0); -    } else { +    bvasprintf(&message, fmt, args); +    if (errors == NULL) +        basprintf(&errors, "%s\n", message); +    else {          char *new_errors; -        new_errors = concat(errors, message, "\n", (char *) 0); +        basprintf(&new_errors, "%s%s\n", errors, message);          free(errors);          errors = new_errors;      } diff --git a/tests/tap/messages.h b/tests/tap/messages.h index 2b9a7db..0544f2d 100644 --- a/tests/tap/messages.h +++ b/tests/tap/messages.h @@ -1,21 +1,37 @@  /*   * Utility functions to test message handling.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Copyright 2002 Russ Allbery <rra@stanford.edu>   * Copyright 2006, 2007, 2009 - *     Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software.   * - * See LICENSE for licensing terms. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #ifndef TAP_MESSAGES_H  #define TAP_MESSAGES_H 1  #include <config.h> -#include <portable/macros.h> +#include <tests/tap/macros.h>  /* A global buffer into which errors_capture stores errors. */  extern char *errors; diff --git a/tests/tap/perl/Test/RRA.pm b/tests/tap/perl/Test/RRA.pm new file mode 100644 index 0000000..2d119f4 --- /dev/null +++ b/tests/tap/perl/Test/RRA.pm @@ -0,0 +1,222 @@ +# Helper functions for test programs written in Perl. +# +# This module provides a collection of helper functions used by test programs +# written in Perl.  This is a general collection of functions that can be used +# by both C packages with Automake and by stand-alone Perl modules.  See +# Test::RRA::Automake for additional functions specifically for C Automake +# distributions. +# +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +# +# Written by Russ Allbery <rra@stanford.edu> +# Copyright 2013 +#     The Board of Trustees of the Leland Stanford Junior University +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +package Test::RRA; + +use 5.006; +use strict; +use warnings; + +use Exporter; +use Test::More; + +# For Perl 5.006 compatibility. +## no critic (ClassHierarchies::ProhibitExplicitISA) + +# Declare variables that should be set in BEGIN for robustness. +our (@EXPORT_OK, @ISA, $VERSION); + +# Set $VERSION and everything export-related in a BEGIN block for robustness +# against circular module loading (not that we load any modules, but +# consistency is good). +BEGIN { +    @ISA       = qw(Exporter); +    @EXPORT_OK = qw(skip_unless_maintainer use_prereq); + +    # This version should match the corresponding rra-c-util release, but with +    # two digits for the minor version, including a leading zero if necessary, +    # so that it will sort properly. +    $VERSION = '4.08'; +} + +# Skip this test unless maintainer tests are requested.  Takes a short +# description of what tests this script would perform, which is used in the +# skip message.  Calls plan skip_all, which will terminate the program. +# +# $description - Short description of the tests +# +# Returns: undef +sub skip_unless_maintainer { +    my ($description) = @_; +    if (!$ENV{RRA_MAINTAINER_TESTS}) { +        plan skip_all => "$description only run for maintainer"; +    } +    return; +} + +# Attempt to load a module and skip the test if the module could not be +# loaded.  If the module could be loaded, call its import function manually. +# If the module could not be loaded, calls plan skip_all, which will terminate +# the program. +# +# The special logic here is based on Test::More and is required to get the +# imports to happen in the caller's namespace. +# +# $module  - Name of the module to load +# @imports - Any arguments to import, possibly including a version +# +# Returns: undef +sub use_prereq { +    my ($module, @imports) = @_; + +    # If the first import looks like a version, pass it as a bare string. +    my $version = q{}; +    if (@imports >= 1 && $imports[0] =~ m{ \A \d+ (?: [.]\d+ )* \z }xms) { +        $version = shift(@imports); +    } + +    # Get caller information to put imports in the correct package. +    my ($package) = caller; + +    # Do the import with eval, and try to isolate it from the surrounding +    # context as much as possible.  Based heavily on Test::More::_eval. +    ## no critic (BuiltinFunctions::ProhibitStringyEval) +    ## no critic (ValuesAndExpressions::ProhibitImplicitNewlines) +    my ($result, $error, $sigdie); +    { +        local $@            = undef; +        local $!            = undef; +        local $SIG{__DIE__} = undef; +        $result = eval qq{ +            package $package; +            use $module $version \@imports; +            1; +        }; +        $error = $@; +        $sigdie = $SIG{__DIE__} || undef; +    } + +    # If the use failed for any reason, skip the test. +    if (!$result || $error) { +        plan skip_all => "$module required for test"; +    } + +    # If the module set $SIG{__DIE__}, we cleared that via local.  Restore it. +    ## no critic (Variables::RequireLocalizedPunctuationVars) +    if (defined($sigdie)) { +        $SIG{__DIE__} = $sigdie; +    } +    return; +} + +1; +__END__ + +=for stopwords +Allbery Allbery's DESC bareword sublicense MERCHANTABILITY NONINFRINGEMENT +rra-c-util + +=head1 NAME + +Test::RRA - Support functions for Perl tests + +=head1 SYNOPSIS + +    use Test::RRA qw(skip_unless_maintainer use_prereq); + +    # Skip this test unless maintainer tests are requested. +    skip_unless_maintainer('Coding style tests'); + +    # Load modules, skipping the test if they're not available. +    use_prereq('File::Slurp'); +    use_prereq('Test::Script::Run', '0.04'); + +=head1 DESCRIPTION + +This module collects utility functions that are useful for Perl test +scripts.  It assumes Russ Allbery's Perl module layout and test +conventions and will only be useful for other people if they use the +same conventions. + +=head1 FUNCTIONS + +None of these functions are imported by default.  The ones used by a +script should be explicitly imported. + +=over 4 + +=item skip_unless_maintainer(DESC) + +Checks whether RRA_MAINTAINER_TESTS is set in the environment and skips +the whole test (by calling C<plan skip_all> from Test::More) if it is not. +DESC is a description of the tests being skipped.  A space and C<only run +for maintainer> will be appended to it and used as the skip reason. + +=item use_prereq(MODULE[, VERSION][, IMPORT ...]) + +Attempts to load MODULE with the given VERSION and import arguments.  If +this fails for any reason, the test will be skipped (by calling C<plan +skip_all> from Test::More) with a skip reason saying that MODULE is +required for the test. + +VERSION will be passed to C<use> as a version bareword if it looks like a +version number.  The remaining IMPORT arguments will be passed as the +value of an array. + +=back + +=head1 AUTHOR + +Russ Allbery <rra@stanford.edu> + +=head1 COPYRIGHT AND LICENSE + +Copyright 2013 The Board of Trustees of the Leland Stanford Junior +University. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +=head1 SEE ALSO + +Test::More(3), Test::RRA::Automake(3), Test::RRA::Config(3) + +This module is maintained in the rra-c-util package.  The current version +is available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>. + +=cut diff --git a/tests/tap/perl/Test/RRA/Automake.pm b/tests/tap/perl/Test/RRA/Automake.pm new file mode 100644 index 0000000..2aadb6a --- /dev/null +++ b/tests/tap/perl/Test/RRA/Automake.pm @@ -0,0 +1,362 @@ +# Helper functions for Perl test programs in Automake distributions. +# +# This module provides a collection of helper functions used by test programs +# written in Perl and included in C source distributions that use Automake. +# They embed knowledge of how I lay out my source trees and test suites with +# Autoconf and Automake.  They may be usable by others, but doing so will +# require closely following the conventions implemented by the rra-c-util +# utility collection. +# +# All the functions here assume that BUILD and SOURCE are set in the +# environment.  This is normally done via the C TAP Harness runtests wrapper. +# +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +# +# Written by Russ Allbery <rra@stanford.edu> +# Copyright 2013 +#     The Board of Trustees of the Leland Stanford Junior University +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +package Test::RRA::Automake; + +use 5.006; +use strict; +use warnings; + +# For Perl 5.006 compatibility. +## no critic (ClassHierarchies::ProhibitExplicitISA) + +use Exporter; +use File::Spec; +use Test::More; +use Test::RRA::Config qw($LIBRARY_PATH); + +# Used below for use lib calls. +my ($PERL_BLIB_ARCH, $PERL_BLIB_LIB); + +# Determine the path to the build tree of any embedded Perl module package in +# this source package.  We do this in a BEGIN block because we're going to use +# the results in a use lib command below. +BEGIN { +    $PERL_BLIB_ARCH = File::Spec->catdir(qw(perl blib arch)); +    $PERL_BLIB_LIB  = File::Spec->catdir(qw(perl blib lib)); + +    # If BUILD is set, we can come up with better values. +    if (defined($ENV{BUILD})) { +        my ($vol, $dirs) = File::Spec->splitpath($ENV{BUILD}, 1); +        my @dirs = File::Spec->splitdir($dirs); +        pop(@dirs); +        $PERL_BLIB_ARCH = File::Spec->catdir(@dirs, qw(perl blib arch)); +        $PERL_BLIB_LIB  = File::Spec->catdir(@dirs, qw(perl blib lib)); +    } +} + +# Prefer the modules built as part of our source package.  Otherwise, we may +# not find Perl modules while testing, or find the wrong versions. +use lib $PERL_BLIB_ARCH; +use lib $PERL_BLIB_LIB; + +# Declare variables that should be set in BEGIN for robustness. +our (@EXPORT_OK, @ISA, $VERSION); + +# Set $VERSION and everything export-related in a BEGIN block for robustness +# against circular module loading (not that we load any modules, but +# consistency is good). +BEGIN { +    @ISA       = qw(Exporter); +    @EXPORT_OK = qw(automake_setup perl_dirs test_file_path); + +    # This version should match the corresponding rra-c-util release, but with +    # two digits for the minor version, including a leading zero if necessary, +    # so that it will sort properly. +    $VERSION = '4.08'; +} + +# Perl directories to skip globally for perl_dirs.  We ignore the perl +# directory if it exists since, in my packages, it is treated as a Perl module +# distribution and has its own standalone test suite. +my @GLOBAL_SKIP = qw(.git perl); + +# Perform initial test setup for running a Perl test in an Automake package. +# This verifies that BUILD and SOURCE are set and then changes directory to +# the SOURCE directory by default.  Sets LD_LIBRARY_PATH if the $LIBRARY_PATH +# configuration option is set.  Calls BAIL_OUT if BUILD or SOURCE are missing +# or if anything else fails. +# +# $args_ref - Reference to a hash of arguments to configure behavior: +#   chdir_build - If set to a true value, changes to BUILD instead of SOURCE +# +# Returns: undef +sub automake_setup { +    my ($args_ref) = @_; + +    # Bail if BUILD or SOURCE are not set. +    if (!$ENV{BUILD}) { +        BAIL_OUT('BUILD not defined (run under runtests)'); +    } +    if (!$ENV{SOURCE}) { +        BAIL_OUT('SOURCE not defined (run under runtests)'); +    } + +    # BUILD or SOURCE will be the test directory.  Change to the parent. +    my $start = $args_ref->{chdir_build} ? $ENV{BUILD} : $ENV{SOURCE}; +    my ($vol, $dirs) = File::Spec->splitpath($start, 1); +    my @dirs = File::Spec->splitdir($dirs); +    pop(@dirs); +    if ($dirs[-1] eq File::Spec->updir) { +        pop(@dirs); +        pop(@dirs); +    } +    my $root = File::Spec->catpath($vol, File::Spec->catdir(@dirs), q{}); +    chdir($root) or BAIL_OUT("cannot chdir to $root: $!"); + +    # If BUILD is a subdirectory of SOURCE, add it to the global ignore list. +    my ($buildvol, $builddirs) = File::Spec->splitpath($ENV{BUILD}, 1); +    my @builddirs = File::Spec->splitdir($builddirs); +    pop(@builddirs); +    if ($buildvol eq $vol && @builddirs == @dirs + 1) { +        while (@dirs && $builddirs[0] eq $dirs[0]) { +            shift(@builddirs); +            shift(@dirs); +        } +        if (@builddirs == 1) { +            push(@GLOBAL_SKIP, $builddirs[0]); +        } +    } + +    # Set LD_LIBRARY_PATH if the $LIBRARY_PATH configuration option is set. +    ## no critic (Variables::RequireLocalizedPunctuationVars) +    if (defined($LIBRARY_PATH)) { +        @builddirs = File::Spec->splitdir($builddirs); +        pop(@builddirs); +        my $libdir = File::Spec->catdir(@builddirs, $LIBRARY_PATH); +        my $path = File::Spec->catpath($buildvol, $libdir, q{}); +        if (-d "$path/.libs") { +            $path .= '/.libs'; +        } +        if ($ENV{LD_LIBRARY_PATH}) { +            $ENV{LD_LIBRARY_PATH} .= ":$path"; +        } else { +            $ENV{LD_LIBRARY_PATH} = $path; +        } +    } +    return; +} + +# Returns a list of directories that may contain Perl scripts and that should +# be passed to Perl test infrastructure that expects a list of directories to +# recursively check.  The list will be all eligible top-level directories in +# the package except for the tests directory, which is broken out to one +# additional level.  Calls BAIL_OUT on any problems +# +# $args_ref - Reference to a hash of arguments to configure behavior: +#   skip - A reference to an array of directories to skip +# +# Returns: List of directories possibly containing Perl scripts to test +sub perl_dirs { +    my ($args_ref) = @_; + +    # Add the global skip list. +    my @skip = $args_ref->{skip} ? @{ $args_ref->{skip} } : (); +    push(@skip, @GLOBAL_SKIP); + +    # Separate directories to skip under tests from top-level directories. +    my @skip_tests = grep { m{ \A tests/ }xms } @skip; +    @skip = grep { !m{ \A tests }xms } @skip; +    for my $skip_dir (@skip_tests) { +        $skip_dir =~ s{ \A tests/ }{}xms; +    } + +    # Convert the skip lists into hashes for convenience. +    my %skip = map { $_ => 1 } @skip, 'tests'; +    my %skip_tests = map { $_ => 1 } @skip_tests; + +    # Build the list of top-level directories to test. +    opendir(my $rootdir, q{.}) or BAIL_OUT("cannot open .: $!"); +    my @dirs = grep { -d $_ && !$skip{$_} } readdir($rootdir); +    closedir($rootdir); +    @dirs = File::Spec->no_upwards(@dirs); + +    # Add the list of subdirectories of the tests directory. +    if (-d 'tests') { +        opendir(my $testsdir, q{tests}) or BAIL_OUT("cannot open tests: $!"); + +        # Skip if found in %skip_tests or if not a directory. +        my $is_skipped = sub { +            my ($dir) = @_; +            return 1 if $skip_tests{$dir}; +            $dir = File::Spec->catdir('tests', $dir); +            return -d $dir ? 0 : 1; +        }; + +        # Build the filtered list of subdirectories of tests. +        my @test_dirs = grep { !$is_skipped->($_) } readdir($testsdir); +        closedir($testsdir); +        @test_dirs = File::Spec->no_upwards(@test_dirs); + +        # Add the tests directory to the start of the directory name. +        push(@dirs, map { File::Spec->catdir('tests', $_) } @test_dirs); +    } +    return @dirs; +} + +# Find a configuration file for the test suite.  Searches relative to BUILD +# first and then SOURCE and returns whichever is found first.  Calls BAIL_OUT +# if the file could not be found. +# +# $file - Partial path to the file +# +# Returns: Full path to the file +sub test_file_path { +    my ($file) = @_; +  BASE: +    for my $base ($ENV{BUILD}, $ENV{SOURCE}) { +        next if !defined($base); +        if (-f "$base/$file") { +            return "$base/$file"; +        } +    } +    BAIL_OUT("cannot find $file"); +    return; +} + +1; +__END__ + +=for stopwords +Allbery Automake Automake-aware Automake-based rra-c-util ARGS +subdirectories sublicense MERCHANTABILITY NONINFRINGEMENT + +=head1 NAME + +Test::RRA::Automake - Automake-aware support functions for Perl tests + +=head1 SYNOPSIS + +    use Test::RRA::Automake qw(automake_setup perl_dirs test_file_path); +    automake_setup({ chdir_build => 1 }); + +    # Paths to directories that may contain Perl scripts. +    my @dirs = perl_dirs({ skip => [qw(lib)] }); + +    # Configuration for Kerberos tests. +    my $keytab = test_file_path('config/keytab'); + +=head1 DESCRIPTION + +This module collects utility functions that are useful for test scripts +written in Perl and included in a C Automake-based package.  They assume +the layout of a package that uses rra-c-util and C TAP Harness for the +test structure. + +Loading this module will also add the directories C<perl/blib/arch> and +C<perl/blib/lib> to the Perl library search path, relative to BUILD if +that environment variable is set.  This is harmless for C Automake +projects that don't contain an embedded Perl module, and for those +projects that do, this will allow subsequent C<use> calls to find modules +that are built as part of the package build process. + +The automake_setup() function should be called before calling any other +functions provided by this module. + +=head1 FUNCTIONS + +None of these functions are imported by default.  The ones used by a +script should be explicitly imported.  On failure, all of these functions +call BAIL_OUT (from Test::More). + +=over 4 + +=item automake_setup([ARGS]) + +Verifies that the BUILD and SOURCE environment variables are set and +then changes directory to the top of the source tree (which is one +directory up from the SOURCE path, since SOURCE points to the top of +the tests directory). + +If ARGS is given, it should be a reference to a hash of configuration +options.  Only one option is supported: C<chdir_build>.  If it is set +to a true value, automake_setup() changes directories to the top of +the build tree instead. + +=item perl_dirs([ARGS]) + +Returns a list of directories that may contain Perl scripts that should be +tested by test scripts that test all Perl in the source tree (such as +syntax or coding style checks).  The paths will be simple directory names +relative to the current directory or two-part directory names under the +F<tests> directory.  (Directories under F<tests> are broken out separately +since it's common to want to apply different policies to different +subdirectories of F<tests>.) + +If ARGS is given, it should be a reference to a hash of configuration +options.  Only one option is supported: C<skip>, whose value should be a +reference to an array of additional top-level directories or directories +starting with C<tests/> that should be skipped. + +=item test_file_path(FILE) + +Given FILE, which should be a relative path, locates that file relative to +the test directory in either the source or build tree.  FILE will be +checked for relative to the environment variable BUILD first, and then +relative to SOURCE.  test_file_path() returns the full path to FILE or +calls BAIL_OUT if FILE could not be found. + +=back + +=head1 AUTHOR + +Russ Allbery <rra@stanford.edu> + +=head1 COPYRIGHT AND LICENSE + +Copyright 2013 The Board of Trustees of the Leland Stanford Junior +University. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +=head1 SEE ALSO + +Test::More(3), Test::RRA(3), Test::RRA::Config(3) + +The C TAP Harness test driver and libraries for TAP-based C testing are +available from L<http://www.eyrie.org/~eagle/software/c-tap-harness/>. + +This module is maintained in the rra-c-util package.  The current version +is available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>. + +=cut diff --git a/tests/tap/perl/Test/RRA/Config.pm b/tests/tap/perl/Test/RRA/Config.pm new file mode 100644 index 0000000..0091b26 --- /dev/null +++ b/tests/tap/perl/Test/RRA/Config.pm @@ -0,0 +1,200 @@ +# Configuration for Perl test cases. +# +# In order to reuse the same Perl test cases in multiple packages, I use a +# configuration file to store some package-specific data.  This module loads +# that configuration and provides the namespace for the configuration +# settings. +# +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + +package Test::RRA::Config; + +use 5.006; +use strict; +use warnings; + +# For Perl 5.006 compatibility. +## no critic (ClassHierarchies::ProhibitExplicitISA) + +use Exporter; +use Test::More; + +# Declare variables that should be set in BEGIN for robustness. +our (@EXPORT_OK, @ISA, $VERSION); + +# Set $VERSION and everything export-related in a BEGIN block for robustness +# against circular module loading (not that we load any modules, but +# consistency is good). +BEGIN { +    @ISA       = qw(Exporter); +    @EXPORT_OK = qw( +      $COVERAGE_LEVEL @COVERAGE_SKIP_TESTS @CRITIC_IGNORE $LIBRARY_PATH +      $MINIMUM_VERSION %MINIMUM_VERSION @POD_COVERAGE_EXCLUDE +    ); + +    # This version should match the corresponding rra-c-util release, but with +    # two digits for the minor version, including a leading zero if necessary, +    # so that it will sort properly. +    $VERSION = '4.08'; +} + +# If BUILD or SOURCE are set in the environment, look for data/perl.conf under +# those paths for a C Automake package.  Otherwise, look in t/data/perl.conf +# for a standalone Perl module.  Don't use Test::RRA::Automake since it may +# not exist. +our $PATH; +for my $base ($ENV{BUILD}, $ENV{SOURCE}, 't') { +    next if !defined($base); +    my $path = "$base/data/perl.conf"; +    if (-r $path) { +        $PATH = $path; +        last; +    } +} +if (!defined($PATH)) { +    BAIL_OUT('cannot find data/perl.conf'); +} + +# Pre-declare all of our variables and set any defaults. +our $COVERAGE_LEVEL = 100; +our @COVERAGE_SKIP_TESTS; +our @CRITIC_IGNORE; +our $LIBRARY_PATH; +our $MINIMUM_VERSION = '5.008'; +our %MINIMUM_VERSION; +our @POD_COVERAGE_EXCLUDE; + +# Load the configuration. +if (!do($PATH)) { +    my $error = $@ || $! || 'loading file did not return true'; +    BAIL_OUT("cannot load data/perl.conf: $error"); +} + +1; +__END__ + +=for stopwords +Allbery rra-c-util Automake perlcritic .libs namespace sublicense +MERCHANTABILITY NONINFRINGEMENT + +=head1 NAME + +Test::RRA::Config - Perl test configuration + +=head1 SYNOPSIS + +    use Test::RRA::Config qw($MINIMUM_VERSION); +    print "Required Perl version is $MINIMUM_VERSION\n"; + +=head1 DESCRIPTION + +Test::RRA::Config encapsulates per-package configuration for generic Perl +test programs that are shared between multiple packages using the +rra-c-util infrastructure.  It handles locating and loading the test +configuration file for both C Automake packages and stand-alone Perl +modules. + +Test::RRA::Config looks for a file named F<data/perl.conf> relative to the +root of the test directory.  That root is taken from the environment +variables BUILD or SOURCE (in that order) if set, which will be the case +for C Automake packages using C TAP Harness.  If neither is set, it +expects the root of the test directory to be a directory named F<t> +relative to the current directory, which will be the case for stand-alone +Perl modules. + +The following variables are supported: + +=over 4 + +=item $COVERAGE_LEVEL + +The coverage level achieved by the test suite for Perl test coverage +testing using Test::Strict, as a percentage.  The test will fail if test +coverage less than this percentage is achieved.  If not given, defaults +to 100. + +=item @COVERAGE_SKIP_TESTS + +Directories under F<t> whose tests should be skipped when doing coverage +testing.  This can be tests that won't contribute to coverage or tests +that don't run properly under Devel::Cover for some reason (such as ones +that use taint checking).  F<docs> and F<style> will always be skipped +regardless of this setting. + +=item @CRITIC_IGNORE + +Additional directories to ignore when doing recursive perlcritic testing. +The contents of this directory must be either top-level directory names or +directory names starting with F<tests/>. + +=item $LIBRARY_PATH + +Add this directory (or a .libs subdirectory) relative to the top of the +source tree to LD_LIBRARY_PATH when checking the syntax of Perl modules. +This may be required to pick up libraries that are used by in-tree Perl +modules so that Perl scripts can pass a syntax check. + +=item $MINIMUM_VERSION + +Default minimum version requirement for included Perl scripts.  If not +given, defaults to 5.008. + +=item %MINIMUM_VERSION + +Minimum version exceptions for specific directories.  The keys should be +minimum versions of Perl to enforce.  The value for each key should be a +reference to an array of either top-level directory names or directory +names starting with F<tests/>.  All files in those directories will have +that minimum Perl version constraint imposed instead of $MINIMUM_VERSION. + +=item @POD_COVERAGE_EXCLUDE + +Regexes that match method names that should be excluded from POD coverage +testing.  Normally, all methods have to be documented in the POD for a +Perl module, but methods matching any of these regexes will be considered +private and won't require documentation. + +=back + +No variables are exported by default, but the variables can be imported +into the local namespace to avoid long variable names. + +=head1 AUTHOR + +Russ Allbery <rra@stanford.edu> + +=head1 COPYRIGHT AND LICENSE + +Copyright 2013 The Board of Trustees of the Leland Stanford Junior +University. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +=head1 SEE ALSO + +Test::RRA(3), Test::RRA::Automake(3) + +This module is maintained in the rra-c-util package.  The current version +is available from L<http://www.eyrie.org/~eagle/software/rra-c-util/>. + +The C TAP Harness test driver and libraries for TAP-based C testing are +available from L<http://www.eyrie.org/~eagle/software/c-tap-harness/>. + +=cut diff --git a/tests/tap/process.c b/tests/tap/process.c index 16154c7..8ed4cfd 100644 --- a/tests/tap/process.c +++ b/tests/tap/process.c @@ -1,18 +1,37 @@  /*   * Utility functions for tests that use subprocesses.   * - * Provides utility functions for subprocess manipulation.  Currently, only - * one utility function is provided: is_function_output, which runs a function - * in a subprocess and checks its output and exit status against expected - * values. + * Provides utility functions for subprocess manipulation.  Specifically, + * provides a function, run_setup, which runs a command and bails if it fails, + * using its error message as the bail output, and is_function_output, which + * runs a function in a subprocess and checks its output and exit status + * against expected values.   * - * Copyright 2009, 2010 Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.   * - * See LICENSE for licensing terms. + * Written by Russ Allbery <rra@stanford.edu> + * Copyright 2002, 2004, 2005 Russ Allbery <rra@stanford.edu> + * Copyright 2009, 2010, 2011 + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #include <config.h> @@ -22,26 +41,24 @@  #include <tests/tap/basic.h>  #include <tests/tap/process.h> -#include <util/xmalloc.h> +#include <tests/tap/string.h>  /*   * Given a function, an expected exit status, and expected output, runs that   * function in a subprocess, capturing stdout and stderr via a pipe, and - * compare the combination of stdout and stderr with the expected output and - * the exit status with the expected status.  Expects the function to always - * exit (not die from a signal). + * returns the function output in newly allocated memory.  Also captures the + * process exit status.   */ -void -is_function_output(test_function_type function, int status, const char *output, -                   const char *format, ...) +static void +run_child_function(test_function_type function, void *data, int *status, +                   char **output)  {      int fds[2];      pid_t child; -    char *buf, *msg; +    char *buf;      ssize_t count, ret, buflen;      int rval; -    va_list args;      /* Flush stdout before we start to avoid odd forking issues. */      fflush(stdout); @@ -61,7 +78,7 @@ is_function_output(test_function_type function, int status, const char *output,              _exit(255);          /* Now, run the function and exit successfully if it returns. */ -        (*function)(); +        (*function)(data);          fflush(stdout);          _exit(0);      } else { @@ -71,7 +88,7 @@ is_function_output(test_function_type function, int status, const char *output,           */          close(fds[1]);          buflen = BUFSIZ; -        buf = xmalloc(buflen); +        buf = bmalloc(buflen);          count = 0;          do {              ret = read(fds[0], buf + count, buflen - count - 1); @@ -79,18 +96,41 @@ is_function_output(test_function_type function, int status, const char *output,                  count += ret;              if (count >= buflen - 1) {                  buflen += BUFSIZ; -                buf = xrealloc(buf, buflen); +                buf = brealloc(buf, buflen);              }          } while (ret > 0);          buf[count < 0 ? 0 : count] = '\0';          if (waitpid(child, &rval, 0) == (pid_t) -1)              sysbail("waitpid failed"); +        close(fds[0]);      } +    /* Store the output and return. */ +    *status = rval; +    *output = buf; +} + + +/* + * Given a function, data to pass to that function, an expected exit status, + * and expected output, runs that function in a subprocess, capturing stdout + * and stderr via a pipe, and compare the combination of stdout and stderr + * with the expected output and the exit status with the expected status. + * Expects the function to always exit (not die from a signal). + */ +void +is_function_output(test_function_type function, void *data, int status, +                   const char *output, const char *format, ...) +{ +    char *buf, *msg; +    int rval; +    va_list args; + +    run_child_function(function, data, &rval, &buf); +      /* Now, check the results against what we expected. */      va_start(args, format); -    if (xvasprintf(&msg, format, args) < 0) -        bail("cannot format test description"); +    bvasprintf(&msg, format, args);      va_end(args);      ok(WIFEXITED(rval), "%s (exited)", msg);      is_int(status, WEXITSTATUS(rval), "%s (status)", msg); @@ -98,3 +138,40 @@ is_function_output(test_function_type function, int status, const char *output,      free(buf);      free(msg);  } + + +/* + * A helper function for run_setup.  This is a function to run an external + * command, suitable for passing into run_child_function.  The expected + * argument must be an argv array, with argv[0] being the command to run. + */ +static void +exec_command(void *data) +{ +    char *const *argv = data; + +    execvp(argv[0], argv); +} + + +/* + * Given a command expressed as an argv struct, with argv[0] the name or path + * to the command, run that command.  If it exits with a non-zero status, use + * the part of its output up to the first newline as the error message when + * calling bail. + */ +void +run_setup(const char *const argv[]) +{ +    char *output, *p; +    int status; + +    run_child_function(exec_command, (void *) argv, &status, &output); +    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { +        p = strchr(output, '\n'); +        if (p != NULL) +            *p = '\0'; +        bail("%s", output); +    } +    free(output); +} diff --git a/tests/tap/process.h b/tests/tap/process.h index b7d3b11..df74b5f 100644 --- a/tests/tap/process.h +++ b/tests/tap/process.h @@ -1,36 +1,64 @@  /*   * Utility functions for tests that use subprocesses.   * - * Copyright 2009, 2010 Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.   * - * See LICENSE for licensing terms. + * Written by Russ Allbery <rra@stanford.edu> + * Copyright 2009, 2010 + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #ifndef TAP_PROCESS_H  #define TAP_PROCESS_H 1  #include <config.h> -#include <portable/macros.h> +#include <tests/tap/macros.h>  BEGIN_DECLS  /*   * Run a function in a subprocess and check the exit status and expected   * output (stdout and stderr combined) against the provided values.  Expects - * the function to always exit (not die from a signal). + * the function to always exit (not die from a signal).  data is optional data + * that's passed into the function as its only argument.   *   * This reports as three separate tests: whether the function exited rather   * than was killed, whether the exit status was correct, and whether the   * output was correct.   */ -typedef void (*test_function_type)(void); -void is_function_output(test_function_type, int status, const char *output, -                        const char *format, ...) -    __attribute__((__format__(printf, 4, 5))); +typedef void (*test_function_type)(void *); +void is_function_output(test_function_type, void *data, int status, +                        const char *output, const char *format, ...) +    __attribute__((__format__(printf, 5, 6), __nonnull__(1))); + +/* + * Run a setup program.  Takes the program to run and its arguments as an argv + * vector, where argv[0] must be either the full path to the program or the + * program name if the PATH should be searched.  If the program does not exit + * successfully, call bail, with the error message being the output from the + * program. + */ +void run_setup(const char *const argv[]) +    __attribute__((__nonnull__));  END_DECLS diff --git a/tests/tap/remctl.sh b/tests/tap/remctl.sh index 9e01bcf..2fd6681 100644 --- a/tests/tap/remctl.sh +++ b/tests/tap/remctl.sh @@ -1,40 +1,67 @@  # Shell function library to start and stop remctld  # +# Note that while many of the functions in this library could benefit from +# using "local" to avoid possibly hammering global variables, Solaris /bin/sh +# doesn't support local and this library aspires to be portable to Solaris +# Bourne shell.  Instead, all private variables are prefixed with "tap_". +# +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +#  # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2009 Board of Trustees, Leland Stanford Jr. University +# Copyright 2009, 2012 +#     The Board of Trustees of the Leland Stanford Junior University +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software.  # -# See LICENSE for licensing terms. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE.  # Start remctld.  Takes the path to remctld, which may be found via configure,  # and the path to the configuration file.  remctld_start () { -    local keytab principal -    rm -f "$BUILD/data/remctld.pid" -    keytab=`test_file_path data/test.keytab` -    principal=`test_file_path data/test.principal` -    principal=`cat "$principal" 2>/dev/null` -    if [ -z "$keytab" ] || [ -z "$principal" ] ; then +    tap_pidfile=`test_tmpdir`/remctld.pid +    rm -f "$tap_pidfile" +    tap_keytab=`test_file_path config/keytab` +    tap_principal=`test_file_path config/principal` +    tap_principal=`cat "$tap_principal" 2>/dev/null` +    if [ -z "$tap_keytab" ] || [ -z "$tap_principal" ] ; then          return 1      fi      if [ -n "$VALGRIND" ] ; then          ( "$VALGRIND" --log-file=valgrind.%p --leak-check=full "$1" -m \ -          -p 14373 -s "$principal" -P "$BUILD/data/remctld.pid" -f "$2" -d \ -          -S -F -k "$keytab" &) +          -p 14373 -s "$tap_principal" -P "$tap_pidfile" -f "$2" -d -S -F \ +          -k "$tap_keytab" &)          [ -f "$BUILD/data/remctld.pid" ] || sleep 5      else -        ( "$1" -m -p 14373 -s "$principal" -P "$BUILD/data/remctld.pid" \ -          -f "$2" -d -S -F -k "$keytab" &) +        ( "$1" -m -p 14373 -s "$tap_principal" -P "$tap_pidfile" -f "$2" \ +          -d -S -F -k "$tap_keytab" &)      fi -    [ -f "$BUILD/data/remctld.pid" ] || sleep 1 -    if [ ! -f "$BUILD/data/remctld.pid" ] ; then +    [ -f "$tap_pidfile" ] || sleep 1 +    [ -f "$tap_pidfile" ] || sleep 1 +    if [ ! -f "$tap_pidfile" ] ; then          bail 'remctld did not start'      fi  }  # Stop remctld and clean up.  remctld_stop () { -    if [ -f "$BUILD/data/remctld.pid" ] ; then -        kill -TERM `cat "$BUILD/data/remctld.pid"` -        rm -f "$BUILD/data/remctld.pid" +    tap_pidfile=`test_tmpdir`/remctld.pid +    if [ -f "$tap_pidfile" ] ; then +        kill -TERM `cat "$tap_pidfile"` +        rm -f "$tap_pidfile"      fi  } diff --git a/tests/tap/string.c b/tests/tap/string.c new file mode 100644 index 0000000..f5c965c --- /dev/null +++ b/tests/tap/string.c @@ -0,0 +1,65 @@ +/* + * String utilities for the TAP protocol. + * + * Additional string utilities that can't be included with C TAP Harness + * because they rely on additional portability code from rra-c-util. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Copyright 2011, 2012 Russ Allbery <rra@stanford.edu> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <config.h> +#include <portable/system.h> + +#include <tests/tap/basic.h> +#include <tests/tap/string.h> + + +/* + * vsprintf into a newly allocated string, reporting a fatal error with bail + * on failure. + */ +void +bvasprintf(char **strp, const char *fmt, va_list args) +{ +    int status; + +    status = vasprintf(strp, fmt, args); +    if (status < 0) +        sysbail("failed to allocate memory for vasprintf"); +} + + +/* + * sprintf into a newly allocated string, reporting a fatal error with bail on + * failure. + */ +void +basprintf(char **strp, const char *fmt, ...) +{ +    va_list args; + +    va_start(args, fmt); +    bvasprintf(strp, fmt, args); +    va_end(args); +} diff --git a/tests/tap/string.h b/tests/tap/string.h new file mode 100644 index 0000000..2f699e4 --- /dev/null +++ b/tests/tap/string.h @@ -0,0 +1,49 @@ +/* + * String utilities for the TAP protocol. + * + * Additional string utilities that can't be included with C TAP Harness + * because they rely on additional portability code from rra-c-util. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Copyright 2011, 2012 Russ Allbery <rra@stanford.edu> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef TAP_STRING_H +#define TAP_STRING_H 1 + +#include <config.h> +#include <tests/tap/macros.h> + +#include <stdarg.h>             /* va_list */ + +BEGIN_DECLS + +/* sprintf into an allocated string, calling bail on any failure. */ +void basprintf(char **, const char *, ...) +    __attribute__((__nonnull__, __format__(printf, 2, 3))); +void bvasprintf(char **, const char *, va_list) +    __attribute__((__nonnull__)); + +END_DECLS + +#endif /* !TAP_STRING_H */ diff --git a/tests/util/messages-krb5-t.c b/tests/util/messages-krb5-t.c index 02d8f92..e3ffe75 100644 --- a/tests/util/messages-krb5-t.c +++ b/tests/util/messages-krb5-t.c @@ -1,10 +1,30 @@  /*   * Test suite for Kerberos error handling routines.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * Copyright 2010 Board of Trustees, Leland Stanford Jr. University + * Copyright 2010, 2011 + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software.   * - * See LICENSE for licensing terms. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #include <config.h> @@ -13,6 +33,7 @@  #include <tests/tap/basic.h>  #include <tests/tap/process.h> +#include <util/macros.h>  #include <util/messages-krb5.h>  #include <util/messages.h>  #include <util/xmalloc.h> @@ -22,7 +43,7 @@   * Test functions.   */  static void -test_warn(void) +test_warn(void *data UNUSED)  {      krb5_context ctx;      krb5_error_code code; @@ -40,7 +61,7 @@ test_warn(void)  }  static void -test_die(void) +test_die(void *data UNUSED)  {      krb5_context ctx;      krb5_error_code code; @@ -80,20 +101,20 @@ main(void)      message = krb5_get_error_message(ctx, code);      xasprintf(&wanted, "principal parse failed: %s\n", message); -    is_function_output(test_warn, 0, wanted, "warn_krb5"); -    is_function_output(test_die, 1, wanted, "die_krb5"); +    is_function_output(test_warn, NULL, 0, wanted, "warn_krb5"); +    is_function_output(test_die, NULL, 1, wanted, "die_krb5");      free(wanted);      message_program_name = "msg-test";      xasprintf(&wanted, "msg-test: principal parse failed: %s\n", message); -    is_function_output(test_warn, 0, wanted, "warn_krb5 with name"); -    is_function_output(test_die, 1, wanted, "die_krb5 with name"); +    is_function_output(test_warn, NULL, 0, wanted, "warn_krb5 with name"); +    is_function_output(test_die, NULL, 1, wanted, "die_krb5 with name");      free(wanted);      message_handlers_warn(0); -    is_function_output(test_warn, 0, "", "warn_krb5 with no handlers"); +    is_function_output(test_warn, NULL, 0, "", "warn_krb5 with no handlers");      message_handlers_die(0); -    is_function_output(test_die, 1, "", "warn_krb5 with no handlers"); +    is_function_output(test_die, NULL, 1, "", "warn_krb5 with no handlers");      return 0;  } diff --git a/tests/util/messages-t.c b/tests/util/messages-t.c index a58f82c..54f1cf1 100644 --- a/tests/util/messages-t.c +++ b/tests/util/messages-t.c @@ -1,14 +1,31 @@  /*   * Test suite for error handling routines.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * Copyright 2009, 2010 Board of Trustees, Leland Stanford Jr. University - * Copyright (c) 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - *     2002, 2003 by The Internet Software Consortium and Rich Salz + * Copyright 2002, 2004, 2005 Russ Allbery <rra@stanford.edu> + * Copyright 2009, 2010, 2011, 2012 + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software.   * - * See LICENSE for licensing terms. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #include <config.h> @@ -21,7 +38,7 @@  #include <tests/tap/basic.h>  #include <tests/tap/process.h> -#include <util/concat.h> +#include <util/macros.h>  #include <util/messages.h>  #include <util/xmalloc.h> @@ -29,24 +46,27 @@  /*   * Test functions.   */ -static void test1(void) { warn("warning"); } -static void test2(void) { die("fatal"); } -static void test3(void) { errno = EPERM; syswarn("permissions"); } -static void test4(void) { errno = EACCES; sysdie("fatal access"); } -static void test5(void) { +static void test1(void *data UNUSED) { warn("warning"); } +static void test2(void *data UNUSED) { die("fatal"); } +static void test3(void *data UNUSED) { errno = EPERM; syswarn("permissions"); } +static void test4(void *data UNUSED) { +    errno = EACCES; +    sysdie("fatal access"); +} +static void test5(void *data UNUSED) {      message_program_name = "test5";      warn("warning");  } -static void test6(void) { +static void test6(void *data UNUSED) {      message_program_name = "test6";      die("fatal");  } -static void test7(void) { +static void test7(void *data UNUSED) {      message_program_name = "test7";      errno = EPERM;      syswarn("perms %d", 7);  } -static void test8(void) { +static void test8(void *data UNUSED) {      message_program_name = "test8";      errno = EACCES;      sysdie("%st%s", "fa", "al"); @@ -54,17 +74,17 @@ static void test8(void) {  static int return10(void) { return 10; } -static void test9(void) { +static void test9(void *data UNUSED) {      message_fatal_cleanup = return10;      die("fatal");  } -static void test10(void) { +static void test10(void *data UNUSED) {      message_program_name = 0;      message_fatal_cleanup = return10;      errno = EPERM;      sysdie("fatal perm");  } -static void test11(void) { +static void test11(void *data UNUSED) {      message_program_name = "test11";      message_fatal_cleanup = return10;      errno = EPERM; @@ -72,61 +92,61 @@ static void test11(void) {      sysdie("fatal");  } -static void log_msg(int len, const char *format, va_list args, int error) { -    fprintf(stderr, "%d %d ", len, error); +static void log_msg(size_t len, const char *format, va_list args, int error) { +    fprintf(stderr, "%lu %d ", (unsigned long) len, error);      vfprintf(stderr, format, args);      fprintf(stderr, "\n");  } -static void test12(void) { +static void test12(void *data UNUSED) {      message_handlers_warn(1, log_msg);      warn("warning");  } -static void test13(void) { +static void test13(void *data UNUSED) {      message_handlers_die(1, log_msg);      die("fatal");  } -static void test14(void) { +static void test14(void *data UNUSED) {      message_handlers_warn(2, log_msg, log_msg);      errno = EPERM;      syswarn("warning");  } -static void test15(void) { +static void test15(void *data UNUSED) {      message_handlers_die(2, log_msg, log_msg);      message_fatal_cleanup = return10;      errno = EPERM;      sysdie("fatal");  } -static void test16(void) { +static void test16(void *data UNUSED) {      message_handlers_warn(2, message_log_stderr, log_msg);      message_program_name = "test16";      errno = EPERM;      syswarn("warning");  } -static void test17(void) { notice("notice"); } -static void test18(void) { +static void test17(void *data UNUSED) { notice("notice"); } +static void test18(void *data UNUSED) {      message_program_name = "test18";      notice("notice");  } -static void test19(void) { debug("debug"); } -static void test20(void) { +static void test19(void *data UNUSED) { debug("debug"); } +static void test20(void *data UNUSED) {      message_handlers_notice(1, log_msg);      notice("foo");  } -static void test21(void) { +static void test21(void *data UNUSED) {      message_handlers_debug(1, message_log_stdout);      message_program_name = "test23";      debug("baz");  } -static void test22(void) { +static void test22(void *data UNUSED) {      message_handlers_die(0);      die("hi mom!");  } -static void test23(void) { +static void test23(void *data UNUSED) {      message_handlers_warn(0);      warn("this is a test");  } -static void test24(void) { +static void test24(void *data UNUSED) {      notice("first");      message_handlers_notice(0);      notice("second"); @@ -145,9 +165,9 @@ test_strerror(int status, const char *output, int error,  {      char *full_output, *name; -    full_output = concat(output, ": ", strerror(error), "\n", (char *) NULL); +    xasprintf(&full_output, "%s: %s\n", output, strerror(error));      xasprintf(&name, "strerror %lu", testnum / 3 + 1); -    is_function_output(function, status, full_output, "%s", name); +    is_function_output(function, NULL, status, full_output, "%s", name);      free(full_output);      free(name);  } @@ -164,43 +184,43 @@ main(void)      plan(24 * 3); -    is_function_output(test1, 0, "warning\n", "test1"); -    is_function_output(test2, 1, "fatal\n", "test2"); +    is_function_output(test1, NULL, 0, "warning\n", "test1"); +    is_function_output(test2, NULL, 1, "fatal\n", "test2");      test_strerror(0, "permissions", EPERM, test3);      test_strerror(1, "fatal access", EACCES, test4); -    is_function_output(test5, 0, "test5: warning\n", "test5"); -    is_function_output(test6, 1, "test6: fatal\n", "test6"); +    is_function_output(test5, NULL, 0, "test5: warning\n", "test5"); +    is_function_output(test6, NULL, 1, "test6: fatal\n", "test6");      test_strerror(0, "test7: perms 7", EPERM, test7);      test_strerror(1, "test8: fatal", EACCES, test8); -    is_function_output(test9, 10, "fatal\n", "test9"); +    is_function_output(test9, NULL, 10, "fatal\n", "test9");      test_strerror(10, "fatal perm", EPERM, test10);      test_strerror(10, "1st test11: fatal", EPERM, test11); -    is_function_output(test12, 0, "7 0 warning\n", "test12"); -    is_function_output(test13, 1, "5 0 fatal\n", "test13"); +    is_function_output(test12, NULL, 0, "7 0 warning\n", "test12"); +    is_function_output(test13, NULL, 1, "5 0 fatal\n", "test13");      sprintf(buff, "%d", EPERM);      xasprintf(&output, "7 %d warning\n7 %d warning\n", EPERM, EPERM); -    is_function_output(test14, 0, output, "test14"); +    is_function_output(test14, NULL, 0, output, "test14");      free(output);      xasprintf(&output, "5 %d fatal\n5 %d fatal\n", EPERM, EPERM); -    is_function_output(test15, 10, output, "test15"); +    is_function_output(test15, NULL, 10, output, "test15");      free(output);      xasprintf(&output, "test16: warning: %s\n7 %d warning\n", strerror(EPERM),                EPERM); -    is_function_output(test16, 0, output, "test16"); +    is_function_output(test16, NULL, 0, output, "test16");      free(output); -    is_function_output(test17, 0, "notice\n", "test17"); -    is_function_output(test18, 0, "test18: notice\n", "test18"); -    is_function_output(test19, 0, "", "test19"); -    is_function_output(test20, 0, "3 0 foo\n", "test20"); -    is_function_output(test21, 0, "test23: baz\n", "test21"); +    is_function_output(test17, NULL, 0, "notice\n", "test17"); +    is_function_output(test18, NULL, 0, "test18: notice\n", "test18"); +    is_function_output(test19, NULL, 0, "", "test19"); +    is_function_output(test20, NULL, 0, "3 0 foo\n", "test20"); +    is_function_output(test21, NULL, 0, "test23: baz\n", "test21");      /* Make sure that it's possible to turn off a message type entirely. */  -    is_function_output(test22, 1, "", "test22"); -    is_function_output(test23, 0, "", "test23"); -    is_function_output(test24, 0, "first\nthird\n", "test24"); +    is_function_output(test22, NULL, 1, "", "test22"); +    is_function_output(test23, NULL, 0, "", "test23"); +    is_function_output(test24, NULL, 0, "first\nthird\n", "test24");      return 0;  } diff --git a/tests/util/xmalloc-t b/tests/util/xmalloc-t index 67d95f6..b6c6dfd 100755 --- a/tests/util/xmalloc-t +++ b/tests/util/xmalloc-t @@ -2,14 +2,31 @@  #  # Test suite for xmalloc and friends.  # +# The canonical version of this file is maintained in the rra-c-util package, +# which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. +#  # Written by Russ Allbery <rra@stanford.edu> -# Copyright 2008, 2009, 2010 Board of Trustees, Leland Stanford Jr. University -# Copyright 2004, 2005, 2006 -#     by Internet Systems Consortium, Inc. ("ISC") -# Copyright 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -#     2003 by The Internet Software Consortium and Rich Salz +# Copyright 2000, 2001, 2006 Russ Allbery <rra@stanford.edu> +# Copyright 2008, 2009, 2010, 2012 +#     The Board of Trustees of the Leland Stanford Junior University +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions:  # -# See LICENSE for licensing terms. +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE.  . "$SOURCE/tap/libtap.sh"  cd "$BUILD/util" @@ -24,18 +41,16 @@ ok_xmalloc () {      shift      w_output="$1"      shift -    output=`./xmalloc "$@" 2>&1` +    output=`strip_colon_error ./xmalloc "$@" 2>&1`      status=$? -    if [ "$w_status" -ne 0 ] ; then -        output=`echo "$output" | sed 's/:.*//'` -    fi      if [ $status = $w_status ] && [ x"$output" = x"$w_output" ] ; then          ok "$desc" true      elif [ $status = 2 ] ; then +        diag "$output"          skip "no data limit support"      else -        echo "#  saw: ($status) $output" -        echo "#  not: ($w_status) $w_output" +        diag "saw: ($status) $output" +        diag "not: ($w_status) $w_output"          ok "$desc" false      fi  } @@ -53,75 +68,76 @@ plan 36  # First run the tests expected to succeed.  ok_xmalloc "malloc small"    0 "" "m" "21"      "0" -ok_xmalloc "malloc large"    0 "" "m" "3500000" "0" +ok_xmalloc "malloc large"    0 "" "m" "5500000" "0"  ok_xmalloc "malloc zero"     0 "" "m" "0"       "0"  ok_xmalloc "realloc small"   0 "" "r" "21"      "0" -ok_xmalloc "realloc large"   0 "" "r" "3500000" "0" +ok_xmalloc "realloc large"   0 "" "r" "5500000" "0"  ok_xmalloc "strdup small"    0 "" "s" "21"      "0" -ok_xmalloc "strdup large"    0 "" "s" "3500000" "0" +ok_xmalloc "strdup large"    0 "" "s" "5500000" "0"  ok_xmalloc "strndup small"   0 "" "n" "21"      "0" -ok_xmalloc "strndup large"   0 "" "n" "3500000" "0" +ok_xmalloc "strndup large"   0 "" "n" "5500000" "0"  ok_xmalloc "calloc small"    0 "" "c" "24"      "0" -ok_xmalloc "calloc large"    0 "" "c" "3500000" "0" +ok_xmalloc "calloc large"    0 "" "c" "5500000" "0"  ok_xmalloc "asprintf small"  0 "" "a" "24"      "0" -ok_xmalloc "asprintf large"  0 "" "a" "3500000" "0" +ok_xmalloc "asprintf large"  0 "" "a" "5500000" "0"  ok_xmalloc "vasprintf small" 0 "" "v" "24"      "0" -ok_xmalloc "vasprintf large" 0 "" "v" "3500000" "0" +ok_xmalloc "vasprintf large" 0 "" "v" "5500000" "0" -# Now limit our memory to 3.5MB and then try the large ones again, all of +# Now limit our memory to 5.5MB and then try the large ones again, all of  # which should fail.  #  # The exact memory limits used here are essentially black magic.  They need to  # be large enough to allow the program to be loaded and do small allocations,  # but not so large that we can't reasonably expect to allocate that much -# memory normally.  3.5MB seems to work reasonably well on both Solaris and -# Linux. +# memory normally.  The amount of memory required varies a lot based on what +# shared libraries are loaded, and if it's too small, all memory allocations +# fail.  5.5MB seems to work reasonably well on both Solaris and Linux.  #  # We assume that there are enough miscellaneous allocations that an allocation  # exactly as large as the limit will always fail.  ok_xmalloc "malloc fail" 1 \ -    "failed to malloc 3500000 bytes at xmalloc.c line 38" \ -    "m" "3500000" "3500000" +    "failed to malloc 5500000 bytes at xmalloc.c line 38" \ +    "m" "5500000" "5500000"  ok_xmalloc "realloc fail" 1 \ -    "failed to realloc 3500000 bytes at xmalloc.c line 66" \ -    "r" "3500000" "3500000" +    "failed to realloc 5500000 bytes at xmalloc.c line 66" \ +    "r" "5500000" "5500000"  ok_xmalloc "strdup fail" 1 \ -    "failed to strdup 3500000 bytes at xmalloc.c line 97" \ -    "s" "3500000" "3500000" +    "failed to strdup 5500000 bytes at xmalloc.c line 97" \ +    "s" "5500000" "5500000"  ok_xmalloc "strndup fail" 1 \ -    "failed to strndup 3500000 bytes at xmalloc.c line 124" \ -    "n" "3500000" "3500000" +    "failed to strndup 5500000 bytes at xmalloc.c line 143" \ +    "n" "5500000" "5500000"  ok_xmalloc "calloc fail" 1 \ -    "failed to calloc 3500000 bytes at xmalloc.c line 148" \ -    "c" "3500000" "3500000" +    "failed to calloc 5500000 bytes at xmalloc.c line 167" \ +    "c" "5500000" "5500000"  ok_xmalloc "asprintf fail" 1 \ -    "failed to asprintf 3500000 bytes at xmalloc.c line 172" \ -    "a" "3500000" "3500000" +    "failed to asprintf 5500000 bytes at xmalloc.c line 191" \ +    "a" "5500000" "5500000"  ok_xmalloc "vasprintf fail" 1 \ -    "failed to vasprintf 3500000 bytes at xmalloc.c line 192" \ -    "v" "3500000" "3500000" +    "failed to vasprintf 5500000 bytes at xmalloc.c line 210" \ +    "v" "5500000" "5500000"  # Check our custom error handler. -ok_xmalloc "malloc custom"    1 "malloc 3500000 xmalloc.c 38" \ -    "M" "3500000" "3500000" -ok_xmalloc "realloc custom"   1 "realloc 3500000 xmalloc.c 66" \ -    "R" "3500000" "3500000" -ok_xmalloc "strdup custom"    1 "strdup 3500000 xmalloc.c 97" \ -    "S" "3500000" "3500000" -ok_xmalloc "strndup custom"   1 "strndup 3500000 xmalloc.c 124" \ -    "N" "3500000" "3500000" -ok_xmalloc "calloc custom"    1 "calloc 3500000 xmalloc.c 148" \ -    "C" "3500000" "3500000" -ok_xmalloc "asprintf custom"  1 "asprintf 3500000 xmalloc.c 172" \ -    "A" "3500000" "3500000" -ok_xmalloc "vasprintf custom" 1 "vasprintf 3500000 xmalloc.c 192" \ -    "V" "3500000" "3500000" +ok_xmalloc "malloc custom"    1 "malloc 5500000 xmalloc.c 38" \ +    "M" "5500000" "5500000" +ok_xmalloc "realloc custom"   1 "realloc 5500000 xmalloc.c 66" \ +    "R" "5500000" "5500000" +ok_xmalloc "strdup custom"    1 "strdup 5500000 xmalloc.c 97" \ +    "S" "5500000" "5500000" +ok_xmalloc "strndup custom"   1 "strndup 5500000 xmalloc.c 143" \ +    "N" "5500000" "5500000" +ok_xmalloc "calloc custom"    1 "calloc 5500000 xmalloc.c 167" \ +    "C" "5500000" "5500000" +ok_xmalloc "asprintf custom"  1 "asprintf 5500000 xmalloc.c 191" \ +    "A" "5500000" "5500000" +ok_xmalloc "vasprintf custom" 1 "vasprintf 5500000 xmalloc.c 210" \ +    "V" "5500000" "5500000"  # Check the smaller ones again just for grins. -ok_xmalloc "malloc retry"    0 "" "m" "21" "3500000" -ok_xmalloc "realloc retry"   0 "" "r" "32" "3500000" -ok_xmalloc "strdup retry"    0 "" "s" "64" "3500000" -ok_xmalloc "strndup retry"   0 "" "n" "20" "3500000" -ok_xmalloc "calloc retry"    0 "" "c" "24" "3500000" -ok_xmalloc "asprintf retry"  0 "" "a" "30" "3500000" -ok_xmalloc "vasprintf retry" 0 "" "v" "35" "3500000" +ok_xmalloc "malloc retry"    0 "" "m" "21" "5500000" +ok_xmalloc "realloc retry"   0 "" "r" "32" "5500000" +ok_xmalloc "strdup retry"    0 "" "s" "64" "5500000" +ok_xmalloc "strndup retry"   0 "" "n" "20" "5500000" +ok_xmalloc "calloc retry"    0 "" "c" "24" "5500000" +ok_xmalloc "asprintf retry"  0 "" "a" "30" "5500000" +ok_xmalloc "vasprintf retry" 0 "" "v" "35" "5500000" diff --git a/tests/util/xmalloc.c b/tests/util/xmalloc.c index c37396e..394cab5 100644 --- a/tests/util/xmalloc.c +++ b/tests/util/xmalloc.c @@ -1,13 +1,30 @@  /*   * Test suite for xmalloc and family.   * - * Copyright 2008 Board of Trustees, Leland Stanford Jr. University - * Copyright 2004, 2005, 2006 - *     by Internet Systems Consortium, Inc. ("ISC") - * Copyright 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - *     2003 by The Internet Software Consortium and Rich Salz + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>.   * - * See LICENSE for licensing terms. + * Copyright 2000, 2001, 2006 Russ Allbery <rra@stanford.edu> + * Copyright 2008, 2012 + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #line 1 "xmalloc.c" @@ -62,9 +79,9 @@ test_malloc(size_t size)  /* - * Allocate half the memory given, write to it, then reallocate to the desired - * size, writing to the rest and then checking it all.  Returns true on - * success, false on any failure. + * Allocate 10 bytes of memory given, write to it, then reallocate to the + * desired size, writing to the rest and then checking it all.  Returns true + * on success, false on any failure.   */  static int  test_realloc(size_t size) @@ -119,15 +136,34 @@ test_strdup(size_t size)  /*   * Generate a string of the size indicated plus some, call xstrndup on it, and - * then ensure the result matches.  Returns true on success, false on any - * failure. + * then ensure the result matches.  Also test xstrdup on a string that's + * shorter than the specified size and ensure that we don't copy too much, and + * on a string that's not nul-terminated.  Returns true on success, false on + * any failure.   */  static int  test_strndup(size_t size)  {      char *string, *copy; -    int match, toomuch; +    int shortmatch, nonulmatch, match, toomuch; + +    /* Copy a short string. */ +    string = xmalloc(5); +    memcpy(string, "test", 5); +    copy = xstrndup(string, size); +    shortmatch = strcmp(string, copy); +    free(string); +    free(copy); +    /* Copy a string that's not nul-terminated. */ +    string = xmalloc(4); +    memcpy(string, "test", 4); +    copy = xstrndup(string, 4); +    nonulmatch = strcmp(copy, "test"); +    free(string); +    free(copy); + +    /* Now the test of running out of memory. */      string = xmalloc(size + 1);      if (string == NULL)          return 0; @@ -141,7 +177,7 @@ test_strndup(size_t size)      toomuch = strcmp(string, copy);      free(string);      free(copy); -    return (match == 0 && toomuch != 0); +    return (shortmatch == 0 && nonulmatch == 0 && match == 0 && toomuch != 0);  } @@ -195,16 +231,14 @@ test_asprintf(size_t size)  /* Wrapper around vasprintf to do the va_list stuff. */ -static int +static void  xvasprintf_wrapper(char **strp, const char *format, ...)  {      va_list args; -    int status;      va_start(args, format); -    status = xvasprintf(strp, format, args); +    xvasprintf(strp, format, args);      va_end(args); -    return status;  } @@ -298,8 +332,8 @@ main(int argc, char *argv[])          if (size < limit || code == 'r') {              tmp = malloc(code == 'r' ? 10 : size);              if (tmp == NULL) { -                syswarn("Can't allocate initial memory of %lu", -                        (unsigned long) size); +                syswarn("Can't allocate initial memory of %lu (limit %lu)", +                        (unsigned long) size, (unsigned long) limit);                  exit(2);              }              free(tmp); diff --git a/util/macros.h b/util/macros.h index 0104d9f..54faee5 100644 --- a/util/macros.h +++ b/util/macros.h @@ -1,8 +1,18 @@  /*   * Some standard helpful macros.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu> - * This work is hereby placed in the public domain by its author. + * + * The authors hereby relinquish any claim to any copyright that they may have + * in this work, whether granted under contract or by operation of law or + * international treaty, and hereby commit to the public, at large, that they + * shall not, at any time in the future, seek to enforce any copyright in this + * work against any person or entity, or prevent any person or entity from + * copying, publishing, distributing or creating derivative works of this + * work.   */  #ifndef UTIL_MACROS_H @@ -10,6 +20,15 @@  #include <portable/macros.h> +/* + * Used for iterating through arrays.  ARRAY_SIZE returns the number of + * elements in the array (useful for a < upper bound in a for loop) and + * ARRAY_END returns a pointer to the element past the end (ISO C99 makes it + * legal to refer to such a pointer as long as it's never dereferenced). + */ +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) +#define ARRAY_END(array)  (&(array)[ARRAY_SIZE(array)]) +  /* Used for unused parameters to silence gcc warnings. */  #define UNUSED __attribute__((__unused__)) diff --git a/util/messages-krb5.c b/util/messages-krb5.c index 7f35d29..23fd56a 100644 --- a/util/messages-krb5.c +++ b/util/messages-krb5.c @@ -1,15 +1,34 @@  /* - * Error handling for Kerberos v5. + * Error handling for Kerberos.   *   * Provides versions of die and warn that take a Kerberos context and a   * Kerberos error code and append the Kerberos error message to the provided   * formatted message.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu>   * Copyright 2006, 2007, 2008, 2009, 2010 - *     Board of Trustees, Leland Stanford Jr. University + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software.   * - * See LICENSE for licensing terms. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #include <config.h> @@ -32,12 +51,15 @@ die_krb5(krb5_context ctx, krb5_error_code code, const char *format, ...)      char *message;      va_list args; -    k5_msg = krb5_get_error_message(ctx, code); +    if (ctx != NULL) +        k5_msg = krb5_get_error_message(ctx, code);      va_start(args, format); -    if (xvasprintf(&message, format, args) < 0) -        die("internal error: unable to format error message"); +    xvasprintf(&message, format, args);      va_end(args); -    die("%s: %s", message, k5_msg); +    if (k5_msg == NULL) +        die("%s", message); +    else +        die("%s: %s", message, k5_msg);  } @@ -51,12 +73,16 @@ warn_krb5(krb5_context ctx, krb5_error_code code, const char *format, ...)      char *message;      va_list args; -    k5_msg = krb5_get_error_message(ctx, code); +    if (ctx != NULL) +        k5_msg = krb5_get_error_message(ctx, code);      va_start(args, format); -    if (xvasprintf(&message, format, args) < 0) -        die("internal error: unable to format error message"); +    xvasprintf(&message, format, args);      va_end(args); -    warn("%s: %s", message, k5_msg); +    if (k5_msg == NULL) +        warn("%s", message); +    else +        warn("%s: %s", message, k5_msg);      free(message); -    krb5_free_error_message(ctx, k5_msg); +    if (k5_msg != NULL) +        krb5_free_error_message(ctx, k5_msg);  } diff --git a/util/messages-krb5.h b/util/messages-krb5.h index 3b763c8..a61d7cd 100644 --- a/util/messages-krb5.h +++ b/util/messages-krb5.h @@ -1,11 +1,30 @@  /*   * Prototypes for error handling for Kerberos.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + *   * Written by Russ Allbery <rra@stanford.edu>   * Copyright 2006, 2007, 2008, 2009, 2010 - *     Board of Trustees, Leland Stanford Jr. University + *     The Board of Trustees of the Leland Stanford Junior University + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software.   * - * See LICENSE for licensing terms. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE.   */  #ifndef UTIL_MESSAGES_KRB5_H diff --git a/util/messages.c b/util/messages.c index 3592692..52fcfb7 100644 --- a/util/messages.c +++ b/util/messages.c @@ -50,13 +50,31 @@   * generates given the format and arguments), a format, an argument list as a   * va_list, and the applicable errno value (if any).   * - * Copyright 2008 Board of Trustees, Leland Stanford Jr. University + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Written by Russ Allbery <rra@stanford.edu> + * Copyright 2008, 2009, 2010 + *     The Board of Trustees of the Leland Stanford Junior University   * Copyright (c) 2004, 2005, 2006   *     by Internet Systems Consortium, Inc. ("ISC")   * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,   *     2002, 2003 by The Internet Software Consortium and Rich Salz   * - * See LICENSE for licensing terms. + * This code is derived from software contributed to the Internet Software + * Consortium by Rich Salz. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE.   */  #include <config.h> @@ -189,8 +207,8 @@ message_log_syslog(int pri, size_t len, const char *fmt, va_list args, int err)      buffer = malloc(len + 1);      if (buffer == NULL) { -        fprintf(stderr, "failed to malloc %u bytes at %s line %d: %s", -                len + 1, __FILE__, __LINE__, strerror(errno)); +        fprintf(stderr, "failed to malloc %lu bytes at %s line %d: %s", +                (unsigned long) len + 1, __FILE__, __LINE__, strerror(errno));          exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1);      }      vsnprintf(buffer, len + 1, fmt, args); diff --git a/util/messages.h b/util/messages.h index dbdb256..463137c 100644 --- a/util/messages.h +++ b/util/messages.h @@ -1,13 +1,30 @@  /*   * Prototypes for message and error reporting (possibly fatal).   * - * Copyright 2008, 2010 Board of Trustees, Leland Stanford Jr. University + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Copyright 2008, 2010 + *     The Board of Trustees of the Leland Stanford Junior University   * Copyright (c) 2004, 2005, 2006   *     by Internet Systems Consortium, Inc. ("ISC")   * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,   *     2002, 2003 by The Internet Software Consortium and Rich Salz   * - * See LICENSE for licensing terms. + * This code is derived from software contributed to the Internet Software + * Consortium by Rich Salz. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE.   */  #ifndef UTIL_MESSAGES_H @@ -60,21 +77,21 @@ void message_handlers_die(unsigned int count, ...);   * argument list, and the errno setting if any.   */  void message_log_stdout(size_t, const char *, va_list, int) -    __attribute((__nonnull__)); +    __attribute__((__nonnull__));  void message_log_stderr(size_t, const char *, va_list, int) -    __attribute((__nonnull__)); +    __attribute__((__nonnull__));  void message_log_syslog_debug(size_t, const char *, va_list, int) -    __attribute((__nonnull__)); +    __attribute__((__nonnull__));  void message_log_syslog_info(size_t, const char *, va_list, int) -    __attribute((__nonnull__)); +    __attribute__((__nonnull__));  void message_log_syslog_notice(size_t, const char *, va_list, int) -    __attribute((__nonnull__)); +    __attribute__((__nonnull__));  void message_log_syslog_warning(size_t, const char *, va_list, int) -    __attribute((__nonnull__)); +    __attribute__((__nonnull__));  void message_log_syslog_err(size_t, const char *, va_list, int) -    __attribute((__nonnull__)); +    __attribute__((__nonnull__));  void message_log_syslog_crit(size_t, const char *, va_list, int) -    __attribute((__nonnull__)); +    __attribute__((__nonnull__));  /* The type of a message handler. */  typedef void (*message_handler_func)(size_t, const char *, va_list, int); diff --git a/util/xmalloc.c b/util/xmalloc.c index 4e05f96..a78e31a 100644 --- a/util/xmalloc.c +++ b/util/xmalloc.c @@ -55,12 +55,30 @@   * header file defines macros named xmalloc, etc. that pass the file name and   * line number to these functions.   * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Copyright 2012 + *     The Board of Trustees of the Leland Stanford Junior University   * Copyright (c) 2004, 2005, 2006   *     by Internet Systems Consortium, Inc. ("ISC")   * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,   *     2002, 2003 by The Internet Software Consortium and Rich Salz   * - * See LICENSE for licensing terms. + * This code is derived from software contributed to the Internet Software + * Consortium by Rich Salz. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE.   */  #include <config.h> @@ -149,23 +167,34 @@ x_strdup(const char *s, const char *file, int line)  } +/* + * Avoid using the system strndup function since it may not exist (on Mac OS + * X, for example), and there's no need to introduce another portability + * requirement. + */  char *  x_strndup(const char *s, size_t size, const char *file, int line)  { -    char *p; +    const char *p; +    size_t length; +    char *copy; -    p = malloc(size + 1); -    while (p == NULL) { -        (*xmalloc_error_handler)("strndup", size + 1, file, line); -        p = malloc(size + 1); +    /* Don't assume that the source string is nul-terminated. */ +    for (p = s; (size_t) (p - s) < size && *p != '\0'; p++) +        ; +    length = p - s; +    copy = malloc(length + 1); +    while (copy == NULL) { +        (*xmalloc_error_handler)("strndup", length + 1, file, line); +        copy = malloc(length + 1);      } -    memcpy(p, s, size); -    p[size] = '\0'; -    return p; +    memcpy(copy, s, length); +    copy[length] = '\0'; +    return copy;  } -int +void  x_vasprintf(char **strp, const char *fmt, va_list args, const char *file,              int line)  { @@ -175,7 +204,7 @@ x_vasprintf(char **strp, const char *fmt, va_list args, const char *file,      va_copy(args_copy, args);      status = vasprintf(strp, fmt, args_copy);      va_end(args_copy); -    while (status < 0 && errno == ENOMEM) { +    while (status < 0) {          va_copy(args_copy, args);          status = vsnprintf(NULL, 0, fmt, args_copy);          va_end(args_copy); @@ -184,12 +213,11 @@ x_vasprintf(char **strp, const char *fmt, va_list args, const char *file,          status = vasprintf(strp, fmt, args_copy);          va_end(args_copy);      } -    return status;  }  #if HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS -int +void  x_asprintf(char **strp, const char *file, int line, const char *fmt, ...)  {      va_list args, args_copy; @@ -199,7 +227,7 @@ x_asprintf(char **strp, const char *file, int line, const char *fmt, ...)      va_copy(args_copy, args);      status = vasprintf(strp, fmt, args_copy);      va_end(args_copy); -    while (status < 0 && errno == ENOMEM) { +    while (status < 0) {          va_copy(args_copy, args);          status = vsnprintf(NULL, 0, fmt, args_copy);          va_end(args_copy); @@ -208,10 +236,9 @@ x_asprintf(char **strp, const char *file, int line, const char *fmt, ...)          status = vasprintf(strp, fmt, args_copy);          va_end(args_copy);      } -    return status;  }  #else /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */ -int +void  x_asprintf(char **strp, const char *fmt, ...)  {      va_list args, args_copy; @@ -221,7 +248,7 @@ x_asprintf(char **strp, const char *fmt, ...)      va_copy(args_copy, args);      status = vasprintf(strp, fmt, args_copy);      va_end(args_copy); -    while (status < 0 && errno == ENOMEM) { +    while (status < 0) {          va_copy(args_copy, args);          status = vsnprintf(NULL, 0, fmt, args_copy);          va_end(args_copy); @@ -230,6 +257,5 @@ x_asprintf(char **strp, const char *fmt, ...)          status = vasprintf(strp, fmt, args_copy);          va_end(args_copy);      } -    return status;  }  #endif /* !(HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS) */ diff --git a/util/xmalloc.h b/util/xmalloc.h index 657a6bb..55a0b91 100644 --- a/util/xmalloc.h +++ b/util/xmalloc.h @@ -1,13 +1,30 @@  /*   * Prototypes for malloc routines with failure handling.   * - * Copyright 2010 Board of Trustees, Leland Stanford Jr. University + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <http://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Copyright 2010, 2012 + *     The Board of Trustees of the Leland Stanford Junior University   * Copyright (c) 2004, 2005, 2006   *     by Internet Systems Consortium, Inc. ("ISC")   * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,   *     2002, 2003 by The Internet Software Consortium and Rich Salz   * - * See LICENSE for licensing terms. + * This code is derived from software contributed to the Internet Software + * Consortium by Rich Salz. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE + * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE.   */  #ifndef UTIL_XMALLOC_H @@ -67,15 +84,15 @@ char *x_strdup(const char *, const char *, int)      __attribute__((__malloc__, __nonnull__));  char *x_strndup(const char *, size_t, const char *, int)      __attribute__((__malloc__, __nonnull__)); -int x_vasprintf(char **, const char *, va_list, const char *, int) +void x_vasprintf(char **, const char *, va_list, const char *, int)      __attribute__((__nonnull__));  /* asprintf special case. */  #if HAVE_C99_VAMACROS || HAVE_GNU_VAMACROS -int x_asprintf(char **, const char *, int, const char *, ...) +void x_asprintf(char **, const char *, int, const char *, ...)      __attribute__((__nonnull__, __format__(printf, 4, 5)));  #else -int x_asprintf(char **, const char *, ...) +void x_asprintf(char **, const char *, ...)      __attribute__((__nonnull__, __format__(printf, 2, 3)));  #endif | 
