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 "ProtoPort.h"
41 #include "SquidTime.h"
42 #include "ip/IpIntercept.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
, APP_SHORTNAME
)) == 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", APP_SHORTNAME
, 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 if (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 "APP_SHORTNAME
" via mallinfo():\n");
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 /* suppress secondary errors from the dying */
467 releaseServerSockets();
468 /* check for store_dirs_rebuilding because fatal() is often
469 * used in early initialization phases, long before we ever
470 * get to the store log. */
472 /* XXX: this should be turned into a callback-on-fatal, or
473 * a mandatory-shutdown-event or something like that.
479 * Call leave_suid() here to make sure that swap.state files
480 * are written as the effective user, rather than root. Squid
481 * may take on root privs during reconfigure. If squid.conf
482 * contains a "Bungled" line, fatal() will be called when the
483 * process still has root privs.
487 if (0 == StoreController::store_dirs_rebuilding
)
488 storeDirWriteCleanLogs(0);
490 fatal_common(message
);
495 /* printf-style interface for fatal */
497 fatalf(const char *fmt
,...)
508 fatalvf(const char *fmt
, va_list args
) {
509 static char fatal_str
[BUFSIZ
];
510 vsnprintf(fatal_str
, sizeof(fatal_str
), fmt
, args
);
514 /* fatal with dumping core */
516 fatal_dump(const char *message
) {
517 failure_notify
= NULL
;
518 releaseServerSockets();
521 fatal_common(message
);
524 * Call leave_suid() here to make sure that swap.state files
525 * are written as the effective user, rather than root. Squid
526 * may take on root privs during reconfigure. If squid.conf
527 * contains a "Bungled" line, fatal() will be called when the
528 * process still has root privs.
532 if (opt_catch_signals
)
533 storeDirWriteCleanLogs(0);
539 debug_trap(const char *message
) {
540 if (!opt_catch_signals
)
543 _db_print("WARNING: %s\n", message
);
548 #ifndef _SQUID_MSWIN_
560 pid
= wait3(&status
, WNOHANG
, NULL
);
563 pid
= waitpid(-1, &status
, WNOHANG
);
565 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
574 while (pid
> 0 || (pid
< 0 && errno
== EINTR
));
575 signal(sig
, sig_child
);
584 LOCAL_ARRAY(char, host
, SQUIDHOSTNAMELEN
+ 1);
585 static int present
= 0;
586 struct addrinfo
*AI
= NULL
;
589 if (Config
.visibleHostname
!= NULL
)
590 return Config
.visibleHostname
;
597 if (Config
.Sockaddr
.http
&& sa
.IsAnyAddr())
598 sa
= Config
.Sockaddr
.http
->s
;
602 if (Config
.Sockaddr
.https
&& sa
.IsAnyAddr())
603 sa
= Config
.Sockaddr
.https
->http
.s
;
608 * If the first http_port address has a specific address, try a
609 * reverse DNS lookup on it.
611 if ( !sa
.IsAnyAddr() ) {
614 /* we are looking for a name. */
615 if (xgetnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, host
, SQUIDHOSTNAMELEN
, NULL
, 0, NI_NAMEREQD
) == 0) {
616 /* DNS lookup successful */
617 /* use the official name from DNS lookup */
618 debugs(50, 4, "getMyHostname: resolved " << sa
<< " to '" << host
<< "'");
624 if (strchr(host
, '.'))
629 debugs(50, 1, "WARNING: failed to resolve " << sa
<< " to a fully qualified hostname");
631 if (gethostname(host
, SQUIDHOSTNAMELEN
) < 0) {
632 debugs(50, 1, "WARNING: gethostname failed: " << xstrerror());
634 /* Verify that the hostname given resolves properly */
635 struct addrinfo hints
;
636 memset(&hints
, 0, sizeof(addrinfo
));
637 hints
.ai_flags
= AI_CANONNAME
;
639 if (xgetaddrinfo(host
, NULL
, NULL
, &AI
) == 0) {
640 /* DNS lookup successful */
641 /* use the official name from DNS lookup */
642 debugs(50, 6, "getMyHostname: '" << host
<< "' has rDNS.");
645 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
654 if (AI
) xfreeaddrinfo(AI
);
655 debugs(50, 1, "WARNING: '" << host
<< "' rDNS test failed: " << xstrerror());
659 /* throw a fatal configuration error when the Host/IP given has bad DNS/rDNS. */
660 if (opt_send_signal
== -1)
661 fatal("Could not determine fully qualified hostname. Please set 'visible_hostname'\n");
663 return ("localhost");
665 return NULL
; /* keep compiler happy */
671 debugs(21, 3, HERE
<< " Config: '" << Config
.uniqueHostname
<< "'");
672 return Config
.uniqueHostname
? Config
.uniqueHostname
: getMyHostname();
675 /** leave a priviliged section. (Give up any privilegies)
676 * Routines that need privilegies can rap themselves in enter_suid()
678 * To give upp all posibilites to gain privilegies use no_suid()
683 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
685 if (Config
.effectiveGroup
) {
689 setgroups(1, &Config2
.effectiveGroupID
);
693 if (setgid(Config2
.effectiveGroupID
) < 0)
694 debugs(50, 0, "ALERT: setgid: " << xstrerror());
701 /* Started as a root, check suid option */
702 if (Config
.effectiveUser
== NULL
)
705 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config
.effectiveUser
<< "'");
707 if (!Config
.effectiveGroup
) {
709 if (setgid(Config2
.effectiveGroupID
) < 0)
710 debugs(50, 0, "ALERT: setgid: " << xstrerror());
712 if (initgroups(Config
.effectiveUser
, Config2
.effectiveGroupID
) < 0) {
713 debugs(50, 0, "ALERT: initgroups: unable to set groups for User " <<
714 Config
.effectiveUser
<< " and Group " <<
715 (unsigned) Config2
.effectiveGroupID
<< "");
721 if (setresuid(Config2
.effectiveUserID
, Config2
.effectiveUserID
, 0) < 0)
722 debugs(50, 0, "ALERT: setresuid: " << xstrerror());
726 if (seteuid(Config2
.effectiveUserID
) < 0)
727 debugs(50, 0, "ALERT: seteuid: " << xstrerror());
731 if (setuid(Config2
.effectiveUserID
) < 0)
732 debugs(50, 0, "ALERT: setuid: " << xstrerror());
736 restoreCapabilities(1);
738 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
739 /* Set Linux DUMPABLE flag */
740 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
741 debugs(50, 2, "ALERT: prctl: " << xstrerror());
746 /* Enter a privilegied section */
750 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root priveleges");
753 setresuid((uid_t
)-1, 0, (uid_t
)-1);
758 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
759 /* Set Linux DUMPABLE flag */
761 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
762 debugs(50, 2, "ALERT: prctl: " << xstrerror());
767 /* Give up the posibility to gain privilegies.
768 * this should be used before starting a sub process
776 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
781 debugs(50, 1, "no_suid: setuid: " << xstrerror());
783 restoreCapabilities(0);
785 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
786 /* Set Linux DUMPABLE flag */
787 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
788 debugs(50, 2, "ALERT: prctl: " << xstrerror());
797 const char *f
= NULL
;
801 if ((f
= Config
.pidFilename
) == NULL
)
804 if (!strcmp(Config
.pidFilename
, "none"))
809 old_umask
= umask(022);
811 fd
= file_open(f
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
);
818 debugs(50, 0, "" << f
<< ": " << xstrerror());
819 debug_trap("Could not write pid file");
823 snprintf(buf
, 32, "%d\n", (int) getpid());
824 FD_WRITE_METHOD(fd
, buf
, strlen(buf
));
833 const char *f
= Config
.pidFilename
;
834 char *chroot_f
= NULL
;
838 if (f
== NULL
|| !strcmp(Config
.pidFilename
, "none")) {
839 fprintf(stderr
, APP_SHORTNAME
": ERROR: No pid file name defined\n");
843 if (Config
.chroot_dir
&& geteuid() == 0) {
844 int len
= strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1;
845 chroot_f
= (char *)xmalloc(strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1);
846 snprintf(chroot_f
, len
, "%s/%s", Config
.chroot_dir
, f
);
850 pid_fp
= fopen(f
, "r");
852 if (pid_fp
!= NULL
) {
855 if (fscanf(pid_fp
, "%d", &i
) == 1)
860 if (errno
!= ENOENT
) {
861 fprintf(stderr
, APP_SHORTNAME
": ERROR: Could not read pid file\n");
862 fprintf(stderr
, "\t%s: %s\n", f
, xstrerror());
876 /* try to use as many file descriptors as possible */
877 /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
880 #if defined(RLIMIT_NOFILE)
882 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
883 debugs(50, 0, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
885 rl
.rlim_cur
= Squid_MaxFD
;
887 if (rl
.rlim_cur
> rl
.rlim_max
)
888 Squid_MaxFD
= rl
.rlim_cur
= rl
.rlim_max
;
890 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
891 snprintf(tmp_error_buf
, ERROR_BUF_SZ
,
892 "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
893 fatal_dump(tmp_error_buf
);
897 #elif defined(RLIMIT_OFILE)
898 if (getrlimit(RLIMIT_OFILE
, &rl
) < 0) {
899 debugs(50, 0, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
901 rl
.rlim_cur
= Squid_MaxFD
;
903 if (rl
.rlim_cur
> rl
.rlim_max
)
904 Squid_MaxFD
= rl
.rlim_cur
= rl
.rlim_max
;
906 if (setrlimit(RLIMIT_OFILE
, &rl
) < 0) {
907 snprintf(tmp_error_buf
, ERROR_BUF_SZ
,
908 "setrlimit: RLIMIT_OFILE: %s", xstrerror());
909 fatal_dump(tmp_error_buf
);
914 #else /* HAVE_SETRLIMIT */
915 debugs(21, 1, "setMaxFD: Cannot increase: setrlimit() not supported on this system");
917 #endif /* HAVE_SETRLIMIT */
919 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
921 if (getrlimit(RLIMIT_DATA
, &rl
) < 0) {
922 debugs(50, 0, "getrlimit: RLIMIT_DATA: " << xstrerror());
923 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
924 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
926 if (setrlimit(RLIMIT_DATA
, &rl
) < 0) {
927 snprintf(tmp_error_buf
, ERROR_BUF_SZ
,
928 "setrlimit: RLIMIT_DATA: %s", xstrerror());
929 fatal_dump(tmp_error_buf
);
933 #endif /* RLIMIT_DATA */
934 #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
935 if (getrlimit(RLIMIT_VMEM
, &rl
) < 0) {
936 debugs(50, 0, "getrlimit: RLIMIT_VMEM: " << xstrerror());
937 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
938 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
940 if (setrlimit(RLIMIT_VMEM
, &rl
) < 0) {
941 snprintf(tmp_error_buf
, ERROR_BUF_SZ
,
942 "setrlimit: RLIMIT_VMEM: %s", xstrerror());
943 fatal_dump(tmp_error_buf
);
947 #endif /* RLIMIT_VMEM */
951 percent(int a
, int b
)
953 return b
? ((int) (100.0 * a
/ b
+ 0.5)) : 0;
957 dpercent(double a
, double b
)
959 return b
? (100.0 * a
/ b
) : 0.0;
963 squid_signal(int sig
, SIGHDLR
* func
, int flags
)
968 sa
.sa_handler
= func
;
970 sigemptyset(&sa
.sa_mask
);
972 if (sigaction(sig
, &sa
, NULL
) < 0)
973 debugs(50, 0, "sigaction: sig=" << sig
<< " func=" << func
<< ": " << xstrerror());
978 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
979 are supported, so we must care of don't call signal() for other value.
980 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
981 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
999 WIN32_ExceptionHandlerInit();
1003 WIN32_ExceptionHandlerInit();
1005 break; /* Nor reached */
1009 break; /* Nor reached */
1020 doubleAverage(double cur
, double newD
, int N
, int max
)
1025 return (cur
* (N
- 1.0) + newD
) / N
;
1029 intAverage(int cur
, int newI
, int n
, int max
)
1034 return (cur
* (n
- 1) + newI
) / n
;
1045 kb_incr(kb_t
* k
, size_t v
)
1048 k
->kb
+= (k
->bytes
>> 10);
1053 debugObj(int section
, int level
, const char *label
, void *obj
, ObjPackMethod pm
)
1057 assert(label
&& obj
&& pm
);
1059 packerToMemInit(&p
, &mb
);
1061 debugs(section
, level
, "" << label
<< "" << mb
.buf
<< "");
1075 if (NULL
== Config
.etcHostsPath
)
1078 if (0 == strcmp(Config
.etcHostsPath
, "none"))
1081 fp
= fopen(Config
.etcHostsPath
, "r");
1084 debugs(1, 1, "parseEtcHosts: " << Config
.etcHostsPath
<< ": " << xstrerror());
1088 #ifdef _SQUID_WIN32_
1089 setmode(fileno(fp
), O_TEXT
);
1093 while (fgets(buf
, 1024, fp
)) { /* for each line */
1094 wordlist
*hosts
= NULL
;
1097 if (buf
[0] == '#') /* MS-windows likes to add comments */
1100 strtok(buf
, "#"); /* chop everything following a comment marker */
1106 debugs(1, 5, "etc_hosts: line is '" << buf
<< "'");
1108 nt
= strpbrk(lt
, w_space
);
1110 if (nt
== NULL
) /* empty line */
1113 *nt
= '\0'; /* null-terminate the address */
1115 debugs(1, 5, "etc_hosts: address is '" << addr
<< "'");
1119 while ((nt
= strpbrk(lt
, w_space
))) {
1122 if (nt
== lt
) { /* multiple spaces */
1123 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
1129 debugs(1, 5, "etc_hosts: got hostname '" << lt
<< "'");
1131 if (Config
.appendDomain
&& !strchr(lt
, '.')) {
1132 /* I know it's ugly, but it's only at reconfig */
1133 strncpy(buf2
, lt
, 512);
1134 strncat(buf2
, Config
.appendDomain
, 512 - strlen(lt
) - 1);
1140 if (ipcacheAddEntryFromHosts(host
, addr
) != 0) {
1141 /* invalid address, continuing is useless */
1142 wordlistDestroy(&hosts
);
1146 wordlistAdd(&hosts
, host
);
1152 fqdncacheAddEntryFromHosts(addr
, hosts
);
1153 wordlistDestroy(&hosts
);
1163 if (Config
.Sockaddr
.http
)
1164 return Config
.Sockaddr
.http
->s
.GetPort();
1168 if (Config
.Sockaddr
.https
)
1169 return Config
.Sockaddr
.https
->http
.s
.GetPort();
1173 fatal("No port defined");
1175 return 0; /* NOT REACHED */
1179 * Set the umask to at least the given mask. This is in addition
1180 * to the umask set at startup
1183 setUmask(mode_t mask
)
1185 // No way to get the current umask value without setting it.
1186 static const mode_t orig_umask
= umask(mask
); // once, to get
1187 umask(mask
| orig_umask
); // always, to set
1191 * Inverse of strwordtok. Quotes a word if needed
1194 strwordquote(MemBuf
* mb
, const char *str
)
1198 if (strchr(str
, ' ')) {
1200 mb
->append("\"", 1);
1204 int l
= strcspn(str
, "\"\\\n\r");
1211 mb
->append("\\n", 2);
1216 mb
->append("\\r", 2);
1224 mb
->append("\\", 1);
1232 mb
->append("\"", 1);
1236 keepCapabilities(void)
1238 #if HAVE_PRCTL && defined(PR_SET_KEEPCAPS) && HAVE_SYS_CAPABILITY_H
1240 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0)) {
1241 IpInterceptor
.StopTransparency("capability setting has failed.");
1247 restoreCapabilities(int keep
)
1249 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
1250 #if defined(_SQUID_LINUX_)
1252 #if HAVE_SYS_CAPABILITY_H
1253 #ifndef _LINUX_CAPABILITY_VERSION_1
1254 #define _LINUX_CAPABILITY_VERSION_1 _LINUX_CAPABILITY_VERSION
1256 cap_user_header_t head
= (cap_user_header_t
) xcalloc(1, sizeof(*head
));
1257 cap_user_data_t cap
= (cap_user_data_t
) xcalloc(1, sizeof(*cap
));
1259 head
->version
= _LINUX_CAPABILITY_VERSION_1
;
1261 if (capget(head
, cap
) != 0) {
1262 debugs(50, DBG_IMPORTANT
, "Can't get current capabilities");
1263 } else if (head
->version
!= _LINUX_CAPABILITY_VERSION_1
) {
1264 debugs(50, DBG_IMPORTANT
, "Invalid capability version " << head
->version
<< " (expected " << _LINUX_CAPABILITY_VERSION_1
<< ")");
1269 cap
->inheritable
= 0;
1270 cap
->effective
= (1 << CAP_NET_BIND_SERVICE
);
1272 if (IpInterceptor
.TransparentActive()) {
1273 cap
->effective
|= (1 << CAP_NET_ADMIN
);
1275 cap
->effective
|= (1 << CAP_NET_BROADCAST
);
1280 cap
->permitted
&= cap
->effective
;
1282 if (capset(head
, cap
) != 0) {
1283 IpInterceptor
.StopTransparency("Error enabling needed capabilities.");
1291 IpInterceptor
.StopTransparency("Missing needed capability support.");
1292 #endif /* HAVE_SYS_CAPABILITY_H */
1294 #endif /* !defined(_SQUID_LINUX_) */
1298 xmemset(void *dst
, int val
, size_t sz
)
1301 debugs(63, 9, "memset: dst=" << dst
<< ", val=" << val
<< ", bytes=" << sz
);
1303 // call the system one to do the actual work ~safely.
1304 return memset(dst
, val
, sz
);