#include #include #include #include #include #include #include #include #define MY_DIR ".f" #define IN_REDIR_FILENAME "stdin_redir" #define OUT_REDIR_FILENAME "stdout_redir" #define ERR_REDIR_FILENAME "stderr_redir" struct redirs { char **in; int n_in; char **out; int n_out; char **err; int n_err; }; int invert; /* Redir streams by default, those progs that are specified are not redirected */ char * mk_path(const char *s) { enum { pathsize = 4096 }; static char path[pathsize]; static char *homedir = NULL; if (!homedir) homedir = getenv("HOME"); snprintf(path, pathsize, "%s/%s/%s", homedir, MY_DIR, s); return path; } char ** str_vec_add(char ***v, int *n, const char *s) { *v = realloc(*v, (*n + 1) * sizeof(char *)); (*v)[(*n)++] = strdup(s); return *v; } void str_vec_free(char ***v, int *n) { int i; for (i = 0; i < *n; ++i) free((*v)[i]); *n = 0; *v = NULL; } const char * str_vec_search(char ***v, int *n, char *key) { int i; if (*v == NULL) return NULL; for (i = 0; i < *n; ++i) if (!strcmp((*v)[i], key)) return ((*v)[i]); return NULL; } void load_redir_file(char ***v, int *n, const char *filename) { FILE *fp; enum { bufsize = 4096 }; char buf[bufsize] = ""; size_t len; if ((fp = fopen(mk_path(filename), "r")) == NULL) return; while (fgets(buf, bufsize, fp)) { if (*buf == '\n') continue; len = strlen(buf); if (buf[len-1] == '\n') buf[len-1] = '\0'; str_vec_add(v, n, buf); } fclose(fp); } int redir_stream(int stream, const char *filename, int flags, int mode) { int fd; if ((fd = open(filename, flags, mode)) < 0) return 0; dup2(fd, stream); return 1; } void f(struct redirs *r, char **argv) { int fd; pid_t pid; char *prog = strdup(argv[0]); if ((pid = fork()) < 0) { return; } else if (pid > 0) { exit(0); } if (invert ^ (str_vec_search(&r->in, &r->n_in, prog) ? 1 : 0)) { if (!redir_stream(0, "/dev/null", O_RDONLY, 0)) return; } if (invert ^ (str_vec_search(&r->out, &r->n_out, prog) ? 1 : 0)) { if (!redir_stream(1, "/dev/null", O_WRONLY | O_CREAT, 0)) return; } if (invert ^ (str_vec_search(&r->err, &r->n_err, prog) ? 1 : 0)) { if (!redir_stream(2, "/dev/null", O_WRONLY | O_CREAT, 0)) return; } execvp(basename(prog), argv); exit(0); } int main(int argc, char **argv) { struct redirs redirs; char *homedir; FILE *fp; memset(&redirs, 0, sizeof(redirs)); if (argc < 2) exit(0); homedir = getenv("HOME"); load_redir_file(&redirs.in, &redirs.n_in, IN_REDIR_FILENAME); load_redir_file(&redirs.out, &redirs.n_out, OUT_REDIR_FILENAME); load_redir_file(&redirs.err, &redirs.n_err, ERR_REDIR_FILENAME); if (fp = fopen(mk_path("invert"), "r")) { invert = 1; fclose(fp); } f(&redirs, argv + 1); /* should never be reached */ err(1, NULL); }