]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/tools.cc
4 * DEBUG: section 21 Misc Functions
5 * AUTHOR: Harvest Derived
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
36 #include "base/Subscription.h"
40 #include "ip/Intercept.h"
41 #include "ip/QosConfig.h"
43 #include "anyp/PortCfg.h"
44 #include "SquidMath.h"
45 #include "SquidTime.h"
47 #include "ipc/Coordinator.h"
54 #include <sys/prctl.h>
70 The Squid Cache (version %s) died.\n\
72 You've encountered a fatal error in the Squid Cache version %s.\n\
73 If a core file was created (possibly in the swap directory),\n\
74 please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
75 and report the trace back to squid-bugs@squid-cache.org.\n\
79 static void fatal_common(const char *);
80 static void fatalvf(const char *fmt
, va_list args
);
81 static void mail_warranty(void);
83 extern void log_trace_done();
84 extern void log_trace_init(char *);
86 static void restoreCapabilities(int keep
);
90 /* Workaround for crappy glic header files */
91 SQUIDCEXTERN
int backtrace(void *, int);
92 SQUIDCEXTERN
void backtrace_symbols_fd(void *, int, int);
93 SQUIDCEXTERN
int setresuid(uid_t
, uid_t
, uid_t
);
94 #else /* _SQUID_LINUX_ */
95 /* needed on Opensolaris for backtrace_symbols_fd */
98 #endif /* HAVE_EXECINFO_H */
100 #endif /* _SQUID_LINUX */
103 releaseServerSockets(void)
105 // Release the main ports as early as possible
107 // clear both http_port and https_port lists.
108 clientHttpConnectionsClose();
113 // XXX: Why not the HTCP, SNMP, DNS ports as well?
114 // XXX: why does this differ from main closeServerConnections() anyway ?
120 LOCAL_ARRAY(char, msg
, 1024);
121 snprintf(msg
, 1024, DEAD_MSG
, version_string
, version_string
);
129 static char command
[256];
132 char filename
[] = "/tmp/squid-XXXXXX";
133 int tfd
= mkstemp(filename
);
138 if ((fp
= fdopen(tfd
, "w")) == NULL
)
145 if ((filename
= tempnam(NULL
, APP_SHORTNAME
)) == NULL
)
148 if ((fp
= fopen(filename
, "w")) == NULL
)
153 if (Config
.EmailFrom
)
154 fprintf(fp
, "From: %s\n", Config
.EmailFrom
);
156 fprintf(fp
, "From: %s@%s\n", APP_SHORTNAME
, uniqueHostname());
158 fprintf(fp
, "To: %s\n", Config
.adminEmail
);
160 fprintf(fp
, "Subject: %s\n", dead_msg());
164 snprintf(command
, 256, "%s %s < %s", Config
.EmailProgram
, Config
.adminEmail
, filename
);
166 if (system(command
)) {} /* XXX should avoid system(3) */
172 dumpMallocStats(void)
174 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
176 struct mstats ms
= mstats();
177 fprintf(debug_log
, "\ttotal space in arena: %6d KB\n",
178 (int) (ms
.bytes_total
>> 10));
179 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
180 (int) (ms
.bytes_free
>> 10),
181 Math::intPercent(ms
.bytes_free
, ms
.bytes_total
));
182 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
192 fprintf(debug_log
, "Memory usage for " APP_SHORTNAME
" via mallinfo():\n");
194 fprintf(debug_log
, "\ttotal space in arena: %6ld KB\n",
195 (long)mp
.arena
>> 10);
197 fprintf(debug_log
, "\tOrdinary blocks: %6ld KB %6ld blks\n",
198 (long)mp
.uordblks
>> 10, (long)mp
.ordblks
);
200 fprintf(debug_log
, "\tSmall blocks: %6ld KB %6ld blks\n",
201 (long)mp
.usmblks
>> 10, (long)mp
.smblks
);
203 fprintf(debug_log
, "\tHolding blocks: %6ld KB %6ld blks\n",
204 (long)mp
.hblkhd
>> 10, (long)mp
.hblks
);
206 fprintf(debug_log
, "\tFree Small blocks: %6ld KB\n",
207 (long)mp
.fsmblks
>> 10);
209 fprintf(debug_log
, "\tFree Ordinary blocks: %6ld KB\n",
210 (long)mp
.fordblks
>> 10);
212 t
= mp
.uordblks
+ mp
.usmblks
+ mp
.hblkhd
;
214 fprintf(debug_log
, "\tTotal in use: %6d KB %d%%\n",
215 t
>> 10, Math::intPercent(t
, mp
.arena
));
217 t
= mp
.fsmblks
+ mp
.fordblks
;
219 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
220 t
>> 10, Math::intPercent(t
, mp
.arena
));
222 #if HAVE_STRUCT_MALLINFO_MXFAST
224 fprintf(debug_log
, "\tmax size of small blocks:\t%d\n",
227 fprintf(debug_log
, "\tnumber of small blocks in a holding block:\t%d\n",
230 fprintf(debug_log
, "\tsmall block rounding factor:\t%d\n",
233 fprintf(debug_log
, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
236 fprintf(debug_log
, "\tnumber of ordinary blocks allocated:\t%d\n",
239 fprintf(debug_log
, "\tbytes used in maintaining the free tree:\t%d\n",
242 #endif /* HAVE_STRUCT_MALLINFO_MXFAST */
243 #endif /* HAVE_MALLINFO */
248 squid_getrusage(struct rusage
*r
)
251 memset(r
, '\0', sizeof(struct rusage
));
252 #if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
254 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
258 getrusage(RUSAGE_SELF
, r
);
268 rusage_cputime(struct rusage
*r
)
270 return (double) r
->ru_stime
.tv_sec
+
271 (double) r
->ru_utime
.tv_sec
+
272 (double) r
->ru_stime
.tv_usec
/ 1000000.0 +
273 (double) r
->ru_utime
.tv_usec
/ 1000000.0;
276 /* Hack for some HP-UX preprocessors */
277 #ifndef HAVE_GETPAGESIZE
278 #define HAVE_GETPAGESIZE 0
283 rusage_maxrss(struct rusage
*r
)
285 #if _SQUID_SGI_ && _ABIAPI
287 #elif _SQUID_SGI_|| _SQUID_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
290 #elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
292 return (r
->ru_maxrss
* getpagesize()) >> 10;
293 #elif defined(PAGESIZE)
295 return (r
->ru_maxrss
* PAGESIZE
) >> 10;
304 rusage_pagefaults(struct rusage
*r
)
306 #if _SQUID_SGI_ && _ABIAPI
318 struct rusage rusage
;
319 squid_getrusage(&rusage
);
320 fprintf(debug_log
, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
321 rusage_cputime(&rusage
),
322 rusage
.ru_utime
.tv_sec
+ ((double) rusage
.ru_utime
.tv_usec
/ 1000000.0),
323 rusage
.ru_stime
.tv_sec
+ ((double) rusage
.ru_stime
.tv_usec
/ 1000000.0));
324 fprintf(debug_log
, "Maximum Resident Size: %d KB\n",
325 rusage_maxrss(&rusage
));
326 fprintf(debug_log
, "Page faults with physical i/o: %d\n",
327 rusage_pagefaults(&rusage
));
334 fprintf(debug_log
, "FATAL: Received Segment Violation...dying.\n");
335 else if (sig
== SIGBUS
)
336 fprintf(debug_log
, "FATAL: Received Bus Error...dying.\n");
338 fprintf(debug_log
, "FATAL: Received signal %d...dying.\n", sig
);
340 #if PRINT_STACK_TRACE
343 extern void U_STACK_TRACE(void); /* link with -lcl */
345 dup2(fileno(debug_log
), 2);
349 #endif /* _SQUID_HPUX_ */
350 #if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
351 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
352 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
354 dup2(fileno(debug_log
), fileno(stdout
));
359 #endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
360 #if HAVE_BACKTRACE_SYMBOLS_FD
362 static void *(callarray
[8192]);
364 n
= backtrace(callarray
, 8192);
365 backtrace_symbols_fd(callarray
, n
, fileno(debug_log
));
369 #endif /* PRINT_STACK_TRACE */
371 #if SA_RESETHAND == 0 && !_SQUID_MSWIN_
372 signal(SIGSEGV
, SIG_DFL
);
374 signal(SIGBUS
, SIG_DFL
);
376 signal(sig
, SIG_DFL
);
380 releaseServerSockets();
382 storeDirWriteCleanLogs(0);
384 if (!shutting_down
) {
390 if (squid_curtime
- SQUID_RELEASE_TIME
< 864000) {
391 /* skip if more than 10 days old */
393 if (Config
.adminEmail
)
403 BroadcastSignalIfAny(int& sig
)
406 if (IamCoordinatorProcess())
407 Ipc::Coordinator::Instance()->broadcastSignal(sig
);
413 sigusr2_handle(int sig
)
415 static int state
= 0;
416 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
422 Debug::parseOptions("ALL,7");
431 Debug::parseOptions(Debug::debugOptions
);
434 log_trace_init("/tmp/squid.alloc");
441 if (signal(sig
, sigusr2_handle
) == SIG_ERR
) /* reinstall */
442 debugs(50, DBG_CRITICAL
, "signal: sig=" << sig
<< " func=sigusr2_handle: " << xstrerror());
448 fatal_common(const char *message
)
451 syslog(LOG_ALERT
, "%s", message
);
454 fprintf(debug_log
, "FATAL: %s\n", message
);
456 if (Debug::log_stderr
> 0 && debug_log
!= stderr
)
457 fprintf(stderr
, "FATAL: %s\n", message
);
459 fprintf(debug_log
, "Squid Cache (Version %s): Terminated abnormally.\n",
471 fatal(const char *message
)
473 /* suppress secondary errors from the dying */
476 releaseServerSockets();
477 /* check for store_dirs_rebuilding because fatal() is often
478 * used in early initialization phases, long before we ever
479 * get to the store log. */
481 /* XXX: this should be turned into a callback-on-fatal, or
482 * a mandatory-shutdown-event or something like that.
488 * Call leave_suid() here to make sure that swap.state files
489 * are written as the effective user, rather than root. Squid
490 * may take on root privs during reconfigure. If squid.conf
491 * contains a "Bungled" line, fatal() will be called when the
492 * process still has root privs.
496 if (0 == StoreController::store_dirs_rebuilding
)
497 storeDirWriteCleanLogs(0);
499 fatal_common(message
);
504 /* printf-style interface for fatal */
506 fatalf(const char *fmt
,...)
516 fatalvf(const char *fmt
, va_list args
)
518 static char fatal_str
[BUFSIZ
];
519 vsnprintf(fatal_str
, sizeof(fatal_str
), fmt
, args
);
523 /* fatal with dumping core */
525 fatal_dump(const char *message
)
527 failure_notify
= NULL
;
528 releaseServerSockets();
531 fatal_common(message
);
534 * Call leave_suid() here to make sure that swap.state files
535 * are written as the effective user, rather than root. Squid
536 * may take on root privs during reconfigure. If squid.conf
537 * contains a "Bungled" line, fatal() will be called when the
538 * process still has root privs.
542 if (opt_catch_signals
)
543 storeDirWriteCleanLogs(0);
549 debug_trap(const char *message
)
551 if (!opt_catch_signals
)
554 _db_print("WARNING: %s\n", message
);
572 pid
= wait3(&status
, WNOHANG
, NULL
);
575 pid
= waitpid(-1, &status
, WNOHANG
);
577 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
586 while (pid
> 0 || (pid
< 0 && errno
== EINTR
));
587 signal(sig
, sig_child
);
594 sig_shutdown(int sig
)
602 LOCAL_ARRAY(char, host
, SQUIDHOSTNAMELEN
+ 1);
603 static int present
= 0;
604 struct addrinfo
*AI
= NULL
;
607 if (Config
.visibleHostname
!= NULL
)
608 return Config
.visibleHostname
;
615 if (Config
.Sockaddr
.http
&& sa
.IsAnyAddr())
616 sa
= Config
.Sockaddr
.http
->s
;
620 if (Config
.Sockaddr
.https
&& sa
.IsAnyAddr())
621 sa
= Config
.Sockaddr
.https
->s
;
626 * If the first http_port address has a specific address, try a
627 * reverse DNS lookup on it.
629 if ( !sa
.IsAnyAddr() ) {
632 /* we are looking for a name. */
633 if (getnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, host
, SQUIDHOSTNAMELEN
, NULL
, 0, NI_NAMEREQD
) == 0) {
634 /* DNS lookup successful */
635 /* use the official name from DNS lookup */
636 debugs(50, 4, "getMyHostname: resolved " << sa
<< " to '" << host
<< "'");
642 if (strchr(host
, '.'))
647 debugs(50, 2, "WARNING: failed to resolve " << sa
<< " to a fully qualified hostname");
650 // still no host. fallback to gethostname()
651 if (gethostname(host
, SQUIDHOSTNAMELEN
) < 0) {
652 debugs(50, DBG_IMPORTANT
, "WARNING: gethostname failed: " << xstrerror());
654 /* Verify that the hostname given resolves properly */
655 struct addrinfo hints
;
656 memset(&hints
, 0, sizeof(addrinfo
));
657 hints
.ai_flags
= AI_CANONNAME
;
659 if (getaddrinfo(host
, NULL
, NULL
, &AI
) == 0) {
660 /* DNS lookup successful */
661 /* use the official name from DNS lookup */
662 debugs(50, 6, "getMyHostname: '" << host
<< "' has DNS resolution.");
665 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
674 if (AI
) freeaddrinfo(AI
);
675 debugs(50, DBG_IMPORTANT
, "WARNING: '" << host
<< "' rDNS test failed: " << xstrerror());
678 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
679 debugs(50, DBG_CRITICAL
, "WARNING: Could not determine this machines public hostname. " <<
680 "Please configure one or set 'visible_hostname'.");
682 return ("localhost");
688 debugs(21, 3, HERE
<< " Config: '" << Config
.uniqueHostname
<< "'");
689 return Config
.uniqueHostname
? Config
.uniqueHostname
: getMyHostname();
692 /** leave a priviliged section. (Give up any privilegies)
693 * Routines that need privilegies can rap themselves in enter_suid()
695 * To give upp all posibilites to gain privilegies use no_suid()
700 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
702 if (Config
.effectiveGroup
) {
706 setgroups(1, &Config2
.effectiveGroupID
);
710 if (setgid(Config2
.effectiveGroupID
) < 0)
711 debugs(50, DBG_CRITICAL
, "ALERT: setgid: " << xstrerror());
718 /* Started as a root, check suid option */
719 if (Config
.effectiveUser
== NULL
)
722 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config
.effectiveUser
<< "'");
724 if (!Config
.effectiveGroup
) {
726 if (setgid(Config2
.effectiveGroupID
) < 0)
727 debugs(50, DBG_CRITICAL
, "ALERT: setgid: " << xstrerror());
729 if (initgroups(Config
.effectiveUser
, Config2
.effectiveGroupID
) < 0) {
730 debugs(50, DBG_CRITICAL
, "ALERT: initgroups: unable to set groups for User " <<
731 Config
.effectiveUser
<< " and Group " <<
732 (unsigned) Config2
.effectiveGroupID
<< "");
738 if (setresuid(Config2
.effectiveUserID
, Config2
.effectiveUserID
, 0) < 0)
739 debugs(50, DBG_CRITICAL
, "ALERT: setresuid: " << xstrerror());
743 if (seteuid(Config2
.effectiveUserID
) < 0)
744 debugs(50, DBG_CRITICAL
, "ALERT: seteuid: " << xstrerror());
748 if (setuid(Config2
.effectiveUserID
) < 0)
749 debugs(50, DBG_CRITICAL
, "ALERT: setuid: " << xstrerror());
753 restoreCapabilities(1);
755 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
756 /* Set Linux DUMPABLE flag */
757 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
758 debugs(50, 2, "ALERT: prctl: " << xstrerror());
763 /* Enter a privilegied section */
767 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root priveleges");
770 setresuid((uid_t
)-1, 0, (uid_t
)-1);
775 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
776 /* Set Linux DUMPABLE flag */
778 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
779 debugs(50, 2, "ALERT: prctl: " << xstrerror());
784 /* Give up the posibility to gain privilegies.
785 * this should be used before starting a sub process
793 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
798 debugs(50, DBG_IMPORTANT
, "no_suid: setuid: " << xstrerror());
800 restoreCapabilities(0);
802 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
803 /* Set Linux DUMPABLE flag */
804 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
805 debugs(50, 2, "ALERT: prctl: " << xstrerror());
813 return KidIdentifier
== 0;
819 // when there is only one process, it has to be the worker
820 if (opt_no_daemon
|| Config
.workers
== 0)
823 return TheProcessKind
== pkWorker
;
829 return TheProcessKind
== pkDisker
;
835 return !opt_no_daemon
&& Config
.workers
> 0;
841 return InDaemonMode() && NumberOfKids() > 1;
845 IamCoordinatorProcess()
847 return TheProcessKind
== pkCoordinator
;
853 // when there is only one process, it has to be primary
854 if (opt_no_daemon
|| Config
.workers
== 0)
857 // when there is a master and worker process, the master delegates
858 // primary functions to its only kid
859 if (NumberOfKids() == 1)
860 return IamWorkerProcess();
862 // in SMP mode, multiple kids delegate primary functions to the coordinator
863 return IamCoordinatorProcess();
869 // no kids in no-daemon mode
873 // XXX: detect and abort when called before workers/cache_dirs are parsed
875 const int rockDirs
= Config
.cacheSwap
.n_strands
;
877 const bool needCoord
= Config
.workers
> 1 || rockDirs
> 0;
878 return (needCoord
? 1 : 0) + Config
.workers
+ rockDirs
;
885 if (IamMasterProcess())
886 roles
.append(" master");
887 if (IamCoordinatorProcess())
888 roles
.append(" coordinator");
889 if (IamWorkerProcess())
890 roles
.append(" worker");
891 if (IamDiskProcess())
892 roles
.append(" disker");
900 const char *f
= NULL
;
904 if (!IamPrimaryProcess())
907 if ((f
= Config
.pidFilename
) == NULL
)
910 if (!strcmp(Config
.pidFilename
, "none"))
915 old_umask
= umask(022);
917 fd
= file_open(f
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
);
924 debugs(50, DBG_CRITICAL
, "" << f
<< ": " << xstrerror());
925 debug_trap("Could not write pid file");
929 snprintf(buf
, 32, "%d\n", (int) getpid());
930 FD_WRITE_METHOD(fd
, buf
, strlen(buf
));
938 const char *f
= Config
.pidFilename
;
939 char *chroot_f
= NULL
;
943 if (f
== NULL
|| !strcmp(Config
.pidFilename
, "none")) {
944 fprintf(stderr
, APP_SHORTNAME
": ERROR: No pid file name defined\n");
948 if (Config
.chroot_dir
&& geteuid() == 0) {
949 int len
= strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1;
950 chroot_f
= (char *)xmalloc(strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1);
951 snprintf(chroot_f
, len
, "%s/%s", Config
.chroot_dir
, f
);
955 pid_fp
= fopen(f
, "r");
957 if (pid_fp
!= NULL
) {
960 if (fscanf(pid_fp
, "%d", &i
) == 1)
965 if (errno
!= ENOENT
) {
966 fprintf(stderr
, APP_SHORTNAME
": ERROR: Could not read pid file\n");
967 fprintf(stderr
, "\t%s: %s\n", f
, xstrerror());
976 /* A little piece of glue for odd systems */
977 #ifndef RLIMIT_NOFILE
979 #define RLIMIT_NOFILE RLIMIT_OFILE
983 /** Figure out the number of supported filedescriptors */
987 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
989 /* On Linux with 64-bit file support the sys/resource.h header
990 * uses #define to change the function definition to require rlimit64
992 #if defined(getrlimit)
993 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
998 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
999 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
1000 } else if (Config
.max_filedescriptors
> 0) {
1001 #if USE_SELECT || USE_SELECT_WIN32
1002 /* select() breaks if this gets set too big */
1003 if (Config
.max_filedescriptors
> FD_SETSIZE
) {
1004 rl
.rlim_cur
= FD_SETSIZE
;
1005 debugs(50, DBG_CRITICAL
, "WARNING: 'max_filedescriptors " << Config
.max_filedescriptors
<< "' does not work with select()");
1008 rl
.rlim_cur
= Config
.max_filedescriptors
;
1009 if (rl
.rlim_cur
> rl
.rlim_max
)
1010 rl
.rlim_max
= rl
.rlim_cur
;
1011 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
1012 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerror());
1013 getrlimit(RLIMIT_NOFILE
, &rl
);
1014 rl
.rlim_cur
= rl
.rlim_max
;
1015 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
1016 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerror());
1020 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
1021 debugs(50, DBG_CRITICAL
, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerror());
1023 Squid_MaxFD
= rl
.rlim_cur
;
1026 #endif /* HAVE_SETRLIMIT */
1030 setSystemLimits(void)
1032 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
1033 /* limit system filedescriptors to our own limit */
1035 /* On Linux with 64-bit file support the sys/resource.h header
1036 * uses #define to change the function definition to require rlimit64
1038 #if defined(getrlimit)
1039 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
1044 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
1045 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
1047 rl
.rlim_cur
= Squid_MaxFD
;
1048 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
1049 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
1050 fatal_dump(tmp_error_buf
);
1053 #endif /* HAVE_SETRLIMIT */
1055 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
1056 if (getrlimit(RLIMIT_DATA
, &rl
) < 0) {
1057 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_DATA: " << xstrerror());
1058 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
1059 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
1061 if (setrlimit(RLIMIT_DATA
, &rl
) < 0) {
1062 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_DATA: %s", xstrerror());
1063 fatal_dump(tmp_error_buf
);
1066 #endif /* RLIMIT_DATA */
1067 if (Config
.max_filedescriptors
> Squid_MaxFD
) {
1068 debugs(50, DBG_IMPORTANT
, "NOTICE: Could not increase the number of filedescriptors");
1071 #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
1072 if (getrlimit(RLIMIT_VMEM
, &rl
) < 0) {
1073 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_VMEM: " << xstrerror());
1074 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
1075 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
1077 if (setrlimit(RLIMIT_VMEM
, &rl
) < 0) {
1078 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_VMEM: %s", xstrerror());
1079 fatal_dump(tmp_error_buf
);
1082 #endif /* RLIMIT_VMEM */
1086 squid_signal(int sig
, SIGHDLR
* func
, int flags
)
1090 struct sigaction sa
;
1091 sa
.sa_handler
= func
;
1092 sa
.sa_flags
= flags
;
1093 sigemptyset(&sa
.sa_mask
);
1095 if (sigaction(sig
, &sa
, NULL
) < 0)
1096 debugs(50, DBG_CRITICAL
, "sigaction: sig=" << sig
<< " func=" << func
<< ": " << xstrerror());
1101 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
1102 are supported, so we must care of don't call signal() for other value.
1103 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
1104 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
1122 WIN32_ExceptionHandlerInit();
1126 WIN32_ExceptionHandlerInit();
1128 break; /* Nor reached */
1132 break; /* Nor reached */
1150 kb_incr(kb_t
* k
, size_t v
)
1153 k
->kb
+= (k
->bytes
>> 10);
1158 debugObj(int section
, int level
, const char *label
, void *obj
, ObjPackMethod pm
)
1162 assert(label
&& obj
&& pm
);
1164 packerToMemInit(&p
, &mb
);
1166 debugs(section
, level
, "" << label
<< "" << mb
.buf
<< "");
1180 if (NULL
== Config
.etcHostsPath
)
1183 if (0 == strcmp(Config
.etcHostsPath
, "none"))
1186 fp
= fopen(Config
.etcHostsPath
, "r");
1189 debugs(1, DBG_IMPORTANT
, "parseEtcHosts: " << Config
.etcHostsPath
<< ": " << xstrerror());
1194 setmode(fileno(fp
), O_TEXT
);
1197 while (fgets(buf
, 1024, fp
)) { /* for each line */
1198 wordlist
*hosts
= NULL
;
1201 if (buf
[0] == '#') /* MS-windows likes to add comments */
1204 strtok(buf
, "#"); /* chop everything following a comment marker */
1210 debugs(1, 5, "etc_hosts: line is '" << buf
<< "'");
1212 nt
= strpbrk(lt
, w_space
);
1214 if (nt
== NULL
) /* empty line */
1217 *nt
= '\0'; /* null-terminate the address */
1219 debugs(1, 5, "etc_hosts: address is '" << addr
<< "'");
1223 while ((nt
= strpbrk(lt
, w_space
))) {
1226 if (nt
== lt
) { /* multiple spaces */
1227 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
1233 debugs(1, 5, "etc_hosts: got hostname '" << lt
<< "'");
1235 /* For IPV6 addresses also check for a colon */
1236 if (Config
.appendDomain
&& !strchr(lt
, '.') && !strchr(lt
, ':')) {
1237 /* I know it's ugly, but it's only at reconfig */
1238 strncpy(buf2
, lt
, 512);
1239 strncat(buf2
, Config
.appendDomain
, 512 - strlen(lt
) - 1);
1245 if (ipcacheAddEntryFromHosts(host
, addr
) != 0) {
1246 /* invalid address, continuing is useless */
1247 wordlistDestroy(&hosts
);
1251 wordlistAdd(&hosts
, host
);
1257 fqdncacheAddEntryFromHosts(addr
, hosts
);
1258 wordlistDestroy(&hosts
);
1268 AnyP::PortCfg
*p
= NULL
;
1269 if ((p
= Config
.Sockaddr
.http
)) {
1270 // skip any special interception ports
1271 while (p
&& (p
->intercepted
|| p
->spoof_client_ip
))
1274 return p
->s
.GetPort();
1278 if ((p
= Config
.Sockaddr
.https
)) {
1279 // skip any special interception ports
1280 while (p
&& (p
->intercepted
|| p
->spoof_client_ip
))
1283 return p
->s
.GetPort();
1287 debugs(21, DBG_CRITICAL
, "ERROR: No forward-proxy ports configured.");
1288 return 0; // Invalid port. This will result in invalid URLs on bad configurations.
1292 * Set the umask to at least the given mask. This is in addition
1293 * to the umask set at startup
1296 setUmask(mode_t mask
)
1298 // No way to get the current umask value without setting it.
1299 static const mode_t orig_umask
= umask(mask
); // once, to get
1300 umask(mask
| orig_umask
); // always, to set
1304 * Inverse of strwordtok. Quotes a word if needed
1307 strwordquote(MemBuf
* mb
, const char *str
)
1311 if (strchr(str
, ' ')) {
1313 mb
->append("\"", 1);
1317 int l
= strcspn(str
, "\"\\\n\r");
1324 mb
->append("\\n", 2);
1329 mb
->append("\\r", 2);
1337 mb
->append("\\", 1);
1345 mb
->append("\"", 1);
1349 keepCapabilities(void)
1351 #if USE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
1353 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0)) {
1354 Ip::Interceptor
.StopTransparency("capability setting has failed.");
1360 restoreCapabilities(int keep
)
1362 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
1366 caps
= cap_get_proc();
1370 Ip::Interceptor
.StopTransparency("Can't get current capabilities");
1374 cap_value_t cap_list
[10];
1375 cap_list
[ncaps
] = CAP_NET_BIND_SERVICE
;
1377 if (Ip::Interceptor
.TransparentActive() || Ip::Qos::TheConfig
.isHitNfmarkActive() || Ip::Qos::TheConfig
.isAclNfmarkActive()) {
1378 cap_list
[ncaps
] = CAP_NET_ADMIN
;
1382 cap_clear_flag(caps
, CAP_EFFECTIVE
);
1383 rc
|= cap_set_flag(caps
, CAP_EFFECTIVE
, ncaps
, cap_list
, CAP_SET
);
1384 rc
|= cap_set_flag(caps
, CAP_PERMITTED
, ncaps
, cap_list
, CAP_SET
);
1386 if (rc
|| cap_set_proc(caps
) != 0) {
1387 Ip::Interceptor
.StopTransparency("Error enabling needed capabilities.");
1392 Ip::Interceptor
.StopTransparency("Missing needed capability support.");
1393 #endif /* HAVE_SYS_CAPABILITY_H */
1397 xmemset(void *dst
, int val
, size_t sz
)
1400 debugs(63, 9, "memset: dst=" << dst
<< ", val=" << val
<< ", bytes=" << sz
);
1402 // call the system one to do the actual work ~safely.
1403 return memset(dst
, val
, sz
);