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