Statistics
| Branch: | Tag: | Revision:

mininet / mnexec.c @ e0bf8ece

History | View | Annotate | Download (5.59 KB)

1 c4ae4232 Bob Lantz
/* mnexec: execution utility for mininet
2
 *
3
 * Starts up programs and does things that are slow or
4
 * difficult in Python, including:
5
 *
6
 *  - closing all file descriptors except stdin/out/error
7
 *  - detaching from a controlling tty using setsid
8 54615659 Rich Lane
 *  - running in network and mount namespaces
9 c4ae4232 Bob Lantz
 *  - printing out the pid of a process so we can identify it later
10 df600200 Bob Lantz
 *  - attaching to a namespace and cgroup
11
 *  - setting RT scheduling
12 c4ae4232 Bob Lantz
 *
13
 * Partially based on public domain setsid(1)
14
*/
15
16 2941bbae Jose Pedro Oliveira
#define _GNU_SOURCE
17 c4ae4232 Bob Lantz
#include <stdio.h>
18
#include <linux/sched.h>
19
#include <unistd.h>
20 e78e8fb5 Bob Lantz
#include <limits.h>
21
#include <syscall.h>
22
#include <fcntl.h>
23 df600200 Bob Lantz
#include <stdlib.h>
24
#include <sched.h>
25 387250cd Jose Pedro Oliveira
#include <ctype.h>
26 54615659 Rich Lane
#include <sys/mount.h>
27 c4ae4232 Bob Lantz
28 d85a58fe Bob Lantz
#if !defined(VERSION)
29
#define VERSION "(devel)"
30
#endif
31
32 b85943dc Bob Lantz
void usage(char *name)
33 c4ae4232 Bob Lantz
{
34 d85a58fe Bob Lantz
    printf("Execution utility for Mininet\n\n"
35
           "Usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\n\n"
36
           "Options:\n"
37
           "  -c: close all file descriptors except stdin/out/error\n"
38
           "  -d: detach from tty by calling setsid()\n"
39 54615659 Rich Lane
           "  -n: run in new network and mount namespaces\n"
40 d85a58fe Bob Lantz
           "  -p: print ^A + pid\n"
41 54615659 Rich Lane
           "  -a pid: attach to pid's network and mount namespaces\n"
42 d85a58fe Bob Lantz
           "  -g group: add to cgroup\n"
43
           "  -r rtprio: run with SCHED_RR (usually requires -g)\n"
44
           "  -v: print version\n",
45 e78e8fb5 Bob Lantz
           name);
46
}
47
48
49
int setns(int fd, int nstype)
50
{
51 36bf8ac9 Vitaliy Ivanov
    return syscall(__NR_setns, fd, nstype);
52 c4ae4232 Bob Lantz
}
53
54 df600200 Bob Lantz
/* Validate alphanumeric path foo1/bar2/baz */
55
void validate(char *path)
56
{
57
    char *s;
58
    for (s=path; *s; s++) {
59
        if (!isalnum(*s) && *s != '/') {
60
            fprintf(stderr, "invalid path: %s\n", path);
61
            exit(1);
62
        }
63
    }
64
}
65
66
/* Add our pid to cgroup */
67 8f80f875 Jose Pedro Oliveira
void cgroup(char *gname)
68 df600200 Bob Lantz
{
69
    static char path[PATH_MAX];
70
    static char *groups[] = {
71
        "cpu", "cpuacct", "cpuset", NULL
72
    };
73
    char **gptr;
74
    pid_t pid = getpid();
75
    int count = 0;
76
    validate(gname);
77
    for (gptr = groups; *gptr; gptr++) {
78
        FILE *f;
79
        snprintf(path, PATH_MAX, "/sys/fs/cgroup/%s/%s/tasks",
80
                 *gptr, gname);
81
        f = fopen(path, "w");
82
        if (f) {
83
            count++;
84
            fprintf(f, "%d\n", pid);
85
            fclose(f);
86
        }
87
    }
88
    if (!count) {
89
        fprintf(stderr, "cgroup: could not add to cgroup %s\n",
90
            gname);
91
        exit(1);
92
    }
93
}
94
95 c4ae4232 Bob Lantz
int main(int argc, char *argv[])
96
{
97 cae7be1a Zi Shen Lim
    int c;
98 c4ae4232 Bob Lantz
    int fd;
99 e78e8fb5 Bob Lantz
    char path[PATH_MAX];
100
    int nsid;
101
    int pid;
102 9b5fa1d7 Bob Lantz
    char *cwd = get_current_dir_name();
103 b85943dc Bob Lantz
104 df600200 Bob Lantz
    static struct sched_param sp;
105 d85a58fe Bob Lantz
    while ((c = getopt(argc, argv, "+cdnpa:g:r:vh")) != -1)
106 c4ae4232 Bob Lantz
        switch(c) {
107
        case 'c':
108
            /* close file descriptors except stdin/out/error */
109
            for (fd = getdtablesize(); fd > 2; fd--)
110
                close(fd);
111
            break;
112
        case 'd':
113
            /* detach from tty */
114
            if (getpgrp() == getpid()) {
115
                switch(fork()) {
116
                    case -1:
117
                        perror("fork");
118
                        return 1;
119 36bf8ac9 Vitaliy Ivanov
                    case 0:     /* child */
120 c4ae4232 Bob Lantz
                        break;
121 36bf8ac9 Vitaliy Ivanov
                    default:    /* parent */
122 c4ae4232 Bob Lantz
                        return 0;
123
                }
124
            }
125
            setsid();
126
            break;
127
        case 'n':
128 54615659 Rich Lane
            /* run in network and mount namespaces */
129
            if (unshare(CLONE_NEWNET|CLONE_NEWNS) == -1) {
130 c4ae4232 Bob Lantz
                perror("unshare");
131
                return 1;
132
            }
133 54615659 Rich Lane
            /* mount sysfs to pick up the new network namespace */
134
            if (mount("sysfs", "/sys", "sysfs", MS_MGC_VAL, NULL) == -1) {
135
                perror("mount");
136
                return 1;
137
            }
138 c4ae4232 Bob Lantz
            break;
139
        case 'p':
140
            /* print pid */
141
            printf("\001%d\n", getpid());
142
            fflush(stdout);
143
            break;
144 e78e8fb5 Bob Lantz
        case 'a':
145 bfdbb708 Bob Lantz
            /* Attach to pid's network namespace and mount namespace */
146 e78e8fb5 Bob Lantz
            pid = atoi(optarg);
147 bfdbb708 Bob Lantz
            sprintf(path, "/proc/%d/ns/net", pid);
148 e78e8fb5 Bob Lantz
            nsid = open(path, O_RDONLY);
149
            if (nsid < 0) {
150
                perror(path);
151
                return 1;
152
            }
153
            if (setns(nsid, 0) != 0) {
154
                perror("setns");
155
                return 1;
156
            }
157 bfdbb708 Bob Lantz
            /* Plan A: call setns() to attach to mount namespace */
158
            sprintf(path, "/proc/%d/ns/mnt", pid);
159 6a81b6df Cody Burkard
            nsid = open(path, O_RDONLY);
160 bfdbb708 Bob Lantz
            if (nsid < 0 || setns(nsid, 0) != 0) {
161 b85943dc Bob Lantz
                /* Plan B: chroot/chdir into pid's root file system */
162 bfdbb708 Bob Lantz
                sprintf(path, "/proc/%d/root", pid);
163
                if (chroot(path) < 0) {
164
                    perror(path);
165
                    return 1;
166
                }
167 9b5fa1d7 Bob Lantz
            }
168
            /* chdir to correct working directory */
169
            if (chdir(cwd) != 0) {
170
                perror(cwd);
171
                return 1;
172 6a81b6df Cody Burkard
            }
173 e78e8fb5 Bob Lantz
            break;
174 df600200 Bob Lantz
        case 'g':
175
            /* Attach to cgroup */
176
            cgroup(optarg);
177
            break;
178
        case 'r':
179
            /* Set RT scheduling priority */
180
            sp.sched_priority = atoi(optarg);
181
            if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) {
182
                perror("sched_setscheduler");
183
                return 1;
184
            }
185
            break;
186 d85a58fe Bob Lantz
        case 'v':
187
            printf("%s\n", VERSION);
188
            exit(0);
189
        case 'h':
190
            usage(argv[0]);
191
            exit(0);
192 c4ae4232 Bob Lantz
        default:
193
            usage(argv[0]);
194 b85943dc Bob Lantz
            exit(1);
195 c4ae4232 Bob Lantz
        }
196
197
    if (optind < argc) {
198 df600200 Bob Lantz
        execvp(argv[optind], &argv[optind]);
199
        perror(argv[optind]);
200
        return 1;
201
    }
202 b85943dc Bob Lantz
203 c4ae4232 Bob Lantz
    usage(argv[0]);
204 b8fd3d2d Jose Pedro Oliveira
205
    return 0;
206 c4ae4232 Bob Lantz
}