/* Copyright (c) 2015 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of version 2 the GNU General Public License as * published by the Free Software Foundation. * * 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, see . * * Written by Matus Marhefka * *********************************************************************** * Enters the namespace(s) of a process specified by a PID and then executes * the indicated program inside that namespace(s). * */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "test.h" #include "lapi/syscalls.h" #include "lapi/namespaces_constants.h" #include "ns_common.h" char *TCID = "ns_exec"; int ns_fd[NS_TOTAL]; int ns_fds; void print_help(void) { int i; printf("usage: ns_exec <%s", params[0].name); for (i = 1; params[i].name; i++) printf("|,%s", params[i].name); printf("> [ARGS]\nSecond argument indicates the types" " of a namespaces maintained by NS_PID\nand is specified" " as a comma separated list.\nExample: ns_exec 1234 net,ipc" " ip a\n"); } static int open_ns_fd(const char *pid, const char *ns) { int fd; char file_buf[30]; sprintf(file_buf, "%s/%s/ns/%s", PROC_PATH, pid, ns); fd = open(file_buf, O_RDONLY); if (fd > 0) { ns_fd[ns_fds] = fd; ++ns_fds; return 0; } else if (fd == -1 && errno != ENOENT) { tst_resm(TINFO | TERRNO, "open"); return -1; } return 0; } static void close_ns_fd(void) { int i; for (i = 0; i < ns_fds; i++) close(ns_fd[i]); } static int child_fn(void *arg) { char **args = (char **)arg; execvp(args[3], args+3); tst_resm(TINFO | TERRNO, "execvp"); return 1; } /* * ./ns_exec [ARGS] */ int main(int argc, char *argv[]) { int i, rv, pid; char *token; rv = syscall(__NR_setns, -1, 0); if (rv == -1 && errno == ENOSYS) { tst_resm(TINFO, "setns is not supported in the kernel"); return 1; } if (argc < 4) { print_help(); return 1; } memset(ns_fd, 0, sizeof(ns_fd)); while ((token = strsep(&argv[2], ","))) { struct param *p = get_param(token); if (!p) { tst_resm(TINFO, "Unknown namespace: %s", token); print_help(); return 1; } if (open_ns_fd(argv[1], token) != 0) return 1; } if (ns_fds == 0) { tst_resm(TINFO, "no namespace entries in /proc/%s/ns/", argv[1]); return 1; } for (i = 0; i < ns_fds; i++) { if (syscall(__NR_setns, ns_fd[i], 0) == -1) { tst_resm(TINFO | TERRNO, "setns"); close_ns_fd(); return 1; } } pid = ltp_clone_quick(SIGCHLD, (void *)child_fn, (void *)argv); if (pid == -1) { tst_resm(TINFO | TERRNO, "ltp_clone_quick"); close_ns_fd(); return 1; } if (waitpid(pid, &rv, 0) == -1) { tst_resm(TINFO | TERRNO, "waitpid"); return 1; } close_ns_fd(); if (WIFEXITED(rv)) return WEXITSTATUS(rv); return 0; }