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