]> git.ipfire.org Git - thirdparty/squid.git/blame - src/tools.cc
parse deny_info
[thirdparty/squid.git] / src / tools.cc
CommitLineData
94e891ea 1
30a4f2a8 2/*
a8f7d3ee 3 * $Id: tools.cc,v 1.51 1996/08/30 23:23:36 wessels Exp $
30a4f2a8 4 *
5 * DEBUG: section 21 Misc Functions
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Internet Object Cache http://www.nlanr.net/Squid/
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 109int do_mallinfo = 0; /* don't do mallinfo() unless this gets set */
b8de7ebe 110time_t squid_curtime;
3a57089e 111struct timeval current_time;
090089c4 112
090089c4 113#define DEAD_MSG "\
c5c666ab 114The Squid Cache (version %s) died.\n\
090089c4 115\n\
c5c666ab 116You've encountered a fatal error in the Squid Cache version %s.\n\
090089c4 117If a core file was created (possibly in the swap directory),\n\
b8de7ebe 118please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
234967c9 119and report the trace back to squid-bugs@nlanr.net.\n\
090089c4 120\n\
121Thanks!\n"
122
123static char *dead_msg()
124{
95d659f0 125 LOCAL_ARRAY(char, msg, 1024);
8213067d 126 sprintf(msg, DEAD_MSG, version_string, version_string);
090089c4 127 return msg;
128}
129
130void mail_warranty()
131{
019dd986 132 FILE *fp = NULL;
6e40f263 133 char *filename;
134 static char command[256];
135 if ((filename = tempnam(NULL, appname)) == NULL)
136 return;
137 if ((fp = fopen(filename, "w")) == NULL)
138 return;
139 fprintf(fp, "From: %s\n", appname);
edae7bc0 140 fprintf(fp, "To: %s\n", Config.adminEmail);
6e40f263 141 fprintf(fp, "Subject: %s\n", dead_msg());
142 fclose(fp);
edae7bc0 143 sprintf(command, "mail %s < %s", Config.adminEmail, filename);
6e40f263 144 system(command); /* XXX should avoid system(3) */
145 unlink(filename);
090089c4 146}
147
3f43b19b 148static void dumpMallocStats(f)
149 FILE *f;
150{
151#if HAVE_MALLINFO
152 struct mallinfo mp;
30a4f2a8 153 int t;
3f43b19b 154 if (!do_mallinfo)
155 return;
3f43b19b 156 mp = mallinfo();
30a4f2a8 157 fprintf(f, "Memory usage for %s via mallinfo():\n", appname);
158 fprintf(f, "\ttotal space in arena: %6d KB\n",
159 mp.arena >> 10);
160 fprintf(f, "\tOrdinary blocks: %6d KB %6d blks\n",
161 mp.uordblks >> 10, mp.ordblks);
162 fprintf(f, "\tSmall blocks: %6d KB %6d blks\n",
163 mp.usmblks >> 10, mp.smblks);
164 fprintf(f, "\tHolding blocks: %6d KB %6d blks\n",
165 mp.hblkhd >> 10, mp.hblks);
166 fprintf(f, "\tFree Small blocks: %6d KB\n",
167 mp.fsmblks >> 10);
168 fprintf(f, "\tFree Ordinary blocks: %6d KB\n",
169 mp.fordblks >> 10);
170 t = mp.uordblks + mp.usmblks + mp.hblkhd;
171 fprintf(f, "\tTotal in use: %6d KB %d%%\n",
172 t >> 10, percent(t, mp.arena));
173 t = mp.fsmblks + mp.fordblks;
174 fprintf(f, "\tTotal free: %6d KB %d%%\n",
175 t >> 10, percent(t, mp.arena));
176#ifdef WE_DONT_USE_KEEP
177 fprintf(f, "\tKeep option: %6d KB\n",
178 mp.keepcost >> 10);
179#endif
46c883ed 180#if HAVE_EXT_MALLINFO
30a4f2a8 181 fprintf(f, "\tmax size of small blocks:\t%d\n",
182 mp.mxfast);
183 fprintf(f, "\tnumber of small blocks in a holding block:\t%d\n",
3f43b19b 184 mp.nlblks);
30a4f2a8 185 fprintf(f, "\tsmall block rounding factor:\t%d\n",
186 mp.grain);
187 fprintf(f, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
3f43b19b 188 mp.uordbytes);
30a4f2a8 189 fprintf(f, "\tnumber of ordinary blocks allocated:\t%d\n",
3f43b19b 190 mp.allocated);
30a4f2a8 191 fprintf(f, "\tbytes used in maintaining the free tree:\t%d\n",
3f43b19b 192 mp.treeoverhead);
46c883ed 193#endif /* HAVE_EXT_MALLINFO */
3f43b19b 194#if PRINT_MMAP
195 mallocmap();
196#endif /* PRINT_MMAP */
197#endif /* HAVE_MALLINFO */
198}
30a4f2a8 199
3f43b19b 200static int PrintRusage(f, lf)
f0f81709 201 void (*f) ();
202 FILE *lf;
203{
30a4f2a8 204#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
f0f81709 205 struct rusage rusage;
206 getrusage(RUSAGE_SELF, &rusage);
30a4f2a8 207 fprintf(lf, "CPU Usage: user %d sys %d\n",
208 (int) rusage.ru_utime.tv_sec, (int) rusage.ru_stime.tv_sec);
209 fprintf(lf, "Memory Usage: rss %ld KB\n",
210 rusage.ru_maxrss * getpagesize() >> 10);
211 fprintf(lf, "Page faults with physical i/o: %ld\n",
f0f81709 212 rusage.ru_majflt);
213#endif
214 dumpMallocStats(lf);
215 if (f)
216 f(0);
217 return 0;
218}
219
0e08ce4b 220void death(sig)
12b9e9b1 221 int sig;
44a47c6e 222{
0e08ce4b 223 if (sig == SIGSEGV)
2c47cf74 224 fprintf(debug_log, "FATAL: Received Segment Violation...dying.\n");
0e08ce4b 225 else if (sig == SIGBUS)
6e40f263 226 fprintf(debug_log, "FATAL: Received Bus Error...dying.\n");
0e08ce4b 227 else
2c47cf74 228 fprintf(debug_log, "FATAL: Received signal %d...dying.\n", sig);
6e40f263 229#if SA_RESETHAND == 0
44a47c6e 230 signal(SIGSEGV, SIG_DFL);
231 signal(SIGBUS, SIG_DFL);
0e08ce4b 232 signal(sig, SIG_DFL);
30a4f2a8 233#endif
44a47c6e 234 storeWriteCleanLog();
2c47cf74 235 PrintRusage(NULL, debug_log);
6e40f263 236 if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
237 /* skip if more than 10 days old */
edae7bc0 238 if (Config.adminEmail)
6e40f263 239 mail_warranty();
240 else
241 puts(dead_msg());
242 }
44a47c6e 243 abort();
244}
245
246
30a4f2a8 247void sigusr2_handle(sig)
090089c4 248 int sig;
249{
30a4f2a8 250 static int state = 0;
251 debug(21, 1, "sigusr2_handle: SIGUSR2 received.\n");
252 if (state == 0) {
b6f794d6 253 _db_init(Config.Log.log, "ALL,10");
30a4f2a8 254 state = 1;
255 } else {
b6f794d6 256 _db_init(Config.Log.log, Config.debugOptions);
30a4f2a8 257 state = 0;
258 }
259#if !HAVE_SIGACTION
260 signal(sig, sigusr2_handle); /* reinstall */
090089c4 261#endif
262}
263
30a4f2a8 264void setSocketShutdownLifetimes()
265{
266 FD_ENTRY *f = NULL;
b6f794d6 267 int lft = Config.lifetimeShutdown;
30a4f2a8 268 int cur;
269 int i;
270 for (i = fdstat_biggest_fd(); i >= 0; i--) {
271 f = &fd_table[i];
272 if (!f->read_handler && !f->write_handler && !f->except_handler)
273 continue;
274 if (fdstatGetType(i) != FD_SOCKET)
275 continue;
276 cur = comm_get_fd_lifetime(i);
277 if (cur > 0 && (cur - squid_curtime) <= lft)
278 continue;
279 comm_set_fd_lifetime(i, lft);
280 }
281}
282
4d64d74a 283void normal_shutdown()
284{
285 debug(21, 1, "Shutting down...\n");
b6f794d6 286 if (Config.pidFilename) {
30a4f2a8 287 enter_suid();
b6f794d6 288 safeunlink(Config.pidFilename, 0);
30a4f2a8 289 leave_suid();
234967c9 290 }
4d64d74a 291 storeWriteCleanLog();
292 PrintRusage(NULL, debug_log);
c5c666ab 293 debug(21, 0, "Squid Cache (Version %s): Exiting normally.\n",
8213067d 294 version_string);
457bedbd 295 storeCloseLog();
296 statCloseLog();
297 fclose(debug_log);
4d64d74a 298 exit(0);
299}
147d3115 300
090089c4 301void fatal_common(message)
302 char *message;
303{
db40ae20 304#if HAVE_SYSLOG
6e40f263 305 if (opt_syslog_enable)
090089c4 306 syslog(LOG_ALERT, message);
db40ae20 307#endif
2c47cf74 308 fprintf(debug_log, "FATAL: %s\n", message);
c5c666ab 309 fprintf(debug_log, "Squid Cache (Version %s): Terminated abnormally.\n",
8213067d 310 version_string);
2c47cf74 311 fflush(debug_log);
312 PrintRusage(NULL, debug_log);
090089c4 313}
314
315/* fatal */
316void fatal(message)
317 char *message;
318{
319 fatal_common(message);
320 exit(1);
321}
322
323/* fatal with dumping core */
324void fatal_dump(message)
325 char *message;
326{
327 if (message)
328 fatal_common(message);
1758c627 329 if (opt_catch_signals)
090089c4 330 storeWriteCleanLog();
331 abort();
332}
333
090089c4 334void sig_child(sig)
335 int sig;
336{
30a4f2a8 337#ifdef _SQUID_NEXT_
338 union wait status;
339#else
090089c4 340 int status;
090089c4 341#endif
30a4f2a8 342 int pid;
090089c4 343
30a4f2a8 344 do {
345#ifdef _SQUID_NEXT_
346 pid = wait3(&status, WNOHANG, NULL);
090089c4 347#else
30a4f2a8 348 pid = waitpid(-1, &status, WNOHANG);
090089c4 349#endif
30a4f2a8 350 debug(21, 3, "sig_child: Ate pid %d\n", pid);
351#if HAVE_SIGACTION
352 } while (pid > 0);
234967c9 353#else
30a4f2a8 354 } while (pid > 0 || (pid < 0 && errno == EINTR));
355 signal(sig, sig_child);
234967c9 356#endif
30a4f2a8 357}
44a47c6e 358
359char *getMyHostname()
360{
95d659f0 361 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
44a47c6e 362 static int present = 0;
363 struct hostent *h = NULL;
019dd986 364 char *t = NULL;
365
b6f794d6 366 if ((t = Config.visibleHostname))
019dd986 367 return t;
44a47c6e 368
369 /* Get the host name and store it in host to return */
370 if (!present) {
371 host[0] = '\0';
372 if (gethostname(host, SQUIDHOSTNAMELEN) == -1) {
019dd986 373 debug(21, 1, "getMyHostname: gethostname failed: %s\n",
44a47c6e 374 xstrerror());
375 return NULL;
376 } else {
30a4f2a8 377 if ((h = ipcache_gethostbyname(host, IP_BLOCKING_LOOKUP)) != NULL) {
44a47c6e 378 /* DNS lookup successful */
379 /* use the official name from DNS lookup */
380 strcpy(host, h->h_name);
381 }
382 present = 1;
383 }
384 }
385 return host;
386}
387
388int safeunlink(s, quiet)
389 char *s;
390 int quiet;
391{
392 int err;
393 if ((err = unlink(s)) < 0)
394 if (!quiet)
019dd986 395 debug(21, 1, "safeunlink: Couldn't delete %s. %s\n", s, xstrerror());
44a47c6e 396 return (err);
397}
12b9e9b1 398
30a4f2a8 399/* leave a privilegied section. (Give up any privilegies)
400 * Routines that need privilegies can rap themselves in enter_suid()
401 * and leave_suid()
402 * To give upp all posibilites to gain privilegies use no_suid()
12b9e9b1 403 */
30a4f2a8 404void leave_suid()
12b9e9b1 405{
406 struct passwd *pwd = NULL;
407 struct group *grp = NULL;
30a4f2a8 408 debug(21, 3, "leave_suid: PID %d called\n", getpid());
12b9e9b1 409 if (geteuid() != 0)
410 return;
411 /* Started as a root, check suid option */
b6f794d6 412 if (Config.effectiveUser == NULL)
12b9e9b1 413 return;
b6f794d6 414 if ((pwd = getpwnam(Config.effectiveUser)) == NULL)
12b9e9b1 415 return;
b6f794d6 416 if (Config.effectiveGroup && (grp = getgrnam(Config.effectiveGroup))) {
12b9e9b1 417 setgid(grp->gr_gid);
418 } else {
419 setgid(pwd->pw_gid);
420 }
30a4f2a8 421 debug(21, 3, "leave_suid: PID %d giving up root, becoming '%s'\n",
422 getpid(), pwd->pw_name);
234967c9 423#if HAVE_SETRESUID
424 setresuid(pwd->pw_uid, pwd->pw_uid, 0);
425#elif HAVE_SETEUID
426 seteuid(pwd->pw_uid);
427#else
12b9e9b1 428 setuid(pwd->pw_uid);
234967c9 429#endif
430}
431
30a4f2a8 432/* Enter a privilegied section */
433void enter_suid()
234967c9 434{
30a4f2a8 435 debug(21, 3, "enter_suid: PID %d taking root priveleges\n", getpid());
234967c9 436#if HAVE_SETRESUID
437 setresuid(-1, 0, -1);
438#else
439 setuid(0);
440#endif
441}
442
30a4f2a8 443/* Give up the posibility to gain privilegies.
444 * this should be used before starting a sub process
445 */
234967c9 446void no_suid()
447{
448 uid_t uid;
30a4f2a8 449 leave_suid();
234967c9 450 uid = geteuid();
30a4f2a8 451 debug(21, 3, "leave_suid: PID %d giving up root priveleges forever\n", getpid());
234967c9 452#if HAVE_SETRESUID
453 setresuid(uid, uid, uid);
454#else
455 setuid(0);
456 setuid(uid);
457#endif
12b9e9b1 458}
ccff9601 459
460void writePidFile()
461{
462 FILE *pid_fp = NULL;
463 char *f = NULL;
464
b6f794d6 465 if ((f = Config.pidFilename) == NULL)
ccff9601 466 return;
30a4f2a8 467 enter_suid();
468 pid_fp = fopen(f, "w");
469 leave_suid();
470 if (pid_fp != NULL) {
471 fprintf(pid_fp, "%d\n", (int) getpid());
472 fclose(pid_fp);
473 } else {
019dd986 474 debug(21, 0, "WARNING: Could not write pid file\n");
475 debug(21, 0, " %s: %s\n", f, xstrerror());
ccff9601 476 }
ccff9601 477}
c4fb974e 478
479
480void setMaxFD()
481{
234967c9 482#if HAVE_SETRLIMIT
c4fb974e 483 /* try to use as many file descriptors as possible */
484 /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
485 struct rlimit rl;
486#if defined(RLIMIT_NOFILE)
487 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
a8f7d3ee 488 debug(21, 0, "setrlimit: RLIMIT_NOFILE: %s\n", xstrerror());
c4fb974e 489 } else {
234967c9 490 rl.rlim_cur = FD_SETSIZE;
30a4f2a8 491 if (rl.rlim_cur > rl.rlim_max)
492 rl.rlim_cur = rl.rlim_max;
c4fb974e 493 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
234967c9 494 sprintf(tmp_error_buf, "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
495 fatal_dump(tmp_error_buf);
c4fb974e 496 }
497 }
498#elif defined(RLIMIT_OFILE)
499 if (getrlimit(RLIMIT_OFILE, &rl) < 0) {
a8f7d3ee 500 debug(21, 0, "setrlimit: RLIMIT_NOFILE: %s\n", xstrerror());
c4fb974e 501 } else {
234967c9 502 rl.rlim_cur = FD_SETSIZE;
30a4f2a8 503 if (rl.rlim_cur > rl.rlim_max)
504 rl.rlim_cur = rl.rlim_max;
c4fb974e 505 if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
234967c9 506 sprintf(tmp_error_buf, "setrlimit: RLIMIT_OFILE: %s", xstrerror());
507 fatal_dump(tmp_error_buf);
c4fb974e 508 }
509 }
510#endif
c4fb974e 511#else /* HAVE_SETRLIMIT */
a8f7d3ee 512 debug(21, 1, "setMaxFD: Cannot increase: setrlimit() not supported on this system\n");
30a4f2a8 513#endif /* HAVE_SETRLIMIT */
514
515#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
516 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
a8f7d3ee 517 debug(21, 0, "getrlimit: RLIMIT_DATA: %s\n", xstrerror());
30a4f2a8 518 } else {
519 rl.rlim_cur = rl.rlim_max; /* set it to the max */
520 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
521 sprintf(tmp_error_buf, "setrlimit: RLIMIT_DATA: %s", xstrerror());
522 fatal_dump(tmp_error_buf);
523 }
524 }
525#endif /* RLIMIT_DATA */
c4fb974e 526}
3a57089e 527
528time_t getCurrentTime()
529{
94e891ea 530#if GETTIMEOFDAY_NO_TZP
30a4f2a8 531 gettimeofday(&current_time);
532#else
d598947a 533 gettimeofday(&current_time, NULL);
5f3f8d0e 534#endif
30a4f2a8 535 return squid_curtime = current_time.tv_sec;
5f3f8d0e 536}
fe113054 537
a0bbd6c8 538int tvSubMsec(t1, t2)
539 struct timeval t1;
540 struct timeval t2;
fe113054 541{
542 return (t2.tv_sec - t1.tv_sec) * 1000 +
a0bbd6c8 543 (t2.tv_usec - t1.tv_usec) / 1000;
fe113054 544}
30a4f2a8 545
546int percent(a, b)
547 int a;
548 int b;
549{
550 return b ? ((int) (100.0 * a / b + 0.5)) : 0;
551}
552
553void squid_signal(sig, func, flags)
554 int sig;
555 void (*func) ();
556 int flags;
557{
558#if HAVE_SIGACTION
559 struct sigaction sa;
560 sa.sa_handler = func;
561 sa.sa_flags = flags;
562 sigemptyset(&sa.sa_mask);
563 if (sigaction(sig, &sa, NULL) < 0)
564 debug(1, 0, "sigaction: sig=%d func=%p: %s\n", sig, func, xstrerror());
565#else
566 (void) signal(sig, func);
567#endif
568}