@@ -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
@@ -173,6 +174,9 @@ using v8::Value;
173
174
static Mutex process_mutex;
174
175
static Mutex environ_mutex;
175
176
177
+ // Safe to call more than once and from signal handlers.
178
+ inline void PlatformExit ();
179
+
176
180
static bool print_eval = false ;
177
181
static bool force_repl = false ;
178
182
static bool syntax_check_only = false ;
@@ -1092,7 +1096,7 @@ void AppendExceptionLine(Environment* env,
1092
1096
Mutex::ScopedLock lock (process_mutex);
1093
1097
env->set_printed_error (true );
1094
1098
1095
- uv_tty_reset_mode ();
1099
+ PlatformExit ();
1096
1100
PrintErrorString (" \n %s" , arrow);
1097
1101
return ;
1098
1102
}
@@ -3011,7 +3015,7 @@ void SetupProcessObject(Environment* env,
3011
3015
3012
3016
3013
3017
void SignalExit (int signo) {
3014
- uv_tty_reset_mode ();
3018
+ PlatformExit ();
3015
3019
v8_platform.StopTracingAgent ();
3016
3020
#ifdef __FreeBSD__
3017
3021
// FreeBSD has a nasty bug, see RegisterSignalHandler for details
@@ -3828,6 +3832,27 @@ static void DebugEnd(const FunctionCallbackInfo<Value>& args) {
3828
3832
}
3829
3833
3830
3834
3835
+ #ifdef __POSIX__
3836
+ static struct {
3837
+ int flags;
3838
+ bool isatty;
3839
+ struct stat stat;
3840
+ struct termios termios;
3841
+ } stdio[1 + STDERR_FILENO];
3842
+
3843
+
3844
+ inline int GetFileDescriptorFlags (int fd) {
3845
+ int flags;
3846
+
3847
+ do {
3848
+ flags = fcntl (fd, F_GETFL);
3849
+ } while (flags == -1 && errno == EINTR);
3850
+
3851
+ return flags;
3852
+ }
3853
+ #endif // __POSIX__
3854
+
3855
+
3831
3856
inline void PlatformInit () {
3832
3857
#ifdef __POSIX__
3833
3858
#if HAVE_INSPECTOR
@@ -3838,16 +3863,18 @@ inline void PlatformInit() {
3838
3863
#endif // HAVE_INSPECTOR
3839
3864
3840
3865
// Make sure file descriptors 0-2 are valid before we start logging anything.
3841
- for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1 ) {
3842
- struct stat ignored ;
3843
- if (fstat (fd, &ignored ) == 0 )
3866
+ for (auto & s : stdio ) {
3867
+ const int fd = &s - stdio ;
3868
+ if (fstat (fd, &s. stat ) == 0 )
3844
3869
continue ;
3845
3870
// Anything but EBADF means something is seriously wrong. We don't
3846
3871
// have to special-case EINTR, fstat() is not interruptible.
3847
3872
if (errno != EBADF)
3848
3873
ABORT ();
3849
3874
if (fd != open (" /dev/null" , O_RDWR))
3850
3875
ABORT ();
3876
+ if (fstat (fd, &s.stat ) != 0 )
3877
+ ABORT ();
3851
3878
}
3852
3879
3853
3880
#if HAVE_INSPECTOR
@@ -3870,6 +3897,24 @@ inline void PlatformInit() {
3870
3897
}
3871
3898
#endif // !NODE_SHARED_MODE
3872
3899
3900
+ // Record the state of the stdio file descriptors so we can restore it
3901
+ // on exit. Needs to happen before installing signal handlers because
3902
+ // they make use of that information.
3903
+ for (auto & s : stdio) {
3904
+ const int fd = &s - stdio;
3905
+ int err;
3906
+
3907
+ s.flags = GetFileDescriptorFlags (fd);
3908
+ CHECK_NE (s.flags , -1 );
3909
+
3910
+ if (!isatty (fd)) continue ;
3911
+ s.isatty = true ;
3912
+ do {
3913
+ err = tcgetattr (fd, &s.termios );
3914
+ } while (err == -1 && errno == EINTR);
3915
+ CHECK_EQ (err, 0 );
3916
+ }
3917
+
3873
3918
RegisterSignalHandler (SIGINT, SignalExit, true );
3874
3919
RegisterSignalHandler (SIGTERM, SignalExit, true );
3875
3920
@@ -3910,6 +3955,49 @@ inline void PlatformInit() {
3910
3955
}
3911
3956
3912
3957
3958
+ // This function must be safe to call more than once and from signal handlers.
3959
+ inline void PlatformExit () {
3960
+ #ifdef __POSIX__
3961
+ for (auto & s : stdio) {
3962
+ const int fd = &s - stdio;
3963
+
3964
+ struct stat tmp;
3965
+ if (-1 == fstat (fd, &tmp)) {
3966
+ CHECK_EQ (errno, EBADF); // Program closed file descriptor.
3967
+ continue ;
3968
+ }
3969
+
3970
+ bool is_same_file =
3971
+ (s.stat .st_dev == tmp.st_dev && s.stat .st_ino == tmp.st_ino );
3972
+ if (!is_same_file) continue ; // Program reopened file descriptor.
3973
+
3974
+ int flags = GetFileDescriptorFlags (fd);
3975
+ CHECK_NE (flags, -1 );
3976
+
3977
+ // Restore the O_NONBLOCK flag if it changed.
3978
+ if (O_NONBLOCK & (flags ^ s.flags )) {
3979
+ flags &= ~O_NONBLOCK;
3980
+ flags |= s.flags & O_NONBLOCK;
3981
+
3982
+ int err;
3983
+ do {
3984
+ err = fcntl (fd, F_SETFL, flags);
3985
+ } while (err == -1 && errno == EINTR);
3986
+ CHECK_NE (err, -1 );
3987
+ }
3988
+
3989
+ if (s.isatty ) {
3990
+ int err;
3991
+ do {
3992
+ err = tcsetattr (fd, TCSANOW, &s.termios );
3993
+ } while (err == -1 && errno == EINTR);
3994
+ CHECK_NE (err, -1 );
3995
+ }
3996
+ }
3997
+ #endif // __POSIX__
3998
+ }
3999
+
4000
+
3913
4001
void ProcessArgv (int * argc,
3914
4002
const char ** argv,
3915
4003
int * exec_argc,
@@ -4374,7 +4462,7 @@ inline int Start(uv_loop_t* event_loop,
4374
4462
}
4375
4463
4376
4464
int Start (int argc, char ** argv) {
4377
- atexit ([] () { uv_tty_reset_mode (); });
4465
+ atexit ([] () { PlatformExit (); });
4378
4466
PlatformInit ();
4379
4467
performance::performance_node_start = PERFORMANCE_NOW ();
4380
4468
0 commit comments