1/*
2 * Copyright (c) 2002, Intel Corporation. All rights reserved.
3 * Created by:  geoffrey.r.gustafson 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  mq_close test plan:
11  1. Create pipes to communicate with child process
12  2. Fork, child waits for command on pipe
13  3. Create and open message queue, set up notification, sends command
14  4. Child opens message queue and tries to set up notification, sends command
15  5. Parent closes the queue, sends command
16  6. Child tries again to set up notification (should succeed verifying that
17      the close successfully removed notify association), sends command
18  7. Parent reports result
19*/
20
21#include <signal.h>
22#include <stdio.h>
23#include <mqueue.h>
24#include <sys/types.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <sys/stat.h>
28#include <errno.h>
29#include "posixtest.h"
30
31#define TEST "2-1"
32#define FUNCTION "mq_close"
33#define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": "
34
35#define PIPE_READ  0
36#define PIPE_WRITE 1
37
38int parent_process(char *qname, int read_pipe, int write_pipe, int child_pid);
39int child_process(char *qname, int read_pipe, int write_pipe);
40mqd_t open_queue(char *qname, int oflag, int mode);
41int send_receive(int read_pipe, int write_pipe, char send, char *reply);
42
43int main()
44{
45	char qname[50];
46	pid_t pid;
47	int rval;
48	int to_parent[2];
49	int to_child[2];
50	struct sigaction sa;
51
52	sprintf(qname, "/" FUNCTION "_" TEST "_%d", getpid());
53
54	rval = pipe(to_parent);
55	if (rval == -1) {
56		perror(ERROR_PREFIX "pipe (1)");
57		return PTS_UNRESOLVED;
58	}
59
60	rval = pipe(to_child);
61	if (rval == -1) {
62		perror(ERROR_PREFIX "pipe (2)");
63		return PTS_UNRESOLVED;
64	}
65
66	sa.sa_handler = SIG_IGN;
67	sa.sa_flags = 0;
68	sigemptyset(&sa.sa_mask);
69	sigaction(SIGCHLD, &sa, NULL);
70
71	pid = fork();
72	if (pid == -1) {
73		perror(ERROR_PREFIX "fork");
74		return PTS_UNRESOLVED;
75	}
76	if (pid == 0) {
77		// child process
78		close(to_parent[PIPE_READ]);
79		close(to_child[PIPE_WRITE]);
80
81		return child_process(qname, to_child[PIPE_READ],
82				     to_parent[PIPE_WRITE]);
83	} else {
84		// parent process
85		close(to_parent[PIPE_WRITE]);
86		close(to_child[PIPE_READ]);
87
88		return parent_process(qname, to_parent[PIPE_READ],
89				      to_child[PIPE_WRITE], pid);
90	}
91
92	return PTS_UNRESOLVED;
93}
94
95int parent_process(char *qname, int read_pipe, int write_pipe, int child_pid)
96{
97	mqd_t queue;
98	struct sigevent se;
99	int rval;
100	char reply;
101
102	queue = open_queue(qname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
103	if (queue == (mqd_t)-1) {
104		return PTS_UNRESOLVED;
105	}
106
107	se.sigev_notify = SIGEV_SIGNAL;
108	se.sigev_signo = SIGUSR1;
109
110	if (mq_notify(queue, &se)) {
111		perror(ERROR_PREFIX "mq_notify (1)");
112		mq_close(queue);
113		mq_unlink(qname);
114		return PTS_UNRESOLVED;
115	}
116
117	// send 'a' - signal child to verify it can't call notify
118	rval = send_receive(read_pipe, write_pipe, 'a', &reply);
119	if (rval) {
120		mq_close(queue);
121		mq_unlink(qname);
122		return rval;
123	}
124
125	if (reply != 'b') {
126		puts(ERROR_PREFIX "send_receive: "
127		     "expected a 'b'");
128		mq_close(queue);
129		mq_unlink(qname);
130		return PTS_UNRESOLVED;
131	}
132
133	// close the queue to perform test
134	rval = mq_close(queue);
135	mq_unlink(qname);
136	if (rval) {
137		perror(ERROR_PREFIX "mq_close:");
138		return PTS_UNRESOLVED;
139	}
140	// send 'c' - signal child to verify it can call notify
141	rval = send_receive(read_pipe, write_pipe, 'c', &reply);
142	if (rval) {
143		return rval;
144	}
145
146	if (reply == 'd') {
147		puts("Test PASSED");
148		return PTS_PASS;
149	} else if (reply == 'e') {
150		puts("Test FAILED");
151		return PTS_FAIL;
152	} else {
153		puts(ERROR_PREFIX "bad reply from child");
154		return PTS_UNRESOLVED;
155	}
156}
157
158int child_process(char *qname, int read_pipe, int write_pipe)
159{
160	mqd_t queue;
161	struct sigevent se;
162	char reply;
163	int rval;
164
165	// wait for 'a' signal from parent
166	rval = send_receive(read_pipe, write_pipe, 0, &reply);
167	if (rval) {
168		return rval;
169	}
170
171	if (reply != 'a') {
172		puts(ERROR_PREFIX "send_receive: "
173		     "expected an 'a'");
174		return PTS_UNRESOLVED;
175	}
176
177	// open the queue and attempt to set up notification
178	queue = open_queue(qname, O_RDWR, 0);
179	if (queue == (mqd_t)-1) {
180		return PTS_UNRESOLVED;
181	}
182
183	// try notify while parent still has queue open - should fail
184	se.sigev_notify = SIGEV_SIGNAL;
185	if (!mq_notify(queue, &se)) {
186		puts(ERROR_PREFIX "mq_notify (2): "
187		     "should have failed");
188		return PTS_UNRESOLVED;
189	}
190
191	// send 'b' - signal parent to close queue
192	rval = send_receive(read_pipe, write_pipe, 'b', &reply);
193	if (rval) {
194		return rval;
195	}
196
197	if (reply != 'c') {
198		puts(ERROR_PREFIX "send_receive: "
199		     "expected a 'c'");
200		return PTS_UNRESOLVED;
201	}
202
203	// try notify after parent closed queue - should succeed
204	se.sigev_notify = SIGEV_SIGNAL;
205	se.sigev_signo = 0;
206	rval = mq_notify(queue, &se);
207
208	// send 'd' for success and 'e' for failure
209	send_receive(read_pipe, write_pipe, rval ? 'e':'d', NULL);
210
211	return 0;
212}
213
214mqd_t open_queue(char *qname, int oflag, int mode) {
215	mqd_t queue;
216
217	queue = mq_open(qname, oflag, mode, NULL);
218	if (queue == (mqd_t)-1) {
219		perror(ERROR_PREFIX "mq_open");
220	}
221
222	return queue;
223}
224
225int send_receive(int read_pipe, int write_pipe, char send, char *reply) {
226	ssize_t bytes;
227
228	if (send) {
229		bytes = write(write_pipe, &send, 1);
230		if (bytes == -1) {
231			perror(ERROR_PREFIX "write (1)");
232			return PTS_UNRESOLVED;
233		}
234	}
235
236	if (reply) {
237		bytes = read(read_pipe, reply, 1);
238		if (bytes == -1) {
239			perror(ERROR_PREFIX "read");
240			return PTS_UNRESOLVED;
241		} else if (bytes == 0) {
242			puts(ERROR_PREFIX "read: EOF");
243			return PTS_UNRESOLVED;
244		}
245	}
246
247	return 0;
248}
249