Statistics
| Branch: | Tag: | Revision:

mininet / mnexec.c @ 387250cd

History | View | Annotate | Download (4.62 KB)

1
/* 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
 *  - running in a network namespace
9
 *  - printing out the pid of a process so we can identify it later
10
 *  - attaching to a namespace and cgroup
11
 *  - setting RT scheduling
12
 *
13
 * Partially based on public domain setsid(1)
14
*/
15

    
16
#include <stdio.h>
17
#include <linux/sched.h>
18
#include <unistd.h>
19
#include <limits.h>
20
#include <syscall.h>
21
#include <fcntl.h>
22
#include <stdlib.h>
23
#include <limits.h>
24
#include <sched.h>
25
#include <ctype.h>
26

    
27
#if !defined(VERSION)
28
#define VERSION "(devel)"
29
#endif
30

    
31
void usage(char *name) 
32
{
33
    printf("Execution utility for Mininet\n\n"
34
           "Usage: %s [-cdnp] [-a pid] [-g group] [-r rtprio] cmd args...\n\n"
35
           "Options:\n"
36
           "  -c: close all file descriptors except stdin/out/error\n"
37
           "  -d: detach from tty by calling setsid()\n"
38
           "  -n: run in new network namespace\n"
39
           "  -p: print ^A + pid\n"
40
           "  -a pid: attach to pid's network namespace\n"
41
           "  -g group: add to cgroup\n"
42
           "  -r rtprio: run with SCHED_RR (usually requires -g)\n"
43
           "  -v: print version\n",
44
           name);
45
}
46

    
47

    
48
int setns(int fd, int nstype)
49
{
50
    return syscall(__NR_setns, fd, nstype);
51
}
52

    
53
/* Validate alphanumeric path foo1/bar2/baz */
54
void validate(char *path)
55
{
56
    char *s;
57
    for (s=path; *s; s++) {
58
        if (!isalnum(*s) && *s != '/') {
59
            fprintf(stderr, "invalid path: %s\n", path);
60
            exit(1);
61
        }
62
    }
63
}
64

    
65
/* Add our pid to cgroup */
66
int cgroup(char *gname)
67
{
68
    static char path[PATH_MAX];
69
    static char *groups[] = {
70
        "cpu", "cpuacct", "cpuset", NULL
71
    };
72
    char **gptr;
73
    pid_t pid = getpid();
74
    int count = 0;
75
    validate(gname);
76
    for (gptr = groups; *gptr; gptr++) {
77
        FILE *f;
78
        snprintf(path, PATH_MAX, "/sys/fs/cgroup/%s/%s/tasks",
79
                 *gptr, gname);
80
        f = fopen(path, "w");
81
        if (f) {
82
            count++;
83
            fprintf(f, "%d\n", pid);
84
            fclose(f);
85
        }
86
    }
87
    if (!count) {
88
        fprintf(stderr, "cgroup: could not add to cgroup %s\n",
89
            gname);
90
        exit(1);
91
    }
92
}
93

    
94
int main(int argc, char *argv[])
95
{
96
    int c;
97
    int fd;
98
    char path[PATH_MAX];
99
    int nsid;
100
    int pid;
101
    static struct sched_param sp;
102
    while ((c = getopt(argc, argv, "+cdnpa:g:r:vh")) != -1)
103
        switch(c) {
104
        case 'c':
105
            /* close file descriptors except stdin/out/error */
106
            for (fd = getdtablesize(); fd > 2; fd--)
107
                close(fd);
108
            break;
109
        case 'd':
110
            /* detach from tty */
111
            if (getpgrp() == getpid()) {
112
                switch(fork()) {
113
                    case -1:
114
                        perror("fork");
115
                        return 1;
116
                    case 0:     /* child */
117
                        break;
118
                    default:    /* parent */
119
                        return 0;
120
                }
121
            }
122
            setsid();
123
            break;
124
        case 'n':
125
            /* run in network namespace */
126
            if (unshare(CLONE_NEWNET) == -1) {
127
                perror("unshare");
128
                return 1;
129
            }
130
            break;
131
        case 'p':
132
            /* print pid */
133
            printf("\001%d\n", getpid());
134
            fflush(stdout);
135
            break;
136
        case 'a':
137
            /* Attach to pid's network namespace */
138
            pid = atoi(optarg);
139
            sprintf(path, "/proc/%d/ns/net", pid );
140
            nsid = open(path, O_RDONLY);
141
            if (nsid < 0) {
142
                perror(path);
143
                return 1;
144
            }
145
            if (setns(nsid, 0) != 0) {
146
                perror("setns");
147
                return 1;
148
            }
149
            break;
150
        case 'g':
151
            /* Attach to cgroup */
152
            cgroup(optarg);
153
            break;
154
        case 'r':
155
            /* Set RT scheduling priority */
156
            sp.sched_priority = atoi(optarg);
157
            if (sched_setscheduler(getpid(), SCHED_RR, &sp) < 0) {
158
                perror("sched_setscheduler");
159
                return 1;
160
            }
161
            break;
162
        case 'v':
163
            printf("%s\n", VERSION);
164
            exit(0);
165
        case 'h':
166
            usage(argv[0]);
167
            exit(0);
168
        default:
169
            usage(argv[0]);
170
            exit(1); 
171
        }
172

    
173
    if (optind < argc) {
174
        execvp(argv[optind], &argv[optind]);
175
        perror(argv[optind]);
176
        return 1;
177
    }
178
    
179
    usage(argv[0]);
180
}