]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/rtld-elf/libmap.c
This commit was generated by cvs2svn to compensate for changes in r136647,
[FreeBSD/FreeBSD.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 void             lm_add          (const char *, const char *, const char *);
42 static void             lm_free         (struct lm_list *);
43 static char *           lml_find        (struct lm_list *, const char *);
44 static struct lm_list * lmp_find        (const char *);
45 static struct lm_list * lmp_init        (char *);
46 static const char * quickbasename       (const char *);
47
48 #define iseol(c)        (((c) == '#') || ((c) == '\0') || \
49                          ((c) == '\n') || ((c) == '\r'))
50
51 int
52 lm_init (void)
53 {
54         FILE    *fp;
55         char    *cp;
56         char    *f, *t, *p, *c;
57         char    prog[MAXPATHLEN];
58         char    line[MAXPATHLEN + 2];
59
60         dbg("%s()", __func__);
61
62         TAILQ_INIT(&lmp_head);
63
64         if ((fp = fopen(_PATH_LIBMAP_CONF, "r")) == NULL)
65                 return (1);
66
67         p = NULL;
68         while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) {
69                 t = f = c = NULL;
70
71                 /* Skip over leading space */
72                 while (isspace(*cp)) cp++;
73
74                 /* Found a comment or EOL */
75                 if (iseol(*cp)) continue;
76
77                 /* Found a constraint selector */
78                 if (*cp == '[') {
79                         cp++;
80
81                         /* Skip leading space */
82                         while (isspace(*cp)) cp++;
83
84                         /* Found comment, EOL or end of selector */
85                         if  (iseol(*cp) || *cp == ']')
86                                 continue;
87
88                         c = cp++;
89                         /* Skip to end of word */
90                         while (!isspace(*cp) && !iseol(*cp) && *cp != ']')
91                                 cp++;
92
93                         /* Skip and zero out trailing space */
94                         while (isspace(*cp)) *cp++ = '\0';
95
96                         /* Check if there is a closing brace */
97                         if (*cp != ']') continue;
98
99                         /* Terminate string if there was no trailing space */
100                         *cp++ = '\0';
101
102                         /*
103                          * There should be nothing except whitespace or comment
104                           from this point to the end of the line.
105                          */
106                         while(isspace(*cp)) cp++;
107                         if (!iseol(*cp)) continue;
108
109                         strcpy(prog, c);
110                         p = prog;
111                         continue;
112                 }
113
114                 /* Parse the 'from' candidate. */
115                 f = cp++;
116                 while (!isspace(*cp) && !iseol(*cp)) cp++;
117
118                 /* Skip and zero out the trailing whitespace */
119                 while (isspace(*cp)) *cp++ = '\0';
120
121                 /* Found a comment or EOL */
122                 if (iseol(*cp)) continue;
123
124                 /* Parse 'to' mapping */
125                 t = cp++;
126                 while (!isspace(*cp) && !iseol(*cp)) cp++;
127
128                 /* Skip and zero out the trailing whitespace */
129                 while (isspace(*cp)) *cp++ = '\0';
130
131                 /* Should be no extra tokens at this point */
132                 if (!iseol(*cp)) continue;
133
134                 *cp = '\0';
135                 lm_add(p, f, t);
136         }
137         fclose(fp);
138         return (0);
139 }
140
141 static void
142 lm_free (struct lm_list *lml)
143 {
144         struct lm *lm;
145
146         dbg("%s(%p)", __func__, lml);
147
148         while (!TAILQ_EMPTY(lml)) {
149                 lm = TAILQ_FIRST(lml);
150                 TAILQ_REMOVE(lml, lm, lm_link);
151                 free(lm->f);
152                 free(lm->t);
153                 free(lm);
154         }
155         return;
156 }
157
158 void
159 lm_fini (void)
160 {
161         struct lmp *lmp;
162
163         dbg("%s()", __func__);
164
165         while (!TAILQ_EMPTY(&lmp_head)) {
166                 lmp = TAILQ_FIRST(&lmp_head);
167                 TAILQ_REMOVE(&lmp_head, lmp, lmp_link);
168                 free(lmp->p);
169                 lm_free(&lmp->lml);
170                 free(lmp);
171         }
172         return;
173 }
174
175 static void
176 lm_add (const char *p, const char *f, const char *t)
177 {
178         struct lm_list *lml;
179         struct lm *lm;
180
181         if (p == NULL)
182                 p = "$DEFAULT$";
183
184         dbg("%s(\"%s\", \"%s\", \"%s\")", __func__, p, f, t);
185
186         if ((lml = lmp_find(p)) == NULL)
187                 lml = lmp_init(xstrdup(p));
188
189         lm = xmalloc(sizeof(struct lm));
190         lm->f = xstrdup(f);
191         lm->t = xstrdup(t);
192         TAILQ_INSERT_HEAD(lml, lm, lm_link);
193 }
194
195 char *
196 lm_find (const char *p, const char *f)
197 {
198         struct lm_list *lml;
199         char *t;
200
201         dbg("%s(\"%s\", \"%s\")", __func__, p, f);
202
203         if (p != NULL && (lml = lmp_find(p)) != NULL) {
204                 t = lml_find(lml, f);
205                 if (t != NULL) {
206                         /*
207                          * Add a global mapping if we have
208                          * a successful constrained match.
209                          */
210                         lm_add(NULL, f, t);
211                         return (t);
212                 }
213         }
214         lml = lmp_find("$DEFAULT$");
215         if (lml != NULL)
216                 return (lml_find(lml, f));
217         else
218                 return (NULL);
219 }
220
221 /* Given a libmap translation list and a library name, return the
222    replacement library, or NULL */
223 #ifdef COMPAT_32BIT
224 char *
225 lm_findn (const char *p, const char *f, const int n)
226 {
227         char pathbuf[64], *s, *t;
228
229         if (n < sizeof(pathbuf) - 1) {
230                 memcpy(pathbuf, f, n);
231                 pathbuf[n] = '\0';
232                 s = pathbuf;
233         } else {
234                 s = xmalloc(n + 1);
235                 strcpy(s, f);
236         }
237         t = lm_find(p, s);
238         if (s != pathbuf)
239                 free(s);
240         return (t);
241 }
242 #endif
243
244 static char *
245 lml_find (struct lm_list *lmh, const char *f)
246 {
247         struct lm *lm;
248
249         dbg("%s(%p, \"%s\")", __func__, lmh, f);
250
251         TAILQ_FOREACH(lm, lmh, lm_link)
252                 if (strcmp(f, lm->f) == 0)
253                         return (lm->t);
254         return NULL;
255 }
256
257 /* Given an executable name, return a pointer to the translation list or
258    NULL if no matches */
259 static struct lm_list *
260 lmp_find (const char *n)
261 {
262         struct lmp *lmp;
263
264         dbg("%s(\"%s\")", __func__, n);
265
266         TAILQ_FOREACH(lmp, &lmp_head, lmp_link)
267                 if ((lmp->type == T_EXACT && strcmp(n, lmp->p) == 0) ||
268                     (lmp->type == T_DIRECTORY && strncmp(n, lmp->p, strlen(lmp->p)) == 0) ||
269                     (lmp->type == T_BASENAME && strcmp(quickbasename(n), lmp->p) == 0))
270                         return (&lmp->lml);
271         return (NULL);
272 }
273
274 static struct lm_list *
275 lmp_init (char *n)
276 {
277         struct lmp *lmp;
278
279         dbg("%s(\"%s\")", __func__, n);
280
281         lmp = xmalloc(sizeof(struct lmp));
282         lmp->p = n;
283         if (n[strlen(n)-1] == '/')
284                 lmp->type = T_DIRECTORY;
285         else if (strchr(n,'/') == NULL)
286                 lmp->type = T_BASENAME;
287         else
288                 lmp->type = T_EXACT;
289         TAILQ_INIT(&lmp->lml);
290         TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link);
291
292         return (&lmp->lml);
293 }
294
295 /* libc basename is overkill.  Return a pointer to the character after the
296    last /, or the original string if there are no slashes. */
297 static const char *
298 quickbasename (const char *path)
299 {
300         const char *p = path;
301         for (; *path; path++)
302         {
303                 if (*path == '/')
304                         p = path+1;
305         }
306         return p;
307 }