]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - libexec/rtld-elf/libmap.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / libexec / rtld-elf / libmap.c
1 /*
2  * $FreeBSD$
3  */
4
5 #include <stdio.h>
6 #include <ctype.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <sys/queue.h>
10 #include <sys/param.h>
11
12 #include "debug.h"
13 #include "rtld.h"
14 #include "libmap.h"
15
16 #ifndef _PATH_LIBMAP_CONF
17 #define _PATH_LIBMAP_CONF       "/etc/libmap.conf"
18 #endif
19
20 #ifdef COMPAT_32BIT
21 #undef _PATH_LIBMAP_CONF
22 #define _PATH_LIBMAP_CONF       "/etc/libmap32.conf"
23 #endif
24
25 TAILQ_HEAD(lm_list, lm);
26 struct lm {
27         char *f;
28         char *t;
29
30         TAILQ_ENTRY(lm) lm_link;
31 };
32
33 TAILQ_HEAD(lmp_list, lmp) lmp_head = TAILQ_HEAD_INITIALIZER(lmp_head);
34 struct lmp {
35         char *p;
36         enum { T_EXACT=0, T_BASENAME, T_DIRECTORY } type;
37         struct lm_list lml;
38         TAILQ_ENTRY(lmp) lmp_link;
39 };
40
41 static int      lm_count;
42
43 static void             lmc_parse       (FILE *);
44 static void             lm_add          (const char *, const char *, const char *);
45 static void             lm_free         (struct lm_list *);
46 static char *           lml_find        (struct lm_list *, const char *);
47 static struct lm_list * lmp_find        (const char *);
48 static struct lm_list * lmp_init        (char *);
49 static const char * quickbasename       (const char *);
50 static int      readstrfn       (void * cookie, char *buf, int len);
51 static int      closestrfn      (void * cookie);
52
53 #define iseol(c)        (((c) == '#') || ((c) == '\0') || \
54                          ((c) == '\n') || ((c) == '\r'))
55
56 int
57 lm_init (char *libmap_override)
58 {
59         FILE    *fp;
60
61         dbg("%s(\"%s\")", __func__, libmap_override);
62
63         TAILQ_INIT(&lmp_head);
64
65         fp = fopen(_PATH_LIBMAP_CONF, "r");
66         if (fp) {
67                 lmc_parse(fp);
68                 fclose(fp);
69         }
70
71         if (libmap_override) {
72                 char    *p;
73                 /* do some character replacement to make $LIBMAP look like a
74                    text file, then "open" it with funopen */
75                 libmap_override = xstrdup(libmap_override);
76
77                 for (p = libmap_override; *p; p++) {
78                         switch (*p) {
79                                 case '=':
80                                         *p = ' '; break;
81                                 case ',':
82                                         *p = '\n'; break;
83                         }
84                 }
85                 fp = funopen(libmap_override, readstrfn, NULL, NULL, closestrfn);
86                 if (fp) {
87                         lmc_parse(fp);
88                         fclose(fp);
89                 }
90         }
91
92         return (lm_count == 0);
93 }
94
95 static void
96 lmc_parse (FILE *fp)
97 {
98         char    *cp;
99         char    *f, *t, *c, *p;
100         char    prog[MAXPATHLEN];
101         char    line[MAXPATHLEN + 2];
102
103         dbg("%s(%p)", __func__, fp);
104         
105         p = NULL;
106         while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) {
107                 t = f = c = NULL;
108
109                 /* Skip over leading space */
110                 while (isspace(*cp)) cp++;
111
112                 /* Found a comment or EOL */
113                 if (iseol(*cp)) continue;
114
115                 /* Found a constraint selector */
116                 if (*cp == '[') {
117                         cp++;
118
119                         /* Skip leading space */
120                         while (isspace(*cp)) cp++;
121
122                         /* Found comment, EOL or end of selector */
123                         if  (iseol(*cp) || *cp == ']')
124                                 continue;
125
126                         c = cp++;
127                         /* Skip to end of word */
128                         while (!isspace(*cp) && !iseol(*cp) && *cp != ']')
129                                 cp++;
130
131                         /* Skip and zero out trailing space */
132                         while (isspace(*cp)) *cp++ = '\0';
133
134                         /* Check if there is a closing brace */
135                         if (*cp != ']') continue;
136
137                         /* Terminate string if there was no trailing space */
138                         *cp++ = '\0';
139
140                         /*
141                          * There should be nothing except whitespace or comment
142                           from this point to the end of the line.
143                          */
144                         while(isspace(*cp)) cp++;
145                         if (!iseol(*cp)) continue;
146
147                         strcpy(prog, c);
148                         p = prog;
149                         continue;
150                 }
151
152                 /* Parse the 'from' candidate. */
153                 f = cp++;
154                 while (!isspace(*cp) && !iseol(*cp)) cp++;
155
156                 /* Skip and zero out the trailing whitespace */
157                 while (isspace(*cp)) *cp++ = '\0';
158
159                 /* Found a comment or EOL */
160                 if (iseol(*cp)) continue;
161
162                 /* Parse 'to' mapping */
163                 t = cp++;
164                 while (!isspace(*cp) && !iseol(*cp)) cp++;
165
166                 /* Skip and zero out the trailing whitespace */
167                 while (isspace(*cp)) *cp++ = '\0';
168
169                 /* Should be no extra tokens at this point */
170                 if (!iseol(*cp)) continue;
171
172                 *cp = '\0';
173                 lm_add(p, f, t);
174         }
175 }
176
177 static void
178 lm_free (struct lm_list *lml)
179 {
180         struct lm *lm;
181
182         dbg("%s(%p)", __func__, lml);
183
184         while (!TAILQ_EMPTY(lml)) {
185                 lm = TAILQ_FIRST(lml);
186                 TAILQ_REMOVE(lml, lm, lm_link);
187                 free(lm->f);
188                 free(lm->t);
189                 free(lm);
190         }
191         return;
192 }
193
194 void
195 lm_fini (void)
196 {
197         struct lmp *lmp;
198
199         dbg("%s()", __func__);
200
201         while (!TAILQ_EMPTY(&lmp_head)) {
202                 lmp = TAILQ_FIRST(&lmp_head);
203                 TAILQ_REMOVE(&lmp_head, lmp, lmp_link);
204                 free(lmp->p);
205                 lm_free(&lmp->lml);
206                 free(lmp);
207         }
208         return;
209 }
210
211 static void
212 lm_add (const char *p, const char *f, const char *t)
213 {
214         struct lm_list *lml;
215         struct lm *lm;
216
217         if (p == NULL)
218                 p = "$DEFAULT$";
219
220         dbg("%s(\"%s\", \"%s\", \"%s\")", __func__, p, f, t);
221
222         if ((lml = lmp_find(p)) == NULL)
223                 lml = lmp_init(xstrdup(p));
224
225         lm = xmalloc(sizeof(struct lm));
226         lm->f = xstrdup(f);
227         lm->t = xstrdup(t);
228         TAILQ_INSERT_HEAD(lml, lm, lm_link);
229         lm_count++;
230 }
231
232 char *
233 lm_find (const char *p, const char *f)
234 {
235         struct lm_list *lml;
236         char *t;
237
238         dbg("%s(\"%s\", \"%s\")", __func__, p, f);
239
240         if (p != NULL && (lml = lmp_find(p)) != NULL) {
241                 t = lml_find(lml, f);
242                 if (t != NULL) {
243                         /*
244                          * Add a global mapping if we have
245                          * a successful constrained match.
246                          */
247                         lm_add(NULL, f, t);
248                         return (t);
249                 }
250         }
251         lml = lmp_find("$DEFAULT$");
252         if (lml != NULL)
253                 return (lml_find(lml, f));
254         else
255                 return (NULL);
256 }
257
258 /* Given a libmap translation list and a library name, return the
259    replacement library, or NULL */
260 #ifdef COMPAT_32BIT
261 char *
262 lm_findn (const char *p, const char *f, const int n)
263 {
264         char pathbuf[64], *s, *t;
265
266         if (n < sizeof(pathbuf) - 1)
267                 s = pathbuf;
268         else
269                 s = xmalloc(n + 1);
270         memcpy(s, f, n);
271         s[n] = '\0';
272         t = lm_find(p, s);
273         if (s != pathbuf)
274                 free(s);
275         return (t);
276 }
277 #endif
278
279 static char *
280 lml_find (struct lm_list *lmh, const char *f)
281 {
282         struct lm *lm;
283
284         dbg("%s(%p, \"%s\")", __func__, lmh, f);
285
286         TAILQ_FOREACH(lm, lmh, lm_link)
287                 if (strcmp(f, lm->f) == 0)
288                         return (lm->t);
289         return (NULL);
290 }
291
292 /* Given an executable name, return a pointer to the translation list or
293    NULL if no matches */
294 static struct lm_list *
295 lmp_find (const char *n)
296 {
297         struct lmp *lmp;
298
299         dbg("%s(\"%s\")", __func__, n);
300
301         TAILQ_FOREACH(lmp, &lmp_head, lmp_link)
302                 if ((lmp->type == T_EXACT && strcmp(n, lmp->p) == 0) ||
303                     (lmp->type == T_DIRECTORY && strncmp(n, lmp->p, strlen(lmp->p)) == 0) ||
304                     (lmp->type == T_BASENAME && strcmp(quickbasename(n), lmp->p) == 0))
305                         return (&lmp->lml);
306         return (NULL);
307 }
308
309 static struct lm_list *
310 lmp_init (char *n)
311 {
312         struct lmp *lmp;
313
314         dbg("%s(\"%s\")", __func__, n);
315
316         lmp = xmalloc(sizeof(struct lmp));
317         lmp->p = n;
318         if (n[strlen(n)-1] == '/')
319                 lmp->type = T_DIRECTORY;
320         else if (strchr(n,'/') == NULL)
321                 lmp->type = T_BASENAME;
322         else
323                 lmp->type = T_EXACT;
324         TAILQ_INIT(&lmp->lml);
325         TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link);
326
327         return (&lmp->lml);
328 }
329
330 /* libc basename is overkill.  Return a pointer to the character after the
331    last /, or the original string if there are no slashes. */
332 static const char *
333 quickbasename (const char *path)
334 {
335         const char *p = path;
336         for (; *path; path++) {
337                 if (*path == '/')
338                         p = path+1;
339         }
340         return (p);
341 }
342
343 static int
344 readstrfn(void * cookie, char *buf, int len)
345 {
346         static char     *current;
347         static int      left;
348         int     copied;
349         
350         copied = 0;
351         if (!current) {
352                 current = cookie;
353                 left = strlen(cookie);
354         }
355         while (*current && left && len) {
356                 *buf++ = *current++;
357                 left--;
358                 len--;
359                 copied++;
360         }
361         return copied;
362 }
363
364 static int
365 closestrfn(void * cookie)
366 {
367         free(cookie);
368         return 0;
369 }