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