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