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