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 #include "debug.h" 13 #include "rtld.h" 14 15 #ifndef _PATH_LIBMAP_CONF 16 #define _PATH_LIBMAP_CONF "/etc/libmap.conf" 17 #endif 18 19 TAILQ_HEAD(lm_list, lm); 20 struct lm { 21 char *f; 22 char *t; 23 24 TAILQ_ENTRY(lm) lm_link; 25 }; 26 27 TAILQ_HEAD(lmp_list, lmp) lmp_head = TAILQ_HEAD_INITIALIZER(lmp_head); 28 struct lmp { 29 char *p; 30 struct lm_list lml; 31 TAILQ_ENTRY(lmp) lmp_link; 32 }; 33 34 static void lm_add (const char *, const char *, const char *); 35 static void lm_free (struct lm_list *); 36 static char * lml_find (struct lm_list *, const char *); 37 static struct lm_list * lmp_find (const char *); 38 static struct lm_list * lmp_init (char *); 39 40 #define iseol(c) (((c) == '#') || ((c) == '\0') || \ 41 ((c) == '\n') || ((c) == '\r')) 42 43 void 44 lm_init (void) 45 { 46 FILE *fp; 47 char *cp; 48 char *f, *t, *p, *c; 49 char prog[MAXPATHLEN]; 50 char line[MAXPATHLEN + 2]; 51 52 dbg("%s()", __func__); 53 54 TAILQ_INIT(&lmp_head); 55 56 if ((fp = fopen(_PATH_LIBMAP_CONF, "r")) == NULL) 57 return; 58 59 p = NULL; 60 while ((cp = fgets(line, MAXPATHLEN + 1, fp)) != NULL) { 61 t = f = c = NULL; 62 63 /* Skip over leading space */ 64 while (isspace(*cp)) cp++; 65 66 /* Found a comment or EOL */ 67 if (iseol(*cp)) continue; 68 69 /* Found a constraint selector */ 70 if (*cp == '[') { 71 cp++; 72 73 /* Skip leading space */ 74 while (isspace(*cp)) cp++; 75 76 /* Found comment, EOL or end of selector */ 77 if (iseol(*cp) || *cp == ']') 78 continue; 79 80 c = cp++; 81 /* Skip to end of word */ 82 while (!isspace(*cp) && !iseol(*cp) && *cp != ']') 83 cp++; 84 85 /* Skip and zero out trailing space */ 86 while (isspace(*cp)) *cp++ = '\0'; 87 88 /* Check if there is a closing brace */ 89 if (*cp != ']') continue; 90 91 /* Terminate string if there was no trailing space */ 92 *cp++ = '\0'; 93 94 /* 95 * There should be nothing except whitespace or comment 96 from this point to the end of the line. 97 */ 98 while(isspace(*cp)) *cp++; 99 if (!iseol(*cp)) continue; 100 101 strcpy(prog, c); 102 p = prog; 103 continue; 104 } 105 106 /* Parse the 'from' candidate. */ 107 f = cp++; 108 while (!isspace(*cp) && !iseol(*cp)) cp++; 109 110 /* Skip and zero out the trailing whitespace */ 111 while (isspace(*cp)) *cp++ = '\0'; 112 113 /* Found a comment or EOL */ 114 if (iseol(*cp)) continue; 115 116 /* Parse 'to' mapping */ 117 t = cp++; 118 while (!isspace(*cp) && !iseol(*cp)) cp++; 119 120 /* Skip and zero out the trailing whitespace */ 121 while (isspace(*cp)) *cp++ = '\0'; 122 123 /* Should be no extra tokens at this point */ 124 if (!iseol(*cp)) continue; 125 126 *cp = '\0'; 127 lm_add(p, f, t); 128 } 129 fclose(fp); 130 return; 131 } 132 133 static void 134 lm_free (struct lm_list *lml) 135 { 136 struct lm *lm; 137 138 dbg("%s(%p)", __func__, lml); 139 140 while (!TAILQ_EMPTY(lml)) { 141 lm = TAILQ_FIRST(lml); 142 TAILQ_REMOVE(lml, lm, lm_link); 143 free(lm->f); 144 free(lm->t); 145 free(lm); 146 } 147 return; 148 } 149 150 void 151 lm_fini (void) 152 { 153 struct lmp *lmp; 154 155 dbg("%s()", __func__); 156 157 while (!TAILQ_EMPTY(&lmp_head)) { 158 lmp = TAILQ_FIRST(&lmp_head); 159 TAILQ_REMOVE(&lmp_head, lmp, lmp_link); 160 free(lmp->p); 161 lm_free(&lmp->lml); 162 free(lmp); 163 } 164 return; 165 } 166 167 static void 168 lm_add (const char *p, const char *f, const char *t) 169 { 170 struct lm_list *lml; 171 struct lm *lm; 172 173 if (p == NULL) 174 p = "$DEFAULT$"; 175 176 dbg("%s(\"%s\", \"%s\", \"%s\")", __func__, p, f, t); 177 178 if ((lml = lmp_find(p)) == NULL) 179 lml = lmp_init(xstrdup(p)); 180 181 lm = xmalloc(sizeof(struct lm)); 182 lm->f = xstrdup(f); 183 lm->t = xstrdup(t); 184 TAILQ_INSERT_HEAD(lml, lm, lm_link); 185 } 186 187 char * 188 lm_find (const char *p, const char *f) 189 { 190 struct lm_list *lml; 191 char *t; 192 193 dbg("%s(\"%s\", \"%s\")", __func__, p, f); 194 195 if (p != NULL && (lml = lmp_find(p)) != NULL) { 196 t = lml_find(lml, f); 197 if (t != NULL) { 198 /* 199 * Add a global mapping if we have 200 * a successful constrained match. 201 */ 202 lm_add(NULL, f, t); 203 return (t); 204 } 205 } 206 lml = lmp_find("$DEFAULT$"); 207 if (lml != NULL) 208 return (lml_find(lml, f)); 209 else 210 return (NULL); 211 } 212 213 static char * 214 lml_find (struct lm_list *lmh, const char *f) 215 { 216 struct lm *lm; 217 218 dbg("%s(%p, \"%s\")", __func__, lmh, f); 219 220 TAILQ_FOREACH(lm, lmh, lm_link) 221 if ((strncmp(f, lm->f, strlen(lm->f)) == 0) && 222 (strlen(f) == strlen(lm->f))) 223 return (lm->t); 224 return NULL; 225 } 226 227 static struct lm_list * 228 lmp_find (const char *n) 229 { 230 struct lmp *lmp; 231 232 dbg("%s(\"%s\")", __func__, n); 233 234 TAILQ_FOREACH(lmp, &lmp_head, lmp_link) 235 if ((strncmp(n, lmp->p, strlen(lmp->p)) == 0) && 236 (strlen(n) == strlen(lmp->p))) 237 return (&lmp->lml); 238 return (NULL); 239 } 240 241 static struct lm_list * 242 lmp_init (char *n) 243 { 244 struct lmp *lmp; 245 246 dbg("%s(\"%s\")", __func__, n); 247 248 lmp = xmalloc(sizeof(struct lmp)); 249 lmp->p = n; 250 TAILQ_INIT(&lmp->lml); 251 TAILQ_INSERT_HEAD(&lmp_head, lmp, lmp_link); 252 253 return (&lmp->lml); 254 } 255