@@ -100,6 +100,7 @@ typedef int mode_t;
100
100
#else
101
101
#include < pthread.h>
102
102
#include < sys/resource.h> // getrlimit, setrlimit
103
+ #include < termios.h> // tcgetattr, tcsetattr
103
104
#include < unistd.h> // setuid, getuid
104
105
#endif
105
106
@@ -172,6 +173,9 @@ using v8::Value;
172
173
static Mutex process_mutex;
173
174
static Mutex environ_mutex;
174
175
176
+ // Safe to call more than once and from signal handlers.
177
+ inline void PlatformExit ();
178
+
175
179
static bool print_eval = false ;
176
180
static bool force_repl = false ;
177
181
static bool syntax_check_only = false ;
@@ -1091,7 +1095,7 @@ void AppendExceptionLine(Environment* env,
1091
1095
Mutex::ScopedLock lock (process_mutex);
1092
1096
env->set_printed_error (true );
1093
1097
1094
- uv_tty_reset_mode ();
1098
+ PlatformExit ();
1095
1099
PrintErrorString (" \n %s" , arrow);
1096
1100
return ;
1097
1101
}
@@ -3025,7 +3029,7 @@ void SetupProcessObject(Environment* env,
3025
3029
3026
3030
3027
3031
void SignalExit (int signo) {
3028
- uv_tty_reset_mode ();
3032
+ PlatformExit ();
3029
3033
v8_platform.StopTracingAgent ();
3030
3034
#ifdef __FreeBSD__
3031
3035
// FreeBSD has a nasty bug, see RegisterSignalHandler for details
@@ -3846,6 +3850,27 @@ static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
3846
3850
}
3847
3851
3848
3852
3853
+ #ifdef __POSIX__
3854
+ static struct {
3855
+ int flags;
3856
+ bool isatty;
3857
+ struct stat stat;
3858
+ struct termios termios;
3859
+ } stdio[1 + STDERR_FILENO];
3860
+
3861
+
3862
+ inline int GetFileDescriptorFlags (int fd) {
3863
+ int flags;
3864
+
3865
+ do {
3866
+ flags = fcntl (fd, F_GETFL);
3867
+ } while (flags == -1 && errno == EINTR);
3868
+
3869
+ return flags;
3870
+ }
3871
+ #endif // __POSIX__
3872
+
3873
+
3849
3874
inline void PlatformInit () {
3850
3875
#ifdef __POSIX__
3851
3876
#if HAVE_INSPECTOR
@@ -3856,16 +3881,18 @@ inline void PlatformInit() {
3856
3881
#endif // HAVE_INSPECTOR
3857
3882
3858
3883
// Make sure file descriptors 0-2 are valid before we start logging anything.
3859
- for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1 ) {
3860
- struct stat ignored ;
3861
- if (fstat (fd, &ignored ) == 0 )
3884
+ for (auto & s : stdio ) {
3885
+ const int fd = &s - stdio ;
3886
+ if (fstat (fd, &s. stat ) == 0 )
3862
3887
continue ;
3863
3888
// Anything but EBADF means something is seriously wrong. We don't
3864
3889
// have to special-case EINTR, fstat() is not interruptible.
3865
3890
if (errno != EBADF)
3866
3891
ABORT ();
3867
3892
if (fd != open (" /dev/null" , O_RDWR))
3868
3893
ABORT ();
3894
+ if (fstat (fd, &s.stat ) != 0 )
3895
+ ABORT ();
3869
3896
}
3870
3897
3871
3898
#if HAVE_INSPECTOR
@@ -3888,6 +3915,24 @@ inline void PlatformInit() {
3888
3915
}
3889
3916
#endif // !NODE_SHARED_MODE
3890
3917
3918
+ // Record the state of the stdio file descriptors so we can restore it
3919
+ // on exit. Needs to happen before installing signal handlers because
3920
+ // they make use of that information.
3921
+ for (auto & s : stdio) {
3922
+ const int fd = &s - stdio;
3923
+ int err;
3924
+
3925
+ s.flags = GetFileDescriptorFlags (fd);
3926
+ CHECK_NE (s.flags , -1 );
3927
+
3928
+ if (!isatty (fd)) continue ;
3929
+ s.isatty = true ;
3930
+ do {
3931
+ err = tcgetattr (fd, &s.termios );
3932
+ } while (err == -1 && errno == EINTR);
3933
+ CHECK_EQ (err, 0 );
3934
+ }
3935
+
3891
3936
RegisterSignalHandler (SIGINT, SignalExit, true );
3892
3937
RegisterSignalHandler (SIGTERM, SignalExit, true );
3893
3938
@@ -3928,6 +3973,49 @@ inline void PlatformInit() {
3928
3973
}
3929
3974
3930
3975
3976
+ // This function must be safe to call more than once and from signal handlers.
3977
+ inline void PlatformExit () {
3978
+ #ifdef __POSIX__
3979
+ for (auto & s : stdio) {
3980
+ const int fd = &s - stdio;
3981
+
3982
+ struct stat tmp;
3983
+ if (-1 == fstat (fd, &tmp)) {
3984
+ CHECK_EQ (errno, EBADF); // Program closed file descriptor.
3985
+ continue ;
3986
+ }
3987
+
3988
+ bool is_same_file =
3989
+ (s.stat .st_dev == tmp.st_dev && s.stat .st_ino == tmp.st_ino );
3990
+ if (!is_same_file) continue ; // Program reopened file descriptor.
3991
+
3992
+ int flags = GetFileDescriptorFlags (fd);
3993
+ CHECK_NE (flags, -1 );
3994
+
3995
+ // Restore the O_NONBLOCK flag if it changed.
3996
+ if (O_NONBLOCK & (flags ^ s.flags )) {
3997
+ flags &= ~O_NONBLOCK;
3998
+ flags |= s.flags & O_NONBLOCK;
3999
+
4000
+ int err;
4001
+ do {
4002
+ err = fcntl (fd, F_SETFL, flags);
4003
+ } while (err == -1 && errno == EINTR);
4004
+ CHECK_NE (err, -1 );
4005
+ }
4006
+
4007
+ if (s.isatty ) {
4008
+ int err;
4009
+ do {
4010
+ err = tcsetattr (fd, TCSANOW, &s.termios );
4011
+ } while (err == -1 && errno == EINTR);
4012
+ CHECK_NE (err, -1 );
4013
+ }
4014
+ }
4015
+ #endif // __POSIX__
4016
+ }
4017
+
4018
+
3931
4019
void ProcessArgv (int * argc,
3932
4020
const char ** argv,
3933
4021
int * exec_argc,
@@ -4392,7 +4480,7 @@ inline int Start(uv_loop_t* event_loop,
4392
4480
}
4393
4481
4394
4482
int Start (int argc, char ** argv) {
4395
- atexit ([] () { uv_tty_reset_mode (); });
4483
+ atexit ([] () { PlatformExit (); });
4396
4484
PlatformInit ();
4397
4485
performance::performance_node_start = PERFORMANCE_NOW ();
4398
4486
0 commit comments