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