Author: pluknet
Date: Mon Apr 29 21:30:04 2013
New Revision: 250076
URL: http://svnweb.freebsd.org/changeset/base/250076

Log:
  MFC r243314:
   Zero the whole struct not just the size of a pointer.
  
  MFC r246670:
   Major update for unix_cmsg.
  
  PR:           bin/131567
  Submitted by: Andrey Simonenko <[email protected]>

Modified:
  stable/9/tools/regression/sockets/unix_cmsg/README
  stable/9/tools/regression/sockets/unix_cmsg/unix_cmsg.c
  stable/9/tools/regression/sockets/unix_cmsg/unix_cmsg.t
Directory Properties:
  stable/9/tools/regression/sockets/   (props changed)

Modified: stable/9/tools/regression/sockets/unix_cmsg/README
==============================================================================
--- stable/9/tools/regression/sockets/unix_cmsg/README  Mon Apr 29 21:12:25 
2013        (r250075)
+++ stable/9/tools/regression/sockets/unix_cmsg/README  Mon Apr 29 21:30:04 
2013        (r250076)
@@ -1,127 +1,160 @@
 $FreeBSD$
 
 About unix_cmsg
-================
+===============
 
-This program is a collection of regression tests for ancillary (control)
-data for PF_LOCAL sockets (local domain or Unix domain sockets).  There
-are tests for stream and datagram sockets.
-
-Usually each test does following steps: create Server, fork Client,
-Client sends something to Server, Server verifies if everything
-is correct in received message.  Sometimes Client sends several
-messages to Server.
+This program is a collection of regression tests for ancillary data
+(control information) for PF_LOCAL sockets (local domain or Unix domain
+sockets).  There are tests for stream and datagram sockets.
+
+Usually each test does following steps: creates Server, forks Client,
+Client sends something to Server, Server verifies whether everything is
+correct in received message(s).
 
 It is better to change the owner of unix_cmsg to some safe user
-(eg. nobody:nogroup) and set SUID and SGID bits, else some tests
-can give correct results for wrong implementation.
+(eg. nobody:nogroup) and set SUID and SGID bits, else some tests that
+check credentials can give correct results for wrong implementation.
+
+It is better to run this program by a user that belongs to more
+than 16 groups.
 
 Available options
 =================
 
--d     Output debugging information, values of different fields of
-       received messages, etc.  Will produce many lines of information.
-
--h     Output help message and exit.
-
--t <socktype>
-       Run tests only for the given socket type: "stream" or "dgram".
-       With this option it is possible to run only particular test,
-       not all of them.
-
--z     Do not send real control data if possible.  Struct cmsghdr{}
-       should be followed by real control data.  It is not clear if
-       a sender should give control data in all cases (this is not
-       documented and an arbitrary application can choose anything).
-
-       At least for PF_LOCAL sockets' control messages with types
-       SCM_CREDS and SCM_TIMESTAMP the kernel does not need any
-       control data.  This option allow to not send real control data
-       for SCM_CREDS and SCM_TIMESTAMP control messages.
+usage: unix_cmsg [-dh] [-n num] [-s size] [-t type] [-z value] [testno]
 
-Description of tests
-====================
+ Options are:
+  -d            Output debugging information
+  -h            Output the help message and exit
+  -n num        Number of messages to send
+  -s size       Specify size of data for IPC
+  -t type       Specify socket type (stream, dgram) for tests
+  -z value      Do not send data in a message (bit 0x1), do not send
+                data array associated with a cmsghdr structure (bit 0x2)
+  testno        Run one test by its number (require the -t option)
+
+Description
+===========
+
+If Client sends something to Server, then it sends 5 messages by default.
+Number of messages can be changed in the -n command line option.  Number
+of messages will be given as N in the following descriptions.
+
+If Client sends something to Server, then it sends some data (few bytes)
+in each message by default.  The size of this data can be changed by the -s
+command line option.  The "-s 0" command line option means, that Client will
+send zero bytes represented by { NULL, 0 } value of struct iovec{}, referenced
+by the msg_iov field from struct msghdr{}.  The "-z 1" or "-z 3" command line
+option means, that Client will send zero bytes represented by the NULL value
+in the msg_iov field from struct msghdr{}.
+
+If Client sends some ancillary data object, then this ancillary data object
+always has associated data array by default.  The "-z 2" or "-z 3" option
+means, that Client will not send associated data array if possible.
 
 For SOCK_STREAM sockets:
 -----------------------
 
  1: Sending, receiving cmsgcred
 
-    Client connects to Server and sends two messages with data and
-    control message with SCM_CREDS type to Server.  Server should
-    receive two messages, in both messages there should be data and
-    control message with SCM_CREDS type followed by struct cmsgcred{}
-    and this structure should contain correct information.
-
- 2: Receiving sockcred (listening socket has LOCAL_CREDS)
-
-    Server creates listen socket and set socket option LOCAL_CREDS
-    for it.  Client connects to Server and sends two messages with data
-    to Server.  Server should receive two messages, in first message
-    there should be data and control message with SCM_CREDS type followed
-    by struct sockcred{} and this structure should contain correct
-    information, in second message there should be data and no control
-    message.
-
- 3: Receiving sockcred (accepted socket has LOCAL_CREDS)
-
-    Client connects to Server and sends two messages with data.  Server
-    accepts connection and set socket option LOCAL_CREDS for just accepted
-    socket (here synchronization is used, to allow Client to see just set
-    flag on Server's socket before sending messages to Server).  Server
-    should receive two messages, in first message there should be data and
-    control message with SOCK_CRED type followed by struct sockcred{} and
-    this structure should contain correct information, in second message
-    there should be data and no control message.
+    Client connects to Server and sends N messages with SCM_CREDS ancillary
+    data object.  Server should receive N messages, each message should
+    have SCM_CREDS ancillary data object followed by struct cmsgcred{}.
+
+ 2: Receiving sockcred (listening socket)
+
+    Server creates a listening stream socket and sets the LOCAL_CREDS
+    socket option for it.  Client connects to Server two times, each time
+    it sends N messages.  Server accepts two connections and receives N
+    messages from each connection.  The first message from each connection
+    should have SCM_CREDS ancillary data object followed by struct sockcred{},
+    next messages from the same connection should not have ancillary data.
+
+ 3: Receiving sockcred (accepted socket)
+
+    Client connects to Server.  Server accepts connection and sets the
+    LOCAL_CREDS socket option for just accepted socket.  Client sends N
+    messages to Server.  Server should receive N messages, the first
+    message should have SCM_CREDS ancillary data object followed by
+    struct sockcred{}, next messages should not have ancillary data.
 
  4: Sending cmsgcred, receiving sockcred
 
-    Server creates listen socket and set socket option LOCAL_CREDS
-    for it.  Client connects to Server and sends one message with data
-    and control message with SCM_CREDS type to Server.  Server should
-    receive one message with data and control message with SCM_CREDS type
-    followed by struct sockcred{} and this structure should contain
-    correct information.
-
- 5: Sending, receiving timestamp
-
-    Client connects to Server and sends message with data and control
-    message with SCM_TIMESTAMP type to Server.  Server should receive
-    message with data and control message with SCM_TIMESTAMP type
-    followed by struct timeval{}.
+    Server creates a listening stream socket and sets the LOCAL_CREDS
+    socket  option for it.  Client connects to Server and sends N messages
+    with SCM_CREDS ancillary data object.  Server should receive N messages,
+    the first message should have SCM_CREDS ancillary data object followed
+    by struct sockcred{}, each of next messages should have SCM_CREDS
+    ancillary data object followed by struct cmsgcred{}.
+
+ 5: Sending, receiving timeval
+
+    Client connects to Server and sends message with SCM_TIMESTAMP ancillary
+    data object.  Server should receive one message with SCM_TIMESTAMP
+    ancillary data object followed by struct timeval{}.
+
+ 6: Sending, receiving bintime
+
+    Client connects to Server and sends message with SCM_BINTIME ancillary
+    data object.  Server should receive one message with SCM_BINTIME
+    ancillary data object followed by struct bintime{}.
+
+ 7: Checking cmsghdr.cmsg_len
+
+    Client connects to Server and tries to send several messages with
+    SCM_CREDS ancillary data object that has wrong cmsg_len field in its
+    struct cmsghdr{}.  All these attempts should fail, since cmsg_len
+    in all requests is less than CMSG_LEN(0).
+
+ 8: Check LOCAL_PEERCRED socket option
+
+    This test does not use ancillary data, but can be implemented here.
+    Client connects to Server.  Both Client and Server verify that
+    credentials of the peer are correct using LOCAL_PEERCRED socket option.
 
 For SOCK_DGRAM sockets:
 ----------------------
 
  1: Sending, receiving cmsgcred
 
-    Client sends to Server two messages with data and control message
-    with SCM_CREDS type to Server.  Server should receive two messages,
-    in both messages there should be data and control message with
-    SCM_CREDS type followed by struct cmsgcred{} and this structure
-    should contain correct information.
+    Client connects to Server and sends N messages with SCM_CREDS ancillary
+    data object.  Server should receive N messages, each message should
+    have SCM_CREDS ancillary data object followed by struct cmsgcred{}.
 
  2: Receiving sockcred
 
-    Server creates datagram socket and set socket option LOCAL_CREDS
-    for it.  Client sends two messages with data to Server.  Server should
-    receive two messages, in both messages there should be data and control
-    message with SCM_CREDS type followed by struct sockcred{} and this
-    structure should contain correct information.
+    Server creates datagram socket and sets the LOCAL_CREDS socket option
+    for it.  Client sends N messages to Server.  Server should receive N
+    messages, each message should have SCM_CREDS ancillary data object
+    followed by struct sockcred{}.
 
  3: Sending cmsgcred, receiving sockcred
- 
-    Server creates datagram socket and set socket option LOCAL_CREDS
-    for it.  Client sends one message with data and control message with
-    SOCK_CREDS type to Server.  Server should receive one message with
-    data and control message with SCM_CREDS type followed by struct
-    sockcred{} and this structure should contain correct information.
-
- 4: Sending, receiving timestamp
-
-    Client sends message with data and control message with SCM_TIMESTAMP
-    type to Server.  Server should receive message with data and control
-    message with SCM_TIMESTAMP type followed by struct timeval{}.
+
+    Server creates datagram socket and sets the LOCAL_CREDS socket option
+    for it.  Client sends N messages with SCM_CREDS ancillary data object
+    to Server.  Server should receive N messages, the first message should
+    have SCM_CREDS ancillary data object followed by struct sockcred{},
+    each of next messages should have SCM_CREDS ancillary data object
+    followed by struct cmsgcred{}.
+
+ 4: Sending, receiving timeval
+
+    Client sends one message with SCM_TIMESTAMP ancillary data object
+    to Server.  Server should receive one message with SCM_TIMESTAMP
+    ancillary data object followed by struct timeval{}.
+
+ 5: Sending, receiving bintime
+
+    Client sends one message with SCM_BINTIME ancillary data object
+    to Server.  Server should receive one message with SCM_BINTIME
+    ancillary data object followed by struct bintime{}.
+
+ 6: Checking cmsghdr.cmsg_len
+
+    Client tries to send Server several messages with SCM_CREDS ancillary
+    data object that has wrong cmsg_len field in its struct cmsghdr{}.
+    All these attempts should fail, since cmsg_len in all requests is less
+    than CMSG_LEN(0).
 
 - Andrey Simonenko
[email protected]
[email protected]

Modified: stable/9/tools/regression/sockets/unix_cmsg/unix_cmsg.c
==============================================================================
--- stable/9/tools/regression/sockets/unix_cmsg/unix_cmsg.c     Mon Apr 29 
21:12:25 2013        (r250075)
+++ stable/9/tools/regression/sockets/unix_cmsg/unix_cmsg.c     Mon Apr 29 
21:30:04 2013        (r250076)
@@ -27,48 +27,46 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
-#include <sys/types.h>
+#include <sys/param.h>
 #include <sys/resource.h>
 #include <sys/time.h>
+#include <sys/select.h>
 #include <sys/socket.h>
+#include <sys/ucred.h>
 #include <sys/un.h>
 #include <sys/wait.h>
 
-#include <assert.h>
 #include <ctype.h>
 #include <err.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <inttypes.h>
 #include <limits.h>
-#include <setjmp.h>
+#include <paths.h>
 #include <signal.h>
 #include <stdarg.h>
+#include <stdbool.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <unistd.h>
 
 /*
  * There are tables with tests descriptions and pointers to test
  * functions.  Each t_*() function returns 0 if its test passed,
- * -1 if its test failed (something wrong was found in local domain
- * control messages), -2 if some system error occurred.  If test
- * function returns -2, then a program exits.
+ * -1 if its test failed, -2 if some system error occurred.
+ * If a test function returns -2, then a program exits.
  *
- * Each test function completely control what to do (eg. fork or
- * do not fork a client process).  If a test function forks a client
- * process, then it waits for its termination.  If a return code of a
- * client process is not equal to zero, or if a client process was
- * terminated by a signal, then test function returns -2.
+ * If a test function forks a client process, then it waits for its
+ * termination.  If a return code of a client process is not equal
+ * to zero, or if a client process was terminated by a signal, then
+ * a test function returns -1 or -2 depending on exit status of
+ * a client process.
  *
- * Each test function and complete program are not optimized
- * a lot to allow easy to modify tests.
- *
- * Each function which can block, is run under TIMEOUT, if timeout
- * occurs, then test function returns -2 or a client process exits
- * with nonzero return code.
+ * Each function which can block, is run under TIMEOUT.  If timeout
+ * occurs, then a test function returns -2 or a client process exits
+ * with a non-zero return code.
  */
 
 #ifndef LISTENQ
@@ -76,207 +74,290 @@ __FBSDID("$FreeBSD$");
 #endif
 
 #ifndef TIMEOUT
-# define TIMEOUT       60
+# define TIMEOUT       2
 #endif
 
-#define EXTRA_CMSG_SPACE 512   /* Memory for not expected control data. */
-
-static int     t_cmsgcred(void), t_sockcred_stream1(void);
-static int     t_sockcred_stream2(void), t_cmsgcred_sockcred(void);
-static int     t_sockcred_dgram(void), t_timestamp(void);
+static int     t_cmsgcred(void);
+static int     t_sockcred_1(void);
+static int     t_sockcred_2(void);
+static int     t_cmsgcred_sockcred(void);
+static int     t_timeval(void);
+static int     t_bintime(void);
+static int     t_cmsg_len(void);
+static int     t_peercred(void);
 
 struct test_func {
-       int     (*func)(void);  /* Pointer to function. */
-       const char *desc;       /* Test description.    */
-};
-
-static struct test_func test_stream_tbl[] = {
-       { NULL,                 " 0: All tests" },
-       { t_cmsgcred,           " 1: Sending, receiving cmsgcred" },
-       { t_sockcred_stream1,   " 2: Receiving sockcred (listening socket has 
LOCAL_CREDS)" },
-       { t_sockcred_stream2,   " 3: Receiving sockcred (accepted socket has 
LOCAL_CREDS)" },
-       { t_cmsgcred_sockcred,  " 4: Sending cmsgcred, receiving sockcred" },
-       { t_timestamp,          " 5: Sending, receiving timestamp" },
-       { NULL, NULL }
+       int             (*func)(void);
+       const char      *desc;
 };
 
-static struct test_func test_dgram_tbl[] = {
-       { NULL,                 " 0: All tests" },
-       { t_cmsgcred,           " 1: Sending, receiving cmsgcred" },
-       { t_sockcred_dgram,     " 2: Receiving sockcred" },
-       { t_cmsgcred_sockcred,  " 3: Sending cmsgcred, receiving sockcred" },
-       { t_timestamp,          " 4: Sending, receiving timestamp" },
-       { NULL, NULL }
+static const struct test_func test_stream_tbl[] = {
+       {
+         .func = NULL,
+         .desc = "All tests"
+       },
+       {
+         .func = t_cmsgcred,
+         .desc = "Sending, receiving cmsgcred"
+       },
+       {
+         .func = t_sockcred_1,
+         .desc = "Receiving sockcred (listening socket)"
+       },
+       {
+         .func = t_sockcred_2,
+         .desc = "Receiving sockcred (accepted socket)"
+       },
+       {
+         .func = t_cmsgcred_sockcred,
+         .desc = "Sending cmsgcred, receiving sockcred"
+       },
+       {
+         .func = t_timeval,
+         .desc = "Sending, receiving timeval"
+       },
+       {
+         .func = t_bintime,
+         .desc = "Sending, receiving bintime"
+       },
+       {
+         .func = t_cmsg_len,
+         .desc = "Check cmsghdr.cmsg_len"
+       },
+       {
+         .func = t_peercred,
+         .desc = "Check LOCAL_PEERCRED socket option"
+       }
 };
 
-#define TEST_STREAM_NO_MAX     (sizeof(test_stream_tbl) / sizeof(struct 
test_func) - 2)
-#define TEST_DGRAM_NO_MAX      (sizeof(test_dgram_tbl) / sizeof(struct 
test_func) - 2)
-
-static const char *myname = "SERVER";  /* "SERVER" or "CLIENT" */
-
-static int     debug = 0;              /* 1, if -d. */
-static int     no_control_data = 0;    /* 1, if -z. */
-
-static u_int   nfailed = 0;            /* Number of failed tests. */
+#define TEST_STREAM_TBL_SIZE \
+       (sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0]))
 
-static int     sock_type;              /* SOCK_STREAM or SOCK_DGRAM */
-static const char *sock_type_str;      /* "SOCK_STREAM" or "SOCK_DGRAN" */
-
-static char    tempdir[] = "/tmp/unix_cmsg.XXXXXXX";
-static char    serv_sock_path[PATH_MAX];
-
-static char    ipc_message[] = "hello";
-
-#define IPC_MESSAGE_SIZE       (sizeof(ipc_message))
-
-static struct sockaddr_un servaddr;    /* Server address. */
-
-static sigjmp_buf env_alrm;
+static const struct test_func test_dgram_tbl[] = {
+       {
+         .func = NULL,
+         .desc = "All tests"
+       },
+       {
+         .func = t_cmsgcred,
+         .desc = "Sending, receiving cmsgcred"
+       },
+       {
+         .func = t_sockcred_2,
+         .desc = "Receiving sockcred"
+       },
+       {
+         .func = t_cmsgcred_sockcred,
+         .desc = "Sending cmsgcred, receiving sockcred"
+       },
+       {
+         .func = t_timeval,
+         .desc = "Sending, receiving timeval"
+       },
+       {
+         .func = t_bintime,
+         .desc = "Sending, receiving bintime"
+       },
+       {
+         .func = t_cmsg_len,
+         .desc = "Check cmsghdr.cmsg_len"
+       }
+};
 
-static uid_t   my_uid;
-static uid_t   my_euid;
-static gid_t   my_gid;
-static gid_t   my_egid;
+#define TEST_DGRAM_TBL_SIZE \
+       (sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0]))
 
-/*
- * my_gids[0] is EGID, next items are supplementary GIDs,
- * my_ngids determines valid items in my_gids array.
- */
-static gid_t   my_gids[NGROUPS_MAX];
-static int     my_ngids;
+static bool    debug = false;
+static bool    server_flag = true;
+static bool    send_data_flag = true;
+static bool    send_array_flag = true; 
+static bool    failed_flag = false;
+
+static int     sock_type;
+static const char *sock_type_str;
+
+static const char *proc_name;
+
+static char    work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX";
+static int     serv_sock_fd;
+static struct sockaddr_un serv_addr_sun;
+
+static struct {
+       char            *buf_send;
+       char            *buf_recv;
+       size_t          buf_size;
+       u_int           msg_num;
+}              ipc_msg;
+
+#define IPC_MSG_NUM_DEF                5
+#define IPC_MSG_NUM_MAX                10
+#define IPC_MSG_SIZE_DEF       7
+#define IPC_MSG_SIZE_MAX       128
+
+static struct {
+       uid_t           uid;
+       uid_t           euid;
+       gid_t           gid;
+       gid_t           egid;
+       gid_t           *gid_arr;
+       int             gid_num;
+}              proc_cred;
+
+static pid_t   client_pid;
+
+#define SYNC_SERVER    0
+#define SYNC_CLIENT    1
+#define SYNC_RECV      0
+#define SYNC_SEND      1
 
-static pid_t   client_pid;             /* PID of forked client. */
+static int     sync_fd[2][2];
 
-#define dbgmsg(x)      do {                    \
-       if (debug)                              \
-              logmsgx x ;                      \
-} while (/* CONSTCOND */0)
+#define LOGMSG_SIZE    128
 
 static void    logmsg(const char *, ...) __printflike(1, 2);
 static void    logmsgx(const char *, ...) __printflike(1, 2);
+static void    dbgmsg(const char *, ...) __printflike(1, 2);
 static void    output(const char *, ...) __printflike(1, 2);
 
-extern char    *__progname;            /* The name of program. */
-
-/*
- * Output the help message (-h switch).
- */
 static void
-usage(int quick)
+usage(bool verbose)
 {
-       const struct test_func *test_func;
+       u_int i;
 
-       fprintf(stderr, "Usage: %s [-dhz] [-t <socktype>] [testno]\n",
-           __progname);
-       if (quick)
+       printf("usage: %s [-dh] [-n num] [-s size] [-t type] "
+           "[-z value] [testno]\n", getprogname());
+       if (!verbose)
                return;
-       fprintf(stderr, "\n Options are:\n\
-  -d\t\t\tOutput debugging information\n\
-  -h\t\t\tOutput this help message and exit\n\
-  -t <socktype>\t\tRun test only for the given socket type:\n\
-\t\t\tstream or dgram\n\
-  -z\t\t\tDo not send real control data if possible\n\n");
-       fprintf(stderr, " Available tests for stream sockets:\n");
-       for (test_func = test_stream_tbl; test_func->desc != NULL; ++test_func)
-               fprintf(stderr, "  %s\n", test_func->desc);
-       fprintf(stderr, "\n Available tests for datagram sockets:\n");
-       for (test_func = test_dgram_tbl; test_func->desc != NULL; ++test_func)
-               fprintf(stderr, "  %s\n", test_func->desc);
+       printf("\n Options are:\n\
+  -d            Output debugging information\n\
+  -h            Output the help message and exit\n\
+  -n num        Number of messages to send\n\
+  -s size       Specify size of data for IPC\n\
+  -t type       Specify socket type (stream, dgram) for tests\n\
+  -z value      Do not send data in a message (bit 0x1), do not send\n\
+                data array associated with a cmsghdr structure (bit 0x2)\n\
+  testno        Run one test by its number (require the -t option)\n\n");
+       printf(" Available tests for stream sockets:\n");
+       for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i)
+               printf("   %u: %s\n", i, test_stream_tbl[i].desc);
+       printf("\n Available tests for datagram sockets:\n");
+       for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i)
+               printf("   %u: %s\n", i, test_dgram_tbl[i].desc);
 }
 
-/*
- * printf-like function for outputting to STDOUT_FILENO.
- */
 static void
 output(const char *format, ...)
 {
-       char buf[128];
+       char buf[LOGMSG_SIZE];
        va_list ap;
 
        va_start(ap, format);
        if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
-               err(EX_SOFTWARE, "output: vsnprintf failed");
+               err(EXIT_FAILURE, "output: vsnprintf failed");
        write(STDOUT_FILENO, buf, strlen(buf));
        va_end(ap);
 }
 
-/*
- * printf-like function for logging, also outputs message for errno.
- */
 static void
 logmsg(const char *format, ...)
 {
-       char buf[128];
+       char buf[LOGMSG_SIZE];
        va_list ap;
        int errno_save;
 
-       errno_save = errno;             /* Save errno. */
-
+       errno_save = errno;
        va_start(ap, format);
        if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
-               err(EX_SOFTWARE, "logmsg: vsnprintf failed");
+               err(EXIT_FAILURE, "logmsg: vsnprintf failed");
        if (errno_save == 0)
-               output("%s: %s\n", myname, buf);
+               output("%s: %s\n", proc_name, buf);
        else
-               output("%s: %s: %s\n", myname, buf, strerror(errno_save));
+               output("%s: %s: %s\n", proc_name, buf, strerror(errno_save));
        va_end(ap);
+       errno = errno_save;
+}
+
+static void
+vlogmsgx(const char *format, va_list ap)
+{
+       char buf[LOGMSG_SIZE];
+
+       if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
+               err(EXIT_FAILURE, "logmsgx: vsnprintf failed");
+       output("%s: %s\n", proc_name, buf);
 
-       errno = errno_save;             /* Restore errno. */
 }
 
-/*
- * printf-like function for logging, do not output message for errno.
- */
 static void
 logmsgx(const char *format, ...)
 {
-       char buf[128];
        va_list ap;
 
        va_start(ap, format);
-       if (vsnprintf(buf, sizeof(buf), format, ap) < 0)
-               err(EX_SOFTWARE, "logmsgx: vsnprintf failed");
-       output("%s: %s\n", myname, buf);
+       vlogmsgx(format, ap);
        va_end(ap);
 }
 
-/*
- * Run tests from testno1 to testno2.
- */
+static void
+dbgmsg(const char *format, ...)
+{
+       va_list ap;
+
+       if (debug) {
+               va_start(ap, format);
+               vlogmsgx(format, ap);
+               va_end(ap);
+       }
+}
+
 static int
-run_tests(u_int testno1, u_int testno2)
+run_tests(int type, u_int testno1)
 {
-       const struct test_func *test_func;
-       u_int i, nfailed1;
+       const struct test_func *tf;
+       u_int i, testno2, failed_num;
 
-       output("Running tests for %s sockets:\n", sock_type_str);
-       test_func = (sock_type == SOCK_STREAM ?
-           test_stream_tbl : test_dgram_tbl) + testno1;
+       sock_type = type;
+       if (type == SOCK_STREAM) {
+               sock_type_str = "SOCK_STREAM";
+               tf = test_stream_tbl;
+               i = TEST_STREAM_TBL_SIZE - 1;
+       } else {
+               sock_type_str = "SOCK_DGRAM";
+               tf = test_dgram_tbl;
+               i = TEST_DGRAM_TBL_SIZE - 1;
+       }
+       if (testno1 == 0) {
+               testno1 = 1;
+               testno2 = i;
+       } else
+               testno2 = testno1;
 
-       nfailed1 = 0;
-       for (i = testno1; i <= testno2; ++test_func, ++i) {
-               output(" %s\n", test_func->desc);
-               switch (test_func->func()) {
+       output("Running tests for %s sockets:\n", sock_type_str);
+       failed_num = 0;
+       for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) {
+               output("  %u: %s\n", i, tf->desc);
+               switch (tf->func()) {
                case -1:
-                       ++nfailed1;
+                       ++failed_num;
                        break;
                case -2:
-                       logmsgx("some system error occurred, exiting");
+                       logmsgx("some system error or timeout occurred");
                        return (-1);
                }
        }
 
-       nfailed += nfailed1;
+       if (failed_num != 0)
+               failed_flag = true;
 
        if (testno1 != testno2) {
-               if (nfailed1 == 0)
-                       output("-- all tests were passed!\n");
+               if (failed_num == 0)
+                       output("-- all tests passed!\n");
                else
-                       output("-- %u test%s failed!\n", nfailed1,
-                           nfailed1 == 1 ? "" : "s");
+                       output("-- %u test%s failed!\n",
+                           failed_num, failed_num == 1 ? "" : "s");
        } else {
-               if (nfailed == 0)
-                       output("-- test was passed!\n");
+               if (failed_num == 0)
+                       output("-- test passed!\n");
                else
                        output("-- test failed!\n");
        }
@@ -284,183 +365,322 @@ run_tests(u_int testno1, u_int testno2)
        return (0);
 }
 
-/* ARGSUSED */
-static void
-sig_alrm(int signo __unused)
+static int
+init(void)
+{
+       struct sigaction sigact;
+       size_t idx;
+       int rv;
+
+       proc_name = "SERVER";
+
+       sigact.sa_handler = SIG_IGN;
+       sigact.sa_flags = 0;
+       sigemptyset(&sigact.sa_mask);
+       if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) {
+               logmsg("init: sigaction");
+               return (-1);
+       }
+
+       if (ipc_msg.buf_size == 0)
+               ipc_msg.buf_send = ipc_msg.buf_recv = NULL;
+       else {
+               ipc_msg.buf_send = malloc(ipc_msg.buf_size);
+               ipc_msg.buf_recv = malloc(ipc_msg.buf_size);
+               if (ipc_msg.buf_send == NULL || ipc_msg.buf_recv == NULL) {
+                       logmsg("init: malloc");
+                       return (-1);
+               }
+               for (idx = 0; idx < ipc_msg.buf_size; ++idx)
+                       ipc_msg.buf_send[idx] = (char)idx;
+       }
+
+       proc_cred.uid = getuid();
+       proc_cred.euid = geteuid();
+       proc_cred.gid = getgid();
+       proc_cred.egid = getegid();
+       proc_cred.gid_num = getgroups(0, (gid_t *)NULL);
+       if (proc_cred.gid_num < 0) {
+               logmsg("init: getgroups");
+               return (-1);
+       }
+       proc_cred.gid_arr = malloc(proc_cred.gid_num *
+           sizeof(*proc_cred.gid_arr));
+       if (proc_cred.gid_arr == NULL) {
+               logmsg("init: malloc");
+               return (-1);
+       }
+       if (getgroups(proc_cred.gid_num, proc_cred.gid_arr) < 0) {
+               logmsg("init: getgroups");
+               return (-1);
+       }
+
+       memset(&serv_addr_sun, 0, sizeof(serv_addr_sun));
+       rv = snprintf(serv_addr_sun.sun_path, sizeof(serv_addr_sun.sun_path),
+           "%s/%s", work_dir, proc_name);
+       if (rv < 0) {
+               logmsg("init: snprintf");
+               return (-1);
+       }
+       if ((size_t)rv >= sizeof(serv_addr_sun.sun_path)) {
+               logmsgx("init: not enough space for socket pathname");
+               return (-1);
+       }
+       serv_addr_sun.sun_family = PF_LOCAL;
+       serv_addr_sun.sun_len = SUN_LEN(&serv_addr_sun);
+
+       return (0);
+}
+
+static int
+client_fork(void)
 {
-       siglongjmp(env_alrm, 1);
+       int fd1, fd2;
+
+       if (pipe(sync_fd[SYNC_SERVER]) < 0 ||
+           pipe(sync_fd[SYNC_CLIENT]) < 0) {
+               logmsg("client_fork: pipe");
+               return (-1);
+       }
+       client_pid = fork();
+       if (client_pid == (pid_t)-1) {
+               logmsg("client_fork: fork");
+               return (-1);
+       }
+       if (client_pid == 0) {
+               proc_name = "CLIENT";
+               server_flag = false;
+               fd1 = sync_fd[SYNC_SERVER][SYNC_RECV];
+               fd2 = sync_fd[SYNC_CLIENT][SYNC_SEND];
+       } else {
+               fd1 = sync_fd[SYNC_SERVER][SYNC_SEND];
+               fd2 = sync_fd[SYNC_CLIENT][SYNC_RECV];
+       }
+       if (close(fd1) < 0 || close(fd2) < 0) {
+               logmsg("client_fork: close");
+               return (-1);
+       }
+       return (client_pid != 0);
 }
 
-/*
- * Initialize signals handlers.
- */
 static void
-sig_init(void)
+client_exit(int rv)
+{
+       if (close(sync_fd[SYNC_SERVER][SYNC_SEND]) < 0 ||
+           close(sync_fd[SYNC_CLIENT][SYNC_RECV]) < 0) {
+               logmsg("client_exit: close");
+               rv = -1;
+       }
+       rv = rv == 0 ? EXIT_SUCCESS : -rv;
+       dbgmsg("exit: code %d", rv);
+       _exit(rv);
+}
+
+static int
+client_wait(void)
 {
-       struct sigaction sa;
+       int status;
+       pid_t pid;
 
-       sa.sa_handler = SIG_IGN;
-       sigemptyset(&sa.sa_mask);
-       sa.sa_flags = 0;
-       if (sigaction(SIGPIPE, &sa, (struct sigaction *)NULL) < 0) 
-               err(EX_OSERR, "sigaction(SIGPIPE)");
-
-       sa.sa_handler = sig_alrm;
-       if (sigaction(SIGALRM, &sa, (struct sigaction *)NULL) < 0)
-               err(EX_OSERR, "sigaction(SIGALRM)");
+       dbgmsg("waiting for client");
+
+       if (close(sync_fd[SYNC_SERVER][SYNC_RECV]) < 0 ||
+           close(sync_fd[SYNC_CLIENT][SYNC_SEND]) < 0) {
+               logmsg("client_wait: close");
+               return (-1);
+       }
+
+       pid = waitpid(client_pid, &status, 0);
+       if (pid == (pid_t)-1) {
+               logmsg("client_wait: waitpid");
+               return (-1);
+       }
+
+       if (WIFEXITED(status)) {
+               if (WEXITSTATUS(status) != EXIT_SUCCESS) {
+                       logmsgx("client exit status is %d",
+                           WEXITSTATUS(status));
+                       return (-WEXITSTATUS(status));
+               }
+       } else {
+               if (WIFSIGNALED(status))
+                       logmsgx("abnormal termination of client, signal %d%s",
+                           WTERMSIG(status), WCOREDUMP(status) ?
+                           " (core file generated)" : "");
+               else
+                       logmsgx("termination of client, unknown status");
+               return (-1);
+       }
+
+       return (0);
 }
 
 int
 main(int argc, char *argv[])
 {
        const char *errstr;
-       int opt, dgramflag, streamflag;
-       u_int testno1, testno2;
-
-       dgramflag = streamflag = 0;
-       while ((opt = getopt(argc, argv, "dht:z")) != -1)
+       u_int testno, zvalue;
+       int opt, rv;
+       bool dgram_flag, stream_flag;
+
+       ipc_msg.buf_size = IPC_MSG_SIZE_DEF;
+       ipc_msg.msg_num = IPC_MSG_NUM_DEF;
+       dgram_flag = stream_flag = false;
+       while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1)
                switch (opt) {
                case 'd':
-                       debug = 1;
+                       debug = true;
                        break;
                case 'h':
-                       usage(0);
-                       return (EX_OK);
+                       usage(true);
+                       return (EXIT_SUCCESS);
+               case 'n':
+                       ipc_msg.msg_num = strtonum(optarg, 1,
+                           IPC_MSG_NUM_MAX, &errstr);
+                       if (errstr != NULL)
+                               errx(EXIT_FAILURE, "option -n: number is %s",
+                                   errstr);
+                       break;
+               case 's':
+                       ipc_msg.buf_size = strtonum(optarg, 0,
+                           IPC_MSG_SIZE_MAX, &errstr);
+                       if (errstr != NULL)
+                               errx(EXIT_FAILURE, "option -s: number is %s",
+                                   errstr);
+                       break;
                case 't':
                        if (strcmp(optarg, "stream") == 0)
-                               streamflag = 1;
+                               stream_flag = true;
                        else if (strcmp(optarg, "dgram") == 0)
-                               dgramflag = 1;
+                               dgram_flag = true;
                        else
-                               errx(EX_USAGE, "wrong socket type in -t 
option");
+                               errx(EXIT_FAILURE, "option -t: "
+                                   "wrong socket type");
                        break;
                case 'z':
-                       no_control_data = 1;
+                       zvalue = strtonum(optarg, 0, 3, &errstr);
+                       if (errstr != NULL)
+                               errx(EXIT_FAILURE, "option -z: number is %s",
+                                   errstr);
+                       if (zvalue & 0x1)
+                               send_data_flag = false;
+                       if (zvalue & 0x2)
+                               send_array_flag = false;
                        break;
-               case '?':
                default:
-                       usage(1);
-                       return (EX_USAGE);
+                       usage(false);
+                       return (EXIT_FAILURE);
                }
 
        if (optind < argc) {
                if (optind + 1 != argc)
-                       errx(EX_USAGE, "too many arguments");
-               testno1 = strtonum(argv[optind], 0, UINT_MAX, &errstr);
+                       errx(EXIT_FAILURE, "too many arguments");
+               testno = strtonum(argv[optind], 0, UINT_MAX, &errstr);
                if (errstr != NULL)
-                       errx(EX_USAGE, "wrong test number: %s", errstr);
+                       errx(EXIT_FAILURE, "test number is %s", errstr);
+               if (stream_flag && testno >= TEST_STREAM_TBL_SIZE)
+                       errx(EXIT_FAILURE, "given test %u for stream "
+                           "sockets does not exist", testno);
+               if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE)

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-stable-9
To unsubscribe, send any mail to "[email protected]"

Reply via email to