2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 21 Misc Functions */
12 #include "anyp/PortCfg.h"
13 #include "base/Subscription.h"
14 #include "client_side.h"
17 #include "fqdncache.h"
20 #include "ip/Intercept.h"
21 #include "ip/QosConfig.h"
22 #include "ipc/Coordinator.h"
26 #include "SquidConfig.h"
27 #include "SquidMath.h"
28 #include "SquidTime.h"
35 #include <sys/prctl.h>
51 The Squid Cache (version %s) died.\n\
53 You've encountered a fatal error in the Squid Cache version %s.\n\
54 If a core file was created (possibly in the swap directory),\n\
55 please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
56 and report the trace back to squid-bugs@squid-cache.org.\n\
60 static void mail_warranty(void);
61 static void restoreCapabilities(bool keep
);
63 SBuf
service_name(APP_SHORTNAME
);
66 /* Workaround for crappy glic header files */
67 SQUIDCEXTERN
int backtrace(void *, int);
68 SQUIDCEXTERN
void backtrace_symbols_fd(void *, int, int);
69 SQUIDCEXTERN
int setresuid(uid_t
, uid_t
, uid_t
);
70 #else /* _SQUID_LINUX_ */
71 /* needed on Opensolaris for backtrace_symbols_fd */
74 #endif /* HAVE_EXECINFO_H */
76 #endif /* _SQUID_LINUX */
79 releaseServerSockets(void)
81 // Release the main ports as early as possible
83 // clear http_port, https_port, and ftp_port lists
84 clientConnectionsClose();
89 // XXX: Why not the HTCP, SNMP, DNS ports as well?
90 // XXX: why does this differ from main closeServerConnections() anyway ?
96 LOCAL_ARRAY(char, msg
, 1024);
97 snprintf(msg
, 1024, DEAD_MSG
, version_string
, version_string
);
105 static char command
[256];
108 * NP: umask() takes the mask of bits we DONT want set.
110 * We want the current user to have read/write access
111 * and since this file will be passed to mailsystem,
112 * the group and other must have read access.
114 const mode_t prev_umask
=umask(S_IXUSR
|S_IXGRP
|S_IWGRP
|S_IWOTH
|S_IXOTH
);
117 char filename
[] = "/tmp/squid-XXXXXX";
118 int tfd
= mkstemp(filename
);
119 if (tfd
< 0 || (fp
= fdopen(tfd
, "w")) == NULL
) {
125 // XXX tempnam is obsolete since POSIX.2008-1
126 // tmpfile is not an option, we want the created files to stick around
127 if ((filename
= tempnam(NULL
, APP_SHORTNAME
)) == NULL
||
128 (fp
= fopen(filename
, "w")) == NULL
) {
135 if (Config
.EmailFrom
)
136 fprintf(fp
, "From: %s\n", Config
.EmailFrom
);
138 fprintf(fp
, "From: %s@%s\n", APP_SHORTNAME
, uniqueHostname());
140 fprintf(fp
, "To: %s\n", Config
.adminEmail
);
141 fprintf(fp
, "Subject: %s\n", dead_msg());
144 snprintf(command
, 256, "%s %s < %s", Config
.EmailProgram
, Config
.adminEmail
, filename
);
145 if (system(command
)) {} /* XXX should avoid system(3) */
148 xfree(filename
); // tempnam() requires us to free its allocation
153 dumpMallocStats(void)
155 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
157 struct mstats ms
= mstats();
158 fprintf(debug_log
, "\ttotal space in arena: %6d KB\n",
159 (int) (ms
.bytes_total
>> 10));
160 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
161 (int) (ms
.bytes_free
>> 10),
162 Math::intPercent(ms
.bytes_free
, ms
.bytes_total
));
167 squid_getrusage(struct rusage
*r
)
169 memset(r
, '\0', sizeof(struct rusage
));
170 #if HAVE_GETRUSAGE && defined(RUSAGE_SELF) && !_SQUID_WINDOWS_
172 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
176 getrusage(RUSAGE_SELF
, r
);
182 #elif _SQUID_WINDOWS_ && HAVE_WIN32_PSAPI
183 // Windows has an alternative method if there is no POSIX getrusage defined.
184 if (WIN32_OS_version
>= _WIN_OS_WINNT
) {
185 /* On Windows NT and later call PSAPI.DLL for process Memory */
186 /* informations -- Guido Serassio */
188 PROCESS_MEMORY_COUNTERS pmc
;
189 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
|
191 FALSE
, GetCurrentProcessId());
193 /* Microsoft CRT doesn't have getrusage function, */
194 /* so we get process CPU time information from PSAPI.DLL. */
195 FILETIME ftCreate
, ftExit
, ftKernel
, ftUser
;
196 if (GetProcessTimes(hProcess
, &ftCreate
, &ftExit
, &ftKernel
, &ftUser
)) {
197 int64_t *ptUser
= (int64_t *)&ftUser
;
198 int64_t tUser64
= *ptUser
/ 10;
199 int64_t *ptKernel
= (int64_t *)&ftKernel
;
200 int64_t tKernel64
= *ptKernel
/ 10;
201 r
->ru_utime
.tv_sec
=(long)(tUser64
/ 1000000);
202 r
->ru_stime
.tv_sec
=(long)(tKernel64
/ 1000000);
203 r
->ru_utime
.tv_usec
=(long)(tUser64
% 1000000);
204 r
->ru_stime
.tv_usec
=(long)(tKernel64
% 1000000);
206 CloseHandle( hProcess
);
210 if (GetProcessMemoryInfo( hProcess
, &pmc
, sizeof(pmc
))) {
211 r
->ru_maxrss
=(DWORD
)(pmc
.WorkingSetSize
/ getpagesize());
212 r
->ru_majflt
=pmc
.PageFaultCount
;
214 CloseHandle( hProcess
);
218 CloseHandle( hProcess
);
225 rusage_cputime(struct rusage
*r
)
227 return (double) r
->ru_stime
.tv_sec
+
228 (double) r
->ru_utime
.tv_sec
+
229 (double) r
->ru_stime
.tv_usec
/ 1000000.0 +
230 (double) r
->ru_utime
.tv_usec
/ 1000000.0;
233 /* Hack for some HP-UX preprocessors */
234 #ifndef HAVE_GETPAGESIZE
235 #define HAVE_GETPAGESIZE 0
240 rusage_maxrss(struct rusage
*r
)
242 #if _SQUID_SGI_ && _ABIAPI
244 #elif _SQUID_SGI_|| _SQUID_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
247 #elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
249 return (r
->ru_maxrss
* getpagesize()) >> 10;
250 #elif defined(PAGESIZE)
252 return (r
->ru_maxrss
* PAGESIZE
) >> 10;
261 rusage_pagefaults(struct rusage
*r
)
263 #if _SQUID_SGI_ && _ABIAPI
275 struct rusage rusage
;
276 squid_getrusage(&rusage
);
277 fprintf(debug_log
, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
278 rusage_cputime(&rusage
),
279 rusage
.ru_utime
.tv_sec
+ ((double) rusage
.ru_utime
.tv_usec
/ 1000000.0),
280 rusage
.ru_stime
.tv_sec
+ ((double) rusage
.ru_stime
.tv_usec
/ 1000000.0));
281 fprintf(debug_log
, "Maximum Resident Size: %d KB\n",
282 rusage_maxrss(&rusage
));
283 fprintf(debug_log
, "Page faults with physical i/o: %d\n",
284 rusage_pagefaults(&rusage
));
291 fprintf(debug_log
, "FATAL: Received Segment Violation...dying.\n");
292 else if (sig
== SIGBUS
)
293 fprintf(debug_log
, "FATAL: Received Bus Error...dying.\n");
295 fprintf(debug_log
, "FATAL: Received signal %d...dying.\n", sig
);
297 #if PRINT_STACK_TRACE
300 extern void U_STACK_TRACE(void); /* link with -lcl */
302 dup2(fileno(debug_log
), 2);
306 #endif /* _SQUID_HPUX_ */
307 #if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
308 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
309 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
311 dup2(fileno(debug_log
), fileno(stdout
));
316 #endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
317 #if HAVE_BACKTRACE_SYMBOLS_FD
319 static void *(callarray
[8192]);
321 n
= backtrace(callarray
, 8192);
322 backtrace_symbols_fd(callarray
, n
, fileno(debug_log
));
326 #endif /* PRINT_STACK_TRACE */
328 #if SA_RESETHAND == 0 && !_SQUID_WINDOWS_
329 signal(SIGSEGV
, SIG_DFL
);
331 signal(SIGBUS
, SIG_DFL
);
333 signal(sig
, SIG_DFL
);
337 releaseServerSockets();
339 storeDirWriteCleanLogs(0);
341 if (!shutting_down
) {
347 if (squid_curtime
- SQUID_RELEASE_TIME
< 864000) {
348 /* skip if more than 10 days old */
350 if (Config
.adminEmail
)
360 BroadcastSignalIfAny(int& sig
)
363 if (IamMasterProcess()) {
364 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
365 Kid
& kid
= TheKids
.get(i
);
366 kill(kid
.getPid(), sig
);
374 sigusr2_handle(int sig
)
376 static int state
= 0;
377 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
382 Debug::parseOptions("ALL,7");
385 Debug::parseOptions(Debug::debugOptions
);
390 if (signal(sig
, sigusr2_handle
) == SIG_ERR
) /* reinstall */
391 debugs(50, DBG_CRITICAL
, "signal: sig=" << sig
<< " func=sigusr2_handle: " << xstrerror());
397 debug_trap(const char *message
)
399 if (!opt_catch_signals
)
402 _db_print("WARNING: %s\n", message
);
408 LOCAL_ARRAY(char, host
, SQUIDHOSTNAMELEN
+ 1);
409 static int present
= 0;
410 struct addrinfo
*AI
= NULL
;
413 if (Config
.visibleHostname
!= NULL
)
414 return Config
.visibleHostname
;
421 if (HttpPortList
!= NULL
&& sa
.isAnyAddr())
422 sa
= HttpPortList
->s
;
426 if (HttpsPortList
!= NULL
&& sa
.isAnyAddr())
427 sa
= HttpsPortList
->s
;
432 * If the first http_port address has a specific address, try a
433 * reverse DNS lookup on it.
435 if ( !sa
.isAnyAddr() ) {
438 /* we are looking for a name. */
439 if (getnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, host
, SQUIDHOSTNAMELEN
, NULL
, 0, NI_NAMEREQD
) == 0) {
440 /* DNS lookup successful */
441 /* use the official name from DNS lookup */
442 debugs(50, 4, "getMyHostname: resolved " << sa
<< " to '" << host
<< "'");
446 Ip::Address::FreeAddr(AI
);
448 if (strchr(host
, '.'))
452 Ip::Address::FreeAddr(AI
);
453 debugs(50, 2, "WARNING: failed to resolve " << sa
<< " to a fully qualified hostname");
456 // still no host. fallback to gethostname()
457 if (gethostname(host
, SQUIDHOSTNAMELEN
) < 0) {
458 debugs(50, DBG_IMPORTANT
, "WARNING: gethostname failed: " << xstrerror());
460 /* Verify that the hostname given resolves properly */
461 struct addrinfo hints
;
462 memset(&hints
, 0, sizeof(addrinfo
));
463 hints
.ai_flags
= AI_CANONNAME
;
465 if (getaddrinfo(host
, NULL
, NULL
, &AI
) == 0) {
466 /* DNS lookup successful */
467 /* use the official name from DNS lookup */
468 debugs(50, 6, "getMyHostname: '" << host
<< "' has DNS resolution.");
471 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
480 debugs(50, DBG_IMPORTANT
, "WARNING: '" << host
<< "' rDNS test failed: " << xstrerror());
483 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
484 debugs(50, DBG_CRITICAL
, "WARNING: Could not determine this machines public hostname. " <<
485 "Please configure one or set 'visible_hostname'.");
487 return ("localhost");
493 debugs(21, 3, HERE
<< " Config: '" << Config
.uniqueHostname
<< "'");
494 return Config
.uniqueHostname
? Config
.uniqueHostname
: getMyHostname();
497 /** leave a priviliged section. (Give up any privilegies)
498 * Routines that need privilegies can rap themselves in enter_suid()
500 * To give upp all posibilites to gain privilegies use no_suid()
505 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
507 if (Config
.effectiveGroup
) {
511 setgroups(1, &Config2
.effectiveGroupID
);
515 if (setgid(Config2
.effectiveGroupID
) < 0)
516 debugs(50, DBG_CRITICAL
, "ALERT: setgid: " << xstrerror());
523 /* Started as a root, check suid option */
524 if (Config
.effectiveUser
== NULL
)
527 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config
.effectiveUser
<< "'");
529 if (!Config
.effectiveGroup
) {
531 if (setgid(Config2
.effectiveGroupID
) < 0)
532 debugs(50, DBG_CRITICAL
, "ALERT: setgid: " << xstrerror());
534 if (initgroups(Config
.effectiveUser
, Config2
.effectiveGroupID
) < 0) {
535 debugs(50, DBG_CRITICAL
, "ALERT: initgroups: unable to set groups for User " <<
536 Config
.effectiveUser
<< " and Group " <<
537 (unsigned) Config2
.effectiveGroupID
<< "");
543 if (setresuid(Config2
.effectiveUserID
, Config2
.effectiveUserID
, 0) < 0)
544 debugs(50, DBG_CRITICAL
, "ALERT: setresuid: " << xstrerror());
548 if (seteuid(Config2
.effectiveUserID
) < 0)
549 debugs(50, DBG_CRITICAL
, "ALERT: seteuid: " << xstrerror());
553 if (setuid(Config2
.effectiveUserID
) < 0)
554 debugs(50, DBG_CRITICAL
, "ALERT: setuid: " << xstrerror());
558 restoreCapabilities(true);
560 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
561 /* Set Linux DUMPABLE flag */
562 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
563 debugs(50, 2, "ALERT: prctl: " << xstrerror());
568 /* Enter a privilegied section */
572 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root privileges");
574 if (setresuid((uid_t
)-1, 0, (uid_t
)-1) < 0)
575 debugs (21, 3, "enter_suid: setresuid failed: " << xstrerror ());
580 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
581 /* Set Linux DUMPABLE flag */
583 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
584 debugs(50, 2, "ALERT: prctl: " << xstrerror());
589 /* Give up the posibility to gain privilegies.
590 * this should be used before starting a sub process
598 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
601 debugs(50, DBG_IMPORTANT
, "WARNING: no_suid: setuid(0): " << xstrerror());
604 debugs(50, DBG_IMPORTANT
, "ERROR: no_suid: setuid(" << uid
<< "): " << xstrerror());
606 restoreCapabilities(false);
608 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
609 /* Set Linux DUMPABLE flag */
610 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
611 debugs(50, 2, "ALERT: prctl: " << xstrerror());
619 return KidIdentifier
== 0;
625 // when there is only one process, it has to be the worker
626 if (opt_no_daemon
|| Config
.workers
== 0)
629 return TheProcessKind
== pkWorker
;
635 return TheProcessKind
== pkDisker
;
641 return !opt_no_daemon
&& Config
.workers
> 0;
647 return InDaemonMode() && NumberOfKids() > 1;
651 IamCoordinatorProcess()
653 return TheProcessKind
== pkCoordinator
;
659 // when there is only one process, it has to be primary
660 if (opt_no_daemon
|| Config
.workers
== 0)
663 // when there is a master and worker process, the master delegates
664 // primary functions to its only kid
665 if (NumberOfKids() == 1)
666 return IamWorkerProcess();
668 // in SMP mode, multiple kids delegate primary functions to the coordinator
669 return IamCoordinatorProcess();
675 // no kids in no-daemon mode
679 // XXX: detect and abort when called before workers/cache_dirs are parsed
681 const int rockDirs
= Config
.cacheSwap
.n_strands
;
683 const bool needCoord
= Config
.workers
> 1 || rockDirs
> 0;
684 return (needCoord
? 1 : 0) + Config
.workers
+ rockDirs
;
691 if (IamMasterProcess())
692 roles
.append(" master");
693 if (IamCoordinatorProcess())
694 roles
.append(" coordinator");
695 if (IamWorkerProcess())
696 roles
.append(" worker");
697 if (IamDiskProcess())
698 roles
.append(" disker");
706 const char *f
= NULL
;
710 if ((f
= Config
.pidFilename
) == NULL
)
713 if (!strcmp(Config
.pidFilename
, "none"))
718 old_umask
= umask(022);
720 fd
= open(f
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
, 0644);
727 debugs(50, DBG_CRITICAL
, "" << f
<< ": " << xstrerror());
728 debug_trap("Could not write pid file");
732 snprintf(buf
, 32, "%d\n", (int) getpid());
733 const size_t ws
= write(fd
, buf
, strlen(buf
));
734 assert(ws
== strlen(buf
));
741 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
743 safeunlink(Config
.pidFilename
, 0);
752 const char *f
= Config
.pidFilename
;
753 char *chroot_f
= NULL
;
757 if (f
== NULL
|| !strcmp(Config
.pidFilename
, "none")) {
758 fprintf(stderr
, APP_SHORTNAME
": ERROR: No pid file name defined\n");
762 if (Config
.chroot_dir
&& geteuid() == 0) {
763 int len
= strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1;
764 chroot_f
= (char *)xmalloc(strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1);
765 snprintf(chroot_f
, len
, "%s/%s", Config
.chroot_dir
, f
);
769 pid_fp
= fopen(f
, "r");
771 if (pid_fp
!= NULL
) {
774 if (fscanf(pid_fp
, "%d", &i
) == 1)
779 if (errno
!= ENOENT
) {
780 fprintf(stderr
, APP_SHORTNAME
": ERROR: Could not read pid file\n");
781 fprintf(stderr
, "\t%s: %s\n", f
, xstrerror());
790 /* A little piece of glue for odd systems */
791 #ifndef RLIMIT_NOFILE
793 #define RLIMIT_NOFILE RLIMIT_OFILE
797 /** Figure out the number of supported filedescriptors */
801 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
803 /* On Linux with 64-bit file support the sys/resource.h header
804 * uses #define to change the function definition to require rlimit64
806 #if defined(getrlimit)
807 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
812 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
813 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
814 } else if (Config
.max_filedescriptors
> 0) {
815 #if USE_SELECT || USE_SELECT_WIN32
816 /* select() breaks if this gets set too big */
817 if (Config
.max_filedescriptors
> FD_SETSIZE
) {
818 rl
.rlim_cur
= FD_SETSIZE
;
819 debugs(50, DBG_CRITICAL
, "WARNING: 'max_filedescriptors " << Config
.max_filedescriptors
<< "' does not work with select()");
822 rl
.rlim_cur
= Config
.max_filedescriptors
;
823 if (rl
.rlim_cur
> rl
.rlim_max
)
824 rl
.rlim_max
= rl
.rlim_cur
;
825 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
826 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerror());
827 getrlimit(RLIMIT_NOFILE
, &rl
);
828 rl
.rlim_cur
= rl
.rlim_max
;
829 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
830 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerror());
834 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
835 debugs(50, DBG_CRITICAL
, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerror());
837 Squid_MaxFD
= rl
.rlim_cur
;
840 #endif /* HAVE_SETRLIMIT */
844 setSystemLimits(void)
846 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
847 /* limit system filedescriptors to our own limit */
849 /* On Linux with 64-bit file support the sys/resource.h header
850 * uses #define to change the function definition to require rlimit64
852 #if defined(getrlimit)
853 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
858 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
859 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
861 rl
.rlim_cur
= Squid_MaxFD
;
862 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
863 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
864 fatal_dump(tmp_error_buf
);
867 #endif /* HAVE_SETRLIMIT */
869 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
870 if (getrlimit(RLIMIT_DATA
, &rl
) < 0) {
871 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_DATA: " << xstrerror());
872 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
873 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
875 if (setrlimit(RLIMIT_DATA
, &rl
) < 0) {
876 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_DATA: %s", xstrerror());
877 fatal_dump(tmp_error_buf
);
880 #endif /* RLIMIT_DATA */
881 if (Config
.max_filedescriptors
> Squid_MaxFD
) {
882 debugs(50, DBG_IMPORTANT
, "NOTICE: Could not increase the number of filedescriptors");
885 #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
886 if (getrlimit(RLIMIT_VMEM
, &rl
) < 0) {
887 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_VMEM: " << xstrerror());
888 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
889 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
891 if (setrlimit(RLIMIT_VMEM
, &rl
) < 0) {
892 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_VMEM: %s", xstrerror());
893 fatal_dump(tmp_error_buf
);
896 #endif /* RLIMIT_VMEM */
900 squid_signal(int sig
, SIGHDLR
* func
, int flags
)
905 sa
.sa_handler
= func
;
907 sigemptyset(&sa
.sa_mask
);
909 if (sigaction(sig
, &sa
, NULL
) < 0)
910 debugs(50, DBG_CRITICAL
, "sigaction: sig=" << sig
<< " func=" << func
<< ": " << xstrerror());
915 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
916 are supported, so we must care of don't call signal() for other value.
917 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
918 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
936 WIN32_ExceptionHandlerInit();
940 WIN32_ExceptionHandlerInit();
942 break; /* Nor reached */
946 break; /* Nor reached */
964 kb_incr(kb_t
* k
, size_t v
)
967 k
->kb
+= (k
->bytes
>> 10);
972 debugObj(int section
, int level
, const char *label
, void *obj
, ObjPackMethod pm
)
976 assert(label
&& obj
&& pm
);
978 packerToMemInit(&p
, &mb
);
980 debugs(section
, level
, "" << label
<< "" << mb
.buf
<< "");
994 if (NULL
== Config
.etcHostsPath
)
997 if (0 == strcmp(Config
.etcHostsPath
, "none"))
1000 fp
= fopen(Config
.etcHostsPath
, "r");
1003 debugs(1, DBG_IMPORTANT
, "parseEtcHosts: " << Config
.etcHostsPath
<< ": " << xstrerror());
1008 setmode(fileno(fp
), O_TEXT
);
1011 while (fgets(buf
, 1024, fp
)) { /* for each line */
1012 wordlist
*hosts
= NULL
;
1015 if (buf
[0] == '#') /* MS-windows likes to add comments */
1018 strtok(buf
, "#"); /* chop everything following a comment marker */
1024 debugs(1, 5, "etc_hosts: line is '" << buf
<< "'");
1026 nt
= strpbrk(lt
, w_space
);
1028 if (nt
== NULL
) /* empty line */
1031 *nt
= '\0'; /* null-terminate the address */
1033 debugs(1, 5, "etc_hosts: address is '" << addr
<< "'");
1037 while ((nt
= strpbrk(lt
, w_space
))) {
1040 if (nt
== lt
) { /* multiple spaces */
1041 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
1047 debugs(1, 5, "etc_hosts: got hostname '" << lt
<< "'");
1049 /* For IPV6 addresses also check for a colon */
1050 if (Config
.appendDomain
&& !strchr(lt
, '.') && !strchr(lt
, ':')) {
1051 /* I know it's ugly, but it's only at reconfig */
1052 strncpy(buf2
, lt
, sizeof(buf2
)-1);
1053 strncat(buf2
, Config
.appendDomain
, sizeof(buf2
) - strlen(lt
) - 1);
1054 buf2
[sizeof(buf2
)-1] = '\0';
1060 if (ipcacheAddEntryFromHosts(host
, addr
) != 0) {
1061 /* invalid address, continuing is useless */
1062 wordlistDestroy(&hosts
);
1066 wordlistAdd(&hosts
, host
);
1072 fqdncacheAddEntryFromHosts(addr
, hosts
);
1073 wordlistDestroy(&hosts
);
1083 AnyP::PortCfgPointer p
;
1084 if ((p
= HttpPortList
) != NULL
) {
1085 // skip any special interception ports
1086 while (p
!= NULL
&& p
->flags
.isIntercepted())
1093 if ((p
= HttpsPortList
) != NULL
) {
1094 // skip any special interception ports
1095 while (p
!= NULL
&& p
->flags
.isIntercepted())
1102 if ((p
= FtpPortList
) != NULL
) {
1103 // skip any special interception ports
1104 while (p
!= NULL
&& p
->flags
.isIntercepted())
1110 debugs(21, DBG_CRITICAL
, "ERROR: No forward-proxy ports configured.");
1111 return 0; // Invalid port. This will result in invalid URLs on bad configurations.
1115 * Set the umask to at least the given mask. This is in addition
1116 * to the umask set at startup
1119 setUmask(mode_t mask
)
1121 // No way to get the current umask value without setting it.
1122 static const mode_t orig_umask
= umask(mask
); // once, to get
1123 umask(mask
| orig_umask
); // always, to set
1127 * Inverse of strwordtok. Quotes a word if needed
1130 strwordquote(MemBuf
* mb
, const char *str
)
1134 if (strchr(str
, ' ')) {
1136 mb
->append("\"", 1);
1140 int l
= strcspn(str
, "\"\\\n\r");
1147 mb
->append("\\n", 2);
1152 mb
->append("\\r", 2);
1160 mb
->append("\\", 1);
1168 mb
->append("\"", 1);
1172 keepCapabilities(void)
1174 #if USE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
1176 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0)) {
1177 Ip::Interceptor
.StopTransparency("capability setting has failed.");
1183 restoreCapabilities(bool keep
)
1185 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
1189 caps
= cap_get_proc();
1193 Ip::Interceptor
.StopTransparency("Can't get current capabilities");
1197 cap_value_t cap_list
[10];
1198 cap_list
[ncaps
] = CAP_NET_BIND_SERVICE
;
1200 if (Ip::Interceptor
.TransparentActive() ||
1201 Ip::Qos::TheConfig
.isHitNfmarkActive() ||
1202 Ip::Qos::TheConfig
.isAclNfmarkActive() ||
1203 Ip::Qos::TheConfig
.isAclTosActive()) {
1204 cap_list
[ncaps
] = CAP_NET_ADMIN
;
1208 cap_clear_flag(caps
, CAP_EFFECTIVE
);
1209 rc
|= cap_set_flag(caps
, CAP_EFFECTIVE
, ncaps
, cap_list
, CAP_SET
);
1210 rc
|= cap_set_flag(caps
, CAP_PERMITTED
, ncaps
, cap_list
, CAP_SET
);
1212 if (rc
|| cap_set_proc(caps
) != 0) {
1213 Ip::Interceptor
.StopTransparency("Error enabling needed capabilities.");
1218 Ip::Interceptor
.StopTransparency("Missing needed capability support.");
1219 #endif /* HAVE_SYS_CAPABILITY_H */
1223 WaitForOnePid(pid_t pid
, PidStatus
&status
, int flags
)
1227 return wait3(&status
, flags
, NULL
);
1228 return wait4(cpid
, &status
, flags
, NULL
);
1230 return waitpid(pid
, &status
, flags
);