version 1.5, 2004/04/07 13:11:35 |
version 1.6, 2007/07/24 21:09:07 |
|
|
char * |
char * |
Cmd_Exec(const char *cmd, char **err) |
Cmd_Exec(const char *cmd, char **err) |
{ |
{ |
char *args[4]; /* Args for invoking the shell */ |
char *args[4]; /* Args for invoking the shell */ |
int fds[2]; /* Pipe streams */ |
int fds[2]; /* Pipe streams */ |
pid_t cpid; /* Child PID */ |
pid_t cpid; /* Child PID */ |
pid_t pid; /* PID from wait() */ |
pid_t pid; /* PID from wait() */ |
char *result; /* Result */ |
char *result; /* Result */ |
int status; /* Command exit status */ |
int status; /* Command exit status */ |
BUFFER buf; /* Buffer to store the result. */ |
BUFFER buf; /* Buffer to store the result. */ |
char *cp; /* Pointer into result. */ |
char *cp; /* Pointer into result. */ |
ssize_t cc; /* Characters read from pipe. */ |
ssize_t cc; /* Characters read from pipe. */ |
size_t length; /* Total length of result. */ |
size_t length; /* Total length of result. */ |
|
|
|
|
*err = NULL; |
*err = NULL; |
|
|
/* Set up arguments for the shell. */ |
/* Set up arguments for the shell. */ |
args[0] = "sh"; |
args[0] = "sh"; |
args[1] = "-c"; |
args[1] = "-c"; |
args[2] = (char *)cmd; |
args[2] = (char *)cmd; |
args[3] = NULL; |
args[3] = NULL; |
|
|
/* Open a pipe for retrieving shell's output. */ |
/* Open a pipe for retrieving shell's output. */ |
if (pipe(fds) == -1) { |
if (pipe(fds) == -1) { |
*err = "Couldn't create pipe for \"%s\""; |
*err = "Couldn't create pipe for \"%s\""; |
goto bad; |
goto bad; |
} |
} |
|
|
/* Fork */ |
/* Fork */ |
switch (cpid = fork()) { |
switch (cpid = fork()) { |
case 0: |
case 0: |
/* Close input side of pipe */ |
/* Close input side of pipe */ |
(void)close(fds[0]); |
(void)close(fds[0]); |
|
|
/* Duplicate the output stream to the shell's output, then |
/* Duplicate the output stream to the shell's output, then |
* shut the extra thing down. Note we don't fetch the error |
* shut the extra thing down. Note we don't fetch the error |
* stream: user can use redirection to grab it as this goes |
* stream: user can use redirection to grab it as this goes |
* through /bin/sh. |
* through /bin/sh. |
*/ |
*/ |
if (fds[1] != 1) { |
if (fds[1] != 1) { |
(void)dup2(fds[1], 1); |
(void)dup2(fds[1], 1); |
(void)close(fds[1]); |
(void)close(fds[1]); |
} |
} |
|
|
(void)execv(_PATH_BSHELL, args); |
(void)execv(_PATH_BSHELL, args); |
_exit(1); |
_exit(1); |
/*NOTREACHED*/ |
/*NOTREACHED*/ |
|
|
case -1: |
case -1: |
*err = "Couldn't exec \"%s\""; |
*err = "Couldn't exec \"%s\""; |
goto bad; |
goto bad; |
|
|
default: |
default: |
/* No need for the writing half. */ |
/* No need for the writing half. */ |
(void)close(fds[1]); |
(void)close(fds[1]); |
|
|
Buf_Init(&buf, MAKE_BSIZE); |
Buf_Init(&buf, MAKE_BSIZE); |
|
|
do { |
do { |
char grab[BUFSIZ]; |
char grab[BUFSIZ]; |
|
|
cc = read(fds[0], grab, sizeof(grab)); |
cc = read(fds[0], grab, sizeof(grab)); |
if (cc > 0) |
if (cc > 0) |
Buf_AddChars(&buf, cc, grab); |
Buf_AddChars(&buf, cc, grab); |
} |
} while (cc > 0 || (cc == -1 && errno == EINTR)); |
while (cc > 0 || (cc == -1 && errno == EINTR)); |
|
|
|
/* Close the input side of the pipe. */ |
/* Close the input side of the pipe. */ |
(void)close(fds[0]); |
(void)close(fds[0]); |
|
|
/* Wait for the child to exit. */ |
/* Wait for the child to exit. */ |
while ((pid = wait(&status)) != cpid && pid >= 0) |
while ((pid = wait(&status)) != cpid && pid >= 0) |
continue; |
continue; |
|
|
if (cc == -1) |
if (cc == -1) |
*err = "Couldn't read shell's output for \"%s\""; |
*err = "Couldn't read shell's output for \"%s\""; |
|
|
if (status) |
if (status) |
*err = "\"%s\" returned non-zero status"; |
*err = "\"%s\" returned non-zero status"; |
|
|
length = Buf_Size(&buf); |
length = Buf_Size(&buf); |
result = Buf_Retrieve(&buf); |
result = Buf_Retrieve(&buf); |
|
|
/* The result is null terminated, Convert newlines to spaces. */ |
/* The result is null terminated, Convert newlines to spaces. */ |
cp = result + length - 1; |
cp = result + length - 1; |
|
|
if (cp >= result && *cp == '\n') |
if (cp >= result && *cp == '\n') |
/* A final newline is just stripped. */ |
/* A final newline is just stripped. */ |
*cp-- = '\0'; |
*cp-- = '\0'; |
|
|
while (cp >= result) { |
while (cp >= result) { |
if (*cp == '\n') |
if (*cp == '\n') |
*cp = ' '; |
*cp = ' '; |
cp--; |
cp--; |
|
} |
|
break; |
} |
} |
break; |
return result; |
} |
bad: |
return result; |
return estrdup(""); |
bad: |
|
return estrdup(""); |
|
} |
} |
|
|