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