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