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 41*5b08cb04SMatthew N. Dodd static int lm_count; 42*5b08cb04SMatthew N. Dodd 43*5b08cb04SMatthew N. Dodd static void lmc_parse (FILE *); 441340fc10SMatthew N. Dodd static void lm_add (const char *, const char *, const char *); 4529ade362SMatthew N. Dodd static void lm_free (struct lm_list *); 4629ade362SMatthew N. Dodd static char * lml_find (struct lm_list *, const char *); 4729ade362SMatthew N. Dodd static struct lm_list * lmp_find (const char *); 4829ade362SMatthew N. Dodd static struct lm_list * lmp_init (char *); 49966efcc7SMatthew N. Dodd static const char * quickbasename (const char *); 50*5b08cb04SMatthew N. Dodd static int readstrfn (void * cookie, char *buf, int len); 51*5b08cb04SMatthew N. Dodd static int closestrfn (void * cookie); 5229ade362SMatthew N. Dodd 53623b6bd2SMatthew N. Dodd #define iseol(c) (((c) == '#') || ((c) == '\0') || \ 54623b6bd2SMatthew N. Dodd ((c) == '\n') || ((c) == '\r')) 55623b6bd2SMatthew N. Dodd 564402996dSMatthew N. Dodd int 57*5b08cb04SMatthew N. Dodd lm_init (char *libmap_override) 5829ade362SMatthew N. Dodd { 5929ade362SMatthew N. Dodd FILE *fp; 6029ade362SMatthew N. Dodd 61*5b08cb04SMatthew N. Dodd dbg("%s(\"%s\")", __func__, libmap_override); 621aac1ed6SMatthew N. Dodd 6329ade362SMatthew N. Dodd TAILQ_INIT(&lmp_head); 6429ade362SMatthew N. Dodd 65*5b08cb04SMatthew N. Dodd fp = fopen(_PATH_LIBMAP_CONF, "r"); 66*5b08cb04SMatthew N. Dodd if (fp) { 67*5b08cb04SMatthew N. Dodd lmc_parse(fp); 68*5b08cb04SMatthew N. Dodd fclose(fp); 69*5b08cb04SMatthew N. Dodd } 70*5b08cb04SMatthew N. Dodd 71*5b08cb04SMatthew N. Dodd if (libmap_override) { 72*5b08cb04SMatthew N. Dodd char *p; 73*5b08cb04SMatthew N. Dodd /* do some character replacement to make $LIBMAP look like a 74*5b08cb04SMatthew N. Dodd text file, then "open" it with funopen */ 75*5b08cb04SMatthew N. Dodd libmap_override = xstrdup(libmap_override); 76*5b08cb04SMatthew N. Dodd 77*5b08cb04SMatthew N. Dodd for (p = libmap_override; *p; p++) { 78*5b08cb04SMatthew N. Dodd switch (*p) { 79*5b08cb04SMatthew N. Dodd case '=': 80*5b08cb04SMatthew N. Dodd *p = ' '; break; 81*5b08cb04SMatthew N. Dodd case ',': 82*5b08cb04SMatthew N. Dodd *p = '\n'; break; 83*5b08cb04SMatthew N. Dodd } 84*5b08cb04SMatthew N. Dodd } 85*5b08cb04SMatthew N. Dodd fp = funopen(libmap_override, readstrfn, NULL, NULL, closestrfn); 86*5b08cb04SMatthew N. Dodd if (fp) { 87*5b08cb04SMatthew N. Dodd lmc_parse(fp); 88*5b08cb04SMatthew N. Dodd fclose(fp); 89*5b08cb04SMatthew N. Dodd } 90*5b08cb04SMatthew N. Dodd } 91*5b08cb04SMatthew N. Dodd 92*5b08cb04SMatthew N. Dodd return (lm_count == 0); 93*5b08cb04SMatthew N. Dodd } 94*5b08cb04SMatthew N. Dodd 95*5b08cb04SMatthew N. Dodd static void 96*5b08cb04SMatthew N. Dodd lmc_parse (FILE *fp) 97*5b08cb04SMatthew N. Dodd { 98*5b08cb04SMatthew N. Dodd char *cp; 99*5b08cb04SMatthew N. Dodd char *f, *t, *c, *p; 100*5b08cb04SMatthew N. Dodd char prog[MAXPATHLEN]; 101*5b08cb04SMatthew N. Dodd char line[MAXPATHLEN + 2]; 102*5b08cb04SMatthew N. Dodd 103*5b08cb04SMatthew N. Dodd dbg("%s(%p)", __func__, fp); 10429ade362SMatthew N. Dodd 10529ade362SMatthew N. Dodd p = NULL; 10629ade362SMatthew N. Dodd while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) { 1071340fc10SMatthew N. Dodd t = f = c = NULL; 108623b6bd2SMatthew N. Dodd 10929ade362SMatthew N. Dodd /* Skip over leading space */ 110623b6bd2SMatthew N. Dodd while (isspace(*cp)) cp++; 111623b6bd2SMatthew N. Dodd 11229ade362SMatthew N. Dodd /* Found a comment or EOL */ 113486089f0SAlexander Kabaev if (iseol(*cp)) continue; 114623b6bd2SMatthew N. Dodd 115623b6bd2SMatthew N. Dodd /* Found a constraint selector */ 11629ade362SMatthew N. Dodd if (*cp == '[') { 11729ade362SMatthew N. Dodd cp++; 118623b6bd2SMatthew N. Dodd 11929ade362SMatthew N. Dodd /* Skip leading space */ 120623b6bd2SMatthew N. Dodd while (isspace(*cp)) cp++; 121623b6bd2SMatthew N. Dodd 12229ade362SMatthew N. Dodd /* Found comment, EOL or end of selector */ 123486089f0SAlexander Kabaev if (iseol(*cp) || *cp == ']') 124486089f0SAlexander Kabaev continue; 125623b6bd2SMatthew N. Dodd 1261340fc10SMatthew N. Dodd c = cp++; 12729ade362SMatthew N. Dodd /* Skip to end of word */ 128486089f0SAlexander Kabaev while (!isspace(*cp) && !iseol(*cp) && *cp != ']') 129486089f0SAlexander Kabaev cp++; 130623b6bd2SMatthew N. Dodd 131623b6bd2SMatthew N. Dodd /* Skip and zero out trailing space */ 132623b6bd2SMatthew N. Dodd while (isspace(*cp)) *cp++ = '\0'; 133623b6bd2SMatthew N. Dodd 134623b6bd2SMatthew N. Dodd /* Check if there is a closing brace */ 135486089f0SAlexander Kabaev if (*cp != ']') continue; 136623b6bd2SMatthew N. Dodd 137623b6bd2SMatthew N. Dodd /* Terminate string if there was no trailing space */ 13829ade362SMatthew N. Dodd *cp++ = '\0'; 139623b6bd2SMatthew N. Dodd 140623b6bd2SMatthew N. Dodd /* 141623b6bd2SMatthew N. Dodd * There should be nothing except whitespace or comment 1426d5d786fSAlexander Kabaev from this point to the end of the line. 143623b6bd2SMatthew N. Dodd */ 1446e918a4dSMax Khon while(isspace(*cp)) cp++; 145486089f0SAlexander Kabaev if (!iseol(*cp)) continue; 146623b6bd2SMatthew N. Dodd 1471340fc10SMatthew N. Dodd strcpy(prog, c); 14829ade362SMatthew N. Dodd p = prog; 149486089f0SAlexander Kabaev continue; 150623b6bd2SMatthew N. Dodd } 151623b6bd2SMatthew N. Dodd 152623b6bd2SMatthew N. Dodd /* Parse the 'from' candidate. */ 153486089f0SAlexander Kabaev f = cp++; 154623b6bd2SMatthew N. Dodd while (!isspace(*cp) && !iseol(*cp)) cp++; 15529ade362SMatthew N. Dodd 156623b6bd2SMatthew N. Dodd /* Skip and zero out the trailing whitespace */ 157623b6bd2SMatthew N. Dodd while (isspace(*cp)) *cp++ = '\0'; 158623b6bd2SMatthew N. Dodd 159623b6bd2SMatthew N. Dodd /* Found a comment or EOL */ 160486089f0SAlexander Kabaev if (iseol(*cp)) continue; 161623b6bd2SMatthew N. Dodd 162623b6bd2SMatthew N. Dodd /* Parse 'to' mapping */ 163486089f0SAlexander Kabaev t = cp++; 164623b6bd2SMatthew N. Dodd while (!isspace(*cp) && !iseol(*cp)) cp++; 165623b6bd2SMatthew N. Dodd 166486089f0SAlexander Kabaev /* Skip and zero out the trailing whitespace */ 167486089f0SAlexander Kabaev while (isspace(*cp)) *cp++ = '\0'; 168486089f0SAlexander Kabaev 169486089f0SAlexander Kabaev /* Should be no extra tokens at this point */ 170486089f0SAlexander Kabaev if (!iseol(*cp)) continue; 171486089f0SAlexander Kabaev 172486089f0SAlexander Kabaev *cp = '\0'; 1731340fc10SMatthew N. Dodd lm_add(p, f, t); 17429ade362SMatthew N. Dodd } 17529ade362SMatthew N. Dodd } 17629ade362SMatthew N. Dodd 17729ade362SMatthew N. Dodd static void 17829ade362SMatthew N. Dodd lm_free (struct lm_list *lml) 17929ade362SMatthew N. Dodd { 18029ade362SMatthew N. Dodd struct lm *lm; 18129ade362SMatthew N. Dodd 1821aac1ed6SMatthew N. Dodd dbg("%s(%p)", __func__, lml); 1831aac1ed6SMatthew N. Dodd 18429ade362SMatthew N. Dodd while (!TAILQ_EMPTY(lml)) { 18529ade362SMatthew N. Dodd lm = TAILQ_FIRST(lml); 18629ade362SMatthew N. Dodd TAILQ_REMOVE(lml, lm, lm_link); 18729ade362SMatthew N. Dodd free(lm->f); 18829ade362SMatthew N. Dodd free(lm->t); 18929ade362SMatthew N. Dodd free(lm); 19029ade362SMatthew N. Dodd } 19129ade362SMatthew N. Dodd return; 19229ade362SMatthew N. Dodd } 19329ade362SMatthew N. Dodd 19429ade362SMatthew N. Dodd void 19529ade362SMatthew N. Dodd lm_fini (void) 19629ade362SMatthew N. Dodd { 19729ade362SMatthew N. Dodd struct lmp *lmp; 19829ade362SMatthew N. Dodd 1991aac1ed6SMatthew N. Dodd dbg("%s()", __func__); 2001aac1ed6SMatthew N. Dodd 20129ade362SMatthew N. Dodd while (!TAILQ_EMPTY(&lmp_head)) { 20229ade362SMatthew N. Dodd lmp = TAILQ_FIRST(&lmp_head); 20329ade362SMatthew N. Dodd TAILQ_REMOVE(&lmp_head, lmp, lmp_link); 20429ade362SMatthew N. Dodd free(lmp->p); 20529ade362SMatthew N. Dodd lm_free(&lmp->lml); 20629ade362SMatthew N. Dodd free(lmp); 20729ade362SMatthew N. Dodd } 20829ade362SMatthew N. Dodd return; 20929ade362SMatthew N. Dodd } 21029ade362SMatthew N. Dodd 21129ade362SMatthew N. Dodd static void 2121340fc10SMatthew N. Dodd lm_add (const char *p, const char *f, const char *t) 21329ade362SMatthew N. Dodd { 21429ade362SMatthew N. Dodd struct lm_list *lml; 21529ade362SMatthew N. Dodd struct lm *lm; 21629ade362SMatthew N. Dodd 21729ade362SMatthew N. Dodd if (p == NULL) 21829ade362SMatthew N. Dodd p = "$DEFAULT$"; 21929ade362SMatthew N. Dodd 2201aac1ed6SMatthew N. Dodd dbg("%s(\"%s\", \"%s\", \"%s\")", __func__, p, f, t); 2211aac1ed6SMatthew N. Dodd 22229ade362SMatthew N. Dodd if ((lml = lmp_find(p)) == NULL) 2233467e8b8SMatthew N. Dodd lml = lmp_init(xstrdup(p)); 22429ade362SMatthew N. Dodd 2253467e8b8SMatthew N. Dodd lm = xmalloc(sizeof(struct lm)); 2261340fc10SMatthew N. Dodd lm->f = xstrdup(f); 2271340fc10SMatthew N. Dodd lm->t = xstrdup(t); 22829ade362SMatthew N. Dodd TAILQ_INSERT_HEAD(lml, lm, lm_link); 229*5b08cb04SMatthew N. Dodd lm_count++; 23029ade362SMatthew N. Dodd } 23129ade362SMatthew N. Dodd 23229ade362SMatthew N. Dodd char * 23329ade362SMatthew N. Dodd lm_find (const char *p, const char *f) 23429ade362SMatthew N. Dodd { 23529ade362SMatthew N. Dodd struct lm_list *lml; 23629ade362SMatthew N. Dodd char *t; 23729ade362SMatthew N. Dodd 2381aac1ed6SMatthew N. Dodd dbg("%s(\"%s\", \"%s\")", __func__, p, f); 2391aac1ed6SMatthew N. Dodd 24029ade362SMatthew N. Dodd if (p != NULL && (lml = lmp_find(p)) != NULL) { 24129ade362SMatthew N. Dodd t = lml_find(lml, f); 2423467e8b8SMatthew N. Dodd if (t != NULL) { 2433467e8b8SMatthew N. Dodd /* 2443467e8b8SMatthew N. Dodd * Add a global mapping if we have 2453467e8b8SMatthew N. Dodd * a successful constrained match. 2463467e8b8SMatthew N. Dodd */ 2471340fc10SMatthew N. Dodd lm_add(NULL, f, t); 24829ade362SMatthew N. Dodd return (t); 24929ade362SMatthew N. Dodd } 2503467e8b8SMatthew N. Dodd } 25129ade362SMatthew N. Dodd lml = lmp_find("$DEFAULT$"); 25229ade362SMatthew N. Dodd if (lml != NULL) 25329ade362SMatthew N. Dodd return (lml_find(lml, f)); 25429ade362SMatthew N. Dodd else 25529ade362SMatthew N. Dodd return (NULL); 25629ade362SMatthew N. Dodd } 25729ade362SMatthew N. Dodd 258966efcc7SMatthew N. Dodd /* Given a libmap translation list and a library name, return the 259966efcc7SMatthew N. Dodd replacement library, or NULL */ 260c905e45dSPeter Wemm #ifdef COMPAT_32BIT 261c905e45dSPeter Wemm char * 262c905e45dSPeter Wemm lm_findn (const char *p, const char *f, const int n) 263c905e45dSPeter Wemm { 264c905e45dSPeter Wemm char pathbuf[64], *s, *t; 265c905e45dSPeter Wemm 266c905e45dSPeter Wemm if (n < sizeof(pathbuf) - 1) { 267c905e45dSPeter Wemm memcpy(pathbuf, f, n); 268c905e45dSPeter Wemm pathbuf[n] = '\0'; 269c905e45dSPeter Wemm s = pathbuf; 270c905e45dSPeter Wemm } else { 271c905e45dSPeter Wemm s = xmalloc(n + 1); 272c905e45dSPeter Wemm strcpy(s, f); 273c905e45dSPeter Wemm } 274c905e45dSPeter Wemm t = lm_find(p, s); 275c905e45dSPeter Wemm if (s != pathbuf) 276c905e45dSPeter Wemm free(s); 277c905e45dSPeter Wemm return (t); 278c905e45dSPeter Wemm } 279c905e45dSPeter Wemm #endif 280c905e45dSPeter Wemm 28129ade362SMatthew N. Dodd static char * 28229ade362SMatthew N. Dodd lml_find (struct lm_list *lmh, const char *f) 28329ade362SMatthew N. Dodd { 28429ade362SMatthew N. Dodd struct lm *lm; 28529ade362SMatthew N. Dodd 2861aac1ed6SMatthew N. Dodd dbg("%s(%p, \"%s\")", __func__, lmh, f); 2871aac1ed6SMatthew N. Dodd 28829ade362SMatthew N. Dodd TAILQ_FOREACH(lm, lmh, lm_link) 289c905e45dSPeter Wemm if (strcmp(f, lm->f) == 0) 29029ade362SMatthew N. Dodd return (lm->t); 291d33da23fSMatthew N. Dodd return (NULL); 29229ade362SMatthew N. Dodd } 29329ade362SMatthew N. Dodd 294966efcc7SMatthew N. Dodd /* Given an executable name, return a pointer to the translation list or 295966efcc7SMatthew N. Dodd NULL if no matches */ 29629ade362SMatthew N. Dodd static struct lm_list * 29729ade362SMatthew N. Dodd lmp_find (const char *n) 29829ade362SMatthew N. Dodd { 29929ade362SMatthew N. Dodd struct lmp *lmp; 30029ade362SMatthew N. Dodd 3011aac1ed6SMatthew N. Dodd dbg("%s(\"%s\")", __func__, n); 3021aac1ed6SMatthew N. Dodd 30329ade362SMatthew N. Dodd TAILQ_FOREACH(lmp, &lmp_head, lmp_link) 304966efcc7SMatthew N. Dodd if ((lmp->type == T_EXACT && strcmp(n, lmp->p) == 0) || 305966efcc7SMatthew N. Dodd (lmp->type == T_DIRECTORY && strncmp(n, lmp->p, strlen(lmp->p)) == 0) || 306966efcc7SMatthew N. Dodd (lmp->type == T_BASENAME && strcmp(quickbasename(n), lmp->p) == 0)) 30729ade362SMatthew N. Dodd return (&lmp->lml); 30829ade362SMatthew N. Dodd return (NULL); 30929ade362SMatthew N. Dodd } 31029ade362SMatthew N. Dodd 31129ade362SMatthew N. Dodd static struct lm_list * 31229ade362SMatthew N. Dodd lmp_init (char *n) 31329ade362SMatthew N. Dodd { 31429ade362SMatthew N. Dodd struct lmp *lmp; 31529ade362SMatthew N. Dodd 3161aac1ed6SMatthew N. Dodd dbg("%s(\"%s\")", __func__, n); 3171aac1ed6SMatthew N. Dodd 3183467e8b8SMatthew N. Dodd lmp = xmalloc(sizeof(struct lmp)); 31929ade362SMatthew N. Dodd lmp->p = n; 320966efcc7SMatthew N. Dodd if (n[strlen(n)-1] == '/') 321966efcc7SMatthew N. Dodd lmp->type = T_DIRECTORY; 322966efcc7SMatthew N. Dodd else if (strchr(n,'/') == NULL) 323966efcc7SMatthew N. Dodd lmp->type = T_BASENAME; 324966efcc7SMatthew N. Dodd else 325966efcc7SMatthew N. Dodd lmp->type = T_EXACT; 32629ade362SMatthew N. Dodd TAILQ_INIT(&lmp->lml); 32729ade362SMatthew N. Dodd TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link); 32829ade362SMatthew N. Dodd 32929ade362SMatthew N. Dodd return (&lmp->lml); 33029ade362SMatthew N. Dodd } 331966efcc7SMatthew N. Dodd 332966efcc7SMatthew N. Dodd /* libc basename is overkill. Return a pointer to the character after the 333966efcc7SMatthew N. Dodd last /, or the original string if there are no slashes. */ 334966efcc7SMatthew N. Dodd static const char * 335966efcc7SMatthew N. Dodd quickbasename (const char *path) 336966efcc7SMatthew N. Dodd { 337966efcc7SMatthew N. Dodd const char *p = path; 338d33da23fSMatthew N. Dodd for (; *path; path++) { 339966efcc7SMatthew N. Dodd if (*path == '/') 340966efcc7SMatthew N. Dodd p = path+1; 341966efcc7SMatthew N. Dodd } 342d33da23fSMatthew N. Dodd return (p); 343966efcc7SMatthew N. Dodd } 344*5b08cb04SMatthew N. Dodd 345*5b08cb04SMatthew N. Dodd static int 346*5b08cb04SMatthew N. Dodd readstrfn(void * cookie, char *buf, int len) 347*5b08cb04SMatthew N. Dodd { 348*5b08cb04SMatthew N. Dodd static char *current; 349*5b08cb04SMatthew N. Dodd static int left; 350*5b08cb04SMatthew N. Dodd int copied; 351*5b08cb04SMatthew N. Dodd 352*5b08cb04SMatthew N. Dodd copied = 0; 353*5b08cb04SMatthew N. Dodd if (!current) { 354*5b08cb04SMatthew N. Dodd current = cookie; 355*5b08cb04SMatthew N. Dodd left = strlen(cookie); 356*5b08cb04SMatthew N. Dodd } 357*5b08cb04SMatthew N. Dodd while (*current && left && len) { 358*5b08cb04SMatthew N. Dodd *buf++ = *current++; 359*5b08cb04SMatthew N. Dodd left--; 360*5b08cb04SMatthew N. Dodd len--; 361*5b08cb04SMatthew N. Dodd copied++; 362*5b08cb04SMatthew N. Dodd } 363*5b08cb04SMatthew N. Dodd return copied; 364*5b08cb04SMatthew N. Dodd } 365*5b08cb04SMatthew N. Dodd 366*5b08cb04SMatthew N. Dodd static int 367*5b08cb04SMatthew N. Dodd closestrfn(void * cookie) 368*5b08cb04SMatthew N. Dodd { 369*5b08cb04SMatthew N. Dodd free(cookie); 370*5b08cb04SMatthew N. Dodd return 0; 371*5b08cb04SMatthew N. Dodd } 372