1/*
2* Copyright (c) International Business Machines Corp., 2009
3* This program is free software; you can redistribute it and/or modify
4* it under the terms of the GNU General Public License as published by
5* the Free Software Foundation; either version 2 of the License, or
6* (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
11* the GNU General Public License for more details.
12* You should have received a copy of the GNU General Public License
13* along with this program; if not, write to the Free Software
14* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15*
16* Author: Serge Hallyn <serue@us.ibm.com>
17*
18* Check mqueuefs lifetime
19* . parent creates /dev/mqueue2
20* . child mounts mqueue there
21* . child does mq_open("/ab")
22* . parent checks for /dev/mqueue2
23* . child exits
24* . parent checks for /dev/mqueue2
25* . parent tries 'touch /dev/mqueue2/dd' -> should fail
26* . parent umounts /dev/mqueue2
27
28***************************************************************************/
29
30#ifndef _GNU_SOURCE
31#define _GNU_SOURCE
32#endif
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/wait.h>
36#include <assert.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <string.h>
41#include <errno.h>
42#include "mqns.h"
43#include "mqns_helper.h"
44
45char *TCID = "posixmq_namespace_04";
46int TST_TOTAL = 1;
47
48int p1[2];
49int p2[2];
50
51#define FNAM1 DEV_MQUEUE2 SLASH_MQ1
52#define FNAM2 DEV_MQUEUE2 SLASH_MQ2
53
54int check_mqueue(void *vtest)
55{
56	char buf[30];
57	mqd_t mqd;
58	int rc;
59
60	(void) vtest;
61
62	close(p1[1]);
63	close(p2[0]);
64
65	read(p1[0], buf, 3);	/* go */
66
67	mqd = ltp_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDWR | O_CREAT | O_EXCL,
68		0755, NULL);
69	if (mqd == -1) {
70		write(p2[1], "mqfail", 7);
71		tst_exit();
72	}
73
74	mq_close(mqd);
75
76	rc = mount("mqueue", DEV_MQUEUE2, "mqueue", 0, NULL);
77	if (rc == -1) {
78		perror("mount");
79		write(p2[1], "mount", 6);
80		tst_exit();
81	}
82
83	write(p2[1], "go", 3);
84	read(p1[0], buf, 3);
85
86	tst_exit();
87}
88
89static void setup(void)
90{
91	tst_require_root();
92	check_mqns();
93}
94
95int main(int argc, char *argv[])
96{
97	int rc;
98	int status;
99	char buf[30];
100	struct stat statbuf;
101	int use_clone = T_UNSHARE;
102
103	setup();
104
105	if (argc == 2 && strcmp(argv[1], "-clone") == 0) {
106		tst_resm(TINFO,
107			 "Testing posix mq namespaces through clone(2).");
108		use_clone = T_CLONE;
109	} else
110		tst_resm(TINFO,
111			 "Testing posix mq namespaces through unshare(2).");
112
113	if (pipe(p1) == -1) {
114		perror("pipe");
115		exit(EXIT_FAILURE);
116	}
117	if (pipe(p2) == -1) {
118		perror("pipe");
119		exit(EXIT_FAILURE);
120	}
121
122	mkdir(DEV_MQUEUE2, 0755);
123
124	tst_resm(TINFO, "Checking mqueue filesystem lifetime");
125
126	/* fire off the test */
127	rc = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mqueue, NULL);
128	if (rc < 0) {
129		tst_resm(TFAIL, "failed clone/unshare");
130		goto fail;
131	}
132
133	close(p1[0]);
134	close(p2[1]);
135	write(p1[1], "go", 3);
136
137	read(p2[0], buf, 7);
138	if (!strcmp(buf, "mqfail")) {
139		tst_resm(TFAIL, "child process could not create mqueue");
140		goto fail;
141	} else if (!strcmp(buf, "mount")) {
142		tst_resm(TFAIL, "child process could not mount mqueue");
143		goto fail;
144	}
145
146	rc = stat(FNAM1, &statbuf);
147	if (rc == -1) {
148		perror("stat");
149		write(p1[1], "go", 3);
150		tst_resm(TFAIL, "parent could not see child's created mq");
151		goto fail;
152	}
153	write(p1[1], "go", 3);
154
155	rc = wait(&status);
156	if (rc == -1) {
157		perror("wait");
158		tst_resm(TFAIL, "error while parent waited on child to exit");
159		goto fail;
160	}
161	if (!WIFEXITED(status)) {
162		tst_resm(TFAIL, "Child did not exit normally (status %d)",
163			 status);
164		goto fail;
165	}
166	rc = stat(FNAM1, &statbuf);
167	if (rc == -1) {
168		tst_resm(TFAIL,
169			 "parent's view of child's mq died with child");
170		goto fail;
171	}
172
173	rc = creat(FNAM2, 0755);
174	if (rc != -1) {
175		tst_resm(TFAIL,
176			 "parent was able to create a file in dead child's mqfs");
177		goto fail;
178	}
179
180	tst_resm(TPASS, "Child mqueue fs still visible for parent");
181
182fail:
183	umount(DEV_MQUEUE2);
184	rmdir(DEV_MQUEUE2);
185
186	tst_exit();
187}
188