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