]> git.ipfire.org Git - thirdparty/squid.git/blame - src/main.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / main.cc
CommitLineData
30a4f2a8 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
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.
30a4f2a8 7 */
44a47c6e 8
bbc27441
AJ
9/* DEBUG: section 01 Startup and Main Loop */
10
582c2af2 11#include "squid.h"
450e0c10 12#include "AccessLogEntry.h"
582c2af2
FC
13#include "acl/Acl.h"
14#include "acl/Asn.h"
5c112575
AJ
15#include "auth/Config.h"
16#include "auth/Gadgets.h"
ae578099 17#include "AuthReg.h"
6d57128b 18#include "base/RunnersRegistry.h"
e0d28505 19#include "base/Subscription.h"
3d93a84d 20#include "base/TextException.h"
fc54b8d2 21#include "cache_cf.h"
3c670b50 22#include "CachePeer.h"
fc54b8d2
FC
23#include "carp.h"
24#include "client_db.h"
25#include "client_side.h"
d841c88d 26#include "comm.h"
62ee09ca 27#include "ConfigParser.h"
96c2bb61 28#include "CpuAffinity.h"
582c2af2 29#include "DiskIO/DiskIOModule.h"
4a3b98d7 30#include "dns/forward.h"
aa839030 31#include "errorpage.h"
a553a5a3 32#include "event.h"
33#include "EventLoop.h"
62ee09ca 34#include "ExternalACL.h"
fc54b8d2 35#include "fd.h"
31971e6a 36#include "format/Token.h"
fc54b8d2 37#include "fqdncache.h"
602d9612 38#include "fs/Module.h"
b3f7fd88 39#include "fs_io.h"
eb13c21e 40#include "FwdState.h"
af69c635 41#include "globals.h"
582c2af2 42#include "htcp.h"
d3dddfb5 43#include "http/Stream.h"
fc54b8d2 44#include "HttpHeader.h"
582c2af2
FC
45#include "HttpReply.h"
46#include "icmp/IcmpSquid.h"
47#include "icmp/net_db.h"
e6ccf245 48#include "ICP.h"
4daaf3cb 49#include "ident/Ident.h"
602d9612 50#include "ip/tools.h"
10cefb7b 51#include "ipc/Coordinator.h"
582c2af2 52#include "ipc/Kids.h"
10cefb7b 53#include "ipc/Strand.h"
602d9612 54#include "ipcache.h"
b65ce00c 55#include "mime.h"
fc54b8d2 56#include "neighbors.h"
d5f21615 57#include "parser/Tokenizer.h"
582c2af2 58#include "pconn.h"
fc54b8d2
FC
59#include "peer_sourcehash.h"
60#include "peer_userhash.h"
602d9612 61#include "PeerSelectState.h"
582c2af2 62#include "profiler/Profiler.h"
c548327a 63#include "redirect.h"
fc54b8d2 64#include "refresh.h"
d87f6b1d 65#include "SBufStatsAction.h"
bc94e5ca 66#include "send-announce.h"
4d5904f7 67#include "SquidConfig.h"
985c86bc 68#include "SquidTime.h"
fc54b8d2 69#include "stat.h"
e4f1fdae 70#include "StatCounters.h"
582c2af2 71#include "Store.h"
2745fea5 72#include "store/Disks.h"
602d9612
A
73#include "store_log.h"
74#include "StoreFileSystem.h"
602d9612 75#include "tools.h"
b6b42084 76#include "unlinkd.h"
fc54b8d2
FC
77#include "URL.h"
78#include "wccp.h"
79#include "wccp2.h"
cf3edd6f 80#include "WinSvc.h"
44a47c6e 81
582c2af2
FC
82#if USE_ADAPTATION
83#include "adaptation/Config.h"
84#endif
85#if USE_ECAP
86#include "adaptation/ecap/Config.h"
87#endif
88#if ICAP_CLIENT
89#include "adaptation/icap/Config.h"
90#include "adaptation/icap/icap_log.h"
91#endif
582c2af2
FC
92#if USE_DELAY_POOLS
93#include "ClientDelayConfig.h"
94#endif
95#if USE_DELAY_POOLS
96#include "DelayPools.h"
97#endif
57afc994
AR
98#if USE_LOADABLE_MODULES
99#include "LoadableModules.h"
100#endif
cb4f4424 101#if USE_OPENSSL
95d2589c 102#include "ssl/context_storage.h"
602d9612 103#include "ssl/helper.h"
95d2589c 104#endif
b958cb0f 105#if ICAP_CLIENT
26cc52cb 106#include "adaptation/icap/Config.h"
b958cb0f 107#endif
6e5db507 108#if USE_ECAP
1f3c65fc 109#include "adaptation/ecap/Config.h"
6e5db507 110#endif
b958cb0f
AR
111#if USE_ADAPTATION
112#include "adaptation/Config.h"
113#endif
79039294
AR
114#if USE_SQUID_ESI
115#include "esi/Module.h"
116#endif
9c0a2256
FC
117#if SQUID_SNMP
118#include "snmp_core.h"
119#endif
7b5b7ba8 120
1a30fdf5 121#include <cerrno>
68dbbe5d
AJ
122#if HAVE_GETOPT_H
123#include <getopt.h>
124#endif
25f98340
AJ
125#if HAVE_PATHS_H
126#include <paths.h>
127#endif
582c2af2
FC
128#if HAVE_SYS_WAIT_H
129#include <sys/wait.h>
130#endif
1a774556 131
25f98340 132#if USE_WIN32_SERVICE
1a774556 133#include <process.h>
134
135static int opt_install_service = FALSE;
136static int opt_remove_service = FALSE;
1a774556 137static int opt_command_line = FALSE;
82afb125 138void WIN32_svcstatusupdate(DWORD, DWORD);
1a774556 139void WINAPI WIN32_svcHandler(DWORD);
1a774556 140#endif
141
cf2155f2 142static int opt_signal_service = FALSE;
5e6d4736 143static char *opt_syslog_facility = NULL;
f53969cc 144static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
e13ee7ad 145static int configured_once = 0;
30a4f2a8 146#if MALLOC_DBG
4d64d74a 147static int malloc_debug_level = 0;
30a4f2a8 148#endif
5cd39a10 149static volatile int do_reconfigure = 0;
150static volatile int do_rotate = 0;
2681d383 151static volatile int do_shutdown = 0;
ae1feb30 152static volatile int shutdown_status = 0;
dbf55289 153static volatile int do_handle_stopped_child = 0;
4d7add01 154
a2c48c98
AR
155static int RotateSignal = -1;
156static int ReconfigureSignal = -1;
157static int ShutdownSignal = -1;
158
5cd39a10 159static void mainRotate(void);
d71e4674
AR
160static void mainReconfigureStart(void);
161static void mainReconfigureFinish(void*);
f5b8bbc4 162static void mainInitialize(void);
f5b8bbc4 163static void usage(void);
63be0a78 164static void mainParseOptions(int argc, char *argv[]);
f5b8bbc4 165static void sendSignal(void);
166static void serverConnectionsOpen(void);
d71e4674 167static void serverConnectionsClose(void);
bbe199dc 168static void watch_child(char **);
85407535 169static void setEffectiveUser(void);
8ff3fa2e 170static void SquidShutdown(void);
b6a2f15e 171static void mainSetCwd(void);
efd900cb 172static int checkRunningPid(void);
85407535 173
7aa9bb3e 174#if !_SQUID_WINDOWS_
e18d7fdc 175static const char *squid_start_script = "squid_start";
b293c4d8 176#endif
e18d7fdc 177
9bc73deb 178#if TEST_ACCESS
179#include "test_access.c"
180#endif
181
63be0a78 182/** temporary thunk across to the unrefactored store interface */
8ff3fa2e 183
184class StoreRootEngine : public AsyncEngine
185{
186
187public:
ced8def3 188 int checkEvents(int) {
8ff3fa2e 189 Store::Root().callback();
190 return EVENT_IDLE;
191 };
192};
193
9688b0ae 194class SignalEngine: public AsyncEngine
a553a5a3 195{
196
197public:
dbf55289
CT
198#if KILL_PARENT_OPT
199 SignalEngine(): parentKillNotified(false) {
200 parentPid = getppid();
201 }
202#endif
203
9688b0ae 204 virtual int checkEvents(int timeout);
a553a5a3 205
206private:
0a720258
AR
207 static void StopEventLoop(void *) {
208 if (EventLoop::Running)
209 EventLoop::Running->stop();
a553a5a3 210 }
211
d442618d
AJ
212 static void FinalShutdownRunners(void *) {
213 RunRegisteredHere(RegisteredRunner::endingShutdown);
214
215 // XXX: this should be a Runner.
216#if USE_AUTH
217 /* detach the auth components (only do this on full shutdown) */
218 Auth::Scheme::FreeAll();
219#endif
220
221 eventAdd("SquidTerminate", &StopEventLoop, NULL, 0, 1, false);
222 }
223
9688b0ae 224 void doShutdown(time_t wait);
dbf55289
CT
225 void handleStoppedChild();
226
227#if KILL_PARENT_OPT
228 bool parentKillNotified;
229 pid_t parentPid;
230#endif
a553a5a3 231};
232
9688b0ae 233int
ced8def3 234SignalEngine::checkEvents(int)
a553a5a3 235{
9688b0ae 236 PROF_start(SignalEngine_checkEvents);
fc68f6b1 237
39d48b4f
AR
238 if (do_reconfigure)
239 mainReconfigureStart();
240 else if (do_rotate)
a553a5a3 241 mainRotate();
39d48b4f 242 else if (do_shutdown)
9688b0ae 243 doShutdown(do_shutdown > 0 ? (int) Config.shutdownLifetime : 0);
39d48b4f 244 if (do_handle_stopped_child)
dbf55289 245 handleStoppedChild();
9688b0ae 246 PROF_stop(SignalEngine_checkEvents);
247 return EVENT_IDLE;
248}
a553a5a3 249
39d48b4f
AR
250/// Decides whether the signal-controlled action X should be delayed, canceled,
251/// or executed immediately. Clears do_X (via signalVar) as needed.
252static bool
253AvoidSignalAction(const char *description, volatile int &signalVar)
254{
255 const char *avoiding = "delaying";
256 const char *currentEvent = "none";
257 if (shutting_down) {
258 currentEvent = "shutdown";
259 avoiding = "canceling";
b4db757f
AJ
260 // do not avoid repeated shutdown signals
261 // which just means the user wants to skip/abort shutdown timeouts
262 if (strcmp(currentEvent, description) == 0)
263 return false;
39d48b4f
AR
264 signalVar = 0;
265 }
266 else if (!configured_once)
267 currentEvent = "startup";
268 else if (reconfiguring)
269 currentEvent = "reconfiguration";
270 else {
271 signalVar = 0;
272 return false; // do not avoid (i.e., execute immediately)
273 // the caller may produce a signal-specific debugging message
274 }
275
276 debugs(1, DBG_IMPORTANT, avoiding << ' ' << description <<
277 " request during " << currentEvent);
278 return true;
279}
280
9688b0ae 281void
282SignalEngine::doShutdown(time_t wait)
283{
39d48b4f
AR
284 if (AvoidSignalAction("shutdown", do_shutdown))
285 return;
286
e0236918
FC
287 debugs(1, DBG_IMPORTANT, "Preparing for shutdown after " << statCounter.client_http.requests << " requests");
288 debugs(1, DBG_IMPORTANT, "Waiting " << wait << " seconds for active connections to finish");
8ff3fa2e 289
dbf55289
CT
290#if KILL_PARENT_OPT
291 if (!IamMasterProcess() && !parentKillNotified && ShutdownSignal > 0 && parentPid > 1) {
292 debugs(1, DBG_IMPORTANT, "Killing master process, pid " << parentPid);
b69e9ffa
AJ
293 if (kill(parentPid, ShutdownSignal) < 0) {
294 int xerrno = errno;
295 debugs(1, DBG_IMPORTANT, "kill " << parentPid << ": " << xstrerr(xerrno));
296 }
dbf55289
CT
297 parentKillNotified = true;
298 }
299#endif
9688b0ae 300
dbf55289
CT
301 if (shutting_down) {
302#if !KILL_PARENT_OPT
303 // Already a shutdown signal has received and shutdown is in progress.
304 // Shutdown as soon as possible.
305 wait = 0;
9688b0ae 306#endif
5c634111 307 } else {
dbf55289 308 shutting_down = 1;
9688b0ae 309
dbf55289
CT
310 /* run the closure code which can be shared with reconfigure */
311 serverConnectionsClose();
dbf55289
CT
312
313 RunRegisteredHere(RegisteredRunner::startShutdown);
314 }
315
316#if USE_WIN32_SERVICE
5c634111 317 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
2f1431ea 318#endif
21b7990f 319
d442618d 320 eventAdd("SquidShutdown", &FinalShutdownRunners, this, (double) (wait + 1), 1, false);
a553a5a3 321}
322
dbf55289
CT
323void
324SignalEngine::handleStoppedChild()
325{
39d48b4f
AR
326 // no AvoidSignalAction() call: This code can run at any time because it
327 // does not depend on Squid state. It does not need debugging because it
328 // handles an "internal" signal, not an external/admin command.
329 do_handle_stopped_child = 0;
dbf55289
CT
330#if !_SQUID_WINDOWS_
331 PidStatus status;
332 pid_t pid;
333
334 do {
335 pid = WaitForAnyPid(status, WNOHANG);
336
337#if HAVE_SIGACTION
338
339 } while (pid > 0);
340
341#else
342
5c634111
SM
343 }
344 while (pid > 0 || (pid < 0 && errno == EINTR));
dbf55289
CT
345#endif
346#endif
347}
348
b8d8561b 349static void
0673c0ba 350usage(void)
ccff9601 351{
0ee4272b 352 fprintf(stderr,
68dbbe5d 353 "Usage: %s [-cdzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]"
0e657244 354#if USE_WIN32_SERVICE
cf2155f2 355 "[-ir] [-O CommandLine]"
0e657244 356#endif
68dbbe5d
AJ
357 "\n"
358 " -h | --help Print help message.\n"
359 " -v | --version Print version details.\n"
cf2155f2 360 "\n"
62e76326 361 " -a port Specify HTTP port number (default: %d).\n"
362 " -d level Write debugging to stderr also.\n"
363 " -f file Use given config-file instead of\n"
364 " %s\n"
0e657244 365#if USE_WIN32_SERVICE
366 " -i Installs as a Windows Service (see -n option).\n"
367#endif
98fcbb0e
AJ
368 " -k reconfigure|rotate|shutdown|"
369#ifdef SIGTTIN
370 "restart|"
371#endif
372 "interrupt|kill|debug|check|parse\n"
62e76326 373 " Parse configuration file, then send signal to \n"
374 " running copy (except -k parse) and exit.\n"
cf2155f2
AJ
375 " -n name Specify service name to use for service operations\n"
376 " default is: " APP_SHORTNAME ".\n"
0e657244 377#if USE_WIN32_SERVICE
0e657244 378 " -r Removes a Windows Service (see -n option).\n"
379#endif
5e6d4736 380 " -s | -l facility\n"
381 " Enable logging to syslog.\n"
62e76326 382 " -u port Specify ICP port number (default: %d), disable with 0.\n"
04632397 383 " -z Create missing swap directories and then exit.\n"
62e76326 384 " -C Do not catch fatal signals.\n"
8eb28163 385 " -D OBSOLETE. Scheduled for removal.\n"
62e76326 386 " -F Don't serve any requests until store is rebuilt.\n"
387 " -N No daemon mode.\n"
effda67e
MM
388 " --foreground\n"
389 " Parent process does not exit until its children have finished.\n"
0e657244 390#if USE_WIN32_SERVICE
391 " -O options\n"
392 " Set Windows Service Command line options in Registry.\n"
393#endif
62e76326 394 " -R Do not set REUSEADDR on port.\n"
395 " -S Double-check swap during rebuild.\n"
62e76326 396 " -X Force full debugging.\n"
397 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
7dbca7a4 398 APP_SHORTNAME, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
77ffc99f 399 exit(1);
ccff9601 400}
401
63be0a78 402/**
403 * Parse the parameters received via command line interface.
404 *
68dbbe5d
AJ
405 * \param argc Number of options received on command line
406 * \param argv List of parameters received on command line
63be0a78 407 */
b8d8561b 408static void
409mainParseOptions(int argc, char *argv[])
090089c4 410{
68dbbe5d 411 int optIndex = 0;
090089c4 412
68dbbe5d
AJ
413 // short options
414 const char *shortOpStr =
0e657244 415#if USE_WIN32_SERVICE
f53969cc 416 "O:Vir"
0e657244 417#endif
f53969cc 418 "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?";
68dbbe5d
AJ
419
420 // long options
421 static struct option squidOptions[] = {
effda67e
MM
422 {"foreground", no_argument, 0, 1 },
423 {"help", no_argument, 0, 'h'},
424 {"version", no_argument, 0, 'v'},
68dbbe5d
AJ
425 {0, 0, 0, 0}
426 };
427
428 int c;
429 while ((c = getopt_long(argc, argv, shortOpStr, squidOptions, &optIndex)) != -1) {
9b7292ce 430
26ac0430 431 switch (c) {
62e76326 432
433 case 'C':
63be0a78 434 /** \par C
435 * Unset/disabel global option for catchign signals. opt_catch_signals */
62e76326 436 opt_catch_signals = 0;
437 break;
438
439 case 'D':
63be0a78 440 /** \par D
8eb28163
AJ
441 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
442 debugs(1,DBG_CRITICAL, "WARNING: -D command-line option is obsolete.");
62e76326 443 break;
444
445 case 'F':
63be0a78 446 /** \par F
447 * Set global option for foreground rebuild. opt_foreground_rebuild */
62e76326 448 opt_foreground_rebuild = 1;
449 break;
450
451 case 'N':
63be0a78 452 /** \par N
453 * Set global option for 'no_daemon' mode. opt_no_daemon */
62e76326 454 opt_no_daemon = 1;
455 break;
63be0a78 456
0e657244 457#if USE_WIN32_SERVICE
458
459 case 'O':
63be0a78 460 /** \par O
461 * Set global option. opt_command_lin and WIN32_Command_Line */
0e657244 462 opt_command_line = 1;
463 WIN32_Command_Line = xstrdup(optarg);
464 break;
465#endif
62e76326 466
467 case 'R':
63be0a78 468 /** \par R
469 * Unset/disable global option opt_reuseaddr */
62e76326 470 opt_reuseaddr = 0;
471 break;
472
473 case 'S':
63be0a78 474 /** \par S
475 * Set global option opt_store_doublecheck */
62e76326 476 opt_store_doublecheck = 1;
477 break;
478
62e76326 479 case 'X':
63be0a78 480 /** \par X
481 * Force full debugging */
62493678
AJ
482 Debug::parseOptions("rotate=0 ALL,9");
483 Debug::override_X = 1;
62e76326 484 sigusr2_handle(SIGUSR2);
62e76326 485 break;
486
487 case 'Y':
63be0a78 488 /** \par Y
489 * Set global option opt_reload_hit_only */
62e76326 490 opt_reload_hit_only = 1;
62e76326 491 break;
492
0e657244 493#if USE_WIN32_SERVICE
494
495 case 'i':
63be0a78 496 /** \par i
497 * Set global option opt_install_service (to TRUE) */
0e657244 498 opt_install_service = TRUE;
0e657244 499 break;
0e657244 500#endif
501
62e76326 502 case 'a':
63be0a78 503 /** \par a
504 * Add optional HTTP port as given following the option */
62e76326 505 add_http_port(optarg);
62e76326 506 break;
507
508 case 'd':
63be0a78 509 /** \par d
68dbbe5d 510 * Set global option Debug::log_stderr to the number given following the option */
62493678 511 Debug::log_stderr = atoi(optarg);
62e76326 512 break;
513
514 case 'f':
63be0a78 515 /** \par f
516 * Load the file given instead of the default squid.conf. */
62e76326 517 xfree(ConfigFile);
62e76326 518 ConfigFile = xstrdup(optarg);
62e76326 519 break;
520
521 case 'k':
63be0a78 522 /** \par k
523 * Run the administrative action given following the option */
fc68f6b1 524
63be0a78 525 /** \li When its an unknown option display the usage help. */
62e76326 526 if ((int) strlen(optarg) < 1)
527 usage();
528
529 if (!strncmp(optarg, "reconfigure", strlen(optarg)))
63be0a78 530 /** \li On reconfigure send SIGHUP. */
62e76326 531 opt_send_signal = SIGHUP;
532 else if (!strncmp(optarg, "rotate", strlen(optarg)))
63be0a78 533 /** \li On rotate send SIGQUIT or SIGUSR1. */
605f2c3e 534#if defined(_SQUID_LINUX_THREADS_)
62e76326 535 opt_send_signal = SIGQUIT;
e3175d1f 536#else
62e76326 537 opt_send_signal = SIGUSR1;
e3175d1f 538#endif
62e76326 539
540 else if (!strncmp(optarg, "debug", strlen(optarg)))
63be0a78 541 /** \li On debug send SIGTRAP or SIGUSR2. */
605f2c3e 542#if defined(_SQUID_LINUX_THREADS_)
62e76326 543 opt_send_signal = SIGTRAP;
e3175d1f 544#else
62e76326 545 opt_send_signal = SIGUSR2;
62e76326 546#endif
547
548 else if (!strncmp(optarg, "shutdown", strlen(optarg)))
63be0a78 549 /** \li On shutdown send SIGTERM. */
62e76326 550 opt_send_signal = SIGTERM;
551 else if (!strncmp(optarg, "interrupt", strlen(optarg)))
63be0a78 552 /** \li On interrupt send SIGINT. */
62e76326 553 opt_send_signal = SIGINT;
554 else if (!strncmp(optarg, "kill", strlen(optarg)))
63be0a78 555 /** \li On kill send SIGKILL. */
62e76326 556 opt_send_signal = SIGKILL;
ae1feb30 557
558#ifdef SIGTTIN
559
560 else if (!strncmp(optarg, "restart", strlen(optarg)))
63be0a78 561 /** \li On restart send SIGTTIN. (exit and restart by parent) */
562 opt_send_signal = SIGTTIN;
ae1feb30 563
564#endif
565
62e76326 566 else if (!strncmp(optarg, "check", strlen(optarg)))
63be0a78 567 /** \li On check send 0 / SIGNULL. */
f53969cc 568 opt_send_signal = 0; /* SIGNULL */
62e76326 569 else if (!strncmp(optarg, "parse", strlen(optarg)))
63be0a78 570 /** \li On parse set global flag to re-parse the config file only. */
571 opt_parse_cfg_only = 1;
62e76326 572 else
573 usage();
574
575 break;
576
577 case 'm':
63be0a78 578 /** \par m
579 * Set global malloc_debug_level to the value given following the option.
580 * if none is given it toggles the xmalloc_trace option on/off */
62e76326 581 if (optarg) {
30a4f2a8 582#if MALLOC_DBG
fc68f6b1 583 malloc_debug_level = atoi(optarg);
30a4f2a8 584#else
fc68f6b1 585 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
33ab18e8 586#endif
62e76326 587
e2849af8 588 }
d9e7ee1f 589 break;
d9e7ee1f 590
0e657244 591 case 'n':
63be0a78 592 /** \par n
cf2155f2
AJ
593 * Set global option opt_signal_service (to true).
594 * Stores the additional parameter given in global service_name */
eeae1733 595 if (optarg && *optarg != '\0') {
d5f21615
AJ
596 const SBuf t(optarg);
597 ::Parser::Tokenizer tok(t);
598 const CharacterSet chr = CharacterSet::ALPHA+CharacterSet::DIGIT;
8cb327e9
AR
599 if (!tok.prefix(service_name, chr))
600 fatalf("Expected alphanumeric service name for the -n option but got: %s", optarg);
601 if (!tok.atEnd())
602 fatalf("Garbage after alphanumeric service name in the -n option value: %s", optarg);
d5f21615
AJ
603 if (service_name.length() > 32)
604 fatalf("Service name (-n option) must be limited to 32 characters but got %u", service_name.length());
605 opt_signal_service = true;
606 } else {
607 fatal("A service name is required for the -n option");
608 }
0e657244 609 break;
610
cf2155f2
AJ
611#if USE_WIN32_SERVICE
612
0e657244 613 case 'r':
63be0a78 614 /** \par r
615 * Set global option opt_remove_service (to TRUE) */
0e657244 616 opt_remove_service = TRUE;
617
618 break;
619
620#endif
621
5e6d4736 622 case 'l':
63be0a78 623 /** \par l
624 * Stores the syslog facility name in global opt_syslog_facility
625 * then performs actions for -s option. */
5c6dae44 626 xfree(opt_syslog_facility); // ignore any previous options sent
5e6d4736 627 opt_syslog_facility = xstrdup(optarg);
628
62e76326 629 case 's':
63be0a78 630 /** \par s
631 * Initialize the syslog for output */
c307aec3 632#if HAVE_SYSLOG
62e76326 633
5e6d4736 634 _db_set_syslog(opt_syslog_facility);
0e657244 635
62e76326 636 break;
0e657244 637
c307aec3 638#else
62e76326 639
640 fatal("Logging to syslog not available on this platform");
0e657244 641
62e76326 642 /* NOTREACHED */
643#endif
644
645 case 'u':
63be0a78 646 /** \par u
647 * Store the ICP port number given in global option icpPortNumOverride
648 * ensuring its a positive number. */
62e76326 649 icpPortNumOverride = atoi(optarg);
650
651 if (icpPortNumOverride < 0)
652 icpPortNumOverride = 0;
653
654 break;
655
656 case 'v':
63be0a78 657 /** \par v
658 * Display squid version and build information. Then exit. */
4fe75473 659 printf("Squid Cache: Version %s\n" ,version_string);
d5f21615 660 printf("Service Name: " SQUIDSBUFPH "\n", SQUIDSBUFPRINT(service_name));
4fe75473
FC
661 if (strlen(SQUID_BUILD_INFO))
662 printf("%s\n",SQUID_BUILD_INFO);
663 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS);
62e76326 664
1a774556 665#if USE_WIN32_SERVICE
666
667 printf("Compiled as Windows System Service.\n");
668
669#endif
670
62e76326 671 exit(0);
672
f53969cc 673 /* NOTREACHED */
62e76326 674
675 case 'z':
63be0a78 676 /** \par z
62493678
AJ
677 * Set global option Debug::log_stderr and opt_create_swap_dirs */
678 Debug::log_stderr = 1;
62e76326 679 opt_create_swap_dirs = 1;
62e76326 680 break;
681
effda67e
MM
682 case 1:
683 /** \par --foreground
684 * Set global option opt_foreground */
685 opt_foreground = 1;
686 break;
687
63be0a78 688 case 'h':
689
62e76326 690 case '?':
691
692 default:
63be0a78 693 /** \par h,?, or unknown
694 * \copydoc usage() */
62e76326 695 usage();
696
697 break;
698 }
9b7292ce 699
090089c4 700 }
4d64d74a 701}
090089c4 702
7a2f978b 703/* ARGSUSED */
b293c4d8 704void
9b7292ce 705rotate_logs(int sig)
706{
5cd39a10 707 do_rotate = 1;
a2c48c98 708 RotateSignal = sig;
7aa9bb3e 709#if !_SQUID_WINDOWS_
30a4f2a8 710#if !HAVE_SIGACTION
62e76326 711
30a4f2a8 712 signal(sig, rotate_logs);
713#endif
a50bfe93 714#endif
30a4f2a8 715}
716
7a2f978b 717/* ARGSUSED */
b293c4d8 718void
9b7292ce 719reconfigure(int sig)
720{
5cd39a10 721 do_reconfigure = 1;
a2c48c98 722 ReconfigureSignal = sig;
7aa9bb3e 723#if !_SQUID_WINDOWS_
30a4f2a8 724#if !HAVE_SIGACTION
62e76326 725
30a4f2a8 726 signal(sig, reconfigure);
727#endif
a50bfe93 728#endif
30a4f2a8 729}
730
dbf55289
CT
731/// Shutdown signal handler for master process
732void
733master_shutdown(int sig)
734{
735 do_shutdown = 1;
736 ShutdownSignal = sig;
737
738#if !_SQUID_WINDOWS_
739#if !HAVE_SIGACTION
740 signal(sig, master_shutdown);
741#endif
742#endif
743
744}
745
b8d8561b 746void
9b7292ce 747shut_down(int sig)
748{
2681d383 749 do_shutdown = sig == SIGINT ? -1 : 1;
a2c48c98 750 ShutdownSignal = sig;
d75df34a 751#if defined(SIGTTIN)
ae1feb30 752 if (SIGTTIN == sig)
753 shutdown_status = 1;
ae1feb30 754#endif
ca4b9ee6 755
d75df34a 756#if !_SQUID_WINDOWS_
dbf55289
CT
757#if !HAVE_SIGACTION
758 signal(sig, shut_down);
759#endif
760#endif
761}
62e76326 762
dbf55289
CT
763void
764sig_child(int sig)
765{
766 do_handle_stopped_child = 1;
62e76326 767
dbf55289
CT
768#if !_SQUID_WINDOWS_
769#if !HAVE_SIGACTION
770 signal(sig, sig_child);
a50bfe93 771#endif
6e40f263 772#endif
30a4f2a8 773}
774
24382924 775static void
9b7292ce 776serverConnectionsOpen(void)
777{
7de94c8c
AR
778 if (IamPrimaryProcess()) {
779#if USE_WCCP
5667a628 780 wccpConnectionOpen();
7de94c8c 781#endif
45aae82b 782
7de94c8c
AR
783#if USE_WCCPv2
784
5667a628 785 wccp2ConnectionOpen();
7de94c8c
AR
786#endif
787 }
095ec2b1
AR
788 // start various proxying services if we are responsible for them
789 if (IamWorkerProcess()) {
5667a628 790 clientOpenListenSockets();
65d448bc 791 icpOpenPorts();
ace287ee 792#if USE_HTCP
65d448bc 793 htcpOpenPorts();
ace287ee 794#endif
a67d2b2e 795#if SQUID_SNMP
65d448bc 796 snmpOpenPorts();
320e9f36 797#endif
0b0cfcf2 798
5667a628
AR
799 icmpEngine.Open();
800 netdbInit();
801 asnInit();
802 ACL::Initialize();
803 peerSelectInit();
804
805 carpInit();
2f1431ea 806#if USE_AUTH
5667a628 807 peerUserHashInit();
2f1431ea 808#endif
5667a628 809 peerSourceHashInit();
7de94c8c 810 }
5f3f8d0e 811}
812
d71e4674 813static void
9b7292ce 814serverConnectionsClose(void)
815{
0a5a8601 816 assert(shutting_down || reconfiguring);
7de94c8c
AR
817
818 if (IamPrimaryProcess()) {
819#if USE_WCCP
820
5667a628 821 wccpConnectionClose();
7de94c8c
AR
822#endif
823#if USE_WCCPv2
824
5667a628 825 wccp2ConnectionClose();
7de94c8c
AR
826#endif
827 }
095ec2b1 828 if (IamWorkerProcess()) {
434a79b0 829 clientConnectionsClose();
5667a628 830 icpConnectionShutdown();
72549e05 831#if USE_HTCP
5667a628 832 htcpSocketShutdown();
72549e05 833#endif
62e76326 834
5667a628 835 icmpEngine.Close();
a67d2b2e 836#if SQUID_SNMP
65d448bc 837 snmpClosePorts();
320e9f36 838#endif
62e76326 839
5667a628 840 asnFreeMemory();
7de94c8c 841 }
5f3f8d0e 842}
843
b8d8561b 844static void
d71e4674 845mainReconfigureStart(void)
9b7292ce 846{
39d48b4f
AR
847 if (AvoidSignalAction("reconfiguration", do_reconfigure))
848 return;
849
e0236918 850 debugs(1, DBG_IMPORTANT, "Reconfiguring Squid Cache (version " << version_string << ")...");
5cd39a10 851 reconfiguring = 1;
d71e4674 852
ee58de20
AJ
853 RunRegisteredHere(RegisteredRunner::startReconfigure);
854
d71e4674 855 // Initiate asynchronous closing sequence
15df8349 856 serverConnectionsClose();
65d448bc 857 icpClosePorts();
72549e05 858#if USE_HTCP
65d448bc 859 htcpClosePorts();
72549e05 860#endif
95d2589c
CT
861#if USE_SSL_CRTD
862 Ssl::Helper::GetInstance()->Shutdown();
863#endif
cb4f4424 864#if USE_OPENSSL
f54e3d4c
AR
865 if (Ssl::CertValidationHelper::GetInstance())
866 Ssl::CertValidationHelper::GetInstance()->Shutdown();
95d2589c
CT
867 Ssl::TheGlobalContextStorage.reconfigureStart();
868#endif
74addf6c 869 redirectShutdown();
2f1431ea 870#if USE_AUTH
0bcb6908 871 authenticateReset();
2f1431ea 872#endif
d9572179 873 externalAclShutdown();
2db68ce5 874 storeDirCloseSwapLogs();
2e923080 875 storeLogClose();
876 accessLogClose();
3ff65596
AR
877#if ICAP_CLIENT
878 icapLogClose();
879#endif
d71e4674
AR
880
881 eventAdd("mainReconfigureFinish", &mainReconfigureFinish, NULL, 0, 1,
26ac0430 882 false);
d71e4674
AR
883}
884
885static void
26ac0430
AJ
886mainReconfigureFinish(void *)
887{
d71e4674
AR
888 debugs(1, 3, "finishing reconfiguring");
889
c68e9c6b 890 errorClean();
f53969cc 891 enter_suid(); /* root to read config file */
936b23cd
AJ
892
893 // we may have disabled the need for PURGE
e1381638 894 if (Config2.onoff.enable_purge)
936b23cd
AJ
895 Config2.onoff.enable_purge = 2;
896
18631119 897 // parse the config returns a count of errors encountered.
13aeac35 898 const int oldWorkers = Config.workers;
8951901e
AJ
899 try {
900 if (parseConfigFile(ConfigFile) != 0) {
901 // for now any errors are a fatal condition...
902 self_destruct();
903 }
904 } catch (...) {
18631119 905 // for now any errors are a fatal condition...
8951901e
AJ
906 debugs(1, DBG_CRITICAL, "FATAL: Unhandled exception parsing config file. " <<
907 " Run squid -k parse and check for errors.");
18631119
AJ
908 self_destruct();
909 }
8951901e 910
13aeac35
AR
911 if (oldWorkers != Config.workers) {
912 debugs(1, DBG_CRITICAL, "WARNING: Changing 'workers' (from " <<
5667a628 913 oldWorkers << " to " << Config.workers <<
0b68976e 914 ") requires a full restart. It has been ignored by reconfigure.");
13aeac35 915 Config.workers = oldWorkers;
a2c48c98 916 }
936b23cd 917
21b7990f
AR
918 RunRegisteredHere(RegisteredRunner::syncConfig);
919
96c2bb61
AR
920 if (IamPrimaryProcess())
921 CpuAffinityCheck();
922 CpuAffinityReconfigure();
923
c642c141 924 setUmask(Config.umask);
97244680 925 Mem::Report();
3aa4adbc 926 setEffectiveUser();
62493678 927 _db_init(Debug::cache_log, Debug::debugOptions);
f53969cc
SM
928 ipcache_restart(); /* clear stuck entries */
929 fqdncache_restart(); /* sigh, fqdncache too */
0e70aa1e 930 parseEtcHosts();
f53969cc 931 errorInitialize(); /* reload error pages */
2e923080 932 accessLogInit();
76fc7e57
AJ
933
934#if USE_LOADABLE_MODULES
935 LoadableModulesConfigure(Config.loadable_module_names);
936#endif
937
938#if USE_ADAPTATION
939 bool enableAdaptation = false;
940#if ICAP_CLIENT
941 Adaptation::Icap::TheConfig.finalize();
942 enableAdaptation = Adaptation::Icap::TheConfig.onoff || enableAdaptation;
943#endif
944#if USE_ECAP
945 Adaptation::Ecap::TheConfig.finalize(); // must be after we load modules
946 enableAdaptation = Adaptation::Ecap::TheConfig.onoff || enableAdaptation;
947#endif
948 Adaptation::Config::Finalize(enableAdaptation);
949#endif
d090e020 950
3ff65596
AR
951#if ICAP_CLIENT
952 icapLogOpen();
953#endif
2e923080 954 storeLogOpen();
4a3b98d7 955 Dns::Init();
95d2589c
CT
956#if USE_SSL_CRTD
957 Ssl::Helper::GetInstance()->Init();
958#endif
cb4f4424 959#if USE_OPENSSL
2cef0ca6
AR
960 if (Ssl::CertValidationHelper::GetInstance())
961 Ssl::CertValidationHelper::GetInstance()->Init();
962#endif
62e76326 963
74addf6c 964 redirectInit();
2f1431ea 965#if USE_AUTH
5c112575 966 authenticateInit(&Auth::TheConfig.schemes);
2f1431ea 967#endif
d9572179 968 externalAclInit();
7de94c8c
AR
969
970 if (IamPrimaryProcess()) {
1f38f50a 971#if USE_WCCP
62e76326 972
5667a628 973 wccpInit();
1f38f50a 974#endif
0b0cfcf2 975#if USE_WCCPv2
976
5667a628 977 wccp2Init();
0b0cfcf2 978#endif
7de94c8c 979 }
62e76326 980
0ffd22bc 981 serverConnectionsOpen();
9c2e9b50 982
3ee2b4f8 983 neighbors_init();
9c2e9b50 984
2db68ce5 985 storeDirOpenSwapLogs();
9c2e9b50 986
9c021a38 987 mimeInit(Config.mimeTablePathname);
9c2e9b50 988
c521ad17
DK
989 if (unlinkdNeeded())
990 unlinkdInit();
c521ad17 991
9a0a18de 992#if USE_DELAY_POOLS
b4cd430a
CT
993 Config.ClientDelay.finalize();
994#endif
995
926375e6 996 if (Config.onoff.announce) {
997 if (!eventFind(start_announce, NULL))
998 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
999 } else {
1000 if (eventFind(start_announce, NULL))
1001 eventDelete(start_announce, NULL);
1002 }
1003
dbf55289 1004 if (!InDaemonMode())
5c634111 1005 writePidFile(); /* write PID file */
9c2e9b50 1006
5cd39a10 1007 reconfiguring = 0;
1008}
1009
1010static void
9b7292ce 1011mainRotate(void)
1012{
39d48b4f
AR
1013 if (AvoidSignalAction("log rotation", do_rotate))
1014 return;
1015
cc192b50 1016 icmpEngine.Close();
e40aa8da 1017 redirectShutdown();
2f1431ea 1018#if USE_AUTH
0bcb6908 1019 authenticateRotate();
2f1431ea 1020#endif
d9572179 1021 externalAclShutdown();
0a6dd8fb 1022
f53969cc 1023 _db_rotate_log(); /* cache.log */
5cd39a10 1024 storeDirWriteCleanLogs(1);
f53969cc
SM
1025 storeLogRotate(); /* store.log */
1026 accessLogRotate(); /* access.log */
3ff65596
AR
1027#if ICAP_CLIENT
1028 icapLogRotate(); /*icap.log*/
1029#endif
cc192b50 1030 icmpEngine.Open();
e40aa8da 1031 redirectInit();
2f1431ea 1032#if USE_AUTH
5c112575 1033 authenticateInit(&Auth::TheConfig.schemes);
2f1431ea 1034#endif
d9572179 1035 externalAclInit();
5f3f8d0e 1036}
1037
067bea91 1038static void
9b7292ce 1039setEffectiveUser(void)
1040{
fc68f6b1 1041 keepCapabilities();
f53969cc 1042 leave_suid(); /* Run as non privilegied user */
1191b93b 1043#if _SQUID_OS2_
62e76326 1044
cd377065 1045 return;
1046#endif
62e76326 1047
85407535 1048 if (geteuid() == 0) {
fa84c01d
FC
1049 debugs(0, DBG_CRITICAL, "Squid is not safe to run as root! If you must");
1050 debugs(0, DBG_CRITICAL, "start Squid as root, then you must configure");
1051 debugs(0, DBG_CRITICAL, "it to run as a non-priveledged user with the");
1052 debugs(0, DBG_CRITICAL, "'cache_effective_user' option in the config file.");
62e76326 1053 fatal("Don't run Squid as root, set 'cache_effective_user'!");
85407535 1054 }
1055}
1056
dd0cbc64
AR
1057/// changes working directory, providing error reporting
1058static bool
1059mainChangeDir(const char *dir)
1060{
1061 if (chdir(dir) == 0)
1062 return true;
1063
b69e9ffa
AJ
1064 int xerrno = errno;
1065 debugs(50, DBG_CRITICAL, "ERROR: cannot change current directory to " << dir <<
1066 ": " << xstrerr(xerrno));
dd0cbc64
AR
1067 return false;
1068}
1069
133906f5 1070/// set the working directory.
b6a2f15e 1071static void
9b7292ce 1072mainSetCwd(void)
1073{
133906f5 1074 static bool chrooted = false;
133906f5
AJ
1075 if (Config.chroot_dir && !chrooted) {
1076 chrooted = true;
62e76326 1077
b69e9ffa
AJ
1078 if (chroot(Config.chroot_dir) != 0) {
1079 int xerrno = errno;
1080 fatalf("chroot to %s failed: %s", Config.chroot_dir, xstrerr(xerrno));
1081 }
133906f5 1082
dd0cbc64
AR
1083 if (!mainChangeDir("/"))
1084 fatalf("chdir to / after chroot to %s failed", Config.chroot_dir);
133906f5
AJ
1085 }
1086
dd0cbc64
AR
1087 if (Config.coredump_dir && strcmp("none", Config.coredump_dir) != 0) {
1088 if (mainChangeDir(Config.coredump_dir)) {
e0236918 1089 debugs(0, DBG_IMPORTANT, "Set Current Directory to " << Config.coredump_dir);
62e76326 1090 return;
62e76326 1091 }
b6a2f15e 1092 }
62e76326 1093
02e8115e 1094 /* If we don't have coredump_dir or couldn't cd there, report current dir */
dd0cbc64 1095 char pathbuf[MAXPATHLEN];
4a504376 1096 if (getcwd(pathbuf, MAXPATHLEN)) {
e0236918 1097 debugs(0, DBG_IMPORTANT, "Current Directory is " << pathbuf);
4a504376 1098 } else {
b69e9ffa
AJ
1099 int xerrno = errno;
1100 debugs(50, DBG_CRITICAL, "WARNING: Can't find current directory, getcwd: " << xstrerr(xerrno));
4a504376 1101 }
b6a2f15e 1102}
1103
b8d8561b 1104static void
9b7292ce 1105mainInitialize(void)
1106{
efd900cb 1107 /* chroot if configured to run inside chroot */
133906f5 1108 mainSetCwd();
62e76326 1109
1758c627 1110 if (opt_catch_signals) {
62e76326 1111 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
1112 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
44f99671 1113 }
62e76326 1114
30a4f2a8 1115 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
1116 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
a918ecc6 1117 squid_signal(SIGHUP, reconfigure, SA_RESTART);
44f99671 1118
85407535 1119 setEffectiveUser();
62e76326 1120
30a4f2a8 1121 if (icpPortNumOverride != 1)
f45dd259 1122 Config.Port.icp = (unsigned short) icpPortNumOverride;
30a4f2a8 1123
62493678 1124 _db_init(Debug::cache_log, Debug::debugOptions);
62e76326 1125
62493678 1126 fd_open(fileno(debug_log), FD_LOG, Debug::cache_log);
62e76326 1127
fa84c01d 1128 debugs(1, DBG_CRITICAL, "Starting Squid Cache version " << version_string << " for " << CONFIG_HOST_TYPE << "...");
cf2155f2 1129 debugs(1, DBG_CRITICAL, "Service Name: " << service_name);
62e76326 1130
be266cb2 1131#if _SQUID_WINDOWS_
b293c4d8 1132 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
fa84c01d 1133 debugs(1, DBG_CRITICAL, "Service command line is: " << WIN32_Service_Command_Line);
b293c4d8 1134 } else
fa84c01d 1135 debugs(1, DBG_CRITICAL, "Running on " << WIN32_OS_string);
b293c4d8 1136#endif
1137
e0236918 1138 debugs(1, DBG_IMPORTANT, "Process ID " << getpid());
095ec2b1 1139
e0236918 1140 debugs(1, DBG_IMPORTANT, "Process Roles:" << ProcessRoles());
095ec2b1 1141
f3f0f563 1142 setSystemLimits();
e0236918 1143 debugs(1, DBG_IMPORTANT, "With " << Squid_MaxFD << " file descriptors available");
5f3f8d0e 1144
7aa9bb3e 1145#if _SQUID_WINDOWS_
6c1962dd 1146
e0236918 1147 debugs(1, DBG_IMPORTANT, "With " << _getmaxstdio() << " CRT stdio descriptors available");
6c1962dd 1148
1149 if (WIN32_Socks_initialized)
e0236918 1150 debugs(1, DBG_IMPORTANT, "Windows sockets initialized");
6c1962dd 1151
babd1fd5 1152 if (WIN32_OS_version > _WIN_OS_WINNT) {
26ac0430 1153 WIN32_IpAddrChangeMonitorInit();
babd1fd5 1154 }
1155
6c1962dd 1156#endif
1157
5f3f8d0e 1158 ipcache_init();
62e76326 1159
f88bb09c 1160 fqdncache_init();
62e76326 1161
0e70aa1e 1162 parseEtcHosts();
62e76326 1163
4a3b98d7 1164 Dns::Init();
62e76326 1165
586089cd
CT
1166#if USE_SSL_CRTD
1167 Ssl::Helper::GetInstance()->Init();
1168#endif
1169
cb4f4424 1170#if USE_OPENSSL
2cef0ca6
AR
1171 if (Ssl::CertValidationHelper::GetInstance())
1172 Ssl::CertValidationHelper::GetInstance()->Init();
1173#endif
1174
74addf6c 1175 redirectInit();
2f1431ea 1176#if USE_AUTH
5c112575 1177 authenticateInit(&Auth::TheConfig.schemes);
2f1431ea 1178#endif
d9572179 1179 externalAclInit();
62e76326 1180
f53969cc 1181 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
62e76326 1182
9b312a19 1183 errorInitialize();
62e76326 1184
7a2f978b 1185 accessLogInit();
62e76326 1186
e1381638 1187#if ICAP_CLIENT
3ff65596
AR
1188 icapLogOpen();
1189#endif
1190
3898f57f 1191#if USE_IDENT
4daaf3cb 1192 Ident::Init();
3898f57f 1193#endif
4daaf3cb 1194
59ad6d31 1195#if SQUID_SNMP
62e76326 1196
5e14bf6d 1197 snmpInit();
62e76326 1198
5e14bf6d 1199#endif
30a4f2a8 1200#if MALLOC_DBG
62e76326 1201
5f3f8d0e 1202 malloc_debug(0, malloc_debug_level);
62e76326 1203
5f3f8d0e 1204#endif
1205
dbe4fd8e 1206 if (!configured_once) {
c521ad17
DK
1207 if (unlinkdNeeded())
1208 unlinkdInit();
62e76326 1209
1210 urlInitialize();
62e76326 1211 statInit();
1212 storeInit();
1213 mainSetCwd();
62e76326 1214 mimeInit(Config.mimeTablePathname);
62e76326 1215 refreshInit();
9a0a18de 1216#if USE_DELAY_POOLS
62e76326 1217 DelayPools::Init();
0d7e5d78 1218#endif
62e76326 1219
b6b6f466 1220 FwdState::initModule();
62ee09ca 1221 /* register the modules in the cache manager menus */
62ee09ca 1222
a08f1b5a 1223 cbdataRegisterWithCacheManager();
d87f6b1d
HN
1224 SBufStatsAction::RegisterWithCacheManager();
1225
62ee09ca 1226 /* These use separate calls so that the comm loops can eventually
1227 * coexist.
1228 */
62ee09ca 1229
15b3c0d7 1230 eventInit();
610ee341 1231
26ac0430 1232 // TODO: pconn is a good candidate for new-style registration
6852be71 1233 // PconnModule::GetInstance()->registerWithCacheManager();
26ac0430 1234 // moved to PconnModule::PconnModule()
5f3f8d0e 1235 }
62e76326 1236
7de94c8c 1237 if (IamPrimaryProcess()) {
1f38f50a 1238#if USE_WCCP
5667a628 1239 wccpInit();
62e76326 1240
0b0cfcf2 1241#endif
1242#if USE_WCCPv2
1243
5667a628 1244 wccp2Init();
0b0cfcf2 1245
1f38f50a 1246#endif
7de94c8c 1247 }
62e76326 1248
2285407f 1249 serverConnectionsOpen();
62e76326 1250
3ee2b4f8 1251 neighbors_init();
fc68f6b1 1252
5f5e883f 1253 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
62e76326 1254
efd900cb 1255 if (Config.chroot_dir)
62e76326 1256 no_suid();
1257
dbf55289 1258 if (!configured_once && !InDaemonMode())
f53969cc 1259 writePidFile(); /* write PID file */
0a5b9b32 1260
605f2c3e 1261#if defined(_SQUID_LINUX_THREADS_)
62e76326 1262
e3175d1f 1263 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
62e76326 1264
e3175d1f 1265 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
62e76326 1266
e3175d1f 1267#else
62e76326 1268
30a4f2a8 1269 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
62e76326 1270
30a4f2a8 1271 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
62e76326 1272
9fc0b4b8 1273#endif
62e76326 1274
dbf55289 1275 squid_signal(SIGTERM, shut_down, SA_RESTART);
62e76326 1276
dbf55289 1277 squid_signal(SIGINT, shut_down, SA_RESTART);
62e76326 1278
ae1feb30 1279#ifdef SIGTTIN
1280
dbf55289 1281 squid_signal(SIGTTIN, shut_down, SA_RESTART);
ae1feb30 1282
1283#endif
1284
58a39dc9 1285 memCheckInit();
62e76326 1286
57afc994
AR
1287#if USE_LOADABLE_MODULES
1288 LoadableModulesConfigure(Config.loadable_module_names);
1289#endif
1290
8f361c50
AR
1291#if USE_ADAPTATION
1292 bool enableAdaptation = false;
1293
1294 // We can remove this dependency on specific adaptation mechanisms
1295 // if we create a generic Registry of such mechanisms. Should we?
b958cb0f 1296#if ICAP_CLIENT
26cc52cb
AR
1297 Adaptation::Icap::TheConfig.finalize();
1298 enableAdaptation = Adaptation::Icap::TheConfig.onoff || enableAdaptation;
6e5db507
AR
1299#endif
1300#if USE_ECAP
574b508c
AR
1301 Adaptation::Ecap::TheConfig.finalize(); // must be after we load modules
1302 enableAdaptation = Adaptation::Ecap::TheConfig.onoff || enableAdaptation;
b958cb0f 1303#endif
8f361c50
AR
1304 // must be the last adaptation-related finalize
1305 Adaptation::Config::Finalize(enableAdaptation);
b958cb0f
AR
1306#endif
1307
79039294
AR
1308#if USE_SQUID_ESI
1309 Esi::Init();
1310#endif
b958cb0f 1311
9a0a18de 1312#if USE_DELAY_POOLS
b4cd430a
CT
1313 Config.ClientDelay.finalize();
1314#endif
1315
dbe4fd8e 1316 if (!configured_once) {
c8f4eac4 1317 eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
62e76326 1318
1319 if (Config.onoff.announce)
1320 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
1321
1322 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
1323
1324 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
1325
88bfe092 1326#if USE_XPROF_STATS
62e76326 1327
1328 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
1329
88bfe092 1330#endif
62e76326 1331
1332 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
4d7add01 1333 }
62e76326 1334
dbe4fd8e 1335 configured_once = 1;
4d64d74a 1336}
1337
c842329d 1338/// unsafe main routine -- may throw
f3f3e961 1339int SquidMain(int argc, char **argv);
c842329d 1340/// unsafe main routine wrapper to catch exceptions
6e5db507
AR
1341static int SquidMainSafe(int argc, char **argv);
1342
6c1962dd 1343#if USE_WIN32_SERVICE
a74922b5 1344/* Entry point for Windows services */
6c1962dd 1345extern "C" void WINAPI
e1381638 1346SquidWinSvcMain(int argc, char **argv)
18631119
AJ
1347{
1348 SquidMainSafe(argc, argv);
1349}
a74922b5
AJ
1350#endif
1351
b8d8561b 1352int
1353main(int argc, char **argv)
6e5db507 1354{
a74922b5
AJ
1355#if USE_WIN32_SERVICE
1356 SetErrorMode(SEM_NOGPFAULTERRORBOX);
1357 if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION))
1358 return WIN32_StartService(argc, argv);
1359 else {
1360 WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE;
1361 opt_no_daemon = 1;
1362 }
1363#endif
1364
18631119 1365 return SquidMainSafe(argc, argv);
6e5db507
AR
1366}
1367
1368static int
1369SquidMainSafe(int argc, char **argv)
1370{
1371 try {
1372 return SquidMain(argc, argv);
26ac0430 1373 } catch (const std::exception &e) {
51618c6a 1374 debugs(1, DBG_CRITICAL, "FATAL: dying from an unhandled exception: " <<
9199139f 1375 e.what());
26ac0430
AJ
1376 throw;
1377 } catch (...) {
51618c6a 1378 debugs(1, DBG_CRITICAL, "FATAL: dying from an unhandled exception.");
26ac0430
AJ
1379 throw;
1380 }
1381 return -1; // not reached
6e5db507
AR
1382}
1383
d4a3e179
AR
1384/// computes name and ID for the current kid process
1385static void
1386ConfigureCurrentKid(const char *processName)
1387{
5667a628 1388 // kids are marked with parenthesis around their process names
d4a3e179
AR
1389 if (processName && processName[0] == '(') {
1390 if (const char *idStart = strrchr(processName, '-')) {
1391 KidIdentifier = atoi(idStart + 1);
9de6c973
AR
1392 const size_t nameLen = idStart - (processName + 1);
1393 assert(nameLen < sizeof(TheKidName));
1394 xstrncpy(TheKidName, processName + 1, nameLen + 1);
095ec2b1
AR
1395 if (!strcmp(TheKidName, "squid-coord"))
1396 TheProcessKind = pkCoordinator;
9199139f 1397 else if (!strcmp(TheKidName, "squid"))
095ec2b1 1398 TheProcessKind = pkWorker;
9199139f 1399 else if (!strcmp(TheKidName, "squid-disk"))
095ec2b1
AR
1400 TheProcessKind = pkDisker;
1401 else
1402 TheProcessKind = pkOther; // including coordinator
d4a3e179 1403 }
2664c457 1404 } else {
9de6c973 1405 xstrncpy(TheKidName, APP_SHORTNAME, sizeof(TheKidName));
2664c457 1406 KidIdentifier = 0;
d4a3e179 1407 }
d4a3e179
AR
1408}
1409
f3f3e961 1410int
6e5db507 1411SquidMain(int argc, char **argv)
9b7292ce 1412{
d4a3e179 1413 ConfigureCurrentKid(argv[0]);
007d775d 1414
fb6a61d1 1415 Debug::parseOptions(NULL);
9b7292ce 1416 debug_log = stderr;
62e76326 1417
b9269882 1418#if defined(SQUID_MAXFD_LIMIT)
1419
1420 if (SQUID_MAXFD_LIMIT < Squid_MaxFD)
1421 Squid_MaxFD = SQUID_MAXFD_LIMIT;
1422
1423#endif
399e85ea 1424
cf3edd6f
FC
1425 /* NOP under non-windows */
1426 int WIN32_init_err=0;
a0aa9e74 1427 if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
1428 return WIN32_init_err;
0e6d05ef 1429
9b7292ce 1430 /* call mallopt() before anything else */
0b29fe44 1431#if HAVE_MALLOPT
7328e889 1432#ifdef M_GRAIN
9b7292ce 1433 /* Round up all sizes to a multiple of this */
1434 mallopt(M_GRAIN, 16);
62e76326 1435
7328e889 1436#endif
1437#ifdef M_MXFAST
9b7292ce 1438 /* biggest size that is considered a small block */
1439 mallopt(M_MXFAST, 256);
62e76326 1440
7328e889 1441#endif
1442#ifdef M_NBLKS
9b7292ce 1443 /* allocate this many small blocks at once */
1444 mallopt(M_NLBLKS, 32);
62e76326 1445
7328e889 1446#endif
1447#endif /* HAVE_MALLOPT */
1448
9b7292ce 1449 getCurrentTime();
62e76326 1450
9b7292ce 1451 squid_start = current_time;
62e76326 1452
9b7292ce 1453 failure_notify = fatal_dump;
4d64d74a 1454
6c1962dd 1455#if USE_WIN32_SERVICE
1456
9b7292ce 1457 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1458
1459#endif
1460
9b7292ce 1461 mainParseOptions(argc, argv);
4d64d74a 1462
effda67e
MM
1463 if (opt_foreground && opt_no_daemon) {
1464 debugs(1, DBG_CRITICAL, "WARNING: --foreground command-line option has no effect with -N.");
1465 }
1466
9aae6be3 1467 if (opt_parse_cfg_only) {
26ac0430 1468 Debug::parseOptions("ALL,1");
9aae6be3 1469 }
1470
6c1962dd 1471#if USE_WIN32_SERVICE
1472
26ac0430 1473 if (opt_install_service) {
9b7292ce 1474 WIN32_InstallService();
a0aa9e74 1475 return 0;
9b7292ce 1476 }
6c1962dd 1477
26ac0430 1478 if (opt_remove_service) {
9b7292ce 1479 WIN32_RemoveService();
a0aa9e74 1480 return 0;
9b7292ce 1481 }
6c1962dd 1482
26ac0430 1483 if (opt_command_line) {
9b7292ce 1484 WIN32_SetServiceCommandLine();
a0aa9e74 1485 return 0;
9b7292ce 1486 }
6c1962dd 1487
1488#endif
1489
9b7292ce 1490 /* parse configuration file
1491 * note: in "normal" case this used to be called from mainInitialize() */
1492 {
1493 int parse_err;
62e76326 1494
9b7292ce 1495 if (!ConfigFile)
1496 ConfigFile = xstrdup(DefaultConfigFile);
62e76326 1497
9b7292ce 1498 assert(!configured_once);
62e76326 1499
9b7292ce 1500 Mem::Init();
62e76326 1501
f53969cc 1502 storeFsInit(); /* required for config parsing */
62e76326 1503
7b5b7ba8 1504 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
af6a12ee 1505 Fs::Init();
7b5b7ba8 1506
b9ae18aa 1507 /* May not be needed for parsing, have not audited for such */
1508 DiskIOModule::SetupAllModules();
1509
59b2d47f 1510 /* Shouldn't be needed for config parsing, but have not audited for such */
1511 StoreFileSystem::SetupAllFs();
1512
c8f4eac4 1513 /* we may want the parsing process to set this up in the future */
2745fea5 1514 Store::Init();
89736861 1515 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
055421ee
AJ
1516 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1517
31971e6a
AJ
1518 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1519
8951901e
AJ
1520 try {
1521 parse_err = parseConfigFile(ConfigFile);
1522 } catch (...) {
1523 // for now any errors are a fatal condition...
1524 debugs(1, DBG_CRITICAL, "FATAL: Unhandled exception parsing config file." <<
1525 (opt_parse_cfg_only ? " Run squid -k parse and check for errors." : ""));
1526 parse_err = 1;
1527 }
62e76326 1528
97244680 1529 Mem::Report();
26ac0430 1530
18631119 1531 if (opt_parse_cfg_only || parse_err > 0)
9b7292ce 1532 return parse_err;
9b7292ce 1533 }
c642c141 1534 setUmask(Config.umask);
9b7292ce 1535 if (-1 == opt_send_signal)
1536 if (checkRunningPid())
205d7c3b 1537 exit(0);
e13ee7ad 1538
9bc73deb 1539#if TEST_ACCESS
62e76326 1540
95564b0d 1541 comm_init();
62e76326 1542
9b7292ce 1543 mainInitialize();
62e76326 1544
9b7292ce 1545 test_access();
62e76326 1546
9b7292ce 1547 return 0;
62e76326 1548
9bc73deb 1549#endif
1550
9b7292ce 1551 /* send signal to running copy and exit */
26ac0430 1552 if (opt_send_signal != -1) {
9b7292ce 1553 /* chroot if configured to run inside chroot */
133906f5 1554 mainSetCwd();
a572d8be 1555 if (Config.chroot_dir) {
a572d8be 1556 no_suid();
1557 } else {
1558 leave_suid();
9b7292ce 1559 }
62e76326 1560
9b7292ce 1561 sendSignal();
1562 /* NOTREACHED */
1563 }
62e76326 1564
6d57128b 1565 debugs(1,2, HERE << "Doing post-config initialization\n");
520e0073 1566 leave_suid();
21b7990f
AR
1567 RunRegisteredHere(RegisteredRunner::finalizeConfig);
1568 RunRegisteredHere(RegisteredRunner::claimMemoryNeeds);
1569 RunRegisteredHere(RegisteredRunner::useConfig);
520e0073 1570 enter_suid();
9487bae9 1571
dbf55289 1572 if (InDaemonMode() && IamMasterProcess()) {
2ae5c85f 1573 watch_child(argv);
dbf55289
CT
1574 // NOTREACHED
1575 }
2ae5c85f 1576
26ac0430 1577 if (opt_create_swap_dirs) {
9b7292ce 1578 /* chroot if configured to run inside chroot */
133906f5 1579 mainSetCwd();
62e76326 1580
9b7292ce 1581 setEffectiveUser();
04632397 1582 debugs(0, DBG_CRITICAL, "Creating missing swap directories");
c8f4eac4 1583 Store::Root().create();
6c1962dd 1584
9b7292ce 1585 return 0;
9b7292ce 1586 }
62e76326 1587
96c2bb61
AR
1588 if (IamPrimaryProcess())
1589 CpuAffinityCheck();
1590 CpuAffinityInit();
1591
95564b0d 1592 setMaxFD();
1593
1594 /* init comm module */
1595 comm_init();
62e76326 1596
26ac0430 1597 if (opt_no_daemon) {
9b7292ce 1598 /* we have to init fdstat here. */
1599 fd_open(0, FD_LOG, "stdin");
1600 fd_open(1, FD_LOG, "stdout");
1601 fd_open(2, FD_LOG, "stderr");
1602 }
62e76326 1603
6c1962dd 1604#if USE_WIN32_SERVICE
1605
9b7292ce 1606 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1607
1608#endif
1609
9b7292ce 1610 mainInitialize();
4d64d74a 1611
6c1962dd 1612#if USE_WIN32_SERVICE
1613
9b7292ce 1614 WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
6c1962dd 1615
1616#endif
1617
9b7292ce 1618 /* main loop */
a553a5a3 1619 EventLoop mainLoop;
62e76326 1620
0a720258 1621 SignalEngine signalEngine;
6c1962dd 1622
9688b0ae 1623 mainLoop.registerEngine(&signalEngine);
62e76326 1624
8ff3fa2e 1625 /* TODO: stop requiring the singleton here */
1626 mainLoop.registerEngine(EventScheduler::GetInstance());
62e76326 1627
8ff3fa2e 1628 StoreRootEngine store_engine;
615f9581 1629
8ff3fa2e 1630 mainLoop.registerEngine(&store_engine);
a774fd3f 1631
8ff3fa2e 1632 CommSelectEngine comm_engine;
1633
8ff3fa2e 1634 mainLoop.registerEngine(&comm_engine);
1635
bef81ea5 1636 mainLoop.setPrimaryEngine(&comm_engine);
1637
8ff3fa2e 1638 /* use the standard time service */
1639 TimeEngine time_engine;
1640
1641 mainLoop.setTimeService(&time_engine);
1642
7de94c8c 1643 if (IamCoordinatorProcess())
4299f876 1644 AsyncJob::Start(Ipc::Coordinator::Instance());
095ec2b1 1645 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
4299f876 1646 AsyncJob::Start(new Ipc::Strand);
10cefb7b 1647
48d54e4d
AJ
1648 /* at this point we are finished the synchronous startup. */
1649 starting_up = 0;
1650
8ff3fa2e 1651 mainLoop.run();
1652
1653 if (mainLoop.errcount == 10)
1654 fatal_dump("Event loop exited with failure.");
1655
1656 /* shutdown squid now */
1657 SquidShutdown();
62e76326 1658
9b7292ce 1659 /* NOTREACHED */
9b7292ce 1660 return 0;
090089c4 1661}
7690e8eb 1662
b8d8561b 1663static void
0673c0ba 1664sendSignal(void)
7690e8eb 1665{
ff8d0ea6 1666 pid_t pid;
fedac7e5 1667 debug_log = stderr;
258ac4d7 1668
1669 if (strcmp(Config.pidFilename, "none") == 0) {
e0236918 1670 debugs(0, DBG_IMPORTANT, "No pid_filename specified. Trusting you know what you are doing.");
258ac4d7 1671 }
1672
fedac7e5 1673 pid = readPidFile();
62e76326 1674
fedac7e5 1675 if (pid > 1) {
6c1962dd 1676#if USE_WIN32_SERVICE
6c1962dd 1677 if (opt_signal_service) {
1678 WIN32_sendSignal(opt_send_signal);
1679 exit(0);
cf3edd6f 1680 } else {
7dbca7a4 1681 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
6c1962dd 1682 fprintf(stderr, "signal to Squid Service:\n");
1683 fprintf(stderr, "missing -n command line switch.\n");
1684 exit(1);
1685 }
6c1962dd 1686 /* NOTREACHED */
6c1962dd 1687#endif
1688
62e76326 1689 if (kill(pid, opt_send_signal) &&
1690 /* ignore permissions if just running check */
1691 !(opt_send_signal == 0 && errno == EPERM)) {
b69e9ffa 1692 int xerrno = errno;
7dbca7a4 1693 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
62e76326 1694 fprintf(stderr, "signal %d to process %d: %s\n",
b69e9ffa 1695 opt_send_signal, (int) pid, xstrerr(xerrno));
62e76326 1696 exit(1);
1697 }
fedac7e5 1698 } else {
205d7c3b 1699 if (opt_send_signal != SIGTERM) {
e08d498f 1700 fprintf(stderr, "%s: ERROR: No running copy\n", APP_SHORTNAME);
205d7c3b
AJ
1701 exit(1);
1702 } else {
e08d498f 1703 fprintf(stderr, "%s: No running copy\n", APP_SHORTNAME);
205d7c3b
AJ
1704 exit(0);
1705 }
7690e8eb 1706 }
62e76326 1707
fedac7e5 1708 /* signal successfully sent */
1709 exit(0);
1710}
f95b8144 1711
7aa9bb3e 1712#if !_SQUID_WINDOWS_
e18d7fdc 1713/*
1714 * This function is run when Squid is in daemon mode, just
1715 * before the parent forks and starts up the child process.
1716 * It can be used for admin-specific tasks, such as notifying
1717 * someone that Squid is (re)started.
1718 */
1719static void
1720mainStartScript(const char *prog)
1721{
ef364f64 1722 char script[MAXPATHLEN];
e18d7fdc 1723 char *t;
1724 size_t sl = 0;
1725 pid_t cpid;
1726 pid_t rpid;
1727 xstrncpy(script, prog, MAXPATHLEN);
62e76326 1728
e18d7fdc 1729 if ((t = strrchr(script, '/'))) {
62e76326 1730 *(++t) = '\0';
1731 sl = strlen(script);
e18d7fdc 1732 }
62e76326 1733
e18d7fdc 1734 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
62e76326 1735
e18d7fdc 1736 if ((cpid = fork()) == 0) {
62e76326 1737 /* child */
f75662c9 1738 execl(script, squid_start_script, (char *)NULL);
482aa790 1739 _exit(-1);
e18d7fdc 1740 } else {
62e76326 1741 do {
dbf55289
CT
1742 PidStatus status;
1743 rpid = WaitForOnePid(cpid, status, 0);
62e76326 1744 } while (rpid != cpid);
e18d7fdc 1745 }
1746}
1747
7aa9bb3e 1748#endif /* _SQUID_WINDOWS_ */
a50bfe93 1749
efd900cb 1750static int
1751checkRunningPid(void)
1752{
b81949b9 1753 // master process must start alone, but its kids processes may co-exist
7de94c8c 1754 if (!IamMasterProcess())
b81949b9
AR
1755 return 0;
1756
efd900cb 1757 pid_t pid;
e0077312 1758
1759 if (!debug_log)
1760 debug_log = stderr;
1761
efd900cb 1762 pid = readPidFile();
62e76326 1763
efd900cb 1764 if (pid < 2)
62e76326 1765 return 0;
1766
efd900cb 1767 if (kill(pid, 0) < 0)
62e76326 1768 return 0;
1769
fa84c01d 1770 debugs(0, DBG_CRITICAL, "Squid is already running! Process ID " << pid);
62e76326 1771
efd900cb 1772 return 1;
1773}
1774
c92fcbad 1775#if !_SQUID_WINDOWS_
f95b8144 1776static void
dbf55289 1777masterCheckAndBroadcastSignals()
f95b8144 1778{
a6201b10
CT
1779 // if (do_reconfigure)
1780 // TODO: hot-reconfiguration of the number of kids and PID file location
1781
dbf55289
CT
1782 if (do_shutdown)
1783 shutting_down = 1;
62e76326 1784
dbf55289
CT
1785 BroadcastSignalIfAny(DebugSignal);
1786 BroadcastSignalIfAny(RotateSignal);
1787 BroadcastSignalIfAny(ReconfigureSignal);
1788 BroadcastSignalIfAny(ShutdownSignal);
1789}
c92fcbad 1790#endif
62e76326 1791
dbf55289
CT
1792static inline bool
1793masterSignaled()
1794{
1795 return (DebugSignal > 0 || RotateSignal > 0 || ReconfigureSignal > 0 || ShutdownSignal > 0);
1796}
62e76326 1797
dbf55289
CT
1798static void
1799watch_child(char *argv[])
1800{
1801#if !_SQUID_WINDOWS_
1802 char *prog;
effda67e 1803 PidStatus status_f, status;
e3a3b845 1804 pid_t pid;
c99c5397 1805#ifdef TIOCNOTTY
1806
54f742e7 1807 int i;
c99c5397 1808#endif
1809
742724a4 1810 int nullfd;
62e76326 1811
7dbca7a4 1812 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1813
b69e9ffa
AJ
1814 if ((pid = fork()) < 0) {
1815 int xerrno = errno;
1816 syslog(LOG_ALERT, "fork failed: %s", xstrerr(xerrno));
1817 } else if (pid > 0) {
effda67e
MM
1818 // parent
1819 if (opt_foreground) {
1820 if (WaitForAnyPid(status_f, 0) < 0) {
b69e9ffa
AJ
1821 int xerrno = errno;
1822 syslog(LOG_ALERT, "WaitForAnyPid failed: %s", xstrerr(xerrno));
effda67e
MM
1823 }
1824 }
1825
62e76326 1826 exit(0);
effda67e 1827 }
62e76326 1828
b69e9ffa
AJ
1829 if (setsid() < 0) {
1830 int xerrno = errno;
1831 syslog(LOG_ALERT, "setsid failed: %s", xstrerr(xerrno));
1832 }
62e76326 1833
efd900cb 1834 closelog();
62e76326 1835
54f742e7 1836#ifdef TIOCNOTTY
62e76326 1837
c4aefe96 1838 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
62e76326 1839 ioctl(i, TIOCNOTTY, NULL);
1840 close(i);
54f742e7 1841 }
62e76326 1842
54f742e7 1843#endif
b05490a8 1844
7f6ffd15 1845 /*
1846 * RBCOLLINS - if cygwin stackdumps when squid is run without
1847 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1848 * 1.1.3. execvp had a bit overflow error in a loop..
1849 */
742724a4 1850 /* Connect stdio to /dev/null in daemon mode */
4da086c4 1851 nullfd = open(_PATH_DEVNULL, O_RDWR | O_TEXT);
62e76326 1852
b69e9ffa
AJ
1853 if (nullfd < 0) {
1854 int xerrno = errno;
1855 fatalf(_PATH_DEVNULL " %s\n", xstrerr(xerrno));
1856 }
e4a1325e 1857
742724a4 1858 dup2(nullfd, 0);
62e76326 1859
62493678 1860 if (Debug::log_stderr < 0) {
62e76326 1861 dup2(nullfd, 1);
1862 dup2(nullfd, 2);
742724a4 1863 }
62e76326 1864
dbf55289 1865 writePidFile();
8209c7e6 1866 enter_suid(); // writePidFile() uses leave_suid()
dbf55289
CT
1867
1868#if defined(_SQUID_LINUX_THREADS_)
1869 squid_signal(SIGQUIT, rotate_logs, 0);
1870 squid_signal(SIGTRAP, sigusr2_handle, 0);
1871#else
1872 squid_signal(SIGUSR1, rotate_logs, 0);
1873 squid_signal(SIGUSR2, sigusr2_handle, 0);
1874#endif
1875
1876 squid_signal(SIGHUP, reconfigure, 0);
1877
1878 squid_signal(SIGTERM, master_shutdown, 0);
1879 squid_signal(SIGINT, master_shutdown, 0);
1880#ifdef SIGTTIN
1881 squid_signal(SIGTTIN, master_shutdown, 0);
1882#endif
ca4b9ee6 1883
13aeac35
AR
1884 if (Config.workers > 128) {
1885 syslog(LOG_ALERT, "Suspiciously high workers value: %d",
5667a628 1886 Config.workers);
007d775d 1887 // but we keep going in hope that user knows best
5667a628 1888 }
095ec2b1
AR
1889 TheKids.init();
1890
a2515f86 1891 syslog(LOG_NOTICE, "Squid Parent: will start %d kids", (int)TheKids.count());
007d775d
AR
1892
1893 // keep [re]starting kids until it is time to quit
f95b8144 1894 for (;;) {
dbf55289 1895 bool mainStartScriptCalled = false;
007d775d 1896 // start each kid that needs to be [re]started; once
dbf55289 1897 for (int i = TheKids.count() - 1; i >= 0 && !shutting_down; --i) {
007d775d 1898 Kid& kid = TheKids.get(i);
ca4b9ee6 1899 if (!kid.shouldRestart())
007d775d
AR
1900 continue;
1901
dbf55289
CT
1902 if (!mainStartScriptCalled) {
1903 mainStartScript(argv[0]);
1904 mainStartScriptCalled = true;
1905 }
1906
007d775d
AR
1907 if ((pid = fork()) == 0) {
1908 /* child */
1909 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
bc91a636 1910 prog = argv[0];
007d775d
AR
1911 argv[0] = const_cast<char*>(kid.name().termedBuf());
1912 execvp(prog, argv);
b69e9ffa
AJ
1913 int xerrno = errno;
1914 syslog(LOG_ALERT, "execvp failed: %s", xstrerr(xerrno));
007d775d
AR
1915 }
1916
1917 kid.start(pid);
095ec2b1 1918 syslog(LOG_NOTICE, "Squid Parent: %s process %d started",
9199139f 1919 kid.name().termedBuf(), pid);
62e76326 1920 }
1921
1922 /* parent */
7dbca7a4 1923 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1924
dbf55289
CT
1925 // If Squid received a signal while checking for dying kids (below) or
1926 // starting new kids (above), then do a fast check for a new dying kid
1927 // (WaitForAnyPid with the WNOHANG option) and continue to forward
1928 // signals to kids. Otherwise, wait for a kid to die or for a signal
1929 // to abort the blocking WaitForAnyPid() call.
1930 // With the WNOHANG option, we could check whether WaitForAnyPid() was
5c634111 1931 // aborted by a dying kid or a signal, but it is not required: The
dbf55289
CT
1932 // next do/while loop will check again for any dying kids.
1933 int waitFlag = 0;
1934 if (masterSignaled())
1935 waitFlag = WNOHANG;
1936 pid = WaitForAnyPid(status, waitFlag);
1937
1938 // check for a stopped kid
1939 Kid* kid = pid > 0 ? TheKids.find(pid) : NULL;
1940 if (kid) {
1941 kid->stop(status);
1942 if (kid->calledExit()) {
1943 syslog(LOG_NOTICE,
1944 "Squid Parent: %s process %d exited with status %d",
1945 kid->name().termedBuf(),
1946 kid->getPid(), kid->exitStatus());
1947 } else if (kid->signaled()) {
1948 syslog(LOG_NOTICE,
1949 "Squid Parent: %s process %d exited due to signal %d with status %d",
1950 kid->name().termedBuf(),
1951 kid->getPid(), kid->termSignal(), kid->exitStatus());
007d775d 1952 } else {
dbf55289
CT
1953 syslog(LOG_NOTICE, "Squid Parent: %s process %d exited",
1954 kid->name().termedBuf(), kid->getPid());
007d775d 1955 }
dbf55289
CT
1956 if (kid->hopeless()) {
1957 syslog(LOG_NOTICE, "Squid Parent: %s process %d will not"
1958 " be restarted due to repeated, frequent failures",
1959 kid->name().termedBuf(), kid->getPid());
1960 }
5c634111 1961 } else if (pid > 0) {
dbf55289 1962 syslog(LOG_NOTICE, "Squid Parent: unknown child process %d exited", pid);
5667a628 1963 }
62e76326 1964
ca4b9ee6 1965 if (!TheKids.someRunning() && !TheKids.shouldRestartSome()) {
520e0073 1966 leave_suid();
21b7990f
AR
1967 // XXX: Master process has no main loop and, hence, should not call
1968 // RegisteredRunner::startShutdown which promises a loop iteration.
1969 RunRegisteredHere(RegisteredRunner::finishShutdown);
520e0073 1970 enter_suid();
c011f9bc 1971
dbf55289 1972 removePidFile();
8209c7e6 1973 enter_suid(); // removePidFile() uses leave_suid()
ca4b9ee6
DK
1974 if (TheKids.someSignaled(SIGINT) || TheKids.someSignaled(SIGTERM)) {
1975 syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
1976 exit(1);
1977 }
62e76326 1978
ca4b9ee6
DK
1979 if (TheKids.allHopeless()) {
1980 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
1981 exit(1);
1982 }
62e76326 1983
007d775d
AR
1984 exit(0);
1985 }
06a0fbd3 1986
dbf55289 1987 masterCheckAndBroadcastSignals();
f95b8144 1988 }
62e76326 1989
bbe199dc 1990 /* NOTREACHED */
7aa9bb3e 1991#endif /* _SQUID_WINDOWS_ */
a572d8be 1992
f95b8144 1993}
fff6ad65 1994
9ec1a1dc 1995static void
8ff3fa2e 1996SquidShutdown()
fff6ad65 1997{
d71e4674
AR
1998 /* XXX: This function is called after the main loop has quit, which
1999 * means that no AsyncCalls would be called, including close handlers.
2000 * TODO: We need to close/shut/free everything that needs calls before
2001 * exiting the loop.
26ac0430 2002 */
d71e4674 2003
6c1962dd 2004#if USE_WIN32_SERVICE
2005 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
2006#endif
2007
e0236918 2008 debugs(1, DBG_IMPORTANT, "Shutting down...");
95d2589c
CT
2009#if USE_SSL_CRTD
2010 Ssl::Helper::GetInstance()->Shutdown();
2cef0ca6 2011#endif
cb4f4424 2012#if USE_OPENSSL
f54e3d4c
AR
2013 if (Ssl::CertValidationHelper::GetInstance())
2014 Ssl::CertValidationHelper::GetInstance()->Shutdown();
95d2589c 2015#endif
95a83c22 2016 redirectShutdown();
2017 externalAclShutdown();
65d448bc 2018 icpClosePorts();
d723bf6b 2019#if USE_HTCP
65d448bc 2020 htcpClosePorts();
d723bf6b 2021#endif
59ad6d31 2022#if SQUID_SNMP
65d448bc 2023 snmpClosePorts();
320e9f36 2024#endif
eb824054 2025#if USE_WCCP
62e76326 2026
320e9f36 2027 wccpConnectionClose();
d723bf6b 2028#endif
0b0cfcf2 2029#if USE_WCCPv2
2030
2031 wccp2ConnectionClose();
2032#endif
62e76326 2033
fff6ad65 2034 releaseServerSockets();
d723bf6b 2035 commCloseAllSockets();
79039294
AR
2036
2037#if USE_SQUID_ESI
2038 Esi::Clean();
2039#endif
2040
9a0a18de 2041#if USE_DELAY_POOLS
b67e2c8c 2042 DelayPools::FreePools();
515ec4dc 2043#endif
2f1431ea 2044#if USE_AUTH
0bcb6908 2045 authenticateReset();
2f1431ea 2046#endif
6c1962dd 2047#if USE_WIN32_SERVICE
2048
2049 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
2050#endif
e2b80c5b
CT
2051#if ICAP_CLIENT
2052 Adaptation::Icap::TheConfig.freeService();
2053#endif
62e76326 2054
c8f4eac4 2055 Store::Root().sync(); /* Flush pending object writes/unlinks */
4d075ba0 2056
f53969cc 2057 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
fc68f6b1 2058
fff6ad65 2059 storeDirWriteCleanLogs(0);
2060 PrintRusage();
2061 dumpMallocStats();
f53969cc 2062 Store::Root().sync(); /* Flush log writes */
fff6ad65 2063 storeLogClose();
2064 accessLogClose();
f53969cc 2065 Store::Root().sync(); /* Flush log close */
59b2d47f 2066 StoreFileSystem::FreeAllFs();
b9ae18aa 2067 DiskIOModule::FreeAllModules();
afec404b 2068#if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
62e76326 2069
fff6ad65 2070 configFreeMemory();
2071 storeFreeMemory();
33ab18e8 2072 /*stmemFreeMemory(); */
fff6ad65 2073 netdbFreeMemory();
2074 ipcacheFreeMemory();
2075 fqdncacheFreeMemory();
2076 asnFreeMemory();
26a369ba 2077 clientdbFreeMemory();
d2db411c 2078 statFreeMemory();
f1fc2a8d 2079 eventFreeMemory();
c68e9c6b 2080 mimeFreeMemory();
2081 errorClean();
33ab18e8 2082#endif
2745fea5 2083 Store::FreeMemory();
57fc379e 2084
fff6ad65 2085 fdDumpOpen();
62e76326 2086
236d1779 2087 comm_exit();
62e76326 2088
21b7990f 2089 RunRegisteredHere(RegisteredRunner::finishShutdown);
62e76326 2090
553d498c
AJ
2091 memClean();
2092
dbf55289
CT
2093 if (!InDaemonMode()) {
2094 removePidFile();
ab50ee9e 2095 }
62e76326 2096
e0236918 2097 debugs(1, DBG_IMPORTANT, "Squid Cache (Version " << version_string << "): Exiting normally.");
62e76326 2098
0cfa98cb 2099 /*
2100 * DPW 2006-10-23
2101 * We used to fclose(debug_log) here if it was set, but then
2102 * we forgot to set it to NULL. That caused some coredumps
2103 * because exit() ends up calling a bunch of destructors and
2104 * such. So rather than forcing the debug_log to close, we'll
2105 * leave it open so that those destructors can write some
2106 * debugging if necessary. The file will be closed anyway when
2107 * the process truly exits.
2108 */
62e76326 2109
ae1feb30 2110 exit(shutdown_status);
fff6ad65 2111}
bef81ea5 2112