]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tools.cc
Bug #1262: Duplicate content-length headers logged as conflicting with
[thirdparty/squid.git] / src / tools.cc
CommitLineData
94e891ea 1
30a4f2a8 2/*
e504b0a7 3 * $Id: tools.cc,v 1.251 2005/02/06 09:37:15 serassio Exp $
30a4f2a8 4 *
5 * DEBUG: section 21 Misc Functions
6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
019dd986 34 */
44a47c6e 35
36#include "squid.h"
c8f4eac4 37#include "SwapDir.h"
528b2c61 38#include "fde.h"
44a47c6e 39
090089c4 40#define DEAD_MSG "\
c5c666ab 41The Squid Cache (version %s) died.\n\
090089c4 42\n\
c5c666ab 43You've encountered a fatal error in the Squid Cache version %s.\n\
090089c4 44If a core file was created (possibly in the swap directory),\n\
b8de7ebe 45please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
784219b8 46and report the trace back to squid-bugs@squid-cache.org.\n\
090089c4 47\n\
48Thanks!\n"
49
f5b8bbc4 50static void fatal_common(const char *);
137ee196 51static void fatalvf(const char *fmt, va_list args);
f5b8bbc4 52static void mail_warranty(void);
63986a85 53#if MEM_GEN_TRACE
399e85ea 54extern void log_trace_done();
63986a85 55extern void log_trace_init(char *);
399e85ea 56#endif
24382924 57
941a3077 58#ifdef _SQUID_LINUX_
59/* Workaround for crappy glic header files */
e6ccf245 60SQUIDCEXTERN int backtrace(void *, int);
61SQUIDCEXTERN void backtrace_symbols_fd(void *, int, int);
62SQUIDCEXTERN int setresuid(uid_t, uid_t, uid_t);
941a3077 63#endif /* _SQUID_LINUX */
64
8fd63c35 65SQUIDCEXTERN void (*failure_notify) (const char *);
7e3ce7b9 66
b001e822 67MemAllocator *dlink_node_pool = NULL;
94439e4e 68
4a5a6c62 69void
429fdbec 70releaseServerSockets(void)
71{
812ed90c 72 int i;
429fdbec 73 /* Release the main ports as early as possible */
62e76326 74
812ed90c 75 for (i = 0; i < NHttpSockets; i++) {
62e76326 76 if (HttpSockets[i] >= 0)
77 close(HttpSockets[i]);
812ed90c 78 }
62e76326 79
429fdbec 80 if (theInIcpConnection >= 0)
62e76326 81 close(theInIcpConnection);
82
429fdbec 83 if (theOutIcpConnection >= 0 && theOutIcpConnection != theInIcpConnection)
62e76326 84 close(theOutIcpConnection);
429fdbec 85}
86
b8d8561b 87static char *
0673c0ba 88dead_msg(void)
090089c4 89{
95d659f0 90 LOCAL_ARRAY(char, msg, 1024);
56878878 91 snprintf(msg, 1024, DEAD_MSG, version_string, version_string);
090089c4 92 return msg;
93}
94
24382924 95static void
0673c0ba 96mail_warranty(void)
090089c4 97{
019dd986 98 FILE *fp = NULL;
6e40f263 99 static char command[256];
b99a6dec 100#if HAVE_MKSTEMP
62e76326 101
b99a6dec 102 char filename[] = "/tmp/squid-XXXXXX";
103 int tfd = mkstemp(filename);
62e76326 104
b99a6dec 105 if (tfd < 0)
62e76326 106 return;
107
b99a6dec 108 if ((fp = fdopen(tfd, "w")) == NULL)
62e76326 109 return;
110
b99a6dec 111#else
62e76326 112
b99a6dec 113 char *filename;
62e76326 114
6e40f263 115 if ((filename = tempnam(NULL, appname)) == NULL)
62e76326 116 return;
117
6e40f263 118 if ((fp = fopen(filename, "w")) == NULL)
62e76326 119 return;
120
b99a6dec 121#endif
62e76326 122
6e40f263 123 fprintf(fp, "From: %s\n", appname);
62e76326 124
edae7bc0 125 fprintf(fp, "To: %s\n", Config.adminEmail);
62e76326 126
6e40f263 127 fprintf(fp, "Subject: %s\n", dead_msg());
62e76326 128
6e40f263 129 fclose(fp);
62e76326 130
56878878 131 snprintf(command, 256, "mail %s < %s", Config.adminEmail, filename);
62e76326 132
6e40f263 133 system(command); /* XXX should avoid system(3) */
62e76326 134
6e40f263 135 unlink(filename);
090089c4 136}
137
4a5a6c62 138void
43c3424b 139dumpMallocStats(void)
3f43b19b 140{
88738790 141#if HAVE_MSTATS && HAVE_GNUMALLOC_H
62e76326 142
88738790 143 struct mstats ms = mstats();
144 fprintf(debug_log, "\ttotal space in arena: %6d KB\n",
62e76326 145 (int) (ms.bytes_total >> 10));
88738790 146 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
62e76326 147 (int) (ms.bytes_free >> 10),
148 percent(ms.bytes_free, ms.bytes_total));
eb824054 149#elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
62e76326 150
3f43b19b 151 struct mallinfo mp;
30a4f2a8 152 int t;
62e76326 153
3f43b19b 154 if (!do_mallinfo)
62e76326 155 return;
156
3f43b19b 157 mp = mallinfo();
62e76326 158
9e4ad609 159 fprintf(debug_log, "Memory usage for %s via mallinfo():\n", appname);
62e76326 160
e4049756 161 fprintf(debug_log, "\ttotal space in arena: %6ld KB\n",
162 (long)mp.arena >> 10);
62e76326 163
e4049756 164 fprintf(debug_log, "\tOrdinary blocks: %6ld KB %6ld blks\n",
165 (long)mp.uordblks >> 10, (long)mp.ordblks);
62e76326 166
e4049756 167 fprintf(debug_log, "\tSmall blocks: %6ld KB %6ld blks\n",
168 (long)mp.usmblks >> 10, (long)mp.smblks);
62e76326 169
e4049756 170 fprintf(debug_log, "\tHolding blocks: %6ld KB %6ld blks\n",
171 (long)mp.hblkhd >> 10, (long)mp.hblks);
62e76326 172
e4049756 173 fprintf(debug_log, "\tFree Small blocks: %6ld KB\n",
174 (long)mp.fsmblks >> 10);
62e76326 175
e4049756 176 fprintf(debug_log, "\tFree Ordinary blocks: %6ld KB\n",
177 (long)mp.fordblks >> 10);
62e76326 178
30a4f2a8 179 t = mp.uordblks + mp.usmblks + mp.hblkhd;
62e76326 180
9e4ad609 181 fprintf(debug_log, "\tTotal in use: %6d KB %d%%\n",
62e76326 182 t >> 10, percent(t, mp.arena));
183
30a4f2a8 184 t = mp.fsmblks + mp.fordblks;
62e76326 185
9e4ad609 186 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
62e76326 187 t >> 10, percent(t, mp.arena));
188
6a9f6389 189#if HAVE_STRUCT_MALLINFO_MXFAST
62e76326 190
9e4ad609 191 fprintf(debug_log, "\tmax size of small blocks:\t%d\n",
62e76326 192 mp.mxfast);
193
9e4ad609 194 fprintf(debug_log, "\tnumber of small blocks in a holding block:\t%d\n",
62e76326 195 mp.nlblks);
196
9e4ad609 197 fprintf(debug_log, "\tsmall block rounding factor:\t%d\n",
62e76326 198 mp.grain);
199
9e4ad609 200 fprintf(debug_log, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
62e76326 201 mp.uordbytes);
202
9e4ad609 203 fprintf(debug_log, "\tnumber of ordinary blocks allocated:\t%d\n",
62e76326 204 mp.allocated);
205
9e4ad609 206 fprintf(debug_log, "\tbytes used in maintaining the free tree:\t%d\n",
62e76326 207 mp.treeoverhead);
208
6a9f6389 209#endif /* HAVE_STRUCT_MALLINFO_MXFAST */
3f43b19b 210#endif /* HAVE_MALLINFO */
211}
30a4f2a8 212
f2908497 213void
62e76326 214
f2908497 215squid_getrusage(struct rusage *r)
f0f81709 216{
62e76326 217
8da94b66 218 memset(r, '\0', sizeof(struct rusage));
30a4f2a8 219#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
cd19f0b6 220#ifdef _SQUID_SOLARIS_
221 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
222 enter_suid();
223#endif
62e76326 224
f2908497 225 getrusage(RUSAGE_SELF, r);
cd19f0b6 226#ifdef _SQUID_SOLARIS_
62e76326 227
cd19f0b6 228 leave_suid();
229#endif
56983a01 230#endif
f2908497 231}
232
233double
62e76326 234
f2908497 235rusage_cputime(struct rusage *r)
236{
237 return (double) r->ru_stime.tv_sec +
62e76326 238 (double) r->ru_utime.tv_sec +
239 (double) r->ru_stime.tv_usec / 1000000.0 +
240 (double) r->ru_utime.tv_usec / 1000000.0;
f2908497 241}
242
ec603b25 243/* Hack for some HP-UX preprocessors */
244#ifndef HAVE_GETPAGESIZE
245#define HAVE_GETPAGESIZE 0
246#endif
247
f2908497 248int
62e76326 249
f2908497 250rusage_maxrss(struct rusage *r)
251{
4fdc3986 252#if defined(_SQUID_SGI_) && _ABIAPI
253 return r->ru_pad[0];
254#elif defined(_SQUID_SGI_)
62e76326 255
f2908497 256 return r->ru_maxrss;
257#elif defined(_SQUID_OSF_)
62e76326 258
a6e0ad1e 259 return r->ru_maxrss;
260#elif defined(_SQUID_AIX_)
261
f2908497 262 return r->ru_maxrss;
263#elif defined(BSD4_4)
62e76326 264
f2908497 265 return r->ru_maxrss;
6b8e7481 266#elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
62e76326 267
f2908497 268 return (r->ru_maxrss * getpagesize()) >> 10;
c7a1083d 269#elif defined(PAGESIZE)
62e76326 270
c7a1083d 271 return (r->ru_maxrss * PAGESIZE) >> 10;
8505e57b 272#else
62e76326 273
8505e57b 274 return r->ru_maxrss;
f2908497 275#endif
276}
277
278int
62e76326 279
f2908497 280rusage_pagefaults(struct rusage *r)
281{
4fdc3986 282#if defined(_SQUID_SGI_) && _ABIAPI
283 return r->ru_pad[5];
284#else
62e76326 285
f2908497 286 return r->ru_majflt;
4fdc3986 287#endif
f2908497 288}
289
290
4a5a6c62 291void
f2908497 292PrintRusage(void)
293{
62e76326 294
f2908497 295 struct rusage rusage;
296 squid_getrusage(&rusage);
2b906e48 297 fprintf(debug_log, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
62e76326 298 rusage_cputime(&rusage),
299 rusage.ru_utime.tv_sec + ((double) rusage.ru_utime.tv_usec / 1000000.0),
300 rusage.ru_stime.tv_sec + ((double) rusage.ru_stime.tv_usec / 1000000.0));
f2908497 301 fprintf(debug_log, "Maximum Resident Size: %d KB\n",
62e76326 302 rusage_maxrss(&rusage));
f2908497 303 fprintf(debug_log, "Page faults with physical i/o: %d\n",
62e76326 304 rusage_pagefaults(&rusage));
f0f81709 305}
306
03d7b07f 307
b8d8561b 308void
309death(int sig)
44a47c6e 310{
0e08ce4b 311 if (sig == SIGSEGV)
62e76326 312 fprintf(debug_log, "FATAL: Received Segment Violation...dying.\n");
0e08ce4b 313 else if (sig == SIGBUS)
62e76326 314 fprintf(debug_log, "FATAL: Received Bus Error...dying.\n");
0e08ce4b 315 else
62e76326 316 fprintf(debug_log, "FATAL: Received signal %d...dying.\n", sig);
0b4639af 317
318#ifdef PRINT_STACK_TRACE
319#ifdef _SQUID_HPUX_
320 {
62e76326 321 extern void U_STACK_TRACE(void); /* link with -lcl */
322 fflush(debug_log);
323 dup2(fileno(debug_log), 2);
324 U_STACK_TRACE();
0b4639af 325 }
62e76326 326
0b4639af 327#endif /* _SQUID_HPUX_ */
328#ifdef _SQUID_SOLARIS_
4f07153c 329 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
62e76326 330 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
331 fflush(debug_log);
332 dup2(fileno(debug_log), fileno(stdout));
333 opcom_stack_trace();
334 fflush(stdout);
0b4639af 335 }
62e76326 336
0b4639af 337#endif /* _SQUID_SOLARIS_ */
ce3d30fb 338#if HAVE_BACKTRACE_SYMBOLS_FD
339 {
62e76326 340 static void *(callarray[8192]);
341 int n;
342 n = backtrace(callarray, 8192);
343 backtrace_symbols_fd(callarray, n, fileno(debug_log));
ce3d30fb 344 }
62e76326 345
ce3d30fb 346#endif
0b4639af 347#endif /* PRINT_STACK_TRACE */
348
6e40f263 349#if SA_RESETHAND == 0
44a47c6e 350 signal(SIGSEGV, SIG_DFL);
62e76326 351
44a47c6e 352 signal(SIGBUS, SIG_DFL);
62e76326 353
0e08ce4b 354 signal(sig, SIG_DFL);
62e76326 355
30a4f2a8 356#endif
62e76326 357
429fdbec 358 releaseServerSockets();
62e76326 359
e3ef2b09 360 storeDirWriteCleanLogs(0);
62e76326 361
9e4ad609 362 PrintRusage();
62e76326 363
9e4ad609 364 dumpMallocStats();
62e76326 365
6e40f263 366 if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
62e76326 367 /* skip if more than 10 days old */
368
369 if (Config.adminEmail)
370 mail_warranty();
371 else
372 puts(dead_msg());
6e40f263 373 }
62e76326 374
44a47c6e 375 abort();
376}
377
378
b8d8561b 379void
23d92c64 380sigusr2_handle(int sig)
090089c4 381{
a50bfe93 382#if defined(_SQUID_MSWIN_) && defined(_DEBUG)
383 do_debug = 1;
384#endif
385#if (defined(_SQUID_MSWIN_) && !defined(_DEBUG)) || !defined(_SQUID_MSWIN_)
386
30a4f2a8 387 static int state = 0;
545f551a 388 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
62e76326 389
30a4f2a8 390 if (state == 0) {
2bf05976 391#ifndef MEM_GEN_TRACE
3dc275d6 392 Debug::parseOptions("ALL,10");
2bf05976 393#else
62e76326 394
395 log_trace_done();
63986a85 396#endif
62e76326 397
398 state = 1;
30a4f2a8 399 } else {
2bf05976 400#ifndef MEM_GEN_TRACE
3dc275d6 401 Debug::parseOptions(Config.debugOptions);
2bf05976 402#else
62e76326 403
404 log_trace_init("/tmp/squid.alloc");
63986a85 405#endif
62e76326 406
407 state = 0;
30a4f2a8 408 }
62e76326 409
a50bfe93 410#endif
30a4f2a8 411#if !HAVE_SIGACTION
e504b0a7 412 if (signal(sig, sigusr2_handle) == SIG_ERR) /* reinstall */
413 debug(50, 0) ("signal: sig=%d func=%p: %s\n", sig, sigusr2_handle, xstrerror());
62e76326 414
090089c4 415#endif
416}
417
24382924 418static void
0ee4272b 419fatal_common(const char *message)
090089c4 420{
db40ae20 421#if HAVE_SYSLOG
6b8e7481 422 syslog(LOG_ALERT, "%s", message);
db40ae20 423#endif
62e76326 424
9bc73deb 425 fprintf(debug_log, "FATAL: %s\n", message);
62e76326 426
9bc73deb 427 if (opt_debug_stderr > 0 && debug_log != stderr)
62e76326 428 fprintf(stderr, "FATAL: %s\n", message);
429
c5c666ab 430 fprintf(debug_log, "Squid Cache (Version %s): Terminated abnormally.\n",
62e76326 431 version_string);
432
2c47cf74 433 fflush(debug_log);
62e76326 434
9e4ad609 435 PrintRusage();
62e76326 436
9e4ad609 437 dumpMallocStats();
090089c4 438}
439
440/* fatal */
b8d8561b 441void
0ee4272b 442fatal(const char *message)
090089c4 443{
429fdbec 444 releaseServerSockets();
b2c141d4 445 /* check for store_dirs_rebuilding because fatal() is often
d399be0e 446 * used in early initialization phases, long before we ever
447 * get to the store log. */
62e76326 448
b2c141d4 449 if (0 == store_dirs_rebuilding)
62e76326 450 storeDirWriteCleanLogs(0);
451
090089c4 452 fatal_common(message);
62e76326 453
edd3d24f 454 if (shutting_down)
62e76326 455 exit(0);
edd3d24f 456 else
62e76326 457 abort();
090089c4 458}
459
137ee196 460/* printf-style interface for fatal */
6de2df60 461#if STDC_HEADERS
137ee196 462void
463fatalf(const char *fmt,...)
464{
465 va_list args;
466 va_start(args, fmt);
467#else
468void
469fatalf(va_alist)
62e76326 470va_dcl
137ee196 471{
472 va_list args;
473 const char *fmt = NULL;
474 va_start(args);
475 fmt = va_arg(args, char *);
476#endif
62e76326 477
137ee196 478 fatalvf(fmt, args);
479 va_end(args);
480}
481
482
483/* used by fatalf */
484static void
62e76326 485fatalvf(const char *fmt, va_list args) {
137ee196 486 static char fatal_str[BUFSIZ];
487 vsnprintf(fatal_str, sizeof(fatal_str), fmt, args);
488 fatal(fatal_str);
489}
490
090089c4 491/* fatal with dumping core */
b8d8561b 492void
62e76326 493fatal_dump(const char *message) {
7e3ce7b9 494 failure_notify = NULL;
429fdbec 495 releaseServerSockets();
62e76326 496
090089c4 497 if (message)
62e76326 498 fatal_common(message);
499
4a69c163 500 if (opt_catch_signals)
62e76326 501 storeDirWriteCleanLogs(0);
502
090089c4 503 abort();
504}
505
b8d8561b 506void
62e76326 507debug_trap(const char *message) {
4a69c163 508 if (!opt_catch_signals)
62e76326 509 fatal_dump(message);
510
a3d5953d 511 _db_print("WARNING: %s\n", message);
85b701ed 512}
513
b8d8561b 514void
62e76326 515sig_child(int sig) {
a50bfe93 516#ifndef _SQUID_MSWIN_
30a4f2a8 517#ifdef _SQUID_NEXT_
518 union wait status;
519#else
62e76326 520
090089c4 521 int status;
090089c4 522#endif
62e76326 523
ff8d0ea6 524 pid_t pid;
090089c4 525
30a4f2a8 526 do {
527#ifdef _SQUID_NEXT_
62e76326 528 pid = wait3(&status, WNOHANG, NULL);
090089c4 529#else
62e76326 530
531 pid = waitpid(-1, &status, WNOHANG);
090089c4 532#endif
62e76326 533 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
30a4f2a8 534#if HAVE_SIGACTION
62e76326 535
30a4f2a8 536 } while (pid > 0);
62e76326 537
234967c9 538#else
62e76326 539
540 }
541
542 while (pid > 0 || (pid < 0 && errno == EINTR))
543
544 ;
30a4f2a8 545 signal(sig, sig_child);
62e76326 546
a50bfe93 547#endif
234967c9 548#endif
30a4f2a8 549}
44a47c6e 550
0ee4272b 551const char *
0673c0ba 552getMyHostname(void)
44a47c6e 553{
95d659f0 554 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
44a47c6e 555 static int present = 0;
62e76326 556
0ee4272b 557 const struct hostent *h = NULL;
62e76326 558
aa2b5399 559 struct in_addr sa;
62e76326 560
af85f811 561 if (Config.visibleHostname != NULL)
62e76326 562 return Config.visibleHostname;
563
d20b1cd0 564 if (present)
62e76326 565 return host;
566
d20b1cd0 567 host[0] = '\0';
62e76326 568
aa2b5399 569 memcpy(&sa, &any_addr, sizeof(sa));
62e76326 570
aa2b5399 571 if (Config.Sockaddr.http && sa.s_addr == any_addr.s_addr)
62e76326 572 memcpy(&sa, &Config.Sockaddr.http->s.sin_addr, sizeof(sa));
573
aa2b5399 574#if USE_SSL
62e76326 575
aa2b5399 576 if (Config.Sockaddr.https && sa.s_addr == any_addr.s_addr)
62e76326 577 memcpy(&sa, &Config.Sockaddr.https->http.s.sin_addr, sizeof(sa));
578
aa2b5399 579#endif
580 /*
581 * If the first http_port address has a specific address, try a
582 * reverse DNS lookup on it.
583 */
584 if (sa.s_addr != any_addr.s_addr) {
62e76326 585 h = gethostbyaddr((char *) &sa,
586 sizeof(sa), AF_INET);
587
588 if (h != NULL) {
589 /* DNS lookup successful */
590 /* use the official name from DNS lookup */
591 xstrncpy(host, h->h_name, SQUIDHOSTNAMELEN);
592 debug(50, 4) ("getMyHostname: resolved %s to '%s'\n",
593 inet_ntoa(sa),
594 host);
595 present = 1;
596
597 if (strchr(host, '.'))
598 return host;
599
600 }
601
602 debug(50, 1) ("WARNING: failed to resolve %s to a fully qualified hostname\n",
603 inet_ntoa(sa));
d20b1cd0 604 }
62e76326 605
d20b1cd0 606 /*
607 * Get the host name and store it in host to return
608 */
609 if (gethostname(host, SQUIDHOSTNAMELEN) < 0) {
62e76326 610 debug(50, 1) ("WARNING: gethostname failed: %s\n", xstrerror());
d20b1cd0 611 } else if ((h = gethostbyname(host)) == NULL) {
62e76326 612 debug(50, 1) ("WARNING: gethostbyname failed for %s\n", host);
7e3ce7b9 613 } else {
62e76326 614 debug(50, 6) ("getMyHostname: '%s' resolved into '%s'\n",
615 host, h->h_name);
616 /* DNS lookup successful */
617 /* use the official name from DNS lookup */
618 xstrncpy(host, h->h_name, SQUIDHOSTNAMELEN);
619 present = 1;
620
621 if (strchr(host, '.'))
622 return host;
44a47c6e 623 }
62e76326 624
d20b1cd0 625 fatal("Could not determine fully qualified hostname. Please set 'visible_hostname'\n");
626 return NULL; /* keep compiler happy */
44a47c6e 627}
628
98829f69 629const char *
630uniqueHostname(void)
631{
632 return Config.uniqueHostname ? Config.uniqueHostname : getMyHostname();
633}
634
30a4f2a8 635/* leave a privilegied section. (Give up any privilegies)
636 * Routines that need privilegies can rap themselves in enter_suid()
637 * and leave_suid()
638 * To give upp all posibilites to gain privilegies use no_suid()
12b9e9b1 639 */
b8d8561b 640void
0673c0ba 641leave_suid(void)
12b9e9b1 642{
be20dac7 643 debug(21, 3) ("leave_suid: PID %d called\n", (int) getpid());
62e76326 644
e3d74828 645 if (Config.effectiveGroup) {
646
647#if HAVE_SETGROUPS
648
649 setgroups(1, &Config2.effectiveGroupID);
650
651#endif
652
653 if (setgid(Config2.effectiveGroupID) < 0)
654 debug(50, 0) ("ALERT: setgid: %s\n", xstrerror());
655
656 }
657
12b9e9b1 658 if (geteuid() != 0)
62e76326 659 return;
660
12b9e9b1 661 /* Started as a root, check suid option */
b6f794d6 662 if (Config.effectiveUser == NULL)
62e76326 663 return;
664
e3d74828 665 debug(21, 3) ("leave_suid: PID %d giving up root, becoming '%s'\n",
666 (int) getpid(), Config.effectiveUser);
62e76326 667
e3d74828 668 if (!Config.effectiveGroup) {
62e76326 669
e3d74828 670 if (setgid(Config2.effectiveGroupID) < 0)
671 debug(50, 0) ("ALERT: setgid: %s\n", xstrerror());
62e76326 672
e3d74828 673 if (initgroups(Config.effectiveUser, Config2.effectiveGroupID) < 0) {
674 debug(50, 0) ("ALERT: initgroups: unable to set groups for User %s "
675 "and Group %u", Config.effectiveUser,
676 (unsigned) Config2.effectiveGroupID);
677 }
678 }
62e76326 679
234967c9 680#if HAVE_SETRESUID
62e76326 681
d20b1cd0 682 if (setresuid(Config2.effectiveUserID, Config2.effectiveUserID, 0) < 0)
62e76326 683 debug(50, 0) ("ALERT: setresuid: %s\n", xstrerror());
684
234967c9 685#elif HAVE_SETEUID
62e76326 686
d20b1cd0 687 if (seteuid(Config2.effectiveUserID) < 0)
62e76326 688 debug(50, 0) ("ALERT: seteuid: %s\n", xstrerror());
689
234967c9 690#else
62e76326 691
d20b1cd0 692 if (setuid(Config2.effectiveUserID) < 0)
62e76326 693 debug(50, 0) ("ALERT: setuid: %s\n", xstrerror());
694
234967c9 695#endif
696}
697
30a4f2a8 698/* Enter a privilegied section */
b8d8561b 699void
0673c0ba 700enter_suid(void)
234967c9 701{
be20dac7 702 debug(21, 3) ("enter_suid: PID %d taking root priveleges\n", (int) getpid());
234967c9 703#if HAVE_SETRESUID
62e76326 704
e6ccf245 705 setresuid((uid_t)-1, 0, (uid_t)-1);
234967c9 706#else
62e76326 707
234967c9 708 setuid(0);
709#endif
710}
711
30a4f2a8 712/* Give up the posibility to gain privilegies.
713 * this should be used before starting a sub process
714 */
b8d8561b 715void
0673c0ba 716no_suid(void)
234967c9 717{
718 uid_t uid;
30a4f2a8 719 leave_suid();
234967c9 720 uid = geteuid();
be20dac7 721 debug(21, 3) ("leave_suid: PID %d giving up root priveleges forever\n", (int) getpid());
234967c9 722#if HAVE_SETRESUID
62e76326 723
429fdbec 724 if (setresuid(uid, uid, uid) < 0)
62e76326 725 debug(50, 1) ("no_suid: setresuid: %s\n", xstrerror());
726
234967c9 727#else
62e76326 728
234967c9 729 setuid(0);
62e76326 730
429fdbec 731 if (setuid(uid) < 0)
62e76326 732 debug(50, 1) ("no_suid: setuid: %s\n", xstrerror());
733
234967c9 734#endif
12b9e9b1 735}
ccff9601 736
b8d8561b 737void
0673c0ba 738writePidFile(void)
ccff9601 739{
9e4ad609 740 int fd;
0b4639af 741 const char *f = NULL;
973e9fe1 742 mode_t old_umask;
9e4ad609 743 char buf[32];
62e76326 744
9e4ad609 745 if ((f = Config.pidFilename) == NULL)
62e76326 746 return;
747
9e4ad609 748 if (!strcmp(Config.pidFilename, "none"))
62e76326 749 return;
750
30a4f2a8 751 enter_suid();
62e76326 752
973e9fe1 753 old_umask = umask(022);
62e76326 754
c4aefe96 755 fd = file_open(f, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT);
62e76326 756
973e9fe1 757 umask(old_umask);
62e76326 758
30a4f2a8 759 leave_suid();
62e76326 760
9e4ad609 761 if (fd < 0) {
62e76326 762 debug(50, 0) ("%s: %s\n", f, xstrerror());
763 debug_trap("Could not write pid file");
764 return;
ccff9601 765 }
62e76326 766
56878878 767 snprintf(buf, 32, "%d\n", (int) getpid());
1f7c9178 768 FD_WRITE_METHOD(fd, buf, strlen(buf));
9e4ad609 769 file_close(fd);
ccff9601 770}
c4fb974e 771
772
ff8d0ea6 773pid_t
0673c0ba 774readPidFile(void)
7690e8eb 775{
776 FILE *pid_fp = NULL;
9e4ad609 777 const char *f = Config.pidFilename;
ff8d0ea6 778 pid_t pid = -1;
779 int i;
7690e8eb 780
9e4ad609 781 if (f == NULL || !strcmp(Config.pidFilename, "none")) {
62e76326 782 fprintf(stderr, "%s: ERROR: No pid file name defined\n", appname);
783 exit(1);
7690e8eb 784 }
62e76326 785
7690e8eb 786 pid_fp = fopen(f, "r");
62e76326 787
7690e8eb 788 if (pid_fp != NULL) {
62e76326 789 pid = 0;
790
791 if (fscanf(pid_fp, "%d", &i) == 1)
792 pid = (pid_t) i;
793
794 fclose(pid_fp);
7690e8eb 795 } else {
62e76326 796 if (errno != ENOENT) {
797 fprintf(stderr, "%s: ERROR: Could not read pid file\n", appname);
798 fprintf(stderr, "\t%s: %s\n", f, xstrerror());
799 exit(1);
800 }
7690e8eb 801 }
62e76326 802
7690e8eb 803 return pid;
804}
805
806
b8d8561b 807void
0673c0ba 808setMaxFD(void)
c4fb974e 809{
234967c9 810#if HAVE_SETRLIMIT
c4fb974e 811 /* try to use as many file descriptors as possible */
812 /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
62e76326 813
c4fb974e 814 struct rlimit rl;
815#if defined(RLIMIT_NOFILE)
62e76326 816
c4fb974e 817 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
62e76326 818 debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %s\n", xstrerror());
c4fb974e 819 } else {
62e76326 820 rl.rlim_cur = Squid_MaxFD;
821
822 if (rl.rlim_cur > rl.rlim_max)
823 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
824
825 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
826 snprintf(tmp_error_buf, ERROR_BUF_SZ,
827 "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
828 fatal_dump(tmp_error_buf);
829 }
c4fb974e 830 }
62e76326 831
c4fb974e 832#elif defined(RLIMIT_OFILE)
833 if (getrlimit(RLIMIT_OFILE, &rl) < 0) {
62e76326 834 debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %s\n", xstrerror());
c4fb974e 835 } else {
62e76326 836 rl.rlim_cur = Squid_MaxFD;
837
838 if (rl.rlim_cur > rl.rlim_max)
839 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
840
841 if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
842 snprintf(tmp_error_buf, ERROR_BUF_SZ,
843 "setrlimit: RLIMIT_OFILE: %s", xstrerror());
844 fatal_dump(tmp_error_buf);
845 }
c4fb974e 846 }
62e76326 847
c4fb974e 848#endif
c4fb974e 849#else /* HAVE_SETRLIMIT */
a3d5953d 850 debug(21, 1) ("setMaxFD: Cannot increase: setrlimit() not supported on this system\n");
62e76326 851
30a4f2a8 852#endif /* HAVE_SETRLIMIT */
853
854#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
62e76326 855
30a4f2a8 856 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
62e76326 857 debug(50, 0) ("getrlimit: RLIMIT_DATA: %s\n", xstrerror());
88738790 858 } else if (rl.rlim_max > rl.rlim_cur) {
62e76326 859 rl.rlim_cur = rl.rlim_max; /* set it to the max */
860
861 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
862 snprintf(tmp_error_buf, ERROR_BUF_SZ,
863 "setrlimit: RLIMIT_DATA: %s", xstrerror());
864 fatal_dump(tmp_error_buf);
865 }
30a4f2a8 866 }
62e76326 867
30a4f2a8 868#endif /* RLIMIT_DATA */
ad7ef91a 869#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
870 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
62e76326 871 debug(50, 0) ("getrlimit: RLIMIT_VMEM: %s\n", xstrerror());
88738790 872 } else if (rl.rlim_max > rl.rlim_cur) {
62e76326 873 rl.rlim_cur = rl.rlim_max; /* set it to the max */
874
875 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
876 snprintf(tmp_error_buf, ERROR_BUF_SZ,
877 "setrlimit: RLIMIT_VMEM: %s", xstrerror());
878 fatal_dump(tmp_error_buf);
879 }
ad7ef91a 880 }
62e76326 881
ad7ef91a 882#endif /* RLIMIT_VMEM */
c4fb974e 883}
3a57089e 884
b8d8561b 885time_t
0673c0ba 886getCurrentTime(void)
3a57089e 887{
94e891ea 888#if GETTIMEOFDAY_NO_TZP
30a4f2a8 889 gettimeofday(&current_time);
890#else
62e76326 891
d598947a 892 gettimeofday(&current_time, NULL);
5f3f8d0e 893#endif
62e76326 894
52040193 895 current_dtime = (double) current_time.tv_sec +
62e76326 896 (double) current_time.tv_usec / 1000000.0;
30a4f2a8 897 return squid_curtime = current_time.tv_sec;
5f3f8d0e 898}
fe113054 899
b8d8561b 900int
901percent(int a, int b)
30a4f2a8 902{
903 return b ? ((int) (100.0 * a / b + 0.5)) : 0;
904}
905
a7c05555 906double
f2908497 907dpercent(double a, double b)
908{
909 return b ? (100.0 * a / b) : 0.0;
910}
911
b8d8561b 912void
ea3a2a69 913squid_signal(int sig, SIGHDLR * func, int flags)
30a4f2a8 914{
915#if HAVE_SIGACTION
62e76326 916
30a4f2a8 917 struct sigaction sa;
918 sa.sa_handler = func;
919 sa.sa_flags = flags;
920 sigemptyset(&sa.sa_mask);
62e76326 921
30a4f2a8 922 if (sigaction(sig, &sa, NULL) < 0)
62e76326 923 debug(50, 0) ("sigaction: sig=%d func=%p: %s\n", sig, func, xstrerror());
924
30a4f2a8 925#else
62e76326 926
4ece5eb6 927 if (signal(sig, func) == SIG_ERR)
928 debug(50, 0) ("signal: sig=%d func=%p: %s\n", sig, func, xstrerror());
62e76326 929
30a4f2a8 930#endif
931}
396c5745 932
16b204c4 933struct in_addr
62e76326 934
935 inaddrFromHostent(const struct hostent *hp)
16b204c4 936{
62e76326 937
cc6a9d2e 938 struct in_addr s;
3c0117c9 939 xmemcpy(&s.s_addr, hp->h_addr, sizeof(s.s_addr));
cc6a9d2e 940 return s;
16b204c4 941}
88738790 942
9e4ad609 943double
e6ccf245 944doubleAverage(double cur, double newD, int N, int max)
9e4ad609 945{
1d8e0d40 946 if (N > max)
62e76326 947 N = max;
948
e6ccf245 949 return (cur * (N - 1.0) + newD) / N;
9e4ad609 950}
951
952int
e6ccf245 953intAverage(int cur, int newI, int n, int max)
9e4ad609 954{
955 if (n > max)
62e76326 956 n = max;
957
e6ccf245 958 return (cur * (n - 1) + newI) / n;
9e4ad609 959}
70364f29 960
961void
962logsFlush(void)
963{
964 if (debug_log)
62e76326 965 fflush(debug_log);
70364f29 966}
88738790 967
94439e4e 968dlink_node *
969dlinkNodeNew()
970{
971 if (dlink_node_pool == NULL)
b001e822 972 dlink_node_pool = MemPools::GetInstance().create("Dlink list nodes", sizeof(dlink_node));
62e76326 973
b001e822 974 /* where should we call delete dlink_node_pool;dlink_node_pool = NULL; */
975 return (dlink_node *)dlink_node_pool->alloc();
94439e4e 976}
977
978/* the node needs to be unlinked FIRST */
979void
980dlinkNodeDelete(dlink_node * m)
981{
982 if (m == NULL)
62e76326 983 return;
984
b001e822 985 dlink_node_pool->free(m);
94439e4e 986}
987
2ac237e2 988void
989dlinkAdd(void *data, dlink_node * m, dlink_list * list)
990{
991 m->data = data;
992 m->prev = NULL;
993 m->next = list->head;
62e76326 994
2ac237e2 995 if (list->head)
62e76326 996 list->head->prev = m;
997
2ac237e2 998 list->head = m;
62e76326 999
2ac237e2 1000 if (list->tail == NULL)
62e76326 1001 list->tail = m;
2ac237e2 1002}
1003
edce4d98 1004void
1005dlinkAddAfter(void *data, dlink_node * m, dlink_node * n, dlink_list * list)
1006{
1007 m->data = data;
1008 m->prev = n;
1009 m->next = n->next;
62e76326 1010
edce4d98 1011 if (n->next)
62e76326 1012 n->next->prev = m;
edce4d98 1013 else {
62e76326 1014 assert(list->tail == n);
1015 list->tail = m;
edce4d98 1016 }
62e76326 1017
edce4d98 1018 n->next = m;
1019}
1020
b2329b6a 1021void
1022dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
1023{
1024 m->data = data;
1025 m->next = NULL;
1026 m->prev = list->tail;
62e76326 1027
b2329b6a 1028 if (list->tail)
62e76326 1029 list->tail->next = m;
1030
b2329b6a 1031 list->tail = m;
62e76326 1032
b2329b6a 1033 if (list->head == NULL)
62e76326 1034 list->head = m;
b2329b6a 1035}
1036
2ac237e2 1037void
1038dlinkDelete(dlink_node * m, dlink_list * list)
1039{
1040 if (m->next)
62e76326 1041 m->next->prev = m->prev;
1042
2ac237e2 1043 if (m->prev)
62e76326 1044 m->prev->next = m->next;
1045
2ac237e2 1046 if (m == list->head)
62e76326 1047 list->head = m->next;
1048
2ac237e2 1049 if (m == list->tail)
62e76326 1050 list->tail = m->prev;
1051
92b8c095 1052 m->next = m->prev = NULL;
2ac237e2 1053}
a7c05555 1054
16300b58 1055void
0e473d70 1056kb_incr(kb_t * k, size_t v)
a7c05555 1057{
0e473d70 1058 k->bytes += v;
1059 k->kb += (k->bytes >> 10);
1060 k->bytes &= 0x3FF;
a7c05555 1061}
c1dabf04 1062
a00a7c85 1063void
6bbf9cc4 1064debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
a00a7c85 1065{
1066 MemBuf mb;
1067 Packer p;
6bbf9cc4 1068 assert(label && obj && pm);
a00a7c85 1069 memBufDefInit(&mb);
1070 packerToMemInit(&p, &mb);
0cdcddb9 1071 (*pm) (obj, &p);
6bbf9cc4 1072 debug(section, level) ("%s%s", label, mb.buf);
a00a7c85 1073 packerClean(&p);
1074 memBufClean(&mb);
1075}
d548ee64 1076
0e70aa1e 1077void
1078parseEtcHosts(void)
1079{
1080 FILE *fp;
1081 char buf[1024];
1082 char buf2[512];
1083 char *nt = buf;
1084 char *lt = buf;
fa2bfbab 1085
0e70aa1e 1086 if (NULL == Config.etcHostsPath)
62e76326 1087 return;
1088
0e70aa1e 1089 if (0 == strcmp(Config.etcHostsPath, "none"))
62e76326 1090 return;
1091
0e70aa1e 1092 fp = fopen(Config.etcHostsPath, "r");
62e76326 1093
0e70aa1e 1094 if (fp == NULL) {
62e76326 1095 debug(1, 1) ("parseEtcHosts: %s: %s\n",
1096 Config.etcHostsPath, xstrerror());
1097 return;
0e70aa1e 1098 }
62e76326 1099
ec4daaa5 1100#ifdef _SQUID_WIN32_
c4aefe96 1101 setmode(fileno(fp), O_TEXT);
62e76326 1102
c4aefe96 1103#endif
62e76326 1104
0e70aa1e 1105 while (fgets(buf, 1024, fp)) { /* for each line */
62e76326 1106 wordlist *hosts = NULL;
1107 char *addr;
1108
c31616ae 1109 if (buf[0] == '#') /* MS-windows likes to add comments */
1110 continue;
1111
7a10c315 1112 strtok(buf, "#"); /* chop everything following a comment marker */
62e76326 1113
1114 lt = buf;
1115
1116 addr = buf;
1117
1118 debug(1, 5) ("etc_hosts: line is '%s'\n", buf);
1119
1120 nt = strpbrk(lt, w_space);
1121
1122 if (nt == NULL) /* empty line */
1123 continue;
1124
1125 *nt = '\0'; /* null-terminate the address */
1126
1127 debug(1, 5) ("etc_hosts: address is '%s'\n", addr);
1128
1129 lt = nt + 1;
1130
1131 while ((nt = strpbrk(lt, w_space))) {
1132 char *host = NULL;
1133
1134 if (nt == lt) { /* multiple spaces */
1135 debug(1, 5) ("etc_hosts: multiple spaces, skipping\n");
1136 lt = nt + 1;
1137 continue;
1138 }
1139
1140 *nt = '\0';
1141 debug(1, 5) ("etc_hosts: got hostname '%s'\n", lt);
1142
1143 if (Config.appendDomain && !strchr(lt, '.')) {
1144 /* I know it's ugly, but it's only at reconfig */
1145 strncpy(buf2, lt, 512);
1146 strncat(buf2, Config.appendDomain, 512 - strlen(lt));
1147 host = buf2;
1148 } else {
1149 host = lt;
1150 }
1151
1152 if (ipcacheAddEntryFromHosts(host, addr) != 0)
1153 goto skip; /* invalid address, continuing is useless */
1154
1155 wordlistAdd(&hosts, host);
1156
1157 lt = nt + 1;
1158 }
1159
1160 fqdncacheAddEntryFromHosts(addr, hosts);
1161
1162skip:
1163 wordlistDestroy(&hosts);
0e70aa1e 1164 }
62e76326 1165
1f3c7397 1166 fclose (fp);
0e70aa1e 1167}
52f772de 1168
1169int
1170getMyPort(void)
1171{
52f772de 1172 if (Config.Sockaddr.http)
62e76326 1173 return ntohs(Config.Sockaddr.http->s.sin_port);
1174
a2727cdb 1175#if USE_SSL
62e76326 1176
a2727cdb 1177 if (Config.Sockaddr.https)
62e76326 1178 return ntohs(Config.Sockaddr.https->http.s.sin_port);
1179
52f772de 1180#endif
62e76326 1181
a2727cdb 1182 fatal("No port defined");
62e76326 1183
bac6d4bd 1184 return 0; /* NOT REACHED */
52f772de 1185}
d860a1aa 1186
d860a1aa 1187
1188/*
1189 * Inverse of strwordtok. Quotes a word if needed
1190 */
42419a95 1191void
d860a1aa 1192strwordquote(MemBuf * mb, const char *str)
1193{
1194 int quoted = 0;
62e76326 1195
d860a1aa 1196 if (strchr(str, ' ')) {
62e76326 1197 quoted = 1;
1198 memBufAppend(mb, "\"", 1);
d860a1aa 1199 }
62e76326 1200
d860a1aa 1201 while (*str) {
dc1af3cf 1202 int l = strcspn(str, "\"\\\n\r");
62e76326 1203 memBufAppend(mb, str, l);
1204 str += l;
1205
dc1af3cf 1206 switch(*str) {
1207
1208 case '\n':
1209 memBufAppend(mb, "\\n", 2);
1210 str++;
1211 break;
1212
1213 case '\r':
1214 memBufAppend(mb, "\\r", 2);
1215 str++;
1216 break;
1217
1218 case '\0':
1219 break;
1220
1221 default:
62e76326 1222 memBufAppend(mb, "\\", 1);
1223 memBufAppend(mb, str, 1);
1224 str++;
dc1af3cf 1225 break;
62e76326 1226 }
d860a1aa 1227 }
62e76326 1228
d860a1aa 1229 if (quoted)
62e76326 1230 memBufAppend(mb, "\"", 1);
d860a1aa 1231}