t_msgget.c revision 276478
1219888Sed/* $NetBSD: t_msgget.c,v 1.2 2014/02/27 00:59:50 joerg Exp $ */ 2219888Sed 3219888Sed/*- 4219888Sed * Copyright (c) 2011 The NetBSD Foundation, Inc. 5219888Sed * All rights reserved. 6219888Sed * 7219888Sed * This code is derived from software contributed to The NetBSD Foundation 8219888Sed * by Jukka Ruohonen. 9219888Sed * 10219888Sed * Redistribution and use in source and binary forms, with or without 11219888Sed * modification, are permitted provided that the following conditions 12219888Sed * are met: 13219888Sed * 1. Redistributions of source code must retain the above copyright 14219888Sed * notice, this list of conditions and the following disclaimer. 15219888Sed * 2. Redistributions in binary form must reproduce the above copyright 16219888Sed * notice, this list of conditions and the following disclaimer in the 17219888Sed * documentation and/or other materials provided with the distribution. 18219888Sed * 19219888Sed * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20219888Sed * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21219888Sed * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22219888Sed * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23219888Sed * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24219888Sed * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25219888Sed * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26219888Sed * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27219888Sed * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28219888Sed * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29219888Sed * POSSIBILITY OF SUCH DAMAGE. 30219888Sed */ 31219888Sed#include <sys/cdefs.h> 32219888Sed__RCSID("$NetBSD: t_msgget.c,v 1.2 2014/02/27 00:59:50 joerg Exp $"); 33219888Sed 34219888Sed#include <sys/msg.h> 35219888Sed#include <sys/stat.h> 36219888Sed#include <sys/sysctl.h> 37219888Sed#include <sys/wait.h> 38219888Sed 39219888Sed#include <atf-c.h> 40219888Sed#include <errno.h> 41219888Sed#include <pwd.h> 42219888Sed#include <stdio.h> 43219888Sed#include <stdlib.h> 44219888Sed#include <string.h> 45219888Sed#include <sysexits.h> 46219888Sed#include <time.h> 47219888Sed#include <unistd.h> 48219888Sed 49219888Sed#define MSG_KEY 12345689 50219888Sed 51219888Sedstatic void clean(void); 52219888Sed 53219888Sedstatic void 54219888Sedclean(void) 55219888Sed{ 56219888Sed int id; 57219888Sed 58219888Sed if ((id = msgget(MSG_KEY, 0)) != -1) 59219888Sed (void)msgctl(id, IPC_RMID, 0); 60219888Sed} 61219888Sed 62219888SedATF_TC_WITH_CLEANUP(msgget_excl); 63219888SedATF_TC_HEAD(msgget_excl, tc) 64219888Sed{ 65219888Sed atf_tc_set_md_var(tc, "descr", "Test msgget(2) with IPC_EXCL"); 66219888Sed} 67219888Sed 68219888SedATF_TC_BODY(msgget_excl, tc) 69219888Sed{ 70219888Sed int id; 71219888Sed 72219888Sed /* 73219888Sed * Create a message queue and re-open it with 74219888Sed * O_CREAT and IPC_EXCL set. This should fail. 75219888Sed */ 76219888Sed id = msgget(MSG_KEY, IPC_CREAT | 0600); 77219888Sed 78219888Sed if (id < 0) 79219888Sed atf_tc_fail("failed to create message queue"); 80219888Sed 81219888Sed errno = 0; 82219888Sed 83219888Sed if (msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | 0600) != -1) 84219888Sed atf_tc_fail("msgget(2) failed for IPC_EXCL"); 85219888Sed 86219888Sed ATF_REQUIRE(errno == EEXIST); 87219888Sed 88219888Sed /* 89219888Sed * However, the same call should succeed 90219888Sed * when IPC_EXCL is not set in the flags. 91219888Sed */ 92219888Sed id = msgget(MSG_KEY, IPC_CREAT | 0600); 93219888Sed 94219888Sed if (id < 0) 95219888Sed atf_tc_fail("msgget(2) failed to re-open"); 96219888Sed 97219888Sed ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 98219888Sed} 99219888Sed 100219888SedATF_TC_CLEANUP(msgget_excl, tc) 101219888Sed{ 102219888Sed clean(); 103219888Sed} 104219888Sed 105219888SedATF_TC_WITH_CLEANUP(msgget_exit); 106219888SedATF_TC_HEAD(msgget_exit, tc) 107219888Sed{ 108219888Sed atf_tc_set_md_var(tc, "descr", 109219888Sed "Test that XSI message queues are " 110219888Sed "not removed when the process exits"); 111219888Sed} 112219888Sed 113219888SedATF_TC_BODY(msgget_exit, tc) 114219888Sed{ 115219888Sed int id, sta; 116219888Sed pid_t pid; 117219888Sed 118219888Sed pid = fork(); 119219888Sed ATF_REQUIRE(pid >= 0); 120219888Sed 121219888Sed if (pid == 0) { 122219888Sed 123219888Sed if (msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | 0600) == -1) 124219888Sed _exit(EXIT_FAILURE); 125219888Sed 126219888Sed _exit(EXIT_SUCCESS); 127219888Sed } 128219888Sed 129219888Sed (void)wait(&sta); 130219888Sed 131219888Sed if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) 132219888Sed atf_tc_fail("failed to create message queue"); 133219888Sed 134219888Sed id = msgget(MSG_KEY, 0); 135219888Sed 136219888Sed if (id == -1) 137219888Sed atf_tc_fail("message queue was removed on process exit"); 138219888Sed 139219888Sed ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 140219888Sed} 141219888Sed 142219888SedATF_TC_CLEANUP(msgget_exit, tc) 143219888Sed{ 144219888Sed clean(); 145219888Sed} 146219888Sed 147219888SedATF_TC_WITH_CLEANUP(msgget_init); 148219888SedATF_TC_HEAD(msgget_init, tc) 149219888Sed{ 150219888Sed atf_tc_set_md_var(tc, "descr", 151219888Sed "Test that msgget(2) initializes data structures properly"); 152219888Sed} 153219888Sed 154219888SedATF_TC_BODY(msgget_init, tc) 155219888Sed{ 156219888Sed const uid_t uid = geteuid(); 157219888Sed const gid_t gid = getegid(); 158219888Sed struct msqid_ds msgds; 159219888Sed time_t t; 160219888Sed int id; 161219888Sed 162219888Sed (void)memset(&msgds, 0x9, sizeof(struct msqid_ds)); 163219888Sed 164219888Sed t = time(NULL); 165219888Sed id = msgget(MSG_KEY, IPC_CREAT | 0600); 166219888Sed 167219888Sed ATF_REQUIRE(id !=-1); 168219888Sed ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); 169219888Sed 170219888Sed ATF_CHECK(msgds.msg_qnum == 0); 171219888Sed ATF_CHECK(msgds.msg_lspid == 0); 172219888Sed ATF_CHECK(msgds.msg_lrpid == 0); 173219888Sed ATF_CHECK(msgds.msg_rtime == 0); 174219888Sed ATF_CHECK(msgds.msg_stime == 0); 175219888Sed ATF_CHECK(msgds.msg_perm.uid == uid); 176219888Sed ATF_CHECK(msgds.msg_perm.gid == gid); 177219888Sed ATF_CHECK(msgds.msg_perm.cuid == uid); 178219888Sed ATF_CHECK(msgds.msg_perm.cgid == gid); 179219888Sed ATF_CHECK(msgds.msg_perm.mode == 0600); 180219888Sed 181219888Sed if (llabs(t - msgds.msg_ctime) > 5) 182219888Sed atf_tc_fail("msgget(2) initialized current time incorrectly"); 183219888Sed 184219888Sed ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 185219888Sed} 186219888Sed 187219888SedATF_TC_CLEANUP(msgget_init, tc) 188219888Sed{ 189219888Sed clean(); 190219888Sed} 191219888Sed 192219888SedATF_TC(msgget_limit); 193219888SedATF_TC_HEAD(msgget_limit, tc) 194219888Sed{ 195219888Sed atf_tc_set_md_var(tc, "descr", "Test msgget(2) against system limits"); 196219888Sed} 197219888Sed 198219888SedATF_TC_BODY(msgget_limit, tc) 199219888Sed{ 200219888Sed size_t len = sizeof(int); 201219888Sed bool fail = false; 202219888Sed int i, lim = 0; 203219888Sed int *buf; 204219888Sed 205219888Sed if (sysctlbyname("kern.ipc.msgmni", &lim, &len, NULL, 0) != 0) 206219888Sed atf_tc_skip("failed to read kern.ipc.msgmni sysctl"); 207219888Sed 208219888Sed buf = calloc(lim + 1, sizeof(*buf)); 209219888Sed ATF_REQUIRE(buf != NULL); 210219888Sed 211219888Sed for (i = 0; i < lim; i++) { 212219888Sed 213219888Sed buf[i] = msgget(MSG_KEY + i, IPC_CREAT | IPC_EXCL | 0600); 214219888Sed 215219888Sed (void)fprintf(stderr, "key[%d] = %d\n", i, buf[i]); 216219888Sed 217219888Sed /* 218219888Sed * This test only works when there are zero existing 219219888Sed * message queues. Thus, bypass the unit test when 220219888Sed * this precondition is not met, for reason or another. 221219888Sed */ 222219888Sed if (buf[i] == -1) 223219888Sed goto out; 224219888Sed } 225219888Sed 226219888Sed i++; 227219888Sed errno = 0; 228219888Sed 229219888Sed buf[i] = msgget(MSG_KEY + i, IPC_CREAT | IPC_EXCL | 0600); 230219888Sed 231219888Sed if (buf[i] != -1 || errno != ENOSPC) 232219888Sed fail = true; 233219888Sed 234219888Sedout: /* Remember to clean-up. */ 235219888Sed for (i = 0; i < lim; i++) 236219888Sed (void)msgctl(buf[i], IPC_RMID, 0); 237219888Sed 238219888Sed free(buf); 239219888Sed 240219888Sed if (fail != false) 241219888Sed atf_tc_fail("msgget(2) opened more than %d queues", lim); 242219888Sed} 243219888Sed 244219888SedATF_TC_WITH_CLEANUP(msgget_mode); 245219888SedATF_TC_HEAD(msgget_mode, tc) 246219888Sed{ 247219888Sed atf_tc_set_md_var(tc, "descr", "Test different modes with msgget(2)"); 248219888Sed atf_tc_set_md_var(tc, "require.user", "root"); 249219888Sed} 250219888Sed 251219888SedATF_TC_BODY(msgget_mode, tc) 252219888Sed{ 253219888Sed static const mode_t mode[] = { 254219888Sed S_IRWXU, S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXG, S_IRGRP, 255219888Sed S_IWGRP, S_IXGRP, S_IRWXO, S_IROTH, S_IWOTH, S_IXOTH 256219888Sed }; 257219888Sed 258219888Sed struct msqid_ds msgds; 259219888Sed size_t i; 260219888Sed int id; 261219888Sed 262219888Sed for (i = 0; i < __arraycount(mode); i++) { 263219888Sed 264219888Sed (void)fprintf(stderr, "testing mode %d\n", mode[i]); 265219888Sed (void)memset(&msgds, 0, sizeof(struct msqid_ds)); 266219888Sed 267219888Sed id = msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | (int)mode[i]); 268219888Sed 269219888Sed ATF_REQUIRE(id != -1); 270219888Sed ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); 271219888Sed ATF_REQUIRE(msgds.msg_perm.mode == mode[i]); 272219888Sed ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); 273219888Sed } 274219888Sed} 275219888Sed 276219888SedATF_TC_CLEANUP(msgget_mode, tc) 277219888Sed{ 278219888Sed clean(); 279219888Sed} 280219888Sed 281219888Sed 282219888SedATF_TP_ADD_TCS(tp) 283219888Sed{ 284219888Sed 285219888Sed ATF_TP_ADD_TC(tp, msgget_excl); 286219888Sed ATF_TP_ADD_TC(tp, msgget_exit); 287219888Sed ATF_TP_ADD_TC(tp, msgget_init); 288219888Sed ATF_TP_ADD_TC(tp, msgget_limit); 289219888Sed ATF_TP_ADD_TC(tp, msgget_mode); 290219888Sed 291219888Sed return atf_no_error(); 292219888Sed} 293219888Sed