]> git.ipfire.org Git - thirdparty/squid.git/blame - src/main.cc
Refactored actions for clientdb, comm_select, dns and idns to
[thirdparty/squid.git] / src / main.cc
CommitLineData
30a4f2a8 1/*
63be0a78 2 * $Id: main.cc,v 1.459 2008/02/26 21:49:35 amosjeffries Exp $
30a4f2a8 3 *
4 * DEBUG: section 1 Startup and Main Loop
5 * AUTHOR: Harvest Derived
6 *
2b6662ba 7 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 8 * ----------------------------------------------------------
30a4f2a8 9 *
2b6662ba 10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
30a4f2a8 18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
cbdec147 31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 32 *
30a4f2a8 33 */
44a47c6e 34
35#include "squid.h"
450e0c10 36#include "AccessLogEntry.h"
e6ccf245 37#include "authenticate.h"
62ee09ca 38#include "CacheManager.h"
39#include "ConfigParser.h"
aa839030 40#include "errorpage.h"
a553a5a3 41#include "event.h"
42#include "EventLoop.h"
62ee09ca 43#include "ExternalACL.h"
e6ccf245 44#include "Store.h"
45#include "ICP.h"
5a7431b8 46#include "ident.h"
528b2c61 47#include "HttpReply.h"
62ee09ca 48#include "pconn.h"
528b2c61 49#include "Mem.h"
b0dd28ba 50#include "ACLASN.h"
51#include "ACL.h"
75faaa7a 52#include "htcp.h"
59b2d47f 53#include "StoreFileSystem.h"
b9ae18aa 54#include "DiskIO/DiskIOModule.h"
f900210a 55#include "comm.h"
62ee09ca 56#if USE_EPOLL
57#include "comm_epoll.h"
58#endif
59#if USE_KQUEUE
60#include "comm_kqueue.h"
61#endif
62#if USE_POLL
63#include "comm_poll.h"
64#endif
7cdb47bc 65#if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
663c0a38 66#include "comm_select.h"
67#endif
985c86bc 68#include "SquidTime.h"
c8f4eac4 69#include "SwapDir.h"
b6b6f466 70#include "forward.h"
d9e7ee1f 71#include "MemPool.h"
cc192b50 72#include "ICMPSquid.h"
44a47c6e 73
57afc994
AR
74#if USE_LOADABLE_MODULES
75#include "LoadableModules.h"
76#endif
77
b958cb0f
AR
78#if ICAP_CLIENT
79#include "ICAP/ICAPConfig.h"
80#endif
81#if USE_ADAPTATION
82#include "adaptation/Config.h"
83#endif
84
1a774556 85#if USE_WIN32_SERVICE
86
87#include "squid_windows.h"
88#include <process.h>
89
90static int opt_install_service = FALSE;
91static int opt_remove_service = FALSE;
92static int opt_signal_service = FALSE;
93static int opt_command_line = FALSE;
94extern void WIN32_svcstatusupdate(DWORD, DWORD);
95void WINAPI WIN32_svcHandler(DWORD);
96
97#endif
98
63be0a78 99/** for error reporting from xmalloc and friends */
b293c4d8 100SQUIDCEXTERN void (*failure_notify) (const char *);
30a4f2a8 101
e13ee7ad 102static int opt_parse_cfg_only = 0;
5e6d4736 103static char *opt_syslog_facility = NULL;
30a4f2a8 104static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
e13ee7ad 105static int configured_once = 0;
30a4f2a8 106#if MALLOC_DBG
4d64d74a 107static int malloc_debug_level = 0;
30a4f2a8 108#endif
5cd39a10 109static volatile int do_reconfigure = 0;
110static volatile int do_rotate = 0;
2681d383 111static volatile int do_shutdown = 0;
ae1feb30 112static volatile int shutdown_status = 0;
4d7add01 113
5cd39a10 114static void mainRotate(void);
115static void mainReconfigure(void);
f5b8bbc4 116static void mainInitialize(void);
f5b8bbc4 117static void usage(void);
63be0a78 118static void mainParseOptions(int argc, char *argv[]);
f5b8bbc4 119static void sendSignal(void);
120static void serverConnectionsOpen(void);
bbe199dc 121static void watch_child(char **);
85407535 122static void setEffectiveUser(void);
36a97e19 123#if MEM_GEN_TRACE
124extern void log_trace_done();
125extern void log_trace_init(char *);
126#endif
8ff3fa2e 127static void SquidShutdown(void);
b6a2f15e 128static void mainSetCwd(void);
efd900cb 129static int checkRunningPid(void);
85407535 130
c83f0bd5 131static CacheManager *manager=CacheManager::GetInstance();
62ee09ca 132
b293c4d8 133#ifndef _SQUID_MSWIN_
e18d7fdc 134static const char *squid_start_script = "squid_start";
b293c4d8 135#endif
e18d7fdc 136
9bc73deb 137#if TEST_ACCESS
138#include "test_access.c"
139#endif
140
63be0a78 141/** temporary thunk across to the unrefactored store interface */
8ff3fa2e 142
143class StoreRootEngine : public AsyncEngine
144{
145
146public:
147 int checkEvents(int timeout)
148 {
149 Store::Root().callback();
150 return EVENT_IDLE;
151 };
152};
153
9688b0ae 154class SignalEngine: public AsyncEngine
a553a5a3 155{
156
157public:
9688b0ae 158 SignalEngine(EventLoop &loop) : loop(loop) {}
159 virtual int checkEvents(int timeout);
a553a5a3 160
161private:
162 static void StopEventLoop(void * data)
163 {
9688b0ae 164 static_cast<SignalEngine *>(data)->loop.stop();
a553a5a3 165 }
166
9688b0ae 167 void doShutdown(time_t wait);
168
a553a5a3 169 EventLoop &loop;
170};
171
9688b0ae 172int
173SignalEngine::checkEvents(int timeout)
a553a5a3 174{
9688b0ae 175 PROF_start(SignalEngine_checkEvents);
fc68f6b1 176
a553a5a3 177 if (do_reconfigure) {
178 mainReconfigure();
179 do_reconfigure = 0;
a553a5a3 180 } else if (do_rotate) {
181 mainRotate();
182 do_rotate = 0;
183 } else if (do_shutdown) {
9688b0ae 184 doShutdown(do_shutdown > 0 ? (int) Config.shutdownLifetime : 0);
a553a5a3 185 do_shutdown = 0;
9688b0ae 186 }
a553a5a3 187
9688b0ae 188 PROF_stop(SignalEngine_checkEvents);
189 return EVENT_IDLE;
190}
a553a5a3 191
9688b0ae 192void
193SignalEngine::doShutdown(time_t wait)
194{
195 debugs(1, 1, "Preparing for shutdown after " << statCounter.client_http.requests << " requests");
196 debugs(1, 1, "Waiting " << wait << " seconds for active connections to finish");
8ff3fa2e 197
9688b0ae 198 shutting_down = 1;
199
200#if USE_WIN32_SERVICE
201 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
202#endif
203
204 serverConnectionsClose();
205 eventAdd("SquidShutdown", &StopEventLoop, this, (double) (wait + 1), 1, false);
a553a5a3 206}
207
b8d8561b 208static void
0673c0ba 209usage(void)
ccff9601 210{
0ee4272b 211 fprintf(stderr,
0e657244 212#if USE_WIN32_SERVICE
5e6d4736 213 "Usage: %s [-cdhirvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
0e657244 214#else
5e6d4736 215 "Usage: %s [-cdhvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
0e657244 216#endif
62e76326 217 " -a port Specify HTTP port number (default: %d).\n"
218 " -d level Write debugging to stderr also.\n"
219 " -f file Use given config-file instead of\n"
220 " %s\n"
221 " -h Print help message.\n"
0e657244 222#if USE_WIN32_SERVICE
223 " -i Installs as a Windows Service (see -n option).\n"
224#endif
62e76326 225 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
226 " Parse configuration file, then send signal to \n"
227 " running copy (except -k parse) and exit.\n"
0e657244 228#if USE_WIN32_SERVICE
229 " -n name Specify Windows Service name to use for service operations\n"
230 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
231 " -r Removes a Windows Service (see -n option).\n"
232#endif
5e6d4736 233 " -s | -l facility\n"
234 " Enable logging to syslog.\n"
62e76326 235 " -u port Specify ICP port number (default: %d), disable with 0.\n"
236 " -v Print version.\n"
237 " -z Create swap directories\n"
238 " -C Do not catch fatal signals.\n"
239 " -D Disable initial DNS tests.\n"
240 " -F Don't serve any requests until store is rebuilt.\n"
241 " -N No daemon mode.\n"
0e657244 242#if USE_WIN32_SERVICE
243 " -O options\n"
244 " Set Windows Service Command line options in Registry.\n"
245#endif
62e76326 246 " -R Do not set REUSEADDR on port.\n"
247 " -S Double-check swap during rebuild.\n"
248 " -V Virtual host httpd-accelerator.\n"
249 " -X Force full debugging.\n"
250 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
7dbca7a4 251 APP_SHORTNAME, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
77ffc99f 252 exit(1);
ccff9601 253}
254
63be0a78 255/**
256 * Parse the parameters received via command line interface.
257 *
258 \param argc[in] Number of options received on command line
259 \param argv[in] List of parameters received on command line
260 */
b8d8561b 261static void
262mainParseOptions(int argc, char *argv[])
090089c4 263{
090089c4 264 extern char *optarg;
4d64d74a 265 int c;
090089c4 266
0e657244 267#if USE_WIN32_SERVICE
5e6d4736 268 while ((c = getopt(argc, argv, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
0e657244 269#else
05f1c52c 270 while ((c = getopt(argc, argv, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
0e657244 271#endif
9b7292ce 272 {
273
274 switch (c)
275 {
62e76326 276
277 case 'C':
63be0a78 278 /** \par C
279 * Unset/disabel global option for catchign signals. opt_catch_signals */
62e76326 280 opt_catch_signals = 0;
281 break;
282
283 case 'D':
63be0a78 284 /** \par D
285 * Unset/disable global option for optional DNS tests. opt_dns_tests */
62e76326 286 opt_dns_tests = 0;
287 break;
288
289 case 'F':
63be0a78 290 /** \par F
291 * Set global option for foreground rebuild. opt_foreground_rebuild */
62e76326 292 opt_foreground_rebuild = 1;
293 break;
294
295 case 'N':
63be0a78 296 /** \par N
297 * Set global option for 'no_daemon' mode. opt_no_daemon */
62e76326 298 opt_no_daemon = 1;
299 break;
63be0a78 300
0e657244 301#if USE_WIN32_SERVICE
302
303 case 'O':
63be0a78 304 /** \par O
305 * Set global option. opt_command_lin and WIN32_Command_Line */
0e657244 306 opt_command_line = 1;
307 WIN32_Command_Line = xstrdup(optarg);
308 break;
309#endif
62e76326 310
311 case 'R':
63be0a78 312 /** \par R
313 * Unset/disable global option opt_reuseaddr */
62e76326 314 opt_reuseaddr = 0;
315 break;
316
317 case 'S':
63be0a78 318 /** \par S
319 * Set global option opt_store_doublecheck */
62e76326 320 opt_store_doublecheck = 1;
321 break;
322
62e76326 323 case 'X':
63be0a78 324 /** \par X
325 * Force full debugging */
37296f4c 326 Debug::parseOptions("debug_options ALL,9");
327 Config.onoff.debug_override_X = 1;
62e76326 328 sigusr2_handle(SIGUSR2);
62e76326 329 break;
330
331 case 'Y':
63be0a78 332 /** \par Y
333 * Set global option opt_reload_hit_only */
62e76326 334 opt_reload_hit_only = 1;
62e76326 335 break;
336
0e657244 337#if USE_WIN32_SERVICE
338
339 case 'i':
63be0a78 340 /** \par i
341 * Set global option opt_install_service (to TRUE) */
0e657244 342 opt_install_service = TRUE;
0e657244 343 break;
0e657244 344#endif
345
62e76326 346 case 'a':
63be0a78 347 /** \par a
348 * Add optional HTTP port as given following the option */
62e76326 349 add_http_port(optarg);
62e76326 350 break;
351
352 case 'd':
63be0a78 353 /** \par d
354 * Set global option opt_debug_stderr to the number given follwoign the option */
62e76326 355 opt_debug_stderr = atoi(optarg);
62e76326 356 break;
357
358 case 'f':
63be0a78 359 /** \par f
360 * Load the file given instead of the default squid.conf. */
62e76326 361 xfree(ConfigFile);
62e76326 362 ConfigFile = xstrdup(optarg);
62e76326 363 break;
364
365 case 'k':
63be0a78 366 /** \par k
367 * Run the administrative action given following the option */
fc68f6b1 368
63be0a78 369 /** \li When its an unknown option display the usage help. */
62e76326 370 if ((int) strlen(optarg) < 1)
371 usage();
372
373 if (!strncmp(optarg, "reconfigure", strlen(optarg)))
63be0a78 374 /** \li On reconfigure send SIGHUP. */
62e76326 375 opt_send_signal = SIGHUP;
376 else if (!strncmp(optarg, "rotate", strlen(optarg)))
63be0a78 377 /** \li On rotate send SIGQUIT or SIGUSR1. */
7e7a0442 378#ifdef _SQUID_LINUX_THREADS_
62e76326 379
380 opt_send_signal = SIGQUIT;
381
e3175d1f 382#else
62e76326 383
384 opt_send_signal = SIGUSR1;
385
e3175d1f 386#endif
62e76326 387
388 else if (!strncmp(optarg, "debug", strlen(optarg)))
63be0a78 389 /** \li On debug send SIGTRAP or SIGUSR2. */
7e7a0442 390#ifdef _SQUID_LINUX_THREADS_
62e76326 391
392 opt_send_signal = SIGTRAP;
393
e3175d1f 394#else
62e76326 395
396 opt_send_signal = SIGUSR2;
397
398#endif
399
400 else if (!strncmp(optarg, "shutdown", strlen(optarg)))
63be0a78 401 /** \li On shutdown send SIGTERM. */
62e76326 402 opt_send_signal = SIGTERM;
403 else if (!strncmp(optarg, "interrupt", strlen(optarg)))
63be0a78 404 /** \li On interrupt send SIGINT. */
62e76326 405 opt_send_signal = SIGINT;
406 else if (!strncmp(optarg, "kill", strlen(optarg)))
63be0a78 407 /** \li On kill send SIGKILL. */
62e76326 408 opt_send_signal = SIGKILL;
ae1feb30 409
410#ifdef SIGTTIN
411
412 else if (!strncmp(optarg, "restart", strlen(optarg)))
63be0a78 413 /** \li On restart send SIGTTIN. (exit and restart by parent) */
414 opt_send_signal = SIGTTIN;
ae1feb30 415
416#endif
417
62e76326 418 else if (!strncmp(optarg, "check", strlen(optarg)))
63be0a78 419 /** \li On check send 0 / SIGNULL. */
62e76326 420 opt_send_signal = 0; /* SIGNULL */
421 else if (!strncmp(optarg, "parse", strlen(optarg)))
63be0a78 422 /** \li On parse set global flag to re-parse the config file only. */
423 opt_parse_cfg_only = 1;
62e76326 424 else
425 usage();
426
427 break;
428
429 case 'm':
63be0a78 430 /** \par m
431 * Set global malloc_debug_level to the value given following the option.
432 * if none is given it toggles the xmalloc_trace option on/off */
62e76326 433 if (optarg) {
30a4f2a8 434#if MALLOC_DBG
fc68f6b1 435 malloc_debug_level = atoi(optarg);
30a4f2a8 436#else
fc68f6b1 437 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
33ab18e8 438#endif
62e76326 439
440 } else {
33ab18e8 441#if XMALLOC_TRACE
62e76326 442 xmalloc_trace = !xmalloc_trace;
33ab18e8 443#else
62e76326 444 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
30a4f2a8 445#endif
62e76326 446 }
d9e7ee1f 447 break;
d9e7ee1f 448
0e657244 449#if USE_WIN32_SERVICE
450
451 case 'n':
63be0a78 452 /** \par n
453 * Set global option opt_signal_service (to TRUE).
454 * Stores the additional parameter given in global WIN32_Service_name */
0e657244 455 xfree(WIN32_Service_name);
456
457 WIN32_Service_name = xstrdup(optarg);
458
459 opt_signal_service = TRUE;
460
461 break;
462
463 case 'r':
63be0a78 464 /** \par r
465 * Set global option opt_remove_service (to TRUE) */
0e657244 466 opt_remove_service = TRUE;
467
468 break;
469
470#endif
471
5e6d4736 472 case 'l':
63be0a78 473 /** \par l
474 * Stores the syslog facility name in global opt_syslog_facility
475 * then performs actions for -s option. */
5e6d4736 476 opt_syslog_facility = xstrdup(optarg);
477
62e76326 478 case 's':
63be0a78 479 /** \par s
480 * Initialize the syslog for output */
c307aec3 481#if HAVE_SYSLOG
62e76326 482
5e6d4736 483 _db_set_syslog(opt_syslog_facility);
0e657244 484
62e76326 485 break;
0e657244 486
c307aec3 487#else
62e76326 488
489 fatal("Logging to syslog not available on this platform");
0e657244 490
62e76326 491 /* NOTREACHED */
492#endif
493
494 case 'u':
63be0a78 495 /** \par u
496 * Store the ICP port number given in global option icpPortNumOverride
497 * ensuring its a positive number. */
62e76326 498 icpPortNumOverride = atoi(optarg);
499
500 if (icpPortNumOverride < 0)
501 icpPortNumOverride = 0;
502
503 break;
504
505 case 'v':
63be0a78 506 /** \par v
507 * Display squid version and build information. Then exit. */
62e76326 508 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
509
1a774556 510#if USE_WIN32_SERVICE
511
512 printf("Compiled as Windows System Service.\n");
513
514#endif
515
62e76326 516 exit(0);
517
518 /* NOTREACHED */
519
520 case 'z':
63be0a78 521 /** \par z
522 * Set global option opt_debug_stderr and opt_create_swap_dirs */
930dea4a 523 opt_debug_stderr = 1;
524
62e76326 525 opt_create_swap_dirs = 1;
526
527 break;
528
63be0a78 529 case 'h':
530
62e76326 531 case '?':
532
533 default:
63be0a78 534 /** \par h,?, or unknown
535 * \copydoc usage() */
62e76326 536 usage();
537
538 break;
539 }
9b7292ce 540
090089c4 541 }
4d64d74a 542}
090089c4 543
7a2f978b 544/* ARGSUSED */
b293c4d8 545void
9b7292ce 546rotate_logs(int sig)
547{
5cd39a10 548 do_rotate = 1;
a50bfe93 549#ifndef _SQUID_MSWIN_
30a4f2a8 550#if !HAVE_SIGACTION
62e76326 551
30a4f2a8 552 signal(sig, rotate_logs);
553#endif
a50bfe93 554#endif
30a4f2a8 555}
556
7a2f978b 557/* ARGSUSED */
b293c4d8 558void
9b7292ce 559reconfigure(int sig)
560{
5cd39a10 561 do_reconfigure = 1;
a50bfe93 562#ifndef _SQUID_MSWIN_
30a4f2a8 563#if !HAVE_SIGACTION
62e76326 564
30a4f2a8 565 signal(sig, reconfigure);
566#endif
a50bfe93 567#endif
30a4f2a8 568}
569
b8d8561b 570void
9b7292ce 571shut_down(int sig)
572{
2681d383 573 do_shutdown = sig == SIGINT ? -1 : 1;
ae1feb30 574#ifdef SIGTTIN
575
576 if (SIGTTIN == sig)
577 shutdown_status = 1;
578
579#endif
a50bfe93 580#ifndef _SQUID_MSWIN_
cadc2d55 581#ifdef KILL_PARENT_OPT
62e76326 582
5cd39a10 583 if (getppid() > 1) {
36584579 584 debugs(1, 1, "Killing RunCache, pid " << getppid());
62e76326 585
586 if (kill(getppid(), sig) < 0)
36584579 587 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
88738790 588 }
62e76326 589
cadc2d55 590#endif
6e40f263 591#if SA_RESETHAND == 0
592 signal(SIGTERM, SIG_DFL);
62e76326 593
6e40f263 594 signal(SIGINT, SIG_DFL);
62e76326 595
a50bfe93 596#endif
6e40f263 597#endif
30a4f2a8 598}
599
24382924 600static void
9b7292ce 601serverConnectionsOpen(void)
602{
d193a436 603 clientOpenListenSockets();
15df8349 604 icpConnectionsOpen();
ace287ee 605#if USE_HTCP
62e76326 606
ace287ee 607 htcpInit();
608#endif
678c6099 609#ifdef SQUID_SNMP
62e76326 610
3265e68d 611 snmpConnectionOpen();
320e9f36 612#endif
eb824054 613#if USE_WCCP
62e76326 614
320e9f36 615 wccpConnectionOpen();
2bbd722b 616#endif
62e76326 617
0b0cfcf2 618#if USE_WCCPv2
619
620 wccp2ConnectionOpen();
621#endif
622
5ecceaa4 623 clientdbInit();
cc192b50 624 icmpEngine.Open();
67508012 625 netdbInit();
f899fac1 626 asnInit();
b0dd28ba 627 ACL::Initialize();
85034133 628 peerSelectInit();
afd88fbe 629#if USE_CARP
62e76326 630
afd88fbe 631 carpInit();
632#endif
5f3f8d0e 633}
634
b8d8561b 635void
9b7292ce 636serverConnectionsClose(void)
637{
0a5a8601 638 assert(shutting_down || reconfiguring);
c0fbae16 639 clientHttpConnectionsClose();
17e6c0a1 640 icpConnectionShutdown();
72549e05 641#if USE_HTCP
62e76326 642
72549e05 643 htcpSocketShutdown();
644#endif
62e76326 645
cc192b50 646 icmpEngine.Close();
15df8349 647#ifdef SQUID_SNMP
62e76326 648
17e6c0a1 649 snmpConnectionShutdown();
320e9f36 650#endif
eb824054 651#if USE_WCCP
62e76326 652
0b0cfcf2 653 wccpConnectionClose();
654#endif
655#if USE_WCCPv2
656
657 wccp2ConnectionClose();
15df8349 658#endif
62e76326 659
4bac8de8 660 asnFreeMemory();
5f3f8d0e 661}
662
b8d8561b 663static void
9b7292ce 664mainReconfigure(void)
665{
bf8fe701 666 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string << ")...");
5cd39a10 667 reconfiguring = 1;
0ffd22bc 668 /* Already called serverConnectionsClose and ipcacheShutdownServers() */
15df8349 669 serverConnectionsClose();
17e6c0a1 670 icpConnectionClose();
72549e05 671#if USE_HTCP
62e76326 672
72549e05 673 htcpSocketClose();
674#endif
17e6c0a1 675#ifdef SQUID_SNMP
62e76326 676
17e6c0a1 677 snmpConnectionClose();
320e9f36 678#endif
3c573763 679#if USE_DNSSERVERS
62e76326 680
74addf6c 681 dnsShutdown();
3c573763 682#else
62e76326 683
7b724b86 684 idnsShutdown();
eb824054 685#endif
62e76326 686
74addf6c 687 redirectShutdown();
688 authenticateShutdown();
d9572179 689 externalAclShutdown();
2db68ce5 690 storeDirCloseSwapLogs();
2e923080 691 storeLogClose();
692 accessLogClose();
693 useragentLogClose();
694 refererCloseLog();
c68e9c6b 695 errorClean();
3aa4adbc 696 enter_suid(); /* root to read config file */
dd9b1081 697 parseConfigFile(ConfigFile);
c642c141 698 setUmask(Config.umask);
97244680 699 Mem::Report();
3aa4adbc 700 setEffectiveUser();
b6f794d6 701 _db_init(Config.Log.log, Config.debugOptions);
429fdbec 702 ipcache_restart(); /* clear stuck entries */
94439e4e 703 authenticateUserCacheRestart(); /* clear stuck ACL entries */
429fdbec 704 fqdncache_restart(); /* sigh, fqdncache too */
0e70aa1e 705 parseEtcHosts();
53ad48e6 706 errorInitialize(); /* reload error pages */
2e923080 707 accessLogInit();
708 storeLogOpen();
709 useragentOpenLog();
710 refererOpenLog();
3c573763 711#if USE_DNSSERVERS
62e76326 712
74addf6c 713 dnsInit();
3c573763 714#else
62e76326 715
7b724b86 716 idnsInit();
eb824054 717#endif
62e76326 718
74addf6c 719 redirectInit();
e6ccf245 720 authenticateInit(&Config.authConfiguration);
d9572179 721 externalAclInit();
1f38f50a 722#if USE_WCCP
62e76326 723
1f38f50a 724 wccpInit();
725#endif
0b0cfcf2 726#if USE_WCCPv2
727
728 wccp2Init();
729#endif
62e76326 730
0ffd22bc 731 serverConnectionsOpen();
9c2e9b50 732
3ee2b4f8 733 neighbors_init();
2ea8b120 734 neighborsRegisterWithCacheManager();
9c2e9b50 735
2db68ce5 736 storeDirOpenSwapLogs();
9c2e9b50 737
9c021a38 738 mimeInit(Config.mimeTablePathname);
9c2e9b50 739
926375e6 740 if (Config.onoff.announce) {
741 if (!eventFind(start_announce, NULL))
742 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
743 } else {
744 if (eventFind(start_announce, NULL))
745 eventDelete(start_announce, NULL);
746 }
747
b8890359 748 writePidFile(); /* write PID file */
9c2e9b50 749
bf8fe701 750 debugs(1, 1, "Ready to serve requests.");
9c2e9b50 751
5cd39a10 752 reconfiguring = 0;
753}
754
755static void
9b7292ce 756mainRotate(void)
757{
cc192b50 758 icmpEngine.Close();
3c573763 759#if USE_DNSSERVERS
62e76326 760
e40aa8da 761 dnsShutdown();
3c573763 762#endif
62e76326 763
e40aa8da 764 redirectShutdown();
765 authenticateShutdown();
d9572179 766 externalAclShutdown();
5cd39a10 767 _db_rotate_log(); /* cache.log */
768 storeDirWriteCleanLogs(1);
769 storeLogRotate(); /* store.log */
770 accessLogRotate(); /* access.log */
771 useragentRotateLog(); /* useragent.log */
fd2c5549 772 refererRotateLog(); /* referer.log */
225644d7 773#if WIP_FWD_LOG
62e76326 774
225644d7 775 fwdLogRotate();
776#endif
62e76326 777
cc192b50 778 icmpEngine.Open();
3c573763 779#if USE_DNSSERVERS
62e76326 780
e40aa8da 781 dnsInit();
3c573763 782#endif
62e76326 783
e40aa8da 784 redirectInit();
e6ccf245 785 authenticateInit(&Config.authConfiguration);
d9572179 786 externalAclInit();
5f3f8d0e 787}
788
067bea91 789static void
9b7292ce 790setEffectiveUser(void)
791{
fc68f6b1 792 keepCapabilities();
85407535 793 leave_suid(); /* Run as non privilegied user */
cd377065 794#ifdef _SQUID_OS2_
62e76326 795
cd377065 796 return;
797#endif
62e76326 798
85407535 799 if (geteuid() == 0) {
bf8fe701 800 debugs(0, 0, "Squid is not safe to run as root! If you must");
801 debugs(0, 0, "start Squid as root, then you must configure");
802 debugs(0, 0, "it to run as a non-priveledged user with the");
803 debugs(0, 0, "'cache_effective_user' option in the config file.");
62e76326 804 fatal("Don't run Squid as root, set 'cache_effective_user'!");
85407535 805 }
806}
807
b6a2f15e 808static void
9b7292ce 809mainSetCwd(void)
810{
4a504376 811 char pathbuf[MAXPATHLEN];
62e76326 812
b6a2f15e 813 if (Config.coredump_dir) {
62e76326 814 if (0 == strcmp("none", Config.coredump_dir)) {
815 (void) 0;
816 } else if (chdir(Config.coredump_dir) == 0) {
bf8fe701 817 debugs(0, 1, "Set Current Directory to " << Config.coredump_dir);
62e76326 818 return;
819 } else {
bf8fe701 820 debugs(50, 0, "chdir: " << Config.coredump_dir << ": " << xstrerror());
62e76326 821 }
b6a2f15e 822 }
62e76326 823
02e8115e 824 /* If we don't have coredump_dir or couldn't cd there, report current dir */
4a504376 825 if (getcwd(pathbuf, MAXPATHLEN)) {
bf8fe701 826 debugs(0, 1, "Current Directory is " << pathbuf);
4a504376 827 } else {
bf8fe701 828 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
4a504376 829 }
b6a2f15e 830}
831
b67e2c8c 832#if DELAY_POOLS
833#include "DelayPools.h"
834#endif
835
b8d8561b 836static void
9b7292ce 837mainInitialize(void)
838{
efd900cb 839 /* chroot if configured to run inside chroot */
62e76326 840
64b0a10d 841 if (Config.chroot_dir && (chroot(Config.chroot_dir) != 0 || chdir("/") != 0)) {
62e76326 842 fatal("failed to chroot");
efd900cb 843 }
62e76326 844
1758c627 845 if (opt_catch_signals) {
62e76326 846 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
847 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
44f99671 848 }
62e76326 849
30a4f2a8 850 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
851 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
44f99671 852
85407535 853 setEffectiveUser();
62e76326 854
30a4f2a8 855 if (icpPortNumOverride != 1)
62e76326 856 Config.Port.icp = (u_short) icpPortNumOverride;
30a4f2a8 857
b6f794d6 858 _db_init(Config.Log.log, Config.debugOptions);
62e76326 859
5c5783a2 860 fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
62e76326 861
71a17702 862#if MEM_GEN_TRACE
62e76326 863
71a17702 864 log_trace_init("/tmp/squid.alloc");
62e76326 865
71a17702 866#endif
62e76326 867
bf8fe701 868 debugs(1, 0, "Starting Squid Cache version " << version_string << " for " << CONFIG_HOST_TYPE << "...");
62e76326 869
ec4daaa5 870#ifdef _SQUID_WIN32_
b293c4d8 871
872 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
bf8fe701 873 debugs(1, 0, "Running as " << WIN32_Service_name << " Windows System Service on " << WIN32_OS_string);
874 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line);
b293c4d8 875 } else
bf8fe701 876 debugs(1, 0, "Running on " << WIN32_OS_string);
b293c4d8 877
878#endif
879
36584579 880 debugs(1, 1, "Process ID " << getpid());
62e76326 881
bf8fe701 882 debugs(1, 1, "With " << Squid_MaxFD << " file descriptors available");
5f3f8d0e 883
6c1962dd 884#ifdef _SQUID_MSWIN_
885
bf8fe701 886 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
6c1962dd 887
888 if (WIN32_Socks_initialized)
bf8fe701 889 debugs(1, 1, "Windows sockets initialized");
6c1962dd 890
babd1fd5 891 if (WIN32_OS_version > _WIN_OS_WINNT) {
892 WIN32_IpAddrChangeMonitorInit();
893 }
894
6c1962dd 895#endif
896
9f75c559 897 if (!configured_once)
62e76326 898 disk_init(); /* disk_init must go before ipcache_init() */
899
5f3f8d0e 900 ipcache_init();
62e76326 901
f88bb09c 902 fqdncache_init();
62e76326 903
0e70aa1e 904 parseEtcHosts();
62e76326 905
3c573763 906#if USE_DNSSERVERS
62e76326 907
74addf6c 908 dnsInit();
62e76326 909
3c573763 910#else
62e76326 911
7b724b86 912 idnsInit();
62e76326 913
eb824054 914#endif
62e76326 915
74addf6c 916 redirectInit();
62e76326 917
e6ccf245 918 authenticateInit(&Config.authConfiguration);
62e76326 919
d9572179 920 externalAclInit();
62e76326 921
b012353a 922 useragentOpenLog();
62e76326 923
fd2c5549 924 refererOpenLog();
62e76326 925
2ac76861 926 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
62e76326 927
2246b732 928 httpReplyInitModule(); /* must go before accepting replies */
62e76326 929
9b312a19 930 errorInitialize();
62e76326 931
7a2f978b 932 accessLogInit();
62e76326 933
3898f57f 934#if USE_IDENT
62e76326 935
05832ae1 936 identInit();
62e76326 937
3898f57f 938#endif
5e14bf6d 939#ifdef SQUID_SNMP
62e76326 940
5e14bf6d 941 snmpInit();
62e76326 942
5e14bf6d 943#endif
30a4f2a8 944#if MALLOC_DBG
62e76326 945
5f3f8d0e 946 malloc_debug(0, malloc_debug_level);
62e76326 947
5f3f8d0e 948#endif
949
dbe4fd8e 950 if (!configured_once) {
a3d0a19d 951#if USE_UNLINKD
62e76326 952 unlinkdInit();
953#endif
954
955 urlInitialize();
62e76326 956 statInit();
957 storeInit();
958 mainSetCwd();
959 /* after this point we want to see the mallinfo() output */
960 do_mallinfo = 1;
961 mimeInit(Config.mimeTablePathname);
62e76326 962 refreshInit();
0d7e5d78 963#if DELAY_POOLS
62e76326 964
965 DelayPools::Init();
0d7e5d78 966#endif
62e76326 967
b6b6f466 968 FwdState::initModule();
62ee09ca 969 /* register the modules in the cache manager menus */
d62a240c
FC
970 accessLogRegisterWithCacheManager();
971 asnRegisterWithCacheManager();
15fab853 972 authenticateRegisterWithCacheManager(&Config.authConfiguration);
62ee09ca 973#if USE_CARP
974
1b8a5f51 975 carpRegisterWithCacheManager();
62ee09ca 976#endif
977
a08f1b5a 978 cbdataRegisterWithCacheManager();
62ee09ca 979 /* These use separate calls so that the comm loops can eventually
980 * coexist.
981 */
982#ifdef USE_EPOLL
983
dbeed9ea 984 commEPollRegisterWithCacheManager();
62ee09ca 985#endif
986#ifdef USE_KQUEUE
987
706744c3 988 commKQueueRegisterWithCacheManager();
62ee09ca 989#endif
990#ifdef USE_POLL
991
edfab338 992 commPollRegisterWithCacheManager();
62ee09ca 993#endif
7cdb47bc 994#if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
62ee09ca 995
c5108ed5 996 commSelectRegisterWithCacheManager();
62ee09ca 997#endif
998
c5108ed5 999 clientdbRegisterWithCacheManager();
610ee341 1000#if DELAY_POOLS
1001
c83f0bd5 1002 DelayPools::RegisterWithCacheManager(*manager);
610ee341 1003#endif
1004
15fab853 1005 DiskIOModule::RegisterAllModulesWithCacheManager();
62ee09ca 1006#if USE_DNSSERVERS
1007
c5108ed5 1008 dnsRegisterWithCacheManager();
62ee09ca 1009#endif
1010
c83f0bd5
K
1011 eventInit(*manager);
1012 externalAclRegisterWithCacheManager(*manager);
1013 fqdncacheRegisterWithCacheManager(*manager);
1014 FwdState::RegisterWithCacheManager(*manager);
1015 httpHeaderRegisterWithCacheManager(*manager);
5615c096 1016#if !USE_DNSSERVERS
1017
c5108ed5 1018 idnsRegisterWithCacheManager();
5615c096 1019#endif
1020
c83f0bd5
K
1021 ipcacheRegisterWithCacheManager(*manager);
1022 Mem::RegisterWithCacheManager(*manager);
1023 netdbRegisterWitHCacheManager(*manager);
15fab853 1024 PconnModule::GetInstance()->registerWithCacheManager();
c83f0bd5
K
1025 redirectRegisterWithCacheManager(*manager);
1026 refreshRegisterWithCacheManager(*manager);
1027 statRegisterWithCacheManager(*manager);
1028 storeDigestRegisterWithCacheManager(*manager);
1029 StoreFileSystem::RegisterAllFsWithCacheManager(*manager);
1030 storeRegisterWithCacheManager(*manager);
1031 storeLogRegisterWithCacheManager(*manager);
62ee09ca 1032#if DEBUGSTRINGS
1033
15fab853 1034 StringRegistry::Instance().registerWithCacheManager();
62ee09ca 1035#endif
1036
610ee341 1037#if USE_XPROF_STATS
1038
c83f0bd5 1039 xprofRegisterWithCacheManager(*manager);
610ee341 1040#endif
1041
5f3f8d0e 1042 }
62e76326 1043
1f38f50a 1044#if USE_WCCP
1045 wccpInit();
62e76326 1046
0b0cfcf2 1047#endif
1048#if USE_WCCPv2
1049
1050 wccp2Init();
1051
1f38f50a 1052#endif
62e76326 1053
2285407f 1054 serverConnectionsOpen();
62e76326 1055
3ee2b4f8 1056 neighbors_init();
fc68f6b1 1057
2ea8b120 1058 neighborsRegisterWithCacheManager();
62e76326 1059
efd900cb 1060 if (Config.chroot_dir)
62e76326 1061 no_suid();
1062
dbe4fd8e 1063 if (!configured_once)
62e76326 1064 writePidFile(); /* write PID file */
0a5b9b32 1065
7e7a0442 1066#ifdef _SQUID_LINUX_THREADS_
62e76326 1067
e3175d1f 1068 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
62e76326 1069
e3175d1f 1070 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
62e76326 1071
e3175d1f 1072#else
62e76326 1073
30a4f2a8 1074 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
62e76326 1075
30a4f2a8 1076 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
62e76326 1077
9fc0b4b8 1078#endif
62e76326 1079
30a4f2a8 1080 squid_signal(SIGHUP, reconfigure, SA_RESTART);
62e76326 1081
30a4f2a8 1082 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
62e76326 1083
30a4f2a8 1084 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
62e76326 1085
ae1feb30 1086#ifdef SIGTTIN
1087
1088 squid_signal(SIGTTIN, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
1089
1090#endif
1091
58a39dc9 1092 memCheckInit();
62e76326 1093
57afc994
AR
1094#if USE_LOADABLE_MODULES
1095 LoadableModulesConfigure(Config.loadable_module_names);
1096#endif
1097
8f361c50
AR
1098#if USE_ADAPTATION
1099 bool enableAdaptation = false;
1100
1101 // We can remove this dependency on specific adaptation mechanisms
1102 // if we create a generic Registry of such mechanisms. Should we?
b958cb0f
AR
1103#if ICAP_CLIENT
1104 TheICAPConfig.finalize(); // must be after we load modules
8f361c50 1105 enableAdaptation = TheICAPConfig.onoff;
b958cb0f 1106#endif
8f361c50
AR
1107 // same for eCAP
1108
1109 // must be the last adaptation-related finalize
1110 Adaptation::Config::Finalize(enableAdaptation);
b958cb0f
AR
1111#endif
1112
1113
bf8fe701 1114 debugs(1, 1, "Ready to serve requests.");
62e76326 1115
dbe4fd8e 1116 if (!configured_once) {
c8f4eac4 1117 eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
62e76326 1118
1119 if (Config.onoff.announce)
1120 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
1121
1122 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
1123
1124 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
1125
88bfe092 1126#if USE_XPROF_STATS
62e76326 1127
1128 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
1129
88bfe092 1130#endif
62e76326 1131
1132 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
f900210a 1133
1134 eventAdd("commCheckHalfClosed", commCheckHalfClosed, NULL, 1.0, false);
4d7add01 1135 }
62e76326 1136
dbe4fd8e 1137 configured_once = 1;
4d64d74a 1138}
1139
6c1962dd 1140#if USE_WIN32_SERVICE
1141/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1142extern "C" void WINAPI
a0aa9e74 1143 SquidWinSvcMain(int argc, char **argv)
1144{
1145 SquidMain(argc, argv);
1146}
1147
1148int
1149SquidMain(int argc, char **argv)
6c1962dd 1150#else
b8d8561b 1151int
1152main(int argc, char **argv)
9b7292ce 1153#endif
1154{
a0aa9e74 1155#ifdef _SQUID_WIN32_
1156
1157 int WIN32_init_err;
1158#endif
4d64d74a 1159
a4ba1105 1160#if HAVE_SBRK
62e76326 1161
9b7292ce 1162 sbrk_start = sbrk(0);
a4ba1105 1163#endif
1164
fb6a61d1 1165 Debug::parseOptions(NULL);
9b7292ce 1166 debug_log = stderr;
62e76326 1167
b9269882 1168#if defined(SQUID_MAXFD_LIMIT)
1169
1170 if (SQUID_MAXFD_LIMIT < Squid_MaxFD)
1171 Squid_MaxFD = SQUID_MAXFD_LIMIT;
1172
1173#endif
399e85ea 1174
ec4daaa5 1175#ifdef _SQUID_WIN32_
6c1962dd 1176
a0aa9e74 1177 if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
1178 return WIN32_init_err;
62e76326 1179
0e6d05ef 1180#endif
1181
9b7292ce 1182 /* call mallopt() before anything else */
0b29fe44 1183#if HAVE_MALLOPT
7328e889 1184#ifdef M_GRAIN
9b7292ce 1185 /* Round up all sizes to a multiple of this */
1186 mallopt(M_GRAIN, 16);
62e76326 1187
7328e889 1188#endif
1189#ifdef M_MXFAST
9b7292ce 1190 /* biggest size that is considered a small block */
1191 mallopt(M_MXFAST, 256);
62e76326 1192
7328e889 1193#endif
1194#ifdef M_NBLKS
9b7292ce 1195 /* allocate this many small blocks at once */
1196 mallopt(M_NLBLKS, 32);
62e76326 1197
7328e889 1198#endif
1199#endif /* HAVE_MALLOPT */
1200
9b7292ce 1201 squid_srandom(time(NULL));
4d64d74a 1202
9b7292ce 1203 getCurrentTime();
62e76326 1204
9b7292ce 1205 squid_start = current_time;
62e76326 1206
9b7292ce 1207 failure_notify = fatal_dump;
4d64d74a 1208
6c1962dd 1209#if USE_WIN32_SERVICE
1210
9b7292ce 1211 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1212
1213#endif
1214
9b7292ce 1215 mainParseOptions(argc, argv);
4d64d74a 1216
9aae6be3 1217 if (opt_parse_cfg_only) {
1218 Debug::parseOptions("ALL,1");
1219 }
1220
6c1962dd 1221#if USE_WIN32_SERVICE
1222
a0aa9e74 1223 if (opt_install_service)
1224 {
9b7292ce 1225 WIN32_InstallService();
a0aa9e74 1226 return 0;
9b7292ce 1227 }
6c1962dd 1228
a0aa9e74 1229 if (opt_remove_service)
1230 {
9b7292ce 1231 WIN32_RemoveService();
a0aa9e74 1232 return 0;
9b7292ce 1233 }
6c1962dd 1234
a0aa9e74 1235 if (opt_command_line)
1236 {
9b7292ce 1237 WIN32_SetServiceCommandLine();
a0aa9e74 1238 return 0;
9b7292ce 1239 }
6c1962dd 1240
1241#endif
1242
9b7292ce 1243 /* parse configuration file
1244 * note: in "normal" case this used to be called from mainInitialize() */
1245 {
1246 int parse_err;
62e76326 1247
9b7292ce 1248 if (!ConfigFile)
1249 ConfigFile = xstrdup(DefaultConfigFile);
62e76326 1250
9b7292ce 1251 assert(!configured_once);
62e76326 1252
9b7292ce 1253 Mem::Init();
62e76326 1254
9b7292ce 1255 storeFsInit(); /* required for config parsing */
62e76326 1256
b9ae18aa 1257 /* May not be needed for parsing, have not audited for such */
1258 DiskIOModule::SetupAllModules();
1259
59b2d47f 1260 /* Shouldn't be needed for config parsing, but have not audited for such */
1261 StoreFileSystem::SetupAllFs();
1262
c8f4eac4 1263 /* we may want the parsing process to set this up in the future */
1264 Store::Root(new StoreController);
1265
dd9b1081 1266 parse_err = parseConfigFile(ConfigFile);
62e76326 1267
97244680 1268 Mem::Report();
1269
9b7292ce 1270 if (opt_parse_cfg_only)
6c1962dd 1271
9b7292ce 1272 return parse_err;
9b7292ce 1273 }
c642c141 1274 setUmask(Config.umask);
9b7292ce 1275 if (-1 == opt_send_signal)
1276 if (checkRunningPid())
1277 exit(1);
e13ee7ad 1278
9bc73deb 1279#if TEST_ACCESS
62e76326 1280
95564b0d 1281 comm_init();
62e76326 1282
9b7292ce 1283 comm_select_init();
62e76326 1284
9b7292ce 1285 mainInitialize();
62e76326 1286
9b7292ce 1287 test_access();
62e76326 1288
9b7292ce 1289 return 0;
62e76326 1290
9bc73deb 1291#endif
1292
9b7292ce 1293 /* send signal to running copy and exit */
a0aa9e74 1294 if (opt_send_signal != -1)
1295 {
9b7292ce 1296 /* chroot if configured to run inside chroot */
62e76326 1297
a572d8be 1298 if (Config.chroot_dir) {
1299 if (chroot(Config.chroot_dir))
1300 fatal("failed to chroot");
1301
1302 no_suid();
1303 } else {
1304 leave_suid();
9b7292ce 1305 }
62e76326 1306
9b7292ce 1307 sendSignal();
1308 /* NOTREACHED */
1309 }
62e76326 1310
a0aa9e74 1311 if (opt_create_swap_dirs)
1312 {
9b7292ce 1313 /* chroot if configured to run inside chroot */
0e657244 1314
9b7292ce 1315 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
1316 fatal("failed to chroot");
1317 }
62e76326 1318
9b7292ce 1319 setEffectiveUser();
bf8fe701 1320 debugs(0, 0, "Creating Swap Directories");
c8f4eac4 1321 Store::Root().create();
6c1962dd 1322
9b7292ce 1323 return 0;
9b7292ce 1324 }
62e76326 1325
9b7292ce 1326 if (!opt_no_daemon)
1327 watch_child(argv);
62e76326 1328
95564b0d 1329 setMaxFD();
1330
1331 /* init comm module */
1332 comm_init();
62e76326 1333
9b7292ce 1334 comm_select_init();
4d64d74a 1335
a0aa9e74 1336 if (opt_no_daemon)
1337 {
9b7292ce 1338 /* we have to init fdstat here. */
1339 fd_open(0, FD_LOG, "stdin");
1340 fd_open(1, FD_LOG, "stdout");
1341 fd_open(2, FD_LOG, "stderr");
1342 }
62e76326 1343
6c1962dd 1344#if USE_WIN32_SERVICE
1345
9b7292ce 1346 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1347
1348#endif
1349
9b7292ce 1350 mainInitialize();
4d64d74a 1351
6c1962dd 1352#if USE_WIN32_SERVICE
1353
9b7292ce 1354 WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
6c1962dd 1355
1356#endif
1357
9b7292ce 1358 /* main loop */
a553a5a3 1359 EventLoop mainLoop;
62e76326 1360
9688b0ae 1361 SignalEngine signalEngine(mainLoop);
6c1962dd 1362
9688b0ae 1363 mainLoop.registerEngine(&signalEngine);
62e76326 1364
8ff3fa2e 1365 /* TODO: stop requiring the singleton here */
1366 mainLoop.registerEngine(EventScheduler::GetInstance());
62e76326 1367
8ff3fa2e 1368 StoreRootEngine store_engine;
615f9581 1369
8ff3fa2e 1370 mainLoop.registerEngine(&store_engine);
a774fd3f 1371
8ff3fa2e 1372 CommSelectEngine comm_engine;
1373
8ff3fa2e 1374 mainLoop.registerEngine(&comm_engine);
1375
bef81ea5 1376 mainLoop.setPrimaryEngine(&comm_engine);
1377
8ff3fa2e 1378 /* use the standard time service */
1379 TimeEngine time_engine;
1380
1381 mainLoop.setTimeService(&time_engine);
1382
1383 mainLoop.run();
1384
1385 if (mainLoop.errcount == 10)
1386 fatal_dump("Event loop exited with failure.");
1387
1388 /* shutdown squid now */
1389 SquidShutdown();
62e76326 1390
9b7292ce 1391 /* NOTREACHED */
9b7292ce 1392 return 0;
090089c4 1393}
7690e8eb 1394
b8d8561b 1395static void
0673c0ba 1396sendSignal(void)
7690e8eb 1397{
ff8d0ea6 1398 pid_t pid;
fedac7e5 1399 debug_log = stderr;
258ac4d7 1400
1401 if (strcmp(Config.pidFilename, "none") == 0) {
bf8fe701 1402 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
258ac4d7 1403 }
1404
fedac7e5 1405 pid = readPidFile();
62e76326 1406
fedac7e5 1407 if (pid > 1) {
6c1962dd 1408#if USE_WIN32_SERVICE
1409
1410 if (opt_signal_service) {
1411 WIN32_sendSignal(opt_send_signal);
1412 exit(0);
1413 } else
1414#ifdef _SQUID_MSWIN_
1415 {
7dbca7a4 1416 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
6c1962dd 1417 fprintf(stderr, "signal to Squid Service:\n");
1418 fprintf(stderr, "missing -n command line switch.\n");
1419 exit(1);
1420 }
1421
1422 /* NOTREACHED */
1423#endif
1424
1425#endif
1426
62e76326 1427 if (kill(pid, opt_send_signal) &&
1428 /* ignore permissions if just running check */
1429 !(opt_send_signal == 0 && errno == EPERM)) {
7dbca7a4 1430 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
62e76326 1431 fprintf(stderr, "signal %d to process %d: %s\n",
1432 opt_send_signal, (int) pid, xstrerror());
1433 exit(1);
1434 }
fedac7e5 1435 } else {
7dbca7a4 1436 fprintf(stderr, "%s: ERROR: No running copy\n", APP_SHORTNAME);
62e76326 1437 exit(1);
7690e8eb 1438 }
62e76326 1439
fedac7e5 1440 /* signal successfully sent */
1441 exit(0);
1442}
f95b8144 1443
a50bfe93 1444#ifndef _SQUID_MSWIN_
e18d7fdc 1445/*
1446 * This function is run when Squid is in daemon mode, just
1447 * before the parent forks and starts up the child process.
1448 * It can be used for admin-specific tasks, such as notifying
1449 * someone that Squid is (re)started.
1450 */
1451static void
1452mainStartScript(const char *prog)
1453{
1454 char script[SQUID_MAXPATHLEN];
1455 char *t;
1456 size_t sl = 0;
1457 pid_t cpid;
1458 pid_t rpid;
1459 xstrncpy(script, prog, MAXPATHLEN);
62e76326 1460
e18d7fdc 1461 if ((t = strrchr(script, '/'))) {
62e76326 1462 *(++t) = '\0';
1463 sl = strlen(script);
e18d7fdc 1464 }
62e76326 1465
e18d7fdc 1466 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
62e76326 1467
e18d7fdc 1468 if ((cpid = fork()) == 0) {
62e76326 1469 /* child */
f75662c9 1470 execl(script, squid_start_script, (char *)NULL);
482aa790 1471 _exit(-1);
e18d7fdc 1472 } else {
62e76326 1473 do {
e18d7fdc 1474#ifdef _SQUID_NEXT_
62e76326 1475 union wait status;
1476 rpid = wait3(&status, 0, NULL);
e18d7fdc 1477#else
62e76326 1478
1479 int status;
1480 rpid = waitpid(-1, &status, 0);
e18d7fdc 1481#endif
62e76326 1482
1483 } while (rpid != cpid);
e18d7fdc 1484 }
1485}
1486
a50bfe93 1487#endif /* _SQUID_MSWIN_ */
1488
efd900cb 1489static int
1490checkRunningPid(void)
1491{
1492 pid_t pid;
e0077312 1493
1494 if (!debug_log)
1495 debug_log = stderr;
1496
efd900cb 1497 pid = readPidFile();
62e76326 1498
efd900cb 1499 if (pid < 2)
62e76326 1500 return 0;
1501
efd900cb 1502 if (kill(pid, 0) < 0)
62e76326 1503 return 0;
1504
cb7a4fcb 1505 debugs(0, 0, "Squid is already running! Process ID " << pid);
62e76326 1506
efd900cb 1507 return 1;
1508}
1509
f95b8144 1510static void
bbe199dc 1511watch_child(char *argv[])
f95b8144 1512{
a50bfe93 1513#ifndef _SQUID_MSWIN_
f95b8144 1514 char *prog;
f95b8144 1515 int failcount = 0;
1516 time_t start;
1517 time_t stop;
1518#ifdef _SQUID_NEXT_
62e76326 1519
f95b8144 1520 union wait status;
1521#else
62e76326 1522
f95b8144 1523 int status;
1524#endif
62e76326 1525
e3a3b845 1526 pid_t pid;
c99c5397 1527#ifdef TIOCNOTTY
1528
54f742e7 1529 int i;
c99c5397 1530#endif
1531
742724a4 1532 int nullfd;
62e76326 1533
f95b8144 1534 if (*(argv[0]) == '(')
62e76326 1535 return;
1536
7dbca7a4 1537 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1538
54f742e7 1539 if ((pid = fork()) < 0)
62e76326 1540 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
54f742e7 1541 else if (pid > 0)
62e76326 1542 exit(0);
1543
54f742e7 1544 if (setsid() < 0)
62e76326 1545 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
1546
efd900cb 1547 closelog();
62e76326 1548
54f742e7 1549#ifdef TIOCNOTTY
62e76326 1550
c4aefe96 1551 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
62e76326 1552 ioctl(i, TIOCNOTTY, NULL);
1553 close(i);
54f742e7 1554 }
62e76326 1555
54f742e7 1556#endif
b05490a8 1557
7f6ffd15 1558 /*
1559 * RBCOLLINS - if cygwin stackdumps when squid is run without
1560 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1561 * 1.1.3. execvp had a bit overflow error in a loop..
1562 */
742724a4 1563 /* Connect stdio to /dev/null in daemon mode */
4da086c4 1564 nullfd = open(_PATH_DEVNULL, O_RDWR | O_TEXT);
62e76326 1565
e4a1325e 1566 if (nullfd < 0)
4da086c4 1567 fatalf(_PATH_DEVNULL " %s\n", xstrerror());
e4a1325e 1568
742724a4 1569 dup2(nullfd, 0);
62e76326 1570
742724a4 1571 if (opt_debug_stderr < 0) {
62e76326 1572 dup2(nullfd, 1);
1573 dup2(nullfd, 2);
742724a4 1574 }
62e76326 1575
f95b8144 1576 for (;;) {
62e76326 1577 mainStartScript(argv[0]);
1578
1579 if ((pid = fork()) == 0) {
1580 /* child */
7dbca7a4 1581 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1582 prog = xstrdup(argv[0]);
1583 argv[0] = xstrdup("(squid)");
1584 execvp(prog, argv);
1585 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
1586 }
1587
1588 /* parent */
7dbca7a4 1589 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1590
1591 syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
1592
1593 time(&start);
1594
1595 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
1596
f95b8144 1597#ifdef _SQUID_NEXT_
62e76326 1598
1599 pid = wait3(&status, 0, NULL);
1600
f95b8144 1601#else
62e76326 1602
1603 pid = waitpid(-1, &status, 0);
1604
1605#endif
1606
1607 time(&stop);
1608
1609 if (WIFEXITED(status)) {
1610 syslog(LOG_NOTICE,
1611 "Squid Parent: child process %d exited with status %d",
1612 pid, WEXITSTATUS(status));
1613 } else if (WIFSIGNALED(status)) {
1614 syslog(LOG_NOTICE,
cc192b50 1615 "Squid Parent: child process %d exited due to signal %d with status %d",
1616 pid, WTERMSIG(status), WEXITSTATUS(status));
62e76326 1617 } else {
1618 syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
1619 }
1620
1621 if (stop - start < 10)
1622 failcount++;
1623 else
1624 failcount = 0;
1625
1626 if (failcount == 5) {
1627 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
1628 exit(1);
1629 }
1630
1631 if (WIFEXITED(status))
1632 if (WEXITSTATUS(status) == 0)
1633 exit(0);
1634
1635 if (WIFSIGNALED(status)) {
1636 switch (WTERMSIG(status)) {
1637
1638 case SIGKILL:
1639 exit(0);
1640 break;
1641
06a0fbd3 1642 case SIGINT:
1643 case SIGTERM:
1644 syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
1645 exit(1);
1646 break;
1647
62e76326 1648 default:
1649 break;
1650 }
1651 }
1652
1653 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
1654 sleep(3);
f95b8144 1655 }
62e76326 1656
bbe199dc 1657 /* NOTREACHED */
a50bfe93 1658#endif /* _SQUID_MSWIN_ */
a572d8be 1659
f95b8144 1660}
fff6ad65 1661
9ec1a1dc 1662static void
8ff3fa2e 1663SquidShutdown()
fff6ad65 1664{
6c1962dd 1665#if USE_WIN32_SERVICE
1666 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1667#endif
1668
bf8fe701 1669 debugs(1, 1, "Shutting down...");
95a83c22 1670#if USE_DNSSERVERS
1671
1672 dnsShutdown();
1673#else
1674
1675 idnsShutdown();
1676#endif
1677
1678 redirectShutdown();
1679 externalAclShutdown();
d723bf6b 1680 icpConnectionClose();
1681#if USE_HTCP
62e76326 1682
d723bf6b 1683 htcpSocketClose();
1684#endif
1685#ifdef SQUID_SNMP
62e76326 1686
d723bf6b 1687 snmpConnectionClose();
320e9f36 1688#endif
eb824054 1689#if USE_WCCP
62e76326 1690
320e9f36 1691 wccpConnectionClose();
d723bf6b 1692#endif
0b0cfcf2 1693#if USE_WCCPv2
1694
1695 wccp2ConnectionClose();
1696#endif
62e76326 1697
fff6ad65 1698 releaseServerSockets();
d723bf6b 1699 commCloseAllSockets();
515ec4dc 1700#if DELAY_POOLS
62e76326 1701
b67e2c8c 1702 DelayPools::FreePools();
515ec4dc 1703#endif
62e76326 1704
5dae8514 1705 authenticateShutdown();
6c1962dd 1706#if USE_WIN32_SERVICE
1707
1708 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1709#endif
62e76326 1710
c8f4eac4 1711 Store::Root().sync(); /* Flush pending object writes/unlinks */
4d075ba0 1712#if USE_UNLINKD
1713
1714 unlinkdClose(); /* after sync/flush */
1715#endif
fc68f6b1 1716
fff6ad65 1717 storeDirWriteCleanLogs(0);
1718 PrintRusage();
1719 dumpMallocStats();
c8f4eac4 1720 Store::Root().sync(); /* Flush log writes */
fff6ad65 1721 storeLogClose();
1722 accessLogClose();
5b824235 1723 useragentLogClose();
c9b99797 1724 refererCloseLog();
225644d7 1725#if WIP_FWD_LOG
62e76326 1726
225644d7 1727 fwdUninit();
1728#endif
62e76326 1729
c8f4eac4 1730 Store::Root().sync(); /* Flush log close */
59b2d47f 1731 StoreFileSystem::FreeAllFs();
b9ae18aa 1732 DiskIOModule::FreeAllModules();
afec404b 1733#if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
62e76326 1734
fff6ad65 1735 configFreeMemory();
1736 storeFreeMemory();
33ab18e8 1737 /*stmemFreeMemory(); */
fff6ad65 1738 netdbFreeMemory();
1739 ipcacheFreeMemory();
1740 fqdncacheFreeMemory();
1741 asnFreeMemory();
26a369ba 1742 clientdbFreeMemory();
7021844c 1743 httpHeaderCleanModule();
d2db411c 1744 statFreeMemory();
f1fc2a8d 1745 eventFreeMemory();
c68e9c6b 1746 mimeFreeMemory();
1747 errorClean();
fff6ad65 1748#endif
26a369ba 1749#if !XMALLOC_TRACE
62e76326 1750
54f742e7 1751 if (opt_no_daemon) {
62e76326 1752 file_close(0);
1753 file_close(1);
1754 file_close(2);
54f742e7 1755 }
62e76326 1756
33ab18e8 1757#endif
fff6ad65 1758 fdDumpOpen();
62e76326 1759
236d1779 1760 comm_exit();
62e76326 1761
ddb43c58 1762 memClean();
62e76326 1763
33ab18e8 1764#if XMALLOC_TRACE
62e76326 1765
26a369ba 1766 xmalloc_find_leaks();
62e76326 1767
bf8fe701 1768 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total);
62e76326 1769
33ab18e8 1770#endif
36a97e19 1771#if MEM_GEN_TRACE
62e76326 1772
399e85ea 1773 log_trace_done();
62e76326 1774
36a97e19 1775#endif
62e76326 1776
ab50ee9e 1777 if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
62e76326 1778 enter_suid();
1779 safeunlink(Config.pidFilename, 0);
1780 leave_suid();
ab50ee9e 1781 }
62e76326 1782
bf8fe701 1783 debugs(1, 1, "Squid Cache (Version " << version_string << "): Exiting normally.");
62e76326 1784
0cfa98cb 1785 /*
1786 * DPW 2006-10-23
1787 * We used to fclose(debug_log) here if it was set, but then
1788 * we forgot to set it to NULL. That caused some coredumps
1789 * because exit() ends up calling a bunch of destructors and
1790 * such. So rather than forcing the debug_log to close, we'll
1791 * leave it open so that those destructors can write some
1792 * debugging if necessary. The file will be closed anyway when
1793 * the process truly exits.
1794 */
62e76326 1795
ae1feb30 1796 exit(shutdown_status);
fff6ad65 1797}
bef81ea5 1798