15 #ifndef _PATH_LIBMAP_CONF
16 #define _PATH_LIBMAP_CONF "/etc/libmap.conf"
20 #undef _PATH_LIBMAP_CONF
21 #define _PATH_LIBMAP_CONF "/etc/libmap32.conf"
24 TAILQ_HEAD(lm_list, lm);
29 TAILQ_ENTRY(lm) lm_link;
32 TAILQ_HEAD(lmp_list, lmp) lmp_head = TAILQ_HEAD_INITIALIZER(lmp_head);
35 enum { T_EXACT=0, T_BASENAME, T_DIRECTORY } type;
37 TAILQ_ENTRY(lmp) lmp_link;
42 static void lmc_parse (FILE *);
43 static void lm_add (const char *, const char *, const char *);
44 static void lm_free (struct lm_list *);
45 static char * lml_find (struct lm_list *, const char *);
46 static struct lm_list * lmp_find (const char *);
47 static struct lm_list * lmp_init (char *);
48 static const char * quickbasename (const char *);
49 static int readstrfn (void * cookie, char *buf, int len);
50 static int closestrfn (void * cookie);
52 #define iseol(c) (((c) == '#') || ((c) == '\0') || \
53 ((c) == '\n') || ((c) == '\r'))
56 * Do not use ctype.h macros, which rely on working TLS. It is
57 * too early to have thread-local variables functional.
59 #define rtld_isspace(c) ((c) == ' ' || (c) == '\t')
62 lm_init (char *libmap_override)
66 dbg("%s(\"%s\")", __func__, libmap_override);
68 TAILQ_INIT(&lmp_head);
70 fp = fopen(_PATH_LIBMAP_CONF, "r");
76 if (libmap_override) {
78 /* do some character replacement to make $LIBMAP look like a
79 text file, then "open" it with funopen */
80 libmap_override = xstrdup(libmap_override);
82 for (p = libmap_override; *p; p++) {
90 fp = funopen(libmap_override, readstrfn, NULL, NULL, closestrfn);
97 return (lm_count == 0);
105 char prog[MAXPATHLEN];
106 char line[MAXPATHLEN + 2];
108 dbg("%s(%p)", __func__, fp);
111 while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) {
114 /* Skip over leading space */
115 while (rtld_isspace(*cp)) cp++;
117 /* Found a comment or EOL */
118 if (iseol(*cp)) continue;
120 /* Found a constraint selector */
124 /* Skip leading space */
125 while (rtld_isspace(*cp)) cp++;
127 /* Found comment, EOL or end of selector */
128 if (iseol(*cp) || *cp == ']')
132 /* Skip to end of word */
133 while (!rtld_isspace(*cp) && !iseol(*cp) && *cp != ']')
136 /* Skip and zero out trailing space */
137 while (rtld_isspace(*cp)) *cp++ = '\0';
139 /* Check if there is a closing brace */
140 if (*cp != ']') continue;
142 /* Terminate string if there was no trailing space */
146 * There should be nothing except whitespace or comment
147 from this point to the end of the line.
149 while(rtld_isspace(*cp)) cp++;
150 if (!iseol(*cp)) continue;
157 /* Parse the 'from' candidate. */
159 while (!rtld_isspace(*cp) && !iseol(*cp)) cp++;
161 /* Skip and zero out the trailing whitespace */
162 while (rtld_isspace(*cp)) *cp++ = '\0';
164 /* Found a comment or EOL */
165 if (iseol(*cp)) continue;
167 /* Parse 'to' mapping */
169 while (!rtld_isspace(*cp) && !iseol(*cp)) cp++;
171 /* Skip and zero out the trailing whitespace */
172 while (rtld_isspace(*cp)) *cp++ = '\0';
174 /* Should be no extra tokens at this point */
175 if (!iseol(*cp)) continue;
183 lm_free (struct lm_list *lml)
187 dbg("%s(%p)", __func__, lml);
189 while (!TAILQ_EMPTY(lml)) {
190 lm = TAILQ_FIRST(lml);
191 TAILQ_REMOVE(lml, lm, lm_link);
204 dbg("%s()", __func__);
206 while (!TAILQ_EMPTY(&lmp_head)) {
207 lmp = TAILQ_FIRST(&lmp_head);
208 TAILQ_REMOVE(&lmp_head, lmp, lmp_link);
217 lm_add (const char *p, const char *f, const char *t)
225 dbg("%s(\"%s\", \"%s\", \"%s\")", __func__, p, f, t);
227 if ((lml = lmp_find(p)) == NULL)
228 lml = lmp_init(xstrdup(p));
230 lm = xmalloc(sizeof(struct lm));
233 TAILQ_INSERT_HEAD(lml, lm, lm_link);
238 lm_find (const char *p, const char *f)
243 dbg("%s(\"%s\", \"%s\")", __func__, p, f);
245 if (p != NULL && (lml = lmp_find(p)) != NULL) {
246 t = lml_find(lml, f);
249 * Add a global mapping if we have
250 * a successful constrained match.
256 lml = lmp_find("$DEFAULT$");
258 return (lml_find(lml, f));
263 /* Given a libmap translation list and a library name, return the
264 replacement library, or NULL */
267 lm_findn (const char *p, const char *f, const int n)
269 char pathbuf[64], *s, *t;
271 if (n < sizeof(pathbuf) - 1)
285 lml_find (struct lm_list *lmh, const char *f)
289 dbg("%s(%p, \"%s\")", __func__, lmh, f);
291 TAILQ_FOREACH(lm, lmh, lm_link)
292 if (strcmp(f, lm->f) == 0)
297 /* Given an executable name, return a pointer to the translation list or
298 NULL if no matches */
299 static struct lm_list *
300 lmp_find (const char *n)
304 dbg("%s(\"%s\")", __func__, n);
306 TAILQ_FOREACH(lmp, &lmp_head, lmp_link)
307 if ((lmp->type == T_EXACT && strcmp(n, lmp->p) == 0) ||
308 (lmp->type == T_DIRECTORY && strncmp(n, lmp->p, strlen(lmp->p)) == 0) ||
309 (lmp->type == T_BASENAME && strcmp(quickbasename(n), lmp->p) == 0))
314 static struct lm_list *
319 dbg("%s(\"%s\")", __func__, n);
321 lmp = xmalloc(sizeof(struct lmp));
323 if (n[strlen(n)-1] == '/')
324 lmp->type = T_DIRECTORY;
325 else if (strchr(n,'/') == NULL)
326 lmp->type = T_BASENAME;
329 TAILQ_INIT(&lmp->lml);
330 TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link);
335 /* libc basename is overkill. Return a pointer to the character after the
336 last /, or the original string if there are no slashes. */
338 quickbasename (const char *path)
340 const char *p = path;
341 for (; *path; path++) {
349 readstrfn(void * cookie, char *buf, int len)
351 static char *current;
358 left = strlen(cookie);
360 while (*current && left && len) {
370 closestrfn(void * cookie)