* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)system.c 8.1 (Berkeley) 6/9/93";
esystem(sp
, shell
, command
)
const u_char
*shell
, *command
;
sig_ret_t intsave
, quitsave
;
sigaddset(&bmask
, SIGCHLD
);
(void)sigprocmask(SIG_BLOCK
, &bmask
, &omask
);
(void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
msgq(sp
, M_ERR
, "fork: %s", strerror(errno
));
(void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
if ((name
= strrchr((char *)shell
, '/')) == NULL
)
execl((char *)shell
, name
, "-c", command
, NULL
);
msgq(sp
, M_ERR
, "exec: %s: %s", shell
, strerror(errno
));
intsave
= signal(SIGINT
, SIG_IGN
);
quitsave
= signal(SIGQUIT
, SIG_IGN
);
pid
= waitpid(pid
, (int *)&pstat
, 0);
(void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
(void)signal(SIGINT
, intsave
);
(void)signal(SIGQUIT
, quitsave
);
return(pid
== -1 ? -1 : WEXITSTATUS(pstat
));
* Fork a process and exec a program, reading the standard out of the
* program and piping it to the output of ex, whether that's really
* stdout, or the vi screen.
ex_run_process(sp
, cmd
, lenp
, bp
, blen
)
int ch
, cnt
, nr
, pstat
, rval
, pdes
[2];
char *p
, *sh
, *sh_path
, buf
[1024];
msgq(sp
, M_ERR
, "Error: pipe: %s", strerror(errno
));
sh_path
= O_STR(sp
, O_SHELL
);
if ((sh
= strrchr(sh_path
, '/')) == NULL
)
msgq(sp
, M_ERR
, "Error: vfork: %s", strerror(errno
));
if (pdes
[1] != STDOUT_FILENO
) {
(void)dup2(pdes
[1], STDOUT_FILENO
);
if (pdes
[1] != STDERR_FILENO
)
(void)dup2(STDOUT_FILENO
, STDERR_FILENO
);
/* Use -f for the csh; assume that all shells have -c. */
if (!strcmp(sh_path
, _PATH_CSHELL
))
execl(sh_path
, sh
, "-f", "-c", cmd
, NULL
);
execl(sh_path
, sh
, "-c", cmd
, NULL
);
msgq(sp
, M_ERR
, "Error: %s: %s", sh_path
, strerror(errno
));
/* Parent; assume fdopen can't fail. */
iop
= fdopen(pdes
[0], "r");
/* Copy process output into a buffer. */
--blen
&& (ch
= getc(iop
)) != EOF
; *p
++ = ch
, ++len
);
msgq(sp
, M_ERR
, "%s: output truncated", sh
);
if (p
> bp
&& p
[-1] == '\n' || p
[-1] == '\r') {
/* Copy process output to ex output, changing \r's to \n's. */
while (nr
= fread(buf
, sizeof(buf
[0]), sizeof(buf
), iop
)) {
for (p
= buf
, cnt
= nr
; --cnt
; ++p
)
if (fwrite(buf
, sizeof(buf
[0]), nr
, sp
->stdfp
) != nr
) {
msgq(sp
, M_ERR
, "I/O error: %s", sh
);
msgq(sp
, M_ERR
, "I/O error: %s", sh
);
/* Get the status of the process. */
sigaddset(&bmask
, SIGINT
);
sigaddset(&bmask
, SIGQUIT
);
sigaddset(&bmask
, SIGHUP
);
(void)sigprocmask(SIG_BLOCK
, &bmask
, &omask
);
pid
= waitpid(pid
, (int *)&pstat
, 0);
} while (pid
== -1 && errno
== EINTR
);
(void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
if (WIFSIGNALED(pstat
)) {
(void)fprintf(sp
->stdfp
, "%s\n", bp
);
(void)fprintf(sp
->stdfp
, "%s: exited with signal %d%s.\n", sh
,
WTERMSIG(pstat
), WCOREDUMP(pstat
) ? "; core dumped" : "");
} else if (WIFEXITED(pstat
) && WEXITSTATUS(pstat
)) {
(void)fprintf(sp
->stdfp
, "%s\n", bp
);
"%s: exited with status %d.\n", sh
, WEXITSTATUS(pstat
));
* Fork a process and exec a shell, copying our input from to its
* standard input, reading its standard output and piping it to the
* output of ex, whether that's really stdout, or the vi screen.
int cnt
, nr
, pstat
, cdes
[2], pdes
[2];
char *p
, *sh
, *sh_path
, buf
[1024];
/* Open the parent-to-child file descriptors. */
msgq(sp
, M_ERR
, "Error: pipe: %s", strerror(errno
));
/* Open the child-to-parent file descriptors. */
msgq(sp
, M_ERR
, "Error: pipe: %s", strerror(errno
));
sh_path
= O_STR(sp
, O_SHELL
);
if ((sh
= strrchr(sh_path
, '/')) == NULL
)
* ++++++++++++++++++++++++++++++
msgq(sp
, M_ERR
, "Error: vfork: %s", strerror(errno
));
(void)close(cdes
[0]); /* Unused. */
if (pdes
[0] != STDIN_FILENO
) {
(void)dup2(pdes
[0], STDIN_FILENO
);
if (cdes
[1] != STDOUT_FILENO
) {
(void)dup2(cdes
[1], STDOUT_FILENO
);
if (cdes
[1] != STDERR_FILENO
)
(void)dup2(STDOUT_FILENO
, STDERR_FILENO
);
execl(sh_path
, sh
, "-i", NULL
);
msgq(sp
, M_ERR
, "Error: %s: %s", sh_path
, strerror(errno
));
(void)close(cdes
[1]); /* Parent. */
(void)close(pdes
[0]); /* Unused. */
FD_SET(STDIN_FILENO
, &fdset
);
if (select(32, &fdset
, NULL
, NULL
, NULL
) == -1)
if (FD_ISSET(cdes
[0], &fdset
)) {
nr
= read(cdes
[0], buf
, sizeof(buf
));
for (p
= buf
, cnt
= 0; cnt
< nr
; ++cnt
, ++p
)
if (fwrite(buf
, sizeof(buf
[0]), nr
, sp
->stdfp
) != nr
) {
err
: msgq(sp
, M_ERR
, "I/O error: %s: %s",
} else if (FD_ISSET(STDIN_FILENO
, &fdset
)) {
userwait
: nr
= read(STDIN_FILENO
, buf
, sizeof(buf
));
for (p
= buf
, cnt
= 0; cnt
< nr
; ++cnt
, ++p
)
if (fwrite(buf
, sizeof(buf
[0]), nr
, sp
->stdfp
) != nr
)
if (write(pdes
[1], buf
, nr
) != nr
)
/* Get the status of the process. */
sigaddset(&bmask
, SIGINT
);
sigaddset(&bmask
, SIGQUIT
);
sigaddset(&bmask
, SIGHUP
);
(void)sigprocmask(SIG_BLOCK
, &bmask
, &omask
);
pid
= waitpid(pid
, (int *)&pstat
, 0);
} while (pid
== -1 && errno
== EINTR
);
(void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
if (WIFSIGNALED(pstat
)) {
(void)fprintf(sp
->stdfp
, "%.*s%s: exited with signal %d%s.\n",
(int)MIN(len
, 10), len
> 10 ? "..." : "", sh
,
WTERMSIG(pstat
), WCOREDUMP(pstat
) ? "; core dumped" : "");
} else if (WIFEXITED(pstat
) && WEXITSTATUS(pstat
)) {
(void)fprintf(sp
->stdfp
, "%.*s%s: exited with status %d.\n",
len
> 10 ? "..." : "", WEXITSTATUS(pstat
));