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