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