2 * DEBUG: section 21 Misc Functions
3 * AUTHOR: Harvest Derived
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "anyp/PortCfg.h"
35 #include "base/Subscription.h"
36 #include "client_side.h"
39 #include "fqdncache.h"
42 #include "ip/Intercept.h"
43 #include "ip/QosConfig.h"
44 #include "ipc/Coordinator.h"
48 #include "SquidConfig.h"
49 #include "SquidMath.h"
50 #include "SquidTime.h"
56 #include <sys/prctl.h>
75 The Squid Cache (version %s) died.\n\
77 You've encountered a fatal error in the Squid Cache version %s.\n\
78 If a core file was created (possibly in the swap directory),\n\
79 please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
80 and report the trace back to squid-bugs@squid-cache.org.\n\
84 static void mail_warranty(void);
86 void log_trace_done();
87 void log_trace_init(char *);
89 static void restoreCapabilities(int keep
);
93 /* Workaround for crappy glic header files */
94 SQUIDCEXTERN
int backtrace(void *, int);
95 SQUIDCEXTERN
void backtrace_symbols_fd(void *, int, int);
96 SQUIDCEXTERN
int setresuid(uid_t
, uid_t
, uid_t
);
97 #else /* _SQUID_LINUX_ */
98 /* needed on Opensolaris for backtrace_symbols_fd */
100 #include <execinfo.h>
101 #endif /* HAVE_EXECINFO_H */
103 #endif /* _SQUID_LINUX */
106 releaseServerSockets(void)
108 // Release the main ports as early as possible
110 // clear both http_port and https_port lists.
111 clientHttpConnectionsClose();
116 // XXX: Why not the HTCP, SNMP, DNS ports as well?
117 // XXX: why does this differ from main closeServerConnections() anyway ?
123 LOCAL_ARRAY(char, msg
, 1024);
124 snprintf(msg
, 1024, DEAD_MSG
, version_string
, version_string
);
132 static char command
[256];
134 const mode_t prev_umask
=umask(S_IRWXU
);
137 char filename
[] = "/tmp/squid-XXXXXX";
138 int tfd
= mkstemp(filename
);
139 if (tfd
< 0 || (fp
= fdopen(tfd
, "w")) == NULL
) {
145 // XXX tempnam is obsolete since POSIX.2008-1
146 // tmpfile is not an option, we want the created files to stick around
147 if ((filename
= tempnam(NULL
, APP_SHORTNAME
)) == NULL
||
148 (fp
= fopen(filename
, "w")) == NULL
) {
155 if (Config
.EmailFrom
)
156 fprintf(fp
, "From: %s\n", Config
.EmailFrom
);
158 fprintf(fp
, "From: %s@%s\n", APP_SHORTNAME
, uniqueHostname());
160 fprintf(fp
, "To: %s\n", Config
.adminEmail
);
161 fprintf(fp
, "Subject: %s\n", dead_msg());
164 snprintf(command
, 256, "%s %s < %s", Config
.EmailProgram
, Config
.adminEmail
, filename
);
165 if (system(command
)) {} /* XXX should avoid system(3) */
168 xfree(filename
); // tempnam() requires us to free its allocation
173 dumpMallocStats(void)
175 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
177 struct mstats ms
= mstats();
178 fprintf(debug_log
, "\ttotal space in arena: %6d KB\n",
179 (int) (ms
.bytes_total
>> 10));
180 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
181 (int) (ms
.bytes_free
>> 10),
182 Math::intPercent(ms
.bytes_free
, ms
.bytes_total
));
183 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
193 fprintf(debug_log
, "Memory usage for " APP_SHORTNAME
" via mallinfo():\n");
195 fprintf(debug_log
, "\ttotal space in arena: %6ld KB\n",
196 (long)mp
.arena
>> 10);
198 fprintf(debug_log
, "\tOrdinary blocks: %6ld KB %6ld blks\n",
199 (long)mp
.uordblks
>> 10, (long)mp
.ordblks
);
201 fprintf(debug_log
, "\tSmall blocks: %6ld KB %6ld blks\n",
202 (long)mp
.usmblks
>> 10, (long)mp
.smblks
);
204 fprintf(debug_log
, "\tHolding blocks: %6ld KB %6ld blks\n",
205 (long)mp
.hblkhd
>> 10, (long)mp
.hblks
);
207 fprintf(debug_log
, "\tFree Small blocks: %6ld KB\n",
208 (long)mp
.fsmblks
>> 10);
210 fprintf(debug_log
, "\tFree Ordinary blocks: %6ld KB\n",
211 (long)mp
.fordblks
>> 10);
213 t
= mp
.uordblks
+ mp
.usmblks
+ mp
.hblkhd
;
215 fprintf(debug_log
, "\tTotal in use: %6d KB %d%%\n",
216 t
>> 10, Math::intPercent(t
, mp
.arena
));
218 t
= mp
.fsmblks
+ mp
.fordblks
;
220 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
221 t
>> 10, Math::intPercent(t
, mp
.arena
));
223 #if HAVE_STRUCT_MALLINFO_MXFAST
225 fprintf(debug_log
, "\tmax size of small blocks:\t%d\n",
228 fprintf(debug_log
, "\tnumber of small blocks in a holding block:\t%d\n",
231 fprintf(debug_log
, "\tsmall block rounding factor:\t%d\n",
234 fprintf(debug_log
, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
237 fprintf(debug_log
, "\tnumber of ordinary blocks allocated:\t%d\n",
240 fprintf(debug_log
, "\tbytes used in maintaining the free tree:\t%d\n",
243 #endif /* HAVE_STRUCT_MALLINFO_MXFAST */
244 #endif /* HAVE_MALLINFO */
248 squid_getrusage(struct rusage
*r
)
250 memset(r
, '\0', sizeof(struct rusage
));
251 #if HAVE_GETRUSAGE && defined(RUSAGE_SELF) && !_SQUID_WINDOWS_
253 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
257 getrusage(RUSAGE_SELF
, r
);
263 #elif _SQUID_WINDOWS_ && HAVE_WIN32_PSAPI
264 // Windows has an alternative method if there is no POSIX getrusage defined.
265 if (WIN32_OS_version
>= _WIN_OS_WINNT
) {
266 /* On Windows NT and later call PSAPI.DLL for process Memory */
267 /* informations -- Guido Serassio */
269 PROCESS_MEMORY_COUNTERS pmc
;
270 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
|
272 FALSE
, GetCurrentProcessId());
274 /* Microsoft CRT doesn't have getrusage function, */
275 /* so we get process CPU time information from PSAPI.DLL. */
276 FILETIME ftCreate
, ftExit
, ftKernel
, ftUser
;
277 if (GetProcessTimes(hProcess
, &ftCreate
, &ftExit
, &ftKernel
, &ftUser
)) {
278 int64_t *ptUser
= (int64_t *)&ftUser
;
279 int64_t tUser64
= *ptUser
/ 10;
280 int64_t *ptKernel
= (int64_t *)&ftKernel
;
281 int64_t tKernel64
= *ptKernel
/ 10;
282 r
->ru_utime
.tv_sec
=(long)(tUser64
/ 1000000);
283 r
->ru_stime
.tv_sec
=(long)(tKernel64
/ 1000000);
284 r
->ru_utime
.tv_usec
=(long)(tUser64
% 1000000);
285 r
->ru_stime
.tv_usec
=(long)(tKernel64
% 1000000);
287 CloseHandle( hProcess
);
291 if (GetProcessMemoryInfo( hProcess
, &pmc
, sizeof(pmc
))) {
292 r
->ru_maxrss
=(DWORD
)(pmc
.WorkingSetSize
/ getpagesize());
293 r
->ru_majflt
=pmc
.PageFaultCount
;
295 CloseHandle( hProcess
);
299 CloseHandle( hProcess
);
306 rusage_cputime(struct rusage
*r
)
308 return (double) r
->ru_stime
.tv_sec
+
309 (double) r
->ru_utime
.tv_sec
+
310 (double) r
->ru_stime
.tv_usec
/ 1000000.0 +
311 (double) r
->ru_utime
.tv_usec
/ 1000000.0;
314 /* Hack for some HP-UX preprocessors */
315 #ifndef HAVE_GETPAGESIZE
316 #define HAVE_GETPAGESIZE 0
321 rusage_maxrss(struct rusage
*r
)
323 #if _SQUID_SGI_ && _ABIAPI
325 #elif _SQUID_SGI_|| _SQUID_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
328 #elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
330 return (r
->ru_maxrss
* getpagesize()) >> 10;
331 #elif defined(PAGESIZE)
333 return (r
->ru_maxrss
* PAGESIZE
) >> 10;
342 rusage_pagefaults(struct rusage
*r
)
344 #if _SQUID_SGI_ && _ABIAPI
356 struct rusage rusage
;
357 squid_getrusage(&rusage
);
358 fprintf(debug_log
, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
359 rusage_cputime(&rusage
),
360 rusage
.ru_utime
.tv_sec
+ ((double) rusage
.ru_utime
.tv_usec
/ 1000000.0),
361 rusage
.ru_stime
.tv_sec
+ ((double) rusage
.ru_stime
.tv_usec
/ 1000000.0));
362 fprintf(debug_log
, "Maximum Resident Size: %d KB\n",
363 rusage_maxrss(&rusage
));
364 fprintf(debug_log
, "Page faults with physical i/o: %d\n",
365 rusage_pagefaults(&rusage
));
372 fprintf(debug_log
, "FATAL: Received Segment Violation...dying.\n");
373 else if (sig
== SIGBUS
)
374 fprintf(debug_log
, "FATAL: Received Bus Error...dying.\n");
376 fprintf(debug_log
, "FATAL: Received signal %d...dying.\n", sig
);
378 #if PRINT_STACK_TRACE
381 extern void U_STACK_TRACE(void); /* link with -lcl */
383 dup2(fileno(debug_log
), 2);
387 #endif /* _SQUID_HPUX_ */
388 #if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
389 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
390 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
392 dup2(fileno(debug_log
), fileno(stdout
));
397 #endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
398 #if HAVE_BACKTRACE_SYMBOLS_FD
400 static void *(callarray
[8192]);
402 n
= backtrace(callarray
, 8192);
403 backtrace_symbols_fd(callarray
, n
, fileno(debug_log
));
407 #endif /* PRINT_STACK_TRACE */
409 #if SA_RESETHAND == 0 && !_SQUID_WINDOWS_
410 signal(SIGSEGV
, SIG_DFL
);
412 signal(SIGBUS
, SIG_DFL
);
414 signal(sig
, SIG_DFL
);
418 releaseServerSockets();
420 storeDirWriteCleanLogs(0);
422 if (!shutting_down
) {
428 if (squid_curtime
- SQUID_RELEASE_TIME
< 864000) {
429 /* skip if more than 10 days old */
431 if (Config
.adminEmail
)
441 BroadcastSignalIfAny(int& sig
)
444 if (IamCoordinatorProcess())
445 Ipc::Coordinator::Instance()->broadcastSignal(sig
);
451 sigusr2_handle(int sig
)
453 static int state
= 0;
454 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
460 Debug::parseOptions("ALL,7");
469 Debug::parseOptions(Debug::debugOptions
);
472 log_trace_init("/tmp/squid.alloc");
479 if (signal(sig
, sigusr2_handle
) == SIG_ERR
) /* reinstall */
480 debugs(50, DBG_CRITICAL
, "signal: sig=" << sig
<< " func=sigusr2_handle: " << xstrerror());
486 debug_trap(const char *message
)
488 if (!opt_catch_signals
)
491 _db_print("WARNING: %s\n", message
);
509 pid
= wait3(&status
, WNOHANG
, NULL
);
512 pid
= waitpid(-1, &status
, WNOHANG
);
514 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
523 while (pid
> 0 || (pid
< 0 && errno
== EINTR
));
524 signal(sig
, sig_child
);
531 sig_shutdown(int sig
)
539 LOCAL_ARRAY(char, host
, SQUIDHOSTNAMELEN
+ 1);
540 static int present
= 0;
541 struct addrinfo
*AI
= NULL
;
544 if (Config
.visibleHostname
!= NULL
)
545 return Config
.visibleHostname
;
552 if (Config
.Sockaddr
.http
&& sa
.isAnyAddr())
553 sa
= Config
.Sockaddr
.http
->s
;
557 if (Config
.Sockaddr
.https
&& sa
.isAnyAddr())
558 sa
= Config
.Sockaddr
.https
->s
;
563 * If the first http_port address has a specific address, try a
564 * reverse DNS lookup on it.
566 if ( !sa
.isAnyAddr() ) {
569 /* we are looking for a name. */
570 if (getnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, host
, SQUIDHOSTNAMELEN
, NULL
, 0, NI_NAMEREQD
) == 0) {
571 /* DNS lookup successful */
572 /* use the official name from DNS lookup */
573 debugs(50, 4, "getMyHostname: resolved " << sa
<< " to '" << host
<< "'");
577 Ip::Address::FreeAddrInfo(AI
);
579 if (strchr(host
, '.'))
583 Ip::Address::FreeAddrInfo(AI
);
584 debugs(50, 2, "WARNING: failed to resolve " << sa
<< " to a fully qualified hostname");
587 // still no host. fallback to gethostname()
588 if (gethostname(host
, SQUIDHOSTNAMELEN
) < 0) {
589 debugs(50, DBG_IMPORTANT
, "WARNING: gethostname failed: " << xstrerror());
591 /* Verify that the hostname given resolves properly */
592 struct addrinfo hints
;
593 memset(&hints
, 0, sizeof(addrinfo
));
594 hints
.ai_flags
= AI_CANONNAME
;
596 if (getaddrinfo(host
, NULL
, NULL
, &AI
) == 0) {
597 /* DNS lookup successful */
598 /* use the official name from DNS lookup */
599 debugs(50, 6, "getMyHostname: '" << host
<< "' has DNS resolution.");
602 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
611 debugs(50, DBG_IMPORTANT
, "WARNING: '" << host
<< "' rDNS test failed: " << xstrerror());
614 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
615 debugs(50, DBG_CRITICAL
, "WARNING: Could not determine this machines public hostname. " <<
616 "Please configure one or set 'visible_hostname'.");
618 return ("localhost");
624 debugs(21, 3, HERE
<< " Config: '" << Config
.uniqueHostname
<< "'");
625 return Config
.uniqueHostname
? Config
.uniqueHostname
: getMyHostname();
628 /** leave a priviliged section. (Give up any privilegies)
629 * Routines that need privilegies can rap themselves in enter_suid()
631 * To give upp all posibilites to gain privilegies use no_suid()
636 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
638 if (Config
.effectiveGroup
) {
642 setgroups(1, &Config2
.effectiveGroupID
);
646 if (setgid(Config2
.effectiveGroupID
) < 0)
647 debugs(50, DBG_CRITICAL
, "ALERT: setgid: " << xstrerror());
654 /* Started as a root, check suid option */
655 if (Config
.effectiveUser
== NULL
)
658 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config
.effectiveUser
<< "'");
660 if (!Config
.effectiveGroup
) {
662 if (setgid(Config2
.effectiveGroupID
) < 0)
663 debugs(50, DBG_CRITICAL
, "ALERT: setgid: " << xstrerror());
665 if (initgroups(Config
.effectiveUser
, Config2
.effectiveGroupID
) < 0) {
666 debugs(50, DBG_CRITICAL
, "ALERT: initgroups: unable to set groups for User " <<
667 Config
.effectiveUser
<< " and Group " <<
668 (unsigned) Config2
.effectiveGroupID
<< "");
674 if (setresuid(Config2
.effectiveUserID
, Config2
.effectiveUserID
, 0) < 0)
675 debugs(50, DBG_CRITICAL
, "ALERT: setresuid: " << xstrerror());
679 if (seteuid(Config2
.effectiveUserID
) < 0)
680 debugs(50, DBG_CRITICAL
, "ALERT: seteuid: " << xstrerror());
684 if (setuid(Config2
.effectiveUserID
) < 0)
685 debugs(50, DBG_CRITICAL
, "ALERT: setuid: " << xstrerror());
689 restoreCapabilities(1);
691 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
692 /* Set Linux DUMPABLE flag */
693 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
694 debugs(50, 2, "ALERT: prctl: " << xstrerror());
699 /* Enter a privilegied section */
703 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root privileges");
705 if (setresuid((uid_t
)-1, 0, (uid_t
)-1) < 0)
706 debugs (21, 3, "enter_suid: setresuid failed: " << xstrerror ());
711 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
712 /* Set Linux DUMPABLE flag */
714 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
715 debugs(50, 2, "ALERT: prctl: " << xstrerror());
720 /* Give up the posibility to gain privilegies.
721 * this should be used before starting a sub process
729 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
732 debugs(50, DBG_IMPORTANT
, "WARNING: no_suid: setuid(0): " << xstrerror());
735 debugs(50, DBG_IMPORTANT
, "ERROR: no_suid: setuid(" << uid
<< "): " << xstrerror());
737 restoreCapabilities(0);
739 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
740 /* Set Linux DUMPABLE flag */
741 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
742 debugs(50, 2, "ALERT: prctl: " << xstrerror());
750 return KidIdentifier
== 0;
756 // when there is only one process, it has to be the worker
757 if (opt_no_daemon
|| Config
.workers
== 0)
760 return TheProcessKind
== pkWorker
;
766 return TheProcessKind
== pkDisker
;
772 return !opt_no_daemon
&& Config
.workers
> 0;
778 return InDaemonMode() && NumberOfKids() > 1;
782 IamCoordinatorProcess()
784 return TheProcessKind
== pkCoordinator
;
790 // when there is only one process, it has to be primary
791 if (opt_no_daemon
|| Config
.workers
== 0)
794 // when there is a master and worker process, the master delegates
795 // primary functions to its only kid
796 if (NumberOfKids() == 1)
797 return IamWorkerProcess();
799 // in SMP mode, multiple kids delegate primary functions to the coordinator
800 return IamCoordinatorProcess();
806 // no kids in no-daemon mode
810 // XXX: detect and abort when called before workers/cache_dirs are parsed
812 const int rockDirs
= Config
.cacheSwap
.n_strands
;
814 const bool needCoord
= Config
.workers
> 1 || rockDirs
> 0;
815 return (needCoord
? 1 : 0) + Config
.workers
+ rockDirs
;
822 if (IamMasterProcess())
823 roles
.append(" master");
824 if (IamCoordinatorProcess())
825 roles
.append(" coordinator");
826 if (IamWorkerProcess())
827 roles
.append(" worker");
828 if (IamDiskProcess())
829 roles
.append(" disker");
837 const char *f
= NULL
;
841 if (!IamPrimaryProcess())
844 if ((f
= Config
.pidFilename
) == NULL
)
847 if (!strcmp(Config
.pidFilename
, "none"))
852 old_umask
= umask(022);
854 fd
= file_open(f
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
);
861 debugs(50, DBG_CRITICAL
, "" << f
<< ": " << xstrerror());
862 debug_trap("Could not write pid file");
866 snprintf(buf
, 32, "%d\n", (int) getpid());
867 FD_WRITE_METHOD(fd
, buf
, strlen(buf
));
875 const char *f
= Config
.pidFilename
;
876 char *chroot_f
= NULL
;
880 if (f
== NULL
|| !strcmp(Config
.pidFilename
, "none")) {
881 fprintf(stderr
, APP_SHORTNAME
": ERROR: No pid file name defined\n");
885 if (Config
.chroot_dir
&& geteuid() == 0) {
886 int len
= strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1;
887 chroot_f
= (char *)xmalloc(strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1);
888 snprintf(chroot_f
, len
, "%s/%s", Config
.chroot_dir
, f
);
892 pid_fp
= fopen(f
, "r");
894 if (pid_fp
!= NULL
) {
897 if (fscanf(pid_fp
, "%d", &i
) == 1)
902 if (errno
!= ENOENT
) {
903 fprintf(stderr
, APP_SHORTNAME
": ERROR: Could not read pid file\n");
904 fprintf(stderr
, "\t%s: %s\n", f
, xstrerror());
913 /* A little piece of glue for odd systems */
914 #ifndef RLIMIT_NOFILE
916 #define RLIMIT_NOFILE RLIMIT_OFILE
920 /** Figure out the number of supported filedescriptors */
924 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
926 /* On Linux with 64-bit file support the sys/resource.h header
927 * uses #define to change the function definition to require rlimit64
929 #if defined(getrlimit)
930 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
935 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
936 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
937 } else if (Config
.max_filedescriptors
> 0) {
938 #if USE_SELECT || USE_SELECT_WIN32
939 /* select() breaks if this gets set too big */
940 if (Config
.max_filedescriptors
> FD_SETSIZE
) {
941 rl
.rlim_cur
= FD_SETSIZE
;
942 debugs(50, DBG_CRITICAL
, "WARNING: 'max_filedescriptors " << Config
.max_filedescriptors
<< "' does not work with select()");
945 rl
.rlim_cur
= Config
.max_filedescriptors
;
946 if (rl
.rlim_cur
> rl
.rlim_max
)
947 rl
.rlim_max
= rl
.rlim_cur
;
948 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
949 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerror());
950 getrlimit(RLIMIT_NOFILE
, &rl
);
951 rl
.rlim_cur
= rl
.rlim_max
;
952 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
953 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerror());
957 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
958 debugs(50, DBG_CRITICAL
, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerror());
960 Squid_MaxFD
= rl
.rlim_cur
;
963 #endif /* HAVE_SETRLIMIT */
967 setSystemLimits(void)
969 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
970 /* limit system filedescriptors to our own limit */
972 /* On Linux with 64-bit file support the sys/resource.h header
973 * uses #define to change the function definition to require rlimit64
975 #if defined(getrlimit)
976 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
981 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
982 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
984 rl
.rlim_cur
= Squid_MaxFD
;
985 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
986 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
987 fatal_dump(tmp_error_buf
);
990 #endif /* HAVE_SETRLIMIT */
992 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
993 if (getrlimit(RLIMIT_DATA
, &rl
) < 0) {
994 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_DATA: " << xstrerror());
995 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
996 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
998 if (setrlimit(RLIMIT_DATA
, &rl
) < 0) {
999 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_DATA: %s", xstrerror());
1000 fatal_dump(tmp_error_buf
);
1003 #endif /* RLIMIT_DATA */
1004 if (Config
.max_filedescriptors
> Squid_MaxFD
) {
1005 debugs(50, DBG_IMPORTANT
, "NOTICE: Could not increase the number of filedescriptors");
1008 #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
1009 if (getrlimit(RLIMIT_VMEM
, &rl
) < 0) {
1010 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_VMEM: " << xstrerror());
1011 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
1012 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
1014 if (setrlimit(RLIMIT_VMEM
, &rl
) < 0) {
1015 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_VMEM: %s", xstrerror());
1016 fatal_dump(tmp_error_buf
);
1019 #endif /* RLIMIT_VMEM */
1023 squid_signal(int sig
, SIGHDLR
* func
, int flags
)
1027 struct sigaction sa
;
1028 sa
.sa_handler
= func
;
1029 sa
.sa_flags
= flags
;
1030 sigemptyset(&sa
.sa_mask
);
1032 if (sigaction(sig
, &sa
, NULL
) < 0)
1033 debugs(50, DBG_CRITICAL
, "sigaction: sig=" << sig
<< " func=" << func
<< ": " << xstrerror());
1038 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
1039 are supported, so we must care of don't call signal() for other value.
1040 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
1041 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
1059 WIN32_ExceptionHandlerInit();
1063 WIN32_ExceptionHandlerInit();
1065 break; /* Nor reached */
1069 break; /* Nor reached */
1087 kb_incr(kb_t
* k
, size_t v
)
1090 k
->kb
+= (k
->bytes
>> 10);
1095 debugObj(int section
, int level
, const char *label
, void *obj
, ObjPackMethod pm
)
1099 assert(label
&& obj
&& pm
);
1101 packerToMemInit(&p
, &mb
);
1103 debugs(section
, level
, "" << label
<< "" << mb
.buf
<< "");
1117 if (NULL
== Config
.etcHostsPath
)
1120 if (0 == strcmp(Config
.etcHostsPath
, "none"))
1123 fp
= fopen(Config
.etcHostsPath
, "r");
1126 debugs(1, DBG_IMPORTANT
, "parseEtcHosts: " << Config
.etcHostsPath
<< ": " << xstrerror());
1131 setmode(fileno(fp
), O_TEXT
);
1134 while (fgets(buf
, 1024, fp
)) { /* for each line */
1135 wordlist
*hosts
= NULL
;
1138 if (buf
[0] == '#') /* MS-windows likes to add comments */
1141 strtok(buf
, "#"); /* chop everything following a comment marker */
1147 debugs(1, 5, "etc_hosts: line is '" << buf
<< "'");
1149 nt
= strpbrk(lt
, w_space
);
1151 if (nt
== NULL
) /* empty line */
1154 *nt
= '\0'; /* null-terminate the address */
1156 debugs(1, 5, "etc_hosts: address is '" << addr
<< "'");
1160 while ((nt
= strpbrk(lt
, w_space
))) {
1163 if (nt
== lt
) { /* multiple spaces */
1164 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
1170 debugs(1, 5, "etc_hosts: got hostname '" << lt
<< "'");
1172 /* For IPV6 addresses also check for a colon */
1173 if (Config
.appendDomain
&& !strchr(lt
, '.') && !strchr(lt
, ':')) {
1174 /* I know it's ugly, but it's only at reconfig */
1175 strncpy(buf2
, lt
, sizeof(buf2
)-1);
1176 strncat(buf2
, Config
.appendDomain
, sizeof(buf2
) - strlen(lt
) - 1);
1177 buf2
[sizeof(buf2
)-1] = '\0';
1183 if (ipcacheAddEntryFromHosts(host
, addr
) != 0) {
1184 /* invalid address, continuing is useless */
1185 wordlistDestroy(&hosts
);
1189 wordlistAdd(&hosts
, host
);
1195 fqdncacheAddEntryFromHosts(addr
, hosts
);
1196 wordlistDestroy(&hosts
);
1206 AnyP::PortCfg
*p
= NULL
;
1207 if ((p
= Config
.Sockaddr
.http
)) {
1208 // skip any special interception ports
1209 while (p
&& p
->flags
.isIntercepted())
1216 if ((p
= Config
.Sockaddr
.https
)) {
1217 // skip any special interception ports
1218 while (p
&& p
->flags
.isIntercepted())
1225 debugs(21, DBG_CRITICAL
, "ERROR: No forward-proxy ports configured.");
1226 return 0; // Invalid port. This will result in invalid URLs on bad configurations.
1230 * Set the umask to at least the given mask. This is in addition
1231 * to the umask set at startup
1234 setUmask(mode_t mask
)
1236 // No way to get the current umask value without setting it.
1237 static const mode_t orig_umask
= umask(mask
); // once, to get
1238 umask(mask
| orig_umask
); // always, to set
1242 * Inverse of strwordtok. Quotes a word if needed
1245 strwordquote(MemBuf
* mb
, const char *str
)
1249 if (strchr(str
, ' ')) {
1251 mb
->append("\"", 1);
1255 int l
= strcspn(str
, "\"\\\n\r");
1262 mb
->append("\\n", 2);
1267 mb
->append("\\r", 2);
1275 mb
->append("\\", 1);
1283 mb
->append("\"", 1);
1287 keepCapabilities(void)
1289 #if USE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
1291 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0)) {
1292 Ip::Interceptor
.StopTransparency("capability setting has failed.");
1298 restoreCapabilities(int keep
)
1300 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
1304 caps
= cap_get_proc();
1308 Ip::Interceptor
.StopTransparency("Can't get current capabilities");
1312 cap_value_t cap_list
[10];
1313 cap_list
[ncaps
] = CAP_NET_BIND_SERVICE
;
1315 if (Ip::Interceptor
.TransparentActive() || Ip::Qos::TheConfig
.isHitNfmarkActive() || Ip::Qos::TheConfig
.isAclNfmarkActive()) {
1316 cap_list
[ncaps
] = CAP_NET_ADMIN
;
1320 cap_clear_flag(caps
, CAP_EFFECTIVE
);
1321 rc
|= cap_set_flag(caps
, CAP_EFFECTIVE
, ncaps
, cap_list
, CAP_SET
);
1322 rc
|= cap_set_flag(caps
, CAP_PERMITTED
, ncaps
, cap_list
, CAP_SET
);
1324 if (rc
|| cap_set_proc(caps
) != 0) {
1325 Ip::Interceptor
.StopTransparency("Error enabling needed capabilities.");
1330 Ip::Interceptor
.StopTransparency("Missing needed capability support.");
1331 #endif /* HAVE_SYS_CAPABILITY_H */