1 /* $OpenPackages$ */ 2 /* $OpenBSD: cmd_exec.c,v 1.3 2002/08/05 17:04:36 millert Exp $ */ 3 /* 4 * Copyright (c) 2001 Marc Espie. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 16 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD 19 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/types.h> 29 #include <sys/wait.h> 30 #include <errno.h> 31 #include <stdio.h> 32 #include <unistd.h> 33 #include "config.h" 34 #include "defines.h" 35 #include "cmd_exec.h" 36 #include "buf.h" 37 #include "memory.h" 38 #include "pathnames.h" 39 40 char * 41 Cmd_Exec(cmd, err) 42 const char *cmd; 43 char **err; 44 { 45 char *args[4]; /* Args for invoking the shell */ 46 int fds[2]; /* Pipe streams */ 47 pid_t cpid; /* Child PID */ 48 pid_t pid; /* PID from wait() */ 49 char *result; /* Result */ 50 int status; /* Command exit status */ 51 BUFFER buf; /* Buffer to store the result. */ 52 char *cp; /* Pointer into result. */ 53 ssize_t cc; /* Characters read from pipe. */ 54 size_t length; /* Total length of result. */ 55 56 57 *err = NULL; 58 59 /* Set up arguments for the shell. */ 60 args[0] = "sh"; 61 args[1] = "-c"; 62 args[2] = (char *)cmd; 63 args[3] = NULL; 64 65 /* Open a pipe for retrieving shell's output. */ 66 if (pipe(fds) == -1) { 67 *err = "Couldn't create pipe for \"%s\""; 68 goto bad; 69 } 70 71 /* Fork */ 72 switch (cpid = fork()) { 73 case 0: 74 /* Close input side of pipe */ 75 (void)close(fds[0]); 76 77 /* Duplicate the output stream to the shell's output, then 78 * shut the extra thing down. Note we don't fetch the error 79 * stream: user can use redirection to grab it as this goes 80 * through /bin/sh. 81 */ 82 if (fds[1] != 1) { 83 (void)dup2(fds[1], 1); 84 (void)close(fds[1]); 85 } 86 87 (void)execv(_PATH_BSHELL, args); 88 _exit(1); 89 /*NOTREACHED*/ 90 91 case -1: 92 *err = "Couldn't exec \"%s\""; 93 goto bad; 94 95 default: 96 /* No need for the writing half. */ 97 (void)close(fds[1]); 98 99 Buf_Init(&buf, MAKE_BSIZE); 100 101 do { 102 char grab[BUFSIZ]; 103 104 cc = read(fds[0], grab, sizeof(grab)); 105 if (cc > 0) 106 Buf_AddChars(&buf, cc, grab); 107 } 108 while (cc > 0 || (cc == -1 && errno == EINTR)); 109 110 /* Close the input side of the pipe. */ 111 (void)close(fds[0]); 112 113 /* Wait for the child to exit. */ 114 while ((pid = wait(&status)) != cpid && pid >= 0) 115 continue; 116 117 if (cc == -1) 118 *err = "Couldn't read shell's output for \"%s\""; 119 120 if (status) 121 *err = "\"%s\" returned non-zero status"; 122 123 length = Buf_Size(&buf); 124 result = Buf_Retrieve(&buf); 125 126 /* The result is null terminated, Convert newlines to spaces. */ 127 cp = result + length - 1; 128 129 if (*cp == '\n') 130 /* A final newline is just stripped. */ 131 *cp-- = '\0'; 132 133 while (cp >= result) { 134 if (*cp == '\n') 135 *cp = ' '; 136 cp--; 137 } 138 break; 139 } 140 return result; 141 bad: 142 return estrdup(""); 143 } 144 145