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