GridLab
Grid Application Toolkit

A simple API for Grid Applications
GAT

Menu



Main Page   Alphabetical List   Compound List   File List   Compound Members   File Members  

GATSelf.c

Go to the documentation of this file.
00001 /** @file GATSelf.c
00002  * Main File for the GATSelf class.
00003  * 
00004  * The GATSelf class corresponds to the current GAT job.  There is
00005  * only ever one instance of this class, which is
00006  * obtained by the GetInstance method.  This object can be used to
00007  * change various properties of this job, such as whether it is
00008  * checkpointable or not, and what metrics or events it can report.  It
00009  * can also provide the  GATJob instance associated with this
00010  * job, which may then be advertised.
00011  * 
00012  * @date Tue Sep 2 2003
00013  * 
00014  * @version $Header: /export/cvs-gridlab/wp-1/Codes/GATEngine/C-reference/src/GATSelf.c,v 1.56 2004/05/12 18:56:01 hartmutkaiser Exp $
00015  *
00016  *  Copyright (C) Tom Goodale
00017  *  This file is part of the GAT Engine.
00018  *  Contributed by Tom Goodale <goodale@aei.mpg.de>.
00019  *
00020  *  Use, modification and distribution is subject to the Gridlab Software
00021  *  License. (See accompanying file GLlicense.txt or copy at
00022  *  http://www.gridlab.org/GLlicense.txt)
00023  */
00024 
00025 static const char *rcsid = "$Header: /export/cvs-gridlab/wp-1/Codes/GATEngine/C-reference/src/GATSelf.c,v 1.56 2004/05/12 18:56:01 hartmutkaiser Exp $";
00026 
00027 /* System Header Files */
00028 
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 
00033 #include <sys/types.h>
00034 #include <dirent.h>
00035 
00036 #include <sys/stat.h>
00037 #include <unistd.h>
00038 
00039 #include <ctype.h>
00040 #include <errno.h>
00041 
00042 #include <limits.h>
00043 
00044 /* include headers of dependand libraries */
00045 #include "uuid.h"
00046 #include "sqlite.h"
00047 #include "regex.h"
00048 
00049 /* GAT Header Files */
00050 #include "GATInternal.h"
00051 #include "GATErrors.h"
00052 #include "GATSelf.h"
00053 
00054 #include "GATJob.h"
00055 #include "GATRequest.h"
00056 #include "GATContext.h"
00057 #include "GATTable.h"
00058 
00059 #include "GATRegistry.h"
00060 #include "GATLoader.h"
00061 #include "GATConfig.h"
00062 #include "GATInterfaceMap.h"
00063 
00064 /* defines */
00065 #if !defined(MAX_PATH)
00066 #define MAX_PATH _POSIX_PATH_MAX
00067 #endif
00068 
00069 /* define the vtable types */
00070 GATOBJECT_DEFINE_VTABLE(GATSelf);
00071 
00072 /*
00073  *  The GATErrorMessageHandlerData structure holds the data associated with a
00074  *  registered error message handler.
00075  */
00076 typedef struct GATErrorMessageHandlerData
00077 {
00078   GATuint32 facility;
00079   GATuint32 cookie;
00080   GATErrorMessageHandler handler;
00081 } GATErrorMessageHandlerData;
00082 
00083 GATLIST_DEFINE_QUALIFIED(static, GATErrorMessageHandlerData, 
00084   GATList_GATErrorMessageHandlerData, GATType_PlainOldData)
00085 
00086 /* Declare the converters to/from GATObject */
00087 GATOBJECT_DEFINE_CONVERTERS(GATSelf);
00088 GATOBJECT_DEFINE_CONVERTERS_QUALIFIED(static, GATList_GATErrorMessageHandlerData,
00089   GATType_GATList);
00090 
00091 /* Macros */
00092 
00093 #ifndef PATH_MAX
00094   #define PATH_MAX 4096
00095 #endif /* ! PATH_MAX */
00096 
00097 /* Structures, unions and enums */
00098 
00099 /*
00100  *  The structure stored for a GATRequest inside the corresponding list
00101  */
00102 typedef struct GATRequestListenerData {
00103   GATRequest request; /* the registered GATRequest */
00104   GATuint32 cookie;   /* cookie identifying the registered GATRequestListener */
00105 } GATRequestListenerData;
00106 
00107 /*  Define the type specific interface functions for the GATRequestListenerData 
00108     list */
00109 GATLIST_DEFINE_QUALIFIED(static, GATRequestListenerData, 
00110   GATList_GATRequestListenerData, GATType_PlainOldData);
00111 
00112 /* Declare the converters to/from GATObject */
00113 GATOBJECT_DEFINE_CONVERTERS_QUALIFIED(static, GATList_GATRequestListenerData,
00114   GATType_GATList);
00115 
00116 struct contextlist
00117 {
00118   struct contextlist *prev;
00119   struct contextlist *next;
00120 
00121   GATContext context;
00122 };
00123 
00124 struct GATSelf_S
00125 {
00126   /* supported interfaces */
00127   GATSelf_vtable *GATObject__vtable;
00128 
00129   /* GATSelf instance data */
00130   GATConfig config;
00131   GATLoader loader;
00132   GATRegistry registry;
00133   struct contextlist *contexts;
00134 
00135   GATJobID gatjobid;      /* the GAT job id of this job */
00136   GATList_GATRequestListenerData listeners;
00137   
00138   /* GATSelf CPI specific data */
00139   GATSelfCPI_Instance data; /* instance data of the corresponding CPI object */
00140   GATSelfCPI cpi;         /* CPI object to use for all subsequent operations */
00141   GATSelfCPIList cpilist; /* CPI list of appropriate CPI objects */
00142 };
00143 
00144 struct load_data
00145 {
00146   GATConfig config;
00147   GATLoader loader;
00148   GATRegistry registry;
00149 };
00150 
00151 /* Static function prototypes */
00152 
00153 static GATSelf 
00154   GATSelf_Create(GATContext error_context);
00155 static void 
00156   GATSelf_Destroy(GATSelf *this);
00157 
00158 static GATResult 
00159   LoadAdaptors(GATContext error_context, GATLoader loader, GATRegistry registry, 
00160     GATConfig config);
00161 
00162 static GATResult 
00163   Load(GATContext error_context, const char *filename, void *data);
00164 
00165 static GATResult
00166   ProcessDir(GATContext error_context, const char *dirname, 
00167     int (*action)(GATContext, const char *, void *), void *data);
00168 
00169 static GATResult 
00170   ProcessFile(GATContext error_context, const char *filename, 
00171     int (*action)(GATContext, const char *, void *), void *data);
00172 
00173 static const char *
00174   MakePath(const char *base, const char *original, char sep, char *pathentry,
00175     int pathentry_length);
00176 
00177 static char *
00178   CanonicaliseName(const char *original);
00179 
00180 /* local GATObject interface functions */
00181 static GATResult
00182   GATSelf_GetCPIInstanceData(GATSelf object, void **data);
00183 
00184 static GATResult 
00185   GATSelf_Equals(GATSelf_const lhs, GATSelf_const rhs, GATBool *isequal);
00186 
00187 static GATResult 
00188   GATSelf_Clone(GATSelf_const object, GATSelf *new_object);
00189 
00190 static GATType
00191   GATSelf_GetType(GATSelf_const object);
00192 
00193 static GATResult  
00194   GATSelf_GetInterface(GATSelf_const object, GATInterface iftype, 
00195     void const **ifp);
00196 
00197 /* Error message handler functions */
00198 static GATResult  
00199   GATStatus_ErrorMessagesEngine(GATResult err_code, char *buffer, 
00200     GATuint32 length, GATuint32 *written);
00201 static GATResult  
00202   GATStatus_ErrorMessagesXds(GATResult err_code, char *buffer, 
00203     GATuint32 length, GATuint32 *written);
00204 static GATResult  
00205   GATStatus_ErrorMessagesUuid(GATResult err_code, char *buffer, 
00206     GATuint32 length, GATuint32 *written);  
00207 static GATResult  
00208   GATStatus_ErrorMessagesRegex(GATResult err_code, char *buffer, 
00209     GATuint32 length, GATuint32 *written);  
00210 static GATResult  
00211   GATStatus_ErrorMessagesSQLite(GATResult err_code, char *buffer, 
00212     GATuint32 length, GATuint32 *written);  
00213 static GATResult  
00214   GATStatus_ErrorMessagesPosix(GATResult err_code, char *buffer, 
00215     GATuint32 length, GATuint32 *written);  
00216   
00217 /* File scope variables */
00218 GATSelf_vtable GATSelf__vtable = {
00219   GATSelf_GetType,
00220   GATSelf_Destroy,
00221   GATSelf_Equals,
00222   GATSelf_Clone,
00223   GATSelf_GetInterface,
00224   GATSelf_GetCPIInstanceData
00225 };
00226 
00227 /* GATSelf is a singleton variable */
00228 static GATSelf thegatself = NULL;
00229 
00230 /* the cookies are static and separate from the GATSelf to allow error 
00231    reporting, even if the GATSelf creation fails */
00232 static GATuint32 cookie_engine = 0;
00233 static GATuint32 cookie_xds = 0;
00234 static GATuint32 cookie_uuid = 0;
00235 static GATuint32 cookie_regex = 0;
00236 static GATuint32 cookie_sqlite = 0;
00237 static GATuint32 cookie_posix = 0;
00238 
00239 /* 
00240  *  Holds the next available cookie used for identifying the registered 
00241  *  requests.
00242  */
00243 static GATuint32 request_cookie_jar = 0;
00244 
00245 /* static data for managing registered error message handlers */
00246 static GATList_GATErrorMessageHandlerData error_message_handlers = NULL;
00247 static GATuint32 error_cookie_jar = 0;
00248 
00249 
00250 /* External functions */
00251 
00252 /** GATSelf_GetInstance
00253  *  Gets the GATSelf object.
00254  *  This is the method used by any application code to get the GATSelf
00255  *  object.
00256  *  
00257  * @param context A GATContext which is used to find the GATSelf object.
00258  *
00259  * @return The GATSelf object
00260  */
00261 GATSelf_const GATSelf_GetInstance(GATContext context)
00262 {
00263   GATSelf_const ret_val;
00264 
00265   if(context)
00266   {
00267     ret_val = GATContext_internal_GetSelf(context);
00268   }
00269   else
00270   {
00271     ret_val = NULL;
00272   }
00273   return ret_val;
00274 }
00275 
00276 /** GATSelf_Equals
00277  *  @brief Compare two GATSelf objects
00278  *
00279  *  The function @c GATSelf_Equals compares two objects of the
00280  *  @c GATSelf type.
00281  *
00282  *  @param lhs The first list to compare
00283  *  @param rhs The second list to compare
00284  *  @param isequal The pointer to the GATBool variable, which should receive 
00285  *        the result if the comparision
00286  *
00287  *  @return An error code.
00288  */
00289 GATResult 
00290 GATSelf_Equals(GATSelf_const lhs, GATSelf_const rhs, GATBool *isequal)
00291 {
00292   GAT_UNUSED_PARAMETER(lhs);
00293   GAT_UNUSED_PARAMETER(rhs);
00294   GAT_UNUSED_PARAMETER(isequal);
00295   return GAT_NOTIMPL;   /* shouldn't ever get called */
00296 }
00297 
00298 /** GATSelf_Clone
00299  *  @brief Clone the given GATSelf
00300  *
00301  *  The function @c GATSelf_Clone generates a (deep) copy of 
00302  *  the given GATSelf. 
00303  *
00304  *  @param description The object to clone
00305  *  @param new_object The pointer, through which the result is to be 
00306  *        returned.
00307  *
00308  *  @return An error type.
00309  */
00310 GATResult 
00311 GATSelf_Clone(GATSelf_const handle, GATSelf *new_handle)
00312 {
00313   GAT_UNUSED_PARAMETER(handle);
00314   GAT_UNUSED_PARAMETER(new_handle);
00315   return GAT_NOTIMPL;   /* shouldn't ever get called */
00316 }
00317 
00318 /** GATType GATSelf_GetType(GATSelf_const resource)
00319  *  @brief Return the type of the GATSelf
00320  *
00321  *  The function @c GATSelf_GetType always returns 
00322  *  @c #GATType_GATSelf. 
00323  *
00324  *  @param object The object to inspect
00325  *
00326  *  @return Returns always @c #GATType_GATSelf. 
00327  */
00328 GATType
00329 GATSelf_GetType(GATSelf_const object)
00330 {
00331   GAT_UNUSED_PARAMETER(object);
00332   return GATType_GATSelf;
00333 }
00334 
00335 /** GATResult GATSelf_GetInterface(GATSelf_const file, GATInterface iftype, void const **ifp)
00336  *  @brief Get an interface supported by a GATObject
00337  *
00338  *  The function GATSelf_GetInterface allows to get a pointer to an 
00339  *  additional interface supported by this GATSelf.
00340  *
00341  *  @param object The object to be asked for the new interface.
00342  *  @param iftype The interface the object is to be asked for.
00343  *  @param ifp The pointer, through which the result is to be returned.
00344  *
00345  *  @return An error type.
00346  */
00347 GATResult 
00348 GATSelf_GetInterface(GATSelf_const object, GATInterface iftype, void const **ifp)
00349 {
00350   GATResult retval = GAT_INVALID_PARAMETER;
00351 
00352   GAT_UNUSED_PARAMETER(object);
00353   GAT_UNUSED_PARAMETER(iftype);
00354   if (NULL != ifp)
00355   {
00356     *ifp = NULL;
00357     retval = GAT_NO_INTERFACE;
00358   }
00359   return retval;
00360 }
00361 
00362 /** GATSelf_AddRequestListener
00363  *  Adds a GATRequestListener to the GATSelf.
00364  *  Registers a new callback function and a new type of
00365  *  request which the GATEngine should react to when queried from
00366  *  the outside world.
00367  *  Request names should be unique.
00368  *  
00369  *  @param self The GATSelf object
00370  *  @param listener The callback function
00371  *  @param data Data object for the callback function
00372  *  @param type The type of the new request
00373  *  @param name The name of the new request
00374  *
00375  * @return An error code
00376  */
00377 GATResult 
00378 GATSelf_AddRequestListener(GATContext context, 
00379   GATRequestListener listener, void *data, GATRequestType type, 
00380   GATTable_const parameters, const char *name, GATuint32 *cookie)
00381 {
00382   GAT_STATUS_APIENTRY(context, "GATSelf_AddRequestListener");
00383   GATSelf self = GATContext_internal_GetSelf(context);
00384   if (NULL != self)
00385   {
00386     GATRequest request = NULL;
00387     
00388     GAT_CREATE_STATUS(GATSelfCPI_CreateRequestForListener(self->cpi, 
00389       &self->data, context, listener, data, type, parameters, name, &request));
00390           
00391     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00392     {
00393       /* insert the listener data into the appropriate list */
00394       GATRequestListenerData localdata;
00395       GATList_GATRequestListenerData_Iterator it = 
00396         GATList_GATRequestListenerData_Begin(self->listeners);
00397       
00398       /* verify, that this listener isn't already registered */
00399       GATList_GATRequestListenerData_Iterator end = 
00400         GATList_GATRequestListenerData_End(self->listeners);
00401         
00402       for (/**/; it != end; it = GATList_GATRequestListenerData_Next(it))
00403       {
00404         GATBool isequal = GATFalse;
00405         GATRequestListenerData *value = GATList_GATRequestListenerData_Get(it);
00406         if (NULL == value)
00407         {
00408           GAT_CREATE_STATUS(GAT_FAIL);
00409           break;
00410         }
00411         
00412         GAT_CREATE_STATUS(GATRequest_Equals(request, value->request, 
00413           &isequal));
00414         if (GAT_FAILED(GAT_CURRENT_STATUS()) || GATFalse == isequal)
00415         {
00416           GAT_CREATE_STATUS(GAT_KEY_ALREADY_EXISTS);
00417           break;
00418         }
00419       }
00420         
00421       if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00422       {
00423         if (NULL != cookie)
00424         {
00425           GATuint32 mycookie = ++request_cookie_jar;
00426           
00427           localdata.request = request;
00428           localdata.cookie = mycookie;
00429           
00430           it = GATList_GATRequestListenerData_Insert(self->listeners, end, 
00431             localdata);
00432           if (NULL == it)
00433           {
00434             GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00435           } 
00436           else
00437           {
00438             *cookie = mycookie;
00439           }
00440         }
00441         else
00442         {
00443           GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00444         }
00445       }
00446     }
00447   } 
00448   else
00449   {
00450     GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00451   }
00452   return GAT_RETURN_STATUS();
00453 }
00454 
00455 
00456 /** GATSelf_RemoveRequestListener
00457  *  Removes a GATRequestListener from the GATSelf.
00458  *  Unregisters a request callback function.
00459  *  
00460  *  @param this The GATSelf object
00461  *  @param name The name of the old request
00462  *
00463  *  @return An error code
00464  */
00465 GATResult 
00466 GATSelf_RemoveRequestListener(GATContext context, GATuint32 cookie)
00467 {
00468   GAT_STATUS_APIENTRY(context, "GATSelf_RemoveRequestListener");
00469   GATSelf self = GATContext_internal_GetSelf(context);
00470   if (NULL != self)
00471   {
00472     GATList_GATRequestListenerData_Iterator it = 
00473       GATList_GATRequestListenerData_Begin(self->listeners);
00474     GATList_GATRequestListenerData_Iterator end = 
00475       GATList_GATRequestListenerData_End(self->listeners);
00476     GATBool found = GATFalse;
00477     
00478     for (/**/; it != end; it = GATList_GATRequestListenerData_Next(it))
00479     {
00480       GATRequestListenerData *value = GATList_GATRequestListenerData_Get(it);
00481       if (NULL == value)
00482       {
00483         GAT_CREATE_STATUS(GAT_FAIL);
00484         break;
00485       }
00486       
00487       if (value->cookie == cookie)
00488       {
00489         GAT_CREATE_STATUS(GATSelfCPI_DestroyRequestForListener(self->cpi, 
00490           &self->data, context, &value->request));
00491         found = GATTrue;
00492         break;
00493       }
00494     }
00495     
00496     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00497     {
00498       GATList_GATRequestListenerData_Erase(self->listeners, it);
00499       if (GATFalse == found)
00500       {
00501         GAT_CREATE_STATUS(GAT_KEY_NOT_FOUND);
00502       }
00503     }
00504   }
00505   else
00506   {
00507     GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00508   }
00509   return GAT_RETURN_STATUS();
00510 }
00511 
00512 /** GATSelf_GetJob
00513  *  Gets the GATJob associated with this job.
00514  *  Each GAT job has an associated GATJob object
00515  *  which can be advertised to allow other GAT applications
00516  *  to manipulate it.
00517  *  
00518  *  @param self The GATSelf object
00519  *  @param job The pointer to the variable, which receives the created job 
00520  *        object.
00521  *
00522  *  @return The associated GATJob.
00523  */
00524 GATResult
00525 GATSelf_GetJob(GATContext context, GATJob *job)
00526 {
00527   GAT_STATUS_APIENTRY(context, "GATSelf_GetJob");
00528   GATSelf self = GATContext_internal_GetSelf(context);
00529   if (NULL != self)
00530   {
00531     if (NULL != self->cpi)
00532     {
00533       GAT_CREATE_STATUS(GATSelfCPI_GetJob(self->cpi, &self->data, context, job));
00534       GAT_CREATE_STATUS(GATJob_internal_SetGATJobId(*job, self->gatjobid));
00535     }
00536     else
00537     {
00538       /* there was no adaptor found, which knows our RMS */
00539       GAT_CREATE_STATUS(GAT_NO_REGISTERED_CPI);
00540     }
00541   }
00542   else
00543   {
00544     GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
00545   }
00546   return GAT_RETURN_STATUS();
00547 }
00548 
00549 
00550 /** GATSelf_internal_GetInstance
00551  *  Private GATEngine method to get the GATSelf object.
00552  *  This is the method used by the constructor of a GATContext to get the 
00553  *  GATSelf object.  This creates the GATSelf if it has not already been
00554  *  created.
00555  *  
00556  *  @param error_context This is the created context, which potentially 
00557  *        triggers the creation of the GATSelf. This context may be used for
00558  *        storing/retrieving the current status only.
00559  *        
00560  *  @return The GATSelf object
00561  */
00562 GATSelf 
00563 GATSelf_internal_GetInstance(GATContext error_context)
00564 {
00565   if (!thegatself)
00566   {
00567     thegatself = GATSelf_Create(error_context);
00568   }
00569   return thegatself;
00570 }
00571 
00572 /** GATSelf_internal_GetRegistry
00573  *  Gets the GATRegsitry object.
00574  *  This is the method used by a new GATContext to get the registry
00575  *  object from the GATSelf
00576  *  
00577  * @param this The GATSelf which is used to find the GATRegistry object.
00578  *
00579  * @return A GATRegistry object
00580  */
00581 GATRegistry 
00582 GATSelf_internal_GetRegistry(GATSelf self)
00583 {
00584   if (NULL != self)
00585   {
00586     return self->registry;
00587   }
00588   return NULL;
00589 }
00590 
00591 /** GATSelf_internal_AddContext
00592  *  Private method to add a new GATContext to the GATSelf object.
00593  *  This is the method used by the constructor of a GATContext to add itself 
00594  *  to the list of GATContexts maintained by the GATSelf.
00595  *  
00596  * @param this The GATSelf object
00597  * @param context A new GATContext
00598  *
00599  */
00600 GATResult 
00601 GATSelf_internal_AddContext(GATSelf self, GATContext context)
00602 {
00603   if (NULL != self)
00604   {
00605     GAT_USES_STATUS(context, "GATSelf_internal_AddContext");
00606     
00607     struct contextlist *new_context = 
00608       (struct contextlist *)malloc(sizeof(struct contextlist));
00609 
00610     if (NULL != new_context)
00611     {
00612       new_context->prev = NULL;
00613       new_context->next = NULL;
00614       new_context->context = context;
00615 
00616       /* Now add it to list */
00617       if (NULL != self->contexts)
00618       {
00619         /* Find the end of the list */
00620         struct contextlist *current = self->contexts;
00621         for(/**/; NULL != current->next; current = current->next)
00622         {
00623           /* Do nothing */
00624         }
00625 
00626         current->next = new_context;
00627         new_context->prev = current;
00628       }
00629       else
00630       {
00631         /* New list */
00632         self->contexts = new_context;
00633       }
00634     }   
00635     else
00636     {
00637       GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
00638     }
00639     
00640     return GAT_RETURN_STATUS();
00641   }
00642   return GAT_INVALID_HANDLE;
00643 }
00644 
00645 /** GATSelf_internal_RemoveContext
00646  *  Private method to remove a GATContext from the GATSelf object.
00647  *  This is the method used by the destructor of a GATContext to remove itself
00648  *  from the list of GATContexts maintained by the GATSelf.  If this was the last
00649  *  GATContext on the list, the GATSelf is destroyed.
00650  *  
00651  * @param this The GATSelf object
00652  * @param context An old GATContext
00653  *
00654  */
00655 void 
00656 GATSelf_internal_RemoveContext(GATSelf self, GATContext context)
00657 {
00658   if (NULL != self)
00659   {
00660     if (NULL != self->contexts)
00661     {
00662       /* Find the context on the list */
00663       struct contextlist *current = self->contexts;
00664 
00665       for (/**/; current->context != context; current = current->next)
00666       {
00667         /* Do nothing */
00668       }
00669       
00670       if (NULL != current)
00671       {
00672         if (NULL != current->next)
00673         {
00674           current->next->prev = current->prev;
00675         }
00676         if (NULL != current->prev)
00677         {
00678           current->prev->next = current->next;
00679         }
00680 
00681         if (current == self->contexts)
00682         {
00683           /* we have to remove the first element in the context list */
00684           self->contexts = current->next;
00685         }      
00686         free(current);
00687 
00688         if(NULL == self->contexts)
00689         {
00690           /* this was the last context on this list */
00691           GATSelf_Destroy(&self);
00692         }
00693       }
00694       else
00695       {
00696         /* Error ! */
00697       }
00698     }
00699     else
00700     {
00701       /* Error ! */
00702     }
00703   }
00704 }
00705 
00706 /* Local functions */
00707 
00708 /** GATSelf_Create
00709  *  The  GATSelf constructor.
00710  *  This is the constuctor for the GATSelf.
00711  *  It should initialise the GATEngine, e.g. load adaptors or
00712  *  at least find them, load configuration files, etc.
00713  *
00714  *  @param error_context This is the created context, which potentially 
00715  *        triggers the creation of the GATSelf. This context may be used for
00716  *        storing/retrieving the current status only.
00717  *
00718  *  @return A new GATSelf
00719  */
00720 static GATSelf 
00721 GATSelf_Create(GATContext error_context)
00722 {
00723   GAT_USES_STATUS(error_context, "GATSelf_Create");
00724   
00725   /* create the new GATSelf object */
00726   GATSelf new_self = (GATSelf)malloc(sizeof(struct GATSelf_S));
00727   if (NULL != new_self)
00728   {
00729     // initialise all the members
00730     memset(new_self, 0, sizeof(struct GATSelf_S));
00731     new_self->GATObject__vtable = &GATSelf__vtable;
00732     new_self->contexts = NULL;
00733     new_self->config = GATConfig_Create(error_context);
00734     GAT_CREATE_STATUS_IF(NULL == new_self->config, GAT_MEMORYFAILURE);
00735     
00736     new_self->registry = GATRegistry_Create();
00737     GAT_CREATE_STATUS_IF(NULL == new_self->registry, GAT_MEMORYFAILURE);
00738     
00739     new_self->loader = GATLoader_Create();
00740     GAT_CREATE_STATUS_IF(NULL == new_self->loader, GAT_MEMORYFAILURE);
00741 
00742     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00743     {
00744       char *jobid_env = getenv("GAT_JOBID");
00745       if (NULL != jobid_env)
00746       {
00747         /* GAT_JOBID environment exists,  use whatever is given there */
00748         new_self->gatjobid = GATString_Create(jobid_env, strlen(jobid_env)+1, 
00749           "ASCII");
00750         GAT_CREATE_STATUS_IF(NULL == new_self->gatjobid, GAT_MEMORYFAILURE);
00751       }
00752       else
00753       {
00754         GAT_CREATE_STATUS(GATSelf_internal_CreateGATJobId(new_self, 
00755           error_context, &new_self->gatjobid));
00756         if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00757         {
00758           /* set the GAT job id, if it isn't set already */
00759           setenv("GAT_JOBID", GATString_GetBuffer(new_self->gatjobid), 1);
00760         }
00761       }
00762     }
00763     
00764     new_self->listeners = GATList_GATRequestListenerData_Create();
00765     GAT_CREATE_STATUS_IF(NULL == new_self->listeners, GAT_MEMORYFAILURE);
00766     
00767     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00768     {
00769       GAT_CREATE_STATUS(LoadAdaptors(error_context, new_self->loader, 
00770         new_self->registry, new_self->config));
00771       GAT_CREATE_STATUS(GATObject_Register_GATSerialisables());
00772       
00773       /* find CPI provider, which knows how to manage this job */
00774       if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00775       {
00776         GATRegistry registry = GATSelf_internal_GetRegistry(new_self);
00777         new_self->cpilist = GATRegistry_FindGATSelfCPI(registry, 0);
00778         if (NULL != new_self->cpilist)
00779         {
00780           GATBool found_cpi = GATFalse;
00781           GATSelfCPIList current = NULL;
00782           for(current = new_self->cpilist; NULL != current; current = current->next)
00783           {
00784             GAT_CREATE_STATUS(GATSelfCPI_CreateInstance(current->cpi, 
00785               &new_self->data));
00786             if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
00787             {
00788               new_self->cpi = current->cpi;
00789               found_cpi = GATTrue;
00790               break;
00791             }
00792           }
00793 
00794           /* register this object with the engine */
00795           if (GATTrue == found_cpi)
00796           {
00797             GAT_CREATE_STATUS(GATRegistry_internal_AddGATSelfToCPIList(registry, 
00798               new_self->cpi, new_self));
00799           }
00800         }
00801         /* the load process shouldn't fail, if no GATSelfCPI is found */
00802       }
00803     }
00804   }
00805 
00806   /* error handling */
00807   if (GAT_FAILED(GAT_CURRENT_STATUS()))
00808   {
00809     GATSelf_Destroy(&new_self);
00810   }
00811 
00812   GAT_STORE_STATUS();
00813   
00814   /* register error message handlers */
00815   if (0 == cookie_engine)
00816   {
00817     GAT_CREATE_STATUS_UNCOND(GATSelf_AddErrorMessageHandler(GAT_FACILITY_ENGINE, 
00818       GATStatus_ErrorMessagesEngine, &cookie_engine));
00819   }
00820   if (0 == cookie_xds)
00821   {
00822     GAT_CREATE_STATUS_UNCOND(GATSelf_AddErrorMessageHandler(GAT_FACILITY_ENGINE_XDS, 
00823       GATStatus_ErrorMessagesXds, &cookie_xds));
00824   }
00825   if (0 == cookie_uuid)
00826   {
00827     GAT_CREATE_STATUS_UNCOND(GATSelf_AddErrorMessageHandler(GAT_FACILITY_ENGINE_UUID, 
00828       GATStatus_ErrorMessagesUuid, &cookie_uuid));
00829   }
00830   if (0 == cookie_regex)
00831   {
00832     GAT_CREATE_STATUS_UNCOND(GATSelf_AddErrorMessageHandler(GAT_FACILITY_ENGINE_REGEX, 
00833       GATStatus_ErrorMessagesRegex, &cookie_regex));
00834   }
00835   if (0 == cookie_sqlite)
00836   {
00837     GAT_CREATE_STATUS_UNCOND(GATSelf_AddErrorMessageHandler(GAT_FACILITY_SQLITE, 
00838       GATStatus_ErrorMessagesSQLite, &cookie_sqlite));
00839   }
00840   if (0 == cookie_posix)
00841   {
00842     GAT_CREATE_STATUS_UNCOND(GATSelf_AddErrorMessageHandler(GAT_FACILITY_POSIX, 
00843       GATStatus_ErrorMessagesPosix, &cookie_posix));
00844   }
00845     
00846   return new_self;
00847 }
00848 
00849 /** GATSelf_Destroy
00850  *  The GATSelf destructor.
00851  *  This is the destructor for the GATSelf.  It should shut-down
00852  *  the GATEngine, e.g. unload adaptors, etc.
00853  *
00854  * @param this An old GATContext
00855  */
00856 static void 
00857 GATSelf_Destroy(GATSelf *object)
00858 {
00859   if (NULL != object && NULL != *object)
00860   {
00861     GATSelf_RemoveErrorMessageHandler(&cookie_engine);
00862     GATSelf_RemoveErrorMessageHandler(&cookie_xds);
00863     GATSelf_RemoveErrorMessageHandler(&cookie_uuid);
00864     GATSelf_RemoveErrorMessageHandler(&cookie_regex);
00865     GATSelf_RemoveErrorMessageHandler(&cookie_sqlite);
00866     GATSelf_RemoveErrorMessageHandler(&cookie_posix);
00867     
00868     GATList_GATRequestListenerData_Destroy(&(*object)->listeners);
00869 
00870     if (NULL != (*object)->cpi)
00871     {
00872       GATRegistry registry = GATSelf_internal_GetRegistry(*object);
00873       GATRegistry_internal_RemoveGATSelfFromCPIList(registry, (*object)->cpi, 
00874         *object);
00875     }
00876 
00877     GATObject_Unregister_GATSerialisables();
00878     
00879     GATString_Destroy(&(*object)->gatjobid);
00880     GATSelfCPIList_Destroy((*object)->cpilist);
00881     GATConfig_Destroy(&(*object)->config);
00882     GATRegistry_Destroy(&(*object)->registry);
00883     GATLoader_Destroy(&(*object)->loader);
00884     
00885     free(*object);
00886     *object = NULL;
00887   }
00888 }
00889 
00890 /** LoadAdaptors
00891  *  Load all adaptors on adaptor path.
00892  *  This function examines the GAT_ADAPTOR_PATH environment
00893  *  variable and loads all the adaptors it finds.
00894  *  The environment variable is a colon seperated list of files
00895  *  or directories.
00896  *
00897  * @param loader The GATLoader object which loads and track individual adaptors.
00898  * @param registry The CPI registry
00899  * @param config The GAT configuration database.
00900  *
00901  * @return An error code - 0 for success, -1 for failure.
00902  */
00903 static GATResult 
00904 LoadAdaptors(GATContext error_context, GATLoader loader, GATRegistry registry, 
00905   GATConfig config)
00906 {
00907   GAT_USES_STATUS(error_context, "LoadAdaptors");
00908   
00909   struct load_data ldata;
00910   struct stat buf;
00911   const char *env_var = NULL;
00912 
00913   ldata.config = config;
00914   ldata.loader = loader;
00915   ldata.registry = registry;
00916   
00917   env_var = getenv("GAT_ADAPTOR_PATH");
00918   if (NULL != env_var)
00919   {
00920     /* Copy into a local variable as 
00921      * another thread may also call getenv.
00922      */
00923     char *adaptor_path = (char *)malloc(strlen(env_var)+1);
00924     if (NULL != adaptor_path)
00925     {
00926       char base[PATH_MAX+1];
00927       const char *position = NULL;
00928       strcpy(adaptor_path, env_var);
00929 
00930       /* Get the current working directory, to
00931        * allow relative paths on the GAT_ADAPTOR_PATH
00932        */
00933       getcwd(base, PATH_MAX);
00934 
00935       /* Now split the environment variable into
00936        * individual paths, which may be either files
00937        * or directories, and load the indicated adaptors.
00938        */
00939       position = adaptor_path;
00940       do
00941       {
00942         char path[PATH_MAX+1];
00943         
00944         position = MakePath(base, position, ':', path, PATH_MAX+1);
00945         if(path[0] == '/')
00946         {
00947           if (!stat(path, &buf))
00948           {
00949             if (S_ISDIR(buf.st_mode))
00950             {
00951               GAT_CREATE_STATUS(ProcessDir(error_context, path, Load, 
00952                 (void *)&ldata));
00953             }
00954             else if (S_ISREG(buf.st_mode))
00955             {
00956               GAT_CREATE_STATUS(ProcessFile(error_context, path, Load, 
00957                 (void *)&ldata));
00958             }
00959             else
00960             {
00961               /* Not a directory or regular file. Not a critical error. */
00962               char buffer[PATH_MAX+100];
00963               
00964               sprintf(buffer, "Entry '%s' on GAT_ADAPTOR_PATH is not a file "
00965                               "or a directory", path);
00966               GAT_CREATE_STATUS_MSG(GAT_FALSE, buffer);
00967             }
00968           }
00969           else
00970           {
00971             char buffer[PATH_MAX+100];
00972             
00973             /* Couldn't stat the file - probably doesn't exist */
00974             if(errno == ENOENT)
00975             {
00976               sprintf(buffer, "Entry '%s' on GAT_ADAPTOR_PATH doesn't exist",
00977                 path);
00978             }
00979             else if(errno == EACCES)
00980             {
00981               sprintf(buffer, "Entry '%s' on GAT_ADAPTOR_PATH doesn't exist",
00982                 path);
00983             }
00984             else
00985             {
00986               sprintf(buffer, "Could not get status of entry '%s' on "
00987                               "GAT_ADAPTOR_PATH", path);
00988             }
00989             GAT_CREATE_STATUS_MSG(POSIX_TO_GAT(errno), buffer);
00990           }
00991         }
00992         else
00993         {
00994           /* Something went wrong when processing the path element.
00995            * e.g. "/.." is erroneous.
00996            */
00997           char buffer[PATH_MAX+100];
00998           
00999           sprintf(buffer, "Erroneous GAT_ADAPTOR_PATH '%s'", adaptor_path);
01000           GAT_CREATE_STATUS_MSG(GAT_FAIL, buffer);
01001         }
01002       } while(NULL != position);
01003 
01004       free(adaptor_path);
01005     }
01006     else
01007     {
01008       GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
01009     }
01010   }
01011   else
01012   {
01013     /* No GAT_ADAPTOR_PATH environment variable.
01014      * Could use a system defined one coming from
01015      * configure, or the configuration database.
01016      */
01017     GAT_CREATE_STATUS_MSG(GAT_FAIL, 
01018       "GAT_ADAPTOR_PATH not set, no adaptors loaded");
01019   }
01020   
01021   return GAT_RETURN_STATUS();
01022 }
01023 
01024 /** Load
01025  *  Loads an single adaptor, as many times as configured.
01026  *  A callback function invoked by the functions which scan
01027  *  directories or files for adaptors.  It takes a full path
01028  *  to an adaptor and then invokes the GATLoader with this
01029  *  adaptor and any associated config database tables.
01030  *
01031  * @param filename The full path to the adaptor.
01032  * @param registry The CPI registry
01033  * @param config The GAT configuration database.
01034  *
01035  * @return The number of adaptors loaded.
01036  */
01037 static GATResult
01038 Load (GATContext error_context, const char *filename, void *data)
01039 {
01040   GAT_USES_STATUS(error_context, "Load");
01041 
01042   struct load_data *ldata = (struct load_data *)data;
01043 
01044   /* Extract the adaptor name from the full path 
01045    * Need to do this here to use it as the key to
01046    * getting the config table(s) for this adaptor.
01047    */
01048   char *adaptorname = CanonicaliseName(filename);
01049 
01050   if (NULL != adaptorname)
01051   {
01052     /* Get any configuration tables associated with the adaptor. */
01053     GATTable_const system_config = GATConfig_GetSystemConfig(ldata->config);
01054     GATConfigTableList_const instance_configs = GATConfig_GetAdaptorConfigs(
01055       ldata->config, adaptorname);  
01056 
01057     if (NULL != instance_configs)
01058     {
01059       /* We have at least one set of configuration options for this adaptor. */
01060       GATConfigTableList_const current = NULL;
01061       for (current = instance_configs; NULL != current; current = current->next)
01062       {
01063         GAT_CREATE_STATUS_UNCOND(GATLoader_LoadAdaptor(ldata->loader, 
01064           error_context, ldata->registry, system_config, current->config, 
01065           filename, adaptorname, current->nickname));
01066       }
01067     }
01068     else
01069     {    
01070       /* No configuration options. */
01071       GATTable instance_config = GATTable_Create();
01072       
01073       if (NULL != instance_config)
01074       {
01075         /* Create a table to allow this adaptor to be configured later. */
01076         GAT_CREATE_STATUS(GATConfig_AddAdaptorConfig(ldata->config, 
01077           error_context, adaptorname, adaptorname, instance_config));
01078                                     
01079         /* Now load the adaptor */
01080         GAT_CREATE_STATUS(GATLoader_LoadAdaptor(ldata->loader, error_context,
01081           ldata->registry, system_config, instance_config, filename, 
01082           adaptorname, NULL));
01083       }
01084       else
01085       {
01086         GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
01087       }
01088     }
01089 
01090     free(adaptorname);
01091   }
01092   else
01093   {
01094     GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
01095   }
01096   return GAT_RETURN_STATUS();
01097 }
01098 
01099 /** ProcessDir
01100  *  Search a directory for files and invoke an action on each one.
01101  *  Finds all non-hidden files in a directory and invokes the designated
01102  *  function on them.
01103  *
01104  * @param dirname The full path to a directory.
01105  * @param action A callback function which does something with this file
01106  * @param data Data for the callback function.
01107  *
01108  * @return The number of files found.
01109  */
01110 static GATResult
01111 ProcessDir(GATContext error_context, const char *dirname, 
01112   int (*action)(GATContext, const char *, void *), void *data)
01113 {
01114   GAT_USES_STATUS(error_context, "ProcessDir");
01115   
01116   DIR *directory;
01117 
01118   if (NULL != (directory = opendir(dirname)))
01119   {
01120     struct dirent *entry = NULL;
01121     char const *sep = NULL;
01122     size_t dirname_length = strlen(dirname);
01123 
01124     if (dirname[dirname_length-1] == '/')
01125     {
01126       sep = "";
01127     }
01128     else
01129     {
01130       sep = "/";
01131     }
01132 
01133     while (NULL != (entry = readdir(directory)))
01134     {
01135       if(strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
01136       {
01137         char *fullpathname = (char *)malloc(dirname_length + strlen(entry->d_name)+2);
01138         if (NULL != fullpathname)
01139         {
01140           struct stat buf;
01141 
01142           sprintf(fullpathname, "%s%s%s", dirname,  sep, entry->d_name);        
01143           stat(fullpathname, &buf);
01144 
01145           if(S_ISREG(buf.st_mode) && entry->d_name[0] != '.')
01146           {
01147             GAT_CREATE_STATUS_UNCOND(action(error_context, fullpathname, data));
01148           }
01149           free(fullpathname);
01150         }
01151         else
01152         {
01153           GAT_CREATE_STATUS(GAT_MEMORYFAILURE);
01154           break;
01155         }
01156       }
01157     }
01158     
01159     closedir(directory);
01160   }
01161   return GAT_RETURN_STATUS();
01162 }
01163 
01164 /** ProcessFile
01165  *  Search a file for valid filenames and invoke an action on each one.
01166  *  Finds all non-empty, non-commented out lines in the file and
01167  *  strips leading and trailing whitespace before converting into
01168  *  a full pathname and passing to a callback function.
01169  *
01170  * @param filename The full path to a file
01171  * @param action A callback function which does something with a file
01172  * @param data Data for the callback function.
01173  *
01174  * @return The number of files found.
01175  */
01176 static GATResult
01177 ProcessFile(GATContext error_context, const char *filename, 
01178   int (*action)(GATContext, const char *, void *), void *data)
01179 {
01180   GAT_USES_STATUS(error_context, "ProcessFile");
01181   
01182   FILE *file = NULL;
01183   
01184   if(NULL != (file = fopen(filename, "r")))
01185   {
01186     char *pos = NULL;
01187 
01188     char line[PATH_MAX+1];
01189     char directory[PATH_MAX+1];
01190     char fullpathname[PATH_MAX+1];
01191 
01192     /* Get directory part of filename */
01193     strncpy(directory, filename, PATH_MAX);
01194 
01195     for(pos = directory+strlen(directory);
01196         pos > directory && *pos != '/';
01197         pos--)
01198     {
01199       /* Do nothing */
01200     }
01201     
01202     if(*pos == '/')
01203     {
01204       *(pos+1) = 0;
01205     }
01206     else
01207     {
01208       /* filename was not absolute. Internal error. */
01209       GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
01210     }
01211 
01212     if (GAT_SUCCEEDED(GAT_CURRENT_STATUS()))
01213     {
01214       while (NULL != fgets(line, PATH_MAX+1, file))
01215       {
01216           /* Allow lines to be commented out. */
01217         if(*line == '#')
01218         {
01219           continue;
01220         }
01221 
01222         /* Strip off trailing whitepace or newlines */
01223         for(pos = line + strlen(line)-1; pos >= line; pos--)
01224         {
01225           if (isspace(*pos))
01226           {
01227             *pos = 0;
01228           }
01229           else
01230           {
01231             break;
01232           }
01233         }
01234 
01235         /* Strip off preceding whitespace */
01236         for(pos = line; 0 != *pos; pos++)
01237         {
01238           if(isspace(*pos))
01239           {
01240             *pos = 0;
01241           }
01242           else
01243           {
01244             break;
01245           }
01246         }
01247 
01248         /* Now make path from a non-empty line */
01249         if (*pos)
01250         {
01251           MakePath (directory, pos, 0, fullpathname, PATH_MAX+1);
01252           if (*fullpathname == '/')
01253           {
01254             GAT_CREATE_STATUS(action(error_context, fullpathname, data));
01255           }
01256           else
01257           {
01258             /* something went wrong when processing the path. */
01259             GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
01260           }
01261         }
01262       }            
01263     }
01264     fclose(file);
01265   }
01266   else
01267   {
01268     /* Couldn't open file */
01269     char buffer[MAX_PATH+100];
01270     
01271     sprintf(buffer, "Couldn't open adaptor list file '%s'", filename);
01272     GAT_CREATE_STATUS_MSG(GAT_FILEOPEN_ERROR, buffer);
01273   }
01274 
01275   return GAT_RETURN_STATUS();
01276 }
01277 
01278 /** MakePath
01279  *  Search a delimited string and return full paths.
01280  *  Parses a string, splitting it into tokens which it
01281  *  assumes are path-names.  It returns the first path-name
01282  *  in the pathentry buffer, after converting it to an absolute path.
01283  *  The return value is a pointer to the next path in the string.
01284  *
01285  * @param base The base for pathames - used if path starts with ./
01286  * @param original The search string 
01287  * @param sep The delimiter between different pathnames
01288  * @param pathentry A buffer to put the new pathname into
01289  * @param pathentry_length the length of the pathentry buffer
01290  *
01291  * @return The number of files found.
01292  */
01293 static const char *
01294 MakePath(const char *base, const char *original, char sep, char *pathentry,
01295   int pathentry_length)
01296 {
01297   const char *place;
01298   char *current;
01299   int count;
01300 
01301   /* Is it an absolute or relative path. */
01302   if(original[0] != '/')
01303   {
01304     if(base)
01305     {
01306       strncpy(pathentry, base, pathentry_length-1);
01307     }
01308     else
01309     {
01310       getcwd(pathentry, pathentry_length-1);
01311     }
01312 
01313     current = pathentry+strlen(pathentry);
01314     *current = '/';
01315     current++;
01316   }
01317   else
01318   {
01319     current = pathentry;
01320   }
01321 
01322   /* Now parse this pathentry removing /./ and /../
01323    * parts.
01324    */
01325   for(place = original; 
01326       *place && (current - pathentry) < pathentry_length; 
01327       place++)
01328   {
01329     if(*place == sep)
01330     {
01331       break;
01332     }
01333     if(*place !='.' ||
01334        (place > original && *(place-1) != '/'))
01335     {
01336       /* Just a normal character */
01337       *current = *place;
01338       current++;
01339     }
01340     else if(*(place+1) == '/' || ! *(place+1) || *(place+1) == sep)
01341     {
01342       /* Embedded /./ - ignore */
01343       place++;
01344       if(! *place || *place == sep)
01345       {
01346         break;
01347       }
01348     }
01349     else if(*(place+1) == '.' && (*(place+2) == '/' || ! *(place+2) || *(place+2) == sep))
01350     {
01351       /* We have a /.. - so backtrack two slashes*/
01352 
01353       for(count = 0; 
01354           current > pathentry || count == 1; 
01355           current--)
01356       {
01357         if(*current == '/')
01358         {
01359           count++;
01360         }
01361         if(count ==2)
01362         {
01363           current++;
01364           break;
01365         }
01366       }
01367 
01368       if(current == pathentry)
01369       {
01370         /* This is an error */
01371         strcpy(pathentry, "Invalid path");
01372 
01373         current = pathentry+strlen(pathentry);
01374 
01375         place = strchr(place, sep);
01376 
01377         break;
01378       }
01379 
01380       place +=2;
01381 
01382       if(! *place || *place == sep)
01383       {
01384         break;
01385       }
01386     }
01387     else
01388     {
01389       /* Just a normal character */
01390       *current = *place;
01391       current++;
01392     }
01393   }
01394 
01395   if(current == pathentry)
01396   {
01397     /* Root directory */
01398     *current = '/';
01399     current++;
01400   }
01401 
01402   /* Null terminate */
01403   *current = 0;
01404 
01405   if(place && *place == sep)
01406   {
01407     place++;
01408   }
01409   else if (place && ! *place)
01410   {
01411     place = NULL;
01412   }
01413 
01414   return place;
01415 }
01416 
01417 /** CanonicaliseName
01418  *  Extract the canonical name of an adaptor from its full path name.
01419  *  We need the name of the adaptor in order to invoke its 
01420  *  registration function.  CanonicaliseName takes the path
01421  *  to an adaptor and extracts the base filename from it.
01422  *  Additionally, if it is a libtool library, it removes the "lib"
01423  *  prefix which libtool insists on having.
01424  *
01425  * @param input The path to an adaptor file.
01426  *
01427  * @return A canonoical name for the adaptor.
01428  */
01429 static char *
01430 CanonicaliseName(const char *original)
01431 {
01432   char *retval;
01433   const char *start;
01434   const char *end;
01435   char *pos;
01436 
01437   /* Find filename part of name */
01438   start = strrchr(original, '/');
01439 
01440   if(!start)
01441   {
01442     start = original;
01443   }
01444   else
01445   {
01446     start++;
01447   }
01448 
01449   /* Scan forward and end at any character not in [a-zA-Z0-9_-] */
01450 
01451   for(end = start; 
01452       *end && (isalnum(*end) || *end == '_' || *end == '-'); 
01453       end++)
01454   {
01455     /* Do nothing */
01456   }
01457 
01458   if(!strcmp(end,".la"))
01459   {
01460     /* It's a libtool library, which insists on having lib as
01461      * first three chars.
01462      */
01463     if(start[0] == 'l' && start[1] == 'i' && start[2] == 'b')
01464     {
01465       start += 3;
01466     }
01467   }
01468 
01469   /* Allocate memory */
01470   retval = (char *)malloc(end-start + 1);
01471 
01472   if(retval)
01473   {
01474     /* Copy data */
01475     for(pos = retval; start < end ; start++, pos++)
01476     {
01477       *pos = *start;
01478     }
01479 
01480     *pos = 0;
01481   }
01482 
01483   return retval;
01484 }
01485 
01486 
01487 /* internal helper functions */
01488 
01489 /*  GATSelf_internal_GetGATJobId
01490  *  
01491  *  The function GATSelf_internal_GetGATJobId retrieves the GAT related job id
01492  *  of the give job.
01493  *
01494  *  @param self The GATSelf object to query for its GAT job id.
01495  *  @param context The error context to use for error reporting.
01496  *  @param The pointer to a variable, which should receive the GAT job id 
01497  *        associated with the current job.
01498  *
01499  *  @return An error code.
01500  */
01501 GATResult
01502 GATSelf_internal_GetGATJobId(GATSelf_const self, GATContext context, 
01503   GATString_const *gatjobid)
01504 {
01505   if (NULL != self)
01506   {
01507     GAT_USES_STATUS(context, "GATSelf_internal_GetGATJobId");
01508     
01509     if (NULL != gatjobid)
01510     {
01511       *gatjobid = self->gatjobid;
01512     }
01513     else
01514     {
01515       GAT_CREATE_STATUS(GAT_INVALID_PARAMETER);
01516     }
01517     
01518     return GAT_RETURN_STATUS();
01519   }
01520   return GAT_INVALID_HANDLE;
01521 }
01522 
01523 GATResult
01524 GATSelf_internal_CreateGATJobId(GATSelf_const self, GATContext context, 
01525   GATString *gatjobid)
01526 {
01527   GAT_USES_STATUS(context, "GATSelf_internal_CreateGATJobId");
01528   GAT_UNUSED_PARAMETER(self);
01529   if (NULL != gatjobid)
01530   {
01531     /* create a new GAT job id (here UUID) */
01532     uuid_rc_t uuid_rc = UUID_RC_OK;
01533     uuid_t *uuid;
01534     char *str = NULL;
01535 
01536     if (UUID_RC_OK == (uuid_rc = uuid_create(&uuid)) &&
01537         UUID_RC_OK == (uuid_rc = uuid_make(uuid, UUID_MAKE_V1)) &&
01538         UUID_RC_OK == (uuid_rc = uuid_export(uuid, UUID_FMT_STR, (void **)&str, 0)) &&
01539         UUID_RC_OK == (uuid_rc = uuid_destroy (uuid)))
01540     {
01541       char gatjobid_prefix[] = "GAT_JOBID:";
01542       char buffer[UUID_LEN_STR + sizeof(gatjobid_prefix) +1];
01543       
01544       strcpy(buffer, gatjobid_prefix);
01545       strcpy(&buffer[sizeof(gatjobid_prefix)-1], str);
01546 
01547       *gatjobid = GATString_Create(buffer, strlen(buffer)+1, "ASCII");
01548       GAT_CREATE_STATUS_IF(NULL == *gatjobid, GAT_MEMORYFAILURE);
01549     }
01550     else
01551     {
01552       GAT_CREATE_STATUS(UUID_TO_GAT(uuid_rc));
01553     }
01554     free(str);
01555   }
01556   return GAT_RETURN_STATUS();
01557 }
01558 
01559 /*  GATSelf_GetCPIInstanceData
01560  *  
01561  *  The function GATSelf_GetCPIInstanceData returns the CPI instance data, 
01562  *  associated with the given GATSelf object.
01563  *
01564  *  @param object The object, for which to return the CPI instance data.
01565  *  @param data The pointer to the variable, which should receive the
01566  *        resulting CPI instance data.
01567  *
01568  *  @return An error code.
01569  */
01570 static GATResult
01571 GATSelf_GetCPIInstanceData(GATSelf object, void **data)
01572 {
01573   GATResult retval = GAT_INVALID_HANDLE;
01574   if (NULL != object)
01575   {
01576     if (NULL != data)
01577     {
01578       *data = (void *)&object->data;
01579       retval = GAT_SUCCESS;
01580     }
01581     else
01582     {
01583       retval = GAT_INVALID_PARAMETER;
01584     }
01585   }
01586   return retval;
01587 }
01588 
01589 /** GATSelf_AddErrorMessageHandler
01590  *  
01591  *  The GATSelf_AddErrorMessageHandler function registeres the given callback 
01592  *  function with the engine. This callback function is used by the engine to 
01593  *  get the error message corresponding to a given error code. The callback
01594  *  function is called for error codes belonging to the given facility (the 
01595  *  facility code is contained in the error code, namely bits 16...27).
01596  *
01597  *  @param facility The facility code, for which this callback function has to 
01598  *        be called.
01599  *  @param callback The callback function to call to get the error messages for 
01600  *        error codes belon ing to the given facility.
01601  *  @param cookie The pointer to a variable, which receives a unique cookie
01602  *        representing the registered function, which should be used to remove
01603  *        the registration of this function later on.
01604  *
01605  *  @return An error code.
01606  */
01607 GATResult
01608 GATSelf_AddErrorMessageHandler(GATuint32 facility, 
01609   GATErrorMessageHandler handler, GATuint32 *cookie)
01610 {
01611   GATResult retval = GAT_MEMORYFAILURE;
01612   if (NULL == error_message_handlers)
01613   {
01614     error_message_handlers = GATList_GATErrorMessageHandlerData_Create();
01615   }
01616   
01617   if (NULL != error_message_handlers)
01618   {
01619     if (NULL != cookie)
01620     {
01621       GATErrorMessageHandlerData data;
01622       GATuint32 mycookie = ++error_cookie_jar;
01623       GATList_GATErrorMessageHandlerData_Iterator it = NULL;
01624       
01625       data.facility = facility;
01626       data.cookie = mycookie;
01627       data.handler = handler;
01628       
01629       it = GATList_GATErrorMessageHandlerData_Insert(error_message_handlers, 
01630         GATList_GATErrorMessageHandlerData_End(error_message_handlers), data);
01631       if (NULL == it)
01632       {
01633         retval = GAT_MEMORYFAILURE;
01634       }
01635       else
01636       {
01637         retval = GAT_SUCCESS;
01638         *cookie = mycookie;
01639       }
01640     }
01641     else
01642     {
01643       retval = GAT_INVALID_PARAMETER;
01644     }
01645   }
01646 
01647   if (GAT_FAILED(retval) && NULL != error_message_handlers)
01648   {
01649     /* free the list, if it is empty */
01650     if (0 == GATList_GATErrorMessageHandlerData_Size(error_message_handlers))
01651     {
01652       GATList_GATErrorMessageHandlerData_Destroy(&error_message_handlers);
01653     }
01654   }
01655   return retval;
01656 }
01657   
01658 /** GATSelf_RemoveErrorMessageHandler
01659  *  
01660  *  The GATSelf_RemoveErrorMessageHandler function removes the registration of
01661  *  the error message handler associated with the given cookie.
01662  */
01663 GATResult
01664 GATSelf_RemoveErrorMessageHandler(GATuint32 *cookie)
01665 {
01666   GATResult retval = GAT_KEY_NOT_FOUND;
01667   if (NULL != cookie)
01668   {
01669     if (0 != *cookie && NULL != error_message_handlers)
01670     {
01671       GATList_GATErrorMessageHandlerData_Iterator it = 
01672         GATList_GATErrorMessageHandlerData_Begin(error_message_handlers);
01673       GATList_GATErrorMessageHandlerData_Iterator end = 
01674         GATList_GATErrorMessageHandlerData_End(error_message_handlers);
01675       
01676       for (/**/; it != end; it = GATList_GATErrorMessageHandlerData_Next(it))
01677       {
01678         GATErrorMessageHandlerData *data = GATList_GATErrorMessageHandlerData_Get(it);
01679         if (NULL != data && data->cookie == *cookie)
01680         {
01681           GATList_GATErrorMessageHandlerData_Erase(error_message_handlers, it);
01682           retval = GAT_SUCCESS;
01683           break;
01684         }
01685       }
01686     }
01687     *cookie = 0;
01688   }
01689     
01690   if (NULL != error_message_handlers && 
01691       0 == GATList_GATErrorMessageHandlerData_Size(error_message_handlers))
01692   {
01693     /* free the list, if it is empty */
01694     GATList_GATErrorMessageHandlerData_Destroy(&error_message_handlers);
01695   }
01696   return retval;
01697 }
01698 
01699 /** GATSelf_ResolveErrorMessage
01700  *  
01701  *  The function GATSelf_ResolveErrorMessage returns an error message 
01702  *  associated with the given error code.
01703  *
01704  *  @param err_code The error code, for which the system needs to get the error 
01705  *        message.
01706  *  @param buffer The buffer, where to return the resulting error message.
01707  *  @param length The size of the given buffer. If this size is insufficient for 
01708  *        the error message to return, the error callback function should return
01709  *        the required length in the written output parameter and it should 
01710  *        additionally return the GAT_BUFFER_TOO_SMALL return value to the 
01711  *        caller.
01712  *  @param written The pointer to a variable, which should receive the real
01713  *        size of the generated error message.
01714  *
01715  *  @return An error code.
01716  */
01717 GATResult
01718 GATSelf_ResolveErrorMessage(GATResult err_code, char *buffer, 
01719   GATuint32 length, GATuint32 *written)
01720 {
01721   GATResult retval = GAT_KEY_NOT_FOUND;
01722   if (NULL != error_message_handlers)
01723   {
01724     GATList_GATErrorMessageHandlerData_Iterator it = 
01725       GATList_GATErrorMessageHandlerData_Begin(error_message_handlers);
01726     GATList_GATErrorMessageHandlerData_Iterator end = 
01727       GATList_GATErrorMessageHandlerData_End(error_message_handlers);
01728     
01729     for (/**/; it != end; it = GATList_GATErrorMessageHandlerData_Next(it))
01730     {
01731       GATErrorMessageHandlerData *data = GATList_GATErrorMessageHandlerData_Get(it);
01732       if (NULL != data && data->facility == GAT_RESULT_FACILITY(err_code))
01733       {
01734         retval = data->handler(err_code, buffer, length, written);
01735         if (GAT_SUCCEEDED(retval) || GAT_BUFFER_TOO_SMALL == retval)
01736         {
01737           // found an error message handler, which knows about this error code
01738           break;
01739         }
01740       }
01741     }
01742   }
01743   return retval;
01744 }
01745 
01746 
01747 /* Error message handler functions */
01748 static GATResult  
01749 GATStatus_ErrorMessagesEngine(GATResult err_code, char *buffer, 
01750   GATuint32 length, GATuint32 *written)
01751 {
01752   static char const *error_strings[] = {
01753     "GAT: No error",                                                   
01754     "GAT: Generic (unspecified error)",
01755     "GAT: Not implemented",
01756     "GAT: Out of memory",
01757     "GAT: Duplicate adaptorname",
01758     "GAT: Failed to load adaptor",
01759     "GAT: No appropriate adaptor registration function found",
01760     "GAT: Duplicate configuration key",
01761     "GAT: File open error (file not found?)",
01762     "GAT: Key not found",
01763     "GAT: Unexpected/wrong key type",
01764     "GAT: Invalid GAT handle",
01765     "GAT: Invalid parameter",
01766     "GAT: Unknown CPI structure version",
01767     "GAT: No registered CPI found",
01768     "GAT: Invalid encoding",
01769     "GAT: Incomplete enconding",
01770     "GAT: No matching CPI found",
01771     "GAT: No matching resource found",
01772     "GAT: This interface is not implemented by the given GAT object",
01773     "GAT: Unknown format",
01774     "GAT: Key already exists in this context",
01775     "GAT: Remote call failed",
01776     "GAT: Generic input/output error",
01777     "GAT: Invalid state",
01778     "GAT: Type mismatch",
01779     "GAT: Buffer too small",
01780     "GAT: Bad object conversion",
01781     "GAT: Invalid config file format",
01782     "GAT: The referenced GATContext instance is usable as error context only",
01783   };
01784   
01785   GATResult retval = GAT_INVALID_PARAMETER;
01786   if (NULL != buffer && NULL != written)
01787   {
01788     GATuint32 code = GAT_RESULT_CODE(err_code);
01789     if (0 <= code && code < sizeof(error_strings)/sizeof(error_strings[0]))
01790     {
01791       size_t len = strlen(error_strings[code]);
01792       if (length > len)
01793       {
01794         strncpy(buffer, error_strings[code], length);
01795         buffer[length-1] = '\0';
01796         *written = length;
01797         retval = GAT_SUCCESS;
01798       }
01799       else
01800       {
01801         *written = len+1;
01802         retval = GAT_BUFFER_TOO_SMALL;
01803       }
01804     }
01805   }
01806   return retval;
01807 }
01808 
01809 static GATResult  
01810 GATStatus_ErrorMessagesXds(GATResult err_code, char *buffer, 
01811   GATuint32 length, GATuint32 *written)
01812 {
01813   static char const *error_strings[] = {
01814     "Xds: No error",
01815     "Xds: Out of memory",
01816     "Xds: Buffer overflow",
01817     "Xds: Invalid parameter",
01818     "Xds: Type mismatch",
01819     "Xds: Unknown engine",
01820     "Xds: Invalid mode",
01821     "Xds: Buffer underflow",
01822     "Xds: Unknown error",
01823     "Xds: System error",
01824   };
01825   
01826   GATResult retval = GAT_INVALID_PARAMETER;
01827   if (NULL != buffer && NULL != written)
01828   {
01829     GATuint32 code = GAT_RESULT_CODE(err_code);
01830     if (0 <= code && code < sizeof(error_strings)/sizeof(error_strings[0]))
01831     {
01832       size_t len = strlen(error_strings[code]);
01833       if (length > len)
01834       {
01835         strncpy(buffer, error_strings[code], length);
01836         buffer[length-1] = '\0';
01837         *written = length;
01838         retval = GAT_SUCCESS;
01839       }
01840       else
01841       {
01842         *written = len+1;
01843         retval = GAT_BUFFER_TOO_SMALL;
01844       }
01845     }
01846   }
01847   return retval;
01848 }
01849 
01850 static GATResult  
01851 GATStatus_ErrorMessagesUuid(GATResult err_code, char *buffer, 
01852   GATuint32 length, GATuint32 *written)
01853 {
01854   static char const *error_strings[] = {
01855     "Uuid: No error",
01856     "Uuid: Invalid parameter",
01857     "Uuid: Out of memory",
01858     "Uuid: System error",
01859     "Uuid: Internal error",
01860     "Uuid: Not implemented",
01861   };
01862   
01863   GATResult retval = GAT_INVALID_PARAMETER;
01864   if (NULL != buffer && NULL != written)
01865   {
01866     GATuint32 code = GAT_RESULT_CODE(err_code);
01867     if (0 <= code && code < sizeof(error_strings)/sizeof(error_strings[0]))
01868     {
01869       size_t len = strlen(error_strings[code]);
01870       if (length > len)
01871       {
01872         strncpy(buffer, error_strings[code], length);
01873         buffer[length-1] = '\0';
01874         *written = length;
01875         retval = GAT_SUCCESS;
01876       }
01877       else
01878       {
01879         *written = len+1;
01880         retval = GAT_BUFFER_TOO_SMALL;
01881       }
01882     }
01883   }
01884   return retval;
01885 }  
01886 
01887 static GATResult  
01888 GATStatus_ErrorMessagesRegex(GATResult err_code, char *buffer, 
01889   GATuint32 length, GATuint32 *written)
01890 {
01891   static char const *error_strings[] = {
01892     "Regex: Success",
01893     "Regex: Didn't find a match (for regexec)",
01894     "Regex: Invalid pattern",
01895     "Regex: Not implemented",
01896     "Regex: Invalid character class name",
01897     "Regex: Trailing backslash",
01898     "Regex: Invalid back reference",
01899     "Regex: Unmatched left bracket",
01900     "Regex: Parenthesis imbalance",
01901     "Regex: Unmatched \\{",
01902     "Regex: Invalid contents of \\{\\}",
01903     "Regex: Invalid range end",
01904     "Regex: Ran out of memory",
01905     "Regex: No preceding regulare for repetition operand",
01906     "Regex: Premature end",
01907     "Regex: Compiled pattern bigger than 2^16 bytes",
01908     "Regex: Unmatched ) or \\); not returned from regcomp"
01909   };
01910   
01911   GATResult retval = GAT_INVALID_PARAMETER;
01912   if (NULL != buffer && NULL != written)
01913   {
01914     GATuint32 code = GAT_RESULT_CODE(err_code);
01915     if (0 <= code && code < sizeof(error_strings)/sizeof(error_strings[0]))
01916     {
01917       size_t len = strlen(error_strings[code]);
01918       if (length > len)
01919       {
01920         strncpy(buffer, error_strings[code], length);
01921         buffer[length-1] = '\0';
01922         *written = length;
01923         retval = GAT_SUCCESS;
01924       }
01925       else
01926       {
01927         *written = len+1;
01928         retval = GAT_BUFFER_TOO_SMALL;
01929       }
01930     }
01931   }
01932   return retval;
01933 }  
01934 
01935 static GATResult  
01936 GATStatus_ErrorMessagesSQLite(GATResult err_code, char *buffer, 
01937   GATuint32 length, GATuint32 *written)
01938 {
01939   static char const *error_strings[] = {
01940     "SQLite: Successful result",                                                   
01941     "SQLite: SQL error or missing database",
01942     "SQLite: An internal logic error in SQLite",
01943     "SQLite: Access permission denied",
01944     "SQLite: Callback routine requested an abort",
01945     "SQLite: The database file is locked",
01946     "SQLite: A table in the database is locked",
01947     "SQLite: A malloc() failed",
01948     "SQLite: Attempt to write a readonly database",
01949     "SQLite: Operation terminated by sqlite_interrupt()",
01950     "SQLite: Some kind of disk I/O error occurred",
01951     "SQLite: The database disk image is malformed",
01952     "SQLite: Table or record not found",
01953     "SQLite: Insertion failed because database is full",
01954     "SQLite: Unable to open the database file",
01955     "SQLite: Database lock protocol error",
01956     "SQLite: (Internal Only) Database table is empty",
01957     "SQLite: The database schema changed",
01958     "SQLite: Too much data for one row of a table",
01959     "SQLite: Abort due to constraint violation",
01960     "SQLite: Data type mismatch",
01961     "SQLite: Library used incorrectly",
01962     "SQLite: Uses OS features not supported on host",
01963     "SQLite: Authorization denied",
01964     "SQLite: Auxiliary database format error",
01965     "SQLite: 2nd parameter to sqlite_bind out of range",
01966     "SQLite: File opened that is not a database file"
01967   };
01968   
01969   GATResult retval = GAT_INVALID_PARAMETER;
01970   if (NULL != buffer && NULL != written)
01971   {
01972     GATuint32 code = GAT_RESULT_CODE(err_code);
01973     if (0 <= code && code < sizeof(error_strings)/sizeof(error_strings[0]))
01974     {
01975       size_t len = strlen(error_strings[code]);
01976       if (length > len)
01977       {
01978         strncpy(buffer, error_strings[code], length);
01979         buffer[length-1] = '\0';
01980         *written = length;
01981         retval = GAT_SUCCESS;
01982       }
01983       else
01984       {
01985         *written = len+1;
01986         retval = GAT_BUFFER_TOO_SMALL;
01987       }
01988     }
01989     else if (SQLITE_ROW == code)
01990     {
01991       char const *err_msg = "SQLite: sqlite_step() has another row ready";
01992       size_t len = strlen(err_msg);
01993       if (length > len)
01994       {
01995         strncpy(buffer, err_msg, length);
01996         buffer[length-1] = '\0';
01997         *written = length;
01998         retval = GAT_SUCCESS;
01999       }
02000       else
02001       {
02002         *written = len+1;
02003         retval = GAT_BUFFER_TOO_SMALL;
02004       }
02005     }
02006     else if (SQLITE_DONE == code)
02007     {
02008       char const *err_msg = "SQLite: sqlite_step() has finished executing";
02009       size_t len = strlen(err_msg);
02010       if (length > len)
02011       {
02012         strncpy(buffer, err_msg, length);
02013         buffer[length-1] = '\0';
02014         *written = length;
02015         retval = GAT_SUCCESS;
02016       }
02017       else
02018       {
02019         *written = len+1;
02020         retval = GAT_BUFFER_TOO_SMALL;
02021       }
02022     }
02023   }
02024   return retval;
02025 }
02026 
02027 static GATResult  
02028 GATStatus_ErrorMessagesPosix(GATResult err_code, char *buffer, 
02029   GATuint32 length, GATuint32 *written)
02030 {
02031   GATResult retval = GAT_INVALID_PARAMETER;
02032   if (NULL != buffer && NULL != written)
02033   {
02034     GATuint32 code = GAT_RESULT_CODE(err_code);
02035     if (0 == code)
02036     {
02037       char const *no_error = "Posix: No error.";
02038       size_t len = strlen(no_error);
02039       if (length > len)
02040       {
02041         strncpy(buffer, no_error, length);
02042         buffer[length-1] = '\0';
02043         retval = GAT_SUCCESS;
02044       }
02045       else
02046       {
02047         *written = len+1;
02048         retval = GAT_BUFFER_TOO_SMALL;
02049       }
02050     }
02051     else
02052     {
02053       char const *error_text = strerror(code);
02054       size_t posix_len = strlen("Posix: ");
02055       size_t len = strlen(error_text);
02056       if (length > len+posix_len)
02057       {
02058         strcpy(buffer, "Posix: ");
02059         strncat(buffer, error_text, length-posix_len); 
02060         buffer[length+posix_len-2] = '\0';    /* truncate trailing '\n' */
02061         *written = length+posix_len-1;
02062         retval = GAT_SUCCESS;
02063       }
02064       else
02065       {
02066         *written = len;
02067         retval = GAT_BUFFER_TOO_SMALL;
02068       }
02069     }
02070   }
02071   return retval;
02072 }  
02073 
02074 
02075 /* I hate IRIX.  Why?  Because you need to define the symbols
02076  * 'allow_severity' and 'deny_severity' to use getenv.  Oops you
02077  * say, and Oops it is!  So, why is that?  IRIX defined getenv not
02078  * in libc.so, oh no, but in libwrapp.so.  Well, why not - but,
02079  * also, libwrap.so defines some syslog stuff, which require the
02080  * user to define log severity flags externally to the lib.  Uhm.
02081  * Whatever - if configure deremines that this is the case, the
02082  * code below is used, and we are fine... :-)
02083  *
02084  * -- Andre
02085  */
02086 
02087 #ifdef NEED_SEVERITY_HACK
02088 #include <sys/syslog.h>
02089 int allow_severity = LOG_INFO;
02090 int deny_severity  = LOG_WARNING;
02091 #endif
02092