1/*
2 * Copyright (c) 2003, Intel Corporation. All rights reserved.
3 * Created by:  crystal.xiong 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_unlink() test plan:
11 *  If one or more process have the message queue open, destruction of the
12 *  message queue will be postponed until all reference to the message queue
13 *  have been closed. At this time, call to mq_open() with O_CREAT flag may fail
14 *  until the message queue is actually removed.
15 *  Steps:
16 *  1. Create 2 pipes to communicate with parent and child processes.
17 *  2. Parent uses mq_open to create a new mq and tell child to open it using pipe.
18 *  3. Child open the mq and tell Parent, so mq has 2 reference now.
19 *  4. Parent mq_unlink the mq and tell Child to close this mq.
20 *  5. Child close the mq and tell parent.
21 *  6. Parent recreate the mq using mq_open, if the mq is actually removed, this operation
22 *     will succeed, if not, it may fail.
23 */
24
25#include <signal.h>
26#include <stdio.h>
27#include <errno.h>
28#include <mqueue.h>
29#include <fcntl.h>
30#include <sys/stat.h>
31#include <sys/types.h>
32#include <unistd.h>
33#include "posixtest.h"
34
35#define PIPE_READ  0
36#define PIPE_WRITE 1
37
38#define TEST "2-2"
39#define FUNCTION "mq_unlink"
40#define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": "
41
42int parent_process(char *mqname, int read_pipe, int write_pipe, int child_pid);
43int child_process(char *mqname, int read_pipe, int write_pipe);
44int send_receive(int read_pipe, int write_pipe, char send, char *reply);
45
46int main()
47{
48	char mqname[50];
49	pid_t pid;
50	int to_parent[2];
51        int to_child[2];
52	int rval;
53	struct sigaction sa;
54
55	sa.sa_handler = SIG_IGN;
56	sa.sa_flags = 0;
57	sigemptyset(&sa.sa_mask);
58	sigaction(SIGCHLD, &sa, NULL);
59
60	sprintf(mqname, "/" FUNCTION "_" TEST "_%d", getpid());
61	rval = pipe(to_parent);
62        if (rval == -1) {
63                perror(ERROR_PREFIX "fd[0]");
64                return PTS_UNRESOLVED;
65        }
66        rval = pipe(to_child);
67        if (rval == -1) {
68               perror(ERROR_PREFIX "fd[1]");
69               return PTS_UNRESOLVED;
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		return child_process(mqname, to_child[PIPE_READ],
81                                     to_parent[PIPE_WRITE]);
82	}
83	else {
84		//parent process
85		close(to_parent[PIPE_WRITE]);
86                close(to_child[PIPE_READ]);
87		return parent_process(mqname, to_parent[PIPE_READ],
88                                      to_child[PIPE_WRITE], pid);
89	}
90}
91int parent_process(char *mqname, int read_pipe, int write_pipe, int child_pid)
92{
93	mqd_t mqdes;
94	char reply;
95	int rval;
96
97	mqdes = mq_open(mqname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, 0);
98	if (mqdes == (mqd_t)-1) {
99		perror(ERROR_PREFIX "mq_open");
100		return PTS_UNRESOLVED;
101	}
102	// Tell child a message queue has been opened.
103	rval = send_receive(read_pipe, write_pipe, 'a', &reply);
104	if (rval) {
105	        return rval;
106        }
107	if (reply != 'b') {
108	        printf(ERROR_PREFIX "send_receive: " "expected a 'b'\n");
109                return PTS_UNRESOLVED;
110        }
111	if (mq_unlink(mqname) == 0) {
112		rval = send_receive(read_pipe, write_pipe, 'c', &reply);
113		if (rval) {
114		        return rval;
115	        }
116	        if (reply != 'd') {
117		        printf(ERROR_PREFIX "send_receive: " "expected a 'd'\n");
118	                return PTS_UNRESOLVED;
119	        }
120		if (mq_open(mqname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, 0) != -1) {
121			if (mq_unlink(mqname) != 0) {
122		        	perror(ERROR_PREFIX "mq_unlink(2)");
123	                	return PTS_UNRESOLVED;
124			}
125			printf("Test PASSED\n");
126			return PTS_PASS;
127		}
128		else {
129			printf("mq_open may fail until the message queue is actually removed \n");
130			printf("Test PASSED\n");
131			return PTS_PASS;
132		}
133	}
134	printf(ERROR_PREFIX "mq_unlink\n");
135	return PTS_UNRESOLVED;
136}
137
138int child_process(char *mqname, int read_pipe, int write_pipe)
139{
140	mqd_t mqdes;
141	int rval;
142	char reply;
143
144	rval = send_receive(read_pipe, write_pipe, 0, &reply);
145	if (rval) {
146                return rval;
147        }
148        if (reply != 'a') {
149                printf(ERROR_PREFIX "send_receive: " "expected an 'a'");
150                return PTS_UNRESOLVED;
151        }
152	mqdes = mq_open(mqname, O_RDWR, 0, 0);
153	if (mqdes == (mqd_t)-1) {
154		perror(ERROR_PREFIX "mq_open");
155		return PTS_UNRESOLVED;
156	}
157	rval = send_receive(read_pipe, write_pipe, 'b', &reply);
158	if (rval) {
159                return rval;
160        }
161	if (reply != 'c') {
162                printf(ERROR_PREFIX "send_receive: " "expected a 'c'\n");
163                return PTS_UNRESOLVED;
164        }
165	if (mq_close(mqdes) == -1) {
166		perror(ERROR_PREFIX "mq_close");
167		return PTS_UNRESOLVED;
168	}
169	rval = send_receive(read_pipe, write_pipe, 'd', NULL);
170        if (rval) {
171                return rval;
172        }
173	return 0;
174}
175
176int send_receive(int read_pipe, int write_pipe, char send, char *reply)
177{
178        ssize_t bytes;
179        if (send) {
180                bytes = write(write_pipe, &send, 1);
181                if (bytes == -1) {
182                perror(ERROR_PREFIX "write fd[1]");
183                return PTS_UNRESOLVED;
184	        }
185        }
186        if (reply) {
187                bytes = read(read_pipe, reply, 1);
188                if (bytes == -1) {
189	                perror(ERROR_PREFIX "read fd[0]");
190                        return PTS_UNRESOLVED;
191                } else if (bytes == 0) {
192                        printf(ERROR_PREFIX "read: EOF\n");
193                        return PTS_UNRESOLVED;
194                }
195        }
196	return 0;
197}
198