1 /* $NetBSD: paths.c,v 1.25 2002/10/06 01:36:36 junyoung 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 for (; path != NULL; path = path->sp_next) { 67 if (pathlen == path->sp_pathlen && 68 memcmp(path->sp_path, pathstr, pathlen) == 0) 69 return path; 70 } 71 return NULL; 72 } 73 74 static Search_Path ** 75 _rtld_append_path(head_p, path_p, bp, len) 76 Search_Path **head_p, **path_p; 77 const char *bp; 78 size_t len; 79 { 80 char *cp; 81 Search_Path *path; 82 83 if (_rtld_find_path(*head_p, bp, len) != NULL) 84 return path_p; 85 86 path = NEW(Search_Path); 87 path->sp_pathlen = len; 88 cp = xmalloc(len + 1); 89 memcpy(cp, bp, len); 90 cp[len] = '\0'; 91 path->sp_path = cp; 92 path->sp_next = (*path_p); 93 (*path_p) = path; 94 path_p = &path->sp_next; 95 96 dbg((" added path \"%s\"", path->sp_path)); 97 return path_p; 98 } 99 100 void 101 _rtld_add_paths(path_p, pathstr) 102 Search_Path **path_p; 103 const char *pathstr; 104 { 105 Search_Path **head_p = path_p; 106 107 if (pathstr == NULL) 108 return; 109 110 if (pathstr[0] == ':') { 111 /* 112 * Leading colon means append to current path 113 */ 114 while ((*path_p) != NULL) 115 path_p = &(*path_p)->sp_next; 116 pathstr++; 117 } 118 119 for (;;) { 120 const char *bp = pathstr; 121 const char *ep = strchr(bp, ':'); 122 if (ep == NULL) 123 ep = &pathstr[strlen(pathstr)]; 124 125 path_p = _rtld_append_path(head_p, path_p, bp, ep - bp); 126 127 if (ep[0] == '\0') 128 break; 129 pathstr = ep + 1; 130 } 131 } 132 133 134 struct sysctldesc { 135 const char *name; 136 int type; 137 }; 138 139 struct list { 140 const struct sysctldesc *ctl; 141 int numentries; 142 }; 143 144 #ifdef CTL_MACHDEP_NAMES 145 static const struct sysctldesc ctl_machdep[] = CTL_MACHDEP_NAMES; 146 #endif 147 static const struct sysctldesc ctl_toplvl[] = CTL_NAMES; 148 149 const struct list toplevel[] = { 150 { 0, 0 }, 151 { ctl_toplvl, CTL_MAXID }, 152 { 0, -1 }, 153 }; 154 155 const struct list secondlevel[] = { 156 { 0, 0 }, /* CTL_UNSPEC */ 157 { 0, KERN_MAXID }, /* CTL_KERN */ 158 { 0, VM_MAXID }, /* CTL_VM */ 159 { 0, VFS_MAXID }, /* CTL_VFS */ 160 { 0, NET_MAXID }, /* CTL_NET */ 161 { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */ 162 { 0, HW_MAXID }, /* CTL_HW */ 163 #ifdef CTL_MACHDEP_NAMES 164 { ctl_machdep, CPU_MAXID }, /* CTL_MACHDEP */ 165 #else 166 { 0, 0 }, /* CTL_MACHDEP */ 167 #endif 168 { 0, USER_MAXID }, /* CTL_USER_NAMES */ 169 { 0, DDBCTL_MAXID }, /* CTL_DDB_NAMES */ 170 { 0, 2 }, /* dummy name */ 171 { 0, -1 }, 172 }; 173 174 const struct list *lists[] = { 175 toplevel, 176 secondlevel, 177 0 178 }; 179 180 #define CTL_MACHDEP_SIZE (sizeof(ctl_machdep) / sizeof(ctl_machdep[0])) 181 182 /* 183 * Process library mappings of the form: 184 * <library_name> <machdep_variable> <value,...:library_name,...> ... 185 */ 186 static void 187 _rtld_process_mapping(lib_p, bp, len) 188 Library_Xform **lib_p; 189 char *bp; 190 size_t len; 191 { 192 static const char WS[] = " \t\n"; 193 Library_Xform *hwptr = NULL; 194 char *ptr, *key, *lib, *l; 195 int i, j, k; 196 197 dbg((" processing mapping \"%s\"", bp)); 198 199 if ((ptr = strsep(&bp, WS)) == NULL) 200 return; 201 202 dbg((" library \"%s\"", ptr)); 203 204 hwptr = xmalloc(sizeof(*hwptr)); 205 memset(hwptr, 0, sizeof(*hwptr)); 206 hwptr->name = xstrdup(ptr); 207 208 while ((ptr = strsep(&bp, WS)) != NULL) 209 if (*ptr != '\0') 210 break; 211 if (ptr == NULL) { 212 xwarnx("missing sysctl variable name"); 213 goto cleanup; 214 } 215 216 dbg((" sysctl \"%s\"", ptr)); 217 218 for (i = 0; (l = strsep(&ptr, ".")) != NULL; i++) { 219 220 if (lists[i] == NULL || i >= RTLD_MAX_CTL) { 221 xwarnx("sysctl nesting too deep"); 222 goto cleanup; 223 } 224 225 for (j = 1; lists[i][j].numentries != -1; j++) { 226 227 if (lists[i][j].ctl == NULL) 228 continue; 229 230 for (k = 1; k < lists[i][j].numentries; k++) { 231 if (strcmp(lists[i][j].ctl[k].name, l) == 0) 232 break; 233 } 234 235 if (lists[i][j].numentries == -1) { 236 xwarnx("unknown sysctl variable name `%s'", l); 237 goto cleanup; 238 } 239 240 hwptr->ctl[hwptr->ctlmax] = k; 241 hwptr->ctltype[hwptr->ctlmax++] = 242 lists[i][j].ctl[k].type; 243 } 244 } 245 246 for (i = 0; i < hwptr->ctlmax; i++) 247 dbg((" sysctl %d, %d", hwptr->ctl[i], hwptr->ctltype[i])); 248 249 for (i = 0; (ptr = strsep(&bp, WS)) != NULL; i++) { 250 if (*ptr == '\0') { 251 /* back up index and continue */ 252 i--; 253 continue; 254 } 255 if (i == RTLD_MAX_ENTRY) { 256 no_more: 257 xwarnx("maximum library entries exceeded `%s'", 258 hwptr->name); 259 goto cleanup; 260 } 261 if ((key = strsep(&ptr, ":")) == NULL) { 262 xwarnx("missing sysctl variable value for `%s'", 263 hwptr->name); 264 goto cleanup; 265 } 266 if ((lib = strsep(&ptr, ":")) == NULL) { 267 xwarnx("missing sysctl library list for `%s'", 268 hwptr->name); 269 goto cleanup; 270 } 271 for (j = 0; (l = strsep(&lib, ",")) != NULL; j++) { 272 if (j == RTLD_MAX_LIBRARY) { 273 xwarnx("maximum library entries exceeded `%s'", 274 hwptr->name); 275 goto cleanup; 276 } 277 dbg((" library \"%s\"", l)); 278 hwptr->entry[i].library[j] = xstrdup(l); 279 } 280 if (j == 0) { 281 xwarnx("No library map entries for `%s/%s'", 282 hwptr->name, ptr); 283 goto cleanup; 284 } 285 j = i; 286 for (; (l = strsep(&key, ",")) != NULL; i++) { 287 dbg((" key \"%s\"", l)); 288 if (i == RTLD_MAX_ENTRY) 289 goto no_more; 290 if (i != j) 291 (void)memcpy(hwptr->entry[i].library, 292 hwptr->entry[j].library, 293 sizeof(hwptr->entry[j].library)); 294 hwptr->entry[i].value = xstrdup(l); 295 } 296 297 if (j != i) 298 i--; 299 } 300 301 if (i == 0) { 302 xwarnx("No library entries for `%s'", hwptr->name); 303 goto cleanup; 304 } 305 306 hwptr->next = *lib_p; 307 *lib_p = hwptr; 308 309 return; 310 311 cleanup: 312 if (hwptr->name) 313 free(hwptr->name); 314 free(hwptr); 315 } 316 317 void 318 _rtld_process_hints(path_p, lib_p, fname) 319 Search_Path **path_p; 320 Library_Xform **lib_p; 321 const char *fname; 322 { 323 int fd; 324 char *buf, *b, *ebuf; 325 struct stat st; 326 size_t sz, len; 327 Search_Path **head_p = path_p; 328 int doing_path = 0; 329 330 if ((fd = open(fname, O_RDONLY)) == -1) { 331 /* Don't complain */ 332 return; 333 } 334 335 if (fstat(fd, &st) == -1) { 336 /* Complain */ 337 xwarn("fstat: %s", fname); 338 return; 339 } 340 341 sz = (size_t) st.st_size; 342 343 buf = mmap(0, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FILE, fd, 0); 344 if (buf == MAP_FAILED) { 345 xwarn("fstat: %s", fname); 346 (void)close(fd); 347 return; 348 } 349 (void)close(fd); 350 351 while ((*path_p) != NULL) 352 path_p = &(*path_p)->sp_next; 353 354 for (b = buf, ebuf = buf + sz; b < ebuf; ) { 355 b += strspn(b, " \t\n"); 356 if (*b == '\0') 357 break; 358 359 len = strcspn(b, "\n#"); 360 if (len == 0) { 361 b += strcspn(b, "\n"); 362 continue; 363 } 364 365 doing_path = *b == '/'; 366 if (doing_path) { 367 size_t tmp = len - 1; 368 while (b[tmp] == '#' || b[tmp] == ' ' || b[tmp] == '\t') 369 tmp--; 370 path_p = _rtld_append_path(head_p, path_p, b, tmp + 1); 371 } else { 372 char tmp = b[len]; 373 b[len] = '\0'; 374 _rtld_process_mapping(lib_p, b, len); 375 b[len] = tmp; 376 } 377 378 b += len; 379 } 380 381 (void)munmap(buf, sz); 382 } 383