tools.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 21 Misc Functions */
10
11#include "squid.h"
12#include "anyp/PortCfg.h"
13#include "base/Subscription.h"
14#include "client_side.h"
15#include "fatal.h"
16#include "fde.h"
17#include "fqdncache.h"
18#include "fs_io.h"
19#include "htcp.h"
20#include "http/Stream.h"
21#include "ICP.h"
22#include "ip/Intercept.h"
23#include "ip/QosConfig.h"
24#include "ipc/Coordinator.h"
25#include "ipc/Kids.h"
26#include "ipcache.h"
27#include "MemBuf.h"
28#include "sbuf/Stream.h"
29#include "SquidConfig.h"
30#include "SquidMath.h"
31#include "store/Disks.h"
32#include "tools.h"
33#include "wordlist.h"
34
35#include <cerrno>
36#if HAVE_SYS_CAPABILITY_H
37#include <sys/capability.h>
38#endif
39#if HAVE_SYS_PRCTL_H
40#include <sys/prctl.h>
41#endif
42#if HAVE_SYS_PROCCTL_H
43#include <sys/procctl.h>
44#endif
45#if HAVE_PRIV_H
46#include <priv.h>
47#endif
48#if HAVE_PSAPI_H
49#include <psapi.h>
50#endif
51#if HAVE_SYS_STAT_H
52#include <sys/stat.h>
53#endif
54#if HAVE_SYS_WAIT_H
55#include <sys/wait.h>
56#endif
57#if HAVE_GRP_H
58#include <grp.h>
59#endif
60
61#define DEAD_MSG "\
62The Squid Cache (version %s) died.\n\
63\n\
64You've encountered a fatal error in the Squid Cache version %s.\n\
65If a core file was created (possibly in the swap directory),\n\
66please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
67and report the trace back to squid-bugs@lists.squid-cache.org.\n\
68\n\
69Thanks!\n"
70
71static void mail_warranty(void);
72static void restoreCapabilities(bool keep);
73int DebugSignal = -1;
75
76#if _SQUID_LINUX_
77/* Workaround for crappy glic header files */
78SQUIDCEXTERN int backtrace(void *, int);
79SQUIDCEXTERN void backtrace_symbols_fd(void *, int, int);
80SQUIDCEXTERN int setresuid(uid_t, uid_t, uid_t);
81#else /* _SQUID_LINUX_ */
82/* needed on Opensolaris for backtrace_symbols_fd */
83#if HAVE_EXECINFO_H
84#include <execinfo.h>
85#endif /* HAVE_EXECINFO_H */
86
87#endif /* _SQUID_LINUX */
88
89static char tmp_error_buf[32768]; /* 32KB */
90
91void
93{
94 // Release the main ports as early as possible
95
96 // clear http_port, https_port, and ftp_port lists
98
99 // clear icp_port's
101
102 // XXX: Why not the HTCP, SNMP, DNS ports as well?
103 // XXX: why does this differ from main closeServerConnections() anyway ?
104}
105
106static char *
108{
109 LOCAL_ARRAY(char, msg, 1024);
110 snprintf(msg, 1024, DEAD_MSG, version_string, version_string);
111 return msg;
112}
113
114static void
116{
117 FILE *fp = nullptr;
118 static char command[256];
119
120 /*
121 * NP: umask() takes the mask of bits we DONT want set.
122 *
123 * We want the current user to have read/write access
124 * and since this file will be passed to mailsystem,
125 * the group and other must have read access.
126 */
127 const mode_t prev_umask=umask(S_IXUSR|S_IXGRP|S_IWGRP|S_IWOTH|S_IXOTH);
128
129#if HAVE_MKSTEMP
130 char filename[] = "/tmp/squid-XXXXXX";
131 int tfd = mkstemp(filename);
132 if (tfd < 0 || (fp = fdopen(tfd, "w")) == nullptr) {
133 umask(prev_umask);
134 return;
135 }
136#else
137 char *filename;
138 // XXX tempnam is obsolete since POSIX.2008-1
139 // tmpfile is not an option, we want the created files to stick around
140 if ((filename = tempnam(nullptr, APP_SHORTNAME)) == NULL ||
141 (fp = fopen(filename, "w")) == NULL) {
142 umask(prev_umask);
143 return;
144 }
145#endif
146 umask(prev_umask);
147
148 if (Config.EmailFrom)
149 fprintf(fp, "From: %s\n", Config.EmailFrom);
150 else
151 fprintf(fp, "From: %s@%s\n", APP_SHORTNAME, uniqueHostname());
152
153 fprintf(fp, "To: %s\n", Config.adminEmail);
154 fprintf(fp, "Subject: %s\n", dead_msg());
155 fclose(fp);
156
157 snprintf(command, 256, "%s %s < %s", Config.EmailProgram, Config.adminEmail, filename);
158 if (system(command)) {} /* XXX should avoid system(3) */
159 unlink(filename);
160#if !HAVE_MKSTEMP
161 xfree(filename); // tempnam() requires us to free its allocation
162#endif
163}
164
165void
167{
168#if HAVE_MSTATS && HAVE_GNUMALLOC_H
169
170 struct mstats ms = mstats();
171 fprintf(debug_log, "\ttotal space in arena: %6d KB\n",
172 (int) (ms.bytes_total >> 10));
173 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
174 (int) (ms.bytes_free >> 10),
175 Math::intPercent(ms.bytes_free, ms.bytes_total));
176#endif
177}
178
179void
181{
182 memset(r, '\0', sizeof(struct rusage));
183#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
184#if _SQUID_SOLARIS_
185 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
186 enter_suid();
187#endif
188
189 getrusage(RUSAGE_SELF, r);
190
191#if _SQUID_SOLARIS_
192 leave_suid();
193#endif
194
195#elif defined(PSAPI_VERSION)
196 // Windows has an alternative method if there is no POSIX getrusage defined.
197 if (WIN32_OS_version >= _WIN_OS_WINNT) {
198 /* On Windows NT and later call PSAPI.DLL for process Memory */
199 /* information -- Guido Serassio */
200 HANDLE hProcess;
201 PROCESS_MEMORY_COUNTERS pmc;
202 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
203 PROCESS_VM_READ,
204 FALSE, GetCurrentProcessId());
205 {
206 /* Microsoft CRT doesn't have getrusage function, */
207 /* so we get process CPU time information from PSAPI.DLL. */
208 FILETIME ftCreate, ftExit, ftKernel, ftUser;
209 if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
210 int64_t *ptUser = (int64_t *)&ftUser;
211 int64_t tUser64 = *ptUser / 10;
212 int64_t *ptKernel = (int64_t *)&ftKernel;
213 int64_t tKernel64 = *ptKernel / 10;
214 r->ru_utime.tv_sec =(long)(tUser64 / 1000000);
215 r->ru_stime.tv_sec =(long)(tKernel64 / 1000000);
216 r->ru_utime.tv_usec =(long)(tUser64 % 1000000);
217 r->ru_stime.tv_usec =(long)(tKernel64 % 1000000);
218 } else {
219 CloseHandle( hProcess );
220 return;
221 }
222 }
223 if (GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc))) {
224 r->ru_maxrss=(DWORD)(pmc.WorkingSetSize / getpagesize());
225 r->ru_majflt=pmc.PageFaultCount;
226 } else {
227 CloseHandle( hProcess );
228 return;
229 }
230
231 CloseHandle( hProcess );
232 }
233#endif
234}
235
236double
237
239{
240 return (double) r->ru_stime.tv_sec +
241 (double) r->ru_utime.tv_sec +
242 (double) r->ru_stime.tv_usec / 1000000.0 +
243 (double) r->ru_utime.tv_usec / 1000000.0;
244}
245
246/* Hack for some HP-UX preprocessors */
247#ifndef HAVE_GETPAGESIZE
248#define HAVE_GETPAGESIZE 0
249#endif
250
251int
252
254{
255#if _SQUID_SGI_ && _ABIAPI
256 return r->ru_pad[0];
257#elif _SQUID_SGI_|| _SQUID_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
258
259 return r->ru_maxrss;
260#elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
261
262 return (r->ru_maxrss * getpagesize()) >> 10;
263#elif defined(PAGESIZE)
264
265 return (r->ru_maxrss * PAGESIZE) >> 10;
266#else
267
268 return r->ru_maxrss;
269#endif
270}
271
272int
273
275{
276#if _SQUID_SGI_ && _ABIAPI
277 return r->ru_pad[5];
278#else
279
280 return r->ru_majflt;
281#endif
282}
283
287static void
289{
290 const auto handleError = [](const char * const syscall, const int savedErrno) {
291 throw TextException(ToSBuf(syscall, " failure: ", xstrerr(savedErrno)), Here());
292 };
293#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
294 if (prctl(PR_SET_DUMPABLE, 1) != 0)
295 handleError("prctl(PR_SET_DUMPABLE)", errno);
296#elif HAVE_PROCCTL && defined(PROC_TRACE_CTL)
297 // TODO: when FreeBSD 14 becomes the lowest version, we can
298 // possibly save one getpid syscall, for now still necessary.
299 int traceable = PROC_TRACE_CTL_ENABLE;
300 if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &traceable) != 0)
301 handleError("procctl(PROC_TRACE_CTL_ENABLE)", errno);
302#elif HAVE_SETPFLAGS
303 if (setpflags(__PROC_PROTECT, 0) != 0)
304 handleError("setpflags(__PROC_PROTECT)", errno);
305#else
306 debugs(50, 2, "WARNING: Assuming this process is traceable");
307 (void)handleError; // just "use" the variable; there is no error here
308#endif
309}
310
313static void
315{
316 // for now, setting coredump_dir is required to make the process traceable
317 if (!Config.coredump_dir)
318 return;
319
320 try {
322 } catch (...) {
323 debugs(50, DBG_IMPORTANT, "ERROR: Cannot make the process traceable:" <<
324 Debug::Extra << "exception: " << CurrentException);
325 }
326}
327
328void
330{
331
332 struct rusage rusage;
334 fprintf(debug_log, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
336 rusage.ru_utime.tv_sec + ((double) rusage.ru_utime.tv_usec / 1000000.0),
337 rusage.ru_stime.tv_sec + ((double) rusage.ru_stime.tv_usec / 1000000.0));
338 fprintf(debug_log, "Maximum Resident Size: %d KB\n",
340 fprintf(debug_log, "Page faults with physical i/o: %d\n",
342}
343
344void
345death(int sig)
346{
347 if (sig == SIGSEGV)
348 debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received Segment Violation...dying.");
349 else if (sig == SIGBUS)
350 debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received Bus Error...dying.");
351 else
352 debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received signal " << sig << "...dying.");
353
354#if PRINT_STACK_TRACE
355#if _SQUID_HPUX_
356 {
357 extern void U_STACK_TRACE(void); /* link with -lcl */
358 fflush(debug_log);
359 dup2(fileno(debug_log), 2);
360 U_STACK_TRACE();
361 }
362
363#endif /* _SQUID_HPUX_ */
364#if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
365 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
366 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
367 fflush(debug_log);
368 dup2(fileno(debug_log), fileno(stdout));
369 opcom_stack_trace();
370 fflush(stdout);
371 }
372
373#endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
374#if HAVE_BACKTRACE_SYMBOLS_FD
375 {
376 static void *callarray[8192];
377 int n;
378 n = backtrace(callarray, 8192);
379 backtrace_symbols_fd(callarray, n, fileno(debug_log));
380 }
381
382#endif
383#endif /* PRINT_STACK_TRACE */
384
385#if SA_RESETHAND == 0 && !_SQUID_WINDOWS_
386 signal(SIGSEGV, SIG_DFL);
387
388 signal(SIGBUS, SIG_DFL);
389
390 signal(sig, SIG_DFL);
391
392#endif
393
395
397
398 if (!shutting_down) {
399 PrintRusage();
400
402 }
403
404 if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
405 /* skip if more than 10 days old */
406
407 if (Config.adminEmail)
409
410 puts(dead_msg());
411 }
412
414 abort();
415}
416
417void
419{
420 if (sig > 0) {
421 if (IamMasterProcess()) {
422 for (int i = TheKids.count() - 1; i >= 0; --i) {
423 const auto &kid = TheKids.get(i);
424 if (kid.running())
425 kill(kid.getPid(), sig);
426 }
427 }
428 sig = -1;
429 }
430}
431
432void
434{
435 static int state = 0;
436 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
437
438 DebugSignal = sig;
439
440 if (state == 0) {
441 Debug::parseOptions("ALL,7");
442 state = 1;
443 } else {
445 state = 0;
446 }
447
448#if !HAVE_SIGACTION
449 /* reinstall */
450 if (signal(sig, sigusr2_handle) == SIG_ERR) {
451 int xerrno = errno;
452 debugs(50, DBG_CRITICAL, "signal: sig=" << sig << " func=sigusr2_handle: " << xstrerr(xerrno));
453 }
454#endif
455}
456
457void
458debug_trap(const char *message)
459{
461 fatal_dump(message);
462
463 debugs(50, DBG_CRITICAL, "WARNING: " << message);
464}
465
466const char *
468{
469 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
470 static int present = 0;
471 struct addrinfo *AI = nullptr;
472 Ip::Address sa;
473
474 if (Config.visibleHostname != nullptr)
475 return Config.visibleHostname;
476
477 if (present)
478 return host;
479
480 host[0] = '\0';
481
482 if (HttpPortList != nullptr && sa.isAnyAddr())
483 sa = HttpPortList->s;
484
485 /*
486 * If the first http_port address has a specific address, try a
487 * reverse DNS lookup on it.
488 */
489 if ( !sa.isAnyAddr() ) {
490
491 sa.getAddrInfo(AI);
492 /* we are looking for a name. */
493 if (getnameinfo(AI->ai_addr, AI->ai_addrlen, host, SQUIDHOSTNAMELEN, nullptr, 0, NI_NAMEREQD ) == 0) {
494 /* DNS lookup successful */
495 /* use the official name from DNS lookup */
496 debugs(50, 4, "getMyHostname: resolved " << sa << " to '" << host << "'");
497
498 present = 1;
499
501
502 if (strchr(host, '.'))
503 return host;
504 }
505
507 debugs(50, 2, "WARNING: failed to resolve " << sa << " to a fully qualified hostname");
508 }
509
510 // still no host. fallback to gethostname()
511 if (gethostname(host, SQUIDHOSTNAMELEN) < 0) {
512 int xerrno = errno;
513 debugs(50, DBG_IMPORTANT, "WARNING: gethostname failed: " << xstrerr(xerrno));
514 } else {
515 /* Verify that the hostname given resolves properly */
516 struct addrinfo hints;
517 memset(&hints, 0, sizeof(addrinfo));
518 hints.ai_flags = AI_CANONNAME;
519
520 if (getaddrinfo(host, nullptr, nullptr, &AI) == 0) {
521 /* DNS lookup successful */
522 /* use the official name from DNS lookup */
523 debugs(50, 6, "getMyHostname: '" << host << "' has DNS resolution.");
524 present = 1;
525
526 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
527 if (AI)
528 freeaddrinfo(AI);
529
530 return host;
531 }
532 int xerrno = errno;
533
534 if (AI)
535 freeaddrinfo(AI);
536 debugs(50, DBG_IMPORTANT, "WARNING: '" << host << "' rDNS test failed: " << xstrerr(xerrno));
537 }
538
539 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
540 debugs(50, DBG_CRITICAL, "WARNING: Could not determine this machines public hostname. " <<
541 "Please configure one or set 'visible_hostname'.");
542
543 return ("localhost");
544}
545
546const char *
548{
549 debugs(21, 3, " Config: '" << Config.uniqueHostname << "'");
551}
552
558void
560{
561 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
562
564#if HAVE_SETGROUPS
565 setgroups(1, &Config2.effectiveGroupID);
566#endif
567
568 if (setgid(Config2.effectiveGroupID) < 0) {
569 int xerrno = errno;
570 debugs(50, DBG_CRITICAL, "ERROR: setgid: " << xstrerr(xerrno));
571 }
572 }
573
574 if (geteuid() != 0)
575 return;
576
577 /* Started as a root, check suid option */
578 if (Config.effectiveUser == nullptr)
579 return;
580
581 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config.effectiveUser << "'");
582
583 if (!Config.effectiveGroup) {
584
585 if (setgid(Config2.effectiveGroupID) < 0) {
586 int xerrno = errno;
587 debugs(50, DBG_CRITICAL, "ERROR: setgid: " << xstrerr(xerrno));
588 }
589
591 debugs(50, DBG_CRITICAL, "ERROR: initgroups: unable to set groups for User " <<
592 Config.effectiveUser << " and Group " <<
593 (unsigned) Config2.effectiveGroupID << "");
594 }
595 }
596
597#if HAVE_SETRESUID
598 if (setresuid(Config2.effectiveUserID, Config2.effectiveUserID, 0) < 0) {
599 const auto xerrno = errno;
600 fatalf("FATAL: setresuid: %s", xstrerr(xerrno));
601 }
602
603#elif HAVE_SETEUID
604 if (seteuid(Config2.effectiveUserID) < 0) {
605 const auto xerrno = errno;
606 fatalf("FATAL: seteuid: %s", xstrerr(xerrno));
607 }
608
609#else
610 if (setuid(Config2.effectiveUserID) < 0) {
611 const auto xerrno = errno;
612 fatalf("FATAL: setuid: %s", xstrerr(xerrno));
613 }
614
615#endif
616
619}
620
621/* Enter a privilegied section */
622void
624{
625 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root privileges");
626#if HAVE_SETRESUID
627 if (setresuid((uid_t)-1, 0, (uid_t)-1) < 0) {
628 const auto xerrno = errno;
629 debugs (21, 3, "enter_suid: setresuid failed: " << xstrerr(xerrno));
630 }
631#else
632
633 if (setuid(0) < 0) {
634 const auto xerrno = errno;
635 debugs(21, 3, "setuid(0) failed: " << xstrerr(xerrno));
636 }
637#endif
638
640}
641
642/* Give up the possibility to gain privilegies.
643 * this should be used before starting a sub process
644 */
645void
647{
648 uid_t uid;
649 leave_suid();
650 uid = geteuid();
651 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root privileges forever");
652
653 if (setuid(0) < 0) {
654 int xerrno = errno;
655 debugs(50, DBG_IMPORTANT, "WARNING: no_suid: setuid(0): " << xstrerr(xerrno));
656 }
657
658 if (setuid(uid) < 0) {
659 int xerrno = errno;
660 debugs(50, DBG_IMPORTANT, "ERROR: no_suid: setuid(" << uid << "): " << xstrerr(xerrno));
661 }
662
663 restoreCapabilities(false);
665}
666
667bool
669{
670 return KidIdentifier == 0;
671}
672
673bool
675{
676 // when there is only one process, it has to be the worker
677 if (opt_no_daemon || Config.workers == 0)
678 return true;
679
680 return TheProcessKind == pkWorker;
681}
682
683bool
685{
686 return TheProcessKind == pkDisker;
687}
688
689bool
691{
692 return !opt_no_daemon && Config.workers > 0;
693}
694
695bool
697{
698 return InDaemonMode() && NumberOfKids() > 1;
699}
700
701bool
703{
705}
706
707bool
709{
710 // when there is only one process, it has to be primary
711 if (opt_no_daemon || Config.workers == 0)
712 return true;
713
714 // when there is a master and worker process, the master delegates
715 // primary functions to its only kid
716 if (NumberOfKids() == 1)
717 return IamWorkerProcess();
718
719 // in SMP mode, multiple kids delegate primary functions to the coordinator
720 return IamCoordinatorProcess();
721}
722
723int
725{
726 // no kids in no-daemon mode
727 if (!InDaemonMode())
728 return 0;
729
730 // XXX: detect and abort when called before workers/cache_dirs are parsed
731
732 const int rockDirs = Config.cacheSwap.n_strands;
733
734 const bool needCoord = Config.workers > 1 || rockDirs > 0;
735 return (needCoord ? 1 : 0) + Config.workers + rockDirs;
736}
737
738SBuf
740{
741 SBuf roles;
742 if (IamMasterProcess())
743 roles.append(" master");
745 roles.append(" coordinator");
746 if (IamWorkerProcess())
747 roles.append(" worker");
748 if (IamDiskProcess())
749 roles.append(" disker");
750 return roles;
751}
752
753/* A little piece of glue for odd systems */
754#ifndef RLIMIT_NOFILE
755#ifdef RLIMIT_OFILE
756#define RLIMIT_NOFILE RLIMIT_OFILE
757#endif
758#endif
759
761void
763{
764#if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
765
766 /* On Linux with 64-bit file support the sys/resource.h header
767 * uses #define to change the function definition to require rlimit64
768 */
769#if defined(getrlimit)
770 struct rlimit64 rl; // Assume its a 64-bit redefine anyways.
771#else
772 struct rlimit rl;
773#endif
774
775 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
776 int xerrno = errno;
777 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
778 } else if (Config.max_filedescriptors > 0) {
779#if USE_SELECT
780 /* select() breaks if this gets set too big */
781 if (Config.max_filedescriptors > FD_SETSIZE) {
782 rl.rlim_cur = FD_SETSIZE;
783 debugs(50, DBG_CRITICAL, "WARNING: 'max_filedescriptors " << Config.max_filedescriptors << "' does not work with select()");
784 } else
785#endif
786 rl.rlim_cur = Config.max_filedescriptors;
787 if (rl.rlim_cur > rl.rlim_max)
788 rl.rlim_max = rl.rlim_cur;
789 if (setrlimit(RLIMIT_NOFILE, &rl)) {
790 int xerrno = errno;
791 debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
792 getrlimit(RLIMIT_NOFILE, &rl);
793 rl.rlim_cur = rl.rlim_max;
794 if (setrlimit(RLIMIT_NOFILE, &rl)) {
795 xerrno = errno;
796 debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
797 }
798 }
799 }
800 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
801 int xerrno = errno;
802 debugs(50, DBG_CRITICAL, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
803 } else {
804 Squid_MaxFD = rl.rlim_cur;
805 }
806
807#endif /* HAVE_SETRLIMIT */
808}
809
810void
812{
813#if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
814 /* limit system filedescriptors to our own limit */
815
816 /* On Linux with 64-bit file support the sys/resource.h header
817 * uses #define to change the function definition to require rlimit64
818 */
819#if defined(getrlimit)
820 struct rlimit64 rl; // Assume its a 64-bit redefine anyways.
821#else
822 struct rlimit rl;
823#endif
824
825 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
826 int xerrno = errno;
827 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
828 } else {
829 rl.rlim_cur = Squid_MaxFD;
830 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
831 int xerrno = errno;
832 snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_NOFILE: %s", xstrerr(xerrno));
834 }
835 }
836#endif /* HAVE_SETRLIMIT */
837
838#if HAVE_SETRLIMIT && defined(RLIMIT_DATA) && !_SQUID_CYGWIN_
839 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
840 int xerrno = errno;
841 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_DATA: " << xstrerr(xerrno));
842 } else if (rl.rlim_max > rl.rlim_cur) {
843 rl.rlim_cur = rl.rlim_max; /* set it to the max */
844
845 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
846 int xerrno = errno;
847 snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_DATA: %s", xstrerr(xerrno));
849 }
850 }
851#endif /* RLIMIT_DATA */
853 debugs(50, DBG_IMPORTANT, "WARNING: Could not increase the number of filedescriptors");
854 }
855
856#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM) && !_SQUID_CYGWIN_
857 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
858 int xerrno = errno;
859 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_VMEM: " << xstrerr(xerrno));
860 } else if (rl.rlim_max > rl.rlim_cur) {
861 rl.rlim_cur = rl.rlim_max; /* set it to the max */
862
863 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
864 int xerrno = errno;
865 snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_VMEM: %s", xstrerr(xerrno));
867 }
868 }
869#endif /* RLIMIT_VMEM */
870}
871
872void
873squid_signal(int sig, SIGHDLR * func, int flags)
874{
875#if HAVE_SIGACTION
876
877 struct sigaction sa;
878 sa.sa_handler = func;
879 sa.sa_flags = flags;
880 sigemptyset(&sa.sa_mask);
881
882 if (sigaction(sig, &sa, nullptr) < 0) {
883 int xerrno = errno;
884 debugs(50, DBG_CRITICAL, "sigaction: sig=" << sig << " func=" << func << ": " << xstrerr(xerrno));
885 }
886#else
887#if _SQUID_WINDOWS_
888 /*
889 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
890 are supported, so we must care of don't call signal() for other value.
891 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
892 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
893 */
894 switch (sig) {
895
896 case SIGINT:
897
898 case SIGILL:
899
900 case SIGFPE:
901
902 case SIGTERM:
903
904 case SIGBREAK:
905
906 case SIGABRT:
907 break;
908
909 case SIGSEGV:
910 WIN32_ExceptionHandlerInit();
911 break;
912
913 case SIGBUS:
914 WIN32_ExceptionHandlerInit();
915 return;
916 break; /* Nor reached */
917
918 default:
919 return;
920 break; /* Nor reached */
921 }
922
923#endif
924
925 signal(sig, func);
926
927#endif
928}
929
930void
932{
933 if (debug_log)
934 fflush(debug_log);
935}
936
937void
938debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
939{
940 assert(label && obj && pm);
941 MemBuf mb;
942 mb.init();
943 (*pm) (obj, &mb);
944 debugs(section, level, "" << label << "" << mb.buf << "");
945 mb.clean();
946}
947
948void
950{
951 char buf[1024];
952 char buf2[512];
953 char *nt = buf;
954 char *lt = buf;
955
956 if (!Config.etcHostsPath)
957 return;
958
959 if (0 == strcmp(Config.etcHostsPath, "none"))
960 return;
961
962 FILE *fp = fopen(Config.etcHostsPath, "r");
963
964 if (!fp) {
965 int xerrno = errno;
966 debugs(1, DBG_IMPORTANT, "parseEtcHosts: '" << Config.etcHostsPath << "' : " << xstrerr(xerrno));
967 return;
968 }
969
970#if _SQUID_WINDOWS_
971 setmode(fileno(fp), O_TEXT);
972#endif
973
974 while (fgets(buf, 1024, fp)) { /* for each line */
975
976 if (buf[0] == '#') /* MS-windows likes to add comments */
977 continue;
978
979 strtok(buf, "#"); /* chop everything following a comment marker */
980
981 lt = buf;
982
983 char *addr = buf;
984
985 debugs(1, 5, "etc_hosts: line is '" << buf << "'");
986
987 nt = strpbrk(lt, w_space);
988
989 if (nt == nullptr) /* empty line */
990 continue;
991
992 *nt = '\0'; /* null-terminate the address */
993
994 debugs(1, 5, "etc_hosts: address is '" << addr << "'");
995
996 lt = nt + 1;
997
998 SBufList hosts;
999
1000 while ((nt = strpbrk(lt, w_space))) {
1001 char *host = nullptr;
1002
1003 if (nt == lt) { /* multiple spaces */
1004 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
1005 lt = nt + 1;
1006 continue;
1007 }
1008
1009 *nt = '\0';
1010 debugs(1, 5, "etc_hosts: got hostname '" << lt << "'");
1011
1012 /* For IPV6 addresses also check for a colon */
1013 if (Config.appendDomain && !strchr(lt, '.') && !strchr(lt, ':')) {
1014 /* I know it's ugly, but it's only at reconfig */
1015 strncpy(buf2, lt, sizeof(buf2)-1);
1016 strncat(buf2, Config.appendDomain, sizeof(buf2) - strlen(lt) - 1);
1017 buf2[sizeof(buf2)-1] = '\0';
1018 host = buf2;
1019 } else {
1020 host = lt;
1021 }
1022
1023 if (ipcacheAddEntryFromHosts(host, addr) != 0) {
1024 /* invalid address, continuing is useless */
1025 hosts.clear();
1026 break;
1027 }
1028 hosts.emplace_back(SBuf(host));
1029
1030 lt = nt + 1;
1031 }
1032
1033 if (!hosts.empty())
1034 fqdncacheAddEntryFromHosts(addr, hosts);
1035 }
1036
1037 fclose (fp);
1038}
1039
1040int
1042{
1044 if ((p = HttpPortList) != nullptr) {
1045 // skip any special interception ports
1046 while (p != nullptr && p->flags.isIntercepted())
1047 p = p->next;
1048 if (p != nullptr)
1049 return p->s.port();
1050 }
1051
1052 if ((p = FtpPortList) != nullptr) {
1053 // skip any special interception ports
1054 while (p != nullptr && p->flags.isIntercepted())
1055 p = p->next;
1056 if (p != nullptr)
1057 return p->s.port();
1058 }
1059
1060 debugs(21, DBG_CRITICAL, "ERROR: No forward-proxy ports configured.");
1061 return 0; // Invalid port. This will result in invalid URLs on bad configurations.
1062}
1063
1064/*
1065 * Set the umask to at least the given mask. This is in addition
1066 * to the umask set at startup
1067 */
1068void
1070{
1071 // No way to get the current umask value without setting it.
1072 static const mode_t orig_umask = umask(mask); // once, to get
1073 umask(mask | orig_umask); // always, to set
1074}
1075
1076/*
1077 * Inverse of strwordtok. Quotes a word if needed
1078 */
1079void
1080strwordquote(MemBuf * mb, const char *str)
1081{
1082 int quoted = 0;
1083
1084 if (strchr(str, ' ')) {
1085 quoted = 1;
1086 mb->append("\"", 1);
1087 }
1088
1089 while (*str) {
1090 int l = strcspn(str, "\"\\\n\r");
1091 mb->append(str, l);
1092 str += l;
1093
1094 switch (*str) {
1095
1096 case '\n':
1097 mb->append("\\n", 2);
1098 ++str;
1099 break;
1100
1101 case '\r':
1102 mb->append("\\r", 2);
1103 ++str;
1104 break;
1105
1106 case '\0':
1107 break;
1108
1109 default:
1110 mb->append("\\", 1);
1111 mb->append(str, 1);
1112 ++str;
1113 break;
1114 }
1115 }
1116
1117 if (quoted)
1118 mb->append("\"", 1);
1119}
1120
1121void
1123{
1124#if USE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
1125
1126 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
1127 Ip::Interceptor.StopTransparency("capability setting has failed.");
1128 }
1129#endif
1130}
1131
1132static void
1134{
1135 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
1136#if USE_LIBCAP
1137 cap_t caps;
1138 if (keep)
1139 caps = cap_get_proc();
1140 else
1141 caps = cap_init();
1142 if (!caps) {
1143 Ip::Interceptor.StopTransparency("Can't get current capabilities");
1144 } else {
1145 int ncaps = 0;
1146 int rc = 0;
1147 cap_value_t cap_list[10];
1148 cap_list[ncaps] = CAP_NET_BIND_SERVICE;
1149 ++ncaps;
1150 if (Ip::Interceptor.TransparentActive() ||
1151#if USE_LIBNETFILTERCONNTRACK
1152 // netfilter_conntrack requires CAP_NET_ADMIN to get client's CONNMARK
1153 Ip::Interceptor.InterceptActive() ||
1154#endif
1155 Ip::Qos::TheConfig.isHitNfmarkActive() ||
1156 Ip::Qos::TheConfig.isAclNfmarkActive() ||
1157 Ip::Qos::TheConfig.isAclTosActive()) {
1158 cap_list[ncaps] = CAP_NET_ADMIN;
1159 ++ncaps;
1160 }
1161
1162 cap_clear_flag(caps, CAP_EFFECTIVE);
1163 rc |= cap_set_flag(caps, CAP_EFFECTIVE, ncaps, cap_list, CAP_SET);
1164 rc |= cap_set_flag(caps, CAP_PERMITTED, ncaps, cap_list, CAP_SET);
1165
1166 if (rc || cap_set_proc(caps) != 0) {
1167 Ip::Interceptor.StopTransparency("Error enabling needed capabilities.");
1168 }
1169 cap_free(caps);
1170 }
1171#elif _SQUID_LINUX_
1172 (void)keep;
1173 Ip::Interceptor.StopTransparency("Missing needed capability support.");
1174#else
1175 (void)keep;
1176#endif /* HAVE_SYS_CAPABILITY_H */
1177}
1178
1179pid_t
1180WaitForOnePid(pid_t pid, PidStatus &status, int flags)
1181{
1182#if _SQUID_WINDOWS_
1183 return 0; // function not used on Windows
1184#else
1185 return waitpid(pid, &status, flags);
1186#endif
1187}
1188
1189#if _SQUID_WINDOWS_
1190SBuf
1191WindowsErrorMessage(DWORD errorId)
1192{
1193 char *rawMessage = nullptr;
1194 const auto length = FormatMessage(
1195 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1196 FORMAT_MESSAGE_FROM_SYSTEM |
1197 FORMAT_MESSAGE_IGNORE_INSERTS,
1198 nullptr,
1199 errorId,
1200 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1201 static_cast<LPTSTR>(&rawMessage),
1202 0,
1203 nullptr);
1204 if (!length) {
1205 Must(!rawMessage); // nothing to LocalFree()
1206 return ToSBuf("windows error ", errorId);
1207 }
1208 const auto result = SBuf(rawMessage, length);
1209 LocalFree(rawMessage);
1210 return result;
1211}
1212#endif // _SQUID_WINDOWS_
1213
int storeDirWriteCleanLogs(int reopen)
Definition: Disks.cc:699
#define Here()
source code location of the caller
Definition: Here.h:15
static pid_t pid
Definition: IcmpSquid.cc:34
int TheProcessKind
ProcessKind for the current process.
Definition: Kid.cc:21
@ pkWorker
general-purpose worker bee
Definition: Kid.h:105
@ pkCoordinator
manages all other kids
Definition: Kid.h:104
@ pkDisker
cache_dir manager
Definition: Kid.h:106
Kids TheKids
All kids being maintained.
Definition: Kids.cc:18
time_t squid_curtime
Definition: stub_libtime.cc:20
AnyP::PortCfgPointer FtpPortList
list of Squid ftp_port configured
Definition: PortCfg.cc:23
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:22
class SquidConfig Config
Definition: SquidConfig.cc:12
class SquidConfig2 Config2
Definition: SquidConfig.cc:14
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
#define Must(condition)
Definition: TextException.h:75
#define assert(EX)
Definition: assert.h:17
static void parseOptions(char const *)
Definition: debug.cc:1092
static void PrepareToDie()
Definition: debug.cc:562
static std::ostream & Extra(std::ostream &)
Definition: debug.cc:1313
static char * debugOptions
Definition: Stream.h:80
static void FreeAddr(struct addrinfo *&ai)
Definition: Address.cc:686
void getAddrInfo(struct addrinfo *&ai, int force=AF_UNSPEC) const
Definition: Address.cc:599
bool isAnyAddr() const
Definition: Address.cc:170
size_t count() const
returns the number of kids
Definition: Kids.cc:146
Kid & get(size_t i)
returns the kid by index, useful for kids iteration
Definition: Kids.cc:60
Definition: MemBuf.h:24
void clean()
Definition: MemBuf.cc:110
void append(const char *c, int sz) override
Definition: MemBuf.cc:209
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
char * buf
Definition: MemBuf.h:134
Definition: SBuf.h:94
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
gid_t effectiveGroupID
Definition: SquidConfig.h:562
uid_t effectiveUserID
Definition: SquidConfig.h:561
int max_filedescriptors
Definition: SquidConfig.h:517
char * effectiveGroup
Definition: SquidConfig.h:198
char * EmailFrom
Definition: SquidConfig.h:194
char * etcHostsPath
Definition: SquidConfig.h:227
Store::DiskConfig cacheSwap
Definition: SquidConfig.h:423
char * appendDomain
Definition: SquidConfig.h:222
char * coredump_dir
Definition: SquidConfig.h:472
char * visibleHostname
Definition: SquidConfig.h:228
char * adminEmail
Definition: SquidConfig.h:193
char * uniqueHostname
Definition: SquidConfig.h:229
char * EmailProgram
Definition: SquidConfig.h:195
char * effectiveUser
Definition: SquidConfig.h:196
int n_strands
number of disk processes required to support all cache_dirs
Definition: SquidConfig.h:72
an std::runtime_error with thrower location info
Definition: TextException.h:21
void clientConnectionsClose()
#define w_space
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define debug_log
change-avoidance macro; new code should call DebugStream() instead
Definition: Stream.h:183
#define DBG_CRITICAL
Definition: Stream.h:37
#define O_TEXT
Definition: defines.h:133
void fatal_dump(const char *message)
Definition: fatal.cc:78
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
void fqdncacheAddEntryFromHosts(char *addr, SBufList &hostnames)
Definition: fqdncache.cc:636
int opt_no_daemon
int shutting_down
const char * version_string
int Squid_MaxFD
int opt_catch_signals
int KidIdentifier
int ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
Definition: ipcache.cc:1123
Intercept Interceptor
Definition: Intercept.h:130
void icpClosePorts(void)
Definition: icp_v2.cc:804
int initgroups(const char *name, gid_t basegid)
Definition: initgroups.c:28
Config TheConfig
Globally available instance of Qos::Config.
Definition: QosConfig.cc:283
int intPercent(const int a, const int b)
Definition: SquidMath.cc:13
#define xfree
#define SQUIDHOSTNAMELEN
Definition: rfc2181.h:30
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:63
std::list< SBuf > SBufList
Definition: forward.h:23
#define SQUIDCEXTERN
Definition: squid.h:21
#define LOCAL_ARRAY(type, name, size)
Definition: squid.h:68
std::ostream & ForceAlert(std::ostream &s)
Definition: debug.cc:1408
#define FALSE
Definition: std-includes.h:56
struct timeval ru_utime
Definition: compat_shared.h:88
struct timeval ru_stime
Definition: compat_shared.h:87
int ru_majflt
Definition: compat_shared.h:90
int ru_maxrss
Definition: compat_shared.h:89
void EVH void double
Definition: stub_event.cc:16
char * tempnam(const char *dir, const char *pfx)
Definition: tempnam.c:119
void leave_suid(void)
Definition: tools.cc:559
bool IamMasterProcess()
whether the current process is the parent of all other Squid processes
Definition: tools.cc:668
static void setTraceability()
Definition: tools.cc:314
static void makeTraceable()
Definition: tools.cc:288
bool InDaemonMode()
Whether we are running in daemon mode.
Definition: tools.cc:690
void strwordquote(MemBuf *mb, const char *str)
Definition: tools.cc:1080
void squid_signal(int sig, SIGHDLR *func, int flags)
Definition: tools.cc:873
pid_t WaitForOnePid(pid_t pid, PidStatus &status, int flags)
Definition: tools.cc:1180
bool IamWorkerProcess()
whether the current process handles HTTP transactions and such
Definition: tools.cc:674
const char * getMyHostname(void)
Definition: tools.cc:467
void setUmask(mode_t mask)
Definition: tools.cc:1069
void death(int sig)
Definition: tools.cc:345
void keepCapabilities(void)
Definition: tools.cc:1122
void sigusr2_handle(int sig)
Definition: tools.cc:433
void setMaxFD(void)
Definition: tools.cc:762
void squid_getrusage(struct rusage *r)
Definition: tools.cc:180
static char * dead_msg(void)
Definition: tools.cc:107
double rusage_cputime(struct rusage *r)
Definition: tools.cc:238
bool IamPrimaryProcess()
Definition: tools.cc:708
void no_suid(void)
Definition: tools.cc:646
int rusage_maxrss(struct rusage *r)
Definition: tools.cc:253
void PrintRusage(void)
Definition: tools.cc:329
SBuf service_name(APP_SHORTNAME)
int NumberOfKids()
number of Kid processes as defined in src/ipc/Kid.h
Definition: tools.cc:724
#define DEAD_MSG
Definition: tools.cc:61
void enter_suid(void)
Definition: tools.cc:623
void logsFlush(void)
Definition: tools.cc:931
int getMyPort(void)
Definition: tools.cc:1041
static void mail_warranty(void)
Definition: tools.cc:115
static void restoreCapabilities(bool keep)
Definition: tools.cc:1133
void debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
Definition: tools.cc:938
int DebugSignal
Definition: tools.cc:73
void parseEtcHosts(void)
Definition: tools.cc:949
void debug_trap(const char *message)
Definition: tools.cc:458
int rusage_pagefaults(struct rusage *r)
Definition: tools.cc:274
void BroadcastSignalIfAny(int &sig)
Definition: tools.cc:418
bool IamCoordinatorProcess()
whether the current process coordinates worker processes
Definition: tools.cc:702
const char * uniqueHostname(void)
Definition: tools.cc:547
void releaseServerSockets(void)
Definition: tools.cc:92
void dumpMallocStats(void)
Definition: tools.cc:166
bool UsingSmp()
Whether there should be more than one worker process running.
Definition: tools.cc:696
SBuf ProcessRoles()
a string describing this process roles such as worker or coordinator
Definition: tools.cc:739
bool IamDiskProcess()
whether the current process is dedicated to managing a cache_dir
Definition: tools.cc:684
void setSystemLimits(void)
Definition: tools.cc:811
static char tmp_error_buf[32768]
Definition: tools.cc:89
void SIGHDLR(int sig)
callback type for signal handlers
Definition: tools.h:39
int PidStatus
Definition: tools.h:91
void(* ObjPackMethod)(void *obj, Packable *p)
Definition: tools.h:33
#define NULL
Definition: types.h:145
unsigned short mode_t
Definition: types.h:129
#define SQUID_RELEASE_TIME
Definition: version.h:13
#define APP_SHORTNAME
Definition: version.h:22
const char * xstrerr(int error)
Definition: xstrerror.cc:83

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors