MagickCore  6.9.13-46
Convert, Edit, Or Compose Bitmap Images
resource.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % RRRR EEEEE SSSSS OOO U U RRRR CCCC EEEEE %
7 % R R E SS O O U U R R C E %
8 % RRRR EEE SSS O O U U RRRR C EEE %
9 % R R E SS O O U U R R C E %
10 % R R EEEEE SSSSS OOO UUU R R CCCC EEEEE %
11 % %
12 % %
13 % Get/Set MagickCore Resources %
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 "magick/studio.h"
43 #include "magick/cache.h"
44 #include "magick/cache-private.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/image.h"
51 #include "magick/image-private.h"
52 #include "magick/memory_.h"
53 #include "magick/nt-base-private.h"
54 #include "magick/option.h"
55 #include "magick/policy.h"
56 #include "magick/random_.h"
57 #include "magick/registry.h"
58 #include "magick/resource_.h"
59 #include "magick/semaphore.h"
60 #include "magick/signature-private.h"
61 #include "magick/string_.h"
62 #include "magick/string-private.h"
63 #include "magick/splay-tree.h"
64 #include "magick/thread-private.h"
65 #include "magick/timer-private.h"
66 #include "magick/token.h"
67 #include "magick/timer-private.h"
68 #include "magick/utility.h"
69 #include "magick/utility-private.h"
70 
71 /*
72  Define declarations.
73 */
74 #define MagickPathTemplate "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" /* min 6 X's */
75 #define NumberOfResourceTypes \
76  (sizeof(resource_semaphore)/sizeof(*resource_semaphore))
77 
78 /*
79  Typedef declarations.
80 */
81 typedef struct _ResourceInfo
82 {
83  MagickOffsetType
84  width,
85  height,
86  list_length,
87  area,
88  memory,
89  map,
90  disk,
91  file,
92  thread,
93  throttle,
94  time;
95 
96  MagickSizeType
97  width_limit,
98  height_limit,
99  list_length_limit,
100  area_limit,
101  memory_limit,
102  map_limit,
103  disk_limit,
104  file_limit,
105  thread_limit,
106  throttle_limit,
107  time_limit;
108 } ResourceInfo;
109 
110 /*
111  Global declarations.
112 */
113 static RandomInfo
114  *random_info = (RandomInfo *) NULL;
115 
116 static ResourceInfo
117  resource_info =
118  {
119  MagickULLConstant(0), /* initial width */
120  MagickULLConstant(0), /* initial height */
121  MagickULLConstant(0), /* initial list length */
122  MagickULLConstant(0), /* initial area */
123  MagickULLConstant(0), /* initial memory */
124  MagickULLConstant(0), /* initial map */
125  MagickULLConstant(0), /* initial disk */
126  MagickULLConstant(0), /* initial file */
127  MagickULLConstant(0), /* initial thread */
128  MagickULLConstant(0), /* initial throttle */
129  MagickULLConstant(0), /* initial time */
130  (MagickSizeType) (MAGICK_SSIZE_MAX/sizeof(PixelPacket)/5), /* width limit */
131  (MagickSizeType) (MAGICK_SSIZE_MAX/sizeof(PixelPacket)/5), /* height limit */
132  MagickResourceInfinity, /* list length limit */
133  MagickULLConstant(3072)*1024*1024, /* area limit */
134  MagickULLConstant(1536)*1024*1024, /* memory limit */
135  MagickULLConstant(3072)*1024*1024, /* map limit */
136  MagickResourceInfinity, /* disk limit */
137  MagickULLConstant(768), /* file limit */
138  MagickULLConstant(1), /* thread limit */
139  MagickULLConstant(0), /* throttle limit */
140  MagickResourceInfinity, /* time limit */
141  };
142 
143 static SemaphoreInfo
144  *resource_semaphore[] = {
145  (SemaphoreInfo *) NULL,
146  (SemaphoreInfo *) NULL,
147  (SemaphoreInfo *) NULL,
148  (SemaphoreInfo *) NULL,
149  (SemaphoreInfo *) NULL,
150  (SemaphoreInfo *) NULL,
151  (SemaphoreInfo *) NULL,
152  (SemaphoreInfo *) NULL,
153  (SemaphoreInfo *) NULL,
154  (SemaphoreInfo *) NULL,
155  (SemaphoreInfo *) NULL,
156  (SemaphoreInfo *) NULL
157  };
158 
159 static SplayTreeInfo
160  *temporary_resources = (SplayTreeInfo *) NULL;
161 
162 /*
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 % %
165 % %
166 % %
167 % A c q u i r e M a g i c k R e s o u r c e %
168 % %
169 % %
170 % %
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 %
173 % AcquireMagickResource() acquires resources of the specified type.
174 % MagickFalse is returned if the specified resource is exhausted otherwise
175 % MagickTrue.
176 %
177 % The format of the AcquireMagickResource() method is:
178 %
179 % MagickBooleanType AcquireMagickResource(const ResourceType type,
180 % const MagickSizeType size)
181 %
182 % A description of each parameter follows:
183 %
184 % o type: the type of resource.
185 %
186 % o size: the number of bytes needed from for this resource.
187 %
188 */
189 MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type,
190  const MagickSizeType size)
191 {
192  char
193  resource_current[MaxTextExtent] = "",
194  resource_limit[MaxTextExtent] = "",
195  resource_request[MaxTextExtent] = "";
196 
197  MagickBooleanType
198  logging,
199  status;
200 
201  MagickOffsetType
202  request;
203 
204  MagickSizeType
205  limit;
206 
207  request=(MagickOffsetType) size;
208  if (request < 0)
209  return(MagickFalse);
210  status=MagickFalse;
211  logging=(GetLogEventMask() & ResourceEvent) != 0 ? MagickTrue : MagickFalse;
212  switch (type)
213  {
214  case DiskResource:
215  case FileResource:
216  case MapResource:
217  case MemoryResource:
218  case TimeResource:
219  {
220  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
221  ActivateSemaphoreInfo(&resource_semaphore[type]);
222  LockSemaphoreInfo(resource_semaphore[type]);
223  break;
224  }
225  default: ;
226  }
227  switch (type)
228  {
229  case AreaResource:
230  {
231  resource_info.area=(MagickOffsetType) size;
232  limit=resource_info.area_limit;
233  if ((limit == MagickResourceInfinity) || (size < limit))
234  status=MagickTrue;
235  if (logging != MagickFalse)
236  {
237  (void) FormatMagickSize(size,MagickFalse,resource_request);
238  (void) FormatMagickSize(size,MagickFalse,resource_current);
239  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
240  }
241  break;
242  }
243  case DiskResource:
244  {
245  limit=resource_info.disk_limit;
246  if (resource_info.disk <= (MagickOffsetMax-request))
247  {
248  resource_info.disk+=request;
249  if ((limit == MagickResourceInfinity) ||
250  (resource_info.disk < (MagickOffsetType) limit))
251  status=MagickTrue;
252  else
253  resource_info.disk-=request;
254  }
255  if (logging != MagickFalse)
256  {
257  (void) FormatMagickSize(size,MagickTrue,resource_request);
258  (void) FormatMagickSize((MagickSizeType) resource_info.disk,
259  MagickTrue,resource_current);
260  (void) FormatMagickSize(limit,MagickTrue,resource_limit);
261  }
262  break;
263  }
264  case FileResource:
265  {
266  limit=resource_info.file_limit;
267  if (resource_info.file <= (MagickOffsetMax-request))
268  {
269  resource_info.file+=request;
270  if ((limit == MagickResourceInfinity) ||
271  (resource_info.file < (MagickOffsetType) limit))
272  status=MagickTrue;
273  }
274  if (logging != MagickFalse)
275  {
276  (void) FormatMagickSize(size,MagickFalse,resource_request);
277  (void) FormatMagickSize((MagickSizeType) resource_info.file,
278  MagickFalse,resource_current);
279  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
280  }
281  break;
282  }
283  case HeightResource:
284  {
285  resource_info.height=(MagickOffsetType) size;
286  limit=resource_info.height_limit;
287  if ((limit == MagickResourceInfinity) || (size < limit))
288  status=MagickTrue;
289  if (logging != MagickFalse)
290  {
291  (void) FormatMagickSize(size,MagickFalse,resource_request);
292  (void) FormatMagickSize(size,MagickFalse,resource_current);
293  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
294  }
295  break;
296  }
297  case ListLengthResource:
298  {
299  resource_info.list_length=(MagickOffsetType) size;
300  limit=resource_info.list_length_limit;
301  if ((limit == MagickResourceInfinity) || (size < limit))
302  status=MagickTrue;
303  if (logging != MagickFalse)
304  {
305  (void) FormatMagickSize(size,MagickFalse,resource_request);
306  (void) FormatMagickSize(size,MagickFalse,resource_current);
307  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
308  }
309  break;
310  }
311  case MapResource:
312  {
313  limit=resource_info.map_limit;
314  if (resource_info.map <= (MagickOffsetMax-request))
315  {
316  resource_info.map+=request;
317  if ((limit == MagickResourceInfinity) ||
318  (resource_info.map < (MagickOffsetType) limit))
319  status=MagickTrue;
320  else
321  resource_info.map-=request;
322  }
323  if (logging != MagickFalse)
324  {
325  (void) FormatMagickSize(size,MagickTrue,resource_request);
326  (void) FormatMagickSize((MagickSizeType) resource_info.map,
327  MagickTrue,resource_current);
328  (void) FormatMagickSize(limit,MagickTrue,resource_limit);
329  }
330  break;
331  }
332  case MemoryResource:
333  {
334  limit=resource_info.memory_limit;
335  if (resource_info.memory <= (MagickOffsetMax-request))
336  {
337  resource_info.memory+=request;
338  if ((limit == MagickResourceInfinity) ||
339  (resource_info.memory < (MagickOffsetType) limit))
340  status=MagickTrue;
341  else
342  resource_info.memory-=request;
343  }
344  if (logging != MagickFalse)
345  {
346  (void) FormatMagickSize(size,MagickTrue,resource_request);
347  (void) FormatMagickSize((MagickSizeType) resource_info.memory,
348  MagickTrue,resource_current);
349  (void) FormatMagickSize(limit,MagickTrue,resource_limit);
350  }
351  break;
352  }
353  case ThreadResource:
354  {
355  limit=resource_info.thread_limit;
356  if ((limit == MagickResourceInfinity) ||
357  (resource_info.thread < (MagickOffsetType) limit))
358  status=MagickTrue;
359  if (logging != MagickFalse)
360  {
361  (void) FormatMagickSize(size,MagickFalse,resource_request);
362  (void) FormatMagickSize((MagickSizeType) resource_info.thread,
363  MagickFalse,resource_current);
364  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
365  }
366  break;
367  }
368  case ThrottleResource:
369  {
370  limit=resource_info.throttle_limit;
371  if ((limit == MagickResourceInfinity) ||
372  (resource_info.throttle < (MagickOffsetType) limit))
373  status=MagickTrue;
374  if (logging != MagickFalse)
375  {
376  (void) FormatMagickSize(size,MagickFalse,resource_request);
377  (void) FormatMagickSize((MagickSizeType) resource_info.throttle,
378  MagickFalse,resource_current);
379  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
380  }
381  break;
382  }
383  case TimeResource:
384  {
385  limit=resource_info.time_limit;
386  if (resource_info.time <= (MagickOffsetMax-request))
387  {
388  resource_info.time+=request;
389  if ((limit == MagickResourceInfinity) ||
390  (resource_info.time < (MagickOffsetType) limit))
391  status=MagickTrue;
392  else
393  resource_info.time-=request;
394  }
395  if (logging != MagickFalse)
396  {
397  (void) FormatMagickSize(size,MagickFalse,resource_request);
398  (void) FormatMagickSize((MagickSizeType) resource_info.time,
399  MagickFalse,resource_current);
400  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
401  }
402  break;
403  }
404  case WidthResource:
405  {
406  resource_info.width=(MagickOffsetType) size;
407  limit=resource_info.width_limit;
408  if ((limit == MagickResourceInfinity) || (size < limit))
409  status=MagickTrue;
410  if (logging != MagickFalse)
411  {
412  (void) FormatMagickSize(size,MagickFalse,resource_request);
413  (void) FormatMagickSize(size,MagickFalse,resource_current);
414  (void) FormatMagickSize(limit,MagickFalse,resource_limit);
415  }
416  break;
417  }
418  default:
419  break;
420  }
421  switch (type)
422  {
423  case DiskResource:
424  case FileResource:
425  case MapResource:
426  case MemoryResource:
427  case TimeResource:
428  {
429  UnlockSemaphoreInfo(resource_semaphore[type]);
430  break;
431  }
432  default: ;
433  }
434  if (logging != MagickFalse)
435  {
436  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
437  CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
438  resource_request,resource_current,resource_limit);
439  }
440  return(status);
441 }
442 
443 /*
444 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
445 % %
446 % %
447 % %
448 + A s y n c h r o n o u s R e s o u r c e C o m p o n e n t T e r m i n u s %
449 % %
450 % %
451 % %
452 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
453 %
454 % AsynchronousResourceComponentTerminus() destroys the resource environment.
455 % It differs from ResourceComponentTerminus() in that it can be called from a
456 % asynchronous signal handler.
457 %
458 % The format of the ResourceComponentTerminus() method is:
459 %
460 % ResourceComponentTerminus(void)
461 %
462 */
463 MagickExport void AsynchronousResourceComponentTerminus(void)
464 {
465  const char
466  *path;
467 
468  if (temporary_resources == (SplayTreeInfo *) NULL)
469  return;
470  /*
471  Remove any lingering temporary files.
472  */
473  ResetSplayTreeIterator(temporary_resources);
474  path=(const char *) GetNextKeyInSplayTree(temporary_resources);
475  while (path != (const char *) NULL)
476  {
477  (void) ShredFile(path);
478  (void) remove_utf8(path);
479  path=(const char *) GetNextKeyInSplayTree(temporary_resources);
480  }
481 }
482 
483 /*
484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485 % %
486 % %
487 % %
488 % A c q u i r e U n i q u e F i l e R e s o u r c e %
489 % %
490 % %
491 % %
492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493 %
494 % AcquireUniqueFileResource() returns a unique file name, and returns a file
495 % descriptor for the file open for reading and writing.
496 %
497 % The format of the AcquireUniqueFileResource() method is:
498 %
499 % int AcquireUniqueFileResource(char *path)
500 %
501 % A description of each parameter follows:
502 %
503 % o path: Specifies a pointer to an array of characters. The unique path
504 % name is returned in this array.
505 %
506 */
507 
508 static void *DestroyTemporaryResources(void *temporary_resource)
509 {
510  (void) ShredFile((char *) temporary_resource);
511  (void) remove_utf8((char *) temporary_resource);
512  temporary_resource=DestroyString((char *) temporary_resource);
513  return((void *) NULL);
514 }
515 
516 MagickExport MagickBooleanType GetPathTemplate(char *path)
517 {
518  char
519  *directory,
520  *value;
521 
523  *exception;
524 
525  MagickBooleanType
526  status;
527 
528  struct stat
529  attributes;
530 
531  (void) FormatLocaleString(path,MaxTextExtent,"magick-" MagickPathTemplate);
532  exception=AcquireExceptionInfo();
533  directory=(char *) GetImageRegistry(StringRegistryType,"temporary-path",
534  exception);
535  exception=DestroyExceptionInfo(exception);
536  if (directory == (char *) NULL)
537  directory=GetEnvironmentValue("MAGICK_TEMPORARY_PATH");
538  if (directory == (char *) NULL)
539  directory=GetEnvironmentValue("MAGICK_TMPDIR");
540  if (directory == (char *) NULL)
541  directory=GetEnvironmentValue("TMPDIR");
542 #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__) || defined(__CYGWIN__)
543  if (directory == (char *) NULL)
544  directory=GetEnvironmentValue("TMP");
545  if (directory == (char *) NULL)
546  directory=GetEnvironmentValue("TEMP");
547 #endif
548 #if defined(__VMS)
549  if (directory == (char *) NULL)
550  directory=GetEnvironmentValue("MTMPDIR");
551 #endif
552 #if defined(P_tmpdir)
553  if (directory == (char *) NULL)
554  directory=ConstantString(P_tmpdir);
555 #endif
556  if (directory == (char *) NULL)
557  return(MagickFalse);
558  value=GetPolicyValue("resource:temporary-path");
559  if (value != (char *) NULL)
560  {
561  (void) CloneString(&directory,value);
562  value=DestroyString(value);
563  }
564  if (strlen(directory) > (MaxTextExtent-25))
565  {
566  directory=DestroyString(directory);
567  return(MagickFalse);
568  }
569  status=GetPathAttributes(directory,&attributes);
570  if ((status == MagickFalse) || !S_ISDIR(attributes.st_mode))
571  {
572  directory=DestroyString(directory);
573  return(MagickFalse);
574  }
575  if (directory[strlen(directory)-1] == *DirectorySeparator)
576  (void) FormatLocaleString(path,MaxTextExtent,"%smagick-" MagickPathTemplate,
577  directory);
578  else
579  (void) FormatLocaleString(path,MaxTextExtent,"%s%smagick-"
580  MagickPathTemplate,directory,DirectorySeparator);
581  directory=DestroyString(directory);
582 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
583  {
584  char
585  *p;
586 
587  /*
588  Ghostscript does not like backslashes so we need to replace them. The
589  forward slash also works under Windows.
590  */
591  for (p=(path[1] == *DirectorySeparator ? path+2 : path); *p != '\0'; p++)
592  if (*p == *DirectorySeparator)
593  *p='/';
594  }
595 #endif
596  return(MagickTrue);
597 }
598 
599 MagickExport int AcquireUniqueFileResource(char *path)
600 {
601 #if !defined(O_NOFOLLOW)
602 #define O_NOFOLLOW 0
603 #endif
604 #if !defined(TMP_MAX)
605 # define TMP_MAX 238328
606 #endif
607 
608  int
609  c,
610  file;
611 
612  char
613  *p;
614 
615  ssize_t
616  i;
617 
618  static const char
619  portable_filename[65] =
620  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
621 
622  StringInfo
623  *key;
624 
625  unsigned char
626  *datum;
627 
628  assert(path != (char *) NULL);
629  if ((GetLogEventMask() & ResourceEvent) != 0)
630  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"...");
631  if (random_info == (RandomInfo *) NULL)
632  {
633  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
634  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
635  LockSemaphoreInfo(resource_semaphore[FileResource]);
636  if (random_info == (RandomInfo *) NULL)
637  random_info=AcquireRandomInfo();
638  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
639  }
640  file=(-1);
641  for (i=0; i < (ssize_t) TMP_MAX; i++)
642  {
643  ssize_t
644  j;
645 
646  /*
647  Get temporary pathname.
648  */
649  (void) GetPathTemplate(path);
650  key=GetRandomKey(random_info,strlen(MagickPathTemplate)-6);
651  p=path+strlen(path)-strlen(MagickPathTemplate);
652  datum=GetStringInfoDatum(key);
653  for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
654  {
655  c=(int) (datum[j] & 0x3f);
656  *p++=portable_filename[c];
657  }
658  key=DestroyStringInfo(key);
659 #if defined(MAGICKCORE_HAVE_MKSTEMP)
660  file=mkstemp(path);
661  if (file != -1)
662  {
663 #if defined(MAGICKCORE_HAVE_FCHMOD)
664  (void) fchmod(file,0600);
665 #endif
666 #if defined(__OS2__)
667  setmode(file,O_BINARY);
668 #endif
669  break;
670  }
671 #endif
672  key=GetRandomKey(random_info,strlen(MagickPathTemplate));
673  p=path+strlen(path)-strlen(MagickPathTemplate);
674  datum=GetStringInfoDatum(key);
675  for (j=0; j < (ssize_t) GetStringInfoLength(key); j++)
676  {
677  c=(int) (datum[j] & 0x3f);
678  *p++=portable_filename[c];
679  }
680  key=DestroyStringInfo(key);
681  file=open_utf8(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW,
682  S_MODE);
683  if ((file >= 0) || (errno != EEXIST))
684  break;
685  }
686  if ((GetLogEventMask() & ResourceEvent) != 0)
687  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"Acquire %s",path);
688  if (file == -1)
689  return(file);
690  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
691  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
692  LockSemaphoreInfo(resource_semaphore[FileResource]);
693  if (temporary_resources == (SplayTreeInfo *) NULL)
694  temporary_resources=NewSplayTree(CompareSplayTreeString,
695  DestroyTemporaryResources,(void *(*)(void *)) NULL);
696  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
697  (void) AddValueToSplayTree(temporary_resources,ConstantString(path),
698  (const void *) NULL);
699  return(file);
700 }
701 
702 /*
703 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
704 % %
705 % %
706 % %
707 % G e t M a g i c k R e s o u r c e %
708 % %
709 % %
710 % %
711 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
712 %
713 % GetMagickResource() returns the specified resource.
714 %
715 % The format of the GetMagickResource() method is:
716 %
717 % MagickSizeType GetMagickResource(const ResourceType type)
718 %
719 % A description of each parameter follows:
720 %
721 % o type: the type of resource.
722 %
723 */
724 MagickExport MagickSizeType GetMagickResource(const ResourceType type)
725 {
726  MagickSizeType
727  resource;
728 
729  resource=0;
730  switch (type)
731  {
732  case DiskResource:
733  case FileResource:
734  case MapResource:
735  case MemoryResource:
736  case TimeResource:
737  {
738  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
739  ActivateSemaphoreInfo(&resource_semaphore[type]);
740  LockSemaphoreInfo(resource_semaphore[type]);
741  break;
742  }
743  default: ;
744  }
745  switch (type)
746  {
747  case AreaResource:
748  {
749  resource=(MagickSizeType) resource_info.area;
750  break;
751  }
752  case DiskResource:
753  {
754  resource=(MagickSizeType) resource_info.disk;
755  break;
756  }
757  case FileResource:
758  {
759  resource=(MagickSizeType) resource_info.file;
760  break;
761  }
762  case HeightResource:
763  {
764  resource=(MagickSizeType) resource_info.height;
765  break;
766  }
767  case ListLengthResource:
768  {
769  resource=(MagickSizeType) resource_info.list_length;
770  break;
771  }
772  case MapResource:
773  {
774  resource=(MagickSizeType) resource_info.map;
775  break;
776  }
777  case MemoryResource:
778  {
779  resource=(MagickSizeType) resource_info.memory;
780  break;
781  }
782  case ThreadResource:
783  {
784  resource=(MagickSizeType) resource_info.thread;
785  break;
786  }
787  case ThrottleResource:
788  {
789  resource=(MagickSizeType) resource_info.throttle;
790  break;
791  }
792  case TimeResource:
793  {
794  resource=(MagickSizeType) resource_info.time;
795  break;
796  }
797  case WidthResource:
798  {
799  resource=(MagickSizeType) resource_info.width;
800  break;
801  }
802  default:
803  break;
804  }
805  switch (type)
806  {
807  case DiskResource:
808  case FileResource:
809  case MapResource:
810  case MemoryResource:
811  case TimeResource:
812  {
813  UnlockSemaphoreInfo(resource_semaphore[type]);
814  break;
815  }
816  default: ;
817  }
818  return(resource);
819 }
820 
821 /*
822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
823 % %
824 % %
825 % %
826 % G e t M a g i c k R e s o u r c e L i m i t %
827 % %
828 % %
829 % %
830 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
831 %
832 % GetMagickResourceLimit() returns the specified resource limit.
833 %
834 % The format of the GetMagickResourceLimit() method is:
835 %
836 % MagickSizeType GetMagickResourceLimit(const ResourceType type)
837 %
838 % A description of each parameter follows:
839 %
840 % o type: the type of resource.
841 %
842 */
843 MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
844 {
845  MagickSizeType
846  resource;
847 
848  resource=0;
849  if (type >= NumberOfResourceTypes)
850  return(resource);
851  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
852  ActivateSemaphoreInfo(&resource_semaphore[type]);
853  LockSemaphoreInfo(resource_semaphore[type]);
854  switch (type)
855  {
856  case AreaResource:
857  {
858  resource=resource_info.area_limit;
859  break;
860  }
861  case DiskResource:
862  {
863  resource=resource_info.disk_limit;
864  break;
865  }
866  case FileResource:
867  {
868  resource=resource_info.file_limit;
869  break;
870  }
871  case HeightResource:
872  {
873  resource=resource_info.height_limit;
874  break;
875  }
876  case ListLengthResource:
877  {
878  resource=resource_info.list_length_limit;
879  break;
880  }
881  case MemoryResource:
882  {
883  resource=resource_info.memory_limit;
884  break;
885  }
886  case MapResource:
887  {
888  resource=resource_info.map_limit;
889  break;
890  }
891  case ThreadResource:
892  {
893  resource=resource_info.thread_limit;
894  break;
895  }
896  case ThrottleResource:
897  {
898  resource=resource_info.throttle_limit;
899  break;
900  }
901  case TimeResource:
902  {
903  resource=resource_info.time_limit;
904  break;
905  }
906  case WidthResource:
907  {
908  resource=resource_info.width_limit;
909  break;
910  }
911  default:
912  break;
913  }
914  UnlockSemaphoreInfo(resource_semaphore[type]);
915  return(resource);
916 }
917 
918 /*
919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
920 % %
921 % %
922 % %
923 % L i s t M a g i c k R e s o u r c e I n f o %
924 % %
925 % %
926 % %
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
928 %
929 % ListMagickResourceInfo() lists the resource info to a file.
930 %
931 % The format of the ListMagickResourceInfo method is:
932 %
933 % MagickBooleanType ListMagickResourceInfo(FILE *file,
934 % ExceptionInfo *exception)
935 %
936 % A description of each parameter follows.
937 %
938 % o file: An pointer to a FILE.
939 %
940 % o exception: return any errors or warnings in this structure.
941 %
942 */
943 
944 static ssize_t FormatPixelSize(const MagickSizeType size,
945  const MagickBooleanType bi,char *format)
946 {
947  const char
948  **units;
949 
950  double
951  bytes,
952  length;
953 
954  ssize_t
955  count,
956  i,
957  j;
958 
959  static const char
960  *bi_units[] =
961  {
962  "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi", "Ri", "Qi", (char *) NULL
963  },
964  *traditional_units[] =
965  {
966  "", "K", "M", "G", "T", "P", "E", "Z", "Y", "R", "Q", (char *) NULL
967  };
968 
969  bytes=1000.0;
970  units=traditional_units;
971  if (bi != MagickFalse)
972  {
973  bytes=1024.0;
974  units=bi_units;
975  }
976 #if defined(_MSC_VER) && (_MSC_VER == 1200)
977  length=(double) ((MagickOffsetType) size);
978 #else
979  length=(double) size;
980 #endif
981  for (i=0; (length >= bytes) && (units[i+1] != (const char *) NULL); i++)
982  length/=bytes;
983  count=0;
984  for (j=2; j < 12; j++)
985  {
986  count=FormatLocaleString(format,MaxTextExtent,"%.*g%sP",(int) (i+j),length,
987  units[i]);
988  if (strchr(format,'+') == (char *) NULL)
989  break;
990  }
991  return(count);
992 }
993 
994 static void FormatTimeToLive(const MagickSizeType ttl,char *timeString)
995 {
996  MagickSizeType
997  days,
998  hours,
999  minutes,
1000  months,
1001  seconds,
1002  weeks,
1003  years;
1004 
1005  years=ttl/31536000;
1006  seconds=ttl % 31536000;
1007  if (seconds == 0)
1008  {
1009  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld years",years);
1010  return;
1011  }
1012  months=ttl/2628000;
1013  seconds=ttl % 2628000;
1014  if (seconds == 0)
1015  {
1016  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld months",
1017  months);
1018  return;
1019  }
1020  weeks=ttl/604800;
1021  seconds=ttl % 604800;
1022  if (seconds == 0)
1023  {
1024  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld weeks",weeks);
1025  return;
1026  }
1027  days=ttl/86400;
1028  seconds=ttl % 86400;
1029  if (seconds == 0)
1030  {
1031  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld days",days);
1032  return;
1033  }
1034  hours=ttl/3600;
1035  seconds=ttl % 3600;
1036  if (seconds == 0)
1037  {
1038  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld hours",hours);
1039  return;
1040  }
1041  minutes=ttl/60;
1042  seconds=ttl % 60;
1043  if (seconds == 0)
1044  {
1045  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld minutes",
1046  minutes);
1047  return;
1048  }
1049  (void) FormatLocaleString(timeString,MagickPathExtent,"%lld seconds",ttl);
1050 }
1051 
1052 MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file,
1053  ExceptionInfo *magick_unused(exception))
1054 {
1055  char
1056  area_limit[MaxTextExtent],
1057  disk_limit[MaxTextExtent],
1058  height_limit[MaxTextExtent],
1059  list_length_limit[MaxTextExtent],
1060  map_limit[MaxTextExtent],
1061  memory_limit[MaxTextExtent],
1062  time_limit[MaxTextExtent],
1063  width_limit[MaxTextExtent];
1064 
1065  magick_unreferenced(exception);
1066 
1067  if (file == (const FILE *) NULL)
1068  file=stdout;
1069  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
1070  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
1071  LockSemaphoreInfo(resource_semaphore[FileResource]);
1072  (void) FormatPixelSize(resource_info.width_limit,MagickFalse,width_limit);
1073  (void) FormatPixelSize(resource_info.height_limit,MagickFalse,height_limit);
1074  (void) FormatPixelSize(resource_info.area_limit,MagickFalse,area_limit);
1075  (void) CopyMagickString(list_length_limit,"unlimited",MaxTextExtent);
1076  if (resource_info.list_length_limit != MagickResourceInfinity)
1077  (void) FormatMagickSize(resource_info.list_length_limit,MagickTrue,
1078  list_length_limit);
1079  (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,memory_limit);
1080  (void) FormatMagickSize(resource_info.map_limit,MagickTrue,map_limit);
1081  (void) CopyMagickString(disk_limit,"unlimited",MaxTextExtent);
1082  if (resource_info.disk_limit != MagickResourceInfinity)
1083  (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,disk_limit);
1084  (void) CopyMagickString(time_limit,"unlimited",MaxTextExtent);
1085  if (resource_info.time_limit != MagickResourceInfinity)
1086  FormatTimeToLive(resource_info.time_limit,time_limit);
1087  (void) FormatLocaleFile(file,"Resource limits:\n");
1088  (void) FormatLocaleFile(file," Width: %s\n",width_limit);
1089  (void) FormatLocaleFile(file," Height: %s\n",height_limit);
1090  (void) FormatLocaleFile(file," List length: %s\n",list_length_limit);
1091  (void) FormatLocaleFile(file," Area: %s\n",area_limit);
1092  (void) FormatLocaleFile(file," Memory: %s\n",memory_limit);
1093  (void) FormatLocaleFile(file," Map: %s\n",map_limit);
1094  (void) FormatLocaleFile(file," Disk: %s\n",disk_limit);
1095  (void) FormatLocaleFile(file," File: %.20g\n",(double) ((MagickOffsetType)
1096  resource_info.file_limit));
1097  (void) FormatLocaleFile(file," Thread: %.20g\n",(double) ((MagickOffsetType)
1098  resource_info.thread_limit));
1099  (void) FormatLocaleFile(file," Throttle: %.20g\n",(double)
1100  ((MagickOffsetType) resource_info.throttle_limit));
1101  (void) FormatLocaleFile(file," Time: %s\n",time_limit);
1102  (void) fflush(file);
1103  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1104  return(MagickTrue);
1105 }
1106 
1107 /*
1108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1109 % %
1110 % %
1111 % %
1112 % R e l i n q u i s h M a g i c k R e s o u r c e %
1113 % %
1114 % %
1115 % %
1116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1117 %
1118 % RelinquishMagickResource() relinquishes resources of the specified type.
1119 %
1120 % The format of the RelinquishMagickResource() method is:
1121 %
1122 % void RelinquishMagickResource(const ResourceType type,
1123 % const MagickSizeType size)
1124 %
1125 % A description of each parameter follows:
1126 %
1127 % o type: the type of resource.
1128 %
1129 % o size: the size of the resource.
1130 %
1131 */
1132 MagickExport void RelinquishMagickResource(const ResourceType type,
1133  const MagickSizeType size)
1134 {
1135  char
1136  resource_current[MaxTextExtent],
1137  resource_limit[MaxTextExtent],
1138  resource_request[MaxTextExtent];
1139 
1140  MagickBooleanType
1141  logging;
1142 
1143  logging=(GetLogEventMask() & ResourceEvent) != 0 ? MagickTrue : MagickFalse;
1144  if (logging != MagickFalse)
1145  (void) FormatMagickSize(size,MagickFalse,resource_request);
1146  switch (type)
1147  {
1148  case DiskResource:
1149  case FileResource:
1150  case MapResource:
1151  case MemoryResource:
1152  case TimeResource:
1153  {
1154  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1155  ActivateSemaphoreInfo(&resource_semaphore[type]);
1156  LockSemaphoreInfo(resource_semaphore[type]);
1157  break;
1158  }
1159  default: ;
1160  }
1161  switch (type)
1162  {
1163  case AreaResource:
1164  {
1165  resource_info.area=(MagickOffsetType) size;
1166  if (logging != MagickFalse)
1167  {
1168  (void) FormatMagickSize((MagickSizeType) resource_info.area,
1169  MagickFalse,resource_current);
1170  (void) FormatMagickSize(resource_info.area_limit,MagickFalse,
1171  resource_limit);
1172  }
1173  break;
1174  }
1175  case DiskResource:
1176  {
1177  resource_info.disk-=size;
1178  assert(resource_info.disk >= 0);
1179  if (logging != MagickFalse)
1180  {
1181  (void) FormatMagickSize((MagickSizeType) resource_info.disk,
1182  MagickTrue,resource_current);
1183  (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,
1184  resource_limit);
1185  }
1186  break;
1187  }
1188  case FileResource:
1189  {
1190  resource_info.file-=size;
1191  assert(resource_info.file >= 0);
1192  if (logging != MagickFalse)
1193  {
1194  (void) FormatMagickSize((MagickSizeType) resource_info.file,
1195  MagickFalse,resource_current);
1196  (void) FormatMagickSize((MagickSizeType) resource_info.file_limit,
1197  MagickFalse,resource_limit);
1198  }
1199  break;
1200  }
1201  case HeightResource:
1202  {
1203  resource_info.height=(MagickOffsetType) size;
1204  if (logging != MagickFalse)
1205  {
1206  (void) FormatMagickSize((MagickSizeType) resource_info.height,
1207  MagickFalse,resource_current);
1208  (void) FormatMagickSize(resource_info.height_limit,MagickFalse,
1209  resource_limit);
1210  }
1211  break;
1212  }
1213  case ListLengthResource:
1214  {
1215  resource_info.list_length=(MagickOffsetType) size;
1216  if (logging != MagickFalse)
1217  {
1218  (void) FormatMagickSize((MagickSizeType) resource_info.list_length,
1219  MagickFalse,resource_current);
1220  (void) FormatMagickSize(resource_info.list_length_limit,MagickFalse,
1221  resource_limit);
1222  }
1223  break;
1224  }
1225  case MapResource:
1226  {
1227  resource_info.map-=size;
1228  assert(resource_info.map >= 0);
1229  if (logging != MagickFalse)
1230  {
1231  (void) FormatMagickSize((MagickSizeType) resource_info.map,
1232  MagickTrue,resource_current);
1233  (void) FormatMagickSize(resource_info.map_limit,MagickTrue,
1234  resource_limit);
1235  }
1236  break;
1237  }
1238  case MemoryResource:
1239  {
1240  resource_info.memory-=size;
1241  assert(resource_info.memory >= 0);
1242  if (logging != MagickFalse)
1243  {
1244  (void) FormatMagickSize((MagickSizeType) resource_info.memory,
1245  MagickTrue,resource_current);
1246  (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,
1247  resource_limit);
1248  }
1249  break;
1250  }
1251  case ThreadResource:
1252  {
1253  if (logging != MagickFalse)
1254  {
1255  (void) FormatMagickSize((MagickSizeType) resource_info.thread,
1256  MagickFalse,resource_current);
1257  (void) FormatMagickSize((MagickSizeType) resource_info.thread_limit,
1258  MagickFalse,resource_limit);
1259  }
1260  break;
1261  }
1262  case ThrottleResource:
1263  {
1264  if (logging != MagickFalse)
1265  {
1266  (void) FormatMagickSize((MagickSizeType) resource_info.throttle,
1267  MagickFalse,resource_current);
1268  (void) FormatMagickSize((MagickSizeType) resource_info.throttle_limit,
1269  MagickFalse,resource_limit);
1270  }
1271  break;
1272  }
1273  case TimeResource:
1274  {
1275  resource_info.time-=size;
1276  assert(resource_info.time >= 0);
1277  if (logging != MagickFalse)
1278  {
1279  (void) FormatMagickSize((MagickSizeType) resource_info.time,
1280  MagickFalse,resource_current);
1281  (void) FormatMagickSize((MagickSizeType) resource_info.time_limit,
1282  MagickFalse,resource_limit);
1283  }
1284  break;
1285  }
1286  case WidthResource:
1287  {
1288  resource_info.width=(MagickOffsetType) size;
1289  if (logging != MagickFalse)
1290  {
1291  (void) FormatMagickSize((MagickSizeType) resource_info.width,
1292  MagickFalse,resource_current);
1293  (void) FormatMagickSize(resource_info.width_limit,MagickFalse,
1294  resource_limit);
1295  }
1296  break;
1297  }
1298  default:
1299  break;
1300  }
1301  switch (type)
1302  {
1303  case DiskResource:
1304  case FileResource:
1305  case MapResource:
1306  case MemoryResource:
1307  case TimeResource:
1308  {
1309  UnlockSemaphoreInfo(resource_semaphore[type]);
1310  break;
1311  }
1312  default: ;
1313  }
1314  if (logging != MagickFalse)
1315  {
1316  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s",
1317  CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type),
1318  resource_request,resource_current,resource_limit);
1319  }
1320 }
1321 
1322 /*
1323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1324 % %
1325 % %
1326 % %
1327 % R e l i n q u i s h U n i q u e F i l e R e s o u r c e %
1328 % %
1329 % %
1330 % %
1331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1332 %
1333 % RelinquishUniqueFileResource() relinquishes a unique file resource.
1334 %
1335 % The format of the RelinquishUniqueFileResource() method is:
1336 %
1337 % MagickBooleanType RelinquishUniqueFileResource(const char *path)
1338 %
1339 % A description of each parameter follows:
1340 %
1341 % o name: the name of the temporary resource.
1342 %
1343 */
1344 MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path)
1345 {
1346  char
1347  cache_path[MaxTextExtent];
1348 
1349  MagickStatusType
1350  status;
1351 
1352  assert(path != (const char *) NULL);
1353  status=MagickFalse;
1354  if ((GetLogEventMask() & ResourceEvent) != 0)
1355  (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"Relinquish %s",path);
1356  if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL)
1357  ActivateSemaphoreInfo(&resource_semaphore[FileResource]);
1358  LockSemaphoreInfo(resource_semaphore[FileResource]);
1359  if (temporary_resources != (SplayTreeInfo *) NULL)
1360  status=DeleteNodeFromSplayTree(temporary_resources, (const void *) path);
1361  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1362  (void) CopyMagickString(cache_path,path,MaxTextExtent);
1363  AppendImageFormat("cache",cache_path);
1364  if (access_utf8(cache_path,F_OK) == 0)
1365  {
1366  status=ShredFile(cache_path);
1367  status|=remove_utf8(cache_path);
1368  }
1369  if (status == MagickFalse)
1370  {
1371  status=ShredFile(path);
1372  status|=remove_utf8(path);
1373  }
1374  return(status == 0 ? MagickFalse : MagickTrue);
1375 }
1376 
1377 /*
1378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1379 % %
1380 % %
1381 % %
1382 + R e s o u r c e C o m p o n e n t G e n e s i s %
1383 % %
1384 % %
1385 % %
1386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 %
1388 % ResourceComponentGenesis() instantiates the resource component.
1389 %
1390 % The format of the ResourceComponentGenesis method is:
1391 %
1392 % MagickBooleanType ResourceComponentGenesis(void)
1393 %
1394 */
1395 MagickExport MagickBooleanType ResourceComponentGenesis(void)
1396 {
1397  char
1398  *limit;
1399 
1400  MagickSizeType
1401  memory;
1402 
1403  ssize_t
1404  files,
1405  i,
1406  number_threads,
1407  pages,
1408  pagesize;
1409 
1410  /*
1411  Set Magick resource limits.
1412  */
1413  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1414  if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1415  ActivateSemaphoreInfo(&resource_semaphore[i]);
1416  (void) SetMagickResourceLimit(WidthResource,resource_info.width_limit);
1417  limit=GetEnvironmentValue("MAGICK_WIDTH_LIMIT");
1418  if (limit != (char *) NULL)
1419  {
1420  (void) SetMagickResourceLimit(WidthResource,StringToSizeType(limit,
1421  100.0));
1422  limit=DestroyString(limit);
1423  }
1424  (void) SetMagickResourceLimit(HeightResource,resource_info.height_limit);
1425  limit=GetEnvironmentValue("MAGICK_HEIGHT_LIMIT");
1426  if (limit != (char *) NULL)
1427  {
1428  (void) SetMagickResourceLimit(HeightResource,StringToSizeType(limit,
1429  100.0));
1430  limit=DestroyString(limit);
1431  }
1432  pagesize=GetMagickPageSize();
1433  pages=(-1);
1434 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES)
1435  pages=(ssize_t) sysconf(_SC_PHYS_PAGES);
1436 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1437  pages=pages/2;
1438 #endif
1439 #endif
1440  memory=(MagickSizeType) pages*pagesize;
1441  if ((pagesize <= 0) || (pages <= 0))
1442  memory=2048UL*1024UL*1024UL;
1443 #if defined(MAGICKCORE_PixelCacheThreshold)
1444  memory=StringToMagickSizeType(MAGICKCORE_PixelCacheThreshold,100.0);
1445 #endif
1446  (void) SetMagickResourceLimit(AreaResource,4*memory);
1447  limit=GetEnvironmentValue("MAGICK_AREA_LIMIT");
1448  if (limit != (char *) NULL)
1449  {
1450  (void) SetMagickResourceLimit(AreaResource,StringToSizeType(limit,100.0));
1451  limit=DestroyString(limit);
1452  }
1453  (void) SetMagickResourceLimit(MemoryResource,memory);
1454  limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT");
1455  if (limit != (char *) NULL)
1456  {
1457  (void) SetMagickResourceLimit(MemoryResource,
1458  StringToSizeType(limit,100.0));
1459  limit=DestroyString(limit);
1460  }
1461  (void) SetMagickResourceLimit(MapResource,2*memory);
1462  limit=GetEnvironmentValue("MAGICK_MAP_LIMIT");
1463  if (limit != (char *) NULL)
1464  {
1465  (void) SetMagickResourceLimit(MapResource,StringToSizeType(limit,100.0));
1466  limit=DestroyString(limit);
1467  }
1468  (void) SetMagickResourceLimit(DiskResource,MagickResourceInfinity);
1469  limit=GetEnvironmentValue("MAGICK_DISK_LIMIT");
1470  if (limit != (char *) NULL)
1471  {
1472  (void) SetMagickResourceLimit(DiskResource,StringToSizeType(limit,100.0));
1473  limit=DestroyString(limit);
1474  }
1475  files=(-1);
1476 #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
1477  files=(ssize_t) sysconf(_SC_OPEN_MAX);
1478 #endif
1479 #if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE)
1480  if (files < 0)
1481  {
1482  struct rlimit
1483  resources;
1484 
1485  if (getrlimit(RLIMIT_NOFILE,&resources) != -1)
1486  files=(ssize_t) resources.rlim_cur;
1487  }
1488 #endif
1489 #if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT)
1490  if (files < 0)
1491  files=(ssize_t) getdtablesize();
1492 #endif
1493  if (files < 0)
1494  files=64;
1495  (void) SetMagickResourceLimit(FileResource,MagickMax((size_t)
1496  (3*files/4),64));
1497  limit=GetEnvironmentValue("MAGICK_FILE_LIMIT");
1498  if (limit != (char *) NULL)
1499  {
1500  (void) SetMagickResourceLimit(FileResource,StringToSizeType(limit,100.0));
1501  limit=DestroyString(limit);
1502  }
1503  number_threads=(ssize_t) GetOpenMPMaximumThreads();
1504  if (number_threads > 1)
1505  number_threads--; /* reserve core for OS */
1506  (void) SetMagickResourceLimit(ThreadResource,(size_t) number_threads);
1507  limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT");
1508  if (limit != (char *) NULL)
1509  {
1510  (void) SetMagickResourceLimit(ThreadResource,StringToSizeType(limit,
1511  100.0));
1512  limit=DestroyString(limit);
1513  }
1514  (void) SetMagickResourceLimit(ThrottleResource,0);
1515  limit=GetEnvironmentValue("MAGICK_THROTTLE_LIMIT");
1516  if (limit != (char *) NULL)
1517  {
1518  (void) SetMagickResourceLimit(ThrottleResource,StringToSizeType(limit,
1519  100.0));
1520  limit=DestroyString(limit);
1521  }
1522  (void) SetMagickResourceLimit(TimeResource,MagickResourceInfinity);
1523  limit=GetEnvironmentValue("MAGICK_TIME_LIMIT");
1524  if (limit != (char *) NULL)
1525  {
1526  (void) SetMagickResourceLimit(TimeResource,(MagickSizeType)
1527  ParseMagickTimeToLive(limit));
1528  limit=DestroyString(limit);
1529  }
1530  (void) SetMagickResourceLimit(ListLengthResource,MagickResourceInfinity);
1531  limit=GetEnvironmentValue("MAGICK_LIST_LENGTH_LIMIT");
1532  if (limit != (char *) NULL)
1533  {
1534  (void) SetMagickResourceLimit(ListLengthResource,
1535  StringToSizeType(limit,100.0));
1536  limit=DestroyString(limit);
1537  }
1538  return(MagickTrue);
1539 }
1540 
1541 /*
1542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1543 % %
1544 % %
1545 % %
1546 + R e s o u r c e C o m p o n e n t T e r m i n u s %
1547 % %
1548 % %
1549 % %
1550 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1551 %
1552 % ResourceComponentTerminus() destroys the resource component.
1553 %
1554 % The format of the ResourceComponentTerminus() method is:
1555 %
1556 % ResourceComponentTerminus(void)
1557 %
1558 */
1559 MagickExport void ResourceComponentTerminus(void)
1560 {
1561  ssize_t
1562  i;
1563 
1564  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1565  if (resource_semaphore[i] == (SemaphoreInfo *) NULL)
1566  ActivateSemaphoreInfo(&resource_semaphore[i]);
1567  LockSemaphoreInfo(resource_semaphore[FileResource]);
1568  if (temporary_resources != (SplayTreeInfo *) NULL)
1569  temporary_resources=DestroySplayTree(temporary_resources);
1570  if (random_info != (RandomInfo *) NULL)
1571  random_info=DestroyRandomInfo(random_info);
1572  UnlockSemaphoreInfo(resource_semaphore[FileResource]);
1573  for (i=0; i < (ssize_t) NumberOfResourceTypes; i++)
1574  DestroySemaphoreInfo(&resource_semaphore[i]);
1575 }
1576 
1577 /*
1578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1579 % %
1580 % %
1581 % %
1582 % S e t M a g i c k R e s o u r c e L i m i t %
1583 % %
1584 % %
1585 % %
1586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1587 %
1588 % SetMagickResourceLimit() sets the limit for a particular resource.
1589 %
1590 % The format of the SetMagickResourceLimit() method is:
1591 %
1592 % MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1593 % const MagickSizeType limit)
1594 %
1595 % A description of each parameter follows:
1596 %
1597 % o type: the type of resource.
1598 %
1599 % o limit: the maximum limit for the resource.
1600 %
1601 */
1602 
1603 MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type,
1604  const MagickSizeType limit)
1605 {
1606  char
1607  *value;
1608 
1609  MagickBooleanType
1610  status;
1611 
1612  status=MagickTrue;
1613  if (resource_semaphore[type] == (SemaphoreInfo *) NULL)
1614  ActivateSemaphoreInfo(&resource_semaphore[type]);
1615  LockSemaphoreInfo(resource_semaphore[type]);
1616  value=(char *) NULL;
1617  switch (type)
1618  {
1619  case AreaResource:
1620  {
1621  value=GetPolicyValue("resource:area");
1622  if (value == (char *) NULL)
1623  resource_info.area_limit=limit;
1624  else
1625  resource_info.area_limit=MagickMin(limit,StringToSizeType(value,100.0));
1626  break;
1627  }
1628  case DiskResource:
1629  {
1630  value=GetPolicyValue("resource:disk");
1631  if (value == (char *) NULL)
1632  resource_info.disk_limit=limit;
1633  else
1634  resource_info.disk_limit=MagickMin(limit,StringToSizeType(value,100.0));
1635  break;
1636  }
1637  case FileResource:
1638  {
1639  value=GetPolicyValue("resource:file");
1640  if (value == (char *) NULL)
1641  resource_info.file_limit=limit;
1642  else
1643  resource_info.file_limit=MagickMin(limit,StringToSizeType(value,100.0));
1644  break;
1645  }
1646  case HeightResource:
1647  {
1648  value=GetPolicyValue("resource:height");
1649  if (value == (char *) NULL)
1650  resource_info.height_limit=limit;
1651  else
1652  resource_info.height_limit=MagickMin(limit,StringToSizeType(value,
1653  100.0));
1654  resource_info.height_limit=MagickMin(resource_info.height_limit,
1655  (MagickSizeType) MAGICK_SSIZE_MAX);
1656  break;
1657  }
1658  case ListLengthResource:
1659  {
1660  value=GetPolicyValue("resource:list-length");
1661  if (value == (char *) NULL)
1662  resource_info.list_length_limit=limit;
1663  else
1664  resource_info.list_length_limit=MagickMin(limit,
1665  StringToSizeType(value,100.0));
1666  break;
1667  }
1668  case MapResource:
1669  {
1670  value=GetPolicyValue("resource:map");
1671  if (value == (char *) NULL)
1672  resource_info.map_limit=limit;
1673  else
1674  resource_info.map_limit=MagickMin(limit,StringToSizeType(value,100.0));
1675  break;
1676  }
1677  case MemoryResource:
1678  {
1679  value=GetPolicyValue("resource:memory");
1680  if (value == (char *) NULL)
1681  resource_info.memory_limit=limit;
1682  else
1683  resource_info.memory_limit=MagickMin(limit,StringToSizeType(value,
1684  100.0));
1685  break;
1686  }
1687  case ThreadResource:
1688  {
1689  value=GetPolicyValue("resource:thread");
1690  if (value == (char *) NULL)
1691  resource_info.thread_limit=limit;
1692  else
1693  resource_info.thread_limit=MagickMin(limit,StringToSizeType(value,
1694  100.0));
1695  if (resource_info.thread_limit > GetOpenMPMaximumThreads())
1696  resource_info.thread_limit=GetOpenMPMaximumThreads();
1697  else
1698  if (resource_info.thread_limit == 0)
1699  resource_info.thread_limit=1;
1700  break;
1701  }
1702  case ThrottleResource:
1703  {
1704  value=GetPolicyValue("resource:throttle");
1705  if (value == (char *) NULL)
1706  resource_info.throttle_limit=limit;
1707  else
1708  resource_info.throttle_limit=MagickMax(limit,StringToSizeType(value,
1709  100.0));
1710  break;
1711  }
1712  case TimeResource:
1713  {
1714  value=GetPolicyValue("resource:time");
1715  if (value == (char *) NULL)
1716  resource_info.time_limit=limit;
1717  else
1718  resource_info.time_limit=MagickMin(limit,(MagickSizeType)
1719  ParseMagickTimeToLive(value));
1720  break;
1721  }
1722  case WidthResource:
1723  {
1724  value=GetPolicyValue("resource:width");
1725  if (value == (char *) NULL)
1726  resource_info.width_limit=limit;
1727  else
1728  resource_info.width_limit=MagickMin(limit,StringToSizeType(value,
1729  100.0));
1730  resource_info.width_limit=MagickMin(resource_info.width_limit,
1731  (MagickSizeType) MAGICK_SSIZE_MAX);
1732  break;
1733  }
1734  default:
1735  {
1736  status=MagickFalse;
1737  break;
1738  }
1739  }
1740  if (value != (char *) NULL)
1741  value=DestroyString(value);
1742  UnlockSemaphoreInfo(resource_semaphore[type]);
1743  return(status);
1744 }