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