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