• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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