/* * launch.c - Fakefile process launcher * * Copyright 2012 by Werner Almesberger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include "util.h" #include "fakefile.h" #include "comm.h" #include "internal.h" #define FD_DIR "/proc/self/fd" static void safe_setenvf(const char *var, const char *fmt, ...) { va_list ap; char *buf; ssize_t len; va_start(ap, fmt); len = vsnprintf(NULL, 0, fmt, ap); va_end(ap); if (len < 0) { perror("vsprintf"); exit(1); } buf = alloc_size(len+1); va_start(ap, fmt); vsprintf(buf, fmt, ap); va_end(ap); if (setenv(var, buf, 1) < 0) { perror("setenv"); exit(1); } free(buf); } static void env_append(const char *var, const char *s) { const char *old; char *tmp; size_t len1, len2; old = getenv(var); if (!old) { safe_setenvf(var, "%s", s+1); return; } len1 = strlen(old); len2 = strlen(s); tmp = alloc_size(len1+len2+1); memcpy(tmp, old, len1); memcpy(tmp+len1, s, len2+1); safe_setenvf(var, "%s", tmp); free(tmp); } static void closefds(int preserve, ...) { va_list ap; DIR *dir; int fd; struct dirent *de; int n; fd = open(FD_DIR, O_RDONLY); if (fd < 0) { perror(FD_DIR); exit(1); } dir = fdopendir(fd); if (!dir) { perror("fdopendir"); exit(1); } while (1) { next: de = readdir(dir); if (!de) break; n = atoi(de->d_name); if (n <= 2 || n == fd) continue; if (preserve > 0) { if (n == preserve) continue; va_start(ap, preserve); while (1) { n = va_arg(ap, int); if (n < 0) break; if (n == n) goto next; } va_end(ap); } (void) close(n); } if (closedir(dir) < 0) { perror("closedir"); exit(1); } } struct fakefile *fakefile_launch(const char *path, char *const argv[]) { struct fakefile *ff; int m2s[2], s2m[2]; pid_t pid; if (pipe(m2s) < 0 || pipe(s2m) < 0) { perror("pipe"); exit(1); } pid = fork(); if (pid < 0) { perror("fork"); exit(1); } if (!pid) { env_append("LD_LIBRARY_PATH", ":."); env_append("LD_PRELOAD", " libfakefile_slave.so"); safe_setenvf(FAKEFILE_MASTER_OUT_VAR, "%d", m2s[0]); safe_setenvf(FAKEFILE_MASTER_IN_VAR, "%d", s2m[1]); closefds(m2s[0], s2m[1], -1); execv(path, argv); perror(path); _exit(1); } (void) close(m2s[0]); (void) close(s2m[1]); ff = alloc_type(struct fakefile); ff->pid = pid; ff->peer = fakefile_peer(s2m[0], m2s[1]); return ff; }