t_msgget.c revision 285830
190075Sobrien/* $NetBSD: t_msgget.c,v 1.2 2014/02/27 00:59:50 joerg Exp $ */
250397Sobrien
3169689Skan/*-
450397Sobrien * Copyright (c) 2011 The NetBSD Foundation, Inc.
590075Sobrien * All rights reserved.
650397Sobrien *
790075Sobrien * This code is derived from software contributed to The NetBSD Foundation
890075Sobrien * by Jukka Ruohonen.
990075Sobrien *
1090075Sobrien * Redistribution and use in source and binary forms, with or without
1150397Sobrien * modification, are permitted provided that the following conditions
1290075Sobrien * are met:
1390075Sobrien * 1. Redistributions of source code must retain the above copyright
1490075Sobrien *    notice, this list of conditions and the following disclaimer.
1590075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1650397Sobrien *    notice, this list of conditions and the following disclaimer in the
1750397Sobrien *    documentation and/or other materials provided with the distribution.
1890075Sobrien *
19169689Skan * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20169689Skan * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2150397Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2250397Sobrien * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2350397Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2450397Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2550397Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2650397Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2750397Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2850397Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2990075Sobrien * POSSIBILITY OF SUCH DAMAGE.
3090075Sobrien */
3150397Sobrien#include <sys/cdefs.h>
3290075Sobrien__RCSID("$NetBSD: t_msgget.c,v 1.2 2014/02/27 00:59:50 joerg Exp $");
3350397Sobrien
3450397Sobrien#include <sys/msg.h>
35169689Skan#include <sys/stat.h>
3650397Sobrien#include <sys/sysctl.h>
3750397Sobrien#include <sys/wait.h>
3850397Sobrien
3990075Sobrien#include <atf-c.h>
4090075Sobrien#include <errno.h>
4190075Sobrien#include <pwd.h>
4290075Sobrien#include <stdio.h>
4390075Sobrien#include <stdlib.h>
4490075Sobrien#include <string.h>
4590075Sobrien#include <sysexits.h>
4690075Sobrien#include <time.h>
4790075Sobrien#include <unistd.h>
4890075Sobrien
4990075Sobrien#define MSG_KEY		12345689
5090075Sobrien
5190075Sobrienstatic void		clean(void);
5290075Sobrien
5350397Sobrienstatic void
54117395Skanclean(void)
5550397Sobrien{
5690075Sobrien	int id;
5790075Sobrien
5890075Sobrien	if ((id = msgget(MSG_KEY, 0)) != -1)
5990075Sobrien		(void)msgctl(id, IPC_RMID, 0);
6090075Sobrien}
6190075Sobrien
62117395SkanATF_TC_WITH_CLEANUP(msgget_excl);
6390075SobrienATF_TC_HEAD(msgget_excl, tc)
6490075Sobrien{
6590075Sobrien	atf_tc_set_md_var(tc, "descr", "Test msgget(2) with IPC_EXCL");
6690075Sobrien}
6790075Sobrien
6890075SobrienATF_TC_BODY(msgget_excl, tc)
6990075Sobrien{
7090075Sobrien	int id;
7190075Sobrien
72117395Skan	/*
7390075Sobrien	 * Create a message queue and re-open it with
7490075Sobrien	 * O_CREAT and IPC_EXCL set. This should fail.
7590075Sobrien	 */
7690075Sobrien	id = msgget(MSG_KEY, IPC_CREAT | 0600);
7790075Sobrien
7890075Sobrien	if (id < 0)
7990075Sobrien		atf_tc_fail("failed to create message queue");
80117395Skan
8190075Sobrien	errno = 0;
8290075Sobrien
8390075Sobrien	if (msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | 0600) != -1)
8490075Sobrien		atf_tc_fail("msgget(2) failed for IPC_EXCL");
8590075Sobrien
8690075Sobrien	ATF_REQUIRE(errno == EEXIST);
8790075Sobrien
88117395Skan	/*
8990075Sobrien	 * However, the same call should succeed
9090075Sobrien	 * when IPC_EXCL is not set in the flags.
9190075Sobrien	 */
9290075Sobrien	id = msgget(MSG_KEY, IPC_CREAT | 0600);
9390075Sobrien
9490075Sobrien	if (id < 0)
95117395Skan		atf_tc_fail("msgget(2) failed to re-open");
9690075Sobrien
9790075Sobrien	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
9890075Sobrien}
9990075Sobrien
10090075SobrienATF_TC_CLEANUP(msgget_excl, tc)
10190075Sobrien{
102117395Skan	clean();
10390075Sobrien}
10490075Sobrien
10590075SobrienATF_TC_WITH_CLEANUP(msgget_exit);
106117395SkanATF_TC_HEAD(msgget_exit, tc)
10790075Sobrien{
10890075Sobrien	atf_tc_set_md_var(tc, "descr",
10990075Sobrien	    "Test that XSI message queues are "
11090075Sobrien	    "not removed when the process exits");
11190075Sobrien}
112117395Skan
11390075SobrienATF_TC_BODY(msgget_exit, tc)
11490075Sobrien{
115117395Skan	int id, sta;
11690075Sobrien	pid_t pid;
11790075Sobrien
11890075Sobrien	pid = fork();
11990075Sobrien	ATF_REQUIRE(pid >= 0);
120117395Skan
12190075Sobrien	if (pid == 0) {
12290075Sobrien
12350397Sobrien		if (msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | 0600) == -1)
12450397Sobrien			_exit(EXIT_FAILURE);
12550397Sobrien
12690075Sobrien		_exit(EXIT_SUCCESS);
12790075Sobrien	}
128117395Skan
12990075Sobrien	(void)wait(&sta);
13090075Sobrien
13190075Sobrien	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
13290075Sobrien		atf_tc_fail("failed to create message queue");
13390075Sobrien
13490075Sobrien	id = msgget(MSG_KEY, 0);
13590075Sobrien
13650397Sobrien	if (id == -1)
137117395Skan		atf_tc_fail("message queue was removed on process exit");
13850397Sobrien
13950397Sobrien	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
14050397Sobrien}
14150397Sobrien
14290075SobrienATF_TC_CLEANUP(msgget_exit, tc)
14350397Sobrien{
144117395Skan	clean();
14550397Sobrien}
14650397Sobrien
14750397SobrienATF_TC_WITH_CLEANUP(msgget_init);
14850397SobrienATF_TC_HEAD(msgget_init, tc)
14990075Sobrien{
15050397Sobrien	atf_tc_set_md_var(tc, "descr",
151117395Skan	    "Test that msgget(2) initializes data structures properly");
15250397Sobrien}
15390075Sobrien
15450397SobrienATF_TC_BODY(msgget_init, tc)
15550397Sobrien{
15650397Sobrien	const uid_t uid = geteuid();
15790075Sobrien	const gid_t gid = getegid();
15890075Sobrien	struct msqid_ds msgds;
159117395Skan	time_t t;
16090075Sobrien	int id;
16190075Sobrien
16290075Sobrien	(void)memset(&msgds, 0x9, sizeof(struct msqid_ds));
16390075Sobrien
16490075Sobrien	t = time(NULL);
16590075Sobrien	id = msgget(MSG_KEY, IPC_CREAT | 0600);
16690075Sobrien
167117395Skan	ATF_REQUIRE(id !=-1);
16890075Sobrien	ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0);
16990075Sobrien
17090075Sobrien	ATF_CHECK(msgds.msg_qnum == 0);
17190075Sobrien	ATF_CHECK(msgds.msg_lspid == 0);
17290075Sobrien	ATF_CHECK(msgds.msg_lrpid == 0);
17390075Sobrien	ATF_CHECK(msgds.msg_rtime == 0);
17490075Sobrien	ATF_CHECK(msgds.msg_stime == 0);
17590075Sobrien	ATF_CHECK(msgds.msg_perm.uid == uid);
176117395Skan	ATF_CHECK(msgds.msg_perm.gid == gid);
17790075Sobrien	ATF_CHECK(msgds.msg_perm.cuid == uid);
17890075Sobrien	ATF_CHECK(msgds.msg_perm.cgid == gid);
17990075Sobrien	ATF_CHECK(msgds.msg_perm.mode == 0600);
18090075Sobrien
18190075Sobrien	if (llabs(t - msgds.msg_ctime) > 5)
18290075Sobrien		atf_tc_fail("msgget(2) initialized current time incorrectly");
183117395Skan
18490075Sobrien	ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
18590075Sobrien}
18690075Sobrien
18790075SobrienATF_TC_CLEANUP(msgget_init, tc)
18890075Sobrien{
18990075Sobrien	clean();
190117395Skan}
191117395Skan
19290075SobrienATF_TC(msgget_limit);
19390075SobrienATF_TC_HEAD(msgget_limit, tc)
19490075Sobrien{
19590075Sobrien	atf_tc_set_md_var(tc, "descr", "Test msgget(2) against system limits");
19690075Sobrien}
19790075Sobrien
198117395SkanATF_TC_BODY(msgget_limit, tc)
19990075Sobrien{
20090075Sobrien	size_t len = sizeof(int);
20190075Sobrien	bool fail = false;
20290075Sobrien	int i, lim = 0;
20390075Sobrien	int *buf;
20490075Sobrien
205117395Skan	if (sysctlbyname("kern.ipc.msgmni", &lim, &len, NULL, 0) != 0)
20690075Sobrien		atf_tc_skip("failed to read kern.ipc.msgmni sysctl");
20790075Sobrien
20890075Sobrien	buf = calloc(lim + 1, sizeof(*buf));
20990075Sobrien	ATF_REQUIRE(buf != NULL);
21090075Sobrien
21190075Sobrien	for (i = 0; i < lim; i++) {
21290075Sobrien
21390075Sobrien		buf[i] = msgget(MSG_KEY + i, IPC_CREAT | IPC_EXCL | 0600);
21490075Sobrien
21590075Sobrien		(void)fprintf(stderr, "key[%d] = %d\n", i, buf[i]);
21690075Sobrien
21790075Sobrien		/*
21890075Sobrien		 * This test only works when there are zero existing
21990075Sobrien		 * message queues. Thus, bypass the unit test when
22090075Sobrien		 * this precondition is not met, for reason or another.
22190075Sobrien		 */
22290075Sobrien		if (buf[i] == -1)
22390075Sobrien			goto out;
22490075Sobrien	}
22590075Sobrien
22690075Sobrien	i++;
22790075Sobrien	errno = 0;
22890075Sobrien
22990075Sobrien	buf[i] = msgget(MSG_KEY + i, IPC_CREAT | IPC_EXCL | 0600);
23090075Sobrien
23190075Sobrien	if (buf[i] != -1 || errno != ENOSPC)
23290075Sobrien		fail = true;
23390075Sobrien
23490075Sobrienout:	/* Remember to clean-up. */
23590075Sobrien	for (i = 0; i < lim; i++)
236169689Skan		(void)msgctl(buf[i], IPC_RMID, 0);
237169689Skan
238169689Skan	free(buf);
239169689Skan
240169689Skan	if (fail != false)
241169689Skan		atf_tc_fail("msgget(2) opened more than %d queues", lim);
242169689Skan}
243169689Skan
244169689SkanATF_TC_WITH_CLEANUP(msgget_mode);
245169689SkanATF_TC_HEAD(msgget_mode, tc)
246169689Skan{
247169689Skan	atf_tc_set_md_var(tc, "descr", "Test different modes with msgget(2)");
248169689Skan	atf_tc_set_md_var(tc, "require.user", "root");
249169689Skan}
250169689Skan
251169689SkanATF_TC_BODY(msgget_mode, tc)
252169689Skan{
253169689Skan	static const mode_t mode[] = {
25490075Sobrien		S_IRWXU, S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXG, S_IRGRP,
25590075Sobrien		S_IWGRP, S_IXGRP, S_IRWXO, S_IROTH, S_IWOTH, S_IXOTH
25690075Sobrien	};
25790075Sobrien
25890075Sobrien	struct msqid_ds msgds;
259	size_t i;
260	int id;
261
262	for (i = 0; i < __arraycount(mode); i++) {
263
264		(void)fprintf(stderr, "testing mode %d\n", mode[i]);
265		(void)memset(&msgds, 0, sizeof(struct msqid_ds));
266
267		id = msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | (int)mode[i]);
268
269		ATF_REQUIRE(id != -1);
270		ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0);
271		ATF_REQUIRE(msgds.msg_perm.mode == mode[i]);
272		ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0);
273	}
274}
275
276ATF_TC_CLEANUP(msgget_mode, tc)
277{
278	clean();
279}
280
281
282ATF_TP_ADD_TCS(tp)
283{
284
285	ATF_TP_ADD_TC(tp, msgget_excl);
286	ATF_TP_ADD_TC(tp, msgget_exit);
287	ATF_TP_ADD_TC(tp, msgget_init);
288	ATF_TP_ADD_TC(tp, msgget_limit);
289	ATF_TP_ADD_TC(tp, msgget_mode);
290
291	return atf_no_error();
292}
293