1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % L OOO GGGG %
7 % L O O G %
8 % L O O G GG %
9 % L O O G G %
10 % LLLLL OOO GGG %
11 % %
12 % %
13 % MagickCore Log Events %
14 % %
15 % Software Design %
16 % Cristy %
17 % September 2002 %
18 % %
19 % %
20 % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38
39 /*
40 Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/client.h"
45 #include "MagickCore/configure.h"
46 #include "MagickCore/configure-private.h"
47 #include "MagickCore/exception.h"
48 #include "MagickCore/exception-private.h"
49 #include "MagickCore/linked-list.h"
50 #include "MagickCore/log.h"
51 #include "MagickCore/log-private.h"
52 #include "MagickCore/memory_.h"
53 #include "MagickCore/nt-base-private.h"
54 #include "MagickCore/option.h"
55 #include "MagickCore/semaphore.h"
56 #include "MagickCore/timer.h"
57 #include "MagickCore/string_.h"
58 #include "MagickCore/string-private.h"
59 #include "MagickCore/thread_.h"
60 #include "MagickCore/thread-private.h"
61 #include "MagickCore/timer-private.h"
62 #include "MagickCore/token.h"
63 #include "MagickCore/utility.h"
64 #include "MagickCore/utility-private.h"
65 #include "MagickCore/version.h"
66 #include "MagickCore/xml-tree.h"
67 #include "MagickCore/xml-tree-private.h"
68
69 /*
70 Define declarations.
71 */
72 #define LogFilename "log.xml"
73
74 /*
75 Typedef declarations.
76 */
77 typedef enum
78 {
79 UndefinedHandler = 0x0000,
80 NoHandler = 0x0000,
81 ConsoleHandler = 0x0001,
82 StdoutHandler = 0x0002,
83 StderrHandler = 0x0004,
84 FileHandler = 0x0008,
85 DebugHandler = 0x0010,
86 EventHandler = 0x0020,
87 MethodHandler = 0x0040
88 } LogHandlerType;
89
90 typedef struct _EventInfo
91 {
92 char
93 *name;
94
95 LogEventType
96 event;
97 } EventInfo;
98
99 typedef struct _HandlerInfo
100 {
101 const char
102 name[10];
103
104 LogHandlerType
105 handler;
106 } HandlerInfo;
107
108 struct _LogInfo
109 {
110 LogEventType
111 event_mask;
112
113 LogHandlerType
114 handler_mask;
115
116 char
117 *path,
118 *name,
119 *filename,
120 *format;
121
122 size_t
123 generations,
124 limit;
125
126 FILE
127 *file;
128
129 size_t
130 generation;
131
132 MagickBooleanType
133 append,
134 stealth;
135
136 TimerInfo
137 timer;
138
139 MagickLogMethod
140 method;
141
142 SemaphoreInfo
143 *event_semaphore;
144
145 size_t
146 signature;
147 };
148
149 typedef struct _LogMapInfo
150 {
151 const LogEventType
152 event_mask;
153
154 const LogHandlerType
155 handler_mask;
156
157 const char
158 *filename,
159 *format;
160 } LogMapInfo;
161
162 /*
163 Static declarations.
164 */
165 static const HandlerInfo
166 LogHandlers[32] =
167 {
168 { "Console", ConsoleHandler },
169 { "Debug", DebugHandler },
170 { "Event", EventHandler },
171 { "File", FileHandler },
172 { "None", NoHandler },
173 { "Stderr", StderrHandler },
174 { "Stdout", StdoutHandler },
175 { "", UndefinedHandler },
176 { "", UndefinedHandler },
177 { "", UndefinedHandler },
178 { "", UndefinedHandler },
179 { "", UndefinedHandler },
180 { "", UndefinedHandler },
181 { "", UndefinedHandler },
182 { "", UndefinedHandler },
183 { "", UndefinedHandler },
184 { "", UndefinedHandler },
185 { "", UndefinedHandler },
186 { "", UndefinedHandler },
187 { "", UndefinedHandler },
188 { "", UndefinedHandler },
189 { "", UndefinedHandler },
190 { "", UndefinedHandler },
191 { "", UndefinedHandler },
192 { "", UndefinedHandler },
193 { "", UndefinedHandler },
194 { "", UndefinedHandler },
195 { "", UndefinedHandler },
196 { "", UndefinedHandler },
197 { "", UndefinedHandler },
198 { "", UndefinedHandler },
199 { "", UndefinedHandler }
200 };
201
202 static const LogMapInfo
203 LogMap[] =
204 {
205 { NoEvents, ConsoleHandler, "Magick-%g.log",
206 "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\\n %e" }
207 };
208
209 static char
210 log_name[MagickPathExtent] = "Magick";
211
212 static LinkedListInfo
213 *log_cache = (LinkedListInfo *) NULL;
214
215 static MagickBooleanType
216 event_logging = MagickFalse;
217
218 static SemaphoreInfo
219 *log_semaphore = (SemaphoreInfo *) NULL;
220
221 /*
222 Forward declarations.
223 */
224 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
225 static LogHandlerType
226 ParseLogHandlers(const char *) magick_attribute((__pure__));
227 #endif
228
229 static LogInfo
230 *GetLogInfo(const char *,ExceptionInfo *);
231
232 static MagickBooleanType
233 IsLogCacheInstantiated(ExceptionInfo *) magick_attribute((__pure__));
234
235 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
236 static MagickBooleanType
237 LoadLogCache(LinkedListInfo *,const char *,const char *,const size_t,
238 ExceptionInfo *);
239 #endif
240
241 /*
242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
243 % %
244 % %
245 % %
246 % A c q u i r e L o g C a c h e %
247 % %
248 % %
249 % %
250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251 %
252 % AcquireLogCache() caches one or more log configurations which provides a
253 % mapping between log attributes and log name.
254 %
255 % The format of the AcquireLogCache method is:
256 %
257 % LinkedListInfo *AcquireLogCache(const char *filename,
258 % ExceptionInfo *exception)
259 %
260 % A description of each parameter follows:
261 %
262 % o filename: the log configuration filename.
263 %
264 % o exception: return any errors or warnings in this structure.
265 %
266 */
AcquireLogCache(const char * filename,ExceptionInfo * exception)267 static LinkedListInfo *AcquireLogCache(const char *filename,
268 ExceptionInfo *exception)
269 {
270 LinkedListInfo
271 *cache;
272
273 MagickStatusType
274 status;
275
276 ssize_t
277 i;
278
279 /*
280 Load external log map.
281 */
282 cache=NewLinkedList(0);
283 status=MagickTrue;
284 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
285 {
286 const StringInfo
287 *option;
288
289 LinkedListInfo
290 *options;
291
292 options=GetConfigureOptions(filename,exception);
293 option=(const StringInfo *) GetNextValueInLinkedList(options);
294 while (option != (const StringInfo *) NULL)
295 {
296 status&=LoadLogCache(cache,(const char *) GetStringInfoDatum(option),
297 GetStringInfoPath(option),0,exception);
298 option=(const StringInfo *) GetNextValueInLinkedList(options);
299 }
300 options=DestroyConfigureOptions(options);
301 }
302 #endif
303 /*
304 Load built-in log map.
305 */
306 for (i=0; i < (ssize_t) (sizeof(LogMap)/sizeof(*LogMap)); i++)
307 {
308 LogInfo
309 *log_info;
310
311 const LogMapInfo
312 *p;
313
314 p=LogMap+i;
315 log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
316 if (log_info == (LogInfo *) NULL)
317 {
318 (void) ThrowMagickException(exception,GetMagickModule(),
319 ResourceLimitError,"MemoryAllocationFailed","`%s'",p->filename);
320 continue;
321 }
322 (void) memset(log_info,0,sizeof(*log_info));
323 log_info->path=ConstantString("[built-in]");
324 GetTimerInfo((TimerInfo *) &log_info->timer);
325 log_info->event_mask=p->event_mask;
326 log_info->handler_mask=p->handler_mask;
327 log_info->filename=ConstantString(p->filename);
328 log_info->format=ConstantString(p->format);
329 log_info->signature=MagickCoreSignature;
330 status&=AppendValueToLinkedList(cache,log_info);
331 if (status == MagickFalse)
332 (void) ThrowMagickException(exception,GetMagickModule(),
333 ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
334 }
335 return(cache);
336 }
337
338 /*
339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 % %
341 % %
342 % %
343 % C l o s e M a g i c k L o g %
344 % %
345 % %
346 % %
347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348 %
349 % CloseMagickLog() closes the Magick log.
350 %
351 % The format of the CloseMagickLog method is:
352 %
353 % CloseMagickLog(void)
354 %
355 */
CloseMagickLog(void)356 MagickExport void CloseMagickLog(void)
357 {
358 ExceptionInfo
359 *exception;
360
361 LogInfo
362 *log_info;
363
364 if (IsEventLogging() == MagickFalse)
365 return;
366 exception=AcquireExceptionInfo();
367 log_info=GetLogInfo("*",exception);
368 exception=DestroyExceptionInfo(exception);
369 LockSemaphoreInfo(log_semaphore);
370 if (log_info->file != (FILE *) NULL)
371 {
372 (void) FormatLocaleFile(log_info->file,"</log>\n");
373 (void) fclose(log_info->file);
374 log_info->file=(FILE *) NULL;
375 }
376 UnlockSemaphoreInfo(log_semaphore);
377 }
378
379 /*
380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381 % %
382 % %
383 % %
384 + G e t L o g I n f o %
385 % %
386 % %
387 % %
388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389 %
390 % GetLogInfo() searches the log list for the specified name and if found
391 % returns attributes for that log.
392 %
393 % The format of the GetLogInfo method is:
394 %
395 % LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
396 %
397 % A description of each parameter follows:
398 %
399 % o name: the log name.
400 %
401 % o exception: return any errors or warnings in this structure.
402 %
403 */
GetLogInfo(const char * name,ExceptionInfo * exception)404 static LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
405 {
406 LogInfo
407 *p;
408
409 assert(exception != (ExceptionInfo *) NULL);
410 if (IsLogCacheInstantiated(exception) == MagickFalse)
411 return((LogInfo *) NULL);
412 /*
413 Search for log tag.
414 */
415 LockSemaphoreInfo(log_semaphore);
416 ResetLinkedListIterator(log_cache);
417 p=(LogInfo *) GetNextValueInLinkedList(log_cache);
418 if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
419 {
420 UnlockSemaphoreInfo(log_semaphore);
421 return(p);
422 }
423 while (p != (LogInfo *) NULL)
424 {
425 if (LocaleCompare(name,p->name) == 0)
426 break;
427 p=(LogInfo *) GetNextValueInLinkedList(log_cache);
428 }
429 if (p != (LogInfo *) NULL)
430 (void) InsertValueInLinkedList(log_cache,0,
431 RemoveElementByValueFromLinkedList(log_cache,p));
432 UnlockSemaphoreInfo(log_semaphore);
433 return(p);
434 }
435
436 /*
437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438 % %
439 % %
440 % %
441 % G e t L o g I n f o L i s t %
442 % %
443 % %
444 % %
445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446 %
447 % GetLogInfoList() returns any logs that match the specified pattern.
448 %
449 % The format of the GetLogInfoList function is:
450 %
451 % const LogInfo **GetLogInfoList(const char *pattern,
452 % size_t *number_preferences,ExceptionInfo *exception)
453 %
454 % A description of each parameter follows:
455 %
456 % o pattern: Specifies a pointer to a text string containing a pattern.
457 %
458 % o number_preferences: This integer returns the number of logs in the list.
459 %
460 % o exception: return any errors or warnings in this structure.
461 %
462 */
463 #if defined(__cplusplus) || defined(c_plusplus)
464 extern "C" {
465 #endif
466
LogInfoCompare(const void * x,const void * y)467 static int LogInfoCompare(const void *x,const void *y)
468 {
469 const LogInfo
470 **p,
471 **q;
472
473 p=(const LogInfo **) x,
474 q=(const LogInfo **) y;
475 if (LocaleCompare((*p)->path,(*q)->path) == 0)
476 return(LocaleCompare((*p)->name,(*q)->name));
477 return(LocaleCompare((*p)->path,(*q)->path));
478 }
479
480 #if defined(__cplusplus) || defined(c_plusplus)
481 }
482 #endif
483
GetLogInfoList(const char * pattern,size_t * number_preferences,ExceptionInfo * exception)484 MagickExport const LogInfo **GetLogInfoList(const char *pattern,
485 size_t *number_preferences,ExceptionInfo *exception)
486 {
487 const LogInfo
488 **preferences;
489
490 const LogInfo
491 *p;
492
493 ssize_t
494 i;
495
496 /*
497 Allocate log list.
498 */
499 assert(pattern != (char *) NULL);
500 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
501 assert(number_preferences != (size_t *) NULL);
502 *number_preferences=0;
503 p=GetLogInfo("*",exception);
504 if (p == (const LogInfo *) NULL)
505 return((const LogInfo **) NULL);
506 preferences=(const LogInfo **) AcquireQuantumMemory((size_t)
507 GetNumberOfElementsInLinkedList(log_cache)+1UL,sizeof(*preferences));
508 if (preferences == (const LogInfo **) NULL)
509 return((const LogInfo **) NULL);
510 /*
511 Generate log list.
512 */
513 LockSemaphoreInfo(log_semaphore);
514 ResetLinkedListIterator(log_cache);
515 p=(const LogInfo *) GetNextValueInLinkedList(log_cache);
516 for (i=0; p != (const LogInfo *) NULL; )
517 {
518 if ((p->stealth == MagickFalse) &&
519 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
520 preferences[i++]=p;
521 p=(const LogInfo *) GetNextValueInLinkedList(log_cache);
522 }
523 UnlockSemaphoreInfo(log_semaphore);
524 qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
525 preferences[i]=(LogInfo *) NULL;
526 *number_preferences=(size_t) i;
527 return(preferences);
528 }
529
530 /*
531 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
532 % %
533 % %
534 % %
535 % G e t L o g L i s t %
536 % %
537 % %
538 % %
539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
540 %
541 % GetLogList() returns any logs that match the specified pattern.
542 %
543 % The format of the GetLogList function is:
544 %
545 % char **GetLogList(const char *pattern,size_t *number_preferences,
546 % ExceptionInfo *exception)
547 %
548 % A description of each parameter follows:
549 %
550 % o pattern: Specifies a pointer to a text string containing a pattern.
551 %
552 % o number_preferences: This integer returns the number of logs in the list.
553 %
554 % o exception: return any errors or warnings in this structure.
555 %
556 */
557
558 #if defined(__cplusplus) || defined(c_plusplus)
559 extern "C" {
560 #endif
561
LogCompare(const void * x,const void * y)562 static int LogCompare(const void *x,const void *y)
563 {
564 const char
565 **p,
566 **q;
567
568 p=(const char **) x;
569 q=(const char **) y;
570 return(LocaleCompare(*p,*q));
571 }
572
573 #if defined(__cplusplus) || defined(c_plusplus)
574 }
575 #endif
576
GetLogList(const char * pattern,size_t * number_preferences,ExceptionInfo * exception)577 MagickExport char **GetLogList(const char *pattern,size_t *number_preferences,
578 ExceptionInfo *exception)
579 {
580 char
581 **preferences;
582
583 const LogInfo
584 *p;
585
586 ssize_t
587 i;
588
589 /*
590 Allocate log list.
591 */
592 assert(pattern != (char *) NULL);
593 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
594 assert(number_preferences != (size_t *) NULL);
595 *number_preferences=0;
596 p=GetLogInfo("*",exception);
597 if (p == (const LogInfo *) NULL)
598 return((char **) NULL);
599 preferences=(char **) AcquireQuantumMemory((size_t)
600 GetNumberOfElementsInLinkedList(log_cache)+1UL,sizeof(*preferences));
601 if (preferences == (char **) NULL)
602 return((char **) NULL);
603 /*
604 Generate log list.
605 */
606 LockSemaphoreInfo(log_semaphore);
607 ResetLinkedListIterator(log_cache);
608 p=(const LogInfo *) GetNextValueInLinkedList(log_cache);
609 for (i=0; p != (const LogInfo *) NULL; )
610 {
611 if ((p->stealth == MagickFalse) &&
612 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
613 preferences[i++]=ConstantString(p->name);
614 p=(const LogInfo *) GetNextValueInLinkedList(log_cache);
615 }
616 UnlockSemaphoreInfo(log_semaphore);
617 qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
618 preferences[i]=(char *) NULL;
619 *number_preferences=(size_t) i;
620 return(preferences);
621 }
622
623 /*
624 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
625 % %
626 % %
627 % %
628 % G e t L o g N a m e %
629 % %
630 % %
631 % %
632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
633 %
634 % GetLogName() returns the current log name.
635 %
636 % The format of the GetLogName method is:
637 %
638 % const char *GetLogName(void)
639 %
640 */
GetLogName(void)641 MagickExport const char *GetLogName(void)
642 {
643 return(log_name);
644 }
645
646 /*
647 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
648 % %
649 % %
650 % %
651 + I s L o g C a c h e I n s t a n t i a t e d %
652 % %
653 % %
654 % %
655 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
656 %
657 % IsLogCacheInstantiated() determines if the log list is instantiated. If
658 % not, it instantiates the list and returns it.
659 %
660 % The format of the IsLogInstantiated method is:
661 %
662 % MagickBooleanType IsLogCacheInstantiated(ExceptionInfo *exception)
663 %
664 % A description of each parameter follows.
665 %
666 % o exception: return any errors or warnings in this structure.
667 %
668 */
669
CheckEventLogging()670 static inline void CheckEventLogging()
671 {
672 /*
673 Are we logging events?
674 */
675 if (IsLinkedListEmpty(log_cache) != MagickFalse)
676 event_logging=MagickFalse;
677 else
678 {
679 LogInfo
680 *p;
681
682 ResetLinkedListIterator(log_cache);
683 p=(LogInfo *) GetNextValueInLinkedList(log_cache);
684 event_logging=(p != (LogInfo *) NULL) && (p->event_mask != NoEvents) ?
685 MagickTrue: MagickFalse;
686 }
687 }
688
IsLogCacheInstantiated(ExceptionInfo * exception)689 static MagickBooleanType IsLogCacheInstantiated(ExceptionInfo *exception)
690 {
691 if (log_cache == (LinkedListInfo *) NULL)
692 {
693 if (log_semaphore == (SemaphoreInfo *) NULL)
694 ActivateSemaphoreInfo(&log_semaphore);
695 LockSemaphoreInfo(log_semaphore);
696 if (log_cache == (LinkedListInfo *) NULL)
697 {
698 log_cache=AcquireLogCache(LogFilename,exception);
699 CheckEventLogging();
700 }
701 UnlockSemaphoreInfo(log_semaphore);
702 }
703 return(log_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
704 }
705
706 /*
707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
708 % %
709 % %
710 % %
711 % I s E v e n t L o g g i n g %
712 % %
713 % %
714 % %
715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
716 %
717 % IsEventLogging() returns MagickTrue if debug of events is enabled otherwise
718 % MagickFalse.
719 %
720 % The format of the IsEventLogging method is:
721 %
722 % MagickBooleanType IsEventLogging(void)
723 %
724 */
IsEventLogging(void)725 MagickExport MagickBooleanType IsEventLogging(void)
726 {
727 return(event_logging);
728 }
729
730 /*
731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
732 % %
733 % %
734 % %
735 % L i s t L o g I n f o %
736 % %
737 % %
738 % %
739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
740 %
741 % ListLogInfo() lists the log info to a file.
742 %
743 % The format of the ListLogInfo method is:
744 %
745 % MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
746 %
747 % A description of each parameter follows.
748 %
749 % o file: An pointer to a FILE.
750 %
751 % o exception: return any errors or warnings in this structure.
752 %
753 */
ListLogInfo(FILE * file,ExceptionInfo * exception)754 MagickExport MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
755 {
756 #define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024)
757
758 const char
759 *path;
760
761 const LogInfo
762 **log_info;
763
764 ssize_t
765 i;
766
767 size_t
768 number_aliases;
769
770 ssize_t
771 j;
772
773 if (file == (const FILE *) NULL)
774 file=stdout;
775 log_info=GetLogInfoList("*",&number_aliases,exception);
776 if (log_info == (const LogInfo **) NULL)
777 return(MagickFalse);
778 j=0;
779 path=(const char *) NULL;
780 for (i=0; i < (ssize_t) number_aliases; i++)
781 {
782 if (log_info[i]->stealth != MagickFalse)
783 continue;
784 if ((path == (const char *) NULL) ||
785 (LocaleCompare(path,log_info[i]->path) != 0))
786 {
787 size_t
788 length;
789
790 if (log_info[i]->path != (char *) NULL)
791 (void) FormatLocaleFile(file,"\nPath: %s\n\n",log_info[i]->path);
792 length=0;
793 for (j=0; j < (ssize_t) (8*sizeof(LogHandlerType)); j++)
794 {
795 size_t
796 mask;
797
798 if (*LogHandlers[j].name == '\0')
799 break;
800 mask=1;
801 mask<<=j;
802 if ((log_info[i]->handler_mask & mask) != 0)
803 {
804 (void) FormatLocaleFile(file,"%s ",LogHandlers[j].name);
805 length+=strlen(LogHandlers[j].name);
806 }
807 }
808 for (j=(ssize_t) length; j <= 12; j++)
809 (void) FormatLocaleFile(file," ");
810 (void) FormatLocaleFile(file," Generations Limit Format\n");
811 (void) FormatLocaleFile(file,"-----------------------------------------"
812 "--------------------------------------\n");
813 }
814 path=log_info[i]->path;
815 if (log_info[i]->filename != (char *) NULL)
816 {
817 (void) FormatLocaleFile(file,"%s",log_info[i]->filename);
818 for (j=(ssize_t) strlen(log_info[i]->filename); j <= 16; j++)
819 (void) FormatLocaleFile(file," ");
820 }
821 (void) FormatLocaleFile(file,"%9g ",(double) log_info[i]->generations);
822 (void) FormatLocaleFile(file,"%8g ",(double) log_info[i]->limit);
823 if (log_info[i]->format != (char *) NULL)
824 (void) FormatLocaleFile(file,"%s",log_info[i]->format);
825 (void) FormatLocaleFile(file,"\n");
826 }
827 (void) fflush(file);
828 log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
829 return(MagickTrue);
830 }
831
832 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
833 /*
834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
835 % %
836 % %
837 % %
838 % L o a d L o g C a c h e %
839 % %
840 % %
841 % %
842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
843 %
844 % LoadLogCache() loads the log configurations which provides a
845 % mapping between log attributes and log name.
846 %
847 % The format of the LoadLogCache method is:
848 %
849 % MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
850 % const char *filename,const size_t depth,ExceptionInfo *exception)
851 %
852 % A description of each parameter follows:
853 %
854 % o xml: The log list in XML format.
855 %
856 % o filename: The log list filename.
857 %
858 % o depth: depth of <include /> statements.
859 %
860 % o exception: return any errors or warnings in this structure.
861 %
862 */
LoadLogCache(LinkedListInfo * cache,const char * xml,const char * filename,const size_t depth,ExceptionInfo * exception)863 static MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
864 const char *filename,const size_t depth,ExceptionInfo *exception)
865 {
866 char
867 keyword[MagickPathExtent],
868 *token;
869
870 const char
871 *q;
872
873 LogInfo
874 *log_info = (LogInfo *) NULL;
875
876 MagickStatusType
877 status;
878
879 size_t
880 extent;
881
882 /*
883 Load the log map file.
884 */
885 if (xml == (const char *) NULL)
886 return(MagickFalse);
887 status=MagickTrue;
888 token=AcquireString(xml);
889 extent=strlen(token)+MagickPathExtent;
890 for (q=(const char *) xml; *q != '\0'; )
891 {
892 /*
893 Interpret XML.
894 */
895 (void) GetNextToken(q,&q,extent,token);
896 if (*token == '\0')
897 break;
898 (void) CopyMagickString(keyword,token,MagickPathExtent);
899 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
900 {
901 /*
902 Doctype element.
903 */
904 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
905 (void) GetNextToken(q,&q,extent,token);
906 continue;
907 }
908 if (LocaleNCompare(keyword,"<!--",4) == 0)
909 {
910 /*
911 Comment element.
912 */
913 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
914 (void) GetNextToken(q,&q,extent,token);
915 continue;
916 }
917 if (LocaleCompare(keyword,"<include") == 0)
918 {
919 /*
920 Include element.
921 */
922 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
923 {
924 (void) CopyMagickString(keyword,token,MagickPathExtent);
925 (void) GetNextToken(q,&q,extent,token);
926 if (*token != '=')
927 continue;
928 (void) GetNextToken(q,&q,extent,token);
929 if (LocaleCompare(keyword,"file") == 0)
930 {
931 if (depth > MagickMaxRecursionDepth)
932 (void) ThrowMagickException(exception,GetMagickModule(),
933 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
934 else
935 {
936 char
937 path[MagickPathExtent],
938 *file_xml;
939
940 GetPathComponent(filename,HeadPath,path);
941 if (*path != '\0')
942 (void) ConcatenateMagickString(path,DirectorySeparator,
943 MagickPathExtent);
944 if (*token == *DirectorySeparator)
945 (void) CopyMagickString(path,token,MagickPathExtent);
946 else
947 (void) ConcatenateMagickString(path,token,MagickPathExtent);
948 file_xml=FileToXML(path,~0UL);
949 if (file_xml != (char *) NULL)
950 {
951 status&=LoadLogCache(cache,file_xml,path,depth+1,
952 exception);
953 file_xml=DestroyString(file_xml);
954 }
955 }
956 }
957 }
958 continue;
959 }
960 if (LocaleCompare(keyword,"<logmap>") == 0)
961 {
962 /*
963 Allocate memory for the log list.
964 */
965 log_info=(LogInfo *) AcquireCriticalMemory(sizeof(*log_info));
966 (void) memset(log_info,0,sizeof(*log_info));
967 log_info->path=ConstantString(filename);
968 GetTimerInfo((TimerInfo *) &log_info->timer);
969 log_info->signature=MagickCoreSignature;
970 continue;
971 }
972 if (log_info == (LogInfo *) NULL)
973 continue;
974 if (LocaleCompare(keyword,"</logmap>") == 0)
975 {
976 status=AppendValueToLinkedList(cache,log_info);
977 if (status == MagickFalse)
978 (void) ThrowMagickException(exception,GetMagickModule(),
979 ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
980 log_info=(LogInfo *) NULL;
981 continue;
982 }
983 (void) GetNextToken(q,(const char **) NULL,extent,token);
984 if (*token != '=')
985 continue;
986 (void) GetNextToken(q,&q,extent,token);
987 (void) GetNextToken(q,&q,extent,token);
988 switch (*keyword)
989 {
990 case 'E':
991 case 'e':
992 {
993 if (LocaleCompare((char *) keyword,"events") == 0)
994 {
995 log_info->event_mask=(LogEventType) (log_info->event_mask |
996 ParseCommandOption(MagickLogEventOptions,MagickTrue,token));
997 break;
998 }
999 break;
1000 }
1001 case 'F':
1002 case 'f':
1003 {
1004 if (LocaleCompare((char *) keyword,"filename") == 0)
1005 {
1006 if (log_info->filename != (char *) NULL)
1007 log_info->filename=(char *)
1008 RelinquishMagickMemory(log_info->filename);
1009 log_info->filename=ConstantString(token);
1010 break;
1011 }
1012 if (LocaleCompare((char *) keyword,"format") == 0)
1013 {
1014 if (log_info->format != (char *) NULL)
1015 log_info->format=(char *)
1016 RelinquishMagickMemory(log_info->format);
1017 log_info->format=ConstantString(token);
1018 break;
1019 }
1020 break;
1021 }
1022 case 'G':
1023 case 'g':
1024 {
1025 if (LocaleCompare((char *) keyword,"generations") == 0)
1026 {
1027 if (LocaleCompare(token,"unlimited") == 0)
1028 {
1029 log_info->generations=(~0UL);
1030 break;
1031 }
1032 log_info->generations=StringToUnsignedLong(token);
1033 break;
1034 }
1035 break;
1036 }
1037 case 'L':
1038 case 'l':
1039 {
1040 if (LocaleCompare((char *) keyword,"limit") == 0)
1041 {
1042 if (LocaleCompare(token,"unlimited") == 0)
1043 {
1044 log_info->limit=(~0UL);
1045 break;
1046 }
1047 log_info->limit=StringToUnsignedLong(token);
1048 break;
1049 }
1050 break;
1051 }
1052 case 'O':
1053 case 'o':
1054 {
1055 if (LocaleCompare((char *) keyword,"output") == 0)
1056 {
1057 log_info->handler_mask=(LogHandlerType)
1058 (log_info->handler_mask | ParseLogHandlers(token));
1059 break;
1060 }
1061 break;
1062 }
1063 default:
1064 break;
1065 }
1066 }
1067 token=DestroyString(token);
1068 if (cache == (LinkedListInfo *) NULL)
1069 return(MagickFalse);
1070 return(status != 0 ? MagickTrue : MagickFalse);
1071 }
1072 #endif
1073
1074 /*
1075 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1076 % %
1077 % %
1078 % %
1079 + L o g C o m p o n e n t G e n e s i s %
1080 % %
1081 % %
1082 % %
1083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1084 %
1085 % LogComponentGenesis() instantiates the log component.
1086 %
1087 % The format of the LogComponentGenesis method is:
1088 %
1089 % MagickBooleanType LogComponentGenesis(void)
1090 %
1091 */
LogComponentGenesis(void)1092 MagickPrivate MagickBooleanType LogComponentGenesis(void)
1093 {
1094 ExceptionInfo
1095 *exception;
1096
1097 if (log_semaphore == (SemaphoreInfo *) NULL)
1098 log_semaphore=AcquireSemaphoreInfo();
1099 exception=AcquireExceptionInfo();
1100 (void) GetLogInfo("*",exception);
1101 exception=DestroyExceptionInfo(exception);
1102 return(MagickTrue);
1103 }
1104
1105 /*
1106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1107 % %
1108 % %
1109 % %
1110 + L o g C o m p o n e n t T e r m i n u s %
1111 % %
1112 % %
1113 % %
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1115 %
1116 % LogComponentTerminus() destroys the logging component.
1117 %
1118 % The format of the LogComponentTerminus method is:
1119 %
1120 % LogComponentTerminus(void)
1121 %
1122 */
1123
DestroyLogElement(void * log_info)1124 static void *DestroyLogElement(void *log_info)
1125 {
1126 LogInfo
1127 *p;
1128
1129 p=(LogInfo *) log_info;
1130 if (p->file != (FILE *) NULL)
1131 {
1132 (void) FormatLocaleFile(p->file,"</log>\n");
1133 (void) fclose(p->file);
1134 p->file=(FILE *) NULL;
1135 }
1136 if (p->format != (char *) NULL)
1137 p->format=DestroyString(p->format);
1138 if (p->path != (char *) NULL)
1139 p->path=DestroyString(p->path);
1140 if (p->filename != (char *) NULL)
1141 p->filename=DestroyString(p->filename);
1142 if (p->event_semaphore != (SemaphoreInfo *) NULL)
1143 RelinquishSemaphoreInfo(&p->event_semaphore);
1144 p=(LogInfo *) RelinquishMagickMemory(p);
1145 return((void *) NULL);
1146 }
1147
LogComponentTerminus(void)1148 MagickPrivate void LogComponentTerminus(void)
1149 {
1150 if (log_semaphore == (SemaphoreInfo *) NULL)
1151 ActivateSemaphoreInfo(&log_semaphore);
1152 LockSemaphoreInfo(log_semaphore);
1153 if (log_cache != (LinkedListInfo *) NULL)
1154 log_cache=DestroyLinkedList(log_cache,DestroyLogElement);
1155 event_logging=MagickFalse;
1156 UnlockSemaphoreInfo(log_semaphore);
1157 RelinquishSemaphoreInfo(&log_semaphore);
1158 }
1159
1160 /*
1161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1162 % %
1163 % %
1164 % %
1165 % L o g M a g i c k E v e n t %
1166 % %
1167 % %
1168 % %
1169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1170 %
1171 % LogMagickEvent() logs an event as determined by the log configuration file.
1172 % If an error occurs, MagickFalse is returned otherwise MagickTrue.
1173 %
1174 % The format of the LogMagickEvent method is:
1175 %
1176 % MagickBooleanType LogMagickEvent(const LogEventType type,
1177 % const char *module,const char *function,const size_t line,
1178 % const char *format,...)
1179 %
1180 % A description of each parameter follows:
1181 %
1182 % o type: the event type.
1183 %
1184 % o filename: the source module filename.
1185 %
1186 % o function: the function name.
1187 %
1188 % o line: the line number of the source module.
1189 %
1190 % o format: the output format.
1191 %
1192 */
TranslateEvent(const char * module,const char * function,const size_t line,const char * domain,const char * event)1193 static char *TranslateEvent(const char *module,const char *function,
1194 const size_t line,const char *domain,const char *event)
1195 {
1196 char
1197 *text;
1198
1199 double
1200 elapsed_time,
1201 user_time;
1202
1203 ExceptionInfo
1204 *exception;
1205
1206 LogInfo
1207 *log_info;
1208
1209 char
1210 *q;
1211
1212 const char
1213 *p;
1214
1215 size_t
1216 extent;
1217
1218 time_t
1219 seconds;
1220
1221 exception=AcquireExceptionInfo();
1222 log_info=(LogInfo *) GetLogInfo("*",exception);
1223 exception=DestroyExceptionInfo(exception);
1224 seconds=GetMagickTime();
1225 elapsed_time=GetElapsedTime(&log_info->timer);
1226 user_time=GetUserTime(&log_info->timer);
1227 text=AcquireString(event);
1228 if (log_info->format == (char *) NULL)
1229 return(text);
1230 extent=strlen(event)+MagickPathExtent;
1231 if (LocaleCompare(log_info->format,"xml") == 0)
1232 {
1233 char
1234 timestamp[MagickTimeExtent];
1235
1236 /*
1237 Translate event in "XML" format.
1238 */
1239 (void) FormatMagickTime(seconds,sizeof(timestamp),timestamp);
1240 (void) FormatLocaleString(text,extent,
1241 "<entry>\n"
1242 " <timestamp>%s</timestamp>\n"
1243 " <elapsed-time>%lu:%02lu.%06lu</elapsed-time>\n"
1244 " <user-time>%0.3f</user-time>\n"
1245 " <process-id>%.20g</process-id>\n"
1246 " <thread-id>%.20g</thread-id>\n"
1247 " <module>%s</module>\n"
1248 " <function>%s</function>\n"
1249 " <line>%.20g</line>\n"
1250 " <domain>%s</domain>\n"
1251 " <event>%s</event>\n"
1252 "</entry>",timestamp,(unsigned long) (elapsed_time/60.0),
1253 (unsigned long) floor(fmod(elapsed_time,60.0)),(unsigned long)
1254 (1000000.0*(elapsed_time-floor(elapsed_time))+0.5),user_time,
1255 (double) getpid(),(double) GetMagickThreadSignature(),module,function,
1256 (double) line,domain,event);
1257 return(text);
1258 }
1259 /*
1260 Translate event in "human readable" format.
1261 */
1262 q=text;
1263 for (p=log_info->format; *p != '\0'; p++)
1264 {
1265 *q='\0';
1266 if ((size_t) (q-text+MagickPathExtent) >= extent)
1267 {
1268 extent+=MagickPathExtent;
1269 text=(char *) ResizeQuantumMemory(text,extent+MagickPathExtent,
1270 sizeof(*text));
1271 if (text == (char *) NULL)
1272 return((char *) NULL);
1273 q=text+strlen(text);
1274 }
1275 /*
1276 The format of the log is defined by embedding special format characters:
1277
1278 %c client name
1279 %d domain
1280 %e event
1281 %f function
1282 %g generation
1283 %i thread id
1284 %l line
1285 %m module
1286 %n log name
1287 %p process id
1288 %r real CPU time
1289 %t wall clock time
1290 %u user CPU time
1291 %v version
1292 %% percent sign
1293 \n newline
1294 \r carriage return
1295 */
1296 if ((*p == '\\') && (*(p+1) == 'r'))
1297 {
1298 *q++='\r';
1299 p++;
1300 continue;
1301 }
1302 if ((*p == '\\') && (*(p+1) == 'n'))
1303 {
1304 *q++='\n';
1305 p++;
1306 continue;
1307 }
1308 if (*p != '%')
1309 {
1310 *q++=(*p);
1311 continue;
1312 }
1313 p++;
1314 if (*p == '\0')
1315 break;
1316 switch (*p)
1317 {
1318 case 'c':
1319 {
1320 q+=CopyMagickString(q,GetClientName(),extent);
1321 break;
1322 }
1323 case 'd':
1324 {
1325 q+=CopyMagickString(q,domain,extent);
1326 break;
1327 }
1328 case 'e':
1329 {
1330 q+=CopyMagickString(q,event,extent);
1331 break;
1332 }
1333 case 'f':
1334 {
1335 q+=CopyMagickString(q,function,extent);
1336 break;
1337 }
1338 case 'g':
1339 {
1340 if (log_info->generations == 0)
1341 {
1342 (void) CopyMagickString(q,"0",extent);
1343 q++;
1344 break;
1345 }
1346 q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
1347 log_info->generations));
1348 break;
1349 }
1350 case 'i':
1351 {
1352 q+=FormatLocaleString(q,extent,"%.20g",(double)
1353 GetMagickThreadSignature());
1354 break;
1355 }
1356 case 'l':
1357 {
1358 q+=FormatLocaleString(q,extent,"%.20g",(double) line);
1359 break;
1360 }
1361 case 'm':
1362 {
1363 const char
1364 *r;
1365
1366 for (r=module+strlen(module)-1; r > module; r--)
1367 if (*r == *DirectorySeparator)
1368 {
1369 r++;
1370 break;
1371 }
1372 q+=CopyMagickString(q,r,extent);
1373 break;
1374 }
1375 case 'n':
1376 {
1377 q+=CopyMagickString(q,GetLogName(),extent);
1378 break;
1379 }
1380 case 'p':
1381 {
1382 q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
1383 break;
1384 }
1385 case 'r':
1386 {
1387 q+=FormatLocaleString(q,extent,"%lu:%02lu.%03lu",(unsigned long)
1388 (elapsed_time/60.0),(unsigned long) floor(fmod(elapsed_time,60.0)),
1389 (unsigned long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
1390 break;
1391 }
1392 case 't':
1393 {
1394 q+=FormatMagickTime(seconds,extent,q);
1395 break;
1396 }
1397 case 'u':
1398 {
1399 q+=FormatLocaleString(q,extent,"%0.3fu",user_time);
1400 break;
1401 }
1402 case 'v':
1403 {
1404 q+=CopyMagickString(q,MagickLibVersionText,extent);
1405 break;
1406 }
1407 case '%':
1408 {
1409 *q++=(*p);
1410 break;
1411 }
1412 default:
1413 {
1414 *q++='%';
1415 *q++=(*p);
1416 break;
1417 }
1418 }
1419 }
1420 *q='\0';
1421 return(text);
1422 }
1423
TranslateFilename(const LogInfo * log_info)1424 static char *TranslateFilename(const LogInfo *log_info)
1425 {
1426 char
1427 *filename;
1428
1429 char
1430 *q;
1431
1432 const char
1433 *p;
1434
1435 size_t
1436 extent;
1437
1438 /*
1439 Translate event in "human readable" format.
1440 */
1441 assert(log_info != (LogInfo *) NULL);
1442 assert(log_info->filename != (char *) NULL);
1443 filename=AcquireString((char *) NULL);
1444 extent=MagickPathExtent;
1445 q=filename;
1446 for (p=log_info->filename; *p != '\0'; p++)
1447 {
1448 *q='\0';
1449 if ((size_t) (q-filename+MagickPathExtent) >= extent)
1450 {
1451 extent+=MagickPathExtent;
1452 filename=(char *) ResizeQuantumMemory(filename,extent+MagickPathExtent,
1453 sizeof(*filename));
1454 if (filename == (char *) NULL)
1455 return((char *) NULL);
1456 q=filename+strlen(filename);
1457 }
1458 /*
1459 The format of the filename is defined by embedding special format
1460 characters:
1461
1462 %c client name
1463 %n log name
1464 %p process id
1465 %v version
1466 %% percent sign
1467 */
1468 if (*p != '%')
1469 {
1470 *q++=(*p);
1471 continue;
1472 }
1473 p++;
1474 if (*p == '\0')
1475 break;
1476 switch (*p)
1477 {
1478 case '\0':
1479 {
1480 p--;
1481 break;
1482 }
1483 case 'c':
1484 {
1485 q+=CopyMagickString(q,GetClientName(),extent);
1486 break;
1487 }
1488 case 'g':
1489 {
1490 if (log_info->generations == 0)
1491 {
1492 (void) CopyMagickString(q,"0",extent);
1493 q++;
1494 break;
1495 }
1496 q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
1497 log_info->generations));
1498 break;
1499 }
1500 case 'n':
1501 {
1502 q+=CopyMagickString(q,GetLogName(),extent);
1503 break;
1504 }
1505 case 'p':
1506 {
1507 q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
1508 break;
1509 }
1510 case 'v':
1511 {
1512 q+=CopyMagickString(q,MagickLibVersionText,extent);
1513 break;
1514 }
1515 case '%':
1516 {
1517 *q++=(*p);
1518 break;
1519 }
1520 default:
1521 {
1522 *q++='%';
1523 *q++=(*p);
1524 break;
1525 }
1526 }
1527 }
1528 *q='\0';
1529 return(filename);
1530 }
1531
LogMagickEventList(const LogEventType type,const char * module,const char * function,const size_t line,const char * format,va_list operands)1532 MagickExport MagickBooleanType LogMagickEventList(const LogEventType type,
1533 const char *module,const char *function,const size_t line,const char *format,
1534 va_list operands)
1535 {
1536 char
1537 event[MagickPathExtent],
1538 *text;
1539
1540 const char
1541 *domain;
1542
1543 ExceptionInfo
1544 *exception;
1545
1546 int
1547 n;
1548
1549 LogInfo
1550 *log_info;
1551
1552 exception=AcquireExceptionInfo();
1553 log_info=(LogInfo *) GetLogInfo("*",exception);
1554 exception=DestroyExceptionInfo(exception);
1555 if (log_info->event_semaphore == (SemaphoreInfo *) NULL)
1556 ActivateSemaphoreInfo(&log_info->event_semaphore);
1557 LockSemaphoreInfo(log_info->event_semaphore);
1558 if ((log_info->event_mask & type) == 0)
1559 {
1560 UnlockSemaphoreInfo(log_info->event_semaphore);
1561 return(MagickTrue);
1562 }
1563 domain=CommandOptionToMnemonic(MagickLogEventOptions,type);
1564 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
1565 n=vsnprintf(event,MagickPathExtent,format,operands);
1566 #else
1567 n=vsprintf(event,format,operands);
1568 #endif
1569 if (n < 0)
1570 event[MagickPathExtent-1]='\0';
1571 text=TranslateEvent(module,function,line,domain,event);
1572 if (text == (char *) NULL)
1573 {
1574 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1575 UnlockSemaphoreInfo(log_info->event_semaphore);
1576 return(MagickFalse);
1577 }
1578 if ((log_info->handler_mask & ConsoleHandler) != 0)
1579 {
1580 (void) FormatLocaleFile(stderr,"%s\n",text);
1581 (void) fflush(stderr);
1582 }
1583 if ((log_info->handler_mask & DebugHandler) != 0)
1584 {
1585 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1586 OutputDebugString(text);
1587 OutputDebugString("\n");
1588 #endif
1589 }
1590 if ((log_info->handler_mask & EventHandler) != 0)
1591 {
1592 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1593 (void) NTReportEvent(text,MagickFalse);
1594 #endif
1595 }
1596 if ((log_info->handler_mask & FileHandler) != 0)
1597 {
1598 struct stat
1599 file_info;
1600
1601 file_info.st_size=0;
1602 if (log_info->file != (FILE *) NULL)
1603 (void) fstat(fileno(log_info->file),&file_info);
1604 if (file_info.st_size > (MagickOffsetType) (1024*1024*log_info->limit))
1605 {
1606 (void) FormatLocaleFile(log_info->file,"</log>\n");
1607 (void) fclose(log_info->file);
1608 log_info->file=(FILE *) NULL;
1609 }
1610 if (log_info->file == (FILE *) NULL)
1611 {
1612 char
1613 *filename;
1614
1615 filename=TranslateFilename(log_info);
1616 if (filename == (char *) NULL)
1617 {
1618 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1619 UnlockSemaphoreInfo(log_info->event_semaphore);
1620 return(MagickFalse);
1621 }
1622 log_info->append=IsPathAccessible(filename);
1623 log_info->file=fopen_utf8(filename,"ab");
1624 filename=(char *) RelinquishMagickMemory(filename);
1625 if (log_info->file == (FILE *) NULL)
1626 {
1627 UnlockSemaphoreInfo(log_info->event_semaphore);
1628 return(MagickFalse);
1629 }
1630 log_info->generation++;
1631 if (log_info->append == MagickFalse)
1632 (void) FormatLocaleFile(log_info->file,"<?xml version=\"1.0\" "
1633 "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
1634 (void) FormatLocaleFile(log_info->file,"<log>\n");
1635 }
1636 (void) FormatLocaleFile(log_info->file," <event>%s</event>\n",text);
1637 (void) fflush(log_info->file);
1638 }
1639 if ((log_info->handler_mask & MethodHandler) != 0)
1640 {
1641 if (log_info->method != (MagickLogMethod) NULL)
1642 log_info->method(type,text);
1643 }
1644 if ((log_info->handler_mask & StdoutHandler) != 0)
1645 {
1646 (void) FormatLocaleFile(stdout,"%s\n",text);
1647 (void) fflush(stdout);
1648 }
1649 if ((log_info->handler_mask & StderrHandler) != 0)
1650 {
1651 (void) FormatLocaleFile(stderr,"%s\n",text);
1652 (void) fflush(stderr);
1653 }
1654 text=(char *) RelinquishMagickMemory(text);
1655 (void) ContinueTimer((TimerInfo *) &log_info->timer);
1656 UnlockSemaphoreInfo(log_info->event_semaphore);
1657 return(MagickTrue);
1658 }
1659
LogMagickEvent(const LogEventType type,const char * module,const char * function,const size_t line,const char * format,...)1660 MagickExport MagickBooleanType LogMagickEvent(const LogEventType type,
1661 const char *module,const char *function,const size_t line,
1662 const char *format,...)
1663 {
1664 va_list
1665 operands;
1666
1667 MagickBooleanType
1668 status;
1669
1670 if (IsEventLogging() == MagickFalse)
1671 return(MagickFalse);
1672 va_start(operands,format);
1673 status=LogMagickEventList(type,module,function,line,format,operands);
1674 va_end(operands);
1675 return(status);
1676 }
1677
1678 #if !MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
1679 /*
1680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1681 % %
1682 % %
1683 % %
1684 % P a r s e L o g H a n d l e r s %
1685 % %
1686 % %
1687 % %
1688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1689 %
1690 % ParseLogHandlers() parses a string defining which handlers takes a log
1691 % message and exports them.
1692 %
1693 % The format of the ParseLogHandlers method is:
1694 %
1695 % LogHandlerType ParseLogHandlers(const char *handlers)
1696 %
1697 % A description of each parameter follows:
1698 %
1699 % o handlers: one or more handlers separated by commas.
1700 %
1701 */
ParseLogHandlers(const char * handlers)1702 static LogHandlerType ParseLogHandlers(const char *handlers)
1703 {
1704 LogHandlerType
1705 handler_mask;
1706
1707 const char
1708 *p;
1709
1710 ssize_t
1711 i;
1712
1713 size_t
1714 length;
1715
1716 handler_mask=NoHandler;
1717 for (p=handlers; p != (char *) NULL; p=strchr(p,','))
1718 {
1719 while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
1720 (*p == ',')))
1721 p++;
1722 for (i=0; *LogHandlers[i].name != '\0'; i++)
1723 {
1724 length=strlen(LogHandlers[i].name);
1725 if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
1726 {
1727 handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
1728 break;
1729 }
1730 }
1731 if (*LogHandlers[i].name == '\0')
1732 return(UndefinedHandler);
1733 }
1734 return(handler_mask);
1735 }
1736 #endif
1737
1738 /*
1739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1740 % %
1741 % %
1742 % %
1743 % S e t L o g E v e n t M a s k %
1744 % %
1745 % %
1746 % %
1747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1748 %
1749 % SetLogEventMask() accepts a list that determines which events to log. All
1750 % other events are ignored. By default, no debug is enabled. This method
1751 % returns the previous log event mask.
1752 %
1753 % The format of the SetLogEventMask method is:
1754 %
1755 % LogEventType SetLogEventMask(const char *events)
1756 %
1757 % A description of each parameter follows:
1758 %
1759 % o events: log these events.
1760 %
1761 */
SetLogEventMask(const char * events)1762 MagickExport LogEventType SetLogEventMask(const char *events)
1763 {
1764 ExceptionInfo
1765 *exception;
1766
1767 LogInfo
1768 *log_info;
1769
1770 ssize_t
1771 option;
1772
1773 exception=AcquireExceptionInfo();
1774 log_info=(LogInfo *) GetLogInfo("*",exception);
1775 exception=DestroyExceptionInfo(exception);
1776 option=ParseCommandOption(MagickLogEventOptions,MagickTrue,events);
1777 LockSemaphoreInfo(log_semaphore);
1778 log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1779 log_info->event_mask=(LogEventType) option;
1780 if (option == -1)
1781 log_info->event_mask=UndefinedEvents;
1782 CheckEventLogging();
1783 UnlockSemaphoreInfo(log_semaphore);
1784 return(log_info->event_mask);
1785 }
1786
1787 /*
1788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1789 % %
1790 % %
1791 % %
1792 % S e t L o g F o r m a t %
1793 % %
1794 % %
1795 % %
1796 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1797 %
1798 % SetLogFormat() sets the format for the "human readable" log record.
1799 %
1800 % The format of the LogMagickFormat method is:
1801 %
1802 % SetLogFormat(const char *format)
1803 %
1804 % A description of each parameter follows:
1805 %
1806 % o format: the log record format.
1807 %
1808 */
SetLogFormat(const char * format)1809 MagickExport void SetLogFormat(const char *format)
1810 {
1811 LogInfo
1812 *log_info;
1813
1814 ExceptionInfo
1815 *exception;
1816
1817 exception=AcquireExceptionInfo();
1818 log_info=(LogInfo *) GetLogInfo("*",exception);
1819 exception=DestroyExceptionInfo(exception);
1820 LockSemaphoreInfo(log_semaphore);
1821 if (log_info->format != (char *) NULL)
1822 log_info->format=DestroyString(log_info->format);
1823 log_info->format=ConstantString(format);
1824 UnlockSemaphoreInfo(log_semaphore);
1825 }
1826
1827 /*
1828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1829 % %
1830 % %
1831 % %
1832 % S e t L o g M e t h o d %
1833 % %
1834 % %
1835 % %
1836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1837 %
1838 % SetLogMethod() sets the method that will be called when an event is logged.
1839 %
1840 % The format of the SetLogMethod method is:
1841 %
1842 % void SetLogMethod(MagickLogMethod method)
1843 %
1844 % A description of each parameter follows:
1845 %
1846 % o method: pointer to a method that will be called when LogMagickEvent is
1847 % being called.
1848 %
1849 */
SetLogMethod(MagickLogMethod method)1850 MagickExport void SetLogMethod(MagickLogMethod method)
1851 {
1852 ExceptionInfo
1853 *exception;
1854
1855 LogInfo
1856 *log_info;
1857
1858 exception=AcquireExceptionInfo();
1859 log_info=(LogInfo *) GetLogInfo("*",exception);
1860 exception=DestroyExceptionInfo(exception);
1861 LockSemaphoreInfo(log_semaphore);
1862 log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1863 log_info->handler_mask=(LogHandlerType) (log_info->handler_mask |
1864 MethodHandler);
1865 log_info->method=method;
1866 UnlockSemaphoreInfo(log_semaphore);
1867 }
1868
1869 /*
1870 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1871 % %
1872 % %
1873 % %
1874 % S e t L o g N a m e %
1875 % %
1876 % %
1877 % %
1878 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1879 %
1880 % SetLogName() sets the log name and returns it.
1881 %
1882 % The format of the SetLogName method is:
1883 %
1884 % const char *SetLogName(const char *name)
1885 %
1886 % A description of each parameter follows:
1887 %
1888 % o log_name: SetLogName() returns the current client name.
1889 %
1890 % o name: Specifies the new client name.
1891 %
1892 */
SetLogName(const char * name)1893 MagickExport const char *SetLogName(const char *name)
1894 {
1895 if ((name != (char *) NULL) && (*name != '\0'))
1896 (void) CopyMagickString(log_name,name,MagickPathExtent);
1897 return(log_name);
1898 }
1899