DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
Executable.cpp
Go to the documentation of this file.
1// DUNE DAQ modification notice:
2// This file has been modified from the original ATLAS system source for the DUNE DAQ project.
3// Fork baseline commit: system-00-00-20 (2020-09-25).
4// Renamed since fork: yes (from src/Executable.cxx to src/Executable.cpp).
5
6/*
7 * Executable.cxx
8 * ers
9 *
10 * Created by Matthias Wiesmann on 06.01.05.
11 * Copyright 2005 CERN. All rights reserved.
12 *
13 */
14
15#include <pthread.h>
16#include <signal.h>
17#include <sys/types.h>
18#include <sys/uio.h>
19#include <sys/stat.h>
20#include <fcntl.h>
21#include <cstdlib>
22#include <unistd.h>
23#include <cstdio>
24#include <sstream>
25#include <iostream>
26
27#include "ers/Assertion.hpp"
28#include "ers/ers.hpp"
29
32#include "okssystem/Process.hpp"
35
36const char* const OksSystem::Executable::SHELL_COMMAND = "/bin/sh";
37const char* const OksSystem::Executable::SHELL_COMMAND_PARAM = "-c";
38
49
50
51std::string OksSystem::Executable::okssystem(const std::string &command) {
53 std::vector<std::string> params;
54 params.push_back(SHELL_COMMAND_PARAM);
55 params.push_back(command);
56 return shell.pipe_in(params);
57} // std::string
58
63
64
71
72void OksSystem::Executable::exec(char** argv) const {
73 ERS_PRECONDITION(argv);
74 ERS_PRECONDITION(argv[0]);
75 const int status = ::execv(argv[0],argv);
76 throw OksSystem::ExecutionIssue( ERS_HERE, errno, argv[0], status );
77} // exec
78
86void OksSystem::Executable::exec(char** const argv, char** const env) const {
87 ERS_PRECONDITION(argv);
88 ERS_PRECONDITION(argv[0]);
90 const int status = ::execve(argv[0],argv,env);
91 throw OksSystem::ExecutionIssue( ERS_HERE, errno, argv[0], status );
92}
93
98
100 const int argc = params.size(); // number of parameters
101 const int argclen = argc+2; // size of array parameters + program name + null pointer
102 char **argv = (char **) calloc(sizeof(char*),argclen);
103 OKSSYSTEM_ALLOC_CHECK(argv,sizeof(char*)*argclen);
104 const char* name = *this;
105 argv[0] = strdup(name);
106 OKSSYSTEM_ALLOC_CHECK(argv[0],strlen(name));
107 for(int i=0;i<argc;i++) {
108 argv[i+1] = strdup(params[i].c_str());
109 } // loop over args
110 argv[argc+1] = 0;
111 try {
112 exec(argv);
113 }
114 catch(OksSystem::ExecutionIssue &ex) {
115 for(int i=0;argv[i]!=0;i++) {
116 free(argv[i]);
117 } // for
118 free(argv);
119 throw;
120 }
121 catch (ers::Issue &issue) { // there was a problem so we deallocate the argc array.
122 for(int i=0;argv[i]!=0;i++) {
123 free(argv[i]);
124 } // for
125 free(argv);
126 throw;
127 } // catch
128} // exec
129
134
135void OksSystem::Executable::exec(const param_collection &params, const env_collection &envs) const {
136
137 // Elaborate the environment
138 const unsigned int envArraySize = envs.size() + 1; // The last elements must be NULL
139 char** const env = new char*[envArraySize];
140
141 {
142 const env_collection::const_iterator b = envs.begin();
143 const env_collection::const_iterator e = envs.end();
144 env_collection::const_iterator it;
145
146 unsigned int counter = 0;
147 for(it = b; it != e; ++it) {
148 const std::string entry = it->first + "=" + it->second;
149 env[counter] = new char[entry.size() + 1]; // Add the NULL terminator
150 ::strcpy(env[counter], entry.c_str());
151 ++counter;
152 }
153
154 env[envArraySize - 1] = (char*) 0;
155 }
156
157 // Elaborate the paramenters
158 const unsigned int paramArraySize = params.size() + 2; // Add the executable name and the NULL terminator
159 char** const par = new char*[paramArraySize];
160
161 {
162 const std::string& binName = this->full_name();
163 par[0] = new char[binName.size() + 1]; // Add the NULL terminator
164 ::strcpy(par[0], binName.c_str());
165
166 const param_collection::const_iterator b = params.begin();
167 const param_collection::const_iterator e = params.end();
168 param_collection::const_iterator it;
169
170 unsigned int counter = 1;
171 for(it = b; it != e; ++it) {
172 const std::string& value = *it;
173 par[counter] = new char[value.size() + 1]; // Add the NULL terminator
174 ::strcpy(par[counter], value.c_str());
175 ++counter;
176 }
177
178 par[paramArraySize - 1] = (char*) 0;
179 }
180
181 try {
182 exec(par, env);
183 }
184 catch(OksSystem::ExecutionIssue& ex) {
185 // if we are here it means that the exec call failed!!!
186 // Free the allocated memory
187 for(unsigned int i = 0; i < envArraySize; ++i) {
188 delete[] env[i];
189 }
190 delete[] env;
191
192 for(unsigned int i = 0; i < paramArraySize; ++i) {
193 delete[] par[i];
194 }
195 delete[] par;
196
197 // Re-throw the exception
198 throw ex;
199 }
200
201}
202
203
208
210
211 // Block all signals before fork()
212 sigset_t new_set;
213 sigset_t old_set;
214 sigfillset(&new_set);
215 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
216
217 const pid_t child_id = fork();
218 if (0 == child_id) { // we are the child
219
220 // Put some signals to their default
221 signal(SIGTERM, SIG_DFL);
222 signal(SIGINT, SIG_DFL);
223
224 // Restore the original signal mask in child
225 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
226
227 try {
228 exec(params);
229 }
230 catch(OksSystem::ExecutionIssue &ex) {
231 ers::warning(ex);
232 _exit(EXIT_FAILURE);
233 }
234 catch(ers::Issue &ex) {
235 ers::warning(ex);
236 _exit(EXIT_FAILURE);
237 }
238
239 } // we are the child
240 if (child_id > 0) { // we are the parent
241
242 // Restore the original signal mask in parent
243 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
244
245 return Process(child_id,to_string(params));
246
247 } // we are the parent
248
249 // Restore the original signal mask in case of a fork() failure
250 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
251
252 throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "fork", "" );// We are screwed up
253} // start
254
255
260
262
263 // Block all signals before fork()
264 sigset_t new_set;
265 sigset_t old_set;
266 sigfillset(&new_set);
267 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
268
269 signal(SIGCLD, SIG_IGN); /* now I don't have to wait()! */
270
271 const pid_t child_id = fork();
272 if (0 == child_id) { // we are the child
273
274 // Put some signals to their default
275 signal(SIGTERM, SIG_DFL);
276 signal(SIGINT, SIG_DFL);
277 signal(SIGCLD, SIG_DFL); /* Restore default SIGCLD handling in the child process */
278
279 // Restore the original signal mask in child
280 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
281
282 try {
283 exec(params);
284 }
285 catch(OksSystem::ExecutionIssue &ex) {
286 ers::warning(ex);
287 _exit(EXIT_FAILURE);
288 }
289 catch(ers::Issue &ex) {
290 ers::warning(ex);
291 _exit(EXIT_FAILURE);
292 }
293
294 } // we are the child
295 if (child_id > 0) { // we are the parent
296
297 // Restore the original signal mask in parent
298 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
299
300 return Process(child_id,to_string(params));
301 } // we are the parent
302
303 // Restore the original signal mask in case of a fork() failure
304 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
305
306 throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "fork", "" );// We are screwed up
307} // start
308
309
315
316void OksSystem::Executable::copy_fd(int fd, std::ostream &target) {
317 while(true) {
318 char buffer[256];
319 long status = read(fd,buffer,sizeof(buffer));
320 if (status <= 0) return;
321 ERS_ASSERT( status<=(long) sizeof(buffer) );
322 for(int i=0;i<status;i++) {
323 target << (char) buffer[i];
324 } // for
325 } // while
326} // copy_fd
327
329
330std::string OksSystem::Executable::pipe_in(const param_collection &params) const {
331
332 int input_pipe[2];
333 int data_pipe[2];
334 int error_pipe[2];
335 const int input_pipe_status = pipe(input_pipe);
336 if (input_pipe_status<0) throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "pipe", "" );
337 const int data_pipe_status = pipe(data_pipe);
338 if (data_pipe_status<0) throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "pipe", "" );
339 const int error_pipe_status = pipe(error_pipe);
340 if (error_pipe_status<0) throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "pipe", "" );
341
342 // Block all signals before fork()
343 sigset_t new_set;
344 sigset_t old_set;
345 sigfillset(&new_set);
346 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
347
348 const pid_t child_id = fork();
349 if (0 == child_id) { // we are the child
350
351 // Put some signals to their default
352 signal(SIGTERM, SIG_DFL);
353 signal(SIGINT, SIG_DFL);
354
355 // Restore the original signal mask in child
356 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
357
358 dup2(input_pipe[1], fileno(stdin));
359 dup2(data_pipe[1], fileno(stdout));
360 dup2(error_pipe[1], fileno(stderr));
361
362 try {
363 this->exec(params);
364 }
365 catch(OksSystem::ExecutionIssue &ex) {
366 ers::warning(ex);
367 _exit(EXIT_FAILURE);
368 }
369 catch(ers::Issue &ex) {
370 ers::warning(ex);
371 _exit(EXIT_FAILURE);
372 }
373
374 } // we are the child
375 if (child_id > 0) { // we are the parent
376
377 // Restore the original signal mask in parent
378 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
379
380 Process child_process(child_id,to_string(params));
381 close(input_pipe[1]);
382 close(data_pipe[1]);
383 close(error_pipe[1]);
384 const int child_status = child_process.join();
385 const int in_fd = input_pipe[0];
386 const int err_fd = error_pipe[0];
387 const int out_fd = data_pipe[0];
388 std::ostringstream in_stream;
389 std::ostringstream out_stream;
390 std::ostringstream err_stream;
391 copy_fd(in_fd,in_stream);
392 copy_fd(out_fd,out_stream);
393 copy_fd(err_fd,err_stream);
394 close(in_fd);
395 close(out_fd);
396 close(err_fd);
397 if (0==child_status) {
398 return out_stream.str();
399 } // if
400 std::string command = to_string(params);
401 std::string error_str = err_stream.str();
402 throw OksSystem::ExecutionIssue(ERS_HERE,errno,command.c_str(),child_status);
403 } // we are the parent
404
405 // Restore the original signal mask in case of a fork() failure
406 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
407
408 return std::string();
409} // pipe_in
410
422
423std::string OksSystem::Executable::pipe_in(const param_collection &params, const env_collection &envs) const {
425 return pipe_in(params);
426} // pipe_in
427
429
430OksSystem::Process OksSystem::Executable::pipe_out(const param_collection &params, const File &input_file, const File &output_file, const File &error_file,mode_t perm) const {
431
432 // Block all signals before fork()
433 sigset_t new_set;
434 sigset_t old_set;
435 sigfillset(&new_set);
436 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
437
438 OksSystem::Descriptor in(&input_file,OksSystem::Descriptor::flags(true,false),perm); // May throw OksSystem::OpenFileIssue
439 OksSystem::Descriptor out(&output_file,OksSystem::Descriptor::flags(false,true),perm);
440 OksSystem::Descriptor err(&error_file,OksSystem::Descriptor::flags(false,true),perm);
441
442 const pid_t child_id = fork();
443 if (0 == child_id) { // we are the child
444
445 // Put some signals to their default
446 signal(SIGTERM, SIG_DFL);
447 signal(SIGINT, SIG_DFL);
448
449 // Restore the original signal mask in child
450 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
451
452 try {
453 ::dup2(in,::fileno(stdin));
454 ::dup2(out,::fileno(stdout));
455 ::dup2(err,::fileno(stderr));
456 ::close(in.fd());
457 ::close(out.fd());
458 ::close(err.fd());
459 this->exec(params);
460 }
461 catch(OksSystem::ExecutionIssue &ex) {
462 ers::warning(ex);
463 _exit(EXIT_FAILURE);
464 }
465 catch(OksSystem::PosixIssue &ex) {
466 ers::warning(ex);
467 _exit(EXIT_FAILURE);
468 }
469 catch(ers::Issue &ex) {
470 ers::warning(ex);
471 _exit(EXIT_FAILURE);
472 }
473
474 } // we are the child
475 if (child_id > 0) { // we are the parent
476
477 // Restore the original signal mask in parent
478 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
479
480 return Process(child_id,to_string(params));
481 } // we are the parent
482
483 // Restore the original signal mask in case of a fork() failure
484 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
485
486 throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "fork", "" );// We are screwed up
487} // pipe_out
488
497
498OksSystem::Process OksSystem::Executable::pipe_out(const param_collection &params, const env_collection &envs, const File &input_file, const File &output_file, const File &error_file, mode_t perm) const {
499
500 // Block all signals before fork()
501 sigset_t new_set;
502 sigset_t old_set;
503 sigfillset(&new_set);
504 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
505
506 OksSystem::Descriptor in(&input_file,OksSystem::Descriptor::flags(true,false),perm); // May throw OksSystem::OpenFileIssue
507 OksSystem::Descriptor out(&output_file,OksSystem::Descriptor::flags(false,true),perm);
508 OksSystem::Descriptor err(&error_file,OksSystem::Descriptor::flags(false,true),perm);
509
510 const pid_t child_id = fork();
511 if (0 == child_id) { // we are the child
512
513 // Put some signals to their default
514 signal(SIGTERM, SIG_DFL);
515 signal(SIGINT, SIG_DFL);
516
517 // Restore the original signal mask in child
518 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
519
520 try {
521 ::dup2(in,::fileno(stdin));
522 ::dup2(out,::fileno(stdout));
523 ::dup2(err,::fileno(stderr));
524 ::close(in.fd());
525 ::close(out.fd());
526 ::close(err.fd());
527 this->exec(params,envs);
528 }
529 catch(OksSystem::ExecutionIssue &ex) {
530 ers::warning(ex);
531 _exit(EXIT_FAILURE);
532 }
533 catch(OksSystem::PosixIssue &ex) {
534 ers::warning(ex);
535 _exit(EXIT_FAILURE);
536 }
537 catch(ers::Issue &ex) {
538 ers::warning(ex);
539 _exit(EXIT_FAILURE);
540 }
541
542 } // we are the child
543 if (child_id > 0) { // we are the parent
544
545 // Restore the original signal mask in parent
546 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
547
548 return Process(child_id,to_string(params));
549 } // we are the parent
550
551 // Restore the original signal mask in case of a fork() failure
552 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
553
554 throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "fork", "" );// We are screwed up
555
556} //pipe_out
557
562
564
565 // Block all signals before fork()
566 sigset_t new_set;
567 sigset_t old_set;
568 sigfillset(&new_set);
569 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
570
571 const pid_t child_id = fork();
572 if (child_id == 0) { // we are the child
573
574 // Put some signals to their default
575 signal(SIGTERM, SIG_DFL);
576 signal(SIGINT, SIG_DFL);
577
578 // Restore the original signal mask in child
579 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
580
581 try {
582 exec(params,envs);
583 }
584 catch(OksSystem::ExecutionIssue &ex) {
585 ers::warning(ex);
586 _exit(EXIT_FAILURE);
587 }
588 catch(ers::Issue &ex) {
589 ers::warning(ex);
590 _exit(EXIT_FAILURE);
591 }
592
593 } // we are the child
594 if (child_id > 0) { // we are the parent
595
596 // Restore the original signal mask in parent
597 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
598
599 return Process(child_id);
600 } // we are the parent
601
602 // Restore the original signal mask in case of a fork() failure
603 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
604
605 throw OksSystem::OksSystemCallIssue( ERS_HERE, errno, "fork", "" );// We are screwed up
606} // start
607
613
614std::string OksSystem::Executable::to_string(const param_collection &params) const {
615 std::ostringstream stream;
616 stream << m_full_name;
617 for(param_collection::const_iterator pos=params.begin();pos!=params.end();++pos) {
618 stream << " " << (*pos);
619 } // for
620 return stream.str();
621} // to_string
622
623
#define ERS_PRECONDITION(expression)
#define ERS_ASSERT(expression)
#define ERS_HERE
File descriptor / Socket wrapper.
int fd() const
file descritptor
static int flags(bool read_mode, bool write_mode)
Wrapper for executable file manipulation.
Process start_and_forget(const param_collection &params) const
start the executable in another process; do not wait for termination of child
Executable(const OksSystem::File &file)
std::string pipe_in(const param_collection &params) const
run the executable and pipe results back
Process pipe_out(const param_collection &params, const File &input_file, const File &output_file, const File &error_file, mode_t perm) const
static const char *const SHELL_COMMAND
command to execute in a shell
std::vector< std::string > param_collection
std::map< std::string, std::string > env_collection
Process start(const param_collection &params) const
start the executable in another process
void exec(char **argv) const
does the actual exec
static std::string okssystem(const std::string &command)
execute a command in a shell
static const char *const SHELL_COMMAND_PARAM
parameter to execute in a shell
std::string to_string(const param_collection &params) const
converts executable name and a parameter sequence into a string
void exec() const
run the executable
static void copy_fd(int fd, std::ostream &target)
copies the content of a file descriptor into a STL stream
Wrapper for file operations.
Definition File.hpp:37
File(const std::string &name)
Definition File.cpp:301
const std::string & full_name() const
full name for file *‍/
Definition File.cpp:411
std::string m_full_name
full name (path) of the file *‍/
Definition File.hpp:41
Wrapper for process manipulation.
Definition Process.hpp:30
int join(bool throw_non_zero=false) const
Waits for the process to terminate.
Definition Process.cpp:151
Base class for any user define issue.
Definition Issue.hpp:80
void warning(const Issue &issue)
Definition ers.hpp:126
static void set(const std::string &key, const std::string &value)
sets an environnement variable
#define OKSSYSTEM_ALLOC_CHECK(p, size)