1 1.6 christos /* $NetBSD: t_sysv.c,v 1.6 2022/05/14 14:02:03 christos Exp $ */ 2 1.1 pgoyette 3 1.1 pgoyette /*- 4 1.1 pgoyette * Copyright (c) 1999, 2007 The NetBSD Foundation, Inc. 5 1.1 pgoyette * All rights reserved. 6 1.1 pgoyette * 7 1.1 pgoyette * This code is derived from software contributed to The NetBSD Foundation 8 1.1 pgoyette * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 1.1 pgoyette * NASA Ames Research Center, and by Andrew Doran. 10 1.1 pgoyette * 11 1.1 pgoyette * Redistribution and use in source and binary forms, with or without 12 1.1 pgoyette * modification, are permitted provided that the following conditions 13 1.1 pgoyette * are met: 14 1.1 pgoyette * 1. Redistributions of source code must retain the above copyright 15 1.1 pgoyette * notice, this list of conditions and the following disclaimer. 16 1.1 pgoyette * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 pgoyette * notice, this list of conditions and the following disclaimer in the 18 1.1 pgoyette * documentation and/or other materials provided with the distribution. 19 1.1 pgoyette * 20 1.1 pgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.1 pgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.1 pgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.1 pgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.1 pgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.1 pgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.1 pgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.1 pgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.1 pgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.1 pgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.1 pgoyette * POSSIBILITY OF SUCH DAMAGE. 31 1.1 pgoyette */ 32 1.1 pgoyette 33 1.1 pgoyette /* 34 1.1 pgoyette * Test the SVID-compatible Message Queue facility. 35 1.1 pgoyette */ 36 1.1 pgoyette 37 1.1 pgoyette #include <atf-c.h> 38 1.1 pgoyette 39 1.1 pgoyette #include <err.h> 40 1.1 pgoyette #include <errno.h> 41 1.1 pgoyette #include <fcntl.h> 42 1.1 pgoyette #include <signal.h> 43 1.1 pgoyette #include <stdio.h> 44 1.1 pgoyette #include <stdlib.h> 45 1.1 pgoyette #include <string.h> 46 1.1 pgoyette #include <time.h> 47 1.1 pgoyette #include <unistd.h> 48 1.1 pgoyette 49 1.1 pgoyette #include <sys/ipc.h> 50 1.1 pgoyette #include <sys/msg.h> 51 1.1 pgoyette #include <sys/param.h> 52 1.1 pgoyette #include <sys/sem.h> 53 1.1 pgoyette #include <sys/shm.h> 54 1.1 pgoyette #include <sys/wait.h> 55 1.1 pgoyette 56 1.6 christos volatile int did_sigsys; 57 1.1 pgoyette 58 1.1 pgoyette void sigsys_handler(int); 59 1.1 pgoyette 60 1.2 pgoyette key_t get_ftok(int); 61 1.2 pgoyette 62 1.1 pgoyette void print_msqid_ds(struct msqid_ds *, mode_t); 63 1.1 pgoyette void receiver(void); 64 1.1 pgoyette 65 1.1 pgoyette void print_semid_ds(struct semid_ds *, mode_t); 66 1.1 pgoyette void waiter(void); 67 1.1 pgoyette 68 1.1 pgoyette void print_shmid_ds(struct shmid_ds *, mode_t); 69 1.1 pgoyette void sharer(void); 70 1.1 pgoyette 71 1.1 pgoyette #define MESSAGE_TEXT_LEN 256 72 1.1 pgoyette 73 1.5 pgoyette struct testmsg { 74 1.1 pgoyette long mtype; 75 1.1 pgoyette char mtext[MESSAGE_TEXT_LEN]; 76 1.1 pgoyette }; 77 1.1 pgoyette 78 1.1 pgoyette const char *m1_str = "California is overrated."; 79 1.1 pgoyette const char *m2_str = "The quick brown fox jumped over the lazy dog."; 80 1.1 pgoyette 81 1.1 pgoyette size_t pgsize; 82 1.1 pgoyette 83 1.1 pgoyette #define MTYPE_1 1 84 1.1 pgoyette #define MTYPE_1_ACK 2 85 1.1 pgoyette 86 1.1 pgoyette #define MTYPE_2 3 87 1.1 pgoyette #define MTYPE_2_ACK 4 88 1.1 pgoyette 89 1.1 pgoyette pid_t child_pid; 90 1.1 pgoyette 91 1.1 pgoyette key_t msgkey, semkey, shmkey; 92 1.1 pgoyette 93 1.1 pgoyette int maxloop = 1; 94 1.1 pgoyette 95 1.1 pgoyette union semun { 96 1.1 pgoyette int val; /* value for SETVAL */ 97 1.1 pgoyette struct semid_ds *buf; /* buffer for IPC_{STAT,SET} */ 98 1.1 pgoyette u_short *array; /* array for GETALL & SETALL */ 99 1.1 pgoyette }; 100 1.1 pgoyette 101 1.1 pgoyette 102 1.4 jmmv /* Writes an integer to a file. To be used from the body of the test 103 1.4 jmmv * cases below to pass any global identifiers to the cleanup routine. */ 104 1.4 jmmv static void 105 1.4 jmmv write_int(const char *path, const int value) 106 1.4 jmmv { 107 1.4 jmmv int output; 108 1.4 jmmv 109 1.4 jmmv output = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); 110 1.4 jmmv ATF_REQUIRE_MSG(output != -1, "Failed to create %s", path); 111 1.4 jmmv write(output, &value, sizeof(value)); 112 1.4 jmmv close(output); 113 1.4 jmmv } 114 1.4 jmmv 115 1.4 jmmv 116 1.4 jmmv /* Reads an integer from a file. To be used from the cleanup routines 117 1.4 jmmv * of the test cases below. */ 118 1.4 jmmv static int 119 1.4 jmmv read_int(const char *path) 120 1.4 jmmv { 121 1.6 christos int input, value; 122 1.4 jmmv 123 1.4 jmmv input = open(path, O_RDONLY); 124 1.4 jmmv if (input == -1) 125 1.4 jmmv return -1; 126 1.6 christos 127 1.6 christos read(input, &value, sizeof(value)); 128 1.6 christos return value; 129 1.4 jmmv } 130 1.4 jmmv 131 1.4 jmmv 132 1.1 pgoyette void 133 1.1 pgoyette sigsys_handler(int signo) 134 1.1 pgoyette { 135 1.1 pgoyette 136 1.1 pgoyette did_sigsys = 1; 137 1.1 pgoyette } 138 1.1 pgoyette 139 1.2 pgoyette key_t get_ftok(int id) 140 1.2 pgoyette { 141 1.2 pgoyette int fd; 142 1.2 pgoyette char token_key[64], token_dir[64]; 143 1.2 pgoyette char *tmpdir; 144 1.2 pgoyette key_t key; 145 1.2 pgoyette 146 1.2 pgoyette strlcpy(token_key, "/tmp/t_sysv.XXXXXX", sizeof(token_key)); 147 1.2 pgoyette tmpdir = mkdtemp(token_key); 148 1.2 pgoyette ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp() failed: %d", errno); 149 1.2 pgoyette 150 1.2 pgoyette strlcpy(token_dir, tmpdir, sizeof(token_dir)); 151 1.2 pgoyette strlcpy(token_key, tmpdir, sizeof(token_key)); 152 1.2 pgoyette strlcat(token_key, "/token_key", sizeof(token_key)); 153 1.2 pgoyette 154 1.2 pgoyette /* Create the file, since ftok() requires it to exist! */ 155 1.2 pgoyette 156 1.5 pgoyette fd = open(token_key, O_RDWR | O_CREAT | O_EXCL, 0600); 157 1.2 pgoyette if (fd == -1) { 158 1.2 pgoyette rmdir(tmpdir); 159 1.2 pgoyette atf_tc_fail("open() of temp file failed: %d", errno); 160 1.2 pgoyette return (key_t)-1; 161 1.6 christos } 162 1.6 christos 163 1.6 christos close(fd); 164 1.2 pgoyette 165 1.2 pgoyette key = ftok(token_key, id); 166 1.5 pgoyette ATF_REQUIRE_MSG(key != (key_t)-1, "ftok() failed"); 167 1.2 pgoyette 168 1.2 pgoyette ATF_REQUIRE_MSG(unlink(token_key) != -1, "unlink() failed: %d", errno); 169 1.2 pgoyette ATF_REQUIRE_MSG(rmdir(token_dir) != -1, "rmdir() failed: %d", errno); 170 1.2 pgoyette 171 1.2 pgoyette return key; 172 1.2 pgoyette } 173 1.2 pgoyette 174 1.2 pgoyette ATF_TC_WITH_CLEANUP(msg); 175 1.1 pgoyette ATF_TC_HEAD(msg, tc) 176 1.1 pgoyette { 177 1.1 pgoyette 178 1.1 pgoyette atf_tc_set_md_var(tc, "timeout", "3"); 179 1.1 pgoyette atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); 180 1.1 pgoyette } 181 1.1 pgoyette 182 1.1 pgoyette ATF_TC_BODY(msg, tc) 183 1.1 pgoyette { 184 1.1 pgoyette struct sigaction sa; 185 1.1 pgoyette struct msqid_ds m_ds; 186 1.5 pgoyette struct testmsg m; 187 1.4 jmmv int sender_msqid; 188 1.1 pgoyette int loop; 189 1.1 pgoyette int c_status; 190 1.6 christos pid_t wait_result; 191 1.1 pgoyette 192 1.1 pgoyette /* 193 1.1 pgoyette * Install a SIGSYS handler so that we can exit gracefully if 194 1.1 pgoyette * System V Message Queue support isn't in the kernel. 195 1.1 pgoyette */ 196 1.1 pgoyette did_sigsys = 0; 197 1.1 pgoyette sa.sa_handler = sigsys_handler; 198 1.1 pgoyette sigemptyset(&sa.sa_mask); 199 1.1 pgoyette sa.sa_flags = 0; 200 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 201 1.1 pgoyette "sigaction SIGSYS: %d", errno); 202 1.1 pgoyette 203 1.2 pgoyette msgkey = get_ftok(4160); 204 1.2 pgoyette ATF_REQUIRE_MSG(msgkey != (key_t)-1, "get_ftok failed"); 205 1.1 pgoyette 206 1.1 pgoyette sender_msqid = msgget(msgkey, IPC_CREAT | 0640); 207 1.1 pgoyette ATF_REQUIRE_MSG(sender_msqid != -1, "msgget: %d", errno); 208 1.4 jmmv write_int("sender_msqid", sender_msqid); 209 1.1 pgoyette 210 1.1 pgoyette if (did_sigsys) { 211 1.1 pgoyette atf_tc_skip("SYSV Message Queue not supported"); 212 1.1 pgoyette return; 213 1.1 pgoyette } 214 1.1 pgoyette 215 1.1 pgoyette ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 216 1.1 pgoyette "msgctl IPC_STAT 1: %d", errno); 217 1.1 pgoyette 218 1.1 pgoyette print_msqid_ds(&m_ds, 0640); 219 1.1 pgoyette 220 1.1 pgoyette m_ds.msg_perm.mode = (m_ds.msg_perm.mode & ~0777) | 0600; 221 1.1 pgoyette 222 1.1 pgoyette ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_SET, &m_ds) != -1, 223 1.1 pgoyette "msgctl IPC_SET: %d", errno); 224 1.1 pgoyette 225 1.1 pgoyette memset(&m_ds, 0, sizeof(m_ds)); 226 1.1 pgoyette 227 1.1 pgoyette ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 228 1.1 pgoyette "msgctl IPC_STAT 2: %d", errno); 229 1.1 pgoyette 230 1.1 pgoyette ATF_REQUIRE_MSG((m_ds.msg_perm.mode & 0777) == 0600, 231 1.1 pgoyette "IPC_SET of mode didn't hold"); 232 1.1 pgoyette 233 1.1 pgoyette print_msqid_ds(&m_ds, 0600); 234 1.1 pgoyette 235 1.6 christos fflush(stdout); 236 1.6 christos 237 1.1 pgoyette switch ((child_pid = fork())) { 238 1.1 pgoyette case -1: 239 1.1 pgoyette atf_tc_fail("fork: %d", errno); 240 1.1 pgoyette return; 241 1.1 pgoyette 242 1.1 pgoyette case 0: 243 1.1 pgoyette receiver(); 244 1.1 pgoyette break; 245 1.1 pgoyette 246 1.1 pgoyette default: 247 1.1 pgoyette break; 248 1.1 pgoyette } 249 1.1 pgoyette 250 1.1 pgoyette for (loop = 0; loop < maxloop; loop++) { 251 1.1 pgoyette /* 252 1.1 pgoyette * Send the first message to the receiver and wait for the ACK. 253 1.1 pgoyette */ 254 1.1 pgoyette m.mtype = MTYPE_1; 255 1.1 pgoyette strcpy(m.mtext, m1_str); 256 1.3 skrll ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 257 1.3 skrll 0) != -1, "sender: msgsnd 1: %d", errno); 258 1.1 pgoyette 259 1.3 skrll ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, 260 1.6 christos MTYPE_1_ACK, 0) == MESSAGE_TEXT_LEN, 261 1.1 pgoyette "sender: msgrcv 1 ack: %d", errno); 262 1.1 pgoyette 263 1.1 pgoyette print_msqid_ds(&m_ds, 0600); 264 1.1 pgoyette 265 1.1 pgoyette /* 266 1.1 pgoyette * Send the second message to the receiver and wait for the ACK. 267 1.1 pgoyette */ 268 1.1 pgoyette m.mtype = MTYPE_2; 269 1.1 pgoyette strcpy(m.mtext, m2_str); 270 1.6 christos ATF_REQUIRE_MSG(msgsnd(sender_msqid, &m, MESSAGE_TEXT_LEN, 0) 271 1.6 christos != -1, "sender: msgsnd 2: %d", errno); 272 1.1 pgoyette 273 1.3 skrll ATF_REQUIRE_MSG(msgrcv(sender_msqid, &m, MESSAGE_TEXT_LEN, 274 1.6 christos MTYPE_2_ACK, 0) == MESSAGE_TEXT_LEN, 275 1.1 pgoyette "sender: msgrcv 2 ack: %d", errno); 276 1.1 pgoyette } 277 1.1 pgoyette 278 1.1 pgoyette /* 279 1.1 pgoyette * Wait for child to finish 280 1.1 pgoyette */ 281 1.6 christos wait_result = wait(&c_status); 282 1.6 christos ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)", 283 1.6 christos wait_result, wait_result == -1 ? strerror(errno) : ""); 284 1.6 christos ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)", 285 1.6 christos c_status, WTERMSIG(c_status)); 286 1.6 christos ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d", 287 1.6 christos WEXITSTATUS(c_status)); 288 1.1 pgoyette 289 1.6 christos ATF_REQUIRE_MSG(msgctl(sender_msqid, IPC_STAT, &m_ds) != -1, 290 1.6 christos "msgctl IPC_STAT: %d", errno); 291 1.1 pgoyette 292 1.6 christos print_msqid_ds(&m_ds, 0600); 293 1.1 pgoyette } 294 1.1 pgoyette 295 1.2 pgoyette ATF_TC_CLEANUP(msg, tc) 296 1.1 pgoyette { 297 1.4 jmmv int sender_msqid; 298 1.1 pgoyette 299 1.1 pgoyette /* 300 1.2 pgoyette * Remove the message queue if it exists. 301 1.1 pgoyette */ 302 1.4 jmmv sender_msqid = read_int("sender_msqid"); 303 1.6 christos if (sender_msqid == -1) 304 1.6 christos return; 305 1.6 christos if (msgctl(sender_msqid, IPC_RMID, NULL) == -1) 306 1.6 christos err(EXIT_FAILURE, "msgctl IPC_RMID"); 307 1.1 pgoyette } 308 1.1 pgoyette 309 1.1 pgoyette void 310 1.5 pgoyette print_msqid_ds(struct msqid_ds *mp, mode_t mode) 311 1.1 pgoyette { 312 1.1 pgoyette uid_t uid = geteuid(); 313 1.1 pgoyette gid_t gid = getegid(); 314 1.1 pgoyette 315 1.1 pgoyette printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 316 1.1 pgoyette mp->msg_perm.uid, mp->msg_perm.gid, 317 1.1 pgoyette mp->msg_perm.cuid, mp->msg_perm.cgid, 318 1.1 pgoyette mp->msg_perm.mode & 0777); 319 1.1 pgoyette 320 1.6 christos printf("qnum %lu, qbytes %ju, lspid %d, lrpid %d\n", 321 1.6 christos mp->msg_qnum, (uintmax_t)mp->msg_qbytes, mp->msg_lspid, 322 1.1 pgoyette mp->msg_lrpid); 323 1.1 pgoyette 324 1.1 pgoyette printf("stime: %s", ctime(&mp->msg_stime)); 325 1.1 pgoyette printf("rtime: %s", ctime(&mp->msg_rtime)); 326 1.1 pgoyette printf("ctime: %s", ctime(&mp->msg_ctime)); 327 1.1 pgoyette 328 1.1 pgoyette /* 329 1.1 pgoyette * Sanity check a few things. 330 1.1 pgoyette */ 331 1.1 pgoyette 332 1.1 pgoyette ATF_REQUIRE_MSG(mp->msg_perm.uid == uid && mp->msg_perm.cuid == uid, 333 1.1 pgoyette "uid mismatch"); 334 1.1 pgoyette 335 1.1 pgoyette ATF_REQUIRE_MSG(mp->msg_perm.gid == gid && mp->msg_perm.cgid == gid, 336 1.1 pgoyette "gid mismatch"); 337 1.1 pgoyette 338 1.1 pgoyette ATF_REQUIRE_MSG((mp->msg_perm.mode & 0777) == mode, "mode mismatch"); 339 1.1 pgoyette } 340 1.1 pgoyette 341 1.1 pgoyette void 342 1.5 pgoyette receiver(void) 343 1.1 pgoyette { 344 1.5 pgoyette struct testmsg m; 345 1.1 pgoyette int msqid, loop; 346 1.1 pgoyette 347 1.1 pgoyette if ((msqid = msgget(msgkey, 0)) == -1) 348 1.6 christos err(EXIT_FAILURE, "receiver: msgget"); 349 1.1 pgoyette 350 1.1 pgoyette for (loop = 0; loop < maxloop; loop++) { 351 1.1 pgoyette /* 352 1.1 pgoyette * Receive the first message, print it, and send an ACK. 353 1.1 pgoyette */ 354 1.6 christos if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_1, 0) 355 1.6 christos != MESSAGE_TEXT_LEN) 356 1.6 christos err(EXIT_FAILURE, "receiver: msgrcv 1"); 357 1.1 pgoyette 358 1.1 pgoyette printf("%s\n", m.mtext); 359 1.1 pgoyette if (strcmp(m.mtext, m1_str) != 0) 360 1.6 christos errx(EXIT_FAILURE, 361 1.6 christos "receiver: message 1 data isn't correct"); 362 1.1 pgoyette 363 1.1 pgoyette m.mtype = MTYPE_1_ACK; 364 1.1 pgoyette 365 1.3 skrll if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) 366 1.6 christos err(EXIT_FAILURE, "receiver: msgsnd ack 1"); 367 1.1 pgoyette 368 1.1 pgoyette /* 369 1.1 pgoyette * Receive the second message, print it, and send an ACK. 370 1.1 pgoyette */ 371 1.1 pgoyette 372 1.6 christos if (msgrcv(msqid, &m, MESSAGE_TEXT_LEN, MTYPE_2, 0) 373 1.6 christos != MESSAGE_TEXT_LEN) 374 1.6 christos err(EXIT_FAILURE, "receiver: msgrcv 2"); 375 1.1 pgoyette 376 1.1 pgoyette printf("%s\n", m.mtext); 377 1.1 pgoyette if (strcmp(m.mtext, m2_str) != 0) 378 1.6 christos errx(EXIT_FAILURE, 379 1.6 christos "receiver: message 2 data isn't correct"); 380 1.1 pgoyette 381 1.1 pgoyette m.mtype = MTYPE_2_ACK; 382 1.1 pgoyette 383 1.3 skrll if (msgsnd(msqid, &m, MESSAGE_TEXT_LEN, 0) == -1) 384 1.6 christos err(EXIT_FAILURE, "receiver: msgsnd ack 2"); 385 1.1 pgoyette } 386 1.1 pgoyette 387 1.6 christos exit(EXIT_SUCCESS); 388 1.1 pgoyette } 389 1.1 pgoyette 390 1.1 pgoyette /* 391 1.1 pgoyette * Test the SVID-compatible Semaphore facility. 392 1.1 pgoyette */ 393 1.1 pgoyette 394 1.2 pgoyette ATF_TC_WITH_CLEANUP(sem); 395 1.1 pgoyette ATF_TC_HEAD(sem, tc) 396 1.1 pgoyette { 397 1.1 pgoyette 398 1.1 pgoyette atf_tc_set_md_var(tc, "timeout", "3"); 399 1.1 pgoyette atf_tc_set_md_var(tc, "descr", "Checks sysvmsg passing"); 400 1.1 pgoyette } 401 1.1 pgoyette 402 1.1 pgoyette ATF_TC_BODY(sem, tc) 403 1.1 pgoyette { 404 1.1 pgoyette struct sigaction sa; 405 1.1 pgoyette union semun sun; 406 1.1 pgoyette struct semid_ds s_ds; 407 1.4 jmmv int sender_semid; 408 1.1 pgoyette int i; 409 1.1 pgoyette int c_status; 410 1.6 christos int child_count; 411 1.6 christos pid_t wait_result; 412 1.1 pgoyette 413 1.1 pgoyette /* 414 1.1 pgoyette * Install a SIGSYS handler so that we can exit gracefully if 415 1.1 pgoyette * System V Semaphore support isn't in the kernel. 416 1.1 pgoyette */ 417 1.1 pgoyette did_sigsys = 0; 418 1.1 pgoyette sa.sa_handler = sigsys_handler; 419 1.1 pgoyette sigemptyset(&sa.sa_mask); 420 1.1 pgoyette sa.sa_flags = 0; 421 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 422 1.1 pgoyette "sigaction SIGSYS: %d", errno); 423 1.1 pgoyette 424 1.2 pgoyette semkey = get_ftok(4160); 425 1.2 pgoyette ATF_REQUIRE_MSG(semkey != (key_t)-1, "get_ftok failed"); 426 1.1 pgoyette 427 1.1 pgoyette sender_semid = semget(semkey, 1, IPC_CREAT | 0640); 428 1.1 pgoyette ATF_REQUIRE_MSG(sender_semid != -1, "semget: %d", errno); 429 1.4 jmmv write_int("sender_semid", sender_semid); 430 1.1 pgoyette 431 1.1 pgoyette if (did_sigsys) { 432 1.1 pgoyette atf_tc_skip("SYSV Semaphore not supported"); 433 1.1 pgoyette return; 434 1.1 pgoyette } 435 1.1 pgoyette 436 1.1 pgoyette sun.buf = &s_ds; 437 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 438 1.1 pgoyette "semctl IPC_STAT: %d", errno); 439 1.1 pgoyette 440 1.1 pgoyette print_semid_ds(&s_ds, 0640); 441 1.1 pgoyette 442 1.1 pgoyette s_ds.sem_perm.mode = (s_ds.sem_perm.mode & ~0777) | 0600; 443 1.1 pgoyette 444 1.1 pgoyette sun.buf = &s_ds; 445 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_SET, sun) != -1, 446 1.1 pgoyette "semctl IPC_SET: %d", errno); 447 1.1 pgoyette 448 1.1 pgoyette memset(&s_ds, 0, sizeof(s_ds)); 449 1.1 pgoyette 450 1.1 pgoyette sun.buf = &s_ds; 451 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 452 1.1 pgoyette "semctl IPC_STAT: %d", errno); 453 1.1 pgoyette 454 1.1 pgoyette ATF_REQUIRE_MSG((s_ds.sem_perm.mode & 0777) == 0600, 455 1.1 pgoyette "IPC_SET of mode didn't hold"); 456 1.1 pgoyette 457 1.1 pgoyette print_semid_ds(&s_ds, 0600); 458 1.1 pgoyette 459 1.6 christos fflush(stdout); 460 1.6 christos 461 1.1 pgoyette for (child_count = 0; child_count < 5; child_count++) { 462 1.1 pgoyette switch ((child_pid = fork())) { 463 1.1 pgoyette case -1: 464 1.1 pgoyette atf_tc_fail("fork: %d", errno); 465 1.1 pgoyette return; 466 1.1 pgoyette 467 1.1 pgoyette case 0: 468 1.1 pgoyette waiter(); 469 1.1 pgoyette break; 470 1.1 pgoyette 471 1.1 pgoyette default: 472 1.1 pgoyette break; 473 1.1 pgoyette } 474 1.1 pgoyette } 475 1.1 pgoyette 476 1.1 pgoyette /* 477 1.1 pgoyette * Wait for all of the waiters to be attempting to acquire the 478 1.1 pgoyette * semaphore. 479 1.1 pgoyette */ 480 1.1 pgoyette for (;;) { 481 1.1 pgoyette i = semctl(sender_semid, 0, GETNCNT); 482 1.1 pgoyette if (i == -1) 483 1.1 pgoyette atf_tc_fail("semctl GETNCNT: %d", i); 484 1.1 pgoyette if (i == 5) 485 1.1 pgoyette break; 486 1.1 pgoyette } 487 1.1 pgoyette 488 1.1 pgoyette /* 489 1.1 pgoyette * Now set the thundering herd in motion by initializing the 490 1.1 pgoyette * semaphore to the value 1. 491 1.1 pgoyette */ 492 1.1 pgoyette sun.val = 1; 493 1.1 pgoyette ATF_REQUIRE_MSG(semctl(sender_semid, 0, SETVAL, sun) != -1, 494 1.1 pgoyette "sender: semctl SETVAL to 1: %d", errno); 495 1.1 pgoyette 496 1.1 pgoyette /* 497 1.1 pgoyette * Wait for all children to finish 498 1.1 pgoyette */ 499 1.6 christos while (child_count-- > 0) { 500 1.6 christos wait_result = wait(&c_status); 501 1.6 christos ATF_REQUIRE_MSG(wait_result != -1, "wait failed: %s", 502 1.6 christos strerror(errno)); 503 1.6 christos ATF_REQUIRE_MSG(WIFEXITED(c_status), 504 1.6 christos "child abnormal exit: %d (sig %d)", 505 1.6 christos c_status, WTERMSIG(c_status)); 506 1.6 christos ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d", 507 1.6 christos WEXITSTATUS(c_status)); 508 1.6 christos 509 1.6 christos sun.buf = &s_ds; 510 1.6 christos ATF_REQUIRE_MSG(semctl(sender_semid, 0, IPC_STAT, sun) != -1, 511 1.6 christos "semctl IPC_STAT: %d", errno); 512 1.6 christos 513 1.6 christos print_semid_ds(&s_ds, 0600); 514 1.1 pgoyette } 515 1.1 pgoyette } 516 1.1 pgoyette 517 1.2 pgoyette ATF_TC_CLEANUP(sem, tc) 518 1.1 pgoyette { 519 1.4 jmmv int sender_semid; 520 1.1 pgoyette 521 1.1 pgoyette /* 522 1.2 pgoyette * Remove the semaphore if it exists 523 1.1 pgoyette */ 524 1.4 jmmv sender_semid = read_int("sender_semid"); 525 1.6 christos if (sender_semid == -1) 526 1.6 christos return; 527 1.6 christos if (semctl(sender_semid, 0, IPC_RMID) == -1) 528 1.6 christos err(EXIT_FAILURE, "semctl IPC_RMID"); 529 1.1 pgoyette } 530 1.1 pgoyette 531 1.1 pgoyette void 532 1.5 pgoyette print_semid_ds(struct semid_ds *sp, mode_t mode) 533 1.1 pgoyette { 534 1.1 pgoyette uid_t uid = geteuid(); 535 1.1 pgoyette gid_t gid = getegid(); 536 1.1 pgoyette 537 1.1 pgoyette printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 538 1.1 pgoyette sp->sem_perm.uid, sp->sem_perm.gid, 539 1.1 pgoyette sp->sem_perm.cuid, sp->sem_perm.cgid, 540 1.1 pgoyette sp->sem_perm.mode & 0777); 541 1.1 pgoyette 542 1.1 pgoyette printf("nsems %u\n", sp->sem_nsems); 543 1.1 pgoyette 544 1.1 pgoyette printf("otime: %s", ctime(&sp->sem_otime)); 545 1.1 pgoyette printf("ctime: %s", ctime(&sp->sem_ctime)); 546 1.1 pgoyette 547 1.1 pgoyette /* 548 1.1 pgoyette * Sanity check a few things. 549 1.1 pgoyette */ 550 1.1 pgoyette 551 1.1 pgoyette ATF_REQUIRE_MSG(sp->sem_perm.uid == uid && sp->sem_perm.cuid == uid, 552 1.1 pgoyette "uid mismatch"); 553 1.1 pgoyette 554 1.1 pgoyette ATF_REQUIRE_MSG(sp->sem_perm.gid == gid && sp->sem_perm.cgid == gid, 555 1.1 pgoyette "gid mismatch"); 556 1.1 pgoyette 557 1.1 pgoyette ATF_REQUIRE_MSG((sp->sem_perm.mode & 0777) == mode, 558 1.1 pgoyette "mode mismatch %o != %o", (sp->sem_perm.mode & 0777), mode); 559 1.1 pgoyette } 560 1.1 pgoyette 561 1.1 pgoyette void 562 1.5 pgoyette waiter(void) 563 1.1 pgoyette { 564 1.1 pgoyette struct sembuf s; 565 1.1 pgoyette int semid; 566 1.1 pgoyette 567 1.1 pgoyette if ((semid = semget(semkey, 1, 0)) == -1) 568 1.6 christos err(EXIT_FAILURE, "waiter: semget"); 569 1.1 pgoyette 570 1.1 pgoyette /* 571 1.1 pgoyette * Attempt to acquire the semaphore. 572 1.1 pgoyette */ 573 1.1 pgoyette s.sem_num = 0; 574 1.1 pgoyette s.sem_op = -1; 575 1.1 pgoyette s.sem_flg = SEM_UNDO; 576 1.1 pgoyette 577 1.1 pgoyette if (semop(semid, &s, 1) == -1) 578 1.6 christos err(EXIT_FAILURE, "waiter: semop -1"); 579 1.1 pgoyette 580 1.1 pgoyette printf("WOO! GOT THE SEMAPHORE!\n"); 581 1.6 christos usleep(10000); 582 1.1 pgoyette 583 1.1 pgoyette /* 584 1.1 pgoyette * Release the semaphore and exit. 585 1.1 pgoyette */ 586 1.1 pgoyette s.sem_num = 0; 587 1.1 pgoyette s.sem_op = 1; 588 1.1 pgoyette s.sem_flg = SEM_UNDO; 589 1.1 pgoyette 590 1.1 pgoyette if (semop(semid, &s, 1) == -1) 591 1.6 christos err(EXIT_FAILURE, "waiter: semop +1"); 592 1.1 pgoyette 593 1.6 christos exit(EXIT_SUCCESS); 594 1.1 pgoyette } 595 1.1 pgoyette 596 1.1 pgoyette /* 597 1.1 pgoyette * Test the SVID-compatible Shared Memory facility. 598 1.1 pgoyette */ 599 1.1 pgoyette 600 1.2 pgoyette ATF_TC_WITH_CLEANUP(shm); 601 1.1 pgoyette ATF_TC_HEAD(shm, tc) 602 1.1 pgoyette { 603 1.1 pgoyette 604 1.1 pgoyette atf_tc_set_md_var(tc, "timeout", "3"); 605 1.1 pgoyette atf_tc_set_md_var(tc, "descr", "Checks sysv shared memory"); 606 1.1 pgoyette } 607 1.1 pgoyette 608 1.1 pgoyette ATF_TC_BODY(shm, tc) 609 1.1 pgoyette { 610 1.1 pgoyette struct sigaction sa; 611 1.1 pgoyette struct shmid_ds s_ds; 612 1.1 pgoyette char *shm_buf; 613 1.4 jmmv int sender_shmid; 614 1.1 pgoyette int c_status; 615 1.6 christos pid_t wait_result; 616 1.1 pgoyette 617 1.1 pgoyette /* 618 1.1 pgoyette * Install a SIGSYS handler so that we can exit gracefully if 619 1.1 pgoyette * System V Shared Memory support isn't in the kernel. 620 1.1 pgoyette */ 621 1.1 pgoyette did_sigsys = 0; 622 1.1 pgoyette sa.sa_handler = sigsys_handler; 623 1.1 pgoyette sigemptyset(&sa.sa_mask); 624 1.1 pgoyette sa.sa_flags = 0; 625 1.1 pgoyette ATF_REQUIRE_MSG(sigaction(SIGSYS, &sa, NULL) != -1, 626 1.1 pgoyette "sigaction SIGSYS: %d", errno); 627 1.1 pgoyette 628 1.1 pgoyette pgsize = sysconf(_SC_PAGESIZE); 629 1.1 pgoyette 630 1.2 pgoyette shmkey = get_ftok(4160); 631 1.2 pgoyette ATF_REQUIRE_MSG(shmkey != (key_t)-1, "get_ftok failed"); 632 1.1 pgoyette 633 1.1 pgoyette ATF_REQUIRE_MSG((sender_shmid = shmget(shmkey, pgsize, 634 1.1 pgoyette IPC_CREAT | 0640)) != -1, 635 1.1 pgoyette "shmget: %d", errno); 636 1.4 jmmv write_int("sender_shmid", sender_shmid); 637 1.1 pgoyette 638 1.1 pgoyette ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 639 1.1 pgoyette "shmctl IPC_STAT: %d", errno); 640 1.1 pgoyette 641 1.1 pgoyette print_shmid_ds(&s_ds, 0640); 642 1.1 pgoyette 643 1.1 pgoyette s_ds.shm_perm.mode = (s_ds.shm_perm.mode & ~0777) | 0600; 644 1.1 pgoyette 645 1.1 pgoyette ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_SET, &s_ds) != -1, 646 1.1 pgoyette "shmctl IPC_SET: %d", errno); 647 1.1 pgoyette 648 1.1 pgoyette memset(&s_ds, 0, sizeof(s_ds)); 649 1.1 pgoyette 650 1.1 pgoyette ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 651 1.1 pgoyette "shmctl IPC_STAT: %d", errno); 652 1.1 pgoyette 653 1.1 pgoyette ATF_REQUIRE_MSG((s_ds.shm_perm.mode & 0777) == 0600, 654 1.1 pgoyette "IPC_SET of mode didn't hold"); 655 1.1 pgoyette 656 1.1 pgoyette print_shmid_ds(&s_ds, 0600); 657 1.1 pgoyette 658 1.1 pgoyette shm_buf = shmat(sender_shmid, NULL, 0); 659 1.1 pgoyette ATF_REQUIRE_MSG(shm_buf != (void *) -1, "sender: shmat: %d", errno); 660 1.1 pgoyette 661 1.1 pgoyette /* 662 1.1 pgoyette * Write the test pattern into the shared memory buffer. 663 1.1 pgoyette */ 664 1.1 pgoyette strcpy(shm_buf, m2_str); 665 1.1 pgoyette 666 1.6 christos fflush(stdout); 667 1.6 christos 668 1.1 pgoyette switch ((child_pid = fork())) { 669 1.1 pgoyette case -1: 670 1.1 pgoyette atf_tc_fail("fork: %d", errno); 671 1.1 pgoyette return; 672 1.1 pgoyette 673 1.1 pgoyette case 0: 674 1.1 pgoyette sharer(); 675 1.1 pgoyette break; 676 1.1 pgoyette 677 1.1 pgoyette default: 678 1.1 pgoyette break; 679 1.1 pgoyette } 680 1.1 pgoyette 681 1.1 pgoyette /* 682 1.1 pgoyette * Wait for child to finish 683 1.1 pgoyette */ 684 1.6 christos wait_result = wait(&c_status); 685 1.6 christos ATF_REQUIRE_EQ_MSG(wait_result, child_pid, "wait returned %d (%s)", 686 1.6 christos wait_result, wait_result == -1 ? strerror(errno) : ""); 687 1.6 christos ATF_REQUIRE_MSG(WIFEXITED(c_status), "child abnormal exit: %d (sig %d)", 688 1.6 christos c_status, WTERMSIG(c_status)); 689 1.6 christos ATF_REQUIRE_EQ_MSG(WEXITSTATUS(c_status), 0, "child status: %d", 690 1.6 christos WEXITSTATUS(c_status)); 691 1.1 pgoyette 692 1.6 christos ATF_REQUIRE_MSG(shmctl(sender_shmid, IPC_STAT, &s_ds) != -1, 693 1.6 christos "shmctl IPC_STAT: %d", errno); 694 1.1 pgoyette 695 1.6 christos print_shmid_ds(&s_ds, 0600); 696 1.1 pgoyette } 697 1.1 pgoyette 698 1.2 pgoyette ATF_TC_CLEANUP(shm, tc) 699 1.1 pgoyette { 700 1.4 jmmv int sender_shmid; 701 1.1 pgoyette 702 1.1 pgoyette /* 703 1.2 pgoyette * Remove the shared memory area if it exists. 704 1.1 pgoyette */ 705 1.4 jmmv sender_shmid = read_int("sender_shmid"); 706 1.6 christos if (sender_shmid == -1) 707 1.6 christos return; 708 1.6 christos if (shmctl(sender_shmid, IPC_RMID, NULL) == -1) 709 1.6 christos err(EXIT_FAILURE, "shmctl IPC_RMID"); 710 1.1 pgoyette } 711 1.1 pgoyette 712 1.1 pgoyette void 713 1.5 pgoyette print_shmid_ds(struct shmid_ds *sp, mode_t mode) 714 1.1 pgoyette { 715 1.1 pgoyette uid_t uid = geteuid(); 716 1.1 pgoyette gid_t gid = getegid(); 717 1.1 pgoyette 718 1.1 pgoyette printf("PERM: uid %d, gid %d, cuid %d, cgid %d, mode 0%o\n", 719 1.1 pgoyette sp->shm_perm.uid, sp->shm_perm.gid, 720 1.1 pgoyette sp->shm_perm.cuid, sp->shm_perm.cgid, 721 1.1 pgoyette sp->shm_perm.mode & 0777); 722 1.1 pgoyette 723 1.6 christos printf("segsz %ju, lpid %d, cpid %d, nattch %u\n", 724 1.6 christos (uintmax_t)sp->shm_segsz, sp->shm_lpid, sp->shm_cpid, 725 1.1 pgoyette sp->shm_nattch); 726 1.1 pgoyette 727 1.1 pgoyette printf("atime: %s", ctime(&sp->shm_atime)); 728 1.1 pgoyette printf("dtime: %s", ctime(&sp->shm_dtime)); 729 1.1 pgoyette printf("ctime: %s", ctime(&sp->shm_ctime)); 730 1.1 pgoyette 731 1.1 pgoyette /* 732 1.1 pgoyette * Sanity check a few things. 733 1.1 pgoyette */ 734 1.1 pgoyette 735 1.1 pgoyette ATF_REQUIRE_MSG(sp->shm_perm.uid == uid && sp->shm_perm.cuid == uid, 736 1.1 pgoyette "uid mismatch"); 737 1.1 pgoyette 738 1.1 pgoyette ATF_REQUIRE_MSG(sp->shm_perm.gid == gid && sp->shm_perm.cgid == gid, 739 1.1 pgoyette "gid mismatch"); 740 1.1 pgoyette 741 1.5 pgoyette ATF_REQUIRE_MSG((sp->shm_perm.mode & 0777) == mode, 742 1.5 pgoyette "mode mismatch %o != %o", sp->shm_perm.mode & 0777, mode); 743 1.1 pgoyette } 744 1.1 pgoyette 745 1.1 pgoyette void 746 1.5 pgoyette sharer(void) 747 1.1 pgoyette { 748 1.1 pgoyette int shmid; 749 1.1 pgoyette void *shm_buf; 750 1.1 pgoyette 751 1.1 pgoyette shmid = shmget(shmkey, pgsize, 0); 752 1.6 christos if (shmid == -1) 753 1.6 christos err(EXIT_FAILURE, "receiver: shmget"); 754 1.1 pgoyette 755 1.1 pgoyette shm_buf = shmat(shmid, NULL, 0); 756 1.6 christos if (shm_buf == (void *) -1) 757 1.6 christos err(EXIT_FAILURE, "receiver: shmat"); 758 1.1 pgoyette 759 1.1 pgoyette printf("%s\n", (const char *)shm_buf); 760 1.1 pgoyette 761 1.6 christos if (strcmp((const char *)shm_buf, m2_str) != 0) 762 1.6 christos errx(EXIT_FAILURE, "receiver: data isn't correct"); 763 1.6 christos 764 1.6 christos exit(EXIT_SUCCESS); 765 1.1 pgoyette } 766 1.1 pgoyette 767 1.1 pgoyette ATF_TP_ADD_TCS(tp) 768 1.1 pgoyette { 769 1.1 pgoyette 770 1.1 pgoyette ATF_TP_ADD_TC(tp, msg); 771 1.1 pgoyette ATF_TP_ADD_TC(tp, sem); 772 1.1 pgoyette ATF_TP_ADD_TC(tp, shm); 773 1.1 pgoyette 774 1.1 pgoyette return atf_no_error(); 775 1.1 pgoyette } 776