nsprpub/pr/src/io/prlog.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "primpl.h"
     8 #include "prenv.h"
     9 #include "prprf.h"
    10 #include <string.h>
    11 #ifdef ANDROID
    12 #include <android/log.h>
    13 #endif
    15 /*
    16  * Lock used to lock the log.
    17  *
    18  * We can't define _PR_LOCK_LOG simply as PR_Lock because PR_Lock may
    19  * contain assertions.  We have to avoid assertions in _PR_LOCK_LOG
    20  * because PR_ASSERT calls PR_LogPrint, which in turn calls _PR_LOCK_LOG.
    21  * This can lead to infinite recursion.
    22  */
    23 static PRLock *_pr_logLock;
    24 #if defined(_PR_PTHREADS) || defined(_PR_BTHREADS)
    25 #define _PR_LOCK_LOG() PR_Lock(_pr_logLock);
    26 #define _PR_UNLOCK_LOG() PR_Unlock(_pr_logLock);
    27 #elif defined(_PR_GLOBAL_THREADS_ONLY)
    28 #define _PR_LOCK_LOG() { _PR_LOCK_LOCK(_pr_logLock)
    29 #define _PR_UNLOCK_LOG() _PR_LOCK_UNLOCK(_pr_logLock); }
    30 #else
    32 #define _PR_LOCK_LOG() \
    33 { \
    34     PRIntn _is; \
    35     PRThread *_me = _PR_MD_CURRENT_THREAD(); \
    36     if (!_PR_IS_NATIVE_THREAD(_me)) \
    37         _PR_INTSOFF(_is); \
    38     _PR_LOCK_LOCK(_pr_logLock)
    40 #define _PR_UNLOCK_LOG() \
    41     _PR_LOCK_UNLOCK(_pr_logLock); \
    42     PR_ASSERT(_me == _PR_MD_CURRENT_THREAD()); \
    43     if (!_PR_IS_NATIVE_THREAD(_me)) \
    44         _PR_INTSON(_is); \
    45 }
    47 #endif
    49 #if defined(XP_PC)
    50 #define strcasecmp stricmp
    51 #endif
    53 /*
    54  * On NT, we can't define _PUT_LOG as PR_Write or _PR_MD_WRITE,
    55  * because every asynchronous file io operation leads to a fiber context
    56  * switch.  So we define _PUT_LOG as fputs (from stdio.h).  A side
    57  * benefit is that fputs handles the LF->CRLF translation.  This
    58  * code can also be used on other platforms with file stream io.
    59  */
    60 #if defined(WIN32) || defined(XP_OS2)
    61 #define _PR_USE_STDIO_FOR_LOGGING
    62 #endif
    64 /*
    65 ** Coerce Win32 log output to use OutputDebugString() when
    66 ** NSPR_LOG_FILE is set to "WinDebug".
    67 */
    68 #if defined(XP_PC)
    69 #define WIN32_DEBUG_FILE (FILE*)-2
    70 #endif
    72 #ifdef WINCE
    73 static void OutputDebugStringA(const char* msg) {
    74     int len = MultiByteToWideChar(CP_ACP, 0, msg, -1, 0, 0);
    75     WCHAR *wMsg = (WCHAR *)PR_Malloc(len * sizeof(WCHAR));
    76     MultiByteToWideChar(CP_ACP, 0, msg, -1, wMsg, len);
    77     OutputDebugStringW(wMsg);
    78     PR_Free(wMsg);
    79 }
    80 #endif
    82 /* Macros used to reduce #ifdef pollution */
    84 #if defined(_PR_USE_STDIO_FOR_LOGGING) && defined(XP_PC)
    85 #define _PUT_LOG(fd, buf, nb) \
    86     PR_BEGIN_MACRO \
    87     if (logFile == WIN32_DEBUG_FILE) { \
    88         char savebyte = buf[nb]; \
    89         buf[nb] = '\0'; \
    90         OutputDebugStringA(buf); \
    91         buf[nb] = savebyte; \
    92     } else { \
    93         fwrite(buf, 1, nb, fd); \
    94         fflush(fd); \
    95     } \
    96     PR_END_MACRO
    97 #elif defined(_PR_USE_STDIO_FOR_LOGGING)
    98 #define _PUT_LOG(fd, buf, nb) {fwrite(buf, 1, nb, fd); fflush(fd);}
    99 #elif defined(ANDROID)
   100 #define _PUT_LOG(fd, buf, nb)                                \
   101     PR_BEGIN_MACRO                                           \
   102     if (fd == _pr_stderr) {                                  \
   103         char savebyte = buf[nb];                             \
   104         buf[nb] = '\0';                                      \
   105         __android_log_write(ANDROID_LOG_INFO, "PRLog", buf); \
   106         buf[nb] = savebyte;                                  \
   107     } else {                                                 \
   108         PR_Write(fd, buf, nb);                               \
   109     }                                                        \
   110     PR_END_MACRO
   111 #elif defined(_PR_PTHREADS)
   112 #define _PUT_LOG(fd, buf, nb) PR_Write(fd, buf, nb)
   113 #else
   114 #define _PUT_LOG(fd, buf, nb) _PR_MD_WRITE(fd, buf, nb)
   115 #endif
   117 /************************************************************************/
   119 static PRLogModuleInfo *logModules;
   121 static char *logBuf = NULL;
   122 static char *logp;
   123 static char *logEndp;
   124 #ifdef _PR_USE_STDIO_FOR_LOGGING
   125 static FILE *logFile = NULL;
   126 #else
   127 static PRFileDesc *logFile = 0;
   128 #endif
   129 static PRBool outputTimeStamp = PR_FALSE;
   130 static PRBool appendToLog = PR_FALSE;
   132 #define LINE_BUF_SIZE           512
   133 #define DEFAULT_BUF_SIZE        16384
   135 #ifdef _PR_NEED_STRCASECMP
   137 /*
   138  * strcasecmp is defined in /usr/ucblib/libucb.a on some platforms
   139  * such as NCR and Unixware.  Linking with both libc and libucb
   140  * may cause some problem, so I just provide our own implementation
   141  * of strcasecmp here.
   142  */
   144 static const unsigned char uc[] =
   145 {
   146     '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
   147     '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
   148     '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
   149     '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
   150     ' ',    '!',    '"',    '#',    '$',    '%',    '&',    '\'',
   151     '(',    ')',    '*',    '+',    ',',    '-',    '.',    '/',
   152     '0',    '1',    '2',    '3',    '4',    '5',    '6',    '7',
   153     '8',    '9',    ':',    ';',    '<',    '=',    '>',    '?',
   154     '@',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
   155     'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
   156     'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
   157     'X',    'Y',    'Z',    '[',    '\\',   ']',    '^',    '_',
   158     '`',    'A',    'B',    'C',    'D',    'E',    'F',    'G',
   159     'H',    'I',    'J',    'K',    'L',    'M',    'N',    'O',
   160     'P',    'Q',    'R',    'S',    'T',    'U',    'V',    'W',
   161     'X',    'Y',    'Z',    '{',    '|',    '}',    '~',    '\177'
   162 };
   164 PRIntn strcasecmp(const char *a, const char *b)
   165 {
   166     const unsigned char *ua = (const unsigned char *)a;
   167     const unsigned char *ub = (const unsigned char *)b;
   169     if( ((const char *)0 == a) || (const char *)0 == b ) 
   170         return (PRIntn)(a-b);
   172     while( (uc[*ua] == uc[*ub]) && ('\0' != *a) )
   173     {
   174         a++;
   175         ua++;
   176         ub++;
   177     }
   179     return (PRIntn)(uc[*ua] - uc[*ub]);
   180 }
   182 #endif /* _PR_NEED_STRCASECMP */
   184 void _PR_InitLog(void)
   185 {
   186     char *ev;
   188     _pr_logLock = PR_NewLock();
   190     ev = PR_GetEnv("NSPR_LOG_MODULES");
   191     if (ev && ev[0]) {
   192         char module[64];  /* Security-Critical: If you change this
   193                            * size, you must also change the sscanf
   194                            * format string to be size-1.
   195                            */
   196         PRBool isSync = PR_FALSE;
   197         PRIntn evlen = strlen(ev), pos = 0;
   198         PRInt32 bufSize = DEFAULT_BUF_SIZE;
   199         while (pos < evlen) {
   200             PRIntn level = 1, count = 0, delta = 0;
   201             count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n",
   202                            module, &delta, &level, &delta);
   203             pos += delta;
   204             if (count == 0) break;
   206             /*
   207             ** If count == 2, then we got module and level. If count
   208             ** == 1, then level defaults to 1 (module enabled).
   209             */
   210             if (strcasecmp(module, "sync") == 0) {
   211                 isSync = PR_TRUE;
   212             } else if (strcasecmp(module, "bufsize") == 0) {
   213                 if (level >= LINE_BUF_SIZE) {
   214                     bufSize = level;
   215                 }
   216             } else if (strcasecmp(module, "timestamp") == 0) {
   217                 outputTimeStamp = PR_TRUE;
   218             } else if (strcasecmp(module, "append") == 0) {
   219                 appendToLog = PR_TRUE;
   220             } else {
   221                 PRLogModuleInfo *lm = logModules;
   222                 PRBool skip_modcheck =
   223                     (0 == strcasecmp (module, "all")) ? PR_TRUE : PR_FALSE;
   225                 while (lm != NULL) {
   226                     if (skip_modcheck) lm -> level = (PRLogModuleLevel)level;
   227                     else if (strcasecmp(module, lm->name) == 0) {
   228                         lm->level = (PRLogModuleLevel)level;
   229                         break;
   230                     }
   231                     lm = lm->next;
   232                 }
   233             }
   234             /*found:*/
   235             count = sscanf(&ev[pos], " , %n", &delta);
   236             pos += delta;
   237             if (count == EOF) break;
   238         }
   239         PR_SetLogBuffering(isSync ? 0 : bufSize);
   241 #ifdef XP_UNIX
   242         if ((getuid() != geteuid()) || (getgid() != getegid())) {
   243             return;
   244         }
   245 #endif /* XP_UNIX */
   247         ev = PR_GetEnv("NSPR_LOG_FILE");
   248         if (ev && ev[0]) {
   249             if (!PR_SetLogFile(ev)) {
   250 #ifdef XP_PC
   251                 char* str = PR_smprintf("Unable to create nspr log file '%s'\n", ev);
   252                 if (str) {
   253                     OutputDebugStringA(str);
   254                     PR_smprintf_free(str);
   255                 }
   256 #else
   257                 fprintf(stderr, "Unable to create nspr log file '%s'\n", ev);
   258 #endif
   259             }
   260         } else {
   261 #ifdef _PR_USE_STDIO_FOR_LOGGING
   262             logFile = stderr;
   263 #else
   264             logFile = _pr_stderr;
   265 #endif
   266         }
   267     }
   268 }
   270 void _PR_LogCleanup(void)
   271 {
   272     PRLogModuleInfo *lm = logModules;
   274     PR_LogFlush();
   276 #ifdef _PR_USE_STDIO_FOR_LOGGING
   277     if (logFile
   278         && logFile != stdout
   279         && logFile != stderr
   280 #ifdef XP_PC
   281         && logFile != WIN32_DEBUG_FILE
   282 #endif
   283         ) {
   284         fclose(logFile);
   285     }
   286 #else
   287     if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
   288         PR_Close(logFile);
   289     }
   290 #endif
   291     logFile = NULL;
   293     if (logBuf)
   294         PR_DELETE(logBuf);
   296     while (lm != NULL) {
   297         PRLogModuleInfo *next = lm->next;
   298         free((/*const*/ char *)lm->name);
   299         PR_Free(lm);
   300         lm = next;
   301     }
   302     logModules = NULL;
   304     if (_pr_logLock) {
   305         PR_DestroyLock(_pr_logLock);
   306         _pr_logLock = NULL;
   307     }
   308 }
   310 static void _PR_SetLogModuleLevel( PRLogModuleInfo *lm )
   311 {
   312     char *ev;
   314     ev = PR_GetEnv("NSPR_LOG_MODULES");
   315     if (ev && ev[0]) {
   316         char module[64];  /* Security-Critical: If you change this
   317                            * size, you must also change the sscanf
   318                            * format string to be size-1.
   319                            */
   320         PRIntn evlen = strlen(ev), pos = 0;
   321         while (pos < evlen) {
   322             PRIntn level = 1, count = 0, delta = 0;
   324             count = sscanf(&ev[pos], "%63[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-]%n:%d%n",
   325                            module, &delta, &level, &delta);
   326             pos += delta;
   327             if (count == 0) break;
   329             /*
   330             ** If count == 2, then we got module and level. If count
   331             ** == 1, then level defaults to 1 (module enabled).
   332             */
   333             if (lm != NULL)
   334             {
   335                 if ((strcasecmp(module, "all") == 0)
   336                     || (strcasecmp(module, lm->name) == 0))
   337                 {
   338                     lm->level = (PRLogModuleLevel)level;
   339                 }
   340             }
   341             count = sscanf(&ev[pos], " , %n", &delta);
   342             pos += delta;
   343             if (count == EOF) break;
   344         }
   345     }
   346 } /* end _PR_SetLogModuleLevel() */
   348 PR_IMPLEMENT(PRLogModuleInfo*) PR_NewLogModule(const char *name)
   349 {
   350     PRLogModuleInfo *lm;
   352         if (!_pr_initialized) _PR_ImplicitInitialization();
   354     lm = PR_NEWZAP(PRLogModuleInfo);
   355     if (lm) {
   356         lm->name = strdup(name);
   357         lm->level = PR_LOG_NONE;
   358         lm->next = logModules;
   359         logModules = lm;
   360         _PR_SetLogModuleLevel(lm);
   361     }
   362     return lm;
   363 }
   365 PR_IMPLEMENT(PRBool) PR_SetLogFile(const char *file)
   366 {
   367 #ifdef _PR_USE_STDIO_FOR_LOGGING
   368     FILE *newLogFile;
   370 #ifdef XP_PC
   371     if ( strcmp( file, "WinDebug") == 0)
   372     {
   373         newLogFile = WIN32_DEBUG_FILE;
   374     }
   375     else
   376 #endif
   377     {
   378         const char *mode = appendToLog ? "a" : "w";
   379         newLogFile = fopen(file, mode);
   380         if (!newLogFile)
   381             return PR_FALSE;
   383 #ifndef WINCE  /* _IONBF does not exist in the Windows Mobile 6 SDK. */
   384         /* We do buffering ourselves. */
   385         setvbuf(newLogFile, NULL, _IONBF, 0);
   386 #endif
   387     }
   388     if (logFile
   389         && logFile != stdout
   390         && logFile != stderr
   391 #ifdef XP_PC
   392         && logFile != WIN32_DEBUG_FILE
   393 #endif
   394         ) {
   395         fclose(logFile);
   396     }
   397     logFile = newLogFile;
   398     return PR_TRUE;
   399 #else
   400     PRFileDesc *newLogFile;
   401     PRIntn flags = PR_WRONLY|PR_CREATE_FILE;
   402     if (appendToLog) {
   403         flags |= PR_APPEND;
   404     } else {
   405         flags |= PR_TRUNCATE;
   406     }
   408     newLogFile = PR_Open(file, flags, 0666);
   409     if (newLogFile) {
   410         if (logFile && logFile != _pr_stdout && logFile != _pr_stderr) {
   411             PR_Close(logFile);
   412         }
   413         logFile = newLogFile;
   414     }
   415     return (PRBool) (newLogFile != 0);
   416 #endif /* _PR_USE_STDIO_FOR_LOGGING */
   417 }
   419 PR_IMPLEMENT(void) PR_SetLogBuffering(PRIntn buffer_size)
   420 {
   421     PR_LogFlush();
   423     if (logBuf)
   424         PR_DELETE(logBuf);
   426     if (buffer_size >= LINE_BUF_SIZE) {
   427         logp = logBuf = (char*) PR_MALLOC(buffer_size);
   428         logEndp = logp + buffer_size;
   429     }
   430 }
   432 PR_IMPLEMENT(void) PR_LogPrint(const char *fmt, ...)
   433 {
   434     va_list ap;
   435     char line[LINE_BUF_SIZE];
   436     char *line_long = NULL;
   437     PRUint32 nb_tid = 0, nb;
   438     PRThread *me;
   439     PRExplodedTime now;
   441     if (!_pr_initialized) _PR_ImplicitInitialization();
   443     if (!logFile) {
   444         return;
   445     }
   447     if (outputTimeStamp) {
   448         PR_ExplodeTime(PR_Now(), PR_GMTParameters, &now);
   449         nb_tid = PR_snprintf(line, sizeof(line)-1,
   450                              "%04d-%02d-%02d %02d:%02d:%02d.%06d UTC - ",
   451                              now.tm_year, now.tm_month + 1, now.tm_mday,
   452                              now.tm_hour, now.tm_min, now.tm_sec,
   453                              now.tm_usec);
   454     }
   456     me = PR_GetCurrentThread();
   457     nb_tid += PR_snprintf(line+nb_tid, sizeof(line)-nb_tid-1, "%ld[%p]: ",
   458 #if defined(_PR_BTHREADS)
   459                           me, me);
   460 #else
   461                           me ? me->id : 0L, me);
   462 #endif
   464     va_start(ap, fmt);
   465     nb = nb_tid + PR_vsnprintf(line+nb_tid, sizeof(line)-nb_tid-1, fmt, ap);
   466     va_end(ap);
   468     /*
   469      * Check if we might have run out of buffer space (in case we have a
   470      * long line), and malloc a buffer just this once.
   471      */
   472     if (nb == sizeof(line)-2) {
   473         va_start(ap, fmt);
   474         line_long = PR_vsmprintf(fmt, ap);
   475         va_end(ap);
   476         /* If this failed, we'll fall back to writing the truncated line. */
   477     }
   479     if (line_long) {
   480         nb = strlen(line_long);
   481         _PR_LOCK_LOG();
   482         if (logBuf != 0) {
   483             _PUT_LOG(logFile, logBuf, logp - logBuf);
   484             logp = logBuf;
   485         }
   486         /*
   487          * Write out the thread id (with an optional timestamp) and the
   488          * malloc'ed buffer.
   489          */
   490         _PUT_LOG(logFile, line, nb_tid);
   491         _PUT_LOG(logFile, line_long, nb);
   492         /* Ensure there is a trailing newline. */
   493         if (!nb || (line_long[nb-1] != '\n')) {
   494             char eol[2];
   495             eol[0] = '\n';
   496             eol[1] = '\0';
   497             _PUT_LOG(logFile, eol, 1);
   498         }
   499         _PR_UNLOCK_LOG();
   500         PR_smprintf_free(line_long);
   501     } else {
   502         /* Ensure there is a trailing newline. */
   503         if (nb && (line[nb-1] != '\n')) {
   504             line[nb++] = '\n';
   505             line[nb] = '\0';
   506         }
   507         _PR_LOCK_LOG();
   508         if (logBuf == 0) {
   509             _PUT_LOG(logFile, line, nb);
   510         } else {
   511             /* If nb can't fit into logBuf, write out logBuf first. */
   512             if (logp + nb > logEndp) {
   513                 _PUT_LOG(logFile, logBuf, logp - logBuf);
   514                 logp = logBuf;
   515             }
   516             /* nb is guaranteed to fit into logBuf. */
   517             memcpy(logp, line, nb);
   518             logp += nb;
   519         }
   520         _PR_UNLOCK_LOG();
   521     }
   522     PR_LogFlush();
   523 }
   525 PR_IMPLEMENT(void) PR_LogFlush(void)
   526 {
   527     if (logBuf && logFile) {
   528         _PR_LOCK_LOG();
   529             if (logp > logBuf) {
   530                 _PUT_LOG(logFile, logBuf, logp - logBuf);
   531                 logp = logBuf;
   532             }
   533         _PR_UNLOCK_LOG();
   534     }
   535 }
   537 PR_IMPLEMENT(void) PR_Abort(void)
   538 {
   539     PR_LogPrint("Aborting");
   540     abort();
   541 }
   543 PR_IMPLEMENT(void) PR_Assert(const char *s, const char *file, PRIntn ln)
   544 {
   545     PR_LogPrint("Assertion failure: %s, at %s:%d\n", s, file, ln);
   546     fprintf(stderr, "Assertion failure: %s, at %s:%d\n", s, file, ln);
   547     fflush(stderr);
   548 #ifdef WIN32
   549     DebugBreak();
   550 #endif
   551 #ifdef XP_OS2
   552     asm("int $3");
   553 #endif
   554     abort();
   555 }

mercurial