Coverage Report

Created: 2026-03-31 06:56

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