Home | History | Annotate | Download | only in share
      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