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