subr_hints.c revision 79696
1/*- 2 * Copyright (c) 2000,2001 Peter Wemm <peter@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/kern/subr_hints.c 79696 2001-07-14 00:23:10Z peter $ 27 */ 28 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/bus.h> 32 33/* 34 * Access functions for device resources. 35 */ 36 37extern char static_hints[]; /* by config for now */ 38extern int hintmode; /* 0 = off. 1 = config, 2 = fallback */ 39static char *hintp; 40 41/* 42 * Evil wildcarding resource string lookup. 43 * This walks the supplied env string table and returns a match. 44 * The start point can be remembered for incremental searches. 45 */ 46static int 47res_find(int *line, int *startln, 48 const char *name, int *unit, const char *resname, const char *value, 49 const char **ret_name, int *ret_namelen, int *ret_unit, 50 const char **ret_resname, int *ret_resnamelen, const char **ret_value) 51{ 52 int n = 0, hit; 53 char r_name[32]; 54 int r_unit; 55 char r_resname[32]; 56 char r_value[128]; 57 const char *s, *cp; 58 char *p; 59 60 if (hintp == NULL) { 61 switch (hintmode) { 62 case 0: /* config supplied nothing */ 63 hintp = kern_envp; 64 break; 65 case 1: /* static hints only */ 66 hintp = static_hints; 67 break; 68 case 2: /* fallback mode */ 69 cp = kern_envp; 70 while (cp) { 71 if (strncmp(cp, "hint.", 5) == 0) { 72 cp = NULL; 73 hintp = kern_envp; 74 break; 75 } 76 while (*cp != '\0') 77 cp++; 78 cp++; 79 if (*cp == '\0') { 80 cp = NULL; 81 hintp = static_hints; 82 break; 83 } 84 } 85 break; 86 default: 87 break; 88 } 89 if (hintp == NULL) 90 hintp = kern_envp; 91 } 92 93 cp = hintp; 94 while (cp) { 95 hit = 1; 96 (*line)++; 97 if (strncmp(cp, "hint.", 5) != 0) 98 hit = 0; 99 else 100 n = sscanf(cp, "hint.%32[^.].%d.%32[^=]=%128s", 101 r_name, &r_unit, r_resname, r_value); 102 if (hit && n != 4) { 103 printf("CONFIG: invalid hint '%s'\n", cp); 104 /* XXX: abuse bogus index() declaration */ 105 p = index(cp, 'h'); 106 *p = 'H'; 107 hit = 0; 108 } 109 if (hit && startln && *startln >= 0 && *line < *startln) 110 hit = 0; 111 if (hit && name && strcmp(name, r_name) != 0) 112 hit = 0; 113 if (hit && unit && *unit != r_unit) 114 hit = 0; 115 if (hit && resname && strcmp(resname, r_resname) != 0) 116 hit = 0; 117 if (hit && value && strcmp(value, r_value) != 0) 118 hit = 0; 119 if (hit) 120 break; 121 while (*cp != '\0') 122 cp++; 123 cp++; 124 if (*cp == '\0') { 125 cp = NULL; 126 break; 127 } 128 } 129 if (cp == NULL) 130 return ENOENT; 131 132 s = cp; 133 /* This is a bit of a hack, but at least is reentrant */ 134 /* Note that it returns some !unterminated! strings. */ 135 s = index(s, '.') + 1; /* start of device */ 136 if (ret_name) 137 *ret_name = s; 138 s = index(s, '.') + 1; /* start of unit */ 139 if (ret_namelen) 140 *ret_namelen = s - *ret_name - 1; /* device length */ 141 if (ret_unit) 142 *ret_unit = r_unit; 143 s = index(s, '.') + 1; /* start of resname */ 144 if (ret_resname) 145 *ret_resname = s; 146 s = index(s, '=') + 1; /* start of value */ 147 if (ret_resnamelen) 148 *ret_resnamelen = s - *ret_resname - 1; /* value len */ 149 if (ret_value) 150 *ret_value = s; 151 if (startln) /* line number for anchor */ 152 *startln = *line + 1; 153 return 0; 154} 155 156/* 157 * Search all the data sources for matches to our query. We look for 158 * dynamic hints first as overrides for static or fallback hints. 159 */ 160static int 161resource_find(int *line, int *startln, 162 const char *name, int *unit, const char *resname, const char *value, 163 const char **ret_name, int *ret_namelen, int *ret_unit, 164 const char **ret_resname, int *ret_resnamelen, const char **ret_value) 165{ 166 int i; 167 int un; 168 169 *line = 0; 170 171 /* Search for exact unit matches first */ 172 i = res_find(line, startln, name, unit, resname, value, 173 ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 174 ret_value); 175 if (i == 0) 176 return 0; 177 if (unit == NULL) 178 return ENOENT; 179 /* If we are still here, search for wildcard matches */ 180 un = -1; 181 i = res_find(line, startln, name, &un, resname, value, 182 ret_name, ret_namelen, ret_unit, ret_resname, ret_resnamelen, 183 ret_value); 184 if (i == 0) 185 return 0; 186 return ENOENT; 187} 188 189int 190resource_int_value(const char *name, int unit, const char *resname, int *result) 191{ 192 int error; 193 const char *str; 194 char *op; 195 unsigned long val; 196 int line; 197 198 line = 0; 199 error = resource_find(&line, NULL, name, &unit, resname, NULL, 200 NULL, NULL, NULL, NULL, NULL, &str); 201 if (error) 202 return error; 203 if (*str == '\0') 204 return EFTYPE; 205 val = strtoul(str, &op, 0); 206 if (*op != '\0') 207 return EFTYPE; 208 *result = val; 209 return 0; 210} 211 212int 213resource_long_value(const char *name, int unit, const char *resname, 214 long *result) 215{ 216 int error; 217 const char *str; 218 char *op; 219 unsigned long val; 220 int line; 221 222 line = 0; 223 error = resource_find(&line, NULL, name, &unit, resname, NULL, 224 NULL, NULL, NULL, NULL, NULL, &str); 225 if (error) 226 return error; 227 if (*str == '\0') 228 return EFTYPE; 229 val = strtoul(str, &op, 0); 230 if (*op != '\0') 231 return EFTYPE; 232 *result = val; 233 return 0; 234} 235 236int 237resource_string_value(const char *name, int unit, const char *resname, 238 const char **result) 239{ 240 int error; 241 const char *str; 242 int line; 243 244 line = 0; 245 error = resource_find(&line, NULL, name, &unit, resname, NULL, 246 NULL, NULL, NULL, NULL, NULL, &str); 247 if (error) 248 return error; 249 *result = str; 250 return 0; 251} 252 253/* 254 * This is a bit nasty, but allows us to not modify the env strings. 255 */ 256static const char * 257resource_string_copy(const char *s, int len) 258{ 259 static char stringbuf[256]; 260 static int offset = 0; 261 const char *ret; 262 263 if (len == 0) 264 len = strlen(s); 265 if (len > 255) 266 return NULL; 267 if ((offset + len + 1) > 255) 268 offset = 0; 269 bcopy(s, &stringbuf[offset], len); 270 stringbuf[offset + len] = '\0'; 271 ret = &stringbuf[offset]; 272 offset += len + 1; 273 return ret; 274} 275 276/* 277 * err = resource_find_at(&anchor, &name, &unit, resname, value) 278 * Iteratively fetch a list of devices wired "at" something 279 * res and value are restrictions. eg: "at", "scbus0". 280 * For practical purposes, res = required, value = optional. 281 * *name and *unit are set. 282 * set *anchor to zero before starting. 283 */ 284int 285resource_find_match(int *anchor, const char **name, int *unit, 286 const char *resname, const char *value) 287{ 288 const char *found_name; 289 int found_namelen; 290 int found_unit; 291 int ret; 292 int newln; 293 294 newln = *anchor; 295 ret = resource_find(anchor, &newln, NULL, NULL, resname, value, 296 &found_name, &found_namelen, &found_unit, NULL, NULL, NULL); 297 if (ret == 0) { 298 *name = resource_string_copy(found_name, found_namelen); 299 *unit = found_unit; 300 } 301 *anchor = newln; 302 return ret; 303} 304 305 306/* 307 * err = resource_find_dev(&anchor, name, &unit, res, value); 308 * Iterate through a list of devices, returning their unit numbers. 309 * res and value are optional restrictions. eg: "at", "scbus0". 310 * *unit is set to the value. 311 * set *anchor to zero before starting. 312 */ 313int 314resource_find_dev(int *anchor, const char *name, int *unit, 315 const char *resname, const char *value) 316{ 317 int found_unit; 318 int newln; 319 int ret; 320 321 newln = *anchor; 322 ret = resource_find(anchor, &newln, name, NULL, resname, value, 323 NULL, NULL, &found_unit, NULL, NULL, NULL); 324 if (ret == 0) { 325 *unit = found_unit; 326 } 327 *anchor = newln; 328 return ret; 329} 330