]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tools.cc
Bugfix a cut & paste typo
[thirdparty/squid.git] / src / tools.cc
CommitLineData
94e891ea 1
30a4f2a8 2/*
f55d98b9 3 * $Id: tools.cc,v 1.250 2005/02/06 09:30:38 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
4ece5eb6 412 if (signal(sig, sigusr2_handle) == SIG_ERR)
413
414 ; /* reinstall */
f55d98b9 415 debug(50, 0) ("signal: sig=%d func=%p: %s\n", sig, sigusr2_handle, xstrerror());
62e76326 416
090089c4 417#endif
418}
419
24382924 420static void
0ee4272b 421fatal_common(const char *message)
090089c4 422{
db40ae20 423#if HAVE_SYSLOG
6b8e7481 424 syslog(LOG_ALERT, "%s", message);
db40ae20 425#endif
62e76326 426
9bc73deb 427 fprintf(debug_log, "FATAL: %s\n", message);
62e76326 428
9bc73deb 429 if (opt_debug_stderr > 0 && debug_log != stderr)
62e76326 430 fprintf(stderr, "FATAL: %s\n", message);
431
c5c666ab 432 fprintf(debug_log, "Squid Cache (Version %s): Terminated abnormally.\n",
62e76326 433 version_string);
434
2c47cf74 435 fflush(debug_log);
62e76326 436
9e4ad609 437 PrintRusage();
62e76326 438
9e4ad609 439 dumpMallocStats();
090089c4 440}
441
442/* fatal */
b8d8561b 443void
0ee4272b 444fatal(const char *message)
090089c4 445{
429fdbec 446 releaseServerSockets();
b2c141d4 447 /* check for store_dirs_rebuilding because fatal() is often
d399be0e 448 * used in early initialization phases, long before we ever
449 * get to the store log. */
62e76326 450
b2c141d4 451 if (0 == store_dirs_rebuilding)
62e76326 452 storeDirWriteCleanLogs(0);
453
090089c4 454 fatal_common(message);
62e76326 455
edd3d24f 456 if (shutting_down)
62e76326 457 exit(0);
edd3d24f 458 else
62e76326 459 abort();
090089c4 460}
461
137ee196 462/* printf-style interface for fatal */
6de2df60 463#if STDC_HEADERS
137ee196 464void
465fatalf(const char *fmt,...)
466{
467 va_list args;
468 va_start(args, fmt);
469#else
470void
471fatalf(va_alist)
62e76326 472va_dcl
137ee196 473{
474 va_list args;
475 const char *fmt = NULL;
476 va_start(args);
477 fmt = va_arg(args, char *);
478#endif
62e76326 479
137ee196 480 fatalvf(fmt, args);
481 va_end(args);
482}
483
484
485/* used by fatalf */
486static void
62e76326 487fatalvf(const char *fmt, va_list args) {
137ee196 488 static char fatal_str[BUFSIZ];
489 vsnprintf(fatal_str, sizeof(fatal_str), fmt, args);
490 fatal(fatal_str);
491}
492
090089c4 493/* fatal with dumping core */
b8d8561b 494void
62e76326 495fatal_dump(const char *message) {
7e3ce7b9 496 failure_notify = NULL;
429fdbec 497 releaseServerSockets();
62e76326 498
090089c4 499 if (message)
62e76326 500 fatal_common(message);
501
4a69c163 502 if (opt_catch_signals)
62e76326 503 storeDirWriteCleanLogs(0);
504
090089c4 505 abort();
506}
507
b8d8561b 508void
62e76326 509debug_trap(const char *message) {
4a69c163 510 if (!opt_catch_signals)
62e76326 511 fatal_dump(message);
512
a3d5953d 513 _db_print("WARNING: %s\n", message);
85b701ed 514}
515
b8d8561b 516void
62e76326 517sig_child(int sig) {
a50bfe93 518#ifndef _SQUID_MSWIN_
30a4f2a8 519#ifdef _SQUID_NEXT_
520 union wait status;
521#else
62e76326 522
090089c4 523 int status;
090089c4 524#endif
62e76326 525
ff8d0ea6 526 pid_t pid;
090089c4 527
30a4f2a8 528 do {
529#ifdef _SQUID_NEXT_
62e76326 530 pid = wait3(&status, WNOHANG, NULL);
090089c4 531#else
62e76326 532
533 pid = waitpid(-1, &status, WNOHANG);
090089c4 534#endif
62e76326 535 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
30a4f2a8 536#if HAVE_SIGACTION
62e76326 537
30a4f2a8 538 } while (pid > 0);
62e76326 539
234967c9 540#else
62e76326 541
542 }
543
544 while (pid > 0 || (pid < 0 && errno == EINTR))
545
546 ;
30a4f2a8 547 signal(sig, sig_child);
62e76326 548
a50bfe93 549#endif
234967c9 550#endif
30a4f2a8 551}
44a47c6e 552
0ee4272b 553const char *
0673c0ba 554getMyHostname(void)
44a47c6e 555{
95d659f0 556 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
44a47c6e 557 static int present = 0;
62e76326 558
0ee4272b 559 const struct hostent *h = NULL;
62e76326 560
aa2b5399 561 struct in_addr sa;
62e76326 562
af85f811 563 if (Config.visibleHostname != NULL)
62e76326 564 return Config.visibleHostname;
565
d20b1cd0 566 if (present)
62e76326 567 return host;
568
d20b1cd0 569 host[0] = '\0';
62e76326 570
aa2b5399 571 memcpy(&sa, &any_addr, sizeof(sa));
62e76326 572
aa2b5399 573 if (Config.Sockaddr.http && sa.s_addr == any_addr.s_addr)
62e76326 574 memcpy(&sa, &Config.Sockaddr.http->s.sin_addr, sizeof(sa));
575
aa2b5399 576#if USE_SSL
62e76326 577
aa2b5399 578 if (Config.Sockaddr.https && sa.s_addr == any_addr.s_addr)
62e76326 579 memcpy(&sa, &Config.Sockaddr.https->http.s.sin_addr, sizeof(sa));
580
aa2b5399 581#endif
582 /*
583 * If the first http_port address has a specific address, try a
584 * reverse DNS lookup on it.
585 */
586 if (sa.s_addr != any_addr.s_addr) {
62e76326 587 h = gethostbyaddr((char *) &sa,
588 sizeof(sa), AF_INET);
589
590 if (h != NULL) {
591 /* DNS lookup successful */
592 /* use the official name from DNS lookup */
593 xstrncpy(host, h->h_name, SQUIDHOSTNAMELEN);
594 debug(50, 4) ("getMyHostname: resolved %s to '%s'\n",
595 inet_ntoa(sa),
596 host);
597 present = 1;
598
599 if (strchr(host, '.'))
600 return host;
601
602 }
603
604 debug(50, 1) ("WARNING: failed to resolve %s to a fully qualified hostname\n",
605 inet_ntoa(sa));
d20b1cd0 606 }
62e76326 607
d20b1cd0 608 /*
609 * Get the host name and store it in host to return
610 */
611 if (gethostname(host, SQUIDHOSTNAMELEN) < 0) {
62e76326 612 debug(50, 1) ("WARNING: gethostname failed: %s\n", xstrerror());
d20b1cd0 613 } else if ((h = gethostbyname(host)) == NULL) {
62e76326 614 debug(50, 1) ("WARNING: gethostbyname failed for %s\n", host);
7e3ce7b9 615 } else {
62e76326 616 debug(50, 6) ("getMyHostname: '%s' resolved into '%s'\n",
617 host, h->h_name);
618 /* DNS lookup successful */
619 /* use the official name from DNS lookup */
620 xstrncpy(host, h->h_name, SQUIDHOSTNAMELEN);
621 present = 1;
622
623 if (strchr(host, '.'))
624 return host;
44a47c6e 625 }
62e76326 626
d20b1cd0 627 fatal("Could not determine fully qualified hostname. Please set 'visible_hostname'\n");
628 return NULL; /* keep compiler happy */
44a47c6e 629}
630
98829f69 631const char *
632uniqueHostname(void)
633{
634 return Config.uniqueHostname ? Config.uniqueHostname : getMyHostname();
635}
636
30a4f2a8 637/* leave a privilegied section. (Give up any privilegies)
638 * Routines that need privilegies can rap themselves in enter_suid()
639 * and leave_suid()
640 * To give upp all posibilites to gain privilegies use no_suid()
12b9e9b1 641 */
b8d8561b 642void
0673c0ba 643leave_suid(void)
12b9e9b1 644{
be20dac7 645 debug(21, 3) ("leave_suid: PID %d called\n", (int) getpid());
62e76326 646
e3d74828 647 if (Config.effectiveGroup) {
648
649#if HAVE_SETGROUPS
650
651 setgroups(1, &Config2.effectiveGroupID);
652
653#endif
654
655 if (setgid(Config2.effectiveGroupID) < 0)
656 debug(50, 0) ("ALERT: setgid: %s\n", xstrerror());
657
658 }
659
12b9e9b1 660 if (geteuid() != 0)
62e76326 661 return;
662
12b9e9b1 663 /* Started as a root, check suid option */
b6f794d6 664 if (Config.effectiveUser == NULL)
62e76326 665 return;
666
e3d74828 667 debug(21, 3) ("leave_suid: PID %d giving up root, becoming '%s'\n",
668 (int) getpid(), Config.effectiveUser);
62e76326 669
e3d74828 670 if (!Config.effectiveGroup) {
62e76326 671
e3d74828 672 if (setgid(Config2.effectiveGroupID) < 0)
673 debug(50, 0) ("ALERT: setgid: %s\n", xstrerror());
62e76326 674
e3d74828 675 if (initgroups(Config.effectiveUser, Config2.effectiveGroupID) < 0) {
676 debug(50, 0) ("ALERT: initgroups: unable to set groups for User %s "
677 "and Group %u", Config.effectiveUser,
678 (unsigned) Config2.effectiveGroupID);
679 }
680 }
62e76326 681
234967c9 682#if HAVE_SETRESUID
62e76326 683
d20b1cd0 684 if (setresuid(Config2.effectiveUserID, Config2.effectiveUserID, 0) < 0)
62e76326 685 debug(50, 0) ("ALERT: setresuid: %s\n", xstrerror());
686
234967c9 687#elif HAVE_SETEUID
62e76326 688
d20b1cd0 689 if (seteuid(Config2.effectiveUserID) < 0)
62e76326 690 debug(50, 0) ("ALERT: seteuid: %s\n", xstrerror());
691
234967c9 692#else
62e76326 693
d20b1cd0 694 if (setuid(Config2.effectiveUserID) < 0)
62e76326 695 debug(50, 0) ("ALERT: setuid: %s\n", xstrerror());
696
234967c9 697#endif
698}
699
30a4f2a8 700/* Enter a privilegied section */
b8d8561b 701void
0673c0ba 702enter_suid(void)
234967c9 703{
be20dac7 704 debug(21, 3) ("enter_suid: PID %d taking root priveleges\n", (int) getpid());
234967c9 705#if HAVE_SETRESUID
62e76326 706
e6ccf245 707 setresuid((uid_t)-1, 0, (uid_t)-1);
234967c9 708#else
62e76326 709
234967c9 710 setuid(0);
711#endif
712}
713
30a4f2a8 714/* Give up the posibility to gain privilegies.
715 * this should be used before starting a sub process
716 */
b8d8561b 717void
0673c0ba 718no_suid(void)
234967c9 719{
720 uid_t uid;
30a4f2a8 721 leave_suid();
234967c9 722 uid = geteuid();
be20dac7 723 debug(21, 3) ("leave_suid: PID %d giving up root priveleges forever\n", (int) getpid());
234967c9 724#if HAVE_SETRESUID
62e76326 725
429fdbec 726 if (setresuid(uid, uid, uid) < 0)
62e76326 727 debug(50, 1) ("no_suid: setresuid: %s\n", xstrerror());
728
234967c9 729#else
62e76326 730
234967c9 731 setuid(0);
62e76326 732
429fdbec 733 if (setuid(uid) < 0)
62e76326 734 debug(50, 1) ("no_suid: setuid: %s\n", xstrerror());
735
234967c9 736#endif
12b9e9b1 737}
ccff9601 738
b8d8561b 739void
0673c0ba 740writePidFile(void)
ccff9601 741{
9e4ad609 742 int fd;
0b4639af 743 const char *f = NULL;
973e9fe1 744 mode_t old_umask;
9e4ad609 745 char buf[32];
62e76326 746
9e4ad609 747 if ((f = Config.pidFilename) == NULL)
62e76326 748 return;
749
9e4ad609 750 if (!strcmp(Config.pidFilename, "none"))
62e76326 751 return;
752
30a4f2a8 753 enter_suid();
62e76326 754
973e9fe1 755 old_umask = umask(022);
62e76326 756
c4aefe96 757 fd = file_open(f, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT);
62e76326 758
973e9fe1 759 umask(old_umask);
62e76326 760
30a4f2a8 761 leave_suid();
62e76326 762
9e4ad609 763 if (fd < 0) {
62e76326 764 debug(50, 0) ("%s: %s\n", f, xstrerror());
765 debug_trap("Could not write pid file");
766 return;
ccff9601 767 }
62e76326 768
56878878 769 snprintf(buf, 32, "%d\n", (int) getpid());
1f7c9178 770 FD_WRITE_METHOD(fd, buf, strlen(buf));
9e4ad609 771 file_close(fd);
ccff9601 772}
c4fb974e 773
774
ff8d0ea6 775pid_t
0673c0ba 776readPidFile(void)
7690e8eb 777{
778 FILE *pid_fp = NULL;
9e4ad609 779 const char *f = Config.pidFilename;
ff8d0ea6 780 pid_t pid = -1;
781 int i;
7690e8eb 782
9e4ad609 783 if (f == NULL || !strcmp(Config.pidFilename, "none")) {
62e76326 784 fprintf(stderr, "%s: ERROR: No pid file name defined\n", appname);
785 exit(1);
7690e8eb 786 }
62e76326 787
7690e8eb 788 pid_fp = fopen(f, "r");
62e76326 789
7690e8eb 790 if (pid_fp != NULL) {
62e76326 791 pid = 0;
792
793 if (fscanf(pid_fp, "%d", &i) == 1)
794 pid = (pid_t) i;
795
796 fclose(pid_fp);
7690e8eb 797 } else {
62e76326 798 if (errno != ENOENT) {
799 fprintf(stderr, "%s: ERROR: Could not read pid file\n", appname);
800 fprintf(stderr, "\t%s: %s\n", f, xstrerror());
801 exit(1);
802 }
7690e8eb 803 }
62e76326 804
7690e8eb 805 return pid;
806}
807
808
b8d8561b 809void
0673c0ba 810setMaxFD(void)
c4fb974e 811{
234967c9 812#if HAVE_SETRLIMIT
c4fb974e 813 /* try to use as many file descriptors as possible */
814 /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
62e76326 815
c4fb974e 816 struct rlimit rl;
817#if defined(RLIMIT_NOFILE)
62e76326 818
c4fb974e 819 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
62e76326 820 debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %s\n", xstrerror());
c4fb974e 821 } else {
62e76326 822 rl.rlim_cur = Squid_MaxFD;
823
824 if (rl.rlim_cur > rl.rlim_max)
825 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
826
827 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
828 snprintf(tmp_error_buf, ERROR_BUF_SZ,
829 "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
830 fatal_dump(tmp_error_buf);
831 }
c4fb974e 832 }
62e76326 833
c4fb974e 834#elif defined(RLIMIT_OFILE)
835 if (getrlimit(RLIMIT_OFILE, &rl) < 0) {
62e76326 836 debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %s\n", xstrerror());
c4fb974e 837 } else {
62e76326 838 rl.rlim_cur = Squid_MaxFD;
839
840 if (rl.rlim_cur > rl.rlim_max)
841 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
842
843 if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
844 snprintf(tmp_error_buf, ERROR_BUF_SZ,
845 "setrlimit: RLIMIT_OFILE: %s", xstrerror());
846 fatal_dump(tmp_error_buf);
847 }
c4fb974e 848 }
62e76326 849
c4fb974e 850#endif
c4fb974e 851#else /* HAVE_SETRLIMIT */
a3d5953d 852 debug(21, 1) ("setMaxFD: Cannot increase: setrlimit() not supported on this system\n");
62e76326 853
30a4f2a8 854#endif /* HAVE_SETRLIMIT */
855
856#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
62e76326 857
30a4f2a8 858 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
62e76326 859 debug(50, 0) ("getrlimit: RLIMIT_DATA: %s\n", xstrerror());
88738790 860 } else if (rl.rlim_max > rl.rlim_cur) {
62e76326 861 rl.rlim_cur = rl.rlim_max; /* set it to the max */
862
863 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
864 snprintf(tmp_error_buf, ERROR_BUF_SZ,
865 "setrlimit: RLIMIT_DATA: %s", xstrerror());
866 fatal_dump(tmp_error_buf);
867 }
30a4f2a8 868 }
62e76326 869
30a4f2a8 870#endif /* RLIMIT_DATA */
ad7ef91a 871#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
872 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
62e76326 873 debug(50, 0) ("getrlimit: RLIMIT_VMEM: %s\n", xstrerror());
88738790 874 } else if (rl.rlim_max > rl.rlim_cur) {
62e76326 875 rl.rlim_cur = rl.rlim_max; /* set it to the max */
876
877 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
878 snprintf(tmp_error_buf, ERROR_BUF_SZ,
879 "setrlimit: RLIMIT_VMEM: %s", xstrerror());
880 fatal_dump(tmp_error_buf);
881 }
ad7ef91a 882 }
62e76326 883
ad7ef91a 884#endif /* RLIMIT_VMEM */
c4fb974e 885}
3a57089e 886
b8d8561b 887time_t
0673c0ba 888getCurrentTime(void)
3a57089e 889{
94e891ea 890#if GETTIMEOFDAY_NO_TZP
30a4f2a8 891 gettimeofday(&current_time);
892#else
62e76326 893
d598947a 894 gettimeofday(&current_time, NULL);
5f3f8d0e 895#endif
62e76326 896
52040193 897 current_dtime = (double) current_time.tv_sec +
62e76326 898 (double) current_time.tv_usec / 1000000.0;
30a4f2a8 899 return squid_curtime = current_time.tv_sec;
5f3f8d0e 900}
fe113054 901
b8d8561b 902int
903percent(int a, int b)
30a4f2a8 904{
905 return b ? ((int) (100.0 * a / b + 0.5)) : 0;
906}
907
a7c05555 908double
f2908497 909dpercent(double a, double b)
910{
911 return b ? (100.0 * a / b) : 0.0;
912}
913
b8d8561b 914void
ea3a2a69 915squid_signal(int sig, SIGHDLR * func, int flags)
30a4f2a8 916{
917#if HAVE_SIGACTION
62e76326 918
30a4f2a8 919 struct sigaction sa;
920 sa.sa_handler = func;
921 sa.sa_flags = flags;
922 sigemptyset(&sa.sa_mask);
62e76326 923
30a4f2a8 924 if (sigaction(sig, &sa, NULL) < 0)
62e76326 925 debug(50, 0) ("sigaction: sig=%d func=%p: %s\n", sig, func, xstrerror());
926
30a4f2a8 927#else
62e76326 928
4ece5eb6 929 if (signal(sig, func) == SIG_ERR)
930 debug(50, 0) ("signal: sig=%d func=%p: %s\n", sig, func, xstrerror());
62e76326 931
30a4f2a8 932#endif
933}
396c5745 934
16b204c4 935struct in_addr
62e76326 936
937 inaddrFromHostent(const struct hostent *hp)
16b204c4 938{
62e76326 939
cc6a9d2e 940 struct in_addr s;
3c0117c9 941 xmemcpy(&s.s_addr, hp->h_addr, sizeof(s.s_addr));
cc6a9d2e 942 return s;
16b204c4 943}
88738790 944
9e4ad609 945double
e6ccf245 946doubleAverage(double cur, double newD, int N, int max)
9e4ad609 947{
1d8e0d40 948 if (N > max)
62e76326 949 N = max;
950
e6ccf245 951 return (cur * (N - 1.0) + newD) / N;
9e4ad609 952}
953
954int
e6ccf245 955intAverage(int cur, int newI, int n, int max)
9e4ad609 956{
957 if (n > max)
62e76326 958 n = max;
959
e6ccf245 960 return (cur * (n - 1) + newI) / n;
9e4ad609 961}
70364f29 962
963void
964logsFlush(void)
965{
966 if (debug_log)
62e76326 967 fflush(debug_log);
70364f29 968}
88738790 969
94439e4e 970dlink_node *
971dlinkNodeNew()
972{
973 if (dlink_node_pool == NULL)
b001e822 974 dlink_node_pool = MemPools::GetInstance().create("Dlink list nodes", sizeof(dlink_node));
62e76326 975
b001e822 976 /* where should we call delete dlink_node_pool;dlink_node_pool = NULL; */
977 return (dlink_node *)dlink_node_pool->alloc();
94439e4e 978}
979
980/* the node needs to be unlinked FIRST */
981void
982dlinkNodeDelete(dlink_node * m)
983{
984 if (m == NULL)
62e76326 985 return;
986
b001e822 987 dlink_node_pool->free(m);
94439e4e 988}
989
2ac237e2 990void
991dlinkAdd(void *data, dlink_node * m, dlink_list * list)
992{
993 m->data = data;
994 m->prev = NULL;
995 m->next = list->head;
62e76326 996
2ac237e2 997 if (list->head)
62e76326 998 list->head->prev = m;
999
2ac237e2 1000 list->head = m;
62e76326 1001
2ac237e2 1002 if (list->tail == NULL)
62e76326 1003 list->tail = m;
2ac237e2 1004}
1005
edce4d98 1006void
1007dlinkAddAfter(void *data, dlink_node * m, dlink_node * n, dlink_list * list)
1008{
1009 m->data = data;
1010 m->prev = n;
1011 m->next = n->next;
62e76326 1012
edce4d98 1013 if (n->next)
62e76326 1014 n->next->prev = m;
edce4d98 1015 else {
62e76326 1016 assert(list->tail == n);
1017 list->tail = m;
edce4d98 1018 }
62e76326 1019
edce4d98 1020 n->next = m;
1021}
1022
b2329b6a 1023void
1024dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
1025{
1026 m->data = data;
1027 m->next = NULL;
1028 m->prev = list->tail;
62e76326 1029
b2329b6a 1030 if (list->tail)
62e76326 1031 list->tail->next = m;
1032
b2329b6a 1033 list->tail = m;
62e76326 1034
b2329b6a 1035 if (list->head == NULL)
62e76326 1036 list->head = m;
b2329b6a 1037}
1038
2ac237e2 1039void
1040dlinkDelete(dlink_node * m, dlink_list * list)
1041{
1042 if (m->next)
62e76326 1043 m->next->prev = m->prev;
1044
2ac237e2 1045 if (m->prev)
62e76326 1046 m->prev->next = m->next;
1047
2ac237e2 1048 if (m == list->head)
62e76326 1049 list->head = m->next;
1050
2ac237e2 1051 if (m == list->tail)
62e76326 1052 list->tail = m->prev;
1053
92b8c095 1054 m->next = m->prev = NULL;
2ac237e2 1055}
a7c05555 1056
16300b58 1057void
0e473d70 1058kb_incr(kb_t * k, size_t v)
a7c05555 1059{
0e473d70 1060 k->bytes += v;
1061 k->kb += (k->bytes >> 10);
1062 k->bytes &= 0x3FF;
a7c05555 1063}
c1dabf04 1064
a00a7c85 1065void
6bbf9cc4 1066debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
a00a7c85 1067{
1068 MemBuf mb;
1069 Packer p;
6bbf9cc4 1070 assert(label && obj && pm);
a00a7c85 1071 memBufDefInit(&mb);
1072 packerToMemInit(&p, &mb);
0cdcddb9 1073 (*pm) (obj, &p);
6bbf9cc4 1074 debug(section, level) ("%s%s", label, mb.buf);
a00a7c85 1075 packerClean(&p);
1076 memBufClean(&mb);
1077}
d548ee64 1078
0e70aa1e 1079void
1080parseEtcHosts(void)
1081{
1082 FILE *fp;
1083 char buf[1024];
1084 char buf2[512];
1085 char *nt = buf;
1086 char *lt = buf;
fa2bfbab 1087
0e70aa1e 1088 if (NULL == Config.etcHostsPath)
62e76326 1089 return;
1090
0e70aa1e 1091 if (0 == strcmp(Config.etcHostsPath, "none"))
62e76326 1092 return;
1093
0e70aa1e 1094 fp = fopen(Config.etcHostsPath, "r");
62e76326 1095
0e70aa1e 1096 if (fp == NULL) {
62e76326 1097 debug(1, 1) ("parseEtcHosts: %s: %s\n",
1098 Config.etcHostsPath, xstrerror());
1099 return;
0e70aa1e 1100 }
62e76326 1101
ec4daaa5 1102#ifdef _SQUID_WIN32_
c4aefe96 1103 setmode(fileno(fp), O_TEXT);
62e76326 1104
c4aefe96 1105#endif
62e76326 1106
0e70aa1e 1107 while (fgets(buf, 1024, fp)) { /* for each line */
62e76326 1108 wordlist *hosts = NULL;
1109 char *addr;
1110
c31616ae 1111 if (buf[0] == '#') /* MS-windows likes to add comments */
1112 continue;
1113
7a10c315 1114 strtok(buf, "#"); /* chop everything following a comment marker */
62e76326 1115
1116 lt = buf;
1117
1118 addr = buf;
1119
1120 debug(1, 5) ("etc_hosts: line is '%s'\n", buf);
1121
1122 nt = strpbrk(lt, w_space);
1123
1124 if (nt == NULL) /* empty line */
1125 continue;
1126
1127 *nt = '\0'; /* null-terminate the address */
1128
1129 debug(1, 5) ("etc_hosts: address is '%s'\n", addr);
1130
1131 lt = nt + 1;
1132
1133 while ((nt = strpbrk(lt, w_space))) {
1134 char *host = NULL;
1135
1136 if (nt == lt) { /* multiple spaces */
1137 debug(1, 5) ("etc_hosts: multiple spaces, skipping\n");
1138 lt = nt + 1;
1139 continue;
1140 }
1141
1142 *nt = '\0';
1143 debug(1, 5) ("etc_hosts: got hostname '%s'\n", lt);
1144
1145 if (Config.appendDomain && !strchr(lt, '.')) {
1146 /* I know it's ugly, but it's only at reconfig */
1147 strncpy(buf2, lt, 512);
1148 strncat(buf2, Config.appendDomain, 512 - strlen(lt));
1149 host = buf2;
1150 } else {
1151 host = lt;
1152 }
1153
1154 if (ipcacheAddEntryFromHosts(host, addr) != 0)
1155 goto skip; /* invalid address, continuing is useless */
1156
1157 wordlistAdd(&hosts, host);
1158
1159 lt = nt + 1;
1160 }
1161
1162 fqdncacheAddEntryFromHosts(addr, hosts);
1163
1164skip:
1165 wordlistDestroy(&hosts);
0e70aa1e 1166 }
62e76326 1167
1f3c7397 1168 fclose (fp);
0e70aa1e 1169}
52f772de 1170
1171int
1172getMyPort(void)
1173{
52f772de 1174 if (Config.Sockaddr.http)
62e76326 1175 return ntohs(Config.Sockaddr.http->s.sin_port);
1176
a2727cdb 1177#if USE_SSL
62e76326 1178
a2727cdb 1179 if (Config.Sockaddr.https)
62e76326 1180 return ntohs(Config.Sockaddr.https->http.s.sin_port);
1181
52f772de 1182#endif
62e76326 1183
a2727cdb 1184 fatal("No port defined");
62e76326 1185
bac6d4bd 1186 return 0; /* NOT REACHED */
52f772de 1187}
d860a1aa 1188
d860a1aa 1189
1190/*
1191 * Inverse of strwordtok. Quotes a word if needed
1192 */
42419a95 1193void
d860a1aa 1194strwordquote(MemBuf * mb, const char *str)
1195{
1196 int quoted = 0;
62e76326 1197
d860a1aa 1198 if (strchr(str, ' ')) {
62e76326 1199 quoted = 1;
1200 memBufAppend(mb, "\"", 1);
d860a1aa 1201 }
62e76326 1202
d860a1aa 1203 while (*str) {
dc1af3cf 1204 int l = strcspn(str, "\"\\\n\r");
62e76326 1205 memBufAppend(mb, str, l);
1206 str += l;
1207
dc1af3cf 1208 switch(*str) {
1209
1210 case '\n':
1211 memBufAppend(mb, "\\n", 2);
1212 str++;
1213 break;
1214
1215 case '\r':
1216 memBufAppend(mb, "\\r", 2);
1217 str++;
1218 break;
1219
1220 case '\0':
1221 break;
1222
1223 default:
62e76326 1224 memBufAppend(mb, "\\", 1);
1225 memBufAppend(mb, str, 1);
1226 str++;
dc1af3cf 1227 break;
62e76326 1228 }
d860a1aa 1229 }
62e76326 1230
d860a1aa 1231 if (quoted)
62e76326 1232 memBufAppend(mb, "\"", 1);
d860a1aa 1233}