13
13
#include " tools.h"
14
14
#include " flang/Runtime/descriptor.h"
15
15
#include < cstdlib>
16
+ #include < errno.h>
16
17
#include < future>
17
18
#include < limits>
19
+
18
20
#ifdef _WIN32
19
21
#include " flang/Common/windows-include.h"
20
22
#else
@@ -32,13 +34,16 @@ namespace Fortran::runtime {
32
34
// and the processor does not support asynchronous execution. Otherwise it is
33
35
// assigned the value 0
34
36
enum CMD_STAT {
35
- ASYNC_NO_SUPPORT_ERR = -2 ,
36
- NO_SUPPORT_ERR = -1 ,
37
- CMD_EXECUTED = 0 ,
38
- FORK_ERR = 1 ,
39
- EXECL_ERR = 2 ,
40
- INVALID_CL_ERR = 3 ,
41
- SIGNAL_ERR = 4
37
+ ASYNC_NO_SUPPORT_ERR = -2 , // system returns -1 with ENOENT
38
+ NO_SUPPORT_ERR = -1 , // Linux setsid() returns -1
39
+ CMD_EXECUTED = 0 , // command executed with no error
40
+ FORK_ERR = 1 , // Linux fork() returns < 0
41
+ EXECL_ERR = 2 , // system returns -1 with other errno
42
+ COMMAND_EXECUTION_ERR = 3 , // exit code 1
43
+ COMMAND_CANNOT_EXECUTE_ERR = 4 , // Linux exit code 126
44
+ COMMAND_NOT_FOUND_ERR = 5 , // Linux exit code 127
45
+ INVALID_CL_ERR = 6 , // cover all other non-zero exit code
46
+ SIGNAL_ERR = 7
42
47
};
43
48
44
49
// Override CopyCharsToDescriptor in tools.h, pass string directly
@@ -62,24 +67,86 @@ void CheckAndStoreIntToDescriptor(
62
67
63
68
// If a condition occurs that would assign a nonzero value to CMDSTAT but
64
69
// the CMDSTAT variable is not present, error termination is initiated.
65
- int TerminationCheck (int status, const Descriptor *cmdstat,
70
+ std:: int64_t TerminationCheck (std:: int64_t status, const Descriptor *cmdstat,
66
71
const Descriptor *cmdmsg, Terminator &terminator) {
72
+ // On both Windows and Linux, errno is set when system returns -1.
67
73
if (status == -1 ) {
68
- if (!cmdstat) {
69
- terminator.Crash (" Execution error with system status code: %d" , status);
74
+ // On Windows, ENOENT means the command interpreter can't be found.
75
+ // On Linux, system calls execl with filepath "/bin/sh", ENOENT means the
76
+ // file pathname does not exist.
77
+ if (errno == ENOENT) {
78
+ if (!cmdstat) {
79
+ terminator.Crash (" Command line execution is not supported, system "
80
+ " returns -1 with errno ENOENT." );
81
+ } else {
82
+ StoreIntToDescriptor (cmdstat, NO_SUPPORT_ERR, terminator);
83
+ CheckAndCopyCharsToDescriptor (cmdmsg,
84
+ " Command line execution is not supported, system returns -1 with "
85
+ " errno ENOENT." );
86
+ }
70
87
} else {
71
- StoreIntToDescriptor (cmdstat, EXECL_ERR, terminator);
72
- CheckAndCopyCharsToDescriptor (cmdmsg, " Execution error" );
88
+ char err_buffer[30 ];
89
+ char msg[]{" Execution error with system status code: -1, errno: " };
90
+ #ifdef _WIN32
91
+ if (strerror_s (err_buffer, sizeof (err_buffer), errno) != 0 )
92
+ #else
93
+ if (strerror_r (errno, err_buffer, sizeof (err_buffer)) != 0 )
94
+ #endif
95
+ terminator.Crash (" errno to char msg failed." );
96
+ char *newMsg{static_cast <char *>(AllocateMemoryOrCrash (
97
+ terminator, std::strlen (msg) + std::strlen (err_buffer) + 1 ))};
98
+ std::strcat (newMsg, err_buffer);
99
+
100
+ if (!cmdstat) {
101
+ terminator.Crash (newMsg);
102
+ } else {
103
+ StoreIntToDescriptor (cmdstat, EXECL_ERR, terminator);
104
+ CheckAndCopyCharsToDescriptor (cmdmsg, newMsg);
105
+ }
106
+ FreeMemory (newMsg);
73
107
}
74
108
}
109
+
75
110
#ifdef _WIN32
76
111
// On WIN32 API std::system returns exit status directly
77
- int exitStatusVal{status};
78
- if (exitStatusVal == 1 ) {
112
+ std::int64_t exitStatusVal{status};
113
+ if (exitStatusVal != 0 ) {
114
+ if (!cmdstat) {
115
+ terminator.Crash (
116
+ " Invalid command quit with exit status code: %d" , exitStatusVal);
117
+ } else {
118
+ StoreIntToDescriptor (cmdstat, INVALID_CL_ERR, terminator);
119
+ CheckAndCopyCharsToDescriptor (cmdmsg, " Invalid command line" );
120
+ }
121
+ }
79
122
#else
80
- int exitStatusVal{WEXITSTATUS (status)};
81
- if (exitStatusVal == 127 || exitStatusVal == 126 ) {
82
- #endif
123
+ std::int64_t exitStatusVal{WEXITSTATUS (status)};
124
+ if (exitStatusVal == 1 ) {
125
+ if (!cmdstat) {
126
+ terminator.Crash (" Command line execution failed with exit code: 1." );
127
+ } else {
128
+ StoreIntToDescriptor (cmdstat, COMMAND_EXECUTION_ERR, terminator);
129
+ CheckAndCopyCharsToDescriptor (
130
+ cmdmsg, " Command line execution failed with exit code: 1." );
131
+ }
132
+ } else if (exitStatusVal == 126 ) {
133
+ if (!cmdstat) {
134
+ terminator.Crash (" Command cannot be executed with exit code: 126." );
135
+ } else {
136
+ StoreIntToDescriptor (cmdstat, COMMAND_CANNOT_EXECUTE_ERR, terminator);
137
+ CheckAndCopyCharsToDescriptor (
138
+ cmdmsg, " Command cannot be executed with exit code: 126." );
139
+ }
140
+ } else if (exitStatusVal == 127 ) {
141
+ if (!cmdstat) {
142
+ terminator.Crash (" Command not found with exit code: 127." );
143
+ } else {
144
+ StoreIntToDescriptor (cmdstat, COMMAND_NOT_FOUND_ERR, terminator);
145
+ CheckAndCopyCharsToDescriptor (
146
+ cmdmsg, " Command not found with exit code: 127." );
147
+ }
148
+ // capture all other nonzero exit code
149
+ } else if (exitStatusVal != 0 ) {
83
150
if (!cmdstat) {
84
151
terminator.Crash (
85
152
" Invalid command quit with exit status code: %d" , exitStatusVal);
@@ -88,23 +155,26 @@ int TerminationCheck(int status, const Descriptor *cmdstat,
88
155
CheckAndCopyCharsToDescriptor (cmdmsg, " Invalid command line" );
89
156
}
90
157
}
158
+ #endif
159
+
91
160
#if defined(WIFSIGNALED) && defined(WTERMSIG)
92
161
if (WIFSIGNALED (status)) {
93
162
if (!cmdstat) {
94
- terminator.Crash (" killed by signal: %d" , WTERMSIG (status));
163
+ terminator.Crash (" Killed by signal: %d" , WTERMSIG (status));
95
164
} else {
96
165
StoreIntToDescriptor (cmdstat, SIGNAL_ERR, terminator);
97
- CheckAndCopyCharsToDescriptor (cmdmsg, " killed by signal" );
166
+ CheckAndCopyCharsToDescriptor (cmdmsg, " Killed by signal" );
98
167
}
99
168
}
100
169
#endif
170
+
101
171
#if defined(WIFSTOPPED) && defined(WSTOPSIG)
102
172
if (WIFSTOPPED (status)) {
103
173
if (!cmdstat) {
104
- terminator.Crash (" stopped by signal: %d" , WSTOPSIG (status));
174
+ terminator.Crash (" Stopped by signal: %d" , WSTOPSIG (status));
105
175
} else {
106
176
StoreIntToDescriptor (cmdstat, SIGNAL_ERR, terminator);
107
- CheckAndCopyCharsToDescriptor (cmdmsg, " stopped by signal" );
177
+ CheckAndCopyCharsToDescriptor (cmdmsg, " Stopped by signal" );
108
178
}
109
179
}
110
180
#endif
@@ -134,8 +204,9 @@ void RTNAME(ExecuteCommandLine)(const Descriptor &command, bool wait,
134
204
135
205
if (wait) {
136
206
// either wait is not specified or wait is true: synchronous mode
137
- int status{std::system (newCmd)};
138
- int exitStatusVal{TerminationCheck (status, cmdstat, cmdmsg, terminator)};
207
+ std::int64_t status{std::system (newCmd)};
208
+ std::int64_t exitStatusVal{
209
+ TerminationCheck (status, cmdstat, cmdmsg, terminator)};
139
210
// If sync, assigned processor-dependent exit status. Otherwise unchanged
140
211
CheckAndStoreIntToDescriptor (exitstat, exitStatusVal, terminator);
141
212
} else {
@@ -173,7 +244,7 @@ void RTNAME(ExecuteCommandLine)(const Descriptor &command, bool wait,
173
244
terminator.Crash (
174
245
" CreateProcess failed with error code: %lu." , GetLastError ());
175
246
} else {
176
- StoreIntToDescriptor (cmdstat, ( uint32_t ) GetLastError () , terminator);
247
+ StoreIntToDescriptor (cmdstat, ASYNC_NO_SUPPORT_ERR , terminator);
177
248
CheckAndCopyCharsToDescriptor (cmdmsg, " CreateProcess failed." );
178
249
}
179
250
}
@@ -201,7 +272,7 @@ void RTNAME(ExecuteCommandLine)(const Descriptor &command, bool wait,
201
272
}
202
273
exit (EXIT_FAILURE);
203
274
}
204
- int status{std::system (newCmd)};
275
+ std:: int64_t status{std::system (newCmd)};
205
276
TerminationCheck (status, cmdstat, cmdmsg, terminator);
206
277
exit (status);
207
278
}
0 commit comments