1
//============================================================================
2
// Spawn a child process and establish a connection.
3
//============================================================================
6
This file is part of Code_Saturne, a general-purpose CFD tool.
8
Copyright (C) 1998-2011 EDF S.A.
10
This program is free software; you can redistribute it and/or modify it under
11
the terms of the GNU General Public License as published by the Free Software
12
Foundation; either version 2 of the License, or (at your option) any later
15
This program is distributed in the hope that it will be useful, but WITHOUT
16
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
20
You should have received a copy of the GNU General Public License along with
21
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22
Street, Fifth Floor, Boston, MA 02110-1301, USA.
25
#include "cs_config.h"
33
#include <sys/types.h>
38
#if defined(HAVE_POSIX_SPAWN)
44
#include "cfd_proxy_defs.h"
45
#include "cfd_proxy_comm.h"
46
#include "cfd_proxy_forward.h"
48
#include "cfd_proxy_child.h"
50
//----------------------------------------------------------------------------
55
} /* Fake brace to force back Emacs auto-indentation back to column 0 */
57
#endif /* __cplusplus */
59
//============================================================================
60
// Local structure definitions
61
//============================================================================
63
struct _cfd_proxy_child_t {
65
pid_t pid; // Child pid
66
cfd_proxy_comm_t *comm; // Associated communicator
70
//============================================================================
71
// Private Function Definitions
72
//============================================================================
74
//----------------------------------------------------------------------------
75
// Wait for child process and print status info
76
//----------------------------------------------------------------------------
79
_wait_child(cfd_proxy_child_t *child,
85
cfd_proxy_printf(_("Waiting for child process (%lu) to finish ..."),
86
(unsigned long)(child->pid));
87
cfd_proxy_printf_flush();
90
child->pid = waitpid(child->pid, &status, 0);
95
cfd_proxy_printf(_(" [error]\n"));
97
#if defined(WIFEXITED)
98
if (WIFEXITED(status))
99
cfd_proxy_printf(_("Child exited with status %d\n"),
100
WEXITSTATUS(status));
101
else if (WIFSIGNALED(status))
102
cfd_proxy_printf(_("Child killed by signal %d\n"), WTERMSIG(status));
103
else if (WIFSTOPPED(status))
104
cfd_proxy_printf(_("Child stopped by signal %d\n"), WSTOPSIG(status));
106
cfd_proxy_printf(_("Child exited or killed with status %d\n"), status);
108
cfd_proxy_printf_flush();
111
cfd_proxy_printf(_(" [ok]\n"));
113
cfd_proxy_printf_flush();
118
//============================================================================
119
// Public Function Definitions
120
//============================================================================
122
//----------------------------------------------------------------------------
123
// Spawn a child process and establish a connection
126
// child process handle in case of success, NULL in case of error.
127
//----------------------------------------------------------------------------
130
cfd_proxy_child_start(const char *path,
131
char *const argv[restrict],
132
char *const envp[restrict],
133
cfd_proxy_comm_type_t comm_type,
139
cfd_proxy_child_t *child = NULL;
140
char ** _argv = NULL;
141
char *socketopt = NULL;
143
const char socketoptbase[] = "--proxy-socket=";
144
const char keyoptbase[] = "--proxy-key=";
151
if (stat(path, &s) != 0) {
152
cfd_proxy_error(__FILE__, __LINE__, errno,
153
_("Impossible to run file: %s"), path);
157
else if (S_ISDIR(s.st_mode)) {
158
cfd_proxy_error(__FILE__, __LINE__, 0,
159
_("File is a directory: %s"), path);
163
else if (!((S_IXUSR | S_IXGRP | S_IXOTH) & s.st_mode)) {
164
cfd_proxy_error(__FILE__, __LINE__, 0,
165
_("File is not executable: %s"), path);
170
// Initialize communicator
172
CFDP_MALLOC(child, 1, cfd_proxy_child_t);
175
child->comm = cfd_proxy_comm_initialize(comm_type, comm_verbosity);
177
if (child->comm == NULL) {
182
// Add communication info to argv
184
CFDP_MALLOC(socketopt,
185
( strlen(socketoptbase)
186
+ strlen(cfd_proxy_comm_get_name(child->comm)) + 1),
188
sprintf(socketopt, "%s%s",
190
cfd_proxy_comm_get_name(child->comm));
192
CFDP_MALLOC(keyopt, strlen(keyoptbase) + sizeof(int)*8 + 1, char);
193
sprintf(keyopt, "%s%d", keyoptbase, cfd_proxy_comm_get_key(child->comm));
195
for (i = 0; argv[i] != NULL; i++);
197
CFDP_MALLOC(_argv, i + 3, char *);
199
for (i = 0; argv[i] != NULL; i++)
202
_argv[i++] = socketopt;
206
#if defined(HAVE_POSIX_SPAWN)
208
posix_spawn_file_actions_t file_actions;
209
posix_spawnattr_t attrp;
211
posix_spawn_file_actions_init(&file_actions);
212
posix_spawnattr_init(&attrp);
214
retval = posix_spawn(&(child->pid), path, &file_actions, &attrp,
218
cfd_proxy_error(__FILE__, __LINE__, retval,
219
_("Error spawning child process %s."), path);
221
posix_spawnattr_destroy(&attrp);
222
posix_spawn_file_actions_destroy(&file_actions);
224
#elif defined(HAVE_FORK_EXECVE)
229
cfd_proxy_error(__FILE__, __LINE__, errno,
230
_("Error spawning child process %s."), path);
232
if (child->pid == 0) {
236
retval = execve(path, (char *const *)_argv, envp);
239
cfd_proxy_error(__FILE__, __LINE__, errno,
240
_("Error spawning child process %s."), path);
248
// Free additional command-line arguments
252
CFDP_FREE(socketopt);
254
// Wait for connection
256
if (child->pid != 0) {
257
retval = cfd_proxy_comm_connect(child->comm,
258
"CFD_Proxy_comm_socket");
260
_wait_child(child, false);
261
child->comm = cfd_proxy_comm_finalize(child->comm);
269
//----------------------------------------------------------------------------
270
// End connection with a child process and free associated structure
271
//----------------------------------------------------------------------------
274
cfd_proxy_child_stop(cfd_proxy_child_t **child)
276
cfd_proxy_child_t *_child = *child;
280
if (_child->comm != NULL)
281
_child->comm = cfd_proxy_comm_finalize(_child->comm);
283
// Wait for child to finish if not already finished
285
retval = _wait_child(_child, true);
287
if (_child->pid == -1) {
288
cfd_proxy_printf(_("\n"));
289
cfd_proxy_error(__FILE__, __LINE__, errno,
290
_("Error waiting for child process."));
303
//----------------------------------------------------------------------------
304
// Forward all calls from the client and their responses.
305
//----------------------------------------------------------------------------
308
cfd_proxy_child_forward_all(cfd_proxy_child_t *child)
310
if (child->comm != NULL)
311
cfd_proxy_forward_all(child->comm);
314
//----------------------------------------------------------------------------
318
#endif /* __cplusplus */