Statistics
| Branch: | Tag: | Revision:

mininet / mnexec.c @ d85a58fe

History | View | Annotate | Download (4.59 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

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

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

    
46

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

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

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

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

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