1 /* Copyright (c) 2015 Red Hat, Inc. 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of version 2 the GNU General Public License as 5 * published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * 15 * Written by Matus Marhefka <mmarhefk (at) redhat.com> 16 * 17 *********************************************************************** 18 * Enters the namespace(s) of a process specified by a PID and then executes 19 * the indicated program inside that namespace(s). 20 * 21 */ 22 23 #define _GNU_SOURCE 24 #include <sched.h> 25 #include <sys/syscall.h> 26 #include <sys/types.h> 27 #include <sys/wait.h> 28 #include <fcntl.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <errno.h> 32 #include "test.h" 33 #include "lapi/syscalls.h" 34 #include "lapi/namespaces_constants.h" 35 #include "ns_common.h" 36 37 char *TCID = "ns_exec"; 38 int ns_fd[NS_TOTAL]; 39 int ns_fds; 40 41 42 void print_help(void) 43 { 44 int i; 45 46 printf("usage: ns_exec <NS_PID> <%s", params[0].name); 47 48 for (i = 1; params[i].name; i++) 49 printf("|,%s", params[i].name); 50 printf("> <PROGRAM> [ARGS]\nSecond argument indicates the types" 51 " of a namespaces maintained by NS_PID\nand is specified" 52 " as a comma separated list.\nExample: ns_exec 1234 net,ipc" 53 " ip a\n"); 54 } 55 56 static int open_ns_fd(const char *pid, const char *ns) 57 { 58 int fd; 59 char file_buf[30]; 60 61 sprintf(file_buf, "%s/%s/ns/%s", PROC_PATH, pid, ns); 62 63 fd = open(file_buf, O_RDONLY); 64 if (fd > 0) { 65 ns_fd[ns_fds] = fd; 66 ++ns_fds; 67 return 0; 68 } else if (fd == -1 && errno != ENOENT) { 69 tst_resm(TINFO | TERRNO, "open"); 70 return -1; 71 } 72 73 return 0; 74 } 75 76 static void close_ns_fd(void) 77 { 78 int i; 79 80 for (i = 0; i < ns_fds; i++) 81 close(ns_fd[i]); 82 } 83 84 static int child_fn(void *arg) 85 { 86 char **args = (char **)arg; 87 88 execvp(args[3], args+3); 89 tst_resm(TINFO | TERRNO, "execvp"); 90 return 1; 91 } 92 93 /* 94 * ./ns_exec <NS_PID> <ipc,mnt,net,pid,user,uts> <PROGRAM> [ARGS] 95 */ 96 int main(int argc, char *argv[]) 97 { 98 int i, rv, pid; 99 char *token; 100 101 rv = syscall(__NR_setns, -1, 0); 102 if (rv == -1 && errno == ENOSYS) { 103 tst_resm(TINFO, "setns is not supported in the kernel"); 104 return 1; 105 } 106 107 if (argc < 4) { 108 print_help(); 109 return 1; 110 } 111 112 memset(ns_fd, 0, sizeof(ns_fd)); 113 while ((token = strsep(&argv[2], ","))) { 114 struct param *p = get_param(token); 115 116 if (!p) { 117 tst_resm(TINFO, "Unknown namespace: %s", token); 118 print_help(); 119 return 1; 120 } 121 122 if (open_ns_fd(argv[1], token) != 0) 123 return 1; 124 } 125 126 if (ns_fds == 0) { 127 tst_resm(TINFO, "no namespace entries in /proc/%s/ns/", 128 argv[1]); 129 return 1; 130 } 131 132 for (i = 0; i < ns_fds; i++) { 133 if (syscall(__NR_setns, ns_fd[i], 0) == -1) { 134 tst_resm(TINFO | TERRNO, "setns"); 135 close_ns_fd(); 136 return 1; 137 } 138 } 139 140 pid = ltp_clone_quick(SIGCHLD, (void *)child_fn, (void *)argv); 141 if (pid == -1) { 142 tst_resm(TINFO | TERRNO, "ltp_clone_quick"); 143 close_ns_fd(); 144 return 1; 145 } 146 147 if (waitpid(pid, &rv, 0) == -1) { 148 tst_resm(TINFO | TERRNO, "waitpid"); 149 return 1; 150 } 151 152 close_ns_fd(); 153 154 if (WIFEXITED(rv)) 155 return WEXITSTATUS(rv); 156 157 return 0; 158 } 159