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