]> git.ipfire.org Git - thirdparty/squid.git/blob - src/main.cc
IPv6 preparation by Rafael Martinez Torres <rafael.martinez@novagnet.com>
[thirdparty/squid.git] / src / main.cc
1
2 /*
3 * $Id: main.cc,v 1.408 2005/04/18 21:52:42 hno 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 #include "AccessLogEntry.h"
38 #include "authenticate.h"
39 #include "Store.h"
40 #include "ICP.h"
41 #include "HttpReply.h"
42 #include "Mem.h"
43 #include "ACLASN.h"
44 #include "ACL.h"
45 #include "htcp.h"
46 #include "StoreFileSystem.h"
47 #include "DiskIO/DiskIOModule.h"
48 #include "comm.h"
49 #include "SwapDir.h"
50
51 #if USE_WIN32_SERVICE
52
53 #include "squid_windows.h"
54 #include <process.h>
55
56 static int opt_install_service = FALSE;
57 static int opt_remove_service = FALSE;
58 static int opt_signal_service = FALSE;
59 static int opt_command_line = FALSE;
60 extern void WIN32_svcstatusupdate(DWORD, DWORD);
61 void WINAPI WIN32_svcHandler(DWORD);
62
63 #endif
64
65 /* for error reporting from xmalloc and friends */
66 SQUIDCEXTERN void (*failure_notify) (const char *);
67
68 static int opt_send_signal = -1;
69 static int opt_parse_cfg_only = 0;
70 static char *opt_syslog_facility = NULL;
71 static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
72 static int configured_once = 0;
73 #if MALLOC_DBG
74 static int malloc_debug_level = 0;
75 #endif
76 static volatile int do_reconfigure = 0;
77 static volatile int do_rotate = 0;
78 static volatile int do_shutdown = 0;
79
80 static void mainRotate(void);
81 static void mainReconfigure(void);
82 static void mainInitialize(void);
83 static void usage(void);
84 static void mainParseOptions(int, char **);
85 static void sendSignal(void);
86 static void serverConnectionsOpen(void);
87 static void watch_child(char **);
88 static void setEffectiveUser(void);
89 #if MEM_GEN_TRACE
90 extern void log_trace_done();
91 extern void log_trace_init(char *);
92 #endif
93 static EVH SquidShutdown;
94 static void mainSetCwd(void);
95 static int checkRunningPid(void);
96
97 #ifndef _SQUID_MSWIN_
98 static const char *squid_start_script = "squid_start";
99 #endif
100
101 #if TEST_ACCESS
102 #include "test_access.c"
103 #endif
104
105 static void
106 usage(void)
107 {
108 fprintf(stderr,
109 #if USE_WIN32_SERVICE
110 "Usage: %s [-cdhirvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
111 #else
112 "Usage: %s [-cdhvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
113 #endif
114 " -a port Specify HTTP port number (default: %d).\n"
115 " -d level Write debugging to stderr also.\n"
116 " -f file Use given config-file instead of\n"
117 " %s\n"
118 " -h Print help message.\n"
119 #if USE_WIN32_SERVICE
120 " -i Installs as a Windows Service (see -n option).\n"
121 #endif
122 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
123 " Parse configuration file, then send signal to \n"
124 " running copy (except -k parse) and exit.\n"
125 #if USE_WIN32_SERVICE
126 " -n name Specify Windows Service name to use for service operations\n"
127 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
128 " -r Removes a Windows Service (see -n option).\n"
129 #endif
130 " -s | -l facility\n"
131 " Enable logging to syslog.\n"
132 " -u port Specify ICP port number (default: %d), disable with 0.\n"
133 " -v Print version.\n"
134 " -z Create swap directories\n"
135 " -C Do not catch fatal signals.\n"
136 " -D Disable initial DNS tests.\n"
137 " -F Don't serve any requests until store is rebuilt.\n"
138 " -N No daemon mode.\n"
139 #if USE_WIN32_SERVICE
140 " -O options\n"
141 " Set Windows Service Command line options in Registry.\n"
142 #endif
143 " -R Do not set REUSEADDR on port.\n"
144 " -S Double-check swap during rebuild.\n"
145 " -V Virtual host httpd-accelerator.\n"
146 " -X Force full debugging.\n"
147 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
148 appname, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
149 exit(1);
150 }
151
152 static void
153 mainParseOptions(int argc, char *argv[])
154 {
155 extern char *optarg;
156 int c;
157
158 #if USE_WIN32_SERVICE
159
160 while ((c = getopt(argc, argv, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
161 #else
162
163 while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::sl:u:vz?")) != -1)
164 #endif
165
166 {
167
168 switch (c)
169 {
170
171 case 'C':
172 opt_catch_signals = 0;
173 break;
174
175 case 'D':
176 opt_dns_tests = 0;
177 break;
178
179 case 'F':
180 opt_foreground_rebuild = 1;
181 break;
182
183 case 'N':
184 opt_no_daemon = 1;
185 break;
186 #if USE_WIN32_SERVICE
187
188 case 'O':
189 opt_command_line = 1;
190 WIN32_Command_Line = xstrdup(optarg);
191 break;
192 #endif
193
194 case 'R':
195 opt_reuseaddr = 0;
196 break;
197
198 case 'S':
199 opt_store_doublecheck = 1;
200 break;
201
202 case 'V':
203
204 if (Config.Sockaddr.http)
205 Config.Sockaddr.http->vhost = 1;
206
207 #if USE_SSL
208
209 else if (Config.Sockaddr.https)
210 Config.Sockaddr.https->http.vhost = 1;
211
212 #endif
213
214 else
215 fatal("No http_port specified\n");
216
217 break;
218
219 case 'X':
220 /* force full debugging */
221 sigusr2_handle(SIGUSR2);
222
223 break;
224
225 case 'Y':
226 opt_reload_hit_only = 1;
227
228 break;
229
230 #if USE_WIN32_SERVICE
231
232 case 'i':
233 opt_install_service = TRUE;
234
235 break;
236
237 #endif
238
239 case 'a':
240 add_http_port(optarg);
241
242 break;
243
244 case 'd':
245 opt_debug_stderr = atoi(optarg);
246
247 break;
248
249 case 'f':
250 xfree(ConfigFile);
251
252 ConfigFile = xstrdup(optarg);
253
254 break;
255
256 case 'h':
257 usage();
258
259 break;
260
261 case 'k':
262 if ((int) strlen(optarg) < 1)
263 usage();
264
265 if (!strncmp(optarg, "reconfigure", strlen(optarg)))
266 opt_send_signal = SIGHUP;
267 else if (!strncmp(optarg, "rotate", strlen(optarg)))
268 #ifdef _SQUID_LINUX_THREADS_
269
270 opt_send_signal = SIGQUIT;
271
272 #else
273
274 opt_send_signal = SIGUSR1;
275
276 #endif
277
278 else if (!strncmp(optarg, "debug", strlen(optarg)))
279 #ifdef _SQUID_LINUX_THREADS_
280
281 opt_send_signal = SIGTRAP;
282
283 #else
284
285 opt_send_signal = SIGUSR2;
286
287 #endif
288
289 else if (!strncmp(optarg, "shutdown", strlen(optarg)))
290 opt_send_signal = SIGTERM;
291 else if (!strncmp(optarg, "interrupt", strlen(optarg)))
292 opt_send_signal = SIGINT;
293 else if (!strncmp(optarg, "kill", strlen(optarg)))
294 opt_send_signal = SIGKILL;
295 else if (!strncmp(optarg, "check", strlen(optarg)))
296 opt_send_signal = 0; /* SIGNULL */
297 else if (!strncmp(optarg, "parse", strlen(optarg)))
298 opt_parse_cfg_only = 1; /* parse cfg file only */
299 else
300 usage();
301
302 break;
303
304 case 'm':
305 if (optarg) {
306 #if MALLOC_DBG
307 malloc_debug_level = atoi(optarg);
308 /* NOTREACHED */
309 break;
310 #else
311
312 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
313 /* NOTREACHED */
314 #endif
315
316 } else {
317 #if XMALLOC_TRACE
318 xmalloc_trace = !xmalloc_trace;
319 #else
320
321 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
322 #endif
323
324 }
325
326 #if USE_WIN32_SERVICE
327
328 case 'n':
329 xfree(WIN32_Service_name);
330
331 WIN32_Service_name = xstrdup(optarg);
332
333 opt_signal_service = TRUE;
334
335 break;
336
337 case 'r':
338 opt_remove_service = TRUE;
339
340 break;
341
342 #endif
343
344 case 'l':
345 opt_syslog_facility = xstrdup(optarg);
346
347 case 's':
348 #if HAVE_SYSLOG
349
350 _db_set_syslog(opt_syslog_facility);
351
352 break;
353
354 #else
355
356 fatal("Logging to syslog not available on this platform");
357
358 /* NOTREACHED */
359 #endif
360
361 case 'u':
362 icpPortNumOverride = atoi(optarg);
363
364 if (icpPortNumOverride < 0)
365 icpPortNumOverride = 0;
366
367 break;
368
369 case 'v':
370 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
371
372 #if USE_WIN32_SERVICE
373
374 printf("Compiled as Windows System Service.\n");
375
376 #endif
377
378 exit(0);
379
380 /* NOTREACHED */
381
382 case 'z':
383 opt_create_swap_dirs = 1;
384
385 break;
386
387 case '?':
388
389 default:
390 usage();
391
392 break;
393 }
394
395 }
396 }
397
398 /* ARGSUSED */
399 void
400 rotate_logs(int sig)
401 {
402 do_rotate = 1;
403 #ifndef _SQUID_MSWIN_
404 #if !HAVE_SIGACTION
405
406 signal(sig, rotate_logs);
407 #endif
408 #endif
409 }
410
411 /* ARGSUSED */
412 void
413 reconfigure(int sig)
414 {
415 do_reconfigure = 1;
416 #ifndef _SQUID_MSWIN_
417 #if !HAVE_SIGACTION
418
419 signal(sig, reconfigure);
420 #endif
421 #endif
422 }
423
424 void
425 shut_down(int sig)
426 {
427 do_shutdown = sig == SIGINT ? -1 : 1;
428 #ifndef _SQUID_MSWIN_
429 #ifdef KILL_PARENT_OPT
430
431 if (getppid() > 1) {
432 debugs(1, 1, "Killing RunCache, pid " << getppid());
433
434 if (kill(getppid(), sig) < 0)
435 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
436 }
437
438 #endif
439 #if SA_RESETHAND == 0
440 signal(SIGTERM, SIG_DFL);
441
442 signal(SIGINT, SIG_DFL);
443
444 #endif
445 #endif
446 }
447
448 static void
449 serverConnectionsOpen(void)
450 {
451 clientOpenListenSockets();
452 icpConnectionsOpen();
453 #if USE_HTCP
454
455 htcpInit();
456 #endif
457 #ifdef SQUID_SNMP
458
459 snmpConnectionOpen();
460 #endif
461 #if USE_WCCP
462
463 wccpConnectionOpen();
464 #endif
465
466 clientdbInit();
467 icmpOpen();
468 netdbInit();
469 asnInit();
470 ACL::Initialize();
471 peerSelectInit();
472 #if USE_CARP
473
474 carpInit();
475 #endif
476 }
477
478 void
479 serverConnectionsClose(void)
480 {
481 assert(shutting_down || reconfiguring);
482 clientHttpConnectionsClose();
483 icpConnectionShutdown();
484 #if USE_HTCP
485
486 htcpSocketShutdown();
487 #endif
488
489 icmpClose();
490 #ifdef SQUID_SNMP
491
492 snmpConnectionShutdown();
493 #endif
494 #if USE_WCCP
495
496 wccpConnectionShutdown();
497 #endif
498
499 asnFreeMemory();
500 }
501
502 static void
503 mainReconfigure(void)
504 {
505 debug(1, 1) ("Reconfiguring Squid Cache (version %s)...\n", version_string);
506 reconfiguring = 1;
507 /* Already called serverConnectionsClose and ipcacheShutdownServers() */
508 serverConnectionsClose();
509 icpConnectionClose();
510 #if USE_HTCP
511
512 htcpSocketClose();
513 #endif
514 #ifdef SQUID_SNMP
515
516 snmpConnectionClose();
517 #endif
518 #if USE_WCCP
519
520 wccpConnectionClose();
521 #endif
522 #if USE_DNSSERVERS
523
524 dnsShutdown();
525 #else
526
527 idnsShutdown();
528 #endif
529
530 redirectShutdown();
531 authenticateShutdown();
532 externalAclShutdown();
533 storeDirCloseSwapLogs();
534 storeLogClose();
535 accessLogClose();
536 useragentLogClose();
537 refererCloseLog();
538 errorClean();
539 enter_suid(); /* root to read config file */
540 parseConfigFile(ConfigFile);
541 setEffectiveUser();
542 _db_init(Config.Log.log, Config.debugOptions);
543 ipcache_restart(); /* clear stuck entries */
544 authenticateUserCacheRestart(); /* clear stuck ACL entries */
545 fqdncache_restart(); /* sigh, fqdncache too */
546 parseEtcHosts();
547 errorInitialize(); /* reload error pages */
548 accessLogInit();
549 storeLogOpen();
550 useragentOpenLog();
551 refererOpenLog();
552 #if USE_DNSSERVERS
553
554 dnsInit();
555 #else
556
557 idnsInit();
558 #endif
559
560 redirectInit();
561 authenticateInit(&Config.authConfiguration);
562 externalAclInit();
563 #if USE_WCCP
564
565 wccpInit();
566 #endif
567
568 serverConnectionsOpen();
569
570 if (theOutIcpConnection >= 0)
571 neighbors_init();
572
573 storeDirOpenSwapLogs();
574
575 mimeInit(Config.mimeTablePathname);
576
577 writePidFile(); /* write PID file */
578
579 debug(1, 1) ("Ready to serve requests.\n");
580
581 reconfiguring = 0;
582 }
583
584 static void
585 mainRotate(void)
586 {
587 icmpClose();
588 #if USE_DNSSERVERS
589
590 dnsShutdown();
591 #endif
592
593 redirectShutdown();
594 authenticateShutdown();
595 externalAclShutdown();
596 _db_rotate_log(); /* cache.log */
597 storeDirWriteCleanLogs(1);
598 storeLogRotate(); /* store.log */
599 accessLogRotate(); /* access.log */
600 useragentRotateLog(); /* useragent.log */
601 refererRotateLog(); /* referer.log */
602 #if WIP_FWD_LOG
603
604 fwdLogRotate();
605 #endif
606
607 icmpOpen();
608 #if USE_DNSSERVERS
609
610 dnsInit();
611 #endif
612
613 redirectInit();
614 authenticateInit(&Config.authConfiguration);
615 externalAclInit();
616 }
617
618 static void
619 setEffectiveUser(void)
620 {
621 leave_suid(); /* Run as non privilegied user */
622 #ifdef _SQUID_OS2_
623
624 return;
625 #endif
626
627 if (geteuid() == 0) {
628 debug(0, 0) ("Squid is not safe to run as root! If you must\n");
629 debug(0, 0) ("start Squid as root, then you must configure\n");
630 debug(0, 0) ("it to run as a non-priveledged user with the\n");
631 debug(0, 0) ("'cache_effective_user' option in the config file.\n");
632 fatal("Don't run Squid as root, set 'cache_effective_user'!");
633 }
634 }
635
636 static void
637 mainSetCwd(void)
638 {
639 char pathbuf[MAXPATHLEN];
640
641 if (Config.coredump_dir) {
642 if (0 == strcmp("none", Config.coredump_dir)) {
643 (void) 0;
644 } else if (chdir(Config.coredump_dir) == 0) {
645 debug(0, 1) ("Set Current Directory to %s\n", Config.coredump_dir);
646 return;
647 } else {
648 debug(50, 0) ("chdir: %s: %s\n", Config.coredump_dir, xstrerror());
649 }
650 }
651
652 /* If we don't have coredump_dir or couldn't cd there, report current dir */
653 if (getcwd(pathbuf, MAXPATHLEN)) {
654 debug(0, 1) ("Current Directory is %s\n", pathbuf);
655 } else {
656 debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
657 }
658 }
659
660 #if DELAY_POOLS
661 #include "DelayPools.h"
662 #endif
663
664 static void
665 mainInitialize(void)
666 {
667 /* chroot if configured to run inside chroot */
668
669 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
670 fatal("failed to chroot");
671 }
672
673 if (opt_catch_signals) {
674 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
675 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
676 }
677
678 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
679 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
680
681 setEffectiveUser();
682
683 if (icpPortNumOverride != 1)
684 Config.Port.icp = (u_short) icpPortNumOverride;
685
686 _db_init(Config.Log.log, Config.debugOptions);
687
688 fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
689
690 #if MEM_GEN_TRACE
691
692 log_trace_init("/tmp/squid.alloc");
693
694 #endif
695
696 debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
697 version_string,
698 CONFIG_HOST_TYPE);
699
700 #ifdef _SQUID_WIN32_
701
702 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
703 debug(1, 0) ("Running as %s Windows System Service on %s\n", WIN32_Service_name, WIN32_OS_string);
704 debug(1, 0) ("Service command line is: %s\n", WIN32_Service_Command_Line);
705 } else
706 debug(1, 0) ("Running on %s\n",WIN32_OS_string);
707
708 #endif
709
710 debugs(1, 1, "Process ID " << getpid());
711
712 debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);
713
714 #ifdef _SQUID_MSWIN_
715
716 debug(1, 1) ("With %d CRT stdio descriptors available\n", _getmaxstdio());
717
718 if (WIN32_Socks_initialized)
719 debug(1, 1)("Windows sockets initialized\n");
720
721 #endif
722
723 if (!configured_once)
724 disk_init(); /* disk_init must go before ipcache_init() */
725
726 ipcache_init();
727
728 fqdncache_init();
729
730 parseEtcHosts();
731
732 #if USE_DNSSERVERS
733
734 dnsInit();
735
736 #else
737
738 idnsInit();
739
740 #endif
741
742 redirectInit();
743
744 authenticateInit(&Config.authConfiguration);
745
746 externalAclInit();
747
748 useragentOpenLog();
749
750 refererOpenLog();
751
752 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
753
754 httpReplyInitModule(); /* must go before accepting replies */
755
756 errorInitialize();
757
758 accessLogInit();
759
760 #if USE_IDENT
761
762 identInit();
763
764 #endif
765 #ifdef SQUID_SNMP
766
767 snmpInit();
768
769 #endif
770 #if MALLOC_DBG
771
772 malloc_debug(0, malloc_debug_level);
773
774 #endif
775
776 if (!configured_once) {
777 #if USE_UNLINKD
778 unlinkdInit();
779 #endif
780
781 urlInitialize();
782 cachemgrInit();
783 statInit();
784 storeInit();
785 mainSetCwd();
786 /* after this point we want to see the mallinfo() output */
787 do_mallinfo = 1;
788 mimeInit(Config.mimeTablePathname);
789 pconnInit();
790 refreshInit();
791 #if DELAY_POOLS
792
793 DelayPools::Init();
794 #endif
795
796 fwdInit();
797 }
798
799 #if USE_WCCP
800 wccpInit();
801
802 #endif
803
804 serverConnectionsOpen();
805
806 if (theOutIcpConnection >= 0)
807 neighbors_init();
808
809 if (Config.chroot_dir)
810 no_suid();
811
812 if (!configured_once)
813 writePidFile(); /* write PID file */
814
815 #ifdef _SQUID_LINUX_THREADS_
816
817 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
818
819 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
820
821 #else
822
823 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
824
825 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
826
827 #endif
828
829 squid_signal(SIGHUP, reconfigure, SA_RESTART);
830
831 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
832
833 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
834
835 memCheckInit();
836
837 debug(1, 1) ("Ready to serve requests.\n");
838
839 if (!configured_once) {
840 eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
841
842 if (Config.onoff.announce)
843 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
844
845 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
846
847 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
848
849 #if USE_XPROF_STATS
850
851 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
852
853 #endif
854
855 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
856
857 eventAdd("commCheckHalfClosed", commCheckHalfClosed, NULL, 1.0, false);
858 }
859
860 configured_once = 1;
861 }
862
863 #if USE_WIN32_SERVICE
864 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
865 extern "C" void WINAPI
866 SquidMain(int argc, char **argv)
867 #else
868 int
869 main(int argc, char **argv)
870 #endif
871 {
872 int errcount = 0;
873 mode_t oldmask;
874
875 #if HAVE_SBRK
876
877 sbrk_start = sbrk(0);
878 #endif
879
880 Debug::parseOptions("ALL,1");
881 debug_log = stderr;
882
883 if (FD_SETSIZE < Squid_MaxFD)
884 Squid_MaxFD = FD_SETSIZE;
885
886 #ifdef _SQUID_WIN32_
887 #ifdef USE_WIN32_SERVICE
888
889 if (WIN32_Subsystem_Init(&argc, &argv))
890 return;
891
892 #else
893
894 {
895 int WIN32_init_err;
896
897 if ((WIN32_init_err = WIN32_Subsystem_Init()))
898 return WIN32_init_err;
899 }
900 #endif
901
902 #endif
903
904 /* call mallopt() before anything else */
905 #if HAVE_MALLOPT
906 #ifdef M_GRAIN
907 /* Round up all sizes to a multiple of this */
908 mallopt(M_GRAIN, 16);
909
910 #endif
911 #ifdef M_MXFAST
912 /* biggest size that is considered a small block */
913 mallopt(M_MXFAST, 256);
914
915 #endif
916 #ifdef M_NBLKS
917 /* allocate this many small blocks at once */
918 mallopt(M_NLBLKS, 32);
919
920 #endif
921 #endif /* HAVE_MALLOPT */
922
923 /*
924 * The plan here is to set the umask to 007 (deny others for
925 * read,write,execute), but only if the umask is not already
926 * set. Unfortunately, there is no way to get the current
927 * umask value without setting it.
928 */
929 oldmask = umask(S_IRWXO);
930
931 if (oldmask)
932 umask(oldmask);
933
934 memset(&local_addr, '\0', sizeof(struct IN_ADDR));
935
936 safe_inet_addr(localhost, &local_addr);
937
938 memset(&any_addr, '\0', sizeof(struct IN_ADDR));
939
940 safe_inet_addr("0.0.0.0", &any_addr);
941
942 memset(&no_addr, '\0', sizeof(struct IN_ADDR));
943
944 safe_inet_addr("255.255.255.255", &no_addr);
945
946 squid_srandom(time(NULL));
947
948 getCurrentTime();
949
950 squid_start = current_time;
951
952 failure_notify = fatal_dump;
953
954 #if USE_WIN32_SERVICE
955
956 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
957
958 #endif
959
960 mainParseOptions(argc, argv);
961
962 #if USE_WIN32_SERVICE
963
964 if (opt_install_service) {
965 WIN32_InstallService();
966 return;
967 }
968
969 if (opt_remove_service) {
970 WIN32_RemoveService();
971 return;
972 }
973
974 if (opt_command_line) {
975 WIN32_SetServiceCommandLine();
976 return;
977 }
978
979 #endif
980
981 /* parse configuration file
982 * note: in "normal" case this used to be called from mainInitialize() */
983 {
984 int parse_err;
985
986 if (!ConfigFile)
987 ConfigFile = xstrdup(DefaultConfigFile);
988
989 assert(!configured_once);
990
991 #if USE_LEAKFINDER
992
993 leakInit();
994
995 #endif
996
997 Mem::Init();
998
999 cbdataInit();
1000
1001 eventInit(); /* eventInit() is required for config parsing */
1002
1003 storeFsInit(); /* required for config parsing */
1004
1005 /* May not be needed for parsing, have not audited for such */
1006 DiskIOModule::SetupAllModules();
1007
1008 /* Shouldn't be needed for config parsing, but have not audited for such */
1009 StoreFileSystem::SetupAllFs();
1010
1011 /* we may want the parsing process to set this up in the future */
1012 Store::Root(new StoreController);
1013
1014 parse_err = parseConfigFile(ConfigFile);
1015
1016 if (opt_parse_cfg_only)
1017 #if USE_WIN32_SERVICE
1018
1019 return;
1020
1021 #else
1022
1023 return parse_err;
1024
1025 #endif
1026
1027 }
1028 if (-1 == opt_send_signal)
1029 if (checkRunningPid())
1030 exit(1);
1031
1032 #if TEST_ACCESS
1033
1034 comm_init();
1035
1036 comm_select_init();
1037
1038 mainInitialize();
1039
1040 test_access();
1041
1042 return 0;
1043
1044 #endif
1045
1046 /* send signal to running copy and exit */
1047 if (opt_send_signal != -1) {
1048 /* chroot if configured to run inside chroot */
1049
1050 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
1051 fatal("failed to chroot");
1052 }
1053
1054 sendSignal();
1055 /* NOTREACHED */
1056 }
1057
1058 if (opt_create_swap_dirs) {
1059 /* chroot if configured to run inside chroot */
1060
1061 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
1062 fatal("failed to chroot");
1063 }
1064
1065 setEffectiveUser();
1066 debug(0, 0) ("Creating Swap Directories\n");
1067 Store::Root().create();
1068 #if USE_WIN32_SERVICE
1069
1070 return;
1071 #else
1072
1073 return 0;
1074 #endif
1075
1076 }
1077
1078 if (!opt_no_daemon)
1079 watch_child(argv);
1080
1081 setMaxFD();
1082
1083 /* init comm module */
1084 comm_init();
1085
1086 comm_select_init();
1087
1088 if (opt_no_daemon) {
1089 /* we have to init fdstat here. */
1090 fd_open(0, FD_LOG, "stdin");
1091 fd_open(1, FD_LOG, "stdout");
1092 fd_open(2, FD_LOG, "stderr");
1093 }
1094
1095 #if USE_WIN32_SERVICE
1096
1097 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
1098
1099 #endif
1100
1101 mainInitialize();
1102
1103 #if USE_WIN32_SERVICE
1104
1105 WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
1106
1107 #endif
1108
1109 /* main loop */
1110
1111 for (;;) {
1112 if (do_reconfigure) {
1113 mainReconfigure();
1114 do_reconfigure = 0;
1115 #if defined(_SQUID_MSWIN_) && defined(_DEBUG)
1116
1117 } else if (do_debug_trap) {
1118 do_debug_trap = 0;
1119 __asm int 3;
1120 #endif
1121
1122 } else if (do_rotate) {
1123 mainRotate();
1124 do_rotate = 0;
1125 } else if (do_shutdown) {
1126 time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
1127 debug(1, 1) ("Preparing for shutdown after %d requests\n",
1128 statCounter.client_http.requests);
1129 debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
1130 (int) wait);
1131 do_shutdown = 0;
1132 shutting_down = 1;
1133 #if USE_WIN32_SERVICE
1134
1135 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
1136 #endif
1137
1138 serverConnectionsClose();
1139 eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
1140 }
1141
1142 eventRun();
1143 int loop_delay = eventNextTime();
1144
1145 if (loop_delay < 0)
1146 loop_delay = 0;
1147
1148 /* Attempt any pending storedir IO */
1149 Store::Root().callback();
1150
1151 comm_calliocallback();
1152
1153 /* and again to deal with indirectly queued events
1154 * resulting from the first call. These are usually
1155 * callbacks and should be dealt with immediately.
1156 */
1157 if (comm_iocallbackpending())
1158 comm_calliocallback();
1159
1160 switch (comm_select(loop_delay)) {
1161
1162 case COMM_OK:
1163 errcount = 0; /* reset if successful */
1164 break;
1165
1166 case COMM_ERROR:
1167 errcount++;
1168 debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
1169
1170 if (errcount == 10)
1171 fatal_dump("Select Loop failed!");
1172
1173 break;
1174
1175 case COMM_TIMEOUT:
1176 break;
1177
1178 case COMM_SHUTDOWN:
1179 SquidShutdown(NULL);
1180
1181 break;
1182
1183 default:
1184 fatal_dump("MAIN: Internal error -- this should never happen.");
1185
1186 break;
1187 }
1188 }
1189
1190 /* NOTREACHED */
1191 #if USE_WIN32_SERVICE
1192 return;
1193
1194 #else
1195
1196 return 0;
1197
1198 #endif
1199 }
1200
1201 static void
1202 sendSignal(void)
1203 {
1204 pid_t pid;
1205 debug_log = stderr;
1206
1207 if (strcmp(Config.pidFilename, "none") == 0) {
1208 debug(0, 1) ("No pid_filename specified. Trusting you know what you are doing.\n");
1209 }
1210
1211 pid = readPidFile();
1212
1213 if (pid > 1) {
1214 #if USE_WIN32_SERVICE
1215
1216 if (opt_signal_service) {
1217 WIN32_sendSignal(opt_send_signal);
1218 exit(0);
1219 } else
1220 #ifdef _SQUID_MSWIN_
1221 {
1222 fprintf(stderr, "%s: ERROR: Could not send ", appname);
1223 fprintf(stderr, "signal to Squid Service:\n");
1224 fprintf(stderr, "missing -n command line switch.\n");
1225 exit(1);
1226 }
1227
1228 /* NOTREACHED */
1229 #endif
1230
1231 #endif
1232
1233 if (kill(pid, opt_send_signal) &&
1234 /* ignore permissions if just running check */
1235 !(opt_send_signal == 0 && errno == EPERM)) {
1236 fprintf(stderr, "%s: ERROR: Could not send ", appname);
1237 fprintf(stderr, "signal %d to process %d: %s\n",
1238 opt_send_signal, (int) pid, xstrerror());
1239 exit(1);
1240 }
1241 } else {
1242 fprintf(stderr, "%s: ERROR: No running copy\n", appname);
1243 exit(1);
1244 }
1245
1246 /* signal successfully sent */
1247 exit(0);
1248 }
1249
1250 #ifndef _SQUID_MSWIN_
1251 /*
1252 * This function is run when Squid is in daemon mode, just
1253 * before the parent forks and starts up the child process.
1254 * It can be used for admin-specific tasks, such as notifying
1255 * someone that Squid is (re)started.
1256 */
1257 static void
1258 mainStartScript(const char *prog)
1259 {
1260 char script[SQUID_MAXPATHLEN];
1261 char *t;
1262 size_t sl = 0;
1263 pid_t cpid;
1264 pid_t rpid;
1265 xstrncpy(script, prog, MAXPATHLEN);
1266
1267 if ((t = strrchr(script, '/'))) {
1268 *(++t) = '\0';
1269 sl = strlen(script);
1270 }
1271
1272 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
1273
1274 if ((cpid = fork()) == 0) {
1275 /* child */
1276 execl(script, squid_start_script, NULL);
1277 _exit(-1);
1278 } else {
1279 do {
1280 #ifdef _SQUID_NEXT_
1281 union wait status;
1282 rpid = wait3(&status, 0, NULL);
1283 #else
1284
1285 int status;
1286 rpid = waitpid(-1, &status, 0);
1287 #endif
1288
1289 } while (rpid != cpid);
1290 }
1291 }
1292
1293 #endif /* _SQUID_MSWIN_ */
1294
1295 static int
1296 checkRunningPid(void)
1297 {
1298 pid_t pid;
1299
1300 if (!debug_log)
1301 debug_log = stderr;
1302
1303 pid = readPidFile();
1304
1305 if (pid < 2)
1306 return 0;
1307
1308 if (kill(pid, 0) < 0)
1309 return 0;
1310
1311 debugs(0, 0, "Squid is already running! Process ID " << pid);
1312
1313 return 1;
1314 }
1315
1316 static void
1317 watch_child(char *argv[])
1318 {
1319 #ifndef _SQUID_MSWIN_
1320 char *prog;
1321 int failcount = 0;
1322 time_t start;
1323 time_t stop;
1324 #ifdef _SQUID_NEXT_
1325
1326 union wait status;
1327 #else
1328
1329 int status;
1330 #endif
1331
1332 pid_t pid;
1333 #ifdef TIOCNOTTY
1334
1335 int i;
1336 #endif
1337
1338 int nullfd;
1339
1340 if (*(argv[0]) == '(')
1341 return;
1342
1343 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1344
1345 if ((pid = fork()) < 0)
1346 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
1347 else if (pid > 0)
1348 exit(0);
1349
1350 if (setsid() < 0)
1351 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
1352
1353 closelog();
1354
1355 #ifdef TIOCNOTTY
1356
1357 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
1358 ioctl(i, TIOCNOTTY, NULL);
1359 close(i);
1360 }
1361
1362 #endif
1363
1364
1365 /*
1366 * RBCOLLINS - if cygwin stackdumps when squid is run without
1367 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1368 * 1.1.3. execvp had a bit overflow error in a loop..
1369 */
1370 /* Connect stdio to /dev/null in daemon mode */
1371 nullfd = open("/dev/null", O_RDWR | O_TEXT);
1372
1373 if (nullfd < 0)
1374 fatalf("/dev/null: %s\n", xstrerror());
1375
1376 dup2(nullfd, 0);
1377
1378 if (opt_debug_stderr < 0) {
1379 dup2(nullfd, 1);
1380 dup2(nullfd, 2);
1381 }
1382
1383 for (;;) {
1384 mainStartScript(argv[0]);
1385
1386 if ((pid = fork()) == 0) {
1387 /* child */
1388 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1389 prog = xstrdup(argv[0]);
1390 argv[0] = xstrdup("(squid)");
1391 execvp(prog, argv);
1392 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
1393 }
1394
1395 /* parent */
1396 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1397
1398 syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
1399
1400 time(&start);
1401
1402 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
1403
1404 #ifdef _SQUID_NEXT_
1405
1406 pid = wait3(&status, 0, NULL);
1407
1408 #else
1409
1410 pid = waitpid(-1, &status, 0);
1411
1412 #endif
1413
1414 time(&stop);
1415
1416 if (WIFEXITED(status)) {
1417 syslog(LOG_NOTICE,
1418 "Squid Parent: child process %d exited with status %d",
1419 pid, WEXITSTATUS(status));
1420 } else if (WIFSIGNALED(status)) {
1421 syslog(LOG_NOTICE,
1422 "Squid Parent: child process %d exited due to signal %d",
1423 pid, WTERMSIG(status));
1424 } else {
1425 syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
1426 }
1427
1428 if (stop - start < 10)
1429 failcount++;
1430 else
1431 failcount = 0;
1432
1433 if (failcount == 5) {
1434 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
1435 exit(1);
1436 }
1437
1438 if (WIFEXITED(status))
1439 if (WEXITSTATUS(status) == 0)
1440 exit(0);
1441
1442 if (WIFSIGNALED(status)) {
1443 switch (WTERMSIG(status)) {
1444
1445 case SIGKILL:
1446 exit(0);
1447 break;
1448
1449 default:
1450 break;
1451 }
1452 }
1453
1454 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
1455 sleep(3);
1456 }
1457
1458 /* NOTREACHED */
1459 #endif /* _SQUID_MSWIN_ */
1460 }
1461
1462 static void
1463 SquidShutdown(void *unused)
1464 {
1465 #if USE_WIN32_SERVICE
1466 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1467 #endif
1468
1469 debug(1, 1) ("Shutting down...\n");
1470 #if USE_DNSSERVERS
1471
1472 dnsShutdown();
1473 #else
1474
1475 idnsShutdown();
1476 #endif
1477
1478 redirectShutdown();
1479 externalAclShutdown();
1480 icpConnectionClose();
1481 #if USE_HTCP
1482
1483 htcpSocketClose();
1484 #endif
1485 #ifdef SQUID_SNMP
1486
1487 snmpConnectionClose();
1488 #endif
1489 #if USE_WCCP
1490
1491 wccpConnectionClose();
1492 #endif
1493
1494 releaseServerSockets();
1495 commCloseAllSockets();
1496 #if DELAY_POOLS
1497
1498 DelayPools::FreePools();
1499 #endif
1500
1501 authenticateShutdown();
1502 #if USE_UNLINKD
1503
1504 unlinkdClose();
1505 #endif
1506 #if USE_WIN32_SERVICE
1507
1508 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1509 #endif
1510
1511 Store::Root().sync(); /* Flush pending object writes/unlinks */
1512 storeDirWriteCleanLogs(0);
1513 PrintRusage();
1514 dumpMallocStats();
1515 Store::Root().sync(); /* Flush log writes */
1516 storeLogClose();
1517 accessLogClose();
1518 useragentLogClose();
1519 refererCloseLog();
1520 #if WIP_FWD_LOG
1521
1522 fwdUninit();
1523 #endif
1524
1525 Store::Root().sync(); /* Flush log close */
1526 StoreFileSystem::FreeAllFs();
1527 DiskIOModule::FreeAllModules();
1528 #if PURIFY || XMALLOC_TRACE
1529
1530 configFreeMemory();
1531 storeFreeMemory();
1532 /*stmemFreeMemory(); */
1533 netdbFreeMemory();
1534 ipcacheFreeMemory();
1535 fqdncacheFreeMemory();
1536 asnFreeMemory();
1537 clientdbFreeMemory();
1538 httpHeaderCleanModule();
1539 statFreeMemory();
1540 eventFreeMemory();
1541 mimeFreeMemory();
1542 errorClean();
1543 #endif
1544 #if !XMALLOC_TRACE
1545
1546 if (opt_no_daemon) {
1547 file_close(0);
1548 file_close(1);
1549 file_close(2);
1550 }
1551
1552 #endif
1553 fdDumpOpen();
1554
1555 fdFreeMemory();
1556
1557 memClean();
1558
1559 #if XMALLOC_TRACE
1560
1561 xmalloc_find_leaks();
1562
1563 debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
1564
1565 #endif
1566 #if MEM_GEN_TRACE
1567
1568 log_trace_done();
1569
1570 #endif
1571
1572 if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
1573 enter_suid();
1574 safeunlink(Config.pidFilename, 0);
1575 leave_suid();
1576 }
1577
1578 debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
1579 version_string);
1580
1581 if (debug_log)
1582 fclose(debug_log);
1583
1584 exit(0);
1585 }