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