1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1997-2012 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                                                                      *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22  * Glenn Fowler
23  * AT&T Research
24  */
25 
26 #include "dlllib.h"
27 
28 typedef void* (*Dll_lib_f)(const char*, void*, const char*);
29 
30 typedef struct Dll_lib_s
31 {
32 	struct Dll_lib_s*	next;
33 	Dll_lib_f		libf;
34 	char*			path;
35 	char			base[1];
36 } Dll_lib_t;
37 
38 /*
39  * split <name,base,type,opts> from name into names
40  */
41 
42 Dllnames_t*
dllnames(const char * id,const char * name,Dllnames_t * names)43 dllnames(const char* id, const char* name, Dllnames_t* names)
44 {
45 	char*	s;
46 	char*	t;
47 	char*	b;
48 	char*	e;
49 	size_t	n;
50 
51 	n = strlen(id);
52 	if (strneq(name, id, n) && (streq(name + n, "_s") || streq(name + n, "_t")))
53 		return 0;
54 	if (!names)
55 	{
56 		s = fmtbuf(sizeof(Dllnames_t*) + sizeof(names) - 1);
57 		if (n = (s - (char*)0) % sizeof(names))
58 			s += sizeof(names) - n;
59 		names = (Dllnames_t*)s;
60 	}
61 
62 	/*
63 	 * determine the base name
64 	 */
65 
66 	if ((s = strrchr(name, '/')) || (s = strrchr(name, '\\')))
67 		s++;
68 	else
69 		s = (char*)name;
70 	if (strneq(s, "lib", 3))
71 		s += 3;
72 	b = names->base = names->data;
73 	e = b + sizeof(names->data) - 1;
74 	t = s;
75 	while (b < e && *t && *t != '.' && *t != '-' && *t != ':')
76 		*b++ = *t++;
77 	*b++ = 0;
78 
79 	/*
80 	 * determine the optional type
81 	 */
82 
83 	if (t = strrchr(s, ':'))
84 	{
85 		names->name = b;
86 		while (b < e && s < t)
87 			*b++ = *s++;
88 		*b++ = 0;
89 		names->type = b;
90 		while (b < e && *++t)
91 			*b++ = *t;
92 		*b++ = 0;
93 	}
94 	else
95 	{
96 		names->name = (char*)name;
97 		names->type = 0;
98 	}
99 	*(names->path = b) = 0;
100 	names->opts = 0;
101 	names->id = (char*)id;
102 	return names;
103 }
104 
105 /*
106  * return method pointer for <id,version> in names
107  */
108 
109 void*
dll_lib(Dllnames_t * names,unsigned long version,Dllerror_f dllerrorf,void * disc)110 dll_lib(Dllnames_t* names, unsigned long version, Dllerror_f dllerrorf, void* disc)
111 {
112 	void*			dll;
113 	Dll_lib_t*		lib;
114 	Dll_lib_f		libf;
115 	ssize_t			n;
116 	char			sym[64];
117 
118 	static Dll_lib_t*	loaded;
119 
120 	if (!names)
121 		return 0;
122 
123 	/*
124 	 * check if plugin already loaded
125 	 */
126 
127 	for (lib = loaded; lib; lib = lib->next)
128 		if (streq(names->base, lib->base))
129 		{
130 			libf = lib->libf;
131 			goto init;
132 		}
133 
134 	/*
135 	 * load
136 	 */
137 
138 	if (!(dll = dllplugin(names->id, names->name, NiL, version, NiL, RTLD_LAZY, names->path, names->data + sizeof(names->data) - names->path)) && (streq(names->name, names->base) || !(dll = dllplugin(names->id, names->base, NiL, version, NiL, RTLD_LAZY, names->path, names->data + sizeof(names->data) - names->path))))
139 	{
140 		if (dllerrorf)
141 			(*dllerrorf)(NiL, disc, 2, "%s: library not found", names->name);
142 		else
143 			errorf("dll", NiL, -1, "dll_lib: %s version %lu library not found", names->name, version);
144 		return 0;
145 	}
146 
147 	/*
148 	 * init
149 	 */
150 
151 	sfsprintf(sym, sizeof(sym), "%s_lib", names->id);
152 	if (!(libf = (Dll_lib_f)dlllook(dll, sym)))
153 	{
154 		if (dllerrorf)
155 			(*dllerrorf)(NiL, disc, 2, "%s: %s: initialization function not found in library", names->path, sym);
156 		else
157 			errorf("dll", NiL, -1, "dll_lib: %s version %lu initialization function %s not found in library", names->name, version, sym);
158 		return 0;
159 	}
160 
161 	/*
162 	 * add to the loaded list
163 	 */
164 
165 	if (lib = newof(0, Dll_lib_t, 1, (n = strlen(names->base)) + strlen(names->path) + 1))
166 	{
167 		lib->libf = libf;
168 		strcpy(lib->base, names->base);
169 		strcpy(lib->path = lib->base + n + 1, names->path);
170 		lib->next = loaded;
171 		loaded = lib;
172 		errorf("dll", NiL, -1, "dll_lib: %s version %lu loaded from %s", names->name, version, lib->path);
173 	}
174  init:
175 	return (*libf)(names->path, disc, names->type);
176 }
177 
178 /*
179  * return method pointer for <id,name,version>
180  */
181 
182 void*
dllmeth(const char * id,const char * name,unsigned long version)183 dllmeth(const char* id, const char* name, unsigned long version)
184 {
185 	Dllnames_t	names;
186 
187 	return dll_lib(dllnames(id, name, &names), version, 0, 0);
188 }
189