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