]> git.ipfire.org Git - thirdparty/squid.git/blame - src/main.cc
Renamed ICAP source files from icap/ICAPFoo.{cc,h} to icap/Foo.{cc,h}.
[thirdparty/squid.git] / src / main.cc
CommitLineData
30a4f2a8 1/*
262a0e14 2 * $Id$
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.
26ac0430 23 *
30a4f2a8 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.
26ac0430 28 *
30a4f2a8 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 "ConfigParser.h"
aa839030 39#include "errorpage.h"
a553a5a3 40#include "event.h"
41#include "EventLoop.h"
62ee09ca 42#include "ExternalACL.h"
e6ccf245 43#include "Store.h"
44#include "ICP.h"
5a7431b8 45#include "ident.h"
528b2c61 46#include "HttpReply.h"
62ee09ca 47#include "pconn.h"
528b2c61 48#include "Mem.h"
b0dd28ba 49#include "ACLASN.h"
50#include "ACL.h"
75faaa7a 51#include "htcp.h"
59b2d47f 52#include "StoreFileSystem.h"
b9ae18aa 53#include "DiskIO/DiskIOModule.h"
f900210a 54#include "comm.h"
62ee09ca 55#if USE_EPOLL
56#include "comm_epoll.h"
57#endif
58#if USE_KQUEUE
59#include "comm_kqueue.h"
60#endif
61#if USE_POLL
62#include "comm_poll.h"
63#endif
7cdb47bc 64#if defined(USE_SELECT) || defined(USE_SELECT_WIN32)
663c0a38 65#include "comm_select.h"
66#endif
985c86bc 67#include "SquidTime.h"
c8f4eac4 68#include "SwapDir.h"
b6b6f466 69#include "forward.h"
d9e7ee1f 70#include "MemPool.h"
9b5c4a9a
AJ
71#include "icmp/IcmpSquid.h"
72#include "icmp/net_db.h"
6e5db507 73#include "TextException.h"
44a47c6e 74
57afc994
AR
75#if USE_LOADABLE_MODULES
76#include "LoadableModules.h"
77#endif
78
b958cb0f 79#if ICAP_CLIENT
26cc52cb 80#include "adaptation/icap/Config.h"
b958cb0f 81#endif
6e5db507 82#if USE_ECAP
1f3c65fc 83#include "adaptation/ecap/Config.h"
6e5db507 84#endif
b958cb0f
AR
85#if USE_ADAPTATION
86#include "adaptation/Config.h"
87#endif
88
1a774556 89#if USE_WIN32_SERVICE
90
91#include "squid_windows.h"
92#include <process.h>
93
94static int opt_install_service = FALSE;
95static int opt_remove_service = FALSE;
96static int opt_signal_service = FALSE;
97static int opt_command_line = FALSE;
98extern void WIN32_svcstatusupdate(DWORD, DWORD);
99void WINAPI WIN32_svcHandler(DWORD);
100
101#endif
102
63be0a78 103/** for error reporting from xmalloc and friends */
b293c4d8 104SQUIDCEXTERN void (*failure_notify) (const char *);
30a4f2a8 105
e13ee7ad 106static int opt_parse_cfg_only = 0;
5e6d4736 107static char *opt_syslog_facility = NULL;
30a4f2a8 108static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
e13ee7ad 109static int configured_once = 0;
30a4f2a8 110#if MALLOC_DBG
4d64d74a 111static int malloc_debug_level = 0;
30a4f2a8 112#endif
5cd39a10 113static volatile int do_reconfigure = 0;
114static volatile int do_rotate = 0;
2681d383 115static volatile int do_shutdown = 0;
ae1feb30 116static volatile int shutdown_status = 0;
4d7add01 117
5cd39a10 118static void mainRotate(void);
d71e4674
AR
119static void mainReconfigureStart(void);
120static void mainReconfigureFinish(void*);
f5b8bbc4 121static void mainInitialize(void);
f5b8bbc4 122static void usage(void);
63be0a78 123static void mainParseOptions(int argc, char *argv[]);
f5b8bbc4 124static void sendSignal(void);
125static void serverConnectionsOpen(void);
d71e4674 126static void serverConnectionsClose(void);
bbe199dc 127static void watch_child(char **);
85407535 128static void setEffectiveUser(void);
36a97e19 129#if MEM_GEN_TRACE
130extern void log_trace_done();
131extern void log_trace_init(char *);
132#endif
8ff3fa2e 133static void SquidShutdown(void);
b6a2f15e 134static void mainSetCwd(void);
efd900cb 135static int checkRunningPid(void);
85407535 136
b293c4d8 137#ifndef _SQUID_MSWIN_
e18d7fdc 138static const char *squid_start_script = "squid_start";
b293c4d8 139#endif
e18d7fdc 140
9bc73deb 141#if TEST_ACCESS
142#include "test_access.c"
143#endif
144
63be0a78 145/** temporary thunk across to the unrefactored store interface */
8ff3fa2e 146
147class StoreRootEngine : public AsyncEngine
148{
149
150public:
26ac0430 151 int checkEvents(int timeout) {
8ff3fa2e 152 Store::Root().callback();
153 return EVENT_IDLE;
154 };
155};
156
9688b0ae 157class SignalEngine: public AsyncEngine
a553a5a3 158{
159
160public:
9688b0ae 161 SignalEngine(EventLoop &loop) : loop(loop) {}
162 virtual int checkEvents(int timeout);
a553a5a3 163
164private:
26ac0430 165 static void StopEventLoop(void * data) {
9688b0ae 166 static_cast<SignalEngine *>(data)->loop.stop();
a553a5a3 167 }
168
9688b0ae 169 void doShutdown(time_t wait);
170
a553a5a3 171 EventLoop &loop;
172};
173
9688b0ae 174int
175SignalEngine::checkEvents(int timeout)
a553a5a3 176{
9688b0ae 177 PROF_start(SignalEngine_checkEvents);
fc68f6b1 178
a553a5a3 179 if (do_reconfigure) {
d71e4674 180 mainReconfigureStart();
a553a5a3 181 do_reconfigure = 0;
a553a5a3 182 } else if (do_rotate) {
183 mainRotate();
184 do_rotate = 0;
185 } else if (do_shutdown) {
9688b0ae 186 doShutdown(do_shutdown > 0 ? (int) Config.shutdownLifetime : 0);
a553a5a3 187 do_shutdown = 0;
26ac0430 188 }
a553a5a3 189
9688b0ae 190 PROF_stop(SignalEngine_checkEvents);
191 return EVENT_IDLE;
192}
a553a5a3 193
9688b0ae 194void
195SignalEngine::doShutdown(time_t wait)
196{
197 debugs(1, 1, "Preparing for shutdown after " << statCounter.client_http.requests << " requests");
198 debugs(1, 1, "Waiting " << wait << " seconds for active connections to finish");
8ff3fa2e 199
9688b0ae 200 shutting_down = 1;
201
202#if USE_WIN32_SERVICE
203 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
204#endif
205
206 serverConnectionsClose();
207 eventAdd("SquidShutdown", &StopEventLoop, this, (double) (wait + 1), 1, false);
a553a5a3 208}
209
b8d8561b 210static void
0673c0ba 211usage(void)
ccff9601 212{
0ee4272b 213 fprintf(stderr,
0e657244 214#if USE_WIN32_SERVICE
8eb28163 215 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
0e657244 216#else
8eb28163 217 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
0e657244 218#endif
62e76326 219 " -a port Specify HTTP port number (default: %d).\n"
220 " -d level Write debugging to stderr also.\n"
221 " -f file Use given config-file instead of\n"
222 " %s\n"
223 " -h Print help message.\n"
0e657244 224#if USE_WIN32_SERVICE
225 " -i Installs as a Windows Service (see -n option).\n"
226#endif
62e76326 227 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
228 " Parse configuration file, then send signal to \n"
229 " running copy (except -k parse) and exit.\n"
0e657244 230#if USE_WIN32_SERVICE
231 " -n name Specify Windows Service name to use for service operations\n"
232 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
233 " -r Removes a Windows Service (see -n option).\n"
234#endif
5e6d4736 235 " -s | -l facility\n"
236 " Enable logging to syslog.\n"
62e76326 237 " -u port Specify ICP port number (default: %d), disable with 0.\n"
238 " -v Print version.\n"
239 " -z Create swap directories\n"
240 " -C Do not catch fatal signals.\n"
8eb28163 241 " -D OBSOLETE. Scheduled for removal.\n"
62e76326 242 " -F Don't serve any requests until store is rebuilt.\n"
243 " -N No daemon mode.\n"
0e657244 244#if USE_WIN32_SERVICE
245 " -O options\n"
246 " Set Windows Service Command line options in Registry.\n"
247#endif
62e76326 248 " -R Do not set REUSEADDR on port.\n"
249 " -S Double-check swap during rebuild.\n"
62e76326 250 " -X Force full debugging.\n"
251 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
7dbca7a4 252 APP_SHORTNAME, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
77ffc99f 253 exit(1);
ccff9601 254}
255
63be0a78 256/**
257 * Parse the parameters received via command line interface.
258 *
259 \param argc[in] Number of options received on command line
260 \param argv[in] List of parameters received on command line
261 */
b8d8561b 262static void
263mainParseOptions(int argc, char *argv[])
090089c4 264{
090089c4 265 extern char *optarg;
4d64d74a 266 int c;
090089c4 267
0e657244 268#if USE_WIN32_SERVICE
5e6d4736 269 while ((c = getopt(argc, argv, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
0e657244 270#else
05f1c52c 271 while ((c = getopt(argc, argv, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
0e657244 272#endif
9b7292ce 273 {
274
26ac0430 275 switch (c) {
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
8eb28163
AJ
285 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
286 debugs(1,DBG_CRITICAL, "WARNING: -D command-line option is obsolete.");
62e76326 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();
62e76326 629
afd88fbe 630 carpInit();
f7e1d9ce
HN
631 peerUserHashInit();
632 peerSourceHashInit();
5f3f8d0e 633}
634
d71e4674 635static void
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
d71e4674 664mainReconfigureStart(void)
9b7292ce 665{
bf8fe701 666 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string << ")...");
5cd39a10 667 reconfiguring = 1;
d71e4674
AR
668
669 // Initiate asynchronous closing sequence
15df8349 670 serverConnectionsClose();
17e6c0a1 671 icpConnectionClose();
72549e05 672#if USE_HTCP
62e76326 673
72549e05 674 htcpSocketClose();
675#endif
17e6c0a1 676#ifdef SQUID_SNMP
62e76326 677
17e6c0a1 678 snmpConnectionClose();
320e9f36 679#endif
3c573763 680#if USE_DNSSERVERS
62e76326 681
74addf6c 682 dnsShutdown();
3c573763 683#else
62e76326 684
7b724b86 685 idnsShutdown();
eb824054 686#endif
62e76326 687
74addf6c 688 redirectShutdown();
689 authenticateShutdown();
d9572179 690 externalAclShutdown();
2db68ce5 691 storeDirCloseSwapLogs();
2e923080 692 storeLogClose();
693 accessLogClose();
694 useragentLogClose();
695 refererCloseLog();
d71e4674
AR
696
697 eventAdd("mainReconfigureFinish", &mainReconfigureFinish, NULL, 0, 1,
26ac0430 698 false);
d71e4674
AR
699}
700
701static void
26ac0430
AJ
702mainReconfigureFinish(void *)
703{
d71e4674
AR
704 debugs(1, 3, "finishing reconfiguring");
705
c68e9c6b 706 errorClean();
3aa4adbc 707 enter_suid(); /* root to read config file */
dd9b1081 708 parseConfigFile(ConfigFile);
c642c141 709 setUmask(Config.umask);
97244680 710 Mem::Report();
3aa4adbc 711 setEffectiveUser();
b6f794d6 712 _db_init(Config.Log.log, Config.debugOptions);
429fdbec 713 ipcache_restart(); /* clear stuck entries */
94439e4e 714 authenticateUserCacheRestart(); /* clear stuck ACL entries */
429fdbec 715 fqdncache_restart(); /* sigh, fqdncache too */
0e70aa1e 716 parseEtcHosts();
53ad48e6 717 errorInitialize(); /* reload error pages */
2e923080 718 accessLogInit();
719 storeLogOpen();
720 useragentOpenLog();
721 refererOpenLog();
3c573763 722#if USE_DNSSERVERS
62e76326 723
74addf6c 724 dnsInit();
3c573763 725#else
62e76326 726
7b724b86 727 idnsInit();
eb824054 728#endif
62e76326 729
74addf6c 730 redirectInit();
e6ccf245 731 authenticateInit(&Config.authConfiguration);
d9572179 732 externalAclInit();
1f38f50a 733#if USE_WCCP
62e76326 734
1f38f50a 735 wccpInit();
736#endif
0b0cfcf2 737#if USE_WCCPv2
738
739 wccp2Init();
740#endif
62e76326 741
0ffd22bc 742 serverConnectionsOpen();
9c2e9b50 743
3ee2b4f8 744 neighbors_init();
9c2e9b50 745
2db68ce5 746 storeDirOpenSwapLogs();
9c2e9b50 747
9c021a38 748 mimeInit(Config.mimeTablePathname);
9c2e9b50 749
926375e6 750 if (Config.onoff.announce) {
751 if (!eventFind(start_announce, NULL))
752 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
753 } else {
754 if (eventFind(start_announce, NULL))
755 eventDelete(start_announce, NULL);
756 }
757
b8890359 758 writePidFile(); /* write PID file */
9c2e9b50 759
bf8fe701 760 debugs(1, 1, "Ready to serve requests.");
9c2e9b50 761
5cd39a10 762 reconfiguring = 0;
763}
764
765static void
9b7292ce 766mainRotate(void)
767{
cc192b50 768 icmpEngine.Close();
3c573763 769#if USE_DNSSERVERS
62e76326 770
e40aa8da 771 dnsShutdown();
3c573763 772#endif
62e76326 773
e40aa8da 774 redirectShutdown();
775 authenticateShutdown();
d9572179 776 externalAclShutdown();
5cd39a10 777 _db_rotate_log(); /* cache.log */
778 storeDirWriteCleanLogs(1);
779 storeLogRotate(); /* store.log */
780 accessLogRotate(); /* access.log */
781 useragentRotateLog(); /* useragent.log */
fd2c5549 782 refererRotateLog(); /* referer.log */
225644d7 783#if WIP_FWD_LOG
62e76326 784
225644d7 785 fwdLogRotate();
786#endif
62e76326 787
cc192b50 788 icmpEngine.Open();
3c573763 789#if USE_DNSSERVERS
62e76326 790
e40aa8da 791 dnsInit();
3c573763 792#endif
62e76326 793
e40aa8da 794 redirectInit();
e6ccf245 795 authenticateInit(&Config.authConfiguration);
d9572179 796 externalAclInit();
5f3f8d0e 797}
798
067bea91 799static void
9b7292ce 800setEffectiveUser(void)
801{
fc68f6b1 802 keepCapabilities();
85407535 803 leave_suid(); /* Run as non privilegied user */
cd377065 804#ifdef _SQUID_OS2_
62e76326 805
cd377065 806 return;
807#endif
62e76326 808
85407535 809 if (geteuid() == 0) {
bf8fe701 810 debugs(0, 0, "Squid is not safe to run as root! If you must");
811 debugs(0, 0, "start Squid as root, then you must configure");
812 debugs(0, 0, "it to run as a non-priveledged user with the");
813 debugs(0, 0, "'cache_effective_user' option in the config file.");
62e76326 814 fatal("Don't run Squid as root, set 'cache_effective_user'!");
85407535 815 }
816}
817
b6a2f15e 818static void
9b7292ce 819mainSetCwd(void)
820{
4a504376 821 char pathbuf[MAXPATHLEN];
62e76326 822
b6a2f15e 823 if (Config.coredump_dir) {
62e76326 824 if (0 == strcmp("none", Config.coredump_dir)) {
825 (void) 0;
826 } else if (chdir(Config.coredump_dir) == 0) {
bf8fe701 827 debugs(0, 1, "Set Current Directory to " << Config.coredump_dir);
62e76326 828 return;
829 } else {
bf8fe701 830 debugs(50, 0, "chdir: " << Config.coredump_dir << ": " << xstrerror());
62e76326 831 }
b6a2f15e 832 }
62e76326 833
02e8115e 834 /* If we don't have coredump_dir or couldn't cd there, report current dir */
4a504376 835 if (getcwd(pathbuf, MAXPATHLEN)) {
bf8fe701 836 debugs(0, 1, "Current Directory is " << pathbuf);
4a504376 837 } else {
bf8fe701 838 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
4a504376 839 }
b6a2f15e 840}
841
b67e2c8c 842#if DELAY_POOLS
843#include "DelayPools.h"
844#endif
845
b8d8561b 846static void
9b7292ce 847mainInitialize(void)
848{
efd900cb 849 /* chroot if configured to run inside chroot */
62e76326 850
64b0a10d 851 if (Config.chroot_dir && (chroot(Config.chroot_dir) != 0 || chdir("/") != 0)) {
62e76326 852 fatal("failed to chroot");
efd900cb 853 }
62e76326 854
1758c627 855 if (opt_catch_signals) {
62e76326 856 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
857 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
44f99671 858 }
62e76326 859
30a4f2a8 860 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
861 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
44f99671 862
85407535 863 setEffectiveUser();
62e76326 864
30a4f2a8 865 if (icpPortNumOverride != 1)
62e76326 866 Config.Port.icp = (u_short) icpPortNumOverride;
30a4f2a8 867
b6f794d6 868 _db_init(Config.Log.log, Config.debugOptions);
62e76326 869
5c5783a2 870 fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
62e76326 871
71a17702 872#if MEM_GEN_TRACE
62e76326 873
71a17702 874 log_trace_init("/tmp/squid.alloc");
62e76326 875
71a17702 876#endif
62e76326 877
bf8fe701 878 debugs(1, 0, "Starting Squid Cache version " << version_string << " for " << CONFIG_HOST_TYPE << "...");
62e76326 879
ec4daaa5 880#ifdef _SQUID_WIN32_
b293c4d8 881
882 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
bf8fe701 883 debugs(1, 0, "Running as " << WIN32_Service_name << " Windows System Service on " << WIN32_OS_string);
884 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line);
b293c4d8 885 } else
bf8fe701 886 debugs(1, 0, "Running on " << WIN32_OS_string);
b293c4d8 887
888#endif
889
36584579 890 debugs(1, 1, "Process ID " << getpid());
62e76326 891
bf8fe701 892 debugs(1, 1, "With " << Squid_MaxFD << " file descriptors available");
5f3f8d0e 893
6c1962dd 894#ifdef _SQUID_MSWIN_
895
bf8fe701 896 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
6c1962dd 897
898 if (WIN32_Socks_initialized)
bf8fe701 899 debugs(1, 1, "Windows sockets initialized");
6c1962dd 900
babd1fd5 901 if (WIN32_OS_version > _WIN_OS_WINNT) {
26ac0430 902 WIN32_IpAddrChangeMonitorInit();
babd1fd5 903 }
904
6c1962dd 905#endif
906
9f75c559 907 if (!configured_once)
62e76326 908 disk_init(); /* disk_init must go before ipcache_init() */
909
5f3f8d0e 910 ipcache_init();
62e76326 911
f88bb09c 912 fqdncache_init();
62e76326 913
0e70aa1e 914 parseEtcHosts();
62e76326 915
3c573763 916#if USE_DNSSERVERS
62e76326 917
74addf6c 918 dnsInit();
62e76326 919
3c573763 920#else
62e76326 921
7b724b86 922 idnsInit();
62e76326 923
eb824054 924#endif
62e76326 925
74addf6c 926 redirectInit();
62e76326 927
e6ccf245 928 authenticateInit(&Config.authConfiguration);
62e76326 929
d9572179 930 externalAclInit();
62e76326 931
b012353a 932 useragentOpenLog();
62e76326 933
fd2c5549 934 refererOpenLog();
62e76326 935
2ac76861 936 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
62e76326 937
2246b732 938 httpReplyInitModule(); /* must go before accepting replies */
62e76326 939
9b312a19 940 errorInitialize();
62e76326 941
7a2f978b 942 accessLogInit();
62e76326 943
3898f57f 944#if USE_IDENT
62e76326 945
05832ae1 946 identInit();
62e76326 947
3898f57f 948#endif
5e14bf6d 949#ifdef SQUID_SNMP
62e76326 950
5e14bf6d 951 snmpInit();
62e76326 952
5e14bf6d 953#endif
30a4f2a8 954#if MALLOC_DBG
62e76326 955
5f3f8d0e 956 malloc_debug(0, malloc_debug_level);
62e76326 957
5f3f8d0e 958#endif
959
dbe4fd8e 960 if (!configured_once) {
a3d0a19d 961#if USE_UNLINKD
62e76326 962 unlinkdInit();
963#endif
964
965 urlInitialize();
62e76326 966 statInit();
967 storeInit();
968 mainSetCwd();
969 /* after this point we want to see the mallinfo() output */
970 do_mallinfo = 1;
971 mimeInit(Config.mimeTablePathname);
62e76326 972 refreshInit();
0d7e5d78 973#if DELAY_POOLS
62e76326 974
975 DelayPools::Init();
0d7e5d78 976#endif
62e76326 977
b6b6f466 978 FwdState::initModule();
62ee09ca 979 /* register the modules in the cache manager menus */
62ee09ca 980
a08f1b5a 981 cbdataRegisterWithCacheManager();
62ee09ca 982 /* These use separate calls so that the comm loops can eventually
983 * coexist.
984 */
62ee09ca 985
15b3c0d7 986 eventInit();
610ee341 987
26ac0430 988 // TODO: pconn is a good candidate for new-style registration
6852be71 989 // PconnModule::GetInstance()->registerWithCacheManager();
26ac0430 990 // moved to PconnModule::PconnModule()
5f3f8d0e 991 }
62e76326 992
1f38f50a 993#if USE_WCCP
994 wccpInit();
62e76326 995
0b0cfcf2 996#endif
997#if USE_WCCPv2
998
999 wccp2Init();
1000
1f38f50a 1001#endif
62e76326 1002
2285407f 1003 serverConnectionsOpen();
62e76326 1004
3ee2b4f8 1005 neighbors_init();
fc68f6b1 1006
5f5e883f 1007 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
62e76326 1008
efd900cb 1009 if (Config.chroot_dir)
62e76326 1010 no_suid();
1011
dbe4fd8e 1012 if (!configured_once)
62e76326 1013 writePidFile(); /* write PID file */
0a5b9b32 1014
7e7a0442 1015#ifdef _SQUID_LINUX_THREADS_
62e76326 1016
e3175d1f 1017 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
62e76326 1018
e3175d1f 1019 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
62e76326 1020
e3175d1f 1021#else
62e76326 1022
30a4f2a8 1023 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
62e76326 1024
30a4f2a8 1025 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
62e76326 1026
9fc0b4b8 1027#endif
62e76326 1028
30a4f2a8 1029 squid_signal(SIGHUP, reconfigure, SA_RESTART);
62e76326 1030
30a4f2a8 1031 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
62e76326 1032
30a4f2a8 1033 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
62e76326 1034
ae1feb30 1035#ifdef SIGTTIN
1036
1037 squid_signal(SIGTTIN, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
1038
1039#endif
1040
58a39dc9 1041 memCheckInit();
62e76326 1042
57afc994
AR
1043#if USE_LOADABLE_MODULES
1044 LoadableModulesConfigure(Config.loadable_module_names);
1045#endif
1046
8f361c50
AR
1047#if USE_ADAPTATION
1048 bool enableAdaptation = false;
1049
1050 // We can remove this dependency on specific adaptation mechanisms
1051 // if we create a generic Registry of such mechanisms. Should we?
b958cb0f 1052#if ICAP_CLIENT
26cc52cb
AR
1053 Adaptation::Icap::TheConfig.finalize();
1054 enableAdaptation = Adaptation::Icap::TheConfig.onoff || enableAdaptation;
6e5db507
AR
1055#endif
1056#if USE_ECAP
1057 Ecap::TheConfig.finalize(); // must be after we load modules
1058 enableAdaptation = Ecap::TheConfig.onoff || enableAdaptation;
b958cb0f 1059#endif
8f361c50
AR
1060 // must be the last adaptation-related finalize
1061 Adaptation::Config::Finalize(enableAdaptation);
b958cb0f
AR
1062#endif
1063
1064
bf8fe701 1065 debugs(1, 1, "Ready to serve requests.");
62e76326 1066
dbe4fd8e 1067 if (!configured_once) {
c8f4eac4 1068 eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
62e76326 1069
1070 if (Config.onoff.announce)
1071 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
1072
1073 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
1074
1075 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
1076
88bfe092 1077#if USE_XPROF_STATS
62e76326 1078
1079 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
1080
88bfe092 1081#endif
62e76326 1082
1083 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
4d7add01 1084 }
62e76326 1085
dbe4fd8e 1086 configured_once = 1;
4d64d74a 1087}
1088
c842329d 1089/// unsafe main routine -- may throw
6e5db507 1090static int SquidMain(int argc, char **argv);
c842329d 1091/// unsafe main routine wrapper to catch exceptions
6e5db507
AR
1092static int SquidMainSafe(int argc, char **argv);
1093
6c1962dd 1094#if USE_WIN32_SERVICE
1095/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1096extern "C" void WINAPI
a0aa9e74 1097 SquidWinSvcMain(int argc, char **argv)
6c1962dd 1098#else
b8d8561b 1099int
1100main(int argc, char **argv)
9b7292ce 1101#endif
6e5db507
AR
1102{
1103 SquidMainSafe(argc, argv);
1104}
1105
1106static int
1107SquidMainSafe(int argc, char **argv)
1108{
1109 try {
1110 return SquidMain(argc, argv);
26ac0430 1111 } catch (const std::exception &e) {
bba7c3d0 1112 std::cerr << "dying from an unhandled exception: " << e.what() << std::endl;
26ac0430
AJ
1113 throw;
1114 } catch (...) {
bba7c3d0 1115 std::cerr << "dying from an unhandled exception." << std::endl;
26ac0430
AJ
1116 throw;
1117 }
1118 return -1; // not reached
6e5db507
AR
1119}
1120
1121static int
1122SquidMain(int argc, char **argv)
9b7292ce 1123{
a0aa9e74 1124#ifdef _SQUID_WIN32_
1125
1126 int WIN32_init_err;
1127#endif
4d64d74a 1128
a4ba1105 1129#if HAVE_SBRK
62e76326 1130
9b7292ce 1131 sbrk_start = sbrk(0);
a4ba1105 1132#endif
1133
fb6a61d1 1134 Debug::parseOptions(NULL);
9b7292ce 1135 debug_log = stderr;
62e76326 1136
b9269882 1137#if defined(SQUID_MAXFD_LIMIT)
1138
1139 if (SQUID_MAXFD_LIMIT < Squid_MaxFD)
1140 Squid_MaxFD = SQUID_MAXFD_LIMIT;
1141
1142#endif
399e85ea 1143
ec4daaa5 1144#ifdef _SQUID_WIN32_
6c1962dd 1145
a0aa9e74 1146 if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
1147 return WIN32_init_err;
62e76326 1148
0e6d05ef 1149#endif
1150
9b7292ce 1151 /* call mallopt() before anything else */
0b29fe44 1152#if HAVE_MALLOPT
7328e889 1153#ifdef M_GRAIN
9b7292ce 1154 /* Round up all sizes to a multiple of this */
1155 mallopt(M_GRAIN, 16);
62e76326 1156
7328e889 1157#endif
1158#ifdef M_MXFAST
9b7292ce 1159 /* biggest size that is considered a small block */
1160 mallopt(M_MXFAST, 256);
62e76326 1161
7328e889 1162#endif
1163#ifdef M_NBLKS
9b7292ce 1164 /* allocate this many small blocks at once */
1165 mallopt(M_NLBLKS, 32);
62e76326 1166
7328e889 1167#endif
1168#endif /* HAVE_MALLOPT */
1169
9b7292ce 1170 squid_srandom(time(NULL));
4d64d74a 1171
9b7292ce 1172 getCurrentTime();
62e76326 1173
9b7292ce 1174 squid_start = current_time;
62e76326 1175
9b7292ce 1176 failure_notify = fatal_dump;
4d64d74a 1177
6c1962dd 1178#if USE_WIN32_SERVICE
1179
9b7292ce 1180 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1181
1182#endif
1183
9b7292ce 1184 mainParseOptions(argc, argv);
4d64d74a 1185
9aae6be3 1186 if (opt_parse_cfg_only) {
26ac0430 1187 Debug::parseOptions("ALL,1");
9aae6be3 1188 }
1189
6c1962dd 1190#if USE_WIN32_SERVICE
1191
26ac0430 1192 if (opt_install_service) {
9b7292ce 1193 WIN32_InstallService();
a0aa9e74 1194 return 0;
9b7292ce 1195 }
6c1962dd 1196
26ac0430 1197 if (opt_remove_service) {
9b7292ce 1198 WIN32_RemoveService();
a0aa9e74 1199 return 0;
9b7292ce 1200 }
6c1962dd 1201
26ac0430 1202 if (opt_command_line) {
9b7292ce 1203 WIN32_SetServiceCommandLine();
a0aa9e74 1204 return 0;
9b7292ce 1205 }
6c1962dd 1206
1207#endif
1208
9b7292ce 1209 /* parse configuration file
1210 * note: in "normal" case this used to be called from mainInitialize() */
1211 {
1212 int parse_err;
62e76326 1213
9b7292ce 1214 if (!ConfigFile)
1215 ConfigFile = xstrdup(DefaultConfigFile);
62e76326 1216
9b7292ce 1217 assert(!configured_once);
62e76326 1218
9b7292ce 1219 Mem::Init();
62e76326 1220
9b7292ce 1221 storeFsInit(); /* required for config parsing */
62e76326 1222
b9ae18aa 1223 /* May not be needed for parsing, have not audited for such */
1224 DiskIOModule::SetupAllModules();
1225
59b2d47f 1226 /* Shouldn't be needed for config parsing, but have not audited for such */
1227 StoreFileSystem::SetupAllFs();
1228
c8f4eac4 1229 /* we may want the parsing process to set this up in the future */
1230 Store::Root(new StoreController);
1231
dd9b1081 1232 parse_err = parseConfigFile(ConfigFile);
62e76326 1233
97244680 1234 Mem::Report();
26ac0430 1235
9b7292ce 1236 if (opt_parse_cfg_only)
6c1962dd 1237
9b7292ce 1238 return parse_err;
9b7292ce 1239 }
c642c141 1240 setUmask(Config.umask);
9b7292ce 1241 if (-1 == opt_send_signal)
1242 if (checkRunningPid())
1243 exit(1);
e13ee7ad 1244
9bc73deb 1245#if TEST_ACCESS
62e76326 1246
95564b0d 1247 comm_init();
62e76326 1248
9b7292ce 1249 comm_select_init();
62e76326 1250
9b7292ce 1251 mainInitialize();
62e76326 1252
9b7292ce 1253 test_access();
62e76326 1254
9b7292ce 1255 return 0;
62e76326 1256
9bc73deb 1257#endif
1258
9b7292ce 1259 /* send signal to running copy and exit */
26ac0430 1260 if (opt_send_signal != -1) {
9b7292ce 1261 /* chroot if configured to run inside chroot */
62e76326 1262
a572d8be 1263 if (Config.chroot_dir) {
1264 if (chroot(Config.chroot_dir))
1265 fatal("failed to chroot");
1266
1267 no_suid();
1268 } else {
1269 leave_suid();
9b7292ce 1270 }
62e76326 1271
9b7292ce 1272 sendSignal();
1273 /* NOTREACHED */
1274 }
62e76326 1275
26ac0430 1276 if (opt_create_swap_dirs) {
9b7292ce 1277 /* chroot if configured to run inside chroot */
0e657244 1278
9b7292ce 1279 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
1280 fatal("failed to chroot");
1281 }
62e76326 1282
9b7292ce 1283 setEffectiveUser();
bf8fe701 1284 debugs(0, 0, "Creating Swap Directories");
c8f4eac4 1285 Store::Root().create();
6c1962dd 1286
9b7292ce 1287 return 0;
9b7292ce 1288 }
62e76326 1289
9b7292ce 1290 if (!opt_no_daemon)
1291 watch_child(argv);
62e76326 1292
95564b0d 1293 setMaxFD();
1294
1295 /* init comm module */
1296 comm_init();
62e76326 1297
9b7292ce 1298 comm_select_init();
4d64d74a 1299
26ac0430 1300 if (opt_no_daemon) {
9b7292ce 1301 /* we have to init fdstat here. */
1302 fd_open(0, FD_LOG, "stdin");
1303 fd_open(1, FD_LOG, "stdout");
1304 fd_open(2, FD_LOG, "stderr");
1305 }
62e76326 1306
6c1962dd 1307#if USE_WIN32_SERVICE
1308
9b7292ce 1309 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1310
1311#endif
1312
9b7292ce 1313 mainInitialize();
4d64d74a 1314
6c1962dd 1315#if USE_WIN32_SERVICE
1316
9b7292ce 1317 WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
6c1962dd 1318
1319#endif
1320
9b7292ce 1321 /* main loop */
a553a5a3 1322 EventLoop mainLoop;
62e76326 1323
9688b0ae 1324 SignalEngine signalEngine(mainLoop);
6c1962dd 1325
9688b0ae 1326 mainLoop.registerEngine(&signalEngine);
62e76326 1327
8ff3fa2e 1328 /* TODO: stop requiring the singleton here */
1329 mainLoop.registerEngine(EventScheduler::GetInstance());
62e76326 1330
8ff3fa2e 1331 StoreRootEngine store_engine;
615f9581 1332
8ff3fa2e 1333 mainLoop.registerEngine(&store_engine);
a774fd3f 1334
8ff3fa2e 1335 CommSelectEngine comm_engine;
1336
8ff3fa2e 1337 mainLoop.registerEngine(&comm_engine);
1338
bef81ea5 1339 mainLoop.setPrimaryEngine(&comm_engine);
1340
8ff3fa2e 1341 /* use the standard time service */
1342 TimeEngine time_engine;
1343
1344 mainLoop.setTimeService(&time_engine);
1345
1346 mainLoop.run();
1347
1348 if (mainLoop.errcount == 10)
1349 fatal_dump("Event loop exited with failure.");
1350
1351 /* shutdown squid now */
1352 SquidShutdown();
62e76326 1353
9b7292ce 1354 /* NOTREACHED */
9b7292ce 1355 return 0;
090089c4 1356}
7690e8eb 1357
b8d8561b 1358static void
0673c0ba 1359sendSignal(void)
7690e8eb 1360{
ff8d0ea6 1361 pid_t pid;
fedac7e5 1362 debug_log = stderr;
258ac4d7 1363
1364 if (strcmp(Config.pidFilename, "none") == 0) {
bf8fe701 1365 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
258ac4d7 1366 }
1367
fedac7e5 1368 pid = readPidFile();
62e76326 1369
fedac7e5 1370 if (pid > 1) {
6c1962dd 1371#if USE_WIN32_SERVICE
1372
1373 if (opt_signal_service) {
1374 WIN32_sendSignal(opt_send_signal);
1375 exit(0);
1376 } else
1377#ifdef _SQUID_MSWIN_
1378 {
7dbca7a4 1379 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
6c1962dd 1380 fprintf(stderr, "signal to Squid Service:\n");
1381 fprintf(stderr, "missing -n command line switch.\n");
1382 exit(1);
1383 }
1384
1385 /* NOTREACHED */
1386#endif
1387
1388#endif
1389
62e76326 1390 if (kill(pid, opt_send_signal) &&
1391 /* ignore permissions if just running check */
1392 !(opt_send_signal == 0 && errno == EPERM)) {
7dbca7a4 1393 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
62e76326 1394 fprintf(stderr, "signal %d to process %d: %s\n",
1395 opt_send_signal, (int) pid, xstrerror());
1396 exit(1);
1397 }
fedac7e5 1398 } else {
7dbca7a4 1399 fprintf(stderr, "%s: ERROR: No running copy\n", APP_SHORTNAME);
62e76326 1400 exit(1);
7690e8eb 1401 }
62e76326 1402
fedac7e5 1403 /* signal successfully sent */
1404 exit(0);
1405}
f95b8144 1406
a50bfe93 1407#ifndef _SQUID_MSWIN_
e18d7fdc 1408/*
1409 * This function is run when Squid is in daemon mode, just
1410 * before the parent forks and starts up the child process.
1411 * It can be used for admin-specific tasks, such as notifying
1412 * someone that Squid is (re)started.
1413 */
1414static void
1415mainStartScript(const char *prog)
1416{
1417 char script[SQUID_MAXPATHLEN];
1418 char *t;
1419 size_t sl = 0;
1420 pid_t cpid;
1421 pid_t rpid;
1422 xstrncpy(script, prog, MAXPATHLEN);
62e76326 1423
e18d7fdc 1424 if ((t = strrchr(script, '/'))) {
62e76326 1425 *(++t) = '\0';
1426 sl = strlen(script);
e18d7fdc 1427 }
62e76326 1428
e18d7fdc 1429 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
62e76326 1430
e18d7fdc 1431 if ((cpid = fork()) == 0) {
62e76326 1432 /* child */
f75662c9 1433 execl(script, squid_start_script, (char *)NULL);
482aa790 1434 _exit(-1);
e18d7fdc 1435 } else {
62e76326 1436 do {
e18d7fdc 1437#ifdef _SQUID_NEXT_
62e76326 1438 union wait status;
1439 rpid = wait3(&status, 0, NULL);
e18d7fdc 1440#else
62e76326 1441
1442 int status;
1443 rpid = waitpid(-1, &status, 0);
e18d7fdc 1444#endif
62e76326 1445
1446 } while (rpid != cpid);
e18d7fdc 1447 }
1448}
1449
a50bfe93 1450#endif /* _SQUID_MSWIN_ */
1451
efd900cb 1452static int
1453checkRunningPid(void)
1454{
1455 pid_t pid;
e0077312 1456
1457 if (!debug_log)
1458 debug_log = stderr;
1459
efd900cb 1460 pid = readPidFile();
62e76326 1461
efd900cb 1462 if (pid < 2)
62e76326 1463 return 0;
1464
efd900cb 1465 if (kill(pid, 0) < 0)
62e76326 1466 return 0;
1467
cb7a4fcb 1468 debugs(0, 0, "Squid is already running! Process ID " << pid);
62e76326 1469
efd900cb 1470 return 1;
1471}
1472
f95b8144 1473static void
bbe199dc 1474watch_child(char *argv[])
f95b8144 1475{
a50bfe93 1476#ifndef _SQUID_MSWIN_
f95b8144 1477 char *prog;
f95b8144 1478 int failcount = 0;
1479 time_t start;
1480 time_t stop;
1481#ifdef _SQUID_NEXT_
62e76326 1482
f95b8144 1483 union wait status;
1484#else
62e76326 1485
f95b8144 1486 int status;
1487#endif
62e76326 1488
e3a3b845 1489 pid_t pid;
c99c5397 1490#ifdef TIOCNOTTY
1491
54f742e7 1492 int i;
c99c5397 1493#endif
1494
742724a4 1495 int nullfd;
62e76326 1496
f95b8144 1497 if (*(argv[0]) == '(')
62e76326 1498 return;
1499
7dbca7a4 1500 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1501
54f742e7 1502 if ((pid = fork()) < 0)
62e76326 1503 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
54f742e7 1504 else if (pid > 0)
62e76326 1505 exit(0);
1506
54f742e7 1507 if (setsid() < 0)
62e76326 1508 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
1509
efd900cb 1510 closelog();
62e76326 1511
54f742e7 1512#ifdef TIOCNOTTY
62e76326 1513
c4aefe96 1514 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
62e76326 1515 ioctl(i, TIOCNOTTY, NULL);
1516 close(i);
54f742e7 1517 }
62e76326 1518
54f742e7 1519#endif
b05490a8 1520
7f6ffd15 1521 /*
1522 * RBCOLLINS - if cygwin stackdumps when squid is run without
1523 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1524 * 1.1.3. execvp had a bit overflow error in a loop..
1525 */
742724a4 1526 /* Connect stdio to /dev/null in daemon mode */
4da086c4 1527 nullfd = open(_PATH_DEVNULL, O_RDWR | O_TEXT);
62e76326 1528
e4a1325e 1529 if (nullfd < 0)
4da086c4 1530 fatalf(_PATH_DEVNULL " %s\n", xstrerror());
e4a1325e 1531
742724a4 1532 dup2(nullfd, 0);
62e76326 1533
742724a4 1534 if (opt_debug_stderr < 0) {
62e76326 1535 dup2(nullfd, 1);
1536 dup2(nullfd, 2);
742724a4 1537 }
62e76326 1538
f95b8144 1539 for (;;) {
62e76326 1540 mainStartScript(argv[0]);
1541
1542 if ((pid = fork()) == 0) {
1543 /* child */
7dbca7a4 1544 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1545 prog = xstrdup(argv[0]);
1546 argv[0] = xstrdup("(squid)");
1547 execvp(prog, argv);
1548 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
1549 }
1550
1551 /* parent */
7dbca7a4 1552 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1553
1554 syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
1555
1556 time(&start);
1557
1558 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
1559
f95b8144 1560#ifdef _SQUID_NEXT_
62e76326 1561
1562 pid = wait3(&status, 0, NULL);
1563
f95b8144 1564#else
62e76326 1565
1566 pid = waitpid(-1, &status, 0);
1567
1568#endif
1569
1570 time(&stop);
1571
1572 if (WIFEXITED(status)) {
1573 syslog(LOG_NOTICE,
1574 "Squid Parent: child process %d exited with status %d",
1575 pid, WEXITSTATUS(status));
1576 } else if (WIFSIGNALED(status)) {
1577 syslog(LOG_NOTICE,
cc192b50 1578 "Squid Parent: child process %d exited due to signal %d with status %d",
1579 pid, WTERMSIG(status), WEXITSTATUS(status));
62e76326 1580 } else {
1581 syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
1582 }
1583
1584 if (stop - start < 10)
1585 failcount++;
1586 else
1587 failcount = 0;
1588
1589 if (failcount == 5) {
1590 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
1591 exit(1);
1592 }
1593
1594 if (WIFEXITED(status))
1595 if (WEXITSTATUS(status) == 0)
1596 exit(0);
1597
1598 if (WIFSIGNALED(status)) {
1599 switch (WTERMSIG(status)) {
1600
1601 case SIGKILL:
1602 exit(0);
1603 break;
1604
06a0fbd3 1605 case SIGINT:
1606 case SIGTERM:
26ac0430 1607 syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
06a0fbd3 1608 exit(1);
1609 break;
1610
62e76326 1611 default:
1612 break;
1613 }
1614 }
1615
1616 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
1617 sleep(3);
f95b8144 1618 }
62e76326 1619
bbe199dc 1620 /* NOTREACHED */
a50bfe93 1621#endif /* _SQUID_MSWIN_ */
a572d8be 1622
f95b8144 1623}
fff6ad65 1624
9ec1a1dc 1625static void
8ff3fa2e 1626SquidShutdown()
fff6ad65 1627{
d71e4674
AR
1628 /* XXX: This function is called after the main loop has quit, which
1629 * means that no AsyncCalls would be called, including close handlers.
1630 * TODO: We need to close/shut/free everything that needs calls before
1631 * exiting the loop.
26ac0430 1632 */
d71e4674 1633
6c1962dd 1634#if USE_WIN32_SERVICE
1635 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1636#endif
1637
bf8fe701 1638 debugs(1, 1, "Shutting down...");
95a83c22 1639#if USE_DNSSERVERS
1640
1641 dnsShutdown();
1642#else
1643
1644 idnsShutdown();
1645#endif
1646
1647 redirectShutdown();
1648 externalAclShutdown();
d723bf6b 1649 icpConnectionClose();
1650#if USE_HTCP
62e76326 1651
d723bf6b 1652 htcpSocketClose();
1653#endif
1654#ifdef SQUID_SNMP
62e76326 1655
d723bf6b 1656 snmpConnectionClose();
320e9f36 1657#endif
eb824054 1658#if USE_WCCP
62e76326 1659
320e9f36 1660 wccpConnectionClose();
d723bf6b 1661#endif
0b0cfcf2 1662#if USE_WCCPv2
1663
1664 wccp2ConnectionClose();
1665#endif
62e76326 1666
fff6ad65 1667 releaseServerSockets();
d723bf6b 1668 commCloseAllSockets();
515ec4dc 1669#if DELAY_POOLS
62e76326 1670
b67e2c8c 1671 DelayPools::FreePools();
515ec4dc 1672#endif
62e76326 1673
5dae8514 1674 authenticateShutdown();
6c1962dd 1675#if USE_WIN32_SERVICE
1676
1677 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1678#endif
62e76326 1679
c8f4eac4 1680 Store::Root().sync(); /* Flush pending object writes/unlinks */
4d075ba0 1681#if USE_UNLINKD
1682
1683 unlinkdClose(); /* after sync/flush */
1684#endif
fc68f6b1 1685
fff6ad65 1686 storeDirWriteCleanLogs(0);
1687 PrintRusage();
1688 dumpMallocStats();
c8f4eac4 1689 Store::Root().sync(); /* Flush log writes */
fff6ad65 1690 storeLogClose();
1691 accessLogClose();
5b824235 1692 useragentLogClose();
c9b99797 1693 refererCloseLog();
225644d7 1694#if WIP_FWD_LOG
62e76326 1695
225644d7 1696 fwdUninit();
1697#endif
62e76326 1698
c8f4eac4 1699 Store::Root().sync(); /* Flush log close */
59b2d47f 1700 StoreFileSystem::FreeAllFs();
b9ae18aa 1701 DiskIOModule::FreeAllModules();
afec404b 1702#if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
62e76326 1703
fff6ad65 1704 configFreeMemory();
1705 storeFreeMemory();
33ab18e8 1706 /*stmemFreeMemory(); */
fff6ad65 1707 netdbFreeMemory();
1708 ipcacheFreeMemory();
1709 fqdncacheFreeMemory();
1710 asnFreeMemory();
26a369ba 1711 clientdbFreeMemory();
7021844c 1712 httpHeaderCleanModule();
d2db411c 1713 statFreeMemory();
f1fc2a8d 1714 eventFreeMemory();
c68e9c6b 1715 mimeFreeMemory();
1716 errorClean();
fff6ad65 1717#endif
26a369ba 1718#if !XMALLOC_TRACE
62e76326 1719
54f742e7 1720 if (opt_no_daemon) {
62e76326 1721 file_close(0);
1722 file_close(1);
1723 file_close(2);
54f742e7 1724 }
62e76326 1725
33ab18e8 1726#endif
fff6ad65 1727 fdDumpOpen();
62e76326 1728
236d1779 1729 comm_exit();
62e76326 1730
ddb43c58 1731 memClean();
62e76326 1732
33ab18e8 1733#if XMALLOC_TRACE
62e76326 1734
26a369ba 1735 xmalloc_find_leaks();
62e76326 1736
bf8fe701 1737 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total);
62e76326 1738
33ab18e8 1739#endif
36a97e19 1740#if MEM_GEN_TRACE
62e76326 1741
399e85ea 1742 log_trace_done();
62e76326 1743
36a97e19 1744#endif
62e76326 1745
ab50ee9e 1746 if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
62e76326 1747 enter_suid();
1748 safeunlink(Config.pidFilename, 0);
1749 leave_suid();
ab50ee9e 1750 }
62e76326 1751
bf8fe701 1752 debugs(1, 1, "Squid Cache (Version " << version_string << "): Exiting normally.");
62e76326 1753
0cfa98cb 1754 /*
1755 * DPW 2006-10-23
1756 * We used to fclose(debug_log) here if it was set, but then
1757 * we forgot to set it to NULL. That caused some coredumps
1758 * because exit() ends up calling a bunch of destructors and
1759 * such. So rather than forcing the debug_log to close, we'll
1760 * leave it open so that those destructors can write some
1761 * debugging if necessary. The file will be closed anyway when
1762 * the process truly exits.
1763 */
62e76326 1764
ae1feb30 1765 exit(shutdown_status);
fff6ad65 1766}
bef81ea5 1767