1/*
2 * Copyright (c) 2003, Intel Corporation. All rights reserved.
3 * Created by:  julie.n.fleischer REMOVE-THIS AT intel DOT com
4 * This file is licensed under the GPL license.  For the full content
5 * of this license, see the COPYING file at the top level of this
6 * source tree.
7 */
8
9/*
10 * Test that tests to check if O_CREAT and O_EXCL are set that no other
11 * message queue exists are atomic.
12 *
13 * Test case will just attempt to call mq_open() with O_CREAT and O_EXCL
14 * using the same name in two different processes.  If one process fails,
15 * the test is considered a pass.
16 *
17 * This is a best attempt to test that these are atomic.  It does make the
18 * assumption (which could generally be untrue) that both mq_open() calls
19 * will attempt to be made at the same time.  For the sake of this test case,
20 * this is fine (will have some false positives, but no false negatives).
21 */
22
23#include <sys/mman.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/wait.h>
27#include <errno.h>
28#include <fcntl.h>
29#include <mqueue.h>
30#include <signal.h>
31#include <stdio.h>
32#include <string.h>
33#include <unistd.h>
34#include "posixtest.h"
35
36#define NAMESIZE 50
37#define TNAME "mq_open/16-1.c"
38
39int main(void)
40{
41	char qname[NAMESIZE];
42	char fname[NAMESIZE];
43	int pid, succeeded = 0;
44	int fd;
45	void *pa = NULL;
46	mqd_t childqueue, queue;
47
48	/*
49	 * initialize both queues
50	 */
51	childqueue = (mqd_t) - 1;
52	queue = (mqd_t) - 1;
53
54	sprintf(qname, "/mq_open_16-1_%d", getpid());
55
56	sprintf(fname, "/tmp/pts_mq_open_16_1_%d", getpid());
57	unlink(fname);
58	fd = open(fname, O_CREAT | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
59	if (fd == -1) {
60		printf(TNAME " Error at open(): %s\n", strerror(errno));
61		return PTS_UNRESOLVED;
62	}
63	/* file is empty now, will cause "Bus error" */
64	write(fd, fname, sizeof(int));
65	unlink(fname);
66
67	pa = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
68	if (pa == MAP_FAILED) {
69		printf(TNAME " Error at mmap: %s\n", strerror(errno));
70		close(fd);
71		return PTS_FAIL;
72	}
73	*(int *)pa = 0;
74
75	pid = fork();
76	if (pid == 0) {
77		sigset_t mask;
78		int sig;
79
80		/* child here */
81
82		/* try to sync with parent for mq_open */
83		sigemptyset(&mask);
84		sigaddset(&mask, SIGUSR1);
85		sigprocmask(SIG_BLOCK, &mask, NULL);
86		sigwait(&mask, &sig);
87
88		childqueue = mq_open(qname, O_CREAT | O_EXCL | O_RDWR,
89				     S_IRUSR | S_IWUSR, NULL);
90		if (childqueue != (mqd_t) - 1) {
91			++*(int *)pa;
92#ifdef DEBUG
93			printf("mq_open() in child succeeded\n");
94		} else {
95			printf("mq_open() in child failed\n");
96#endif
97		}
98	} else {
99		/* parent here */
100		int i;
101
102		sleep(1);
103		kill(pid, SIGUSR1);
104
105		queue = mq_open(qname, O_CREAT | O_EXCL | O_RDWR,
106				S_IRUSR | S_IWUSR, NULL);
107		if (queue != (mqd_t) - 1) {
108			++*(int *)pa;
109#ifdef DEBUG
110			printf("mq_open() in parent succeeded\n");
111		} else {
112			printf("mq_open() in parent failed\n");
113#endif
114		}
115
116		if (wait(&i) == -1) {
117			perror("Error waiting for child to exit");
118			printf("Test UNRESOLVED\n");
119			mq_close(queue);
120			mq_close(childqueue);
121			mq_unlink(qname);
122			close(fd);
123			munmap(pa, sizeof(int));
124			return PTS_UNRESOLVED;
125		}
126
127		mq_close(queue);
128		mq_close(childqueue);
129		mq_unlink(qname);
130
131		succeeded = *(int *)pa;
132		close(fd);
133		munmap(pa, sizeof(int));
134
135		if (succeeded == 0) {
136			printf("Test FAILED - mq_open() never succeeded\n");
137			return PTS_FAIL;
138		}
139
140		if (succeeded > 1) {
141			printf("Test FAILED - mq_open() succeeded twice\n");
142			return PTS_FAIL;
143		}
144
145		printf("Test PASSED\n");
146		return PTS_PASS;
147	}
148
149	return PTS_UNRESOLVED;
150}
151