• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
print_help(void)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 
open_ns_fd(const char * pid,const char * ns)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 
close_ns_fd(void)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 
child_fn(void * arg)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  */
main(int argc,char * argv[])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