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