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