| /* |
| * Copyright (c) International Business Machines Corp., 2007 |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| ***************************************************************************/ |
| #include "libclone.h" |
| |
| int do_clone_tests(unsigned long clone_flags, |
| int(*fn1)(void *arg), void *arg1, |
| int(*fn2)(void *arg), void *arg2) |
| { |
| int ret; |
| |
| ret = ltp_clone_quick(clone_flags | SIGCHLD, fn1, arg1); |
| |
| if (ret == -1) { |
| return -1; |
| } |
| if (fn2) |
| ret = fn2(arg2); |
| else |
| ret = 0; |
| |
| return ret; |
| } |
| |
| int do_unshare_tests(unsigned long clone_flags, |
| int (*fn1)(void *arg), void *arg1, |
| int (*fn2)(void *arg), void *arg2) |
| { |
| int pid, ret = 0; |
| int retpipe[2]; |
| char buf[2]; |
| |
| if (pipe(retpipe) == -1) { |
| perror("pipe"); |
| return -1; |
| } |
| pid = fork(); |
| if (pid == -1) { |
| perror("fork"); |
| close(retpipe[0]); |
| close(retpipe[1]); |
| return -1; |
| } |
| if (pid == 0) { |
| close(retpipe[0]); |
| ret = syscall(SYS_unshare, clone_flags); |
| if (ret == -1) { |
| if (write(retpipe[1], "0", 2) < 0) { |
| perror("unshare:write(retpipe[1], ..)"); |
| } |
| close(retpipe[1]); |
| exit(1); |
| } else { |
| if (write(retpipe[1], "1", 2) < 0) { |
| perror("unshare:write(retpipe[1], ..)"); |
| } |
| } |
| close(retpipe[1]); |
| ret = fn1(arg1); |
| exit(ret); |
| } else { |
| close(retpipe[1]); |
| if (read(retpipe[0], &buf, 2) < 0) { |
| perror("unshare:read(retpipe[0], ..)"); |
| } |
| close(retpipe[0]); |
| if (*buf == '0') |
| return -1; |
| if (fn2) |
| ret = fn2(arg2); |
| } |
| |
| return ret; |
| } |
| |
| int do_plain_tests(int (*fn1)(void *arg), void *arg1, |
| int (*fn2)(void *arg), void *arg2) |
| { |
| int ret = 0, pid; |
| |
| pid = fork(); |
| if (pid == -1) { |
| perror("fork"); |
| return -1; |
| } |
| if (pid == 0) |
| return fn1(arg1); |
| if (fn2) |
| ret = fn2(arg2); |
| return ret; |
| } |
| |
| int do_clone_unshare_test(int use_clone, unsigned long clone_flags, |
| int (*fn1)(void *arg), void *arg1) |
| { |
| switch (use_clone) { |
| case T_NONE: |
| return do_plain_tests(fn1, arg1, NULL, NULL); |
| case T_CLONE: |
| return do_clone_tests(clone_flags, fn1, arg1, NULL, NULL); |
| case T_UNSHARE: |
| return do_unshare_tests(clone_flags, fn1, arg1, NULL, NULL); |
| default: |
| printf("%s: bad use_clone option: %d\n", __FUNCTION__, |
| use_clone); |
| return -1; |
| } |
| } |
| |
| |
| /* |
| * Run fn1 in a unshared environmnent, and fn2 in the original context |
| */ |
| int do_clone_unshare_tests(int use_clone, unsigned long clone_flags, |
| int (*fn1)(void *arg), void *arg1, |
| int (*fn2)(void *arg), void *arg2) |
| { |
| switch (use_clone) { |
| case T_NONE: |
| return do_plain_tests(fn1, arg1, fn2, arg2); |
| case T_CLONE: |
| return do_clone_tests(clone_flags, fn1, arg1, fn2, arg2); |
| case T_UNSHARE: |
| return do_unshare_tests(clone_flags, fn1, arg1, fn2, arg2); |
| default: |
| printf("%s: bad use_clone option: %d\n", __FUNCTION__, |
| use_clone); |
| return -1; |
| } |
| } |