tools.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:20k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: tools.c,v 1.173 1999/01/11 21:55:44 wessels Exp $
  3.  *
  4.  * DEBUG: section 21    Misc Functions
  5.  * AUTHOR: Harvest Derived
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  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.
  23.  *  
  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.
  28.  *  
  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.
  32.  *
  33.  */
  34. #include "squid.h"
  35. #define DEAD_MSG "
  36. The Squid Cache (version %s) died.n
  37. n
  38. You've encountered a fatal error in the Squid Cache version %s.n
  39. If a core file was created (possibly in the swap directory),n
  40. please execute 'gdb squid core' or 'dbx squid core', then type 'where',n
  41. and report the trace back to squid-bugs@ircache.net.n
  42. n
  43. Thanks!n"
  44. static void fatal_common(const char *);
  45. static void fatalvf(const char *fmt, va_list args);
  46. static void mail_warranty(void);
  47. #if USE_ASYNC_IO
  48. static AIOCB safeunlinkComplete;
  49. #endif
  50. #if MEM_GEN_TRACE
  51. extern void log_trace_done();
  52. extern void log_trace_init(char *);
  53. #endif
  54. void
  55. releaseServerSockets(void)
  56. {
  57.     int i;
  58.     /* Release the main ports as early as possible */
  59.     for (i = 0; i < NHttpSockets; i++) {
  60. if (HttpSockets[i] >= 0)
  61.     close(HttpSockets[i]);
  62.     }
  63.     if (theInIcpConnection >= 0)
  64. close(theInIcpConnection);
  65.     if (theOutIcpConnection >= 0 && theOutIcpConnection != theInIcpConnection)
  66. close(theOutIcpConnection);
  67. }
  68. static char *
  69. dead_msg(void)
  70. {
  71.     LOCAL_ARRAY(char, msg, 1024);
  72.     snprintf(msg, 1024, DEAD_MSG, version_string, version_string);
  73.     return msg;
  74. }
  75. static void
  76. mail_warranty(void)
  77. {
  78.     FILE *fp = NULL;
  79.     char *filename;
  80.     static char command[256];
  81.     if ((filename = tempnam(NULL, appname)) == NULL)
  82. return;
  83.     if ((fp = fopen(filename, "w")) == NULL)
  84. return;
  85.     fprintf(fp, "From: %sn", appname);
  86.     fprintf(fp, "To: %sn", Config.adminEmail);
  87.     fprintf(fp, "Subject: %sn", dead_msg());
  88.     fclose(fp);
  89.     snprintf(command, 256, "mail %s < %s", Config.adminEmail, filename);
  90.     system(command); /* XXX should avoid system(3) */
  91.     unlink(filename);
  92. }
  93. void
  94. dumpMallocStats(void)
  95. {
  96. #if HAVE_MSTATS && HAVE_GNUMALLOC_H
  97.     struct mstats ms = mstats();
  98.     fprintf(debug_log, "ttotal space in arena:  %6d KBn",
  99. (int) (ms.bytes_total >> 10));
  100.     fprintf(debug_log, "tTotal free:            %6d KB %d%%n",
  101. (int) (ms.bytes_free >> 10),
  102. percent(ms.bytes_free, ms.bytes_total));
  103. #elif HAVE_MALLINFO
  104.     struct mallinfo mp;
  105.     int t;
  106.     if (!do_mallinfo)
  107. return;
  108.     mp = mallinfo();
  109.     fprintf(debug_log, "Memory usage for %s via mallinfo():n", appname);
  110.     fprintf(debug_log, "ttotal space in arena:  %6d KBn",
  111. mp.arena >> 10);
  112.     fprintf(debug_log, "tOrdinary blocks:       %6d KB %6d blksn",
  113. mp.uordblks >> 10, mp.ordblks);
  114.     fprintf(debug_log, "tSmall blocks:          %6d KB %6d blksn",
  115. mp.usmblks >> 10, mp.smblks);
  116.     fprintf(debug_log, "tHolding blocks:        %6d KB %6d blksn",
  117. mp.hblkhd >> 10, mp.hblks);
  118.     fprintf(debug_log, "tFree Small blocks:     %6d KBn",
  119. mp.fsmblks >> 10);
  120.     fprintf(debug_log, "tFree Ordinary blocks:  %6d KBn",
  121. mp.fordblks >> 10);
  122.     t = mp.uordblks + mp.usmblks + mp.hblkhd;
  123.     fprintf(debug_log, "tTotal in use:          %6d KB %d%%n",
  124. t >> 10, percent(t, mp.arena));
  125.     t = mp.fsmblks + mp.fordblks;
  126.     fprintf(debug_log, "tTotal free:            %6d KB %d%%n",
  127. t >> 10, percent(t, mp.arena));
  128. #if HAVE_EXT_MALLINFO
  129.     fprintf(debug_log, "tmax size of small blocks:t%dn",
  130. mp.mxfast);
  131.     fprintf(debug_log, "tnumber of small blocks in a holding block:t%dn",
  132. mp.nlblks);
  133.     fprintf(debug_log, "tsmall block rounding factor:t%dn",
  134. mp.grain);
  135.     fprintf(debug_log, "tspace (including overhead) allocated in ord. blks:t%dn",
  136. mp.uordbytes);
  137.     fprintf(debug_log, "tnumber of ordinary blocks allocated:t%dn",
  138. mp.allocated);
  139.     fprintf(debug_log, "tbytes used in maintaining the free tree:t%dn",
  140. mp.treeoverhead);
  141. #endif /* HAVE_EXT_MALLINFO */
  142. #endif /* HAVE_MALLINFO */
  143. }
  144. void
  145. squid_getrusage(struct rusage *r)
  146. {
  147.     memset(r, '', sizeof(struct rusage));
  148. #if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
  149. #ifdef _SQUID_SOLARIS_
  150.     /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
  151.     enter_suid();
  152. #endif
  153.     getrusage(RUSAGE_SELF, r);
  154. #ifdef _SQUID_SOLARIS_
  155.     leave_suid();
  156. #endif
  157. #endif
  158. }
  159. double
  160. rusage_cputime(struct rusage *r)
  161. {
  162.     return (double) r->ru_stime.tv_sec +
  163. (double) r->ru_utime.tv_sec +
  164. (double) r->ru_stime.tv_usec / 1000000.0 +
  165. (double) r->ru_utime.tv_usec / 1000000.0;
  166. }
  167. int
  168. rusage_maxrss(struct rusage *r)
  169. {
  170. #if defined(_SQUID_SGI_) && _ABIAPI
  171.     return r->ru_pad[0];
  172. #elif defined(_SQUID_SGI_)
  173.     return r->ru_maxrss;
  174. #elif defined(_SQUID_OSF_)
  175.     return r->ru_maxrss;
  176. #elif defined(BSD4_4)
  177.     return r->ru_maxrss;
  178. #elif HAVE_GETPAGESIZE
  179.     return (r->ru_maxrss * getpagesize()) >> 10;
  180. #elif defined(PAGESIZE)
  181.     return (r->ru_maxrss * PAGESIZE) >> 10;
  182. #else
  183.     return r->ru_maxrss;
  184. #endif
  185. }
  186. int
  187. rusage_pagefaults(struct rusage *r)
  188. {
  189. #if defined(_SQUID_SGI_) && _ABIAPI
  190.     return r->ru_pad[5];
  191. #else
  192.     return r->ru_majflt;
  193. #endif
  194. }
  195. void
  196. PrintRusage(void)
  197. {
  198.     struct rusage rusage;
  199.     squid_getrusage(&rusage);
  200.     fprintf(debug_log, "CPU Usage: %.3f secondsn", rusage_cputime(&rusage));
  201.     fprintf(debug_log, "Maximum Resident Size: %d KBn",
  202. rusage_maxrss(&rusage));
  203.     fprintf(debug_log, "Page faults with physical i/o: %dn",
  204. rusage_pagefaults(&rusage));
  205. }
  206. void
  207. death(int sig)
  208. {
  209.     if (sig == SIGSEGV)
  210. fprintf(debug_log, "FATAL: Received Segment Violation...dying.n");
  211.     else if (sig == SIGBUS)
  212. fprintf(debug_log, "FATAL: Received Bus Error...dying.n");
  213.     else
  214. fprintf(debug_log, "FATAL: Received signal %d...dying.n", sig);
  215. #ifdef PRINT_STACK_TRACE
  216. #ifdef _SQUID_HPUX_
  217.     {
  218. extern void U_STACK_TRACE(void); /* link with -lcl */
  219. fflush(debug_log);
  220. dup2(fileno(debug_log), 2);
  221. U_STACK_TRACE();
  222.     }
  223. #endif /* _SQUID_HPUX_ */
  224. #ifdef _SQUID_SOLARIS_
  225.     { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
  226. extern void opcom_stack_trace(void); /* link with -lopcom_stack */
  227. fflush(debug_log);
  228. dup2(fileno(debug_log), fileno(stdout));
  229. opcom_stack_trace();
  230. fflush(stdout);
  231.     }
  232. #endif /* _SQUID_SOLARIS_ */
  233. #endif /* PRINT_STACK_TRACE */
  234. #if SA_RESETHAND == 0
  235.     signal(SIGSEGV, SIG_DFL);
  236.     signal(SIGBUS, SIG_DFL);
  237.     signal(sig, SIG_DFL);
  238. #endif
  239.     releaseServerSockets();
  240.     storeDirWriteCleanLogs(0);
  241.     PrintRusage();
  242.     dumpMallocStats();
  243.     if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
  244. /* skip if more than 10 days old */
  245. if (Config.adminEmail)
  246.     mail_warranty();
  247. else
  248.     puts(dead_msg());
  249.     }
  250.     abort();
  251. }
  252. void
  253. sigusr2_handle(int sig)
  254. {
  255.     static int state = 0;
  256.     /* no debug() here; bad things happen if the signal is delivered during _db_print() */
  257.     if (state == 0) {
  258. #ifndef MEM_GEN_TRACE
  259. _db_init(Config.Log.log, "ALL,10");
  260. #else
  261. log_trace_done();
  262. #endif
  263. state = 1;
  264.     } else {
  265. #ifndef MEM_GEN_TRACE
  266. _db_init(Config.Log.log, Config.debugOptions);
  267. #else
  268. log_trace_init("/tmp/squid.alloc");
  269. #endif
  270. state = 0;
  271.     }
  272. #if !HAVE_SIGACTION
  273.     signal(sig, sigusr2_handle); /* reinstall */
  274. #endif
  275. }
  276. static void
  277. fatal_common(const char *message)
  278. {
  279. #if HAVE_SYSLOG
  280.     if (opt_syslog_enable)
  281. syslog(LOG_ALERT, "%s", message);
  282. #endif
  283.     fprintf(debug_log, "FATAL: %sn", message);
  284.     if (opt_debug_stderr && debug_log != stderr)
  285. fprintf(stderr, "FATAL: %sn", message);
  286.     fprintf(debug_log, "Squid Cache (Version %s): Terminated abnormally.n",
  287. version_string);
  288.     fflush(debug_log);
  289.     PrintRusage();
  290.     dumpMallocStats();
  291. }
  292. /* fatal */
  293. void
  294. fatal(const char *message)
  295. {
  296.     releaseServerSockets();
  297.     /* check for store_rebuilding flag because fatal() is often
  298.      * used in early initialization phases, long before we ever
  299.      * get to the store log. */
  300.     if (!store_rebuilding)
  301. storeDirWriteCleanLogs(0);
  302.     fatal_common(message);
  303.     exit(shutting_down ? 0 : 1);
  304. }
  305. /* printf-style interface for fatal */
  306. #if STDC_HEADERS
  307. void
  308. fatalf(const char *fmt,...)
  309. {
  310.     va_list args;
  311.     va_start(args, fmt);
  312. #else
  313. void
  314. fatalf(va_alist)
  315.      va_dcl
  316. {
  317.     va_list args;
  318.     const char *fmt = NULL;
  319.     va_start(args);
  320.     fmt = va_arg(args, char *);
  321. #endif
  322.     fatalvf(fmt, args);
  323.     va_end(args);
  324. }
  325. /* used by fatalf */
  326. static void
  327. fatalvf(const char *fmt, va_list args)
  328. {
  329.     static char fatal_str[BUFSIZ];
  330.     vsnprintf(fatal_str, sizeof(fatal_str), fmt, args);
  331.     fatal(fatal_str);
  332. }
  333. /* fatal with dumping core */
  334. void
  335. fatal_dump(const char *message)
  336. {
  337.     releaseServerSockets();
  338.     if (message)
  339. fatal_common(message);
  340.     if (opt_catch_signals)
  341. storeDirWriteCleanLogs(0);
  342.     abort();
  343. }
  344. void
  345. debug_trap(const char *message)
  346. {
  347.     if (!opt_catch_signals)
  348. fatal_dump(message);
  349.     _db_print("WARNING: %sn", message);
  350. }
  351. void
  352. sig_child(int sig)
  353. {
  354. #ifdef _SQUID_NEXT_
  355.     union wait status;
  356. #else
  357.     int status;
  358. #endif
  359.     pid_t pid;
  360.     do {
  361. #ifdef _SQUID_NEXT_
  362. pid = wait3(&status, WNOHANG, NULL);
  363. #else
  364. pid = waitpid(-1, &status, WNOHANG);
  365. #endif
  366. /* no debug() here; bad things happen if the signal is delivered during _db_print() */
  367. #if HAVE_SIGACTION
  368.     } while (pid > 0);
  369. #else
  370.     } while (pid > 0 || (pid < 0 && errno == EINTR));
  371.     signal(sig, sig_child);
  372. #endif
  373. }
  374. const char *
  375. getMyHostname(void)
  376. {
  377.     LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
  378.     static int present = 0;
  379.     const struct hostent *h = NULL;
  380.     char *t = NULL;
  381.     if ((t = Config.visibleHostname) != NULL)
  382. return t;
  383.     /* Get the host name and store it in host to return */
  384.     if (!present) {
  385. host[0] = '';
  386. if (gethostname(host, SQUIDHOSTNAMELEN) == -1) {
  387.     debug(50, 1) ("getMyHostname: gethostname failed: %sn",
  388. xstrerror());
  389.     return NULL;
  390. } else {
  391.     if ((h = gethostbyname(host)) != NULL) {
  392. /* DNS lookup successful */
  393. /* use the official name from DNS lookup */
  394. strcpy(host, h->h_name);
  395.     }
  396.     present = 1;
  397. }
  398.     }
  399.     return host;
  400. }
  401. const char *
  402. uniqueHostname(void)
  403. {
  404.     return Config.uniqueHostname ? Config.uniqueHostname : getMyHostname();
  405. }
  406. void
  407. safeunlink(const char *s, int quiet)
  408. {
  409. #if USE_ASYNC_IO
  410.     aioUnlink(s,
  411. quiet ? NULL : safeunlinkComplete,
  412. quiet ? NULL : xstrdup(s));
  413. #else
  414.     Counter.syscalls.disk.unlinks++;
  415.     if (unlink(s) < 0 && !quiet)
  416. debug(50, 1) ("safeunlink: Couldn't delete %s: %sn", s, xstrerror());
  417. #endif
  418. }
  419. #if USE_ASYNC_IO
  420. static void
  421. safeunlinkComplete(int fd, void *data, int retcode, int errcode)
  422. {
  423.     char *s = data;
  424.     if (retcode < 0) {
  425. errno = errcode;
  426. debug(50, 1) ("safeunlink: Couldn't delete %s. %sn", s, xstrerror());
  427. errno = 0;
  428.     }
  429.     xfree(s);
  430. }
  431. #endif
  432. /* leave a privilegied section. (Give up any privilegies)
  433.  * Routines that need privilegies can rap themselves in enter_suid()
  434.  * and leave_suid()
  435.  * To give upp all posibilites to gain privilegies use no_suid()
  436.  */
  437. void
  438. leave_suid(void)
  439. {
  440.     struct passwd *pwd = NULL;
  441.     struct group *grp = NULL;
  442.     debug(21, 3) ("leave_suid: PID %d calledn", getpid());
  443.     if (geteuid() != 0)
  444. return;
  445.     /* Started as a root, check suid option */
  446.     if (Config.effectiveUser == NULL)
  447. return;
  448.     if ((pwd = getpwnam(Config.effectiveUser)) == NULL)
  449. return;
  450.     if (Config.effectiveGroup && (grp = getgrnam(Config.effectiveGroup))) {
  451. if (setgid(grp->gr_gid) < 0)
  452.     debug(50, 1) ("leave_suid: setgid: %sn", xstrerror());
  453.     } else {
  454. if (setgid(pwd->pw_gid) < 0)
  455.     debug(50, 1) ("leave_suid: setgid: %sn", xstrerror());
  456.     }
  457.     debug(21, 3) ("leave_suid: PID %d giving up root, becoming '%s'n",
  458. getpid(), pwd->pw_name);
  459. #if HAVE_SETRESUID
  460.     if (setresuid(pwd->pw_uid, pwd->pw_uid, 0) < 0)
  461. debug(50, 1) ("leave_suid: setresuid: %sn", xstrerror());
  462. #elif HAVE_SETEUID
  463.     if (seteuid(pwd->pw_uid) < 0)
  464. debug(50, 1) ("leave_suid: seteuid: %sn", xstrerror());
  465. #else
  466.     if (setuid(pwd->pw_uid) < 0)
  467. debug(50, 1) ("leave_suid: setuid: %sn", xstrerror());
  468. #endif
  469. }
  470. /* Enter a privilegied section */
  471. void
  472. enter_suid(void)
  473. {
  474.     debug(21, 3) ("enter_suid: PID %d taking root privelegesn", getpid());
  475. #if HAVE_SETRESUID
  476.     setresuid(-1, 0, -1);
  477. #else
  478.     setuid(0);
  479. #endif
  480. }
  481. /* Give up the posibility to gain privilegies.
  482.  * this should be used before starting a sub process
  483.  */
  484. void
  485. no_suid(void)
  486. {
  487.     uid_t uid;
  488.     leave_suid();
  489.     uid = geteuid();
  490.     debug(21, 3) ("leave_suid: PID %d giving up root priveleges forevern", getpid());
  491. #if HAVE_SETRESUID
  492.     if (setresuid(uid, uid, uid) < 0)
  493. debug(50, 1) ("no_suid: setresuid: %sn", xstrerror());
  494. #else
  495.     setuid(0);
  496.     if (setuid(uid) < 0)
  497. debug(50, 1) ("no_suid: setuid: %sn", xstrerror());
  498. #endif
  499. }
  500. void
  501. writePidFile(void)
  502. {
  503.     int fd;
  504.     const char *f = NULL;
  505.     mode_t old_umask;
  506.     char buf[32];
  507.     if ((f = Config.pidFilename) == NULL)
  508. return;
  509.     if (!strcmp(Config.pidFilename, "none"))
  510. return;
  511.     enter_suid();
  512.     old_umask = umask(022);
  513.     fd = file_open(f, O_WRONLY | O_CREAT | O_TRUNC, NULL, NULL, NULL);
  514.     umask(old_umask);
  515.     leave_suid();
  516.     if (fd < 0) {
  517. debug(50, 0) ("%s: %sn", f, xstrerror());
  518. debug_trap("Could not write pid file");
  519. return;
  520.     }
  521.     snprintf(buf, 32, "%dn", (int) getpid());
  522.     write(fd, buf, strlen(buf));
  523.     file_close(fd);
  524. }
  525. pid_t
  526. readPidFile(void)
  527. {
  528.     FILE *pid_fp = NULL;
  529.     const char *f = Config.pidFilename;
  530.     pid_t pid = -1;
  531.     int i;
  532.     if (f == NULL || !strcmp(Config.pidFilename, "none")) {
  533. fprintf(stderr, "%s: ERROR: No pid file name definedn", appname);
  534. exit(1);
  535.     }
  536.     pid_fp = fopen(f, "r");
  537.     if (pid_fp != NULL) {
  538. pid = 0;
  539. if (fscanf(pid_fp, "%d", &i) == 1)
  540.     pid = (pid_t) i;
  541. fclose(pid_fp);
  542.     } else {
  543. if (errno != ENOENT) {
  544.     fprintf(stderr, "%s: ERROR: Could not read pid filen", appname);
  545.     fprintf(stderr, "t%s: %sn", f, xstrerror());
  546.     exit(1);
  547. }
  548.     }
  549.     return pid;
  550. }
  551. void
  552. setMaxFD(void)
  553. {
  554. #if HAVE_SETRLIMIT
  555.     /* try to use as many file descriptors as possible */
  556.     /* System V uses RLIMIT_NOFILE and BSD uses RLIMIT_OFILE */
  557.     struct rlimit rl;
  558. #if defined(RLIMIT_NOFILE)
  559.     if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
  560. debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %sn", xstrerror());
  561.     } else {
  562. rl.rlim_cur = Squid_MaxFD;
  563. if (rl.rlim_cur > rl.rlim_max)
  564.     Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
  565. if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
  566.     snprintf(tmp_error_buf, ERROR_BUF_SZ,
  567. "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
  568.     fatal_dump(tmp_error_buf);
  569. }
  570.     }
  571. #elif defined(RLIMIT_OFILE)
  572.     if (getrlimit(RLIMIT_OFILE, &rl) < 0) {
  573. debug(50, 0) ("setrlimit: RLIMIT_NOFILE: %sn", xstrerror());
  574.     } else {
  575. rl.rlim_cur = Squid_MaxFD;
  576. if (rl.rlim_cur > rl.rlim_max)
  577.     Squid_MaxFD = rl.rlim_cur = rl.rlim_max;
  578. if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
  579.     snprintf(tmp_error_buf, ERROR_BUF_SZ,
  580. "setrlimit: RLIMIT_OFILE: %s", xstrerror());
  581.     fatal_dump(tmp_error_buf);
  582. }
  583.     }
  584. #endif
  585. #else /* HAVE_SETRLIMIT */
  586.     debug(21, 1) ("setMaxFD: Cannot increase: setrlimit() not supported on this systemn");
  587. #endif /* HAVE_SETRLIMIT */
  588. #if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
  589.     if (getrlimit(RLIMIT_DATA, &rl) < 0) {
  590. debug(50, 0) ("getrlimit: RLIMIT_DATA: %sn", xstrerror());
  591.     } else if (rl.rlim_max > rl.rlim_cur) {
  592. rl.rlim_cur = rl.rlim_max; /* set it to the max */
  593. if (setrlimit(RLIMIT_DATA, &rl) < 0) {
  594.     snprintf(tmp_error_buf, ERROR_BUF_SZ,
  595. "setrlimit: RLIMIT_DATA: %s", xstrerror());
  596.     fatal_dump(tmp_error_buf);
  597. }
  598.     }
  599. #endif /* RLIMIT_DATA */
  600. #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM)
  601.     if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
  602. debug(50, 0) ("getrlimit: RLIMIT_VMEM: %sn", xstrerror());
  603.     } else if (rl.rlim_max > rl.rlim_cur) {
  604. rl.rlim_cur = rl.rlim_max; /* set it to the max */
  605. if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
  606.     snprintf(tmp_error_buf, ERROR_BUF_SZ,
  607. "setrlimit: RLIMIT_VMEM: %s", xstrerror());
  608.     fatal_dump(tmp_error_buf);
  609. }
  610.     }
  611. #endif /* RLIMIT_VMEM */
  612. }
  613. time_t
  614. getCurrentTime(void)
  615. {
  616. #if GETTIMEOFDAY_NO_TZP
  617.     gettimeofday(&current_time);
  618. #else
  619.     gettimeofday(&current_time, NULL);
  620. #endif
  621.     current_dtime = (double) current_time.tv_sec +
  622. (double) current_time.tv_usec / 1000000.0;
  623.     return squid_curtime = current_time.tv_sec;
  624. }
  625. int
  626. percent(int a, int b)
  627. {
  628.     return b ? ((int) (100.0 * a / b + 0.5)) : 0;
  629. }
  630. double
  631. dpercent(double a, double b)
  632. {
  633.     return b ? (100.0 * a / b) : 0.0;
  634. }
  635. void
  636. squid_signal(int sig, SIGHDLR * func, int flags)
  637. {
  638. #if HAVE_SIGACTION
  639.     struct sigaction sa;
  640.     sa.sa_handler = func;
  641.     sa.sa_flags = flags;
  642.     sigemptyset(&sa.sa_mask);
  643.     if (sigaction(sig, &sa, NULL) < 0)
  644. debug(50, 0) ("sigaction: sig=%d func=%p: %sn", sig, func, xstrerror());
  645. #else
  646.     signal(sig, func);
  647. #endif
  648. }
  649. struct in_addr
  650. inaddrFromHostent(const struct hostent *hp)
  651. {
  652.     struct in_addr s;
  653.     xmemcpy(&s.s_addr, hp->h_addr, sizeof(s.s_addr));
  654.     return s;
  655. }
  656. double
  657. doubleAverage(double cur, double new, int N, int max)
  658. {
  659.     if (N > max)
  660. N = max;
  661.     return (cur * (N - 1.0) + new) / N;
  662. }
  663. int
  664. intAverage(int cur, int new, int n, int max)
  665. {
  666.     if (n > max)
  667. n = max;
  668.     return (cur * (n - 1) + new) / n;
  669. }
  670. void
  671. logsFlush(void)
  672. {
  673.     if (debug_log)
  674. fflush(debug_log);
  675.     if (cache_useragent_log)
  676. fflush(cache_useragent_log);
  677. }
  678. char *
  679. checkNullString(char *p)
  680. {
  681.     return p ? p : "(NULL)";
  682. }
  683. void
  684. dlinkAdd(void *data, dlink_node * m, dlink_list * list)
  685. {
  686.     m->data = data;
  687.     m->prev = NULL;
  688.     m->next = list->head;
  689.     if (list->head)
  690. list->head->prev = m;
  691.     list->head = m;
  692.     if (list->tail == NULL)
  693. list->tail = m;
  694. }
  695. void
  696. dlinkAddTail(void *data, dlink_node * m, dlink_list * list)
  697. {
  698.     m->data = data;
  699.     m->next = NULL;
  700.     m->prev = list->tail;
  701.     if (list->tail)
  702. list->tail->next = m;
  703.     list->tail = m;
  704.     if (list->head == NULL)
  705. list->head = m;
  706. }
  707. void
  708. dlinkDelete(dlink_node * m, dlink_list * list)
  709. {
  710.     if (m->next)
  711. m->next->prev = m->prev;
  712.     if (m->prev)
  713. m->prev->next = m->next;
  714.     if (m == list->head)
  715. list->head = m->next;
  716.     if (m == list->tail)
  717. list->tail = m->prev;
  718. }
  719. void
  720. kb_incr(kb_t * k, size_t v)
  721. {
  722.     k->bytes += v;
  723.     k->kb += (k->bytes >> 10);
  724.     k->bytes &= 0x3FF;
  725. }
  726. void
  727. gb_flush(gb_t * g)
  728. {
  729.     g->gb += (g->bytes >> 30);
  730.     g->bytes &= (1 << 30) - 1;
  731. }
  732. double
  733. gb_to_double(const gb_t * g)
  734. {
  735.     return ((double) g->gb) * ((double) (1 << 30)) + ((double) g->bytes);
  736. }
  737. const char *
  738. gb_to_str(const gb_t * g)
  739. {
  740.     /*
  741.      * it is often convenient to call gb_to_str several times for _one_ printf
  742.      */
  743. #define max_cc_calls 5
  744.     typedef char GbBuf[32];
  745.     static GbBuf bufs[max_cc_calls];
  746.     static int call_id = 0;
  747.     double value = gb_to_double(g);
  748.     char *buf = bufs[call_id++];
  749.     /* select format */
  750.     if (value < 1e9)
  751. snprintf(buf, sizeof(GbBuf), "%.2f MB", value / 1e6);
  752.     else if (value < 1e12)
  753. snprintf(buf, sizeof(GbBuf), "%.2f GB", value / 1e9);
  754.     else
  755. snprintf(buf, sizeof(GbBuf), "%.2f TB", value / 1e12);
  756.     return buf;
  757. }
  758. void
  759. debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
  760. {
  761.     MemBuf mb;
  762.     Packer p;
  763.     assert(label && obj && pm);
  764.     memBufDefInit(&mb);
  765.     packerToMemInit(&p, &mb);
  766.     (*pm) (obj, &p);
  767.     debug(section, level) ("%s%s", label, mb.buf);
  768.     packerClean(&p);
  769.     memBufClean(&mb);
  770. }
  771. int
  772. stringHasWhitespace(const char *s)
  773. {
  774.     return (strcspn(s, w_space) != strlen(s));
  775. }