]> git.ipfire.org Git - thirdparty/gcc.git/blame - libgfortran/intrinsics/execute_command_line.c
Darwin, libsanitizer : Support libsanitizer for x86_64-darwin20.
[thirdparty/gcc.git] / libgfortran / intrinsics / execute_command_line.c
CommitLineData
c14c8155 1/* Implementation of the EXECUTE_COMMAND_LINE intrinsic.
8d9254fc 2 Copyright (C) 2009-2020 Free Software Foundation, Inc.
f4742991 3 Contributed by François-Xavier Coudert.
c14c8155
FXC
4
5This file is part of the GNU Fortran runtime library (libgfortran).
6
7Libgfortran is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12Libgfortran is distributed in the hope that it will be useful, but WITHOUT
13ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24<http://www.gnu.org/licenses/>. */
25
26#include "libgfortran.h"
27#include <string.h>
74544378 28
c14c8155
FXC
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_SYS_WAIT_H
33#include <sys/wait.h>
34#endif
f8886038
JB
35#ifdef HAVE_POSIX_SPAWN
36#include <spawn.h>
37extern char **environ;
38#endif
ef536b41
JB
39#if defined(HAVE_POSIX_SPAWN) || defined(HAVE_FORK)
40#include <signal.h>
41#endif
c14c8155 42
b4224aec 43enum { EXEC_SYNCHRONOUS = -2, EXEC_NOERROR = 0, EXEC_SYSTEMFAILED,
1487cca0 44 EXEC_CHILDFAILED, EXEC_INVALIDCOMMAND };
c14c8155 45static const char *cmdmsg_values[] =
b4224aec
TB
46 { "",
47 "Termination status of the command-language interpreter cannot be obtained",
1487cca0
FXC
48 "Execution of child process impossible",
49 "Invalid command line" };
c14c8155
FXC
50
51
52
53static void
54set_cmdstat (int *cmdstat, int value)
55{
56 if (cmdstat)
57 *cmdstat = value;
b4224aec 58 else if (value > EXEC_NOERROR)
1487cca0
FXC
59 {
60#define MSGLEN 200
61 char msg[MSGLEN] = "EXECUTE_COMMAND_LINE: ";
62 strncat (msg, cmdmsg_values[value], MSGLEN - strlen(msg) - 1);
f4742991 63 runtime_error ("%s", msg);
1487cca0 64 }
c14c8155
FXC
65}
66
67
ef536b41
JB
68#if defined(HAVE_WAITPID) && defined(HAVE_SIGACTION)
69static void
70sigchld_handler (int signum __attribute__((unused)))
71{
72 while (waitpid ((pid_t)(-1), NULL, WNOHANG) > 0) {}
73}
74#endif
75
c14c8155
FXC
76static void
77execute_command_line (const char *command, bool wait, int *exitstat,
78 int *cmdstat, char *cmdmsg,
79 gfc_charlen_type command_len,
80 gfc_charlen_type cmdmsg_len)
81{
82 /* Transform the Fortran string to a C string. */
581d2326 83 char *cmd = fc_strdup (command, command_len);
c14c8155
FXC
84
85 /* Flush all I/O units before executing the command. */
86 flush_all_units();
87
f8886038 88#if defined(HAVE_POSIX_SPAWN) || defined(HAVE_FORK)
c14c8155
FXC
89 if (!wait)
90 {
91 /* Asynchronous execution. */
92 pid_t pid;
93
b4224aec 94 set_cmdstat (cmdstat, EXEC_NOERROR);
c14c8155 95
ef536b41
JB
96#if defined(HAVE_SIGACTION) && defined(HAVE_WAITPID)
97 static bool sig_init_saved;
98 bool sig_init = __atomic_load_n (&sig_init_saved, __ATOMIC_RELAXED);
99 if (!sig_init)
100 {
101 struct sigaction sa;
102 sa.sa_handler = &sigchld_handler;
103 sigemptyset(&sa.sa_mask);
104 sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
105 sigaction(SIGCHLD, &sa, 0);
106 __atomic_store_n (&sig_init_saved, true, __ATOMIC_RELAXED);
107 }
108#endif
109
f8886038
JB
110#ifdef HAVE_POSIX_SPAWN
111 const char * const argv[] = {"sh", "-c", cmd, NULL};
112 if (posix_spawn (&pid, "/bin/sh", NULL, NULL,
113 (char * const* restrict) argv, environ))
b4224aec 114 set_cmdstat (cmdstat, EXEC_CHILDFAILED);
f8886038
JB
115#elif defined(HAVE_FORK)
116 if ((pid = fork()) < 0)
117 set_cmdstat (cmdstat, EXEC_CHILDFAILED);
c14c8155
FXC
118 else if (pid == 0)
119 {
120 /* Child process. */
121 int res = system (cmd);
122 _exit (WIFEXITED(res) ? WEXITSTATUS(res) : res);
123 }
f8886038 124#endif
c14c8155
FXC
125 }
126 else
127#endif
128 {
129 /* Synchronous execution. */
130 int res = system (cmd);
131
b4224aec 132 if (res == -1)
c14c8155 133 set_cmdstat (cmdstat, EXEC_SYSTEMFAILED);
f8886038 134#if !defined(HAVE_POSIX_SPAWN) && !defined(HAVE_FORK)
b4224aec
TB
135 else if (!wait)
136 set_cmdstat (cmdstat, EXEC_SYNCHRONOUS);
43b594b4 137#endif
1487cca0
FXC
138 else if (res == 127 || res == 126
139#if defined(WEXITSTATUS) && defined(WIFEXITED)
140 || (WIFEXITED(res) && WEXITSTATUS(res) == 127)
141 || (WIFEXITED(res) && WEXITSTATUS(res) == 126)
142#endif
143 )
144 /* Shell return codes 126 and 127 mean that the command line could
145 not be executed for various reasons. */
146 set_cmdstat (cmdstat, EXEC_INVALIDCOMMAND);
c14c8155 147 else
b4224aec
TB
148 set_cmdstat (cmdstat, EXEC_NOERROR);
149
150 if (res != -1)
c14c8155 151 {
c14c8155
FXC
152#if defined(WEXITSTATUS) && defined(WIFEXITED)
153 *exitstat = WIFEXITED(res) ? WEXITSTATUS(res) : res;
154#else
155 *exitstat = res;
156#endif
157 }
158 }
159
581d2326
JB
160 free (cmd);
161
c14c8155 162 /* Now copy back to the Fortran string if needed. */
3934b625
TK
163 if (cmdstat && *cmdstat > EXEC_NOERROR && cmdmsg)
164 fstrcpy (cmdmsg, cmdmsg_len, cmdmsg_values[*cmdstat],
c14c8155 165 strlen (cmdmsg_values[*cmdstat]));
c14c8155
FXC
166}
167
168
169extern void
170execute_command_line_i4 (const char *command, GFC_LOGICAL_4 *wait,
171 GFC_INTEGER_4 *exitstat, GFC_INTEGER_4 *cmdstat,
172 char *cmdmsg, gfc_charlen_type command_len,
173 gfc_charlen_type cmdmsg_len);
174export_proto(execute_command_line_i4);
175
176void
177execute_command_line_i4 (const char *command, GFC_LOGICAL_4 *wait,
178 GFC_INTEGER_4 *exitstat, GFC_INTEGER_4 *cmdstat,
179 char *cmdmsg, gfc_charlen_type command_len,
180 gfc_charlen_type cmdmsg_len)
181{
182 bool w = wait ? *wait : true;
183 int estat, estat_initial, cstat;
184
185 if (exitstat)
186 estat_initial = estat = *exitstat;
187
188 execute_command_line (command, w, &estat, cmdstat ? &cstat : NULL,
189 cmdmsg, command_len, cmdmsg_len);
190
191 if (exitstat && estat != estat_initial)
192 *exitstat = estat;
193 if (cmdstat)
194 *cmdstat = cstat;
195}
196
197
198extern void
199execute_command_line_i8 (const char *command, GFC_LOGICAL_8 *wait,
200 GFC_INTEGER_8 *exitstat, GFC_INTEGER_8 *cmdstat,
201 char *cmdmsg, gfc_charlen_type command_len,
202 gfc_charlen_type cmdmsg_len);
203export_proto(execute_command_line_i8);
204
205void
206execute_command_line_i8 (const char *command, GFC_LOGICAL_8 *wait,
207 GFC_INTEGER_8 *exitstat, GFC_INTEGER_8 *cmdstat,
208 char *cmdmsg, gfc_charlen_type command_len,
209 gfc_charlen_type cmdmsg_len)
210{
211 bool w = wait ? *wait : true;
212 int estat, estat_initial, cstat;
213
214 if (exitstat)
215 estat_initial = estat = *exitstat;
216
217 execute_command_line (command, w, &estat, cmdstat ? &cstat : NULL,
218 cmdmsg, command_len, cmdmsg_len);
219
220 if (exitstat && estat != estat_initial)
221 *exitstat = estat;
222 if (cmdstat)
223 *cmdstat = cstat;
224}