aboutsummaryrefslogtreecommitdiff
path: root/src/os_unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/os_unix.c')
-rw-r--r--src/os_unix.c492
1 files changed, 0 insertions, 492 deletions
diff --git a/src/os_unix.c b/src/os_unix.c
index 3f95f7bdc8..7df61f012f 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -87,7 +87,6 @@ typedef union wait waitstatus;
#else
typedef int waitstatus;
#endif
-static pid_t wait4pid(pid_t, waitstatus *);
static int RealWaitForChar(int, long, int *);
@@ -1070,497 +1069,6 @@ void mch_new_shellsize()
}
/*
- * Wait for process "child" to end.
- * Return "child" if it exited properly, <= 0 on error.
- */
-static pid_t wait4pid(child, status)
-pid_t child;
-waitstatus *status;
-{
- pid_t wait_pid = 0;
-
- while (wait_pid != child) {
- /* When compiled with Python threads are probably used, in which case
- * wait() sometimes hangs for no obvious reason. Use waitpid()
- * instead and loop (like the GUI). Also needed for other interfaces,
- * they might call system(). */
-# ifdef __NeXT__
- wait_pid = wait4(child, status, WNOHANG, (struct rusage *)0);
-# else
- wait_pid = waitpid(child, status, WNOHANG);
-# endif
- if (wait_pid == 0) {
- /* Wait for 10 msec before trying again. */
- os_delay(10L, TRUE);
- continue;
- }
- if (wait_pid <= 0
-# ifdef ECHILD
- && errno == ECHILD
-# endif
- )
- break;
- }
- return wait_pid;
-}
-
-int mch_call_shell(char_u *cmd, ShellOpts opts, char_u *extra_shell_arg)
-{
- int tmode = cur_tmode;
-
-# define EXEC_FAILED 122 /* Exit code when shell didn't execute. Don't use
- 127, some shells use that already */
-
- pid_t pid;
- pid_t wpid = 0;
- pid_t wait_pid = 0;
-# ifdef HAVE_UNION_WAIT
- union wait status;
-# else
- int status = -1;
-# endif
- int retval = -1;
- char **argv = NULL;
- int i;
- int fd_toshell[2]; /* for pipes */
- int fd_fromshell[2];
- int pipe_error = FALSE;
- char envbuf[50];
- int did_settmode = FALSE; /* settmode(TMODE_RAW) called */
-
- out_flush();
- if (opts & kShellOptCooked)
- settmode(TMODE_COOK); /* set to normal mode */
-
- argv = shell_build_argv(cmd, extra_shell_arg);
-
- if (argv == NULL) {
- goto error;
- }
-
- /*
- * For the GUI, when writing the output into the buffer and when reading
- * input from the buffer: Try using a pseudo-tty to get the stdin/stdout
- * of the executed command into the Vim window. Or use a pipe.
- */
- if (opts & (kShellOptRead|kShellOptWrite)) {
- {
- pipe_error = (pipe(fd_toshell) < 0);
- if (!pipe_error) { /* pipe create OK */
- pipe_error = (pipe(fd_fromshell) < 0);
- if (pipe_error) { /* pipe create failed */
- close(fd_toshell[0]);
- close(fd_toshell[1]);
- }
- }
- if (pipe_error) {
- MSG_PUTS(_("\nCannot create pipes\n"));
- out_flush();
- }
- }
- }
-
- if (!pipe_error) { /* pty or pipe opened or not used */
-
- if ((pid = fork()) == -1) { /* maybe we should use vfork() */
- MSG_PUTS(_("\nCannot fork\n"));
- if (opts & (kShellOptRead | kShellOptWrite)) {
- {
- close(fd_toshell[0]);
- close(fd_toshell[1]);
- close(fd_fromshell[0]);
- close(fd_fromshell[1]);
- }
- }
- } else if (pid == 0) { /* child */
- signal_stop(); /* handle signals normally */
-
- if (opts & (kShellOptHideMess | kShellOptExpand)) {
- int fd;
-
- /*
- * Don't want to show any message from the shell. Can't just
- * close stdout and stderr though, because some systems will
- * break if you try to write to them after that, so we must
- * use dup() to replace them with something else -- webb
- * Connect stdin to /dev/null too, so ":n `cat`" doesn't hang,
- * waiting for input.
- */
- fd = open("/dev/null", O_RDWR | O_EXTRA, 0);
- fclose(stdin);
- fclose(stdout);
- fclose(stderr);
-
- /*
- * If any of these open()'s and dup()'s fail, we just continue
- * anyway. It's not fatal, and on most systems it will make
- * no difference at all. On a few it will cause the execvp()
- * to exit with a non-zero status even when the completion
- * could be done, which is nothing too serious. If the open()
- * or dup() failed we'd just do the same thing ourselves
- * anyway -- webb
- */
- if (fd >= 0) {
- ignored = dup(fd); /* To replace stdin (fd 0) */
- ignored = dup(fd); /* To replace stdout (fd 1) */
- ignored = dup(fd); /* To replace stderr (fd 2) */
-
- /* Don't need this now that we've duplicated it */
- close(fd);
- }
- } else if (opts & (kShellOptRead|kShellOptWrite)) {
-
-# ifdef HAVE_SETSID
- /* Create our own process group, so that the child and all its
- * children can be kill()ed. Don't do this when using pipes,
- * because stdin is not a tty, we would lose /dev/tty. */
- if (p_stmp) {
- (void)setsid();
-# if defined(SIGHUP)
- /* When doing "!xterm&" and 'shell' is bash: the shell
- * will exit and send SIGHUP to all processes in its
- * group, killing the just started process. Ignore SIGHUP
- * to avoid that. (suggested by Simon Schubert)
- */
- signal(SIGHUP, SIG_IGN);
-# endif
- }
-# endif
- /* Simulate to have a dumb terminal (for now) */
- os_setenv("TERM", "dumb", 1);
- sprintf((char *)envbuf, "%ld", Rows);
- os_setenv("ROWS", (char *)envbuf, 1);
- sprintf((char *)envbuf, "%ld", Rows);
- os_setenv("LINES", (char *)envbuf, 1);
- sprintf((char *)envbuf, "%ld", Columns);
- os_setenv("COLUMNS", (char *)envbuf, 1);
-
- /*
- * stderr is only redirected when using the GUI, so that a
- * program like gpg can still access the terminal to get a
- * passphrase using stderr.
- */
- {
- /* set up stdin for the child */
- close(fd_toshell[1]);
- close(0);
- ignored = dup(fd_toshell[0]);
- close(fd_toshell[0]);
-
- /* set up stdout for the child */
- close(fd_fromshell[0]);
- close(1);
- ignored = dup(fd_fromshell[1]);
- close(fd_fromshell[1]);
-
- }
- }
-
- /*
- * There is no type cast for the argv, because the type may be
- * different on different machines. This may cause a warning
- * message with strict compilers, don't worry about it.
- * Call _exit() instead of exit() to avoid closing the connection
- * to the X server (esp. with GTK, which uses atexit()).
- */
- execvp(argv[0], argv);
- _exit(EXEC_FAILED); /* exec failed, return failure code */
- } else { /* parent */
- /*
- * While child is running, ignore terminating signals.
- * Do catch CTRL-C, so that "got_int" is set.
- */
- signal_reject_deadly();
-
- /*
- * For the GUI we redirect stdin, stdout and stderr to our window.
- * This is also used to pipe stdin/stdout to/from the external
- * command.
- */
- if (opts & (kShellOptRead|kShellOptWrite)) {
-# define BUFLEN 100 /* length for buffer, pseudo tty limit is 128 */
- char_u buffer[BUFLEN + 1];
- int buffer_off = 0; /* valid bytes in buffer[] */
- char_u ta_buf[BUFLEN + 1]; /* TypeAHead */
- int ta_len = 0; /* valid bytes in ta_buf[] */
- int len;
- int p_more_save;
- int old_State;
- int toshell_fd;
- int fromshell_fd;
- garray_T ga;
- int noread_cnt;
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
- struct timeval start_tv;
-# endif
-
- {
- close(fd_toshell[0]);
- close(fd_fromshell[1]);
- toshell_fd = fd_toshell[1];
- fromshell_fd = fd_fromshell[0];
- }
-
- /*
- * Write to the child if there are typed characters.
- * Read from the child if there are characters available.
- * Repeat the reading a few times if more characters are
- * available. Need to check for typed keys now and then, but
- * not too often (delays when no chars are available).
- * This loop is quit if no characters can be read from the pty
- * (WaitForChar detected special condition), or there are no
- * characters available and the child has exited.
- * Only check if the child has exited when there is no more
- * output. The child may exit before all the output has
- * been printed.
- *
- * Currently this busy loops!
- * This can probably dead-lock when the write blocks!
- */
- p_more_save = p_more;
- p_more = FALSE;
- old_State = State;
- State = EXTERNCMD; /* don't redraw at window resize */
-
- if ((opts & kShellOptWrite) && toshell_fd >= 0) {
- /* Fork a process that will write the lines to the
- * external program. */
- if ((wpid = fork()) == -1) {
- MSG_PUTS(_("\nCannot fork\n"));
- } else if (wpid == 0) { /* child */
- linenr_T lnum = curbuf->b_op_start.lnum;
- int written = 0;
- char_u *lp = ml_get(lnum);
- size_t l;
-
- close(fromshell_fd);
- for (;; ) {
- l = STRLEN(lp + written);
- if (l == 0)
- len = 0;
- else if (lp[written] == NL)
- /* NL -> NUL translation */
- len = write(toshell_fd, "", (size_t)1);
- else {
- char_u *s = vim_strchr(lp + written, NL);
-
- len = write(toshell_fd, (char *)lp + written,
- s == NULL ? l
- : (size_t)(s - (lp + written)));
- }
- if (len == (int)l) {
- /* Finished a line, add a NL, unless this line
- * should not have one. */
- if (lnum != curbuf->b_op_end.lnum
- || !curbuf->b_p_bin
- || (lnum != curbuf->b_no_eol_lnum
- && (lnum !=
- curbuf->b_ml.ml_line_count
- || curbuf->b_p_eol)))
- ignored = write(toshell_fd, "\n",
- (size_t)1);
- ++lnum;
- if (lnum > curbuf->b_op_end.lnum) {
- /* finished all the lines, close pipe */
- close(toshell_fd);
- toshell_fd = -1;
- break;
- }
- lp = ml_get(lnum);
- written = 0;
- } else if (len > 0)
- written += len;
- }
- _exit(0);
- } else { /* parent */
- close(toshell_fd);
- toshell_fd = -1;
- }
- }
-
- if (opts & kShellOptRead)
- ga_init(&ga, 1, BUFLEN);
-
- noread_cnt = 0;
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
- gettimeofday(&start_tv, NULL);
-# endif
- for (;; ) {
- len = 0;
- if (got_int) {
- /* CTRL-C sends a signal to the child, we ignore it
- * ourselves */
-# ifdef HAVE_SETSID
- kill(-pid, SIGINT);
-# else
- kill(0, SIGINT);
-# endif
- if (wpid > 0)
- kill(wpid, SIGINT);
- got_int = FALSE;
- }
-
- /*
- * Check if the child has any characters to be printed.
- * Read them and write them to our window. Repeat this as
- * long as there is something to do, avoid the 10ms wait
- * for os_inchar(), or sending typeahead characters to
- * the external process.
- * TODO: This should handle escape sequences, compatible
- * to some terminal (vt52?).
- */
- ++noread_cnt;
- while (RealWaitForChar(fromshell_fd, 10L, NULL)) {
- len = read_eintr(fromshell_fd, buffer
- + buffer_off, (size_t)(BUFLEN - buffer_off)
- );
- if (len <= 0) /* end of file or error */
- goto finished;
-
- noread_cnt = 0;
- if (opts & kShellOptRead) {
- /* Do NUL -> NL translation, append NL separated
- * lines to the current buffer. */
- for (i = 0; i < len; ++i) {
- if (buffer[i] == NL)
- append_ga_line(&ga);
- else if (buffer[i] == NUL)
- ga_append(&ga, NL);
- else
- ga_append(&ga, buffer[i]);
- }
- }
-
- windgoto(msg_row, msg_col);
- cursor_on();
- out_flush();
- if (got_int)
- break;
-
-# if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
- {
- struct timeval now_tv;
- long msec;
-
- /* Avoid that we keep looping here without
- * checking for a CTRL-C for a long time. Don't
- * break out too often to avoid losing typeahead. */
- gettimeofday(&now_tv, NULL);
- msec = (now_tv.tv_sec - start_tv.tv_sec) * 1000L
- + (now_tv.tv_usec - start_tv.tv_usec) / 1000L;
- if (msec > 2000) {
- noread_cnt = 5;
- break;
- }
- }
-# endif
- }
-
- /* If we already detected the child has finished break the
- * loop now. */
- if (wait_pid == pid)
- break;
-
- /*
- * Check if the child still exists, before checking for
- * typed characters (otherwise we would lose typeahead).
- */
-# ifdef __NeXT__
- wait_pid = wait4(pid, &status, WNOHANG, (struct rusage *)0);
-# else
- wait_pid = waitpid(pid, &status, WNOHANG);
-# endif
- if ((wait_pid == (pid_t)-1 && errno == ECHILD)
- || (wait_pid == pid && WIFEXITED(status))) {
- /* Don't break the loop yet, try reading more
- * characters from "fromshell_fd" first. When using
- * pipes there might still be something to read and
- * then we'll break the loop at the "break" above. */
- wait_pid = pid;
- } else
- wait_pid = 0;
-
- }
-finished:
- p_more = p_more_save;
- if (opts & kShellOptRead) {
- if (ga.ga_len > 0) {
- append_ga_line(&ga);
- /* remember that the NL was missing */
- curbuf->b_no_eol_lnum = curwin->w_cursor.lnum;
- } else
- curbuf->b_no_eol_lnum = 0;
- ga_clear(&ga);
- }
-
- /*
- * Give all typeahead that wasn't used back to ui_inchar().
- */
- if (ta_len)
- ui_inchar_undo(ta_buf, ta_len);
- State = old_State;
- if (toshell_fd >= 0)
- close(toshell_fd);
- close(fromshell_fd);
- }
-
- /*
- * Wait until our child has exited.
- * Ignore wait() returning pids of other children and returning
- * because of some signal like SIGWINCH.
- * Don't wait if wait_pid was already set above, indicating the
- * child already exited.
- */
- if (wait_pid != pid)
- wait_pid = wait4pid(pid, &status);
-
-
- /* Make sure the child that writes to the external program is
- * dead. */
- if (wpid > 0) {
- kill(wpid, SIGKILL);
- wait4pid(wpid, NULL);
- }
-
- /*
- * Set to raw mode right now, otherwise a CTRL-C after
- * catch_signals() will kill Vim.
- */
- if (tmode == TMODE_RAW)
- settmode(TMODE_RAW);
- did_settmode = TRUE;
- signal_accept_deadly();
-
- if (WIFEXITED(status)) {
- /* LINTED avoid "bitwise operation on signed value" */
- retval = WEXITSTATUS(status);
- if (retval != 0 && !emsg_silent) {
- if (retval == EXEC_FAILED) {
- MSG_PUTS(_("\nCannot execute shell "));
- msg_outtrans(p_sh);
- msg_putchar('\n');
- } else if (!(opts & kShellOptSilent)) {
- MSG_PUTS(_("\nshell returned "));
- msg_outnum((long)retval);
- msg_putchar('\n');
- }
- }
- } else
- MSG_PUTS(_("\nCommand terminated\n"));
- }
- }
- shell_free_argv(argv);
-
-error:
- if (!did_settmode)
- if (tmode == TMODE_RAW)
- settmode(TMODE_RAW); /* set to raw mode */
- resettitle();
-
- return retval;
-}
-
-/*
* Wait "msec" msec until a character is available from file descriptor "fd".
* "msec" == 0 will check for characters once.
* "msec" == -1 will block until a character is available.