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