129ade362SMatthew N. Dodd /* 229ade362SMatthew N. Dodd * $FreeBSD$ 329ade362SMatthew N. Dodd */ 429ade362SMatthew N. Dodd 529ade362SMatthew N. Dodd #include <stdio.h> 629ade362SMatthew N. Dodd #include <string.h> 729ade362SMatthew N. Dodd #include <stdlib.h> 829ade362SMatthew N. Dodd #include <sys/queue.h> 929ade362SMatthew N. Dodd #include <sys/param.h> 1029ade362SMatthew N. Dodd 113467e8b8SMatthew N. Dodd #include "debug.h" 123467e8b8SMatthew N. Dodd #include "rtld.h" 137227105fSMatthew N. Dodd #include "libmap.h" 143467e8b8SMatthew N. Dodd 1529ade362SMatthew N. Dodd #ifndef _PATH_LIBMAP_CONF 1629ade362SMatthew N. Dodd #define _PATH_LIBMAP_CONF "/etc/libmap.conf" 1729ade362SMatthew N. Dodd #endif 1829ade362SMatthew N. Dodd 19c905e45dSPeter Wemm #ifdef COMPAT_32BIT 20c905e45dSPeter Wemm #undef _PATH_LIBMAP_CONF 21c905e45dSPeter Wemm #define _PATH_LIBMAP_CONF "/etc/libmap32.conf" 22c905e45dSPeter Wemm #endif 23c905e45dSPeter Wemm 2429ade362SMatthew N. Dodd TAILQ_HEAD(lm_list, lm); 2529ade362SMatthew N. Dodd struct lm { 2629ade362SMatthew N. Dodd char *f; 2729ade362SMatthew N. Dodd char *t; 2829ade362SMatthew N. Dodd 2929ade362SMatthew N. Dodd TAILQ_ENTRY(lm) lm_link; 3029ade362SMatthew N. Dodd }; 3129ade362SMatthew N. Dodd 3229ade362SMatthew N. Dodd TAILQ_HEAD(lmp_list, lmp) lmp_head = TAILQ_HEAD_INITIALIZER(lmp_head); 3329ade362SMatthew N. Dodd struct lmp { 3429ade362SMatthew N. Dodd char *p; 35966efcc7SMatthew N. Dodd enum { T_EXACT=0, T_BASENAME, T_DIRECTORY } type; 3629ade362SMatthew N. Dodd struct lm_list lml; 3729ade362SMatthew N. Dodd TAILQ_ENTRY(lmp) lmp_link; 3829ade362SMatthew N. Dodd }; 3929ade362SMatthew N. Dodd 405b08cb04SMatthew N. Dodd static int lm_count; 415b08cb04SMatthew N. Dodd 425b08cb04SMatthew N. Dodd static void lmc_parse (FILE *); 431340fc10SMatthew N. Dodd static void lm_add (const char *, const char *, const char *); 4429ade362SMatthew N. Dodd static void lm_free (struct lm_list *); 4529ade362SMatthew N. Dodd static char * lml_find (struct lm_list *, const char *); 4629ade362SMatthew N. Dodd static struct lm_list * lmp_find (const char *); 4729ade362SMatthew N. Dodd static struct lm_list * lmp_init (char *); 48966efcc7SMatthew N. Dodd static const char * quickbasename (const char *); 495b08cb04SMatthew N. Dodd static int readstrfn (void * cookie, char *buf, int len); 505b08cb04SMatthew N. Dodd static int closestrfn (void * cookie); 5129ade362SMatthew N. Dodd 52623b6bd2SMatthew N. Dodd #define iseol(c) (((c) == '#') || ((c) == '\0') || \ 53623b6bd2SMatthew N. Dodd ((c) == '\n') || ((c) == '\r')) 54623b6bd2SMatthew N. Dodd 55b36070f5SKonstantin Belousov /* 56b36070f5SKonstantin Belousov * Do not use ctype.h macros, which rely on working TLS. It is 57b36070f5SKonstantin Belousov * too early to have thread-local variables functional. 58b36070f5SKonstantin Belousov */ 59*44976acaSSergey Kandaurov #define rtld_isspace(c) ((c) == ' ' || (c) == '\t') 60b36070f5SKonstantin Belousov 614402996dSMatthew N. Dodd int 625b08cb04SMatthew N. Dodd lm_init (char *libmap_override) 6329ade362SMatthew N. Dodd { 6429ade362SMatthew N. Dodd FILE *fp; 6529ade362SMatthew N. Dodd 665b08cb04SMatthew N. Dodd dbg("%s(\"%s\")", __func__, libmap_override); 671aac1ed6SMatthew N. Dodd 6829ade362SMatthew N. Dodd TAILQ_INIT(&lmp_head); 6929ade362SMatthew N. Dodd 705b08cb04SMatthew N. Dodd fp = fopen(_PATH_LIBMAP_CONF, "r"); 715b08cb04SMatthew N. Dodd if (fp) { 725b08cb04SMatthew N. Dodd lmc_parse(fp); 735b08cb04SMatthew N. Dodd fclose(fp); 745b08cb04SMatthew N. Dodd } 755b08cb04SMatthew N. Dodd 765b08cb04SMatthew N. Dodd if (libmap_override) { 775b08cb04SMatthew N. Dodd char *p; 785b08cb04SMatthew N. Dodd /* do some character replacement to make $LIBMAP look like a 795b08cb04SMatthew N. Dodd text file, then "open" it with funopen */ 805b08cb04SMatthew N. Dodd libmap_override = xstrdup(libmap_override); 815b08cb04SMatthew N. Dodd 825b08cb04SMatthew N. Dodd for (p = libmap_override; *p; p++) { 835b08cb04SMatthew N. Dodd switch (*p) { 845b08cb04SMatthew N. Dodd case '=': 855b08cb04SMatthew N. Dodd *p = ' '; break; 865b08cb04SMatthew N. Dodd case ',': 875b08cb04SMatthew N. Dodd *p = '\n'; break; 885b08cb04SMatthew N. Dodd } 895b08cb04SMatthew N. Dodd } 905b08cb04SMatthew N. Dodd fp = funopen(libmap_override, readstrfn, NULL, NULL, closestrfn); 915b08cb04SMatthew N. Dodd if (fp) { 925b08cb04SMatthew N. Dodd lmc_parse(fp); 935b08cb04SMatthew N. Dodd fclose(fp); 945b08cb04SMatthew N. Dodd } 955b08cb04SMatthew N. Dodd } 965b08cb04SMatthew N. Dodd 975b08cb04SMatthew N. Dodd return (lm_count == 0); 985b08cb04SMatthew N. Dodd } 995b08cb04SMatthew N. Dodd 1005b08cb04SMatthew N. Dodd static void 1015b08cb04SMatthew N. Dodd lmc_parse (FILE *fp) 1025b08cb04SMatthew N. Dodd { 1035b08cb04SMatthew N. Dodd char *cp; 1045b08cb04SMatthew N. Dodd char *f, *t, *c, *p; 1055b08cb04SMatthew N. Dodd char prog[MAXPATHLEN]; 1065b08cb04SMatthew N. Dodd char line[MAXPATHLEN + 2]; 1075b08cb04SMatthew N. Dodd 1085b08cb04SMatthew N. Dodd dbg("%s(%p)", __func__, fp); 10929ade362SMatthew N. Dodd 11029ade362SMatthew N. Dodd p = NULL; 11129ade362SMatthew N. Dodd while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) { 1121340fc10SMatthew N. Dodd t = f = c = NULL; 113623b6bd2SMatthew N. Dodd 11429ade362SMatthew N. Dodd /* Skip over leading space */ 115*44976acaSSergey Kandaurov while (rtld_isspace(*cp)) cp++; 116623b6bd2SMatthew N. Dodd 11729ade362SMatthew N. Dodd /* Found a comment or EOL */ 118486089f0SAlexander Kabaev if (iseol(*cp)) continue; 119623b6bd2SMatthew N. Dodd 120623b6bd2SMatthew N. Dodd /* Found a constraint selector */ 12129ade362SMatthew N. Dodd if (*cp == '[') { 12229ade362SMatthew N. Dodd cp++; 123623b6bd2SMatthew N. Dodd 12429ade362SMatthew N. Dodd /* Skip leading space */ 125*44976acaSSergey Kandaurov while (rtld_isspace(*cp)) cp++; 126623b6bd2SMatthew N. Dodd 12729ade362SMatthew N. Dodd /* Found comment, EOL or end of selector */ 128486089f0SAlexander Kabaev if (iseol(*cp) || *cp == ']') 129486089f0SAlexander Kabaev continue; 130623b6bd2SMatthew N. Dodd 1311340fc10SMatthew N. Dodd c = cp++; 13229ade362SMatthew N. Dodd /* Skip to end of word */ 133*44976acaSSergey Kandaurov while (!rtld_isspace(*cp) && !iseol(*cp) && *cp != ']') 134486089f0SAlexander Kabaev cp++; 135623b6bd2SMatthew N. Dodd 136623b6bd2SMatthew N. Dodd /* Skip and zero out trailing space */ 137*44976acaSSergey Kandaurov while (rtld_isspace(*cp)) *cp++ = '\0'; 138623b6bd2SMatthew N. Dodd 139623b6bd2SMatthew N. Dodd /* Check if there is a closing brace */ 140486089f0SAlexander Kabaev if (*cp != ']') continue; 141623b6bd2SMatthew N. Dodd 142623b6bd2SMatthew N. Dodd /* Terminate string if there was no trailing space */ 14329ade362SMatthew N. Dodd *cp++ = '\0'; 144623b6bd2SMatthew N. Dodd 145623b6bd2SMatthew N. Dodd /* 146623b6bd2SMatthew N. Dodd * There should be nothing except whitespace or comment 1476d5d786fSAlexander Kabaev from this point to the end of the line. 148623b6bd2SMatthew N. Dodd */ 149*44976acaSSergey Kandaurov while(rtld_isspace(*cp)) cp++; 150486089f0SAlexander Kabaev if (!iseol(*cp)) continue; 151623b6bd2SMatthew N. Dodd 1521340fc10SMatthew N. Dodd strcpy(prog, c); 15329ade362SMatthew N. Dodd p = prog; 154486089f0SAlexander Kabaev continue; 155623b6bd2SMatthew N. Dodd } 156623b6bd2SMatthew N. Dodd 157623b6bd2SMatthew N. Dodd /* Parse the 'from' candidate. */ 158486089f0SAlexander Kabaev f = cp++; 159*44976acaSSergey Kandaurov while (!rtld_isspace(*cp) && !iseol(*cp)) cp++; 16029ade362SMatthew N. Dodd 161623b6bd2SMatthew N. Dodd /* Skip and zero out the trailing whitespace */ 162*44976acaSSergey Kandaurov while (rtld_isspace(*cp)) *cp++ = '\0'; 163623b6bd2SMatthew N. Dodd 164623b6bd2SMatthew N. Dodd /* Found a comment or EOL */ 165486089f0SAlexander Kabaev if (iseol(*cp)) continue; 166623b6bd2SMatthew N. Dodd 167623b6bd2SMatthew N. Dodd /* Parse 'to' mapping */ 168486089f0SAlexander Kabaev t = cp++; 169*44976acaSSergey Kandaurov while (!rtld_isspace(*cp) && !iseol(*cp)) cp++; 170623b6bd2SMatthew N. Dodd 171486089f0SAlexander Kabaev /* Skip and zero out the trailing whitespace */ 172*44976acaSSergey Kandaurov while (rtld_isspace(*cp)) *cp++ = '\0'; 173486089f0SAlexander Kabaev 174486089f0SAlexander Kabaev /* Should be no extra tokens at this point */ 175486089f0SAlexander Kabaev if (!iseol(*cp)) continue; 176486089f0SAlexander Kabaev 177486089f0SAlexander Kabaev *cp = '\0'; 1781340fc10SMatthew N. Dodd lm_add(p, f, t); 17929ade362SMatthew N. Dodd } 18029ade362SMatthew N. Dodd } 18129ade362SMatthew N. Dodd 18229ade362SMatthew N. Dodd static void 18329ade362SMatthew N. Dodd lm_free (struct lm_list *lml) 18429ade362SMatthew N. Dodd { 18529ade362SMatthew N. Dodd struct lm *lm; 18629ade362SMatthew N. Dodd 1871aac1ed6SMatthew N. Dodd dbg("%s(%p)", __func__, lml); 1881aac1ed6SMatthew N. Dodd 18929ade362SMatthew N. Dodd while (!TAILQ_EMPTY(lml)) { 19029ade362SMatthew N. Dodd lm = TAILQ_FIRST(lml); 19129ade362SMatthew N. Dodd TAILQ_REMOVE(lml, lm, lm_link); 19229ade362SMatthew N. Dodd free(lm->f); 19329ade362SMatthew N. Dodd free(lm->t); 19429ade362SMatthew N. Dodd free(lm); 19529ade362SMatthew N. Dodd } 19629ade362SMatthew N. Dodd return; 19729ade362SMatthew N. Dodd } 19829ade362SMatthew N. Dodd 19929ade362SMatthew N. Dodd void 20029ade362SMatthew N. Dodd lm_fini (void) 20129ade362SMatthew N. Dodd { 20229ade362SMatthew N. Dodd struct lmp *lmp; 20329ade362SMatthew N. Dodd 2041aac1ed6SMatthew N. Dodd dbg("%s()", __func__); 2051aac1ed6SMatthew N. Dodd 20629ade362SMatthew N. Dodd while (!TAILQ_EMPTY(&lmp_head)) { 20729ade362SMatthew N. Dodd lmp = TAILQ_FIRST(&lmp_head); 20829ade362SMatthew N. Dodd TAILQ_REMOVE(&lmp_head, lmp, lmp_link); 20929ade362SMatthew N. Dodd free(lmp->p); 21029ade362SMatthew N. Dodd lm_free(&lmp->lml); 21129ade362SMatthew N. Dodd free(lmp); 21229ade362SMatthew N. Dodd } 21329ade362SMatthew N. Dodd return; 21429ade362SMatthew N. Dodd } 21529ade362SMatthew N. Dodd 21629ade362SMatthew N. Dodd static void 2171340fc10SMatthew N. Dodd lm_add (const char *p, const char *f, const char *t) 21829ade362SMatthew N. Dodd { 21929ade362SMatthew N. Dodd struct lm_list *lml; 22029ade362SMatthew N. Dodd struct lm *lm; 22129ade362SMatthew N. Dodd 22229ade362SMatthew N. Dodd if (p == NULL) 22329ade362SMatthew N. Dodd p = "$DEFAULT$"; 22429ade362SMatthew N. Dodd 2251aac1ed6SMatthew N. Dodd dbg("%s(\"%s\", \"%s\", \"%s\")", __func__, p, f, t); 2261aac1ed6SMatthew N. Dodd 22729ade362SMatthew N. Dodd if ((lml = lmp_find(p)) == NULL) 2283467e8b8SMatthew N. Dodd lml = lmp_init(xstrdup(p)); 22929ade362SMatthew N. Dodd 2303467e8b8SMatthew N. Dodd lm = xmalloc(sizeof(struct lm)); 2311340fc10SMatthew N. Dodd lm->f = xstrdup(f); 2321340fc10SMatthew N. Dodd lm->t = xstrdup(t); 23329ade362SMatthew N. Dodd TAILQ_INSERT_HEAD(lml, lm, lm_link); 2345b08cb04SMatthew N. Dodd lm_count++; 23529ade362SMatthew N. Dodd } 23629ade362SMatthew N. Dodd 23729ade362SMatthew N. Dodd char * 23829ade362SMatthew N. Dodd lm_find (const char *p, const char *f) 23929ade362SMatthew N. Dodd { 24029ade362SMatthew N. Dodd struct lm_list *lml; 24129ade362SMatthew N. Dodd char *t; 24229ade362SMatthew N. Dodd 2431aac1ed6SMatthew N. Dodd dbg("%s(\"%s\", \"%s\")", __func__, p, f); 2441aac1ed6SMatthew N. Dodd 24529ade362SMatthew N. Dodd if (p != NULL && (lml = lmp_find(p)) != NULL) { 24629ade362SMatthew N. Dodd t = lml_find(lml, f); 2473467e8b8SMatthew N. Dodd if (t != NULL) { 2483467e8b8SMatthew N. Dodd /* 2493467e8b8SMatthew N. Dodd * Add a global mapping if we have 2503467e8b8SMatthew N. Dodd * a successful constrained match. 2513467e8b8SMatthew N. Dodd */ 2521340fc10SMatthew N. Dodd lm_add(NULL, f, t); 25329ade362SMatthew N. Dodd return (t); 25429ade362SMatthew N. Dodd } 2553467e8b8SMatthew N. Dodd } 25629ade362SMatthew N. Dodd lml = lmp_find("$DEFAULT$"); 25729ade362SMatthew N. Dodd if (lml != NULL) 25829ade362SMatthew N. Dodd return (lml_find(lml, f)); 25929ade362SMatthew N. Dodd else 26029ade362SMatthew N. Dodd return (NULL); 26129ade362SMatthew N. Dodd } 26229ade362SMatthew N. Dodd 263966efcc7SMatthew N. Dodd /* Given a libmap translation list and a library name, return the 264966efcc7SMatthew N. Dodd replacement library, or NULL */ 265c905e45dSPeter Wemm #ifdef COMPAT_32BIT 266c905e45dSPeter Wemm char * 267c905e45dSPeter Wemm lm_findn (const char *p, const char *f, const int n) 268c905e45dSPeter Wemm { 269c905e45dSPeter Wemm char pathbuf[64], *s, *t; 270c905e45dSPeter Wemm 2718c6a035eSPeter Wemm if (n < sizeof(pathbuf) - 1) 272c905e45dSPeter Wemm s = pathbuf; 2738c6a035eSPeter Wemm else 274c905e45dSPeter Wemm s = xmalloc(n + 1); 2758c6a035eSPeter Wemm memcpy(s, f, n); 2768c6a035eSPeter Wemm s[n] = '\0'; 277c905e45dSPeter Wemm t = lm_find(p, s); 278c905e45dSPeter Wemm if (s != pathbuf) 279c905e45dSPeter Wemm free(s); 280c905e45dSPeter Wemm return (t); 281c905e45dSPeter Wemm } 282c905e45dSPeter Wemm #endif 283c905e45dSPeter Wemm 28429ade362SMatthew N. Dodd static char * 28529ade362SMatthew N. Dodd lml_find (struct lm_list *lmh, const char *f) 28629ade362SMatthew N. Dodd { 28729ade362SMatthew N. Dodd struct lm *lm; 28829ade362SMatthew N. Dodd 2891aac1ed6SMatthew N. Dodd dbg("%s(%p, \"%s\")", __func__, lmh, f); 2901aac1ed6SMatthew N. Dodd 29129ade362SMatthew N. Dodd TAILQ_FOREACH(lm, lmh, lm_link) 292c905e45dSPeter Wemm if (strcmp(f, lm->f) == 0) 29329ade362SMatthew N. Dodd return (lm->t); 294d33da23fSMatthew N. Dodd return (NULL); 29529ade362SMatthew N. Dodd } 29629ade362SMatthew N. Dodd 297966efcc7SMatthew N. Dodd /* Given an executable name, return a pointer to the translation list or 298966efcc7SMatthew N. Dodd NULL if no matches */ 29929ade362SMatthew N. Dodd static struct lm_list * 30029ade362SMatthew N. Dodd lmp_find (const char *n) 30129ade362SMatthew N. Dodd { 30229ade362SMatthew N. Dodd struct lmp *lmp; 30329ade362SMatthew N. Dodd 3041aac1ed6SMatthew N. Dodd dbg("%s(\"%s\")", __func__, n); 3051aac1ed6SMatthew N. Dodd 30629ade362SMatthew N. Dodd TAILQ_FOREACH(lmp, &lmp_head, lmp_link) 307966efcc7SMatthew N. Dodd if ((lmp->type == T_EXACT && strcmp(n, lmp->p) == 0) || 308966efcc7SMatthew N. Dodd (lmp->type == T_DIRECTORY && strncmp(n, lmp->p, strlen(lmp->p)) == 0) || 309966efcc7SMatthew N. Dodd (lmp->type == T_BASENAME && strcmp(quickbasename(n), lmp->p) == 0)) 31029ade362SMatthew N. Dodd return (&lmp->lml); 31129ade362SMatthew N. Dodd return (NULL); 31229ade362SMatthew N. Dodd } 31329ade362SMatthew N. Dodd 31429ade362SMatthew N. Dodd static struct lm_list * 31529ade362SMatthew N. Dodd lmp_init (char *n) 31629ade362SMatthew N. Dodd { 31729ade362SMatthew N. Dodd struct lmp *lmp; 31829ade362SMatthew N. Dodd 3191aac1ed6SMatthew N. Dodd dbg("%s(\"%s\")", __func__, n); 3201aac1ed6SMatthew N. Dodd 3213467e8b8SMatthew N. Dodd lmp = xmalloc(sizeof(struct lmp)); 32229ade362SMatthew N. Dodd lmp->p = n; 323966efcc7SMatthew N. Dodd if (n[strlen(n)-1] == '/') 324966efcc7SMatthew N. Dodd lmp->type = T_DIRECTORY; 325966efcc7SMatthew N. Dodd else if (strchr(n,'/') == NULL) 326966efcc7SMatthew N. Dodd lmp->type = T_BASENAME; 327966efcc7SMatthew N. Dodd else 328966efcc7SMatthew N. Dodd lmp->type = T_EXACT; 32929ade362SMatthew N. Dodd TAILQ_INIT(&lmp->lml); 33029ade362SMatthew N. Dodd TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link); 33129ade362SMatthew N. Dodd 33229ade362SMatthew N. Dodd return (&lmp->lml); 33329ade362SMatthew N. Dodd } 334966efcc7SMatthew N. Dodd 335966efcc7SMatthew N. Dodd /* libc basename is overkill. Return a pointer to the character after the 336966efcc7SMatthew N. Dodd last /, or the original string if there are no slashes. */ 337966efcc7SMatthew N. Dodd static const char * 338966efcc7SMatthew N. Dodd quickbasename (const char *path) 339966efcc7SMatthew N. Dodd { 340966efcc7SMatthew N. Dodd const char *p = path; 341d33da23fSMatthew N. Dodd for (; *path; path++) { 342966efcc7SMatthew N. Dodd if (*path == '/') 343966efcc7SMatthew N. Dodd p = path+1; 344966efcc7SMatthew N. Dodd } 345d33da23fSMatthew N. Dodd return (p); 346966efcc7SMatthew N. Dodd } 3475b08cb04SMatthew N. Dodd 3485b08cb04SMatthew N. Dodd static int 3495b08cb04SMatthew N. Dodd readstrfn(void * cookie, char *buf, int len) 3505b08cb04SMatthew N. Dodd { 3515b08cb04SMatthew N. Dodd static char *current; 3525b08cb04SMatthew N. Dodd static int left; 3535b08cb04SMatthew N. Dodd int copied; 3545b08cb04SMatthew N. Dodd 3555b08cb04SMatthew N. Dodd copied = 0; 3565b08cb04SMatthew N. Dodd if (!current) { 3575b08cb04SMatthew N. Dodd current = cookie; 3585b08cb04SMatthew N. Dodd left = strlen(cookie); 3595b08cb04SMatthew N. Dodd } 3605b08cb04SMatthew N. Dodd while (*current && left && len) { 3615b08cb04SMatthew N. Dodd *buf++ = *current++; 3625b08cb04SMatthew N. Dodd left--; 3635b08cb04SMatthew N. Dodd len--; 3645b08cb04SMatthew N. Dodd copied++; 3655b08cb04SMatthew N. Dodd } 3665b08cb04SMatthew N. Dodd return copied; 3675b08cb04SMatthew N. Dodd } 3685b08cb04SMatthew N. Dodd 3695b08cb04SMatthew N. Dodd static int 3705b08cb04SMatthew N. Dodd closestrfn(void * cookie) 3715b08cb04SMatthew N. Dodd { 3725b08cb04SMatthew N. Dodd free(cookie); 3735b08cb04SMatthew N. Dodd return 0; 3745b08cb04SMatthew N. Dodd } 375