1 /* $NetBSD: paths.c,v 1.15 2001/05/24 17:41:42 christos Exp $ */ 2 3 /* 4 * Copyright 1996 Matt Thomas <matt@3am-software.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 31 #include <err.h> 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <stdarg.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <unistd.h> 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <sys/sysctl.h> 42 #include <sys/mman.h> 43 #include <sys/stat.h> 44 #include <sys/gmon.h> 45 #include <sys/socket.h> 46 #include <sys/mount.h> 47 #include <sys/mbuf.h> 48 #include <sys/resource.h> 49 #include <machine/cpu.h> 50 51 #include "debug.h" 52 #include "rtld.h" 53 54 static Search_Path *_rtld_find_path __P((Search_Path *, const char *, size_t)); 55 static Search_Path **_rtld_append_path __P((Search_Path **, Search_Path **, 56 const char *, const char *, bool)); 57 static void _rtld_process_mapping __P((Library_Xform **, char *, char *, bool)); 58 59 static Search_Path * 60 _rtld_find_path(path, pathstr, pathlen) 61 Search_Path *path; 62 const char *pathstr; 63 size_t pathlen; 64 { 65 for (; path != NULL; path = path->sp_next) { 66 if (pathlen == path->sp_pathlen && 67 memcmp(path->sp_path, pathstr, pathlen) == 0) 68 return path; 69 } 70 return NULL; 71 } 72 73 static Search_Path ** 74 _rtld_append_path(head_p, path_p, bp, ep, dodebug) 75 Search_Path **head_p, **path_p; 76 const char *bp; 77 const char *ep; 78 bool dodebug; 79 { 80 char *cp; 81 Search_Path *path; 82 83 if (bp == NULL || bp == ep || *bp == '\0') 84 return path_p; 85 86 if (_rtld_find_path(*head_p, bp, ep - bp) != NULL) 87 return path_p; 88 89 path = CNEW(Search_Path); 90 path->sp_pathlen = ep - bp; 91 cp = xmalloc(path->sp_pathlen + 1); 92 strncpy(cp, bp, path->sp_pathlen); 93 cp[path->sp_pathlen] = '\0'; 94 path->sp_path = cp; 95 path->sp_next = (*path_p); 96 (*path_p) = path; 97 path_p = &path->sp_next; 98 99 if (dodebug) 100 dbg((" added path \"%s\"", path->sp_path)); 101 return path_p; 102 } 103 104 void 105 _rtld_add_paths(path_p, pathstr, dodebug) 106 Search_Path **path_p; 107 const char *pathstr; 108 bool dodebug; 109 { 110 Search_Path **head_p = path_p; 111 112 if (pathstr == NULL) 113 return; 114 115 if (pathstr[0] == ':') { 116 /* 117 * Leading colon means append to current path 118 */ 119 while ((*path_p) != NULL) 120 path_p = &(*path_p)->sp_next; 121 pathstr++; 122 } 123 124 for (;;) { 125 const char *bp = pathstr; 126 const char *ep = strchr(bp, ':'); 127 if (ep == NULL) 128 ep = &pathstr[strlen(pathstr)]; 129 130 path_p = _rtld_append_path(head_p, path_p, bp, ep, dodebug); 131 132 if (ep[0] == '\0') 133 break; 134 pathstr = ep + 1; 135 } 136 } 137 138 139 struct sysctldesc { 140 const char *name; 141 int type; 142 }; 143 144 struct list { 145 const struct sysctldesc *ctl; 146 int numentries; 147 }; 148 149 #ifdef CTL_MACHDEP_NAMES 150 static struct sysctldesc ctl_machdep[] = CTL_MACHDEP_NAMES; 151 #endif 152 static struct sysctldesc ctl_toplvl[] = CTL_NAMES; 153 154 struct list toplevel[] = { 155 { 0, 0 }, 156 { ctl_toplvl, CTL_MAXID }, 157 { 0, -1 }, 158 }; 159 160 struct list secondlevel[] = { 161 { 0, 0 }, /* CTL_UNSPEC */ 162 { 0, KERN_MAXID }, /* CTL_KERN */ 163 { 0, VM_MAXID }, /* CTL_VM */ 164 { 0, VFS_MAXID }, /* CTL_VFS */ 165 { 0, NET_MAXID }, /* CTL_NET */ 166 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ 167 { 0, HW_MAXID }, /* CTL_HW */ 168 #ifdef CTL_MACHDEP_NAMES 169 { ctl_machdep, CPU_MAXID }, /* CTL_MACHDEP */ 170 #else 171 { 0, 0 }, /* CTL_MACHDEP */ 172 #endif 173 { 0, USER_MAXID }, /* CTL_USER_NAMES */ 174 { 0, DDBCTL_MAXID }, /* CTL_DDB_NAMES */ 175 { 0, 2 }, /* dummy name */ 176 { 0, -1 }, 177 }; 178 179 struct list *lists[] = { 180 toplevel, 181 secondlevel, 182 0 183 }; 184 185 #define CTL_MACHDEP_SIZE (sizeof(ctl_machdep) / sizeof(ctl_machdep[0])) 186 187 /* 188 * Process library mappings of the form: 189 * <library_name> <machdep_variable> <value,...:library_name,...> ... 190 */ 191 static void 192 _rtld_process_mapping(lib_p, bp, ep, dodebug) 193 Library_Xform **lib_p; 194 char *bp, *ep; 195 bool dodebug; 196 { 197 static const char WS[] = " \t\n"; 198 Library_Xform *hwptr = NULL; 199 char *ptr, *key, *lib, *l; 200 int i, j, k; 201 202 if (bp == NULL || bp == ep || *bp == '\0') 203 return; 204 205 if (dodebug) 206 dbg((" processing mapping \"%s\"", bp)); 207 208 if ((ptr = strsep(&bp, WS)) == NULL) 209 return; 210 211 if (dodebug) 212 dbg((" library \"%s\"", ptr)); 213 214 hwptr = xmalloc(sizeof(*hwptr)); 215 memset(hwptr, 0, sizeof(*hwptr)); 216 hwptr->name = xstrdup(ptr); 217 218 while ((ptr = strsep(&bp, WS)) != NULL) 219 if (*ptr != '\0') 220 break; 221 if (ptr == NULL) { 222 xwarnx("missing sysctl variable name"); 223 goto cleanup; 224 } 225 226 if (dodebug) 227 dbg((" sysctl \"%s\"", ptr)); 228 229 for (i = 0; (l = strsep(&ptr, ".")) != NULL; i++) { 230 231 if (lists[i] == NULL || i >= RTLD_MAX_CTL) { 232 xwarnx("sysctl nesting too deep"); 233 goto cleanup; 234 } 235 236 for (j = 1; lists[i][j].numentries != -1; j++) { 237 238 if (lists[i][j].ctl == NULL) 239 continue; 240 241 for (k = 1; k < lists[i][j].numentries; k++) { 242 if (strcmp(lists[i][j].ctl[k].name, l) == 0) 243 break; 244 } 245 246 if (lists[i][j].numentries == -1) { 247 xwarnx("unknown sysctl variable name `%s'", l); 248 goto cleanup; 249 } 250 251 hwptr->ctl[hwptr->ctlmax] = k; 252 hwptr->ctltype[hwptr->ctlmax++] = 253 lists[i][j].ctl[k].type; 254 } 255 } 256 257 if (dodebug) 258 for (i = 0; i < hwptr->ctlmax; i++) 259 dbg((" sysctl %d, %d", hwptr->ctl[i], 260 hwptr->ctltype[i])); 261 262 for (i = 0; (ptr = strsep(&bp, WS)) != NULL; i++) { 263 if (*ptr == '\0') { 264 /* back up index and continue */ 265 i--; 266 continue; 267 } 268 if (i == RTLD_MAX_ENTRY) { 269 no_more: 270 xwarnx("maximum library entries exceeded `%s'", 271 hwptr->name); 272 goto cleanup; 273 } 274 if ((key = strsep(&ptr, ":")) == NULL) { 275 xwarnx("missing sysctl variable value for `%s'", 276 hwptr->name); 277 goto cleanup; 278 } 279 if ((lib = strsep(&ptr, ":")) == NULL) { 280 xwarnx("missing sysctl library list for `%s'", 281 hwptr->name); 282 goto cleanup; 283 } 284 for (j = 0; (l = strsep(&lib, ",")) != NULL; j++) { 285 if (j == RTLD_MAX_LIBRARY) { 286 xwarnx("maximum library entries exceeded `%s'", 287 hwptr->name); 288 goto cleanup; 289 } 290 if (dodebug) 291 dbg((" library \"%s\"", l)); 292 hwptr->entry[i].library[j] = xstrdup(l); 293 } 294 if (j == 0) { 295 xwarnx("No library map entries for `%s/%s'", 296 hwptr->name, ptr); 297 goto cleanup; 298 } 299 j = i; 300 for (; (l = strsep(&key, ",")) != NULL; i++) { 301 if (dodebug) 302 dbg((" key \"%s\"", l)); 303 if (i == RTLD_MAX_ENTRY) 304 goto no_more; 305 if (i != j) 306 (void)memcpy(hwptr->entry[i].library, 307 hwptr->entry[j].library, 308 sizeof(hwptr->entry[j].library)); 309 hwptr->entry[i].value = xstrdup(l); 310 } 311 312 if (j != i) 313 i--; 314 } 315 316 if (i == 0) { 317 xwarnx("No library entries for `%s'", hwptr->name); 318 goto cleanup; 319 } 320 321 hwptr->next = *lib_p; 322 *lib_p = hwptr; 323 324 return; 325 326 cleanup: 327 if (hwptr->name) 328 free(hwptr->name); 329 free(hwptr); 330 } 331 332 void 333 _rtld_process_hints(path_p, lib_p, fname, dodebug) 334 Search_Path **path_p; 335 Library_Xform **lib_p; 336 const char *fname; 337 bool dodebug; 338 { 339 int fd; 340 char *p, *buf, *b, *ebuf; 341 struct stat st; 342 size_t sz; 343 Search_Path **head_p = path_p; 344 int doing_path = 0; 345 346 if ((fd = open(fname, O_RDONLY)) == -1) { 347 /* Don't complain */ 348 return; 349 } 350 351 if (fstat(fd, &st) == -1) { 352 /* Complain */ 353 xwarn("fstat: %s", fname); 354 return; 355 } 356 357 sz = (size_t) st.st_size; 358 359 buf = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FILE, fd, 0); 360 if (buf == MAP_FAILED) { 361 xwarn("fstat: %s", fname); 362 (void)close(fd); 363 return; 364 } 365 (void)close(fd); 366 367 while ((*path_p) != NULL) 368 path_p = &(*path_p)->sp_next; 369 370 for (b = NULL, p = buf, ebuf = buf + sz; p < ebuf; p++) { 371 372 if ((p == buf || p[-1] == '\0') && b == NULL) 373 b = p; 374 375 switch (*p) { 376 case '/': 377 if (b == p) 378 doing_path = 1; 379 break; 380 381 case ' ': case '\t': 382 if (b == p) 383 b++; 384 break; 385 386 case '\n': 387 *p = '\0'; 388 if (doing_path) 389 path_p = _rtld_append_path(head_p, path_p, b, p, 390 dodebug); 391 else 392 _rtld_process_mapping(lib_p, b, p, dodebug); 393 b = NULL; 394 break; 395 396 case '#': 397 if (b != p) { 398 char *sp; 399 for (sp = p - 1; *sp == ' ' || 400 *sp == '\t'; --sp) 401 continue; 402 *++sp = '\0'; 403 if (doing_path) 404 path_p = _rtld_append_path(head_p, 405 path_p, b, sp, dodebug); 406 else 407 _rtld_process_mapping(lib_p, b, sp, 408 dodebug); 409 *sp = ' '; 410 } 411 b = NULL; 412 break; 413 414 default: 415 if (b == p) 416 doing_path = 0; 417 break; 418 } 419 } 420 421 if (doing_path) 422 path_p = _rtld_append_path(head_p, path_p, b, ebuf, dodebug); 423 else 424 _rtld_process_mapping(lib_p, b, ebuf, dodebug); 425 426 (void)munmap(buf, sz); 427 } 428