159498Swollman/*
259498Swollman * Test the POSIX shared-memory API.
3228975Suqs * Dedicated to the public domain by Garrett A. Wollman, 2000.
459498Swollman * $FreeBSD$
559498Swollman */
659498Swollman
759498Swollman#include <sys/types.h>
859498Swollman#include <sys/mman.h>
959498Swollman#include <sys/wait.h>
1059498Swollman
1159498Swollman#include <err.h>
1259498Swollman#include <errno.h>
1359498Swollman#include <fcntl.h>
1459498Swollman#include <signal.h>
1559498Swollman#include <stdio.h>
1659498Swollman#include <stdlib.h>
1759498Swollman#include <string.h>
1859498Swollman#include <unistd.h>
1959498Swollman
2059498Swollman/*
2159498Swollman * Signal handler which does nothing.
2259498Swollman */
2359498Swollmanstatic void
24254604Skibignoreit(int sig __unused)
2559498Swollman{
2659498Swollman	;
2759498Swollman}
2859498Swollman
2959498Swollmanint
3059498Swollmanmain(int argc, char **argv)
3159498Swollman{
32254604Skib	char buf[1024], *cp, c;
33254604Skib	int error, desc, rv;
3459498Swollman	long scval;
3559498Swollman	sigset_t ss;
3659498Swollman	struct sigaction sa;
3759498Swollman	void *region;
38254604Skib	size_t i, psize;
3959498Swollman
4059498Swollman#ifndef _POSIX_SHARED_MEMORY_OBJECTS
4159498Swollman	printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n");
4259498Swollman#else
4359498Swollman	printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n",
4459498Swollman	       (long)_POSIX_SHARED_MEMORY_OBJECTS - 0);
4559498Swollman	if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1)
4659498Swollman		printf("***Indicates this feature may be unsupported!\n");
4759498Swollman#endif
4859498Swollman	errno = 0;
4959498Swollman	scval = sysconf(_SC_SHARED_MEMORY_OBJECTS);
5059498Swollman	if (scval == -1 && errno != 0) {
5159498Swollman		err(1, "sysconf(_SC_SHARED_MEMORY_OBJECTS)");
5259498Swollman	} else {
5359498Swollman		printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n",
5459498Swollman		       scval);
5559498Swollman		if (scval == -1)
5659498Swollman			printf("***Indicates this feature is unsupported!\n");
5759498Swollman	}
5859498Swollman
5959498Swollman	errno = 0;
6059498Swollman	scval = sysconf(_SC_PAGESIZE);
6159498Swollman	if (scval == -1 && errno != 0) {
6259498Swollman		err(1, "sysconf(_SC_PAGESIZE)");
6359498Swollman	} else if (scval <= 0 || (size_t)psize != psize) {
6459498Swollman		warnx("bogus return from sysconf(_SC_PAGESIZE): %ld",
6559498Swollman		      scval);
6659498Swollman		psize = 4096;
6759498Swollman	} else {
6859498Swollman		printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval);
6959498Swollman		psize = scval;
7059498Swollman	}
7159498Swollman
7259498Swollman	argc--, argv++;
7359498Swollman
7459498Swollman	if (*argv) {
7559498Swollman		strncat(buf, *argv, (sizeof buf) - 1);
7659498Swollman		desc = shm_open(buf, O_EXCL | O_CREAT | O_RDWR, 0600);
7759498Swollman	} else {
7859498Swollman		do {
7959498Swollman			/*
8059498Swollman			 * Can't use mkstemp for obvious reasons...
8159498Swollman			 */
8259498Swollman			strcpy(buf, "/tmp/shmtest.XXXXXXXXXXXX");
8359498Swollman			mktemp(buf);
8459498Swollman			desc = shm_open(buf, O_EXCL | O_CREAT | O_RDWR, 0600);
8559498Swollman		} while (desc < 0 && errno == EEXIST);
8659498Swollman	}
8759498Swollman
8859498Swollman	if (desc < 0)
8959498Swollman		err(1, "shm_open");
9059498Swollman
9159498Swollman	if (shm_unlink(buf) < 0)
9259498Swollman		err(1, "shm_unlink");
9359498Swollman
9459498Swollman	if (ftruncate(desc, (off_t)psize) < 0)
9559498Swollman		err(1, "ftruncate");
9659498Swollman
9759498Swollman	region = mmap((void *)0, psize, PROT_READ | PROT_WRITE, MAP_SHARED,
9859498Swollman		      desc, (off_t)0);
9959498Swollman	if (region == MAP_FAILED)
10059498Swollman		err(1, "mmap");
10159498Swollman	memset(region, '\377', psize);
10259498Swollman
10359498Swollman	sa.sa_flags = 0;
10459498Swollman	sa.sa_handler = ignoreit;
10559498Swollman	sigemptyset(&sa.sa_mask);
10659498Swollman	if (sigaction(SIGUSR1, &sa, (struct sigaction *)0) < 0)
10759498Swollman		err(1, "sigaction");
10859498Swollman
10959498Swollman	sigemptyset(&ss);
11059498Swollman	sigaddset(&ss, SIGUSR1);
11159498Swollman	if (sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) < 0)
11259498Swollman		err(1, "sigprocmask");
11359498Swollman
11459498Swollman	rv = fork();
11559498Swollman	if (rv < 0) {
11659498Swollman		err(1, "fork");
11759498Swollman	} else if (rv == 0) {
11859498Swollman		sigemptyset(&ss);
11959498Swollman		sigsuspend(&ss);
12059498Swollman
121254604Skib		for (cp = region; cp < (char *)region + psize; cp++) {
12259498Swollman			if (*cp != '\151')
12359498Swollman				_exit(1);
124254604Skib		}
125254604Skib		if (lseek(desc, 0, SEEK_SET) == -1)
126254604Skib			_exit(1);
127254604Skib		for (i = 0; i < psize; i++) {
128254604Skib			error = read(desc, &c, 1);
129254604Skib			if (c != '\151')
130254604Skib				_exit(1);
131254604Skib		}
13259498Swollman		_exit(0);
13359498Swollman	} else {
13459498Swollman		int status;
13559498Swollman
136254604Skib		memset(region, '\151', psize - 2);
137254604Skib		error = pwrite(desc, region, 2, psize - 2);
138254604Skib		if (error != 2) {
139254604Skib			if (error >= 0)
140254604Skib				errx(1, "short write %d", error);
141254604Skib			else
142254604Skib				err(1, "shmfd write");
143254604Skib		}
14459498Swollman		kill(rv, SIGUSR1);
14559498Swollman		waitpid(rv, &status, 0);
14659498Swollman
14759498Swollman		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
14859498Swollman			printf("Functionality test successful\n");
14959498Swollman			exit(0);
15059498Swollman		} else if (WIFEXITED(status)) {
15159498Swollman			printf("Child process exited with status %d\n",
15259498Swollman			       WEXITSTATUS(status));
15359498Swollman		} else {
15459498Swollman			printf("Child process terminated with %s\n",
15559498Swollman			       strsignal(WTERMSIG(status)));
15659498Swollman		}
15759498Swollman	}
15859498Swollman	exit(1);
15959498Swollman}
160