| 1 | /* $Id$ */ |
|---|
| 2 | /* $URL$ */ |
|---|
| 3 | |
|---|
| 4 | #define _XOPEN_SOURCE |
|---|
| 5 | |
|---|
| 6 | #include "forkopen.h" |
|---|
| 7 | |
|---|
| 8 | #include <stdio.h> |
|---|
| 9 | #include <unistd.h> |
|---|
| 10 | #include <string.h> |
|---|
| 11 | #include <sys/wait.h> |
|---|
| 12 | #include <time.h> |
|---|
| 13 | |
|---|
| 14 | static int REDIRECT_STDERR = 0; |
|---|
| 15 | int forkopen_stderr(int truth) { |
|---|
| 16 | int old = REDIRECT_STDERR; |
|---|
| 17 | REDIRECT_STDERR = truth; |
|---|
| 18 | return old; |
|---|
| 19 | } |
|---|
| 20 | |
|---|
| 21 | enum {DUPREAD = 0, DUPWRITE = 1, DUPSZ = 2}; |
|---|
| 22 | |
|---|
| 23 | static int dodup(int filedes[DUPSZ]) { |
|---|
| 24 | int d; |
|---|
| 25 | if ((d = dup2(filedes[DUPWRITE], STDOUT_FILENO)) == -1) { |
|---|
| 26 | perror("dup failed"); |
|---|
| 27 | return 0; |
|---|
| 28 | } |
|---|
| 29 | if (REDIRECT_STDERR) |
|---|
| 30 | dup2(filedes[DUPWRITE], STDERR_FILENO); |
|---|
| 31 | //fprintf(stderr, "dup worked: %d now points to %d\n", d, filedes[DUPWRITE]); |
|---|
| 32 | return 1; |
|---|
| 33 | } |
|---|
| 34 | |
|---|
| 35 | static int forkopen_gen(const char *prog, const char *arg, pid_t *ochild, |
|---|
| 36 | char *const argv[], int searchpath) { |
|---|
| 37 | int filedes[DUPSZ]; |
|---|
| 38 | pid_t child; |
|---|
| 39 | if (pipe(filedes) == -1) { |
|---|
| 40 | perror("pipe"); |
|---|
| 41 | return -1; |
|---|
| 42 | } |
|---|
| 43 | child = fork(); |
|---|
| 44 | if (child == 0) { |
|---|
| 45 | int err; |
|---|
| 46 | close(filedes[DUPREAD]); //close unused read end |
|---|
| 47 | if (dodup(filedes)) { |
|---|
| 48 | if (argv && searchpath) { |
|---|
| 49 | err = execvp(prog, argv); |
|---|
| 50 | } else if (argv) { |
|---|
| 51 | err = execv(prog, argv); |
|---|
| 52 | } else if (searchpath) { |
|---|
| 53 | err = execlp(prog, prog, arg, (char*)0); |
|---|
| 54 | } else { |
|---|
| 55 | err = execl(prog, prog, arg, (char*)0); |
|---|
| 56 | } |
|---|
| 57 | if (err < 0) { |
|---|
| 58 | perror("exec? failed"); |
|---|
| 59 | } //else never reached. |
|---|
| 60 | } |
|---|
| 61 | close(filedes[DUPWRITE]); |
|---|
| 62 | return -1; |
|---|
| 63 | } else if (child < 0) { |
|---|
| 64 | fprintf(stderr, "Critical -- couldn't fork()\n"); |
|---|
| 65 | close(filedes[DUPREAD]); |
|---|
| 66 | close(filedes[DUPWRITE]); |
|---|
| 67 | return -1; |
|---|
| 68 | } else { //we are the parent |
|---|
| 69 | close(filedes[DUPWRITE]); //close unused write end |
|---|
| 70 | if (ochild) |
|---|
| 71 | *ochild = child; |
|---|
| 72 | return filedes[DUPREAD]; |
|---|
| 73 | } |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | int forkopen(const char *prog, const char *arg, pid_t *ochild) { |
|---|
| 77 | return forkopen_gen(prog, arg, ochild, 0, 0); |
|---|
| 78 | } |
|---|
| 79 | int forkopenp(const char *prog, const char *arg, pid_t *ochild) { |
|---|
| 80 | return forkopen_gen(prog, arg, ochild, 0, 1); |
|---|
| 81 | } |
|---|
| 82 | int forkopenv(const char *prog, char *const argv[], pid_t *ochild) { |
|---|
| 83 | return forkopen_gen(prog, 0, ochild, argv, 0); |
|---|
| 84 | } |
|---|
| 85 | int forkopenvp(const char *prog, char *const argv[], pid_t *ochild) { |
|---|
| 86 | return forkopen_gen(prog, 0, ochild, argv, 1); |
|---|
| 87 | } |
|---|
| 88 | |
|---|
| 89 | static int fcreadfd(char* buf, size_t sz, int *ostatus, |
|---|
| 90 | int fd, pid_t *ichild) { |
|---|
| 91 | int status; |
|---|
| 92 | ssize_t nread; |
|---|
| 93 | pid_t child = *ichild; |
|---|
| 94 | |
|---|
| 95 | if (fd < 0) |
|---|
| 96 | return fd; |
|---|
| 97 | |
|---|
| 98 | nread = read(fd, buf, sz-1); |
|---|
| 99 | |
|---|
| 100 | switch (nread) { |
|---|
| 101 | case -1: |
|---|
| 102 | perror("read error"); |
|---|
| 103 | close(fd); |
|---|
| 104 | /* waitpid?? */ |
|---|
| 105 | return -1; |
|---|
| 106 | case 0: |
|---|
| 107 | //perror("nothing read"); |
|---|
| 108 | /* fall through */ |
|---|
| 109 | default: |
|---|
| 110 | buf[nread] = '\0'; |
|---|
| 111 | } |
|---|
| 112 | |
|---|
| 113 | close(fd); |
|---|
| 114 | waitpid(child, &status, 0); |
|---|
| 115 | |
|---|
| 116 | if (ostatus && WIFEXITED(status)) |
|---|
| 117 | *ostatus = WEXITSTATUS(status); |
|---|
| 118 | else if (ostatus) |
|---|
| 119 | *ostatus = status; |
|---|
| 120 | |
|---|
| 121 | return nread; |
|---|
| 122 | } |
|---|
| 123 | |
|---|
| 124 | int fork_cstr_read(char* buf, size_t sz, const char* prog, const char* arg, int *ostatus) { |
|---|
| 125 | pid_t child; |
|---|
| 126 | return fcreadfd(buf, sz, ostatus, forkopen(prog, arg, &child), &child); |
|---|
| 127 | } |
|---|
| 128 | int fork_cstr_readp(char* buf, size_t sz, const char* prog, const char* arg, int *ostatus) { |
|---|
| 129 | pid_t child; |
|---|
| 130 | return fcreadfd(buf, sz, ostatus, forkopenp(prog, arg, &child), &child); |
|---|
| 131 | } |
|---|
| 132 | int fork_cstr_readv(char* buf, size_t sz, const char* prog, char *const argv[], int *ostatus) { |
|---|
| 133 | pid_t child; |
|---|
| 134 | return fcreadfd(buf, sz, ostatus, forkopenv(prog, argv, &child), &child); |
|---|
| 135 | } |
|---|
| 136 | int fork_cstr_readvp(char* buf, size_t sz, const char* prog, char *const argv[], int *ostatus) { |
|---|
| 137 | pid_t child; |
|---|
| 138 | return fcreadfd(buf, sz, ostatus, forkopenvp(prog, argv, &child), &child); |
|---|
| 139 | } |
|---|
| 140 | |
|---|
| 141 | #if 0 |
|---|
| 142 | |
|---|
| 143 | static const char* NONBLANKED = "non-blanked since "; |
|---|
| 144 | |
|---|
| 145 | static int ignored_main() { |
|---|
| 146 | char buf[1024]; |
|---|
| 147 | char *p; |
|---|
| 148 | if (fork_cstr_read(buf, 1024, "/usr/bin/xscreensaver-command", "-time", 0) == -1) { |
|---|
| 149 | return -1; |
|---|
| 150 | } |
|---|
| 151 | if ((p = strstr(buf, NONBLANKED))) { |
|---|
| 152 | struct tm when; |
|---|
| 153 | fprintf(stderr, p); |
|---|
| 154 | if (strptime(p+strlen(NONBLANKED), "%c", &when)) { |
|---|
| 155 | fprintf(stderr, "%d:%d\n", when.tm_hour, when.tm_min); |
|---|
| 156 | } |
|---|
| 157 | } else { |
|---|
| 158 | /* ... */ |
|---|
| 159 | } |
|---|
| 160 | return 0; |
|---|
| 161 | } |
|---|
| 162 | #endif |
|---|