diff options
author | Damien Miller <djm@mindrot.org> | 2007-01-29 10:16:28 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2007-01-29 10:16:28 +1100 |
commit | e42bd24b22bdce7e58b517d0b797d1d66bbec52b (patch) | |
tree | eade7b9ec5316bd757b75711e9aeaa37b50474ba | |
parent | 07877ca68066593473fbe29dd309dcdc61b6d629 (diff) |
- (djm) [channels.c serverloop.c] Fix so-called "hang on exit" (bz #52)
when closing a tty session when a background process still holds tty
fds open. Great detective work and patch by Marc Aurele La France,
slightly tweaked by me; ok dtucker@
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | channels.c | 10 | ||||
-rw-r--r-- | serverloop.c | 20 |
3 files changed, 29 insertions, 9 deletions
@@ -1,3 +1,9 @@ | |||
1 | 20070128 | ||
2 | - (djm) [channels.c serverloop.c] Fix so-called "hang on exit" (bz #52) | ||
3 | when closing a tty session when a background process still holds tty | ||
4 | fds open. Great detective work and patch by Marc Aurele La France, | ||
5 | slightly tweaked by me; ok dtucker@ | ||
6 | |||
1 | 20070123 | 7 | 20070123 |
2 | - (dtucker) [openbsd-compat/bsd-snprintf.c] Static declarations for public | 8 | - (dtucker) [openbsd-compat/bsd-snprintf.c] Static declarations for public |
3 | library interfaces aren't very helpful. Fix up the DOPR_OUTCH macro | 9 | library interfaces aren't very helpful. Fix up the DOPR_OUTCH macro |
@@ -2686,4 +2692,4 @@ | |||
2686 | OpenServer 6 and add osr5bigcrypt support so when someone migrates | 2692 | OpenServer 6 and add osr5bigcrypt support so when someone migrates |
2687 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ | 2693 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ |
2688 | 2694 | ||
2689 | $Id: ChangeLog,v 1.4608 2007/01/23 13:07:29 dtucker Exp $ | 2695 | $Id: ChangeLog,v 1.4609 2007/01/28 23:16:28 djm Exp $ |
diff --git a/channels.c b/channels.c index 9d522a6c3..c68ad6419 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1449,10 +1449,11 @@ channel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset) | |||
1449 | int len; | 1449 | int len; |
1450 | 1450 | ||
1451 | if (c->rfd != -1 && | 1451 | if (c->rfd != -1 && |
1452 | FD_ISSET(c->rfd, readset)) { | 1452 | (c->detach_close || FD_ISSET(c->rfd, readset))) { |
1453 | errno = 0; | 1453 | errno = 0; |
1454 | len = read(c->rfd, buf, sizeof(buf)); | 1454 | len = read(c->rfd, buf, sizeof(buf)); |
1455 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | 1455 | if (len < 0 && (errno == EINTR || |
1456 | (errno == EAGAIN && !(c->isatty && c->detach_close)))) | ||
1456 | return 1; | 1457 | return 1; |
1457 | #ifndef PTY_ZEROREAD | 1458 | #ifndef PTY_ZEROREAD |
1458 | if (len <= 0) { | 1459 | if (len <= 0) { |
@@ -1604,11 +1605,12 @@ channel_handle_efd(Channel *c, fd_set *readset, fd_set *writeset) | |||
1604 | c->local_consumed += len; | 1605 | c->local_consumed += len; |
1605 | } | 1606 | } |
1606 | } else if (c->extended_usage == CHAN_EXTENDED_READ && | 1607 | } else if (c->extended_usage == CHAN_EXTENDED_READ && |
1607 | FD_ISSET(c->efd, readset)) { | 1608 | (c->detach_close || FD_ISSET(c->efd, readset))) { |
1608 | len = read(c->efd, buf, sizeof(buf)); | 1609 | len = read(c->efd, buf, sizeof(buf)); |
1609 | debug2("channel %d: read %d from efd %d", | 1610 | debug2("channel %d: read %d from efd %d", |
1610 | c->self, len, c->efd); | 1611 | c->self, len, c->efd); |
1611 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) | 1612 | if (len < 0 && (errno == EINTR || |
1613 | (errno == EAGAIN && !c->detach_close))) | ||
1612 | return 1; | 1614 | return 1; |
1613 | if (len <= 0) { | 1615 | if (len <= 0) { |
1614 | debug2("channel %d: closing read-efd %d", | 1616 | debug2("channel %d: closing read-efd %d", |
diff --git a/serverloop.c b/serverloop.c index 69304b5fa..7e373f01b 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -280,6 +280,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
280 | struct timeval tv, *tvp; | 280 | struct timeval tv, *tvp; |
281 | int ret; | 281 | int ret; |
282 | int client_alive_scheduled = 0; | 282 | int client_alive_scheduled = 0; |
283 | int program_alive_scheduled = 0; | ||
283 | 284 | ||
284 | /* | 285 | /* |
285 | * if using client_alive, set the max timeout accordingly, | 286 | * if using client_alive, set the max timeout accordingly, |
@@ -317,6 +318,7 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
317 | * the client, try to get some more data from the program. | 318 | * the client, try to get some more data from the program. |
318 | */ | 319 | */ |
319 | if (packet_not_very_much_data_to_write()) { | 320 | if (packet_not_very_much_data_to_write()) { |
321 | program_alive_scheduled = child_terminated; | ||
320 | if (!fdout_eof) | 322 | if (!fdout_eof) |
321 | FD_SET(fdout, *readsetp); | 323 | FD_SET(fdout, *readsetp); |
322 | if (!fderr_eof) | 324 | if (!fderr_eof) |
@@ -362,8 +364,16 @@ wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, | |||
362 | memset(*writesetp, 0, *nallocp); | 364 | memset(*writesetp, 0, *nallocp); |
363 | if (errno != EINTR) | 365 | if (errno != EINTR) |
364 | error("select: %.100s", strerror(errno)); | 366 | error("select: %.100s", strerror(errno)); |
365 | } else if (ret == 0 && client_alive_scheduled) | 367 | } else { |
366 | client_alive_check(); | 368 | if (ret == 0 && client_alive_scheduled) |
369 | client_alive_check(); | ||
370 | if (!compat20 && program_alive_scheduled && fdin_is_tty) { | ||
371 | if (!fdout_eof) | ||
372 | FD_SET(fdout, *readsetp); | ||
373 | if (!fderr_eof) | ||
374 | FD_SET(fderr, *readsetp); | ||
375 | } | ||
376 | } | ||
367 | 377 | ||
368 | notify_done(*readsetp); | 378 | notify_done(*readsetp); |
369 | } | 379 | } |
@@ -407,7 +417,8 @@ process_input(fd_set *readset) | |||
407 | if (!fdout_eof && FD_ISSET(fdout, readset)) { | 417 | if (!fdout_eof && FD_ISSET(fdout, readset)) { |
408 | errno = 0; | 418 | errno = 0; |
409 | len = read(fdout, buf, sizeof(buf)); | 419 | len = read(fdout, buf, sizeof(buf)); |
410 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) { | 420 | if (len < 0 && (errno == EINTR || |
421 | (errno == EAGAIN && !child_terminated))) { | ||
411 | /* do nothing */ | 422 | /* do nothing */ |
412 | #ifndef PTY_ZEROREAD | 423 | #ifndef PTY_ZEROREAD |
413 | } else if (len <= 0) { | 424 | } else if (len <= 0) { |
@@ -425,7 +436,8 @@ process_input(fd_set *readset) | |||
425 | if (!fderr_eof && FD_ISSET(fderr, readset)) { | 436 | if (!fderr_eof && FD_ISSET(fderr, readset)) { |
426 | errno = 0; | 437 | errno = 0; |
427 | len = read(fderr, buf, sizeof(buf)); | 438 | len = read(fderr, buf, sizeof(buf)); |
428 | if (len < 0 && (errno == EINTR || errno == EAGAIN)) { | 439 | if (len < 0 && (errno == EINTR || |
440 | (errno == EAGAIN && !child_terminated))) { | ||
429 | /* do nothing */ | 441 | /* do nothing */ |
430 | #ifndef PTY_ZEROREAD | 442 | #ifndef PTY_ZEROREAD |
431 | } else if (len <= 0) { | 443 | } else if (len <= 0) { |