summaryrefslogtreecommitdiffstats
path: root/src/util/load_lib.c
blob: 44e540d646103d4f965126f2c60d970f14905d93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*++
/* NAME
/*	load_lib 3
/* SUMMARY
/*	library loading wrappers
/* SYNOPSIS
/*	#include <load_lib.h>
/*
/*	void	load_library_symbols(const char *, LIB_FN *, LIB_DP *);
/*	const char *libname;
/*	LIB_FN	*libfuncs;
/*	LIB_DP	*libdata;
/* DESCRIPTION
/*	load_library_symbols() loads the specified shared object
/*	and looks up the function or data pointers for the specified
/*	symbols. All errors are fatal.
/*
/*	Arguments:
/* .IP libname
/*	shared-library pathname.
/* .IP libfuncs
/*	Array of LIB_FN structures. The last name member must be null.
/* .IP libdata
/*	Array of LIB_DP structures. The last name member must be null.
/* SEE ALSO
/*	msg(3) diagnostics interface
/* DIAGNOSTICS
/*	Problems are reported via the msg(3) diagnostics routines:
/*	library not found, symbols not found, other fatal errors.
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	LaMont Jones
/*	Hewlett-Packard Company
/*	3404 Harmony Road
/*	Fort Collins, CO 80528, USA
/*
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*--*/

 /*
  * System libraries.
  */
#include "sys_defs.h"
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#ifdef USE_DYNAMIC_MAPS
#if defined(HAS_DLOPEN)
#include <dlfcn.h>
#elif defined(HAS_SHL_LOAD)
#include <dl.h>
#else
#error "USE_DYNAMIC_LIBS requires HAS_DLOPEN or HAS_SHL_LOAD"
#endif

 /*
  * Utility library.
  */
#include <msg.h>
#include <load_lib.h>

/* load_library_symbols - load shared library and look up symbols */

void    load_library_symbols(const char *libname, LIB_FN *libfuncs,
			             LIB_DP *libdata)
{
    static const char myname[] = "load_library_symbols";
    LIB_FN *fn;
    LIB_DP *dp;

#if defined(HAS_DLOPEN)
    void   *handle;
    char   *emsg;

    /*
     * XXX This is basically how FreeBSD dlfunc() silences a compiler warning
     * about a data/function pointer conversion. The solution below is non-
     * portable: it assumes that both data and function pointers are the same
     * in size, and that both have the same representation.
     */
    union {
	void   *dptr;			/* data pointer */
	void    (*fptr) (void);		/* function pointer */
    }       non_portable_union;

    if ((handle = dlopen(libname, RTLD_NOW)) == 0) {
	emsg = dlerror();
	msg_fatal("%s: dlopen failure loading %s: %s", myname, libname,
		  emsg ? emsg : "don't know why");
    }
    if (libfuncs) {
	for (fn = libfuncs; fn->name; fn++) {
	    if ((non_portable_union.dptr = dlsym(handle, fn->name)) == 0) {
		emsg = dlerror();
		msg_fatal("%s: dlsym failure looking up %s in %s: %s", myname,
			  fn->name, libname, emsg ? emsg : "don't know why");
	    }
	    fn->fptr = non_portable_union.fptr;
	    if (msg_verbose > 1)
		msg_info("loaded %s = %p", fn->name, non_portable_union.dptr);
	}
    }
    if (libdata) {
	for (dp = libdata; dp->name; dp++) {
	    if ((dp->dptr = dlsym(handle, dp->name)) == 0) {
		emsg = dlerror();
		msg_fatal("%s: dlsym failure looking up %s in %s: %s", myname,
			  dp->name, libname, emsg ? emsg : "don't know why");
	    }
	    if (msg_verbose > 1)
		msg_info("loaded %s = %p", dp->name, dp->dptr);
	}
    }
#elif defined(HAS_SHL_LOAD)
    shl_t   handle;

    handle = shl_load(libname, BIND_IMMEDIATE, 0);

    if (libfuncs) {
	for (fn = libfuncs; fn->name; fn++) {
	    if (shl_findsym(&handle, fn->name, TYPE_PROCEDURE, &fn->fptr) != 0)
		msg_fatal("%s: shl_findsym failure looking up %s in %s: %m",
			  myname, fn->name, libname);
	    if (msg_verbose > 1)
		msg_info("loaded %s = %p", fn->name, (void *) fn->fptr);
	}
    }
    if (libdata) {
	for (dp = libdata; dp->name; dp++) {
	    if (shl_findsym(&handle, dp->name, TYPE_DATA, &dp->dptr) != 0)
		msg_fatal("%s: shl_findsym failure looking up %s in %s: %m",
			  myname, dp->name, libname);
	    if (msg_verbose > 1)
		msg_info("loaded %s = %p", dp->name, dp->dptr);
	}
    }
#endif
}

#endif