diff options
| -rw-r--r-- | src/term.c | 69 |
1 files changed, 34 insertions, 35 deletions
| @@ -652,41 +652,55 @@ static int lst_tcsetattr(lua_State *L) | |||
| 652 | #ifndef _WIN32 | 652 | #ifndef _WIN32 |
| 653 | /* | 653 | /* |
| 654 | reopen FDs for independent file descriptions. | 654 | reopen FDs for independent file descriptions. |
| 655 | fd should be either 1 or 2 (stdout or stderr) | ||
| 656 | */ | 655 | */ |
| 657 | static int reopen_fd(lua_State *L, int fd, int flags) { | 656 | static void reopen_fd(lua_State *L, int fd, int flags) { |
| 658 | char path[64]; | 657 | char path[64]; |
| 659 | int newfd = -1; | 658 | int newfd = -1; |
| 660 | 659 | ||
| 660 | if (fd != STDOUT_FILENO && fd != STDERR_FILENO) { | ||
| 661 | luaL_error(L, "Invalid file descriptor: %d. Only stdout (1) and stderr (2) are supported.", fd); | ||
| 662 | } | ||
| 663 | |||
| 664 | const char *fallback_path = (fd == STDOUT_FILENO) ? "/dev/stdout" : | ||
| 665 | (fd == STDERR_FILENO) ? "/dev/stderr" : NULL; | ||
| 666 | |||
| 661 | // If fd is a terminal, reopen its actual device (e.g. /dev/ttys003) | 667 | // If fd is a terminal, reopen its actual device (e.g. /dev/ttys003) |
| 662 | // Works on all POSIX platforms that have terminals (macOS, Linux, BSD, etc.) | 668 | // Works on all POSIX platforms that have terminals (macOS, Linux, BSD, etc.) |
| 663 | if (isatty(fd)) { | 669 | if (isatty(fd)) { |
| 664 | const char *tty = ttyname(fd); | 670 | const char *tty = ttyname(fd); |
| 665 | if (tty) { | 671 | if (tty) { |
| 666 | newfd = open(tty, flags); | 672 | newfd = open(tty, flags); |
| 667 | if (newfd >= 0) return newfd; | ||
| 668 | } | 673 | } |
| 669 | } | 674 | } |
| 670 | 675 | ||
| 671 | // For non-tty: try /dev/fd/N — POSIX-compliant and standard on macOS, Linux, BSD. | 676 | if (newfd < 0) { |
| 672 | // This gives a new file description even if the target is a file or pipe. | 677 | // For non-tty: try /dev/fd/N — POSIX-compliant and standard on macOS, Linux, BSD. |
| 673 | snprintf(path, sizeof(path), "/dev/fd/%d", fd); | 678 | // This gives a new file description even if the target is a file or pipe. |
| 674 | newfd = open(path, flags); | 679 | snprintf(path, sizeof(path), "/dev/fd/%d", fd); |
| 675 | if (newfd >= 0) return newfd; | 680 | newfd = open(path, flags); |
| 681 | } | ||
| 676 | 682 | ||
| 677 | // Fallback: for platforms/environments where /dev/fd/N doesn't exist. | 683 | if (newfd < 0) { |
| 678 | // /dev/stdout and /dev/stderr are standard on Linux, but may not create new descriptions. | 684 | // Fallback: for platforms/environments where /dev/fd/N doesn't exist. |
| 679 | const char *fallback_path = (fd == 1) ? "/dev/stdout" : | 685 | // /dev/stdout and /dev/stderr are standard on Linux, but may not create new descriptions. |
| 680 | (fd == 2) ? "/dev/stderr" : NULL; | 686 | if (fallback_path) { |
| 687 | newfd = open(fallback_path, flags); | ||
| 688 | } | ||
| 689 | } | ||
| 681 | 690 | ||
| 682 | if (fallback_path) { | 691 | if (newfd < 0) { |
| 683 | newfd = open(fallback_path, flags); | 692 | // All attempts failed — raise error with detailed info (call will not return) |
| 684 | if (newfd >= 0) return newfd; | 693 | luaL_error(L, "Failed to reopen fd %d: tried ttyname(), /dev/fd/%d, and fallback %s: %s", |
| 694 | fd, fd, fallback_path ? fallback_path : "(none)", strerror(errno)); | ||
| 685 | } | 695 | } |
| 686 | 696 | ||
| 687 | // All attempts failed — raise error with detailed info | 697 | // Replace the original fd with the new one |
| 688 | return luaL_error(L, "Failed to reopen fd %d: tried ttyname(), /dev/fd/%d, and fallback %s: %s", | 698 | if (dup2(newfd, fd) < 0) { |
| 689 | fd, fd, fallback_path ? fallback_path : "(none)", strerror(errno)); | 699 | close(newfd); |
| 700 | luaL_error(L, "dup2 failed for fd %d: %s", fd, strerror(errno)); | ||
| 701 | } | ||
| 702 | |||
| 703 | close(newfd); // Close the new fd, as dup2 has replaced the original fd with it | ||
| 690 | } | 704 | } |
| 691 | #endif | 705 | #endif |
| 692 | 706 | ||
| @@ -720,23 +734,8 @@ static int lst_detachfds(lua_State *L) { | |||
| 720 | 734 | ||
| 721 | #ifndef _WIN32 | 735 | #ifndef _WIN32 |
| 722 | // Reopen stdout and stderr with new file descriptions | 736 | // Reopen stdout and stderr with new file descriptions |
| 723 | int fd_out = reopen_fd(L, 1, O_WRONLY); | 737 | reopen_fd(L, STDOUT_FILENO, O_WRONLY); |
| 724 | int fd_err = reopen_fd(L, 2, O_WRONLY); | 738 | reopen_fd(L, STDERR_FILENO, O_WRONLY); |
| 725 | |||
| 726 | // Replace fd 1 and 2 in-place using dup2 | ||
| 727 | if (dup2(fd_out, 1) < 0) { | ||
| 728 | close(fd_out); | ||
| 729 | return luaL_error(L, "dup2 failed for stdout: %s", strerror(errno)); | ||
| 730 | } | ||
| 731 | if (dup2(fd_err, 2) < 0) { | ||
| 732 | close(fd_err); | ||
| 733 | return luaL_error(L, "dup2 failed for stderr: %s", strerror(errno)); | ||
| 734 | } | ||
| 735 | |||
| 736 | // Clean up temporary file descriptors — fd 1 and 2 now own them | ||
| 737 | close(fd_out); | ||
| 738 | close(fd_err); | ||
| 739 | |||
| 740 | #endif | 739 | #endif |
| 741 | 740 | ||
| 742 | lua_pushboolean(L, 1); | 741 | lua_pushboolean(L, 1); |
