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

📄 subshell.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Figure out whether the subshell has stopped, exited or been killed */
/* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */

void sigchld_handler (int sig)
{
    int pid, status;

    pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);

    if (pid == subshell_pid) {
	/* {{{ Figure out what has happened to the subshell */

	if (WIFSTOPPED (status))
	{
	    if (WSTOPSIG (status) == SIGTSTP)
		/* The user has suspended the subshell.  Revive it */
		kill (subshell_pid, SIGCONT);
	    else
		/* The subshell has received a SIGSTOP signal */
		subshell_stopped = TRUE;
	}
	else  /* The subshell has either exited normally or been killed */
	{
	    subshell_alive = FALSE;
	    if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
		quit |= SUBSHELL_EXIT;  /* Exited normally */
	}

	/* }}} */
    }

#ifndef HAVE_X
#ifndef SCO_FLAVOR
    pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);

    if (pid == cons_saver_pid) {
	/* {{{ Someone has stopped or killed cons.saver; restart it */

	if (WIFSTOPPED (status))
	    kill (pid, SIGCONT);
	else
	{
	    handle_console (CONSOLE_DONE);
	    handle_console (CONSOLE_INIT);
	    /* Ought to do: if (in_subshell) handle_console (CONSOLE_SAVE)
	       Can't do this without adding a new variable `in_subshell';
	       it hardly seems to be worth the trouble. */
	}

	/* }}} */
    }
#endif /* ! SCO_FLAVOR */
#endif /* ! HAVE_X */
    /* If we get here, some other child exited; ignore it */
}

/* }}} */

/* {{{ feed_subshell */

/* Feed the subshell our keyboard input until it says it's finished */

static int feed_subshell (int how, int fail_on_error)
{
    /* {{{ Local variables */
    fd_set read_set;	/* For `select' */
    int bytes;		/* For the return value from `read' */
    int i;		/* Loop counter */

    struct timeval wtime; /* Maximum time we wait for the subshell */
    struct timeval *wptr;
    /* }}} */

    /* we wait up to 10 seconds if fail_on_error */
    wtime.tv_sec = 10;
    wtime.tv_usec = 0;

    for (wptr = fail_on_error ? &wtime : NULL;;)
    {
	if (!subshell_alive)
	    return FALSE;

	/* {{{ Prepare the file-descriptor set and call `select' */

	FD_ZERO (&read_set);
	FD_SET (subshell_pty, &read_set);
	FD_SET (subshell_pipe[READ], &read_set);
	if (how == VISIBLY)
	    FD_SET (STDIN_FILENO, &read_set);

	if (select (FD_SETSIZE, &read_set, NULL, NULL, wptr) == -1){

	    /* Despite using SA_RESTART, we still have to check for this */
	    if (errno == EINTR)
		continue;	/* try all over again */
	    tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
	    perror ("\n"__FILE__": select (FD_SETSIZE, &read_set...)");
	    exit (1);
	}
	/* }}} */

	/* From now on: block forever on the select call */
	wptr = NULL;

	if (FD_ISSET (subshell_pty, &read_set))
	    /* {{{ Read from the subshell, write to stdout */

	    /* This loop improves performance by reducing context switches
               by a factor of 20 or so... unfortunately, it also hangs MC
               randomly, because of an apparent Linux bug.  Investigate. */
	    /* for (i=0; i<5; ++i)  * FIXME -- experimental */
	    {
		bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
		if (bytes == -1 && errno != EIO)
		{
		    tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
		    perror ("\n"__FILE__": read (subshell_pty...)");
		    exit (1);
		}
		if (how == VISIBLY)
		    write (STDOUT_FILENO, pty_buffer, bytes);
	    }

	    /* }}} */

	else if (FD_ISSET (subshell_pipe[READ], &read_set))
	    /* {{{ Read the subshell's CWD and capture its prompt */

	    {
		bytes = read (subshell_pipe[READ], subshell_cwd, MC_MAXPATHLEN+1);
		if (bytes == -1)
		{
		    tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
		    perror ("\n"__FILE__": read (subshell_pipe[READ]...)");
		    exit (1);
		}
		if (bytes >= 1)
		    subshell_cwd[bytes-1] = 0;  /* Squash the final '\n' */

		synchronize ();

		subshell_ready = TRUE;
		if (subshell_state == RUNNING_COMMAND)
		{
		    subshell_state = INACTIVE;
		    return 1;
		}
	    }

	    /* }}} */

	else if (FD_ISSET (STDIN_FILENO, &read_set))
	    /* {{{ Read from stdin, write to the subshell */

	    {
		bytes = read (STDIN_FILENO, pty_buffer, pty_buffer_size);
		if (bytes == -1)
		{
		    tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
		    perror ("\n"__FILE__": read (STDIN_FILENO, pty_buffer...)");
		    exit (1);
		}

		for (i=0; i<bytes; ++i)
		    if (pty_buffer[i] == subshell_switch_key)
		    {
			write (subshell_pty, pty_buffer, i);
			if (subshell_ready)
			    subshell_state = INACTIVE;
			return TRUE;
		    }

		write (subshell_pty, pty_buffer, bytes);
		subshell_ready = FALSE;
	    } else {
		return FALSE;
	    }

	    /* }}} */
    }
}

/* }}} */
/* {{{ synchronize */

/* Wait until the subshell dies or stops.  If it stops, make it resume.  */
/* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */

static void synchronize (void)
{
    sigset_t sigchld_mask, old_mask;

    sigemptyset (&sigchld_mask);
    sigaddset (&sigchld_mask, SIGCHLD);
    sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);

    /* Wait until the subshell has stopped */
    while (subshell_alive && !subshell_stopped)
	sigsuspend (&old_mask);
    subshell_stopped = FALSE;
    kill (subshell_pid, SIGCONT);

    sigprocmask (SIG_SETMASK, &old_mask, NULL);
    /* We can't do any better without modifying the shell(s) */
}

/* }}} */
/* {{{ pty opening functions */

#ifdef SCO_FLAVOR

/* {{{ SCO version of pty_open_master */

static int pty_open_master (char *pty_name)
{
    int pty_master;
    int num;
    char *ptr;

    strcpy (pty_name, "/dev/ptyp");
    ptr = pty_name+9;
    for (num=0;;num++)
    {
	sprintf(ptr,"%d",num);	/* surpriiise ... SCO lacks itoa() */
	/* Try to open master */
	if ((pty_master = open (pty_name, O_RDWR)) == -1)
	    if (errno == ENOENT)  /* Different from EIO */
		return -1;	      /* Out of pty devices */
	    else
		continue;	      /* Try next pty device */
	pty_name [5] = 't';	      /* Change "pty" to "tty" */
	if (access (pty_name, 6)){
	    close (pty_master);
	    pty_name [5] = 'p';
	    continue;
	}
	return pty_master;
    }
    return -1;  /* Ran out of pty devices */
}

/* }}} */
/* {{{ SCO version of pty_open_slave */

static int pty_open_slave (const char *pty_name)
{
    int pty_slave;
    struct group *group_info = getgrnam ("terminal");

    if (group_info != NULL)
    {
	/* The following two calls will only succeed if we are root */
	/* [Commented out while permissions problem is investigated] */
	/* chown (pty_name, getuid (), group_info->gr_gid);  FIXME */
	/* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP);   FIXME */
    }
    if ((pty_slave = open (pty_name, O_RDWR)) == -1)
	perror ("open (pty_name, O_RDWR)");
    return pty_slave;
}

/* }}} */

#elif HAVE_GRANTPT

/* {{{ System V version of pty_open_master */

static int pty_open_master (char *pty_name)
{
    char *slave_name;
    int pty_master;

    strcpy (pty_name, "/dev/ptmx");
    if ((pty_master = open (pty_name, O_RDWR)) == -1
	|| grantpt (pty_master) == -1		  /* Grant access to slave */
	|| unlockpt (pty_master) == -1		  /* Clear slave's lock flag */
	|| !(slave_name = ptsname (pty_master)))  /* Get slave's name */
    {
	close (pty_master);
	return -1;
    }
    strcpy (pty_name, slave_name);
    return pty_master;
}

/* }}} */
/* {{{ System V version of pty_open_slave */

static int pty_open_slave (const char *pty_name)
{
    int pty_slave = open (pty_name, O_RDWR);

    if (pty_slave == -1)
    {
	perror ("open (pty_name, O_RDWR)");
	return -1;
    }

#if !defined(__osf__)
    if (!ioctl (pty_slave, I_FIND, "ptem"))
	if (ioctl (pty_slave, I_PUSH, "ptem") == -1)
	{
	    perror ("ioctl (pty_slave, I_PUSH, \"ptem\")");
	    close (pty_slave);
	    return -1;
	}

    if (!ioctl (pty_slave, I_FIND, "ldterm"))
        if (ioctl (pty_slave, I_PUSH, "ldterm") == -1)
	{
	    perror ("ioctl (pty_slave, I_PUSH, \"ldterm\")");
	    close (pty_slave);
	    return -1;
	}

#if !defined(sgi) && !defined(__sgi)
    if (!ioctl (pty_slave, I_FIND, "ttcompat"))
        if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
	{
	    perror ("ioctl (pty_slave, I_PUSH, \"ttcompat\")");
	    close (pty_slave);
	    return -1;
	}
#endif /* sgi || __sgi */
#endif /* __osf__ */

    return pty_slave;
}

/* }}} */

#else

/* {{{ BSD version of pty_open_master */

static int pty_open_master (char *pty_name)
{
    int pty_master;
    char *ptr1, *ptr2;

    strcpy (pty_name, "/dev/ptyXX");
    for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
    {
	pty_name [8] = *ptr1;
	for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
	{
	    pty_name [9] = *ptr2;

	    /* Try to open master */
	    if ((pty_master = open (pty_name, O_RDWR)) == -1)
		if (errno == ENOENT)  /* Different from EIO */
		    return -1;	      /* Out of pty devices */
		else
		    continue;	      /* Try next pty device */
	    pty_name [5] = 't';	      /* Change "pty" to "tty" */
	    if (access (pty_name, 6)){
		close (pty_master);
		pty_name [5] = 'p';
		continue;
	    }
	    return pty_master;
	}
    }
    return -1;  /* Ran out of pty devices */
}

/* }}} */
/* {{{ BSD version of pty_open_slave */

static int pty_open_slave (const char *pty_name)
{
    int pty_slave;
    struct group *group_info = getgrnam ("tty");

    if (group_info != NULL)
    {
	/* The following two calls will only succeed if we are root */
	/* [Commented out while permissions problem is investigated] */
	/* chown (pty_name, getuid (), group_info->gr_gid);  FIXME */
	/* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP);   FIXME */
    }
    if ((pty_slave = open (pty_name, O_RDWR)) == -1)
	perror ("open (pty_name, O_RDWR)");
    return pty_slave;
}

/* }}} */

#endif

/* }}} */

#endif /* HAVE_SUBSHELL_SUPPORT */

/* {{{ Emacs local variables */

/*
  Cause emacs to enter folding mode for this file:
  Local variables:
  end:
*/

/* }}} */

⌨️ 快捷键说明

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