File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / proc_open.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:35:00 2016 UTC (7 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_41p8, HEAD
lighttpd 1.4.41

    1: #include "first.h"
    2: 
    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 (;;) {
  285: 		buffer_string_prepare_append(b, 1024);
  286: 		if ((s = read(fd, (void *)(b->ptr + buffer_string_length(b)), buffer_string_space(b))) <= 0) {
  287: 			break;
  288: 		}
  289: 		buffer_commit(b, s);
  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) {
  302: 		if (write(proc.in.fd, CONST_BUF_LEN(in)) < 0) {
  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);
  319: 		if (!buffer_string_is_empty(tmp) &&  write(2, CONST_BUF_LEN(tmp)) < 0) {
  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>