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