Annotation of embedaddon/lighttpd/src/proc_open.c, revision 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>