Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtems_rap
0007  *
0008  * @brief RTEMS Application Loader
0009  *
0010  * This is the RAP implementation.
0011  */
0012 
0013 /*
0014  *  COPYRIGHT (c) 2012, 2018 Chris Johns <chrisj@rtems.org>
0015  *
0016  * Redistribution and use in source and binary forms, with or without
0017  * modification, are permitted provided that the following conditions
0018  * are met:
0019  * 1. Redistributions of source code must retain the above copyright
0020  *    notice, this list of conditions and the following disclaimer.
0021  * 2. Redistributions in binary form must reproduce the above copyright
0022  *    notice, this list of conditions and the following disclaimer in the
0023  *    documentation and/or other materials provided with the distribution.
0024  *
0025  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0026  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0027  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0028  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0029  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0030  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0031  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0032  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0033  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0034  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0035  * POSSIBILITY OF SUCH DAMAGE.
0036  */
0037 
0038 #ifdef HAVE_CONFIG_H
0039 #include "config.h"
0040 #endif
0041 
0042 #include <pthread.h>
0043 #include <stdarg.h>
0044 #include <stdlib.h>
0045 #include <stdio.h>
0046 #include <string.h>
0047 
0048 #include <rtems/libio_.h>
0049 
0050 #include <dlfcn.h>
0051 #include <rtems/rtl/rap.h>
0052 #include <rtems/rtl/rtl.h>
0053 
0054 #include "rtl-find-file.h"
0055 
0056 /**
0057  * The global RAP data. This structure is allocated on the heap when the first
0058  * call to location an application and is never released.
0059  */
0060 typedef struct rtems_rap_data_s
0061 {
0062   pthread_once_t      once;
0063   rtems_mutex         lock;           /**< The RAP lock id */
0064   rtems_chain_control apps;           /**< List if loaded application. */
0065   int                 last_errno;     /**< Last error number. */
0066   char                last_error[64]; /**< Last error string. */
0067 } rtems_rap_data;
0068 
0069 /**
0070  * The RAP file data. This structure is allocated on the heap when a file is
0071  * loaded.
0072  */
0073 typedef struct rtems_rap_app
0074 {
0075   rtems_chain_node node;         /**< The node's link in the chain. */
0076   const char*      name;         /**< The file name */
0077   void*            handle;       /**< The dlopen handle. */
0078 } rtems_rap_app;
0079 
0080 /**
0081  * RTL entry.
0082  */
0083 #if (RTL_GLUE(__USER_LABEL_PREFIX__, 1) == RTL_GLUE(_, 1))
0084   #define RTL_ENTRY_POINT "_rtems"
0085 #else
0086   #define RTL_ENTRY_POINT "rtems"
0087 #endif
0088 
0089 /**
0090  * Static RAP data is returned to the user when the loader is locked.
0091  */
0092 static rtems_rap_data rap_ = { .once = PTHREAD_ONCE_INIT };
0093 
0094 /**
0095  * Verbose level for the RAP loader.
0096  */
0097 static bool rap_verbose;
0098 
0099 /**
0100  * RAP entry call signature.
0101  */
0102 typedef int (*rtems_rap_entry)(int argc, const char* argv[]);
0103 
0104 /**
0105  * Forward decl.
0106  */
0107 static void rtems_rap_unlock (void);
0108 
0109 static void
0110 rtems_rap_data_init (void)
0111 {
0112   /*
0113    * Create the RAP lock.
0114    */
0115   rtems_mutex_init (&rap_.lock, "RAP");
0116 
0117   /*
0118    * Initialise the objects list and create any required services.
0119    */
0120   rtems_chain_initialize_empty (&rap_.apps);
0121 }
0122 
0123 static rtems_rap_data*
0124 rtems_rap_lock (void)
0125 {
0126   pthread_once (&rap_.once, rtems_rap_data_init);
0127   rtems_mutex_lock (&rap_.lock);
0128 
0129   return &rap_;
0130 }
0131 
0132 static void
0133 rtems_rap_unlock (void)
0134 {
0135   rtems_mutex_unlock (&rap_.lock);
0136 }
0137 
0138 static rtems_rap_app*
0139 rtems_rap_check_handle (void* handle)
0140 {
0141   rtems_rap_app*    app;
0142   rtems_chain_node* node;
0143 
0144   app = handle;
0145   node = rtems_chain_first (&rap_.apps);
0146 
0147   while (!rtems_chain_is_tail (&rap_.apps, node))
0148   {
0149     rtems_rap_app* check = (rtems_rap_app*) node;
0150     if (check == app)
0151       return app;
0152     node = rtems_chain_next (node);
0153   }
0154 
0155   return NULL;
0156 }
0157 
0158 static rtems_rap_app*
0159 rtems_rap_app_alloc (void)
0160 {
0161   rtems_rap_app* app = malloc (sizeof (rtems_rap_app));
0162   memset (app, 0, sizeof (rtems_rap_app));
0163   rtems_chain_append (&rap_.apps, &app->node);
0164   return app;
0165 }
0166 
0167 static void
0168 rtems_rap_app_free (rtems_rap_app* app)
0169 {
0170   if (app->handle)
0171   {
0172     dlclose (app->handle);
0173     app->handle = NULL;
0174   }
0175 
0176   if (!rtems_chain_is_node_off_chain (&app->node))
0177     rtems_chain_extract (&app->node);
0178 }
0179 
0180 static bool
0181 rtems_rap_match_name (rtems_rap_app* app, const char* name)
0182 {
0183   const char* a;
0184 
0185   /*
0186    * Assume the app name is absolute, ie points to the file on disk. This means
0187    * there is at least one delimiter in the name.
0188    */
0189 
0190   if (strncmp (app->name, name, strlen (name)) == 0)
0191     return true;
0192 
0193   a = app->name + strlen (app->name) - 1;
0194 
0195   while (a >= app->name)
0196   {
0197     if (rtems_filesystem_is_delimiter (*a))
0198     {
0199       const char* n = name;
0200 
0201       ++a;
0202 
0203       while (*a && *n)
0204       {
0205         if (*a == '.')
0206         {
0207           if (*n == '\0')
0208             return true;
0209         }
0210 
0211         ++a;
0212         ++n;
0213       }
0214 
0215       return false;
0216     }
0217 
0218     --a;
0219   }
0220 
0221   return false;
0222 }
0223 
0224 static void
0225 rtems_rap_get_rtl_error (void)
0226 {
0227   rap_.last_errno =
0228     rtems_rtl_get_error (rap_.last_error, sizeof (rap_.last_error));
0229 }
0230 
0231 static void
0232 rtems_rap_set_error (int error, const char* format, ...)
0233 {
0234   rtems_rap_data* rap = rtems_rap_lock ();
0235   va_list         ap;
0236   va_start (ap, format);
0237   rap->last_errno = error;
0238   vsnprintf (rap->last_error, sizeof (rap->last_error), format, ap);
0239   rtems_rap_unlock ();
0240   va_end (ap);
0241 }
0242 
0243 bool
0244 rtems_rap_load (const char* name, int mode, int argc, const char* argv[])
0245 {
0246   rtems_rap_data* rap = rtems_rap_lock ();
0247 
0248   if (!rap)
0249     return false;
0250 
0251   if (rap_verbose)
0252     printf ("rap: loading '%s'\n", name);
0253 
0254   /*
0255    * See if the app has already been loaded.
0256    */
0257   if (!rtems_rap_find (name))
0258   {
0259     rtems_rap_app*  app;
0260     rtems_rap_entry init;
0261     rtems_rap_entry fini;
0262     size_t          size = 0;
0263     int             r;
0264 
0265     /*
0266      * Allocate a new application descriptor and attempt to load it.
0267      */
0268     app = rtems_rap_app_alloc ();
0269     if (app == NULL)
0270     {
0271       rtems_rap_set_error (ENOMEM, "no memory for application");
0272       rtems_rap_unlock ();
0273       return false;
0274     }
0275 
0276     /*
0277      * Find the file in the file system using the search path.
0278      */
0279     if (!rtems_rtl_find_file (name, getenv ("PATH"), &app->name, &size))
0280     {
0281       rtems_rap_set_error (ENOENT, "file not found");
0282       rtems_rap_app_free (app);
0283       rtems_rap_unlock ();
0284       return false;
0285     }
0286 
0287     app->handle = dlopen (app->name, RTLD_NOW | mode);
0288     if (!app->handle)
0289     {
0290       rtems_rap_get_rtl_error ();
0291       rtems_rap_app_free (app);
0292       rtems_rap_unlock ();
0293       return false;
0294     }
0295 
0296     init = dlsym (app->handle, RTL_ENTRY_POINT);
0297     if (!init)
0298     {
0299       rtems_rap_get_rtl_error ();
0300       rtems_rap_app_free (app);
0301       rtems_rap_unlock ();
0302       return false;
0303     }
0304 
0305     fini = dlsym (app->handle, RTL_ENTRY_POINT);
0306     if (!fini)
0307     {
0308       rtems_rap_get_rtl_error ();
0309       rtems_rap_app_free (app);
0310       rtems_rap_unlock ();
0311       return false;
0312     }
0313 
0314     r = init (argc, argv);
0315     if (r != 0)
0316     {
0317       rtems_rap_set_error (r, "init call failure");
0318       rtems_rap_app_free (app);
0319       rtems_rap_unlock ();
0320       return false;
0321     }
0322   }
0323 
0324   rtems_rap_unlock ();
0325 
0326   return true;
0327 }
0328 
0329 bool
0330 rtems_rap_unload (const char* name)
0331 {
0332   rtems_rap_app*  app;
0333   rtems_rap_entry fini;
0334   int             r;
0335 
0336   rtems_rap_lock ();
0337 
0338   app = rtems_rap_find (name);
0339 
0340   if (rap_verbose)
0341     printf ("rap: unloading '%s'\n", name);
0342 
0343   if (!app)
0344   {
0345     rtems_rap_set_error (ENOENT, "invalid handle");
0346     rtems_rap_unlock ();
0347     return false;
0348   }
0349 
0350   fini = dlsym (app->handle, RTL_ENTRY_POINT);
0351   if (!fini)
0352   {
0353     rtems_rap_get_rtl_error ();
0354     rtems_rap_unlock ();
0355     return false;
0356   }
0357 
0358   r = fini (0, NULL);
0359   if (r != 0)
0360   {
0361     rtems_rap_set_error (r, "fini failure");
0362     rtems_rap_unlock ();
0363     return false;
0364   }
0365 
0366   rtems_rap_app_free (app);
0367   rtems_rap_unlock ();
0368 
0369   return true;
0370 }
0371 
0372 void*
0373 rtems_rap_find (const char* name)
0374 {
0375   rtems_rap_data*   rap = rtems_rap_lock ();
0376   rtems_chain_node* node;
0377 
0378   node = rtems_chain_first (&rap->apps);
0379 
0380   while (!rtems_chain_is_tail (&rap->apps, node))
0381   {
0382     rtems_rap_app* app = (rtems_rap_app*) node;
0383     if (rtems_rap_match_name (app, name))
0384     {
0385       rtems_rap_unlock ();
0386       return app;
0387     }
0388     node = rtems_chain_next (node);
0389   }
0390 
0391   rtems_rap_unlock ();
0392 
0393   return NULL;
0394 }
0395 
0396 bool
0397 rtems_rap_iterate (rtems_rap_iterator iterator)
0398 {
0399   rtems_rap_data*   rap = rtems_rap_lock ();
0400   rtems_chain_node* node;
0401   bool              result = true;
0402 
0403   node = rtems_chain_first (&rap->apps);
0404 
0405   while (!rtems_chain_is_tail (&rap->apps, node))
0406   {
0407     rtems_rap_app* app = (rtems_rap_app*) node;
0408     result = iterator (app);
0409     if (!result)
0410       break;
0411     node = rtems_chain_next (node);
0412   }
0413 
0414   rtems_rap_unlock ();
0415 
0416   return result;
0417 }
0418 
0419 const char*
0420 rtems_rap_name (void* handle)
0421 {
0422   rtems_rap_app* app = rtems_rap_check_handle (handle);
0423   if (app)
0424     return app->name;
0425   return NULL;
0426 }
0427 
0428 void*
0429 rtems_rap_dl_handle (void* handle)
0430 {
0431   rtems_rap_app* app = rtems_rap_check_handle (handle);
0432   if (app)
0433     return app->handle;
0434   return NULL;
0435 }
0436 
0437 int
0438 rtems_rap_get_error (char* message, size_t max_message)
0439 {
0440   rtems_rap_data* rap = rtems_rap_lock ();
0441   int             last_errno = rap->last_errno;
0442   strlcpy (message, rap->last_error, max_message);
0443   rtems_rap_unlock ();
0444   return last_errno;
0445 }