]> git.ipfire.org Git - thirdparty/squid.git/blob - src/main.cc
Andres Kroonmaa's hi-res cpu profiling patch
[thirdparty/squid.git] / src / main.cc
1
2 /*
3 * $Id: main.cc,v 1.354 2002/10/02 11:06:31 robertc Exp $
4 *
5 * DEBUG: section 1 Startup and Main Loop
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
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
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37
38 /* for error reporting from xmalloc and friends */
39 extern void (*failure_notify) (const char *);
40
41 static int opt_send_signal = -1;
42 static int opt_no_daemon = 0;
43 static int opt_parse_cfg_only = 0;
44 static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
45 static int configured_once = 0;
46 #if MALLOC_DBG
47 static int malloc_debug_level = 0;
48 #endif
49 static volatile int do_reconfigure = 0;
50 static volatile int do_rotate = 0;
51 static volatile int do_shutdown = 0;
52
53 static void mainRotate(void);
54 static void mainReconfigure(void);
55 static SIGHDLR rotate_logs;
56 static SIGHDLR reconfigure;
57 static void mainInitialize(void);
58 static void usage(void);
59 static void mainParseOptions(int, char **);
60 static void sendSignal(void);
61 static void serverConnectionsOpen(void);
62 static void watch_child(char **);
63 static void setEffectiveUser(void);
64 #if MEM_GEN_TRACE
65 extern void log_trace_done();
66 extern void log_trace_init(char *);
67 #endif
68 static EVH SquidShutdown;
69 static void mainSetCwd(void);
70 static int checkRunningPid(void);
71
72 static const char *squid_start_script = "squid_start";
73
74 #if TEST_ACCESS
75 #include "test_access.c"
76 #endif
77
78 static void
79 usage(void)
80 {
81 fprintf(stderr,
82 "Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n"
83 " -a port Specify HTTP port number (default: %d).\n"
84 " -d level Write debugging to stderr also.\n"
85 " -f file Use given config-file instead of\n"
86 " %s\n"
87 " -h Print help message.\n"
88 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
89 " Parse configuration file, then send signal to \n"
90 " running copy (except -k parse) and exit.\n"
91 " -s Enable logging to syslog.\n"
92 " -u port Specify ICP port number (default: %d), disable with 0.\n"
93 " -v Print version.\n"
94 " -z Create swap directories\n"
95 " -C Do not catch fatal signals.\n"
96 " -D Disable initial DNS tests.\n"
97 " -F Don't serve any requests until store is rebuilt.\n"
98 " -N No daemon mode.\n"
99 " -R Do not set REUSEADDR on port.\n"
100 " -S Double-check swap during rebuild.\n"
101 " -V Virtual host httpd-accelerator.\n"
102 " -X Force full debugging.\n"
103 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
104 appname, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
105 exit(1);
106 }
107
108 static void
109 mainParseOptions(int argc, char *argv[])
110 {
111 extern char *optarg;
112 int c;
113
114 while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) {
115 switch (c) {
116 case 'C':
117 opt_catch_signals = 0;
118 break;
119 case 'D':
120 opt_dns_tests = 0;
121 break;
122 case 'F':
123 opt_foreground_rebuild = 1;
124 break;
125 case 'N':
126 opt_no_daemon = 1;
127 break;
128 case 'R':
129 opt_reuseaddr = 0;
130 break;
131 case 'S':
132 opt_store_doublecheck = 1;
133 break;
134 case 'V':
135 vhost_mode = 1;
136 break;
137 case 'X':
138 /* force full debugging */
139 sigusr2_handle(SIGUSR2);
140 break;
141 case 'Y':
142 opt_reload_hit_only = 1;
143 break;
144 case 'a':
145 parse_sockaddr_in_list_token(&Config.Sockaddr.http, optarg);
146 break;
147 case 'd':
148 opt_debug_stderr = atoi(optarg);
149 break;
150 case 'f':
151 xfree(ConfigFile);
152 ConfigFile = xstrdup(optarg);
153 break;
154 case 'h':
155 usage();
156 break;
157 case 'k':
158 if ((int) strlen(optarg) < 1)
159 usage();
160 if (!strncmp(optarg, "reconfigure", strlen(optarg)))
161 opt_send_signal = SIGHUP;
162 else if (!strncmp(optarg, "rotate", strlen(optarg)))
163 #ifdef _SQUID_LINUX_THREADS_
164 opt_send_signal = SIGQUIT;
165 #else
166 opt_send_signal = SIGUSR1;
167 #endif
168 else if (!strncmp(optarg, "debug", strlen(optarg)))
169 #ifdef _SQUID_LINUX_THREADS_
170 opt_send_signal = SIGTRAP;
171 #else
172 opt_send_signal = SIGUSR2;
173 #endif
174 else if (!strncmp(optarg, "shutdown", strlen(optarg)))
175 opt_send_signal = SIGTERM;
176 else if (!strncmp(optarg, "interrupt", strlen(optarg)))
177 opt_send_signal = SIGINT;
178 else if (!strncmp(optarg, "kill", strlen(optarg)))
179 opt_send_signal = SIGKILL;
180 else if (!strncmp(optarg, "check", strlen(optarg)))
181 opt_send_signal = 0; /* SIGNULL */
182 else if (!strncmp(optarg, "parse", strlen(optarg)))
183 opt_parse_cfg_only = 1; /* parse cfg file only */
184 else
185 usage();
186 break;
187 case 'm':
188 if (optarg) {
189 #if MALLOC_DBG
190 malloc_debug_level = atoi(optarg);
191 /* NOTREACHED */
192 break;
193 #else
194 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
195 /* NOTREACHED */
196 #endif
197 } else {
198 #if XMALLOC_TRACE
199 xmalloc_trace = !xmalloc_trace;
200 #else
201 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
202 #endif
203 }
204 case 's':
205 #if HAVE_SYSLOG
206 opt_syslog_enable = 1;
207 break;
208 #else
209 fatal("Logging to syslog not available on this platform");
210 /* NOTREACHED */
211 #endif
212 case 'u':
213 icpPortNumOverride = atoi(optarg);
214 if (icpPortNumOverride < 0)
215 icpPortNumOverride = 0;
216 break;
217 case 'v':
218 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
219 exit(0);
220 /* NOTREACHED */
221 case 'z':
222 opt_create_swap_dirs = 1;
223 break;
224 case '?':
225 default:
226 usage();
227 break;
228 }
229 }
230 }
231
232 /* ARGSUSED */
233 static void
234 rotate_logs(int sig)
235 {
236 do_rotate = 1;
237 #if !HAVE_SIGACTION
238 signal(sig, rotate_logs);
239 #endif
240 }
241
242 /* ARGSUSED */
243 static void
244 reconfigure(int sig)
245 {
246 do_reconfigure = 1;
247 #if !HAVE_SIGACTION
248 signal(sig, reconfigure);
249 #endif
250 }
251
252 void
253 shut_down(int sig)
254 {
255 do_shutdown = sig == SIGINT ? -1 : 1;
256 #ifdef KILL_PARENT_OPT
257 if (getppid() > 1) {
258 debug(1, 1) ("Killing RunCache, pid %d\n", getppid());
259 if (kill(getppid(), sig) < 0)
260 debug(1, 1) ("kill %d: %s\n", getppid(), xstrerror());
261 }
262 #endif
263 #if SA_RESETHAND == 0
264 signal(SIGTERM, SIG_DFL);
265 signal(SIGINT, SIG_DFL);
266 #endif
267 }
268
269 static void
270 serverConnectionsOpen(void)
271 {
272 clientOpenListenSockets();
273 icpConnectionsOpen();
274 #if USE_HTCP
275 htcpInit();
276 #endif
277 #ifdef SQUID_SNMP
278 snmpConnectionOpen();
279 #endif
280 #if USE_WCCP
281 wccpConnectionOpen();
282 #endif
283 clientdbInit();
284 icmpOpen();
285 netdbInit();
286 asnInit();
287 peerSelectInit();
288 #if USE_CARP
289 carpInit();
290 #endif
291 }
292
293 void
294 serverConnectionsClose(void)
295 {
296 assert(shutting_down || reconfiguring);
297 clientHttpConnectionsClose();
298 icpConnectionShutdown();
299 #if USE_HTCP
300 htcpSocketShutdown();
301 #endif
302 icmpClose();
303 #ifdef SQUID_SNMP
304 snmpConnectionShutdown();
305 #endif
306 #if USE_WCCP
307 wccpConnectionShutdown();
308 #endif
309 asnFreeMemory();
310 }
311
312 static void
313 mainReconfigure(void)
314 {
315 debug(1, 1) ("Restarting Squid Cache (version %s)...\n", version_string);
316 reconfiguring = 1;
317 /* Already called serverConnectionsClose and ipcacheShutdownServers() */
318 serverConnectionsClose();
319 icpConnectionClose();
320 #if USE_HTCP
321 htcpSocketClose();
322 #endif
323 #ifdef SQUID_SNMP
324 snmpConnectionClose();
325 #endif
326 #if USE_WCCP
327 wccpConnectionClose();
328 #endif
329 #if USE_DNSSERVERS
330 dnsShutdown();
331 #else
332 idnsShutdown();
333 #endif
334 redirectShutdown();
335 authenticateShutdown();
336 externalAclShutdown();
337 storeDirCloseSwapLogs();
338 errorClean();
339 enter_suid(); /* root to read config file */
340 parseConfigFile(ConfigFile);
341 setEffectiveUser();
342 _db_init(Config.Log.log, Config.debugOptions);
343 ipcache_restart(); /* clear stuck entries */
344 authenticateUserCacheRestart(); /* clear stuck ACL entries */
345 fqdncache_restart(); /* sigh, fqdncache too */
346 parseEtcHosts();
347 errorInitialize(); /* reload error pages */
348 #if USE_DNSSERVERS
349 dnsInit();
350 #else
351 idnsInit();
352 #endif
353 redirectInit();
354 authenticateInit(&Config.authConfig);
355 externalAclInit();
356 #if USE_WCCP
357 wccpInit();
358 #endif
359 serverConnectionsOpen();
360 if (theOutIcpConnection >= 0) {
361 if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
362 neighbors_open(theOutIcpConnection);
363 else
364 debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
365 }
366 storeDirOpenSwapLogs();
367 mimeInit(Config.mimeTablePathname);
368 writePidFile(); /* write PID file */
369 debug(1, 1) ("Ready to serve requests.\n");
370 reconfiguring = 0;
371 }
372
373 static void
374 mainRotate(void)
375 {
376 icmpClose();
377 #if USE_DNSSERVERS
378 dnsShutdown();
379 #endif
380 redirectShutdown();
381 authenticateShutdown();
382 externalAclShutdown();
383 _db_rotate_log(); /* cache.log */
384 storeDirWriteCleanLogs(1);
385 storeLogRotate(); /* store.log */
386 accessLogRotate(); /* access.log */
387 useragentRotateLog(); /* useragent.log */
388 refererRotateLog(); /* referer.log */
389 #if WIP_FWD_LOG
390 fwdLogRotate();
391 #endif
392 icmpOpen();
393 #if USE_DNSSERVERS
394 dnsInit();
395 #endif
396 redirectInit();
397 authenticateInit(&Config.authConfig);
398 externalAclInit();
399 }
400
401 static void
402 setEffectiveUser(void)
403 {
404 leave_suid(); /* Run as non privilegied user */
405 #ifdef _SQUID_OS2_
406 return;
407 #endif
408 if (geteuid() == 0) {
409 debug(0, 0) ("Squid is not safe to run as root! If you must\n");
410 debug(0, 0) ("start Squid as root, then you must configure\n");
411 debug(0, 0) ("it to run as a non-priveledged user with the\n");
412 debug(0, 0) ("'cache_effective_user' option in the config file.\n");
413 fatal("Don't run Squid as root, set 'cache_effective_user'!");
414 }
415 }
416
417 static void
418 mainSetCwd(void)
419 {
420 char pathbuf[MAXPATHLEN];
421 if (Config.coredump_dir) {
422 if (0 == strcmp("none", Config.coredump_dir)) {
423 (void) 0;
424 } else if (chdir(Config.coredump_dir) == 0) {
425 debug(0, 1) ("Set Current Directory to %s\n", Config.coredump_dir);
426 return;
427 } else {
428 debug(50, 0) ("chdir: %s: %s\n", Config.coredump_dir, xstrerror());
429 }
430 }
431 /* If we don't have coredump_dir or couldn't cd there, report current dir */
432 if (getcwd(pathbuf, MAXPATHLEN)) {
433 debug(0, 1) ("Current Directory is %s\n", pathbuf);
434 } else {
435 debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
436 }
437 }
438
439 static void
440 mainInitialize(void)
441 {
442 /* chroot if configured to run inside chroot */
443 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
444 fatal("failed to chroot");
445 }
446 if (opt_catch_signals) {
447 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
448 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
449 }
450 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
451 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
452
453 setEffectiveUser();
454 if (icpPortNumOverride != 1)
455 Config.Port.icp = (u_short) icpPortNumOverride;
456
457 _db_init(Config.Log.log, Config.debugOptions);
458 fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
459 #if MEM_GEN_TRACE
460 log_trace_init("/tmp/squid.alloc");
461 #endif
462 debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
463 version_string,
464 CONFIG_HOST_TYPE);
465 debug(1, 1) ("Process ID %d\n", (int) getpid());
466 debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);
467
468 if (!configured_once)
469 disk_init(); /* disk_init must go before ipcache_init() */
470 ipcache_init();
471 fqdncache_init();
472 parseEtcHosts();
473 #if USE_DNSSERVERS
474 dnsInit();
475 #else
476 idnsInit();
477 #endif
478 redirectInit();
479 authenticateInit(&Config.authConfig);
480 externalAclInit();
481 useragentOpenLog();
482 refererOpenLog();
483 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
484 httpReplyInitModule(); /* must go before accepting replies */
485 errorInitialize();
486 accessLogInit();
487 #if USE_IDENT
488 identInit();
489 #endif
490 #ifdef SQUID_SNMP
491 snmpInit();
492 #endif
493 #if MALLOC_DBG
494 malloc_debug(0, malloc_debug_level);
495 #endif
496
497 if (!configured_once) {
498 #if USE_UNLINKD
499 unlinkdInit();
500 #endif
501 urlInitialize();
502 cachemgrInit();
503 statInit();
504 storeInit();
505 mainSetCwd();
506 /* after this point we want to see the mallinfo() output */
507 do_mallinfo = 1;
508 mimeInit(Config.mimeTablePathname);
509 pconnInit();
510 refreshInit();
511 #if DELAY_POOLS
512 delayPoolsInit();
513 #endif
514 fwdInit();
515 }
516 #if USE_WCCP
517 wccpInit();
518 #endif
519 serverConnectionsOpen();
520 if (theOutIcpConnection >= 0) {
521 if (!Config2.Accel.on || Config.onoff.accel_with_proxy)
522 neighbors_open(theOutIcpConnection);
523 else
524 debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
525 }
526 if (Config.chroot_dir)
527 no_suid();
528 if (!configured_once)
529 writePidFile(); /* write PID file */
530
531 #ifdef _SQUID_LINUX_THREADS_
532 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
533 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
534 #else
535 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
536 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
537 #endif
538 squid_signal(SIGHUP, reconfigure, SA_RESTART);
539 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
540 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
541 memCheckInit();
542 debug(1, 1) ("Ready to serve requests.\n");
543 if (!configured_once) {
544 eventAdd("storeMaintain", storeMaintainSwapSpace, NULL, 1.0, 1);
545 if (Config.onoff.announce)
546 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
547 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
548 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
549 #if USE_XPROF_STATS
550 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
551 #endif
552 eventAdd("memPoolCleanIdlePools", memPoolCleanIdlePools, NULL, 15.0, 1);
553 }
554 configured_once = 1;
555 }
556
557 int
558 main(int argc, char **argv)
559 {
560 int errcount = 0;
561 int n; /* # of GC'd objects */
562 time_t loop_delay;
563 mode_t oldmask;
564 #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
565 int WIN32_init_err;
566 #endif
567
568 debug_log = stderr;
569 if (FD_SETSIZE < Squid_MaxFD)
570 Squid_MaxFD = FD_SETSIZE;
571
572 #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
573 if ((WIN32_init_err = WIN32_Subsystem_Init()))
574 return WIN32_init_err;
575 #endif
576
577 /* call mallopt() before anything else */
578 #if HAVE_MALLOPT
579 #ifdef M_GRAIN
580 /* Round up all sizes to a multiple of this */
581 mallopt(M_GRAIN, 16);
582 #endif
583 #ifdef M_MXFAST
584 /* biggest size that is considered a small block */
585 mallopt(M_MXFAST, 256);
586 #endif
587 #ifdef M_NBLKS
588 /* allocate this many small blocks at once */
589 mallopt(M_NLBLKS, 32);
590 #endif
591 #endif /* HAVE_MALLOPT */
592
593 /*
594 * The plan here is to set the umask to 007 (deny others for
595 * read,write,execute), but only if the umask is not already
596 * set. Unfortunately, there is no way to get the current
597 * umask value without setting it.
598 */
599 oldmask = umask(S_IRWXO);
600 if (oldmask)
601 umask(oldmask);
602
603 memset(&local_addr, '\0', sizeof(struct in_addr));
604 safe_inet_addr(localhost, &local_addr);
605 memset(&any_addr, '\0', sizeof(struct in_addr));
606 safe_inet_addr("0.0.0.0", &any_addr);
607 memset(&no_addr, '\0', sizeof(struct in_addr));
608 safe_inet_addr("255.255.255.255", &no_addr);
609 squid_srandom(time(NULL));
610
611 getCurrentTime();
612 squid_start = current_time;
613 failure_notify = fatal_dump;
614
615 mainParseOptions(argc, argv);
616
617 /* parse configuration file
618 * note: in "normal" case this used to be called from mainInitialize() */
619 {
620 int parse_err;
621 if (!ConfigFile)
622 ConfigFile = xstrdup(DefaultConfigFile);
623 assert(!configured_once);
624 #if USE_LEAKFINDER
625 leakInit();
626 #endif
627 memInit();
628 cbdataInit();
629 eventInit(); /* eventInit() is required for config parsing */
630 storeFsInit(); /* required for config parsing */
631 authenticateSchemeInit(); /* required for config parsign */
632 parse_err = parseConfigFile(ConfigFile);
633
634 if (opt_parse_cfg_only)
635 return parse_err;
636 }
637 if (-1 == opt_send_signal)
638 if (checkRunningPid())
639 exit(1);
640
641 #if TEST_ACCESS
642 comm_init();
643 comm_select_init();
644 mainInitialize();
645 test_access();
646 return 0;
647 #endif
648
649 /* send signal to running copy and exit */
650 if (opt_send_signal != -1) {
651 /* chroot if configured to run inside chroot */
652 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
653 fatal("failed to chroot");
654 }
655 sendSignal();
656 /* NOTREACHED */
657 }
658 if (opt_create_swap_dirs) {
659 /* chroot if configured to run inside chroot */
660 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
661 fatal("failed to chroot");
662 }
663 setEffectiveUser();
664 debug(0, 0) ("Creating Swap Directories\n");
665 storeCreateSwapDirectories();
666 return 0;
667 }
668 if (!opt_no_daemon)
669 watch_child(argv);
670 setMaxFD();
671
672 if (opt_catch_signals)
673 for (n = Squid_MaxFD; n > 2; n--)
674 close(n);
675
676 /* init comm module */
677 comm_init();
678 comm_select_init();
679
680 if (opt_no_daemon) {
681 /* we have to init fdstat here. */
682 fd_open(0, FD_LOG, "stdin");
683 fd_open(1, FD_LOG, "stdout");
684 fd_open(2, FD_LOG, "stderr");
685 }
686 mainInitialize();
687
688 /* main loop */
689 for (;;) {
690 if (do_reconfigure) {
691 mainReconfigure();
692 do_reconfigure = 0;
693 } else if (do_rotate) {
694 mainRotate();
695 do_rotate = 0;
696 } else if (do_shutdown) {
697 time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
698 debug(1, 1) ("Preparing for shutdown after %d requests\n",
699 statCounter.client_http.requests);
700 debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
701 (int) wait);
702 do_shutdown = 0;
703 shutting_down = 1;
704 serverConnectionsClose();
705 #if USE_DNSSERVERS
706 dnsShutdown();
707 #else
708 idnsShutdown();
709 #endif
710 redirectShutdown();
711 externalAclShutdown();
712 eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
713 }
714 eventRun();
715 if ((loop_delay = eventNextTime()) < 0)
716 loop_delay = 0;
717 switch (comm_select(loop_delay)) {
718 case COMM_OK:
719 errcount = 0; /* reset if successful */
720 break;
721 case COMM_ERROR:
722 errcount++;
723 debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
724 if (errcount == 10)
725 fatal_dump("Select Loop failed!");
726 break;
727 case COMM_TIMEOUT:
728 break;
729 case COMM_SHUTDOWN:
730 SquidShutdown(NULL);
731 break;
732 default:
733 fatal_dump("MAIN: Internal error -- this should never happen.");
734 break;
735 }
736 }
737 /* NOTREACHED */
738 return 0;
739 }
740
741 static void
742 sendSignal(void)
743 {
744 pid_t pid;
745 debug_log = stderr;
746 pid = readPidFile();
747 if (pid > 1) {
748 if (kill(pid, opt_send_signal) &&
749 /* ignore permissions if just running check */
750 !(opt_send_signal == 0 && errno == EPERM)) {
751 fprintf(stderr, "%s: ERROR: Could not send ", appname);
752 fprintf(stderr, "signal %d to process %d: %s\n",
753 opt_send_signal, (int) pid, xstrerror());
754 exit(1);
755 }
756 } else {
757 fprintf(stderr, "%s: ERROR: No running copy\n", appname);
758 exit(1);
759 }
760 /* signal successfully sent */
761 exit(0);
762 }
763
764 /*
765 * This function is run when Squid is in daemon mode, just
766 * before the parent forks and starts up the child process.
767 * It can be used for admin-specific tasks, such as notifying
768 * someone that Squid is (re)started.
769 */
770 static void
771 mainStartScript(const char *prog)
772 {
773 char script[SQUID_MAXPATHLEN];
774 char *t;
775 size_t sl = 0;
776 pid_t cpid;
777 pid_t rpid;
778 xstrncpy(script, prog, MAXPATHLEN);
779 if ((t = strrchr(script, '/'))) {
780 *(++t) = '\0';
781 sl = strlen(script);
782 }
783 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
784 if ((cpid = fork()) == 0) {
785 /* child */
786 execl(script, squid_start_script, 0);
787 _exit(0);
788 } else {
789 do {
790 #ifdef _SQUID_NEXT_
791 union wait status;
792 rpid = wait3(&status, 0, NULL);
793 #else
794 int status;
795 rpid = waitpid(-1, &status, 0);
796 #endif
797 } while (rpid != cpid);
798 }
799 }
800
801 static int
802 checkRunningPid(void)
803 {
804 pid_t pid;
805 debug_log = stderr;
806 pid = readPidFile();
807 if (pid < 2)
808 return 0;
809 if (kill(pid, 0) < 0)
810 return 0;
811 debug(0, 0) ("Squid is already running! Process ID %d\n", pid);
812 return 1;
813 }
814
815 static void
816 watch_child(char *argv[])
817 {
818 char *prog;
819 int failcount = 0;
820 time_t start;
821 time_t stop;
822 #ifdef _SQUID_NEXT_
823 union wait status;
824 #else
825 int status;
826 #endif
827 pid_t pid;
828 int i;
829 int nullfd;
830 if (*(argv[0]) == '(')
831 return;
832 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
833 if ((pid = fork()) < 0)
834 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
835 else if (pid > 0)
836 exit(0);
837 if (setsid() < 0)
838 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
839 closelog();
840 #ifdef TIOCNOTTY
841 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
842 ioctl(i, TIOCNOTTY, NULL);
843 close(i);
844 }
845 #endif
846
847
848 /*
849 * RBCOLLINS - if cygwin stackdumps when squid is run without
850 * -N, check the cygwin1.dll version, it needs to be AT LEAST
851 * 1.1.3. execvp had a bit overflow error in a loop..
852 */
853 /* Connect stdio to /dev/null in daemon mode */
854 nullfd = open("/dev/null", O_RDWR | O_TEXT);
855 dup2(nullfd, 0);
856 if (opt_debug_stderr < 0) {
857 dup2(nullfd, 1);
858 dup2(nullfd, 2);
859 }
860 /* Close all else */
861 for (i = 3; i < Squid_MaxFD; i++)
862 close(i);
863 for (;;) {
864 mainStartScript(argv[0]);
865 if ((pid = fork()) == 0) {
866 /* child */
867 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
868 prog = xstrdup(argv[0]);
869 argv[0] = xstrdup("(squid)");
870 execvp(prog, argv);
871 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
872 }
873 /* parent */
874 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
875 syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
876 time(&start);
877 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
878 #ifdef _SQUID_NEXT_
879 pid = wait3(&status, 0, NULL);
880 #else
881 pid = waitpid(-1, &status, 0);
882 #endif
883 time(&stop);
884 if (WIFEXITED(status)) {
885 syslog(LOG_NOTICE,
886 "Squid Parent: child process %d exited with status %d",
887 pid, WEXITSTATUS(status));
888 } else if (WIFSIGNALED(status)) {
889 syslog(LOG_NOTICE,
890 "Squid Parent: child process %d exited due to signal %d",
891 pid, WTERMSIG(status));
892 } else {
893 syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
894 }
895 if (stop - start < 10)
896 failcount++;
897 else
898 failcount = 0;
899 if (failcount == 5) {
900 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
901 exit(1);
902 }
903 if (WIFEXITED(status))
904 if (WEXITSTATUS(status) == 0)
905 exit(0);
906 if (WIFSIGNALED(status)) {
907 switch (WTERMSIG(status)) {
908 case SIGKILL:
909 exit(0);
910 break;
911 default:
912 break;
913 }
914 }
915 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
916 sleep(3);
917 }
918 /* NOTREACHED */
919 }
920
921 static void
922 SquidShutdown(void *unused)
923 {
924 debug(1, 1) ("Shutting down...\n");
925 if (Config.pidFilename && strcmp(Config.pidFilename, "none")) {
926 enter_suid();
927 safeunlink(Config.pidFilename, 0);
928 leave_suid();
929 }
930 icpConnectionClose();
931 #if USE_HTCP
932 htcpSocketClose();
933 #endif
934 #ifdef SQUID_SNMP
935 snmpConnectionClose();
936 #endif
937 #if USE_WCCP
938 wccpConnectionClose();
939 #endif
940 releaseServerSockets();
941 commCloseAllSockets();
942 authenticateShutdown();
943 #if USE_UNLINKD
944 unlinkdClose();
945 #endif
946 storeDirSync(); /* Flush pending object writes/unlinks */
947 storeDirWriteCleanLogs(0);
948 PrintRusage();
949 dumpMallocStats();
950 storeDirSync(); /* Flush log writes */
951 storeLogClose();
952 accessLogClose();
953 useragentLogClose();
954 #if WIP_FWD_LOG
955 fwdUninit();
956 #endif
957 storeDirSync(); /* Flush log close */
958 #if PURIFY || XMALLOC_TRACE
959 storeFsDone();
960 configFreeMemory();
961 storeFreeMemory();
962 /*stmemFreeMemory(); */
963 netdbFreeMemory();
964 ipcacheFreeMemory();
965 fqdncacheFreeMemory();
966 asnFreeMemory();
967 clientdbFreeMemory();
968 httpHeaderCleanModule();
969 statFreeMemory();
970 eventFreeMemory();
971 mimeFreeMemory();
972 errorClean();
973 #endif
974 #if !XMALLOC_TRACE
975 if (opt_no_daemon) {
976 file_close(0);
977 file_close(1);
978 file_close(2);
979 }
980 #endif
981 fdDumpOpen();
982 fdFreeMemory();
983 memClean();
984 #if XMALLOC_TRACE
985 xmalloc_find_leaks();
986 debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
987 #endif
988 #if MEM_GEN_TRACE
989 log_trace_done();
990 #endif
991 debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
992 version_string);
993 if (debug_log)
994 fclose(debug_log);
995 exit(0);
996 }