123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /*
- * pty.c - pseudo-terminal handling
- */
- #define _XOPEN_SOURCE 500
- #include <features.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <termios.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <pwd.h>
- #include "pty.h"
- #include "malloc.h"
- static char ptyname[FILENAME_MAX];
- int master = -1;
- void pty_preinit(void)
- {
- /*
- * Allocate the pty.
- */
- master = open("/dev/ptmx", O_RDWR);
- if (master < 0) {
- perror("/dev/ptmx: open");
- exit(1);
- }
- if (grantpt(master) < 0) {
- perror("grantpt");
- exit(1);
- }
- if (unlockpt(master) < 0) {
- perror("unlockpt");
- exit(1);
- }
- }
- void pty_resize(int w, int h)
- {
- struct winsize sz;
- assert(master >= 0);
- sz.ws_row = h;
- sz.ws_col = w;
- sz.ws_xpixel = sz.ws_ypixel = 0;
- ioctl(master, TIOCSWINSZ, &sz);
- }
- int run_program_in_pty(const struct shell_data *shdata,
- char *directory, char **program_args)
- {
- int slave, pid;
- char *fallback_args[2];
- assert(master >= 0);
- ptyname[FILENAME_MAX-1] = '\0';
- strncpy(ptyname, ptsname(master), FILENAME_MAX-1);
- #if 0
- {
- struct winsize ws;
- struct termios ts;
- /*
- * FIXME: think up some good defaults here
- */
- if (!ioctl(0, TIOCGWINSZ, &ws))
- ioctl(master, TIOCSWINSZ, &ws);
- if (!tcgetattr(0, &ts))
- tcsetattr(master, TCSANOW, &ts);
- }
- #endif
- slave = open(ptyname, O_RDWR | O_NOCTTY);
- if (slave < 0) {
- perror("slave pty: open");
- return 1;
- }
- /*
- * Fork and execute the command.
- */
- pid = fork();
- if (pid < 0) {
- perror("fork");
- return 1;
- }
- if (pid == 0) {
- int i, fd;
- /*
- * We are the child.
- */
- close(master);
- fcntl(slave, F_SETFD, 0); /* don't close on exec */
- dup2(slave, 0);
- dup2(slave, 1);
- if (slave != 0 && slave != 1)
- close(slave);
- dup2(1, 2);
- setsid();
- setpgrp();
- i = 0;
- #ifdef TIOCNOTTY
- if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
- ioctl(fd, TIOCNOTTY, &i);
- close(fd);
- }
- #endif
- /*
- * Make the new pty our controlling terminal. On some OSes
- * this is done with TIOCSCTTY; Cygwin doesn't have that, so
- * instead it's done by simply opening the pty without
- * O_NOCTTY. This code is primarily intended for Cygwin, but
- * it's useful to have it work in other contexts for testing
- * purposes, so I leave the TIOCSCTTY here anyway.
- */
- if ((fd = open(ptyname, O_RDWR)) >= 0) {
- #ifdef TIOCSCTTY
- ioctl(fd, TIOCSCTTY, &i);
- #endif
- close(fd);
- } else {
- perror("slave pty: open");
- exit(127);
- }
- tcsetpgrp(0, getpgrp());
- for (i = 0; i < shdata->nenvvars; i++)
- putenv(shdata->envvars[i]);
- if (shdata->termtype)
- putenv(shdata->termtype);
- if (directory)
- chdir(directory);
- /*
- * Use the provided shell program name, if the user gave
- * one. Failing that, use $SHELL; failing that, look up
- * the user's default shell in the password file; failing
- * _that_, revert to the bog-standard /bin/sh.
- */
- if (!program_args) {
- char *shell;
- shell = getenv("SHELL");
- if (!shell) {
- const char *login;
- uid_t uid;
- struct passwd *pwd;
- /*
- * For maximum generality in the face of multiple
- * /etc/passwd entries with different login names and
- * shells but a shared uid, we start by using
- * getpwnam(getlogin()) if it's available - but we
- * insist that its uid must match our real one, or we
- * give up and fall back to getpwuid(getuid()).
- */
- uid = getuid();
- login = getlogin();
- if (login && (pwd = getpwnam(login)) && pwd->pw_uid == uid)
- shell = pwd->pw_shell;
- else if ((pwd = getpwuid(uid)))
- shell = pwd->pw_shell;
- }
- if (!shell)
- shell = "/bin/sh";
- fallback_args[0] = shell;
- fallback_args[1] = NULL;
- program_args = fallback_args;
- }
- execv(program_args[0], program_args);
- /*
- * If we're here, exec has gone badly foom.
- */
- perror("exec");
- exit(127);
- }
- close(slave);
- return master;
- }
|