xref: /freebsd-12.1/libexec/rtld-elf/libmap.c (revision ac9953bf)
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)) goto next;
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 == ']') goto next;
73 
74 			p = cp;
75 			/* Skip to end of word */
76 			while (!isspace(*cp) && !iseol(*cp) && *cp != ']') cp++;
77 
78 			/* Skip and zero out trailing space */
79 			while (isspace(*cp)) *cp++ = '\0';
80 
81 			/* Check if there is a closing brace */
82 			if (*cp != ']') goto next;
83 
84 			/* Terminate string if there was no trailing space */
85 			*cp++ = '\0';
86 
87 			/*
88 			 * There should be nothing except whitespace or comment
89 			 * from this point to the end of the line.
90 			 */
91 			while(isspace(*cp++));
92 			if (*cp != '\0' && *cp != '#') goto next;
93 
94 			if (strlen(p) > 0) {
95 				bzero(prog, MAXPATHLEN);
96 				strncpy(prog, p, strlen(p));
97 				p = prog;
98 			}
99 			goto next;
100 		}
101 
102 		/* Parse the 'from' candidate. */
103 		f = cp;
104 		while (!isspace(*cp) && !iseol(*cp)) cp++;
105 		*cp++ = '\0';
106 
107 		/* Skip and zero out the trailing whitespace */
108 		while (isspace(*cp)) *cp++ = '\0';
109 
110 		/* Found a comment or EOL */
111 		if (iseol(*cp)) goto next;
112 
113 		/* Parse 'to' mapping */
114 		t = cp;
115 		while (!isspace(*cp) && !iseol(*cp)) cp++;
116 		*cp++ = '\0';
117 
118 		if ((strlen(f) > 0) && (strlen(t) > 0))
119 			lm_add(p, strdup(f), strdup(t));
120 next:
121 		bzero(line, sizeof(line));
122 	}
123 	(void)fclose(fp);
124 	return;
125 }
126 
127 static void
128 lm_free (struct lm_list *lml)
129 {
130 	struct lm *lm;
131 
132 	while (!TAILQ_EMPTY(lml)) {
133 		lm = TAILQ_FIRST(lml);
134 		TAILQ_REMOVE(lml, lm, lm_link);
135 		free(lm->f);
136 		free(lm->t);
137 		free(lm);
138 	}
139 	return;
140 }
141 
142 void
143 lm_fini (void)
144 {
145 	struct lmp *lmp;
146 
147 	while (!TAILQ_EMPTY(&lmp_head)) {
148 		lmp = TAILQ_FIRST(&lmp_head);
149 		TAILQ_REMOVE(&lmp_head, lmp, lmp_link);
150 		free(lmp->p);
151 		lm_free(&lmp->lml);
152 		free(lmp);
153 	}
154 	return;
155 }
156 
157 static void
158 lm_add (char *p, char *f, char *t)
159 {
160 	struct lm_list *lml;
161 	struct lm *lm;
162 
163 	if (p == NULL)
164 		p = "$DEFAULT$";
165 
166 #if 0
167 	printf("%s(\"%s\", \"%s\", \"%s\")\n", __func__, p, f, t);
168 #endif
169 
170 	if ((lml = lmp_find(p)) == NULL)
171 		lml = lmp_init(strdup(p));
172 
173 	lm = malloc(sizeof(struct lm));
174 	lm->f = f;
175 	lm->t = t;
176 	TAILQ_INSERT_HEAD(lml, lm, lm_link);
177 }
178 
179 char *
180 lm_find (const char *p, const char *f)
181 {
182 	struct lm_list *lml;
183 	char *t;
184 
185 	if (p != NULL && (lml = lmp_find(p)) != NULL) {
186 		t = lml_find(lml, f);
187 		if (t != NULL)
188 			return (t);
189 	}
190 	lml = lmp_find("$DEFAULT$");
191 	if (lml != NULL)
192 		return (lml_find(lml, f));
193 	else
194 		return (NULL);
195 }
196 
197 static char *
198 lml_find (struct lm_list *lmh, const char *f)
199 {
200 	struct lm *lm;
201 
202 	TAILQ_FOREACH(lm, lmh, lm_link)
203 		if ((strncmp(f, lm->f, strlen(lm->f)) == 0) &&
204 		    (strlen(f) == strlen(lm->f)))
205 			return (lm->t);
206 	return NULL;
207 }
208 
209 static struct lm_list *
210 lmp_find (const char *n)
211 {
212 	struct lmp *lmp;
213 
214 	TAILQ_FOREACH(lmp, &lmp_head, lmp_link)
215 		if ((strncmp(n, lmp->p, strlen(lmp->p)) == 0) &&
216 		    (strlen(n) == strlen(lmp->p)))
217 			return (&lmp->lml);
218 	return (NULL);
219 }
220 
221 static struct lm_list *
222 lmp_init (char *n)
223 {
224 	struct lmp *lmp;
225 
226 	lmp = malloc(sizeof(struct lmp));
227 	lmp->p = n;
228 	TAILQ_INIT(&lmp->lml);
229 	TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link);
230 
231 	return (&lmp->lml);
232 }
233