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 "bionic/pthread_internal.h"
40 #include "private/FdPath.h"
41 
getpt()42 int getpt() {
43   return posix_openpt(O_RDWR|O_NOCTTY);
44 }
45 
grantpt(int)46 int grantpt(int) {
47   return 0;
48 }
49 
posix_openpt(int flags)50 int posix_openpt(int flags) {
51   return open("/dev/ptmx", flags);
52 }
53 
ptsname(int fd)54 char* ptsname(int fd) {
55   bionic_tls& tls = __get_bionic_tls();
56   char* buf = tls.ptsname_buf;
57   int error = ptsname_r(fd, buf, sizeof(tls.ptsname_buf));
58   return (error == 0) ? buf : nullptr;
59 }
60 
ptsname_r(int fd,char * buf,size_t len)61 int ptsname_r(int fd, char* buf, size_t len) {
62   if (buf == nullptr) {
63     errno = EINVAL;
64     return errno;
65   }
66 
67   unsigned int pty_num;
68   if (ioctl(fd, TIOCGPTN, &pty_num) != 0) {
69     errno = ENOTTY;
70     return errno;
71   }
72 
73   if (snprintf(buf, len, "/dev/pts/%u", pty_num) >= static_cast<int>(len)) {
74     errno = ERANGE;
75     return errno;
76   }
77 
78   return 0;
79 }
80 
ttyname(int fd)81 char* ttyname(int fd) {
82   bionic_tls& tls = __get_bionic_tls();
83   char* buf = tls.ttyname_buf;
84   int error = ttyname_r(fd, buf, sizeof(tls.ttyname_buf));
85   return (error == 0) ? buf : nullptr;
86 }
87 
ttyname_r(int fd,char * buf,size_t len)88 int ttyname_r(int fd, char* buf, size_t len) {
89   if (buf == nullptr) {
90     errno = EINVAL;
91     return errno;
92   }
93 
94   if (!isatty(fd)) {
95     return errno;
96   }
97 
98   ssize_t count = readlink(FdPath(fd).c_str(), buf, len);
99   if (count == -1) {
100     return errno;
101   }
102   if (static_cast<size_t>(count) == len) {
103     errno = ERANGE;
104     return errno;
105   }
106   buf[count] = '\0';
107   return 0;
108 }
109 
unlockpt(int fd)110 int unlockpt(int fd) {
111   int unlock = 0;
112   return ioctl(fd, TIOCSPTLCK, &unlock);
113 }
114 
openpty(int * pty,int * tty,char * name,const termios * t,const winsize * ws)115 int openpty(int* pty, int* tty, char* name, const termios* t, const winsize* ws) {
116   *pty = getpt();
117   if (*pty == -1) {
118     return -1;
119   }
120 
121   if (grantpt(*pty) == -1 || unlockpt(*pty) == -1) {
122     close(*pty);
123     return -1;
124   }
125 
126   char buf[32];
127   if (name == nullptr) {
128     name = buf;
129   }
130   if (ptsname_r(*pty, name, sizeof(buf)) != 0) {
131     close(*pty);
132     return -1;
133   }
134 
135   *tty = open(name, O_RDWR | O_NOCTTY);
136   if (*tty == -1) {
137     close(*pty);
138     return -1;
139   }
140 
141   if (t != nullptr) {
142     tcsetattr(*tty, TCSAFLUSH, t);
143   }
144   if (ws != nullptr) {
145     ioctl(*tty, TIOCSWINSZ, ws);
146   }
147 
148   return 0;
149 }
150 
forkpty(int * parent_pty,char * child_tty_name,const termios * t,const winsize * ws)151 int forkpty(int* parent_pty, char* child_tty_name, const termios* t, const winsize* ws) {
152   int pty;
153   int tty;
154   if (openpty(&pty, &tty, child_tty_name, t, ws) == -1) {
155     return -1;
156   }
157 
158   pid_t pid = fork();
159   if (pid == -1) {
160     close(pty);
161     close(tty);
162     return -1;
163   }
164 
165   if (pid == 0) {
166     // Child.
167     *parent_pty = -1;
168     close(pty);
169     if (login_tty(tty) == -1) {
170       _exit(1);
171     }
172     return 0;
173   }
174 
175   // Parent.
176   *parent_pty = pty;
177   close(tty);
178   return pid;
179 }
180 
login_tty(int fd)181 int login_tty(int fd) {
182   setsid();
183 
184   if (ioctl(fd, TIOCSCTTY, nullptr) == -1) {
185     return -1;
186   }
187 
188   dup2(fd, STDIN_FILENO);
189   dup2(fd, STDOUT_FILENO);
190   dup2(fd, STDERR_FILENO);
191   if (fd > STDERR_FILENO) {
192     close(fd);
193   }
194 
195   return 0;
196 }
197