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