Coverage Report

Created: 2024-05-20 06:11

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