Statistics
| Branch: | Tag: | Revision:

mininet / mnexec.c @ bfdbb708

History | View | Annotate | Download (5.39 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 c4ae4232 Bob Lantz
void usage(char *name) 
33
{
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 df600200 Bob Lantz
    static struct sched_param sp;
103 d85a58fe Bob Lantz
    while ((c = getopt(argc, argv, "+cdnpa:g:r:vh")) != -1)
104 c4ae4232 Bob Lantz
        switch(c) {
105
        case 'c':
106
            /* close file descriptors except stdin/out/error */
107
            for (fd = getdtablesize(); fd > 2; fd--)
108
                close(fd);
109
            break;
110
        case 'd':
111
            /* detach from tty */
112
            if (getpgrp() == getpid()) {
113
                switch(fork()) {
114
                    case -1:
115
                        perror("fork");
116
                        return 1;
117 36bf8ac9 Vitaliy Ivanov
                    case 0:     /* child */
118 c4ae4232 Bob Lantz
                        break;
119 36bf8ac9 Vitaliy Ivanov
                    default:    /* parent */
120 c4ae4232 Bob Lantz
                        return 0;
121
                }
122
            }
123
            setsid();
124
            break;
125
        case 'n':
126 54615659 Rich Lane
            /* run in network and mount namespaces */
127
            if (unshare(CLONE_NEWNET|CLONE_NEWNS) == -1) {
128 c4ae4232 Bob Lantz
                perror("unshare");
129
                return 1;
130
            }
131 54615659 Rich Lane
            /* mount sysfs to pick up the new network namespace */
132
            if (mount("sysfs", "/sys", "sysfs", MS_MGC_VAL, NULL) == -1) {
133
                perror("mount");
134
                return 1;
135
            }
136 c4ae4232 Bob Lantz
            break;
137
        case 'p':
138
            /* print pid */
139
            printf("\001%d\n", getpid());
140
            fflush(stdout);
141
            break;
142 e78e8fb5 Bob Lantz
        case 'a':
143 bfdbb708 Bob Lantz
            /* Attach to pid's network namespace and mount namespace */
144 e78e8fb5 Bob Lantz
            pid = atoi(optarg);
145 bfdbb708 Bob Lantz
            sprintf(path, "/proc/%d/ns/net", pid);
146 e78e8fb5 Bob Lantz
            nsid = open(path, O_RDONLY);
147
            if (nsid < 0) {
148
                perror(path);
149
                return 1;
150
            }
151
            if (setns(nsid, 0) != 0) {
152
                perror("setns");
153
                return 1;
154
            }
155 bfdbb708 Bob Lantz
            /* Plan A: call setns() to attach to mount namespace */
156
            sprintf(path, "/proc/%d/ns/mnt", pid);
157 6a81b6df Cody Burkard
            nsid = open(path, O_RDONLY);
158 bfdbb708 Bob Lantz
            if (nsid < 0 || setns(nsid, 0) != 0) {
159
                /* Plan B: chroot into pid's root file system */
160
                sprintf(path, "/proc/%d/root", pid);
161
                if (chroot(path) < 0) {
162
                    perror(path);
163
                    return 1;
164
                }
165 6a81b6df Cody Burkard
            }
166 e78e8fb5 Bob Lantz
            break;
167 df600200 Bob Lantz
        case 'g':
168
            /* Attach to cgroup */
169
            cgroup(optarg);
170
            break;
171
        case 'r':
172
            /* Set RT scheduling priority */
173
            sp.sched_priority = atoi(optarg);
174
            if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) {
175
                perror("sched_setscheduler");
176
                return 1;
177
            }
178
            break;
179 d85a58fe Bob Lantz
        case 'v':
180
            printf("%s\n", VERSION);
181
            exit(0);
182
        case 'h':
183
            usage(argv[0]);
184
            exit(0);
185 c4ae4232 Bob Lantz
        default:
186
            usage(argv[0]);
187 d85a58fe Bob Lantz
            exit(1); 
188 c4ae4232 Bob Lantz
        }
189
190
    if (optind < argc) {
191 df600200 Bob Lantz
        execvp(argv[optind], &argv[optind]);
192
        perror(argv[optind]);
193
        return 1;
194
    }
195 c4ae4232 Bob Lantz
    
196
    usage(argv[0]);
197 b8fd3d2d Jose Pedro Oliveira
198
    return 0;
199 c4ae4232 Bob Lantz
}