]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/tools.cc
4 * DEBUG: section 21 Misc Functions
5 * AUTHOR: Harvest Derived
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
36 #include "compat/initgroups.h"
37 #include "compat/getaddrinfo.h"
38 #include "compat/getnameinfo.h"
39 #include "compat/tempnam.h"
41 #include "ip/Intercept.h"
42 #include "ip/QosConfig.h"
44 #include "ProtoPort.h"
45 #include "SquidMath.h"
46 #include "SquidTime.h"
48 #include "ipc/Coordinator.h"
53 #include <sys/prctl.h>
57 The Squid Cache (version %s) died.\n\
59 You've encountered a fatal error in the Squid Cache version %s.\n\
60 If a core file was created (possibly in the swap directory),\n\
61 please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
62 and report the trace back to squid-bugs@squid-cache.org.\n\
66 static void fatal_common(const char *);
67 static void fatalvf(const char *fmt
, va_list args
);
68 static void mail_warranty(void);
70 extern void log_trace_done();
71 extern void log_trace_init(char *);
73 static void restoreCapabilities(int keep
);
77 /* Workaround for crappy glic header files */
78 SQUIDCEXTERN
int backtrace(void *, int);
79 SQUIDCEXTERN
void backtrace_symbols_fd(void *, int, int);
80 SQUIDCEXTERN
int setresuid(uid_t
, uid_t
, uid_t
);
81 #else /* _SQUID_LINUX_ */
82 /* needed on Opensolaris for backtrace_symbols_fd */
85 #endif /* HAVE_EXECINFO_H */
87 #endif /* _SQUID_LINUX */
89 SQUIDCEXTERN
void (*failure_notify
) (const char *);
92 releaseServerSockets(void)
95 /* Release the main ports as early as possible */
97 for (i
= 0; i
< NHttpSockets
; i
++) {
98 if (HttpSockets
[i
] >= 0)
99 close(HttpSockets
[i
]);
102 if (theInIcpConnection
>= 0)
103 close(theInIcpConnection
);
105 if (theOutIcpConnection
>= 0 && theOutIcpConnection
!= theInIcpConnection
)
106 close(theOutIcpConnection
);
112 LOCAL_ARRAY(char, msg
, 1024);
113 snprintf(msg
, 1024, DEAD_MSG
, version_string
, version_string
);
121 static char command
[256];
124 char filename
[] = "/tmp/squid-XXXXXX";
125 int tfd
= mkstemp(filename
);
130 if ((fp
= fdopen(tfd
, "w")) == NULL
)
137 if ((filename
= tempnam(NULL
, APP_SHORTNAME
)) == NULL
)
140 if ((fp
= fopen(filename
, "w")) == NULL
)
145 if (Config
.EmailFrom
)
146 fprintf(fp
, "From: %s\n", Config
.EmailFrom
);
148 fprintf(fp
, "From: %s@%s\n", APP_SHORTNAME
, uniqueHostname());
150 fprintf(fp
, "To: %s\n", Config
.adminEmail
);
152 fprintf(fp
, "Subject: %s\n", dead_msg());
156 snprintf(command
, 256, "%s %s < %s", Config
.EmailProgram
, Config
.adminEmail
, filename
);
158 if (system(command
)) {} /* XXX should avoid system(3) */
164 dumpMallocStats(void)
166 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
168 struct mstats ms
= mstats();
169 fprintf(debug_log
, "\ttotal space in arena: %6d KB\n",
170 (int) (ms
.bytes_total
>> 10));
171 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
172 (int) (ms
.bytes_free
>> 10),
173 Math::intPercent(ms
.bytes_free
, ms
.bytes_total
));
174 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
184 fprintf(debug_log
, "Memory usage for "APP_SHORTNAME
" via mallinfo():\n");
186 fprintf(debug_log
, "\ttotal space in arena: %6ld KB\n",
187 (long)mp
.arena
>> 10);
189 fprintf(debug_log
, "\tOrdinary blocks: %6ld KB %6ld blks\n",
190 (long)mp
.uordblks
>> 10, (long)mp
.ordblks
);
192 fprintf(debug_log
, "\tSmall blocks: %6ld KB %6ld blks\n",
193 (long)mp
.usmblks
>> 10, (long)mp
.smblks
);
195 fprintf(debug_log
, "\tHolding blocks: %6ld KB %6ld blks\n",
196 (long)mp
.hblkhd
>> 10, (long)mp
.hblks
);
198 fprintf(debug_log
, "\tFree Small blocks: %6ld KB\n",
199 (long)mp
.fsmblks
>> 10);
201 fprintf(debug_log
, "\tFree Ordinary blocks: %6ld KB\n",
202 (long)mp
.fordblks
>> 10);
204 t
= mp
.uordblks
+ mp
.usmblks
+ mp
.hblkhd
;
206 fprintf(debug_log
, "\tTotal in use: %6d KB %d%%\n",
207 t
>> 10, Math::intPercent(t
, mp
.arena
));
209 t
= mp
.fsmblks
+ mp
.fordblks
;
211 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
212 t
>> 10, Math::intPercent(t
, mp
.arena
));
214 #if HAVE_STRUCT_MALLINFO_MXFAST
216 fprintf(debug_log
, "\tmax size of small blocks:\t%d\n",
219 fprintf(debug_log
, "\tnumber of small blocks in a holding block:\t%d\n",
222 fprintf(debug_log
, "\tsmall block rounding factor:\t%d\n",
225 fprintf(debug_log
, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
228 fprintf(debug_log
, "\tnumber of ordinary blocks allocated:\t%d\n",
231 fprintf(debug_log
, "\tbytes used in maintaining the free tree:\t%d\n",
234 #endif /* HAVE_STRUCT_MALLINFO_MXFAST */
235 #endif /* HAVE_MALLINFO */
240 squid_getrusage(struct rusage
*r
)
243 memset(r
, '\0', sizeof(struct rusage
));
244 #if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
245 #ifdef _SQUID_SOLARIS_
246 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
250 getrusage(RUSAGE_SELF
, r
);
251 #ifdef _SQUID_SOLARIS_
260 rusage_cputime(struct rusage
*r
)
262 return (double) r
->ru_stime
.tv_sec
+
263 (double) r
->ru_utime
.tv_sec
+
264 (double) r
->ru_stime
.tv_usec
/ 1000000.0 +
265 (double) r
->ru_utime
.tv_usec
/ 1000000.0;
268 /* Hack for some HP-UX preprocessors */
269 #ifndef HAVE_GETPAGESIZE
270 #define HAVE_GETPAGESIZE 0
275 rusage_maxrss(struct rusage
*r
)
277 #if defined(_SQUID_SGI_) && _ABIAPI
279 #elif defined(_SQUID_SGI_)
282 #elif defined(_SQUID_OSF_)
285 #elif defined(_SQUID_AIX_)
288 #elif defined(BSD4_4)
291 #elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
293 return (r
->ru_maxrss
* getpagesize()) >> 10;
294 #elif defined(PAGESIZE)
296 return (r
->ru_maxrss
* PAGESIZE
) >> 10;
305 rusage_pagefaults(struct rusage
*r
)
307 #if defined(_SQUID_SGI_) && _ABIAPI
320 struct rusage rusage
;
321 squid_getrusage(&rusage
);
322 fprintf(debug_log
, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
323 rusage_cputime(&rusage
),
324 rusage
.ru_utime
.tv_sec
+ ((double) rusage
.ru_utime
.tv_usec
/ 1000000.0),
325 rusage
.ru_stime
.tv_sec
+ ((double) rusage
.ru_stime
.tv_usec
/ 1000000.0));
326 fprintf(debug_log
, "Maximum Resident Size: %d KB\n",
327 rusage_maxrss(&rusage
));
328 fprintf(debug_log
, "Page faults with physical i/o: %d\n",
329 rusage_pagefaults(&rusage
));
337 fprintf(debug_log
, "FATAL: Received Segment Violation...dying.\n");
338 else if (sig
== SIGBUS
)
339 fprintf(debug_log
, "FATAL: Received Bus Error...dying.\n");
341 fprintf(debug_log
, "FATAL: Received signal %d...dying.\n", sig
);
343 #if PRINT_STACK_TRACE
346 extern void U_STACK_TRACE(void); /* link with -lcl */
348 dup2(fileno(debug_log
), 2);
352 #endif /* _SQUID_HPUX_ */
353 #if defined(_SQUID_SOLARIS_) && HAVE_LIBOPCOM_STACK
354 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
355 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
357 dup2(fileno(debug_log
), fileno(stdout
));
362 #endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
363 #if HAVE_BACKTRACE_SYMBOLS_FD
365 static void *(callarray
[8192]);
367 n
= backtrace(callarray
, 8192);
368 backtrace_symbols_fd(callarray
, n
, fileno(debug_log
));
372 #endif /* PRINT_STACK_TRACE */
374 #if SA_RESETHAND == 0 && !defined(_SQUID_MSWIN_)
375 signal(SIGSEGV
, SIG_DFL
);
377 signal(SIGBUS
, SIG_DFL
);
379 signal(sig
, SIG_DFL
);
383 releaseServerSockets();
385 storeDirWriteCleanLogs(0);
387 if (!shutting_down
) {
393 if (squid_curtime
- SQUID_RELEASE_TIME
< 864000) {
394 /* skip if more than 10 days old */
396 if (Config
.adminEmail
)
409 BroadcastSignalIfAny(int& sig
)
412 if (IamCoordinatorProcess())
413 Ipc::Coordinator::Instance()->broadcastSignal(sig
);
419 sigusr2_handle(int sig
)
421 static int state
= 0;
422 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
428 Debug::parseOptions("ALL,7");
437 Debug::parseOptions(Debug::debugOptions
);
440 log_trace_init("/tmp/squid.alloc");
447 if (signal(sig
, sigusr2_handle
) == SIG_ERR
) /* reinstall */
448 debugs(50, 0, "signal: sig=" << sig
<< " func=sigusr2_handle: " << xstrerror());
454 fatal_common(const char *message
)
457 syslog(LOG_ALERT
, "%s", message
);
460 fprintf(debug_log
, "FATAL: %s\n", message
);
462 if (Debug::log_stderr
> 0 && debug_log
!= stderr
)
463 fprintf(stderr
, "FATAL: %s\n", message
);
465 fprintf(debug_log
, "Squid Cache (Version %s): Terminated abnormally.\n",
477 fatal(const char *message
)
479 /* suppress secondary errors from the dying */
482 releaseServerSockets();
483 /* check for store_dirs_rebuilding because fatal() is often
484 * used in early initialization phases, long before we ever
485 * get to the store log. */
487 /* XXX: this should be turned into a callback-on-fatal, or
488 * a mandatory-shutdown-event or something like that.
494 * Call leave_suid() here to make sure that swap.state files
495 * are written as the effective user, rather than root. Squid
496 * may take on root privs during reconfigure. If squid.conf
497 * contains a "Bungled" line, fatal() will be called when the
498 * process still has root privs.
502 if (0 == StoreController::store_dirs_rebuilding
)
503 storeDirWriteCleanLogs(0);
505 fatal_common(message
);
510 /* printf-style interface for fatal */
512 fatalf(const char *fmt
,...)
523 fatalvf(const char *fmt
, va_list args
)
525 static char fatal_str
[BUFSIZ
];
526 vsnprintf(fatal_str
, sizeof(fatal_str
), fmt
, args
);
530 /* fatal with dumping core */
532 fatal_dump(const char *message
)
534 failure_notify
= NULL
;
535 releaseServerSockets();
538 fatal_common(message
);
541 * Call leave_suid() here to make sure that swap.state files
542 * are written as the effective user, rather than root. Squid
543 * may take on root privs during reconfigure. If squid.conf
544 * contains a "Bungled" line, fatal() will be called when the
545 * process still has root privs.
549 if (opt_catch_signals
)
550 storeDirWriteCleanLogs(0);
556 debug_trap(const char *message
)
558 if (!opt_catch_signals
)
561 _db_print("WARNING: %s\n", message
);
567 #ifndef _SQUID_MSWIN_
579 pid
= wait3(&status
, WNOHANG
, NULL
);
582 pid
= waitpid(-1, &status
, WNOHANG
);
584 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
593 while (pid
> 0 || (pid
< 0 && errno
== EINTR
));
594 signal(sig
, sig_child
);
603 LOCAL_ARRAY(char, host
, SQUIDHOSTNAMELEN
+ 1);
604 static int present
= 0;
605 struct addrinfo
*AI
= NULL
;
608 if (Config
.visibleHostname
!= NULL
)
609 return Config
.visibleHostname
;
616 if (Config
.Sockaddr
.http
&& sa
.IsAnyAddr())
617 sa
= Config
.Sockaddr
.http
->s
;
621 if (Config
.Sockaddr
.https
&& sa
.IsAnyAddr())
622 sa
= Config
.Sockaddr
.https
->http
.s
;
627 * If the first http_port address has a specific address, try a
628 * reverse DNS lookup on it.
630 if ( !sa
.IsAnyAddr() ) {
633 /* we are looking for a name. */
634 if (getnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, host
, SQUIDHOSTNAMELEN
, NULL
, 0, NI_NAMEREQD
) == 0) {
635 /* DNS lookup successful */
636 /* use the official name from DNS lookup */
637 debugs(50, 4, "getMyHostname: resolved " << sa
<< " to '" << host
<< "'");
643 if (strchr(host
, '.'))
648 debugs(50, 2, "WARNING: failed to resolve " << sa
<< " to a fully qualified hostname");
651 // still no host. fallback to gethostname()
652 if (gethostname(host
, SQUIDHOSTNAMELEN
) < 0) {
653 debugs(50, DBG_IMPORTANT
, "WARNING: gethostname failed: " << xstrerror());
655 /* Verify that the hostname given resolves properly */
656 struct addrinfo hints
;
657 memset(&hints
, 0, sizeof(addrinfo
));
658 hints
.ai_flags
= AI_CANONNAME
;
660 if (getaddrinfo(host
, NULL
, NULL
, &AI
) == 0) {
661 /* DNS lookup successful */
662 /* use the official name from DNS lookup */
663 debugs(50, 6, "getMyHostname: '" << host
<< "' has DNS resolution.");
666 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
675 if (AI
) freeaddrinfo(AI
);
676 debugs(50, DBG_IMPORTANT
, "WARNING: '" << host
<< "' rDNS test failed: " << xstrerror());
679 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
680 debugs(50, DBG_CRITICAL
, "WARNING: Could not determine this machines public hostname. " <<
681 "Please configure one or set 'visible_hostname'.");
683 return ("localhost");
689 debugs(21, 3, HERE
<< " Config: '" << Config
.uniqueHostname
<< "'");
690 return Config
.uniqueHostname
? Config
.uniqueHostname
: getMyHostname();
693 /** leave a priviliged section. (Give up any privilegies)
694 * Routines that need privilegies can rap themselves in enter_suid()
696 * To give upp all posibilites to gain privilegies use no_suid()
701 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
703 if (Config
.effectiveGroup
) {
707 setgroups(1, &Config2
.effectiveGroupID
);
711 if (setgid(Config2
.effectiveGroupID
) < 0)
712 debugs(50, 0, "ALERT: setgid: " << xstrerror());
719 /* Started as a root, check suid option */
720 if (Config
.effectiveUser
== NULL
)
723 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config
.effectiveUser
<< "'");
725 if (!Config
.effectiveGroup
) {
727 if (setgid(Config2
.effectiveGroupID
) < 0)
728 debugs(50, 0, "ALERT: setgid: " << xstrerror());
730 if (initgroups(Config
.effectiveUser
, Config2
.effectiveGroupID
) < 0) {
731 debugs(50, 0, "ALERT: initgroups: unable to set groups for User " <<
732 Config
.effectiveUser
<< " and Group " <<
733 (unsigned) Config2
.effectiveGroupID
<< "");
739 if (setresuid(Config2
.effectiveUserID
, Config2
.effectiveUserID
, 0) < 0)
740 debugs(50, 0, "ALERT: setresuid: " << xstrerror());
744 if (seteuid(Config2
.effectiveUserID
) < 0)
745 debugs(50, 0, "ALERT: seteuid: " << xstrerror());
749 if (setuid(Config2
.effectiveUserID
) < 0)
750 debugs(50, 0, "ALERT: setuid: " << xstrerror());
754 restoreCapabilities(1);
756 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
757 /* Set Linux DUMPABLE flag */
758 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
759 debugs(50, 2, "ALERT: prctl: " << xstrerror());
764 /* Enter a privilegied section */
768 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root priveleges");
771 setresuid((uid_t
)-1, 0, (uid_t
)-1);
776 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
777 /* Set Linux DUMPABLE flag */
779 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
780 debugs(50, 2, "ALERT: prctl: " << xstrerror());
785 /* Give up the posibility to gain privilegies.
786 * this should be used before starting a sub process
794 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
799 debugs(50, 1, "no_suid: setuid: " << xstrerror());
801 restoreCapabilities(0);
803 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
804 /* Set Linux DUMPABLE flag */
805 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
806 debugs(50, 2, "ALERT: prctl: " << xstrerror());
814 return KidIdentifier
== 0;
820 // when there is only one process, it has to be the worker
821 if (opt_no_daemon
|| Config
.workers
== 0)
824 return 0 < KidIdentifier
&& KidIdentifier
<= Config
.workers
;
830 return !opt_no_daemon
&& Config
.workers
> 0;
836 return !opt_no_daemon
&& Config
.workers
> 1;
840 IamCoordinatorProcess()
842 return UsingSmp() && KidIdentifier
== Config
.workers
+ 1;
848 // when there is only one process, it has to be primary
849 if (opt_no_daemon
|| Config
.workers
== 0)
852 // when there is a master and worker process, the master delegates
853 // primary functions to its only kid
854 if (Config
.workers
== 1)
855 return IamWorkerProcess();
857 // in SMP mode, multiple kids delegate primary functions to the coordinator
858 return IamCoordinatorProcess();
864 // no kids in no-daemon mode
868 // workers + the coordinator process
870 return Config
.workers
+ 1;
872 return Config
.workers
;
879 const char *f
= NULL
;
883 if (!IamPrimaryProcess())
886 if ((f
= Config
.pidFilename
) == NULL
)
889 if (!strcmp(Config
.pidFilename
, "none"))
894 old_umask
= umask(022);
896 fd
= file_open(f
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
);
903 debugs(50, 0, "" << f
<< ": " << xstrerror());
904 debug_trap("Could not write pid file");
908 snprintf(buf
, 32, "%d\n", (int) getpid());
909 FD_WRITE_METHOD(fd
, buf
, strlen(buf
));
918 const char *f
= Config
.pidFilename
;
919 char *chroot_f
= NULL
;
923 if (f
== NULL
|| !strcmp(Config
.pidFilename
, "none")) {
924 fprintf(stderr
, APP_SHORTNAME
": ERROR: No pid file name defined\n");
928 if (Config
.chroot_dir
&& geteuid() == 0) {
929 int len
= strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1;
930 chroot_f
= (char *)xmalloc(strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1);
931 snprintf(chroot_f
, len
, "%s/%s", Config
.chroot_dir
, f
);
935 pid_fp
= fopen(f
, "r");
937 if (pid_fp
!= NULL
) {
940 if (fscanf(pid_fp
, "%d", &i
) == 1)
945 if (errno
!= ENOENT
) {
946 fprintf(stderr
, APP_SHORTNAME
": ERROR: Could not read pid file\n");
947 fprintf(stderr
, "\t%s: %s\n", f
, xstrerror());
956 /* A little piece of glue for odd systems */
957 #ifndef RLIMIT_NOFILE
959 #define RLIMIT_NOFILE RLIMIT_OFILE
963 /** Figure out the number of supported filedescriptors */
967 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
969 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
970 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
971 } else if (Config
.max_filedescriptors
> 0) {
972 #if USE_SELECT || USE_SELECT_WIN32
973 /* select() breaks if this gets set too big */
974 if (Config
.max_filedescriptors
> FD_SETSIZE
)
975 rl
.rlim_cur
= FD_SETSIZE
;
978 rl
.rlim_cur
= Config
.max_filedescriptors
;
979 if (rl
.rlim_cur
> rl
.rlim_max
)
980 rl
.rlim_max
= rl
.rlim_cur
;
981 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
982 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
983 getrlimit(RLIMIT_NOFILE
, &rl
);
984 rl
.rlim_cur
= rl
.rlim_max
;
985 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
986 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
990 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
991 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
993 Squid_MaxFD
= rl
.rlim_cur
;
996 #endif /* HAVE_SETRLIMIT */
1000 setSystemLimits(void)
1002 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !defined(_SQUID_CYGWIN_)
1003 /* limit system filedescriptors to our own limit */
1005 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
1006 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
1008 rl
.rlim_cur
= Squid_MaxFD
;
1009 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
1010 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
1011 fatal_dump(tmp_error_buf
);
1014 #endif /* HAVE_SETRLIMIT */
1016 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
1017 if (getrlimit(RLIMIT_DATA
, &rl
) < 0) {
1018 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_DATA: " << xstrerror());
1019 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
1020 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
1022 if (setrlimit(RLIMIT_DATA
, &rl
) < 0) {
1023 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_DATA: %s", xstrerror());
1024 fatal_dump(tmp_error_buf
);
1027 #endif /* RLIMIT_DATA */
1028 if (Config
.max_filedescriptors
> Squid_MaxFD
) {
1029 debugs(50, DBG_IMPORTANT
, "NOTICE: Could not increase the number of filedescriptors");
1032 #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
1033 if (getrlimit(RLIMIT_VMEM
, &rl
) < 0) {
1034 debugs(50, 0, "getrlimit: RLIMIT_VMEM: " << xstrerror());
1035 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
1036 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
1038 if (setrlimit(RLIMIT_VMEM
, &rl
) < 0) {
1039 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_VMEM: %s", xstrerror());
1040 fatal_dump(tmp_error_buf
);
1043 #endif /* RLIMIT_VMEM */
1047 squid_signal(int sig
, SIGHDLR
* func
, int flags
)
1051 struct sigaction sa
;
1052 sa
.sa_handler
= func
;
1053 sa
.sa_flags
= flags
;
1054 sigemptyset(&sa
.sa_mask
);
1056 if (sigaction(sig
, &sa
, NULL
) < 0)
1057 debugs(50, 0, "sigaction: sig=" << sig
<< " func=" << func
<< ": " << xstrerror());
1060 #ifdef _SQUID_MSWIN_
1062 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
1063 are supported, so we must care of don't call signal() for other value.
1064 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
1065 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
1083 WIN32_ExceptionHandlerInit();
1087 WIN32_ExceptionHandlerInit();
1089 break; /* Nor reached */
1093 break; /* Nor reached */
1111 kb_incr(kb_t
* k
, size_t v
)
1114 k
->kb
+= (k
->bytes
>> 10);
1119 debugObj(int section
, int level
, const char *label
, void *obj
, ObjPackMethod pm
)
1123 assert(label
&& obj
&& pm
);
1125 packerToMemInit(&p
, &mb
);
1127 debugs(section
, level
, "" << label
<< "" << mb
.buf
<< "");
1141 if (NULL
== Config
.etcHostsPath
)
1144 if (0 == strcmp(Config
.etcHostsPath
, "none"))
1147 fp
= fopen(Config
.etcHostsPath
, "r");
1150 debugs(1, 1, "parseEtcHosts: " << Config
.etcHostsPath
<< ": " << xstrerror());
1154 #ifdef _SQUID_WIN32_
1155 setmode(fileno(fp
), O_TEXT
);
1159 while (fgets(buf
, 1024, fp
)) { /* for each line */
1160 wordlist
*hosts
= NULL
;
1163 if (buf
[0] == '#') /* MS-windows likes to add comments */
1166 strtok(buf
, "#"); /* chop everything following a comment marker */
1172 debugs(1, 5, "etc_hosts: line is '" << buf
<< "'");
1174 nt
= strpbrk(lt
, w_space
);
1176 if (nt
== NULL
) /* empty line */
1179 *nt
= '\0'; /* null-terminate the address */
1181 debugs(1, 5, "etc_hosts: address is '" << addr
<< "'");
1185 while ((nt
= strpbrk(lt
, w_space
))) {
1188 if (nt
== lt
) { /* multiple spaces */
1189 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
1195 debugs(1, 5, "etc_hosts: got hostname '" << lt
<< "'");
1197 /* For IPV6 addresses also check for a colon */
1198 if (Config
.appendDomain
&& !strchr(lt
, '.') && !strchr(lt
, ':')) {
1199 /* I know it's ugly, but it's only at reconfig */
1200 strncpy(buf2
, lt
, 512);
1201 strncat(buf2
, Config
.appendDomain
, 512 - strlen(lt
) - 1);
1207 if (ipcacheAddEntryFromHosts(host
, addr
) != 0) {
1208 /* invalid address, continuing is useless */
1209 wordlistDestroy(&hosts
);
1213 wordlistAdd(&hosts
, host
);
1219 fqdncacheAddEntryFromHosts(addr
, hosts
);
1220 wordlistDestroy(&hosts
);
1230 if (Config
.Sockaddr
.http
)
1231 return Config
.Sockaddr
.http
->s
.GetPort();
1235 if (Config
.Sockaddr
.https
)
1236 return Config
.Sockaddr
.https
->http
.s
.GetPort();
1240 fatal("No port defined");
1242 return 0; /* NOT REACHED */
1246 * Set the umask to at least the given mask. This is in addition
1247 * to the umask set at startup
1250 setUmask(mode_t mask
)
1252 // No way to get the current umask value without setting it.
1253 static const mode_t orig_umask
= umask(mask
); // once, to get
1254 umask(mask
| orig_umask
); // always, to set
1258 * Inverse of strwordtok. Quotes a word if needed
1261 strwordquote(MemBuf
* mb
, const char *str
)
1265 if (strchr(str
, ' ')) {
1267 mb
->append("\"", 1);
1271 int l
= strcspn(str
, "\"\\\n\r");
1278 mb
->append("\\n", 2);
1283 mb
->append("\\r", 2);
1291 mb
->append("\\", 1);
1299 mb
->append("\"", 1);
1303 keepCapabilities(void)
1305 #if USE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
1307 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0)) {
1308 Ip::Interceptor
.StopTransparency("capability setting has failed.");
1314 restoreCapabilities(int keep
)
1316 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
1320 caps
= cap_get_proc();
1324 Ip::Interceptor
.StopTransparency("Can't get current capabilities");
1328 cap_value_t cap_list
[10];
1329 cap_list
[ncaps
++] = CAP_NET_BIND_SERVICE
;
1330 if (Ip::Interceptor
.TransparentActive() || Ip::Qos::TheConfig
.isHitNfmarkActive() || Ip::Qos::TheConfig
.isAclNfmarkActive()) {
1331 cap_list
[ncaps
++] = CAP_NET_ADMIN
;
1334 cap_clear_flag(caps
, CAP_EFFECTIVE
);
1335 rc
|= cap_set_flag(caps
, CAP_EFFECTIVE
, ncaps
, cap_list
, CAP_SET
);
1336 rc
|= cap_set_flag(caps
, CAP_PERMITTED
, ncaps
, cap_list
, CAP_SET
);
1338 if (rc
|| cap_set_proc(caps
) != 0) {
1339 Ip::Interceptor
.StopTransparency("Error enabling needed capabilities.");
1343 #elif defined(_SQUID_LINUX_)
1344 Ip::Interceptor
.StopTransparency("Missing needed capability support.");
1345 #endif /* HAVE_SYS_CAPABILITY_H */
1349 xmemset(void *dst
, int val
, size_t sz
)
1352 debugs(63, 9, "memset: dst=" << dst
<< ", val=" << val
<< ", bytes=" << sz
);
1354 // call the system one to do the actual work ~safely.
1355 return memset(dst
, val
, sz
);