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