Annotation of src/usr.bin/make/cmd_exec.c, Revision 1.9
1.9 ! espie 1: /* $OpenBSD: cmd_exec.c,v 1.8 2010/07/19 19:46:43 espie Exp $ */
1.1 espie 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 *
1.5 espie 40: Cmd_Exec(const char *cmd, char **err)
1.1 espie 41: {
1.6 espie 42: char *args[4]; /* Args for invoking the shell */
43: int fds[2]; /* Pipe streams */
44: pid_t cpid; /* Child PID */
45: pid_t pid; /* PID from wait() */
46: char *result; /* Result */
47: int status; /* Command exit status */
48: BUFFER buf; /* Buffer to store the result. */
49: char *cp; /* Pointer into result. */
50: ssize_t cc; /* Characters read from pipe. */
51: size_t length; /* Total length of result. */
52:
53:
54: *err = NULL;
55:
56: /* Set up arguments for the shell. */
57: args[0] = "sh";
58: args[1] = "-c";
59: args[2] = (char *)cmd;
60: args[3] = NULL;
61:
62: /* Open a pipe for retrieving shell's output. */
63: if (pipe(fds) == -1) {
64: *err = "Couldn't create pipe for \"%s\"";
65: goto bad;
1.3 millert 66: }
1.1 espie 67:
1.6 espie 68: /* Fork */
69: switch (cpid = fork()) {
70: case 0:
71: /* Close input side of pipe */
72: (void)close(fds[0]);
73:
74: /* Duplicate the output stream to the shell's output, then
75: * shut the extra thing down. Note we don't fetch the error
76: * stream: user can use redirection to grab it as this goes
77: * through /bin/sh.
78: */
79: if (fds[1] != 1) {
80: (void)dup2(fds[1], 1);
81: (void)close(fds[1]);
82: }
83:
84: (void)execv(_PATH_BSHELL, args);
85: _exit(1);
86: /*NOTREACHED*/
87:
88: case -1:
89: *err = "Couldn't exec \"%s\"";
90: goto bad;
91:
92: default:
93: /* No need for the writing half. */
94: (void)close(fds[1]);
95:
96: Buf_Init(&buf, MAKE_BSIZE);
97:
98: do {
99: char grab[BUFSIZ];
100:
101: cc = read(fds[0], grab, sizeof(grab));
102: if (cc > 0)
103: Buf_AddChars(&buf, cc, grab);
104: } while (cc > 0 || (cc == -1 && errno == EINTR));
105:
106: /* Close the input side of the pipe. */
107: (void)close(fds[0]);
108:
109: /* Wait for the child to exit. */
1.9 ! espie 110: while (waitpid(cpid, &status, 0) == -1 && errno == EINTR)
1.6 espie 111: continue;
112:
113: if (cc == -1)
114: *err = "Couldn't read shell's output for \"%s\"";
115:
116: if (status)
117: *err = "\"%s\" returned non-zero status";
118:
119: length = Buf_Size(&buf);
120: result = Buf_Retrieve(&buf);
121:
122: /* The result is null terminated, Convert newlines to spaces. */
123: cp = result + length - 1;
124:
125: if (cp >= result && *cp == '\n')
126: /* A final newline is just stripped. */
127: *cp-- = '\0';
128:
129: while (cp >= result) {
130: if (*cp == '\n')
131: *cp = ' ';
132: cp--;
133: }
134: break;
1.1 espie 135: }
1.6 espie 136: return result;
137: bad:
138: return estrdup("");
1.1 espie 139: }
140: