xref: /freebsd-src/tools/regression/sockets/unix_cmsg/unix_cmsg.c (revision 6bfca4dcab07dad45a805879d954876b353c0810)
15368db27SMaxim Konovalov /*-
25368db27SMaxim Konovalov  * Copyright (c) 2005 Andrey Simonenko
35368db27SMaxim Konovalov  * All rights reserved.
45368db27SMaxim Konovalov  *
55368db27SMaxim Konovalov  * Redistribution and use in source and binary forms, with or without
65368db27SMaxim Konovalov  * modification, are permitted provided that the following conditions
75368db27SMaxim Konovalov  * are met:
85368db27SMaxim Konovalov  * 1. Redistributions of source code must retain the above copyright
95368db27SMaxim Konovalov  *    notice, this list of conditions and the following disclaimer.
105368db27SMaxim Konovalov  * 2. Redistributions in binary form must reproduce the above copyright
115368db27SMaxim Konovalov  *    notice, this list of conditions and the following disclaimer in the
125368db27SMaxim Konovalov  *    documentation and/or other materials provided with the distribution.
135368db27SMaxim Konovalov  *
145368db27SMaxim Konovalov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
155368db27SMaxim Konovalov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
165368db27SMaxim Konovalov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
175368db27SMaxim Konovalov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
185368db27SMaxim Konovalov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
195368db27SMaxim Konovalov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
205368db27SMaxim Konovalov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
215368db27SMaxim Konovalov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
225368db27SMaxim Konovalov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
235368db27SMaxim Konovalov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
245368db27SMaxim Konovalov  * SUCH DAMAGE.
255368db27SMaxim Konovalov  */
265368db27SMaxim Konovalov 
271fab62b1SMaxim Sobolev #include <sys/types.h>
281fab62b1SMaxim Sobolev #include <sys/limits.h>
295368db27SMaxim Konovalov #include <sys/socket.h>
305368db27SMaxim Konovalov #include <sys/un.h>
315368db27SMaxim Konovalov 
325368db27SMaxim Konovalov #include <err.h>
335368db27SMaxim Konovalov #include <inttypes.h>
34b5718158SSergey Kandaurov #include <paths.h>
355368db27SMaxim Konovalov #include <signal.h>
365368db27SMaxim Konovalov #include <stdarg.h>
37b5718158SSergey Kandaurov #include <stdbool.h>
385368db27SMaxim Konovalov #include <stdio.h>
395368db27SMaxim Konovalov #include <stdlib.h>
405368db27SMaxim Konovalov #include <string.h>
415368db27SMaxim Konovalov #include <unistd.h>
425368db27SMaxim Konovalov 
431fab62b1SMaxim Sobolev #include "uc_common.h"
441fab62b1SMaxim Sobolev #include "t_cmsgcred.h"
451fab62b1SMaxim Sobolev #include "t_bintime.h"
461fab62b1SMaxim Sobolev #include "t_generic.h"
471fab62b1SMaxim Sobolev #include "t_peercred.h"
481fab62b1SMaxim Sobolev #include "t_timeval.h"
491fab62b1SMaxim Sobolev #include "t_sockcred.h"
501fab62b1SMaxim Sobolev #include "t_cmsgcred_sockcred.h"
511fab62b1SMaxim Sobolev #include "t_cmsg_len.h"
52*339efd75SMaxim Sobolev #include "t_timespec_real.h"
53*339efd75SMaxim Sobolev #include "t_timespec_mono.h"
541fab62b1SMaxim Sobolev 
555368db27SMaxim Konovalov /*
565368db27SMaxim Konovalov  * There are tables with tests descriptions and pointers to test
575368db27SMaxim Konovalov  * functions.  Each t_*() function returns 0 if its test passed,
58b5718158SSergey Kandaurov  * -1 if its test failed, -2 if some system error occurred.
59b5718158SSergey Kandaurov  * If a test function returns -2, then a program exits.
605368db27SMaxim Konovalov  *
61b5718158SSergey Kandaurov  * If a test function forks a client process, then it waits for its
62b5718158SSergey Kandaurov  * termination.  If a return code of a client process is not equal
63b5718158SSergey Kandaurov  * to zero, or if a client process was terminated by a signal, then
64b5718158SSergey Kandaurov  * a test function returns -1 or -2 depending on exit status of
65b5718158SSergey Kandaurov  * a client process.
665368db27SMaxim Konovalov  *
67b5718158SSergey Kandaurov  * Each function which can block, is run under TIMEOUT.  If timeout
68b5718158SSergey Kandaurov  * occurs, then a test function returns -2 or a client process exits
69b5718158SSergey Kandaurov  * with a non-zero return code.
705368db27SMaxim Konovalov  */
715368db27SMaxim Konovalov 
725368db27SMaxim Konovalov struct test_func {
73b5718158SSergey Kandaurov 	int		(*func)(void);
74b5718158SSergey Kandaurov 	const char	*desc;
755368db27SMaxim Konovalov };
765368db27SMaxim Konovalov 
77b5718158SSergey Kandaurov static const struct test_func test_stream_tbl[] = {
78b5718158SSergey Kandaurov 	{
79b5718158SSergey Kandaurov 	  .func = NULL,
80b5718158SSergey Kandaurov 	  .desc = "All tests"
81b5718158SSergey Kandaurov 	},
82b5718158SSergey Kandaurov 	{
83b5718158SSergey Kandaurov 	  .func = t_cmsgcred,
84b5718158SSergey Kandaurov 	  .desc = "Sending, receiving cmsgcred"
85b5718158SSergey Kandaurov 	},
86b5718158SSergey Kandaurov 	{
87b5718158SSergey Kandaurov 	  .func = t_sockcred_1,
88b5718158SSergey Kandaurov 	  .desc = "Receiving sockcred (listening socket)"
89b5718158SSergey Kandaurov 	},
90b5718158SSergey Kandaurov 	{
91b5718158SSergey Kandaurov 	  .func = t_sockcred_2,
92b5718158SSergey Kandaurov 	  .desc = "Receiving sockcred (accepted socket)"
93b5718158SSergey Kandaurov 	},
94b5718158SSergey Kandaurov 	{
95b5718158SSergey Kandaurov 	  .func = t_cmsgcred_sockcred,
96b5718158SSergey Kandaurov 	  .desc = "Sending cmsgcred, receiving sockcred"
97b5718158SSergey Kandaurov 	},
98b5718158SSergey Kandaurov 	{
99b5718158SSergey Kandaurov 	  .func = t_timeval,
100b5718158SSergey Kandaurov 	  .desc = "Sending, receiving timeval"
101b5718158SSergey Kandaurov 	},
102b5718158SSergey Kandaurov 	{
103b5718158SSergey Kandaurov 	  .func = t_bintime,
104b5718158SSergey Kandaurov 	  .desc = "Sending, receiving bintime"
105b5718158SSergey Kandaurov 	},
1061fab62b1SMaxim Sobolev /*
1071fab62b1SMaxim Sobolev  * The testcase fails on 64-bit architectures (amd64), but passes on 32-bit
1081fab62b1SMaxim Sobolev  * architectures (i386); see bug 206543
1091fab62b1SMaxim Sobolev  */
1100d6796edSEnji Cooper #ifndef __LP64__
111b5718158SSergey Kandaurov 	{
112b5718158SSergey Kandaurov 	  .func = t_cmsg_len,
113b5718158SSergey Kandaurov 	  .desc = "Check cmsghdr.cmsg_len"
114b5718158SSergey Kandaurov 	},
1150d6796edSEnji Cooper #endif
116b5718158SSergey Kandaurov 	{
117b5718158SSergey Kandaurov 	  .func = t_peercred,
118b5718158SSergey Kandaurov 	  .desc = "Check LOCAL_PEERCRED socket option"
119*339efd75SMaxim Sobolev 	},
120*339efd75SMaxim Sobolev #if defined(SCM_REALTIME)
121*339efd75SMaxim Sobolev 	{
122*339efd75SMaxim Sobolev 	  .func = t_timespec_real,
123*339efd75SMaxim Sobolev 	  .desc = "Sending, receiving realtime"
124*339efd75SMaxim Sobolev 	},
125*339efd75SMaxim Sobolev #endif
126*339efd75SMaxim Sobolev #if defined(SCM_MONOTONIC)
127*339efd75SMaxim Sobolev 	{
128*339efd75SMaxim Sobolev 	  .func = t_timespec_mono,
129*339efd75SMaxim Sobolev 	  .desc = "Sending, receiving monotonic time (uptime)"
130b5718158SSergey Kandaurov 	}
131*339efd75SMaxim Sobolev #endif
1325368db27SMaxim Konovalov };
1335368db27SMaxim Konovalov 
134b5718158SSergey Kandaurov #define TEST_STREAM_TBL_SIZE \
135b5718158SSergey Kandaurov 	(sizeof(test_stream_tbl) / sizeof(test_stream_tbl[0]))
136b5718158SSergey Kandaurov 
137b5718158SSergey Kandaurov static const struct test_func test_dgram_tbl[] = {
138b5718158SSergey Kandaurov 	{
139b5718158SSergey Kandaurov 	  .func = NULL,
140b5718158SSergey Kandaurov 	  .desc = "All tests"
141b5718158SSergey Kandaurov 	},
142b5718158SSergey Kandaurov 	{
143b5718158SSergey Kandaurov 	  .func = t_cmsgcred,
144b5718158SSergey Kandaurov 	  .desc = "Sending, receiving cmsgcred"
145b5718158SSergey Kandaurov 	},
146b5718158SSergey Kandaurov 	{
147b5718158SSergey Kandaurov 	  .func = t_sockcred_2,
148b5718158SSergey Kandaurov 	  .desc = "Receiving sockcred"
149b5718158SSergey Kandaurov 	},
150b5718158SSergey Kandaurov 	{
151b5718158SSergey Kandaurov 	  .func = t_cmsgcred_sockcred,
152b5718158SSergey Kandaurov 	  .desc = "Sending cmsgcred, receiving sockcred"
153b5718158SSergey Kandaurov 	},
154b5718158SSergey Kandaurov 	{
155b5718158SSergey Kandaurov 	  .func = t_timeval,
156b5718158SSergey Kandaurov 	  .desc = "Sending, receiving timeval"
157b5718158SSergey Kandaurov 	},
158b5718158SSergey Kandaurov 	{
159b5718158SSergey Kandaurov 	  .func = t_bintime,
160b5718158SSergey Kandaurov 	  .desc = "Sending, receiving bintime"
161b5718158SSergey Kandaurov 	},
1620d6796edSEnji Cooper #ifndef __LP64__
163b5718158SSergey Kandaurov 	{
164b5718158SSergey Kandaurov 	  .func = t_cmsg_len,
165b5718158SSergey Kandaurov 	  .desc = "Check cmsghdr.cmsg_len"
166*339efd75SMaxim Sobolev 	},
167*339efd75SMaxim Sobolev #endif
168*339efd75SMaxim Sobolev #if defined(SCM_REALTIME)
169*339efd75SMaxim Sobolev 	{
170*339efd75SMaxim Sobolev 	  .func = t_timespec_real,
171*339efd75SMaxim Sobolev 	  .desc = "Sending, receiving realtime"
172*339efd75SMaxim Sobolev 	},
173*339efd75SMaxim Sobolev #endif
174*339efd75SMaxim Sobolev #if defined(SCM_MONOTONIC)
175*339efd75SMaxim Sobolev 	{
176*339efd75SMaxim Sobolev 	  .func = t_timespec_mono,
177*339efd75SMaxim Sobolev 	  .desc = "Sending, receiving monotonic time (uptime)"
178b5718158SSergey Kandaurov 	}
1790d6796edSEnji Cooper #endif
1805368db27SMaxim Konovalov };
1815368db27SMaxim Konovalov 
182b5718158SSergey Kandaurov #define TEST_DGRAM_TBL_SIZE \
183b5718158SSergey Kandaurov 	(sizeof(test_dgram_tbl) / sizeof(test_dgram_tbl[0]))
1845368db27SMaxim Konovalov 
185b5718158SSergey Kandaurov static bool	failed_flag = false;
1865368db27SMaxim Konovalov 
1871fab62b1SMaxim Sobolev struct uc_cfg uc_cfg;
1885368db27SMaxim Konovalov 
189b5718158SSergey Kandaurov static char	work_dir[] = _PATH_TMP "unix_cmsg.XXXXXXX";
1905368db27SMaxim Konovalov 
191b5718158SSergey Kandaurov #define IPC_MSG_NUM_DEF		5
192b5718158SSergey Kandaurov #define IPC_MSG_NUM_MAX		10
193b5718158SSergey Kandaurov #define IPC_MSG_SIZE_DEF	7
194b5718158SSergey Kandaurov #define IPC_MSG_SIZE_MAX	128
1955368db27SMaxim Konovalov 
1965368db27SMaxim Konovalov static void
usage(bool verbose)197b5718158SSergey Kandaurov usage(bool verbose)
1985368db27SMaxim Konovalov {
199b5718158SSergey Kandaurov 	u_int i;
2005368db27SMaxim Konovalov 
201b5718158SSergey Kandaurov 	printf("usage: %s [-dh] [-n num] [-s size] [-t type] "
202b5718158SSergey Kandaurov 	    "[-z value] [testno]\n", getprogname());
203b5718158SSergey Kandaurov 	if (!verbose)
204fd447da1SMaxim Konovalov 		return;
205b5718158SSergey Kandaurov 	printf("\n Options are:\n\
206b5718158SSergey Kandaurov   -d            Output debugging information\n\
207b5718158SSergey Kandaurov   -h            Output the help message and exit\n\
208b5718158SSergey Kandaurov   -n num        Number of messages to send\n\
209b5718158SSergey Kandaurov   -s size       Specify size of data for IPC\n\
210b5718158SSergey Kandaurov   -t type       Specify socket type (stream, dgram) for tests\n\
211b5718158SSergey Kandaurov   -z value      Do not send data in a message (bit 0x1), do not send\n\
212b5718158SSergey Kandaurov                 data array associated with a cmsghdr structure (bit 0x2)\n\
213b5718158SSergey Kandaurov   testno        Run one test by its number (require the -t option)\n\n");
214b5718158SSergey Kandaurov 	printf(" Available tests for stream sockets:\n");
215b5718158SSergey Kandaurov 	for (i = 0; i < TEST_STREAM_TBL_SIZE; ++i)
216b5718158SSergey Kandaurov 		printf("   %u: %s\n", i, test_stream_tbl[i].desc);
217b5718158SSergey Kandaurov 	printf("\n Available tests for datagram sockets:\n");
218b5718158SSergey Kandaurov 	for (i = 0; i < TEST_DGRAM_TBL_SIZE; ++i)
219b5718158SSergey Kandaurov 		printf("   %u: %s\n", i, test_dgram_tbl[i].desc);
2205368db27SMaxim Konovalov }
2215368db27SMaxim Konovalov 
222b5718158SSergey Kandaurov static int
run_tests(int type,u_int testno1)223b5718158SSergey Kandaurov run_tests(int type, u_int testno1)
224b5718158SSergey Kandaurov {
225b5718158SSergey Kandaurov 	const struct test_func *tf;
226b5718158SSergey Kandaurov 	u_int i, testno2, failed_num;
227b5718158SSergey Kandaurov 
2281fab62b1SMaxim Sobolev 	uc_cfg.sock_type = type;
229b5718158SSergey Kandaurov 	if (type == SOCK_STREAM) {
2301fab62b1SMaxim Sobolev 		uc_cfg.sock_type_str = "SOCK_STREAM";
231b5718158SSergey Kandaurov 		tf = test_stream_tbl;
232b5718158SSergey Kandaurov 		i = TEST_STREAM_TBL_SIZE - 1;
233b5718158SSergey Kandaurov 	} else {
2341fab62b1SMaxim Sobolev 		uc_cfg.sock_type_str = "SOCK_DGRAM";
235b5718158SSergey Kandaurov 		tf = test_dgram_tbl;
236b5718158SSergey Kandaurov 		i = TEST_DGRAM_TBL_SIZE - 1;
237b5718158SSergey Kandaurov 	}
238b5718158SSergey Kandaurov 	if (testno1 == 0) {
239b5718158SSergey Kandaurov 		testno1 = 1;
240b5718158SSergey Kandaurov 		testno2 = i;
241b5718158SSergey Kandaurov 	} else
242b5718158SSergey Kandaurov 		testno2 = testno1;
2435368db27SMaxim Konovalov 
2441fab62b1SMaxim Sobolev 	uc_output("Running tests for %s sockets:\n", uc_cfg.sock_type_str);
245b5718158SSergey Kandaurov 	failed_num = 0;
246b5718158SSergey Kandaurov 	for (i = testno1, tf += testno1; i <= testno2; ++tf, ++i) {
2471fab62b1SMaxim Sobolev 		uc_output("  %u: %s\n", i, tf->desc);
248b5718158SSergey Kandaurov 		switch (tf->func()) {
2495368db27SMaxim Konovalov 		case -1:
250b5718158SSergey Kandaurov 			++failed_num;
2515368db27SMaxim Konovalov 			break;
2525368db27SMaxim Konovalov 		case -2:
2531fab62b1SMaxim Sobolev 			uc_logmsgx("some system error or timeout occurred");
2545368db27SMaxim Konovalov 			return (-1);
2555368db27SMaxim Konovalov 		}
2565368db27SMaxim Konovalov 	}
2575368db27SMaxim Konovalov 
258b5718158SSergey Kandaurov 	if (failed_num != 0)
259b5718158SSergey Kandaurov 		failed_flag = true;
2605368db27SMaxim Konovalov 
2615368db27SMaxim Konovalov 	if (testno1 != testno2) {
262b5718158SSergey Kandaurov 		if (failed_num == 0)
2631fab62b1SMaxim Sobolev 			uc_output("-- all tests passed!\n");
2645368db27SMaxim Konovalov 		else
2651fab62b1SMaxim Sobolev 			uc_output("-- %u test%s failed!\n",
266b5718158SSergey Kandaurov 			    failed_num, failed_num == 1 ? "" : "s");
2675368db27SMaxim Konovalov 	} else {
268b5718158SSergey Kandaurov 		if (failed_num == 0)
2691fab62b1SMaxim Sobolev 			uc_output("-- test passed!\n");
2705368db27SMaxim Konovalov 		else
2711fab62b1SMaxim Sobolev 			uc_output("-- test failed!\n");
2725368db27SMaxim Konovalov 	}
2735368db27SMaxim Konovalov 
2745368db27SMaxim Konovalov 	return (0);
2755368db27SMaxim Konovalov }
2765368db27SMaxim Konovalov 
277b5718158SSergey Kandaurov static int
init(void)278b5718158SSergey Kandaurov init(void)
2795368db27SMaxim Konovalov {
280b5718158SSergey Kandaurov 	struct sigaction sigact;
281b5718158SSergey Kandaurov 	size_t idx;
282b5718158SSergey Kandaurov 	int rv;
283b5718158SSergey Kandaurov 
2841fab62b1SMaxim Sobolev 	uc_cfg.proc_name = "SERVER";
285b5718158SSergey Kandaurov 
286b5718158SSergey Kandaurov 	sigact.sa_handler = SIG_IGN;
287b5718158SSergey Kandaurov 	sigact.sa_flags = 0;
288b5718158SSergey Kandaurov 	sigemptyset(&sigact.sa_mask);
289b5718158SSergey Kandaurov 	if (sigaction(SIGPIPE, &sigact, (struct sigaction *)NULL) < 0) {
2901fab62b1SMaxim Sobolev 		uc_logmsg("init: sigaction");
291b5718158SSergey Kandaurov 		return (-1);
2925368db27SMaxim Konovalov 	}
2935368db27SMaxim Konovalov 
2941fab62b1SMaxim Sobolev 	if (uc_cfg.ipc_msg.buf_size == 0)
2951fab62b1SMaxim Sobolev 		uc_cfg.ipc_msg.buf_send = uc_cfg.ipc_msg.buf_recv = NULL;
296b5718158SSergey Kandaurov 	else {
2971fab62b1SMaxim Sobolev 		uc_cfg.ipc_msg.buf_send = malloc(uc_cfg.ipc_msg.buf_size);
2981fab62b1SMaxim Sobolev 		uc_cfg.ipc_msg.buf_recv = malloc(uc_cfg.ipc_msg.buf_size);
2991fab62b1SMaxim Sobolev 		if (uc_cfg.ipc_msg.buf_send == NULL || uc_cfg.ipc_msg.buf_recv == NULL) {
3001fab62b1SMaxim Sobolev 			uc_logmsg("init: malloc");
301b5718158SSergey Kandaurov 			return (-1);
302b5718158SSergey Kandaurov 		}
3031fab62b1SMaxim Sobolev 		for (idx = 0; idx < uc_cfg.ipc_msg.buf_size; ++idx)
3041fab62b1SMaxim Sobolev 			uc_cfg.ipc_msg.buf_send[idx] = (char)idx;
305b5718158SSergey Kandaurov 	}
306b5718158SSergey Kandaurov 
3071fab62b1SMaxim Sobolev 	uc_cfg.proc_cred.uid = getuid();
3081fab62b1SMaxim Sobolev 	uc_cfg.proc_cred.euid = geteuid();
3091fab62b1SMaxim Sobolev 	uc_cfg.proc_cred.gid = getgid();
3101fab62b1SMaxim Sobolev 	uc_cfg.proc_cred.egid = getegid();
3111fab62b1SMaxim Sobolev 	uc_cfg.proc_cred.gid_num = getgroups(0, (gid_t *)NULL);
3121fab62b1SMaxim Sobolev 	if (uc_cfg.proc_cred.gid_num < 0) {
3131fab62b1SMaxim Sobolev 		uc_logmsg("init: getgroups");
314b5718158SSergey Kandaurov 		return (-1);
315b5718158SSergey Kandaurov 	}
3161fab62b1SMaxim Sobolev 	uc_cfg.proc_cred.gid_arr = malloc(uc_cfg.proc_cred.gid_num *
3171fab62b1SMaxim Sobolev 	    sizeof(*uc_cfg.proc_cred.gid_arr));
3181fab62b1SMaxim Sobolev 	if (uc_cfg.proc_cred.gid_arr == NULL) {
3191fab62b1SMaxim Sobolev 		uc_logmsg("init: malloc");
320b5718158SSergey Kandaurov 		return (-1);
321b5718158SSergey Kandaurov 	}
3221fab62b1SMaxim Sobolev 	if (getgroups(uc_cfg.proc_cred.gid_num, uc_cfg.proc_cred.gid_arr) < 0) {
3231fab62b1SMaxim Sobolev 		uc_logmsg("init: getgroups");
324b5718158SSergey Kandaurov 		return (-1);
325b5718158SSergey Kandaurov 	}
326b5718158SSergey Kandaurov 
3271fab62b1SMaxim Sobolev 	memset(&uc_cfg.serv_addr_sun, 0, sizeof(uc_cfg.serv_addr_sun));
3281fab62b1SMaxim Sobolev 	rv = snprintf(uc_cfg.serv_addr_sun.sun_path, sizeof(uc_cfg.serv_addr_sun.sun_path),
3291fab62b1SMaxim Sobolev 	    "%s/%s", work_dir, uc_cfg.proc_name);
330b5718158SSergey Kandaurov 	if (rv < 0) {
3311fab62b1SMaxim Sobolev 		uc_logmsg("init: snprintf");
332b5718158SSergey Kandaurov 		return (-1);
333b5718158SSergey Kandaurov 	}
3341fab62b1SMaxim Sobolev 	if ((size_t)rv >= sizeof(uc_cfg.serv_addr_sun.sun_path)) {
3351fab62b1SMaxim Sobolev 		uc_logmsgx("init: not enough space for socket pathname");
336b5718158SSergey Kandaurov 		return (-1);
337b5718158SSergey Kandaurov 	}
3381fab62b1SMaxim Sobolev 	uc_cfg.serv_addr_sun.sun_family = PF_LOCAL;
3391fab62b1SMaxim Sobolev 	uc_cfg.serv_addr_sun.sun_len = SUN_LEN(&uc_cfg.serv_addr_sun);
340b5718158SSergey Kandaurov 
341b5718158SSergey Kandaurov 	return (0);
3425368db27SMaxim Konovalov }
3435368db27SMaxim Konovalov 
3445368db27SMaxim Konovalov int
main(int argc,char * argv[])3455368db27SMaxim Konovalov main(int argc, char *argv[])
3465368db27SMaxim Konovalov {
3475368db27SMaxim Konovalov 	const char *errstr;
348b5718158SSergey Kandaurov 	u_int testno, zvalue;
349b5718158SSergey Kandaurov 	int opt, rv;
350b5718158SSergey Kandaurov 	bool dgram_flag, stream_flag;
3515368db27SMaxim Konovalov 
3521fab62b1SMaxim Sobolev 	memset(&uc_cfg, '\0', sizeof(uc_cfg));
3531fab62b1SMaxim Sobolev 	uc_cfg.debug = false;
3541fab62b1SMaxim Sobolev 	uc_cfg.server_flag = true;
3551fab62b1SMaxim Sobolev 	uc_cfg.send_data_flag = true;
3561fab62b1SMaxim Sobolev 	uc_cfg.send_array_flag = true;
3571fab62b1SMaxim Sobolev 	uc_cfg.ipc_msg.buf_size = IPC_MSG_SIZE_DEF;
3581fab62b1SMaxim Sobolev 	uc_cfg.ipc_msg.msg_num = IPC_MSG_NUM_DEF;
359b5718158SSergey Kandaurov 	dgram_flag = stream_flag = false;
360b5718158SSergey Kandaurov 	while ((opt = getopt(argc, argv, "dhn:s:t:z:")) != -1)
3615368db27SMaxim Konovalov 		switch (opt) {
3625368db27SMaxim Konovalov 		case 'd':
3631fab62b1SMaxim Sobolev 			uc_cfg.debug = true;
3645368db27SMaxim Konovalov 			break;
3655368db27SMaxim Konovalov 		case 'h':
366b5718158SSergey Kandaurov 			usage(true);
367b5718158SSergey Kandaurov 			return (EXIT_SUCCESS);
368b5718158SSergey Kandaurov 		case 'n':
3691fab62b1SMaxim Sobolev 			uc_cfg.ipc_msg.msg_num = strtonum(optarg, 1,
370b5718158SSergey Kandaurov 			    IPC_MSG_NUM_MAX, &errstr);
371b5718158SSergey Kandaurov 			if (errstr != NULL)
372b5718158SSergey Kandaurov 				errx(EXIT_FAILURE, "option -n: number is %s",
373b5718158SSergey Kandaurov 				    errstr);
374b5718158SSergey Kandaurov 			break;
375b5718158SSergey Kandaurov 		case 's':
3761fab62b1SMaxim Sobolev 			uc_cfg.ipc_msg.buf_size = strtonum(optarg, 0,
377b5718158SSergey Kandaurov 			    IPC_MSG_SIZE_MAX, &errstr);
378b5718158SSergey Kandaurov 			if (errstr != NULL)
379b5718158SSergey Kandaurov 				errx(EXIT_FAILURE, "option -s: number is %s",
380b5718158SSergey Kandaurov 				    errstr);
381b5718158SSergey Kandaurov 			break;
3825368db27SMaxim Konovalov 		case 't':
3835368db27SMaxim Konovalov 			if (strcmp(optarg, "stream") == 0)
384b5718158SSergey Kandaurov 				stream_flag = true;
3855368db27SMaxim Konovalov 			else if (strcmp(optarg, "dgram") == 0)
386b5718158SSergey Kandaurov 				dgram_flag = true;
3875368db27SMaxim Konovalov 			else
388b5718158SSergey Kandaurov 				errx(EXIT_FAILURE, "option -t: "
389b5718158SSergey Kandaurov 				    "wrong socket type");
3905368db27SMaxim Konovalov 			break;
3915368db27SMaxim Konovalov 		case 'z':
392b5718158SSergey Kandaurov 			zvalue = strtonum(optarg, 0, 3, &errstr);
393b5718158SSergey Kandaurov 			if (errstr != NULL)
394b5718158SSergey Kandaurov 				errx(EXIT_FAILURE, "option -z: number is %s",
395b5718158SSergey Kandaurov 				    errstr);
396b5718158SSergey Kandaurov 			if (zvalue & 0x1)
3971fab62b1SMaxim Sobolev 				uc_cfg.send_data_flag = false;
398b5718158SSergey Kandaurov 			if (zvalue & 0x2)
3991fab62b1SMaxim Sobolev 				uc_cfg.send_array_flag = false;
4005368db27SMaxim Konovalov 			break;
4015368db27SMaxim Konovalov 		default:
402b5718158SSergey Kandaurov 			usage(false);
403b5718158SSergey Kandaurov 			return (EXIT_FAILURE);
4045368db27SMaxim Konovalov 		}
4055368db27SMaxim Konovalov 
4065368db27SMaxim Konovalov 	if (optind < argc) {
4075368db27SMaxim Konovalov 		if (optind + 1 != argc)
408b5718158SSergey Kandaurov 			errx(EXIT_FAILURE, "too many arguments");
409b5718158SSergey Kandaurov 		testno = strtonum(argv[optind], 0, UINT_MAX, &errstr);
4105368db27SMaxim Konovalov 		if (errstr != NULL)
411b5718158SSergey Kandaurov 			errx(EXIT_FAILURE, "test number is %s", errstr);
412b5718158SSergey Kandaurov 		if (stream_flag && testno >= TEST_STREAM_TBL_SIZE)
413b5718158SSergey Kandaurov 			errx(EXIT_FAILURE, "given test %u for stream "
414b5718158SSergey Kandaurov 			    "sockets does not exist", testno);
415b5718158SSergey Kandaurov 		if (dgram_flag && testno >= TEST_DGRAM_TBL_SIZE)
416b5718158SSergey Kandaurov 			errx(EXIT_FAILURE, "given test %u for datagram "
417b5718158SSergey Kandaurov 			    "sockets does not exist", testno);
4185368db27SMaxim Konovalov 	} else
419b5718158SSergey Kandaurov 		testno = 0;
4205368db27SMaxim Konovalov 
421b5718158SSergey Kandaurov 	if (!dgram_flag && !stream_flag) {
422b5718158SSergey Kandaurov 		if (testno != 0)
423b5718158SSergey Kandaurov 			errx(EXIT_FAILURE, "particular test number "
424b5718158SSergey Kandaurov 			    "can be used with the -t option only");
425b5718158SSergey Kandaurov 		dgram_flag = stream_flag = true;
4265368db27SMaxim Konovalov 	}
4275368db27SMaxim Konovalov 
428b5718158SSergey Kandaurov 	if (mkdtemp(work_dir) == NULL)
429b5718158SSergey Kandaurov 		err(EXIT_FAILURE, "mkdtemp(%s)", work_dir);
430b5718158SSergey Kandaurov 
431b5718158SSergey Kandaurov 	rv = EXIT_FAILURE;
432b5718158SSergey Kandaurov 	if (init() < 0)
433b5718158SSergey Kandaurov 		goto done;
434b5718158SSergey Kandaurov 
435b5718158SSergey Kandaurov 	if (stream_flag)
436b5718158SSergey Kandaurov 		if (run_tests(SOCK_STREAM, testno) < 0)
437b5718158SSergey Kandaurov 			goto done;
438b5718158SSergey Kandaurov 	if (dgram_flag)
439b5718158SSergey Kandaurov 		if (run_tests(SOCK_DGRAM, testno) < 0)
440b5718158SSergey Kandaurov 			goto done;
441b5718158SSergey Kandaurov 
442b5718158SSergey Kandaurov 	rv = EXIT_SUCCESS;
443b5718158SSergey Kandaurov done:
444b5718158SSergey Kandaurov 	if (rmdir(work_dir) < 0) {
4451fab62b1SMaxim Sobolev 		uc_logmsg("rmdir(%s)", work_dir);
446b5718158SSergey Kandaurov 		rv = EXIT_FAILURE;
447b5718158SSergey Kandaurov 	}
448b5718158SSergey Kandaurov 	return (failed_flag ? EXIT_FAILURE : rv);
4495368db27SMaxim Konovalov }
450