version 1.31, 2012/10/26 20:46:12 |
version 1.32, 2012/12/27 18:49:59 |
|
|
static char leftover[BUFSIZ]; |
static char leftover[BUFSIZ]; |
|
|
static int getregion(struct region *); |
static int getregion(struct region *); |
static int iomux(int); |
static int iomux(int, char * const, int, struct buffer *); |
static int pipeio(const char *); |
|
static int preadin(int, struct buffer *); |
static int preadin(int, struct buffer *); |
static void pwriteout(int, char **, int *); |
static void pwriteout(int, char **, int *); |
static int setsize(struct region *, RSIZE); |
static int setsize(struct region *, RSIZE); |
|
|
int |
int |
piperegion(int f, int n) |
piperegion(int f, int n) |
{ |
{ |
char *cmd, cmdbuf[NFILEN]; |
struct region region; |
|
struct buffer *bp; |
|
int len, ret; |
|
char *cmd, cmdbuf[NFILEN], *shellp, *text; |
|
char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL}; |
|
|
/* C-u M-| is not supported yet */ |
/* C-u M-| is not supported yet */ |
if (n > 1) |
if (n > 1) |
|
|
ewprintf("The mark is not set now, so there is no region"); |
ewprintf("The mark is not set now, so there is no region"); |
return (FALSE); |
return (FALSE); |
} |
} |
|
|
if ((cmd = eread("Shell command on region: ", cmdbuf, sizeof(cmdbuf), |
if ((cmd = eread("Shell command on region: ", cmdbuf, sizeof(cmdbuf), |
EFNEW | EFCR)) == NULL || (cmd[0] == '\0')) |
EFNEW | EFCR)) == NULL || (cmd[0] == '\0')) |
return (ABORT); |
return (ABORT); |
|
|
return (pipeio(cmdbuf)); |
argv[2] = cmd; |
|
|
|
if (getregion(®ion) != TRUE) |
|
return (FALSE); |
|
|
|
len = region.r_size; |
|
|
|
if ((text = malloc(len + 1)) == NULL) { |
|
ewprintf("Cannot allocate memory."); |
|
return (FALSE); |
|
} |
|
|
|
bp = bfind("*Shell Command Output*", TRUE); |
|
bp->b_flag |= BFREADONLY; |
|
if (bclear(bp) != TRUE) { |
|
free(text); |
|
return (FALSE); |
|
} |
|
|
|
region_get_data(®ion, text, len); |
|
shellp = getenv("SHELL"); |
|
|
|
ret = pipeio(shellp, argv, text, len, bp); |
|
|
|
if (ret == TRUE) { |
|
eerase(); |
|
if (lforw(bp->b_headp) == bp->b_headp) |
|
addline(bp, "(Shell command succeeded with no output)"); |
|
} |
|
|
|
free(text); |
|
return (ret); |
} |
} |
|
|
/* |
/* |
* Create a socketpair, fork and execl cmd passed. STDIN, STDOUT |
* Create a socketpair, fork and execv path with argv. |
* and STDERR of child process are redirected to socket. |
* STDIN, STDOUT and STDERR of child process are redirected to socket. |
|
* Parent writes len chars from text to socket. |
*/ |
*/ |
int |
int |
pipeio(const char* const cmd) |
pipeio(const char* const path, char* const argv[], char* const text, int len, |
|
struct buffer *outbp) |
{ |
{ |
int s[2]; |
int s[2]; |
char *shellp; |
char *err; |
|
|
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) { |
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) { |
ewprintf("socketpair error"); |
ewprintf("socketpair error"); |
return (FALSE); |
return (FALSE); |
} |
} |
|
|
switch(fork()) { |
switch(fork()) { |
case -1: |
case -1: |
ewprintf("Can't fork"); |
ewprintf("Can't fork"); |
|
|
_exit(1); |
_exit(1); |
if (dup2(s[1], STDERR_FILENO) == -1) |
if (dup2(s[1], STDERR_FILENO) == -1) |
_exit(1); |
_exit(1); |
if ((shellp = getenv("SHELL")) == NULL) |
if (path == NULL) |
_exit(1); |
_exit(1); |
execl(shellp, "sh", "-c", cmd, (char *)NULL); |
|
|
execv(path, argv); |
|
err = strerror(errno); |
|
write(s[1], err, strlen(err)); |
_exit(1); |
_exit(1); |
default: |
default: |
/* Parent process */ |
/* Parent process */ |
close(s[1]); |
close(s[1]); |
return iomux(s[0]); |
return (iomux(s[0], text, len, outbp)); |
} |
} |
return (FALSE); |
return (FALSE); |
} |
} |
|
|
/* |
/* |
* Multiplex read, write on socket fd passed. First get the region, |
* Multiplex read, write on socket fd passed. Put output in outbp |
* find/create *Shell Command Output* buffer and clear it's contents. |
|
* Poll on the fd for both read and write readiness. |
* Poll on the fd for both read and write readiness. |
*/ |
*/ |
int |
int |
iomux(int fd) |
iomux(int fd, char* const text, int len, struct buffer *outbp) |
{ |
{ |
struct region region; |
|
struct buffer *bp; |
|
struct pollfd pfd[1]; |
struct pollfd pfd[1]; |
int nfds; |
int nfds; |
char *text, *textcopy; |
char *textcopy; |
|
|
if (getregion(®ion) != TRUE) { |
|
close(fd); |
|
return (FALSE); |
|
} |
|
|
|
if ((text = malloc(region.r_size + 1)) == NULL) { |
|
close(fd); |
|
return (ABORT); |
|
} |
|
|
|
region_get_data(®ion, text, region.r_size); |
|
textcopy = text; |
textcopy = text; |
fcntl(fd, F_SETFL, O_NONBLOCK); |
fcntl(fd, F_SETFL, O_NONBLOCK); |
|
pfd[0].fd = fd; |
/* There is nothing to write if r_size is zero |
|
|
/* There is nothing to write if len is zero |
* but the cmd's output should be read so shutdown |
* but the cmd's output should be read so shutdown |
* the socket for writing only. |
* the socket for writing only and don't wait for POLLOUT |
*/ |
*/ |
if (region.r_size == 0) |
if (len == 0) { |
shutdown(fd, SHUT_WR); |
shutdown(fd, SHUT_WR); |
|
pfd[0].events = POLLIN; |
bp = bfind("*Shell Command Output*", TRUE); |
} else |
bp->b_flag |= BFREADONLY; |
pfd[0].events = POLLIN | POLLOUT; |
if (bclear(bp) != TRUE) { |
|
close(fd); |
|
free(text); |
|
return (FALSE); |
|
} |
|
|
|
pfd[0].fd = fd; |
|
pfd[0].events = POLLIN | POLLOUT; |
|
while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 || |
while ((nfds = poll(pfd, 1, TIMEOUT)) != -1 || |
(pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) { |
(pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL))) { |
if (pfd[0].revents & POLLOUT && region.r_size > 0) |
if (pfd[0].revents & POLLOUT && len > 0) |
pwriteout(fd, &textcopy, ®ion.r_size); |
pwriteout(fd, &textcopy, &len); |
else if (pfd[0].revents & POLLIN) |
else if (pfd[0].revents & POLLIN) |
if (preadin(fd, bp) == FALSE) |
if (preadin(fd, outbp) == FALSE) |
break; |
break; |
|
if (len == 0 && pfd[0].events & POLLOUT) |
|
pfd[0].events = POLLIN; |
} |
} |
close(fd); |
close(fd); |
free(text); |
|
/* In case if last line doesn't have a '\n' add the leftover |
/* In case if last line doesn't have a '\n' add the leftover |
* characters to buffer. |
* characters to buffer. |
*/ |
*/ |
if (leftover[0] != '\0') { |
if (leftover[0] != '\0') { |
addline(bp, leftover); |
addline(outbp, leftover); |
leftover[0] = '\0'; |
leftover[0] = '\0'; |
} |
} |
if (nfds == 0) { |
if (nfds == 0) { |
|
|
ewprintf("poll error"); |
ewprintf("poll error"); |
return (FALSE); |
return (FALSE); |
} |
} |
return (popbuftop(bp, WNONE)); |
return (popbuftop(outbp, WNONE)); |
} |
} |
|
|
/* |
/* |
|
|
preadin(int fd, struct buffer *bp) |
preadin(int fd, struct buffer *bp) |
{ |
{ |
int len; |
int len; |
static int nooutput; |
|
char buf[BUFSIZ], *p, *q; |
char buf[BUFSIZ], *p, *q; |
|
|
if ((len = read(fd, buf, BUFSIZ - 1)) == 0) { |
if ((len = read(fd, buf, BUFSIZ - 1)) == 0) |
if (nooutput == 0) |
|
addline(bp, "(Shell command succeeded with no output)"); |
|
nooutput = 0; |
|
return (FALSE); |
return (FALSE); |
} |
|
nooutput = 1; |
|
buf[len] = '\0'; |
buf[len] = '\0'; |
p = q = buf; |
p = q = buf; |
if (leftover[0] != '\0' && ((q = strchr(p, '\n')) != NULL)) { |
if (leftover[0] != '\0' && ((q = strchr(p, '\n')) != NULL)) { |