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