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