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