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 <cstdio>
16#include <cstdlib>
17#include <fcntl.h>
18#include <iostream>
19#include <pthread.h>
20#include <signal.h>
21#include <sstream>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/uio.h>
25#include <unistd.h>
26
27#include "ers/Assertion.hpp"
28#include "ers/ers.hpp"
29
33#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
50std::string
51OksSystem::Executable::okssystem(const std::string& command)
52{
54 std::vector<std::string> params;
55 params.push_back(SHELL_COMMAND_PARAM);
56 params.push_back(command);
57 return shell.pipe_in(params);
58} // std::string
59
66{
67}
68OksSystem::Executable::Executable(const std::string& filename)
70{
71}
73
80
81void
83{
84 ERS_PRECONDITION(argv);
85 ERS_PRECONDITION(argv[0]);
86 const int status = ::execv(argv[0], argv);
87 throw OksSystem::ExecutionIssue(ERS_HERE, errno, argv[0], status);
88} // exec
89
97void
98OksSystem::Executable::exec(char** const argv, char** const env) const
99{
100 ERS_PRECONDITION(argv);
101 ERS_PRECONDITION(argv[0]);
102 ERS_PRECONDITION(env);
103 const int status = ::execve(argv[0], argv, env);
104 throw OksSystem::ExecutionIssue(ERS_HERE, errno, argv[0], status);
105}
106
111
112void
114{
115 const int argc = params.size(); // number of parameters
116 const int argclen = argc + 2; // size of array parameters + program name + null pointer
117 char** argv = (char**)calloc(sizeof(char*), argclen);
118 OKSSYSTEM_ALLOC_CHECK(argv, sizeof(char*) * argclen);
119 const char* name = *this;
120 argv[0] = strdup(name);
121 OKSSYSTEM_ALLOC_CHECK(argv[0], strlen(name));
122 for (int i = 0; i < argc; i++) {
123 argv[i + 1] = strdup(params[i].c_str());
124 } // loop over args
125 argv[argc + 1] = 0;
126 try {
127 exec(argv);
128 } catch (OksSystem::ExecutionIssue& ex) {
129 for (int i = 0; argv[i] != 0; i++) {
130 free(argv[i]);
131 } // for
132 free(argv);
133 throw;
134 } catch (ers::Issue& issue) { // there was a problem so we deallocate the argc array.
135 for (int i = 0; argv[i] != 0; i++) {
136 free(argv[i]);
137 } // for
138 free(argv);
139 throw;
140 } // catch
141} // exec
142
147
148void
150{
151
152 // Elaborate the environment
153 const unsigned int envArraySize = envs.size() + 1; // The last elements must be NULL
154 char** const env = new char*[envArraySize];
155
156 {
157 const env_collection::const_iterator b = envs.begin();
158 const env_collection::const_iterator e = envs.end();
159 env_collection::const_iterator it;
160
161 unsigned int counter = 0;
162 for (it = b; it != e; ++it) {
163 const std::string entry = it->first + "=" + it->second;
164 env[counter] = new char[entry.size() + 1]; // Add the NULL terminator
165 ::strcpy(env[counter], entry.c_str());
166 ++counter;
167 }
168
169 env[envArraySize - 1] = (char*)0;
170 }
171
172 // Elaborate the paramenters
173 const unsigned int paramArraySize = params.size() + 2; // Add the executable name and the NULL terminator
174 char** const par = new char*[paramArraySize];
175
176 {
177 const std::string& binName = this->full_name();
178 par[0] = new char[binName.size() + 1]; // Add the NULL terminator
179 ::strcpy(par[0], binName.c_str());
180
181 const param_collection::const_iterator b = params.begin();
182 const param_collection::const_iterator e = params.end();
183 param_collection::const_iterator it;
184
185 unsigned int counter = 1;
186 for (it = b; it != e; ++it) {
187 const std::string& value = *it;
188 par[counter] = new char[value.size() + 1]; // Add the NULL terminator
189 ::strcpy(par[counter], value.c_str());
190 ++counter;
191 }
192
193 par[paramArraySize - 1] = (char*)0;
194 }
195
196 try {
197 exec(par, env);
198 } catch (OksSystem::ExecutionIssue& ex) {
199 // if we are here it means that the exec call failed!!!
200 // Free the allocated memory
201 for (unsigned int i = 0; i < envArraySize; ++i) {
202 delete[] env[i];
203 }
204 delete[] env;
205
206 for (unsigned int i = 0; i < paramArraySize; ++i) {
207 delete[] par[i];
208 }
209 delete[] par;
210
211 // Re-throw the exception
212 throw ex;
213 }
214}
215
220
223{
224
225 // Block all signals before fork()
226 sigset_t new_set;
227 sigset_t old_set;
228 sigfillset(&new_set);
229 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
230
231 const pid_t child_id = fork();
232 if (0 == child_id) { // we are the child
233
234 // Put some signals to their default
235 signal(SIGTERM, SIG_DFL);
236 signal(SIGINT, SIG_DFL);
237
238 // Restore the original signal mask in child
239 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
240
241 try {
242 exec(params);
243 } catch (OksSystem::ExecutionIssue& ex) {
244 ers::warning(ex);
245 _exit(EXIT_FAILURE);
246 } catch (ers::Issue& ex) {
247 ers::warning(ex);
248 _exit(EXIT_FAILURE);
249 }
250
251 } // we are the child
252 if (child_id > 0) { // we are the parent
253
254 // Restore the original signal mask in parent
255 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
256
257 return Process(child_id, to_string(params));
258
259 } // we are the parent
260
261 // Restore the original signal mask in case of a fork() failure
262 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
263
264 throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "fork", ""); // We are screwed up
265} // start
266
272
275{
276
277 // Block all signals before fork()
278 sigset_t new_set;
279 sigset_t old_set;
280 sigfillset(&new_set);
281 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
282
283 signal(SIGCLD, SIG_IGN); /* now I don't have to wait()! */
284
285 const pid_t child_id = fork();
286 if (0 == child_id) { // we are the child
287
288 // Put some signals to their default
289 signal(SIGTERM, SIG_DFL);
290 signal(SIGINT, SIG_DFL);
291 signal(SIGCLD, SIG_DFL); /* Restore default SIGCLD handling in the child process */
292
293 // Restore the original signal mask in child
294 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
295
296 try {
297 exec(params);
298 } catch (OksSystem::ExecutionIssue& ex) {
299 ers::warning(ex);
300 _exit(EXIT_FAILURE);
301 } catch (ers::Issue& ex) {
302 ers::warning(ex);
303 _exit(EXIT_FAILURE);
304 }
305
306 } // we are the child
307 if (child_id > 0) { // we are the parent
308
309 // Restore the original signal mask in parent
310 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
311
312 return Process(child_id, to_string(params));
313 } // we are the parent
314
315 // Restore the original signal mask in case of a fork() failure
316 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
317
318 throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "fork", ""); // We are screwed up
319} // start
320
326
327void
328OksSystem::Executable::copy_fd(int fd, std::ostream& target)
329{
330 while (true) {
331 char buffer[256];
332 long status = read(fd, buffer, sizeof(buffer));
333 if (status <= 0)
334 return;
335 ERS_ASSERT(status <= (long)sizeof(buffer));
336 for (int i = 0; i < status; i++) {
337 target << (char)buffer[i];
338 } // for
339 } // while
340} // copy_fd
341
343
344std::string
346{
347
348 int input_pipe[2];
349 int data_pipe[2];
350 int error_pipe[2];
351 const int input_pipe_status = pipe(input_pipe);
352 if (input_pipe_status < 0)
353 throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "pipe", "");
354 const int data_pipe_status = pipe(data_pipe);
355 if (data_pipe_status < 0)
356 throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "pipe", "");
357 const int error_pipe_status = pipe(error_pipe);
358 if (error_pipe_status < 0)
359 throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "pipe", "");
360
361 // Block all signals before fork()
362 sigset_t new_set;
363 sigset_t old_set;
364 sigfillset(&new_set);
365 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
366
367 const pid_t child_id = fork();
368 if (0 == child_id) { // we are the child
369
370 // Put some signals to their default
371 signal(SIGTERM, SIG_DFL);
372 signal(SIGINT, SIG_DFL);
373
374 // Restore the original signal mask in child
375 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
376
377 dup2(input_pipe[1], fileno(stdin));
378 dup2(data_pipe[1], fileno(stdout));
379 dup2(error_pipe[1], fileno(stderr));
380
381 try {
382 this->exec(params);
383 } catch (OksSystem::ExecutionIssue& ex) {
384 ers::warning(ex);
385 _exit(EXIT_FAILURE);
386 } catch (ers::Issue& ex) {
387 ers::warning(ex);
388 _exit(EXIT_FAILURE);
389 }
390
391 } // we are the child
392 if (child_id > 0) { // we are the parent
393
394 // Restore the original signal mask in parent
395 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
396
397 Process child_process(child_id, to_string(params));
398 close(input_pipe[1]);
399 close(data_pipe[1]);
400 close(error_pipe[1]);
401 const int child_status = child_process.join();
402 const int in_fd = input_pipe[0];
403 const int err_fd = error_pipe[0];
404 const int out_fd = data_pipe[0];
405 std::ostringstream in_stream;
406 std::ostringstream out_stream;
407 std::ostringstream err_stream;
408 copy_fd(in_fd, in_stream);
409 copy_fd(out_fd, out_stream);
410 copy_fd(err_fd, err_stream);
411 close(in_fd);
412 close(out_fd);
413 close(err_fd);
414 if (0 == child_status) {
415 return out_stream.str();
416 } // if
417 std::string command = to_string(params);
418 std::string error_str = err_stream.str();
419 throw OksSystem::ExecutionIssue(ERS_HERE, errno, command.c_str(), child_status);
420 } // we are the parent
421
422 // Restore the original signal mask in case of a fork() failure
423 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
424
425 return std::string();
426} // pipe_in
427
439
440std::string
442{
444 return pipe_in(params);
445} // pipe_in
446
448
451 const File& input_file,
452 const File& output_file,
453 const File& error_file,
454 mode_t perm) const
455{
456
457 // Block all signals before fork()
458 sigset_t new_set;
459 sigset_t old_set;
460 sigfillset(&new_set);
461 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
462
464 &input_file, OksSystem::Descriptor::flags(true, false), perm); // May throw OksSystem::OpenFileIssue
465 OksSystem::Descriptor out(&output_file, OksSystem::Descriptor::flags(false, true), perm);
466 OksSystem::Descriptor err(&error_file, OksSystem::Descriptor::flags(false, true), perm);
467
468 const pid_t child_id = fork();
469 if (0 == child_id) { // we are the child
470
471 // Put some signals to their default
472 signal(SIGTERM, SIG_DFL);
473 signal(SIGINT, SIG_DFL);
474
475 // Restore the original signal mask in child
476 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
477
478 try {
479 ::dup2(in, ::fileno(stdin));
480 ::dup2(out, ::fileno(stdout));
481 ::dup2(err, ::fileno(stderr));
482 ::close(in.fd());
483 ::close(out.fd());
484 ::close(err.fd());
485 this->exec(params);
486 } catch (OksSystem::ExecutionIssue& ex) {
487 ers::warning(ex);
488 _exit(EXIT_FAILURE);
489 } catch (OksSystem::PosixIssue& ex) {
490 ers::warning(ex);
491 _exit(EXIT_FAILURE);
492 } catch (ers::Issue& ex) {
493 ers::warning(ex);
494 _exit(EXIT_FAILURE);
495 }
496
497 } // we are the child
498 if (child_id > 0) { // we are the parent
499
500 // Restore the original signal mask in parent
501 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
502
503 return Process(child_id, to_string(params));
504 } // we are the parent
505
506 // Restore the original signal mask in case of a fork() failure
507 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
508
509 throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "fork", ""); // We are screwed up
510} // pipe_out
511
520
523 const env_collection& envs,
524 const File& input_file,
525 const File& output_file,
526 const File& error_file,
527 mode_t perm) const
528{
529
530 // Block all signals before fork()
531 sigset_t new_set;
532 sigset_t old_set;
533 sigfillset(&new_set);
534 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
535
537 &input_file, OksSystem::Descriptor::flags(true, false), perm); // May throw OksSystem::OpenFileIssue
538 OksSystem::Descriptor out(&output_file, OksSystem::Descriptor::flags(false, true), perm);
539 OksSystem::Descriptor err(&error_file, OksSystem::Descriptor::flags(false, true), perm);
540
541 const pid_t child_id = fork();
542 if (0 == child_id) { // we are the child
543
544 // Put some signals to their default
545 signal(SIGTERM, SIG_DFL);
546 signal(SIGINT, SIG_DFL);
547
548 // Restore the original signal mask in child
549 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
550
551 try {
552 ::dup2(in, ::fileno(stdin));
553 ::dup2(out, ::fileno(stdout));
554 ::dup2(err, ::fileno(stderr));
555 ::close(in.fd());
556 ::close(out.fd());
557 ::close(err.fd());
558 this->exec(params, envs);
559 } catch (OksSystem::ExecutionIssue& ex) {
560 ers::warning(ex);
561 _exit(EXIT_FAILURE);
562 } catch (OksSystem::PosixIssue& ex) {
563 ers::warning(ex);
564 _exit(EXIT_FAILURE);
565 } catch (ers::Issue& ex) {
566 ers::warning(ex);
567 _exit(EXIT_FAILURE);
568 }
569
570 } // we are the child
571 if (child_id > 0) { // we are the parent
572
573 // Restore the original signal mask in parent
574 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
575
576 return Process(child_id, to_string(params));
577 } // we are the parent
578
579 // Restore the original signal mask in case of a fork() failure
580 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
581
582 throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "fork", ""); // We are screwed up
583
584} // pipe_out
585
590
593{
594
595 // Block all signals before fork()
596 sigset_t new_set;
597 sigset_t old_set;
598 sigfillset(&new_set);
599 pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
600
601 const pid_t child_id = fork();
602 if (child_id == 0) { // we are the child
603
604 // Put some signals to their default
605 signal(SIGTERM, SIG_DFL);
606 signal(SIGINT, SIG_DFL);
607
608 // Restore the original signal mask in child
609 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
610
611 try {
612 exec(params, envs);
613 } catch (OksSystem::ExecutionIssue& ex) {
614 ers::warning(ex);
615 _exit(EXIT_FAILURE);
616 } catch (ers::Issue& ex) {
617 ers::warning(ex);
618 _exit(EXIT_FAILURE);
619 }
620
621 } // we are the child
622 if (child_id > 0) { // we are the parent
623
624 // Restore the original signal mask in parent
625 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
626
627 return Process(child_id);
628 } // we are the parent
629
630 // Restore the original signal mask in case of a fork() failure
631 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
632
633 throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "fork", ""); // We are screwed up
634} // start
635
641
642std::string
644{
645 std::ostringstream stream;
646 stream << m_full_name;
647 for (param_collection::const_iterator pos = params.begin(); pos != params.end(); ++pos) {
648 stream << " " << (*pos);
649 } // for
650 return stream.str();
651} // to_string
#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:38
File(const std::string &name)
Definition File.cpp:327
const std::string & full_name() const
full name for file *‍/
Definition File.cpp:443
std::string m_full_name
full name (path) of the file *‍/
Definition File.hpp:43
Wrapper for process manipulation.
Definition Process.hpp:31
int join(bool throw_non_zero=false) const
Waits for the process to terminate.
Definition Process.cpp:176
Process()
Builds a process representing the current process.
Definition Process.cpp:118
Base class for any user define issue.
Definition Issue.hpp:76
void warning(const Issue &issue)
Definition ers.hpp:150
static void set(const std::string &key, const std::string &value)
sets an environnement variable
#define OKSSYSTEM_ALLOC_CHECK(p, size)