]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/main.cc
3 * $Id: main.cc,v 1.354 2002/10/02 11:06:31 robertc Exp $
5 * DEBUG: section 1 Startup and Main Loop
6 * AUTHOR: Harvest Derived
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
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.
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.
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.
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.
38 /* for error reporting from xmalloc and friends */
39 extern void (*failure_notify
) (const char *);
41 static int opt_send_signal
= -1;
42 static int opt_no_daemon
= 0;
43 static int opt_parse_cfg_only
= 0;
44 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
45 static int configured_once
= 0;
47 static int malloc_debug_level
= 0;
49 static volatile int do_reconfigure
= 0;
50 static volatile int do_rotate
= 0;
51 static volatile int do_shutdown
= 0;
53 static void mainRotate(void);
54 static void mainReconfigure(void);
55 static SIGHDLR rotate_logs
;
56 static SIGHDLR reconfigure
;
57 static void mainInitialize(void);
58 static void usage(void);
59 static void mainParseOptions(int, char **);
60 static void sendSignal(void);
61 static void serverConnectionsOpen(void);
62 static void watch_child(char **);
63 static void setEffectiveUser(void);
65 extern void log_trace_done();
66 extern void log_trace_init(char *);
68 static EVH SquidShutdown
;
69 static void mainSetCwd(void);
70 static int checkRunningPid(void);
72 static const char *squid_start_script
= "squid_start";
75 #include "test_access.c"
82 "Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n"
83 " -a port Specify HTTP port number (default: %d).\n"
84 " -d level Write debugging to stderr also.\n"
85 " -f file Use given config-file instead of\n"
87 " -h Print help message.\n"
88 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
89 " Parse configuration file, then send signal to \n"
90 " running copy (except -k parse) and exit.\n"
91 " -s Enable logging to syslog.\n"
92 " -u port Specify ICP port number (default: %d), disable with 0.\n"
93 " -v Print version.\n"
94 " -z Create swap directories\n"
95 " -C Do not catch fatal signals.\n"
96 " -D Disable initial DNS tests.\n"
97 " -F Don't serve any requests until store is rebuilt.\n"
98 " -N No daemon mode.\n"
99 " -R Do not set REUSEADDR on port.\n"
100 " -S Double-check swap during rebuild.\n"
101 " -V Virtual host httpd-accelerator.\n"
102 " -X Force full debugging.\n"
103 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
104 appname
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
109 mainParseOptions(int argc
, char *argv
[])
114 while ((c
= getopt(argc
, argv
, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) {
117 opt_catch_signals
= 0;
123 opt_foreground_rebuild
= 1;
132 opt_store_doublecheck
= 1;
138 /* force full debugging */
139 sigusr2_handle(SIGUSR2
);
142 opt_reload_hit_only
= 1;
145 parse_sockaddr_in_list_token(&Config
.Sockaddr
.http
, optarg
);
148 opt_debug_stderr
= atoi(optarg
);
152 ConfigFile
= xstrdup(optarg
);
158 if ((int) strlen(optarg
) < 1)
160 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
161 opt_send_signal
= SIGHUP
;
162 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
163 #ifdef _SQUID_LINUX_THREADS_
164 opt_send_signal
= SIGQUIT
;
166 opt_send_signal
= SIGUSR1
;
168 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
169 #ifdef _SQUID_LINUX_THREADS_
170 opt_send_signal
= SIGTRAP
;
172 opt_send_signal
= SIGUSR2
;
174 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
175 opt_send_signal
= SIGTERM
;
176 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
177 opt_send_signal
= SIGINT
;
178 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
179 opt_send_signal
= SIGKILL
;
180 else if (!strncmp(optarg
, "check", strlen(optarg
)))
181 opt_send_signal
= 0; /* SIGNULL */
182 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
183 opt_parse_cfg_only
= 1; /* parse cfg file only */
190 malloc_debug_level
= atoi(optarg
);
194 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
199 xmalloc_trace
= !xmalloc_trace
;
201 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
206 opt_syslog_enable
= 1;
209 fatal("Logging to syslog not available on this platform");
213 icpPortNumOverride
= atoi(optarg
);
214 if (icpPortNumOverride
< 0)
215 icpPortNumOverride
= 0;
218 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string
, SQUID_CONFIGURE_OPTIONS
);
222 opt_create_swap_dirs
= 1;
238 signal(sig
, rotate_logs
);
248 signal(sig
, reconfigure
);
255 do_shutdown
= sig
== SIGINT
? -1 : 1;
256 #ifdef KILL_PARENT_OPT
258 debug(1, 1) ("Killing RunCache, pid %d\n", getppid());
259 if (kill(getppid(), sig
) < 0)
260 debug(1, 1) ("kill %d: %s\n", getppid(), xstrerror());
263 #if SA_RESETHAND == 0
264 signal(SIGTERM
, SIG_DFL
);
265 signal(SIGINT
, SIG_DFL
);
270 serverConnectionsOpen(void)
272 clientOpenListenSockets();
273 icpConnectionsOpen();
278 snmpConnectionOpen();
281 wccpConnectionOpen();
294 serverConnectionsClose(void)
296 assert(shutting_down
|| reconfiguring
);
297 clientHttpConnectionsClose();
298 icpConnectionShutdown();
300 htcpSocketShutdown();
304 snmpConnectionShutdown();
307 wccpConnectionShutdown();
313 mainReconfigure(void)
315 debug(1, 1) ("Restarting Squid Cache (version %s)...\n", version_string
);
317 /* Already called serverConnectionsClose and ipcacheShutdownServers() */
318 serverConnectionsClose();
319 icpConnectionClose();
324 snmpConnectionClose();
327 wccpConnectionClose();
335 authenticateShutdown();
336 externalAclShutdown();
337 storeDirCloseSwapLogs();
339 enter_suid(); /* root to read config file */
340 parseConfigFile(ConfigFile
);
342 _db_init(Config
.Log
.log
, Config
.debugOptions
);
343 ipcache_restart(); /* clear stuck entries */
344 authenticateUserCacheRestart(); /* clear stuck ACL entries */
345 fqdncache_restart(); /* sigh, fqdncache too */
347 errorInitialize(); /* reload error pages */
354 authenticateInit(&Config
.authConfig
);
359 serverConnectionsOpen();
360 if (theOutIcpConnection
>= 0) {
361 if (!Config2
.Accel
.on
|| Config
.onoff
.accel_with_proxy
)
362 neighbors_open(theOutIcpConnection
);
364 debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
366 storeDirOpenSwapLogs();
367 mimeInit(Config
.mimeTablePathname
);
368 writePidFile(); /* write PID file */
369 debug(1, 1) ("Ready to serve requests.\n");
381 authenticateShutdown();
382 externalAclShutdown();
383 _db_rotate_log(); /* cache.log */
384 storeDirWriteCleanLogs(1);
385 storeLogRotate(); /* store.log */
386 accessLogRotate(); /* access.log */
387 useragentRotateLog(); /* useragent.log */
388 refererRotateLog(); /* referer.log */
397 authenticateInit(&Config
.authConfig
);
402 setEffectiveUser(void)
404 leave_suid(); /* Run as non privilegied user */
408 if (geteuid() == 0) {
409 debug(0, 0) ("Squid is not safe to run as root! If you must\n");
410 debug(0, 0) ("start Squid as root, then you must configure\n");
411 debug(0, 0) ("it to run as a non-priveledged user with the\n");
412 debug(0, 0) ("'cache_effective_user' option in the config file.\n");
413 fatal("Don't run Squid as root, set 'cache_effective_user'!");
420 char pathbuf
[MAXPATHLEN
];
421 if (Config
.coredump_dir
) {
422 if (0 == strcmp("none", Config
.coredump_dir
)) {
424 } else if (chdir(Config
.coredump_dir
) == 0) {
425 debug(0, 1) ("Set Current Directory to %s\n", Config
.coredump_dir
);
428 debug(50, 0) ("chdir: %s: %s\n", Config
.coredump_dir
, xstrerror());
431 /* If we don't have coredump_dir or couldn't cd there, report current dir */
432 if (getcwd(pathbuf
, MAXPATHLEN
)) {
433 debug(0, 1) ("Current Directory is %s\n", pathbuf
);
435 debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
442 /* chroot if configured to run inside chroot */
443 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
444 fatal("failed to chroot");
446 if (opt_catch_signals
) {
447 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
448 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
450 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
451 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
454 if (icpPortNumOverride
!= 1)
455 Config
.Port
.icp
= (u_short
) icpPortNumOverride
;
457 _db_init(Config
.Log
.log
, Config
.debugOptions
);
458 fd_open(fileno(debug_log
), FD_LOG
, Config
.Log
.log
);
460 log_trace_init("/tmp/squid.alloc");
462 debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
465 debug(1, 1) ("Process ID %d\n", (int) getpid());
466 debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD
);
468 if (!configured_once
)
469 disk_init(); /* disk_init must go before ipcache_init() */
479 authenticateInit(&Config
.authConfig
);
483 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
484 httpReplyInitModule(); /* must go before accepting replies */
494 malloc_debug(0, malloc_debug_level
);
497 if (!configured_once
) {
506 /* after this point we want to see the mallinfo() output */
508 mimeInit(Config
.mimeTablePathname
);
519 serverConnectionsOpen();
520 if (theOutIcpConnection
>= 0) {
521 if (!Config2
.Accel
.on
|| Config
.onoff
.accel_with_proxy
)
522 neighbors_open(theOutIcpConnection
);
524 debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n");
526 if (Config
.chroot_dir
)
528 if (!configured_once
)
529 writePidFile(); /* write PID file */
531 #ifdef _SQUID_LINUX_THREADS_
532 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
533 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
535 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
536 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
538 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
539 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
540 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
542 debug(1, 1) ("Ready to serve requests.\n");
543 if (!configured_once
) {
544 eventAdd("storeMaintain", storeMaintainSwapSpace
, NULL
, 1.0, 1);
545 if (Config
.onoff
.announce
)
546 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
547 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
548 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
550 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
552 eventAdd("memPoolCleanIdlePools", memPoolCleanIdlePools
, NULL
, 15.0, 1);
558 main(int argc
, char **argv
)
561 int n
; /* # of GC'd objects */
564 #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
569 if (FD_SETSIZE
< Squid_MaxFD
)
570 Squid_MaxFD
= FD_SETSIZE
;
572 #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
573 if ((WIN32_init_err
= WIN32_Subsystem_Init()))
574 return WIN32_init_err
;
577 /* call mallopt() before anything else */
580 /* Round up all sizes to a multiple of this */
581 mallopt(M_GRAIN
, 16);
584 /* biggest size that is considered a small block */
585 mallopt(M_MXFAST
, 256);
588 /* allocate this many small blocks at once */
589 mallopt(M_NLBLKS
, 32);
591 #endif /* HAVE_MALLOPT */
594 * The plan here is to set the umask to 007 (deny others for
595 * read,write,execute), but only if the umask is not already
596 * set. Unfortunately, there is no way to get the current
597 * umask value without setting it.
599 oldmask
= umask(S_IRWXO
);
603 memset(&local_addr
, '\0', sizeof(struct in_addr
));
604 safe_inet_addr(localhost
, &local_addr
);
605 memset(&any_addr
, '\0', sizeof(struct in_addr
));
606 safe_inet_addr("0.0.0.0", &any_addr
);
607 memset(&no_addr
, '\0', sizeof(struct in_addr
));
608 safe_inet_addr("255.255.255.255", &no_addr
);
609 squid_srandom(time(NULL
));
612 squid_start
= current_time
;
613 failure_notify
= fatal_dump
;
615 mainParseOptions(argc
, argv
);
617 /* parse configuration file
618 * note: in "normal" case this used to be called from mainInitialize() */
622 ConfigFile
= xstrdup(DefaultConfigFile
);
623 assert(!configured_once
);
629 eventInit(); /* eventInit() is required for config parsing */
630 storeFsInit(); /* required for config parsing */
631 authenticateSchemeInit(); /* required for config parsign */
632 parse_err
= parseConfigFile(ConfigFile
);
634 if (opt_parse_cfg_only
)
637 if (-1 == opt_send_signal
)
638 if (checkRunningPid())
649 /* send signal to running copy and exit */
650 if (opt_send_signal
!= -1) {
651 /* chroot if configured to run inside chroot */
652 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
653 fatal("failed to chroot");
658 if (opt_create_swap_dirs
) {
659 /* chroot if configured to run inside chroot */
660 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
661 fatal("failed to chroot");
664 debug(0, 0) ("Creating Swap Directories\n");
665 storeCreateSwapDirectories();
672 if (opt_catch_signals
)
673 for (n
= Squid_MaxFD
; n
> 2; n
--)
676 /* init comm module */
681 /* we have to init fdstat here. */
682 fd_open(0, FD_LOG
, "stdin");
683 fd_open(1, FD_LOG
, "stdout");
684 fd_open(2, FD_LOG
, "stderr");
690 if (do_reconfigure
) {
693 } else if (do_rotate
) {
696 } else if (do_shutdown
) {
697 time_t wait
= do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0;
698 debug(1, 1) ("Preparing for shutdown after %d requests\n",
699 statCounter
.client_http
.requests
);
700 debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
704 serverConnectionsClose();
711 externalAclShutdown();
712 eventAdd("SquidShutdown", SquidShutdown
, NULL
, (double) (wait
+ 1), 1);
715 if ((loop_delay
= eventNextTime()) < 0)
717 switch (comm_select(loop_delay
)) {
719 errcount
= 0; /* reset if successful */
723 debug(1, 0) ("Select loop Error. Retry %d\n", errcount
);
725 fatal_dump("Select Loop failed!");
733 fatal_dump("MAIN: Internal error -- this should never happen.");
748 if (kill(pid
, opt_send_signal
) &&
749 /* ignore permissions if just running check */
750 !(opt_send_signal
== 0 && errno
== EPERM
)) {
751 fprintf(stderr
, "%s: ERROR: Could not send ", appname
);
752 fprintf(stderr
, "signal %d to process %d: %s\n",
753 opt_send_signal
, (int) pid
, xstrerror());
757 fprintf(stderr
, "%s: ERROR: No running copy\n", appname
);
760 /* signal successfully sent */
765 * This function is run when Squid is in daemon mode, just
766 * before the parent forks and starts up the child process.
767 * It can be used for admin-specific tasks, such as notifying
768 * someone that Squid is (re)started.
771 mainStartScript(const char *prog
)
773 char script
[SQUID_MAXPATHLEN
];
778 xstrncpy(script
, prog
, MAXPATHLEN
);
779 if ((t
= strrchr(script
, '/'))) {
783 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
784 if ((cpid
= fork()) == 0) {
786 execl(script
, squid_start_script
, 0);
792 rpid
= wait3(&status
, 0, NULL
);
795 rpid
= waitpid(-1, &status
, 0);
797 } while (rpid
!= cpid
);
802 checkRunningPid(void)
809 if (kill(pid
, 0) < 0)
811 debug(0, 0) ("Squid is already running! Process ID %d\n", pid
);
816 watch_child(char *argv
[])
830 if (*(argv
[0]) == '(')
832 openlog(appname
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
833 if ((pid
= fork()) < 0)
834 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
838 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
841 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
842 ioctl(i
, TIOCNOTTY
, NULL
);
849 * RBCOLLINS - if cygwin stackdumps when squid is run without
850 * -N, check the cygwin1.dll version, it needs to be AT LEAST
851 * 1.1.3. execvp had a bit overflow error in a loop..
853 /* Connect stdio to /dev/null in daemon mode */
854 nullfd
= open("/dev/null", O_RDWR
| O_TEXT
);
856 if (opt_debug_stderr
< 0) {
861 for (i
= 3; i
< Squid_MaxFD
; i
++)
864 mainStartScript(argv
[0]);
865 if ((pid
= fork()) == 0) {
867 openlog(appname
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
868 prog
= xstrdup(argv
[0]);
869 argv
[0] = xstrdup("(squid)");
871 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
874 openlog(appname
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
875 syslog(LOG_NOTICE
, "Squid Parent: child process %d started", pid
);
877 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
879 pid
= wait3(&status
, 0, NULL
);
881 pid
= waitpid(-1, &status
, 0);
884 if (WIFEXITED(status
)) {
886 "Squid Parent: child process %d exited with status %d",
887 pid
, WEXITSTATUS(status
));
888 } else if (WIFSIGNALED(status
)) {
890 "Squid Parent: child process %d exited due to signal %d",
891 pid
, WTERMSIG(status
));
893 syslog(LOG_NOTICE
, "Squid Parent: child process %d exited", pid
);
895 if (stop
- start
< 10)
899 if (failcount
== 5) {
900 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
903 if (WIFEXITED(status
))
904 if (WEXITSTATUS(status
) == 0)
906 if (WIFSIGNALED(status
)) {
907 switch (WTERMSIG(status
)) {
915 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
922 SquidShutdown(void *unused
)
924 debug(1, 1) ("Shutting down...\n");
925 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none")) {
927 safeunlink(Config
.pidFilename
, 0);
930 icpConnectionClose();
935 snmpConnectionClose();
938 wccpConnectionClose();
940 releaseServerSockets();
941 commCloseAllSockets();
942 authenticateShutdown();
946 storeDirSync(); /* Flush pending object writes/unlinks */
947 storeDirWriteCleanLogs(0);
950 storeDirSync(); /* Flush log writes */
957 storeDirSync(); /* Flush log close */
958 #if PURIFY || XMALLOC_TRACE
962 /*stmemFreeMemory(); */
965 fqdncacheFreeMemory();
967 clientdbFreeMemory();
968 httpHeaderCleanModule();
985 xmalloc_find_leaks();
986 debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total
);
991 debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",