2012-01-26 15:27:00 +04:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include "util.h"
|
|
|
|
#include "syscall.h"
|
2012-01-31 11:29:23 +03:00
|
|
|
#include "uts_ns.h"
|
2012-01-31 22:28:55 +04:00
|
|
|
#include "ipc_ns.h"
|
2012-05-12 03:30:10 +04:00
|
|
|
#include "mount.h"
|
2012-05-15 13:04:00 +04:00
|
|
|
#include "namespaces.h"
|
2012-01-26 15:27:00 +04:00
|
|
|
|
2012-01-31 11:29:23 +03:00
|
|
|
int switch_ns(int pid, int type, char *ns)
|
2012-01-26 15:27:00 +04:00
|
|
|
{
|
|
|
|
char buf[32];
|
2012-02-01 15:58:30 +04:00
|
|
|
int nsfd;
|
|
|
|
int ret = -1;
|
2012-01-26 15:27:00 +04:00
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "/proc/%d/ns/%s", pid, ns);
|
|
|
|
nsfd = open(buf, O_RDONLY);
|
|
|
|
if (nsfd < 0) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't open ipcns file");
|
2012-01-26 15:27:00 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = setns(nsfd, type);
|
|
|
|
if (ret < 0)
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't setns %d/%s", pid, ns);
|
2012-01-26 15:27:00 +04:00
|
|
|
|
|
|
|
close(nsfd);
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-31 22:28:22 +04:00
|
|
|
static int do_dump_namespaces(int ns_pid, unsigned int ns_flags)
|
2012-01-26 15:27:00 +04:00
|
|
|
{
|
2012-01-26 15:28:00 +04:00
|
|
|
struct cr_fdset *fdset;
|
2012-02-01 15:58:30 +04:00
|
|
|
int ret = 0;
|
2012-01-26 15:28:00 +04:00
|
|
|
|
2012-03-26 17:45:08 +04:00
|
|
|
fdset = cr_ns_fdset_open(ns_pid, O_DUMP);
|
2012-01-26 15:28:00 +04:00
|
|
|
if (fdset == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2012-01-31 22:28:55 +04:00
|
|
|
if (ns_flags & CLONE_NEWUTS) {
|
2012-02-03 16:48:30 +03:00
|
|
|
pr_info("Dump UTS namespace\n");
|
2012-01-31 22:28:55 +04:00
|
|
|
ret = dump_uts_ns(ns_pid, fdset);
|
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
if (ns_flags & CLONE_NEWIPC) {
|
2012-02-03 16:48:30 +03:00
|
|
|
pr_info("Dump IPC namespace\n");
|
2012-01-31 22:28:55 +04:00
|
|
|
ret = dump_ipc_ns(ns_pid, fdset);
|
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
}
|
2012-05-12 03:30:10 +04:00
|
|
|
if (ns_flags & CLONE_NEWNS) {
|
|
|
|
pr_info("Dump MNT namespace (mountpoints)\n");
|
|
|
|
ret = dump_mnt_ns(ns_pid, fdset);
|
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
}
|
2012-01-31 22:28:55 +04:00
|
|
|
err:
|
2012-01-26 15:28:00 +04:00
|
|
|
close_cr_fdset(&fdset);
|
|
|
|
return ret;
|
|
|
|
|
2012-01-26 15:27:00 +04:00
|
|
|
}
|
|
|
|
|
2012-01-31 22:28:22 +04:00
|
|
|
int dump_namespaces(int ns_pid, unsigned int ns_flags)
|
2012-01-26 15:27:00 +04:00
|
|
|
{
|
2012-02-01 15:58:30 +04:00
|
|
|
int pid, status;
|
|
|
|
int ret = 0;
|
2012-01-26 15:27:00 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The setns syscall is cool, we can switch to the other
|
|
|
|
* namespace and then return back to our initial one, but
|
|
|
|
* for me it's much easier just to fork another task and
|
|
|
|
* let it do the job, all the more so it can be done in
|
|
|
|
* parallel with task dumping routine.
|
|
|
|
*
|
|
|
|
* However, the question how to dump sockets from the target
|
|
|
|
* net namesapce with this is still open
|
|
|
|
*/
|
|
|
|
|
|
|
|
pr_info("Dumping %d's namespaces\n", ns_pid);
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
if (pid < 0) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't fork ns dumper");
|
2012-01-26 15:27:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pid == 0) {
|
2012-01-31 22:28:22 +04:00
|
|
|
ret = do_dump_namespaces(ns_pid, ns_flags);
|
2012-01-26 15:27:00 +04:00
|
|
|
exit(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = waitpid(pid, &status, 0);
|
|
|
|
if (ret != pid) {
|
2012-01-31 15:13:05 +04:00
|
|
|
pr_perror("Can't wait ns dumper");
|
2012-01-26 15:27:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
|
|
|
pr_err("Namespaces dumping finished with error %d\n", status);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("Namespaces dump complete\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int prepare_namespace(int pid, unsigned long clone_flags)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
2012-04-13 19:44:00 +04:00
|
|
|
pr_info("Restoring namespaces %d flags 0x%lx\n",
|
2012-01-26 15:27:00 +04:00
|
|
|
pid, clone_flags);
|
|
|
|
|
2012-01-26 15:28:00 +04:00
|
|
|
if (clone_flags & CLONE_NEWUTS)
|
|
|
|
ret = prepare_utsns(pid);
|
2012-01-31 22:29:22 +04:00
|
|
|
if (clone_flags & CLONE_NEWIPC)
|
|
|
|
ret = prepare_ipc_ns(pid);
|
2012-01-26 15:28:00 +04:00
|
|
|
|
2012-01-26 15:27:00 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-03-27 12:01:14 +04:00
|
|
|
int try_show_namespaces(int ns_pid, struct cr_options *o)
|
2012-01-26 15:27:00 +04:00
|
|
|
{
|
2012-01-26 15:28:00 +04:00
|
|
|
struct cr_fdset *fdset;
|
2012-03-27 12:01:14 +04:00
|
|
|
int i;
|
2012-01-26 15:28:00 +04:00
|
|
|
|
2012-03-26 17:45:08 +04:00
|
|
|
fdset = cr_ns_fdset_open(ns_pid, O_SHOW);
|
2012-01-26 15:28:00 +04:00
|
|
|
if (!fdset)
|
|
|
|
return -1;
|
|
|
|
|
2012-03-27 12:01:14 +04:00
|
|
|
for (i = _CR_FD_NS_FROM + 1; i < _CR_FD_NS_TO; i++) {
|
|
|
|
int fd;
|
2012-01-26 15:28:00 +04:00
|
|
|
|
2012-03-27 12:01:14 +04:00
|
|
|
if (!fdset_template[i].show)
|
|
|
|
continue;
|
2012-02-08 15:50:03 +03:00
|
|
|
|
2012-03-27 12:01:14 +04:00
|
|
|
fd = fdset_fd(fdset, i);
|
|
|
|
if (fd == -1)
|
|
|
|
continue;
|
2012-02-09 12:09:48 +03:00
|
|
|
|
2012-03-27 12:01:14 +04:00
|
|
|
fdset_template[i].show(fdset_fd(fdset, i), o);
|
|
|
|
}
|
2012-02-14 19:54:13 +03:00
|
|
|
|
2012-01-26 15:28:00 +04:00
|
|
|
close_cr_fdset(&fdset);
|
2012-01-26 15:27:00 +04:00
|
|
|
return 0;
|
|
|
|
}
|