2 * Copyright (C) 1996-2017 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 "http/Stream.h"
22 #include "ip/Intercept.h"
23 #include "ip/QosConfig.h"
24 #include "ipc/Coordinator.h"
28 #include "sbuf/Stream.h"
29 #include "SquidConfig.h"
30 #include "SquidMath.h"
31 #include "SquidTime.h"
32 #include "store/Disks.h"
38 #include <sys/prctl.h>
54 The Squid Cache (version %s) died.\n\
56 You've encountered a fatal error in the Squid Cache version %s.\n\
57 If a core file was created (possibly in the swap directory),\n\
58 please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
59 and report the trace back to squid-bugs@lists.squid-cache.org.\n\
63 static void mail_warranty(void);
64 static void restoreCapabilities(bool keep
);
66 SBuf
service_name(APP_SHORTNAME
);
69 /* Workaround for crappy glic header files */
70 SQUIDCEXTERN
int backtrace(void *, int);
71 SQUIDCEXTERN
void backtrace_symbols_fd(void *, int, int);
72 SQUIDCEXTERN
int setresuid(uid_t
, uid_t
, uid_t
);
73 #else /* _SQUID_LINUX_ */
74 /* needed on Opensolaris for backtrace_symbols_fd */
77 #endif /* HAVE_EXECINFO_H */
79 #endif /* _SQUID_LINUX */
82 releaseServerSockets(void)
84 // Release the main ports as early as possible
86 // clear http_port, https_port, and ftp_port lists
87 clientConnectionsClose();
92 // XXX: Why not the HTCP, SNMP, DNS ports as well?
93 // XXX: why does this differ from main closeServerConnections() anyway ?
99 LOCAL_ARRAY(char, msg
, 1024);
100 snprintf(msg
, 1024, DEAD_MSG
, version_string
, version_string
);
108 static char command
[256];
111 * NP: umask() takes the mask of bits we DONT want set.
113 * We want the current user to have read/write access
114 * and since this file will be passed to mailsystem,
115 * the group and other must have read access.
117 const mode_t prev_umask
=umask(S_IXUSR
|S_IXGRP
|S_IWGRP
|S_IWOTH
|S_IXOTH
);
120 char filename
[] = "/tmp/squid-XXXXXX";
121 int tfd
= mkstemp(filename
);
122 if (tfd
< 0 || (fp
= fdopen(tfd
, "w")) == NULL
) {
128 // XXX tempnam is obsolete since POSIX.2008-1
129 // tmpfile is not an option, we want the created files to stick around
130 if ((filename
= tempnam(NULL
, APP_SHORTNAME
)) == NULL
||
131 (fp
= fopen(filename
, "w")) == NULL
) {
138 if (Config
.EmailFrom
)
139 fprintf(fp
, "From: %s\n", Config
.EmailFrom
);
141 fprintf(fp
, "From: %s@%s\n", APP_SHORTNAME
, uniqueHostname());
143 fprintf(fp
, "To: %s\n", Config
.adminEmail
);
144 fprintf(fp
, "Subject: %s\n", dead_msg());
147 snprintf(command
, 256, "%s %s < %s", Config
.EmailProgram
, Config
.adminEmail
, filename
);
148 if (system(command
)) {} /* XXX should avoid system(3) */
151 xfree(filename
); // tempnam() requires us to free its allocation
156 dumpMallocStats(void)
158 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
160 struct mstats ms
= mstats();
161 fprintf(debug_log
, "\ttotal space in arena: %6d KB\n",
162 (int) (ms
.bytes_total
>> 10));
163 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
164 (int) (ms
.bytes_free
>> 10),
165 Math::intPercent(ms
.bytes_free
, ms
.bytes_total
));
170 squid_getrusage(struct rusage
*r
)
172 memset(r
, '\0', sizeof(struct rusage
));
173 #if HAVE_GETRUSAGE && defined(RUSAGE_SELF) && !_SQUID_WINDOWS_
175 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
179 getrusage(RUSAGE_SELF
, r
);
185 #elif _SQUID_WINDOWS_ && HAVE_WIN32_PSAPI
186 // Windows has an alternative method if there is no POSIX getrusage defined.
187 if (WIN32_OS_version
>= _WIN_OS_WINNT
) {
188 /* On Windows NT and later call PSAPI.DLL for process Memory */
189 /* informations -- Guido Serassio */
191 PROCESS_MEMORY_COUNTERS pmc
;
192 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
|
194 FALSE
, GetCurrentProcessId());
196 /* Microsoft CRT doesn't have getrusage function, */
197 /* so we get process CPU time information from PSAPI.DLL. */
198 FILETIME ftCreate
, ftExit
, ftKernel
, ftUser
;
199 if (GetProcessTimes(hProcess
, &ftCreate
, &ftExit
, &ftKernel
, &ftUser
)) {
200 int64_t *ptUser
= (int64_t *)&ftUser
;
201 int64_t tUser64
= *ptUser
/ 10;
202 int64_t *ptKernel
= (int64_t *)&ftKernel
;
203 int64_t tKernel64
= *ptKernel
/ 10;
204 r
->ru_utime
.tv_sec
=(long)(tUser64
/ 1000000);
205 r
->ru_stime
.tv_sec
=(long)(tKernel64
/ 1000000);
206 r
->ru_utime
.tv_usec
=(long)(tUser64
% 1000000);
207 r
->ru_stime
.tv_usec
=(long)(tKernel64
% 1000000);
209 CloseHandle( hProcess
);
213 if (GetProcessMemoryInfo( hProcess
, &pmc
, sizeof(pmc
))) {
214 r
->ru_maxrss
=(DWORD
)(pmc
.WorkingSetSize
/ getpagesize());
215 r
->ru_majflt
=pmc
.PageFaultCount
;
217 CloseHandle( hProcess
);
221 CloseHandle( hProcess
);
228 rusage_cputime(struct rusage
*r
)
230 return (double) r
->ru_stime
.tv_sec
+
231 (double) r
->ru_utime
.tv_sec
+
232 (double) r
->ru_stime
.tv_usec
/ 1000000.0 +
233 (double) r
->ru_utime
.tv_usec
/ 1000000.0;
236 /* Hack for some HP-UX preprocessors */
237 #ifndef HAVE_GETPAGESIZE
238 #define HAVE_GETPAGESIZE 0
243 rusage_maxrss(struct rusage
*r
)
245 #if _SQUID_SGI_ && _ABIAPI
247 #elif _SQUID_SGI_|| _SQUID_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
250 #elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
252 return (r
->ru_maxrss
* getpagesize()) >> 10;
253 #elif defined(PAGESIZE)
255 return (r
->ru_maxrss
* PAGESIZE
) >> 10;
264 rusage_pagefaults(struct rusage
*r
)
266 #if _SQUID_SGI_ && _ABIAPI
278 struct rusage rusage
;
279 squid_getrusage(&rusage
);
280 fprintf(debug_log
, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
281 rusage_cputime(&rusage
),
282 rusage
.ru_utime
.tv_sec
+ ((double) rusage
.ru_utime
.tv_usec
/ 1000000.0),
283 rusage
.ru_stime
.tv_sec
+ ((double) rusage
.ru_stime
.tv_usec
/ 1000000.0));
284 fprintf(debug_log
, "Maximum Resident Size: %d KB\n",
285 rusage_maxrss(&rusage
));
286 fprintf(debug_log
, "Page faults with physical i/o: %d\n",
287 rusage_pagefaults(&rusage
));
294 fprintf(debug_log
, "FATAL: Received Segment Violation...dying.\n");
295 else if (sig
== SIGBUS
)
296 fprintf(debug_log
, "FATAL: Received Bus Error...dying.\n");
298 fprintf(debug_log
, "FATAL: Received signal %d...dying.\n", sig
);
300 #if PRINT_STACK_TRACE
303 extern void U_STACK_TRACE(void); /* link with -lcl */
305 dup2(fileno(debug_log
), 2);
309 #endif /* _SQUID_HPUX_ */
310 #if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
311 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
312 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
314 dup2(fileno(debug_log
), fileno(stdout
));
319 #endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
320 #if HAVE_BACKTRACE_SYMBOLS_FD
322 static void *(callarray
[8192]);
324 n
= backtrace(callarray
, 8192);
325 backtrace_symbols_fd(callarray
, n
, fileno(debug_log
));
329 #endif /* PRINT_STACK_TRACE */
331 #if SA_RESETHAND == 0 && !_SQUID_WINDOWS_
332 signal(SIGSEGV
, SIG_DFL
);
334 signal(SIGBUS
, SIG_DFL
);
336 signal(sig
, SIG_DFL
);
340 releaseServerSockets();
342 storeDirWriteCleanLogs(0);
344 if (!shutting_down
) {
350 if (squid_curtime
- SQUID_RELEASE_TIME
< 864000) {
351 /* skip if more than 10 days old */
353 if (Config
.adminEmail
)
363 BroadcastSignalIfAny(int& sig
)
366 if (IamMasterProcess()) {
367 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
368 const auto &kid
= TheKids
.get(i
);
370 kill(kid
.getPid(), sig
);
378 sigusr2_handle(int sig
)
380 static int state
= 0;
381 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
386 Debug::parseOptions("ALL,7");
389 Debug::parseOptions(Debug::debugOptions
);
395 if (signal(sig
, sigusr2_handle
) == SIG_ERR
) {
397 debugs(50, DBG_CRITICAL
, "signal: sig=" << sig
<< " func=sigusr2_handle: " << xstrerr(xerrno
));
403 debug_trap(const char *message
)
405 if (!opt_catch_signals
)
408 _db_print("WARNING: %s\n", message
);
414 LOCAL_ARRAY(char, host
, SQUIDHOSTNAMELEN
+ 1);
415 static int present
= 0;
416 struct addrinfo
*AI
= NULL
;
419 if (Config
.visibleHostname
!= NULL
)
420 return Config
.visibleHostname
;
427 if (HttpPortList
!= NULL
&& sa
.isAnyAddr())
428 sa
= HttpPortList
->s
;
431 * If the first http_port address has a specific address, try a
432 * reverse DNS lookup on it.
434 if ( !sa
.isAnyAddr() ) {
437 /* we are looking for a name. */
438 if (getnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, host
, SQUIDHOSTNAMELEN
, NULL
, 0, NI_NAMEREQD
) == 0) {
439 /* DNS lookup successful */
440 /* use the official name from DNS lookup */
441 debugs(50, 4, "getMyHostname: resolved " << sa
<< " to '" << host
<< "'");
445 Ip::Address::FreeAddr(AI
);
447 if (strchr(host
, '.'))
451 Ip::Address::FreeAddr(AI
);
452 debugs(50, 2, "WARNING: failed to resolve " << sa
<< " to a fully qualified hostname");
455 // still no host. fallback to gethostname()
456 if (gethostname(host
, SQUIDHOSTNAMELEN
) < 0) {
458 debugs(50, DBG_IMPORTANT
, "WARNING: gethostname failed: " << xstrerr(xerrno
));
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? */
481 debugs(50, DBG_IMPORTANT
, "WARNING: '" << host
<< "' rDNS test failed: " << xstrerr(xerrno
));
484 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
485 debugs(50, DBG_CRITICAL
, "WARNING: Could not determine this machines public hostname. " <<
486 "Please configure one or set 'visible_hostname'.");
488 return ("localhost");
494 debugs(21, 3, HERE
<< " Config: '" << Config
.uniqueHostname
<< "'");
495 return Config
.uniqueHostname
? Config
.uniqueHostname
: getMyHostname();
498 /** leave a priviliged section. (Give up any privilegies)
499 * Routines that need privilegies can rap themselves in enter_suid()
501 * To give upp all posibilites to gain privilegies use no_suid()
506 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
508 if (Config
.effectiveGroup
) {
510 setgroups(1, &Config2
.effectiveGroupID
);
513 if (setgid(Config2
.effectiveGroupID
) < 0) {
515 debugs(50, DBG_CRITICAL
, "ALERT: setgid: " << xstrerr(xerrno
));
522 /* Started as a root, check suid option */
523 if (Config
.effectiveUser
== NULL
)
526 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config
.effectiveUser
<< "'");
528 if (!Config
.effectiveGroup
) {
530 if (setgid(Config2
.effectiveGroupID
) < 0) {
532 debugs(50, DBG_CRITICAL
, "ALERT: setgid: " << xstrerr(xerrno
));
535 if (initgroups(Config
.effectiveUser
, Config2
.effectiveGroupID
) < 0) {
536 debugs(50, DBG_CRITICAL
, "ALERT: initgroups: unable to set groups for User " <<
537 Config
.effectiveUser
<< " and Group " <<
538 (unsigned) Config2
.effectiveGroupID
<< "");
543 if (setresuid(Config2
.effectiveUserID
, Config2
.effectiveUserID
, 0) < 0) {
544 const auto xerrno
= errno
;
545 fatalf("FATAL: setresuid: %s", xstrerr(xerrno
));
549 if (seteuid(Config2
.effectiveUserID
) < 0) {
550 const auto xerrno
= errno
;
551 fatalf("FATAL: seteuid: %s", xstrerr(xerrno
));
555 if (setuid(Config2
.effectiveUserID
) < 0) {
556 const auto xerrno
= errno
;
557 fatalf("FATAL: setuid: %s", xstrerr(xerrno
));
562 restoreCapabilities(true);
564 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
565 /* Set Linux DUMPABLE flag */
566 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0) {
568 debugs(50, 2, "ALERT: prctl: " << xstrerr(xerrno
));
573 /* Enter a privilegied section */
577 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root privileges");
579 if (setresuid((uid_t
)-1, 0, (uid_t
)-1) < 0) {
580 const auto xerrno
= errno
;
581 debugs (21, 3, "enter_suid: setresuid failed: " << xstrerr(xerrno
));
587 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
588 /* Set Linux DUMPABLE flag */
590 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0) {
592 debugs(50, 2, "ALERT: prctl: " << xstrerr(xerrno
));
597 /* Give up the posibility to gain privilegies.
598 * this should be used before starting a sub process
606 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
610 debugs(50, DBG_IMPORTANT
, "WARNING: no_suid: setuid(0): " << xstrerr(xerrno
));
613 if (setuid(uid
) < 0) {
615 debugs(50, DBG_IMPORTANT
, "ERROR: no_suid: setuid(" << uid
<< "): " << xstrerr(xerrno
));
618 restoreCapabilities(false);
620 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
621 /* Set Linux DUMPABLE flag */
622 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0) {
624 debugs(50, 2, "ALERT: prctl: " << xstrerr(xerrno
));
632 return KidIdentifier
== 0;
638 // when there is only one process, it has to be the worker
639 if (opt_no_daemon
|| Config
.workers
== 0)
642 return TheProcessKind
== pkWorker
;
648 return TheProcessKind
== pkDisker
;
654 return !opt_no_daemon
&& Config
.workers
> 0;
660 return InDaemonMode() && NumberOfKids() > 1;
664 IamCoordinatorProcess()
666 return TheProcessKind
== pkCoordinator
;
672 // when there is only one process, it has to be primary
673 if (opt_no_daemon
|| Config
.workers
== 0)
676 // when there is a master and worker process, the master delegates
677 // primary functions to its only kid
678 if (NumberOfKids() == 1)
679 return IamWorkerProcess();
681 // in SMP mode, multiple kids delegate primary functions to the coordinator
682 return IamCoordinatorProcess();
688 // no kids in no-daemon mode
692 // XXX: detect and abort when called before workers/cache_dirs are parsed
694 const int rockDirs
= Config
.cacheSwap
.n_strands
;
696 const bool needCoord
= Config
.workers
> 1 || rockDirs
> 0;
697 return (needCoord
? 1 : 0) + Config
.workers
+ rockDirs
;
704 if (IamMasterProcess())
705 roles
.append(" master");
706 if (IamCoordinatorProcess())
707 roles
.append(" coordinator");
708 if (IamWorkerProcess())
709 roles
.append(" worker");
710 if (IamDiskProcess())
711 roles
.append(" disker");
715 /* A little piece of glue for odd systems */
716 #ifndef RLIMIT_NOFILE
718 #define RLIMIT_NOFILE RLIMIT_OFILE
722 /** Figure out the number of supported filedescriptors */
726 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
728 /* On Linux with 64-bit file support the sys/resource.h header
729 * uses #define to change the function definition to require rlimit64
731 #if defined(getrlimit)
732 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
737 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
739 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno
));
740 } else if (Config
.max_filedescriptors
> 0) {
741 #if USE_SELECT || USE_SELECT_WIN32
742 /* select() breaks if this gets set too big */
743 if (Config
.max_filedescriptors
> FD_SETSIZE
) {
744 rl
.rlim_cur
= FD_SETSIZE
;
745 debugs(50, DBG_CRITICAL
, "WARNING: 'max_filedescriptors " << Config
.max_filedescriptors
<< "' does not work with select()");
748 rl
.rlim_cur
= Config
.max_filedescriptors
;
749 if (rl
.rlim_cur
> rl
.rlim_max
)
750 rl
.rlim_max
= rl
.rlim_cur
;
751 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
753 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno
));
754 getrlimit(RLIMIT_NOFILE
, &rl
);
755 rl
.rlim_cur
= rl
.rlim_max
;
756 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
758 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno
));
762 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
764 debugs(50, DBG_CRITICAL
, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno
));
766 Squid_MaxFD
= rl
.rlim_cur
;
769 #endif /* HAVE_SETRLIMIT */
773 setSystemLimits(void)
775 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
776 /* limit system filedescriptors to our own limit */
778 /* On Linux with 64-bit file support the sys/resource.h header
779 * uses #define to change the function definition to require rlimit64
781 #if defined(getrlimit)
782 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
787 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
789 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno
));
791 rl
.rlim_cur
= Squid_MaxFD
;
792 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
794 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_NOFILE: %s", xstrerr(xerrno
));
795 fatal_dump(tmp_error_buf
);
798 #endif /* HAVE_SETRLIMIT */
800 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA) && !_SQUID_CYGWIN_
801 if (getrlimit(RLIMIT_DATA
, &rl
) < 0) {
803 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_DATA: " << xstrerr(xerrno
));
804 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
805 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
807 if (setrlimit(RLIMIT_DATA
, &rl
) < 0) {
809 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_DATA: %s", xstrerr(xerrno
));
810 fatal_dump(tmp_error_buf
);
813 #endif /* RLIMIT_DATA */
814 if (Config
.max_filedescriptors
> Squid_MaxFD
) {
815 debugs(50, DBG_IMPORTANT
, "NOTICE: Could not increase the number of filedescriptors");
818 #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM) && !_SQUID_CYGWIN_
819 if (getrlimit(RLIMIT_VMEM
, &rl
) < 0) {
821 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_VMEM: " << xstrerr(xerrno
));
822 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
823 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
825 if (setrlimit(RLIMIT_VMEM
, &rl
) < 0) {
827 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_VMEM: %s", xstrerr(xerrno
));
828 fatal_dump(tmp_error_buf
);
831 #endif /* RLIMIT_VMEM */
835 squid_signal(int sig
, SIGHDLR
* func
, int flags
)
840 sa
.sa_handler
= func
;
842 sigemptyset(&sa
.sa_mask
);
844 if (sigaction(sig
, &sa
, NULL
) < 0) {
846 debugs(50, DBG_CRITICAL
, "sigaction: sig=" << sig
<< " func=" << func
<< ": " << xstrerr(xerrno
));
851 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
852 are supported, so we must care of don't call signal() for other value.
853 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
854 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
872 WIN32_ExceptionHandlerInit();
876 WIN32_ExceptionHandlerInit();
878 break; /* Nor reached */
882 break; /* Nor reached */
900 debugObj(int section
, int level
, const char *label
, void *obj
, ObjPackMethod pm
)
902 assert(label
&& obj
&& pm
);
906 debugs(section
, level
, "" << label
<< "" << mb
.buf
<< "");
918 if (!Config
.etcHostsPath
)
921 if (0 == strcmp(Config
.etcHostsPath
, "none"))
924 FILE *fp
= fopen(Config
.etcHostsPath
, "r");
928 debugs(1, DBG_IMPORTANT
, "parseEtcHosts: '" << Config
.etcHostsPath
<< "' : " << xstrerr(xerrno
));
933 setmode(fileno(fp
), O_TEXT
);
936 while (fgets(buf
, 1024, fp
)) { /* for each line */
938 if (buf
[0] == '#') /* MS-windows likes to add comments */
941 strtok(buf
, "#"); /* chop everything following a comment marker */
947 debugs(1, 5, "etc_hosts: line is '" << buf
<< "'");
949 nt
= strpbrk(lt
, w_space
);
951 if (nt
== NULL
) /* empty line */
954 *nt
= '\0'; /* null-terminate the address */
956 debugs(1, 5, "etc_hosts: address is '" << addr
<< "'");
962 while ((nt
= strpbrk(lt
, w_space
))) {
965 if (nt
== lt
) { /* multiple spaces */
966 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
972 debugs(1, 5, "etc_hosts: got hostname '" << lt
<< "'");
974 /* For IPV6 addresses also check for a colon */
975 if (Config
.appendDomain
&& !strchr(lt
, '.') && !strchr(lt
, ':')) {
976 /* I know it's ugly, but it's only at reconfig */
977 strncpy(buf2
, lt
, sizeof(buf2
)-1);
978 strncat(buf2
, Config
.appendDomain
, sizeof(buf2
) - strlen(lt
) - 1);
979 buf2
[sizeof(buf2
)-1] = '\0';
985 if (ipcacheAddEntryFromHosts(host
, addr
) != 0) {
986 /* invalid address, continuing is useless */
990 hosts
.emplace_back(SBuf(host
));
996 fqdncacheAddEntryFromHosts(addr
, hosts
);
1005 AnyP::PortCfgPointer p
;
1006 if ((p
= HttpPortList
) != NULL
) {
1007 // skip any special interception ports
1008 while (p
!= NULL
&& p
->flags
.isIntercepted())
1014 if ((p
= FtpPortList
) != NULL
) {
1015 // skip any special interception ports
1016 while (p
!= NULL
&& p
->flags
.isIntercepted())
1022 debugs(21, DBG_CRITICAL
, "ERROR: No forward-proxy ports configured.");
1023 return 0; // Invalid port. This will result in invalid URLs on bad configurations.
1027 * Set the umask to at least the given mask. This is in addition
1028 * to the umask set at startup
1031 setUmask(mode_t mask
)
1033 // No way to get the current umask value without setting it.
1034 static const mode_t orig_umask
= umask(mask
); // once, to get
1035 umask(mask
| orig_umask
); // always, to set
1039 * Inverse of strwordtok. Quotes a word if needed
1042 strwordquote(MemBuf
* mb
, const char *str
)
1046 if (strchr(str
, ' ')) {
1048 mb
->append("\"", 1);
1052 int l
= strcspn(str
, "\"\\\n\r");
1059 mb
->append("\\n", 2);
1064 mb
->append("\\r", 2);
1072 mb
->append("\\", 1);
1080 mb
->append("\"", 1);
1084 keepCapabilities(void)
1086 #if USE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
1088 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0)) {
1089 Ip::Interceptor
.StopTransparency("capability setting has failed.");
1095 restoreCapabilities(bool keep
)
1097 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
1101 caps
= cap_get_proc();
1105 Ip::Interceptor
.StopTransparency("Can't get current capabilities");
1109 cap_value_t cap_list
[10];
1110 cap_list
[ncaps
] = CAP_NET_BIND_SERVICE
;
1112 if (Ip::Interceptor
.TransparentActive() ||
1113 Ip::Qos::TheConfig
.isHitNfmarkActive() ||
1114 Ip::Qos::TheConfig
.isAclNfmarkActive() ||
1115 Ip::Qos::TheConfig
.isAclTosActive()) {
1116 cap_list
[ncaps
] = CAP_NET_ADMIN
;
1120 cap_clear_flag(caps
, CAP_EFFECTIVE
);
1121 rc
|= cap_set_flag(caps
, CAP_EFFECTIVE
, ncaps
, cap_list
, CAP_SET
);
1122 rc
|= cap_set_flag(caps
, CAP_PERMITTED
, ncaps
, cap_list
, CAP_SET
);
1124 if (rc
|| cap_set_proc(caps
) != 0) {
1125 Ip::Interceptor
.StopTransparency("Error enabling needed capabilities.");
1130 Ip::Interceptor
.StopTransparency("Missing needed capability support.");
1131 #endif /* HAVE_SYS_CAPABILITY_H */
1135 WaitForOnePid(pid_t pid
, PidStatus
&status
, int flags
)
1139 return wait3(&status
, flags
, NULL
);
1140 return wait4(pid
, &status
, flags
, NULL
);
1141 #elif _SQUID_WINDOWS_
1142 return 0; // function not used on Windows
1144 return waitpid(pid
, &status
, flags
);
1150 WindowsErrorMessage(DWORD errorId
)
1152 char *rawMessage
= nullptr;
1153 const auto length
= FormatMessage(
1154 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
1155 FORMAT_MESSAGE_FROM_SYSTEM
|
1156 FORMAT_MESSAGE_IGNORE_INSERTS
,
1159 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), // Default language
1160 static_cast<LPTSTR
>(&rawMessage
),
1164 Must(!rawMessage
); // nothing to LocalFree()
1165 return ToSBuf("windows error ", errorId
);
1167 const auto result
= SBuf(rawMessage
, length
);
1168 LocalFree(rawMessage
);
1171 #endif // _SQUID_WINDOWS_