]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/Instance.cc
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
10 #include "base/File.h"
11 #include "debug/Messages.h"
14 #include "parser/Tokenizer.h"
15 #include "sbuf/Stream.h"
16 #include "SquidConfig.h"
21 /* To support concurrent PID files, convert local statics into PidFile class */
23 /// Describes the (last) instance PID file being processed.
24 /// This hack shortens reporting code while keeping its messages consistent.
27 /// PidFilename() helper
28 /// \returns PID file name or, if PID signaling was disabled, an empty SBuf
32 if (!Config
.pidFilename
|| strcmp(Config
.pidFilename
, "none") == 0)
35 // If chroot has been requested, then we first read the PID file before
36 // chroot() and then create/update it inside a chrooted environment.
37 // TODO: Consider removing half-baked chroot support from Squid.
39 if (!Config
.chroot_dir
|| Chrooted
) // no need to compensate
40 return SBuf(Config
.pidFilename
);
43 filename
.append(Config
.chroot_dir
);
45 filename
.append(Config
.pidFilename
);
46 debugs(50, 3, "outside chroot: " << filename
);
50 /// \returns PID file description for debugging messages and error reporting
52 PidFileDescription(const SBuf
&filename
)
54 return ToSBuf("PID file (", filename
, ')');
57 /// Instance entry points are expected to call this first.
58 /// \returns PidFilenameCalc() result while updating TheFile context
62 const auto name
= PidFilenameCalc();
63 TheFile
= PidFileDescription(name
);
67 /// \returns the PID of another Squid instance (or throws)
69 GetOtherPid(File
&pidFile
)
71 const auto input
= pidFile
.readSmall(1, 32);
74 Parser::Tokenizer
tok(input
);
75 if (!(tok
.int64(rawPid
, 10, false) && // PID digits
76 (tok
.skipOne(CharacterSet::CR
)||true) && // optional CR (Windows/etc.)
77 tok
.skipOne(CharacterSet::LF
) && // required end of line
78 tok
.atEnd())) { // no trailing garbage
79 throw TexcHere(ToSBuf("Malformed ", TheFile
));
82 debugs(50, 7, "found PID " << rawPid
<< " in " << TheFile
);
85 throw TexcHere(ToSBuf("Bad ", TheFile
, " contains unreasonably small PID value: ", rawPid
));
86 const auto finalPid
= static_cast<pid_t
>(rawPid
);
87 if (static_cast<int64_t>(finalPid
) != rawPid
)
88 throw TexcHere(ToSBuf("Bad ", TheFile
, " contains unreasonably large PID value: ", rawPid
));
93 /// determines whether a given process is running at the time of the call
95 ProcessIsRunning(const pid_t pid
)
97 const auto result
= kill(pid
, 0);
98 const auto savedErrno
= errno
;
100 debugs(50, 3, "kill(" << pid
<< ", 0) failed: " << xstrerr(savedErrno
));
101 // if we do not have permissions to signal the process, then it is running
102 return (result
== 0 || savedErrno
== EPERM
);
105 /// quits if another Squid instance (that owns the given PID file) is running
107 ThrowIfAlreadyRunningWith(File
&pidFile
)
109 bool running
= false;
112 const auto pid
= GetOtherPid(pidFile
);
113 description
= ToSBuf(TheFile
, " with PID ", pid
);
114 running
= ProcessIsRunning(pid
);
116 catch (const std::exception
&ex
) {
117 debugs(50, 5, "assuming no other Squid instance: " << ex
.what());
122 throw TexcHere(ToSBuf("Squid is already running: Found fresh instance ", description
));
124 debugs(50, 5, "assuming stale instance " << description
);
130 const auto filename
= PidFilename();
131 if (filename
.isEmpty())
132 throw TexcHere("no pid_filename configured");
134 File
pidFile(filename
, File::Be::ReadOnly().locked());
135 return GetOtherPid(pidFile
);
139 Instance::ThrowIfAlreadyRunning()
141 const auto filename
= PidFilename();
142 if (filename
.isEmpty())
143 return; // the check is impossible
145 if (const auto filePtr
= File::Optional(filename
, File::Be::ReadOnly().locked())) {
146 const std::unique_ptr
<File
> pidFile(filePtr
);
147 ThrowIfAlreadyRunningWith(*pidFile
);
149 // It is best to assume then to check because checking without a lock
150 // might lead to false positives that lead to no Squid starting at all!
151 debugs(50, 5, "cannot lock " << TheFile
<< "; assuming no other Squid is running");
152 // If our assumption is false, we will fail to _create_ the PID file,
153 // and, hence, will not start, allowing that other Squid to run.
157 /// ties Instance::WriteOurPid() scheduler and RemoveInstance(void) handler
158 static SBuf ThePidFileToRemove
;
160 /// atexit() handler; removes the PID file created with Instance::WriteOurPid()
164 if (ThePidFileToRemove
.isEmpty()) // not the PidFilename()!
165 return; // nothing to do
167 debugs(50, Important(22), "Removing " << PidFileDescription(ThePidFileToRemove
));
169 // Do not write to cache_log after our PID file is removed because another
170 // instance may already be logging there. Stop logging now because, if we
171 // wait until safeunlink(), some debugs() may slip through into the now
172 // "unlocked" cache_log, especially if we avoid the sensitive suid() area.
173 // Use stderr to capture late debugs() that did not make it into cache_log.
174 Debug::StopCacheLogUse();
176 const char *filename
= ThePidFileToRemove
.c_str(); // avoid complex operations inside enter_suid()
178 safeunlink(filename
, 0);
181 ThePidFileToRemove
.clear();
184 /// creates a PID file; throws on error
186 Instance::WriteOurPid()
188 // Instance code assumes that we do not support PID filename reconfiguration
189 static bool called
= false;
193 const auto filename
= PidFilename();
194 if (filename
.isEmpty())
195 return; // nothing to do
197 File
pidFile(filename
, File::Be::ReadWrite().locked().createdIfMissing().openedByRoot());
199 // another instance may have started after the caller checked (if it did)
200 ThrowIfAlreadyRunningWith(pidFile
);
202 /* now we know that we own the PID file created and/or locked above */
204 // Cleanup is scheduled through atexit() to ensure both:
205 // - cleanup upon fatal() and similar "unplanned" exits and
206 // - enter_suid() existence and proper logging support during cleanup.
207 // Even without PID filename reconfiguration support, we have to remember
208 // the file name we have used because Config.pidFilename may change!
209 (void)std::atexit(&RemoveInstance
); // failures leave the PID file on disk
210 ThePidFileToRemove
= filename
;
212 /* write our PID to the locked file */
214 pidBuf
.Printf("%d\n", static_cast<int>(getpid()));
216 pidFile
.writeAll(pidBuf
);
218 // We must fsync before releasing the lock or other Squid processes may not see
219 // our written PID (and decide that they are dealing with a corrupted PID file).
220 pidFile
.synchronize();
222 debugs(50, Important(23), "Created " << TheFile
);