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, ©, 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>