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