1 /* ===========================================================================
2  *
3  *                            PUBLIC DOMAIN NOTICE
4  *               National Center for Biotechnology Information
5  *
6  *  This software/database is a "United States Government Work" under the
7  *  terms of the United States Copyright Act.  It was written as part of
8  *  the author's official duties as a United States Government employee and
9  *  thus cannot be copyrighted.  This software/database is freely available
10  *  to the public for use. The National Library of Medicine and the U.S.
11  *  Government have not placed any restriction on its use or reproduction.
12  *
13  *  Although all reasonable efforts have been taken to ensure the accuracy
14  *  and reliability of the software and data, the NLM and the U.S.
15  *  Government do not and cannot warrant the performance or results that
16  *  may be obtained by using this software or data. The NLM and the U.S.
17  *  Government disclaim all warranties, express or implied, including
18  *  warranties of performance, merchantability or fitness for any particular
19  *  purpose.
20  *
21  *  Please cite the author in any work or product based on this material.
22  *
23  * ===========================================================================
24  *
25  * Project:
26  *  sratools command line tool
27  *
28  * Purpose:
29  *  process stuff, like fork and exec
30  *
31  */
32 
33 #pragma once
34 #include <string>
35 #include <vector>
36 #include <map>
37 
38 #include <signal.h>
39 #include <sys/wait.h>
40 
41 #include "parse_args.hpp"
42 #include "util.hpp"
43 
44 extern char **environ; // why!!!
45 
46 namespace sratools {
47 
48 struct process {
is_selfsratools::process49     bool is_self() const { return pid == 0; }
get_pidsratools::process50     pid_t get_pid() const { return pid; }
51 
52     /// @brief the result of wait if child did terminate in some way
53     struct exit_status {
54         /// @brief child called exit
exitedsratools::process::exit_status55         bool exited() const {
56             return WIFEXITED(value) ? true : false;
57         }
58         /// @brief child exit code
59         ///
60         /// Only available exited() == true.
61         ///
62         /// @return The low 8-bits of the value passed to exit.
exit_codesratools::process::exit_status63         int exit_code() const {
64             assert(exited());
65             return WEXITSTATUS(value);
66         }
67 
68         /// @brief child was signaled
signaledsratools::process::exit_status69         bool signaled() const {
70             return WIFSIGNALED(value) ? true : false;
71         }
72         /// @brief the signal that terminated the child
73         ///
74         /// Only available signaled() == true
75         ///
76         /// @return the signal that terminated the child
termsigsratools::process::exit_status77         int termsig() const {
78             assert(signaled());
79             return WTERMSIG(value);
80         }
81         /// @brief the symbolic name of the signal that terminated the child
82         ///
83         /// Only available signaled() == true
84         ///
85         /// @return the symbolic name of the signal that terminated the child
termsignamesratools::process::exit_status86         char const *termsigname() const {
87             // list taken from https://pubs.opengroup.org/onlinepubs/009695399/basedefs/signal.h.html
88             // removed entries that were not defined on CentOS Linux release 7.8.2003
89             switch (termsig()) {
90             case SIGHUP   : return "SIGHUP";
91             case SIGINT   : return "SIGINT";
92             case SIGQUIT  : return "SIGQUIT";
93             case SIGILL   : return "SIGILL";
94             case SIGTRAP  : return "SIGTRAP";
95             case SIGABRT  : return "SIGABRT";
96             case SIGBUS   : return "SIGBUS";
97             case SIGFPE   : return "SIGFPE";
98             case SIGKILL  : return "SIGKILL";
99             case SIGUSR1  : return "SIGUSR1";
100             case SIGSEGV  : return "SIGSEGV";
101             case SIGUSR2  : return "SIGUSR2";
102             case SIGPIPE  : return "SIGPIPE";
103             case SIGALRM  : return "SIGALRM";
104             case SIGTERM  : return "SIGTERM";
105             case SIGCHLD  : return "SIGCHLD";
106             case SIGCONT  : return "SIGCONT";
107             case SIGSTOP  : return "SIGSTOP";
108             case SIGTSTP  : return "SIGTSTP";
109             case SIGTTIN  : return "SIGTTIN";
110             case SIGTTOU  : return "SIGTTOU";
111             case SIGURG   : return "SIGURG";
112             case SIGXCPU  : return "SIGXCPU";
113             case SIGXFSZ  : return "SIGXFSZ";
114             case SIGVTALRM: return "SIGVTALRM";
115             case SIGPROF  : return "SIGPROF";
116             case SIGWINCH : return "SIGWINCH";
117             case SIGIO    : return "SIGIO";
118             case SIGSYS   : return "SIGSYS";
119             default:
120                 return nullptr;
121             }
122         }
123         /// @brief a coredump was generated
124         ///
125         /// Only available signaled() == true
126         ///
127         /// @return true if a coredump was generated
coredumpsratools::process::exit_status128         bool coredump() const {
129             assert(signaled());
130             return WCOREDUMP(value) ? true : false;
131         }
132 
133         /// @brief the child is stopped, like in a debugger
stoppedsratools::process::exit_status134         bool stopped() const {
135             return WIFSTOPPED(value) ? true : false;
136         }
137         /// @brief the signal that stopped the child
138         ///
139         /// Only available stopped() == true
140         ///
141         /// @return the signal that stopped the child
stopsigsratools::process::exit_status142         int stopsig() const {
143             assert(stopped());
144             return WSTOPSIG(value);
145         }
146 
147         /// @brief did child exit(0)
normalsratools::process::exit_status148         bool normal() const {
149             return exited() && exit_code() == 0;
150         }
operator boolsratools::process::exit_status151         operator bool() const {
152             return normal();
153         }
154 
exit_statussratools::process::exit_status155         exit_status(exit_status const &other) : value(other.value) {}
operator =sratools::process::exit_status156         exit_status &operator =(exit_status const &other) {
157             value = other.value;
158             return *this;
159         }
160     private:
161         int value;
162         friend struct process;
exit_statussratools::process::exit_status163         exit_status(int status) : value(status) {}
164     };
165 
166       /// @brief wait for this process to finish
167       /// @return exit status
168       /// @throw system_error if wait fails
169     exit_status wait() const;
170 
171     static void run_child(char const *toolpath, char const *toolname, char const **argv, Dictionary const &env = {});
172     static exit_status run_child_and_wait(char const *toolpath, char const *toolname, char const **argv, Dictionary const &env = {});
173     static exit_status run_child_and_get_stdout(std::string *out, char const *toolpath, char const *toolname, char const **argv, bool const for_real = false, Dictionary const &env = {});
174 
processsratools::process175     process(process const &other) : pid(other.pid) {}
operator =sratools::process176     process &operator =(process const &other) {
177         pid = other.pid;
178         return *this;
179     }
180 protected:
selfsratools::process181     static process self() { return process(0); }
processsratools::process182     process(pid_t pid) : pid(pid) {}
183 
184     pid_t pid;
185 };
186 
187 } // namespace sratools
188