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