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