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