/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % RRRR EEEEE SSSSS OOO U U RRRR CCCC EEEEE % % R R E SS O O U U R R C E % % RRRR EEE SSS O O U U RRRR C EEE % % R R E SS O O U U R R C E % % R R EEEEE SSSSS OOO UUU R R CCCC EEEEE % % % % % % Get/Set MagickCore Resources % % % % Software Design % % Cristy % % September 2002 % % % % % % Copyright 1999-2021 ImageMagick Studio LLC, a non-profit organization % % dedicated to making software imaging solutions freely available. % % % % You may not use this file except in compliance with the License. You may % % obtain a copy of the License at % % % % https://imagemagick.org/script/license.php % % % % Unless required by applicable law or agreed to in writing, software % % distributed under the License is distributed on an "AS IS" BASIS, % % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % % See the License for the specific language governing permissions and % % limitations under the License. % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % */ /* Include declarations. */ #include "MagickCore/studio.h" #include "MagickCore/cache.h" #include "MagickCore/cache-private.h" #include "MagickCore/configure.h" #include "MagickCore/exception.h" #include "MagickCore/exception-private.h" #include "MagickCore/linked-list.h" #include "MagickCore/log.h" #include "MagickCore/image.h" #include "MagickCore/image-private.h" #include "MagickCore/memory_.h" #include "MagickCore/nt-base-private.h" #include "MagickCore/option.h" #include "MagickCore/policy.h" #include "MagickCore/random_.h" #include "MagickCore/registry.h" #include "MagickCore/resource_.h" #include "MagickCore/resource-private.h" #include "MagickCore/semaphore.h" #include "MagickCore/signature-private.h" #include "MagickCore/string_.h" #include "MagickCore/string-private.h" #include "MagickCore/splay-tree.h" #include "MagickCore/thread-private.h" #include "MagickCore/token.h" #include "MagickCore/utility.h" #include "MagickCore/utility-private.h" /* Define declarations. */ #define MagickPathTemplate "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" /* min 6 X's */ #define NumberOfResourceTypes \ (sizeof(resource_semaphore)/sizeof(*resource_semaphore)) /* Typedef declarations. */ typedef struct _ResourceInfo { MagickOffsetType width, height, list_length, area, memory, map, disk, file, thread, throttle, time; MagickSizeType width_limit, height_limit, list_length_limit, area_limit, memory_limit, map_limit, disk_limit, file_limit, thread_limit, throttle_limit, time_limit; } ResourceInfo; /* Global declarations. */ static RandomInfo *random_info = (RandomInfo *) NULL; static ResourceInfo resource_info = { MagickULLConstant(0), /* initial width */ MagickULLConstant(0), /* initial height */ MagickULLConstant(0), /* initial list length */ MagickULLConstant(0), /* initial area */ MagickULLConstant(0), /* initial memory */ MagickULLConstant(0), /* initial map */ MagickULLConstant(0), /* initial disk */ MagickULLConstant(0), /* initial file */ MagickULLConstant(0), /* initial thread */ MagickULLConstant(0), /* initial throttle */ MagickULLConstant(0), /* initial time */ MAGICK_SSIZE_MAX/sizeof(Quantum)/5,/* width limit */ MAGICK_SSIZE_MAX/sizeof(Quantum)/5,/* height limit */ MagickResourceInfinity, /* list length limit */ MagickULLConstant(3072)*1024*1024, /* area limit */ MagickULLConstant(1536)*1024*1024, /* memory limit */ MagickULLConstant(3072)*1024*1024, /* map limit */ MagickResourceInfinity, /* disk limit */ MagickULLConstant(768), /* file limit */ MagickULLConstant(1), /* thread limit */ MagickULLConstant(0), /* throttle limit */ MagickResourceInfinity /* time limit */ }; static SemaphoreInfo *resource_semaphore[] = { (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL, (SemaphoreInfo *) NULL }; static SplayTreeInfo *temporary_resources = (SplayTreeInfo *) NULL; /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % A c q u i r e M a g i c k R e s o u r c e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % AcquireMagickResource() acquires resources of the specified type. % MagickFalse is returned if the specified resource is exhausted otherwise % MagickTrue. % % The format of the AcquireMagickResource() method is: % % MagickBooleanType AcquireMagickResource(const ResourceType type, % const MagickSizeType size) % % A description of each parameter follows: % % o type: the type of resource. % % o size: the number of bytes needed from for this resource. % */ MagickExport MagickBooleanType AcquireMagickResource(const ResourceType type, const MagickSizeType size) { MagickBooleanType bi, status; MagickOffsetType current, request; MagickSizeType limit; request=(MagickOffsetType) size; if (request < 0) return(MagickFalse); limit=0; current=0; bi=MagickFalse; status=MagickFalse; switch (type) { case DiskResource: case FileResource: case MapResource: case MemoryResource: case TimeResource: { if (resource_semaphore[type] == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&resource_semaphore[type]); LockSemaphoreInfo(resource_semaphore[type]); break; } default: ; } switch (type) { case AreaResource: { bi=MagickTrue; resource_info.area=request; limit=resource_info.area_limit; if ((limit == MagickResourceInfinity) || (size < limit)) status=MagickTrue; break; } case DiskResource: { bi=MagickTrue; limit=resource_info.disk_limit; if (((MagickSizeType) resource_info.disk+request) > (MagickSizeType) resource_info.disk) { resource_info.disk+=request; if ((limit == MagickResourceInfinity) || (resource_info.disk < (MagickOffsetType) limit)) status=MagickTrue; else resource_info.disk-=request; } current=resource_info.disk; break; } case FileResource: { limit=resource_info.file_limit; if (((MagickSizeType) resource_info.file+request) > (MagickSizeType) resource_info.file) { resource_info.file+=request; if ((limit == MagickResourceInfinity) || (resource_info.file < (MagickOffsetType) limit)) status=MagickTrue; } current=resource_info.file; break; } case HeightResource: { bi=MagickTrue; resource_info.height=request; limit=resource_info.height_limit; if ((limit == MagickResourceInfinity) || (size < limit)) status=MagickTrue; break; } case ListLengthResource: { resource_info.list_length=request; limit=resource_info.list_length_limit; if ((limit == MagickResourceInfinity) || (size < limit)) status=MagickTrue; break; } case MapResource: { bi=MagickTrue; limit=resource_info.map_limit; if (((MagickSizeType) resource_info.map+request) > (MagickSizeType) resource_info.map) { resource_info.map+=request; if ((limit == MagickResourceInfinity) || (resource_info.map < (MagickOffsetType) limit)) status=MagickTrue; else resource_info.map-=request; } current=resource_info.map; break; } case MemoryResource: { bi=MagickTrue; limit=resource_info.memory_limit; if (((MagickSizeType) resource_info.memory+request) > (MagickSizeType) resource_info.memory) { resource_info.memory+=request; if ((limit == MagickResourceInfinity) || (resource_info.memory < (MagickOffsetType) limit)) status=MagickTrue; else resource_info.memory-=request; } current=resource_info.memory; break; } case ThreadResource: { limit=resource_info.thread_limit; if ((limit == MagickResourceInfinity) || (resource_info.thread < (MagickOffsetType) limit)) status=MagickTrue; break; } case ThrottleResource: { limit=resource_info.throttle_limit; if ((limit == MagickResourceInfinity) || (resource_info.throttle < (MagickOffsetType) limit)) status=MagickTrue; break; } case TimeResource: { limit=resource_info.time_limit; if (((MagickSizeType) resource_info.time+request) > (MagickSizeType) resource_info.time) { resource_info.time+=request; if ((limit == MagickResourceInfinity) || (resource_info.time < (MagickOffsetType) limit)) status=MagickTrue; else resource_info.time-=request; } current=resource_info.time; break; } case WidthResource: { bi=MagickTrue; resource_info.width=request; limit=resource_info.width_limit; if ((limit == MagickResourceInfinity) || (size < limit)) status=MagickTrue; break; } default: { current=0; break; } } switch (type) { case DiskResource: case FileResource: case MapResource: case MemoryResource: case TimeResource: { UnlockSemaphoreInfo(resource_semaphore[type]); break; } default: ; } if (IsEventLogging() != MagickFalse) { char resource_current[MagickFormatExtent], resource_limit[MagickFormatExtent], resource_request[MagickFormatExtent]; (void) FormatMagickSize(size,bi,(bi != MagickFalse) ? "B" : (const char *) NULL,MagickFormatExtent,resource_request); (void) FormatMagickSize((MagickSizeType) current,bi,(bi != MagickFalse) ? "B" : (const char *) NULL,MagickFormatExtent,resource_current); (void) FormatMagickSize(limit,bi,(bi != MagickFalse) ? "B" : (const char *) NULL,MagickFormatExtent,resource_limit); (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s", CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type), resource_request,resource_current,resource_limit); } return(status); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + 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 % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % AsynchronousResourceComponentTerminus() destroys the resource environment. % It differs from ResourceComponentTerminus() in that it can be called from a % asynchronous signal handler. % % The format of the ResourceComponentTerminus() method is: % % ResourceComponentTerminus(void) % */ MagickPrivate void AsynchronousResourceComponentTerminus(void) { const char *path; if (temporary_resources == (SplayTreeInfo *) NULL) return; /* Remove any lingering temporary files. */ ResetSplayTreeIterator(temporary_resources); path=(const char *) GetNextKeyInSplayTree(temporary_resources); while (path != (const char *) NULL) { (void) ShredFile(path); path=(const char *) GetNextKeyInSplayTree(temporary_resources); } } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % 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 % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % AcquireUniqueFileResource() returns a unique file name, and returns a file % descriptor for the file open for reading and writing. % % The format of the AcquireUniqueFileResource() method is: % % int AcquireUniqueFileResource(char *path) % % A description of each parameter follows: % % o path: Specifies a pointer to an array of characters. The unique path % name is returned in this array. % */ static void *DestroyTemporaryResources(void *temporary_resource) { (void) ShredFile((char *) temporary_resource); temporary_resource=DestroyString((char *) temporary_resource); return((void *) NULL); } MagickExport MagickBooleanType GetPathTemplate(char *path) { char *directory, *value; ExceptionInfo *exception; MagickBooleanType status; struct stat attributes; (void) FormatLocaleString(path,MagickPathExtent,"magick-" MagickPathTemplate); exception=AcquireExceptionInfo(); directory=(char *) GetImageRegistry(StringRegistryType,"temporary-path", exception); exception=DestroyExceptionInfo(exception); if (directory == (char *) NULL) directory=GetEnvironmentValue("MAGICK_TEMPORARY_PATH"); if (directory == (char *) NULL) directory=GetEnvironmentValue("MAGICK_TMPDIR"); if (directory == (char *) NULL) directory=GetEnvironmentValue("TMPDIR"); #if defined(MAGICKCORE_WINDOWS_SUPPORT) || defined(__OS2__) || defined(__CYGWIN__) if (directory == (char *) NULL) directory=GetEnvironmentValue("TMP"); if (directory == (char *) NULL) directory=GetEnvironmentValue("TEMP"); #endif #if defined(__VMS) if (directory == (char *) NULL) directory=GetEnvironmentValue("MTMPDIR"); #endif #if defined(P_tmpdir) if (directory == (char *) NULL) directory=ConstantString(P_tmpdir); #endif if (directory == (char *) NULL) return(MagickTrue); value=GetPolicyValue("resource:temporary-path"); if (value != (char *) NULL) { (void) CloneString(&directory,value); value=DestroyString(value); } if (strlen(directory) > (MagickPathExtent-25)) { directory=DestroyString(directory); return(MagickFalse); } status=GetPathAttributes(directory,&attributes); if ((status == MagickFalse) || !S_ISDIR(attributes.st_mode)) { directory=DestroyString(directory); return(MagickFalse); } if (directory[strlen(directory)-1] == *DirectorySeparator) (void) FormatLocaleString(path,MagickPathExtent,"%smagick-" MagickPathTemplate,directory); else (void) FormatLocaleString(path,MagickPathExtent, "%s%smagick-" MagickPathTemplate,directory,DirectorySeparator); directory=DestroyString(directory); #if defined(MAGICKCORE_WINDOWS_SUPPORT) { char *p; /* Ghostscript does not like backslashes so we need to replace them. The forward slash also works under Windows. */ for (p=(path[1] == *DirectorySeparator ? path+2 : path); *p != '\0'; p++) if (*p == *DirectorySeparator) *p='/'; } #endif return(MagickTrue); } MagickExport int AcquireUniqueFileResource(char *path) { #if !defined(O_NOFOLLOW) #define O_NOFOLLOW 0 #endif #if !defined(TMP_MAX) # define TMP_MAX 238328 #endif int c, file; char *p; ssize_t i; static const char portable_filename[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"; StringInfo *key; unsigned char *datum; assert(path != (char *) NULL); (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"..."); if (random_info == (RandomInfo *) NULL) { if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&resource_semaphore[FileResource]); LockSemaphoreInfo(resource_semaphore[FileResource]); if (random_info == (RandomInfo *) NULL) random_info=AcquireRandomInfo(); UnlockSemaphoreInfo(resource_semaphore[FileResource]); } file=(-1); for (i=0; i < (ssize_t) TMP_MAX; i++) { ssize_t j; /* Get temporary pathname. */ (void) GetPathTemplate(path); key=GetRandomKey(random_info,strlen(MagickPathTemplate)-6); p=path+strlen(path)-strlen(MagickPathTemplate); datum=GetStringInfoDatum(key); for (j=0; j < (ssize_t) GetStringInfoLength(key); j++) { c=(int) (datum[j] & 0x3f); *p++=portable_filename[c]; } key=DestroyStringInfo(key); #if defined(MAGICKCORE_HAVE_MKSTEMP) file=mkstemp(path); if (file != -1) { #if defined(MAGICKCORE_HAVE_FCHMOD) (void) fchmod(file,0600); #endif #if defined(__OS2__) setmode(file,O_BINARY); #endif break; } #endif key=GetRandomKey(random_info,strlen(MagickPathTemplate)); p=path+strlen(path)-strlen(MagickPathTemplate); datum=GetStringInfoDatum(key); for (j=0; j < (ssize_t) GetStringInfoLength(key); j++) { c=(int) (datum[j] & 0x3f); *p++=portable_filename[c]; } key=DestroyStringInfo(key); file=open_utf8(path,O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_NOFOLLOW, S_MODE); if ((file >= 0) || (errno != EEXIST)) break; } (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path); if (file == -1) return(file); if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&resource_semaphore[FileResource]); LockSemaphoreInfo(resource_semaphore[FileResource]); if (temporary_resources == (SplayTreeInfo *) NULL) temporary_resources=NewSplayTree(CompareSplayTreeString, DestroyTemporaryResources,(void *(*)(void *)) NULL); UnlockSemaphoreInfo(resource_semaphore[FileResource]); (void) AddValueToSplayTree(temporary_resources,ConstantString(path), (const void *) NULL); return(file); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % G e t M a g i c k R e s o u r c e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GetMagickResource() returns the specified resource. % % The format of the GetMagickResource() method is: % % MagickSizeType GetMagickResource(const ResourceType type) % % A description of each parameter follows: % % o type: the type of resource. % */ MagickExport MagickSizeType GetMagickResource(const ResourceType type) { MagickSizeType resource; resource=0; switch (type) { case DiskResource: case FileResource: case MapResource: case MemoryResource: case TimeResource: { if (resource_semaphore[type] == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&resource_semaphore[type]); LockSemaphoreInfo(resource_semaphore[type]); break; } default: ; } switch (type) { case AreaResource: { resource=(MagickSizeType) resource_info.area; break; } case DiskResource: { resource=(MagickSizeType) resource_info.disk; break; } case FileResource: { resource=(MagickSizeType) resource_info.file; break; } case HeightResource: { resource=(MagickSizeType) resource_info.height; break; } case ListLengthResource: { resource=(MagickSizeType) resource_info.list_length; break; } case MapResource: { resource=(MagickSizeType) resource_info.map; break; } case MemoryResource: { resource=(MagickSizeType) resource_info.memory; break; } case TimeResource: { resource=(MagickSizeType) resource_info.time; break; } case ThreadResource: { resource=(MagickSizeType) resource_info.thread; break; } case ThrottleResource: { resource=(MagickSizeType) resource_info.throttle; break; } case WidthResource: { resource=(MagickSizeType) resource_info.width; break; } default: break; } switch (type) { case DiskResource: case FileResource: case MapResource: case MemoryResource: case TimeResource: { UnlockSemaphoreInfo(resource_semaphore[type]); break; } default: ; } return(resource); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % G e t M a g i c k R e s o u r c e L i m i t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % GetMagickResourceLimit() returns the specified resource limit. % % The format of the GetMagickResourceLimit() method is: % % MagickSizeType GetMagickResourceLimit(const ResourceType type) % % A description of each parameter follows: % % o type: the type of resource. % */ MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type) { MagickSizeType resource; switch (type) { case AreaResource: return(resource_info.area_limit); case HeightResource: return(resource_info.height_limit); case ListLengthResource: return(resource_info.list_length_limit); case ThreadResource: return(resource_info.thread_limit); case ThrottleResource: return(resource_info.throttle_limit); case WidthResource: return(resource_info.width_limit); default: ; } resource=0; if (resource_semaphore[type] == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&resource_semaphore[type]); LockSemaphoreInfo(resource_semaphore[type]); switch (type) { case DiskResource: { resource=resource_info.disk_limit; break; } case FileResource: { resource=resource_info.file_limit; break; } case MapResource: { resource=resource_info.map_limit; break; } case MemoryResource: { resource=resource_info.memory_limit; break; } case TimeResource: { resource=resource_info.time_limit; break; } default: break; } UnlockSemaphoreInfo(resource_semaphore[type]); return(resource); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % L i s t M a g i c k R e s o u r c e I n f o % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ListMagickResourceInfo() lists the resource info to a file. % % The format of the ListMagickResourceInfo method is: % % MagickBooleanType ListMagickResourceInfo(FILE *file, % ExceptionInfo *exception) % % A description of each parameter follows. % % o file: An pointer to a FILE. % % o exception: return any errors or warnings in this structure. % */ MagickExport MagickBooleanType ListMagickResourceInfo(FILE *file, ExceptionInfo *magick_unused(exception)) { char area_limit[MagickFormatExtent], disk_limit[MagickFormatExtent], height_limit[MagickFormatExtent], list_length_limit[MagickFormatExtent], map_limit[MagickFormatExtent], memory_limit[MagickFormatExtent], time_limit[MagickFormatExtent], width_limit[MagickFormatExtent]; magick_unreferenced(exception); if (file == (const FILE *) NULL) file=stdout; if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&resource_semaphore[FileResource]); LockSemaphoreInfo(resource_semaphore[FileResource]); (void) FormatMagickSize(resource_info.width_limit,MagickFalse,"P", MagickFormatExtent,width_limit); (void) FormatMagickSize(resource_info.height_limit,MagickFalse,"P", MagickFormatExtent,height_limit); (void) FormatMagickSize(resource_info.area_limit,MagickFalse,"P", MagickFormatExtent,area_limit); (void) CopyMagickString(list_length_limit,"unlimited",MagickFormatExtent); if (resource_info.list_length_limit != MagickResourceInfinity) (void) FormatMagickSize(resource_info.list_length_limit,MagickTrue,"B", MagickFormatExtent,list_length_limit); (void) FormatMagickSize(resource_info.memory_limit,MagickTrue,"B", MagickFormatExtent,memory_limit); (void) FormatMagickSize(resource_info.map_limit,MagickTrue,"B", MagickFormatExtent,map_limit); (void) CopyMagickString(disk_limit,"unlimited",MagickFormatExtent); if (resource_info.disk_limit != MagickResourceInfinity) (void) FormatMagickSize(resource_info.disk_limit,MagickTrue,"B", MagickFormatExtent,disk_limit); (void) CopyMagickString(time_limit,"unlimited",MagickFormatExtent); if (resource_info.time_limit != MagickResourceInfinity) (void) FormatLocaleString(time_limit,MagickFormatExtent,"%.20g",(double) ((MagickOffsetType) resource_info.time_limit)); (void) FormatLocaleFile(file,"Resource limits:\n"); (void) FormatLocaleFile(file," Width: %s\n",width_limit); (void) FormatLocaleFile(file," Height: %s\n",height_limit); (void) FormatLocaleFile(file," Area: %s\n",area_limit); (void) FormatLocaleFile(file," List length: %s\n",list_length_limit); (void) FormatLocaleFile(file," Memory: %s\n",memory_limit); (void) FormatLocaleFile(file," Map: %s\n",map_limit); (void) FormatLocaleFile(file," Disk: %s\n",disk_limit); (void) FormatLocaleFile(file," File: %.20g\n",(double) ((MagickOffsetType) resource_info.file_limit)); (void) FormatLocaleFile(file," Thread: %.20g\n",(double) ((MagickOffsetType) resource_info.thread_limit)); (void) FormatLocaleFile(file," Throttle: %.20g\n",(double) ((MagickOffsetType) resource_info.throttle_limit)); (void) FormatLocaleFile(file," Time: %s\n",time_limit); (void) fflush(file); UnlockSemaphoreInfo(resource_semaphore[FileResource]); return(MagickTrue); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % R e l i n q u i s h M a g i c k R e s o u r c e % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % RelinquishMagickResource() relinquishes resources of the specified type. % % The format of the RelinquishMagickResource() method is: % % void RelinquishMagickResource(const ResourceType type, % const MagickSizeType size) % % A description of each parameter follows: % % o type: the type of resource. % % o size: the size of the resource. % */ MagickExport void RelinquishMagickResource(const ResourceType type, const MagickSizeType size) { MagickBooleanType bi; MagickSizeType current, limit; bi=MagickFalse; limit=0; current=0; switch (type) { case DiskResource: case FileResource: case MapResource: case MemoryResource: case TimeResource: { if (resource_semaphore[type] == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&resource_semaphore[type]); LockSemaphoreInfo(resource_semaphore[type]); break; } default: ; } switch (type) { case DiskResource: { bi=MagickTrue; resource_info.disk-=size; current=(MagickSizeType) resource_info.disk; limit=resource_info.disk_limit; assert(resource_info.disk >= 0); break; } case FileResource: { resource_info.file-=size; current=(MagickSizeType) resource_info.file; limit=resource_info.file_limit; assert(resource_info.file >= 0); break; } case MapResource: { bi=MagickTrue; resource_info.map-=size; current=(MagickSizeType) resource_info.map; limit=resource_info.map_limit; assert(resource_info.map >= 0); break; } case MemoryResource: { bi=MagickTrue; resource_info.memory-=size; current=(MagickSizeType) resource_info.memory; limit=resource_info.memory_limit; assert(resource_info.memory >= 0); break; } case TimeResource: { bi=MagickTrue; resource_info.time-=size; current=(MagickSizeType) resource_info.time; limit=resource_info.time_limit; assert(resource_info.time >= 0); break; } default: { current=0; break; } } switch (type) { case DiskResource: case FileResource: case MapResource: case MemoryResource: case TimeResource: { UnlockSemaphoreInfo(resource_semaphore[type]); break; } default: ; } if (IsEventLogging() != MagickFalse) { char resource_current[MagickFormatExtent], resource_limit[MagickFormatExtent], resource_request[MagickFormatExtent]; (void) FormatMagickSize(size,bi,(bi != MagickFalse) ? "B" : (const char *) NULL,MagickFormatExtent,resource_request); (void) FormatMagickSize(current,bi,(bi != MagickFalse) ? "B" : (const char *) NULL,MagickFormatExtent,resource_current); (void) FormatMagickSize(limit,bi,(bi != MagickFalse) ? "B" : (const char *) NULL,MagickFormatExtent,resource_limit); (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s: %s/%s/%s", CommandOptionToMnemonic(MagickResourceOptions,(ssize_t) type), resource_request,resource_current,resource_limit); } } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % 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 % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % RelinquishUniqueFileResource() relinquishes a unique file resource. % % The format of the RelinquishUniqueFileResource() method is: % % MagickBooleanType RelinquishUniqueFileResource(const char *path) % % A description of each parameter follows: % % o name: the name of the temporary resource. % */ MagickExport MagickBooleanType RelinquishUniqueFileResource(const char *path) { char cache_path[MagickPathExtent]; MagickBooleanType status; assert(path != (const char *) NULL); status=MagickFalse; (void) LogMagickEvent(ResourceEvent,GetMagickModule(),"%s",path); if (resource_semaphore[FileResource] == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&resource_semaphore[FileResource]); LockSemaphoreInfo(resource_semaphore[FileResource]); if (temporary_resources != (SplayTreeInfo *) NULL) status=DeleteNodeFromSplayTree(temporary_resources,(const void *) path); UnlockSemaphoreInfo(resource_semaphore[FileResource]); (void) CopyMagickString(cache_path,path,MagickPathExtent); AppendImageFormat("cache",cache_path); if (access_utf8(cache_path,F_OK) == 0) (void) ShredFile(cache_path); if (status == MagickFalse) status=ShredFile(path); return(status); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + R e s o u r c e C o m p o n e n t G e n e s i s % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ResourceComponentGenesis() instantiates the resource component. % % The format of the ResourceComponentGenesis method is: % % MagickBooleanType ResourceComponentGenesis(void) % */ MagickPrivate MagickBooleanType ResourceComponentGenesis(void) { char *limit; MagickSizeType memory; ssize_t i; ssize_t files, pages, pagesize; /* Set Magick resource limits. */ for (i=0; i < (ssize_t) NumberOfResourceTypes; i++) if (resource_semaphore[i] == (SemaphoreInfo *) NULL) resource_semaphore[i]=AcquireSemaphoreInfo(); (void) SetMagickResourceLimit(WidthResource,resource_info.width_limit); limit=GetEnvironmentValue("MAGICK_WIDTH_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(WidthResource,StringToMagickSizeType(limit, 100.0)); limit=DestroyString(limit); } (void) SetMagickResourceLimit(HeightResource,resource_info.height_limit); limit=GetEnvironmentValue("MAGICK_HEIGHT_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(HeightResource,StringToMagickSizeType( limit,100.0)); limit=DestroyString(limit); } pagesize=GetMagickPageSize(); pages=(-1); #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_PHYS_PAGES) pages=(ssize_t) sysconf(_SC_PHYS_PAGES); #if defined(MAGICKCORE_WINDOWS_SUPPORT) pages=pages/2; #endif #endif memory=(MagickSizeType) pages*pagesize; if ((pagesize <= 0) || (pages <= 0)) memory=2048UL*1024UL*1024UL; #if defined(PixelCacheThreshold) memory=PixelCacheThreshold; #endif (void) SetMagickResourceLimit(AreaResource,2*memory); limit=GetEnvironmentValue("MAGICK_AREA_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(AreaResource,StringToMagickSizeType(limit, 100.0)); limit=DestroyString(limit); } (void) SetMagickResourceLimit(MemoryResource,memory); limit=GetEnvironmentValue("MAGICK_MEMORY_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(MemoryResource,StringToMagickSizeType( limit,100.0)); limit=DestroyString(limit); } (void) SetMagickResourceLimit(MapResource,2*memory); limit=GetEnvironmentValue("MAGICK_MAP_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(MapResource,StringToMagickSizeType(limit, 100.0)); limit=DestroyString(limit); } (void) SetMagickResourceLimit(DiskResource,MagickResourceInfinity); limit=GetEnvironmentValue("MAGICK_DISK_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(DiskResource,StringToMagickSizeType(limit, 100.0)); limit=DestroyString(limit); } files=(-1); #if defined(MAGICKCORE_HAVE_SYSCONF) && defined(_SC_OPEN_MAX) files=(ssize_t) sysconf(_SC_OPEN_MAX); #endif #if defined(MAGICKCORE_HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE) if (files < 0) { struct rlimit resources; if (getrlimit(RLIMIT_NOFILE,&resources) != -1) files=(ssize_t) resources.rlim_cur; } #endif #if defined(MAGICKCORE_HAVE_GETDTABLESIZE) && defined(MAGICKCORE_POSIX_SUPPORT) if (files < 0) files=(ssize_t) getdtablesize(); #endif if (files < 0) files=64; (void) SetMagickResourceLimit(FileResource,MagickMax((size_t) (3*files/4),64)); limit=GetEnvironmentValue("MAGICK_FILE_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(FileResource,StringToMagickSizeType(limit, 100.0)); limit=DestroyString(limit); } (void) SetMagickResourceLimit(ThreadResource,GetOpenMPMaximumThreads()); limit=GetEnvironmentValue("MAGICK_THREAD_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(ThreadResource,StringToMagickSizeType( limit,100.0)); limit=DestroyString(limit); } (void) SetMagickResourceLimit(ThrottleResource,0); limit=GetEnvironmentValue("MAGICK_THROTTLE_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(ThrottleResource,StringToMagickSizeType( limit,100.0)); limit=DestroyString(limit); } (void) SetMagickResourceLimit(TimeResource,MagickResourceInfinity); limit=GetEnvironmentValue("MAGICK_TIME_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(TimeResource,StringToMagickSizeType(limit, 100.0)); limit=DestroyString(limit); } (void) SetMagickResourceLimit(ListLengthResource,MagickResourceInfinity); limit=GetEnvironmentValue("MAGICK_LIST_LENGTH_LIMIT"); if (limit != (char *) NULL) { (void) SetMagickResourceLimit(ListLengthResource, StringToMagickSizeType(limit,100.0)); limit=DestroyString(limit); } return(MagickTrue); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % + 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 % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ResourceComponentTerminus() destroys the resource component. % % The format of the ResourceComponentTerminus() method is: % % ResourceComponentTerminus(void) % */ MagickPrivate void ResourceComponentTerminus(void) { ssize_t i; for (i=0; i < (ssize_t) NumberOfResourceTypes; i++) if (resource_semaphore[i] == (SemaphoreInfo *) NULL) resource_semaphore[i]=AcquireSemaphoreInfo(); LockSemaphoreInfo(resource_semaphore[FileResource]); if (temporary_resources != (SplayTreeInfo *) NULL) temporary_resources=DestroySplayTree(temporary_resources); if (random_info != (RandomInfo *) NULL) random_info=DestroyRandomInfo(random_info); UnlockSemaphoreInfo(resource_semaphore[FileResource]); for (i=0; i < (ssize_t) NumberOfResourceTypes; i++) RelinquishSemaphoreInfo(&resource_semaphore[i]); } /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % % % % % S e t M a g i c k R e s o u r c e L i m i t % % % % % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % SetMagickResourceLimit() sets the limit for a particular resource. % % The format of the SetMagickResourceLimit() method is: % % MagickBooleanType SetMagickResourceLimit(const ResourceType type, % const MagickSizeType limit) % % A description of each parameter follows: % % o type: the type of resource. % % o limit: the maximum limit for the resource. % */ MagickExport MagickBooleanType SetMagickResourceLimit(const ResourceType type, const MagickSizeType limit) { char *value; MagickBooleanType status; status=MagickTrue; value=(char *) NULL; switch (type) { case DiskResource: case FileResource: case MapResource: case MemoryResource: case TimeResource: { if (resource_semaphore[type] == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&resource_semaphore[type]); LockSemaphoreInfo(resource_semaphore[type]); break; } default: ; } switch (type) { case AreaResource: { value=GetPolicyValue("resource:area"); if (value == (char *) NULL) resource_info.area_limit=limit; else resource_info.area_limit=MagickMin(limit,StringToMagickSizeType(value, 100.0)); break; } case DiskResource: { value=GetPolicyValue("resource:disk"); if (value == (char *) NULL) resource_info.disk_limit=limit; else resource_info.disk_limit=MagickMin(limit,StringToMagickSizeType(value, 100.0)); break; } case FileResource: { value=GetPolicyValue("resource:file"); if (value == (char *) NULL) resource_info.file_limit=limit; else resource_info.file_limit=MagickMin(limit,StringToMagickSizeType(value, 100.0)); break; } case HeightResource: { value=GetPolicyValue("resource:height"); if (value == (char *) NULL) resource_info.height_limit=limit; else resource_info.height_limit=MagickMin(limit,StringToMagickSizeType( value,100.0)); resource_info.height_limit=MagickMin(resource_info.height_limit, (MagickSizeType) MAGICK_SSIZE_MAX); break; } case ListLengthResource: { value=GetPolicyValue("resource:list-length"); if (value == (char *) NULL) resource_info.list_length_limit=limit; else resource_info.list_length_limit=MagickMin(limit, StringToMagickSizeType(value,100.0)); break; } case MapResource: { value=GetPolicyValue("resource:map"); if (value == (char *) NULL) resource_info.map_limit=limit; else resource_info.map_limit=MagickMin(limit,StringToMagickSizeType( value,100.0)); break; } case MemoryResource: { value=GetPolicyValue("resource:memory"); if (value == (char *) NULL) resource_info.memory_limit=limit; else resource_info.memory_limit=MagickMin(limit,StringToMagickSizeType( value,100.0)); break; } case ThreadResource: { value=GetPolicyValue("resource:thread"); if (value == (char *) NULL) resource_info.thread_limit=limit; else resource_info.thread_limit=MagickMin(limit,StringToMagickSizeType( value,100.0)); if (resource_info.thread_limit > GetOpenMPMaximumThreads()) resource_info.thread_limit=GetOpenMPMaximumThreads(); else if (resource_info.thread_limit == 0) resource_info.thread_limit=1; break; } case ThrottleResource: { value=GetPolicyValue("resource:throttle"); if (value == (char *) NULL) resource_info.throttle_limit=limit; else resource_info.throttle_limit=MagickMax(limit,StringToMagickSizeType( value,100.0)); break; } case TimeResource: { value=GetPolicyValue("resource:time"); if (value == (char *) NULL) resource_info.time_limit=limit; else resource_info.time_limit=MagickMin(limit,StringToMagickSizeType(value, 100.0)); ResetPixelCacheEpoch(); break; } case WidthResource: { value=GetPolicyValue("resource:width"); if (value == (char *) NULL) resource_info.width_limit=limit; else resource_info.width_limit=MagickMin(limit,StringToMagickSizeType(value, 100.0)); resource_info.width_limit=MagickMin(resource_info.width_limit, (MagickSizeType) MAGICK_SSIZE_MAX); break; } default: { status=MagickFalse; break; } } switch (type) { case DiskResource: case FileResource: case MapResource: case MemoryResource: case TimeResource: { UnlockSemaphoreInfo(resource_semaphore[type]); break; } default: ; } if (value != (char *) NULL) value=DestroyString(value); return(status); }