xref: /openbsd-src/regress/sys/kern/sysvshm/shmtest.c (revision 49a6e16f2c2c8e509184b1f777366d1a6f337e1c)
1c8c5f421Sart /*	$NetBSD: shmtest.c,v 1.2 2001/02/19 22:44:41 cgd Exp $	*/
2c8c5f421Sart 
3c8c5f421Sart /*-
4c8c5f421Sart  * Copyright (c) 1999 The NetBSD Foundation, Inc.
5c8c5f421Sart  * All rights reserved.
6c8c5f421Sart  *
7c8c5f421Sart  * This code is derived from software contributed to The NetBSD Foundation
8c8c5f421Sart  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9c8c5f421Sart  * NASA Ames Research Center.
10c8c5f421Sart  *
11c8c5f421Sart  * Redistribution and use in source and binary forms, with or without
12c8c5f421Sart  * modification, are permitted provided that the following conditions
13c8c5f421Sart  * are met:
14c8c5f421Sart  * 1. Redistributions of source code must retain the above copyright
15c8c5f421Sart  *    notice, this list of conditions and the following disclaimer.
16c8c5f421Sart  * 2. Redistributions in binary form must reproduce the above copyright
17c8c5f421Sart  *    notice, this list of conditions and the following disclaimer in the
18c8c5f421Sart  *    documentation and/or other materials provided with the distribution.
19c8c5f421Sart  *
20c8c5f421Sart  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21c8c5f421Sart  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22c8c5f421Sart  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23c8c5f421Sart  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24c8c5f421Sart  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25c8c5f421Sart  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26c8c5f421Sart  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27c8c5f421Sart  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28c8c5f421Sart  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29c8c5f421Sart  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30c8c5f421Sart  * POSSIBILITY OF SUCH DAMAGE.
31c8c5f421Sart  */
32c8c5f421Sart 
33c8c5f421Sart /*
34c8c5f421Sart  * Test the SVID-compatible Shared Memory facility.
35c8c5f421Sart  */
36c8c5f421Sart 
37c8c5f421Sart #include <sys/ipc.h>
38*37ec931bSguenther #include <sys/mman.h>
39c8c5f421Sart #include <sys/shm.h>
40c8c5f421Sart #include <sys/wait.h>
41c8c5f421Sart 
42c8c5f421Sart #include <err.h>
43c8c5f421Sart #include <errno.h>
44c8c5f421Sart #include <signal.h>
45c8c5f421Sart #include <stdio.h>
46c8c5f421Sart #include <stdlib.h>
47c8c5f421Sart #include <string.h>
48c8c5f421Sart #include <time.h>
49c8c5f421Sart #include <unistd.h>
50c8c5f421Sart 
51f3c3a9c6Smillert int	main(int, char *[]);
52f3c3a9c6Smillert void	print_shmid_ds(struct shmid_ds *, mode_t);
53f3c3a9c6Smillert void	sigsys_handler(int);
54f3c3a9c6Smillert void	sigchld_handler(int);
55f3c3a9c6Smillert void	cleanup(void);
56f3c3a9c6Smillert void	receiver(void);
57c8c5f421Sart 
58c8c5f421Sart const char *m_str = "The quick brown fox jumped over the lazy dog.";
59c8c5f421Sart 
60c8c5f421Sart int	sender_shmid = -1;
61c8c5f421Sart pid_t	child_pid;
62c8c5f421Sart 
63c8c5f421Sart key_t	shmkey;
64c8c5f421Sart 
65c8c5f421Sart char keyname[] = "/tmp/msgtestXXXXXXXX";
66c8c5f421Sart 
67c8c5f421Sart int verbose;
68c8c5f421Sart 
69c8c5f421Sart size_t	pgsize;
70c8c5f421Sart 
71c8c5f421Sart int
main(argc,argv)72c8c5f421Sart main(argc, argv)
73c8c5f421Sart 	int argc;
74c8c5f421Sart 	char *argv[];
75c8c5f421Sart {
76c8c5f421Sart 	struct sigaction sa;
77c8c5f421Sart 	struct shmid_ds s_ds;
78c8c5f421Sart 	sigset_t sigmask;
79c8c5f421Sart 	char *shm_buf;
80c8c5f421Sart 	int fd, ch;
81c8c5f421Sart 
82c8c5f421Sart 	if ((fd = mkstemp(keyname)) < 0)
83c8c5f421Sart 		err(1, "mkstemp");
84c8c5f421Sart 
85c8c5f421Sart 	close(fd);
86c8c5f421Sart 
87c8c5f421Sart 	while ((ch = getopt(argc, argv, "v")) != -1) {
88c8c5f421Sart 		switch (ch) {
89c8c5f421Sart 		case 'v':
90c8c5f421Sart 			verbose = 1;
91c8c5f421Sart 			break;
92c8c5f421Sart 		default:
93c8c5f421Sart 			fprintf(stderr, "Usage: shmtest [-v]\n");
94c8c5f421Sart 			exit(1);
95c8c5f421Sart 		}
96c8c5f421Sart 	}
97c8c5f421Sart 
98c8c5f421Sart 	/*
99c8c5f421Sart 	 * Install a SIGSYS handler so that we can exit gracefully if
100c8c5f421Sart 	 * System V Shared Memory support isn't in the kernel.
101c8c5f421Sart 	 */
102c8c5f421Sart 	sa.sa_handler = sigsys_handler;
103c8c5f421Sart 	sigemptyset(&sa.sa_mask);
104c8c5f421Sart 	sa.sa_flags = 0;
105c8c5f421Sart 	if (sigaction(SIGSYS, &sa, NULL) == -1)
106c8c5f421Sart 		err(1, "sigaction SIGSYS");
107c8c5f421Sart 
108c8c5f421Sart 	/*
109c8c5f421Sart 	 * Install and SIGCHLD handler to deal with all possible exit
110c8c5f421Sart 	 * conditions of the receiver.
111c8c5f421Sart 	 */
112c8c5f421Sart 	sa.sa_handler = sigchld_handler;
113c8c5f421Sart 	sigemptyset(&sa.sa_mask);
114c8c5f421Sart 	sa.sa_flags = 0;
115c8c5f421Sart 	if (sigaction(SIGCHLD, &sa, NULL) == -1)
116c8c5f421Sart 		err(1, "sigaction SIGCHLD");
117c8c5f421Sart 
118c8c5f421Sart 	pgsize = sysconf(_SC_PAGESIZE);
119c8c5f421Sart 
120c8c5f421Sart 	shmkey = ftok(argv[1], 4160);
121c8c5f421Sart 
122c8c5f421Sart 	/*
123c8c5f421Sart 	 * Initialize child_pid to ourselves to that the cleanup function
124c8c5f421Sart 	 * works before we create the receiver.
125c8c5f421Sart 	 */
126c8c5f421Sart 	child_pid = getpid();
127c8c5f421Sart 
128c8c5f421Sart 	/*
129c8c5f421Sart 	 * Make sure that when the sender exits, the message queue is
130c8c5f421Sart 	 * removed.
131c8c5f421Sart 	 */
132c8c5f421Sart 	if (atexit(cleanup) == -1)
133c8c5f421Sart 		err(1, "atexit");
134c8c5f421Sart 
135c8c5f421Sart 	if ((sender_shmid = shmget(shmkey, pgsize, IPC_CREAT | 0640)) == -1)
136c8c5f421Sart 		err(1, "shmget");
137c8c5f421Sart 
138c8c5f421Sart 	if (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1)
139c8c5f421Sart 		err(1, "shmctl IPC_STAT");
140c8c5f421Sart 
141c8c5f421Sart 	if (verbose)
142c8c5f421Sart 		print_shmid_ds(&s_ds, 0640);
143c8c5f421Sart 
144c8c5f421Sart 	s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600;
145c8c5f421Sart 
146c8c5f421Sart 	if (shmctl(sender_shmid, IPC_SET, &s_ds) == -1)
147c8c5f421Sart 		err(1, "shmctl IPC_SET");
148c8c5f421Sart 
149c8c5f421Sart 	memset(&s_ds, 0, sizeof(s_ds));
150c8c5f421Sart 
151c8c5f421Sart 	if (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1)
152c8c5f421Sart 		err(1, "shmctl IPC_STAT");
153c8c5f421Sart 
154c8c5f421Sart 	if ((s_ds.shm_perm.mode & 0777) != 0600)
155c8c5f421Sart 		err(1, "IPC_SET of mode didn't hold");
156c8c5f421Sart 
157c8c5f421Sart 	if (verbose)
158c8c5f421Sart 		print_shmid_ds(&s_ds, 0600);
159c8c5f421Sart 
160c8c5f421Sart 	if ((shm_buf = shmat(sender_shmid, NULL, 0)) == (void *) -1)
161c8c5f421Sart 		err(1, "sender: shmat");
162c8c5f421Sart 
163c8c5f421Sart 	/*
164c8c5f421Sart 	 * Write the test pattern into the shared memory buffer.
165c8c5f421Sart 	 */
1664993325bSderaadt 	strlcpy(shm_buf, m_str, pgsize);
167c8c5f421Sart 
168c8c5f421Sart 	switch ((child_pid = fork())) {
169c8c5f421Sart 	case -1:
170c8c5f421Sart 		err(1, "fork");
171c8c5f421Sart 		/* NOTREACHED */
172c8c5f421Sart 
173c8c5f421Sart 	case 0:
174c8c5f421Sart 		receiver();
175c8c5f421Sart 		break;
176c8c5f421Sart 
177c8c5f421Sart 	default:
178c8c5f421Sart 		break;
179c8c5f421Sart 	}
180c8c5f421Sart 
181c8c5f421Sart 	/*
182c8c5f421Sart 	 * Suspend forever; when we get SIGCHLD, the handler will exit.
183c8c5f421Sart 	 */
184c8c5f421Sart 	sigemptyset(&sigmask);
185c8c5f421Sart 	(void) sigsuspend(&sigmask);
186c8c5f421Sart 
187c8c5f421Sart 	/*
188c8c5f421Sart 	 * ...and any other signal is an unexpected error.
189c8c5f421Sart 	 */
190c8c5f421Sart 	errx(1, "sender: received unexpected signal");
191c8c5f421Sart }
192c8c5f421Sart 
193c8c5f421Sart void
sigsys_handler(signo)194c8c5f421Sart sigsys_handler(signo)
195c8c5f421Sart 	int signo;
196c8c5f421Sart {
197c8c5f421Sart 
198c8c5f421Sart 	errx(1, "System V Shared Memory support is not present in the kernel");
199c8c5f421Sart }
200c8c5f421Sart 
201c8c5f421Sart void
sigchld_handler(signo)202c8c5f421Sart sigchld_handler(signo)
203c8c5f421Sart 	int signo;
204c8c5f421Sart {
205c8c5f421Sart 	struct shmid_ds s_ds;
206c8c5f421Sart 	int cstatus;
207c8c5f421Sart 
208c8c5f421Sart 	/*
209c8c5f421Sart 	 * Reap the child; if it exited successfully, then the test passed!
210c8c5f421Sart 	 */
211c8c5f421Sart 	if (waitpid(child_pid, &cstatus, 0) != child_pid)
212c8c5f421Sart 		err(1, "waitpid");
213c8c5f421Sart 
214c8c5f421Sart 	if (WIFEXITED(cstatus) == 0)
215c8c5f421Sart 		errx(1, "receiver exited abnormally");
216c8c5f421Sart 
217c8c5f421Sart 	if (WEXITSTATUS(cstatus) != 0)
218c20d9ad4Sjsyn 		errx(1, "receiver exited with status %d",
219c8c5f421Sart 		    WEXITSTATUS(cstatus));
220c8c5f421Sart 
221c8c5f421Sart 	/*
222c8c5f421Sart 	 * If we get here, the child has exited normally, and thus
223c8c5f421Sart 	 * we should exit normally too.  First, tho, we print out
224c8c5f421Sart 	 * the final stats for the message queue.
225c8c5f421Sart 	 */
226c8c5f421Sart 
227c8c5f421Sart 	if (shmctl(sender_shmid, IPC_STAT, &s_ds) == -1)
228c8c5f421Sart 		err(1, "shmctl IPC_STAT");
229c8c5f421Sart 
230c8c5f421Sart 	if (verbose)
231c8c5f421Sart 		print_shmid_ds(&s_ds, 0600);
232c8c5f421Sart 
233c8c5f421Sart 	exit(0);
234c8c5f421Sart }
235c8c5f421Sart 
236c8c5f421Sart void
cleanup()237c8c5f421Sart cleanup()
238c8c5f421Sart {
239c8c5f421Sart 
240c8c5f421Sart 	/*
241c8c5f421Sart 	 * If we're the sender, and it exists, remove the shared memory area.
242c8c5f421Sart 	 */
243c8c5f421Sart 	if (child_pid != 0 && sender_shmid != -1) {
244c8c5f421Sart 		if (shmctl(sender_shmid, IPC_RMID, NULL) == -1)
245c8c5f421Sart 			warn("shmctl IPC_RMID");
246c8c5f421Sart 	}
247c8c5f421Sart 
248c8c5f421Sart 	remove(keyname);
249c8c5f421Sart }
250c8c5f421Sart 
251c8c5f421Sart void
print_shmid_ds(sp,mode)252c8c5f421Sart print_shmid_ds(sp, mode)
253c8c5f421Sart 	struct shmid_ds *sp;
254c8c5f421Sart 	mode_t mode;
255c8c5f421Sart {
256c8c5f421Sart 	uid_t uid = geteuid();
257c8c5f421Sart 	gid_t gid = getegid();
258c8c5f421Sart 
2592cc39398Sderaadt 	printf("PERM: uid %u, gid %u, cuid %u, cgid %u, mode 0%o\n",
260c8c5f421Sart 	    sp->shm_perm.uid, sp->shm_perm.gid,
261c8c5f421Sart 	    sp->shm_perm.cuid, sp->shm_perm.cgid,
262c8c5f421Sart 	    sp->shm_perm.mode & 0777);
263c8c5f421Sart 
264c8c5f421Sart 	printf("segsz %lu, lpid %d, cpid %d, nattch %u\n",
265c8c5f421Sart 	    (u_long)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid,
266c8c5f421Sart 	    sp->shm_nattch);
267c8c5f421Sart 
268c8c5f421Sart 	printf("atime: %s", ctime(&sp->shm_atime));
269c8c5f421Sart 	printf("dtime: %s", ctime(&sp->shm_dtime));
270c8c5f421Sart 	printf("ctime: %s", ctime(&sp->shm_ctime));
271c8c5f421Sart 
272c8c5f421Sart 	/*
273c8c5f421Sart 	 * Sanity check a few things.
274c8c5f421Sart 	 */
275c8c5f421Sart 
276c8c5f421Sart 	if (sp->shm_perm.uid != uid || sp->shm_perm.cuid != uid)
277c8c5f421Sart 		errx(1, "uid mismatch");
278c8c5f421Sart 
279c8c5f421Sart 	if (sp->shm_perm.gid != gid || sp->shm_perm.cgid != gid)
280c8c5f421Sart 		errx(1, "gid mismatch");
281c8c5f421Sart 
282c8c5f421Sart 	if ((sp->shm_perm.mode & 0777) != mode)
283c8c5f421Sart 		errx(1, "mode mismatch");
284c8c5f421Sart }
285c8c5f421Sart 
286c8c5f421Sart void
receiver()287c8c5f421Sart receiver()
288c8c5f421Sart {
289c8c5f421Sart 	int shmid;
290c8c5f421Sart 	void *shm_buf;
291*37ec931bSguenther 	void *block;
292c8c5f421Sart 
293c8c5f421Sart 	if ((shmid = shmget(shmkey, pgsize, 0)) == -1)
294c8c5f421Sart 		err(1, "receiver: shmget");
295c8c5f421Sart 
296c8c5f421Sart 	if ((shm_buf = shmat(shmid, NULL, 0)) == (void *) -1)
297c8c5f421Sart 		err(1, "receiver: shmat");
298c8c5f421Sart 
299c8c5f421Sart 	if (verbose)
300*37ec931bSguenther 		printf("%.*s\n", (int)pgsize, (const char *)shm_buf);
301c8c5f421Sart 	if (strcmp((const char *)shm_buf, m_str) != 0)
302*37ec931bSguenther 		errx(1, "receiver: data isn't correct");
303*37ec931bSguenther 
304*37ec931bSguenther 	/* mmap() a page to get a distinct, freeable address */
305*37ec931bSguenther 	block = mmap(NULL, pgsize, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON,
306*37ec931bSguenther 	    -1, 0);
307*37ec931bSguenther 	if (block == MAP_FAILED)
308*37ec931bSguenther 		err(1, "receiver: mmap");
309*37ec931bSguenther 
310*37ec931bSguenther 	/* detach, then try to attach, conflicting with the mmap() */
311*37ec931bSguenther 	if (shmdt(shm_buf) == -1)
312*37ec931bSguenther 		err(1, "receiver: shmdt");
313*37ec931bSguenther 	if ((shm_buf = shmat(shmid, block, 0)) != (void *) -1)
314*37ec931bSguenther 		errx(1, "receiver: shmat(conflict) succeeded!");
315*37ec931bSguenther 	if (errno != ENOMEM)
316*37ec931bSguenther 		err(1, "receiver: shmat(conflict) wrong error");
317*37ec931bSguenther 
318*37ec931bSguenther 	/* free up that address and try again */
319*37ec931bSguenther 	if (munmap(block, pgsize) == -1)
320*37ec931bSguenther 		err(1, "receiver: munmap");
321*37ec931bSguenther 	if ((shm_buf = shmat(shmid, block, 0)) == (void *) -1)
322*37ec931bSguenther 		err(1, "receiver: shmat(fixed)");
323*37ec931bSguenther 
324*37ec931bSguenther 	if (shm_buf != block)
325*37ec931bSguenther 		errx(1, "receiver: shmat not at expected address: %p != %p",
326*37ec931bSguenther 		    shm_buf, block);
327*37ec931bSguenther 
328*37ec931bSguenther 	if (verbose)
329*37ec931bSguenther 		printf("%.*s\n", (int)pgsize, (const char *)shm_buf);
330*37ec931bSguenther 	if (strcmp((const char *)shm_buf, m_str) != 0)
331*37ec931bSguenther 		errx(1, "receiver: data isn't correct second time");
332c8c5f421Sart 
333c8c5f421Sart 	exit(0);
334c8c5f421Sart }
335