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