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 31extern "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 39namespace process = utils::process; 40 41using utils::none; 42using 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). 53process::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. 70process::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. 84process::status 85process::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. 97process::status 98process::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. 112int 113process::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. 122bool 123process::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. 134int 135process::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. 145bool 146process::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. 158int 159process::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. 175bool 176process::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. 189std::ostream& 190process::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