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