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