Skip to content
Newer
Older
100644 254 lines (226 sloc) 6.67 KB
20b3b40 @nelhage Add the license to all of the source files.
authored
1 /*
2 * Copyright (C) 2011 by Nelson Elhage
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/select.h>
26 #include <sys/ioctl.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <termios.h>
33 #include <signal.h>
34
18ebcd0 @nelhage Break out prototypes into a header file.
authored
35 #include "reptyr.h"
36
eeb8c68 @nelhage Check for Linux in an #ifdef for clarity.
authored
37 #ifndef __linux__
38 #error reptyr is currently Linux-only.
39 #endif
40
d5f8060 @rwmacleod Add a [-V]erbose flag; default is off.
rwmacleod authored
41 static int verbose = 0;
42
18ebcd0 @nelhage Break out prototypes into a header file.
authored
43 void _debug(const char *pfx, const char *msg, va_list ap) {
44
45 if (pfx)
46 fprintf(stderr, "%s", pfx);
47 vfprintf(stderr, msg, ap);
48 fprintf(stderr, "\n");
49 }
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
50
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
51 void die(const char *msg, ...) {
52 va_list ap;
53 va_start(ap, msg);
18ebcd0 @nelhage Break out prototypes into a header file.
authored
54 _debug("[!] ", msg, ap);
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
55 va_end(ap);
56
57 exit(1);
58 }
59
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
60 void debug(const char *msg, ...) {
d5f8060 @rwmacleod Add a [-V]erbose flag; default is off.
rwmacleod authored
61
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
62 va_list ap;
d5f8060 @rwmacleod Add a [-V]erbose flag; default is off.
rwmacleod authored
63
64 if (!verbose)
65 return;
66
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
67 va_start(ap, msg);
18ebcd0 @nelhage Break out prototypes into a header file.
authored
68 _debug("[+] ", msg, ap);
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
69 va_end(ap);
18ebcd0 @nelhage Break out prototypes into a header file.
authored
70 }
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
71
18ebcd0 @nelhage Break out prototypes into a header file.
authored
72 void error(const char *msg, ...) {
73 va_list ap;
74 va_start(ap, msg);
75 _debug("[-] ", msg, ap);
76 va_end(ap);
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
77 }
78
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
79 void setup_raw(struct termios *save) {
80 struct termios set;
81 if (tcgetattr(0, save) < 0)
82 die("Unable to read terminal attributes: %m");
83 set = *save;
692b079 @nelhage Use cfmakeraw instead of messing with termios flags ourselves.
authored
84 cfmakeraw(&set);
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
85 if (tcsetattr(0, TCSANOW, &set) < 0)
86 die("Unable to set terminal attributes: %m");
87 }
88
89 void resize_pty(int pty) {
90 struct winsize sz;
91 if (ioctl(0, TIOCGWINSZ, &sz) < 0)
92 return;
93 ioctl(pty, TIOCSWINSZ, &sz);
94 }
95
96 int writeall(int fd, const void *buf, ssize_t count) {
97 ssize_t rv;
98 while (count > 0) {
99 rv = write(fd, buf, count);
100 if (rv < 0)
101 return rv;
102 count -= rv;
103 buf += rv;
104 }
105 return 0;
106 }
107
108 int winch_happened = 0;
109
110 void do_winch(int signal) {
111 winch_happened = 1;
112 }
113
114 void do_proxy(int pty) {
115 char buf[4096];
116 ssize_t count;
117 fd_set set;
118 while (1) {
119 if (winch_happened) {
120 resize_pty(pty);
121 /* FIXME: racy against a second resize */
122 winch_happened = 0;
123 }
124 FD_ZERO(&set);
125 FD_SET(0, &set);
126 FD_SET(pty, &set);
127 if (select(pty+1, &set, NULL, NULL, NULL) < 0) {
128 if (errno == EINTR)
129 continue;
130 fprintf(stderr, "select: %m");
131 return;
132 }
133 if (FD_ISSET(0, &set)) {
134 count = read(0, buf, sizeof buf);
135 if (count < 0)
136 return;
137 writeall(pty, buf, count);
138 }
139 if (FD_ISSET(pty, &set)) {
140 count = read(pty, buf, sizeof buf);
141 if (count < 0)
142 return;
143 writeall(1, buf, count);
144 }
145 }
146 }
147
e2d8d67 @nelhage Add a minimal usage message.
authored
148 void usage(char *me) {
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
149 fprintf(stderr, "Usage: %s [-s] PID\n", me);
150 fprintf(stderr, " %s -l\n", me);
151 fprintf(stderr, " -l Create a new pty pair and print the name of the slave.\n");
152 fprintf(stderr, " -s Attach fds 0-2 on the target, even if it is not attached to a tty.\n");
66888f4 @nelhage Make the man page and -h both mention all available options.
authored
153 fprintf(stderr, " -h Print this help message and exit.\n");
154 fprintf(stderr, " -v Print the version number and exit.\n");
3fa5657 @nelhage Document the -V option in usage and man pages.
authored
155 fprintf(stderr, " -V Print verbose debug output.\n");
e2d8d67 @nelhage Add a minimal usage message.
authored
156 }
157
ff11f6d @nelhage Try to diagnose errors due to Ubuntu's ptrace_scope sysctl.
authored
158 void check_yama_ptrace_scope(void) {
159 int fd = open("/proc/sys/kernel/yama/ptrace_scope", O_RDONLY);
160 if (fd >= 0) {
161 char buf[256];
162 int n;
163 n = read(fd, buf, sizeof buf);
ce2f3eb @nelhage Don't leak an fd in check_yama_ptrace_scope.
authored
164 close(fd);
ff11f6d @nelhage Try to diagnose errors due to Ubuntu's ptrace_scope sysctl.
authored
165 if (n > 0) {
166 if (!atoi(buf)) {
167 return;
168 }
169 }
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
170 } else if (errno == ENOENT)
ff11f6d @nelhage Try to diagnose errors due to Ubuntu's ptrace_scope sysctl.
authored
171 return;
172 fprintf(stderr, "The kernel denied permission while attaching. If your uid matches\n");
173 fprintf(stderr, "the target's, check the value of /proc/sys/kernel/yama/ptrace_scope.\n");
174 fprintf(stderr, "For more information, see /etc/sysctl.d/10-ptrace.conf\n");
175 }
176
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
177 int main(int argc, char **argv) {
178 struct termios saved_termios;
179 struct sigaction act;
180 int pty;
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
181 int arg = 1;
e2d8d67 @nelhage Add a minimal usage message.
authored
182 int do_attach = 1;
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
183 int force_stdio = 0;
e2d8d67 @nelhage Add a minimal usage message.
authored
184
185 if (argc < 2) {
186 usage(argv[0]);
187 return 2;
188 }
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
189 if (argv[arg][0] == '-') {
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
190 switch(argv[arg][1]) {
e2d8d67 @nelhage Add a minimal usage message.
authored
191 case 'h':
192 usage(argv[0]);
193 return 0;
194 case 'l':
195 do_attach = 0;
196 break;
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
197 case 's':
198 arg++;
199 force_stdio = 1;
200 break;
c5c9e51 @nelhage Add a version number.
authored
201 case 'v':
202 printf("This is reptyr version %s.\n", REPTYR_VERSION);
203 printf(" by Nelson Elhage <nelhage@nelhage.com>\n");
204 printf("http://github.com/nelhage/reptyr/\n");
205 return 0;
d5f8060 @rwmacleod Add a [-V]erbose flag; default is off.
rwmacleod authored
206 case 'V':
207 arg++;
208 verbose = 1;
209 break;
e2d8d67 @nelhage Add a minimal usage message.
authored
210 default:
211 usage(argv[0]);
212 return 1;
213 }
214 }
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
215
919fff7 @nelhage Don't crash if the user provides -s without a pid.
authored
216 if (do_attach && arg >= argc) {
217 fprintf(stderr, "%s: No pid specified to attach\n", argv[0]);
218 usage(argv[0]);
219 return 1;
220 }
221
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
222 if ((pty = open("/dev/ptmx", O_RDWR|O_NOCTTY)) < 0)
223 die("Unable to open /dev/ptmx: %m");
224 if (unlockpt(pty) < 0)
225 die("Unable to unlockpt: %m");
226 if (grantpt(pty) < 0)
0274231 @nelhage Fix the text of an error message.
authored
227 die("Unable to grantpt: %m");
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
228
e2d8d67 @nelhage Add a minimal usage message.
authored
229 if (do_attach) {
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
230 pid_t child = atoi(argv[arg]);
b3eb80f @nelhage Improve error-reporting on attach failures somewhat.
authored
231 int err;
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
232 if ((err = attach_child(child, ptsname(pty), force_stdio))) {
61ea2b9 @nelhage Better error reporting if attaching to a child fails.
authored
233 fprintf(stderr, "Unable to attach to pid %d: %s\n", child, strerror(err));
ff11f6d @nelhage Try to diagnose errors due to Ubuntu's ptrace_scope sysctl.
authored
234 if (err == EPERM) {
235 check_yama_ptrace_scope();
236 }
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
237 return 1;
238 }
239 } else {
240 printf("Opened a new pty: %s\n", ptsname(pty));
241 }
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
242
243 setup_raw(&saved_termios);
244 resize_pty(pty);
245 memset(&act, 0, sizeof act);
246 act.sa_handler = do_winch;
247 act.sa_flags = 0;
248 sigaction(SIGWINCH, &act, NULL);
249 do_proxy(pty);
250 tcsetattr(0, TCSANOW, &saved_termios);
251
252 return 0;
253 }
Something went wrong with that request. Please try again.