1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 54    Interprocess Communication */
10 
11 #include "squid.h"
12 #include "globals.h"
13 #include "ipc/Kid.h"
14 #include "SquidConfig.h"
15 
16 #include <ctime>
17 #if HAVE_SYS_WAIT_H
18 #include <sys/wait.h>
19 #endif
20 
21 int TheProcessKind = pkOther;
22 
Kid()23 Kid::Kid()
24 {
25 }
26 
Kid(const char * aRole,const int anId)27 Kid::Kid(const char *aRole, const int anId):
28     processRole(aRole),
29     processId(anId)
30 {
31 }
32 
33 /// called when this kid got started, records PID
start(pid_t cpid)34 void Kid::start(pid_t cpid)
35 {
36     assert(!running());
37     assert(cpid > 0);
38 
39     isRunning = true;
40     stopTime = 0;
41     pid = cpid;
42     startTime = squid_curtime;
43 }
44 
45 /// called when kid terminates, sets exiting status
46 void
stop(PidStatus const theExitStatus)47 Kid::stop(PidStatus const theExitStatus)
48 {
49     assert(running());
50     assert(startTime != 0);
51 
52     isRunning = false;
53     stopTime = squid_curtime;
54     status = theExitStatus;
55 
56     if ((stopTime - startTime) < fastFailureTimeLimit)
57         ++badFailures;
58     else
59         badFailures = 0; // the failures are not "frequent" [any more]
60 
61     reportStopped(); // after all state changes
62 }
63 
64 /// describes a recently stopped kid
65 void
reportStopped() const66 Kid::reportStopped() const
67 {
68     if (calledExit()) {
69         syslog(LOG_NOTICE,
70                "Squid Parent: %s process %d exited with status %d",
71                gist().c_str(), pid, exitStatus());
72     } else if (signaled()) {
73         syslog(LOG_NOTICE,
74                "Squid Parent: %s process %d exited due to signal %d with status %d",
75                gist().c_str(), pid, termSignal(), exitStatus());
76     } else {
77         syslog(LOG_NOTICE, "Squid Parent: %s process %d exited",
78                gist().c_str(), pid);
79     }
80 
81     if (hopeless() && Config.hopelessKidRevivalDelay) {
82         syslog(LOG_NOTICE, "Squid Parent: %s process %d will not be restarted for %ld "
83                "seconds due to repeated, frequent failures",
84                gist().c_str(),
85                pid,
86                static_cast<long int>(Config.hopelessKidRevivalDelay));
87     }
88 }
89 
90 /// returns true if tracking of kid is stopped
running() const91 bool Kid::running() const
92 {
93     return isRunning;
94 }
95 
96 /// returns true if master process should restart this kid
shouldRestart() const97 bool Kid::shouldRestart() const
98 {
99     return !(running() ||
100              exitedHappy() ||
101              hopeless() ||
102              shutting_down ||
103              signaled(SIGKILL) || // squid -k kill
104              signaled(SIGINT) || // unexpected forced shutdown
105              signaled(SIGTERM)); // unexpected forced shutdown
106 }
107 
108 /// returns current pid for a running kid and last pid for a stopped kid
getPid() const109 pid_t Kid::getPid() const
110 {
111     assert(pid > 0);
112     return pid;
113 }
114 
115 /// whether the failures are "repeated and frequent"
hopeless() const116 bool Kid::hopeless() const
117 {
118     return badFailures > badFailureLimit;
119 }
120 
121 /// returns true if the process terminated normally
calledExit() const122 bool Kid::calledExit() const
123 {
124     return (pid > 0) && !running() && WIFEXITED(status);
125 }
126 
127 /// returns the exit status of the process
exitStatus() const128 int Kid::exitStatus() const
129 {
130     return WEXITSTATUS(status);
131 }
132 
133 /// whether the process exited with a given exit status code
calledExit(int code) const134 bool Kid::calledExit(int code) const
135 {
136     return calledExit() && (exitStatus() == code);
137 }
138 
139 /// whether the process exited with code 0
exitedHappy() const140 bool Kid::exitedHappy() const
141 {
142     return calledExit(0);
143 }
144 
145 /// returns true if the kid was terminated by a signal
signaled() const146 bool Kid::signaled() const
147 {
148     return (pid > 0) && !running() && WIFSIGNALED(status);
149 }
150 
151 /// returns the number of the signal that caused the kid to terminate
termSignal() const152 int Kid::termSignal() const
153 {
154     return WTERMSIG(status);
155 }
156 
157 /// whether the process was terminated by a given signal
signaled(int sgnl) const158 bool Kid::signaled(int sgnl) const
159 {
160     return signaled() && (termSignal() == sgnl);
161 }
162 
163 /// returns kid name
processName() const164 SBuf Kid::processName() const
165 {
166     SBuf name("(");
167     name.append(gist());
168     name.append(")");
169     return name;
170 }
171 
gist() const172 SBuf Kid::gist() const
173 {
174     SBuf name(processRole);
175     name.appendf("-%d", processId);
176     return name;
177 }
178 
179 time_t
deathDuration() const180 Kid::deathDuration() const
181 {
182     return squid_curtime > stopTime ? squid_curtime - stopTime : 0;
183 }
184 
185