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