]> git.ipfire.org Git - thirdparty/squid.git/blob - src/main.cc
Cleanup of Windows service code.
[thirdparty/squid.git] / src / main.cc
1
2 /*
3 * $Id: main.cc,v 1.418 2006/04/29 13:53:16 serassio 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 #include "forward.h"
51
52 #if USE_WIN32_SERVICE
53
54 #include "squid_windows.h"
55 #include <process.h>
56
57 static int opt_install_service = FALSE;
58 static int opt_remove_service = FALSE;
59 static int opt_signal_service = FALSE;
60 static int opt_command_line = FALSE;
61 extern void WIN32_svcstatusupdate(DWORD, DWORD);
62 void WINAPI WIN32_svcHandler(DWORD);
63
64 #endif
65
66 /* for error reporting from xmalloc and friends */
67 SQUIDCEXTERN void (*failure_notify) (const char *);
68
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_debug_stderr = 1;
384
385 opt_create_swap_dirs = 1;
386
387 break;
388
389 case '?':
390
391 default:
392 usage();
393
394 break;
395 }
396
397 }
398 }
399
400 /* ARGSUSED */
401 void
402 rotate_logs(int sig)
403 {
404 do_rotate = 1;
405 #ifndef _SQUID_MSWIN_
406 #if !HAVE_SIGACTION
407
408 signal(sig, rotate_logs);
409 #endif
410 #endif
411 }
412
413 /* ARGSUSED */
414 void
415 reconfigure(int sig)
416 {
417 do_reconfigure = 1;
418 #ifndef _SQUID_MSWIN_
419 #if !HAVE_SIGACTION
420
421 signal(sig, reconfigure);
422 #endif
423 #endif
424 }
425
426 void
427 shut_down(int sig)
428 {
429 do_shutdown = sig == SIGINT ? -1 : 1;
430 #ifndef _SQUID_MSWIN_
431 #ifdef KILL_PARENT_OPT
432
433 if (getppid() > 1) {
434 debugs(1, 1, "Killing RunCache, pid " << getppid());
435
436 if (kill(getppid(), sig) < 0)
437 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
438 }
439
440 #endif
441 #if SA_RESETHAND == 0
442 signal(SIGTERM, SIG_DFL);
443
444 signal(SIGINT, SIG_DFL);
445
446 #endif
447 #endif
448 }
449
450 static void
451 serverConnectionsOpen(void)
452 {
453 clientOpenListenSockets();
454 icpConnectionsOpen();
455 #if USE_HTCP
456
457 htcpInit();
458 #endif
459 #ifdef SQUID_SNMP
460
461 snmpConnectionOpen();
462 #endif
463 #if USE_WCCP
464
465 wccpConnectionOpen();
466 #endif
467
468 clientdbInit();
469 icmpOpen();
470 netdbInit();
471 asnInit();
472 ACL::Initialize();
473 peerSelectInit();
474 #if USE_CARP
475
476 carpInit();
477 #endif
478 }
479
480 void
481 serverConnectionsClose(void)
482 {
483 assert(shutting_down || reconfiguring);
484 clientHttpConnectionsClose();
485 icpConnectionShutdown();
486 #if USE_HTCP
487
488 htcpSocketShutdown();
489 #endif
490
491 icmpClose();
492 #ifdef SQUID_SNMP
493
494 snmpConnectionShutdown();
495 #endif
496 #if USE_WCCP
497
498 wccpConnectionShutdown();
499 #endif
500
501 asnFreeMemory();
502 }
503
504 static void
505 mainReconfigure(void)
506 {
507 debug(1, 1) ("Reconfiguring Squid Cache (version %s)...\n", version_string);
508 reconfiguring = 1;
509 /* Already called serverConnectionsClose and ipcacheShutdownServers() */
510 serverConnectionsClose();
511 icpConnectionClose();
512 #if USE_HTCP
513
514 htcpSocketClose();
515 #endif
516 #ifdef SQUID_SNMP
517
518 snmpConnectionClose();
519 #endif
520 #if USE_WCCP
521
522 wccpConnectionClose();
523 #endif
524 #if USE_DNSSERVERS
525
526 dnsShutdown();
527 #else
528
529 idnsShutdown();
530 #endif
531
532 redirectShutdown();
533 authenticateShutdown();
534 externalAclShutdown();
535 storeDirCloseSwapLogs();
536 storeLogClose();
537 accessLogClose();
538 useragentLogClose();
539 refererCloseLog();
540 errorClean();
541 enter_suid(); /* root to read config file */
542 parseConfigFile(ConfigFile);
543 setEffectiveUser();
544 _db_init(Config.Log.log, Config.debugOptions);
545 ipcache_restart(); /* clear stuck entries */
546 authenticateUserCacheRestart(); /* clear stuck ACL entries */
547 fqdncache_restart(); /* sigh, fqdncache too */
548 parseEtcHosts();
549 errorInitialize(); /* reload error pages */
550 accessLogInit();
551 storeLogOpen();
552 useragentOpenLog();
553 refererOpenLog();
554 #if USE_DNSSERVERS
555
556 dnsInit();
557 #else
558
559 idnsInit();
560 #endif
561
562 redirectInit();
563 authenticateInit(&Config.authConfiguration);
564 externalAclInit();
565 #if USE_WCCP
566
567 wccpInit();
568 #endif
569
570 serverConnectionsOpen();
571
572 if (theOutIcpConnection >= 0)
573 neighbors_init();
574
575 storeDirOpenSwapLogs();
576
577 mimeInit(Config.mimeTablePathname);
578
579 writePidFile(); /* write PID file */
580
581 debug(1, 1) ("Ready to serve requests.\n");
582
583 reconfiguring = 0;
584 }
585
586 static void
587 mainRotate(void)
588 {
589 icmpClose();
590 #if USE_DNSSERVERS
591
592 dnsShutdown();
593 #endif
594
595 redirectShutdown();
596 authenticateShutdown();
597 externalAclShutdown();
598 _db_rotate_log(); /* cache.log */
599 storeDirWriteCleanLogs(1);
600 storeLogRotate(); /* store.log */
601 accessLogRotate(); /* access.log */
602 useragentRotateLog(); /* useragent.log */
603 refererRotateLog(); /* referer.log */
604 #if WIP_FWD_LOG
605
606 fwdLogRotate();
607 #endif
608
609 icmpOpen();
610 #if USE_DNSSERVERS
611
612 dnsInit();
613 #endif
614
615 redirectInit();
616 authenticateInit(&Config.authConfiguration);
617 externalAclInit();
618 }
619
620 static void
621 setEffectiveUser(void)
622 {
623 leave_suid(); /* Run as non privilegied user */
624 #ifdef _SQUID_OS2_
625
626 return;
627 #endif
628
629 if (geteuid() == 0) {
630 debug(0, 0) ("Squid is not safe to run as root! If you must\n");
631 debug(0, 0) ("start Squid as root, then you must configure\n");
632 debug(0, 0) ("it to run as a non-priveledged user with the\n");
633 debug(0, 0) ("'cache_effective_user' option in the config file.\n");
634 fatal("Don't run Squid as root, set 'cache_effective_user'!");
635 }
636 }
637
638 static void
639 mainSetCwd(void)
640 {
641 char pathbuf[MAXPATHLEN];
642
643 if (Config.coredump_dir) {
644 if (0 == strcmp("none", Config.coredump_dir)) {
645 (void) 0;
646 } else if (chdir(Config.coredump_dir) == 0) {
647 debug(0, 1) ("Set Current Directory to %s\n", Config.coredump_dir);
648 return;
649 } else {
650 debug(50, 0) ("chdir: %s: %s\n", Config.coredump_dir, xstrerror());
651 }
652 }
653
654 /* If we don't have coredump_dir or couldn't cd there, report current dir */
655 if (getcwd(pathbuf, MAXPATHLEN)) {
656 debug(0, 1) ("Current Directory is %s\n", pathbuf);
657 } else {
658 debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
659 }
660 }
661
662 #if DELAY_POOLS
663 #include "DelayPools.h"
664 #endif
665
666 static void
667 mainInitialize(void)
668 {
669 /* chroot if configured to run inside chroot */
670
671 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
672 fatal("failed to chroot");
673 }
674
675 if (opt_catch_signals) {
676 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
677 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
678 }
679
680 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
681 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
682
683 setEffectiveUser();
684
685 if (icpPortNumOverride != 1)
686 Config.Port.icp = (u_short) icpPortNumOverride;
687
688 _db_init(Config.Log.log, Config.debugOptions);
689
690 fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
691
692 #if MEM_GEN_TRACE
693
694 log_trace_init("/tmp/squid.alloc");
695
696 #endif
697
698 debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
699 version_string,
700 CONFIG_HOST_TYPE);
701
702 #ifdef _SQUID_WIN32_
703
704 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
705 debug(1, 0) ("Running as %s Windows System Service on %s\n", WIN32_Service_name, WIN32_OS_string);
706 debug(1, 0) ("Service command line is: %s\n", WIN32_Service_Command_Line);
707 } else
708 debug(1, 0) ("Running on %s\n",WIN32_OS_string);
709
710 #endif
711
712 debugs(1, 1, "Process ID " << getpid());
713
714 debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);
715
716 #ifdef _SQUID_MSWIN_
717
718 debug(1, 1) ("With %d CRT stdio descriptors available\n", _getmaxstdio());
719
720 if (WIN32_Socks_initialized)
721 debug(1, 1)("Windows sockets initialized\n");
722
723 #endif
724
725 if (!configured_once)
726 disk_init(); /* disk_init must go before ipcache_init() */
727
728 ipcache_init();
729
730 fqdncache_init();
731
732 parseEtcHosts();
733
734 #if USE_DNSSERVERS
735
736 dnsInit();
737
738 #else
739
740 idnsInit();
741
742 #endif
743
744 redirectInit();
745
746 authenticateInit(&Config.authConfiguration);
747
748 externalAclInit();
749
750 useragentOpenLog();
751
752 refererOpenLog();
753
754 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
755
756 httpReplyInitModule(); /* must go before accepting replies */
757
758 errorInitialize();
759
760 accessLogInit();
761
762 #if USE_IDENT
763
764 identInit();
765
766 #endif
767 #ifdef SQUID_SNMP
768
769 snmpInit();
770
771 #endif
772 #if MALLOC_DBG
773
774 malloc_debug(0, malloc_debug_level);
775
776 #endif
777
778 if (!configured_once) {
779 #if USE_UNLINKD
780 unlinkdInit();
781 #endif
782
783 urlInitialize();
784 cachemgrInit();
785 statInit();
786 storeInit();
787 mainSetCwd();
788 /* after this point we want to see the mallinfo() output */
789 do_mallinfo = 1;
790 mimeInit(Config.mimeTablePathname);
791 refreshInit();
792 #if DELAY_POOLS
793
794 DelayPools::Init();
795 #endif
796
797 FwdState::initModule();
798 }
799
800 #if USE_WCCP
801 wccpInit();
802
803 #endif
804
805 serverConnectionsOpen();
806
807 if (theOutIcpConnection >= 0)
808 neighbors_init();
809
810 if (Config.chroot_dir)
811 no_suid();
812
813 if (!configured_once)
814 writePidFile(); /* write PID file */
815
816 #ifdef _SQUID_LINUX_THREADS_
817
818 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
819
820 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
821
822 #else
823
824 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
825
826 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
827
828 #endif
829
830 squid_signal(SIGHUP, reconfigure, SA_RESTART);
831
832 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
833
834 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
835
836 memCheckInit();
837
838 debug(1, 1) ("Ready to serve requests.\n");
839
840 if (!configured_once) {
841 eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
842
843 if (Config.onoff.announce)
844 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
845
846 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
847
848 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
849
850 #if USE_XPROF_STATS
851
852 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
853
854 #endif
855
856 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
857
858 eventAdd("commCheckHalfClosed", commCheckHalfClosed, NULL, 1.0, false);
859 }
860
861 configured_once = 1;
862 }
863
864 #if USE_WIN32_SERVICE
865 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
866 extern "C" void WINAPI
867 SquidWinSvcMain(int argc, char **argv)
868 {
869 SquidMain(argc, argv);
870 }
871
872 int
873 SquidMain(int argc, char **argv)
874 #else
875 int
876 main(int argc, char **argv)
877 #endif
878 {
879 int errcount = 0;
880 mode_t oldmask;
881 #ifdef _SQUID_WIN32_
882
883 int WIN32_init_err;
884 #endif
885
886 #if HAVE_SBRK
887
888 sbrk_start = sbrk(0);
889 #endif
890
891 Debug::parseOptions("ALL,1");
892 debug_log = stderr;
893
894 if (FD_SETSIZE < Squid_MaxFD)
895 Squid_MaxFD = FD_SETSIZE;
896
897 #ifdef _SQUID_WIN32_
898
899 if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
900 return WIN32_init_err;
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 {
966 WIN32_InstallService();
967 return 0;
968 }
969
970 if (opt_remove_service)
971 {
972 WIN32_RemoveService();
973 return 0;
974 }
975
976 if (opt_command_line)
977 {
978 WIN32_SetServiceCommandLine();
979 return 0;
980 }
981
982 #endif
983
984 /* parse configuration file
985 * note: in "normal" case this used to be called from mainInitialize() */
986 {
987 int parse_err;
988
989 if (!ConfigFile)
990 ConfigFile = xstrdup(DefaultConfigFile);
991
992 assert(!configured_once);
993
994 Mem::Init();
995
996 cbdataInit();
997
998 eventInit(); /* eventInit() is required for config parsing */
999
1000 storeFsInit(); /* required for config parsing */
1001
1002 /* May not be needed for parsing, have not audited for such */
1003 DiskIOModule::SetupAllModules();
1004
1005 /* Shouldn't be needed for config parsing, but have not audited for such */
1006 StoreFileSystem::SetupAllFs();
1007
1008 /* we may want the parsing process to set this up in the future */
1009 Store::Root(new StoreController);
1010
1011 parse_err = parseConfigFile(ConfigFile);
1012
1013 if (opt_parse_cfg_only)
1014
1015 return parse_err;
1016 }
1017 if (-1 == opt_send_signal)
1018 if (checkRunningPid())
1019 exit(1);
1020
1021 #if TEST_ACCESS
1022
1023 comm_init();
1024
1025 comm_select_init();
1026
1027 mainInitialize();
1028
1029 test_access();
1030
1031 return 0;
1032
1033 #endif
1034
1035 /* send signal to running copy and exit */
1036 if (opt_send_signal != -1)
1037 {
1038 /* chroot if configured to run inside chroot */
1039
1040 if (Config.chroot_dir) {
1041 if (chroot(Config.chroot_dir))
1042 fatal("failed to chroot");
1043
1044 no_suid();
1045 } else {
1046 leave_suid();
1047 }
1048
1049 sendSignal();
1050 /* NOTREACHED */
1051 }
1052
1053 if (opt_create_swap_dirs)
1054 {
1055 /* chroot if configured to run inside chroot */
1056
1057 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
1058 fatal("failed to chroot");
1059 }
1060
1061 setEffectiveUser();
1062 debug(0, 0) ("Creating Swap Directories\n");
1063 Store::Root().create();
1064
1065 return 0;
1066 }
1067
1068 if (!opt_no_daemon)
1069 watch_child(argv);
1070
1071 setMaxFD();
1072
1073 /* init comm module */
1074 comm_init();
1075
1076 comm_select_init();
1077
1078 if (opt_no_daemon)
1079 {
1080 /* we have to init fdstat here. */
1081 fd_open(0, FD_LOG, "stdin");
1082 fd_open(1, FD_LOG, "stdout");
1083 fd_open(2, FD_LOG, "stderr");
1084 }
1085
1086 #if USE_WIN32_SERVICE
1087
1088 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
1089
1090 #endif
1091
1092 mainInitialize();
1093
1094 #if USE_WIN32_SERVICE
1095
1096 WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
1097
1098 #endif
1099
1100 /* main loop */
1101
1102 for (;;)
1103 {
1104 if (do_reconfigure) {
1105 mainReconfigure();
1106 do_reconfigure = 0;
1107 #if defined(_SQUID_MSWIN_) && defined(_DEBUG)
1108
1109 } else if (do_debug_trap) {
1110 do_debug_trap = 0;
1111 __asm int 3;
1112 #endif
1113
1114 } else if (do_rotate) {
1115 mainRotate();
1116 do_rotate = 0;
1117 } else if (do_shutdown) {
1118 time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
1119 debug(1, 1) ("Preparing for shutdown after %d requests\n",
1120 statCounter.client_http.requests);
1121 debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
1122 (int) wait);
1123 do_shutdown = 0;
1124 shutting_down = 1;
1125 #if USE_WIN32_SERVICE
1126
1127 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
1128 #endif
1129
1130 serverConnectionsClose();
1131 eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
1132 }
1133
1134 eventRun();
1135
1136 /* Attempt any pending storedir IO
1137 * Note: the storedir is roughly a reactor of its own.
1138 */
1139 Store::Root().callback();
1140
1141 comm_calliocallback();
1142
1143 /* and again to deal with indirectly queued events
1144 * resulting from the first call. These are usually
1145 * callbacks and should be dealt with immediately.
1146 */
1147
1148 if (comm_iocallbackpending())
1149 comm_calliocallback();
1150
1151 int loop_delay = eventNextTime();
1152
1153 if (loop_delay < 0)
1154 loop_delay = 0;
1155
1156 switch (comm_select(loop_delay)) {
1157
1158 case COMM_OK:
1159 errcount = 0; /* reset if successful */
1160 break;
1161
1162 case COMM_ERROR:
1163 errcount++;
1164 debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
1165
1166 if (errcount == 10)
1167 fatal_dump("Select Loop failed!");
1168
1169 break;
1170
1171 case COMM_TIMEOUT:
1172 break;
1173
1174 case COMM_SHUTDOWN:
1175 SquidShutdown(NULL);
1176
1177 break;
1178
1179 default:
1180 fatal_dump("MAIN: Internal error -- this should never happen.");
1181
1182 break;
1183 }
1184 }
1185
1186 /* NOTREACHED */
1187 return 0;
1188 }
1189
1190 static void
1191 sendSignal(void)
1192 {
1193 pid_t pid;
1194 debug_log = stderr;
1195
1196 if (strcmp(Config.pidFilename, "none") == 0) {
1197 debug(0, 1) ("No pid_filename specified. Trusting you know what you are doing.\n");
1198 }
1199
1200 pid = readPidFile();
1201
1202 if (pid > 1) {
1203 #if USE_WIN32_SERVICE
1204
1205 if (opt_signal_service) {
1206 WIN32_sendSignal(opt_send_signal);
1207 exit(0);
1208 } else
1209 #ifdef _SQUID_MSWIN_
1210 {
1211 fprintf(stderr, "%s: ERROR: Could not send ", appname);
1212 fprintf(stderr, "signal to Squid Service:\n");
1213 fprintf(stderr, "missing -n command line switch.\n");
1214 exit(1);
1215 }
1216
1217 /* NOTREACHED */
1218 #endif
1219
1220 #endif
1221
1222 if (kill(pid, opt_send_signal) &&
1223 /* ignore permissions if just running check */
1224 !(opt_send_signal == 0 && errno == EPERM)) {
1225 fprintf(stderr, "%s: ERROR: Could not send ", appname);
1226 fprintf(stderr, "signal %d to process %d: %s\n",
1227 opt_send_signal, (int) pid, xstrerror());
1228 exit(1);
1229 }
1230 } else {
1231 fprintf(stderr, "%s: ERROR: No running copy\n", appname);
1232 exit(1);
1233 }
1234
1235 /* signal successfully sent */
1236 exit(0);
1237 }
1238
1239 #ifndef _SQUID_MSWIN_
1240 /*
1241 * This function is run when Squid is in daemon mode, just
1242 * before the parent forks and starts up the child process.
1243 * It can be used for admin-specific tasks, such as notifying
1244 * someone that Squid is (re)started.
1245 */
1246 static void
1247 mainStartScript(const char *prog)
1248 {
1249 char script[SQUID_MAXPATHLEN];
1250 char *t;
1251 size_t sl = 0;
1252 pid_t cpid;
1253 pid_t rpid;
1254 xstrncpy(script, prog, MAXPATHLEN);
1255
1256 if ((t = strrchr(script, '/'))) {
1257 *(++t) = '\0';
1258 sl = strlen(script);
1259 }
1260
1261 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
1262
1263 if ((cpid = fork()) == 0) {
1264 /* child */
1265 execl(script, squid_start_script, (char *)NULL);
1266 _exit(-1);
1267 } else {
1268 do {
1269 #ifdef _SQUID_NEXT_
1270 union wait status;
1271 rpid = wait3(&status, 0, NULL);
1272 #else
1273
1274 int status;
1275 rpid = waitpid(-1, &status, 0);
1276 #endif
1277
1278 } while (rpid != cpid);
1279 }
1280 }
1281
1282 #endif /* _SQUID_MSWIN_ */
1283
1284 static int
1285 checkRunningPid(void)
1286 {
1287 pid_t pid;
1288
1289 if (!debug_log)
1290 debug_log = stderr;
1291
1292 pid = readPidFile();
1293
1294 if (pid < 2)
1295 return 0;
1296
1297 if (kill(pid, 0) < 0)
1298 return 0;
1299
1300 debugs(0, 0, "Squid is already running! Process ID " << pid);
1301
1302 return 1;
1303 }
1304
1305 static void
1306 watch_child(char *argv[])
1307 {
1308 #ifndef _SQUID_MSWIN_
1309 char *prog;
1310 int failcount = 0;
1311 time_t start;
1312 time_t stop;
1313 #ifdef _SQUID_NEXT_
1314
1315 union wait status;
1316 #else
1317
1318 int status;
1319 #endif
1320
1321 pid_t pid;
1322 #ifdef TIOCNOTTY
1323
1324 int i;
1325 #endif
1326
1327 int nullfd;
1328
1329 if (*(argv[0]) == '(')
1330 return;
1331
1332 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1333
1334 if ((pid = fork()) < 0)
1335 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
1336 else if (pid > 0)
1337 exit(0);
1338
1339 if (setsid() < 0)
1340 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
1341
1342 closelog();
1343
1344 #ifdef TIOCNOTTY
1345
1346 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
1347 ioctl(i, TIOCNOTTY, NULL);
1348 close(i);
1349 }
1350
1351 #endif
1352
1353
1354 /*
1355 * RBCOLLINS - if cygwin stackdumps when squid is run without
1356 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1357 * 1.1.3. execvp had a bit overflow error in a loop..
1358 */
1359 /* Connect stdio to /dev/null in daemon mode */
1360 nullfd = open("/dev/null", O_RDWR | O_TEXT);
1361
1362 if (nullfd < 0)
1363 fatalf("/dev/null: %s\n", xstrerror());
1364
1365 dup2(nullfd, 0);
1366
1367 if (opt_debug_stderr < 0) {
1368 dup2(nullfd, 1);
1369 dup2(nullfd, 2);
1370 }
1371
1372 for (;;) {
1373 mainStartScript(argv[0]);
1374
1375 if ((pid = fork()) == 0) {
1376 /* child */
1377 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1378 prog = xstrdup(argv[0]);
1379 argv[0] = xstrdup("(squid)");
1380 execvp(prog, argv);
1381 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
1382 }
1383
1384 /* parent */
1385 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1386
1387 syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
1388
1389 time(&start);
1390
1391 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
1392
1393 #ifdef _SQUID_NEXT_
1394
1395 pid = wait3(&status, 0, NULL);
1396
1397 #else
1398
1399 pid = waitpid(-1, &status, 0);
1400
1401 #endif
1402
1403 time(&stop);
1404
1405 if (WIFEXITED(status)) {
1406 syslog(LOG_NOTICE,
1407 "Squid Parent: child process %d exited with status %d",
1408 pid, WEXITSTATUS(status));
1409 } else if (WIFSIGNALED(status)) {
1410 syslog(LOG_NOTICE,
1411 "Squid Parent: child process %d exited due to signal %d",
1412 pid, WTERMSIG(status));
1413 } else {
1414 syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
1415 }
1416
1417 if (stop - start < 10)
1418 failcount++;
1419 else
1420 failcount = 0;
1421
1422 if (failcount == 5) {
1423 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
1424 exit(1);
1425 }
1426
1427 if (WIFEXITED(status))
1428 if (WEXITSTATUS(status) == 0)
1429 exit(0);
1430
1431 if (WIFSIGNALED(status)) {
1432 switch (WTERMSIG(status)) {
1433
1434 case SIGKILL:
1435 exit(0);
1436 break;
1437
1438 default:
1439 break;
1440 }
1441 }
1442
1443 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
1444 sleep(3);
1445 }
1446
1447 /* NOTREACHED */
1448 #endif /* _SQUID_MSWIN_ */
1449
1450 }
1451
1452 static void
1453 SquidShutdown(void *unused)
1454 {
1455 #if USE_WIN32_SERVICE
1456 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1457 #endif
1458
1459 debug(1, 1) ("Shutting down...\n");
1460 #if USE_DNSSERVERS
1461
1462 dnsShutdown();
1463 #else
1464
1465 idnsShutdown();
1466 #endif
1467
1468 redirectShutdown();
1469 externalAclShutdown();
1470 icpConnectionClose();
1471 #if USE_HTCP
1472
1473 htcpSocketClose();
1474 #endif
1475 #ifdef SQUID_SNMP
1476
1477 snmpConnectionClose();
1478 #endif
1479 #if USE_WCCP
1480
1481 wccpConnectionClose();
1482 #endif
1483
1484 releaseServerSockets();
1485 commCloseAllSockets();
1486 #if DELAY_POOLS
1487
1488 DelayPools::FreePools();
1489 #endif
1490
1491 authenticateShutdown();
1492 #if USE_UNLINKD
1493
1494 unlinkdClose();
1495 #endif
1496 #if USE_WIN32_SERVICE
1497
1498 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1499 #endif
1500
1501 Store::Root().sync(); /* Flush pending object writes/unlinks */
1502 storeDirWriteCleanLogs(0);
1503 PrintRusage();
1504 dumpMallocStats();
1505 Store::Root().sync(); /* Flush log writes */
1506 storeLogClose();
1507 accessLogClose();
1508 useragentLogClose();
1509 refererCloseLog();
1510 #if WIP_FWD_LOG
1511
1512 fwdUninit();
1513 #endif
1514
1515 Store::Root().sync(); /* Flush log close */
1516 StoreFileSystem::FreeAllFs();
1517 DiskIOModule::FreeAllModules();
1518 #if PURIFY || XMALLOC_TRACE
1519
1520 configFreeMemory();
1521 storeFreeMemory();
1522 /*stmemFreeMemory(); */
1523 netdbFreeMemory();
1524 ipcacheFreeMemory();
1525 fqdncacheFreeMemory();
1526 asnFreeMemory();
1527 clientdbFreeMemory();
1528 httpHeaderCleanModule();
1529 statFreeMemory();
1530 eventFreeMemory();
1531 mimeFreeMemory();
1532 errorClean();
1533 #endif
1534 #if !XMALLOC_TRACE
1535
1536 if (opt_no_daemon) {
1537 file_close(0);
1538 file_close(1);
1539 file_close(2);
1540 }
1541
1542 #endif
1543 fdDumpOpen();
1544
1545 fdFreeMemory();
1546
1547 memClean();
1548
1549 #if XMALLOC_TRACE
1550
1551 xmalloc_find_leaks();
1552
1553 debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
1554
1555 #endif
1556 #if MEM_GEN_TRACE
1557
1558 log_trace_done();
1559
1560 #endif
1561
1562 if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
1563 enter_suid();
1564 safeunlink(Config.pidFilename, 0);
1565 leave_suid();
1566 }
1567
1568 debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
1569 version_string);
1570
1571 if (debug_log)
1572 fclose(debug_log);
1573
1574 exit(0);
1575 }