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