root/forkopen/forkopen.c

Revision 377, 4.3 kB (checked in by tapted, 4 years ago)

Add forkopen

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision url Rev Revision
Line 
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
14static int REDIRECT_STDERR = 0;
15int forkopen_stderr(int truth) {
16    int old = REDIRECT_STDERR;
17    REDIRECT_STDERR = truth;
18    return old;
19}
20
21enum {DUPREAD = 0, DUPWRITE = 1, DUPSZ = 2};
22
23static 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
35static 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
76int forkopen(const char *prog, const char *arg, pid_t *ochild) {
77    return forkopen_gen(prog, arg, ochild, 0, 0);
78}
79int forkopenp(const char *prog, const char *arg, pid_t *ochild) {
80    return forkopen_gen(prog, arg, ochild, 0, 1);
81}
82int forkopenv(const char *prog, char *const argv[], pid_t *ochild) {
83    return forkopen_gen(prog, 0, ochild, argv, 0);
84}
85int forkopenvp(const char *prog, char *const argv[], pid_t *ochild) {
86    return forkopen_gen(prog, 0, ochild, argv, 1);
87}
88
89static 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
124int 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}
128int 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}
132int 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}
136int 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
143static const char* NONBLANKED = "non-blanked since ";
144
145static 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
Note: See TracBrowser for help on using the browser.