libclone.c revision 2c28215423293e443469a07ae7011135d058b671
1/*
2* Copyright (c) International Business Machines Corp., 2007
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15*
16***************************************************************************/
17#include "libclone.h"
18
19int do_clone_tests(unsigned long clone_flags,
20			int(*fn1)(void *arg), void *arg1,
21			int(*fn2)(void *arg), void *arg2)
22{
23	int ret;
24
25	ret = ltp_clone_quick(clone_flags | SIGCHLD, fn1, arg1);
26
27	if (ret == -1) {
28		return -1;
29	}
30	if (fn2)
31		ret = fn2(arg2);
32	else
33		ret = 0;
34
35	return ret;
36}
37
38int do_unshare_tests(unsigned long clone_flags,
39			int (*fn1)(void *arg), void *arg1,
40			int (*fn2)(void *arg), void *arg2)
41{
42	int pid, ret = 0;
43	int retpipe[2];
44	char buf[2];
45
46	if (pipe(retpipe) == -1) {
47		perror("pipe");
48		return -1;
49	}
50	pid = fork();
51	if (pid == -1) {
52		perror("fork");
53		close(retpipe[0]);
54		close(retpipe[1]);
55		return -1;
56	}
57	if (pid == 0) {
58		close(retpipe[0]);
59		ret = syscall(SYS_unshare, clone_flags);
60		if (ret == -1) {
61			if (write(retpipe[1], "0", 2) < 0) {
62				perror("unshare:write(retpipe[1], ..)");
63			}
64			close(retpipe[1]);
65			exit(1);
66		} else {
67			if (write(retpipe[1], "1", 2) < 0) {
68				perror("unshare:write(retpipe[1], ..)");
69			}
70		}
71		close(retpipe[1]);
72		ret = fn1(arg1);
73		exit(ret);
74	} else {
75		close(retpipe[1]);
76		if (read(retpipe[0], &buf, 2) < 0) {
77			perror("unshare:read(retpipe[0], ..)");
78		}
79		close(retpipe[0]);
80		if (*buf == '0')
81			return -1;
82		if (fn2)
83			ret = fn2(arg2);
84	}
85
86	return ret;
87}
88
89int do_plain_tests(int (*fn1)(void *arg), void *arg1,
90			int (*fn2)(void *arg), void *arg2)
91{
92	int ret = 0, pid;
93
94	pid = fork();
95	if (pid == -1) {
96		perror("fork");
97		return -1;
98	}
99	if (pid == 0)
100		return fn1(arg1);
101	if (fn2)
102		ret = fn2(arg2);
103	return ret;
104}
105
106int do_clone_unshare_test(int use_clone, unsigned long clone_flags,
107			int (*fn1)(void *arg), void *arg1)
108{
109	switch (use_clone) {
110	case T_NONE:
111		return do_plain_tests(fn1, arg1, NULL, NULL);
112	case T_CLONE:
113		return do_clone_tests(clone_flags, fn1, arg1, NULL, NULL);
114	case T_UNSHARE:
115		return do_unshare_tests(clone_flags, fn1, arg1, NULL, NULL);
116	default:
117		printf("%s: bad use_clone option: %d\n", __FUNCTION__,
118							use_clone);
119		return -1;
120	}
121}
122
123/*
124 * Run fn1 in a unshared environmnent, and fn2 in the original context
125 */
126int do_clone_unshare_tests(int use_clone, unsigned long clone_flags,
127			int (*fn1)(void *arg), void *arg1,
128			int (*fn2)(void *arg), void *arg2)
129{
130	switch (use_clone) {
131	case T_NONE:
132		return do_plain_tests(fn1, arg1, fn2, arg2);
133	case T_CLONE:
134		return do_clone_tests(clone_flags, fn1, arg1, fn2, arg2);
135	case T_UNSHARE:
136		return do_unshare_tests(clone_flags, fn1, arg1, fn2, arg2);
137	default:
138		printf("%s: bad use_clone option: %d\n", __FUNCTION__,
139							use_clone);
140		return -1;
141	}
142}