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