/* vim:set sw=4 sts=4 et: */ /* for ptsname_r */ #if defined __ANDROID__ # define _GNU_SOURCE #endif #include #include #include #include #include #if defined __sun__ # include #endif #include #include #include "ptytty.h" static int ptsname_compat(int fd, char **buf) { #if defined __ANDROID__ static char b[16]; if (ptsname_r(fd, b, sizeof(b)) == -1) return -1; *buf = b; #else if ((*buf = ptsname(fd)) == NULL) return -1; #endif return 0; } static int _internal_get_pty(int *master, char **path) { if ((*master = open("/dev/ptmx", O_RDWR|O_NOCTTY)) == -1) return -1; if (grantpt(*master) != 0) return -1; if (unlockpt(*master) != 0) return -1; if (ptsname_compat(*master, path) == -1) return -1; return 0; } static int _internal_get_tty(int *slave, const char *path, struct termios *termp, struct winsize *winp, int ctty) { if (path != NULL) { if ((*slave = open(path, O_RDWR|O_NOCTTY)) == -1) return -1; } #ifdef TIOCSCTTY if (ctty && ioctl(*slave, TIOCSCTTY, NULL) == -1) return -1; #endif #ifdef I_PUSH if (ioctl(*slave, I_PUSH, "ptem") == -1) return -1; if (ioctl(*slave, I_PUSH, "ldterm") == -1) return -1; #if defined __sun__ if (ioctl(*slave, I_PUSH, "ttcompat") == -1) return -1; #endif #endif if (termp != NULL) tcsetattr(*slave, TCSAFLUSH, termp); if (winp != NULL) ioctl(*slave, TIOCSWINSZ, winp); return 0; } static int _internal_login_tty(int fd, const char *path, struct termios *termp, struct winsize *winp) { setsid(); if (_internal_get_tty(&fd, path, termp, winp, 1) != 0) return -1; dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); if (fd > 2) close(fd); return 0; } int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize *winp) { char *path = NULL; int master = -1, slave = -1; if (amaster == NULL || aslave == NULL) return -1; if (_internal_get_pty(&master, &path) != 0) goto out; if (_internal_get_tty(&slave, path, termp, winp, 0) != 0) goto out; if (name != NULL) strcpy(name, path); *amaster = master; *aslave = slave; return 0; out: if (master != -1) close(master); if (slave != -1) close(slave); return -1; } int forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp) { char *path; int master = -1; pid_t pid; if (amaster == NULL) return -1; if (_internal_get_pty(&master, &path) != 0) goto out; if (name != NULL) strcpy(name, path); if ((pid = fork()) == -1) goto out; if (pid == 0) { close(master); if (_internal_login_tty(-1, path, termp, winp) != 0) _exit(EXIT_FAILURE); return 0; } *amaster = master; return pid; out: if (master != -1) close(master); return -1; } int login_tty(int fd) { return _internal_login_tty(fd, NULL, NULL, NULL); }