log.c
上传用户:sddyfurun
上传日期:2007-01-04
资源大小:525k
文件大小:8k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /* Copyright (c) 1995,1996,1997 NEC Corporation.  All rights reserved.       */
  2. /*                                                                           */
  3. /* The redistribution, use and modification in source or binary forms of     */
  4. /* this software is subject to the conditions set forth in the copyright     */
  5. /* document ("Copyright") included with this distribution.                   */
  6. /*
  7.  * $Id: log.c,v 1.71.4.5 1998/10/09 16:05:14 steve Exp $
  8.  */
  9. #define __NOLOGUPDATEPROTO
  10. #include "socks5p.h"
  11. #include "log.h"       /* Prototypes & defines.                              */
  12. #include "threads.h"   /* MUTEX & THREAD_SELF                                */
  13. void *S5LogDefaultHandle = NULL;
  14. int   S5LogShowThreadIDS   = 0;
  15. #ifdef HAVE_STDARG_H
  16. #include <stdarg.h>
  17. #define VA_START(a, b) va_start((a), (b))
  18. #define va_alist ...
  19. #define va_dcl
  20. #else
  21. #include <varargs.h>
  22. #define VA_START(a, b) va_start((a))
  23. #endif
  24. #ifdef HAVE_NL_TYPES_H
  25. #include <nl_types.h>
  26. #endif
  27. #ifdef HAVE_SYSLOG_H
  28. #include <syslog.h>
  29. #ifndef LOG_DAEMON
  30. #define LOG_DAEMON LOG_USER
  31. #endif
  32. #endif
  33. typedef struct {
  34. #ifdef HAVE_NL_TYPES_H
  35.     nl_catd catalog;
  36. #define NL_START(x, y)     (x)->catalog = catopen((y), 0)
  37. #define NL_UPDATE(x, e, f) if ((x)->catalog != (nl_catd)-1) (f) = catgets((x)->catalog, 0, (e), (f))
  38. #define NL_CLOSE(x)        if ((x)->catalog != (nl_catd)-1) catclose((x)->catalog); (x)->catalog = (nl_catd)-1
  39. #elif defined(HAVE_DGETTEXT)
  40.     char domain[MAXNAMELEN];
  41. #define NL_START(x, y)     strncpy((x)->domain, name, MAX(MAXNAMELEN, strlen(name))); (x)->domain[MAX(MAXNAMELEN, strlen(name))] = ''
  42. #define NL_UPDATE(x, e, f) (f) = dgettext((x)->domain, (f))
  43. #define NL_CLOSE(x)
  44. #else
  45. #define NL_START(x, y) 
  46. #define NL_UPDATE(x, e, f) 
  47. #define NL_CLOSE(x)
  48. #endif
  49.     int level;
  50.     int how;
  51. } S5LogHandle;
  52. static void replacePercentM(const char *inbuffer, char *outbuffer, int olen) {
  53.     register const char *t2;
  54.     register char *t1, ch;
  55.     if (!outbuffer || !inbuffer) return;
  56.     olen--;
  57.     for (t1 = outbuffer; (ch = *inbuffer) && t1-outbuffer < olen ; ++inbuffer)
  58. if (inbuffer[0] == '%' && inbuffer[1] == 'm') 
  59.     for (++inbuffer, t2 = strerror(GETERRNO()); (t2 && t1-outbuffer < olen) && (*t1 = *t2++); t1++);
  60. else *t1++ = ch;
  61.     
  62.     *t1 = '';
  63. }
  64. void S5LogvUpdate(const void *handle, int level, int msgID, const char *oformat, va_list pvar) {
  65. #define FMT_BUFLEN 2*1024 + 2*10
  66.     char fmt_cpy[FMT_BUFLEN], format[FMT_BUFLEN];
  67.     S5LogHandle *h = (S5LogHandle *)handle;
  68.     int serrno = GETERRNO();
  69. #ifndef HAVE_VSNPRINTF
  70.     static FILE *tmpFile = NULL;
  71. #endif
  72.     *fmt_cpy = '';
  73.     /* If S5LogHandle has not been initialized, do it before we start;       */
  74.     /* Saves the mess of making sure it gets called ahead of time.           */
  75.     if (h == NULL) {
  76. S5LogStart(&S5LogDefaultHandle, -1, -1, "libsocks5");
  77. h = (S5LogHandle *)S5LogDefaultHandle;
  78.     }
  79.     /* If the handle is invalid, don't log.                                  */
  80.     /* If the maximum log level is too low for this message, don't log.      */
  81.     /* If something that we call forces us to log a message, don't log.      */
  82.     if (!h || !(h->how) || h->level == -1 || level > h->level) return;
  83.     /* Change the format if the message is in the catalog...                 */
  84.     NL_UPDATE(h, msgID, oformat);
  85.     if (!oformat) return;
  86.     /* Print the pid & maybe the thread id in format here.  Skip forward if  */
  87.     /* you don't want it later (e.g. if syslogging).                         */
  88.     sprintf(format, "%05d:", (int)getpid());
  89.     if (S5LogShowThreadIDS) sprintf(format+strlen(format), "%06d:", (int)THREAD_SELF());
  90.     strcat(format, " ");
  91.     
  92.     replacePercentM(oformat, format + strlen(format), sizeof(format) - strlen(format));
  93. #ifdef HAVE_VSNPRINTF
  94.     if (vsnprintf(fmt_cpy, FMT_BUFLEN-1, format, pvar) < 0) {
  95. fmt_cpy[FMT_BUFLEN-1] = '';
  96.     }
  97. #else
  98.     /* Original idea for VSPRINTF verification courtesy of Sten Gunterbuer   */
  99.     /* (sten@ERGON.CH) a la BUGTRAQ.  Another solution is to use pipes or a  */
  100.     /* temp file, but I'm not convinced it would be more efficient (2 laps   */
  101.     /* through the formatting versus 1 and a bunch of byte copies through    */
  102.     /* the kernel).                                                          */
  103.     /*                                                                       */
  104.     /* Thanks to Zach Brown (zab@zabbo.net) for finding the problem...       */
  105.     if (tmpFile == NULL && (tmpFile = tmpfile()) == NULL) {
  106. sprintf(fmt_cpy, "ERROR: Unable to verify string for vsprintf");
  107. if ((h->level - 1) > S5_LOG_INFO) h->level = S5_LOG_INFO;
  108. else h->level--;
  109. level = S5_LOG_ERROR;
  110.     } else if (vfprintf(tmpFile, format, pvar) > FMT_BUFLEN-1) {
  111. sprintf(fmt_cpy, "ERROR: String verification failed when trying to log message with format: %s", format);
  112. if ((h->level - 1) > S5_LOG_INFO) h->level = S5_LOG_INFO;
  113. else h->level--;
  114. level = S5_LOG_ERROR;
  115.     } else {
  116. rewind(tmpFile);
  117. vsprintf(fmt_cpy, format, pvar);
  118.     }
  119. #endif
  120.     /* Log to the Local log facility, e.g. Stderr on Unix and maybe a window */
  121.     /* or something on NT.  Neither system can deal with a NULL format so    */
  122.     /* check that here too.                                                  */
  123.     if (h->how & S5_LOG_LOCAL && format) {
  124. fprintf(stderr, "%sn", fmt_cpy);
  125. fflush(stderr);
  126.     }
  127.     /* Log to the system logging facility -- e.g. Syslog on Unix & the       */
  128.     /* EventLog on Windows NT.                                               */
  129.     if (h->how & S5_LOG_SYSTEM) {
  130. #if defined(HAVE_SYSLOG_H) && defined(SYSLOG_FAC)
  131. int slfac, offset = 6; 
  132. if      (level == S5_LOG_ERROR)   slfac = LOG_ERR;
  133. else if (level == S5_LOG_INFO)     slfac = LOG_NOTICE;
  134. else if (level >  S5_LOG_INFO && level < S5_LOG_DEBUG(5))  slfac = LOG_WARNING;
  135. else if (level >  S5_LOG_DEBUG(0) && level < S5_LOG_DEBUG(10))  slfac = LOG_NOTICE;
  136. else if (level >  S5_LOG_DEBUG(5) && level < S5_LOG_DEBUG(15))  slfac = LOG_INFO;
  137. else if (level >= S5_LOG_DEBUG(15)) slfac = LOG_DEBUG;
  138. /* skip "%05d:", and maybe another " "                               */
  139. if (!S5LogShowThreadIDS) offset++;
  140. syslog(slfac, fmt_cpy + offset);
  141. #else
  142. #endif
  143.     }
  144.     SETERRNO(serrno); /* restore errno, just in case...?                     */
  145.     return;
  146. }
  147. void  S5LogUpdate(const void *handle, int level, int msgID, const char *format, va_alist) va_dcl {
  148.     va_list pvar;
  149. #ifdef HAVE_STDARG_H
  150.     va_start(pvar, format);
  151. #else
  152.     VA_START(pvar, format);
  153. #endif
  154.     S5LogvUpdate(handle, level, msgID, format, pvar);
  155.     va_end(pvar);
  156. }
  157. void S5LogStart(void **vhp, int how, int level, const char *name) {
  158.     S5LogHandle **hp = (S5LogHandle **)vhp;
  159.     char buf[1024], *tmp;
  160. /*
  161.     char tbuf[1024];
  162.     time_t now = time(NULL);
  163. */
  164.     sprintf(buf, "%s", name);
  165.     if (!(*hp) && ((*hp) = (S5LogHandle *)malloc(sizeof(S5LogHandle))) == NULL) {
  166. /* no where to store things, so just skip it.                        */
  167. return;
  168.     } else {
  169. if (how == -1) {
  170.     (*hp)->how = 0;
  171.     if (getenv("SOCKS5_LOG_SYSLOG")) (*hp)->how |= S5_LOG_SYSTEM;
  172.       if (getenv("SOCKS5_LOG_STDERR")) (*hp)->how |= S5_LOG_LOCAL;
  173. } else (*hp)->how = how;
  174. if (level == -1) {
  175.     if ((tmp = getenv("SOCKS5_DEBUG"))) {
  176. if (isdigit((int)*tmp)) (*hp)->level = S5_LOG_DEBUG(atoi(tmp));
  177.         else (*hp)->level = S5_LOG_DEBUG(25);
  178.     } else (*hp)->level = -1;
  179. } else (*hp)->level = level;
  180. NL_START(*hp, buf);
  181.     }
  182. #if defined(HAVE_SYSLOG_H) && defined(SYSLOG_FAC)
  183.     /* Only the first person to call this gets to open the log, that way the */
  184.     /* monitor doesn't clobber the server's socks5 name in the logs.         */
  185.     if ((*hp)->how & S5_LOG_SYSTEM){
  186. static int logopened = 0;
  187. if (!logopened) {
  188.     logopened = 1;
  189.     openlog(name, LOG_PID, SYSLOG_FAC);
  190. }
  191.     }
  192. #endif
  193. /* Following code is commented out so that we can remove DontLoop...         */
  194. /*
  195.     if (restart && (*hp)->how != 0) {
  196.      MUTEX_LOCK(lt_mutex);
  197.      strftime(tbuf, sizeof(tbuf), "%c", REAL(localtime)(&now));
  198.      S5LogUpdate((*hp), S5_LOG_DEBUG(0), 0, "%s Logging (re)started at %s", name, tbuf);
  199.      MUTEX_UNLOCK(lt_mutex);
  200.     }
  201. */
  202. }
  203. void S5LogEnd(void *vh) {
  204.     S5LogHandle *h = (S5LogHandle *)vh;
  205.     if (!h) return;
  206.     NL_CLOSE(h);
  207. #if defined(HAVE_SYSLOG_H) && defined(SYSLOG_FAC)
  208.     closelog();
  209. #endif
  210.     
  211.     free(h);
  212. }