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