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