X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/0a080c1e34183e089a14114cd782e8ba9045bf0b..5e4a475d63333a4d61cbce0b0a21bf01cf945f74:/contrib/cygtermd/pty.c diff --git a/contrib/cygtermd/pty.c b/contrib/cygtermd/pty.c new file mode 100644 index 00000000..e30f9e0e --- /dev/null +++ b/contrib/cygtermd/pty.c @@ -0,0 +1,188 @@ +/* + * pty.c - pseudo-terminal handling + */ + +#define _XOPEN_SOURCE +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 +#ifdef TIOCSCTTY + ioctl(0, TIOCSCTTY, &i); +#endif + 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; +}