source: rtems/cpukit/libdl/rap.c

Last change on this file was 5dec089, checked in by Joel Sherrill <joel@…>, on 03/18/22 at 14:40:55

cpukit/libdl: Manual file header reordering (SPDX, Doxygen, Copyright)

Updates #3053.

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