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