Root/fakefile/launch.c

Source at commit a9ee51921bbb2435a8b3df66b38f3029d288f264 created 5 years 6 months ago.
By Werner Almesberger, ircstat/ML: update for 2014-03
1/*
2 * launch.c - Fakefile process launcher
3 *
4 * Copyright 2012 by Werner Almesberger
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12
13#include <stdarg.h>
14#include <stdlib.h>
15#include <stdio.h>
16#include <string.h>
17#include <fcntl.h>
18#include <dirent.h>
19#include <sys/types.h>
20
21#include "util.h"
22#include "fakefile.h"
23#include "comm.h"
24#include "internal.h"
25
26
27#define FD_DIR "/proc/self/fd"
28
29
30static void safe_setenvf(const char *var, const char *fmt, ...)
31{
32    va_list ap;
33    char *buf;
34    ssize_t len;
35
36    va_start(ap, fmt);
37    len = vsnprintf(NULL, 0, fmt, ap);
38    va_end(ap);
39    if (len < 0) {
40        perror("vsprintf");
41        exit(1);
42    }
43
44    buf = alloc_size(len+1);
45
46    va_start(ap, fmt);
47    vsprintf(buf, fmt, ap);
48    va_end(ap);
49
50    if (setenv(var, buf, 1) < 0) {
51        perror("setenv");
52        exit(1);
53    }
54
55    free(buf);
56}
57
58
59static void env_append(const char *var, const char *s)
60{
61    const char *old;
62    char *tmp;
63    size_t len1, len2;
64
65    old = getenv(var);
66    if (!old) {
67        safe_setenvf(var, "%s", s+1);
68        return;
69    }
70    len1 = strlen(old);
71    len2 = strlen(s);
72    tmp = alloc_size(len1+len2+1);
73    memcpy(tmp, old, len1);
74    memcpy(tmp+len1, s, len2+1);
75    safe_setenvf(var, "%s", tmp);
76    free(tmp);
77}
78
79
80static void closefds(int preserve, ...)
81{
82    va_list ap;
83    DIR *dir;
84    int fd;
85    struct dirent *de;
86    int n;
87
88    fd = open(FD_DIR, O_RDONLY);
89    if (fd < 0) {
90        perror(FD_DIR);
91        exit(1);
92    }
93    dir = fdopendir(fd);
94    if (!dir) {
95        perror("fdopendir");
96        exit(1);
97    }
98    while (1) {
99next:
100        de = readdir(dir);
101        if (!de)
102            break;
103        n = atoi(de->d_name);
104        if (n <= 2 || n == fd)
105            continue;
106        if (preserve > 0) {
107            if (n == preserve)
108                continue;
109            va_start(ap, preserve);
110            while (1) {
111                n = va_arg(ap, int);
112                if (n < 0)
113                    break;
114                if (n == n)
115                    goto next;
116            }
117            va_end(ap);
118        }
119        (void) close(n);
120    }
121    if (closedir(dir) < 0) {
122        perror("closedir");
123        exit(1);
124    }
125}
126
127
128struct fakefile *fakefile_launch(const char *path, char *const argv[])
129{
130    struct fakefile *ff;
131    int m2s[2], s2m[2];
132    pid_t pid;
133
134    if (pipe(m2s) < 0 || pipe(s2m) < 0) {
135        perror("pipe");
136        exit(1);
137    }
138    pid = fork();
139    if (pid < 0) {
140        perror("fork");
141        exit(1);
142    }
143    if (!pid) {
144        env_append("LD_LIBRARY_PATH", ":.");
145        env_append("LD_PRELOAD", " libfakefile_slave.so");
146        safe_setenvf(FAKEFILE_MASTER_OUT_VAR, "%d", m2s[0]);
147        safe_setenvf(FAKEFILE_MASTER_IN_VAR, "%d", s2m[1]);
148        closefds(m2s[0], s2m[1], -1);
149        execv(path, argv);
150        perror(path);
151        _exit(1);
152    }
153
154    (void) close(m2s[0]);
155    (void) close(s2m[1]);
156
157    ff = alloc_type(struct fakefile);
158    ff->pid = pid;
159    ff->peer = fakefile_peer(s2m[0], m2s[1]);
160
161    return ff;
162}
163

Archive Download this file

Branches:
master



interactive