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