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