1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1997-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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 #ifndef _GNU_SOURCE
27 #define _GNU_SOURCE	1
28 #endif
29 #ifndef __EXTENSIONS__
30 #define __EXTENSIONS__	1
31 #endif
32 
33 #include <ast.h>
34 #include <dlldefs.h>
35 
36 #if _hdr_rld_interface
37 #include <rld_interface.h>
38 #endif
39 
40 /*
41  * return a handle for the next layer down,
42  * i.e., the next layer that has symbols covered
43  * by the main prog and dll's loaded so far
44  *
45  * intentionally light on external lib calls
46  * so this routine can be used early in process
47  * startup
48  */
49 
50 #ifdef	_DLL_RLD_SYM
51 
52 #define DEBUG		1
53 
54 #if DEBUG
55 
56 typedef ssize_t (*Write_f)(int, const void*, size_t);
57 
58 #endif
59 
60 #undef	dllnext
61 
62 void*
63 _dll_next(int flags, _DLL_RLD_SYM_TYPE* here)
64 {
65 	register char*	vp;
66 	register void*	lp;
67 	register int	found = 0;
68 	char*		s;
69 	char*		b;
70 	char*		e;
71 	char		dummy[256];
72 #if DEBUG
73 	Write_f		wr = 0;
74 	Write_f		xr;
75 	char		buf[1024];
76 #endif
77 
78 #if DEBUG
79 	if (getenv("DLL_DEBUG") && (vp = (char*)_rld_new_interface(_RLD_FIRST_PATHNAME)))
80 	{
81 		do
82 		{
83 			if (strcmp(vp, "MAIN") && (lp = dlopen(vp, flags)))
84 			{
85 				if (xr = (Write_f)dlsym(lp, "write"))
86 					wr = xr;
87 			}
88 		} while (vp = (char*)_rld_new_interface(_RLD_NEXT_PATHNAME));
89 	}
90 #endif
91 	if (vp = (char*)_rld_new_interface(_RLD_FIRST_PATHNAME))
92 	{
93 		do
94 		{
95 			if (lp = dlopen(strcmp(vp, "MAIN") ? vp : (char*)0, flags))
96 			{
97 				if (found)
98 				{
99 					b = e = 0;
100 					s = vp;
101 					for (;;)
102 					{
103 						switch (*s++)
104 						{
105 						case 0:
106 							break;
107 						case '/':
108 							b = s;
109 							e = 0;
110 							continue;
111 						case '.':
112 							if (!e)
113 								e = s - 1;
114 							continue;
115 						default:
116 							continue;
117 						}
118 						break;
119 					}
120 					if (b && e)
121 					{
122 						s = dummy;
123 						*s++ = '_';
124 						*s++ = '_';
125 						while (b < e)
126 							*s++ = *b++;
127 						b = "_dummy";
128 						while (*s++ = *b++);
129 						if (dlsym(lp, dummy))
130 						{
131 							dlclose(lp);
132 							lp = 0;
133 						}
134 					}
135 					if (lp)
136 					{
137 #if DEBUG
138 						if (wr)
139 							(*wr)(2, buf, sfsprintf(buf, sizeof(buf), "dll: next %s\n", vp));
140 #endif
141 						return lp;
142 					}
143 #if DEBUG
144 					else if (wr)
145 						(*wr)(2, buf, sfsprintf(buf, sizeof(buf), "dll: skip %s\n", vp));
146 #endif
147 				}
148 				else if ((_DLL_RLD_SYM_TYPE*)dlsym(lp, _DLL_RLD_SYM_STR) == here)
149 				{
150 #if DEBUG
151 					if (wr)
152 						(*wr)(2, buf, sfsprintf(buf, sizeof(buf), "dll: this %s\n", vp));
153 #endif
154 					found = 1;
155 				}
156 			}
157 		} while (vp = (char*)_rld_new_interface(_RLD_NEXT_PATHNAME));
158 	}
159 	return dllnext(flags);
160 }
161 
162 #endif
163 
164 #ifndef RTLD_NEXT
165 #if _dll_DYNAMIC
166 
167 #include <link.h>
168 
169 extern struct link_dynamic	_DYNAMIC;
170 
171 #endif
172 #endif
173 
174 void*
175 dllnext(int flags)
176 {
177 	register void*			dll;
178 #ifndef RTLD_NEXT
179 #if _dll_DYNAMIC
180 	register struct link_map*	map;
181 	register char*			s;
182 	register char*			b;
183 #endif
184 	register char*			ver;
185 	char*				path;
186 
187 	static char			next[] = { _DLL_NEXT_PATH };
188 #endif
189 
190 #ifdef RTLD_NEXT
191 	dll = RTLD_NEXT;
192 #else
193 	path = next;
194 #if _dll_DYNAMIC
195 	for (map = _DYNAMIC.ld_un.ld_1->ld_loaded; map; map = map->lm_next)
196 	{
197 		b = 0;
198 		s = map->lm_name;
199 		while (*s)
200 			if (*s++ == '/')
201 				b = s;
202 		if (b && b[0] == 'l' && b[1] == 'i' && b[2] == 'b' && b[3] == 'c' && b[4] == '.')
203 		{
204 			path = map->lm_name;
205 			break;
206 		}
207 	}
208 #endif
209 	ver = path + strlen(path);
210 	while (!(dll = dlopen(path, flags)))
211 	{
212 		do
213 		{
214 			if (ver <= path)
215 				return 0;
216 		} while (*--ver != '.');
217 		if (*(ver + 1) <= '0' || *(ver + 1) >= '9')
218 			return 0;
219 		*ver = 0;
220 	}
221 #endif
222 	return dll;
223 }
224