⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 subshell.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 3 页
字号:
		/* Make MC's special commands not show up in bash's history */
		putenv ("HISTCONTROL=ignorespace");

		/* Allow alternative readline settings for MC */
		if (access (".mc/inputrc", R_OK) == 0)
		    putenv ("INPUTRC=.mc/inputrc");

		break;

	    case TCSH:
		init_file = ".mc/tcshrc";
		if (access (init_file, R_OK) == -1)
		    init_file += 3;
		break;

	    case ZSH:
		break;

	    default:
		fprintf (stderr, __FILE__": unimplemented subshell type %d\n",
			 subshell_type);
		_exit (FORK_FAILURE);
	}

	/* }}} */
	/* {{{ Attach all our standard file descriptors to the pty */

	/* This is done just before the fork, because stderr must still	 */
	/* be connected to the real tty during the above error messages; */
	/* otherwise the user will never see them.			 */

	dup2 (pty_slave, STDIN_FILENO);
	dup2 (pty_slave, STDOUT_FILENO);
	dup2 (pty_slave, STDERR_FILENO);

	/* }}} */
	/* {{{ Execute the subshell at last */

	close (subshell_pipe[READ]);
	close (pty_slave);  /* These may be FD_CLOEXEC, but just in case... */

	switch (subshell_type)
	{
	    case BASH:
	    execl (shell, "bash", "-rcfile", init_file, NULL);
	    break;

	    case TCSH:
	    execl (shell, "tcsh", NULL);  /* What's the -rcfile equivalent? */
	    break;

	    case ZSH:
	    execl (shell, "zsh", "+Z", NULL);
	    break;
	}

	/* If we get this far, everything failed miserably */
	_exit (FORK_FAILURE);

	/* }}} */
    }

    close(pty_slave);

#ifdef SYNC_PTY_SIDES
	sigsuspend (&old_mask);
	signal (SIGUSR1, SIG_DFL);
	sigprocmask (SIG_SETMASK, &old_mask, NULL);
	/* ...before installing our handler for SIGCHLD. */
#endif

#if 0
    /* {{{ Install our handler for SIGCHLD */

    init_sigchld ();

    /* We could have received the SIGCHLD signal for the subshell
     * before installing the init_sigchld */
    pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
    if (pid == subshell_pid){
	use_subshell = FALSE;
	return;
    }

    /* }}} */
#endif

    /* {{{ Set up `precmd' or equivalent for reading the subshell's CWD */

    switch (subshell_type)
    {
	char precmd[80];

	case BASH:
	sprintf (precmd, " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
		 subshell_pipe[WRITE]);
	goto write_it;

	case ZSH:
	sprintf (precmd, "precmd(){ pwd>&%d;kill -STOP $$ }\n",
		 subshell_pipe[WRITE]);
	goto write_it;

	case TCSH:
	sprintf (precmd, "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n", tcsh_fifo);

	write_it:
	write (subshell_pty, precmd, strlen (precmd));
    }

    /* }}} */
    /* {{{ Wait until the subshell has started up and processed the command */

    subshell_state = RUNNING_COMMAND;
    enable_interrupt_key ();
    if (!feed_subshell (QUIETLY, TRUE)){
	use_subshell = FALSE;
    }
    disable_interrupt_key ();
    if (!subshell_alive)
	use_subshell = FALSE;  /* Subshell died instantly, so don't use it */

    /* }}} */
}

/* }}} */
/* {{{ invoke_subshell */

int invoke_subshell (const char *command, int how, char **new_dir)
{
    /* {{{ Fiddle with terminal modes */

    static struct termios raw_mode = {0};

    /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
    /* original settings.  However, here we need to make this tty very raw, */
    /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
    /* pty.  So, instead of changing the code for execute(), pre_exec(),    */
    /* etc, we just set up the modes we need here, before each command.     */

    if (raw_mode.c_iflag == 0)  /* First time: initialise `raw_mode' */
    {
	tcgetattr (STDOUT_FILENO, &raw_mode);
	raw_mode.c_lflag &= ~ICANON;  /* Disable line-editing chars, etc.   */
	raw_mode.c_lflag &= ~ISIG;    /* Disable intr, quit & suspend chars */
	raw_mode.c_lflag &= ~ECHO;    /* Disable input echoing		    */
	raw_mode.c_iflag &= ~IXON;    /* Pass ^S/^Q to subshell undisturbed */
	raw_mode.c_iflag &= ~ICRNL;   /* Don't translate CRs into LFs	    */
	raw_mode.c_oflag &= ~OPOST;   /* Don't postprocess output	    */
	raw_mode.c_cc[VTIME] = 0;     /* IE: wait forever, and return as    */
	raw_mode.c_cc[VMIN] = 1;      /* soon as a character is available   */
    }

    tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);

    /* }}} */

    /* Make the subshell change to MC's working directory */
    if (new_dir)
	do_subshell_chdir (cpanel->cwd, TRUE, 1);

    if (command == NULL)  /* The user has done "C-o" from MC */
    {
	if (subshell_state == INACTIVE)
	{
	    subshell_state = ACTIVE;
	    /* FIXME: possibly take out this hack; the user can
	       re-play it by hitting C-hyphen a few times! */
	    write (subshell_pty, " \b", 2);  /* Hack to make prompt reappear */
	}
    }
    else  /* MC has passed us a user command */
    {
	if (how == QUIETLY)
	    write (subshell_pty, " ", 1);
	write (subshell_pty, command, strlen (command));
	write (subshell_pty, "\n", 1);
	subshell_state = RUNNING_COMMAND;
	subshell_ready = FALSE;
    }

    feed_subshell (how, FALSE);

    if (new_dir && subshell_alive && strcmp (subshell_cwd, cpanel->cwd))
	*new_dir = subshell_cwd;  /* Make MC change to the subshell's CWD */

    /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
    while (!subshell_alive && !quit && use_subshell)
	init_subshell ();

    prompt_pos = 0;

    return quit;
}

/* }}} */
/* {{{ read_subshell_prompt */

int read_subshell_prompt (int how)
{
    /* {{{ Local variables */

    int clear_now = FALSE;
    static int prompt_size = INITIAL_PROMPT_SIZE;
    int bytes = 0, i, rc = 0;
    struct timeval timeleft = {0, 0};

    fd_set tmp;
    FD_ZERO (&tmp);
    FD_SET (subshell_pty, &tmp);

    /* }}} */

    if (subshell_prompt == NULL)  /* First time through */
    {
	subshell_prompt = (char *) malloc (prompt_size);
	*subshell_prompt = '\0';
	prompt_pos = 0;
    }

    while (subshell_alive &&
	   (rc = select (FD_SETSIZE, &tmp, NULL, NULL, &timeleft)))
    {
	/* {{{ Check for `select' errors */

	if (rc == -1)
	    if (errno == EINTR)
		continue;
	    else
	    {
		tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
		perror ("\n"__FILE__": select (FD_SETSIZE, &tmp...)");
		exit (1);
	    }

	/* }}} */

	bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
	if (how == VISIBLY)
	    write (STDOUT_FILENO, pty_buffer, bytes);

	/* {{{ Extract the prompt from the shell output */

	for (i=0; i<bytes; ++i)
	    if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r'){
		prompt_pos = 0;
		clear_now = FALSE;
	    } else {
		clear_now = TRUE;
		if (!pty_buffer [i])
		    continue;

		subshell_prompt[prompt_pos++] = pty_buffer[i];
		if (prompt_pos == prompt_size)
		    subshell_prompt = (char *) realloc (subshell_prompt,
							prompt_size *= 2);
	    }

	/* Sometimes we get an empty new line and then nothing,
	 * we better just keep the old prompt instead. */
	if (clear_now)
	    subshell_prompt[prompt_pos] = '\0';

	/* }}} */
    }
    if (rc == 0 && bytes == 0)
	return FALSE;
    return TRUE;
}

/* }}} */
/* {{{ resize_subshell */

void resize_subshell (void)
{
#if defined TIOCSWINSZ && !defined SCO_FLAVOR
    struct winsize tty_size;

    tty_size.ws_row = LINES;
    tty_size.ws_col = COLS;
    tty_size.ws_xpixel = tty_size.ws_ypixel = 0;

    if (ioctl (subshell_pty, TIOCSWINSZ, &tty_size))
	perror (__FILE__": couldn't set pty size");
#endif
}

/* }}} */
/* {{{ exit_subshell */

int exit_subshell (void)
{
    int quit = TRUE;

    if (subshell_state != INACTIVE && subshell_alive)
	quit = !query_dialog (_(" Warning "), _(" The shell is still active. Quit anyway? "),
			      0, 2, _("&Yes"), _("&No"));

#if AIX_TCSH_CODE_BELOW_IS_IT_FIXED
    /* New Test code */
    else
    {
	if (subshell_type == TCSH)
	    sprintf (pty_buffer, " echo -n Jobs:>/tmp/mc.pipe.%d;jobs>/tmp/"
		     "mc.pipe.%d;kill -STOP $$\n", getpid (), getpid ());
	else
	    sprintf (pty_buffer, " echo -n Jobs:>&%d;jobs>&%d;kill -STOP $$\n",
		     subshell_pipe[WRITE], subshell_pipe[WRITE]);
	write (subshell_pty, pty_buffer, strlen (pty_buffer));

#ifndef HAVE_GRANTPT  /* FIXME */
	if (subshell_type == ZSH)
	    /* Here we have to drain the shell output, because zsh does a  */
	    /* tcsetattr(SHTTY, TCSADRAIN...) which will block if we don't */
	    read (subshell_pty, pty_buffer, pty_buffer_size);
#endif

	/* TCSH + AIX hang here, fix this before removing the ifdef above */
	if (read (subshell_pipe[READ], pty_buffer, pty_buffer_size) == 5)
	    quit = TRUE;
	else
	    quit = !query_dialog (_(" Warning "), _(" There are stopped jobs.")
				  _(" Quit anyway? "), 0, 2, _("&Yes"), _("&No"));

	synchronize ();
	subshell_state = RUNNING_COMMAND;
	feed_subshell (QUIETLY, FALSE);  /* Drain the shell output (again) */
    }
#endif

    if (quit && subshell_type == TCSH)
    {
	/* We abuse of pty_buffer here, but it doesn't matter at this stage */
	sprintf (pty_buffer, "/tmp/mc.pipe.%d", getpid ());
	if (unlink (pty_buffer) == -1)
	    perror (__FILE__": couldn't remove named pipe /tmp/mc.pipe.NNN");
    }

    return quit;
}

/* }}} */

/* {{{ do_subshell_chdir */
/* If it actually changed the directory it returns true */
void do_subshell_chdir (char *directory, int do_update, int reset_prompt)
{
    char *temp;

    if (!(subshell_state == INACTIVE && strcmp (subshell_cwd, cpanel->cwd))){
	/* We have to repaint the subshell prompt if we read it from
	 * the main program.  Please note that in the code after this
	 * if, the cd command that is sent will make the subshell
	 * repaint the prompt, so we don't have to paint it. */
	if (do_update)
	    do_update_prompt ();
	return;
    }

    /* The initial space keeps this out of the command history (in bash
       because we set "HISTCONTROL=ignorespace") */
    write (subshell_pty, " cd ", 4);
    if (*directory) {
	temp = name_quote (directory, 0);
	write (subshell_pty, temp, strlen (temp));
        free (temp);
    } else {
	write (subshell_pty, "/", 1);
    }
    write (subshell_pty, "\n", 1);

    subshell_state = RUNNING_COMMAND;
    feed_subshell (QUIETLY, FALSE);

    if (subshell_alive && strcmp (subshell_cwd, cpanel->cwd) && strcmp (cpanel->cwd, "."))
	fprintf (stderr, _("Warning: Couldn't change to %s.\n"), cpanel->cwd);

    if (reset_prompt)
	prompt_pos = 0;
    update_prompt = FALSE;
    /* Make sure that MC never stores the CWD in a silly format */
    /* like /usr////lib/../bin, or the strcmp() above will fail */
}

/* }}} */
/* {{{ subshell_get_console_attributes */

void subshell_get_console_attributes (void)
{
    /* {{{ Get our current terminal modes */

    if (tcgetattr (STDOUT_FILENO, &shell_mode))
    {
	perror (__FILE__": couldn't get terminal settings");
	use_subshell = FALSE;
	return;
    }

    /* }}} */
}

/* }}} */
/* {{{ sigchld_handler */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -