libmap.c revision 115445
1/*
2 * $FreeBSD: head/libexec/rtld-elf/libmap.c 115445 2003-05-31 14:46:38Z mdodd $
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
15#ifndef _PATH_LIBMAP_CONF
16#define	_PATH_LIBMAP_CONF	"/etc/libmap.conf"
17#endif
18
19TAILQ_HEAD(lm_list, lm);
20struct lm {
21	char *f;
22	char *t;
23
24	TAILQ_ENTRY(lm)	lm_link;
25};
26
27TAILQ_HEAD(lmp_list, lmp) lmp_head = TAILQ_HEAD_INITIALIZER(lmp_head);
28struct lmp {
29	char *p;
30	struct lm_list lml;
31	TAILQ_ENTRY(lmp) lmp_link;
32};
33
34static void		lm_add		(const char *, const char *, const char *);
35static void		lm_free		(struct lm_list *);
36static char *		lml_find	(struct lm_list *, const char *);
37static struct lm_list *	lmp_find	(const char *);
38static struct lm_list *	lmp_init	(char *);
39
40#define	iseol(c)	(((c) == '#') || ((c) == '\0') || \
41			 ((c) == '\n') || ((c) == '\r'))
42
43void
44lm_init (void)
45{
46	FILE	*fp;
47	char	*cp;
48	char	*f, *t, *p, *c;
49	char	prog[MAXPATHLEN];
50	char	line[MAXPATHLEN + 2];
51
52	dbg("%s()", __func__);
53
54	TAILQ_INIT(&lmp_head);
55
56	if ((fp = fopen(_PATH_LIBMAP_CONF, "r")) == NULL)
57		return;
58
59	p = NULL;
60	while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) {
61		t = f = c = NULL;
62
63		/* Skip over leading space */
64		while (isspace(*cp)) cp++;
65
66		/* Found a comment or EOL */
67		if (iseol(*cp)) continue;
68
69		/* Found a constraint selector */
70		if (*cp == '[') {
71			cp++;
72
73			/* Skip leading space */
74			while (isspace(*cp)) cp++;
75
76			/* Found comment, EOL or end of selector */
77			if  (iseol(*cp) || *cp == ']')
78				continue;
79
80			c = cp++;
81			/* Skip to end of word */
82			while (!isspace(*cp) && !iseol(*cp) && *cp != ']')
83				cp++;
84
85			/* Skip and zero out trailing space */
86			while (isspace(*cp)) *cp++ = '\0';
87
88			/* Check if there is a closing brace */
89			if (*cp != ']') continue;
90
91			/* Terminate string if there was no trailing space */
92			*cp++ = '\0';
93
94			/*
95			 * There should be nothing except whitespace or comment
96			  from this point to the end of the line.
97			 */
98			while(isspace(*cp)) *cp++;
99			if (!iseol(*cp)) continue;
100
101			strcpy(prog, c);
102			p = prog;
103			continue;
104		}
105
106		/* Parse the 'from' candidate. */
107		f = cp++;
108		while (!isspace(*cp) && !iseol(*cp)) cp++;
109
110		/* Skip and zero out the trailing whitespace */
111		while (isspace(*cp)) *cp++ = '\0';
112
113		/* Found a comment or EOL */
114		if (iseol(*cp)) continue;
115
116		/* Parse 'to' mapping */
117		t = cp++;
118		while (!isspace(*cp) && !iseol(*cp)) cp++;
119
120		/* Skip and zero out the trailing whitespace */
121		while (isspace(*cp)) *cp++ = '\0';
122
123		/* Should be no extra tokens at this point */
124		if (!iseol(*cp)) continue;
125
126		*cp = '\0';
127		lm_add(p, f, t);
128	}
129	fclose(fp);
130	return;
131}
132
133static void
134lm_free (struct lm_list *lml)
135{
136	struct lm *lm;
137
138	dbg("%s(%p)", __func__, lml);
139
140	while (!TAILQ_EMPTY(lml)) {
141		lm = TAILQ_FIRST(lml);
142		TAILQ_REMOVE(lml, lm, lm_link);
143		free(lm->f);
144		free(lm->t);
145		free(lm);
146	}
147	return;
148}
149
150void
151lm_fini (void)
152{
153	struct lmp *lmp;
154
155	dbg("%s()", __func__);
156
157	while (!TAILQ_EMPTY(&lmp_head)) {
158		lmp = TAILQ_FIRST(&lmp_head);
159		TAILQ_REMOVE(&lmp_head, lmp, lmp_link);
160		free(lmp->p);
161		lm_free(&lmp->lml);
162		free(lmp);
163	}
164	return;
165}
166
167static void
168lm_add (const char *p, const char *f, const char *t)
169{
170	struct lm_list *lml;
171	struct lm *lm;
172
173	if (p == NULL)
174		p = "$DEFAULT$";
175
176	dbg("%s(\"%s\", \"%s\", \"%s\")", __func__, p, f, t);
177
178	if ((lml = lmp_find(p)) == NULL)
179		lml = lmp_init(xstrdup(p));
180
181	lm = xmalloc(sizeof(struct lm));
182	lm->f = xstrdup(f);
183	lm->t = xstrdup(t);
184	TAILQ_INSERT_HEAD(lml, lm, lm_link);
185}
186
187char *
188lm_find (const char *p, const char *f)
189{
190	struct lm_list *lml;
191	char *t;
192
193	dbg("%s(\"%s\", \"%s\")", __func__, p, f);
194
195	if (p != NULL && (lml = lmp_find(p)) != NULL) {
196		t = lml_find(lml, f);
197		if (t != NULL) {
198			/*
199			 * Add a global mapping if we have
200			 * a successful constrained match.
201			 */
202			lm_add(NULL, f, t);
203			return (t);
204		}
205	}
206	lml = lmp_find("$DEFAULT$");
207	if (lml != NULL)
208		return (lml_find(lml, f));
209	else
210		return (NULL);
211}
212
213static char *
214lml_find (struct lm_list *lmh, const char *f)
215{
216	struct lm *lm;
217
218	dbg("%s(%p, \"%s\")", __func__, lmh, f);
219
220	TAILQ_FOREACH(lm, lmh, lm_link)
221		if ((strncmp(f, lm->f, strlen(lm->f)) == 0) &&
222		    (strlen(f) == strlen(lm->f)))
223			return (lm->t);
224	return NULL;
225}
226
227static struct lm_list *
228lmp_find (const char *n)
229{
230	struct lmp *lmp;
231
232	dbg("%s(\"%s\")", __func__, n);
233
234	TAILQ_FOREACH(lmp, &lmp_head, lmp_link)
235		if ((strncmp(n, lmp->p, strlen(lmp->p)) == 0) &&
236		    (strlen(n) == strlen(lmp->p)))
237			return (&lmp->lml);
238	return (NULL);
239}
240
241static struct lm_list *
242lmp_init (char *n)
243{
244	struct lmp *lmp;
245
246	dbg("%s(\"%s\")", __func__, n);
247
248	lmp = xmalloc(sizeof(struct lmp));
249	lmp->p = n;
250	TAILQ_INIT(&lmp->lml);
251	TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link);
252
253	return (&lmp->lml);
254}
255