1/*
2 * Test the POSIX shared-memory API.
3 * Dedicated to the public domain by Garrett A. Wollman, 2000.
4 * $FreeBSD: releng/10.2/tools/test/posixshm/shm_test.c 254604 2013-08-21 17:47:11Z kib $
5 */
6
7#include <sys/types.h>
8#include <sys/mman.h>
9#include <sys/wait.h>
10
11#include <err.h>
12#include <errno.h>
13#include <fcntl.h>
14#include <signal.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <unistd.h>
19
20/*
21 * Signal handler which does nothing.
22 */
23static void
24ignoreit(int sig __unused)
25{
26	;
27}
28
29int
30main(int argc, char **argv)
31{
32	char buf[1024], *cp, c;
33	int error, desc, rv;
34	long scval;
35	sigset_t ss;
36	struct sigaction sa;
37	void *region;
38	size_t i, psize;
39
40#ifndef _POSIX_SHARED_MEMORY_OBJECTS
41	printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n");
42#else
43	printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n",
44	       (long)_POSIX_SHARED_MEMORY_OBJECTS - 0);
45	if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1)
46		printf("***Indicates this feature may be unsupported!\n");
47#endif
48	errno = 0;
49	scval = sysconf(_SC_SHARED_MEMORY_OBJECTS);
50	if (scval == -1 && errno != 0) {
51		err(1, "sysconf(_SC_SHARED_MEMORY_OBJECTS)");
52	} else {
53		printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n",
54		       scval);
55		if (scval == -1)
56			printf("***Indicates this feature is unsupported!\n");
57	}
58
59	errno = 0;
60	scval = sysconf(_SC_PAGESIZE);
61	if (scval == -1 && errno != 0) {
62		err(1, "sysconf(_SC_PAGESIZE)");
63	} else if (scval <= 0 || (size_t)psize != psize) {
64		warnx("bogus return from sysconf(_SC_PAGESIZE): %ld",
65		      scval);
66		psize = 4096;
67	} else {
68		printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval);
69		psize = scval;
70	}
71
72	argc--, argv++;
73
74	if (*argv) {
75		strncat(buf, *argv, (sizeof buf) - 1);
76		desc = shm_open(buf, O_EXCL | O_CREAT | O_RDWR, 0600);
77	} else {
78		do {
79			/*
80			 * Can't use mkstemp for obvious reasons...
81			 */
82			strcpy(buf, "/tmp/shmtest.XXXXXXXXXXXX");
83			mktemp(buf);
84			desc = shm_open(buf, O_EXCL | O_CREAT | O_RDWR, 0600);
85		} while (desc < 0 && errno == EEXIST);
86	}
87
88	if (desc < 0)
89		err(1, "shm_open");
90
91	if (shm_unlink(buf) < 0)
92		err(1, "shm_unlink");
93
94	if (ftruncate(desc, (off_t)psize) < 0)
95		err(1, "ftruncate");
96
97	region = mmap((void *)0, psize, PROT_READ | PROT_WRITE, MAP_SHARED,
98		      desc, (off_t)0);
99	if (region == MAP_FAILED)
100		err(1, "mmap");
101	memset(region, '\377', psize);
102
103	sa.sa_flags = 0;
104	sa.sa_handler = ignoreit;
105	sigemptyset(&sa.sa_mask);
106	if (sigaction(SIGUSR1, &sa, (struct sigaction *)0) < 0)
107		err(1, "sigaction");
108
109	sigemptyset(&ss);
110	sigaddset(&ss, SIGUSR1);
111	if (sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) < 0)
112		err(1, "sigprocmask");
113
114	rv = fork();
115	if (rv < 0) {
116		err(1, "fork");
117	} else if (rv == 0) {
118		sigemptyset(&ss);
119		sigsuspend(&ss);
120
121		for (cp = region; cp < (char *)region + psize; cp++) {
122			if (*cp != '\151')
123				_exit(1);
124		}
125		if (lseek(desc, 0, SEEK_SET) == -1)
126			_exit(1);
127		for (i = 0; i < psize; i++) {
128			error = read(desc, &c, 1);
129			if (c != '\151')
130				_exit(1);
131		}
132		_exit(0);
133	} else {
134		int status;
135
136		memset(region, '\151', psize - 2);
137		error = pwrite(desc, region, 2, psize - 2);
138		if (error != 2) {
139			if (error >= 0)
140				errx(1, "short write %d", error);
141			else
142				err(1, "shmfd write");
143		}
144		kill(rv, SIGUSR1);
145		waitpid(rv, &status, 0);
146
147		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
148			printf("Functionality test successful\n");
149			exit(0);
150		} else if (WIFEXITED(status)) {
151			printf("Child process exited with status %d\n",
152			       WEXITSTATUS(status));
153		} else {
154			printf("Child process terminated with %s\n",
155			       strsignal(WTERMSIG(status)));
156		}
157	}
158	exit(1);
159}
160