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 want to mq_unlink the mq, since Child does not close the mq,
20 *     mq_unlink will postpone. At this time, if using mq_open to create
21 *     a new mq with the same name, mq_open may fail.
22 *
23 *     3/27/2003    Fixed a bug pointed by Krzysztof Benedyczak and
24 *     		    Gregoire Pichon. mq_open may fail in this case. Not
25 *     		    must fail.
26 */
27
28#include <signal.h>
29#include <stdio.h>
30#include <errno.h>
31#include <mqueue.h>
32#include <fcntl.h>
33#include <sys/stat.h>
34#include <sys/types.h>
35#include <unistd.h>
36#include "posixtest.h"
37
38#define PIPE_READ  0
39#define PIPE_WRITE 1
40
41#define TEST "2-1"
42#define FUNCTION "mq_unlink"
43#define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": "
44
45#define NAMESIZE	50
46
47int parent_process(char *mqname, int read_pipe, int write_pipe, int child_pid);
48int child_process(char *mqname, int read_pipe, int write_pipe);
49int send_receive(int read_pipe, int write_pipe, char send, char *reply);
50
51int main()
52{
53	char mqname[NAMESIZE];
54	pid_t pid;
55	int to_parent[2];
56        int to_child[2];
57	int rval;
58	struct sigaction sa;
59
60	sa.sa_handler = SIG_IGN;
61	sa.sa_flags = 0;
62	sigemptyset(&sa.sa_mask);
63	sigaction(SIGCHLD, &sa, NULL);
64
65	sprintf(mqname, "/" FUNCTION "_" TEST "_%d", getpid());
66	rval = pipe(to_parent);
67        if (rval == -1) {
68                perror(ERROR_PREFIX "fd[0]");
69                return PTS_UNRESOLVED;
70        }
71        rval = pipe(to_child);
72        if (rval == -1) {
73               perror(ERROR_PREFIX "fd[1]");
74               return PTS_UNRESOLVED;
75        }
76	pid = fork();
77	if (pid == -1) {
78		perror(ERROR_PREFIX "fork");
79		return PTS_UNRESOLVED;
80	}
81	if (pid == 0) {
82		//child process
83		close(to_parent[PIPE_READ]);
84		close(to_child[PIPE_WRITE]);
85		return child_process(mqname, to_child[PIPE_READ],
86                                     to_parent[PIPE_WRITE]);
87	}
88	else {
89		//parent process
90		close(to_parent[PIPE_WRITE]);
91                close(to_child[PIPE_READ]);
92		return parent_process(mqname, to_parent[PIPE_READ],
93                                      to_child[PIPE_WRITE], pid);
94	}
95}
96int parent_process(char *mqname, int read_pipe, int write_pipe, int child_pid)
97{
98	mqd_t mqdes;
99	char reply;
100	int rval;
101
102	mqdes = mq_open(mqname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, 0);
103	if (mqdes == (mqd_t)-1) {
104		perror(ERROR_PREFIX "mq_open");
105		return PTS_UNRESOLVED;
106	}
107	// Tell child a message queue has been opened.
108	rval = send_receive(read_pipe, write_pipe, 'a', &reply);
109	if (rval) {
110	        return rval;
111        }
112	if (reply != 'b') {
113	        printf(ERROR_PREFIX "send_receive: " "expected a 'b'");
114                return PTS_UNRESOLVED;
115        }
116	if (mq_unlink(mqname) == 0) {
117		if (mq_open(mqname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, 0) == -1) {
118			printf("mq_open to recreate the message	mqueue may fail until all references to the message queue have been closed, or until the message queue is actually removed. \n");
119			printf("Test PASSED\n");
120			return PTS_PASS;
121		}
122		else {
123			if (mq_unlink(mqname) != 0) {
124	        		printf(ERROR_PREFIX "mq_unlink(2)");
125                		return PTS_UNRESOLVED;
126			}
127			printf("mq_open to recreate the message	mqueue may succeed even if the references to the message queue have not been closed or the message queue is not actually removed. \n");
128			printf("Test PASSED\n");
129			return PTS_PASS;
130		}
131	}
132	printf(ERROR_PREFIX "mq_unlink \n");
133	return PTS_UNRESOLVED;
134}
135
136int child_process(char *mqname, int read_pipe, int write_pipe)
137{
138	mqd_t mqdes;
139	int rval;
140	char reply;
141
142	rval = send_receive(read_pipe, write_pipe, 0, &reply);
143	if (rval) {
144                return rval;
145        }
146        if (reply != 'a') {
147                printf(ERROR_PREFIX "send_receive: " "expected an 'a'\n");
148                return PTS_UNRESOLVED;
149        }
150	mqdes = mq_open(mqname, O_RDWR, 0, 0);
151	if (mqdes == (mqd_t)-1) {
152		perror(ERROR_PREFIX "mq_open");
153		return PTS_UNRESOLVED;
154	}
155	rval = send_receive(read_pipe, write_pipe, 'b', NULL);
156
157	return 0;
158}
159
160int send_receive(int read_pipe, int write_pipe, char send, char *reply)
161{
162        ssize_t bytes;
163
164        if (send) {
165                bytes = write(write_pipe, &send, 1);
166                if (bytes == -1) {
167                perror(ERROR_PREFIX "write fd[1]");
168                return PTS_UNRESOLVED;
169	        }
170        }
171        if (reply) {
172                bytes = read(read_pipe, reply, 1);
173                if (bytes == -1) {
174	                perror(ERROR_PREFIX "read fd[0]");
175                        return PTS_UNRESOLVED;
176                } else if (bytes == 0) {
177                        printf(ERROR_PREFIX "read: EOF \n");
178                        return PTS_UNRESOLVED;
179                }
180        }
181	return 0;
182}
183