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