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