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