1 1.3 kre /* $NetBSD: t_msgget.c,v 1.3 2017/10/08 08:31:05 kre Exp $ */ 2 1.1 jruoho 3 1.1 jruoho /*- 4 1.1 jruoho * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 1.1 jruoho * All rights reserved. 6 1.1 jruoho * 7 1.1 jruoho * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jruoho * by Jukka Ruohonen. 9 1.1 jruoho * 10 1.1 jruoho * Redistribution and use in source and binary forms, with or without 11 1.1 jruoho * modification, are permitted provided that the following conditions 12 1.1 jruoho * are met: 13 1.1 jruoho * 1. Redistributions of source code must retain the above copyright 14 1.1 jruoho * notice, this list of conditions and the following disclaimer. 15 1.1 jruoho * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jruoho * notice, this list of conditions and the following disclaimer in the 17 1.1 jruoho * documentation and/or other materials provided with the distribution. 18 1.1 jruoho * 19 1.1 jruoho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jruoho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jruoho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jruoho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jruoho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jruoho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jruoho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jruoho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jruoho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jruoho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jruoho * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jruoho */ 31 1.1 jruoho #include <sys/cdefs.h> 32 1.3 kre __RCSID("$NetBSD: t_msgget.c,v 1.3 2017/10/08 08:31:05 kre Exp $"); 33 1.1 jruoho 34 1.1 jruoho #include <sys/msg.h> 35 1.1 jruoho #include <sys/stat.h> 36 1.1 jruoho #include <sys/sysctl.h> 37 1.1 jruoho #include <sys/wait.h> 38 1.1 jruoho 39 1.1 jruoho #include <atf-c.h> 40 1.1 jruoho #include <errno.h> 41 1.1 jruoho #include <pwd.h> 42 1.1 jruoho #include <stdio.h> 43 1.1 jruoho #include <stdlib.h> 44 1.1 jruoho #include <string.h> 45 1.1 jruoho #include <sysexits.h> 46 1.1 jruoho #include <time.h> 47 1.1 jruoho #include <unistd.h> 48 1.1 jruoho 49 1.1 jruoho #define MSG_KEY 12345689 50 1.1 jruoho 51 1.1 jruoho static void clean(void); 52 1.1 jruoho 53 1.1 jruoho static void 54 1.1 jruoho clean(void) 55 1.1 jruoho { 56 1.1 jruoho int id; 57 1.1 jruoho 58 1.1 jruoho if ((id = msgget(MSG_KEY, 0)) != -1) 59 1.1 jruoho (void)msgctl(id, IPC_RMID, 0); 60 1.1 jruoho } 61 1.1 jruoho 62 1.1 jruoho ATF_TC_WITH_CLEANUP(msgget_excl); 63 1.1 jruoho ATF_TC_HEAD(msgget_excl, tc) 64 1.1 jruoho { 65 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test msgget(2) with IPC_EXCL"); 66 1.1 jruoho } 67 1.1 jruoho 68 1.1 jruoho ATF_TC_BODY(msgget_excl, tc) 69 1.1 jruoho { 70 1.1 jruoho int id; 71 1.1 jruoho 72 1.1 jruoho /* 73 1.1 jruoho * Create a message queue and re-open it with 74 1.1 jruoho * O_CREAT and IPC_EXCL set. This should fail. 75 1.1 jruoho */ 76 1.1 jruoho id = msgget(MSG_KEY, IPC_CREAT | 0600); 77 1.1 jruoho 78 1.1 jruoho if (id < 0) 79 1.1 jruoho atf_tc_fail("failed to create message queue"); 80 1.1 jruoho 81 1.1 jruoho errno = 0; 82 1.1 jruoho 83 1.1 jruoho if (msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | 0600) != -1) 84 1.1 jruoho atf_tc_fail("msgget(2) failed for IPC_EXCL"); 85 1.1 jruoho 86 1.1 jruoho ATF_REQUIRE(errno == EEXIST); 87 1.1 jruoho 88 1.1 jruoho /* 89 1.1 jruoho * However, the same call should succeed 90 1.1 jruoho * when IPC_EXCL is not set in the flags. 91 1.1 jruoho */ 92 1.1 jruoho id = msgget(MSG_KEY, IPC_CREAT | 0600); 93 1.1 jruoho 94 1.1 jruoho if (id < 0) 95 1.1 jruoho atf_tc_fail("msgget(2) failed to re-open"); 96 1.1 jruoho 97 1.1 jruoho ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 98 1.1 jruoho } 99 1.1 jruoho 100 1.1 jruoho ATF_TC_CLEANUP(msgget_excl, tc) 101 1.1 jruoho { 102 1.1 jruoho clean(); 103 1.1 jruoho } 104 1.1 jruoho 105 1.1 jruoho ATF_TC_WITH_CLEANUP(msgget_exit); 106 1.1 jruoho ATF_TC_HEAD(msgget_exit, tc) 107 1.1 jruoho { 108 1.1 jruoho atf_tc_set_md_var(tc, "descr", 109 1.1 jruoho "Test that XSI message queues are " 110 1.1 jruoho "not removed when the process exits"); 111 1.1 jruoho } 112 1.1 jruoho 113 1.1 jruoho ATF_TC_BODY(msgget_exit, tc) 114 1.1 jruoho { 115 1.1 jruoho int id, sta; 116 1.1 jruoho pid_t pid; 117 1.1 jruoho 118 1.1 jruoho pid = fork(); 119 1.1 jruoho ATF_REQUIRE(pid >= 0); 120 1.1 jruoho 121 1.1 jruoho if (pid == 0) { 122 1.1 jruoho 123 1.1 jruoho if (msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | 0600) == -1) 124 1.1 jruoho _exit(EXIT_FAILURE); 125 1.1 jruoho 126 1.1 jruoho _exit(EXIT_SUCCESS); 127 1.1 jruoho } 128 1.1 jruoho 129 1.1 jruoho (void)wait(&sta); 130 1.1 jruoho 131 1.1 jruoho if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) 132 1.1 jruoho atf_tc_fail("failed to create message queue"); 133 1.1 jruoho 134 1.1 jruoho id = msgget(MSG_KEY, 0); 135 1.1 jruoho 136 1.1 jruoho if (id == -1) 137 1.1 jruoho atf_tc_fail("message queue was removed on process exit"); 138 1.1 jruoho 139 1.1 jruoho ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 140 1.1 jruoho } 141 1.1 jruoho 142 1.1 jruoho ATF_TC_CLEANUP(msgget_exit, tc) 143 1.1 jruoho { 144 1.1 jruoho clean(); 145 1.1 jruoho } 146 1.1 jruoho 147 1.1 jruoho ATF_TC_WITH_CLEANUP(msgget_init); 148 1.1 jruoho ATF_TC_HEAD(msgget_init, tc) 149 1.1 jruoho { 150 1.1 jruoho atf_tc_set_md_var(tc, "descr", 151 1.1 jruoho "Test that msgget(2) initializes data structures properly"); 152 1.1 jruoho } 153 1.1 jruoho 154 1.1 jruoho ATF_TC_BODY(msgget_init, tc) 155 1.1 jruoho { 156 1.1 jruoho const uid_t uid = geteuid(); 157 1.1 jruoho const gid_t gid = getegid(); 158 1.1 jruoho struct msqid_ds msgds; 159 1.1 jruoho time_t t; 160 1.1 jruoho int id; 161 1.1 jruoho 162 1.1 jruoho (void)memset(&msgds, 0x9, sizeof(struct msqid_ds)); 163 1.1 jruoho 164 1.1 jruoho t = time(NULL); 165 1.1 jruoho id = msgget(MSG_KEY, IPC_CREAT | 0600); 166 1.1 jruoho 167 1.1 jruoho ATF_REQUIRE(id !=-1); 168 1.1 jruoho ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); 169 1.1 jruoho 170 1.1 jruoho ATF_CHECK(msgds.msg_qnum == 0); 171 1.1 jruoho ATF_CHECK(msgds.msg_lspid == 0); 172 1.1 jruoho ATF_CHECK(msgds.msg_lrpid == 0); 173 1.1 jruoho ATF_CHECK(msgds.msg_rtime == 0); 174 1.1 jruoho ATF_CHECK(msgds.msg_stime == 0); 175 1.1 jruoho ATF_CHECK(msgds.msg_perm.uid == uid); 176 1.1 jruoho ATF_CHECK(msgds.msg_perm.gid == gid); 177 1.1 jruoho ATF_CHECK(msgds.msg_perm.cuid == uid); 178 1.1 jruoho ATF_CHECK(msgds.msg_perm.cgid == gid); 179 1.1 jruoho ATF_CHECK(msgds.msg_perm.mode == 0600); 180 1.1 jruoho 181 1.2 joerg if (llabs(t - msgds.msg_ctime) > 5) 182 1.1 jruoho atf_tc_fail("msgget(2) initialized current time incorrectly"); 183 1.1 jruoho 184 1.1 jruoho ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 185 1.1 jruoho } 186 1.1 jruoho 187 1.1 jruoho ATF_TC_CLEANUP(msgget_init, tc) 188 1.1 jruoho { 189 1.1 jruoho clean(); 190 1.1 jruoho } 191 1.1 jruoho 192 1.1 jruoho ATF_TC(msgget_limit); 193 1.1 jruoho ATF_TC_HEAD(msgget_limit, tc) 194 1.1 jruoho { 195 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test msgget(2) against system limits"); 196 1.1 jruoho } 197 1.1 jruoho 198 1.1 jruoho ATF_TC_BODY(msgget_limit, tc) 199 1.1 jruoho { 200 1.1 jruoho size_t len = sizeof(int); 201 1.1 jruoho bool fail = false; 202 1.1 jruoho int i, lim = 0; 203 1.1 jruoho int *buf; 204 1.1 jruoho 205 1.1 jruoho if (sysctlbyname("kern.ipc.msgmni", &lim, &len, NULL, 0) != 0) 206 1.1 jruoho atf_tc_skip("failed to read kern.ipc.msgmni sysctl"); 207 1.1 jruoho 208 1.1 jruoho buf = calloc(lim + 1, sizeof(*buf)); 209 1.1 jruoho ATF_REQUIRE(buf != NULL); 210 1.1 jruoho 211 1.1 jruoho for (i = 0; i < lim; i++) { 212 1.1 jruoho 213 1.1 jruoho buf[i] = msgget(MSG_KEY + i, IPC_CREAT | IPC_EXCL | 0600); 214 1.1 jruoho 215 1.1 jruoho (void)fprintf(stderr, "key[%d] = %d\n", i, buf[i]); 216 1.1 jruoho 217 1.1 jruoho /* 218 1.1 jruoho * This test only works when there are zero existing 219 1.1 jruoho * message queues. Thus, bypass the unit test when 220 1.1 jruoho * this precondition is not met, for reason or another. 221 1.1 jruoho */ 222 1.1 jruoho if (buf[i] == -1) 223 1.1 jruoho goto out; 224 1.1 jruoho } 225 1.1 jruoho 226 1.1 jruoho i++; 227 1.1 jruoho errno = 0; 228 1.1 jruoho 229 1.1 jruoho buf[i] = msgget(MSG_KEY + i, IPC_CREAT | IPC_EXCL | 0600); 230 1.1 jruoho 231 1.1 jruoho if (buf[i] != -1 || errno != ENOSPC) 232 1.1 jruoho fail = true; 233 1.1 jruoho 234 1.1 jruoho out: /* Remember to clean-up. */ 235 1.1 jruoho for (i = 0; i < lim; i++) 236 1.1 jruoho (void)msgctl(buf[i], IPC_RMID, 0); 237 1.1 jruoho 238 1.1 jruoho free(buf); 239 1.1 jruoho 240 1.1 jruoho if (fail != false) 241 1.1 jruoho atf_tc_fail("msgget(2) opened more than %d queues", lim); 242 1.1 jruoho } 243 1.1 jruoho 244 1.1 jruoho ATF_TC_WITH_CLEANUP(msgget_mode); 245 1.1 jruoho ATF_TC_HEAD(msgget_mode, tc) 246 1.1 jruoho { 247 1.1 jruoho atf_tc_set_md_var(tc, "descr", "Test different modes with msgget(2)"); 248 1.1 jruoho atf_tc_set_md_var(tc, "require.user", "root"); 249 1.1 jruoho } 250 1.1 jruoho 251 1.1 jruoho ATF_TC_BODY(msgget_mode, tc) 252 1.1 jruoho { 253 1.1 jruoho static const mode_t mode[] = { 254 1.1 jruoho S_IRWXU, S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXG, S_IRGRP, 255 1.1 jruoho S_IWGRP, S_IXGRP, S_IRWXO, S_IROTH, S_IWOTH, S_IXOTH 256 1.1 jruoho }; 257 1.1 jruoho 258 1.1 jruoho struct msqid_ds msgds; 259 1.1 jruoho size_t i; 260 1.1 jruoho int id; 261 1.1 jruoho 262 1.1 jruoho for (i = 0; i < __arraycount(mode); i++) { 263 1.1 jruoho 264 1.1 jruoho (void)fprintf(stderr, "testing mode %d\n", mode[i]); 265 1.1 jruoho (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 266 1.1 jruoho 267 1.1 jruoho id = msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | (int)mode[i]); 268 1.1 jruoho 269 1.1 jruoho ATF_REQUIRE(id != -1); 270 1.1 jruoho ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); 271 1.1 jruoho ATF_REQUIRE(msgds.msg_perm.mode == mode[i]); 272 1.1 jruoho ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 273 1.1 jruoho } 274 1.1 jruoho } 275 1.1 jruoho 276 1.1 jruoho ATF_TC_CLEANUP(msgget_mode, tc) 277 1.1 jruoho { 278 1.1 jruoho clean(); 279 1.1 jruoho } 280 1.1 jruoho 281 1.3 kre static volatile int sig_caught; 282 1.3 kre 283 1.3 kre static void 284 1.3 kre sigsys_handler(int signum) 285 1.3 kre { 286 1.3 kre 287 1.3 kre sig_caught = signum; 288 1.3 kre } 289 1.3 kre 290 1.3 kre static int 291 1.3 kre no_kernel_sysvmsg(void) 292 1.3 kre { 293 1.3 kre int id; 294 1.3 kre void (*osig)(int); 295 1.3 kre 296 1.3 kre sig_caught = 0; 297 1.3 kre osig = signal(SIGSYS, sigsys_handler); 298 1.3 kre id = msgget(MSG_KEY, IPC_CREAT | 0600); 299 1.3 kre if (sig_caught || id == -1) 300 1.3 kre return 1; 301 1.3 kre 302 1.3 kre (void)msgctl(id, IPC_RMID, 0); 303 1.3 kre (void)signal(SIGSYS, osig); 304 1.3 kre 305 1.3 kre return 0; 306 1.3 kre } 307 1.3 kre 308 1.3 kre ATF_TC(msgget_query); 309 1.3 kre ATF_TC_HEAD(msgget_query, tc) 310 1.3 kre { 311 1.3 kre atf_tc_set_md_var(tc, "descr", "Skip msgget_* tests - no SYSVMSG"); 312 1.3 kre } 313 1.3 kre ATF_TC_BODY(msgget_query, tc) 314 1.3 kre { 315 1.3 kre atf_tc_skip("No SYSVMSG in kernel"); 316 1.3 kre } 317 1.1 jruoho 318 1.1 jruoho ATF_TP_ADD_TCS(tp) 319 1.1 jruoho { 320 1.1 jruoho 321 1.3 kre if (no_kernel_sysvmsg()) { 322 1.3 kre ATF_TP_ADD_TC(tp, msgget_query); 323 1.3 kre } else { 324 1.3 kre ATF_TP_ADD_TC(tp, msgget_excl); 325 1.3 kre ATF_TP_ADD_TC(tp, msgget_exit); 326 1.3 kre ATF_TP_ADD_TC(tp, msgget_init); 327 1.3 kre ATF_TP_ADD_TC(tp, msgget_limit); 328 1.3 kre ATF_TP_ADD_TC(tp, msgget_mode); 329 1.3 kre } 330 1.1 jruoho 331 1.1 jruoho return atf_no_error(); 332 1.1 jruoho } 333