aboutsummaryrefslogtreecommitdiff
path: root/toys/pending/nsenter.c
blob: 33db873e9178c24f53e90690950d749264c35673 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/* nsenter.c - Enter existing namespaces
 *
 * Copyright 2014 andy Lutomirski <luto@amacapital.net>

USE_NSENTER(NEWTOY(nsenter, "<1F(no-fork)t#(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN))

config NSENTER
  bool "nsenter"
  default n
  help
    usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND...

    Run COMMAND in a different set of namespaces.

    -T  PID to take namespaces from
    -F  don't fork, even if -p is set

    The namespaces to switch are:

    -i	SysV IPC (message queues, semaphores, shared memory)
    -m	Mount/unmount tree
    -n	Network address, sockets, routing, iptables
    -p	Process IDs and init (will fork unless -F is used)
    -u	Host and domain names
    -U	UIDs, GIDs, capabilities

    Each of those options takes an optional argument giving the path of
    the namespace file (usually in /proc).  This optional argument is
    mandatory unless -t is used.
*/

#define FOR_nsenter
#define _GNU_SOURCE
#include "toys.h"
#include <errno.h>
#include <sched.h>
#include <linux/sched.h>

#define NUM_NSTYPES 6

struct nstype {
  int type;
  const char *name;
};

struct nstype nstypes[NUM_NSTYPES] = {
  {CLONE_NEWUSER, "user"}, /* must be first to allow non-root operation */
  {CLONE_NEWUTS,  "uts"},
  {CLONE_NEWPID,  "pid"},
  {CLONE_NEWNET,  "net"},
  {CLONE_NEWNS,   "mnt"},
  {CLONE_NEWIPC,  "ipc"},
};

GLOBALS(
  char *nsnames[6];
  long targetpid;
)

static void enter_by_name(int idx)
{
  int fd, rc;
  char buf[64];
  char *filename = TT.nsnames[idx];

  if (!(toys.optflags & (1<<idx))) return;

  if (!filename || !*filename) {
    if (!(toys.optflags & (1<<NUM_NSTYPES)))
      error_exit("either -t or an ns filename is required");
    sprintf(buf, "/proc/%ld/ns/%s", TT.targetpid, nstypes[idx].name);
    filename = buf;
  }

  fd = open(filename, O_RDONLY | O_CLOEXEC);
  if (fd == -1) perror_exit(filename);

  rc = setns(fd, nstypes[idx].type);
  if (CFG_TOYBOX_FREE) close(fd);
  if (rc != 0) perror_exit("setns");
}

void nsenter_main(void)
{
  int i;

  for (i = 0; i < NUM_NSTYPES; i++)
    enter_by_name(i);

  if ((toys.optflags & (1<<2)) && !(toys.optflags & 1<<(NUM_NSTYPES+1))) {
    /* changed PID ns and --no-fork wasn't set, so fork. */
    pid_t pid = fork();

    if (pid == -1) {
      perror_exit("fork");
    } else if (pid != 0) {
      while (waitpid(pid, 0, 0) == -1 && errno == EINTR)
        ;
      return;
    }
  }

  xexec_optargs(0);
}