Home | History | Annotate | Download | only in bionic
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <errno.h>
     30 #include <fcntl.h>
     31 #include <pty.h>
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <sys/ioctl.h>
     35 #include <termios.h>
     36 #include <unistd.h>
     37 #include <utmp.h>
     38 
     39 #include "private/ThreadLocalBuffer.h"
     40 
     41 static ThreadLocalBuffer<char, 32> g_ptsname_tls_buffer;
     42 static ThreadLocalBuffer<char, 64> g_ttyname_tls_buffer;
     43 
     44 int getpt() {
     45   return posix_openpt(O_RDWR|O_NOCTTY);
     46 }
     47 
     48 int grantpt(int) {
     49   return 0;
     50 }
     51 
     52 int posix_openpt(int flags) {
     53   return open("/dev/ptmx", flags);
     54 }
     55 
     56 char* ptsname(int fd) {
     57   char* buf = g_ptsname_tls_buffer.get();
     58   int error = ptsname_r(fd, buf, g_ptsname_tls_buffer.size());
     59   return (error == 0) ? buf : NULL;
     60 }
     61 
     62 int ptsname_r(int fd, char* buf, size_t len) {
     63   if (buf == NULL) {
     64     errno = EINVAL;
     65     return errno;
     66   }
     67 
     68   unsigned int pty_num;
     69   if (ioctl(fd, TIOCGPTN, &pty_num) != 0) {
     70     errno = ENOTTY;
     71     return errno;
     72   }
     73 
     74   if (snprintf(buf, len, "/dev/pts/%u", pty_num) >= static_cast<int>(len)) {
     75     errno = ERANGE;
     76     return errno;
     77   }
     78 
     79   return 0;
     80 }
     81 
     82 char* ttyname(int fd) {
     83   char* buf = g_ttyname_tls_buffer.get();
     84   int error = ttyname_r(fd, buf, g_ttyname_tls_buffer.size());
     85   return (error == 0) ? buf : NULL;
     86 }
     87 
     88 int ttyname_r(int fd, char* buf, size_t len) {
     89   if (buf == NULL) {
     90     errno = EINVAL;
     91     return errno;
     92   }
     93 
     94   if (!isatty(fd)) {
     95     return errno;
     96   }
     97 
     98   char path[64];
     99   snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
    100 
    101   ssize_t count = readlink(path, buf, len);
    102   if (count == -1) {
    103     return errno;
    104   }
    105   if (static_cast<size_t>(count) == len) {
    106     errno = ERANGE;
    107     return errno;
    108   }
    109   buf[count] = '\0';
    110   return 0;
    111 }
    112 
    113 int unlockpt(int fd) {
    114   int unlock = 0;
    115   return ioctl(fd, TIOCSPTLCK, &unlock);
    116 }
    117 
    118 int openpty(int* master, int* slave, char* name, const termios* t, const winsize* ws) {
    119   *master = getpt();
    120   if (*master == -1) {
    121     return -1;
    122   }
    123 
    124   if (grantpt(*master) == -1 || unlockpt(*master) == -1) {
    125     close(*master);
    126     return -1;
    127   }
    128 
    129   char buf[32];
    130   if (name == NULL) {
    131     name = buf;
    132   }
    133   if (ptsname_r(*master, name, sizeof(buf)) != 0) {
    134     close(*master);
    135     return -1;
    136   }
    137 
    138   *slave = open(name, O_RDWR|O_NOCTTY);
    139   if (*slave == -1) {
    140     close(*master);
    141     return -1;
    142   }
    143 
    144   if (t != NULL) {
    145     tcsetattr(*slave, TCSAFLUSH, t);
    146   }
    147   if (ws != NULL) {
    148     ioctl(*slave, TIOCSWINSZ, ws);
    149   }
    150 
    151   return 0;
    152 }
    153 
    154 int forkpty(int* amaster, char* name, const termios* t, const winsize* ws) {
    155   int master;
    156   int slave;
    157   if (openpty(&master, &slave, name, t, ws) == -1) {
    158     return -1;
    159   }
    160 
    161   pid_t pid = fork();
    162   if (pid == -1) {
    163     close(master);
    164     close(slave);
    165     return -1;
    166   }
    167 
    168   if (pid == 0) {
    169     // Child.
    170     *amaster = -1;
    171     close(master);
    172     if (login_tty(slave) == -1) {
    173       _exit(1);
    174     }
    175     return 0;
    176   }
    177 
    178   // Parent.
    179   *amaster = master;
    180   close(slave);
    181   return pid;
    182 }
    183 
    184 int login_tty(int fd) {
    185   setsid();
    186 
    187   if (ioctl(fd, TIOCSCTTY, NULL) == -1) {
    188     return -1;
    189   }
    190 
    191   dup2(fd, STDIN_FILENO);
    192   dup2(fd, STDOUT_FILENO);
    193   dup2(fd, STDERR_FILENO);
    194   if (fd > STDERR_FILENO) {
    195     close(fd);
    196   }
    197 
    198   return 0;
    199 }
    200