Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 242 lines (218 sloc) 6.624 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
18ebcd0 @nelhage Break out prototypes into a header file.
authored
41 void _debug(const char *pfx, const char *msg, va_list ap) {
42
43 if (pfx)
44 fprintf(stderr, "%s", pfx);
45 vfprintf(stderr, msg, ap);
46 fprintf(stderr, "\n");
47 }
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
48
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
49 void die(const char *msg, ...) {
50 va_list ap;
51 va_start(ap, msg);
18ebcd0 @nelhage Break out prototypes into a header file.
authored
52 _debug("[!] ", msg, ap);
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
53 va_end(ap);
54
55 exit(1);
56 }
57
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
58 void debug(const char *msg, ...) {
59 va_list ap;
60 va_start(ap, msg);
18ebcd0 @nelhage Break out prototypes into a header file.
authored
61 _debug("[+] ", msg, ap);
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
62 va_end(ap);
18ebcd0 @nelhage Break out prototypes into a header file.
authored
63 }
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
64
18ebcd0 @nelhage Break out prototypes into a header file.
authored
65 void error(const char *msg, ...) {
66 va_list ap;
67 va_start(ap, msg);
68 _debug("[-] ", msg, ap);
69 va_end(ap);
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
70 }
71
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
72 void setup_raw(struct termios *save) {
73 struct termios set;
74 if (tcgetattr(0, save) < 0)
75 die("Unable to read terminal attributes: %m");
76 set = *save;
692b079 @nelhage Use cfmakeraw instead of messing with termios flags ourselves.
authored
77 cfmakeraw(&set);
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
78 if (tcsetattr(0, TCSANOW, &set) < 0)
79 die("Unable to set terminal attributes: %m");
80 }
81
82 void resize_pty(int pty) {
83 struct winsize sz;
84 if (ioctl(0, TIOCGWINSZ, &sz) < 0)
85 return;
86 ioctl(pty, TIOCSWINSZ, &sz);
87 }
88
89 int writeall(int fd, const void *buf, ssize_t count) {
90 ssize_t rv;
91 while (count > 0) {
92 rv = write(fd, buf, count);
93 if (rv < 0)
94 return rv;
95 count -= rv;
96 buf += rv;
97 }
98 return 0;
99 }
100
101 int winch_happened = 0;
102
103 void do_winch(int signal) {
104 winch_happened = 1;
105 }
106
107 void do_proxy(int pty) {
108 char buf[4096];
109 ssize_t count;
110 fd_set set;
111 while (1) {
112 if (winch_happened) {
113 resize_pty(pty);
114 /* FIXME: racy against a second resize */
115 winch_happened = 0;
116 }
117 FD_ZERO(&set);
118 FD_SET(0, &set);
119 FD_SET(pty, &set);
120 if (select(pty+1, &set, NULL, NULL, NULL) < 0) {
121 if (errno == EINTR)
122 continue;
123 fprintf(stderr, "select: %m");
124 return;
125 }
126 if (FD_ISSET(0, &set)) {
127 count = read(0, buf, sizeof buf);
128 if (count < 0)
129 return;
130 writeall(pty, buf, count);
131 }
132 if (FD_ISSET(pty, &set)) {
133 count = read(pty, buf, sizeof buf);
134 if (count < 0)
135 return;
136 writeall(1, buf, count);
137 }
138 }
139 }
140
e2d8d67 @nelhage Add a minimal usage message.
authored
141 void usage(char *me) {
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
142 fprintf(stderr, "Usage: %s [-s] PID\n", me);
143 fprintf(stderr, " %s -l\n", me);
144 fprintf(stderr, " -l Create a new pty pair and print the name of the slave.\n");
145 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
146 fprintf(stderr, " -h Print this help message and exit.\n");
147 fprintf(stderr, " -v Print the version number and exit.\n");
e2d8d67 @nelhage Add a minimal usage message.
authored
148 }
149
ff11f6d @nelhage Try to diagnose errors due to Ubuntu's ptrace_scope sysctl.
authored
150 void check_yama_ptrace_scope(void) {
151 int fd = open("/proc/sys/kernel/yama/ptrace_scope", O_RDONLY);
152 if (fd >= 0) {
153 char buf[256];
154 int n;
155 n = read(fd, buf, sizeof buf);
ce2f3eb @nelhage Don't leak an fd in check_yama_ptrace_scope.
authored
156 close(fd);
ff11f6d @nelhage Try to diagnose errors due to Ubuntu's ptrace_scope sysctl.
authored
157 if (n > 0) {
158 if (!atoi(buf)) {
159 return;
160 }
161 }
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
162 } else if (errno == ENOENT)
ff11f6d @nelhage Try to diagnose errors due to Ubuntu's ptrace_scope sysctl.
authored
163 return;
164 fprintf(stderr, "The kernel denied permission while attaching. If your uid matches\n");
165 fprintf(stderr, "the target's, check the value of /proc/sys/kernel/yama/ptrace_scope.\n");
166 fprintf(stderr, "For more information, see /etc/sysctl.d/10-ptrace.conf\n");
167 }
168
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
169 int main(int argc, char **argv) {
170 struct termios saved_termios;
171 struct sigaction act;
172 int pty;
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
173 int arg = 1;
e2d8d67 @nelhage Add a minimal usage message.
authored
174 int do_attach = 1;
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
175 int force_stdio = 0;
e2d8d67 @nelhage Add a minimal usage message.
authored
176
177 if (argc < 2) {
178 usage(argv[0]);
179 return 2;
180 }
6c5d231 @nelhage Consistently use a space in 'if (...)' and 'while (...)'.
authored
181 if (argv[arg][0] == '-') {
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
182 switch(argv[arg][1]) {
e2d8d67 @nelhage Add a minimal usage message.
authored
183 case 'h':
184 usage(argv[0]);
185 return 0;
186 case 'l':
187 do_attach = 0;
188 break;
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
189 case 's':
190 arg++;
191 force_stdio = 1;
192 break;
c5c9e51 @nelhage Add a version number.
authored
193 case 'v':
194 printf("This is reptyr version %s.\n", REPTYR_VERSION);
195 printf(" by Nelson Elhage <nelhage@nelhage.com>\n");
196 printf("http://github.com/nelhage/reptyr/\n");
197 return 0;
e2d8d67 @nelhage Add a minimal usage message.
authored
198 default:
199 usage(argv[0]);
200 return 1;
201 }
202 }
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
203
919fff7 @nelhage Don't crash if the user provides -s without a pid.
authored
204 if (do_attach && arg >= argc) {
205 fprintf(stderr, "%s: No pid specified to attach\n", argv[0]);
206 usage(argv[0]);
207 return 1;
208 }
209
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
210 if ((pty = open("/dev/ptmx", O_RDWR|O_NOCTTY)) < 0)
211 die("Unable to open /dev/ptmx: %m");
212 if (unlockpt(pty) < 0)
213 die("Unable to unlockpt: %m");
214 if (grantpt(pty) < 0)
0274231 @nelhage Fix the text of an error message.
authored
215 die("Unable to grantpt: %m");
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
216
e2d8d67 @nelhage Add a minimal usage message.
authored
217 if (do_attach) {
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
218 pid_t child = atoi(argv[arg]);
b3eb80f @nelhage Improve error-reporting on attach failures somewhat.
authored
219 int err;
9ce2526 @nelhage Add a -s option to force attaching stdio.
authored
220 if ((err = attach_child(child, ptsname(pty), force_stdio))) {
61ea2b9 @nelhage Better error reporting if attaching to a child fails.
authored
221 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
222 if (err == EPERM) {
223 check_yama_ptrace_scope();
224 }
f5d1d89 @nelhage Checkpoint attach work-in-progress.
authored
225 return 1;
226 }
227 } else {
228 printf("Opened a new pty: %s\n", ptsname(pty));
229 }
e222527 @nelhage Initial import. Mostly able to run barnowl.
authored
230
231 setup_raw(&saved_termios);
232 resize_pty(pty);
233 memset(&act, 0, sizeof act);
234 act.sa_handler = do_winch;
235 act.sa_flags = 0;
236 sigaction(SIGWINCH, &act, NULL);
237 do_proxy(pty);
238 tcsetattr(0, TCSANOW, &saved_termios);
239
240 return 0;
241 }
Something went wrong with that request. Please try again.