1 // Copyright 2010 The Kyua Authors. 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/format/macros.hpp" 36 #include "utils/optional.ipp" 37 #include "utils/sanity.hpp" 38 39 namespace process = utils::process; 40 41 using utils::none; 42 using utils::optional; 43 44 #if !defined(WCOREDUMP) 45 # define WCOREDUMP(x) false 46 #endif 47 48 49 /// Constructs a new status object based on the status value of waitpid(2). 50 /// 51 /// \param dead_pid_ The PID of the process this status belonged to. 52 /// \param stat_loc The status value returnd by waitpid(2). 53 process::status::status(const int dead_pid_, int stat_loc) : 54 _dead_pid(dead_pid_), 55 _exited(WIFEXITED(stat_loc) ? 56 optional< int >(WEXITSTATUS(stat_loc)) : none), 57 _signaled(WIFSIGNALED(stat_loc) ? 58 optional< std::pair< int, bool > >( 59 std::make_pair(WTERMSIG(stat_loc), WCOREDUMP(stat_loc))) : 60 none) 61 { 62 } 63 64 65 /// Constructs a new status object based on fake values. 66 /// 67 /// \param exited_ If not none, specifies the exit status of the program. 68 /// \param signaled_ If not none, specifies the termination signal and whether 69 /// the process dumped core or not. 70 process::status::status(const optional< int >& exited_, 71 const optional< std::pair< int, bool > >& signaled_) : 72 _dead_pid(-1), 73 _exited(exited_), 74 _signaled(signaled_) 75 { 76 } 77 78 79 /// Constructs a new status object based on a fake exit status. 80 /// 81 /// \param exitstatus_ The exit code of the process. 82 /// 83 /// \return A status object with fake data. 84 process::status 85 process::status::fake_exited(const int exitstatus_) 86 { 87 return status(utils::make_optional(exitstatus_), none); 88 } 89 90 91 /// Constructs a new status object based on a fake exit status. 92 /// 93 /// \param termsig_ The termination signal of the process. 94 /// \param coredump_ Whether the process dumped core or not. 95 /// 96 /// \return A status object with fake data. 97 process::status 98 process::status::fake_signaled(const int termsig_, const bool coredump_) 99 { 100 return status(none, utils::make_optional(std::make_pair(termsig_, 101 coredump_))); 102 } 103 104 105 /// Returns the PID of the process this status was taken from. 106 /// 107 /// Please note that the process is already dead and gone from the system. This 108 /// PID can only be used for informational reasons and not to address the 109 /// process in any way. 110 /// 111 /// \return The PID of the original process. 112 int 113 process::status::dead_pid(void) const 114 { 115 return _dead_pid; 116 } 117 118 119 /// Returns whether the process exited cleanly or not. 120 /// 121 /// \return True if the process exited cleanly, false otherwise. 122 bool 123 process::status::exited(void) const 124 { 125 return _exited; 126 } 127 128 129 /// Returns the exit code of the process. 130 /// 131 /// \pre The process must have exited cleanly (i.e. exited() must be true). 132 /// 133 /// \return The exit code. 134 int 135 process::status::exitstatus(void) const 136 { 137 PRE(exited()); 138 return _exited.get(); 139 } 140 141 142 /// Returns whether the process terminated due to a signal or not. 143 /// 144 /// \return True if the process terminated due to a signal, false otherwise. 145 bool 146 process::status::signaled(void) const 147 { 148 return _signaled; 149 } 150 151 152 /// Returns the signal that terminated the process. 153 /// 154 /// \pre The process must have terminated by a signal (i.e. signaled() must be 155 /// true. 156 /// 157 /// \return The signal number. 158 int 159 process::status::termsig(void) const 160 { 161 PRE(signaled()); 162 return _signaled.get().first; 163 } 164 165 166 /// Returns whether the process core dumped or not. 167 /// 168 /// This functionality may be unsupported in some platforms. In such cases, 169 /// this method returns false unconditionally. 170 /// 171 /// \pre The process must have terminated by a signal (i.e. signaled() must be 172 /// true. 173 /// 174 /// \return True if the process dumped core, false otherwise. 175 bool 176 process::status::coredump(void) const 177 { 178 PRE(signaled()); 179 return _signaled.get().second; 180 } 181 182 183 /// Injects the object into a stream. 184 /// 185 /// \param output The stream into which to inject the object. 186 /// \param status The object to format. 187 /// 188 /// \return The output stream. 189 std::ostream& 190 process::operator<<(std::ostream& output, const status& status) 191 { 192 if (status.exited()) { 193 output << F("status{exitstatus=%s}") % status.exitstatus(); 194 } else { 195 INV(status.signaled()); 196 output << F("status{termsig=%s, coredump=%s}") % status.termsig() % 197 status.coredump(); 198 } 199 return output; 200 } 201