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