1/*	$NetBSD: load_lib.c,v 1.3 2022/10/08 16:12:50 christos Exp $	*/
2
3/*++
4/* NAME
5/*	load_lib 3
6/* SUMMARY
7/*	library loading wrappers
8/* SYNOPSIS
9/*	#include <load_lib.h>
10/*
11/*	void	load_library_symbols(const char *, LIB_FN *, LIB_DP *);
12/*	const char *libname;
13/*	LIB_FN	*libfuncs;
14/*	LIB_DP	*libdata;
15/* DESCRIPTION
16/*	load_library_symbols() loads the specified shared object
17/*	and looks up the function or data pointers for the specified
18/*	symbols. All errors are fatal.
19/*
20/*	Arguments:
21/* .IP libname
22/*	shared-library pathname.
23/* .IP libfuncs
24/*	Array of LIB_FN structures. The last name member must be null.
25/* .IP libdata
26/*	Array of LIB_DP structures. The last name member must be null.
27/* SEE ALSO
28/*	msg(3) diagnostics interface
29/* DIAGNOSTICS
30/*	Problems are reported via the msg(3) diagnostics routines:
31/*	library not found, symbols not found, other fatal errors.
32/* LICENSE
33/* .ad
34/* .fi
35/*	The Secure Mailer license must be distributed with this software.
36/* AUTHOR(S)
37/*	LaMont Jones
38/*	Hewlett-Packard Company
39/*	3404 Harmony Road
40/*	Fort Collins, CO 80528, USA
41/*
42/*	Wietse Venema
43/*	IBM T.J. Watson Research
44/*	P.O. Box 704
45/*	Yorktown Heights, NY 10598, USA
46/*--*/
47
48 /*
49  * System libraries.
50  */
51#include "sys_defs.h"
52#include <stdlib.h>
53#include <stddef.h>
54#include <string.h>
55#ifdef USE_DYNAMIC_MAPS
56#if defined(HAS_DLOPEN)
57#include <dlfcn.h>
58#elif defined(HAS_SHL_LOAD)
59#include <dl.h>
60#else
61#error "USE_DYNAMIC_LIBS requires HAS_DLOPEN or HAS_SHL_LOAD"
62#endif
63
64 /*
65  * Utility library.
66  */
67#include <msg.h>
68#include <load_lib.h>
69
70/* load_library_symbols - load shared library and look up symbols */
71
72void    load_library_symbols(const char *libname, LIB_FN *libfuncs,
73			             LIB_DP *libdata)
74{
75    static const char myname[] = "load_library_symbols";
76    LIB_FN *fn;
77    LIB_DP *dp;
78
79#if defined(HAS_DLOPEN)
80    void   *handle;
81    char   *emsg;
82
83    /*
84     * XXX This is basically how FreeBSD dlfunc() silences a compiler warning
85     * about a data/function pointer conversion. The solution below is non-
86     * portable: it assumes that both data and function pointers are the same
87     * in size, and that both have the same representation.
88     */
89    union {
90	void   *dptr;			/* data pointer */
91	void    (*fptr) (void);		/* function pointer */
92    }       non_portable_union;
93
94    if ((handle = dlopen(libname, RTLD_NOW)) == 0) {
95	emsg = dlerror();
96	msg_fatal("%s: dlopen failure loading %s: %s", myname, libname,
97		  emsg ? emsg : "don't know why");
98    }
99    if (libfuncs) {
100	for (fn = libfuncs; fn->name; fn++) {
101	    if ((non_portable_union.dptr = dlsym(handle, fn->name)) == 0) {
102		emsg = dlerror();
103		msg_fatal("%s: dlsym failure looking up %s in %s: %s", myname,
104			  fn->name, libname, emsg ? emsg : "don't know why");
105	    }
106	    fn->fptr = non_portable_union.fptr;
107	    if (msg_verbose > 1)
108		msg_info("loaded %s = %p", fn->name, non_portable_union.dptr);
109	}
110    }
111    if (libdata) {
112	for (dp = libdata; dp->name; dp++) {
113	    if ((dp->dptr = dlsym(handle, dp->name)) == 0) {
114		emsg = dlerror();
115		msg_fatal("%s: dlsym failure looking up %s in %s: %s", myname,
116			  dp->name, libname, emsg ? emsg : "don't know why");
117	    }
118	    if (msg_verbose > 1)
119		msg_info("loaded %s = %p", dp->name, dp->dptr);
120	}
121    }
122#elif defined(HAS_SHL_LOAD)
123    shl_t   handle;
124
125    handle = shl_load(libname, BIND_IMMEDIATE, 0);
126
127    if (libfuncs) {
128	for (fn = libfuncs; fn->name; fn++) {
129	    if (shl_findsym(&handle, fn->name, TYPE_PROCEDURE, &fn->fptr) != 0)
130		msg_fatal("%s: shl_findsym failure looking up %s in %s: %m",
131			  myname, fn->name, libname);
132	    if (msg_verbose > 1)
133		msg_info("loaded %s = %p", fn->name, (void *) fn->fptr);
134	}
135    }
136    if (libdata) {
137	for (dp = libdata; dp->name; dp++) {
138	    if (shl_findsym(&handle, dp->name, TYPE_DATA, &dp->dptr) != 0)
139		msg_fatal("%s: shl_findsym failure looking up %s in %s: %m",
140			  myname, dp->name, libname);
141	    if (msg_verbose > 1)
142		msg_info("loaded %s = %p", dp->name, dp->dptr);
143	}
144    }
145#endif
146}
147
148#endif
149