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