Annotation of embedaddon/lighttpd/src/proc_open.c, revision 1.1.1.2

1.1.1.2 ! misho       1: #include "first.h"
        !             2: 
1.1       misho       3: #include "proc_open.h"
                      4: 
                      5: #include <stdlib.h>
                      6: #include <stdio.h>
                      7: #include <ctype.h>
                      8: #include <string.h>
                      9: #include <errno.h>
                     10: 
                     11: #ifdef WIN32
                     12: # include <io.h>
                     13: # include <fcntl.h>
                     14: #else
                     15: # include <sys/wait.h>
                     16: # include <unistd.h>
                     17: #endif
                     18: 
                     19: 
                     20: #ifdef WIN32
                     21: /* {{{ win32 stuff */
                     22: # define SHELLENV "ComSpec"
                     23: # define SECURITY_DC , SECURITY_ATTRIBUTES *security
                     24: # define SECURITY_CC , security
                     25: # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
                     26: static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
                     27: {
                     28:        HANDLE copy, self = GetCurrentProcess();
                     29: 
                     30:        if (!DuplicateHandle(self, src, self, &copy, 0, inherit, DUPLICATE_SAME_ACCESS |
                     31:                                (closeorig ? DUPLICATE_CLOSE_SOURCE : 0)))
                     32:                return NULL;
                     33:        return copy;
                     34: }
                     35: # define close_descriptor(fd) CloseHandle(fd)
                     36: static void pipe_close_parent(pipe_t *p) {
                     37:        /* don't let the child inherit the parent side of the pipe */
                     38:        p->parent = dup_handle(p->parent, FALSE, TRUE);
                     39: }
                     40: static void pipe_close_child(pipe_t *p) {
                     41:        close_descriptor(p->child);
                     42:        p->fd = _open_osfhandle((long)p->parent,
                     43:                        (p->fd == 0 ? O_RDONLY : O_WRONLY)|O_BINARY);
                     44: }
                     45: /* }}} */
                     46: #else /* WIN32 */
                     47: /* {{{ unix way */
                     48: # define SHELLENV "SHELL"
                     49: # define SECURITY_DC
                     50: # define SECURITY_CC
                     51: # define close_descriptor(fd) close(fd)
                     52: static void pipe_close_parent(pipe_t *p) {
                     53:        /* don't close stdin */
                     54:        close_descriptor(p->parent);
                     55:        if (dup2(p->child, p->fd) != p->fd) {
                     56:                perror("pipe_child dup2");
                     57:        } else {
                     58:                close_descriptor(p->child);
                     59:                p->child = p->fd;
                     60:        }
                     61: }
                     62: static void pipe_close_child(pipe_t *p) {
                     63:        close_descriptor(p->child);
                     64:        p->fd = p->parent;
                     65: }
                     66: /* }}} */
                     67: #endif /* WIN32 */
                     68: 
                     69: /* {{{ pipe_close */
                     70: static void pipe_close(pipe_t *p) {
                     71:        close_descriptor(p->parent);
                     72:        close_descriptor(p->child);
                     73: #ifdef WIN32
                     74:        close(p->fd);
                     75: #endif
                     76: }
                     77: /* }}} */
                     78: /* {{{ pipe_open */
                     79: static int pipe_open(pipe_t *p, int fd SECURITY_DC) {
                     80:        descriptor_t newpipe[2];
                     81: 
                     82:        if (0 != pipe(newpipe)) {
                     83:                fprintf(stderr, "can't open pipe");
                     84:                return -1;
                     85:        }
                     86:        if (0 == fd) {
                     87:                p->parent = newpipe[1]; /* write */
                     88:                p->child  = newpipe[0]; /* read */
                     89:        } else {
                     90:                p->parent = newpipe[0]; /* read */
                     91:                p->child  = newpipe[1]; /* write */
                     92:        }
                     93:        p->fd = fd;
                     94: 
                     95:        return 0;
                     96: }
                     97: /* }}} */
                     98: 
                     99: /* {{{ proc_open_pipes */
                    100: static int proc_open_pipes(proc_handler_t *proc SECURITY_DC) {
                    101:        if (pipe_open(&(proc->in), 0 SECURITY_CC) != 0) {
                    102:                return -1;
                    103:        }
                    104:        if (pipe_open(&(proc->out), 1 SECURITY_CC) != 0) {
                    105:                return -1;
                    106:        }
                    107:        if (pipe_open(&(proc->err), 2 SECURITY_CC) != 0) {
                    108:                return -1;
                    109:        }
                    110:        return 0;
                    111: }
                    112: /* }}} */
                    113: /* {{{ proc_close_pipes */
                    114: static void proc_close_pipes(proc_handler_t *proc) {
                    115:        pipe_close(&proc->in);
                    116:        pipe_close(&proc->out);
                    117:        pipe_close(&proc->err);
                    118: }
                    119: /* }}} */
                    120: /* {{{ proc_close_parents */
                    121: static void proc_close_parents(proc_handler_t *proc) {
                    122:        pipe_close_parent(&proc->in);
                    123:        pipe_close_parent(&proc->out);
                    124:        pipe_close_parent(&proc->err);
                    125: }
                    126: /* }}} */
                    127: /* {{{ proc_close_childs */
                    128: static void proc_close_childs(proc_handler_t *proc) {
                    129:        pipe_close_child(&proc->in);
                    130:        pipe_close_child(&proc->out);
                    131:        pipe_close_child(&proc->err);
                    132: }
                    133: /* }}} */
                    134: 
                    135: #ifdef WIN32
                    136: /* {{{ proc_close */
                    137: int proc_close(proc_handler_t *proc) {
                    138:        proc_pid_t child = proc->child;
                    139:        DWORD wstatus;
                    140: 
                    141:        proc_close_pipes(proc);
                    142:        WaitForSingleObject(child, INFINITE);
                    143:        GetExitCodeProcess(child, &wstatus);
                    144:        CloseHandle(child);
                    145: 
                    146:        return wstatus;
                    147: }
                    148: /* }}} */
                    149: /* {{{ proc_open */
                    150: int proc_open(proc_handler_t *proc, const char *command) {
                    151:        PROCESS_INFORMATION pi;
                    152:        STARTUPINFO si;
                    153:        BOOL procok;
                    154:        SECURITY_ATTRIBUTES security;
                    155:        const char *shell = NULL;
                    156:        const char *windir = NULL;
                    157:        buffer *cmdline;
                    158: 
                    159:        if (NULL == (shell = getenv(SHELLENV)) &&
                    160:                        NULL == (windir = getenv("SystemRoot")) &&
                    161:                        NULL == (windir = getenv("windir"))) {
                    162:                fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
                    163:                return -1;
                    164:        }
                    165: 
                    166:        /* we use this to allow the child to inherit handles */
                    167:        memset(&security, 0, sizeof(security));
                    168:        security.nLength = sizeof(security);
                    169:        security.bInheritHandle = TRUE;
                    170:        security.lpSecurityDescriptor = NULL;
                    171: 
                    172:        if (proc_open_pipes(proc, &security) != 0) {
                    173:                return -1;
                    174:        }
                    175:        proc_close_parents(proc);
                    176: 
                    177:        memset(&si, 0, sizeof(si));
                    178:        si.cb = sizeof(si);
                    179:        si.dwFlags = STARTF_USESTDHANDLES;
                    180:        si.hStdInput = proc->in.child;
                    181:        si.hStdOutput = proc->out.child;
                    182:        si.hStdError = proc->err.child;
                    183: 
                    184:        memset(&pi, 0, sizeof(pi));
                    185: 
                    186:        cmdline = buffer_init();
                    187:        if (shell) {
                    188:                buffer_append_string(cmdline, shell);
                    189:        } else {
                    190:                buffer_append_string(cmdline, windir);
                    191:                buffer_append_string_len(cmdline, CONST_STR_LEN("\\system32\\cmd.exe"));
                    192:        }
                    193:        buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
                    194:        buffer_append_string(cmdline, command);
                    195:        procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
                    196:                        NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
                    197: 
                    198:        if (FALSE == procok) {
                    199:                fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
                    200:                buffer_free(cmdline);
                    201:                return -1;
                    202:        }
                    203:        buffer_free(cmdline);
                    204: 
                    205:        proc->child = pi.hProcess;
                    206:        CloseHandle(pi.hThread);
                    207: 
                    208:        proc_close_childs(proc);
                    209: 
                    210:        return 0;
                    211: }
                    212: /* }}} */
                    213: #else /* WIN32 */
                    214: /* {{{ proc_close */
                    215: int proc_close(proc_handler_t *proc) {
                    216:        pid_t child = proc->child;
                    217:        int wstatus;
                    218:        pid_t wait_pid;
                    219: 
                    220:        proc_close_pipes(proc);
                    221: 
                    222:        do {
                    223:                wait_pid = waitpid(child, &wstatus, 0);
                    224:        } while (wait_pid == -1 && errno == EINTR);
                    225: 
                    226:        if (wait_pid == -1) {
                    227:                return -1;
                    228:        } else {
                    229:                if (WIFEXITED(wstatus))
                    230:                        wstatus = WEXITSTATUS(wstatus);
                    231:        }
                    232: 
                    233:        return wstatus;
                    234: }
                    235: /* }}} */
                    236: /* {{{ proc_open */
                    237: int proc_open(proc_handler_t *proc, const char *command) {
                    238:        pid_t child;
                    239:        const char *shell;
                    240: 
                    241:        if (NULL == (shell = getenv(SHELLENV))) {
                    242:                shell = "/bin/sh";
                    243:        }
                    244: 
                    245:        if (proc_open_pipes(proc) != 0) {
                    246:                return -1;
                    247:        }
                    248: 
                    249:        /* the unix way */
                    250: 
                    251:        child = fork();
                    252: 
                    253:        if (child == 0) {
                    254:                /* this is the child process */
                    255: 
                    256:                /* close those descriptors that we just opened for the parent stuff,
                    257:                 * dup new descriptors into required descriptors and close the original
                    258:                 * cruft
                    259:                 */
                    260:                proc_close_parents(proc);
                    261: 
                    262:                execl(shell, shell, "-c", command, (char *)NULL);
                    263:                fprintf(stderr, "failed to execute shell: %s -c %s: %s\n", shell, command, strerror(errno));
                    264:                _exit(127);
                    265: 
                    266:        } else if (child < 0) {
                    267:                fprintf(stderr, "failed to forking");
                    268:                proc_close(proc);
                    269:                return -1;
                    270: 
                    271:        } else {
                    272:                proc->child = child;
                    273:                proc_close_childs(proc);
                    274:                return 0;
                    275:        }
                    276: }
                    277: /* }}} */
                    278: #endif /* WIN32 */
                    279: 
                    280: /* {{{ proc_read_fd_to_buffer */
                    281: static void proc_read_fd_to_buffer(int fd, buffer *b) {
                    282:        ssize_t s;
                    283: 
                    284:        for (;;) {
1.1.1.2 ! misho     285:                buffer_string_prepare_append(b, 1024);
        !           286:                if ((s = read(fd, (void *)(b->ptr + buffer_string_length(b)), buffer_string_space(b))) <= 0) {
1.1       misho     287:                        break;
                    288:                }
1.1.1.2 ! misho     289:                buffer_commit(b, s);
1.1       misho     290:        }
                    291: }
                    292: /* }}} */
                    293: /* {{{ proc_open_buffer */
                    294: int proc_open_buffer(const char *command, buffer *in, buffer *out, buffer *err) {
                    295:        proc_handler_t proc;
                    296: 
                    297:        if (proc_open(&proc, command) != 0) {
                    298:                return -1;
                    299:        }
                    300: 
                    301:        if (in) {
1.1.1.2 ! misho     302:                if (write(proc.in.fd, CONST_BUF_LEN(in)) < 0) {
1.1       misho     303:                        perror("error writing pipe");
                    304:                        return -1;
                    305:                }
                    306:        }
                    307:        pipe_close(&proc.in);
                    308: 
                    309:        if (out) {
                    310:                proc_read_fd_to_buffer(proc.out.fd, out);
                    311:        }
                    312:        pipe_close(&proc.out);
                    313: 
                    314:        if (err) {
                    315:                proc_read_fd_to_buffer(proc.err.fd, err);
                    316:        } else {
                    317:                buffer *tmp = buffer_init();
                    318:                proc_read_fd_to_buffer(proc.err.fd, tmp);
1.1.1.2 ! misho     319:                if (!buffer_string_is_empty(tmp) &&  write(2, CONST_BUF_LEN(tmp)) < 0) {
1.1       misho     320:                        perror("error writing pipe");
                    321:                        buffer_free(tmp);
                    322:                        return -1;
                    323:                }
                    324:                buffer_free(tmp);
                    325:        }
                    326:        pipe_close(&proc.err);
                    327: 
                    328:        proc_close(&proc);
                    329: 
                    330:        return 0;
                    331: }
                    332: /* }}} */
                    333: 
                    334: /* {{{ test */
                    335: #ifdef DEBUG_PROC_OPEN
                    336: int main(void) {
                    337:        proc_handler_t proc;
                    338:        buffer *in = buffer_init(), *out = buffer_init(), *err = buffer_init();
                    339:        int wstatus;
                    340: 
                    341: #define FREE() do { \
                    342:        buffer_free(in); \
                    343:        buffer_free(out); \
                    344:        buffer_free(err); \
                    345: } while (0)
                    346: 
                    347: #define RESET() do { \
                    348:        buffer_reset(in); \
                    349:        buffer_reset(out); \
                    350:        buffer_reset(err); \
                    351:        wstatus = proc_close(&proc); \
                    352:        if (0&&wstatus != 0) { \
                    353:                fprintf(stdout, "exitstatus %d\n", wstatus); \
                    354:                return __LINE__ - 200; \
                    355:        } \
                    356: } while (0)
                    357: 
                    358: #define ERROR_OUT() do { \
                    359:        fprintf(stdout, "failed opening proc\n"); \
                    360:        wstatus = proc_close(&proc); \
                    361:        fprintf(stdout, "exitstatus %d\n", wstatus); \
                    362:        FREE(); \
                    363:        return __LINE__ - 300; \
                    364: } while (0)
                    365: 
                    366: #ifdef WIN32
                    367: #define CMD_CAT "pause"
                    368: #else
                    369: #define CMD_CAT "cat"
                    370: #endif
                    371: 
                    372:        do {
                    373:                fprintf(stdout, "test: echo 123 without read\n");
                    374:                if (proc_open(&proc, "echo 321") != 0) {
                    375:                        ERROR_OUT();
                    376:                }
                    377:                close_descriptor(proc.in.parent);
                    378:                close_descriptor(proc.out.parent);
                    379:                close_descriptor(proc.err.parent);
                    380:                RESET();
                    381: 
                    382:                fprintf(stdout, "test: echo 321 with read\n"); fflush(stdout);
                    383:                if (proc_open_buffer("echo 321", NULL, out, err) != 0) {
                    384:                        ERROR_OUT();
                    385:                }
                    386:                fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
                    387:                RESET();
                    388: 
                    389:                fprintf(stdout, "test: echo 123 | " CMD_CAT "\n"); fflush(stdout);
                    390:                buffer_copy_string_len(in, CONST_STR_LEN("123\n"));
                    391:                if (proc_open_buffer(CMD_CAT, in, out, err) != 0) {
                    392:                        ERROR_OUT();
                    393:                }
                    394:                fprintf(stdout, "result: ->%s<-\n\n", out->ptr); fflush(stdout);
                    395:                RESET();
                    396:        } while (0);
                    397: 
                    398: #undef RESET
                    399: #undef ERROR_OUT
                    400: 
                    401:        fprintf(stdout, "ok\n");
                    402: 
                    403:        FREE();
                    404:        return 0;
                    405: }
                    406: #endif /* DEBUG_PROC_OPEN */
                    407: /* }}} */
                    408: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>