X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/4a693cfc5c3ee0e639bbee0215345e921715ab04..32f8db2c94c447f20eaa7cc056e2109d5c25ef68:/unix/uxpty.c diff --git a/unix/uxpty.c b/unix/uxpty.c index a9c0676c..186ff5a9 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -167,8 +167,8 @@ static tree234 *ptys_by_pid = NULL; static Pty single_pty = NULL; #ifndef OMIT_UTMP -static pid_t pty_utmp_helper_pid; -static int pty_utmp_helper_pipe; +static pid_t pty_utmp_helper_pid = -1; +static int pty_utmp_helper_pipe = -1; static int pty_stamped_utmp; static struct utmpx utmp_entry; #endif @@ -335,12 +335,28 @@ static void pty_open_master(Pty pty) chown(pty->name, getuid(), gp ? gp->gr_gid : -1); chmod(pty->name, 0600); #else - pty->master_fd = open("/dev/ptmx", O_RDWR); + + const int flags = O_RDWR +#ifdef O_NOCTTY + | O_NOCTTY +#endif + ; + +#ifdef HAVE_POSIX_OPENPT + pty->master_fd = posix_openpt(flags); + + if (pty->master_fd < 0) { + perror("posix_openpt"); + exit(1); + } +#else + pty->master_fd = open("/dev/ptmx", flags); if (pty->master_fd < 0) { perror("/dev/ptmx: open"); exit(1); } +#endif if (grantpt(pty->master_fd) < 0) { perror("grantpt"); @@ -408,106 +424,106 @@ void pty_pre_init(void) if (geteuid() != getuid() || getegid() != getgid()) { pty_open_master(pty); - } #ifndef OMIT_UTMP - /* - * Fork off the utmp helper. - */ - if (pipe(pipefd) < 0) { - perror("pterm: pipe"); - exit(1); - } - cloexec(pipefd[0]); - cloexec(pipefd[1]); - pid = fork(); - if (pid < 0) { - perror("pterm: fork"); - exit(1); - } else if (pid == 0) { - char display[128], buffer[128]; - int dlen, ret; - - close(pipefd[1]); - /* - * Now sit here until we receive a display name from the - * other end of the pipe, and then stamp utmp. Unstamp utmp - * again, and exit, when the pipe closes. - */ + /* + * Fork off the utmp helper. + */ + if (pipe(pipefd) < 0) { + perror("pterm: pipe"); + exit(1); + } + cloexec(pipefd[0]); + cloexec(pipefd[1]); + pid = fork(); + if (pid < 0) { + perror("pterm: fork"); + exit(1); + } else if (pid == 0) { + char display[128], buffer[128]; + int dlen, ret; + + close(pipefd[1]); + /* + * Now sit here until we receive a display name from the + * other end of the pipe, and then stamp utmp. Unstamp utmp + * again, and exit, when the pipe closes. + */ - dlen = 0; - while (1) { + dlen = 0; + while (1) { - ret = read(pipefd[0], buffer, lenof(buffer)); - if (ret <= 0) { - cleanup_utmp(); - _exit(0); - } else if (!pty_stamped_utmp) { - if (dlen < lenof(display)) - memcpy(display+dlen, buffer, - min(ret, lenof(display)-dlen)); - if (buffer[ret-1] == '\0') { - /* - * Now we have a display name. NUL-terminate - * it, and stamp utmp. - */ - display[lenof(display)-1] = '\0'; - /* - * Trap as many fatal signals as we can in the - * hope of having the best possible chance to - * clean up utmp before termination. We are - * unfortunately unprotected against SIGKILL, - * but that's life. - */ - putty_signal(SIGHUP, fatal_sig_handler); - putty_signal(SIGINT, fatal_sig_handler); - putty_signal(SIGQUIT, fatal_sig_handler); - putty_signal(SIGILL, fatal_sig_handler); - putty_signal(SIGABRT, fatal_sig_handler); - putty_signal(SIGFPE, fatal_sig_handler); - putty_signal(SIGPIPE, fatal_sig_handler); - putty_signal(SIGALRM, fatal_sig_handler); - putty_signal(SIGTERM, fatal_sig_handler); - putty_signal(SIGSEGV, fatal_sig_handler); - putty_signal(SIGUSR1, fatal_sig_handler); - putty_signal(SIGUSR2, fatal_sig_handler); + ret = read(pipefd[0], buffer, lenof(buffer)); + if (ret <= 0) { + cleanup_utmp(); + _exit(0); + } else if (!pty_stamped_utmp) { + if (dlen < lenof(display)) + memcpy(display+dlen, buffer, + min(ret, lenof(display)-dlen)); + if (buffer[ret-1] == '\0') { + /* + * Now we have a display name. NUL-terminate + * it, and stamp utmp. + */ + display[lenof(display)-1] = '\0'; + /* + * Trap as many fatal signals as we can in the + * hope of having the best possible chance to + * clean up utmp before termination. We are + * unfortunately unprotected against SIGKILL, + * but that's life. + */ + putty_signal(SIGHUP, fatal_sig_handler); + putty_signal(SIGINT, fatal_sig_handler); + putty_signal(SIGQUIT, fatal_sig_handler); + putty_signal(SIGILL, fatal_sig_handler); + putty_signal(SIGABRT, fatal_sig_handler); + putty_signal(SIGFPE, fatal_sig_handler); + putty_signal(SIGPIPE, fatal_sig_handler); + putty_signal(SIGALRM, fatal_sig_handler); + putty_signal(SIGTERM, fatal_sig_handler); + putty_signal(SIGSEGV, fatal_sig_handler); + putty_signal(SIGUSR1, fatal_sig_handler); + putty_signal(SIGUSR2, fatal_sig_handler); #ifdef SIGBUS - putty_signal(SIGBUS, fatal_sig_handler); + putty_signal(SIGBUS, fatal_sig_handler); #endif #ifdef SIGPOLL - putty_signal(SIGPOLL, fatal_sig_handler); + putty_signal(SIGPOLL, fatal_sig_handler); #endif #ifdef SIGPROF - putty_signal(SIGPROF, fatal_sig_handler); + putty_signal(SIGPROF, fatal_sig_handler); #endif #ifdef SIGSYS - putty_signal(SIGSYS, fatal_sig_handler); + putty_signal(SIGSYS, fatal_sig_handler); #endif #ifdef SIGTRAP - putty_signal(SIGTRAP, fatal_sig_handler); + putty_signal(SIGTRAP, fatal_sig_handler); #endif #ifdef SIGVTALRM - putty_signal(SIGVTALRM, fatal_sig_handler); + putty_signal(SIGVTALRM, fatal_sig_handler); #endif #ifdef SIGXCPU - putty_signal(SIGXCPU, fatal_sig_handler); + putty_signal(SIGXCPU, fatal_sig_handler); #endif #ifdef SIGXFSZ - putty_signal(SIGXFSZ, fatal_sig_handler); + putty_signal(SIGXFSZ, fatal_sig_handler); #endif #ifdef SIGIO - putty_signal(SIGIO, fatal_sig_handler); + putty_signal(SIGIO, fatal_sig_handler); #endif - setup_utmp(pty->name, display); - } - } - } - } else { - close(pipefd[0]); - pty_utmp_helper_pid = pid; - pty_utmp_helper_pipe = pipefd[1]; - } + setup_utmp(pty->name, display); + } + } + } + } else { + close(pipefd[0]); + pty_utmp_helper_pid = pid; + pty_utmp_helper_pipe = pipefd[1]; + } #endif + } /* Drop privs. */ { @@ -735,7 +751,7 @@ static const char *pty_init(void *frontend, void **backend_handle, Conf *conf, if (!conf_get_int(conf, CONF_stamp_utmp)) { close(pty_utmp_helper_pipe); /* just let the child process die */ pty_utmp_helper_pipe = -1; - } else { + } else if (pty_utmp_helper_pipe >= 0) { char *location = get_x_display(pty->frontend); int len = strlen(location)+1, pos = 0; /* +1 to include NUL */ while (pos < len) { @@ -835,9 +851,41 @@ static const char *pty_init(void *frontend, void **backend_handle, Conf *conf, putty_signal(SIGQUIT, SIG_DFL); putty_signal(SIGPIPE, SIG_DFL); block_signal(SIGCHLD, 0); - if (pty_argv) + if (pty_argv) { + /* + * Exec the exact argument list we were given. + */ execvp(pty_argv[0], pty_argv); - else { + /* + * If that fails, and if we had exactly one argument, pass + * that argument to $SHELL -c. + * + * This arranges that we can _either_ follow 'pterm -e' + * with a list of argv elements to be fed directly to + * exec, _or_ with a single argument containing a command + * to be parsed by a shell (but, in cases of doubt, the + * former is more reliable). + * + * A quick survey of other terminal emulators' -e options + * (as of Debian squeeze) suggests that: + * + * - xterm supports both modes, more or less like this + * - gnome-terminal will only accept a one-string shell command + * - Eterm, kterm and rxvt will only accept a list of + * argv elements (as did older versions of pterm). + * + * It therefore seems important to support both usage + * modes in order to be a drop-in replacement for either + * xterm or gnome-terminal, and hence for anyone's + * plausible uses of the Debian-style alias + * 'x-terminal-emulator'... + */ + if (pty_argv[1] == NULL) { + char *shell = getenv("SHELL"); + if (shell) + execl(shell, shell, "-c", pty_argv[0], (void *)NULL); + } + } else { char *shell = getenv("SHELL"); char *shellname; if (conf_get_int(conf, CONF_login_shell)) {