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