]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tools.cc
Remove unused SBUF_SOURCE from parser/Makefile
[thirdparty/squid.git] / src / tools.cc
CommitLineData
30a4f2a8 1/*
bde978a6 2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
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.
019dd986 7 */
44a47c6e 8
bbc27441
AJ
9/* DEBUG: section 21 Misc Functions */
10
582c2af2 11#include "squid.h"
602d9612 12#include "anyp/PortCfg.h"
e0d28505 13#include "base/Subscription.h"
93da1f99 14#include "client_side.h"
438b04d4 15#include "disk.h"
528b2c61 16#include "fde.h"
95e6d864 17#include "fqdncache.h"
65d448bc 18#include "htcp.h"
e0d28505 19#include "ICP.h"
96d89ea0 20#include "ip/Intercept.h"
425de4c8 21#include "ip/QosConfig.h"
602d9612
A
22#include "ipc/Coordinator.h"
23#include "ipc/Kids.h"
24#include "ipcache.h"
0eb49b6d 25#include "MemBuf.h"
4d5904f7 26#include "SquidConfig.h"
a98bcbee 27#include "SquidMath.h"
985c86bc 28#include "SquidTime.h"
27bc2077 29#include "SwapDir.h"
602d9612 30#include "tools.h"
27bc2077 31#include "wordlist.h"
44a47c6e 32
1a30fdf5 33#include <cerrno>
62ae0622 34#if HAVE_SYS_PRCTL_H
35#include <sys/prctl.h>
36#endif
e30fe60a
AJ
37#if HAVE_WIN32_PSAPI
38#include <psapi.h>
39#endif
582c2af2
FC
40#if HAVE_SYS_STAT_H
41#include <sys/stat.h>
42#endif
43#if HAVE_SYS_WAIT_H
44#include <sys/wait.h>
45#endif
46#if HAVE_GRP_H
47#include <grp.h>
48#endif
62ae0622 49
090089c4 50#define DEAD_MSG "\
c5c666ab 51The Squid Cache (version %s) died.\n\
090089c4 52\n\
c5c666ab 53You've encountered a fatal error in the Squid Cache version %s.\n\
090089c4 54If a core file was created (possibly in the swap directory),\n\
b8de7ebe 55please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
784219b8 56and report the trace back to squid-bugs@squid-cache.org.\n\
090089c4 57\n\
58Thanks!\n"
59
f5b8bbc4 60static void mail_warranty(void);
ff2afd7f 61static void restoreCapabilities(bool keep);
a2c48c98 62int DebugSignal = -1;
8b505ba9 63SBuf service_name(APP_SHORTNAME);
24382924 64
1191b93b 65#if _SQUID_LINUX_
941a3077 66/* Workaround for crappy glic header files */
e6ccf245 67SQUIDCEXTERN int backtrace(void *, int);
68SQUIDCEXTERN void backtrace_symbols_fd(void *, int, int);
69SQUIDCEXTERN int setresuid(uid_t, uid_t, uid_t);
10da753f
FC
70#else /* _SQUID_LINUX_ */
71/* needed on Opensolaris for backtrace_symbols_fd */
72#if HAVE_EXECINFO_H
73#include <execinfo.h>
74#endif /* HAVE_EXECINFO_H */
75
941a3077 76#endif /* _SQUID_LINUX */
77
4a5a6c62 78void
429fdbec 79releaseServerSockets(void)
80{
65d448bc 81 // Release the main ports as early as possible
62e76326 82
e7ce227f 83 // clear http_port, https_port, and ftp_port lists
434a79b0 84 clientConnectionsClose();
62e76326 85
e0d28505 86 // clear icp_port's
65d448bc 87 icpClosePorts();
62e76326 88
e0d28505 89 // XXX: Why not the HTCP, SNMP, DNS ports as well?
65d448bc 90 // XXX: why does this differ from main closeServerConnections() anyway ?
429fdbec 91}
92
b8d8561b 93static char *
0673c0ba 94dead_msg(void)
090089c4 95{
95d659f0 96 LOCAL_ARRAY(char, msg, 1024);
56878878 97 snprintf(msg, 1024, DEAD_MSG, version_string, version_string);
090089c4 98 return msg;
99}
100
24382924 101static void
0673c0ba 102mail_warranty(void)
090089c4 103{
019dd986 104 FILE *fp = NULL;
6e40f263 105 static char command[256];
50536c47 106
a2c13db1
AJ
107 /*
108 * NP: umask() takes the mask of bits we DONT want set.
109 *
110 * We want the current user to have read/write access
111 * and since this file will be passed to mailsystem,
112 * the group and other must have read access.
113 */
114 const mode_t prev_umask=umask(S_IXUSR|S_IXGRP|S_IWGRP|S_IWOTH|S_IXOTH);
62e76326 115
50536c47 116#if HAVE_MKSTEMP
b99a6dec 117 char filename[] = "/tmp/squid-XXXXXX";
118 int tfd = mkstemp(filename);
50536c47
FC
119 if (tfd < 0 || (fp = fdopen(tfd, "w")) == NULL) {
120 umask(prev_umask);
62e76326 121 return;
50536c47 122 }
b99a6dec 123#else
124 char *filename;
50536c47
FC
125 // XXX tempnam is obsolete since POSIX.2008-1
126 // tmpfile is not an option, we want the created files to stick around
127 if ((filename = tempnam(NULL, APP_SHORTNAME)) == NULL ||
6a1a5b78 128 (fp = fopen(filename, "w")) == NULL) {
50536c47 129 umask(prev_umask);
62e76326 130 return;
50536c47 131 }
b99a6dec 132#endif
50536c47 133 umask(prev_umask);
62e76326 134
abacf776 135 if (Config.EmailFrom)
136 fprintf(fp, "From: %s\n", Config.EmailFrom);
137 else
7dbca7a4 138 fprintf(fp, "From: %s@%s\n", APP_SHORTNAME, uniqueHostname());
62e76326 139
edae7bc0 140 fprintf(fp, "To: %s\n", Config.adminEmail);
6e40f263 141 fprintf(fp, "Subject: %s\n", dead_msg());
142 fclose(fp);
62e76326 143
d084bf20 144 snprintf(command, 256, "%s %s < %s", Config.EmailProgram, Config.adminEmail, filename);
f53969cc 145 if (system(command)) {} /* XXX should avoid system(3) */
6e40f263 146 unlink(filename);
87cedd31
AJ
147#if !HAVE_MKSTEMP
148 xfree(filename); // tempnam() requires us to free its allocation
149#endif
090089c4 150}
151
4a5a6c62 152void
43c3424b 153dumpMallocStats(void)
3f43b19b 154{
88738790 155#if HAVE_MSTATS && HAVE_GNUMALLOC_H
62e76326 156
88738790 157 struct mstats ms = mstats();
158 fprintf(debug_log, "\ttotal space in arena: %6d KB\n",
62e76326 159 (int) (ms.bytes_total >> 10));
88738790 160 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
62e76326 161 (int) (ms.bytes_free >> 10),
a98bcbee 162 Math::intPercent(ms.bytes_free, ms.bytes_total));
4572073a 163#endif
3f43b19b 164}
30a4f2a8 165
f2908497 166void
167squid_getrusage(struct rusage *r)
f0f81709 168{
8da94b66 169 memset(r, '\0', sizeof(struct rusage));
e30fe60a 170#if HAVE_GETRUSAGE && defined(RUSAGE_SELF) && !_SQUID_WINDOWS_
1da023b5 171#if _SQUID_SOLARIS_
cd19f0b6 172 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
173 enter_suid();
174#endif
62e76326 175
f2908497 176 getrusage(RUSAGE_SELF, r);
62e76326 177
e30fe60a 178#if _SQUID_SOLARIS_
cd19f0b6 179 leave_suid();
180#endif
e30fe60a
AJ
181
182#elif _SQUID_WINDOWS_ && HAVE_WIN32_PSAPI
183 // Windows has an alternative method if there is no POSIX getrusage defined.
184 if (WIN32_OS_version >= _WIN_OS_WINNT) {
185 /* On Windows NT and later call PSAPI.DLL for process Memory */
186 /* informations -- Guido Serassio */
187 HANDLE hProcess;
188 PROCESS_MEMORY_COUNTERS pmc;
189 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
190 PROCESS_VM_READ,
191 FALSE, GetCurrentProcessId());
192 {
193 /* Microsoft CRT doesn't have getrusage function, */
194 /* so we get process CPU time information from PSAPI.DLL. */
195 FILETIME ftCreate, ftExit, ftKernel, ftUser;
196 if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
197 int64_t *ptUser = (int64_t *)&ftUser;
198 int64_t tUser64 = *ptUser / 10;
199 int64_t *ptKernel = (int64_t *)&ftKernel;
200 int64_t tKernel64 = *ptKernel / 10;
201 r->ru_utime.tv_sec =(long)(tUser64 / 1000000);
202 r->ru_stime.tv_sec =(long)(tKernel64 / 1000000);
203 r->ru_utime.tv_usec =(long)(tUser64 % 1000000);
204 r->ru_stime.tv_usec =(long)(tKernel64 % 1000000);
205 } else {
206 CloseHandle( hProcess );
207 return;
208 }
209 }
210 if (GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc))) {
211 r->ru_maxrss=(DWORD)(pmc.WorkingSetSize / getpagesize());
212 r->ru_majflt=pmc.PageFaultCount;
213 } else {
214 CloseHandle( hProcess );
215 return;
216 }
217
218 CloseHandle( hProcess );
219 }
56983a01 220#endif
f2908497 221}
222
223double
62e76326 224
f2908497 225rusage_cputime(struct rusage *r)
226{
227 return (double) r->ru_stime.tv_sec +
62e76326 228 (double) r->ru_utime.tv_sec +
229 (double) r->ru_stime.tv_usec / 1000000.0 +
230 (double) r->ru_utime.tv_usec / 1000000.0;
f2908497 231}
232
ec603b25 233/* Hack for some HP-UX preprocessors */
234#ifndef HAVE_GETPAGESIZE
235#define HAVE_GETPAGESIZE 0
236#endif
237
f2908497 238int
62e76326 239
f2908497 240rusage_maxrss(struct rusage *r)
241{
8a09e810 242#if _SQUID_SGI_ && _ABIAPI
4fdc3986 243 return r->ru_pad[0];
8a09e810 244#elif _SQUID_SGI_|| _SQUID_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
62e76326 245
f2908497 246 return r->ru_maxrss;
6b8e7481 247#elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
62e76326 248
f2908497 249 return (r->ru_maxrss * getpagesize()) >> 10;
c7a1083d 250#elif defined(PAGESIZE)
62e76326 251
c7a1083d 252 return (r->ru_maxrss * PAGESIZE) >> 10;
8505e57b 253#else
62e76326 254
8505e57b 255 return r->ru_maxrss;
f2908497 256#endif
257}
258
259int
62e76326 260
f2908497 261rusage_pagefaults(struct rusage *r)
262{
8a09e810 263#if _SQUID_SGI_ && _ABIAPI
4fdc3986 264 return r->ru_pad[5];
265#else
62e76326 266
f2908497 267 return r->ru_majflt;
4fdc3986 268#endif
f2908497 269}
270
4a5a6c62 271void
f2908497 272PrintRusage(void)
273{
62e76326 274
f2908497 275 struct rusage rusage;
276 squid_getrusage(&rusage);
2b906e48 277 fprintf(debug_log, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
62e76326 278 rusage_cputime(&rusage),
279 rusage.ru_utime.tv_sec + ((double) rusage.ru_utime.tv_usec / 1000000.0),
280 rusage.ru_stime.tv_sec + ((double) rusage.ru_stime.tv_usec / 1000000.0));
f2908497 281 fprintf(debug_log, "Maximum Resident Size: %d KB\n",
62e76326 282 rusage_maxrss(&rusage));
f2908497 283 fprintf(debug_log, "Page faults with physical i/o: %d\n",
62e76326 284 rusage_pagefaults(&rusage));
f0f81709 285}
286
b8d8561b 287void
288death(int sig)
44a47c6e 289{
0e08ce4b 290 if (sig == SIGSEGV)
62e76326 291 fprintf(debug_log, "FATAL: Received Segment Violation...dying.\n");
0e08ce4b 292 else if (sig == SIGBUS)
62e76326 293 fprintf(debug_log, "FATAL: Received Bus Error...dying.\n");
0e08ce4b 294 else
62e76326 295 fprintf(debug_log, "FATAL: Received signal %d...dying.\n", sig);
0b4639af 296
0a081cb0 297#if PRINT_STACK_TRACE
1191b93b 298#if _SQUID_HPUX_
0b4639af 299 {
f53969cc 300 extern void U_STACK_TRACE(void); /* link with -lcl */
62e76326 301 fflush(debug_log);
302 dup2(fileno(debug_log), 2);
303 U_STACK_TRACE();
0b4639af 304 }
62e76326 305
0b4639af 306#endif /* _SQUID_HPUX_ */
8a09e810 307#if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
f53969cc
SM
308 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
309 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
62e76326 310 fflush(debug_log);
311 dup2(fileno(debug_log), fileno(stdout));
312 opcom_stack_trace();
313 fflush(stdout);
0b4639af 314 }
62e76326 315
10da753f 316#endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
ce3d30fb 317#if HAVE_BACKTRACE_SYMBOLS_FD
318 {
62e76326 319 static void *(callarray[8192]);
320 int n;
321 n = backtrace(callarray, 8192);
322 backtrace_symbols_fd(callarray, n, fileno(debug_log));
ce3d30fb 323 }
62e76326 324
ce3d30fb 325#endif
0b4639af 326#endif /* PRINT_STACK_TRACE */
327
7aa9bb3e 328#if SA_RESETHAND == 0 && !_SQUID_WINDOWS_
44a47c6e 329 signal(SIGSEGV, SIG_DFL);
62e76326 330
44a47c6e 331 signal(SIGBUS, SIG_DFL);
62e76326 332
0e08ce4b 333 signal(sig, SIG_DFL);
62e76326 334
30a4f2a8 335#endif
62e76326 336
429fdbec 337 releaseServerSockets();
62e76326 338
e3ef2b09 339 storeDirWriteCleanLogs(0);
62e76326 340
4b0f5de8 341 if (!shutting_down) {
342 PrintRusage();
62e76326 343
4b0f5de8 344 dumpMallocStats();
345 }
62e76326 346
6e40f263 347 if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
62e76326 348 /* skip if more than 10 days old */
349
350 if (Config.adminEmail)
351 mail_warranty();
329ce686 352
353 puts(dead_msg());
6e40f263 354 }
62e76326 355
44a47c6e 356 abort();
357}
358
a2c48c98
AR
359void
360BroadcastSignalIfAny(int& sig)
361{
362 if (sig > 0) {
dbf55289
CT
363 if (IamMasterProcess()) {
364 for (int i = TheKids.count() - 1; i >= 0; --i) {
365 Kid& kid = TheKids.get(i);
366 kill(kid.getPid(), sig);
367 }
368 }
a2c48c98
AR
369 sig = -1;
370 }
371}
44a47c6e 372
b8d8561b 373void
23d92c64 374sigusr2_handle(int sig)
090089c4 375{
30a4f2a8 376 static int state = 0;
96e03dd8 377 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
62e76326 378
a2c48c98
AR
379 DebugSignal = sig;
380
30a4f2a8 381 if (state == 0) {
d7298d24 382 Debug::parseOptions("ALL,7");
62e76326 383 state = 1;
30a4f2a8 384 } else {
62493678 385 Debug::parseOptions(Debug::debugOptions);
62e76326 386 state = 0;
30a4f2a8 387 }
62e76326 388
30a4f2a8 389#if !HAVE_SIGACTION
f53969cc 390 if (signal(sig, sigusr2_handle) == SIG_ERR) /* reinstall */
fa84c01d 391 debugs(50, DBG_CRITICAL, "signal: sig=" << sig << " func=sigusr2_handle: " << xstrerror());
62e76326 392
090089c4 393#endif
394}
395
b8d8561b 396void
af6a12ee
AJ
397debug_trap(const char *message)
398{
4a69c163 399 if (!opt_catch_signals)
62e76326 400 fatal_dump(message);
401
a3d5953d 402 _db_print("WARNING: %s\n", message);
85b701ed 403}
404
0ee4272b 405const char *
0673c0ba 406getMyHostname(void)
44a47c6e 407{
95d659f0 408 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
44a47c6e 409 static int present = 0;
cc192b50 410 struct addrinfo *AI = NULL;
b7ac5457 411 Ip::Address sa;
62e76326 412
af85f811 413 if (Config.visibleHostname != NULL)
62e76326 414 return Config.visibleHostname;
415
d20b1cd0 416 if (present)
62e76326 417 return host;
418
d20b1cd0 419 host[0] = '\0';
62e76326 420
fa720bfb
AJ
421 if (HttpPortList != NULL && sa.isAnyAddr())
422 sa = HttpPortList->s;
62e76326 423
cb4f4424 424#if USE_OPENSSL
62e76326 425
fa720bfb
AJ
426 if (HttpsPortList != NULL && sa.isAnyAddr())
427 sa = HttpsPortList->s;
62e76326 428
aa2b5399 429#endif
cc192b50 430
aa2b5399 431 /*
432 * If the first http_port address has a specific address, try a
433 * reverse DNS lookup on it.
434 */
4dd643d5 435 if ( !sa.isAnyAddr() ) {
62e76326 436
4dd643d5 437 sa.getAddrInfo(AI);
cc192b50 438 /* we are looking for a name. */
27bc2077 439 if (getnameinfo(AI->ai_addr, AI->ai_addrlen, host, SQUIDHOSTNAMELEN, NULL, 0, NI_NAMEREQD ) == 0) {
62e76326 440 /* DNS lookup successful */
441 /* use the official name from DNS lookup */
cc192b50 442 debugs(50, 4, "getMyHostname: resolved " << sa << " to '" << host << "'");
bf8fe701 443
62e76326 444 present = 1;
445
851614a8 446 Ip::Address::FreeAddr(AI);
cc192b50 447
62e76326 448 if (strchr(host, '.'))
449 return host;
62e76326 450 }
451
851614a8 452 Ip::Address::FreeAddr(AI);
c19d1320
AJ
453 debugs(50, 2, "WARNING: failed to resolve " << sa << " to a fully qualified hostname");
454 }
455
456 // still no host. fallback to gethostname()
457 if (gethostname(host, SQUIDHOSTNAMELEN) < 0) {
458 debugs(50, DBG_IMPORTANT, "WARNING: gethostname failed: " << xstrerror());
26ac0430 459 } else {
c19d1320
AJ
460 /* Verify that the hostname given resolves properly */
461 struct addrinfo hints;
462 memset(&hints, 0, sizeof(addrinfo));
463 hints.ai_flags = AI_CANONNAME;
62e76326 464
c19d1320
AJ
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.");
469 present = 1;
470
471 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
4dd643d5 472 if (AI)
c19d1320 473 freeaddrinfo(AI);
cc192b50 474
c19d1320 475 return host;
cc192b50 476 }
c19d1320 477
4dd643d5
AJ
478 if (AI)
479 freeaddrinfo(AI);
c19d1320 480 debugs(50, DBG_IMPORTANT, "WARNING: '" << host << "' rDNS test failed: " << xstrerror());
44a47c6e 481 }
62e76326 482
c19d1320
AJ
483 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
484 debugs(50, DBG_CRITICAL, "WARNING: Could not determine this machines public hostname. " <<
485 "Please configure one or set 'visible_hostname'.");
a572d8be 486
c19d1320 487 return ("localhost");
44a47c6e 488}
489
98829f69 490const char *
491uniqueHostname(void)
492{
23c6ebc4 493 debugs(21, 3, HERE << " Config: '" << Config.uniqueHostname << "'");
98829f69 494 return Config.uniqueHostname ? Config.uniqueHostname : getMyHostname();
495}
496
23c6ebc4 497/** leave a priviliged section. (Give up any privilegies)
30a4f2a8 498 * Routines that need privilegies can rap themselves in enter_suid()
499 * and leave_suid()
500 * To give upp all posibilites to gain privilegies use no_suid()
12b9e9b1 501 */
b8d8561b 502void
0673c0ba 503leave_suid(void)
12b9e9b1 504{
36584579 505 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
62e76326 506
e3d74828 507 if (Config.effectiveGroup) {
508
509#if HAVE_SETGROUPS
510
511 setgroups(1, &Config2.effectiveGroupID);
512
513#endif
514
515 if (setgid(Config2.effectiveGroupID) < 0)
fa84c01d 516 debugs(50, DBG_CRITICAL, "ALERT: setgid: " << xstrerror());
e3d74828 517
518 }
519
12b9e9b1 520 if (geteuid() != 0)
62e76326 521 return;
522
12b9e9b1 523 /* Started as a root, check suid option */
b6f794d6 524 if (Config.effectiveUser == NULL)
62e76326 525 return;
526
36584579 527 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config.effectiveUser << "'");
62e76326 528
e3d74828 529 if (!Config.effectiveGroup) {
62e76326 530
e3d74828 531 if (setgid(Config2.effectiveGroupID) < 0)
fa84c01d 532 debugs(50, DBG_CRITICAL, "ALERT: setgid: " << xstrerror());
62e76326 533
e3d74828 534 if (initgroups(Config.effectiveUser, Config2.effectiveGroupID) < 0) {
fa84c01d 535 debugs(50, DBG_CRITICAL, "ALERT: initgroups: unable to set groups for User " <<
bf8fe701 536 Config.effectiveUser << " and Group " <<
537 (unsigned) Config2.effectiveGroupID << "");
e3d74828 538 }
539 }
62e76326 540
234967c9 541#if HAVE_SETRESUID
62e76326 542
d20b1cd0 543 if (setresuid(Config2.effectiveUserID, Config2.effectiveUserID, 0) < 0)
fa84c01d 544 debugs(50, DBG_CRITICAL, "ALERT: setresuid: " << xstrerror());
62e76326 545
234967c9 546#elif HAVE_SETEUID
62e76326 547
d20b1cd0 548 if (seteuid(Config2.effectiveUserID) < 0)
fa84c01d 549 debugs(50, DBG_CRITICAL, "ALERT: seteuid: " << xstrerror());
62e76326 550
234967c9 551#else
62e76326 552
d20b1cd0 553 if (setuid(Config2.effectiveUserID) < 0)
fa84c01d 554 debugs(50, DBG_CRITICAL, "ALERT: setuid: " << xstrerror());
62e76326 555
fc68f6b1 556#endif
fc68f6b1 557
ff2afd7f 558 restoreCapabilities(true);
fc68f6b1 559
62ae0622 560#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
561 /* Set Linux DUMPABLE flag */
562 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 563 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 564
234967c9 565#endif
566}
567
30a4f2a8 568/* Enter a privilegied section */
b8d8561b 569void
0673c0ba 570enter_suid(void)
234967c9 571{
77468ee5 572 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root privileges");
234967c9 573#if HAVE_SETRESUID
77468ee5 574 if (setresuid((uid_t)-1, 0, (uid_t)-1) < 0)
6595704b 575 debugs (21, 3, "enter_suid: setresuid failed: " << xstrerror ());
234967c9 576#else
62e76326 577
234967c9 578 setuid(0);
579#endif
62ae0622 580#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
581 /* Set Linux DUMPABLE flag */
582
583 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 584 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 585
586#endif
234967c9 587}
588
30a4f2a8 589/* Give up the posibility to gain privilegies.
590 * this should be used before starting a sub process
591 */
b8d8561b 592void
0673c0ba 593no_suid(void)
234967c9 594{
595 uid_t uid;
30a4f2a8 596 leave_suid();
234967c9 597 uid = geteuid();
329ce686 598 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
62e76326 599
77468ee5 600 if (setuid(0) < 0)
6595704b 601 debugs(50, DBG_IMPORTANT, "WARNING: no_suid: setuid(0): " << xstrerror());
62e76326 602
429fdbec 603 if (setuid(uid) < 0)
77468ee5 604 debugs(50, DBG_IMPORTANT, "ERROR: no_suid: setuid(" << uid << "): " << xstrerror());
62e76326 605
ff2afd7f 606 restoreCapabilities(false);
329ce686 607
62ae0622 608#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
609 /* Set Linux DUMPABLE flag */
610 if (Config.coredump_dir && prctl(PR_SET_DUMPABLE, 1) != 0)
bf8fe701 611 debugs(50, 2, "ALERT: prctl: " << xstrerror());
62ae0622 612
234967c9 613#endif
12b9e9b1 614}
ccff9601 615
a2c48c98 616bool
7de94c8c 617IamMasterProcess()
a2c48c98 618{
7de94c8c
AR
619 return KidIdentifier == 0;
620}
621
622bool
623IamWorkerProcess()
624{
625 // when there is only one process, it has to be the worker
13aeac35 626 if (opt_no_daemon || Config.workers == 0)
7de94c8c
AR
627 return true;
628
095ec2b1
AR
629 return TheProcessKind == pkWorker;
630}
631
632bool
633IamDiskProcess()
634{
635 return TheProcessKind == pkDisker;
7de94c8c
AR
636}
637
96c2bb61
AR
638bool
639InDaemonMode()
640{
641 return !opt_no_daemon && Config.workers > 0;
642}
643
7de94c8c
AR
644bool
645UsingSmp()
646{
095ec2b1 647 return InDaemonMode() && NumberOfKids() > 1;
7de94c8c
AR
648}
649
650bool
651IamCoordinatorProcess()
652{
095ec2b1 653 return TheProcessKind == pkCoordinator;
7de94c8c
AR
654}
655
656bool
657IamPrimaryProcess()
658{
659 // when there is only one process, it has to be primary
13aeac35 660 if (opt_no_daemon || Config.workers == 0)
7de94c8c
AR
661 return true;
662
663 // when there is a master and worker process, the master delegates
664 // primary functions to its only kid
254912f3 665 if (NumberOfKids() == 1)
7de94c8c 666 return IamWorkerProcess();
a2c48c98 667
7de94c8c
AR
668 // in SMP mode, multiple kids delegate primary functions to the coordinator
669 return IamCoordinatorProcess();
a2c48c98
AR
670}
671
96c2bb61
AR
672int
673NumberOfKids()
674{
675 // no kids in no-daemon mode
676 if (!InDaemonMode())
677 return 0;
678
095ec2b1
AR
679 // XXX: detect and abort when called before workers/cache_dirs are parsed
680
14911a4e 681 const int rockDirs = Config.cacheSwap.n_strands;
095ec2b1
AR
682
683 const bool needCoord = Config.workers > 1 || rockDirs > 0;
684 return (needCoord ? 1 : 0) + Config.workers + rockDirs;
685}
96c2bb61 686
095ec2b1
AR
687String
688ProcessRoles()
689{
690 String roles = "";
691 if (IamMasterProcess())
692 roles.append(" master");
693 if (IamCoordinatorProcess())
694 roles.append(" coordinator");
695 if (IamWorkerProcess())
696 roles.append(" worker");
697 if (IamDiskProcess())
698 roles.append(" disker");
699 return roles;
96c2bb61
AR
700}
701
b8d8561b 702void
0673c0ba 703writePidFile(void)
ccff9601 704{
9e4ad609 705 int fd;
0b4639af 706 const char *f = NULL;
973e9fe1 707 mode_t old_umask;
9e4ad609 708 char buf[32];
62e76326 709
9e4ad609 710 if ((f = Config.pidFilename) == NULL)
62e76326 711 return;
712
9e4ad609 713 if (!strcmp(Config.pidFilename, "none"))
62e76326 714 return;
715
30a4f2a8 716 enter_suid();
62e76326 717
973e9fe1 718 old_umask = umask(022);
62e76326 719
dbf55289 720 fd = open(f, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT, 0644);
62e76326 721
973e9fe1 722 umask(old_umask);
62e76326 723
30a4f2a8 724 leave_suid();
62e76326 725
9e4ad609 726 if (fd < 0) {
fa84c01d 727 debugs(50, DBG_CRITICAL, "" << f << ": " << xstrerror());
62e76326 728 debug_trap("Could not write pid file");
729 return;
ccff9601 730 }
62e76326 731
56878878 732 snprintf(buf, 32, "%d\n", (int) getpid());
dbf55289
CT
733 const size_t ws = write(fd, buf, strlen(buf));
734 assert(ws == strlen(buf));
735 close(fd);
736}
737
738void
739removePidFile()
740{
741 if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
742 enter_suid();
743 safeunlink(Config.pidFilename, 0);
744 leave_suid();
745 }
ccff9601 746}
c4fb974e 747
ff8d0ea6 748pid_t
0673c0ba 749readPidFile(void)
7690e8eb 750{
751 FILE *pid_fp = NULL;
9e4ad609 752 const char *f = Config.pidFilename;
1ee742a2 753 char *chroot_f = NULL;
ff8d0ea6 754 pid_t pid = -1;
755 int i;
7690e8eb 756
9e4ad609 757 if (f == NULL || !strcmp(Config.pidFilename, "none")) {
7dbca7a4 758 fprintf(stderr, APP_SHORTNAME ": ERROR: No pid file name defined\n");
62e76326 759 exit(1);
7690e8eb 760 }
62e76326 761
1ee742a2 762 if (Config.chroot_dir && geteuid() == 0) {
763 int len = strlen(Config.chroot_dir) + 1 + strlen(f) + 1;
764 chroot_f = (char *)xmalloc(strlen(Config.chroot_dir) + 1 + strlen(f) + 1);
765 snprintf(chroot_f, len, "%s/%s", Config.chroot_dir, f);
766 f = chroot_f;
767 }
768
7690e8eb 769 pid_fp = fopen(f, "r");
62e76326 770
7690e8eb 771 if (pid_fp != NULL) {
62e76326 772 pid = 0;
773
774 if (fscanf(pid_fp, "%d", &i) == 1)
775 pid = (pid_t) i;
776
777 fclose(pid_fp);
7690e8eb 778 } else {
62e76326 779 if (errno != ENOENT) {
7dbca7a4 780 fprintf(stderr, APP_SHORTNAME ": ERROR: Could not read pid file\n");
62e76326 781 fprintf(stderr, "\t%s: %s\n", f, xstrerror());
782 exit(1);
783 }
7690e8eb 784 }
62e76326 785
1ee742a2 786 safe_free(chroot_f);
7690e8eb 787 return pid;
788}
789
f3f0f563
AJ
790/* A little piece of glue for odd systems */
791#ifndef RLIMIT_NOFILE
792#ifdef RLIMIT_OFILE
793#define RLIMIT_NOFILE RLIMIT_OFILE
794#endif
795#endif
7690e8eb 796
f3f0f563 797/** Figure out the number of supported filedescriptors */
b8d8561b 798void
0673c0ba 799setMaxFD(void)
c4fb974e 800{
f3f0f563 801#if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
8527a56f 802
9064ed81
A
803 /* On Linux with 64-bit file support the sys/resource.h header
804 * uses #define to change the function definition to require rlimit64
805 */
8527a56f
AJ
806#if defined(getrlimit)
807 struct rlimit64 rl; // Assume its a 64-bit redefine anyways.
808#else
c4fb974e 809 struct rlimit rl;
8527a56f
AJ
810#endif
811
c4fb974e 812 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
f3f0f563
AJ
813 debugs(50, DBG_CRITICAL, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
814 } else if (Config.max_filedescriptors > 0) {
0979b3a6
AJ
815#if USE_SELECT || USE_SELECT_WIN32
816 /* select() breaks if this gets set too big */
1b7fae06 817 if (Config.max_filedescriptors > FD_SETSIZE) {
0979b3a6 818 rl.rlim_cur = FD_SETSIZE;
1b7fae06
AJ
819 debugs(50, DBG_CRITICAL, "WARNING: 'max_filedescriptors " << Config.max_filedescriptors << "' does not work with select()");
820 } else
0979b3a6
AJ
821#endif
822 rl.rlim_cur = Config.max_filedescriptors;
62e76326 823 if (rl.rlim_cur > rl.rlim_max)
f3f0f563
AJ
824 rl.rlim_max = rl.rlim_cur;
825 if (setrlimit(RLIMIT_NOFILE, &rl)) {
1b7fae06 826 debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerror());
f3f0f563
AJ
827 getrlimit(RLIMIT_NOFILE, &rl);
828 rl.rlim_cur = rl.rlim_max;
829 if (setrlimit(RLIMIT_NOFILE, &rl)) {
1b7fae06 830 debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerror());
f3f0f563 831 }
62e76326 832 }
c4fb974e 833 }
f3f0f563 834 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
1b7fae06 835 debugs(50, DBG_CRITICAL, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerror());
c4fb974e 836 } else {
f3f0f563
AJ
837 Squid_MaxFD = rl.rlim_cur;
838 }
62e76326 839
f3f0f563
AJ
840#endif /* HAVE_SETRLIMIT */
841}
62e76326 842
f3f0f563
AJ
843void
844setSystemLimits(void)
845{
be266cb2 846#if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
f3f0f563 847 /* limit system filedescriptors to our own limit */
8527a56f
AJ
848
849 /* On Linux with 64-bit file support the sys/resource.h header
850 * uses #define to change the function definition to require rlimit64
851 */
852#if defined(getrlimit)
853 struct rlimit64 rl; // Assume its a 64-bit redefine anyways.
854#else
f3f0f563 855 struct rlimit rl;
8527a56f
AJ
856#endif
857
f3f0f563
AJ
858 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
859 debugs(50, DBG_CRITICAL, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
860 } else {
861 rl.rlim_cur = Squid_MaxFD;
862 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
863 snprintf(tmp_error_buf, ERROR_BUF_SZ, "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
62e76326 864 fatal_dump(tmp_error_buf);
865 }
c4fb974e 866 }
30a4f2a8 867#endif /* HAVE_SETRLIMIT */
868
a396d1f8 869#if HAVE_SETRLIMIT && defined(RLIMIT_DATA) && !_SQUID_CYGWIN_
30a4f2a8 870 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
f3f0f563 871 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_DATA: " << xstrerror());
88738790 872 } else if (rl.rlim_max > rl.rlim_cur) {
f53969cc 873 rl.rlim_cur = rl.rlim_max; /* set it to the max */
62e76326 874
875 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
f3f0f563 876 snprintf(tmp_error_buf, ERROR_BUF_SZ, "setrlimit: RLIMIT_DATA: %s", xstrerror());
62e76326 877 fatal_dump(tmp_error_buf);
878 }
30a4f2a8 879 }
880#endif /* RLIMIT_DATA */
f3f0f563
AJ
881 if (Config.max_filedescriptors > Squid_MaxFD) {
882 debugs(50, DBG_IMPORTANT, "NOTICE: Could not increase the number of filedescriptors");
883 }
884
a396d1f8 885#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM) && !_SQUID_CYGWIN_
ad7ef91a 886 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
30c48b1a 887 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_VMEM: " << xstrerror());
88738790 888 } else if (rl.rlim_max > rl.rlim_cur) {
f53969cc 889 rl.rlim_cur = rl.rlim_max; /* set it to the max */
62e76326 890
891 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
f3f0f563 892 snprintf(tmp_error_buf, ERROR_BUF_SZ, "setrlimit: RLIMIT_VMEM: %s", xstrerror());
62e76326 893 fatal_dump(tmp_error_buf);
894 }
ad7ef91a 895 }
896#endif /* RLIMIT_VMEM */
c4fb974e 897}
3a57089e 898
b8d8561b 899void
ea3a2a69 900squid_signal(int sig, SIGHDLR * func, int flags)
30a4f2a8 901{
902#if HAVE_SIGACTION
62e76326 903
30a4f2a8 904 struct sigaction sa;
905 sa.sa_handler = func;
906 sa.sa_flags = flags;
907 sigemptyset(&sa.sa_mask);
62e76326 908
30a4f2a8 909 if (sigaction(sig, &sa, NULL) < 0)
30c48b1a 910 debugs(50, DBG_CRITICAL, "sigaction: sig=" << sig << " func=" << func << ": " << xstrerror());
62e76326 911
30a4f2a8 912#else
7aa9bb3e 913#if _SQUID_WINDOWS_
06648839 914 /*
915 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
916 are supported, so we must care of don't call signal() for other value.
917 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
918 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
919 */
920 switch (sig) {
921
922 case SIGINT:
923
924 case SIGILL:
925
926 case SIGFPE:
927
928 case SIGTERM:
929
930 case SIGBREAK:
931
932 case SIGABRT:
933 break;
934
935 case SIGSEGV:
936 WIN32_ExceptionHandlerInit();
937 break;
938
939 case SIGBUS:
940 WIN32_ExceptionHandlerInit();
941 return;
942 break; /* Nor reached */
943
944 default:
945 return;
946 break; /* Nor reached */
947 }
948
949#endif
62e76326 950
06648839 951 signal(sig, func);
62e76326 952
30a4f2a8 953#endif
954}
396c5745 955
70364f29 956void
957logsFlush(void)
958{
959 if (debug_log)
62e76326 960 fflush(debug_log);
70364f29 961}
88738790 962
16300b58 963void
0e473d70 964kb_incr(kb_t * k, size_t v)
a7c05555 965{
0e473d70 966 k->bytes += v;
967 k->kb += (k->bytes >> 10);
968 k->bytes &= 0x3FF;
a7c05555 969}
c1dabf04 970
a00a7c85 971void
6bbf9cc4 972debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
a00a7c85 973{
6bbf9cc4 974 assert(label && obj && pm);
10201568 975 MemBuf mb;
2fe7eff9 976 mb.init();
10201568 977 (*pm) (obj, &mb);
bf8fe701 978 debugs(section, level, "" << label << "" << mb.buf << "");
2fe7eff9 979 mb.clean();
a00a7c85 980}
d548ee64 981
0e70aa1e 982void
983parseEtcHosts(void)
984{
985 FILE *fp;
986 char buf[1024];
987 char buf2[512];
988 char *nt = buf;
989 char *lt = buf;
fa2bfbab 990
0e70aa1e 991 if (NULL == Config.etcHostsPath)
62e76326 992 return;
993
0e70aa1e 994 if (0 == strcmp(Config.etcHostsPath, "none"))
62e76326 995 return;
996
0e70aa1e 997 fp = fopen(Config.etcHostsPath, "r");
62e76326 998
0e70aa1e 999 if (fp == NULL) {
e0236918 1000 debugs(1, DBG_IMPORTANT, "parseEtcHosts: " << Config.etcHostsPath << ": " << xstrerror());
62e76326 1001 return;
0e70aa1e 1002 }
62e76326 1003
be266cb2 1004#if _SQUID_WINDOWS_
c4aefe96 1005 setmode(fileno(fp), O_TEXT);
1006#endif
62e76326 1007
f53969cc 1008 while (fgets(buf, 1024, fp)) { /* for each line */
62e76326 1009 wordlist *hosts = NULL;
1010 char *addr;
1011
f53969cc 1012 if (buf[0] == '#') /* MS-windows likes to add comments */
c31616ae 1013 continue;
1014
f53969cc 1015 strtok(buf, "#"); /* chop everything following a comment marker */
62e76326 1016
1017 lt = buf;
1018
1019 addr = buf;
1020
bf8fe701 1021 debugs(1, 5, "etc_hosts: line is '" << buf << "'");
62e76326 1022
1023 nt = strpbrk(lt, w_space);
1024
f53969cc 1025 if (nt == NULL) /* empty line */
62e76326 1026 continue;
1027
f53969cc 1028 *nt = '\0'; /* null-terminate the address */
62e76326 1029
bf8fe701 1030 debugs(1, 5, "etc_hosts: address is '" << addr << "'");
62e76326 1031
1032 lt = nt + 1;
1033
1034 while ((nt = strpbrk(lt, w_space))) {
1035 char *host = NULL;
1036
f53969cc 1037 if (nt == lt) { /* multiple spaces */
bf8fe701 1038 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
62e76326 1039 lt = nt + 1;
1040 continue;
1041 }
1042
1043 *nt = '\0';
bf8fe701 1044 debugs(1, 5, "etc_hosts: got hostname '" << lt << "'");
62e76326 1045
532e5dd4
AJ
1046 /* For IPV6 addresses also check for a colon */
1047 if (Config.appendDomain && !strchr(lt, '.') && !strchr(lt, ':')) {
62e76326 1048 /* I know it's ugly, but it's only at reconfig */
0a84e4fb
AJ
1049 strncpy(buf2, lt, sizeof(buf2)-1);
1050 strncat(buf2, Config.appendDomain, sizeof(buf2) - strlen(lt) - 1);
50e746f3 1051 buf2[sizeof(buf2)-1] = '\0';
62e76326 1052 host = buf2;
1053 } else {
1054 host = lt;
1055 }
1056
f6a72b33
AJ
1057 if (ipcacheAddEntryFromHosts(host, addr) != 0) {
1058 /* invalid address, continuing is useless */
1059 wordlistDestroy(&hosts);
1060 hosts = NULL;
1061 break;
1062 }
62e76326 1063 wordlistAdd(&hosts, host);
1064
1065 lt = nt + 1;
1066 }
1067
9e008dda 1068 if (hosts) {
f6a72b33
AJ
1069 fqdncacheAddEntryFromHosts(addr, hosts);
1070 wordlistDestroy(&hosts);
1071 }
0e70aa1e 1072 }
62e76326 1073
1f3c7397 1074 fclose (fp);
0e70aa1e 1075}
52f772de 1076
1077int
1078getMyPort(void)
1079{
fa720bfb
AJ
1080 AnyP::PortCfgPointer p;
1081 if ((p = HttpPortList) != NULL) {
c4ac4197 1082 // skip any special interception ports
fa720bfb 1083 while (p != NULL && p->flags.isIntercepted())
af5ebaf4 1084 p = p->next;
fa720bfb 1085 if (p != NULL)
4dd643d5 1086 return p->s.port();
af5ebaf4 1087 }
62e76326 1088
cb4f4424 1089#if USE_OPENSSL
fa720bfb 1090 if ((p = HttpsPortList) != NULL) {
c4ac4197 1091 // skip any special interception ports
fa720bfb 1092 while (p != NULL && p->flags.isIntercepted())
c4ac4197 1093 p = p->next;
fa720bfb 1094 if (p != NULL)
4dd643d5 1095 return p->s.port();
c4ac4197 1096 }
52f772de 1097#endif
62e76326 1098
8ea0d847 1099 if ((p = FtpPortList) != NULL) {
547f3031 1100 // skip any special interception ports
8ea0d847 1101 while (p != NULL && p->flags.isIntercepted())
547f3031 1102 p = p->next;
8ea0d847 1103 if (p != NULL)
547f3031
AR
1104 return p->s.port();
1105 }
1106
af5ebaf4
AJ
1107 debugs(21, DBG_CRITICAL, "ERROR: No forward-proxy ports configured.");
1108 return 0; // Invalid port. This will result in invalid URLs on bad configurations.
52f772de 1109}
d860a1aa 1110
c642c141
AJ
1111/*
1112 * Set the umask to at least the given mask. This is in addition
1113 * to the umask set at startup
1114 */
1115void
1116setUmask(mode_t mask)
1117{
1118 // No way to get the current umask value without setting it.
1119 static const mode_t orig_umask = umask(mask); // once, to get
1120 umask(mask | orig_umask); // always, to set
1121}
d860a1aa 1122
1123/*
1124 * Inverse of strwordtok. Quotes a word if needed
1125 */
42419a95 1126void
d860a1aa 1127strwordquote(MemBuf * mb, const char *str)
1128{
1129 int quoted = 0;
62e76326 1130
d860a1aa 1131 if (strchr(str, ' ')) {
62e76326 1132 quoted = 1;
2fe7eff9 1133 mb->append("\"", 1);
d860a1aa 1134 }
62e76326 1135
d860a1aa 1136 while (*str) {
dc1af3cf 1137 int l = strcspn(str, "\"\\\n\r");
2fe7eff9 1138 mb->append(str, l);
62e76326 1139 str += l;
1140
26ac0430 1141 switch (*str) {
dc1af3cf 1142
1143 case '\n':
2fe7eff9 1144 mb->append("\\n", 2);
5db6bf73 1145 ++str;
dc1af3cf 1146 break;
1147
1148 case '\r':
2fe7eff9 1149 mb->append("\\r", 2);
5db6bf73 1150 ++str;
dc1af3cf 1151 break;
1152
1153 case '\0':
1154 break;
1155
1156 default:
2fe7eff9 1157 mb->append("\\", 1);
1158 mb->append(str, 1);
5db6bf73 1159 ++str;
dc1af3cf 1160 break;
62e76326 1161 }
d860a1aa 1162 }
62e76326 1163
d860a1aa 1164 if (quoted)
2fe7eff9 1165 mb->append("\"", 1);
d860a1aa 1166}
fc68f6b1 1167
1168void
1169keepCapabilities(void)
1170{
b7ac5457 1171#if USE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
329ce686 1172
1173 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
b7ac5457 1174 Ip::Interceptor.StopTransparency("capability setting has failed.");
fc68f6b1 1175 }
fc68f6b1 1176#endif
1177}
329ce686 1178
1179static void
ff2afd7f 1180restoreCapabilities(bool keep)
329ce686 1181{
9e008dda 1182 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
b64b6030 1183#if USE_LIBCAP
c3487a77
HN
1184 cap_t caps;
1185 if (keep)
1186 caps = cap_get_proc();
1187 else
1188 caps = cap_init();
1189 if (!caps) {
b7ac5457 1190 Ip::Interceptor.StopTransparency("Can't get current capabilities");
9e008dda 1191 } else {
c3487a77
HN
1192 int ncaps = 0;
1193 int rc = 0;
1194 cap_value_t cap_list[10];
5db6bf73
FC
1195 cap_list[ncaps] = CAP_NET_BIND_SERVICE;
1196 ++ncaps;
4a751e2a 1197 if (Ip::Interceptor.TransparentActive() ||
9e27e206
SM
1198 Ip::Qos::TheConfig.isHitNfmarkActive() ||
1199 Ip::Qos::TheConfig.isAclNfmarkActive() ||
1200 Ip::Qos::TheConfig.isAclTosActive()) {
5db6bf73
FC
1201 cap_list[ncaps] = CAP_NET_ADMIN;
1202 ++ncaps;
fc32ce2e 1203 }
329ce686 1204
c3487a77
HN
1205 cap_clear_flag(caps, CAP_EFFECTIVE);
1206 rc |= cap_set_flag(caps, CAP_EFFECTIVE, ncaps, cap_list, CAP_SET);
1207 rc |= cap_set_flag(caps, CAP_PERMITTED, ncaps, cap_list, CAP_SET);
329ce686 1208
c3487a77 1209 if (rc || cap_set_proc(caps) != 0) {
b7ac5457 1210 Ip::Interceptor.StopTransparency("Error enabling needed capabilities.");
b5bd96ce 1211 }
c3487a77 1212 cap_free(caps);
329ce686 1213 }
8a09e810 1214#elif _SQUID_LINUX_
b7ac5457 1215 Ip::Interceptor.StopTransparency("Missing needed capability support.");
b5bd96ce 1216#endif /* HAVE_SYS_CAPABILITY_H */
329ce686 1217}
f53969cc 1218
dbf55289
CT
1219pid_t
1220WaitForOnePid(pid_t pid, PidStatus &status, int flags)
1221{
1222#if _SQUID_NEXT_
1223 if (pid < 0)
1224 return wait3(&status, flags, NULL);
1225 return wait4(cpid, &status, flags, NULL);
c92fcbad
AJ
1226#elif _SQUID_WINDOWS_
1227 return 0; // function not used on Windows
dbf55289
CT
1228#else
1229 return waitpid(pid, &status, flags);
1230#endif
1231}
5c634111 1232