aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-10-15 22:09:15 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-10-15 22:09:15 +0000
commit2450c450ab8af271521c18b3c5e8e1b3c9041838 (patch)
treee784b890030dfc060bbfe4e3b3a8cd697db48dce
parent10916c5c6b34a9268356ef5447f5de0b20089aa7 (diff)
downloadbusybox-w32-2450c450ab8af271521c18b3c5e8e1b3c9041838.tar.gz
busybox-w32-2450c450ab8af271521c18b3c5e8e1b3c9041838.tar.bz2
busybox-w32-2450c450ab8af271521c18b3c5e8e1b3c9041838.zip
telnetd: at Alexander Kriegisch <Alexander@kriegisch.name> insistence
add an option to close sessions as soon as child exits. Maybe it should be a CONFIG option. OTOH, maybe it should be always on, as it mimics, say, getty's behaviour. function old new delta handle_sigchld - 49 +49 telnetd_main 1312 1355 +43 .rodata 123429 123466 +37 packed_usage 22770 22806 +36 make_new_session 525 532 +7 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 4/0 up/down: 172/0) Total: 172 bytes text data bss dec hex filename 676285 2538 12104 690927 a8aef busybox_old 676421 2538 12104 691063 a8b77 busybox_unstripped
-rw-r--r--include/usage.h2
-rw-r--r--networking/telnetd.c99
2 files changed, 66 insertions, 35 deletions
diff --git a/include/usage.h b/include/usage.h
index 210e1f246..1e05532d5 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -3517,6 +3517,8 @@ USE_FEATURE_RUN_PARTS_FANCY("\n -l Prints names of all matching files even when
3517 "\n\nOptions:" \ 3517 "\n\nOptions:" \
3518 "\n -l LOGIN Exec LOGIN on connect" \ 3518 "\n -l LOGIN Exec LOGIN on connect" \
3519 "\n -f issue_file Display issue_file instead of /etc/issue" \ 3519 "\n -f issue_file Display issue_file instead of /etc/issue" \
3520 "\n -K Close connection as soon as login exits" \
3521 "\n (normally wait until all programs close slave pty)" \
3520 USE_FEATURE_TELNETD_STANDALONE( \ 3522 USE_FEATURE_TELNETD_STANDALONE( \
3521 "\n -p PORT Port to listen to" \ 3523 "\n -p PORT Port to listen to" \
3522 "\n -b ADDR Address to bind to" \ 3524 "\n -b ADDR Address to bind to" \
diff --git a/networking/telnetd.c b/networking/telnetd.c
index 85c2ebc44..96620d949 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -37,7 +37,7 @@
37struct tsession { 37struct tsession {
38 struct tsession *next; 38 struct tsession *next;
39 int sockfd_read, sockfd_write, ptyfd; 39 int sockfd_read, sockfd_write, ptyfd;
40 /*int shell_pid;*/ 40 int shell_pid;
41 41
42 /* two circular buffers */ 42 /* two circular buffers */
43 /*char *buf1, *buf2;*/ 43 /*char *buf1, *buf2;*/
@@ -265,7 +265,7 @@ make_new_session(
265 } 265 }
266 if (pid > 0) { 266 if (pid > 0) {
267 /* Parent */ 267 /* Parent */
268 /*ts->shell_pid = pid;*/ 268 ts->shell_pid = pid;
269 return ts; 269 return ts;
270 } 270 }
271 271
@@ -305,7 +305,8 @@ make_new_session(
305 login_argv[0] = loginpath; 305 login_argv[0] = loginpath;
306 login_argv[1] = NULL; 306 login_argv[1] = NULL;
307 execvp(loginpath, (char **)login_argv); 307 execvp(loginpath, (char **)login_argv);
308 /* Safer with vfork, and we shouldn't send this to the client anyway */ 308 /* Safer with vfork, and we shouldn't send message
309 * to remote clients anyway */
309 _exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/ 310 _exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/
310} 311}
311 312
@@ -357,6 +358,24 @@ void free_session(struct tsession *ts);
357 358
358#endif 359#endif
359 360
361static void handle_sigchld(int sig)
362{
363 pid_t pid;
364 struct tsession *ts;
365
366 pid = waitpid(-1, &sig, WNOHANG);
367 if (pid > 0) {
368 ts = sessions;
369 while (ts) {
370 if (ts->shell_pid == pid) {
371 ts->shell_pid = -1;
372 return;
373 }
374 ts = ts->next;
375 }
376 }
377}
378
360 379
361int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 380int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
362int telnetd_main(int argc, char **argv) 381int telnetd_main(int argc, char **argv)
@@ -379,29 +398,35 @@ int telnetd_main(int argc, char **argv)
379 }; 398 };
380#endif 399#endif
381 enum { 400 enum {
382 OPT_INETD = (1 << 2) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */ 401 OPT_WATCHCHILD = (1 << 2), /* -K */
383 OPT_PORT = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */ 402 OPT_INETD = (1 << 3) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -i */
384 OPT_FOREGROUND = (1 << 5) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */ 403 OPT_PORT = (1 << 4) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -p */
404 OPT_FOREGROUND = (1 << 6) * ENABLE_FEATURE_TELNETD_STANDALONE, /* -F */
385 }; 405 };
386 406
387 /* If !STANDALONE, we accept (and ignore) -i, thus people 407 /* Even if !STANDALONE, we accept (and ignore) -i, thus people
388 * don't need to guess whether it's ok to pass -i to us */ 408 * don't need to guess whether it's ok to pass -i to us */
389 opt = getopt32(argv, "f:l:i" USE_FEATURE_TELNETD_STANDALONE("p:b:F"), 409 opt = getopt32(argv, "f:l:Ki" USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
390 &issuefile, &loginpath 410 &issuefile, &loginpath
391 USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr)); 411 USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
412 if (!IS_INETD /*&& !re_execed*/) {
413 /* inform that we start in standalone mode?
414 * May be useful when people forget to give -i */
415 /*bb_error_msg("listening for connections");*/
416 if (!(opt & OPT_FOREGROUND)) {
417 /* DAEMON_CHDIR_ROOT was giving inconsistent
418 * behavior with/wthout -F, -i */
419 bb_daemonize_or_rexec(0 /*DAEMON_CHDIR_ROOT*/, argv);
420 }
421 }
392 /* Redirect log to syslog early, if needed */ 422 /* Redirect log to syslog early, if needed */
393 if (IS_INETD || !(opt & OPT_FOREGROUND)) { 423 if (IS_INETD || !(opt & OPT_FOREGROUND)) {
394 openlog(applet_name, 0, LOG_USER); 424 openlog(applet_name, 0, LOG_USER);
395 logmode = LOGMODE_SYSLOG; 425 logmode = LOGMODE_SYSLOG;
396 } 426 }
397 //if (opt & 1) // -f
398 //if (opt & 2) // -l
399 USE_FEATURE_TELNETD_STANDALONE( 427 USE_FEATURE_TELNETD_STANDALONE(
400 if (opt & OPT_PORT) // -p 428 if (opt & OPT_PORT)
401 portnbr = xatou16(opt_portnbr); 429 portnbr = xatou16(opt_portnbr);
402 //if (opt & 8) // -b
403 //if (opt & 0x10) // -F
404 //if (opt & 0x20) // -i
405 ); 430 );
406 431
407 /* Used to check access(loginpath, X_OK) here. Pointless. 432 /* Used to check access(loginpath, X_OK) here. Pointless.
@@ -413,12 +438,8 @@ int telnetd_main(int argc, char **argv)
413 if (!sessions) /* pty opening or vfork problem, exit */ 438 if (!sessions) /* pty opening or vfork problem, exit */
414 return 1; /* make_new_session prints error message */ 439 return 1; /* make_new_session prints error message */
415 } else { 440 } else {
416//vda: inform that we start in standalone mode?
417 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr); 441 master_fd = create_and_bind_stream_or_die(opt_bindaddr, portnbr);
418 xlisten(master_fd, 1); 442 xlisten(master_fd, 1);
419 if (!(opt & OPT_FOREGROUND))
420//vda: NOMMU?
421 bb_daemonize(DAEMON_CHDIR_ROOT);
422 } 443 }
423#else 444#else
424 sessions = make_new_session(); 445 sessions = make_new_session();
@@ -429,6 +450,9 @@ int telnetd_main(int argc, char **argv)
429 /* We don't want to die if just one session is broken */ 450 /* We don't want to die if just one session is broken */
430 signal(SIGPIPE, SIG_IGN); 451 signal(SIGPIPE, SIG_IGN);
431 452
453 if (opt & OPT_WATCHCHILD)
454 signal(SIGCHLD, handle_sigchld);
455
432/* 456/*
433 This is how the buffers are used. The arrows indicate the movement 457 This is how the buffers are used. The arrows indicate the movement
434 of data. 458 of data.
@@ -450,14 +474,6 @@ int telnetd_main(int argc, char **argv)
450 again: 474 again:
451 FD_ZERO(&rdfdset); 475 FD_ZERO(&rdfdset);
452 FD_ZERO(&wrfdset); 476 FD_ZERO(&wrfdset);
453 if (!IS_INETD) {
454 FD_SET(master_fd, &rdfdset);
455 /* This is needed because free_session() does not
456 * take into account master_fd when it finds new
457 * maxfd among remaining fd's: */
458 if (master_fd > maxfd)
459 maxfd = master_fd;
460 }
461 477
462 /* Select on the master socket, all telnet sockets and their 478 /* Select on the master socket, all telnet sockets and their
463 * ptys if there is room in their session buffers. 479 * ptys if there is room in their session buffers.
@@ -465,15 +481,28 @@ int telnetd_main(int argc, char **argv)
465 * before each select. Can be a problem with 500+ connections. */ 481 * before each select. Can be a problem with 500+ connections. */
466 ts = sessions; 482 ts = sessions;
467 while (ts) { 483 while (ts) {
468 if (ts->size1 > 0) /* can write to pty */ 484 struct tsession *next = ts->next; /* in case we free ts. */
469 FD_SET(ts->ptyfd, &wrfdset); 485 if (ts->shell_pid == -1) {
470 if (ts->size1 < BUFSIZE) /* can read from socket */ 486 free_session(ts);
471 FD_SET(ts->sockfd_read, &rdfdset); 487 } else {
472 if (ts->size2 > 0) /* can write to socket */ 488 if (ts->size1 > 0) /* can write to pty */
473 FD_SET(ts->sockfd_write, &wrfdset); 489 FD_SET(ts->ptyfd, &wrfdset);
474 if (ts->size2 < BUFSIZE) /* can read from pty */ 490 if (ts->size1 < BUFSIZE) /* can read from socket */
475 FD_SET(ts->ptyfd, &rdfdset); 491 FD_SET(ts->sockfd_read, &rdfdset);
476 ts = ts->next; 492 if (ts->size2 > 0) /* can write to socket */
493 FD_SET(ts->sockfd_write, &wrfdset);
494 if (ts->size2 < BUFSIZE) /* can read from pty */
495 FD_SET(ts->ptyfd, &rdfdset);
496 }
497 ts = next;
498 }
499 if (!IS_INETD) {
500 FD_SET(master_fd, &rdfdset);
501 /* This is needed because free_session() does not
502 * take into account master_fd when it finds new
503 * maxfd among remaining fd's */
504 if (master_fd > maxfd)
505 maxfd = master_fd;
477 } 506 }
478 507
479 count = select(maxfd + 1, &rdfdset, &wrfdset, NULL, NULL); 508 count = select(maxfd + 1, &rdfdset, &wrfdset, NULL, NULL);