Coverage Report

Created: 2023-09-25 06:56

/src/FreeRDP/winpr/libwinpr/utils/wlog/wlog.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * WinPR Logger
4
 *
5
 * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
22
#include <stdio.h>
23
#include <stdarg.h>
24
#include <string.h>
25
26
#include <winpr/crt.h>
27
#include <winpr/assert.h>
28
#include <winpr/print.h>
29
#include <winpr/debug.h>
30
#include <winpr/environment.h>
31
#include <winpr/wlog.h>
32
33
#if defined(ANDROID)
34
#include <android/log.h>
35
#include "../log.h"
36
#endif
37
38
#include "wlog.h"
39
40
typedef struct
41
{
42
  DWORD Level;
43
  LPSTR* Names;
44
  size_t NameCount;
45
} wLogFilter;
46
47
0
#define WLOG_FILTER_NOT_FILTERED -1
48
0
#define WLOG_FILTER_NOT_INITIALIZED -2
49
/**
50
 * References for general logging concepts:
51
 *
52
 * Short introduction to log4j:
53
 * http://logging.apache.org/log4j/1.2/manual.html
54
 *
55
 * logging - Logging facility for Python:
56
 * http://docs.python.org/2/library/logging.html
57
 */
58
59
LPCSTR WLOG_LEVELS[7] = { "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "OFF" };
60
61
static INIT_ONCE _WLogInitialized = INIT_ONCE_STATIC_INIT;
62
static DWORD g_FilterCount = 0;
63
static wLogFilter* g_Filters = NULL;
64
static wLog* g_RootLog = NULL;
65
66
static wLog* WLog_New(LPCSTR name, wLog* rootLogger);
67
static void WLog_Free(wLog* log);
68
static LONG WLog_GetFilterLogLevel(wLog* log);
69
static int WLog_ParseLogLevel(LPCSTR level);
70
static BOOL WLog_ParseFilter(wLog* root, wLogFilter* filter, LPCSTR name);
71
static BOOL WLog_ParseFilters(wLog* root);
72
static wLog* WLog_Get_int(wLog* root, LPCSTR name);
73
74
#if !defined(_WIN32)
75
static void WLog_Uninit_(void) __attribute__((destructor));
76
#endif
77
78
static void WLog_Uninit_(void)
79
0
{
80
0
  DWORD index;
81
0
  wLog* child = NULL;
82
0
  wLog* root = g_RootLog;
83
84
0
  if (!root)
85
0
    return;
86
87
0
  for (index = 0; index < root->ChildrenCount; index++)
88
0
  {
89
0
    child = root->Children[index];
90
0
    WLog_Free(child);
91
0
  }
92
93
0
  WLog_Free(root);
94
0
  g_RootLog = NULL;
95
0
}
96
97
static void WLog_Lock(wLog* log)
98
0
{
99
0
  WINPR_ASSERT(log);
100
0
  EnterCriticalSection(&log->lock);
101
0
}
102
103
static void WLog_Unlock(wLog* log)
104
0
{
105
0
  WINPR_ASSERT(log);
106
0
  LeaveCriticalSection(&log->lock);
107
0
}
108
109
static BOOL CALLBACK WLog_InitializeRoot(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context)
110
0
{
111
0
  char* env;
112
0
  DWORD nSize;
113
0
  DWORD logAppenderType;
114
0
  LPCSTR appender = "WLOG_APPENDER";
115
116
0
  WINPR_UNUSED(InitOnce);
117
0
  WINPR_UNUSED(Parameter);
118
0
  WINPR_UNUSED(Context);
119
120
0
  if (!(g_RootLog = WLog_New("", NULL)))
121
0
    return FALSE;
122
123
0
  g_RootLog->IsRoot = TRUE;
124
0
  logAppenderType = WLOG_APPENDER_CONSOLE;
125
0
  nSize = GetEnvironmentVariableA(appender, NULL, 0);
126
127
0
  if (nSize)
128
0
  {
129
0
    env = (LPSTR)malloc(nSize);
130
131
0
    if (!env)
132
0
      goto fail;
133
134
0
    if (GetEnvironmentVariableA(appender, env, nSize) != nSize - 1)
135
0
    {
136
0
      fprintf(stderr, "%s environment variable modified in my back", appender);
137
0
      free(env);
138
0
      goto fail;
139
0
    }
140
141
0
    if (_stricmp(env, "CONSOLE") == 0)
142
0
      logAppenderType = WLOG_APPENDER_CONSOLE;
143
0
    else if (_stricmp(env, "FILE") == 0)
144
0
      logAppenderType = WLOG_APPENDER_FILE;
145
0
    else if (_stricmp(env, "BINARY") == 0)
146
0
      logAppenderType = WLOG_APPENDER_BINARY;
147
148
0
#ifdef WINPR_HAVE_SYSLOG_H
149
0
    else if (_stricmp(env, "SYSLOG") == 0)
150
0
      logAppenderType = WLOG_APPENDER_SYSLOG;
151
152
0
#endif /* WINPR_HAVE_SYSLOG_H */
153
#ifdef WINPR_HAVE_JOURNALD_H
154
    else if (_stricmp(env, "JOURNALD") == 0)
155
      logAppenderType = WLOG_APPENDER_JOURNALD;
156
157
#endif
158
0
    else if (_stricmp(env, "UDP") == 0)
159
0
      logAppenderType = WLOG_APPENDER_UDP;
160
161
0
    free(env);
162
0
  }
163
164
0
  if (!WLog_SetLogAppenderType(g_RootLog, logAppenderType))
165
0
    goto fail;
166
167
0
  if (!WLog_ParseFilters(g_RootLog))
168
0
    goto fail;
169
170
0
  atexit(WLog_Uninit_);
171
172
0
  return TRUE;
173
0
fail:
174
0
  WLog_Uninit_();
175
0
  return FALSE;
176
0
}
177
178
static BOOL log_recursion(LPCSTR file, LPCSTR fkt, size_t line)
179
0
{
180
0
  BOOL status = FALSE;
181
0
  char** msg = NULL;
182
0
  size_t used, i;
183
0
  void* bt = winpr_backtrace(20);
184
#if defined(ANDROID)
185
  LPCSTR tag = WINPR_TAG("utils.wlog");
186
#endif
187
188
0
  if (!bt)
189
0
    return FALSE;
190
191
0
  msg = winpr_backtrace_symbols(bt, &used);
192
193
0
  if (!msg)
194
0
    goto out;
195
196
#if defined(ANDROID)
197
198
  if (__android_log_print(ANDROID_LOG_FATAL, tag, "Recursion detected!!!") < 0)
199
    goto out;
200
201
  if (__android_log_print(ANDROID_LOG_FATAL, tag, "Check %s [%s:%zu]", fkt, file, line) < 0)
202
    goto out;
203
204
  for (i = 0; i < used; i++)
205
    if (__android_log_print(ANDROID_LOG_FATAL, tag, "%zu: %s", i, msg[i]) < 0)
206
      goto out;
207
208
#else
209
210
0
  if (fprintf(stderr, "[%s]: Recursion detected!\n", fkt) < 0)
211
0
    goto out;
212
213
0
  if (fprintf(stderr, "[%s]: Check %s:%" PRIuz "\n", fkt, file, line) < 0)
214
0
    goto out;
215
216
0
  for (i = 0; i < used; i++)
217
0
    if (fprintf(stderr, "%s: %" PRIuz ": %s\n", fkt, i, msg[i]) < 0)
218
0
      goto out;
219
220
0
#endif
221
0
  status = TRUE;
222
0
out:
223
0
  free(msg);
224
0
  winpr_backtrace_free(bt);
225
0
  return status;
226
0
}
227
228
static BOOL WLog_Write(wLog* log, wLogMessage* message)
229
0
{
230
0
  BOOL status = FALSE;
231
0
  wLogAppender* appender;
232
0
  appender = WLog_GetLogAppender(log);
233
234
0
  if (!appender)
235
0
    return FALSE;
236
237
0
  if (!appender->active)
238
0
    if (!WLog_OpenAppender(log))
239
0
      return FALSE;
240
241
0
  EnterCriticalSection(&appender->lock);
242
243
0
  if (appender->WriteMessage)
244
0
  {
245
0
    if (appender->recursive)
246
0
      status = log_recursion(message->FileName, message->FunctionName, message->LineNumber);
247
0
    else
248
0
    {
249
0
      appender->recursive = TRUE;
250
0
      status = appender->WriteMessage(log, appender, message);
251
0
      appender->recursive = FALSE;
252
0
    }
253
0
  }
254
255
0
  LeaveCriticalSection(&appender->lock);
256
0
  return status;
257
0
}
258
259
static BOOL WLog_WriteData(wLog* log, wLogMessage* message)
260
0
{
261
0
  BOOL status;
262
0
  wLogAppender* appender;
263
0
  appender = WLog_GetLogAppender(log);
264
265
0
  if (!appender)
266
0
    return FALSE;
267
268
0
  if (!appender->active)
269
0
    if (!WLog_OpenAppender(log))
270
0
      return FALSE;
271
272
0
  if (!appender->WriteDataMessage)
273
0
    return FALSE;
274
275
0
  EnterCriticalSection(&appender->lock);
276
277
0
  if (appender->recursive)
278
0
    status = log_recursion(message->FileName, message->FunctionName, message->LineNumber);
279
0
  else
280
0
  {
281
0
    appender->recursive = TRUE;
282
0
    status = appender->WriteDataMessage(log, appender, message);
283
0
    appender->recursive = FALSE;
284
0
  }
285
286
0
  LeaveCriticalSection(&appender->lock);
287
0
  return status;
288
0
}
289
290
static BOOL WLog_WriteImage(wLog* log, wLogMessage* message)
291
0
{
292
0
  BOOL status;
293
0
  wLogAppender* appender;
294
0
  appender = WLog_GetLogAppender(log);
295
296
0
  if (!appender)
297
0
    return FALSE;
298
299
0
  if (!appender->active)
300
0
    if (!WLog_OpenAppender(log))
301
0
      return FALSE;
302
303
0
  if (!appender->WriteImageMessage)
304
0
    return FALSE;
305
306
0
  EnterCriticalSection(&appender->lock);
307
308
0
  if (appender->recursive)
309
0
    status = log_recursion(message->FileName, message->FunctionName, message->LineNumber);
310
0
  else
311
0
  {
312
0
    appender->recursive = TRUE;
313
0
    status = appender->WriteImageMessage(log, appender, message);
314
0
    appender->recursive = FALSE;
315
0
  }
316
317
0
  LeaveCriticalSection(&appender->lock);
318
0
  return status;
319
0
}
320
321
static BOOL WLog_WritePacket(wLog* log, wLogMessage* message)
322
0
{
323
0
  BOOL status;
324
0
  wLogAppender* appender;
325
0
  appender = WLog_GetLogAppender(log);
326
327
0
  if (!appender)
328
0
    return FALSE;
329
330
0
  if (!appender->active)
331
0
    if (!WLog_OpenAppender(log))
332
0
      return FALSE;
333
334
0
  if (!appender->WritePacketMessage)
335
0
    return FALSE;
336
337
0
  EnterCriticalSection(&appender->lock);
338
339
0
  if (appender->recursive)
340
0
    status = log_recursion(message->FileName, message->FunctionName, message->LineNumber);
341
0
  else
342
0
  {
343
0
    appender->recursive = TRUE;
344
0
    status = appender->WritePacketMessage(log, appender, message);
345
0
    appender->recursive = FALSE;
346
0
  }
347
348
0
  LeaveCriticalSection(&appender->lock);
349
0
  return status;
350
0
}
351
352
BOOL WLog_PrintMessageVA(wLog* log, DWORD type, DWORD level, size_t line, const char* file,
353
                         const char* function, va_list args)
354
0
{
355
0
  BOOL status = FALSE;
356
0
  wLogMessage message = { 0 };
357
0
  message.Type = type;
358
0
  message.Level = level;
359
0
  message.LineNumber = line;
360
0
  message.FileName = file;
361
0
  message.FunctionName = function;
362
363
0
  switch (type)
364
0
  {
365
0
    case WLOG_MESSAGE_TEXT:
366
0
      message.FormatString = va_arg(args, const char*);
367
368
0
      if (!strchr(message.FormatString, '%'))
369
0
      {
370
0
        message.TextString = message.FormatString;
371
0
        status = WLog_Write(log, &message);
372
0
      }
373
0
      else
374
0
      {
375
0
        char formattedLogMessage[WLOG_MAX_STRING_SIZE] = { 0 };
376
377
0
        if (vsnprintf(formattedLogMessage, WLOG_MAX_STRING_SIZE - 1, message.FormatString,
378
0
                      args) < 0)
379
0
          return FALSE;
380
381
0
        message.TextString = formattedLogMessage;
382
0
        status = WLog_Write(log, &message);
383
0
      }
384
385
0
      break;
386
387
0
    case WLOG_MESSAGE_DATA:
388
0
      message.Data = va_arg(args, void*);
389
0
      message.Length = va_arg(args, size_t);
390
0
      status = WLog_WriteData(log, &message);
391
0
      break;
392
393
0
    case WLOG_MESSAGE_IMAGE:
394
0
      message.ImageData = va_arg(args, void*);
395
0
      message.ImageWidth = va_arg(args, size_t);
396
0
      message.ImageHeight = va_arg(args, size_t);
397
0
      message.ImageBpp = va_arg(args, size_t);
398
0
      status = WLog_WriteImage(log, &message);
399
0
      break;
400
401
0
    case WLOG_MESSAGE_PACKET:
402
0
      message.PacketData = va_arg(args, void*);
403
0
      message.PacketLength = va_arg(args, size_t);
404
0
      message.PacketFlags = va_arg(args, unsigned);
405
0
      status = WLog_WritePacket(log, &message);
406
0
      break;
407
408
0
    default:
409
0
      break;
410
0
  }
411
412
0
  return status;
413
0
}
414
415
BOOL WLog_PrintMessage(wLog* log, DWORD type, DWORD level, size_t line, const char* file,
416
                       const char* function, ...)
417
0
{
418
0
  BOOL status;
419
0
  va_list args;
420
0
  va_start(args, function);
421
0
  status = WLog_PrintMessageVA(log, type, level, line, file, function, args);
422
0
  va_end(args);
423
0
  return status;
424
0
}
425
426
DWORD WLog_GetLogLevel(wLog* log)
427
0
{
428
0
  if (!log)
429
0
    return WLOG_OFF;
430
431
0
  if (log->FilterLevel <= WLOG_FILTER_NOT_INITIALIZED)
432
0
    log->FilterLevel = WLog_GetFilterLogLevel(log);
433
434
0
  if (log->FilterLevel > WLOG_FILTER_NOT_FILTERED)
435
0
    return (DWORD)log->FilterLevel;
436
0
  else if (log->Level == WLOG_LEVEL_INHERIT)
437
0
    log->Level = WLog_GetLogLevel(log->Parent);
438
439
0
  return log->Level;
440
0
}
441
442
BOOL WLog_IsLevelActive(wLog* _log, DWORD _log_level)
443
0
{
444
0
  DWORD level;
445
446
0
  if (!_log)
447
0
    return FALSE;
448
449
0
  level = WLog_GetLogLevel(_log);
450
451
0
  if (level == WLOG_OFF)
452
0
    return FALSE;
453
454
0
  return _log_level >= level;
455
0
}
456
457
BOOL WLog_SetStringLogLevel(wLog* log, LPCSTR level)
458
0
{
459
0
  int lvl;
460
461
0
  if (!log || !level)
462
0
    return FALSE;
463
464
0
  lvl = WLog_ParseLogLevel(level);
465
466
0
  if (lvl < 0)
467
0
    return FALSE;
468
469
0
  return WLog_SetLogLevel(log, (DWORD)lvl);
470
0
}
471
472
static BOOL WLog_reset_log_filters(wLog* log)
473
0
{
474
0
  DWORD x;
475
476
0
  if (!log)
477
0
    return FALSE;
478
479
0
  log->FilterLevel = WLOG_FILTER_NOT_INITIALIZED;
480
481
0
  for (x = 0; x < log->ChildrenCount; x++)
482
0
  {
483
0
    wLog* child = log->Children[x];
484
485
0
    if (!WLog_reset_log_filters(child))
486
0
      return FALSE;
487
0
  }
488
489
0
  return TRUE;
490
0
}
491
492
static BOOL WLog_AddStringLogFilters_int(wLog* root, LPCSTR filter)
493
0
{
494
0
  LPSTR p;
495
0
  LPCSTR filterStr;
496
497
0
  if (!filter)
498
0
    return FALSE;
499
500
0
  DWORD count = 1;
501
0
  LPCSTR cpp = filter;
502
503
0
  while ((cpp = strchr(cpp, ',')) != NULL)
504
0
  {
505
0
    count++;
506
0
    cpp++;
507
0
  }
508
509
0
  DWORD pos = g_FilterCount;
510
0
  DWORD size = g_FilterCount + count;
511
0
  wLogFilter* tmp = (wLogFilter*)realloc(g_Filters, size * sizeof(wLogFilter));
512
513
0
  if (!tmp)
514
0
    return FALSE;
515
516
0
  g_Filters = tmp;
517
0
  LPSTR cp = (LPSTR)_strdup(filter);
518
519
0
  if (!cp)
520
0
    return FALSE;
521
522
0
  p = cp;
523
0
  filterStr = cp;
524
525
0
  do
526
0
  {
527
0
    p = strchr(p, ',');
528
529
0
    if (p)
530
0
      *p = '\0';
531
532
0
    if (pos < size)
533
0
    {
534
0
      if (!WLog_ParseFilter(root, &g_Filters[pos++], filterStr))
535
0
      {
536
0
        free(cp);
537
0
        return FALSE;
538
0
      }
539
0
    }
540
0
    else
541
0
      break;
542
543
0
    if (p)
544
0
    {
545
0
      filterStr = p + 1;
546
0
      p++;
547
0
    }
548
0
  } while (p != NULL);
549
550
0
  g_FilterCount = size;
551
0
  free(cp);
552
0
  return WLog_reset_log_filters(root);
553
0
}
554
555
BOOL WLog_AddStringLogFilters(LPCSTR filter)
556
0
{
557
  /* Ensure logger is initialized */
558
0
  wLog* root = WLog_GetRoot();
559
0
  return WLog_AddStringLogFilters_int(root, filter);
560
0
}
561
562
static BOOL WLog_UpdateInheritLevel(wLog* log, DWORD logLevel)
563
0
{
564
0
  if (!log)
565
0
    return FALSE;
566
567
0
  if (log->inherit)
568
0
  {
569
0
    DWORD x;
570
0
    log->Level = logLevel;
571
572
0
    for (x = 0; x < log->ChildrenCount; x++)
573
0
    {
574
0
      wLog* child = log->Children[x];
575
576
0
      if (!WLog_UpdateInheritLevel(child, logLevel))
577
0
        return FALSE;
578
0
    }
579
0
  }
580
581
0
  return TRUE;
582
0
}
583
584
BOOL WLog_SetLogLevel(wLog* log, DWORD logLevel)
585
0
{
586
0
  DWORD x;
587
588
0
  if (!log)
589
0
    return FALSE;
590
591
0
  if ((logLevel > WLOG_OFF) && (logLevel != WLOG_LEVEL_INHERIT))
592
0
    logLevel = WLOG_OFF;
593
594
0
  log->Level = logLevel;
595
0
  log->inherit = (logLevel == WLOG_LEVEL_INHERIT) ? TRUE : FALSE;
596
597
0
  for (x = 0; x < log->ChildrenCount; x++)
598
0
  {
599
0
    wLog* child = log->Children[x];
600
601
0
    if (!WLog_UpdateInheritLevel(child, logLevel))
602
0
      return FALSE;
603
0
  }
604
605
0
  return WLog_reset_log_filters(log);
606
0
}
607
608
int WLog_ParseLogLevel(LPCSTR level)
609
0
{
610
0
  int iLevel = -1;
611
612
0
  if (!level)
613
0
    return -1;
614
615
0
  if (_stricmp(level, "TRACE") == 0)
616
0
    iLevel = WLOG_TRACE;
617
0
  else if (_stricmp(level, "DEBUG") == 0)
618
0
    iLevel = WLOG_DEBUG;
619
0
  else if (_stricmp(level, "INFO") == 0)
620
0
    iLevel = WLOG_INFO;
621
0
  else if (_stricmp(level, "WARN") == 0)
622
0
    iLevel = WLOG_WARN;
623
0
  else if (_stricmp(level, "ERROR") == 0)
624
0
    iLevel = WLOG_ERROR;
625
0
  else if (_stricmp(level, "FATAL") == 0)
626
0
    iLevel = WLOG_FATAL;
627
0
  else if (_stricmp(level, "OFF") == 0)
628
0
    iLevel = WLOG_OFF;
629
630
0
  return iLevel;
631
0
}
632
633
BOOL WLog_ParseFilter(wLog* root, wLogFilter* filter, LPCSTR name)
634
0
{
635
0
  const char* pc;
636
0
  char* p;
637
0
  char* q;
638
0
  size_t count;
639
0
  LPSTR names;
640
0
  int iLevel;
641
0
  count = 1;
642
643
0
  WINPR_UNUSED(root);
644
645
0
  if (!name)
646
0
    return FALSE;
647
648
0
  pc = name;
649
650
0
  if (pc)
651
0
  {
652
0
    while ((pc = strchr(pc, '.')) != NULL)
653
0
    {
654
0
      count++;
655
0
      pc++;
656
0
    }
657
0
  }
658
659
0
  names = _strdup(name);
660
661
0
  if (!names)
662
0
    return FALSE;
663
664
0
  filter->NameCount = count;
665
0
  filter->Names = (LPSTR*)calloc((count + 1UL), sizeof(LPSTR));
666
667
0
  if (!filter->Names)
668
0
  {
669
0
    free(names);
670
0
    filter->NameCount = 0;
671
0
    return FALSE;
672
0
  }
673
674
0
  filter->Names[count] = NULL;
675
0
  count = 0;
676
0
  p = (char*)names;
677
0
  filter->Names[count++] = p;
678
0
  q = strrchr(p, ':');
679
680
0
  if (!q)
681
0
  {
682
0
    free(names);
683
0
    free(filter->Names);
684
0
    filter->Names = NULL;
685
0
    filter->NameCount = 0;
686
0
    return FALSE;
687
0
  }
688
689
0
  *q = '\0';
690
0
  q++;
691
0
  iLevel = WLog_ParseLogLevel(q);
692
693
0
  if (iLevel < 0)
694
0
  {
695
0
    free(names);
696
0
    free(filter->Names);
697
0
    filter->Names = NULL;
698
0
    filter->NameCount = 0;
699
0
    return FALSE;
700
0
  }
701
702
0
  filter->Level = (DWORD)iLevel;
703
704
0
  while ((p = strchr(p, '.')) != NULL)
705
0
  {
706
0
    if (count < filter->NameCount)
707
0
      filter->Names[count++] = p + 1;
708
709
0
    *p = '\0';
710
0
    p++;
711
0
  }
712
713
0
  return TRUE;
714
0
}
715
716
BOOL WLog_ParseFilters(wLog* root)
717
0
{
718
0
  LPCSTR filter = "WLOG_FILTER";
719
0
  BOOL res = FALSE;
720
0
  char* env;
721
0
  DWORD nSize;
722
0
  free(g_Filters);
723
0
  g_Filters = NULL;
724
0
  g_FilterCount = 0;
725
0
  nSize = GetEnvironmentVariableA(filter, NULL, 0);
726
727
0
  if (nSize < 1)
728
0
    return TRUE;
729
730
0
  env = (LPSTR)malloc(nSize);
731
732
0
  if (!env)
733
0
    return FALSE;
734
735
0
  if (GetEnvironmentVariableA(filter, env, nSize) == nSize - 1)
736
0
    res = WLog_AddStringLogFilters_int(root, env);
737
738
0
  free(env);
739
0
  return res;
740
0
}
741
742
LONG WLog_GetFilterLogLevel(wLog* log)
743
0
{
744
0
  DWORD i, j;
745
0
  BOOL match = FALSE;
746
747
0
  if (log->FilterLevel >= 0)
748
0
    return log->FilterLevel;
749
750
0
  log->FilterLevel = WLOG_FILTER_NOT_FILTERED;
751
0
  for (i = 0; i < g_FilterCount; i++)
752
0
  {
753
0
    const wLogFilter* filter = &g_Filters[i];
754
0
    for (j = 0; j < filter->NameCount; j++)
755
0
    {
756
0
      if (j >= log->NameCount)
757
0
        break;
758
759
0
      if (_stricmp(filter->Names[j], "*") == 0)
760
0
      {
761
0
        match = TRUE;
762
0
        log->FilterLevel = filter->Level;
763
0
        break;
764
0
      }
765
766
0
      if (_stricmp(filter->Names[j], log->Names[j]) != 0)
767
0
        break;
768
769
0
      if (j == (log->NameCount - 1))
770
0
      {
771
0
        match = log->NameCount == filter->NameCount;
772
0
        if (match)
773
0
          log->FilterLevel = filter->Level;
774
0
        break;
775
0
      }
776
0
    }
777
778
0
    if (match)
779
0
      break;
780
0
  }
781
782
0
  return log->FilterLevel;
783
0
}
784
785
static BOOL WLog_ParseName(wLog* log, LPCSTR name)
786
0
{
787
0
  const char* cp = name;
788
0
  char* p;
789
0
  size_t count = 1;
790
0
  LPSTR names;
791
792
0
  while ((cp = strchr(cp, '.')) != NULL)
793
0
  {
794
0
    count++;
795
0
    cp++;
796
0
  }
797
798
0
  names = _strdup(name);
799
800
0
  if (!names)
801
0
    return FALSE;
802
803
0
  log->NameCount = count;
804
0
  log->Names = (LPSTR*)calloc((count + 1UL), sizeof(LPSTR));
805
806
0
  if (!log->Names)
807
0
  {
808
0
    free(names);
809
0
    return FALSE;
810
0
  }
811
812
0
  log->Names[count] = NULL;
813
0
  count = 0;
814
0
  p = (char*)names;
815
0
  log->Names[count++] = p;
816
817
0
  while ((p = strchr(p, '.')) != NULL)
818
0
  {
819
0
    if (count < log->NameCount)
820
0
      log->Names[count++] = p + 1;
821
822
0
    *p = '\0';
823
0
    p++;
824
0
  }
825
826
0
  return TRUE;
827
0
}
828
829
wLog* WLog_New(LPCSTR name, wLog* rootLogger)
830
0
{
831
0
  wLog* log = NULL;
832
0
  char* env = NULL;
833
0
  DWORD nSize;
834
0
  int iLevel;
835
0
  log = (wLog*)calloc(1, sizeof(wLog));
836
837
0
  if (!log)
838
0
    return NULL;
839
840
0
  log->Name = _strdup(name);
841
842
0
  if (!log->Name)
843
0
    goto out_fail;
844
845
0
  if (!WLog_ParseName(log, name))
846
0
    goto out_fail;
847
848
0
  log->Parent = rootLogger;
849
0
  log->ChildrenCount = 0;
850
0
  log->ChildrenSize = 16;
851
0
  log->FilterLevel = WLOG_FILTER_NOT_INITIALIZED;
852
853
0
  if (!(log->Children = (wLog**)calloc(log->ChildrenSize, sizeof(wLog*))))
854
0
    goto out_fail;
855
856
0
  log->Appender = NULL;
857
858
0
  if (rootLogger)
859
0
  {
860
0
    log->Level = WLOG_LEVEL_INHERIT;
861
0
    log->inherit = TRUE;
862
0
  }
863
0
  else
864
0
  {
865
0
    LPCSTR level = "WLOG_LEVEL";
866
0
    log->Level = WLOG_INFO;
867
0
    nSize = GetEnvironmentVariableA(level, NULL, 0);
868
869
0
    if (nSize)
870
0
    {
871
0
      env = (LPSTR)malloc(nSize);
872
873
0
      if (!env)
874
0
        goto out_fail;
875
876
0
      if (GetEnvironmentVariableA(level, env, nSize) != nSize - 1)
877
0
      {
878
0
        fprintf(stderr, "%s environment variable changed in my back !\n", level);
879
0
        free(env);
880
0
        goto out_fail;
881
0
      }
882
883
0
      iLevel = WLog_ParseLogLevel(env);
884
0
      free(env);
885
886
0
      if (iLevel >= 0)
887
0
      {
888
0
        if (!WLog_SetLogLevel(log, (DWORD)iLevel))
889
0
          goto out_fail;
890
0
      }
891
0
    }
892
0
  }
893
894
0
  iLevel = WLog_GetFilterLogLevel(log);
895
896
0
  if (iLevel >= 0)
897
0
  {
898
0
    if (!WLog_SetLogLevel(log, (DWORD)iLevel))
899
0
      goto out_fail;
900
0
  }
901
902
0
  InitializeCriticalSectionAndSpinCount(&log->lock, 4000);
903
904
0
  return log;
905
0
out_fail:
906
0
  free(log->Children);
907
0
  free(log->Name);
908
0
  free(log);
909
0
  return NULL;
910
0
}
911
912
void WLog_Free(wLog* log)
913
0
{
914
0
  if (log)
915
0
  {
916
0
    if (log->Appender)
917
0
    {
918
0
      WLog_Appender_Free(log, log->Appender);
919
0
      log->Appender = NULL;
920
0
    }
921
922
0
    free(log->Name);
923
0
    free(log->Names[0]);
924
0
    free(log->Names);
925
0
    free(log->Children);
926
0
    DeleteCriticalSection(&log->lock);
927
0
    free(log);
928
0
  }
929
0
}
930
931
wLog* WLog_GetRoot(void)
932
0
{
933
0
  if (!InitOnceExecuteOnce(&_WLogInitialized, WLog_InitializeRoot, NULL, NULL))
934
0
    return NULL;
935
936
0
  return g_RootLog;
937
0
}
938
939
static BOOL WLog_AddChild(wLog* parent, wLog* child)
940
0
{
941
0
  BOOL status = FALSE;
942
943
0
  WLog_Lock(parent);
944
945
0
  if (parent->ChildrenCount >= parent->ChildrenSize)
946
0
  {
947
0
    wLog** tmp;
948
0
    parent->ChildrenSize *= 2;
949
950
0
    if (!parent->ChildrenSize)
951
0
    {
952
0
      if (parent->Children)
953
0
        free(parent->Children);
954
955
0
      parent->Children = NULL;
956
0
    }
957
0
    else
958
0
    {
959
0
      tmp = (wLog**)realloc(parent->Children, sizeof(wLog*) * parent->ChildrenSize);
960
961
0
      if (!tmp)
962
0
      {
963
0
        if (parent->Children)
964
0
          free(parent->Children);
965
966
0
        parent->Children = NULL;
967
0
        goto exit;
968
0
      }
969
970
0
      parent->Children = tmp;
971
0
    }
972
0
  }
973
974
0
  if (!parent->Children)
975
0
    goto exit;
976
977
0
  parent->Children[parent->ChildrenCount++] = child;
978
0
  child->Parent = parent;
979
980
0
  WLog_Unlock(parent);
981
982
0
  status = TRUE;
983
0
exit:
984
0
  return status;
985
0
}
986
987
static wLog* WLog_FindChild(wLog* root, LPCSTR name)
988
0
{
989
0
  DWORD index;
990
0
  wLog* child = NULL;
991
0
  BOOL found = FALSE;
992
993
0
  if (!root)
994
0
    return NULL;
995
996
0
  WLog_Lock(root);
997
998
0
  for (index = 0; index < root->ChildrenCount; index++)
999
0
  {
1000
0
    child = root->Children[index];
1001
1002
0
    if (strcmp(child->Name, name) == 0)
1003
0
    {
1004
0
      found = TRUE;
1005
0
      break;
1006
0
    }
1007
0
  }
1008
1009
0
  WLog_Unlock(root);
1010
1011
0
  return (found) ? child : NULL;
1012
0
}
1013
1014
static wLog* WLog_Get_int(wLog* root, LPCSTR name)
1015
0
{
1016
0
  wLog* log;
1017
1018
0
  if (!(log = WLog_FindChild(root, name)))
1019
0
  {
1020
0
    if (!root)
1021
0
      return NULL;
1022
1023
0
    if (!(log = WLog_New(name, root)))
1024
0
      return NULL;
1025
1026
0
    if (!WLog_AddChild(root, log))
1027
0
    {
1028
0
      WLog_Free(log);
1029
0
      return NULL;
1030
0
    }
1031
0
  }
1032
1033
0
  return log;
1034
0
}
1035
1036
wLog* WLog_Get(LPCSTR name)
1037
0
{
1038
0
  wLog* root = WLog_GetRoot();
1039
0
  return WLog_Get_int(root, name);
1040
0
}
1041
1042
#if defined(WITH_WINPR_DEPRECATED)
1043
BOOL WLog_Init(void)
1044
{
1045
  return WLog_GetRoot() != NULL;
1046
}
1047
1048
BOOL WLog_Uninit(void)
1049
{
1050
  DWORD index;
1051
  wLog* root = g_RootLog;
1052
1053
  if (!root)
1054
    return FALSE;
1055
1056
  WLog_Lock(root);
1057
1058
  for (index = 0; index < root->ChildrenCount; index++)
1059
  {
1060
    wLog* child = root->Children[index];
1061
    WLog_Free(child);
1062
  }
1063
1064
  WLog_Unlock(root);
1065
1066
  WLog_Free(root);
1067
  g_RootLog = NULL;
1068
1069
  return TRUE;
1070
}
1071
#endif
1072
1073
BOOL WLog_SetContext(wLog* log, const char* (*fkt)(void*), void* context)
1074
0
{
1075
0
  WINPR_ASSERT(log);
1076
1077
0
  log->custom = fkt;
1078
0
  log->context = context;
1079
0
  return TRUE;
1080
0
}