blob: 2c8618047408b3e157831ba977e7b30151cfe591 [file] [log] [blame]
Elliott Hughes49167062014-07-25 17:24:00 -07001/*
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>
Elliott Hughes65f0df72014-12-03 14:39:20 -080031#include <pty.h>
Elliott Hughes49167062014-07-25 17:24:00 -070032#include <stdio.h>
33#include <stdlib.h>
34#include <sys/ioctl.h>
35#include <termios.h>
36#include <unistd.h>
Elliott Hughes65f0df72014-12-03 14:39:20 -080037#include <utmp.h>
Elliott Hughes49167062014-07-25 17:24:00 -070038
Elliott Hughes65f0df72014-12-03 14:39:20 -080039int getpt() {
Elliott Hughes49167062014-07-25 17:24:00 -070040 return posix_openpt(O_RDWR|O_NOCTTY);
41}
42
43int grantpt(int) {
44 return 0;
45}
46
47int posix_openpt(int flags) {
48 return open("/dev/ptmx", flags);
49}
50
51char* ptsname(int fd) {
Elliott Hughes65f0df72014-12-03 14:39:20 -080052 static char buf[32];
Elliott Hughes49167062014-07-25 17:24:00 -070053 return ptsname_r(fd, buf, sizeof(buf)) == 0 ? buf : NULL;
54}
55
56int ptsname_r(int fd, char* buf, size_t len) {
57 if (buf == NULL) {
58 errno = EINVAL;
59 return errno;
60 }
61
62 unsigned int pty_num;
63 if (ioctl(fd, TIOCGPTN, &pty_num) != 0) {
64 errno = ENOTTY;
65 return errno;
66 }
67
68 if (snprintf(buf, len, "/dev/pts/%u", pty_num) >= static_cast<int>(len)) {
69 errno = ERANGE;
70 return errno;
71 }
72
73 return 0;
74}
75
76char* ttyname(int fd) {
77 static char buf[64];
78 return ttyname_r(fd, buf, sizeof(buf)) == 0 ? buf : NULL;
79}
80
81int ttyname_r(int fd, char* buf, size_t len) {
82 if (buf == NULL) {
83 errno = EINVAL;
84 return errno;
85 }
86
87 if (!isatty(fd)) {
88 return errno;
89 }
90
91 char path[64];
92 snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
93
94 ssize_t count = readlink(path, buf, len);
95 if (count == -1) {
96 return errno;
97 }
98 if (static_cast<size_t>(count) == len) {
99 errno = ERANGE;
100 return errno;
101 }
102 buf[count] = '\0';
103 return 0;
104}
105
106int unlockpt(int fd) {
107 int unlock = 0;
108 return ioctl(fd, TIOCSPTLCK, &unlock);
109}
Elliott Hughes65f0df72014-12-03 14:39:20 -0800110
111int openpty(int* master, int* slave, char* name, const termios* t, const winsize* ws) {
112 *master = getpt();
113 if (*master == -1) {
114 return -1;
115 }
116
117 if (grantpt(*master) == -1 || unlockpt(*master) == -1) {
118 close(*master);
119 return -1;
120 }
121
122 char buf[32];
123 if (name == NULL) {
124 name = buf;
125 }
126 if (ptsname_r(*master, name, sizeof(buf)) != 0) {
127 close(*master);
128 return -1;
129 }
130
131 *slave = open(name, O_RDWR|O_NOCTTY);
132 if (*slave == -1) {
133 close(*master);
134 return -1;
135 }
136
137 if (t != NULL) {
138 tcsetattr(*slave, TCSAFLUSH, t);
139 }
140 if (ws != NULL) {
141 ioctl(*slave, TIOCSWINSZ, ws);
142 }
143
144 return 0;
145}
146
147int forkpty(int* master, char* name, const termios* t, const winsize* ws) {
148 int slave;
149 if (openpty(master, &slave, name, t, ws) == -1) {
150 return -1;
151 }
152
153 pid_t pid = fork();
154 if (pid == -1) {
155 close(*master);
156 close(slave);
157 return -1;
158 }
159
160 if (pid == 0) {
161 // Child.
162 close(*master);
163 if (login_tty(slave) == -1) {
164 _exit(1);
165 }
166 return 0;
167 }
168
169 // Parent.
170 close(slave);
171 return pid;
172}
173
174int login_tty(int fd) {
175 setsid();
176
177 if (ioctl(fd, TIOCSCTTY, NULL) == -1) {
178 return -1;
179 }
180
181 dup2(fd, STDIN_FILENO);
182 dup2(fd, STDOUT_FILENO);
183 dup2(fd, STDERR_FILENO);
184 if (fd > STDERR_FILENO) {
185 close(fd);
186 }
187
188 return 0;
189}