1 // Copyright 2010 Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of Google Inc. nor the names of its contributors 14 // may be used to endorse or promote products derived from this software 15 // without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #include "utils/process/status.hpp" 30 31 extern "C" { 32 #include <sys/wait.h> 33 } 34 35 #include "utils/optional.ipp" 36 #include "utils/sanity.hpp" 37 38 namespace process = utils::process; 39 40 using utils::none; 41 using utils::optional; 42 43 #if !defined(WCOREDUMP) 44 # define WCOREDUMP(x) false 45 #endif 46 47 48 /// Constructs a new status object based on the status value of waitpid(2). 49 /// 50 /// \param dead_pid_ The PID of the process this status belonged to. 51 /// \param stat_loc The status value returnd by waitpid(2). 52 process::status::status(const int dead_pid_, int stat_loc) : 53 _dead_pid(dead_pid_), 54 _exited(WIFEXITED(stat_loc) ? 55 optional< int >(WEXITSTATUS(stat_loc)) : none), 56 _signaled(WIFSIGNALED(stat_loc) ? 57 optional< std::pair< int, bool > >( 58 std::make_pair(WTERMSIG(stat_loc), WCOREDUMP(stat_loc))) : 59 none) 60 { 61 } 62 63 64 /// Constructs a new status object based on fake values. 65 /// 66 /// \param exited_ If not none, specifies the exit status of the program. 67 /// \param signaled_ If not none, specifies the termination signal and whether 68 /// the process dumped core or not. 69 process::status::status(const optional< int >& exited_, 70 const optional< std::pair< int, bool > >& signaled_) : 71 _dead_pid(-1), 72 _exited(exited_), 73 _signaled(signaled_) 74 { 75 } 76 77 78 /// Constructs a new status object based on a fake exit status. 79 /// 80 /// \param exitstatus_ The exit code of the process. 81 /// 82 /// \return A status object with fake data. 83 process::status 84 process::status::fake_exited(const int exitstatus_) 85 { 86 return status(utils::make_optional(exitstatus_), none); 87 } 88 89 90 /// Constructs a new status object based on a fake exit status. 91 /// 92 /// \param termsig_ The termination signal of the process. 93 /// \param coredump_ Whether the process dumped core or not. 94 /// 95 /// \return A status object with fake data. 96 process::status 97 process::status::fake_signaled(const int termsig_, const bool coredump_) 98 { 99 return status(none, utils::make_optional(std::make_pair(termsig_, 100 coredump_))); 101 } 102 103 104 /// Returns the PID of the process this status was taken from. 105 /// 106 /// Please note that the process is already dead and gone from the system. This 107 /// PID can only be used for informational reasons and not to address the 108 /// process in any way. 109 /// 110 /// \return The PID of the original process. 111 int 112 process::status::dead_pid(void) const 113 { 114 return _dead_pid; 115 } 116 117 118 /// Returns whether the process exited cleanly or not. 119 /// 120 /// \return True if the process exited cleanly, false otherwise. 121 bool 122 process::status::exited(void) const 123 { 124 return _exited; 125 } 126 127 128 /// Returns the exit code of the process. 129 /// 130 /// \pre The process must have exited cleanly (i.e. exited() must be true). 131 /// 132 /// \return The exit code. 133 int 134 process::status::exitstatus(void) const 135 { 136 PRE(exited()); 137 return _exited.get(); 138 } 139 140 141 /// Returns whether the process terminated due to a signal or not. 142 /// 143 /// \return True if the process terminated due to a signal, false otherwise. 144 bool 145 process::status::signaled(void) const 146 { 147 return _signaled; 148 } 149 150 151 /// Returns the signal that terminated the process. 152 /// 153 /// \pre The process must have terminated by a signal (i.e. signaled() must be 154 /// true. 155 /// 156 /// \return The signal number. 157 int 158 process::status::termsig(void) const 159 { 160 PRE(signaled()); 161 return _signaled.get().first; 162 } 163 164 165 /// Returns whether the process core dumped or not. 166 /// 167 /// This functionality may be unsupported in some platforms. In such cases, 168 /// this method returns false unconditionally. 169 /// 170 /// \pre The process must have terminated by a signal (i.e. signaled() must be 171 /// true. 172 /// 173 /// \return True if the process dumped core, false otherwise. 174 bool 175 process::status::coredump(void) const 176 { 177 PRE(signaled()); 178 return _signaled.get().second; 179 } 180