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