File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / proc_open.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 10:32:48 2013 UTC (10 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_35p0, v1_4_35, v1_4_33, HEAD
1.4.33

    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>