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