]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tools.cc
test for struct rusage needs to include <sys/time.h
[thirdparty/squid.git] / src / tools.cc
CommitLineData
94e891ea 1
30a4f2a8 2/*
8505e57b 3 * $Id: tools.cc,v 1.139 1998/01/02 21:35:15 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/
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\
234967c9 115and report the trace back to squid-bugs@nlanr.net.\n\
090089c4 116\n\
117Thanks!\n"
118
f5b8bbc4 119static void fatal_common(const char *);
120static void mail_warranty(void);
121static void shutdownTimeoutHandler(int fd, void *data);
0a0bf5db 122#if USE_ASYNC_IO
f5b8bbc4 123static void safeunlinkComplete(void *data, int retcode, int errcode);
0a0bf5db 124#endif
24382924 125
429fdbec 126static void
127releaseServerSockets(void)
128{
812ed90c 129 int i;
429fdbec 130 /* Release the main ports as early as possible */
812ed90c 131 for (i = 0; i < NHttpSockets; i++) {
132 if (HttpSockets[i] >= 0)
88738790 133 close(HttpSockets[i]);
812ed90c 134 }
429fdbec 135 if (theInIcpConnection >= 0)
88738790 136 close(theInIcpConnection);
429fdbec 137 if (theOutIcpConnection >= 0 && theOutIcpConnection != theInIcpConnection)
88738790 138 close(theOutIcpConnection);
429fdbec 139}
140
b8d8561b 141static char *
0673c0ba 142dead_msg(void)
090089c4 143{
95d659f0 144 LOCAL_ARRAY(char, msg, 1024);
56878878 145 snprintf(msg, 1024, DEAD_MSG, version_string, version_string);
090089c4 146 return msg;
147}
148
24382924 149static void
0673c0ba 150mail_warranty(void)
090089c4 151{
019dd986 152 FILE *fp = NULL;
6e40f263 153 char *filename;
154 static char command[256];
155 if ((filename = tempnam(NULL, appname)) == NULL)
156 return;
157 if ((fp = fopen(filename, "w")) == NULL)
158 return;
159 fprintf(fp, "From: %s\n", appname);
edae7bc0 160 fprintf(fp, "To: %s\n", Config.adminEmail);
6e40f263 161 fprintf(fp, "Subject: %s\n", dead_msg());
162 fclose(fp);
56878878 163 snprintf(command, 256, "mail %s < %s", Config.adminEmail, filename);
6e40f263 164 system(command); /* XXX should avoid system(3) */
165 unlink(filename);
090089c4 166}
167
b8d8561b 168static void
43c3424b 169dumpMallocStats(void)
3f43b19b 170{
88738790 171#if HAVE_MSTATS && HAVE_GNUMALLOC_H
172 struct mstats ms = mstats();
173 fprintf(debug_log, "\ttotal space in arena: %6d KB\n",
a97cfa48 174 (int) (ms.bytes_total >> 10));
88738790 175 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
a97cfa48 176 (int) (ms.bytes_free >> 10),
88738790 177 percent(ms.bytes_free, ms.bytes_total));
178#elif HAVE_MALLINFO
3f43b19b 179 struct mallinfo mp;
30a4f2a8 180 int t;
3f43b19b 181 if (!do_mallinfo)
182 return;
3f43b19b 183 mp = mallinfo();
9e4ad609 184 fprintf(debug_log, "Memory usage for %s via mallinfo():\n", appname);
185 fprintf(debug_log, "\ttotal space in arena: %6d KB\n",
30a4f2a8 186 mp.arena >> 10);
9e4ad609 187 fprintf(debug_log, "\tOrdinary blocks: %6d KB %6d blks\n",
30a4f2a8 188 mp.uordblks >> 10, mp.ordblks);
9e4ad609 189 fprintf(debug_log, "\tSmall blocks: %6d KB %6d blks\n",
30a4f2a8 190 mp.usmblks >> 10, mp.smblks);
9e4ad609 191 fprintf(debug_log, "\tHolding blocks: %6d KB %6d blks\n",
30a4f2a8 192 mp.hblkhd >> 10, mp.hblks);
9e4ad609 193 fprintf(debug_log, "\tFree Small blocks: %6d KB\n",
30a4f2a8 194 mp.fsmblks >> 10);
9e4ad609 195 fprintf(debug_log, "\tFree Ordinary blocks: %6d KB\n",
30a4f2a8 196 mp.fordblks >> 10);
197 t = mp.uordblks + mp.usmblks + mp.hblkhd;
9e4ad609 198 fprintf(debug_log, "\tTotal in use: %6d KB %d%%\n",
30a4f2a8 199 t >> 10, percent(t, mp.arena));
200 t = mp.fsmblks + mp.fordblks;
9e4ad609 201 fprintf(debug_log, "\tTotal free: %6d KB %d%%\n",
30a4f2a8 202 t >> 10, percent(t, mp.arena));
46c883ed 203#if HAVE_EXT_MALLINFO
9e4ad609 204 fprintf(debug_log, "\tmax size of small blocks:\t%d\n",
30a4f2a8 205 mp.mxfast);
9e4ad609 206 fprintf(debug_log, "\tnumber of small blocks in a holding block:\t%d\n",
3f43b19b 207 mp.nlblks);
9e4ad609 208 fprintf(debug_log, "\tsmall block rounding factor:\t%d\n",
30a4f2a8 209 mp.grain);
9e4ad609 210 fprintf(debug_log, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
3f43b19b 211 mp.uordbytes);
9e4ad609 212 fprintf(debug_log, "\tnumber of ordinary blocks allocated:\t%d\n",
3f43b19b 213 mp.allocated);
9e4ad609 214 fprintf(debug_log, "\tbytes used in maintaining the free tree:\t%d\n",
3f43b19b 215 mp.treeoverhead);
46c883ed 216#endif /* HAVE_EXT_MALLINFO */
3f43b19b 217#endif /* HAVE_MALLINFO */
218}
30a4f2a8 219
f2908497 220void
221squid_getrusage(struct rusage *r)
f0f81709 222{
8da94b66 223 memset(r, '\0', sizeof(struct rusage));
30a4f2a8 224#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
cd19f0b6 225#ifdef _SQUID_SOLARIS_
226 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
227 enter_suid();
228#endif
f2908497 229 getrusage(RUSAGE_SELF, r);
cd19f0b6 230#ifdef _SQUID_SOLARIS_
231 leave_suid();
232#endif
56983a01 233#endif
f2908497 234}
235
236double
237rusage_cputime(struct rusage *r)
238{
239 return (double) r->ru_stime.tv_sec +
240 (double) r->ru_utime.tv_sec +
241 (double) r->ru_stime.tv_usec / 1000000.0 +
242 (double) r->ru_utime.tv_usec / 1000000.0;
243}
244
245int
246rusage_maxrss(struct rusage *r)
247{
248#if defined(_SQUID_SGI_)
249 return r->ru_maxrss;
250#elif defined(_SQUID_OSF_)
251 return r->ru_maxrss;
252#elif defined(BSD4_4)
253 return r->ru_maxrss;
8505e57b 254#elif HAVE_GETPAGESIZE
f2908497 255 return (r->ru_maxrss * getpagesize()) >> 10;
8505e57b 256#else
257 return r->ru_maxrss;
f2908497 258#endif
259}
260
261int
262rusage_pagefaults(struct rusage *r)
263{
264 return r->ru_majflt;
265}
266
267
268static void
269PrintRusage(void)
270{
271 struct rusage rusage;
272 squid_getrusage(&rusage);
273 fprintf(debug_log, "CPU Usage: %.3f seconds\n", rusage_cputime(&rusage));
274 fprintf(debug_log, "Maximum Resident Size: %d KB\n",
275 rusage_maxrss(&rusage));
276 fprintf(debug_log, "Page faults with physical i/o: %d\n",
277 rusage_pagefaults(&rusage));
f0f81709 278}
279
03d7b07f 280
b8d8561b 281void
282death(int sig)
44a47c6e 283{
0e08ce4b 284 if (sig == SIGSEGV)
2c47cf74 285 fprintf(debug_log, "FATAL: Received Segment Violation...dying.\n");
0e08ce4b 286 else if (sig == SIGBUS)
6e40f263 287 fprintf(debug_log, "FATAL: Received Bus Error...dying.\n");
0e08ce4b 288 else
2c47cf74 289 fprintf(debug_log, "FATAL: Received signal %d...dying.\n", sig);
0b4639af 290
291#ifdef PRINT_STACK_TRACE
292#ifdef _SQUID_HPUX_
293 {
4f07153c 294 extern void U_STACK_TRACE(void); /* link with -lcl */
0b4639af 295 fflush(debug_log);
296 dup2(fileno(debug_log), 2);
297 U_STACK_TRACE();
298 }
299#endif /* _SQUID_HPUX_ */
300#ifdef _SQUID_SOLARIS_
4f07153c 301 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
302 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
0b4639af 303 fflush(debug_log);
304 dup2(fileno(debug_log), fileno(stdout));
305 opcom_stack_trace();
306 fflush(stdout);
307 }
308#endif /* _SQUID_SOLARIS_ */
309#endif /* PRINT_STACK_TRACE */
310
6e40f263 311#if SA_RESETHAND == 0
44a47c6e 312 signal(SIGSEGV, SIG_DFL);
313 signal(SIGBUS, SIG_DFL);
0e08ce4b 314 signal(sig, SIG_DFL);
30a4f2a8 315#endif
429fdbec 316 releaseServerSockets();
e102ebda 317 storeWriteCleanLogs(0);
9e4ad609 318 PrintRusage();
319 dumpMallocStats();
6e40f263 320 if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
321 /* skip if more than 10 days old */
edae7bc0 322 if (Config.adminEmail)
6e40f263 323 mail_warranty();
324 else
325 puts(dead_msg());
326 }
44a47c6e 327 abort();
328}
329
330
b8d8561b 331void
23d92c64 332sigusr2_handle(int sig)
090089c4 333{
30a4f2a8 334 static int state = 0;
545f551a 335 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
30a4f2a8 336 if (state == 0) {
b6f794d6 337 _db_init(Config.Log.log, "ALL,10");
30a4f2a8 338 state = 1;
339 } else {
b6f794d6 340 _db_init(Config.Log.log, Config.debugOptions);
30a4f2a8 341 state = 0;
342 }
343#if !HAVE_SIGACTION
344 signal(sig, sigusr2_handle); /* reinstall */
090089c4 345#endif
346}
347
5c5783a2 348static void
79d39a72 349shutdownTimeoutHandler(int fd, void *datanotused)
5c5783a2 350{
a3d5953d 351 debug(21, 1) ("Forcing close of FD %d\n", fd);
5c5783a2 352 comm_close(fd);
353}
354
b8d8561b 355void
5c5783a2 356setSocketShutdownLifetimes(int to)
30a4f2a8 357{
f1dc9b30 358 fde *f = NULL;
30a4f2a8 359 int i;
429fdbec 360 for (i = Biggest_FD; i >= 0; i--) {
4f92c80c 361 f = &fd_table[i];
362 if (!f->read_handler && !f->write_handler)
363 continue;
364 if (f->type != FD_SOCKET)
365 continue;
366 if (f->timeout > 0 && (int) (f->timeout - squid_curtime) <= to)
367 continue;
368 commSetTimeout(i,
369 to,
370 f->timeout_handler ? f->timeout_handler : shutdownTimeoutHandler,
371 f->timeout_data);
30a4f2a8 372 }
373}
374
b8d8561b 375void
0673c0ba 376normal_shutdown(void)
4d64d74a 377{
a3d5953d 378 debug(21, 1) ("Shutting down...\n");
0b4639af 379 if (Config.pidFilename && strcmp(Config.pidFilename, "none")) {
30a4f2a8 380 enter_suid();
b6f794d6 381 safeunlink(Config.pidFilename, 0);
30a4f2a8 382 leave_suid();
234967c9 383 }
429fdbec 384 releaseServerSockets();
385 unlinkdClose();
e102ebda 386 storeWriteCleanLogs(0);
9e4ad609 387 PrintRusage();
388 dumpMallocStats();
457bedbd 389 storeCloseLog();
a4394ebd 390 accessLogClose();
100fc710 391#if PURIFY
0a21bd84 392 configFreeMemory();
0a21bd84 393 storeFreeMemory();
0a21bd84 394 dnsFreeMemory();
395 redirectFreeMemory();
0a21bd84 396 stmemFreeMemory();
e5f6c5c2 397 netdbFreeMemory();
56e15c50 398 ipcacheFreeMemory();
399 fqdncacheFreeMemory();
f899fac1 400 asnFreeMemory();
100fc710 401#endif
9e4ad609 402 file_close(0);
403 file_close(1);
404 file_close(2);
405 fdDumpOpen();
406 fdFreeMemory();
a3d5953d 407 debug(21, 0) ("Squid Cache (Version %s): Exiting normally.\n",
0a21bd84 408 version_string);
c7433536 409 fclose(debug_log);
4d64d74a 410 exit(0);
411}
147d3115 412
24382924 413static void
0ee4272b 414fatal_common(const char *message)
090089c4 415{
db40ae20 416#if HAVE_SYSLOG
6e40f263 417 if (opt_syslog_enable)
233794cd 418 syslog(LOG_ALERT, "%s", message);
db40ae20 419#endif
2c47cf74 420 fprintf(debug_log, "FATAL: %s\n", message);
9e975e4e 421 if (opt_debug_stderr && debug_log != stderr)
a47b9029 422 fprintf(stderr, "FATAL: %s\n", message);
c5c666ab 423 fprintf(debug_log, "Squid Cache (Version %s): Terminated abnormally.\n",
8213067d 424 version_string);
2c47cf74 425 fflush(debug_log);
9e4ad609 426 PrintRusage();
427 dumpMallocStats();
090089c4 428}
429
430/* fatal */
b8d8561b 431void
0ee4272b 432fatal(const char *message)
090089c4 433{
429fdbec 434 releaseServerSockets();
d399be0e 435 /* check for store_rebuilding flag because fatal() is often
436 * used in early initialization phases, long before we ever
437 * get to the store log. */
438 if (!store_rebuilding)
e102ebda 439 storeWriteCleanLogs(0);
090089c4 440 fatal_common(message);
441 exit(1);
442}
443
444/* fatal with dumping core */
b8d8561b 445void
0ee4272b 446fatal_dump(const char *message)
090089c4 447{
429fdbec 448 releaseServerSockets();
090089c4 449 if (message)
450 fatal_common(message);
4a69c163 451 if (opt_catch_signals)
e102ebda 452 storeWriteCleanLogs(0);
090089c4 453 abort();
454}
455
b8d8561b 456void
a3d5953d 457debug_trap(const char *message)
85b701ed 458{
4a69c163 459 if (!opt_catch_signals)
85b701ed 460 fatal_dump(message);
a3d5953d 461 _db_print("WARNING: %s\n", message);
85b701ed 462}
463
b8d8561b 464void
23d92c64 465sig_child(int sig)
090089c4 466{
30a4f2a8 467#ifdef _SQUID_NEXT_
468 union wait status;
469#else
090089c4 470 int status;
090089c4 471#endif
ff8d0ea6 472 pid_t pid;
090089c4 473
30a4f2a8 474 do {
475#ifdef _SQUID_NEXT_
476 pid = wait3(&status, WNOHANG, NULL);
090089c4 477#else
30a4f2a8 478 pid = waitpid(-1, &status, WNOHANG);
090089c4 479#endif
97a88399 480 /* no debug() here; bad things happen if the signal is delivered during _db_print() */
30a4f2a8 481#if HAVE_SIGACTION
482 } while (pid > 0);
234967c9 483#else
30a4f2a8 484 } while (pid > 0 || (pid < 0 && errno == EINTR));
485 signal(sig, sig_child);
234967c9 486#endif
30a4f2a8 487}
44a47c6e 488
0ee4272b 489const char *
0673c0ba 490getMyHostname(void)
44a47c6e 491{
95d659f0 492 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
44a47c6e 493 static int present = 0;
0ee4272b 494 const struct hostent *h = NULL;
019dd986 495 char *t = NULL;
496
79d39a72 497 if ((t = Config.visibleHostname) != NULL)
019dd986 498 return t;
44a47c6e 499
500 /* Get the host name and store it in host to return */
501 if (!present) {
502 host[0] = '\0';
503 if (gethostname(host, SQUIDHOSTNAMELEN) == -1) {
a3d5953d 504 debug(50, 1) ("getMyHostname: gethostname failed: %s\n",
44a47c6e 505 xstrerror());
506 return NULL;
507 } else {
e5f6c5c2 508 if ((h = gethostbyname(host)) != NULL) {
44a47c6e 509 /* DNS lookup successful */
510 /* use the official name from DNS lookup */
511 strcpy(host, h->h_name);
512 }
513 present = 1;
514 }
515 }
516 return host;
517}
518
0a0bf5db 519void
0ee4272b 520safeunlink(const char *s, int quiet)
44a47c6e 521{
0a0bf5db 522#if USE_ASYNC_IO
523 aioUnlink(s,
524 quiet ? NULL : safeunlinkComplete,
525 quiet ? NULL : xstrdup(s));
526#else
527 if (unlink(s) < 0 && !quiet)
a3d5953d 528 debug(50, 1) ("safeunlink: Couldn't delete %s: %s\n", s, xstrerror());
0a0bf5db 529#endif
530}
531
532#if USE_ASYNC_IO
533static void
534safeunlinkComplete(void *data, int retcode, int errcode)
535{
536 char *s = data;
537 if (retcode < 0) {
538 errno = errcode;
a3d5953d 539 debug(50, 1) ("safeunlink: Couldn't delete %s. %s\n", s, xstrerror());
0a0bf5db 540 errno = 0;
541 }
542 xfree(s);
44a47c6e 543}
0a0bf5db 544#endif
12b9e9b1 545
30a4f2a8 546/* leave a privilegied section. (Give up any privilegies)
547 * Routines that need privilegies can rap themselves in enter_suid()
548 * and leave_suid()
549 * To give upp all posibilites to gain privilegies use no_suid()
12b9e9b1 550 */
b8d8561b 551void
0673c0ba 552leave_suid(void)
12b9e9b1 553{
554 struct passwd *pwd = NULL;
555 struct group *grp = NULL;
a3d5953d 556 debug(21, 3) ("leave_suid: PID %d called\n", getpid());
12b9e9b1 557 if (geteuid() != 0)
558 return;
559 /* Started as a root, check suid option */
b6f794d6 560 if (Config.effectiveUser == NULL)
12b9e9b1 561 return;
b6f794d6 562 if ((pwd = getpwnam(Config.effectiveUser)) == NULL)
12b9e9b1 563 return;
b6f794d6 564 if (Config.effectiveGroup && (grp = getgrnam(Config.effectiveGroup))) {
429fdbec 565 if (setgid(grp->gr_gid) < 0)
a3d5953d 566 debug(50, 1) ("leave_suid: setgid: %s\n", xstrerror());
12b9e9b1 567 } else {
429fdbec 568 if (setgid(pwd->pw_gid) < 0)
a3d5953d 569 debug(50, 1) ("leave_suid: setgid: %s\n", xstrerror());
12b9e9b1 570 }
a3d5953d 571 debug(21, 3) ("leave_suid: PID %d giving up root, becoming '%s'\n",
30a4f2a8 572 getpid(), pwd->pw_name);
234967c9 573#if HAVE_SETRESUID
429fdbec 574 if (setresuid(pwd->pw_uid, pwd->pw_uid, 0) < 0)
a3d5953d 575 debug(50, 1) ("leave_suid: setresuid: %s\n", xstrerror());
234967c9 576#elif HAVE_SETEUID
429fdbec 577 if (seteuid(pwd->pw_uid) < 0)
a3d5953d 578 debug(50, 1) ("leave_suid: seteuid: %s\n", xstrerror());
234967c9 579#else
429fdbec 580 if (setuid(pwd->pw_uid) < 0)
a3d5953d 581 debug(50, 1) ("leave_suid: setuid: %s\n", xstrerror());
234967c9 582#endif
583}
584
30a4f2a8 585/* Enter a privilegied section */
b8d8561b 586void
0673c0ba 587enter_suid(void)
234967c9 588{
a3d5953d 589 debug(21, 3) ("enter_suid: PID %d taking root priveleges\n", getpid());
234967c9 590#if HAVE_SETRESUID
591 setresuid(-1, 0, -1);
592#else
593 setuid(0);
594#endif
595}
596
30a4f2a8 597/* Give up the posibility to gain privilegies.
598 * this should be used before starting a sub process
599 */
b8d8561b 600void
0673c0ba 601no_suid(void)
234967c9 602{
603 uid_t uid;
30a4f2a8 604 leave_suid();
234967c9 605 uid = geteuid();
a3d5953d 606 debug(21, 3) ("leave_suid: PID %d giving up root priveleges forever\n", getpid());
234967c9 607#if HAVE_SETRESUID
429fdbec 608 if (setresuid(uid, uid, uid) < 0)
a3d5953d 609 debug(50, 1) ("no_suid: setresuid: %s\n", xstrerror());
234967c9 610#else
611 setuid(0);
429fdbec 612 if (setuid(uid) < 0)
a3d5953d 613 debug(50, 1) ("no_suid: setuid: %s\n", xstrerror());
234967c9 614#endif
12b9e9b1 615}
ccff9601 616
b8d8561b 617void
0673c0ba 618writePidFile(void)
ccff9601 619{
9e4ad609 620 int fd;
0b4639af 621 const char *f = NULL;
973e9fe1 622 mode_t old_umask;
9e4ad609 623 char buf[32];
624 if ((f = Config.pidFilename) == NULL)
625 return;
626 if (!strcmp(Config.pidFilename, "none"))
ccff9601 627 return;
30a4f2a8 628 enter_suid();
973e9fe1 629 old_umask = umask(022);
9e4ad609 630 fd = file_open(f, O_WRONLY | O_CREAT | O_TRUNC, NULL, NULL);
973e9fe1 631 umask(old_umask);
30a4f2a8 632 leave_suid();
9e4ad609 633 if (fd < 0) {
a3d5953d 634 debug(50, 0) ("%s: %s\n", f, xstrerror());
9e4ad609 635 debug_trap("Could not write pid file");
636 return;
ccff9601 637 }
56878878 638 snprintf(buf, 32, "%d\n", (int) getpid());
9e4ad609 639 write(fd, buf, strlen(buf));
640 file_close(fd);
ccff9601 641}
c4fb974e 642
643
ff8d0ea6 644pid_t
0673c0ba 645readPidFile(void)
7690e8eb 646{
647 FILE *pid_fp = NULL;
9e4ad609 648 const char *f = Config.pidFilename;
ff8d0ea6 649 pid_t pid = -1;
650 int i;
7690e8eb 651
9e4ad609 652 if (f == NULL || !strcmp(Config.pidFilename, "none")) {
7690e8eb 653 fprintf(stderr, "%s: ERROR: No pid file name defined\n", appname);
654 exit(1);
655 }
656 pid_fp = fopen(f, "r");
657 if (pid_fp != NULL) {
ff8d0ea6 658 pid = 0;
659 if (fscanf(pid_fp, "%d", &i) == 1)
660 pid = (pid_t) i;
7690e8eb 661 fclose(pid_fp);
662 } else {
663 if (errno != ENOENT) {
664 fprintf(stderr, "%s: ERROR: Could not read pid file\n", appname);
665 fprintf(stderr, "\t%s: %s\n", f, xstrerror());
666 exit(1);
667 }
668 }
669 return pid;
670}
671
672
b8d8561b 673void
0673c0ba 674setMaxFD(void)
c4fb974e 675{
234967c9 676#if HAVE_SETRLIMIT
c4fb974e 677 /* try to use as many file descriptors as possible */
678 /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
679 struct rlimit rl;
680#if defined(RLIMIT_NOFILE)
681 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
a3d5953d 682 debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %s\n", xstrerror());
c4fb974e 683 } else {
e83892e9 684 rl.rlim_cur = Squid_MaxFD;
30a4f2a8 685 if (rl.rlim_cur > rl.rlim_max)
e83892e9 686 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
c4fb974e 687 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
56878878 688 snprintf(tmp_error_buf, ERROR_BUF_SZ,
689 "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
234967c9 690 fatal_dump(tmp_error_buf);
c4fb974e 691 }
692 }
693#elif defined(RLIMIT_OFILE)
694 if (getrlimit(RLIMIT_OFILE, &rl) < 0) {
a3d5953d 695 debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %s\n", xstrerror());
c4fb974e 696 } else {
e83892e9 697 rl.rlim_cur = Squid_MaxFD;
30a4f2a8 698 if (rl.rlim_cur > rl.rlim_max)
e83892e9 699 Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
c4fb974e 700 if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
56878878 701 snprintf(tmp_error_buf, ERROR_BUF_SZ,
702 "setrlimit: RLIMIT_OFILE: %s", xstrerror());
234967c9 703 fatal_dump(tmp_error_buf);
c4fb974e 704 }
705 }
706#endif
c4fb974e 707#else /* HAVE_SETRLIMIT */
a3d5953d 708 debug(21, 1) ("setMaxFD: Cannot increase: setrlimit() not supported on this system\n");
30a4f2a8 709#endif /* HAVE_SETRLIMIT */
710
711#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
712 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
a3d5953d 713 debug(50, 0) ("getrlimit: RLIMIT_DATA: %s\n", xstrerror());
88738790 714 } else if (rl.rlim_max > rl.rlim_cur) {
30a4f2a8 715 rl.rlim_cur = rl.rlim_max; /* set it to the max */
716 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
56878878 717 snprintf(tmp_error_buf, ERROR_BUF_SZ,
718 "setrlimit: RLIMIT_DATA: %s", xstrerror());
30a4f2a8 719 fatal_dump(tmp_error_buf);
720 }
721 }
722#endif /* RLIMIT_DATA */
ad7ef91a 723#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
724 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
a3d5953d 725 debug(50, 0) ("getrlimit: RLIMIT_VMEM: %s\n", xstrerror());
88738790 726 } else if (rl.rlim_max > rl.rlim_cur) {
ad7ef91a 727 rl.rlim_cur = rl.rlim_max; /* set it to the max */
728 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
56878878 729 snprintf(tmp_error_buf, ERROR_BUF_SZ,
730 "setrlimit: RLIMIT_VMEM: %s", xstrerror());
ad7ef91a 731 fatal_dump(tmp_error_buf);
732 }
733 }
734#endif /* RLIMIT_VMEM */
c4fb974e 735}
3a57089e 736
b8d8561b 737time_t
0673c0ba 738getCurrentTime(void)
3a57089e 739{
94e891ea 740#if GETTIMEOFDAY_NO_TZP
30a4f2a8 741 gettimeofday(&current_time);
742#else
d598947a 743 gettimeofday(&current_time, NULL);
5f3f8d0e 744#endif
30a4f2a8 745 return squid_curtime = current_time.tv_sec;
5f3f8d0e 746}
fe113054 747
b8d8561b 748int
749percent(int a, int b)
30a4f2a8 750{
751 return b ? ((int) (100.0 * a / b + 0.5)) : 0;
752}
753
f2908497 754int
755dpercent(double a, double b)
756{
757 return b ? (100.0 * a / b) : 0.0;
758}
759
b8d8561b 760void
ea3a2a69 761squid_signal(int sig, SIGHDLR * func, int flags)
30a4f2a8 762{
763#if HAVE_SIGACTION
764 struct sigaction sa;
765 sa.sa_handler = func;
766 sa.sa_flags = flags;
767 sigemptyset(&sa.sa_mask);
768 if (sigaction(sig, &sa, NULL) < 0)
a3d5953d 769 debug(50, 0) ("sigaction: sig=%d func=%p: %s\n", sig, func, xstrerror());
30a4f2a8 770#else
88738790 771 signal(sig, func);
30a4f2a8 772#endif
773}
396c5745 774
16b204c4 775struct in_addr
0ee4272b 776inaddrFromHostent(const struct hostent *hp)
16b204c4 777{
cc6a9d2e 778 struct in_addr s;
3c0117c9 779 xmemcpy(&s.s_addr, hp->h_addr, sizeof(s.s_addr));
cc6a9d2e 780 return s;
16b204c4 781}
88738790 782
9e4ad609 783double
1d8e0d40 784doubleAverage(double cur, double new, int N, int max)
9e4ad609 785{
1d8e0d40 786 if (N > max)
787 N = max;
788 return (cur * (N - 1.0) + new) / N;
9e4ad609 789}
790
791int
792intAverage(int cur, int new, int n, int max)
793{
794 if (n > max)
795 n = max;
796 return (cur * (n - 1)) + new / n;
797}
70364f29 798
799void
800logsFlush(void)
801{
802 if (debug_log)
803 fflush(debug_log);
804 if (cache_useragent_log)
805 fflush(cache_useragent_log);
806}
88738790 807
808char *
809checkNullString(char *p)
810{
811 return p ? p : "(NULL)";
812}
2ac237e2 813
814void
815dlinkAdd(void *data, dlink_node * m, dlink_list * list)
816{
817 m->data = data;
818 m->prev = NULL;
819 m->next = list->head;
820 if (list->head)
821 list->head->prev = m;
822 list->head = m;
823 if (list->tail == NULL)
824 list->tail = m;
825}
826
827void
828dlinkDelete(dlink_node * m, dlink_list * list)
829{
830 if (m->next)
831 m->next->prev = m->prev;
832 if (m->prev)
833 m->prev->next = m->next;
834 if (m == list->head)
835 list->head = m->next;
836 if (m == list->tail)
837 list->tail = m->prev;
838}