diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-22 15:54:52 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2006-11-22 15:54:52 +0000 |
commit | 75f8d080a28f2a9076a5f60afeba41ac876a78a4 (patch) | |
tree | 21794599ef01c7603faff7efb1fcaf56868684c9 | |
parent | d6bbf99a8b174d8535c195c71d3560a0d83d95fc (diff) | |
download | busybox-w32-75f8d080a28f2a9076a5f60afeba41ac876a78a4.tar.gz busybox-w32-75f8d080a28f2a9076a5f60afeba41ac876a78a4.tar.bz2 busybox-w32-75f8d080a28f2a9076a5f60afeba41ac876a78a4.zip |
telnetd: we were having telnetd with is ONLY inetd or ONLY standalone.
What if I need to have both?? This patch introduces
CONFIG_FEATURE_TELNETD_STANDALONE: y - both, n - only inetd.
-rw-r--r-- | include/libbb.h | 1 | ||||
-rw-r--r-- | include/usage.h | 18 | ||||
-rw-r--r-- | libbb/xfuncs.c | 12 | ||||
-rw-r--r-- | networking/Config.in | 7 | ||||
-rw-r--r-- | networking/telnetd.c | 671 | ||||
-rw-r--r-- | runit/runit_lib.c | 20 | ||||
-rw-r--r-- | scripts/defconfig | 1 |
7 files changed, 344 insertions, 386 deletions
diff --git a/include/libbb.h b/include/libbb.h index bec3ce11c..1c82cbbba 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -204,6 +204,7 @@ extern off_t bb_copyfd_size(int fd1, int fd2, off_t size); | |||
204 | extern off_t bb_copyfd_eof(int fd1, int fd2); | 204 | extern off_t bb_copyfd_eof(int fd1, int fd2); |
205 | extern char bb_process_escape_sequence(const char **ptr); | 205 | extern char bb_process_escape_sequence(const char **ptr); |
206 | extern char *bb_get_last_path_component(char *path); | 206 | extern char *bb_get_last_path_component(char *path); |
207 | extern int ndelay_on(int fd); | ||
207 | 208 | ||
208 | 209 | ||
209 | extern DIR *xopendir(const char *path); | 210 | extern DIR *xopendir(const char *path); |
diff --git a/include/usage.h b/include/usage.h index 2a6e335ba..69e958d68 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -3034,22 +3034,24 @@ USE_FEATURE_START_STOP_DAEMON_FANCY( \ | |||
3034 | "computer over a network using the TELNET protocol." | 3034 | "computer over a network using the TELNET protocol." |
3035 | #endif | 3035 | #endif |
3036 | 3036 | ||
3037 | #ifdef CONFIG_FEATURE_TELNETD_INETD | 3037 | #ifdef CONFIG_FEATURE_TELNETD_STANDALONE |
3038 | #define telnetd_trivial_usage \ | 3038 | #define telnetd_trivial_usage \ |
3039 | "(inetd mode) [OPTION]" | 3039 | "[OPTION]" |
3040 | #define telnetd_full_usage \ | 3040 | #define telnetd_full_usage \ |
3041 | "Telnetd uses incoming TELNET connections via inetd.\n" \ | 3041 | "Telnetd listens for incoming TELNET connections on PORT.\n" \ |
3042 | "Options:\n" \ | 3042 | "Options:\n" \ |
3043 | "\t-l LOGIN\texec LOGIN on connect (default /bin/sh)\n" \ | 3043 | "\t-p PORT\t\tlisten for connections on PORT (default 23)\n" \ |
3044 | "\t-f issue_file\tDisplay issue_file instead of /etc/issue" | 3044 | "\t-l LOGIN\texec LOGIN on connect\n" \ |
3045 | "\t-f issue_file\tDisplay issue_file instead of /etc/issue\n" \ | ||
3046 | "\t-F\t\tForeground mode\n" \ | ||
3047 | "\t-i\t\tInetd mode" | ||
3045 | #else | 3048 | #else |
3046 | #define telnetd_trivial_usage \ | 3049 | #define telnetd_trivial_usage \ |
3047 | "[OPTION]" | 3050 | "[OPTION]" |
3048 | #define telnetd_full_usage \ | 3051 | #define telnetd_full_usage \ |
3049 | "Telnetd listens for incoming TELNET connections on PORT.\n" \ | 3052 | "Telnetd uses incoming TELNET connections via inetd.\n" \ |
3050 | "Options:\n" \ | 3053 | "Options:\n" \ |
3051 | "\t-p PORT\tlisten for connections on PORT (default 23)\n" \ | 3054 | "\t-l LOGIN\texec LOGIN on connect\n" \ |
3052 | "\t-l LOGIN\texec LOGIN on connect (default /bin/sh)\n" \ | ||
3053 | "\t-f issue_file\tDisplay issue_file instead of /etc/issue" | 3055 | "\t-f issue_file\tDisplay issue_file instead of /etc/issue" |
3054 | #endif | 3056 | #endif |
3055 | 3057 | ||
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 44a551639..e6f4e3a48 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c | |||
@@ -110,6 +110,18 @@ int xopen3(const char *pathname, int flags, int mode) | |||
110 | return ret; | 110 | return ret; |
111 | } | 111 | } |
112 | 112 | ||
113 | /* | ||
114 | int ndelay_off(int fd) | ||
115 | { | ||
116 | return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK); | ||
117 | } | ||
118 | */ | ||
119 | // Turn on nonblocking I/O on a fd | ||
120 | int ndelay_on(int fd) | ||
121 | { | ||
122 | return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK); | ||
123 | } | ||
124 | |||
113 | // Die with an error message if we can't write the entire buffer. | 125 | // Die with an error message if we can't write the entire buffer. |
114 | void xwrite(int fd, void *buf, size_t count) | 126 | void xwrite(int fd, void *buf, size_t count) |
115 | { | 127 | { |
diff --git a/networking/Config.in b/networking/Config.in index ba41ab119..e9694af67 100644 --- a/networking/Config.in +++ b/networking/Config.in | |||
@@ -586,13 +586,12 @@ config TELNETD | |||
586 | with all that done, telnetd _should_ work.... | 586 | with all that done, telnetd _should_ work.... |
587 | 587 | ||
588 | 588 | ||
589 | config FEATURE_TELNETD_INETD | 589 | config FEATURE_TELNETD_STANDALONE |
590 | bool "Support call from inetd only" | 590 | bool "Support standalone telnetd (not inetd only)" |
591 | default n | 591 | default n |
592 | depends on TELNETD | 592 | depends on TELNETD |
593 | help | 593 | help |
594 | Selecting this will make telnetd only callable from inetd, | 594 | Selecting this will make telnetd able to run standalone. |
595 | removing the standalone support. | ||
596 | 595 | ||
597 | config TFTP | 596 | config TFTP |
598 | bool "tftp" | 597 | bool "tftp" |
diff --git a/networking/telnetd.c b/networking/telnetd.c index da7911fcc..549488507 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c | |||
@@ -22,11 +22,11 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | /*#define DEBUG 1 */ | 24 | /*#define DEBUG 1 */ |
25 | #undef DEBUG | 25 | #define DEBUG 0 |
26 | 26 | ||
27 | #include "busybox.h" | 27 | #include "busybox.h" |
28 | 28 | ||
29 | #ifdef DEBUG | 29 | #if DEBUG |
30 | #define TELCMDS | 30 | #define TELCMDS |
31 | #define TELOPTS | 31 | #define TELOPTS |
32 | #endif | 32 | #endif |
@@ -36,7 +36,7 @@ | |||
36 | 36 | ||
37 | #define BUFSIZE 4000 | 37 | #define BUFSIZE 4000 |
38 | 38 | ||
39 | #ifdef CONFIG_FEATURE_IPV6 | 39 | #if ENABLE_FEATURE_IPV6 |
40 | #define SOCKET_TYPE AF_INET6 | 40 | #define SOCKET_TYPE AF_INET6 |
41 | typedef struct sockaddr_in6 sockaddr_type; | 41 | typedef struct sockaddr_in6 sockaddr_type; |
42 | #else | 42 | #else |
@@ -44,27 +44,23 @@ typedef struct sockaddr_in6 sockaddr_type; | |||
44 | typedef struct sockaddr_in sockaddr_type; | 44 | typedef struct sockaddr_in sockaddr_type; |
45 | #endif | 45 | #endif |
46 | 46 | ||
47 | 47 | #if ENABLE_LOGIN | |
48 | #ifdef CONFIG_LOGIN | ||
49 | static const char *loginpath = "/bin/login"; | 48 | static const char *loginpath = "/bin/login"; |
50 | #else | 49 | #else |
51 | static const char *loginpath; | 50 | static const char *loginpath = DEFAULT_SHELL; |
52 | #endif | 51 | #endif |
52 | |||
53 | static const char *issuefile = "/etc/issue.net"; | 53 | static const char *issuefile = "/etc/issue.net"; |
54 | 54 | ||
55 | /* shell name and arguments */ | 55 | /* shell name and arguments */ |
56 | 56 | ||
57 | static const char *argv_init[] = {NULL, NULL}; | 57 | static const char *argv_init[2]; |
58 | 58 | ||
59 | /* structure that describes a session */ | 59 | /* structure that describes a session */ |
60 | 60 | ||
61 | struct tsession { | 61 | struct tsession { |
62 | #ifdef CONFIG_FEATURE_TELNETD_INETD | ||
63 | int sockfd_read, sockfd_write, ptyfd; | ||
64 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | ||
65 | struct tsession *next; | 62 | struct tsession *next; |
66 | int sockfd, ptyfd; | 63 | int sockfd_read, sockfd_write, ptyfd; |
67 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
68 | int shell_pid; | 64 | int shell_pid; |
69 | /* two circular buffers */ | 65 | /* two circular buffers */ |
70 | char *buf1, *buf2; | 66 | char *buf1, *buf2; |
@@ -73,7 +69,6 @@ struct tsession { | |||
73 | }; | 69 | }; |
74 | 70 | ||
75 | /* | 71 | /* |
76 | |||
77 | This is how the buffers are used. The arrows indicate the movement | 72 | This is how the buffers are used. The arrows indicate the movement |
78 | of data. | 73 | of data. |
79 | 74 | ||
@@ -86,7 +81,6 @@ struct tsession { | |||
86 | +-------+ size2++ +------+ size2-- +----------+ | 81 | +-------+ size2++ +------+ size2-- +----------+ |
87 | 82 | ||
88 | Each session has got two buffers. | 83 | Each session has got two buffers. |
89 | |||
90 | */ | 84 | */ |
91 | 85 | ||
92 | static int maxfd; | 86 | static int maxfd; |
@@ -95,7 +89,6 @@ static struct tsession *sessions; | |||
95 | 89 | ||
96 | 90 | ||
97 | /* | 91 | /* |
98 | |||
99 | Remove all IAC's from the buffer pointed to by bf (received IACs are ignored | 92 | Remove all IAC's from the buffer pointed to by bf (received IACs are ignored |
100 | and must be removed so as to not be interpreted by the terminal). Make an | 93 | and must be removed so as to not be interpreted by the terminal). Make an |
101 | uninterrupted string of characters fit for the terminal. Do this by packing | 94 | uninterrupted string of characters fit for the terminal. Do this by packing |
@@ -113,10 +106,10 @@ static struct tsession *sessions; | |||
113 | what is the escape character? We aren't handling that situation here. | 106 | what is the escape character? We aren't handling that situation here. |
114 | 107 | ||
115 | CR-LF ->'s CR mapping is also done here, for convenience | 108 | CR-LF ->'s CR mapping is also done here, for convenience |
116 | 109 | */ | |
117 | */ | ||
118 | static char * | 110 | static char * |
119 | remove_iacs(struct tsession *ts, int *pnum_totty) { | 111 | remove_iacs(struct tsession *ts, int *pnum_totty) |
112 | { | ||
120 | unsigned char *ptr0 = (unsigned char *)ts->buf1 + ts->wridx1; | 113 | unsigned char *ptr0 = (unsigned char *)ts->buf1 + ts->wridx1; |
121 | unsigned char *ptr = ptr0; | 114 | unsigned char *ptr = ptr0; |
122 | unsigned char *totty = ptr; | 115 | unsigned char *totty = ptr; |
@@ -134,8 +127,7 @@ remove_iacs(struct tsession *ts, int *pnum_totty) { | |||
134 | */ | 127 | */ |
135 | if (c == '\r' && (*ptr == '\n' || *ptr == 0) && ptr < end) | 128 | if (c == '\r' && (*ptr == '\n' || *ptr == 0) && ptr < end) |
136 | ptr++; | 129 | ptr++; |
137 | } | 130 | } else { |
138 | else { | ||
139 | /* | 131 | /* |
140 | * TELOPT_NAWS support! | 132 | * TELOPT_NAWS support! |
141 | */ | 133 | */ |
@@ -155,14 +147,13 @@ remove_iacs(struct tsession *ts, int *pnum_totty) { | |||
155 | break; /* incomplete, can't process */ | 147 | break; /* incomplete, can't process */ |
156 | ws.ws_col = (ptr[3] << 8) | ptr[4]; | 148 | ws.ws_col = (ptr[3] << 8) | ptr[4]; |
157 | ws.ws_row = (ptr[5] << 8) | ptr[6]; | 149 | ws.ws_row = (ptr[5] << 8) | ptr[6]; |
158 | (void) ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); | 150 | ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); |
159 | ptr += 9; | 151 | ptr += 9; |
160 | } | 152 | } else { |
161 | else { | ||
162 | /* skip 3-byte IAC non-SB cmd */ | 153 | /* skip 3-byte IAC non-SB cmd */ |
163 | #ifdef DEBUG | 154 | #if DEBUG |
164 | fprintf(stderr, "Ignoring IAC %s,%s\n", | 155 | fprintf(stderr, "Ignoring IAC %s,%s\n", |
165 | TELCMD(*(ptr+1)), TELOPT(*(ptr+2))); | 156 | TELCMD(ptr[1]), TELOPT(ptr[2])); |
166 | #endif | 157 | #endif |
167 | ptr += 3; | 158 | ptr += 3; |
168 | } | 159 | } |
@@ -184,10 +175,10 @@ remove_iacs(struct tsession *ts, int *pnum_totty) { | |||
184 | 175 | ||
185 | 176 | ||
186 | static int | 177 | static int |
187 | getpty(char *line) | 178 | getpty(char *line, int size) |
188 | { | 179 | { |
189 | int p; | 180 | int p; |
190 | #ifdef CONFIG_FEATURE_DEVPTS | 181 | #if ENABLE_FEATURE_DEVPTS |
191 | p = open("/dev/ptmx", O_RDWR); | 182 | p = open("/dev/ptmx", O_RDWR); |
192 | if (p > 0) { | 183 | if (p > 0) { |
193 | const char *name; | 184 | const char *name; |
@@ -198,7 +189,7 @@ getpty(char *line) | |||
198 | bb_perror_msg("ptsname error (is /dev/pts mounted?)"); | 189 | bb_perror_msg("ptsname error (is /dev/pts mounted?)"); |
199 | return -1; | 190 | return -1; |
200 | } | 191 | } |
201 | strcpy(line, name); | 192 | safe_strncpy(line, name, size); |
202 | return p; | 193 | return p; |
203 | } | 194 | } |
204 | #else | 195 | #else |
@@ -216,9 +207,8 @@ getpty(char *line) | |||
216 | } | 207 | } |
217 | for (j = 0; j < 16; j++) { | 208 | for (j = 0; j < 16; j++) { |
218 | line[9] = j < 10 ? j + '0' : j - 10 + 'a'; | 209 | line[9] = j < 10 ? j + '0' : j - 10 + 'a'; |
219 | #ifdef DEBUG | 210 | if (DEBUG) |
220 | fprintf(stderr, "Trying to open device: %s\n", line); | 211 | fprintf(stderr, "Trying to open device: %s\n", line); |
221 | #endif | ||
222 | p = open(line, O_RDWR | O_NOCTTY); | 212 | p = open(line, O_RDWR | O_NOCTTY); |
223 | if (p >= 0) { | 213 | if (p >= 0) { |
224 | line[5] = 't'; | 214 | line[5] = 't'; |
@@ -226,7 +216,7 @@ getpty(char *line) | |||
226 | } | 216 | } |
227 | } | 217 | } |
228 | } | 218 | } |
229 | #endif /* CONFIG_FEATURE_DEVPTS */ | 219 | #endif /* FEATURE_DEVPTS */ |
230 | return -1; | 220 | return -1; |
231 | } | 221 | } |
232 | 222 | ||
@@ -234,7 +224,7 @@ getpty(char *line) | |||
234 | static void | 224 | static void |
235 | send_iac(struct tsession *ts, unsigned char command, int option) | 225 | send_iac(struct tsession *ts, unsigned char command, int option) |
236 | { | 226 | { |
237 | /* We rely on that there is space in the buffer for now. */ | 227 | /* We rely on that there is space in the buffer for now. */ |
238 | char *b = ts->buf2 + ts->rdidx2; | 228 | char *b = ts->buf2 + ts->rdidx2; |
239 | *b++ = IAC; | 229 | *b++ = IAC; |
240 | *b++ = command; | 230 | *b++ = command; |
@@ -245,401 +235,376 @@ send_iac(struct tsession *ts, unsigned char command, int option) | |||
245 | 235 | ||
246 | 236 | ||
247 | static struct tsession * | 237 | static struct tsession * |
248 | #ifdef CONFIG_FEATURE_TELNETD_INETD | 238 | make_new_session( |
249 | make_new_session(void) | 239 | USE_FEATURE_TELNETD_STANDALONE(int sock_r, int sock_w) |
250 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | 240 | SKIP_FEATURE_TELNETD_STANDALONE(void) |
251 | make_new_session(int sockfd) | 241 | ) { |
252 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
253 | { | ||
254 | struct termios termbuf; | 242 | struct termios termbuf; |
255 | int pty, pid; | 243 | int fd, pid; |
256 | char tty_name[32]; | 244 | char tty_name[32]; |
257 | struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2); | 245 | struct tsession *ts = xzalloc(sizeof(struct tsession) + BUFSIZE * 2); |
258 | 246 | ||
259 | ts->buf1 = (char *)(&ts[1]); | 247 | ts->buf1 = (char *)(&ts[1]); |
260 | ts->buf2 = ts->buf1 + BUFSIZE; | 248 | ts->buf2 = ts->buf1 + BUFSIZE; |
261 | 249 | ||
262 | #ifdef CONFIG_FEATURE_TELNETD_INETD | 250 | /* Got a new connection, set up a tty. */ |
263 | ts->sockfd_write = 1; | 251 | fd = getpty(tty_name, 32); |
264 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | 252 | if (fd < 0) { |
265 | ts->sockfd = sockfd; | ||
266 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
267 | |||
268 | /* Got a new connection, set up a tty and spawn a shell. */ | ||
269 | |||
270 | pty = getpty(tty_name); | ||
271 | |||
272 | if (pty < 0) { | ||
273 | bb_error_msg("all terminals in use"); | 253 | bb_error_msg("all terminals in use"); |
274 | return 0; | 254 | return NULL; |
275 | } | 255 | } |
276 | 256 | if (fd > maxfd) maxfd = fd; | |
277 | if (pty > maxfd) | 257 | ndelay_on(ts->ptyfd = fd); |
278 | maxfd = pty; | 258 | #if ENABLE_FEATURE_TELNETD_STANDALONE |
279 | 259 | if (sock_w > maxfd) maxfd = sock_w; | |
280 | ts->ptyfd = pty; | 260 | if (sock_r > maxfd) maxfd = sock_r; |
281 | 261 | ndelay_on(ts->sockfd_write = sock_w); | |
262 | ndelay_on(ts->sockfd_read = sock_r); | ||
263 | #else | ||
264 | ts->sockfd_write = 1; | ||
265 | /* xzalloc: ts->sockfd_read = 0; */ | ||
266 | ndelay_on(0); | ||
267 | ndelay_on(1); | ||
268 | #endif | ||
282 | /* Make the telnet client understand we will echo characters so it | 269 | /* Make the telnet client understand we will echo characters so it |
283 | * should not do it locally. We don't tell the client to run linemode, | 270 | * should not do it locally. We don't tell the client to run linemode, |
284 | * because we want to handle line editing and tab completion and other | 271 | * because we want to handle line editing and tab completion and other |
285 | * stuff that requires char-by-char support. | 272 | * stuff that requires char-by-char support. */ |
286 | */ | ||
287 | |||
288 | send_iac(ts, DO, TELOPT_ECHO); | 273 | send_iac(ts, DO, TELOPT_ECHO); |
289 | send_iac(ts, DO, TELOPT_NAWS); | 274 | send_iac(ts, DO, TELOPT_NAWS); |
290 | send_iac(ts, DO, TELOPT_LFLOW); | 275 | send_iac(ts, DO, TELOPT_LFLOW); |
291 | send_iac(ts, WILL, TELOPT_ECHO); | 276 | send_iac(ts, WILL, TELOPT_ECHO); |
292 | send_iac(ts, WILL, TELOPT_SGA); | 277 | send_iac(ts, WILL, TELOPT_SGA); |
293 | 278 | ||
294 | if ((pid = fork()) < 0) { | 279 | pid = fork(); |
280 | if (pid < 0) { | ||
281 | free(ts); | ||
282 | close(fd); | ||
295 | bb_perror_msg("fork"); | 283 | bb_perror_msg("fork"); |
284 | return NULL; | ||
296 | } | 285 | } |
297 | if (pid == 0) { | 286 | if (pid > 0) { |
298 | /* In child, open the child's side of the tty. */ | 287 | /* parent */ |
299 | int i; | 288 | ts->shell_pid = pid; |
300 | 289 | return ts; | |
301 | for(i = 0; i <= maxfd; i++) | ||
302 | close(i); | ||
303 | /* make new process group */ | ||
304 | setsid(); | ||
305 | |||
306 | xopen(tty_name, O_RDWR /*| O_NOCTTY*/); | ||
307 | dup(0); | ||
308 | dup(0); | ||
309 | |||
310 | tcsetpgrp(0, getpid()); | ||
311 | |||
312 | /* The pseudo-terminal allocated to the client is configured to operate in | ||
313 | * cooked mode, and with XTABS CRMOD enabled (see tty(4)). | ||
314 | */ | ||
315 | |||
316 | tcgetattr(0, &termbuf); | ||
317 | termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */ | ||
318 | termbuf.c_oflag |= ONLCR|XTABS; | ||
319 | termbuf.c_iflag |= ICRNL; | ||
320 | termbuf.c_iflag &= ~IXOFF; | ||
321 | /*termbuf.c_lflag &= ~ICANON;*/ | ||
322 | tcsetattr(0, TCSANOW, &termbuf); | ||
323 | |||
324 | print_login_issue(issuefile, NULL); | ||
325 | |||
326 | /* exec shell, with correct argv and env */ | ||
327 | execv(loginpath, (char *const *)argv_init); | ||
328 | |||
329 | /* NOT REACHED */ | ||
330 | bb_perror_msg_and_die("execv"); | ||
331 | } | 290 | } |
332 | 291 | ||
333 | ts->shell_pid = pid; | 292 | /* child */ |
334 | 293 | ||
335 | return ts; | 294 | /* open the child's side of the tty. */ |
295 | fd = xopen(tty_name, O_RDWR /*| O_NOCTTY*/); | ||
296 | dup2(fd, 0); | ||
297 | dup2(fd, 1); | ||
298 | dup2(fd, 2); | ||
299 | while (fd > 2) close(fd--); | ||
300 | /* make new process group */ | ||
301 | setsid(); | ||
302 | tcsetpgrp(0, getpid()); | ||
303 | |||
304 | /* The pseudo-terminal allocated to the client is configured to operate in | ||
305 | * cooked mode, and with XTABS CRMOD enabled (see tty(4)). */ | ||
306 | tcgetattr(0, &termbuf); | ||
307 | termbuf.c_lflag |= ECHO; /* if we use readline we dont want this */ | ||
308 | termbuf.c_oflag |= ONLCR|XTABS; | ||
309 | termbuf.c_iflag |= ICRNL; | ||
310 | termbuf.c_iflag &= ~IXOFF; | ||
311 | /*termbuf.c_lflag &= ~ICANON;*/ | ||
312 | tcsetattr(0, TCSANOW, &termbuf); | ||
313 | |||
314 | print_login_issue(issuefile, NULL); | ||
315 | |||
316 | /* exec shell, with correct argv and env */ | ||
317 | execv(loginpath, (char *const *)argv_init); | ||
318 | bb_perror_msg_and_die("execv"); | ||
336 | } | 319 | } |
337 | 320 | ||
338 | #ifndef CONFIG_FEATURE_TELNETD_INETD | 321 | #if ENABLE_FEATURE_TELNETD_STANDALONE |
322 | |||
339 | static void | 323 | static void |
340 | free_session(struct tsession *ts) | 324 | free_session(struct tsession *ts) |
341 | { | 325 | { |
342 | struct tsession *t = sessions; | 326 | struct tsession *t = sessions; |
343 | 327 | ||
344 | /* Unlink this telnet session from the session list. */ | 328 | /* unlink this telnet session from the session list */ |
345 | if (t == ts) | 329 | if (t == ts) |
346 | sessions = ts->next; | 330 | sessions = ts->next; |
347 | else { | 331 | else { |
348 | while(t->next != ts) | 332 | while (t->next != ts) |
349 | t = t->next; | 333 | t = t->next; |
350 | t->next = ts->next; | 334 | t->next = ts->next; |
351 | } | 335 | } |
352 | 336 | ||
353 | kill(ts->shell_pid, SIGKILL); | 337 | kill(ts->shell_pid, SIGKILL); |
354 | |||
355 | wait4(ts->shell_pid, NULL, 0, NULL); | 338 | wait4(ts->shell_pid, NULL, 0, NULL); |
356 | |||
357 | close(ts->ptyfd); | 339 | close(ts->ptyfd); |
358 | close(ts->sockfd); | 340 | close(ts->sockfd_read); |
359 | 341 | /* error if ts->sockfd_read == ts->sockfd_write. So what? ;) */ | |
360 | if (ts->ptyfd == maxfd || ts->sockfd == maxfd) | 342 | close(ts->sockfd_write); |
361 | maxfd--; | ||
362 | if (ts->ptyfd == maxfd || ts->sockfd == maxfd) | ||
363 | maxfd--; | ||
364 | |||
365 | free(ts); | 343 | free(ts); |
344 | |||
345 | /* scan all sessions and find new maxfd */ | ||
346 | ts = sessions; | ||
347 | maxfd = 0; | ||
348 | while (ts) { | ||
349 | if (maxfd < ts->ptyfd) | ||
350 | maxfd = ts->ptyfd; | ||
351 | if (maxfd < ts->sockfd_read) | ||
352 | maxfd = ts->sockfd_read; | ||
353 | if (maxfd < ts->sockfd_write) | ||
354 | maxfd = ts->sockfd_write; | ||
355 | ts = ts->next; | ||
356 | } | ||
366 | } | 357 | } |
367 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
368 | 358 | ||
369 | int | 359 | static int |
370 | telnetd_main(int argc, char **argv) | 360 | create_socket(int port, const char *opt_bindaddr) |
371 | { | 361 | { |
372 | unsigned opt; | 362 | static const int on = 1; |
373 | fd_set rdfdset, wrfdset; | 363 | int fd; |
374 | int selret; | ||
375 | #ifndef CONFIG_FEATURE_TELNETD_INETD | ||
376 | sockaddr_type sa; | 364 | sockaddr_type sa; |
377 | int master_fd; | 365 | #if !ENABLE_FEATURE_IPV6 |
378 | int on = 1; | ||
379 | unsigned portnbr = 23; | ||
380 | struct in_addr bind_addr = { .s_addr = 0x0 }; | 366 | struct in_addr bind_addr = { .s_addr = 0x0 }; |
381 | char *opt_portnbr, *opt_bindaddr; | ||
382 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
383 | int maxlen, w, r; | ||
384 | 367 | ||
385 | #ifndef CONFIG_LOGIN | 368 | /* TODO: generic string -> sockaddr converter */ |
386 | loginpath = DEFAULT_SHELL; | 369 | if (opt_bindaddr && inet_aton(opt_bindaddr, &bind_addr) == 0) |
370 | bb_show_usage(); | ||
387 | #endif | 371 | #endif |
388 | 372 | fd = xsocket(SOCKET_TYPE, SOCK_STREAM, 0); | |
389 | /* We use inetd-style operation unconditionally | 373 | setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); |
390 | * (no --foreground option), user most likely will | ||
391 | * look into syslog for all errors, even early ones. | ||
392 | * Direct all output to syslog at once. | ||
393 | */ | ||
394 | openlog(applet_name, 0, LOG_USER); | ||
395 | logmode = LOGMODE_SYSLOG; | ||
396 | |||
397 | opt = getopt32(argc, argv, "f:l:" SKIP_FEATURE_TELNETD_INETD("p:b:"), | ||
398 | &issuefile, &loginpath | ||
399 | SKIP_FEATURE_TELNETD_INETD(, &opt_portnbr, &opt_bindaddr)); | ||
400 | //if (opt & 1) // -f | ||
401 | //if (opt & 2) // -l | ||
402 | #ifndef CONFIG_FEATURE_TELNETD_INETD | ||
403 | if (opt & 4) portnbr = xatou16(opt_portnbr); // -p | ||
404 | if (opt & 8) // -b | ||
405 | if (inet_aton(opt_bindaddr, &bind_addr) == 0) bb_show_usage(); | ||
406 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
407 | |||
408 | if (access(loginpath, X_OK) < 0) { | ||
409 | bb_error_msg_and_die("'%s' unavailable", loginpath); | ||
410 | } | ||
411 | |||
412 | argv_init[0] = loginpath; | ||
413 | |||
414 | #ifdef CONFIG_FEATURE_TELNETD_INETD | ||
415 | maxfd = 1; | ||
416 | sessions = make_new_session(); | ||
417 | #else /* CONFIG_EATURE_TELNETD_INETD */ | ||
418 | sessions = 0; | ||
419 | |||
420 | /* Grab a TCP socket. */ | ||
421 | |||
422 | master_fd = xsocket(SOCKET_TYPE, SOCK_STREAM, 0); | ||
423 | (void)setsockopt(master_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); | ||
424 | |||
425 | /* Set it to listen to specified port. */ | ||
426 | |||
427 | memset((void *)&sa, 0, sizeof(sa)); | 374 | memset((void *)&sa, 0, sizeof(sa)); |
428 | #ifdef CONFIG_FEATURE_IPV6 | 375 | #if ENABLE_FEATURE_IPV6 |
429 | sa.sin6_family = AF_INET6; | 376 | sa.sin6_family = AF_INET6; |
430 | sa.sin6_port = htons(portnbr); | 377 | sa.sin6_port = htons(port); |
431 | /* sa.sin6_addr = bind_addr6; */ | 378 | /* sa.sin6_addr = bind_addr6; */ |
432 | #else | 379 | #else |
433 | sa.sin_family = AF_INET; | 380 | sa.sin_family = AF_INET; |
434 | sa.sin_port = htons(portnbr); | 381 | sa.sin_port = htons(port); |
435 | sa.sin_addr = bind_addr; | 382 | sa.sin_addr = bind_addr; |
436 | #endif | 383 | #endif |
384 | xbind(fd, (struct sockaddr *) &sa, sizeof(sa)); | ||
385 | xlisten(fd, 1); | ||
386 | return fd; | ||
387 | } | ||
437 | 388 | ||
438 | xbind(master_fd, (struct sockaddr *) &sa, sizeof(sa)); | 389 | #else /* !FEATURE_TELNETD_STANDALONE */ |
439 | xlisten(master_fd, 1); | ||
440 | xdaemon(0, 0); | ||
441 | 390 | ||
442 | maxfd = master_fd; | 391 | /* Never actually called */ |
443 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | 392 | void free_session(struct tsession *ts); |
393 | int create_socket(int port, const char *opt_bindaddr); | ||
444 | 394 | ||
445 | while(1) { | 395 | #endif |
446 | struct tsession *ts; | ||
447 | 396 | ||
448 | FD_ZERO(&rdfdset); | ||
449 | FD_ZERO(&wrfdset); | ||
450 | 397 | ||
451 | /* select on the master socket, all telnet sockets and their | 398 | int |
452 | * ptys if there is room in their respective session buffers. | 399 | telnetd_main(int argc, char **argv) |
453 | */ | 400 | { |
401 | fd_set rdfdset, wrfdset; | ||
402 | unsigned opt; | ||
403 | int selret, maxlen, w, r; | ||
404 | struct tsession *ts; | ||
405 | #if ENABLE_FEATURE_TELNETD_STANDALONE | ||
406 | #define IS_INETD (opt & OPT_INETD) | ||
407 | int master_fd = -1; /* be happy, gcc */ | ||
408 | unsigned portnbr = 23; | ||
409 | char *opt_bindaddr = NULL; | ||
410 | char *opt_portnbr; | ||
411 | #else | ||
412 | enum { | ||
413 | IS_INETD = 1, | ||
414 | master_fd = -1, | ||
415 | portnbr = 23, | ||
416 | }; | ||
417 | #endif | ||
418 | enum { | ||
419 | OPT_PORT = 4 * ENABLE_FEATURE_TELNETD_STANDALONE, | ||
420 | OPT_FOREGROUND = 0x10 * ENABLE_FEATURE_TELNETD_STANDALONE, | ||
421 | OPT_INETD = 0x20 * ENABLE_FEATURE_TELNETD_STANDALONE, | ||
422 | }; | ||
454 | 423 | ||
455 | #ifndef CONFIG_FEATURE_TELNETD_INETD | 424 | opt = getopt32(argc, argv, "f:l:" USE_FEATURE_TELNETD_STANDALONE("p:b:Fi"), |
425 | &issuefile, &loginpath | ||
426 | USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)); | ||
427 | /* Redirect log to syslog early, if needed */ | ||
428 | if (IS_INETD || !(opt & OPT_FOREGROUND)) { | ||
429 | openlog(applet_name, 0, LOG_USER); | ||
430 | logmode = LOGMODE_SYSLOG; | ||
431 | } | ||
432 | //if (opt & 1) // -f | ||
433 | //if (opt & 2) // -l | ||
434 | USE_FEATURE_TELNETD_STANDALONE( | ||
435 | if (opt & OPT_PORT) // -p | ||
436 | portnbr = xatou16(opt_portnbr); | ||
437 | //if (opt & 8) // -b | ||
438 | //if (opt & 0x10) // -F | ||
439 | //if (opt & 0x20) // -i | ||
440 | ); | ||
441 | |||
442 | /* Used to check access(loginpath, X_OK) here. Pointless. | ||
443 | * exec will do this for us for free later. */ | ||
444 | argv_init[0] = loginpath; | ||
445 | |||
446 | #if ENABLE_FEATURE_TELNETD_STANDALONE | ||
447 | if (IS_INETD) { | ||
448 | sessions = make_new_session(0, 1); | ||
449 | } else { | ||
450 | master_fd = create_socket(portnbr, opt_bindaddr); | ||
451 | if (!(opt & OPT_FOREGROUND)) | ||
452 | xdaemon(0, 0); | ||
453 | } | ||
454 | #else | ||
455 | sessions = make_new_session(); | ||
456 | #endif | ||
457 | |||
458 | /* We don't want to die if just one session is broken */ | ||
459 | signal(SIGPIPE, SIG_IGN); | ||
460 | |||
461 | again: | ||
462 | FD_ZERO(&rdfdset); | ||
463 | FD_ZERO(&wrfdset); | ||
464 | if (!IS_INETD) { | ||
456 | FD_SET(master_fd, &rdfdset); | 465 | FD_SET(master_fd, &rdfdset); |
457 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | 466 | /* This is needed because free_session() does not |
458 | 467 | * take into account master_fd when it finds new | |
459 | ts = sessions; | 468 | * maxfd among remaining fd's: */ |
460 | #ifndef CONFIG_FEATURE_TELNETD_INETD | 469 | if (master_fd > maxfd) |
461 | while (ts) { | 470 | maxfd = master_fd; |
462 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | 471 | } |
463 | /* buf1 is used from socket to pty | ||
464 | * buf2 is used from pty to socket | ||
465 | */ | ||
466 | if (ts->size1 > 0) { | ||
467 | FD_SET(ts->ptyfd, &wrfdset); /* can write to pty */ | ||
468 | } | ||
469 | if (ts->size1 < BUFSIZE) { | ||
470 | #ifdef CONFIG_FEATURE_TELNETD_INETD | ||
471 | FD_SET(ts->sockfd_read, &rdfdset); /* can read from socket */ | ||
472 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | ||
473 | FD_SET(ts->sockfd, &rdfdset); /* can read from socket */ | ||
474 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
475 | } | ||
476 | if (ts->size2 > 0) { | ||
477 | #ifdef CONFIG_FEATURE_TELNETD_INETD | ||
478 | FD_SET(ts->sockfd_write, &wrfdset); /* can write to socket */ | ||
479 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | ||
480 | FD_SET(ts->sockfd, &wrfdset); /* can write to socket */ | ||
481 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
482 | } | ||
483 | if (ts->size2 < BUFSIZE) { | ||
484 | FD_SET(ts->ptyfd, &rdfdset); /* can read from pty */ | ||
485 | } | ||
486 | #ifndef CONFIG_FEATURE_TELNETD_INETD | ||
487 | ts = ts->next; | ||
488 | } | ||
489 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
490 | 472 | ||
491 | selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0); | 473 | /* select on the master socket, all telnet sockets and their |
474 | * ptys if there is room in their session buffers. */ | ||
475 | ts = sessions; | ||
476 | while (ts) { | ||
477 | /* buf1 is used from socket to pty | ||
478 | * buf2 is used from pty to socket */ | ||
479 | if (ts->size1 > 0) /* can write to pty */ | ||
480 | FD_SET(ts->ptyfd, &wrfdset); | ||
481 | if (ts->size1 < BUFSIZE) /* can read from socket */ | ||
482 | FD_SET(ts->sockfd_read, &rdfdset); | ||
483 | if (ts->size2 > 0) /* can write to socket */ | ||
484 | FD_SET(ts->sockfd_write, &wrfdset); | ||
485 | if (ts->size2 < BUFSIZE) /* can read from pty */ | ||
486 | FD_SET(ts->ptyfd, &rdfdset); | ||
487 | ts = ts->next; | ||
488 | } | ||
492 | 489 | ||
493 | if (!selret) | 490 | selret = select(maxfd + 1, &rdfdset, &wrfdset, 0, 0); |
494 | break; | 491 | if (!selret) |
492 | return 0; | ||
495 | 493 | ||
496 | #ifndef CONFIG_FEATURE_TELNETD_INETD | 494 | #if ENABLE_FEATURE_TELNETD_STANDALONE |
497 | /* First check for and accept new sessions. */ | 495 | /* First check for and accept new sessions. */ |
498 | if (FD_ISSET(master_fd, &rdfdset)) { | 496 | if (!IS_INETD && FD_ISSET(master_fd, &rdfdset)) { |
499 | int fd; | 497 | sockaddr_type sa; |
500 | socklen_t salen; | 498 | int fd; |
499 | socklen_t salen; | ||
500 | struct tsession *new_ts; | ||
501 | |||
502 | salen = sizeof(sa); | ||
503 | fd = accept(master_fd, (struct sockaddr *)&sa, &salen); | ||
504 | if (fd < 0) | ||
505 | goto again; | ||
506 | /* Create a new session and link it into our active list */ | ||
507 | new_ts = make_new_session(fd, fd); | ||
508 | if (new_ts) { | ||
509 | new_ts->next = sessions; | ||
510 | sessions = new_ts; | ||
511 | } else { | ||
512 | close(fd); | ||
513 | } | ||
514 | } | ||
515 | #endif | ||
501 | 516 | ||
502 | salen = sizeof(sa); | 517 | /* Then check for data tunneling. */ |
503 | fd = accept(master_fd, (struct sockaddr *)&sa, &salen); | 518 | ts = sessions; |
504 | if (fd < 0) { | 519 | while (ts) { /* For all sessions... */ |
520 | struct tsession *next = ts->next; /* in case we free ts. */ | ||
521 | |||
522 | if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) { | ||
523 | int num_totty; | ||
524 | char *ptr; | ||
525 | /* Write to pty from buffer 1. */ | ||
526 | ptr = remove_iacs(ts, &num_totty); | ||
527 | w = safe_write(ts->ptyfd, ptr, num_totty); | ||
528 | /* needed? if (w < 0 && errno == EAGAIN) continue; */ | ||
529 | if (w < 0) { | ||
530 | if (IS_INETD) | ||
531 | return 0; | ||
532 | free_session(ts); | ||
533 | ts = next; | ||
505 | continue; | 534 | continue; |
506 | } else { | ||
507 | /* Create a new session and link it into | ||
508 | our active list. */ | ||
509 | struct tsession *new_ts = make_new_session(fd); | ||
510 | if (new_ts) { | ||
511 | new_ts->next = sessions; | ||
512 | sessions = new_ts; | ||
513 | if (fd > maxfd) | ||
514 | maxfd = fd; | ||
515 | } else { | ||
516 | close(fd); | ||
517 | } | ||
518 | } | 535 | } |
536 | ts->wridx1 += w; | ||
537 | ts->size1 -= w; | ||
538 | if (ts->wridx1 == BUFSIZE) | ||
539 | ts->wridx1 = 0; | ||
519 | } | 540 | } |
520 | 541 | ||
521 | /* Then check for data tunneling. */ | 542 | if (ts->size2 && FD_ISSET(ts->sockfd_write, &wrfdset)) { |
522 | 543 | /* Write to socket from buffer 2. */ | |
523 | ts = sessions; | 544 | maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2); |
524 | while (ts) { /* For all sessions... */ | 545 | w = safe_write(ts->sockfd_write, ts->buf2 + ts->wridx2, maxlen); |
525 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | 546 | /* needed? if (w < 0 && errno == EAGAIN) continue; */ |
526 | #ifndef CONFIG_FEATURE_TELNETD_INETD | 547 | if (w < 0) { |
527 | struct tsession *next = ts->next; /* in case we free ts. */ | 548 | if (IS_INETD) |
528 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | 549 | return 0; |
529 | 550 | free_session(ts); | |
530 | if (ts->size1 && FD_ISSET(ts->ptyfd, &wrfdset)) { | 551 | ts = next; |
531 | int num_totty; | 552 | continue; |
532 | char *ptr; | ||
533 | /* Write to pty from buffer 1. */ | ||
534 | |||
535 | ptr = remove_iacs(ts, &num_totty); | ||
536 | |||
537 | w = write(ts->ptyfd, ptr, num_totty); | ||
538 | if (w < 0) { | ||
539 | #ifdef CONFIG_FEATURE_TELNETD_INETD | ||
540 | exit(0); | ||
541 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | ||
542 | free_session(ts); | ||
543 | ts = next; | ||
544 | continue; | ||
545 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
546 | } | ||
547 | ts->wridx1 += w; | ||
548 | ts->size1 -= w; | ||
549 | if (ts->wridx1 == BUFSIZE) | ||
550 | ts->wridx1 = 0; | ||
551 | } | ||
552 | |||
553 | #ifdef CONFIG_FEATURE_TELNETD_INETD | ||
554 | if (ts->size2 && FD_ISSET(ts->sockfd_write, &wrfdset)) { | ||
555 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | ||
556 | if (ts->size2 && FD_ISSET(ts->sockfd, &wrfdset)) { | ||
557 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
558 | /* Write to socket from buffer 2. */ | ||
559 | maxlen = MIN(BUFSIZE - ts->wridx2, ts->size2); | ||
560 | #ifdef CONFIG_FEATURE_TELNETD_INETD | ||
561 | w = write(ts->sockfd_write, ts->buf2 + ts->wridx2, maxlen); | ||
562 | if (w < 0) | ||
563 | exit(0); | ||
564 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | ||
565 | w = write(ts->sockfd, ts->buf2 + ts->wridx2, maxlen); | ||
566 | if (w < 0) { | ||
567 | free_session(ts); | ||
568 | ts = next; | ||
569 | continue; | ||
570 | } | ||
571 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
572 | ts->wridx2 += w; | ||
573 | ts->size2 -= w; | ||
574 | if (ts->wridx2 == BUFSIZE) | ||
575 | ts->wridx2 = 0; | ||
576 | } | 553 | } |
554 | ts->wridx2 += w; | ||
555 | ts->size2 -= w; | ||
556 | if (ts->wridx2 == BUFSIZE) | ||
557 | ts->wridx2 = 0; | ||
558 | } | ||
577 | 559 | ||
578 | #ifdef CONFIG_FEATURE_TELNETD_INETD | 560 | if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd_read, &rdfdset)) { |
579 | if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd_read, &rdfdset)) { | 561 | /* Read from socket to buffer 1. */ |
580 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | 562 | maxlen = MIN(BUFSIZE - ts->rdidx1, BUFSIZE - ts->size1); |
581 | if (ts->size1 < BUFSIZE && FD_ISSET(ts->sockfd, &rdfdset)) { | 563 | r = safe_read(ts->sockfd_read, ts->buf1 + ts->rdidx1, maxlen); |
582 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | 564 | if (r < 0 && errno == EAGAIN) continue; |
583 | /* Read from socket to buffer 1. */ | 565 | if (r <= 0) { |
584 | maxlen = MIN(BUFSIZE - ts->rdidx1, | 566 | if (IS_INETD) |
585 | BUFSIZE - ts->size1); | 567 | return 0; |
586 | #ifdef CONFIG_FEATURE_TELNETD_INETD | 568 | free_session(ts); |
587 | r = read(ts->sockfd_read, ts->buf1 + ts->rdidx1, maxlen); | 569 | ts = next; |
588 | if (!r || (r < 0 && errno != EINTR)) | 570 | continue; |
589 | exit(0); | ||
590 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | ||
591 | r = read(ts->sockfd, ts->buf1 + ts->rdidx1, maxlen); | ||
592 | if (!r || (r < 0 && errno != EINTR)) { | ||
593 | free_session(ts); | ||
594 | ts = next; | ||
595 | continue; | ||
596 | } | ||
597 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
598 | if (!*(ts->buf1 + ts->rdidx1 + r - 1)) { | ||
599 | r--; | ||
600 | if (!r) | ||
601 | continue; | ||
602 | } | ||
603 | ts->rdidx1 += r; | ||
604 | ts->size1 += r; | ||
605 | if (ts->rdidx1 == BUFSIZE) | ||
606 | ts->rdidx1 = 0; | ||
607 | } | 571 | } |
608 | 572 | if (!ts->buf1[ts->rdidx1 + r - 1]) | |
609 | if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) { | 573 | if (!--r) |
610 | /* Read from pty to buffer 2. */ | ||
611 | maxlen = MIN(BUFSIZE - ts->rdidx2, | ||
612 | BUFSIZE - ts->size2); | ||
613 | r = read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen); | ||
614 | if (!r || (r < 0 && errno != EINTR)) { | ||
615 | #ifdef CONFIG_FEATURE_TELNETD_INETD | ||
616 | exit(0); | ||
617 | #else /* CONFIG_FEATURE_TELNETD_INETD */ | ||
618 | free_session(ts); | ||
619 | ts = next; | ||
620 | continue; | 574 | continue; |
621 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | 575 | ts->rdidx1 += r; |
622 | } | 576 | ts->size1 += r; |
623 | ts->rdidx2 += r; | 577 | if (ts->rdidx1 == BUFSIZE) |
624 | ts->size2 += r; | ||
625 | if (ts->rdidx2 == BUFSIZE) | ||
626 | ts->rdidx2 = 0; | ||
627 | } | ||
628 | |||
629 | if (ts->size1 == 0) { | ||
630 | ts->rdidx1 = 0; | 578 | ts->rdidx1 = 0; |
631 | ts->wridx1 = 0; | 579 | } |
580 | |||
581 | if (ts->size2 < BUFSIZE && FD_ISSET(ts->ptyfd, &rdfdset)) { | ||
582 | /* Read from pty to buffer 2. */ | ||
583 | maxlen = MIN(BUFSIZE - ts->rdidx2, BUFSIZE - ts->size2); | ||
584 | r = safe_read(ts->ptyfd, ts->buf2 + ts->rdidx2, maxlen); | ||
585 | if (r < 0 && errno == EAGAIN) continue; | ||
586 | if (r <= 0) { | ||
587 | if (IS_INETD) | ||
588 | return 0; | ||
589 | free_session(ts); | ||
590 | ts = next; | ||
591 | continue; | ||
632 | } | 592 | } |
633 | if (ts->size2 == 0) { | 593 | ts->rdidx2 += r; |
594 | ts->size2 += r; | ||
595 | if (ts->rdidx2 == BUFSIZE) | ||
634 | ts->rdidx2 = 0; | 596 | ts->rdidx2 = 0; |
635 | ts->wridx2 = 0; | ||
636 | } | ||
637 | #ifndef CONFIG_FEATURE_TELNETD_INETD | ||
638 | ts = next; | ||
639 | } | 597 | } |
640 | #endif /* CONFIG_FEATURE_TELNETD_INETD */ | ||
641 | |||
642 | } /* while(1) */ | ||
643 | 598 | ||
644 | return 0; | 599 | if (ts->size1 == 0) { |
600 | ts->rdidx1 = 0; | ||
601 | ts->wridx1 = 0; | ||
602 | } | ||
603 | if (ts->size2 == 0) { | ||
604 | ts->rdidx2 = 0; | ||
605 | ts->wridx2 = 0; | ||
606 | } | ||
607 | ts = next; | ||
608 | } | ||
609 | goto again; | ||
645 | } | 610 | } |
diff --git a/runit/runit_lib.c b/runit/runit_lib.c index c95d641f1..5ebbc5840 100644 --- a/runit/runit_lib.c +++ b/runit/runit_lib.c | |||
@@ -34,10 +34,6 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
34 | #include "libbb.h" | 34 | #include "libbb.h" |
35 | #include "runit_lib.h" | 35 | #include "runit_lib.h" |
36 | 36 | ||
37 | #ifndef O_NONBLOCK | ||
38 | #define O_NONBLOCK O_NDELAY | ||
39 | #endif | ||
40 | |||
41 | /*** buffer.c ***/ | 37 | /*** buffer.c ***/ |
42 | 38 | ||
43 | void buffer_init(buffer *s,int (*op)(int fd,char *buf,unsigned len),int fd,char *buf,unsigned len) | 39 | void buffer_init(buffer *s,int (*op)(int fd,char *buf,unsigned len),int fd,char *buf,unsigned len) |
@@ -625,22 +621,6 @@ int lock_exnb(int fd) | |||
625 | } | 621 | } |
626 | 622 | ||
627 | 623 | ||
628 | /*** ndelay_off.c ***/ | ||
629 | |||
630 | int ndelay_off(int fd) | ||
631 | { | ||
632 | return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) & ~O_NONBLOCK); | ||
633 | } | ||
634 | |||
635 | |||
636 | /*** ndelay_on.c ***/ | ||
637 | |||
638 | int ndelay_on(int fd) | ||
639 | { | ||
640 | return fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK); | ||
641 | } | ||
642 | |||
643 | |||
644 | /*** open_append.c ***/ | 624 | /*** open_append.c ***/ |
645 | 625 | ||
646 | int open_append(const char *fn) | 626 | int open_append(const char *fn) |
diff --git a/scripts/defconfig b/scripts/defconfig index 11361dc42..102c21a5f 100644 --- a/scripts/defconfig +++ b/scripts/defconfig | |||
@@ -560,7 +560,6 @@ CONFIG_TELNET=y | |||
560 | CONFIG_FEATURE_TELNET_TTYPE=y | 560 | CONFIG_FEATURE_TELNET_TTYPE=y |
561 | CONFIG_FEATURE_TELNET_AUTOLOGIN=y | 561 | CONFIG_FEATURE_TELNET_AUTOLOGIN=y |
562 | CONFIG_TELNETD=y | 562 | CONFIG_TELNETD=y |
563 | CONFIG_FEATURE_TELNETD_INETD=y | ||
564 | CONFIG_TFTP=y | 563 | CONFIG_TFTP=y |
565 | CONFIG_FEATURE_TFTP_GET=y | 564 | CONFIG_FEATURE_TFTP_GET=y |
566 | CONFIG_FEATURE_TFTP_PUT=y | 565 | CONFIG_FEATURE_TFTP_PUT=y |