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

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

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