]>
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.
35 #include "squid-old.h"
36 #include "base/Subscription.h"
39 #include "ip/Intercept.h"
40 #include "ip/QosConfig.h"
42 #include "ProtoPort.h"
43 #include "SquidMath.h"
44 #include "SquidTime.h"
46 #include "ipc/Coordinator.h"
52 #include <sys/prctl.h>
56 The Squid Cache (version %s) died.\n\
58 You've encountered a fatal error in the Squid Cache version %s.\n\
59 If a core file was created (possibly in the swap directory),\n\
60 please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
61 and report the trace back to squid-bugs@squid-cache.org.\n\
65 static void fatal_common(const char *);
66 static void fatalvf(const char *fmt
, va_list args
);
67 static void mail_warranty(void);
69 extern void log_trace_done();
70 extern void log_trace_init(char *);
72 static void restoreCapabilities(int keep
);
76 /* Workaround for crappy glic header files */
77 SQUIDCEXTERN
int backtrace(void *, int);
78 SQUIDCEXTERN
void backtrace_symbols_fd(void *, int, int);
79 SQUIDCEXTERN
int setresuid(uid_t
, uid_t
, uid_t
);
80 #else /* _SQUID_LINUX_ */
81 /* needed on Opensolaris for backtrace_symbols_fd */
84 #endif /* HAVE_EXECINFO_H */
86 #endif /* _SQUID_LINUX */
89 releaseServerSockets(void)
92 /* Release the main ports as early as possible */
94 // clear both http_port and https_port lists.
95 for (i
= 0; i
< NHttpSockets
; i
++) {
96 if (HttpSockets
[i
] >= 0)
97 close(HttpSockets
[i
]);
101 icpConnectionClose();
103 // XXX: Why not the HTCP, SNMP, DNS ports as well?
109 LOCAL_ARRAY(char, msg
, 1024);
110 snprintf(msg
, 1024, DEAD_MSG
, version_string
, version_string
);
118 static char command
[256];
121 char filename
[] = "/tmp/squid-XXXXXX";
122 int tfd
= mkstemp(filename
);
127 if ((fp
= fdopen(tfd
, "w")) == NULL
)
134 if ((filename
= tempnam(NULL
, APP_SHORTNAME
)) == NULL
)
137 if ((fp
= fopen(filename
, "w")) == NULL
)
142 if (Config
.EmailFrom
)
143 fprintf(fp
, "From: %s\n", Config
.EmailFrom
);
145 fprintf(fp
, "From: %s@%s\n", APP_SHORTNAME
, uniqueHostname());
147 fprintf(fp
, "To: %s\n", Config
.adminEmail
);
149 fprintf(fp
, "Subject: %s\n", dead_msg());
153 snprintf(command
, 256, "%s %s < %s", Config
.EmailProgram
, Config
.adminEmail
, filename
);
155 if (system(command
)) {} /* XXX should avoid system(3) */
161 dumpMallocStats(void)
163 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
165 struct mstats ms
= mstats();
166 fprintf(debug_log
, "\ttotal space in arena: %6d KB\n",
167 (int) (ms
.bytes_total
>> 10));
168 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
169 (int) (ms
.bytes_free
>> 10),
170 Math::intPercent(ms
.bytes_free
, ms
.bytes_total
));
171 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
181 fprintf(debug_log
, "Memory usage for "APP_SHORTNAME
" via mallinfo():\n");
183 fprintf(debug_log
, "\ttotal space in arena: %6ld KB\n",
184 (long)mp
.arena
>> 10);
186 fprintf(debug_log
, "\tOrdinary blocks: %6ld KB %6ld blks\n",
187 (long)mp
.uordblks
>> 10, (long)mp
.ordblks
);
189 fprintf(debug_log
, "\tSmall blocks: %6ld KB %6ld blks\n",
190 (long)mp
.usmblks
>> 10, (long)mp
.smblks
);
192 fprintf(debug_log
, "\tHolding blocks: %6ld KB %6ld blks\n",
193 (long)mp
.hblkhd
>> 10, (long)mp
.hblks
);
195 fprintf(debug_log
, "\tFree Small blocks: %6ld KB\n",
196 (long)mp
.fsmblks
>> 10);
198 fprintf(debug_log
, "\tFree Ordinary blocks: %6ld KB\n",
199 (long)mp
.fordblks
>> 10);
201 t
= mp
.uordblks
+ mp
.usmblks
+ mp
.hblkhd
;
203 fprintf(debug_log
, "\tTotal in use: %6d KB %d%%\n",
204 t
>> 10, Math::intPercent(t
, mp
.arena
));
206 t
= mp
.fsmblks
+ mp
.fordblks
;
208 fprintf(debug_log
, "\tTotal free: %6d KB %d%%\n",
209 t
>> 10, Math::intPercent(t
, mp
.arena
));
211 #if HAVE_STRUCT_MALLINFO_MXFAST
213 fprintf(debug_log
, "\tmax size of small blocks:\t%d\n",
216 fprintf(debug_log
, "\tnumber of small blocks in a holding block:\t%d\n",
219 fprintf(debug_log
, "\tsmall block rounding factor:\t%d\n",
222 fprintf(debug_log
, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
225 fprintf(debug_log
, "\tnumber of ordinary blocks allocated:\t%d\n",
228 fprintf(debug_log
, "\tbytes used in maintaining the free tree:\t%d\n",
231 #endif /* HAVE_STRUCT_MALLINFO_MXFAST */
232 #endif /* HAVE_MALLINFO */
237 squid_getrusage(struct rusage
*r
)
240 memset(r
, '\0', sizeof(struct rusage
));
241 #if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
243 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
247 getrusage(RUSAGE_SELF
, r
);
257 rusage_cputime(struct rusage
*r
)
259 return (double) r
->ru_stime
.tv_sec
+
260 (double) r
->ru_utime
.tv_sec
+
261 (double) r
->ru_stime
.tv_usec
/ 1000000.0 +
262 (double) r
->ru_utime
.tv_usec
/ 1000000.0;
265 /* Hack for some HP-UX preprocessors */
266 #ifndef HAVE_GETPAGESIZE
267 #define HAVE_GETPAGESIZE 0
272 rusage_maxrss(struct rusage
*r
)
274 #if _SQUID_SGI_ && _ABIAPI
276 #elif _SQUID_SGI_|| _SQUID_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
279 #elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
281 return (r
->ru_maxrss
* getpagesize()) >> 10;
282 #elif defined(PAGESIZE)
284 return (r
->ru_maxrss
* PAGESIZE
) >> 10;
293 rusage_pagefaults(struct rusage
*r
)
295 #if _SQUID_SGI_ && _ABIAPI
308 struct rusage rusage
;
309 squid_getrusage(&rusage
);
310 fprintf(debug_log
, "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
311 rusage_cputime(&rusage
),
312 rusage
.ru_utime
.tv_sec
+ ((double) rusage
.ru_utime
.tv_usec
/ 1000000.0),
313 rusage
.ru_stime
.tv_sec
+ ((double) rusage
.ru_stime
.tv_usec
/ 1000000.0));
314 fprintf(debug_log
, "Maximum Resident Size: %d KB\n",
315 rusage_maxrss(&rusage
));
316 fprintf(debug_log
, "Page faults with physical i/o: %d\n",
317 rusage_pagefaults(&rusage
));
325 fprintf(debug_log
, "FATAL: Received Segment Violation...dying.\n");
326 else if (sig
== SIGBUS
)
327 fprintf(debug_log
, "FATAL: Received Bus Error...dying.\n");
329 fprintf(debug_log
, "FATAL: Received signal %d...dying.\n", sig
);
331 #if PRINT_STACK_TRACE
334 extern void U_STACK_TRACE(void); /* link with -lcl */
336 dup2(fileno(debug_log
), 2);
340 #endif /* _SQUID_HPUX_ */
341 #if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
342 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
343 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
345 dup2(fileno(debug_log
), fileno(stdout
));
350 #endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
351 #if HAVE_BACKTRACE_SYMBOLS_FD
353 static void *(callarray
[8192]);
355 n
= backtrace(callarray
, 8192);
356 backtrace_symbols_fd(callarray
, n
, fileno(debug_log
));
360 #endif /* PRINT_STACK_TRACE */
362 #if SA_RESETHAND == 0 && !_SQUID_MSWIN_
363 signal(SIGSEGV
, SIG_DFL
);
365 signal(SIGBUS
, SIG_DFL
);
367 signal(sig
, SIG_DFL
);
371 releaseServerSockets();
373 storeDirWriteCleanLogs(0);
375 if (!shutting_down
) {
381 if (squid_curtime
- SQUID_RELEASE_TIME
< 864000) {
382 /* skip if more than 10 days old */
384 if (Config
.adminEmail
)
394 BroadcastSignalIfAny(int& sig
)
397 if (IamCoordinatorProcess())
398 Ipc::Coordinator::Instance()->broadcastSignal(sig
);
404 sigusr2_handle(int sig
)
406 static int state
= 0;
407 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
413 Debug::parseOptions("ALL,7");
422 Debug::parseOptions(Debug::debugOptions
);
425 log_trace_init("/tmp/squid.alloc");
432 if (signal(sig
, sigusr2_handle
) == SIG_ERR
) /* reinstall */
433 debugs(50, 0, "signal: sig=" << sig
<< " func=sigusr2_handle: " << xstrerror());
439 fatal_common(const char *message
)
442 syslog(LOG_ALERT
, "%s", message
);
445 fprintf(debug_log
, "FATAL: %s\n", message
);
447 if (Debug::log_stderr
> 0 && debug_log
!= stderr
)
448 fprintf(stderr
, "FATAL: %s\n", message
);
450 fprintf(debug_log
, "Squid Cache (Version %s): Terminated abnormally.\n",
462 fatal(const char *message
)
464 /* suppress secondary errors from the dying */
467 releaseServerSockets();
468 /* check for store_dirs_rebuilding because fatal() is often
469 * used in early initialization phases, long before we ever
470 * get to the store log. */
472 /* XXX: this should be turned into a callback-on-fatal, or
473 * a mandatory-shutdown-event or something like that.
479 * Call leave_suid() here to make sure that swap.state files
480 * are written as the effective user, rather than root. Squid
481 * may take on root privs during reconfigure. If squid.conf
482 * contains a "Bungled" line, fatal() will be called when the
483 * process still has root privs.
487 if (0 == StoreController::store_dirs_rebuilding
)
488 storeDirWriteCleanLogs(0);
490 fatal_common(message
);
495 /* printf-style interface for fatal */
497 fatalf(const char *fmt
,...)
508 fatalvf(const char *fmt
, va_list args
)
510 static char fatal_str
[BUFSIZ
];
511 vsnprintf(fatal_str
, sizeof(fatal_str
), fmt
, args
);
515 /* fatal with dumping core */
517 fatal_dump(const char *message
)
519 failure_notify
= NULL
;
520 releaseServerSockets();
523 fatal_common(message
);
526 * Call leave_suid() here to make sure that swap.state files
527 * are written as the effective user, rather than root. Squid
528 * may take on root privs during reconfigure. If squid.conf
529 * contains a "Bungled" line, fatal() will be called when the
530 * process still has root privs.
534 if (opt_catch_signals
)
535 storeDirWriteCleanLogs(0);
541 debug_trap(const char *message
)
543 if (!opt_catch_signals
)
546 _db_print("WARNING: %s\n", message
);
564 pid
= wait3(&status
, WNOHANG
, NULL
);
567 pid
= waitpid(-1, &status
, WNOHANG
);
569 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
578 while (pid
> 0 || (pid
< 0 && errno
== EINTR
));
579 signal(sig
, sig_child
);
586 sig_shutdown(int sig
)
594 LOCAL_ARRAY(char, host
, SQUIDHOSTNAMELEN
+ 1);
595 static int present
= 0;
596 struct addrinfo
*AI
= NULL
;
599 if (Config
.visibleHostname
!= NULL
)
600 return Config
.visibleHostname
;
607 if (Config
.Sockaddr
.http
&& sa
.IsAnyAddr())
608 sa
= Config
.Sockaddr
.http
->s
;
612 if (Config
.Sockaddr
.https
&& sa
.IsAnyAddr())
613 sa
= Config
.Sockaddr
.https
->s
;
618 * If the first http_port address has a specific address, try a
619 * reverse DNS lookup on it.
621 if ( !sa
.IsAnyAddr() ) {
624 /* we are looking for a name. */
625 if (getnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, host
, SQUIDHOSTNAMELEN
, NULL
, 0, NI_NAMEREQD
) == 0) {
626 /* DNS lookup successful */
627 /* use the official name from DNS lookup */
628 debugs(50, 4, "getMyHostname: resolved " << sa
<< " to '" << host
<< "'");
634 if (strchr(host
, '.'))
639 debugs(50, 2, "WARNING: failed to resolve " << sa
<< " to a fully qualified hostname");
642 // still no host. fallback to gethostname()
643 if (gethostname(host
, SQUIDHOSTNAMELEN
) < 0) {
644 debugs(50, DBG_IMPORTANT
, "WARNING: gethostname failed: " << xstrerror());
646 /* Verify that the hostname given resolves properly */
647 struct addrinfo hints
;
648 memset(&hints
, 0, sizeof(addrinfo
));
649 hints
.ai_flags
= AI_CANONNAME
;
651 if (getaddrinfo(host
, NULL
, NULL
, &AI
) == 0) {
652 /* DNS lookup successful */
653 /* use the official name from DNS lookup */
654 debugs(50, 6, "getMyHostname: '" << host
<< "' has DNS resolution.");
657 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
666 if (AI
) freeaddrinfo(AI
);
667 debugs(50, DBG_IMPORTANT
, "WARNING: '" << host
<< "' rDNS test failed: " << xstrerror());
670 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
671 debugs(50, DBG_CRITICAL
, "WARNING: Could not determine this machines public hostname. " <<
672 "Please configure one or set 'visible_hostname'.");
674 return ("localhost");
680 debugs(21, 3, HERE
<< " Config: '" << Config
.uniqueHostname
<< "'");
681 return Config
.uniqueHostname
? Config
.uniqueHostname
: getMyHostname();
684 /** leave a priviliged section. (Give up any privilegies)
685 * Routines that need privilegies can rap themselves in enter_suid()
687 * To give upp all posibilites to gain privilegies use no_suid()
692 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
694 if (Config
.effectiveGroup
) {
698 setgroups(1, &Config2
.effectiveGroupID
);
702 if (setgid(Config2
.effectiveGroupID
) < 0)
703 debugs(50, 0, "ALERT: setgid: " << xstrerror());
710 /* Started as a root, check suid option */
711 if (Config
.effectiveUser
== NULL
)
714 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config
.effectiveUser
<< "'");
716 if (!Config
.effectiveGroup
) {
718 if (setgid(Config2
.effectiveGroupID
) < 0)
719 debugs(50, 0, "ALERT: setgid: " << xstrerror());
721 if (initgroups(Config
.effectiveUser
, Config2
.effectiveGroupID
) < 0) {
722 debugs(50, 0, "ALERT: initgroups: unable to set groups for User " <<
723 Config
.effectiveUser
<< " and Group " <<
724 (unsigned) Config2
.effectiveGroupID
<< "");
730 if (setresuid(Config2
.effectiveUserID
, Config2
.effectiveUserID
, 0) < 0)
731 debugs(50, 0, "ALERT: setresuid: " << xstrerror());
735 if (seteuid(Config2
.effectiveUserID
) < 0)
736 debugs(50, 0, "ALERT: seteuid: " << xstrerror());
740 if (setuid(Config2
.effectiveUserID
) < 0)
741 debugs(50, 0, "ALERT: setuid: " << xstrerror());
745 restoreCapabilities(1);
747 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
748 /* Set Linux DUMPABLE flag */
749 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
750 debugs(50, 2, "ALERT: prctl: " << xstrerror());
755 /* Enter a privilegied section */
759 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root priveleges");
762 setresuid((uid_t
)-1, 0, (uid_t
)-1);
767 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
768 /* Set Linux DUMPABLE flag */
770 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
771 debugs(50, 2, "ALERT: prctl: " << xstrerror());
776 /* Give up the posibility to gain privilegies.
777 * this should be used before starting a sub process
785 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root priveleges forever");
790 debugs(50, 1, "no_suid: setuid: " << xstrerror());
792 restoreCapabilities(0);
794 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
795 /* Set Linux DUMPABLE flag */
796 if (Config
.coredump_dir
&& prctl(PR_SET_DUMPABLE
, 1) != 0)
797 debugs(50, 2, "ALERT: prctl: " << xstrerror());
805 return KidIdentifier
== 0;
811 // when there is only one process, it has to be the worker
812 if (opt_no_daemon
|| Config
.workers
== 0)
815 return TheProcessKind
== pkWorker
;
821 return TheProcessKind
== pkDisker
;
827 return !opt_no_daemon
&& Config
.workers
> 0;
833 return InDaemonMode() && NumberOfKids() > 1;
837 IamCoordinatorProcess()
839 return TheProcessKind
== pkCoordinator
;
845 // when there is only one process, it has to be primary
846 if (opt_no_daemon
|| Config
.workers
== 0)
849 // when there is a master and worker process, the master delegates
850 // primary functions to its only kid
851 if (NumberOfKids() == 1)
852 return IamWorkerProcess();
854 // in SMP mode, multiple kids delegate primary functions to the coordinator
855 return IamCoordinatorProcess();
861 // no kids in no-daemon mode
865 // XXX: detect and abort when called before workers/cache_dirs are parsed
867 const int rockDirs
= Config
.cacheSwap
.n_strands
;
869 const bool needCoord
= Config
.workers
> 1 || rockDirs
> 0;
870 return (needCoord
? 1 : 0) + Config
.workers
+ rockDirs
;
877 if (IamMasterProcess())
878 roles
.append(" master");
879 if (IamCoordinatorProcess())
880 roles
.append(" coordinator");
881 if (IamWorkerProcess())
882 roles
.append(" worker");
883 if (IamDiskProcess())
884 roles
.append(" disker");
892 const char *f
= NULL
;
896 if (!IamPrimaryProcess())
899 if ((f
= Config
.pidFilename
) == NULL
)
902 if (!strcmp(Config
.pidFilename
, "none"))
907 old_umask
= umask(022);
909 fd
= file_open(f
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_TEXT
);
916 debugs(50, 0, "" << f
<< ": " << xstrerror());
917 debug_trap("Could not write pid file");
921 snprintf(buf
, 32, "%d\n", (int) getpid());
922 FD_WRITE_METHOD(fd
, buf
, strlen(buf
));
931 const char *f
= Config
.pidFilename
;
932 char *chroot_f
= NULL
;
936 if (f
== NULL
|| !strcmp(Config
.pidFilename
, "none")) {
937 fprintf(stderr
, APP_SHORTNAME
": ERROR: No pid file name defined\n");
941 if (Config
.chroot_dir
&& geteuid() == 0) {
942 int len
= strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1;
943 chroot_f
= (char *)xmalloc(strlen(Config
.chroot_dir
) + 1 + strlen(f
) + 1);
944 snprintf(chroot_f
, len
, "%s/%s", Config
.chroot_dir
, f
);
948 pid_fp
= fopen(f
, "r");
950 if (pid_fp
!= NULL
) {
953 if (fscanf(pid_fp
, "%d", &i
) == 1)
958 if (errno
!= ENOENT
) {
959 fprintf(stderr
, APP_SHORTNAME
": ERROR: Could not read pid file\n");
960 fprintf(stderr
, "\t%s: %s\n", f
, xstrerror());
969 /* A little piece of glue for odd systems */
970 #ifndef RLIMIT_NOFILE
972 #define RLIMIT_NOFILE RLIMIT_OFILE
976 /** Figure out the number of supported filedescriptors */
980 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
982 /* On Linux with 64-bit file support the sys/resource.h header
983 * uses #define to change the function definition to require rlimit64
985 #if defined(getrlimit)
986 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
991 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
992 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
993 } else if (Config
.max_filedescriptors
> 0) {
994 #if USE_SELECT || USE_SELECT_WIN32
995 /* select() breaks if this gets set too big */
996 if (Config
.max_filedescriptors
> FD_SETSIZE
) {
997 rl
.rlim_cur
= FD_SETSIZE
;
998 debugs(50, DBG_CRITICAL
, "WARNING: 'max_filedescriptors " << Config
.max_filedescriptors
<< "' does not work with select()");
1001 rl
.rlim_cur
= Config
.max_filedescriptors
;
1002 if (rl
.rlim_cur
> rl
.rlim_max
)
1003 rl
.rlim_max
= rl
.rlim_cur
;
1004 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
1005 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerror());
1006 getrlimit(RLIMIT_NOFILE
, &rl
);
1007 rl
.rlim_cur
= rl
.rlim_max
;
1008 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
1009 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerror());
1013 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
1014 debugs(50, DBG_CRITICAL
, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerror());
1016 Squid_MaxFD
= rl
.rlim_cur
;
1019 #endif /* HAVE_SETRLIMIT */
1023 setSystemLimits(void)
1025 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
1026 /* limit system filedescriptors to our own limit */
1028 /* On Linux with 64-bit file support the sys/resource.h header
1029 * uses #define to change the function definition to require rlimit64
1031 #if defined(getrlimit)
1032 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
1037 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
1038 debugs(50, DBG_CRITICAL
, "setrlimit: RLIMIT_NOFILE: " << xstrerror());
1040 rl
.rlim_cur
= Squid_MaxFD
;
1041 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
1042 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
1043 fatal_dump(tmp_error_buf
);
1046 #endif /* HAVE_SETRLIMIT */
1048 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
1049 if (getrlimit(RLIMIT_DATA
, &rl
) < 0) {
1050 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_DATA: " << xstrerror());
1051 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
1052 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
1054 if (setrlimit(RLIMIT_DATA
, &rl
) < 0) {
1055 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_DATA: %s", xstrerror());
1056 fatal_dump(tmp_error_buf
);
1059 #endif /* RLIMIT_DATA */
1060 if (Config
.max_filedescriptors
> Squid_MaxFD
) {
1061 debugs(50, DBG_IMPORTANT
, "NOTICE: Could not increase the number of filedescriptors");
1064 #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
1065 if (getrlimit(RLIMIT_VMEM
, &rl
) < 0) {
1066 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_VMEM: " << xstrerror());
1067 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
1068 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
1070 if (setrlimit(RLIMIT_VMEM
, &rl
) < 0) {
1071 snprintf(tmp_error_buf
, ERROR_BUF_SZ
, "setrlimit: RLIMIT_VMEM: %s", xstrerror());
1072 fatal_dump(tmp_error_buf
);
1075 #endif /* RLIMIT_VMEM */
1079 squid_signal(int sig
, SIGHDLR
* func
, int flags
)
1083 struct sigaction sa
;
1084 sa
.sa_handler
= func
;
1085 sa
.sa_flags
= flags
;
1086 sigemptyset(&sa
.sa_mask
);
1088 if (sigaction(sig
, &sa
, NULL
) < 0)
1089 debugs(50, DBG_CRITICAL
, "sigaction: sig=" << sig
<< " func=" << func
<< ": " << xstrerror());
1094 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
1095 are supported, so we must care of don't call signal() for other value.
1096 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
1097 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
1115 WIN32_ExceptionHandlerInit();
1119 WIN32_ExceptionHandlerInit();
1121 break; /* Nor reached */
1125 break; /* Nor reached */
1143 kb_incr(kb_t
* k
, size_t v
)
1146 k
->kb
+= (k
->bytes
>> 10);
1151 debugObj(int section
, int level
, const char *label
, void *obj
, ObjPackMethod pm
)
1155 assert(label
&& obj
&& pm
);
1157 packerToMemInit(&p
, &mb
);
1159 debugs(section
, level
, "" << label
<< "" << mb
.buf
<< "");
1173 if (NULL
== Config
.etcHostsPath
)
1176 if (0 == strcmp(Config
.etcHostsPath
, "none"))
1179 fp
= fopen(Config
.etcHostsPath
, "r");
1182 debugs(1, 1, "parseEtcHosts: " << Config
.etcHostsPath
<< ": " << xstrerror());
1187 setmode(fileno(fp
), O_TEXT
);
1190 while (fgets(buf
, 1024, fp
)) { /* for each line */
1191 wordlist
*hosts
= NULL
;
1194 if (buf
[0] == '#') /* MS-windows likes to add comments */
1197 strtok(buf
, "#"); /* chop everything following a comment marker */
1203 debugs(1, 5, "etc_hosts: line is '" << buf
<< "'");
1205 nt
= strpbrk(lt
, w_space
);
1207 if (nt
== NULL
) /* empty line */
1210 *nt
= '\0'; /* null-terminate the address */
1212 debugs(1, 5, "etc_hosts: address is '" << addr
<< "'");
1216 while ((nt
= strpbrk(lt
, w_space
))) {
1219 if (nt
== lt
) { /* multiple spaces */
1220 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
1226 debugs(1, 5, "etc_hosts: got hostname '" << lt
<< "'");
1228 /* For IPV6 addresses also check for a colon */
1229 if (Config
.appendDomain
&& !strchr(lt
, '.') && !strchr(lt
, ':')) {
1230 /* I know it's ugly, but it's only at reconfig */
1231 strncpy(buf2
, lt
, 512);
1232 strncat(buf2
, Config
.appendDomain
, 512 - strlen(lt
) - 1);
1238 if (ipcacheAddEntryFromHosts(host
, addr
) != 0) {
1239 /* invalid address, continuing is useless */
1240 wordlistDestroy(&hosts
);
1244 wordlistAdd(&hosts
, host
);
1250 fqdncacheAddEntryFromHosts(addr
, hosts
);
1251 wordlistDestroy(&hosts
);
1261 http_port_list
*p
= NULL
;
1262 if ((p
= Config
.Sockaddr
.http
)) {
1263 // skip any special interception ports
1264 while (p
&& (p
->intercepted
|| p
->spoof_client_ip
))
1267 return p
->s
.GetPort();
1271 if ((p
= Config
.Sockaddr
.https
)) {
1272 // skip any special interception ports
1273 while (p
&& (p
->intercepted
|| p
->spoof_client_ip
))
1276 return p
->s
.GetPort();
1280 debugs(21, DBG_CRITICAL
, "ERROR: No forward-proxy ports configured.");
1281 return 0; // Invalid port. This will result in invalid URLs on bad configurations.
1285 * Set the umask to at least the given mask. This is in addition
1286 * to the umask set at startup
1289 setUmask(mode_t mask
)
1291 // No way to get the current umask value without setting it.
1292 static const mode_t orig_umask
= umask(mask
); // once, to get
1293 umask(mask
| orig_umask
); // always, to set
1297 * Inverse of strwordtok. Quotes a word if needed
1300 strwordquote(MemBuf
* mb
, const char *str
)
1304 if (strchr(str
, ' ')) {
1306 mb
->append("\"", 1);
1310 int l
= strcspn(str
, "\"\\\n\r");
1317 mb
->append("\\n", 2);
1322 mb
->append("\\r", 2);
1330 mb
->append("\\", 1);
1338 mb
->append("\"", 1);
1342 keepCapabilities(void)
1344 #if USE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
1346 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0)) {
1347 Ip::Interceptor
.StopTransparency("capability setting has failed.");
1353 restoreCapabilities(int keep
)
1355 /* NP: keep these two if-endif separate. Non-Linux work perfectly well without Linux syscap support. */
1359 caps
= cap_get_proc();
1363 Ip::Interceptor
.StopTransparency("Can't get current capabilities");
1367 cap_value_t cap_list
[10];
1368 cap_list
[ncaps
++] = CAP_NET_BIND_SERVICE
;
1369 if (Ip::Interceptor
.TransparentActive() || Ip::Qos::TheConfig
.isHitNfmarkActive() || Ip::Qos::TheConfig
.isAclNfmarkActive()) {
1370 cap_list
[ncaps
++] = CAP_NET_ADMIN
;
1373 cap_clear_flag(caps
, CAP_EFFECTIVE
);
1374 rc
|= cap_set_flag(caps
, CAP_EFFECTIVE
, ncaps
, cap_list
, CAP_SET
);
1375 rc
|= cap_set_flag(caps
, CAP_PERMITTED
, ncaps
, cap_list
, CAP_SET
);
1377 if (rc
|| cap_set_proc(caps
) != 0) {
1378 Ip::Interceptor
.StopTransparency("Error enabling needed capabilities.");
1383 Ip::Interceptor
.StopTransparency("Missing needed capability support.");
1384 #endif /* HAVE_SYS_CAPABILITY_H */
1388 xmemset(void *dst
, int val
, size_t sz
)
1391 debugs(63, 9, "memset: dst=" << dst
<< ", val=" << val
<< ", bytes=" << sz
);
1393 // call the system one to do the actual work ~safely.
1394 return memset(dst
, val
, sz
);