1 /* $OpenPackages$ */ 2 /* $OpenBSD: cmd_exec.c,v 1.1 2001/05/23 12:34:40 espie 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 = vfork()) { 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 (void)dup2(fds[1], 1); 83 if (fds[1] != 1) 84 (void)close(fds[1]); 85 86 (void)execv(_PATH_BSHELL, args); 87 _exit(1); 88 /*NOTREACHED*/ 89 90 case -1: 91 *err = "Couldn't exec \"%s\""; 92 goto bad; 93 94 default: 95 /* No need for the writing half. */ 96 (void)close(fds[1]); 97 98 Buf_Init(&buf, MAKE_BSIZE); 99 100 do { 101 char grab[BUFSIZ]; 102 103 cc = read(fds[0], grab, sizeof(grab)); 104 if (cc > 0) 105 Buf_AddChars(&buf, cc, grab); 106 } 107 while (cc > 0 || (cc == -1 && errno == EINTR)); 108 109 /* Close the input side of the pipe. */ 110 (void)close(fds[0]); 111 112 /* Wait for the child to exit. */ 113 while ((pid = wait(&status)) != cpid && pid >= 0) 114 continue; 115 116 if (cc == -1) 117 *err = "Couldn't read shell's output for \"%s\""; 118 119 if (status) 120 *err = "\"%s\" returned non-zero status"; 121 122 length = Buf_Size(&buf); 123 result = Buf_Retrieve(&buf); 124 125 /* The result is null terminated, Convert newlines to spaces. */ 126 cp = result + length - 1; 127 128 if (*cp == '\n') 129 /* A final newline is just stripped. */ 130 *cp-- = '\0'; 131 132 while (cp >= result) { 133 if (*cp == '\n') 134 *cp = ' '; 135 cp--; 136 } 137 break; 138 } 139 return result; 140 bad: 141 return estrdup(""); 142 } 143 144