129ade362SMatthew N. Dodd /* 229ade362SMatthew N. Dodd * $FreeBSD$ 329ade362SMatthew N. Dodd */ 429ade362SMatthew N. Dodd 529ade362SMatthew N. Dodd #include <stdio.h> 629ade362SMatthew N. Dodd #include <ctype.h> 729ade362SMatthew N. Dodd #include <string.h> 829ade362SMatthew N. Dodd #include <stdlib.h> 929ade362SMatthew N. Dodd #include <sys/queue.h> 1029ade362SMatthew N. Dodd #include <sys/param.h> 1129ade362SMatthew N. Dodd 123467e8b8SMatthew N. Dodd #include "debug.h" 133467e8b8SMatthew N. Dodd #include "rtld.h" 147227105fSMatthew N. Dodd #include "libmap.h" 153467e8b8SMatthew N. Dodd 1629ade362SMatthew N. Dodd #ifndef _PATH_LIBMAP_CONF 1729ade362SMatthew N. Dodd #define _PATH_LIBMAP_CONF "/etc/libmap.conf" 1829ade362SMatthew N. Dodd #endif 1929ade362SMatthew N. Dodd 20c905e45dSPeter Wemm #ifdef COMPAT_32BIT 21c905e45dSPeter Wemm #undef _PATH_LIBMAP_CONF 22c905e45dSPeter Wemm #define _PATH_LIBMAP_CONF "/etc/libmap32.conf" 23c905e45dSPeter Wemm #endif 24c905e45dSPeter Wemm 2529ade362SMatthew N. Dodd TAILQ_HEAD(lm_list, lm); 2629ade362SMatthew N. Dodd struct lm { 2729ade362SMatthew N. Dodd char *f; 2829ade362SMatthew N. Dodd char *t; 2929ade362SMatthew N. Dodd 3029ade362SMatthew N. Dodd TAILQ_ENTRY(lm) lm_link; 3129ade362SMatthew N. Dodd }; 3229ade362SMatthew N. Dodd 3329ade362SMatthew N. Dodd TAILQ_HEAD(lmp_list, lmp) lmp_head = TAILQ_HEAD_INITIALIZER(lmp_head); 3429ade362SMatthew N. Dodd struct lmp { 3529ade362SMatthew N. Dodd char *p; 36966efcc7SMatthew N. Dodd enum { T_EXACT=0, T_BASENAME, T_DIRECTORY } type; 3729ade362SMatthew N. Dodd struct lm_list lml; 3829ade362SMatthew N. Dodd TAILQ_ENTRY(lmp) lmp_link; 3929ade362SMatthew N. Dodd }; 4029ade362SMatthew N. Dodd 411340fc10SMatthew N. Dodd static void lm_add (const char *, const char *, const char *); 4229ade362SMatthew N. Dodd static void lm_free (struct lm_list *); 4329ade362SMatthew N. Dodd static char * lml_find (struct lm_list *, const char *); 4429ade362SMatthew N. Dodd static struct lm_list * lmp_find (const char *); 4529ade362SMatthew N. Dodd static struct lm_list * lmp_init (char *); 46966efcc7SMatthew N. Dodd static const char * quickbasename (const char *); 4729ade362SMatthew N. Dodd 48623b6bd2SMatthew N. Dodd #define iseol(c) (((c) == '#') || ((c) == '\0') || \ 49623b6bd2SMatthew N. Dodd ((c) == '\n') || ((c) == '\r')) 50623b6bd2SMatthew N. Dodd 514402996dSMatthew N. Dodd int 5229ade362SMatthew N. Dodd lm_init (void) 5329ade362SMatthew N. Dodd { 5429ade362SMatthew N. Dodd FILE *fp; 5529ade362SMatthew N. Dodd char *cp; 561340fc10SMatthew N. Dodd char *f, *t, *p, *c; 5729ade362SMatthew N. Dodd char prog[MAXPATHLEN]; 5829ade362SMatthew N. Dodd char line[MAXPATHLEN + 2]; 5929ade362SMatthew N. Dodd 601aac1ed6SMatthew N. Dodd dbg("%s()", __func__); 611aac1ed6SMatthew N. Dodd 6229ade362SMatthew N. Dodd TAILQ_INIT(&lmp_head); 6329ade362SMatthew N. Dodd 6429ade362SMatthew N. Dodd if ((fp = fopen(_PATH_LIBMAP_CONF, "r")) == NULL) 654402996dSMatthew N. Dodd return (1); 6629ade362SMatthew N. Dodd 6729ade362SMatthew N. Dodd p = NULL; 6829ade362SMatthew N. Dodd while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) { 691340fc10SMatthew N. Dodd t = f = c = NULL; 70623b6bd2SMatthew N. Dodd 7129ade362SMatthew N. Dodd /* Skip over leading space */ 72623b6bd2SMatthew N. Dodd while (isspace(*cp)) cp++; 73623b6bd2SMatthew N. Dodd 7429ade362SMatthew N. Dodd /* Found a comment or EOL */ 75486089f0SAlexander Kabaev if (iseol(*cp)) continue; 76623b6bd2SMatthew N. Dodd 77623b6bd2SMatthew N. Dodd /* Found a constraint selector */ 7829ade362SMatthew N. Dodd if (*cp == '[') { 7929ade362SMatthew N. Dodd cp++; 80623b6bd2SMatthew N. Dodd 8129ade362SMatthew N. Dodd /* Skip leading space */ 82623b6bd2SMatthew N. Dodd while (isspace(*cp)) cp++; 83623b6bd2SMatthew N. Dodd 8429ade362SMatthew N. Dodd /* Found comment, EOL or end of selector */ 85486089f0SAlexander Kabaev if (iseol(*cp) || *cp == ']') 86486089f0SAlexander Kabaev continue; 87623b6bd2SMatthew N. Dodd 881340fc10SMatthew N. Dodd c = cp++; 8929ade362SMatthew N. Dodd /* Skip to end of word */ 90486089f0SAlexander Kabaev while (!isspace(*cp) && !iseol(*cp) && *cp != ']') 91486089f0SAlexander Kabaev cp++; 92623b6bd2SMatthew N. Dodd 93623b6bd2SMatthew N. Dodd /* Skip and zero out trailing space */ 94623b6bd2SMatthew N. Dodd while (isspace(*cp)) *cp++ = '\0'; 95623b6bd2SMatthew N. Dodd 96623b6bd2SMatthew N. Dodd /* Check if there is a closing brace */ 97486089f0SAlexander Kabaev if (*cp != ']') continue; 98623b6bd2SMatthew N. Dodd 99623b6bd2SMatthew N. Dodd /* Terminate string if there was no trailing space */ 10029ade362SMatthew N. Dodd *cp++ = '\0'; 101623b6bd2SMatthew N. Dodd 102623b6bd2SMatthew N. Dodd /* 103623b6bd2SMatthew N. Dodd * There should be nothing except whitespace or comment 1046d5d786fSAlexander Kabaev from this point to the end of the line. 105623b6bd2SMatthew N. Dodd */ 1066e918a4dSMax Khon while(isspace(*cp)) cp++; 107486089f0SAlexander Kabaev if (!iseol(*cp)) continue; 108623b6bd2SMatthew N. Dodd 1091340fc10SMatthew N. Dodd strcpy(prog, c); 11029ade362SMatthew N. Dodd p = prog; 111486089f0SAlexander Kabaev continue; 112623b6bd2SMatthew N. Dodd } 113623b6bd2SMatthew N. Dodd 114623b6bd2SMatthew N. Dodd /* Parse the 'from' candidate. */ 115486089f0SAlexander Kabaev f = cp++; 116623b6bd2SMatthew N. Dodd while (!isspace(*cp) && !iseol(*cp)) cp++; 11729ade362SMatthew N. Dodd 118623b6bd2SMatthew N. Dodd /* Skip and zero out the trailing whitespace */ 119623b6bd2SMatthew N. Dodd while (isspace(*cp)) *cp++ = '\0'; 120623b6bd2SMatthew N. Dodd 121623b6bd2SMatthew N. Dodd /* Found a comment or EOL */ 122486089f0SAlexander Kabaev if (iseol(*cp)) continue; 123623b6bd2SMatthew N. Dodd 124623b6bd2SMatthew N. Dodd /* Parse 'to' mapping */ 125486089f0SAlexander Kabaev t = cp++; 126623b6bd2SMatthew N. Dodd while (!isspace(*cp) && !iseol(*cp)) cp++; 127623b6bd2SMatthew N. Dodd 128486089f0SAlexander Kabaev /* Skip and zero out the trailing whitespace */ 129486089f0SAlexander Kabaev while (isspace(*cp)) *cp++ = '\0'; 130486089f0SAlexander Kabaev 131486089f0SAlexander Kabaev /* Should be no extra tokens at this point */ 132486089f0SAlexander Kabaev if (!iseol(*cp)) continue; 133486089f0SAlexander Kabaev 134486089f0SAlexander Kabaev *cp = '\0'; 1351340fc10SMatthew N. Dodd lm_add(p, f, t); 13629ade362SMatthew N. Dodd } 137486089f0SAlexander Kabaev fclose(fp); 1384402996dSMatthew N. Dodd return (0); 13929ade362SMatthew N. Dodd } 14029ade362SMatthew N. Dodd 14129ade362SMatthew N. Dodd static void 14229ade362SMatthew N. Dodd lm_free (struct lm_list *lml) 14329ade362SMatthew N. Dodd { 14429ade362SMatthew N. Dodd struct lm *lm; 14529ade362SMatthew N. Dodd 1461aac1ed6SMatthew N. Dodd dbg("%s(%p)", __func__, lml); 1471aac1ed6SMatthew N. Dodd 14829ade362SMatthew N. Dodd while (!TAILQ_EMPTY(lml)) { 14929ade362SMatthew N. Dodd lm = TAILQ_FIRST(lml); 15029ade362SMatthew N. Dodd TAILQ_REMOVE(lml, lm, lm_link); 15129ade362SMatthew N. Dodd free(lm->f); 15229ade362SMatthew N. Dodd free(lm->t); 15329ade362SMatthew N. Dodd free(lm); 15429ade362SMatthew N. Dodd } 15529ade362SMatthew N. Dodd return; 15629ade362SMatthew N. Dodd } 15729ade362SMatthew N. Dodd 15829ade362SMatthew N. Dodd void 15929ade362SMatthew N. Dodd lm_fini (void) 16029ade362SMatthew N. Dodd { 16129ade362SMatthew N. Dodd struct lmp *lmp; 16229ade362SMatthew N. Dodd 1631aac1ed6SMatthew N. Dodd dbg("%s()", __func__); 1641aac1ed6SMatthew N. Dodd 16529ade362SMatthew N. Dodd while (!TAILQ_EMPTY(&lmp_head)) { 16629ade362SMatthew N. Dodd lmp = TAILQ_FIRST(&lmp_head); 16729ade362SMatthew N. Dodd TAILQ_REMOVE(&lmp_head, lmp, lmp_link); 16829ade362SMatthew N. Dodd free(lmp->p); 16929ade362SMatthew N. Dodd lm_free(&lmp->lml); 17029ade362SMatthew N. Dodd free(lmp); 17129ade362SMatthew N. Dodd } 17229ade362SMatthew N. Dodd return; 17329ade362SMatthew N. Dodd } 17429ade362SMatthew N. Dodd 17529ade362SMatthew N. Dodd static void 1761340fc10SMatthew N. Dodd lm_add (const char *p, const char *f, const char *t) 17729ade362SMatthew N. Dodd { 17829ade362SMatthew N. Dodd struct lm_list *lml; 17929ade362SMatthew N. Dodd struct lm *lm; 18029ade362SMatthew N. Dodd 18129ade362SMatthew N. Dodd if (p == NULL) 18229ade362SMatthew N. Dodd p = "$DEFAULT$"; 18329ade362SMatthew N. Dodd 1841aac1ed6SMatthew N. Dodd dbg("%s(\"%s\", \"%s\", \"%s\")", __func__, p, f, t); 1851aac1ed6SMatthew N. Dodd 18629ade362SMatthew N. Dodd if ((lml = lmp_find(p)) == NULL) 1873467e8b8SMatthew N. Dodd lml = lmp_init(xstrdup(p)); 18829ade362SMatthew N. Dodd 1893467e8b8SMatthew N. Dodd lm = xmalloc(sizeof(struct lm)); 1901340fc10SMatthew N. Dodd lm->f = xstrdup(f); 1911340fc10SMatthew N. Dodd lm->t = xstrdup(t); 19229ade362SMatthew N. Dodd TAILQ_INSERT_HEAD(lml, lm, lm_link); 19329ade362SMatthew N. Dodd } 19429ade362SMatthew N. Dodd 19529ade362SMatthew N. Dodd char * 19629ade362SMatthew N. Dodd lm_find (const char *p, const char *f) 19729ade362SMatthew N. Dodd { 19829ade362SMatthew N. Dodd struct lm_list *lml; 19929ade362SMatthew N. Dodd char *t; 20029ade362SMatthew N. Dodd 2011aac1ed6SMatthew N. Dodd dbg("%s(\"%s\", \"%s\")", __func__, p, f); 2021aac1ed6SMatthew N. Dodd 20329ade362SMatthew N. Dodd if (p != NULL && (lml = lmp_find(p)) != NULL) { 20429ade362SMatthew N. Dodd t = lml_find(lml, f); 2053467e8b8SMatthew N. Dodd if (t != NULL) { 2063467e8b8SMatthew N. Dodd /* 2073467e8b8SMatthew N. Dodd * Add a global mapping if we have 2083467e8b8SMatthew N. Dodd * a successful constrained match. 2093467e8b8SMatthew N. Dodd */ 2101340fc10SMatthew N. Dodd lm_add(NULL, f, t); 21129ade362SMatthew N. Dodd return (t); 21229ade362SMatthew N. Dodd } 2133467e8b8SMatthew N. Dodd } 21429ade362SMatthew N. Dodd lml = lmp_find("$DEFAULT$"); 21529ade362SMatthew N. Dodd if (lml != NULL) 21629ade362SMatthew N. Dodd return (lml_find(lml, f)); 21729ade362SMatthew N. Dodd else 21829ade362SMatthew N. Dodd return (NULL); 21929ade362SMatthew N. Dodd } 22029ade362SMatthew N. Dodd 221966efcc7SMatthew N. Dodd /* Given a libmap translation list and a library name, return the 222966efcc7SMatthew N. Dodd replacement library, or NULL */ 223c905e45dSPeter Wemm #ifdef COMPAT_32BIT 224c905e45dSPeter Wemm char * 225c905e45dSPeter Wemm lm_findn (const char *p, const char *f, const int n) 226c905e45dSPeter Wemm { 227c905e45dSPeter Wemm char pathbuf[64], *s, *t; 228c905e45dSPeter Wemm 229c905e45dSPeter Wemm if (n < sizeof(pathbuf) - 1) { 230c905e45dSPeter Wemm memcpy(pathbuf, f, n); 231c905e45dSPeter Wemm pathbuf[n] = '\0'; 232c905e45dSPeter Wemm s = pathbuf; 233c905e45dSPeter Wemm } else { 234c905e45dSPeter Wemm s = xmalloc(n + 1); 235c905e45dSPeter Wemm strcpy(s, f); 236c905e45dSPeter Wemm } 237c905e45dSPeter Wemm t = lm_find(p, s); 238c905e45dSPeter Wemm if (s != pathbuf) 239c905e45dSPeter Wemm free(s); 240c905e45dSPeter Wemm return (t); 241c905e45dSPeter Wemm } 242c905e45dSPeter Wemm #endif 243c905e45dSPeter Wemm 24429ade362SMatthew N. Dodd static char * 24529ade362SMatthew N. Dodd lml_find (struct lm_list *lmh, const char *f) 24629ade362SMatthew N. Dodd { 24729ade362SMatthew N. Dodd struct lm *lm; 24829ade362SMatthew N. Dodd 2491aac1ed6SMatthew N. Dodd dbg("%s(%p, \"%s\")", __func__, lmh, f); 2501aac1ed6SMatthew N. Dodd 25129ade362SMatthew N. Dodd TAILQ_FOREACH(lm, lmh, lm_link) 252c905e45dSPeter Wemm if (strcmp(f, lm->f) == 0) 25329ade362SMatthew N. Dodd return (lm->t); 25429ade362SMatthew N. Dodd return NULL; 25529ade362SMatthew N. Dodd } 25629ade362SMatthew N. Dodd 257966efcc7SMatthew N. Dodd /* Given an executable name, return a pointer to the translation list or 258966efcc7SMatthew N. Dodd NULL if no matches */ 25929ade362SMatthew N. Dodd static struct lm_list * 26029ade362SMatthew N. Dodd lmp_find (const char *n) 26129ade362SMatthew N. Dodd { 26229ade362SMatthew N. Dodd struct lmp *lmp; 26329ade362SMatthew N. Dodd 2641aac1ed6SMatthew N. Dodd dbg("%s(\"%s\")", __func__, n); 2651aac1ed6SMatthew N. Dodd 26629ade362SMatthew N. Dodd TAILQ_FOREACH(lmp, &lmp_head, lmp_link) 267966efcc7SMatthew N. Dodd if ((lmp->type == T_EXACT && strcmp(n, lmp->p) == 0) || 268966efcc7SMatthew N. Dodd (lmp->type == T_DIRECTORY && strncmp(n, lmp->p, strlen(lmp->p)) == 0) || 269966efcc7SMatthew N. Dodd (lmp->type == T_BASENAME && strcmp(quickbasename(n), lmp->p) == 0)) 27029ade362SMatthew N. Dodd return (&lmp->lml); 27129ade362SMatthew N. Dodd return (NULL); 27229ade362SMatthew N. Dodd } 27329ade362SMatthew N. Dodd 27429ade362SMatthew N. Dodd static struct lm_list * 27529ade362SMatthew N. Dodd lmp_init (char *n) 27629ade362SMatthew N. Dodd { 27729ade362SMatthew N. Dodd struct lmp *lmp; 27829ade362SMatthew N. Dodd 2791aac1ed6SMatthew N. Dodd dbg("%s(\"%s\")", __func__, n); 2801aac1ed6SMatthew N. Dodd 2813467e8b8SMatthew N. Dodd lmp = xmalloc(sizeof(struct lmp)); 28229ade362SMatthew N. Dodd lmp->p = n; 283966efcc7SMatthew N. Dodd if (n[strlen(n)-1] == '/') 284966efcc7SMatthew N. Dodd lmp->type = T_DIRECTORY; 285966efcc7SMatthew N. Dodd else if (strchr(n,'/') == NULL) 286966efcc7SMatthew N. Dodd lmp->type = T_BASENAME; 287966efcc7SMatthew N. Dodd else 288966efcc7SMatthew N. Dodd lmp->type = T_EXACT; 28929ade362SMatthew N. Dodd TAILQ_INIT(&lmp->lml); 29029ade362SMatthew N. Dodd TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link); 29129ade362SMatthew N. Dodd 29229ade362SMatthew N. Dodd return (&lmp->lml); 29329ade362SMatthew N. Dodd } 294966efcc7SMatthew N. Dodd 295966efcc7SMatthew N. Dodd /* libc basename is overkill. Return a pointer to the character after the 296966efcc7SMatthew N. Dodd last /, or the original string if there are no slashes. */ 297966efcc7SMatthew N. Dodd static const char * 298966efcc7SMatthew N. Dodd quickbasename (const char *path) 299966efcc7SMatthew N. Dodd { 300966efcc7SMatthew N. Dodd const char *p = path; 301966efcc7SMatthew N. Dodd for (; *path; path++) 302966efcc7SMatthew N. Dodd { 303966efcc7SMatthew N. Dodd if (*path == '/') 304966efcc7SMatthew N. Dodd p = path+1; 305966efcc7SMatthew N. Dodd } 306966efcc7SMatthew N. Dodd return p; 307966efcc7SMatthew N. Dodd } 308