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