]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tools.cc
merge changes from SQUID_2_3 branch
[thirdparty/squid.git] / src / tools.cc
CommitLineData
94e891ea 1
30a4f2a8 2/*
7e3ce7b9 3 * $Id: tools.cc,v 1.188 1999/12/30 17:37:01 wessels Exp $
30a4f2a8 4 *
5 * DEBUG: section 21 Misc Functions
6 * AUTHOR: Harvest Derived
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
e25c139f 13 * National Laboratory for Applied Network Research and funded by the
14 * National Science Foundation. Squid is Copyrighted (C) 1998 by
15 * Duane Wessels and the University of California San Diego. Please
16 * see the COPYRIGHT file for full details. Squid incorporates
17 * software developed and/or copyrighted by other sources. Please see
18 * 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"
37
090089c4 38#define DEAD_MSG "\
c5c666ab 39The Squid Cache (version %s) died.\n\
090089c4 40\n\
c5c666ab 41You've encountered a fatal error in the Squid Cache version %s.\n\
090089c4 42If a core file was created (possibly in the swap directory),\n\
b8de7ebe 43please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
dc0e7db1 44and report the trace back to squid-bugs@ircache.net.\n\
090089c4 45\n\
46Thanks!\n"
47
f5b8bbc4 48static void fatal_common(const char *);
137ee196 49static void fatalvf(const char *fmt, va_list args);
f5b8bbc4 50static void mail_warranty(void);
63986a85 51#if MEM_GEN_TRACE
399e85ea 52extern void log_trace_done();
63986a85 53extern void log_trace_init(char *);
399e85ea 54#endif
24382924 55
7e3ce7b9 56extern void (*failure_notify) (const char *);
57
4a5a6c62 58void
429fdbec 59releaseServerSockets(void)
60{
812ed90c 61 int i;
429fdbec 62 /* Release the main ports as early as possible */
812ed90c 63 for (i = 0; i < NHttpSockets; i++) {
64 if (HttpSockets[i] >= 0)
88738790 65 close(HttpSockets[i]);
812ed90c 66 }
429fdbec 67 if (theInIcpConnection >= 0)
88738790 68 close(theInIcpConnection);
429fdbec 69 if (theOutIcpConnection >= 0 && theOutIcpConnection != theInIcpConnection)
88738790 70 close(theOutIcpConnection);
429fdbec 71}
72
b8d8561b 73static char *
0673c0ba 74dead_msg(void)
090089c4 75{
95d659f0 76 LOCAL_ARRAY(char, msg, 1024);
56878878 77 snprintf(msg, 1024, DEAD_MSG, version_string, version_string);
090089c4 78 return msg;
79}
80
24382924 81static void
0673c0ba 82mail_warranty(void)
090089c4 83{
019dd986 84 FILE *fp = NULL;
6e40f263 85 char *filename;
86 static char command[256];
87 if ((filename = tempnam(NULL, appname)) == NULL)
88 return;
89 if ((fp = fopen(filename, "w")) == NULL)
90 return;
91 fprintf(fp, "From: %s\n", appname);
edae7bc0 92 fprintf(fp, "To: %s\n", Config.adminEmail);
6e40f263 93 fprintf(fp, "Subject: %s\n", dead_msg());
94 fclose(fp);
56878878 95 snprintf(command, 256, "mail %s < %s", Config.adminEmail, filename);
6e40f263 96 system(command); /* XXX should avoid system(3) */
97 unlink(filename);
090089c4 98}
99
4a5a6c62 100void
43c3424b 101dumpMallocStats(void)
3f43b19b 102{
88738790 103#if HAVE_MSTATS && HAVE_GNUMALLOC_H
104 struct mstats ms = mstats();
105 fprintf(debug_log, "\ttotal space in arena: %6d KB\n",
a97cfa48 106 (int) (ms.bytes_total >> 10));
88738790 107 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
a97cfa48 108 (int) (ms.bytes_free >> 10),
88738790 109 percent(ms.bytes_free, ms.bytes_total));
eb824054 110#elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
3f43b19b 111 struct mallinfo mp;
30a4f2a8 112 int t;
3f43b19b 113 if (!do_mallinfo)
114 return;
3f43b19b 115 mp = mallinfo();
9e4ad609 116 fprintf(debug_log, "Memory usage for %s via mallinfo():\n", appname);
117 fprintf(debug_log, "\ttotal space in arena: %6d KB\n",
30a4f2a8 118 mp.arena >> 10);
9e4ad609 119 fprintf(debug_log, "\tOrdinary blocks: %6d KB %6d blks\n",
30a4f2a8 120 mp.uordblks >> 10, mp.ordblks);
9e4ad609 121 fprintf(debug_log, "\tSmall blocks: %6d KB %6d blks\n",
30a4f2a8 122 mp.usmblks >> 10, mp.smblks);
9e4ad609 123 fprintf(debug_log, "\tHolding blocks: %6d KB %6d blks\n",
30a4f2a8 124 mp.hblkhd >> 10, mp.hblks);
9e4ad609 125 fprintf(debug_log, "\tFree Small blocks: %6d KB\n",
30a4f2a8 126 mp.fsmblks >> 10);
9e4ad609 127 fprintf(debug_log, "\tFree Ordinary blocks: %6d KB\n",
30a4f2a8 128 mp.fordblks >> 10);
129 t = mp.uordblks + mp.usmblks + mp.hblkhd;
9e4ad609 130 fprintf(debug_log, "\tTotal in use: %6d KB %d%%\n",
30a4f2a8 131 t >> 10, percent(t, mp.arena));
132 t = mp.fsmblks + mp.fordblks;
9e4ad609 133 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
30a4f2a8 134 t >> 10, percent(t, mp.arena));
46c883ed 135#if HAVE_EXT_MALLINFO
9e4ad609 136 fprintf(debug_log, "\tmax size of small blocks:\t%d\n",
30a4f2a8 137 mp.mxfast);
9e4ad609 138 fprintf(debug_log, "\tnumber of small blocks in a holding block:\t%d\n",
3f43b19b 139 mp.nlblks);
9e4ad609 140 fprintf(debug_log, "\tsmall block rounding factor:\t%d\n",
30a4f2a8 141 mp.grain);
9e4ad609 142 fprintf(debug_log, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
3f43b19b 143 mp.uordbytes);
9e4ad609 144 fprintf(debug_log, "\tnumber of ordinary blocks allocated:\t%d\n",
3f43b19b 145 mp.allocated);
9e4ad609 146 fprintf(debug_log, "\tbytes used in maintaining the free tree:\t%d\n",
3f43b19b 147 mp.treeoverhead);
46c883ed 148#endif /* HAVE_EXT_MALLINFO */
3f43b19b 149#endif /* HAVE_MALLINFO */
150}
30a4f2a8 151
f2908497 152void
153squid_getrusage(struct rusage *r)
f0f81709 154{
8da94b66 155 memset(r, '\0', sizeof(struct rusage));
30a4f2a8 156#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
cd19f0b6 157#ifdef _SQUID_SOLARIS_
158 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
159 enter_suid();
160#endif
f2908497 161 getrusage(RUSAGE_SELF, r);
cd19f0b6 162#ifdef _SQUID_SOLARIS_
163 leave_suid();
164#endif
56983a01 165#endif
f2908497 166}
167
168double
169rusage_cputime(struct rusage *r)
170{
171 return (double) r->ru_stime.tv_sec +
172 (double) r->ru_utime.tv_sec +
173 (double) r->ru_stime.tv_usec / 1000000.0 +
174 (double) r->ru_utime.tv_usec / 1000000.0;
175}
176
ec603b25 177/* Hack for some HP-UX preprocessors */
178#ifndef HAVE_GETPAGESIZE
179#define HAVE_GETPAGESIZE 0
180#endif
181
f2908497 182int
183rusage_maxrss(struct rusage *r)
184{
4fdc3986 185#if defined(_SQUID_SGI_) && _ABIAPI
186 return r->ru_pad[0];
187#elif defined(_SQUID_SGI_)
f2908497 188 return r->ru_maxrss;
189#elif defined(_SQUID_OSF_)
190 return r->ru_maxrss;
191#elif defined(BSD4_4)
192 return r->ru_maxrss;
6b8e7481 193#elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
f2908497 194 return (r->ru_maxrss * getpagesize()) >> 10;
c7a1083d 195#elif defined(PAGESIZE)
196 return (r->ru_maxrss * PAGESIZE) >> 10;
8505e57b 197#else
198 return r->ru_maxrss;
f2908497 199#endif
200}
201
202int
203rusage_pagefaults(struct rusage *r)
204{
4fdc3986 205#if defined(_SQUID_SGI_) && _ABIAPI
206 return r->ru_pad[5];
207#else
f2908497 208 return r->ru_majflt;
4fdc3986 209#endif
f2908497 210}
211
212
4a5a6c62 213void
f2908497 214PrintRusage(void)
215{
216 struct rusage rusage;
217 squid_getrusage(&rusage);
2b906e48 218 fprintf(debug_log, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
219 rusage_cputime(&rusage),
220 rusage.ru_utime.tv_sec + ((double) rusage.ru_utime.tv_usec / 1000000.0),
221 rusage.ru_stime.tv_sec + ((double) rusage.ru_stime.tv_usec / 1000000.0));
f2908497 222 fprintf(debug_log, "Maximum Resident Size: %d KB\n",
223 rusage_maxrss(&rusage));
224 fprintf(debug_log, "Page faults with physical i/o: %d\n",
225 rusage_pagefaults(&rusage));
f0f81709 226}
227
03d7b07f 228
b8d8561b 229void
230death(int sig)
44a47c6e 231{
0e08ce4b 232 if (sig == SIGSEGV)
2c47cf74 233 fprintf(debug_log, "FATAL: Received Segment Violation...dying.\n");
0e08ce4b 234 else if (sig == SIGBUS)
6e40f263 235 fprintf(debug_log, "FATAL: Received Bus Error...dying.\n");
0e08ce4b 236 else
2c47cf74 237 fprintf(debug_log, "FATAL: Received signal %d...dying.\n", sig);
0b4639af 238
239#ifdef PRINT_STACK_TRACE
240#ifdef _SQUID_HPUX_
241 {
4f07153c 242 extern void U_STACK_TRACE(void); /* link with -lcl */
0b4639af 243 fflush(debug_log);
244 dup2(fileno(debug_log), 2);
245 U_STACK_TRACE();
246 }
247#endif /* _SQUID_HPUX_ */
248#ifdef _SQUID_SOLARIS_
4f07153c 249 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
250 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
0b4639af 251 fflush(debug_log);
252 dup2(fileno(debug_log), fileno(stdout));
253 opcom_stack_trace();
254 fflush(stdout);
255 }
256#endif /* _SQUID_SOLARIS_ */
257#endif /* PRINT_STACK_TRACE */
258
6e40f263 259#if SA_RESETHAND == 0
44a47c6e 260 signal(SIGSEGV, SIG_DFL);
261 signal(SIGBUS, SIG_DFL);
0e08ce4b 262 signal(sig, SIG_DFL);
30a4f2a8 263#endif
429fdbec 264 releaseServerSockets();
e3ef2b09 265 storeDirWriteCleanLogs(0);
9e4ad609 266 PrintRusage();
267 dumpMallocStats();
6e40f263 268 if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
269 /* skip if more than 10 days old */
edae7bc0 270 if (Config.adminEmail)
6e40f263 271 mail_warranty();
272 else
273 puts(dead_msg());
274 }
44a47c6e 275 abort();
276}
277
278
b8d8561b 279void
23d92c64 280sigusr2_handle(int sig)
090089c4 281{
30a4f2a8 282 static int state = 0;
545f551a 283 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
30a4f2a8 284 if (state == 0) {
2bf05976 285#ifndef MEM_GEN_TRACE
b6f794d6 286 _db_init(Config.Log.log, "ALL,10");
2bf05976 287#else
63986a85 288 log_trace_done();
289#endif
2bf05976 290 state = 1;
30a4f2a8 291 } else {
2bf05976 292#ifndef MEM_GEN_TRACE
b6f794d6 293 _db_init(Config.Log.log, Config.debugOptions);
2bf05976 294#else
63986a85 295 log_trace_init("/tmp/squid.alloc");
296#endif
2bf05976 297 state = 0;
30a4f2a8 298 }
299#if !HAVE_SIGACTION
300 signal(sig, sigusr2_handle); /* reinstall */
090089c4 301#endif
302}
303
24382924 304static void
0ee4272b 305fatal_common(const char *message)
090089c4 306{
db40ae20 307#if HAVE_SYSLOG
6b8e7481 308 syslog(LOG_ALERT, "%s", message);
db40ae20 309#endif
9bc73deb 310 fprintf(debug_log, "FATAL: %s\n", message);
311 if (opt_debug_stderr > 0 && debug_log != stderr)
312 fprintf(stderr, "FATAL: %s\n", message);
c5c666ab 313 fprintf(debug_log, "Squid Cache (Version %s): Terminated abnormally.\n",
8213067d 314 version_string);
2c47cf74 315 fflush(debug_log);
9e4ad609 316 PrintRusage();
317 dumpMallocStats();
090089c4 318}
319
320/* fatal */
b8d8561b 321void
0ee4272b 322fatal(const char *message)
090089c4 323{
429fdbec 324 releaseServerSockets();
b2c141d4 325 /* check for store_dirs_rebuilding because fatal() is often
d399be0e 326 * used in early initialization phases, long before we ever
327 * get to the store log. */
b2c141d4 328 if (0 == store_dirs_rebuilding)
e3ef2b09 329 storeDirWriteCleanLogs(0);
090089c4 330 fatal_common(message);
54f742e7 331 exit(shutting_down ? 0 : 1);
090089c4 332}
333
137ee196 334/* printf-style interface for fatal */
6de2df60 335#if STDC_HEADERS
137ee196 336void
337fatalf(const char *fmt,...)
338{
339 va_list args;
340 va_start(args, fmt);
341#else
342void
343fatalf(va_alist)
344 va_dcl
345{
346 va_list args;
347 const char *fmt = NULL;
348 va_start(args);
349 fmt = va_arg(args, char *);
350#endif
351 fatalvf(fmt, args);
352 va_end(args);
353}
354
355
356/* used by fatalf */
357static void
358fatalvf(const char *fmt, va_list args)
359{
360 static char fatal_str[BUFSIZ];
361 vsnprintf(fatal_str, sizeof(fatal_str), fmt, args);
362 fatal(fatal_str);
363}
364
090089c4 365/* fatal with dumping core */
b8d8561b 366void
0ee4272b 367fatal_dump(const char *message)
090089c4 368{
7e3ce7b9 369 failure_notify = NULL;
429fdbec 370 releaseServerSockets();
090089c4 371 if (message)
372 fatal_common(message);
4a69c163 373 if (opt_catch_signals)
e3ef2b09 374 storeDirWriteCleanLogs(0);
090089c4 375 abort();
376}
377
b8d8561b 378void
a3d5953d 379debug_trap(const char *message)
85b701ed 380{
4a69c163 381 if (!opt_catch_signals)
85b701ed 382 fatal_dump(message);
a3d5953d 383 _db_print("WARNING: %s\n", message);
85b701ed 384}
385
b8d8561b 386void
23d92c64 387sig_child(int sig)
090089c4 388{
30a4f2a8 389#ifdef _SQUID_NEXT_
390 union wait status;
391#else
090089c4 392 int status;
090089c4 393#endif
ff8d0ea6 394 pid_t pid;
090089c4 395
30a4f2a8 396 do {
397#ifdef _SQUID_NEXT_
398 pid = wait3(&status, WNOHANG, NULL);
090089c4 399#else
30a4f2a8 400 pid = waitpid(-1, &status, WNOHANG);
090089c4 401#endif
97a88399 402 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
30a4f2a8 403#if HAVE_SIGACTION
404 } while (pid > 0);
234967c9 405#else
30a4f2a8 406 } while (pid > 0 || (pid < 0 && errno == EINTR));
407 signal(sig, sig_child);
234967c9 408#endif
30a4f2a8 409}
44a47c6e 410
0ee4272b 411const char *
0673c0ba 412getMyHostname(void)
44a47c6e 413{
95d659f0 414 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
44a47c6e 415 static int present = 0;
0ee4272b 416 const struct hostent *h = NULL;
af85f811 417 if (Config.visibleHostname != NULL)
418 return Config.visibleHostname;
7e3ce7b9 419 if (present) {
420 (void) 0;
421 } else if (Config.Sockaddr.http->s.sin_addr.s_addr != any_addr.s_addr) {
422 /*
423 * If the first http_port address has a specific address, try a
424 * reverse DNS lookup on it.
425 */
af85f811 426 host[0] = '\0';
7e3ce7b9 427 h = gethostbyaddr((char *) &Config.Sockaddr.http->s.sin_addr,
428 sizeof(Config.Sockaddr.http->s.sin_addr), AF_INET);
af85f811 429 if (h != NULL) {
430 /* DNS lookup successful */
431 /* use the official name from DNS lookup */
432 strcpy(host, h->h_name);
433 debug(50, 4) ("getMyHostname: resolved tcp_incoming_addr to '%s'\n",
434 host);
435 present = 1;
436 } else {
437 debug(50, 6) ("getMyHostname: failed to resolve tcp_incoming_addr\n");
438 }
7e3ce7b9 439 } else {
440 /*
441 * Get the host name and store it in host to return
442 */
44a47c6e 443 host[0] = '\0';
444 if (gethostname(host, SQUIDHOSTNAMELEN) == -1) {
a3d5953d 445 debug(50, 1) ("getMyHostname: gethostname failed: %s\n",
44a47c6e 446 xstrerror());
44a47c6e 447 } else {
e5f6c5c2 448 if ((h = gethostbyname(host)) != NULL) {
af85f811 449 debug(50, 6) ("getMyHostname: '%s' resolved into '%s'\n",
450 host, h->h_name);
44a47c6e 451 /* DNS lookup successful */
452 /* use the official name from DNS lookup */
453 strcpy(host, h->h_name);
454 }
44a47c6e 455 }
af85f811 456 present = 1;
44a47c6e 457 }
af85f811 458 return present ? host : NULL;
44a47c6e 459}
460
98829f69 461const char *
462uniqueHostname(void)
463{
464 return Config.uniqueHostname ? Config.uniqueHostname : getMyHostname();
465}
466
0a0bf5db 467void
0ee4272b 468safeunlink(const char *s, int quiet)
44a47c6e 469{
64b54eed 470 Counter.syscalls.disk.unlinks++;
0a0bf5db 471 if (unlink(s) < 0 && !quiet)
a3d5953d 472 debug(50, 1) ("safeunlink: Couldn't delete %s: %s\n", s, xstrerror());
0a0bf5db 473}
474
30a4f2a8 475/* leave a privilegied section. (Give up any privilegies)
476 * Routines that need privilegies can rap themselves in enter_suid()
477 * and leave_suid()
478 * To give upp all posibilites to gain privilegies use no_suid()
12b9e9b1 479 */
b8d8561b 480void
0673c0ba 481leave_suid(void)
12b9e9b1 482{
483 struct passwd *pwd = NULL;
484 struct group *grp = NULL;
a3d5953d 485 debug(21, 3) ("leave_suid: PID %d called\n", getpid());
12b9e9b1 486 if (geteuid() != 0)
487 return;
488 /* Started as a root, check suid option */
b6f794d6 489 if (Config.effectiveUser == NULL)
12b9e9b1 490 return;
b6f794d6 491 if ((pwd = getpwnam(Config.effectiveUser)) == NULL)
12b9e9b1 492 return;
b6f794d6 493 if (Config.effectiveGroup && (grp = getgrnam(Config.effectiveGroup))) {
429fdbec 494 if (setgid(grp->gr_gid) < 0)
a3d5953d 495 debug(50, 1) ("leave_suid: setgid: %s\n", xstrerror());
12b9e9b1 496 } else {
429fdbec 497 if (setgid(pwd->pw_gid) < 0)
a3d5953d 498 debug(50, 1) ("leave_suid: setgid: %s\n", xstrerror());
12b9e9b1 499 }
a3d5953d 500 debug(21, 3) ("leave_suid: PID %d giving up root, becoming '%s'\n",
30a4f2a8 501 getpid(), pwd->pw_name);
234967c9 502#if HAVE_SETRESUID
429fdbec 503 if (setresuid(pwd->pw_uid, pwd->pw_uid, 0) < 0)
a3d5953d 504 debug(50, 1) ("leave_suid: setresuid: %s\n", xstrerror());
234967c9 505#elif HAVE_SETEUID
429fdbec 506 if (seteuid(pwd->pw_uid) < 0)
a3d5953d 507 debug(50, 1) ("leave_suid: seteuid: %s\n", xstrerror());
234967c9 508#else
429fdbec 509 if (setuid(pwd->pw_uid) < 0)
a3d5953d 510 debug(50, 1) ("leave_suid: setuid: %s\n", xstrerror());
234967c9 511#endif
512}
513
30a4f2a8 514/* Enter a privilegied section */
b8d8561b 515void
0673c0ba 516enter_suid(void)
234967c9 517{
a3d5953d 518 debug(21, 3) ("enter_suid: PID %d taking root priveleges\n", getpid());
234967c9 519#if HAVE_SETRESUID
520 setresuid(-1, 0, -1);
521#else
522 setuid(0);
523#endif
524}
525
30a4f2a8 526/* Give up the posibility to gain privilegies.
527 * this should be used before starting a sub process
528 */
b8d8561b 529void
0673c0ba 530no_suid(void)
234967c9 531{
532 uid_t uid;
30a4f2a8 533 leave_suid();
234967c9 534 uid = geteuid();
a3d5953d 535 debug(21, 3) ("leave_suid: PID %d giving up root priveleges forever\n", getpid());
234967c9 536#if HAVE_SETRESUID
429fdbec 537 if (setresuid(uid, uid, uid) < 0)
a3d5953d 538 debug(50, 1) ("no_suid: setresuid: %s\n", xstrerror());
234967c9 539#else
540 setuid(0);
429fdbec 541 if (setuid(uid) < 0)
a3d5953d 542 debug(50, 1) ("no_suid: setuid: %s\n", xstrerror());
234967c9 543#endif
12b9e9b1 544}
ccff9601 545
b8d8561b 546void
0673c0ba 547writePidFile(void)
ccff9601 548{
9e4ad609 549 int fd;
0b4639af 550 const char *f = NULL;
973e9fe1 551 mode_t old_umask;
9e4ad609 552 char buf[32];
553 if ((f = Config.pidFilename) == NULL)
554 return;
555 if (!strcmp(Config.pidFilename, "none"))
ccff9601 556 return;
30a4f2a8 557 enter_suid();
973e9fe1 558 old_umask = umask(022);
1a94f598 559 fd = file_open(f, O_WRONLY | O_CREAT | O_TRUNC);
973e9fe1 560 umask(old_umask);
30a4f2a8 561 leave_suid();
9e4ad609 562 if (fd < 0) {
a3d5953d 563 debug(50, 0) ("%s: %s\n", f, xstrerror());
9e4ad609 564 debug_trap("Could not write pid file");
565 return;
ccff9601 566 }
56878878 567 snprintf(buf, 32, "%d\n", (int) getpid());
9e4ad609 568 write(fd, buf, strlen(buf));
569 file_close(fd);
ccff9601 570}
c4fb974e 571
572
ff8d0ea6 573pid_t
0673c0ba 574readPidFile(void)
7690e8eb 575{
576 FILE *pid_fp = NULL;
9e4ad609 577 const char *f = Config.pidFilename;
ff8d0ea6 578 pid_t pid = -1;
579 int i;
7690e8eb 580
9e4ad609 581 if (f == NULL || !strcmp(Config.pidFilename, "none")) {
7690e8eb 582 fprintf(stderr, "%s: ERROR: No pid file name defined\n", appname);
583 exit(1);
584 }
585 pid_fp = fopen(f, "r");
586 if (pid_fp != NULL) {
ff8d0ea6 587 pid = 0;
588 if (fscanf(pid_fp, "%d", &i) == 1)
589 pid = (pid_t) i;
7690e8eb 590 fclose(pid_fp);
591 } else {
592 if (errno != ENOENT) {
593 fprintf(stderr, "%s: ERROR: Could not read pid file\n", appname);
594 fprintf(stderr, "\t%s: %s\n", f, xstrerror());
595 exit(1);
596 }
597 }
598 return pid;
599}
600
601
b8d8561b 602void
0673c0ba 603setMaxFD(void)
c4fb974e 604{
234967c9 605#if HAVE_SETRLIMIT
c4fb974e 606 /* try to use as many file descriptors as possible */
607 /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
608 struct rlimit rl;
609#if defined(RLIMIT_NOFILE)
610 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
a3d5953d 611 debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %s\n", xstrerror());
c4fb974e 612 } else {
e83892e9 613 rl.rlim_cur = Squid_MaxFD;
30a4f2a8 614 if (rl.rlim_cur > rl.rlim_max)
e83892e9 615 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
c4fb974e 616 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
56878878 617 snprintf(tmp_error_buf, ERROR_BUF_SZ,
618 "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
234967c9 619 fatal_dump(tmp_error_buf);
c4fb974e 620 }
621 }
622#elif defined(RLIMIT_OFILE)
623 if (getrlimit(RLIMIT_OFILE, &rl) < 0) {
a3d5953d 624 debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %s\n", xstrerror());
c4fb974e 625 } else {
e83892e9 626 rl.rlim_cur = Squid_MaxFD;
30a4f2a8 627 if (rl.rlim_cur > rl.rlim_max)
e83892e9 628 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
c4fb974e 629 if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
066031f8 630 snprintf(tmp_error_buf, ERROR_BUF_SZ,
56878878 631 "setrlimit: RLIMIT_OFILE: %s", xstrerror());
234967c9 632 fatal_dump(tmp_error_buf);
c4fb974e 633 }
634 }
635#endif
c4fb974e 636#else /* HAVE_SETRLIMIT */
a3d5953d 637 debug(21, 1) ("setMaxFD: Cannot increase: setrlimit() not supported on this system\n");
30a4f2a8 638#endif /* HAVE_SETRLIMIT */
639
640#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
641 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
a3d5953d 642 debug(50, 0) ("getrlimit: RLIMIT_DATA: %s\n", xstrerror());
88738790 643 } else if (rl.rlim_max > rl.rlim_cur) {
30a4f2a8 644 rl.rlim_cur = rl.rlim_max; /* set it to the max */
645 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
56878878 646 snprintf(tmp_error_buf, ERROR_BUF_SZ,
647 "setrlimit: RLIMIT_DATA: %s", xstrerror());
30a4f2a8 648 fatal_dump(tmp_error_buf);
649 }
650 }
651#endif /* RLIMIT_DATA */
ad7ef91a 652#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
653 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
a3d5953d 654 debug(50, 0) ("getrlimit: RLIMIT_VMEM: %s\n", xstrerror());
88738790 655 } else if (rl.rlim_max > rl.rlim_cur) {
ad7ef91a 656 rl.rlim_cur = rl.rlim_max; /* set it to the max */
657 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
56878878 658 snprintf(tmp_error_buf, ERROR_BUF_SZ,
659 "setrlimit: RLIMIT_VMEM: %s", xstrerror());
ad7ef91a 660 fatal_dump(tmp_error_buf);
661 }
662 }
663#endif /* RLIMIT_VMEM */
c4fb974e 664}
3a57089e 665
b8d8561b 666time_t
0673c0ba 667getCurrentTime(void)
3a57089e 668{
94e891ea 669#if GETTIMEOFDAY_NO_TZP
30a4f2a8 670 gettimeofday(&current_time);
671#else
d598947a 672 gettimeofday(&current_time, NULL);
5f3f8d0e 673#endif
52040193 674 current_dtime = (double) current_time.tv_sec +
675 (double) current_time.tv_usec / 1000000.0;
30a4f2a8 676 return squid_curtime = current_time.tv_sec;
5f3f8d0e 677}
fe113054 678
b8d8561b 679int
680percent(int a, int b)
30a4f2a8 681{
682 return b ? ((int) (100.0 * a / b + 0.5)) : 0;
683}
684
a7c05555 685double
f2908497 686dpercent(double a, double b)
687{
688 return b ? (100.0 * a / b) : 0.0;
689}
690
b8d8561b 691void
ea3a2a69 692squid_signal(int sig, SIGHDLR * func, int flags)
30a4f2a8 693{
694#if HAVE_SIGACTION
695 struct sigaction sa;
696 sa.sa_handler = func;
697 sa.sa_flags = flags;
698 sigemptyset(&sa.sa_mask);
699 if (sigaction(sig, &sa, NULL) < 0)
a3d5953d 700 debug(50, 0) ("sigaction: sig=%d func=%p: %s\n", sig, func, xstrerror());
30a4f2a8 701#else
88738790 702 signal(sig, func);
30a4f2a8 703#endif
704}
396c5745 705
16b204c4 706struct in_addr
0ee4272b 707inaddrFromHostent(const struct hostent *hp)
16b204c4 708{
cc6a9d2e 709 struct in_addr s;
3c0117c9 710 xmemcpy(&s.s_addr, hp->h_addr, sizeof(s.s_addr));
cc6a9d2e 711 return s;
16b204c4 712}
88738790 713
9e4ad609 714double
1d8e0d40 715doubleAverage(double cur, double new, int N, int max)
9e4ad609 716{
1d8e0d40 717 if (N > max)
718 N = max;
719 return (cur * (N - 1.0) + new) / N;
9e4ad609 720}
721
722int
723intAverage(int cur, int new, int n, int max)
724{
725 if (n > max)
726 n = max;
b14e03c0 727 return (cur * (n - 1) + new) / n;
9e4ad609 728}
70364f29 729
730void
731logsFlush(void)
732{
733 if (debug_log)
734 fflush(debug_log);
735 if (cache_useragent_log)
736 fflush(cache_useragent_log);
737}
88738790 738
739char *
740checkNullString(char *p)
741{
742 return p ? p : "(NULL)";
743}
2ac237e2 744
745void
746dlinkAdd(void *data, dlink_node * m, dlink_list * list)
747{
748 m->data = data;
749 m->prev = NULL;
750 m->next = list->head;
751 if (list->head)
752 list->head->prev = m;
753 list->head = m;
754 if (list->tail == NULL)
755 list->tail = m;
756}
757
b2329b6a 758void
759dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
760{
761 m->data = data;
762 m->next = NULL;
763 m->prev = list->tail;
764 if (list->tail)
765 list->tail->next = m;
766 list->tail = m;
767 if (list->head == NULL)
768 list->head = m;
769}
770
2ac237e2 771void
772dlinkDelete(dlink_node * m, dlink_list * list)
773{
774 if (m->next)
775 m->next->prev = m->prev;
776 if (m->prev)
777 m->prev->next = m->next;
778 if (m == list->head)
779 list->head = m->next;
780 if (m == list->tail)
781 list->tail = m->prev;
92b8c095 782 m->next = m->prev = NULL;
2ac237e2 783}
a7c05555 784
16300b58 785void
0e473d70 786kb_incr(kb_t * k, size_t v)
a7c05555 787{
0e473d70 788 k->bytes += v;
789 k->kb += (k->bytes >> 10);
790 k->bytes &= 0x3FF;
a7c05555 791}
c1dabf04 792
793void
399e85ea 794gb_flush(gb_t * g)
c1dabf04 795{
796 g->gb += (g->bytes >> 30);
399e85ea 797 g->bytes &= (1 << 30) - 1;
c1dabf04 798}
799
800double
399e85ea 801gb_to_double(const gb_t * g)
c1dabf04 802{
399e85ea 803 return ((double) g->gb) * ((double) (1 << 30)) + ((double) g->bytes);
c1dabf04 804}
805
806const char *
399e85ea 807gb_to_str(const gb_t * g)
c1dabf04 808{
809 /*
810 * it is often convenient to call gb_to_str several times for _one_ printf
811 */
399e85ea 812#define max_cc_calls 5
c1dabf04 813 typedef char GbBuf[32];
814 static GbBuf bufs[max_cc_calls];
815 static int call_id = 0;
816 double value = gb_to_double(g);
817 char *buf = bufs[call_id++];
1ecaa0a0 818 if (call_id >= max_cc_calls)
819 call_id = 0;
c1dabf04 820 /* select format */
821 if (value < 1e9)
399e85ea 822 snprintf(buf, sizeof(GbBuf), "%.2f MB", value / 1e6);
823 else if (value < 1e12)
824 snprintf(buf, sizeof(GbBuf), "%.2f GB", value / 1e9);
c1dabf04 825 else
399e85ea 826 snprintf(buf, sizeof(GbBuf), "%.2f TB", value / 1e12);
c1dabf04 827 return buf;
828}
a00a7c85 829
830void
6bbf9cc4 831debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
a00a7c85 832{
833 MemBuf mb;
834 Packer p;
6bbf9cc4 835 assert(label && obj && pm);
a00a7c85 836 memBufDefInit(&mb);
837 packerToMemInit(&p, &mb);
0cdcddb9 838 (*pm) (obj, &p);
6bbf9cc4 839 debug(section, level) ("%s%s", label, mb.buf);
a00a7c85 840 packerClean(&p);
841 memBufClean(&mb);
842}
d548ee64 843
844int
845stringHasWhitespace(const char *s)
846{
847 return (strcspn(s, w_space) != strlen(s));
848}
d03d26fb 849
850void
851linklistPush(link_list ** L, void *p)
852{
853 link_list *l = xmalloc(sizeof(*l));
854 l->next = NULL;
855 l->ptr = p;
856 while (*L)
857 L = &(*L)->next;
858 *L = l;
859}
860
861void *
862linklistShift(link_list ** L)
863{
864 void *p;
865 link_list *l;
866 if (NULL == *L)
867 return NULL;
868 l = *L;
869 p = l->ptr;
870 *L = (*L)->next;
871 xfree(l);
872 return p;
873}
1f38f50a 874
1f38f50a 875/*
876 * Same as rename(2) but complains if something goes wrong;
877 * the caller is responsible for handing and explaining the
878 * consequences of errors.
879 */
880int
881xrename(const char *from, const char *to)
882{
883 debug(21, 2) ("xrename: renaming %s to %s\n", from, to);
884 if (0 == rename(from, to))
885 return 0;
886 debug(21, errno == ENOENT ? 2 : 1) ("xrename: Cannot rename %s to %s: %s\n",
887 from, to, xstrerror());
888 return -1;
889}
9bc73deb 890
891int
892stringHasCntl(const char *s)
893{
894 unsigned char c;
895 while ((c = (unsigned char) *s++) != '\0') {
896 if (c <= 0x1f)
897 return 1;
898 if (c >= 0x7f && c <= 0x9f)
899 return 1;
900 }
901 return 0;
902}