source: rtems/cpukit/libdl/rap.c @ 4408603

Last change on this file since 4408603 was f59d435d, checked in by Chris Johns <chrisj@…>, on Apr 12, 2018 at 7:46:49 AM

libdl: Remove _t from all structures as this is reserved for the standards

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/*
2 *  COPYRIGHT (c) 2012, 2018 Chris Johns <chrisj@rtems.org>
3 *
4 *  The license and distribution terms for this file may be
5 *  found in the file LICENSE in this distribution or at
6 *  http://www.rtems.org/license/LICENSE.
7 */
8/**
9 * @file
10 *
11 * @ingroup rtems_rap
12 *
13 * @brief RTEMS Application Loader
14 *
15 * This is the RAP implementation.
16 */
17
18#if HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <pthread.h>
23#include <stdarg.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27
28#include <rtems/libio_.h>
29
30#include <dlfcn.h>
31#include <rtems/rtl/rap.h>
32#include <rtems/rtl/rtl.h>
33
34#include "rtl-find-file.h"
35
36/**
37 * The global RAP data. This structure is allocated on the heap when the first
38 * call to location an application and is never released.
39 */
40typedef struct rtems_rap_data_s
41{
42  pthread_once_t      once;
43  rtems_mutex         lock;           /**< The RAP lock id */
44  rtems_chain_control apps;           /**< List if loaded application. */
45  int                 last_errno;     /**< Last error number. */
46  char                last_error[64]; /**< Last error string. */
47} rtems_rap_data;
48
49/**
50 * The RAP file data. This structure is allocated on the heap when a file is
51 * loaded.
52 */
53typedef struct rtems_rap_app
54{
55  rtems_chain_node node;         /**< The node's link in the chain. */
56  const char*      name;         /**< The file name */
57  void*            handle;       /**< The dlopen handle. */
58} rtems_rap_app;
59
60/**
61 * RTL entry.
62 */
63#if (RTL_GLUE(__USER_LABEL_PREFIX__, 1) == RTL_GLUE(_, 1))
64  #define RTL_ENTRY_POINT "_rtems"
65#else
66  #define RTL_ENTRY_POINT "rtems"
67#endif
68
69/**
70 * Static RAP data is returned to the user when the loader is locked.
71 */
72static rtems_rap_data rap_ = { .once = PTHREAD_ONCE_INIT };
73
74/**
75 * Verbose level for the RAP loader.
76 */
77static bool rap_verbose;
78
79/**
80 * RAP entry call signature.
81 */
82typedef int (*rtems_rap_entry)(int argc, const char* argv[]);
83
84/**
85 * Forward decl.
86 */
87static void rtems_rap_unlock (void);
88
89static void
90rtems_rap_data_init (void)
91{
92  /*
93   * Create the RAP lock.
94   */
95  rtems_mutex_init (&rap_.lock, "RAP");
96
97  /*
98   * Initialise the objects list and create any required services.
99   */
100  rtems_chain_initialize_empty (&rap_.apps);
101}
102
103static rtems_rap_data*
104rtems_rap_lock (void)
105{
106  pthread_once (&rap_.once, rtems_rap_data_init);
107  rtems_mutex_lock (&rap_.lock);
108
109  return &rap_;
110}
111
112static void
113rtems_rap_unlock (void)
114{
115  rtems_mutex_unlock (&rap_.lock);
116}
117
118static rtems_rap_app*
119rtems_rap_check_handle (void* handle)
120{
121  rtems_rap_app*    app;
122  rtems_chain_node* node;
123
124  app = handle;
125  node = rtems_chain_first (&rap_.apps);
126
127  while (!rtems_chain_is_tail (&rap_.apps, node))
128  {
129    rtems_rap_app* check = (rtems_rap_app*) node;
130    if (check == app)
131      return app;
132    node = rtems_chain_next (node);
133  }
134
135  return NULL;
136}
137
138static rtems_rap_app*
139rtems_rap_app_alloc (void)
140{
141  rtems_rap_app* app = malloc (sizeof (rtems_rap_app));
142  memset (app, 0, sizeof (rtems_rap_app));
143  rtems_chain_append (&rap_.apps, &app->node);
144  return app;
145}
146
147static void
148rtems_rap_app_free (rtems_rap_app* app)
149{
150  if (app->handle)
151  {
152    dlclose (app->handle);
153    app->handle = NULL;
154  }
155
156  if (!rtems_chain_is_node_off_chain (&app->node))
157    rtems_chain_extract (&app->node);
158}
159
160static bool
161rtems_rap_match_name (rtems_rap_app* app, const char* name)
162{
163  const char* a;
164
165  /*
166   * Assume the app name is absolute, ie points to the file on disk. This means
167   * there is at least one delimiter in the name.
168   */
169
170  if (strncmp (app->name, name, strlen (name)) == 0)
171    return true;
172
173  a = app->name + strlen (app->name) - 1;
174
175  while (a >= app->name)
176  {
177    if (rtems_filesystem_is_delimiter (*a))
178    {
179      const char* n = name;
180
181      ++a;
182
183      while (*a && *n)
184      {
185        if (*a == '.')
186        {
187          if (*n == '\0')
188            return true;
189        }
190
191        ++a;
192        ++n;
193      }
194
195      return false;
196    }
197
198    --a;
199  }
200
201  return false;
202}
203
204static void
205rtems_rap_get_rtl_error (void)
206{
207  rap_.last_errno =
208    rtems_rtl_get_error (rap_.last_error, sizeof (rap_.last_error));
209}
210
211static void
212rtems_rap_set_error (int error, const char* format, ...)
213{
214  rtems_rap_data* rap = rtems_rap_lock ();
215  va_list         ap;
216  va_start (ap, format);
217  rap->last_errno = error;
218  vsnprintf (rap->last_error, sizeof (rap->last_error), format, ap);
219  rtems_rap_unlock ();
220  va_end (ap);
221}
222
223bool
224rtems_rap_load (const char* name, int mode, int argc, const char* argv[])
225{
226  rtems_rap_data* rap = rtems_rap_lock ();
227
228  if (!rap)
229    return false;
230
231  if (rap_verbose)
232    printf ("rap: loading '%s'\n", name);
233
234  /*
235   * See if the app has already been loaded.
236   */
237  if (!rtems_rap_find (name))
238  {
239    rtems_rap_app*  app;
240    rtems_rap_entry init;
241    rtems_rap_entry fini;
242    size_t          size = 0;
243    int             r;
244
245    /*
246     * Allocate a new application descriptor and attempt to load it.
247     */
248    app = rtems_rap_app_alloc ();
249    if (app == NULL)
250    {
251      rtems_rap_set_error (ENOMEM, "no memory for application");
252      rtems_rap_unlock ();
253      return false;
254    }
255
256    /*
257     * Find the file in the file system using the search path.
258     */
259    if (!rtems_rtl_find_file (name, getenv ("PATH"), &app->name, &size))
260    {
261      rtems_rap_set_error (ENOENT, "file not found");
262      rtems_rap_app_free (app);
263      rtems_rap_unlock ();
264      return false;
265    }
266
267    app->handle = dlopen (app->name, RTLD_NOW | mode);
268    if (!app->handle)
269    {
270      rtems_rap_get_rtl_error ();
271      rtems_rap_app_free (app);
272      rtems_rap_unlock ();
273      return false;
274    }
275
276    init = dlsym (app->handle, RTL_ENTRY_POINT);
277    if (!init)
278    {
279      rtems_rap_get_rtl_error ();
280      rtems_rap_app_free (app);
281      rtems_rap_unlock ();
282      return false;
283    }
284
285    fini = dlsym (app->handle, RTL_ENTRY_POINT);
286    if (!fini)
287    {
288      rtems_rap_get_rtl_error ();
289      rtems_rap_app_free (app);
290      rtems_rap_unlock ();
291      return false;
292    }
293
294    r = init (argc, argv);
295    if (r != 0)
296    {
297      rtems_rap_set_error (r, "init call failure");
298      rtems_rap_app_free (app);
299      rtems_rap_unlock ();
300      return false;
301    }
302  }
303
304  rtems_rap_unlock ();
305
306  return true;
307}
308
309bool
310rtems_rap_unload (const char* name)
311{
312  rtems_rap_app*  app;
313  rtems_rap_entry fini;
314  int             r;
315
316  rtems_rap_lock ();
317
318  app = rtems_rap_find (name);
319
320  if (rap_verbose)
321    printf ("rap: unloading '%s'\n", name);
322
323  if (!app)
324  {
325    rtems_rap_set_error (ENOENT, "invalid handle");
326    rtems_rap_unlock ();
327    return false;
328  }
329
330  fini = dlsym (app->handle, RTL_ENTRY_POINT);
331  if (!fini)
332  {
333    rtems_rap_get_rtl_error ();
334    rtems_rap_unlock ();
335    return false;
336  }
337
338  r = fini (0, NULL);
339  if (r != 0)
340  {
341    rtems_rap_set_error (r, "fini failure");
342    rtems_rap_unlock ();
343    return false;
344  }
345
346  rtems_rap_app_free (app);
347  rtems_rap_unlock ();
348
349  return true;
350}
351
352void*
353rtems_rap_find (const char* name)
354{
355  rtems_rap_data*   rap = rtems_rap_lock ();
356  rtems_chain_node* node;
357
358  node = rtems_chain_first (&rap->apps);
359
360  while (!rtems_chain_is_tail (&rap->apps, node))
361  {
362    rtems_rap_app* app = (rtems_rap_app*) node;
363    if (rtems_rap_match_name (app, name))
364    {
365      rtems_rap_unlock ();
366      return app;
367    }
368    node = rtems_chain_next (node);
369  }
370
371  rtems_rap_unlock ();
372
373  return NULL;
374}
375
376bool
377rtems_rap_iterate (rtems_rap_iterator iterator)
378{
379  rtems_rap_data*   rap = rtems_rap_lock ();
380  rtems_chain_node* node;
381  bool              result = true;
382
383  node = rtems_chain_first (&rap->apps);
384
385  while (!rtems_chain_is_tail (&rap->apps, node))
386  {
387    rtems_rap_app* app = (rtems_rap_app*) node;
388    result = iterator (app);
389    if (!result)
390      break;
391    node = rtems_chain_next (node);
392  }
393
394  rtems_rap_unlock ();
395
396  return result;
397}
398
399const char*
400rtems_rap_name (void* handle)
401{
402  rtems_rap_app* app = rtems_rap_check_handle (handle);
403  if (app)
404    return app->name;
405  return NULL;
406}
407
408void*
409rtems_rap_dl_handle (void* handle)
410{
411  rtems_rap_app* app = rtems_rap_check_handle (handle);
412  if (app)
413    return app->handle;
414  return NULL;
415}
416
417int
418rtems_rap_get_error (char* message, size_t max_message)
419{
420  rtems_rap_data* rap = rtems_rap_lock ();
421  int             last_errno = rap->last_errno;
422  strlcpy (message, rap->last_error, max_message);
423  rtems_rap_unlock ();
424  return last_errno;
425}
Note: See TracBrowser for help on using the repository browser.