3 * $Id: tools.cc,v 1.281 2008/02/11 22:44:50 rousskov Exp $
5 * DEBUG: section 21 Misc Functions
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.
37 #include "ProtoPort.h"
42 #include "SquidTime.h"
45 #if HAVE_SYS_CAPABILITY_H
47 /* Ugly glue to get around linux header madness colliding with glibc */
48 #define _LINUX_TYPES_H
50 typedef uint32_t __u32
;
51 #include <sys/capability.h>
56 #include <sys/prctl.h>
60 The Squid Cache (version %s) died.\n\
62 You've encountered a fatal error in the Squid Cache version %s.\n\
63 If a core file was created (possibly in the swap directory),\n\
64 please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
65 and report the trace back to squid-bugs@squid-cache.org.\n\
69 static void fatal_common(const char *);
70 static void fatalvf(const char *fmt
, va_list args
);
71 static void mail_warranty(void);
73 extern void log_trace_done();
74 extern void log_trace_init(char *);
76 static void restoreCapabilities(int keep
);
79 /* Workaround for crappy glic header files */
80 SQUIDCEXTERN
int backtrace(void *, int);
81 SQUIDCEXTERN
void backtrace_symbols_fd(void *, int, int);
82 SQUIDCEXTERN
int setresuid(uid_t
, uid_t
, uid_t
);
83 #endif /* _SQUID_LINUX */
85 SQUIDCEXTERN
void (*failure_notify
) (const char *);
88 releaseServerSockets(void)
91 /* Release the main ports as early as possible */
93 for (i
= 0; i
< NHttpSockets
; i
++) {
94 if (HttpSockets
[i
] >= 0)
95 close(HttpSockets
[i
]);
98 if (theInIcpConnection
>= 0)
99 close(theInIcpConnection
);
101 if (theOutIcpConnection
>= 0 && theOutIcpConnection
!= theInIcpConnection
)
102 close(theOutIcpConnection
);
108 LOCAL_ARRAY(char, msg
, 1024);
109 snprintf(msg
, 1024, DEAD_MSG
, version_string
, version_string
);
117 static char command
[256];
120 char filename
[] = "/tmp/squid-XXXXXX";
121 int tfd
= mkstemp(filename
);
126 if ((fp
= fdopen(tfd
, "w")) == NULL
)
133 if ((filename
= tempnam(NULL
, appname
)) == NULL
)
136 if ((fp
= fopen(filename
, "w")) == NULL
)
141 if (Config
.EmailFrom
)
142 fprintf(fp
, "From: %s\n", Config
.EmailFrom
);
144 fprintf(fp
, "From: %s@%s\n", appname
, uniqueHostname());
146 fprintf(fp
, "To: %s\n", Config
.adminEmail
);
148 fprintf(fp
, "Subject: %s\n", dead_msg());
152 snprintf(command
, 256, "%s %s < %s", Config
.EmailProgram
, Config
.adminEmail
, filename
);
154 system(command
); /* XXX should avoid system(3) */
160 dumpMallocStats(void)
162 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
164 struct mstats ms
= mstats();
165 fprintf(debug_log
, "\ttotal space in arena: %6d KB\n",
166 (int) (ms
.bytes_total
>> 10));
167 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
168 (int) (ms
.bytes_free
>> 10),
169 percent(ms
.bytes_free
, ms
.bytes_total
));
170 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
180 fprintf(debug_log
, "Memory usage for %s via mallinfo():\n", appname
);
182 fprintf(debug_log
, "\ttotal space in arena: %6ld KB\n",
183 (long)mp
.arena
>> 10);
185 fprintf(debug_log
, "\tOrdinary blocks: %6ld KB %6ld blks\n",
186 (long)mp
.uordblks
>> 10, (long)mp
.ordblks
);
188 fprintf(debug_log
, "\tSmall blocks: %6ld KB %6ld blks\n",
189 (long)mp
.usmblks
>> 10, (long)mp
.smblks
);
191 fprintf(debug_log
, "\tHolding blocks: %6ld KB %6ld blks\n",
192 (long)mp
.hblkhd
>> 10, (long)mp
.hblks
);
194 fprintf(debug_log
, "\tFree Small blocks: %6ld KB\n",
195 (long)mp
.fsmblks
>> 10);
197 fprintf(debug_log
, "\tFree Ordinary blocks: %6ld KB\n",
198 (long)mp
.fordblks
>> 10);
200 t
= mp
.uordblks
+ mp
.usmblks
+ mp
.hblkhd
;
202 fprintf(debug_log
, "\tTotal in use: %6d KB %d%%\n",
203 t
>> 10, percent(t
, mp
.arena
));
205 t
= mp
.fsmblks
+ mp
.fordblks
;
207 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
208 t
>> 10, percent(t
, mp
.arena
));
210 #if HAVE_STRUCT_MALLINFO_MXFAST
212 fprintf(debug_log
, "\tmax size of small blocks:\t%d\n",
215 fprintf(debug_log
, "\tnumber of small blocks in a holding block:\t%d\n",
218 fprintf(debug_log
, "\tsmall block rounding factor:\t%d\n",
221 fprintf(debug_log
, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
224 fprintf(debug_log
, "\tnumber of ordinary blocks allocated:\t%d\n",
227 fprintf(debug_log
, "\tbytes used in maintaining the free tree:\t%d\n",
230 #endif /* HAVE_STRUCT_MALLINFO_MXFAST */
231 #endif /* HAVE_MALLINFO */
236 squid_getrusage(struct rusage
*r
)
239 memset(r
, '\0', sizeof(struct rusage
));
240 #if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
241 #ifdef _SQUID_SOLARIS_
242 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
246 getrusage(RUSAGE_SELF
, r
);
247 #ifdef _SQUID_SOLARIS_
256 rusage_cputime(struct rusage
*r
)
258 return (double) r
->ru_stime
.tv_sec
+
259 (double) r
->ru_utime
.tv_sec
+
260 (double) r
->ru_stime
.tv_usec
/ 1000000.0 +
261 (double) r
->ru_utime
.tv_usec
/ 1000000.0;
264 /* Hack for some HP-UX preprocessors */
265 #ifndef HAVE_GETPAGESIZE
266 #define HAVE_GETPAGESIZE 0
271 rusage_maxrss(struct rusage
*r
)
273 #if defined(_SQUID_SGI_) && _ABIAPI
275 #elif defined(_SQUID_SGI_)
278 #elif defined(_SQUID_OSF_)
281 #elif defined(_SQUID_AIX_)
284 #elif defined(BSD4_4)
287 #elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
289 return (r
->ru_maxrss
* getpagesize()) >> 10;
290 #elif defined(PAGESIZE)
292 return (r
->ru_maxrss
* PAGESIZE
) >> 10;
301 rusage_pagefaults(struct rusage
*r
)
303 #if defined(_SQUID_SGI_) && _ABIAPI
316 struct rusage rusage
;
317 squid_getrusage(&rusage
);
318 fprintf(debug_log
, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
319 rusage_cputime(&rusage
),
320 rusage
.ru_utime
.tv_sec
+ ((double) rusage
.ru_utime
.tv_usec
/ 1000000.0),
321 rusage
.ru_stime
.tv_sec
+ ((double) rusage
.ru_stime
.tv_usec
/ 1000000.0));
322 fprintf(debug_log
, "Maximum Resident Size: %d KB\n",
323 rusage_maxrss(&rusage
));
324 fprintf(debug_log
, "Page faults with physical i/o: %d\n",
325 rusage_pagefaults(&rusage
));
333 fprintf(debug_log
, "FATAL: Received Segment Violation...dying.\n");
334 else if (sig
== SIGBUS
)
335 fprintf(debug_log
, "FATAL: Received Bus Error...dying.\n");
337 fprintf(debug_log
, "FATAL: Received signal %d...dying.\n", sig
);
339 #ifdef PRINT_STACK_TRACE
342 extern void U_STACK_TRACE(void); /* link with -lcl */
344 dup2(fileno(debug_log
), 2);
348 #endif /* _SQUID_HPUX_ */
349 #ifdef _SQUID_SOLARIS_
350 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
351 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
353 dup2(fileno(debug_log
), fileno(stdout
));
358 #endif /* _SQUID_SOLARIS_ */
359 #if HAVE_BACKTRACE_SYMBOLS_FD
361 static void *(callarray
[8192]);
363 n
= backtrace(callarray
, 8192);
364 backtrace_symbols_fd(callarray
, n
, fileno(debug_log
));
368 #endif /* PRINT_STACK_TRACE */
370 #if SA_RESETHAND == 0 && !defined(_SQUID_MSWIN_)
371 signal(SIGSEGV
, SIG_DFL
);
373 signal(SIGBUS
, SIG_DFL
);
375 signal(sig
, SIG_DFL
);
379 releaseServerSockets();
381 storeDirWriteCleanLogs(0);
383 if (!shutting_down
) {
389 if (squid_curtime
- SQUID_RELEASE_TIME
< 864000) {
390 /* skip if more than 10 days old */
392 if (Config
.adminEmail
)
406 sigusr2_handle(int sig
)
408 static int state
= 0;
409 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
412 #ifndef MEM_GEN_TRACE
413 Debug::parseOptions("ALL,7");
421 #ifndef MEM_GEN_TRACE
422 Debug::parseOptions(Config
.debugOptions
);
425 log_trace_init("/tmp/squid.alloc");
432 if (signal(sig
, sigusr2_handle
) == SIG_ERR
) /* reinstall */
433 debugs(50, 0, "signal: sig=" << sig
<< " func=sigusr2_handle: " << xstrerror());
439 fatal_common(const char *message
)
442 syslog(LOG_ALERT
, "%s", message
);
445 fprintf(debug_log
, "FATAL: %s\n", message
);
447 if (opt_debug_stderr
> 0 && debug_log
!= stderr
)
448 fprintf(stderr
, "FATAL: %s\n", message
);
450 fprintf(debug_log
, "Squid Cache (Version %s): Terminated abnormally.\n",
462 fatal(const char *message
)
464 releaseServerSockets();
465 /* check for store_dirs_rebuilding because fatal() is often
466 * used in early initialization phases, long before we ever
467 * get to the store log. */
469 /* XXX: this should be turned into a callback-on-fatal, or
470 * a mandatory-shutdown-event or something like that.
476 * Call leave_suid() here to make sure that swap.state files
477 * are written as the effective user, rather than root. Squid
478 * may take on root privs during reconfigure. If squid.conf
479 * contains a "Bungled" line, fatal() will be called when the
480 * process still has root privs.
484 if (0 == StoreController::store_dirs_rebuilding
)
485 storeDirWriteCleanLogs(0);
487 fatal_common(message
);
492 /* printf-style interface for fatal */
495 fatalf(const char *fmt
,...)
505 const char *fmt
= NULL
;
507 fmt
= va_arg(args
, char *);
517 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
) {
526 failure_notify
= NULL
;
527 releaseServerSockets();
530 fatal_common(message
);
533 * Call leave_suid() here to make sure that swap.state files
534 * are written as the effective user, rather than root. Squid
535 * may take on root privs during reconfigure. If squid.conf
536 * contains a "Bungled" line, fatal() will be called when the
537 * process still has root privs.
541 if (opt_catch_signals
)
542 storeDirWriteCleanLogs(0);
548 debug_trap(const char *message
) {
549 if (!opt_catch_signals
)
552 _db_print("WARNING: %s\n", message
);
557 #ifndef _SQUID_MSWIN_
569 pid
= wait3(&status
, WNOHANG
, NULL
);
572 pid
= waitpid(-1, &status
, WNOHANG
);
574 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
583 while (pid
> 0 || (pid
< 0 && errno
== EINTR
));
584 signal(sig
, sig_child
);
593 LOCAL_ARRAY(char, host
, SQUIDHOSTNAMELEN
+ 1);
594 static int present
= 0;
595 struct addrinfo
*AI
= NULL
;
598 if (Config
.visibleHostname
!= NULL
)
599 return Config
.visibleHostname
;
606 if (Config
.Sockaddr
.http
&& sa
.IsAnyAddr())
607 sa
= Config
.Sockaddr
.http
->s
;
611 if (Config
.Sockaddr
.https
&& sa
.IsAnyAddr())
612 sa
= Config
.Sockaddr
.https
->http
.s
;
617 * If the first http_port address has a specific address, try a
618 * reverse DNS lookup on it.
620 if( !sa
.IsAnyAddr() ) {
623 /* we are looking for a name. */
624 if(xgetnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, host
, SQUIDHOSTNAMELEN
, NULL
, 0, NI_NAMEREQD
) == 0) {
625 /* DNS lookup successful */
626 /* use the official name from DNS lookup */
627 debugs(50, 4, "getMyHostname: resolved " << sa
<< " to '" << host
<< "'");
633 if (strchr(host
, '.'))
638 debugs(50, 1, "WARNING: failed to resolve " << sa
<< " to a fully qualified hostname");
641 if (gethostname(host
, SQUIDHOSTNAMELEN
) < 0) {
642 debugs(50, 1, "WARNING: gethostname failed: " << xstrerror());
645 /* Verify that the hostname given resolves properly */
646 struct addrinfo hints
;
647 memset(&hints
, 0, sizeof(addrinfo
));
648 hints
.ai_flags
= AI_CANONNAME
;
650 if(xgetaddrinfo(host
, NULL
, NULL
, &AI
) == 0) {
651 /* DNS lookup successful */
652 /* use the official name from DNS lookup */
653 debugs(50, 6, "getMyHostname: '" << host
<< "' resolved into '" << AI
->ai_canonname
<< "'");
654 xstrncpy(host
, AI
->ai_canonname
, SQUIDHOSTNAMELEN
);
657 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
666 if(AI
) xfreeaddrinfo(AI
);
667 debugs(50, 1, "WARNING: getaddrinfo('" << host
<< "') failed: " << xstrerror());
671 /* throw a fatal configuration error when the Host/IP given has bad DNS/rDNS. */
672 if (opt_send_signal
== -1)
673 fatal("Could not determine fully qualified hostname. Please set 'visible_hostname'\n");
675 return ("localhost");
677 return NULL
; /* keep compiler happy */
683 return Config
.uniqueHostname
? Config
.uniqueHostname
: getMyHostname();
686 /* leave a privilegied section. (Give up any privilegies)
687 * Routines that need privilegies can rap themselves in enter_suid()
689 * To give upp all posibilites to gain privilegies use no_suid()
694 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
696 if (Config
.effectiveGroup
) {
700 setgroups(1, &Config2
.effectiveGroupID
);
704 if (setgid(Config2
.effectiveGroupID
) < 0)
705 debugs(50, 0, "ALERT: setgid: " << xstrerror());
712 /* Started as a root, check suid option */
713 if (Config
.effectiveUser
== NULL
)
716 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config
.effectiveUser
<< "'");
718 if (!Config
.effectiveGroup
) {
720 if (setgid(Config2
.effectiveGroupID
) < 0)
721 debugs(50, 0, "ALERT: setgid: " << xstrerror());
723 if (initgroups(Config
.effectiveUser
, Config2
.effectiveGroupID
) < 0) {
724 debugs(50, 0, "ALERT: initgroups: unable to set groups for User " <<
725 Config
.effectiveUser
<< " and Group " <<
726 (unsigned) Config2
.effectiveGroupID
<< "");
732 if (setresuid(Config2
.effectiveUserID
, Config2
.effectiveUserID
, 0) < 0)
733 debugs(50, 0, "ALERT: setresuid: " << xstrerror());
737 if (seteuid(Config2
.effectiveUserID
) < 0)
738 debugs(50, 0, "ALERT: seteuid: " << xstrerror());
742 if (setuid(Config2
.effectiveUserID
) < 0)
743 debugs(50, 0, "ALERT: setuid: " << xstrerror());
747 restoreCapabilities(1);
749 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
750 /* Set Linux DUMPABLE flag */
751 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
752 debugs(50, 2, "ALERT: prctl: " << xstrerror());
757 /* Enter a privilegied section */
761 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root priveleges");
764 setresuid((uid_t
)-1, 0, (uid_t
)-1);
769 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
770 /* Set Linux DUMPABLE flag */
772 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
773 debugs(50, 2, "ALERT: prctl: " << xstrerror());
778 /* Give up the posibility to gain privilegies.
779 * this should be used before starting a sub process
787 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
792 debugs(50, 1, "no_suid: setuid: " << xstrerror());
794 restoreCapabilities(0);
796 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
797 /* Set Linux DUMPABLE flag */
798 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
799 debugs(50, 2, "ALERT: prctl: " << xstrerror());
808 const char *f
= NULL
;
812 if ((f
= Config
.pidFilename
) == NULL
)
815 if (!strcmp(Config
.pidFilename
, "none"))
820 old_umask
= umask(022);
822 fd
= file_open(f
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
);
829 debugs(50, 0, "" << f
<< ": " << xstrerror());
830 debug_trap("Could not write pid file");
834 snprintf(buf
, 32, "%d\n", (int) getpid());
835 FD_WRITE_METHOD(fd
, buf
, strlen(buf
));
844 const char *f
= Config
.pidFilename
;
845 char *chroot_f
= NULL
;
849 if (f
== NULL
|| !strcmp(Config
.pidFilename
, "none")) {
850 fprintf(stderr
, "%s: ERROR: No pid file name defined\n", appname
);
854 if (Config
.chroot_dir
&& geteuid() == 0) {
855 int len
= strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1;
856 chroot_f
= (char *)xmalloc(strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1);
857 snprintf(chroot_f
, len
, "%s/%s", Config
.chroot_dir
, f
);
861 pid_fp
= fopen(f
, "r");
863 if (pid_fp
!= NULL
) {
866 if (fscanf(pid_fp
, "%d", &i
) == 1)
871 if (errno
!= ENOENT
) {
872 fprintf(stderr
, "%s: ERROR: Could not read pid file\n", appname
);
873 fprintf(stderr
, "\t%s: %s\n", f
, xstrerror());
887 /* try to use as many file descriptors as possible */
888 /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
891 #if defined(RLIMIT_NOFILE)
893 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
894 debugs(50, 0, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
896 rl
.rlim_cur
= Squid_MaxFD
;
898 if (rl
.rlim_cur
> rl
.rlim_max
)
899 Squid_MaxFD
= rl
.rlim_cur
= rl
.rlim_max
;
901 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
902 snprintf(tmp_error_buf
, ERROR_BUF_SZ
,
903 "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
904 fatal_dump(tmp_error_buf
);
908 #elif defined(RLIMIT_OFILE)
909 if (getrlimit(RLIMIT_OFILE
, &rl
) < 0) {
910 debugs(50, 0, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
912 rl
.rlim_cur
= Squid_MaxFD
;
914 if (rl
.rlim_cur
> rl
.rlim_max
)
915 Squid_MaxFD
= rl
.rlim_cur
= rl
.rlim_max
;
917 if (setrlimit(RLIMIT_OFILE
, &rl
) < 0) {
918 snprintf(tmp_error_buf
, ERROR_BUF_SZ
,
919 "setrlimit: RLIMIT_OFILE: %s", xstrerror());
920 fatal_dump(tmp_error_buf
);
925 #else /* HAVE_SETRLIMIT */
926 debugs(21, 1, "setMaxFD: Cannot increase: setrlimit() not supported on this system");
928 #endif /* HAVE_SETRLIMIT */
930 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
932 if (getrlimit(RLIMIT_DATA
, &rl
) < 0) {
933 debugs(50, 0, "getrlimit: RLIMIT_DATA: " << xstrerror());
934 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
935 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
937 if (setrlimit(RLIMIT_DATA
, &rl
) < 0) {
938 snprintf(tmp_error_buf
, ERROR_BUF_SZ
,
939 "setrlimit: RLIMIT_DATA: %s", xstrerror());
940 fatal_dump(tmp_error_buf
);
944 #endif /* RLIMIT_DATA */
945 #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
946 if (getrlimit(RLIMIT_VMEM
, &rl
) < 0) {
947 debugs(50, 0, "getrlimit: RLIMIT_VMEM: " << xstrerror());
948 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
949 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
951 if (setrlimit(RLIMIT_VMEM
, &rl
) < 0) {
952 snprintf(tmp_error_buf
, ERROR_BUF_SZ
,
953 "setrlimit: RLIMIT_VMEM: %s", xstrerror());
954 fatal_dump(tmp_error_buf
);
958 #endif /* RLIMIT_VMEM */
962 percent(int a
, int b
)
964 return b
? ((int) (100.0 * a
/ b
+ 0.5)) : 0;
968 dpercent(double a
, double b
)
970 return b
? (100.0 * a
/ b
) : 0.0;
974 squid_signal(int sig
, SIGHDLR
* func
, int flags
)
979 sa
.sa_handler
= func
;
981 sigemptyset(&sa
.sa_mask
);
983 if (sigaction(sig
, &sa
, NULL
) < 0)
984 debugs(50, 0, "sigaction: sig=" << sig
<< " func=" << func
<< ": " << xstrerror());
989 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
990 are supported, so we must care of don't call signal() for other value.
991 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
992 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
1010 WIN32_ExceptionHandlerInit();
1014 WIN32_ExceptionHandlerInit();
1016 break; /* Nor reached */
1020 break; /* Nor reached */
1031 doubleAverage(double cur
, double newD
, int N
, int max
)
1036 return (cur
* (N
- 1.0) + newD
) / N
;
1040 intAverage(int cur
, int newI
, int n
, int max
)
1045 return (cur
* (n
- 1) + newI
) / n
;
1056 kb_incr(kb_t
* k
, size_t v
)
1059 k
->kb
+= (k
->bytes
>> 10);
1064 debugObj(int section
, int level
, const char *label
, void *obj
, ObjPackMethod pm
)
1068 assert(label
&& obj
&& pm
);
1070 packerToMemInit(&p
, &mb
);
1072 debugs(section
, level
, "" << label
<< "" << mb
.buf
<< "");
1086 if (NULL
== Config
.etcHostsPath
)
1089 if (0 == strcmp(Config
.etcHostsPath
, "none"))
1092 fp
= fopen(Config
.etcHostsPath
, "r");
1095 debugs(1, 1, "parseEtcHosts: " << Config
.etcHostsPath
<< ": " << xstrerror());
1099 #ifdef _SQUID_WIN32_
1100 setmode(fileno(fp
), O_TEXT
);
1104 while (fgets(buf
, 1024, fp
)) { /* for each line */
1105 wordlist
*hosts
= NULL
;
1108 if (buf
[0] == '#') /* MS-windows likes to add comments */
1111 strtok(buf
, "#"); /* chop everything following a comment marker */
1117 debugs(1, 5, "etc_hosts: line is '" << buf
<< "'");
1119 nt
= strpbrk(lt
, w_space
);
1121 if (nt
== NULL
) /* empty line */
1124 *nt
= '\0'; /* null-terminate the address */
1126 debugs(1, 5, "etc_hosts: address is '" << addr
<< "'");
1130 while ((nt
= strpbrk(lt
, w_space
))) {
1133 if (nt
== lt
) { /* multiple spaces */
1134 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
1140 debugs(1, 5, "etc_hosts: got hostname '" << lt
<< "'");
1142 if (Config
.appendDomain
&& !strchr(lt
, '.')) {
1143 /* I know it's ugly, but it's only at reconfig */
1144 strncpy(buf2
, lt
, 512);
1145 strncat(buf2
, Config
.appendDomain
, 512 - strlen(lt
) - 1);
1151 if (ipcacheAddEntryFromHosts(host
, addr
) != 0)
1152 goto skip
; /* invalid address, continuing is useless */
1154 wordlistAdd(&hosts
, host
);
1159 fqdncacheAddEntryFromHosts(addr
, hosts
);
1162 wordlistDestroy(&hosts
);
1171 if (Config
.Sockaddr
.http
)
1172 return Config
.Sockaddr
.http
->s
.GetPort();
1176 if (Config
.Sockaddr
.https
)
1177 return Config
.Sockaddr
.https
->http
.s
.GetPort();
1181 fatal("No port defined");
1183 return 0; /* NOT REACHED */
1188 * Inverse of strwordtok. Quotes a word if needed
1191 strwordquote(MemBuf
* mb
, const char *str
)
1195 if (strchr(str
, ' ')) {
1197 mb
->append("\"", 1);
1201 int l
= strcspn(str
, "\"\\\n\r");
1208 mb
->append("\\n", 2);
1213 mb
->append("\\r", 2);
1221 mb
->append("\\", 1);
1229 mb
->append("\"", 1);
1233 keepCapabilities(void)
1235 #if HAVE_PRCTL && defined(PR_SET_KEEPCAPS) && HAVE_SYS_CAPABILITY_H
1237 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0)) {
1238 /* Silent failure unless TPROXY is required. Maybe not started as root */
1239 #if LINUX_TPROXY2 || LINUX_TPROXY4
1241 if (need_linux_tproxy
)
1242 debugs(1, 1, "Error - tproxy support requires capability setting which has failed. Continuing without tproxy support");
1244 need_linux_tproxy
= 0;
1253 restoreCapabilities(int keep
)
1255 #if defined(_SQUID_LINUX_) && HAVE_SYS_CAPABILITY_H
1256 cap_user_header_t head
= (cap_user_header_t
) xcalloc(1, sizeof(cap_user_header_t
));
1257 cap_user_data_t cap
= (cap_user_data_t
) xcalloc(1, sizeof(cap_user_data_t
));
1259 head
->version
= _LINUX_CAPABILITY_VERSION
;
1261 if (capget(head
, cap
) != 0) {
1262 debugs(50, 1, "Can't get current capabilities");
1266 if (head
->version
!= _LINUX_CAPABILITY_VERSION
) {
1267 debugs(50, 1, "Invalid capability version " << head
->version
<< " (expected " << _LINUX_CAPABILITY_VERSION
<< ")");
1273 cap
->inheritable
= 0;
1274 cap
->effective
= (1 << CAP_NET_BIND_SERVICE
);
1277 if (need_linux_tproxy
)
1278 cap
->effective
|= (1 << CAP_NET_ADMIN
) | (1 << CAP_NET_BROADCAST
);
1280 if (need_linux_tproxy
)
1281 cap
->effective
|= (1 << CAP_NET_ADMIN
);
1286 cap
->permitted
&= cap
->effective
;
1288 if (capset(head
, cap
) != 0) {
1289 /* Silent failure unless TPROXY is required */
1290 #if LINUX_TPROXY2 || LINUX_TPROXY4
1292 if (need_linux_tproxy
)
1293 debugs(50, 1, "Error enabling needed capabilities. Will continue without tproxy support");
1295 need_linux_tproxy
= 0;
1304 #else /* not defined(_SQUID_LINUX_) && HAVE_SYS_CAPABILITY_H */
1306 #if LINUX_TPROXY2 || LINUX_TPROXY4
1308 if (need_linux_tproxy
)
1309 debugs(50, 1, "Missing needed capability support. Will continue without tproxy support");
1311 need_linux_tproxy
= 0;
1318 xmemset(void *dst
, int val
, size_t sz
)
1321 debugs(63, 9, "memset: dst=" << dst
<< ", val=" << val
<< ", bytes=" << sz
);
1323 // call the system one to do the actual work ~safely.
1324 return memset(dst
, val
, sz
);