]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/Instance.cc
2 * Copyright (C) 1996-2020 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"
13 #include "parser/Tokenizer.h"
14 #include "sbuf/Stream.h"
15 #include "SquidConfig.h"
20 /* To support concurrent PID files, convert local statics into PidFile class */
22 /// Describes the (last) instance PID file being processed.
23 /// This hack shortens reporting code while keeping its messages consistent.
26 /// PidFilename() helper
27 /// \returns PID file name or, if PID signaling was disabled, an empty SBuf
31 if (!Config
.pidFilename
|| strcmp(Config
.pidFilename
, "none") == 0)
34 // If chroot has been requested, then we first read the PID file before
35 // chroot() and then create/update it inside a chrooted environment.
36 // TODO: Consider removing half-baked chroot support from Squid.
38 if (!Config
.chroot_dir
|| Chrooted
) // no need to compensate
39 return SBuf(Config
.pidFilename
);
42 filename
.append(Config
.chroot_dir
);
44 filename
.append(Config
.pidFilename
);
45 debugs(50, 3, "outside chroot: " << filename
);
49 /// \returns PID file description for debugging messages and error reporting
51 PidFileDescription(const SBuf
&filename
)
53 return ToSBuf("PID file (", filename
, ')');
56 /// Instance entry points are expected to call this first.
57 /// \returns PidFilenameCalc() result while updating TheFile context
61 const auto name
= PidFilenameCalc();
62 TheFile
= PidFileDescription(name
);
66 /// \returns the PID of another Squid instance (or throws)
68 GetOtherPid(File
&pidFile
)
70 const auto input
= pidFile
.readSmall(1, 32);
73 Parser::Tokenizer
tok(input
);
74 if (!(tok
.int64(rawPid
, 10, false) && // PID digits
75 (tok
.skipOne(CharacterSet::CR
)||true) && // optional CR (Windows/etc.)
76 tok
.skipOne(CharacterSet::LF
) && // required end of line
77 tok
.atEnd())) { // no trailing garbage
78 throw TexcHere(ToSBuf("Malformed ", TheFile
));
81 debugs(50, 7, "found PID " << rawPid
<< " in " << TheFile
);
84 throw TexcHere(ToSBuf("Bad ", TheFile
, " contains unreasonably small PID value: ", rawPid
));
85 const auto finalPid
= static_cast<pid_t
>(rawPid
);
86 if (static_cast<int64_t>(finalPid
) != rawPid
)
87 throw TexcHere(ToSBuf("Bad ", TheFile
, " contains unreasonably large PID value: ", rawPid
));
92 /// determines whether a given process is running at the time of the call
94 ProcessIsRunning(const pid_t pid
)
96 const auto result
= kill(pid
, 0);
97 const auto savedErrno
= errno
;
99 debugs(50, 3, "kill(" << pid
<< ", 0) failed: " << xstrerr(savedErrno
));
100 // if we do not have permissions to signal the process, then it is running
101 return (result
== 0 || savedErrno
== EPERM
);
104 /// quits if another Squid instance (that owns the given PID file) is running
106 ThrowIfAlreadyRunningWith(File
&pidFile
)
108 bool running
= false;
111 const auto pid
= GetOtherPid(pidFile
);
112 description
= ToSBuf(TheFile
, " with PID ", pid
);
113 running
= ProcessIsRunning(pid
);
115 catch (const std::exception
&ex
) {
116 debugs(50, 5, "assuming no other Squid instance: " << ex
.what());
121 throw TexcHere(ToSBuf("Squid is already running: Found fresh instance ", description
));
123 debugs(50, 5, "assuming stale instance " << description
);
129 const auto filename
= PidFilename();
130 if (filename
.isEmpty())
131 throw TexcHere("no pid_filename configured");
133 File
pidFile(filename
, File::Be::ReadOnly().locked());
134 return GetOtherPid(pidFile
);
138 Instance::ThrowIfAlreadyRunning()
140 const auto filename
= PidFilename();
141 if (filename
.isEmpty())
142 return; // the check is impossible
144 if (const auto filePtr
= File::Optional(filename
, File::Be::ReadOnly().locked())) {
145 const std::unique_ptr
<File
> pidFile(filePtr
);
146 ThrowIfAlreadyRunningWith(*pidFile
);
148 // It is best to assume then to check because checking without a lock
149 // might lead to false positives that lead to no Squid starting at all!
150 debugs(50, 5, "cannot lock " << TheFile
<< "; assuming no other Squid is running");
151 // If our assumption is false, we will fail to _create_ the PID file,
152 // and, hence, will not start, allowing that other Squid to run.
156 /// ties Instance::WriteOurPid() scheduler and RemoveInstance(void) handler
157 static SBuf ThePidFileToRemove
;
159 /// atexit() handler; removes the PID file created with Instance::WriteOurPid()
163 if (ThePidFileToRemove
.isEmpty()) // not the PidFilename()!
164 return; // nothing to do
166 debugs(50, DBG_IMPORTANT
, "Removing " << PidFileDescription(ThePidFileToRemove
));
167 const char *filename
= ThePidFileToRemove
.c_str(); // avoid complex operations inside enter_suid()
169 safeunlink(filename
, 0);
172 ThePidFileToRemove
.clear();
175 /// creates a PID file; throws on error
177 Instance::WriteOurPid()
179 // Instance code assumes that we do not support PID filename reconfiguration
180 static bool called
= false;
184 const auto filename
= PidFilename();
185 if (filename
.isEmpty())
186 return; // nothing to do
188 File
pidFile(filename
, File::Be::ReadWrite().locked().createdIfMissing().openedByRoot());
190 // another instance may have started after the caller checked (if it did)
191 ThrowIfAlreadyRunningWith(pidFile
);
193 /* now we know that we own the PID file created and/or locked above */
195 // Cleanup is scheduled through atexit() to ensure both:
196 // - cleanup upon fatal() and similar "unplanned" exits and
197 // - enter_suid() existence and proper logging support during cleanup.
198 // Even without PID filename reconfiguration support, we have to remember
199 // the file name we have used because Config.pidFilename may change!
200 (void)std::atexit(&RemoveInstance
); // failures leave the PID file on disk
201 ThePidFileToRemove
= filename
;
203 /* write our PID to the locked file */
205 pidBuf
.Printf("%d\n", static_cast<int>(getpid()));
207 pidFile
.writeAll(pidBuf
);
209 // We must fsync before releasing the lock or other Squid processes may not see
210 // our written PID (and decide that they are dealing with a corrupted PID file).
211 pidFile
.synchronize();
213 debugs(50, DBG_IMPORTANT
, "Created " << TheFile
);