]> git.ipfire.org Git - thirdparty/squid.git/blob - src/main.cc
Merged from trunk
[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 "base/TextException.h"
42 #include "ConfigParser.h"
43 #include "errorpage.h"
44 #include "event.h"
45 #include "EventLoop.h"
46 #include "ExternalACL.h"
47 #include "Store.h"
48 #include "ICP.h"
49 #include "ident/Ident.h"
50 #include "HttpReply.h"
51 #include "pconn.h"
52 #include "Mem.h"
53 #include "acl/Asn.h"
54 #include "acl/Acl.h"
55 #include "htcp.h"
56 #include "StoreFileSystem.h"
57 #include "DiskIO/DiskIOModule.h"
58 #include "comm.h"
59 #if USE_EPOLL
60 #include "comm_epoll.h"
61 #endif
62 #if USE_KQUEUE
63 #include "comm_kqueue.h"
64 #endif
65 #if USE_POLL
66 #include "comm_poll.h"
67 #endif
68 #if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
69 #include "comm_select.h"
70 #endif
71 #include "SquidTime.h"
72 #include "SwapDir.h"
73 #include "forward.h"
74 #include "MemPool.h"
75 #include "icmp/IcmpSquid.h"
76 #include "icmp/net_db.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 &evtLoop) : loop(evtLoop) {}
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 master process, 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(); /* destroys any unused auth schemas */
697 InitAuthSchemes(); /* create new ones required for config parsing */
698
699 externalAclShutdown();
700 storeDirCloseSwapLogs();
701 storeLogClose();
702 accessLogClose();
703 #if ICAP_CLIENT
704 icapLogClose();
705 #endif
706 useragentLogClose();
707 refererCloseLog();
708
709 eventAdd("mainReconfigureFinish", &mainReconfigureFinish, NULL, 0, 1,
710 false);
711 }
712
713 static void
714 mainReconfigureFinish(void *)
715 {
716 debugs(1, 3, "finishing reconfiguring");
717
718 errorClean();
719 enter_suid(); /* root to read config file */
720
721 // we may have disabled the need for PURGE
722 if (Config2.onoff.enable_purge)
723 Config2.onoff.enable_purge = 2;
724
725 // parse the config returns a count of errors encountered.
726 if ( parseConfigFile(ConfigFile) != 0) {
727 // for now any errors are a fatal condition...
728 self_destruct();
729 }
730
731 setUmask(Config.umask);
732 Mem::Report();
733 setEffectiveUser();
734 _db_init(Debug::cache_log, Debug::debugOptions);
735 ipcache_restart(); /* clear stuck entries */
736 authenticateUserCacheRestart(); /* clear stuck ACL entries */
737 fqdncache_restart(); /* sigh, fqdncache too */
738 parseEtcHosts();
739 errorInitialize(); /* reload error pages */
740 accessLogInit();
741 #if ICAP_CLIENT
742 icapLogOpen();
743 #endif
744 storeLogOpen();
745 useragentOpenLog();
746 refererOpenLog();
747 #if USE_DNSSERVERS
748
749 dnsInit();
750 #else
751
752 idnsInit();
753 #endif
754
755 redirectInit();
756 authenticateInit(&Auth::TheConfig);
757 externalAclInit();
758 #if USE_WCCP
759
760 wccpInit();
761 #endif
762 #if USE_WCCPv2
763
764 wccp2Init();
765 #endif
766
767 serverConnectionsOpen();
768
769 neighbors_init();
770
771 storeDirOpenSwapLogs();
772
773 mimeInit(Config.mimeTablePathname);
774
775 if (Config.onoff.announce) {
776 if (!eventFind(start_announce, NULL))
777 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
778 } else {
779 if (eventFind(start_announce, NULL))
780 eventDelete(start_announce, NULL);
781 }
782
783 writePidFile(); /* write PID file */
784
785 debugs(1, 1, "Ready to serve requests.");
786
787 reconfiguring = 0;
788 }
789
790 static void
791 mainRotate(void)
792 {
793 icmpEngine.Close();
794 #if USE_DNSSERVERS
795 dnsShutdown();
796 #endif
797 redirectShutdown();
798
799 /* TODO: should only terminate the helpers they are using. nothing else. */
800 authenticateShutdown(); /* destroys any unused auth schemas */
801 InitAuthSchemes(); /* create new ones required for config parsing */
802
803 externalAclShutdown();
804
805 _db_rotate_log(); /* cache.log */
806 storeDirWriteCleanLogs(1);
807 storeLogRotate(); /* store.log */
808 accessLogRotate(); /* access.log */
809 useragentRotateLog(); /* useragent.log */
810 refererRotateLog(); /* referer.log */
811 #if ICAP_CLIENT
812 icapLogRotate(); /*icap.log*/
813 #endif
814 #if WIP_FWD_LOG
815 fwdLogRotate();
816 #endif
817
818 icmpEngine.Open();
819 #if USE_DNSSERVERS
820 dnsInit();
821 #endif
822 redirectInit();
823 authenticateInit(&Auth::TheConfig);
824 externalAclInit();
825 }
826
827 static void
828 setEffectiveUser(void)
829 {
830 keepCapabilities();
831 leave_suid(); /* Run as non privilegied user */
832 #ifdef _SQUID_OS2_
833
834 return;
835 #endif
836
837 if (geteuid() == 0) {
838 debugs(0, 0, "Squid is not safe to run as root! If you must");
839 debugs(0, 0, "start Squid as root, then you must configure");
840 debugs(0, 0, "it to run as a non-priveledged user with the");
841 debugs(0, 0, "'cache_effective_user' option in the config file.");
842 fatal("Don't run Squid as root, set 'cache_effective_user'!");
843 }
844 }
845
846 static void
847 mainSetCwd(void)
848 {
849 char pathbuf[MAXPATHLEN];
850
851 if (Config.coredump_dir) {
852 if (0 == strcmp("none", Config.coredump_dir)) {
853 (void) 0;
854 } else if (chdir(Config.coredump_dir) == 0) {
855 debugs(0, 1, "Set Current Directory to " << Config.coredump_dir);
856 return;
857 } else {
858 debugs(50, 0, "chdir: " << Config.coredump_dir << ": " << xstrerror());
859 }
860 }
861
862 /* If we don't have coredump_dir or couldn't cd there, report current dir */
863 if (getcwd(pathbuf, MAXPATHLEN)) {
864 debugs(0, 1, "Current Directory is " << pathbuf);
865 } else {
866 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
867 }
868 }
869
870 #if DELAY_POOLS
871 #include "DelayPools.h"
872 #endif
873
874 static void
875 mainInitialize(void)
876 {
877 /* chroot if configured to run inside chroot */
878
879 if (Config.chroot_dir && (chroot(Config.chroot_dir) != 0 || chdir("/") != 0)) {
880 fatal("failed to chroot");
881 }
882
883 if (opt_catch_signals) {
884 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
885 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
886 }
887
888 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
889 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
890
891 setEffectiveUser();
892
893 if (icpPortNumOverride != 1)
894 Config.Port.icp = (u_short) icpPortNumOverride;
895
896 _db_init(Debug::cache_log, Debug::debugOptions);
897
898 fd_open(fileno(debug_log), FD_LOG, Debug::cache_log);
899
900 #if MEM_GEN_TRACE
901
902 log_trace_init("/tmp/squid.alloc");
903
904 #endif
905
906 debugs(1, 0, "Starting Squid Cache version " << version_string << " for " << CONFIG_HOST_TYPE << "...");
907
908 #ifdef _SQUID_WIN32_
909
910 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
911 debugs(1, 0, "Running as " << WIN32_Service_name << " Windows System Service on " << WIN32_OS_string);
912 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line);
913 } else
914 debugs(1, 0, "Running on " << WIN32_OS_string);
915
916 #endif
917
918 debugs(1, 1, "Process ID " << getpid());
919
920 debugs(1, 1, "With " << Squid_MaxFD << " file descriptors available");
921
922 #ifdef _SQUID_MSWIN_
923
924 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
925
926 if (WIN32_Socks_initialized)
927 debugs(1, 1, "Windows sockets initialized");
928
929 if (WIN32_OS_version > _WIN_OS_WINNT) {
930 WIN32_IpAddrChangeMonitorInit();
931 }
932
933 #endif
934
935 if (!configured_once)
936 disk_init(); /* disk_init must go before ipcache_init() */
937
938 ipcache_init();
939
940 fqdncache_init();
941
942 parseEtcHosts();
943
944 #if USE_DNSSERVERS
945
946 dnsInit();
947
948 #else
949
950 idnsInit();
951
952 #endif
953
954 redirectInit();
955
956 authenticateInit(&Auth::TheConfig);
957
958 externalAclInit();
959
960 useragentOpenLog();
961
962 refererOpenLog();
963
964 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
965
966 httpReplyInitModule(); /* must go before accepting replies */
967
968 errorInitialize();
969
970 accessLogInit();
971
972 #if ICAP_CLIENT
973 icapLogOpen();
974 #endif
975
976 #if USE_IDENT
977 Ident::Init();
978 #endif
979
980 #ifdef SQUID_SNMP
981
982 snmpInit();
983
984 #endif
985 #if MALLOC_DBG
986
987 malloc_debug(0, malloc_debug_level);
988
989 #endif
990
991 if (!configured_once) {
992 #if USE_UNLINKD
993 unlinkdInit();
994 #endif
995
996 urlInitialize();
997 statInit();
998 storeInit();
999 mainSetCwd();
1000 /* after this point we want to see the mallinfo() output */
1001 do_mallinfo = 1;
1002 mimeInit(Config.mimeTablePathname);
1003 refreshInit();
1004 #if DELAY_POOLS
1005
1006 DelayPools::Init();
1007 #endif
1008
1009 FwdState::initModule();
1010 /* register the modules in the cache manager menus */
1011
1012 cbdataRegisterWithCacheManager();
1013 /* These use separate calls so that the comm loops can eventually
1014 * coexist.
1015 */
1016
1017 eventInit();
1018
1019 // TODO: pconn is a good candidate for new-style registration
1020 // PconnModule::GetInstance()->registerWithCacheManager();
1021 // moved to PconnModule::PconnModule()
1022 }
1023
1024 #if USE_WCCP
1025 wccpInit();
1026
1027 #endif
1028 #if USE_WCCPv2
1029
1030 wccp2Init();
1031
1032 #endif
1033
1034 serverConnectionsOpen();
1035
1036 neighbors_init();
1037
1038 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1039
1040 if (Config.chroot_dir)
1041 no_suid();
1042
1043 if (!configured_once)
1044 writePidFile(); /* write PID file */
1045
1046 #ifdef _SQUID_LINUX_THREADS_
1047
1048 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
1049
1050 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
1051
1052 #else
1053
1054 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
1055
1056 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
1057
1058 #endif
1059
1060 squid_signal(SIGHUP, reconfigure, SA_RESTART);
1061
1062 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
1063
1064 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
1065
1066 #ifdef SIGTTIN
1067
1068 squid_signal(SIGTTIN, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
1069
1070 #endif
1071
1072 memCheckInit();
1073
1074 #if USE_LOADABLE_MODULES
1075 LoadableModulesConfigure(Config.loadable_module_names);
1076 #endif
1077
1078 #if USE_ADAPTATION
1079 bool enableAdaptation = false;
1080
1081 // We can remove this dependency on specific adaptation mechanisms
1082 // if we create a generic Registry of such mechanisms. Should we?
1083 #if ICAP_CLIENT
1084 Adaptation::Icap::TheConfig.finalize();
1085 enableAdaptation = Adaptation::Icap::TheConfig.onoff || enableAdaptation;
1086 #endif
1087 #if USE_ECAP
1088 Adaptation::Ecap::TheConfig.finalize(); // must be after we load modules
1089 enableAdaptation = Adaptation::Ecap::TheConfig.onoff || enableAdaptation;
1090 #endif
1091 // must be the last adaptation-related finalize
1092 Adaptation::Config::Finalize(enableAdaptation);
1093 #endif
1094
1095 #if USE_SQUID_ESI
1096 Esi::Init();
1097 #endif
1098
1099 debugs(1, 1, "Ready to serve requests.");
1100
1101 if (!configured_once) {
1102 eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
1103
1104 if (Config.onoff.announce)
1105 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
1106
1107 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
1108
1109 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
1110
1111 #if USE_XPROF_STATS
1112
1113 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
1114
1115 #endif
1116
1117 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
1118 }
1119
1120 configured_once = 1;
1121 }
1122
1123 /// unsafe main routine -- may throw
1124 int SquidMain(int argc, char **argv);
1125 /// unsafe main routine wrapper to catch exceptions
1126 static int SquidMainSafe(int argc, char **argv);
1127
1128 #if USE_WIN32_SERVICE
1129 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1130 extern "C" void WINAPI
1131 SquidWinSvcMain(int argc, char **argv)
1132 {
1133 SquidMainSafe(argc, argv);
1134 }
1135 #else
1136 int
1137 main(int argc, char **argv)
1138 {
1139 return SquidMainSafe(argc, argv);
1140 }
1141 #endif
1142
1143 static int
1144 SquidMainSafe(int argc, char **argv)
1145 {
1146 try {
1147 return SquidMain(argc, argv);
1148 } catch (const std::exception &e) {
1149 std::cerr << "dying from an unhandled exception: " << e.what() << std::endl;
1150 throw;
1151 } catch (...) {
1152 std::cerr << "dying from an unhandled exception." << std::endl;
1153 throw;
1154 }
1155 return -1; // not reached
1156 }
1157
1158 int
1159 SquidMain(int argc, char **argv)
1160 {
1161 #ifdef _SQUID_WIN32_
1162
1163 int WIN32_init_err;
1164 #endif
1165
1166 #if HAVE_SBRK
1167
1168 sbrk_start = sbrk(0);
1169 #endif
1170
1171 Debug::parseOptions(NULL);
1172 debug_log = stderr;
1173
1174 #if defined(SQUID_MAXFD_LIMIT)
1175
1176 if (SQUID_MAXFD_LIMIT < Squid_MaxFD)
1177 Squid_MaxFD = SQUID_MAXFD_LIMIT;
1178
1179 #endif
1180
1181 #ifdef _SQUID_WIN32_
1182
1183 if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
1184 return WIN32_init_err;
1185
1186 #endif
1187
1188 /* call mallopt() before anything else */
1189 #if HAVE_MALLOPT
1190 #ifdef M_GRAIN
1191 /* Round up all sizes to a multiple of this */
1192 mallopt(M_GRAIN, 16);
1193
1194 #endif
1195 #ifdef M_MXFAST
1196 /* biggest size that is considered a small block */
1197 mallopt(M_MXFAST, 256);
1198
1199 #endif
1200 #ifdef M_NBLKS
1201 /* allocate this many small blocks at once */
1202 mallopt(M_NLBLKS, 32);
1203
1204 #endif
1205 #endif /* HAVE_MALLOPT */
1206
1207 squid_srandom(time(NULL));
1208
1209 getCurrentTime();
1210
1211 squid_start = current_time;
1212
1213 failure_notify = fatal_dump;
1214
1215 #if USE_WIN32_SERVICE
1216
1217 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
1218
1219 #endif
1220
1221 mainParseOptions(argc, argv);
1222
1223 if (opt_parse_cfg_only) {
1224 Debug::parseOptions("ALL,1");
1225 }
1226
1227 #if USE_WIN32_SERVICE
1228
1229 if (opt_install_service) {
1230 WIN32_InstallService();
1231 return 0;
1232 }
1233
1234 if (opt_remove_service) {
1235 WIN32_RemoveService();
1236 return 0;
1237 }
1238
1239 if (opt_command_line) {
1240 WIN32_SetServiceCommandLine();
1241 return 0;
1242 }
1243
1244 #endif
1245
1246 /* parse configuration file
1247 * note: in "normal" case this used to be called from mainInitialize() */
1248 {
1249 int parse_err;
1250
1251 if (!ConfigFile)
1252 ConfigFile = xstrdup(DefaultConfigFile);
1253
1254 assert(!configured_once);
1255
1256 Mem::Init();
1257
1258 storeFsInit(); /* required for config parsing */
1259
1260 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1261 Fs::Init();
1262
1263 /* May not be needed for parsing, have not audited for such */
1264 DiskIOModule::SetupAllModules();
1265
1266 /* Shouldn't be needed for config parsing, but have not audited for such */
1267 StoreFileSystem::SetupAllFs();
1268
1269 /* we may want the parsing process to set this up in the future */
1270 Store::Root(new StoreController);
1271
1272 InitAuthSchemes(); /* required for config parsing */
1273
1274 parse_err = parseConfigFile(ConfigFile);
1275
1276 Mem::Report();
1277
1278 if (opt_parse_cfg_only || parse_err > 0)
1279 return parse_err;
1280 }
1281 setUmask(Config.umask);
1282 if (-1 == opt_send_signal)
1283 if (checkRunningPid())
1284 exit(0);
1285
1286 #if TEST_ACCESS
1287
1288 comm_init();
1289
1290 comm_select_init();
1291
1292 mainInitialize();
1293
1294 test_access();
1295
1296 return 0;
1297
1298 #endif
1299
1300 /* send signal to running copy and exit */
1301 if (opt_send_signal != -1) {
1302 /* chroot if configured to run inside chroot */
1303
1304 if (Config.chroot_dir) {
1305 if (chroot(Config.chroot_dir))
1306 fatal("failed to chroot");
1307
1308 no_suid();
1309 } else {
1310 leave_suid();
1311 }
1312
1313 sendSignal();
1314 /* NOTREACHED */
1315 }
1316
1317 if (opt_create_swap_dirs) {
1318 /* chroot if configured to run inside chroot */
1319
1320 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
1321 fatal("failed to chroot");
1322 }
1323
1324 setEffectiveUser();
1325 debugs(0, 0, "Creating Swap Directories");
1326 Store::Root().create();
1327
1328 return 0;
1329 }
1330
1331 if (!opt_no_daemon)
1332 watch_child(argv);
1333
1334 setMaxFD();
1335
1336 /* init comm module */
1337 comm_init();
1338
1339 comm_select_init();
1340
1341 if (opt_no_daemon) {
1342 /* we have to init fdstat here. */
1343 fd_open(0, FD_LOG, "stdin");
1344 fd_open(1, FD_LOG, "stdout");
1345 fd_open(2, FD_LOG, "stderr");
1346 }
1347
1348 #if USE_WIN32_SERVICE
1349
1350 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
1351
1352 #endif
1353
1354 mainInitialize();
1355
1356 #if USE_WIN32_SERVICE
1357
1358 WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
1359
1360 #endif
1361
1362 /* main loop */
1363 EventLoop mainLoop;
1364
1365 SignalEngine signalEngine(mainLoop);
1366
1367 mainLoop.registerEngine(&signalEngine);
1368
1369 /* TODO: stop requiring the singleton here */
1370 mainLoop.registerEngine(EventScheduler::GetInstance());
1371
1372 StoreRootEngine store_engine;
1373
1374 mainLoop.registerEngine(&store_engine);
1375
1376 CommSelectEngine comm_engine;
1377
1378 mainLoop.registerEngine(&comm_engine);
1379
1380 mainLoop.setPrimaryEngine(&comm_engine);
1381
1382 /* use the standard time service */
1383 TimeEngine time_engine;
1384
1385 mainLoop.setTimeService(&time_engine);
1386
1387 /* at this point we are finished the synchronous startup. */
1388 starting_up = 0;
1389
1390 mainLoop.run();
1391
1392 if (mainLoop.errcount == 10)
1393 fatal_dump("Event loop exited with failure.");
1394
1395 /* shutdown squid now */
1396 SquidShutdown();
1397
1398 /* NOTREACHED */
1399 return 0;
1400 }
1401
1402 static void
1403 sendSignal(void)
1404 {
1405 pid_t pid;
1406 debug_log = stderr;
1407
1408 if (strcmp(Config.pidFilename, "none") == 0) {
1409 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
1410 }
1411
1412 pid = readPidFile();
1413
1414 if (pid > 1) {
1415 #if USE_WIN32_SERVICE
1416
1417 if (opt_signal_service) {
1418 WIN32_sendSignal(opt_send_signal);
1419 exit(0);
1420 } else
1421 #ifdef _SQUID_MSWIN_
1422 {
1423 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
1424 fprintf(stderr, "signal to Squid Service:\n");
1425 fprintf(stderr, "missing -n command line switch.\n");
1426 exit(1);
1427 }
1428
1429 /* NOTREACHED */
1430 #endif
1431
1432 #endif
1433
1434 if (kill(pid, opt_send_signal) &&
1435 /* ignore permissions if just running check */
1436 !(opt_send_signal == 0 && errno == EPERM)) {
1437 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
1438 fprintf(stderr, "signal %d to process %d: %s\n",
1439 opt_send_signal, (int) pid, xstrerror());
1440 exit(1);
1441 }
1442 } else {
1443 if (opt_send_signal != SIGTERM) {
1444 fprintf(stderr, "%s: ERROR: No running copy\n", APP_SHORTNAME);
1445 exit(1);
1446 } else {
1447 fprintf(stderr, "%s: No running copy\n", APP_SHORTNAME);
1448 exit(0);
1449 }
1450 }
1451
1452 /* signal successfully sent */
1453 exit(0);
1454 }
1455
1456 #ifndef _SQUID_MSWIN_
1457 /*
1458 * This function is run when Squid is in daemon mode, just
1459 * before the parent forks and starts up the child process.
1460 * It can be used for admin-specific tasks, such as notifying
1461 * someone that Squid is (re)started.
1462 */
1463 static void
1464 mainStartScript(const char *prog)
1465 {
1466 char script[MAXPATHLEN];
1467 char *t;
1468 size_t sl = 0;
1469 pid_t cpid;
1470 pid_t rpid;
1471 xstrncpy(script, prog, MAXPATHLEN);
1472
1473 if ((t = strrchr(script, '/'))) {
1474 *(++t) = '\0';
1475 sl = strlen(script);
1476 }
1477
1478 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
1479
1480 if ((cpid = fork()) == 0) {
1481 /* child */
1482 execl(script, squid_start_script, (char *)NULL);
1483 _exit(-1);
1484 } else {
1485 do {
1486 #ifdef _SQUID_NEXT_
1487 union wait status;
1488 rpid = wait3(&status, 0, NULL);
1489 #else
1490
1491 int status;
1492 rpid = waitpid(-1, &status, 0);
1493 #endif
1494
1495 } while (rpid != cpid);
1496 }
1497 }
1498
1499 #endif /* _SQUID_MSWIN_ */
1500
1501 static int
1502 checkRunningPid(void)
1503 {
1504 pid_t pid;
1505
1506 if (!debug_log)
1507 debug_log = stderr;
1508
1509 pid = readPidFile();
1510
1511 if (pid < 2)
1512 return 0;
1513
1514 if (kill(pid, 0) < 0)
1515 return 0;
1516
1517 debugs(0, 0, "Squid is already running! Process ID " << pid);
1518
1519 return 1;
1520 }
1521
1522 static void
1523 watch_child(char *argv[])
1524 {
1525 #ifndef _SQUID_MSWIN_
1526 char *prog;
1527 int failcount = 0;
1528 time_t start;
1529 time_t stop;
1530 #ifdef _SQUID_NEXT_
1531
1532 union wait status;
1533 #else
1534
1535 int status;
1536 #endif
1537
1538 pid_t pid;
1539 #ifdef TIOCNOTTY
1540
1541 int i;
1542 #endif
1543
1544 int nullfd;
1545
1546 if (*(argv[0]) == '(')
1547 return;
1548
1549 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1550
1551 if ((pid = fork()) < 0)
1552 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
1553 else if (pid > 0)
1554 exit(0);
1555
1556 if (setsid() < 0)
1557 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
1558
1559 closelog();
1560
1561 #ifdef TIOCNOTTY
1562
1563 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
1564 ioctl(i, TIOCNOTTY, NULL);
1565 close(i);
1566 }
1567
1568 #endif
1569
1570 /*
1571 * RBCOLLINS - if cygwin stackdumps when squid is run without
1572 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1573 * 1.1.3. execvp had a bit overflow error in a loop..
1574 */
1575 /* Connect stdio to /dev/null in daemon mode */
1576 nullfd = open(_PATH_DEVNULL, O_RDWR | O_TEXT);
1577
1578 if (nullfd < 0)
1579 fatalf(_PATH_DEVNULL " %s\n", xstrerror());
1580
1581 dup2(nullfd, 0);
1582
1583 if (Debug::log_stderr < 0) {
1584 dup2(nullfd, 1);
1585 dup2(nullfd, 2);
1586 }
1587
1588 for (;;) {
1589 mainStartScript(argv[0]);
1590
1591 if ((pid = fork()) == 0) {
1592 /* child */
1593 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1594 prog = xstrdup(argv[0]);
1595 argv[0] = xstrdup("(squid)");
1596 execvp(prog, argv);
1597 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
1598 }
1599
1600 /* parent */
1601 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1602
1603 syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
1604
1605 time(&start);
1606
1607 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
1608
1609 #ifdef _SQUID_NEXT_
1610
1611 pid = wait3(&status, 0, NULL);
1612
1613 #else
1614
1615 pid = waitpid(-1, &status, 0);
1616
1617 #endif
1618
1619 time(&stop);
1620
1621 if (WIFEXITED(status)) {
1622 syslog(LOG_NOTICE,
1623 "Squid Parent: child process %d exited with status %d",
1624 pid, WEXITSTATUS(status));
1625 } else if (WIFSIGNALED(status)) {
1626 syslog(LOG_NOTICE,
1627 "Squid Parent: child process %d exited due to signal %d with status %d",
1628 pid, WTERMSIG(status), WEXITSTATUS(status));
1629 } else {
1630 syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
1631 }
1632
1633 if (stop - start < 10)
1634 failcount++;
1635 else
1636 failcount = 0;
1637
1638 if (failcount == 5) {
1639 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
1640 exit(1);
1641 }
1642
1643 if (WIFEXITED(status))
1644 if (WEXITSTATUS(status) == 0)
1645 exit(0);
1646
1647 if (WIFSIGNALED(status)) {
1648 switch (WTERMSIG(status)) {
1649
1650 case SIGKILL:
1651 exit(0);
1652 break;
1653
1654 case SIGINT:
1655 case SIGTERM:
1656 syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
1657 exit(1);
1658 break;
1659
1660 default:
1661 break;
1662 }
1663 }
1664
1665 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
1666 sleep(3);
1667 }
1668
1669 /* NOTREACHED */
1670 #endif /* _SQUID_MSWIN_ */
1671
1672 }
1673
1674 static void
1675 SquidShutdown()
1676 {
1677 /* XXX: This function is called after the main loop has quit, which
1678 * means that no AsyncCalls would be called, including close handlers.
1679 * TODO: We need to close/shut/free everything that needs calls before
1680 * exiting the loop.
1681 */
1682
1683 #if USE_WIN32_SERVICE
1684 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1685 #endif
1686
1687 debugs(1, 1, "Shutting down...");
1688 #if USE_DNSSERVERS
1689
1690 dnsShutdown();
1691 #else
1692
1693 idnsShutdown();
1694 #endif
1695
1696 redirectShutdown();
1697 externalAclShutdown();
1698 icpConnectionClose();
1699 #if USE_HTCP
1700
1701 htcpSocketClose();
1702 #endif
1703 #ifdef SQUID_SNMP
1704
1705 snmpConnectionClose();
1706 #endif
1707 #if USE_WCCP
1708
1709 wccpConnectionClose();
1710 #endif
1711 #if USE_WCCPv2
1712
1713 wccp2ConnectionClose();
1714 #endif
1715
1716 releaseServerSockets();
1717 commCloseAllSockets();
1718
1719 #if USE_SQUID_ESI
1720 Esi::Clean();
1721 #endif
1722
1723 #if DELAY_POOLS
1724
1725 DelayPools::FreePools();
1726 #endif
1727
1728 authenticateShutdown();
1729 #if USE_WIN32_SERVICE
1730
1731 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1732 #endif
1733
1734 Store::Root().sync(); /* Flush pending object writes/unlinks */
1735 #if USE_UNLINKD
1736
1737 unlinkdClose(); /* after sync/flush */
1738 #endif
1739
1740 storeDirWriteCleanLogs(0);
1741 PrintRusage();
1742 dumpMallocStats();
1743 Store::Root().sync(); /* Flush log writes */
1744 storeLogClose();
1745 accessLogClose();
1746 useragentLogClose();
1747 refererCloseLog();
1748 #if WIP_FWD_LOG
1749
1750 fwdUninit();
1751 #endif
1752
1753 Store::Root().sync(); /* Flush log close */
1754 StoreFileSystem::FreeAllFs();
1755 DiskIOModule::FreeAllModules();
1756 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1757
1758 configFreeMemory();
1759 storeFreeMemory();
1760 /*stmemFreeMemory(); */
1761 netdbFreeMemory();
1762 ipcacheFreeMemory();
1763 fqdncacheFreeMemory();
1764 asnFreeMemory();
1765 clientdbFreeMemory();
1766 httpHeaderCleanModule();
1767 statFreeMemory();
1768 eventFreeMemory();
1769 mimeFreeMemory();
1770 errorClean();
1771 #endif
1772 #if !XMALLOC_TRACE
1773
1774 if (opt_no_daemon) {
1775 file_close(0);
1776 file_close(1);
1777 file_close(2);
1778 }
1779
1780 #endif
1781 fdDumpOpen();
1782
1783 comm_exit();
1784
1785 memClean();
1786
1787 #if XMALLOC_TRACE
1788
1789 xmalloc_find_leaks();
1790
1791 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total);
1792
1793 #endif
1794 #if MEM_GEN_TRACE
1795
1796 log_trace_done();
1797
1798 #endif
1799
1800 if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
1801 enter_suid();
1802 safeunlink(Config.pidFilename, 0);
1803 leave_suid();
1804 }
1805
1806 debugs(1, 1, "Squid Cache (Version " << version_string << "): Exiting normally.");
1807
1808 /*
1809 * DPW 2006-10-23
1810 * We used to fclose(debug_log) here if it was set, but then
1811 * we forgot to set it to NULL. That caused some coredumps
1812 * because exit() ends up calling a bunch of destructors and
1813 * such. So rather than forcing the debug_log to close, we'll
1814 * leave it open so that those destructors can write some
1815 * debugging if necessary. The file will be closed anyway when
1816 * the process truly exits.
1817 */
1818
1819 exit(shutdown_status);
1820 }
1821