kern_conf.c revision 67905
1251881Speter/*- 2251881Speter * Parts Copyright (c) 1995 Terrence R. Lambert 3251881Speter * Copyright (c) 1995 Julian R. Elischer 4251881Speter * All rights reserved. 5251881Speter * 6251881Speter * Redistribution and use in source and binary forms, with or without 7251881Speter * modification, are permitted provided that the following conditions 8251881Speter * are met: 9251881Speter * 1. Redistributions of source code must retain the above copyright 10251881Speter * notice, this list of conditions and the following disclaimer. 11251881Speter * 2. Redistributions in binary form must reproduce the above copyright 12251881Speter * notice, this list of conditions and the following disclaimer in the 13251881Speter * documentation and/or other materials provided with the distribution. 14251881Speter * 3. All advertising materials mentioning features or use of this software 15251881Speter * must display the following acknowledgement: 16251881Speter * This product includes software developed by Terrence R. Lambert. 17251881Speter * 4. The name Terrence R. Lambert may not be used to endorse or promote 18251881Speter * products derived from this software without specific prior written 19251881Speter * permission. 20251881Speter * 21251881Speter * THIS SOFTWARE IS PROVIDED BY Julian R. Elischer ``AS IS'' AND ANY 22251881Speter * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE TERRENCE R. LAMBERT BE LIABLE 25251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31251881Speter * SUCH DAMAGE. 32251881Speter * 33251881Speter * $FreeBSD: head/sys/kern/kern_conf.c 67905 2000-10-29 19:50:06Z phk $ 34251881Speter */ 35251881Speter 36251881Speter#include <sys/param.h> 37251881Speter#include <sys/kernel.h> 38251881Speter#include <sys/sysctl.h> 39251881Speter#include <sys/systm.h> 40251881Speter#include <sys/module.h> 41251881Speter#include <sys/malloc.h> 42251881Speter#include <sys/conf.h> 43251881Speter#include <sys/vnode.h> 44251881Speter#include <sys/queue.h> 45251881Speter#include <sys/ctype.h> 46251881Speter#include <machine/stdarg.h> 47251881Speter 48251881Speter#define cdevsw_ALLOCSTART (NUMCDEVSW/2) 49251881Speter 50251881Speterstruct cdevsw *cdevsw[NUMCDEVSW]; 51251881Speter 52251881Speterstatic int bmaj2cmaj[NUMCDEVSW]; 53251881Speter 54251881SpeterMALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 55251881Speter 56251881Speter/* 57251881Speter * This is the number of hash-buckets. Experiements with 'real-life' 58251881Speter * udev_t's show that a prime halfway between two powers of two works 59251881Speter * best. 60251881Speter */ 61251881Speter#define DEVT_HASH 83 62251881Speter 63251881Speter/* The number of dev_t's we can create before malloc(9) kick in. */ 64251881Speter#define DEVT_STASH 50 65251881Speter 66251881Speterstatic struct specinfo devt_stash[DEVT_STASH]; 67251881Speter 68251881Speterstatic LIST_HEAD(, specinfo) dev_hash[DEVT_HASH]; 69251881Speter 70251881Speterstatic LIST_HEAD(, specinfo) dev_free; 71251881Speter 72251881Speterdevfs_create_t *devfs_create_hook; 73251881Speterdevfs_destroy_t *devfs_destroy_hook; 74251881Speterint devfs_present; 75251881Speter 76251881Speterstatic int free_devt; 77251881SpeterSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 78251881Speter 79251881Speterstruct cdevsw * 80251881Speterdevsw(dev_t dev) 81251881Speter{ 82251881Speter if (dev->si_devsw) 83251881Speter return (dev->si_devsw); 84251881Speter return(cdevsw[major(dev)]); 85251881Speter} 86251881Speter 87251881Speter/* 88251881Speter * Add a cdevsw entry 89251881Speter */ 90251881Speter 91251881Speterint 92251881Spetercdevsw_add(struct cdevsw *newentry) 93251881Speter{ 94251881Speter int i; 95251881Speter static int setup; 96251881Speter 97251881Speter if (!setup) { 98251881Speter for (i = 0; i < NUMCDEVSW; i++) 99251881Speter if (!bmaj2cmaj[i]) 100251881Speter bmaj2cmaj[i] = 254; 101251881Speter setup++; 102251881Speter } 103251881Speter 104251881Speter if (newentry->d_maj < 0 || newentry->d_maj >= NUMCDEVSW) { 105251881Speter printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 106251881Speter newentry->d_name, newentry->d_maj); 107251881Speter return (EINVAL); 108251881Speter } 109251881Speter if (newentry->d_bmaj >= NUMCDEVSW) { 110251881Speter printf("%s: ERROR: driver has bogus cdevsw->d_bmaj = %d\n", 111251881Speter newentry->d_name, newentry->d_bmaj); 112251881Speter return (EINVAL); 113251881Speter } 114251881Speter if (newentry->d_bmaj >= 0 && (newentry->d_flags & D_DISK) == 0) { 115251881Speter printf("ERROR: \"%s\" bmaj but is not a disk\n", 116251881Speter newentry->d_name); 117251881Speter return (EINVAL); 118251881Speter } 119251881Speter 120251881Speter if (cdevsw[newentry->d_maj]) { 121251881Speter printf("WARNING: \"%s\" is usurping \"%s\"'s cdevsw[]\n", 122251881Speter newentry->d_name, cdevsw[newentry->d_maj]->d_name); 123251881Speter } 124251881Speter 125251881Speter cdevsw[newentry->d_maj] = newentry; 126251881Speter 127251881Speter if (newentry->d_bmaj < 0) 128251881Speter return (0); 129251881Speter 130251881Speter if (bmaj2cmaj[newentry->d_bmaj] != 254) { 131251881Speter printf("WARNING: \"%s\" is usurping \"%s\"'s bmaj\n", 132251881Speter newentry->d_name, 133251881Speter cdevsw[bmaj2cmaj[newentry->d_bmaj]]->d_name); 134251881Speter } 135251881Speter bmaj2cmaj[newentry->d_bmaj] = newentry->d_maj; 136251881Speter return (0); 137251881Speter} 138251881Speter 139251881Speter/* 140251881Speter * Remove a cdevsw entry 141251881Speter */ 142251881Speter 143251881Speterint 144251881Spetercdevsw_remove(struct cdevsw *oldentry) 145251881Speter{ 146251881Speter if (oldentry->d_maj < 0 || oldentry->d_maj >= NUMCDEVSW) { 147251881Speter printf("%s: ERROR: driver has bogus cdevsw->d_maj = %d\n", 148251881Speter oldentry->d_name, oldentry->d_maj); 149251881Speter return EINVAL; 150251881Speter } 151251881Speter 152251881Speter cdevsw[oldentry->d_maj] = NULL; 153251881Speter 154251881Speter if (oldentry->d_bmaj >= 0 && oldentry->d_bmaj < NUMCDEVSW) 155251881Speter bmaj2cmaj[oldentry->d_bmaj] = 254; 156251881Speter 157251881Speter return 0; 158251881Speter} 159251881Speter 160251881Speter/* 161251881Speter * dev_t and u_dev_t primitives 162251881Speter */ 163251881Speter 164251881Speterint 165251881Spetermajor(dev_t x) 166251881Speter{ 167251881Speter if (x == NODEV) 168251881Speter return NOUDEV; 169251881Speter return((x->si_udev >> 8) & 0xff); 170251881Speter} 171251881Speter 172251881Speterint 173251881Speterminor(dev_t x) 174251881Speter{ 175251881Speter if (x == NODEV) 176251881Speter return NOUDEV; 177251881Speter return(x->si_udev & 0xffff00ff); 178251881Speter} 179251881Speter 180251881Speterint 181251881Speterdev2unit(dev_t x) 182251881Speter{ 183251881Speter int i; 184251881Speter 185251881Speter if (x == NODEV) 186251881Speter return NOUDEV; 187251881Speter i = minor(x); 188251881Speter return ((i & 0xff) | (i >> 8)); 189251881Speter} 190251881Speter 191251881Speterint 192251881Speterunit2minor(int unit) 193251881Speter{ 194251881Speter 195251881Speter return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 196251881Speter} 197251881Speter 198251881Speterdev_t 199251881Spetermakebdev(int x, int y) 200251881Speter{ 201251881Speter 202251881Speter if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 203251881Speter Debugger("makebdev of NOUDEV"); 204251881Speter return (makedev(bmaj2cmaj[x], y)); 205251881Speter} 206251881Speter 207251881Speterstatic dev_t 208251881Speterallocdev(void) 209251881Speter{ 210251881Speter static int stashed; 211251881Speter struct specinfo *si; 212251881Speter 213251881Speter if (stashed >= DEVT_STASH) { 214251881Speter MALLOC(si, struct specinfo *, sizeof(*si), M_DEVT, 215251881Speter M_USE_RESERVE); 216251881Speter bzero(si, sizeof(*si)); 217251881Speter } else if (LIST_FIRST(&dev_free)) { 218251881Speter si = LIST_FIRST(&dev_free); 219251881Speter LIST_REMOVE(si, si_hash); 220251881Speter } else { 221251881Speter si = devt_stash + stashed++; 222251881Speter si->si_flags |= SI_STASHED; 223251881Speter } 224251881Speter LIST_INIT(&si->si_names); 225251881Speter return (si); 226251881Speter} 227251881Speter 228251881Speterdev_t 229251881Spetermakedev(int x, int y) 230251881Speter{ 231251881Speter struct specinfo *si; 232251881Speter udev_t udev; 233251881Speter int hash; 234251881Speter 235251881Speter if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 236251881Speter Debugger("makedev of NOUDEV"); 237251881Speter udev = (x << 8) | y; 238251881Speter hash = udev % DEVT_HASH; 239251881Speter LIST_FOREACH(si, &dev_hash[hash], si_hash) { 240251881Speter if (si->si_udev == udev) 241251881Speter return (si); 242251881Speter } 243251881Speter si = allocdev(); 244251881Speter si->si_udev = udev; 245251881Speter LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 246251881Speter return (si); 247251881Speter} 248251881Speter 249251881Spetervoid 250251881Speterfreedev(dev_t dev) 251251881Speter{ 252251881Speter dev_t adev; 253251881Speter 254251881Speter if (!free_devt) 255251881Speter return; 256251881Speter if (SLIST_FIRST(&dev->si_hlist)) 257251881Speter return; 258251881Speter if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 259251881Speter return; 260251881Speter while (!LIST_EMPTY(&dev->si_names)) { 261251881Speter adev = LIST_FIRST(&dev->si_names); 262251881Speter adev->si_drv1 = NULL; 263251881Speter freedev(adev); 264251881Speter } 265251881Speter LIST_REMOVE(dev, si_hash); 266251881Speter if (dev->si_flags & SI_STASHED) { 267251881Speter bzero(dev, sizeof(*dev)); 268251881Speter LIST_INSERT_HEAD(&dev_free, dev, si_hash); 269251881Speter } else { 270251881Speter FREE(dev, M_DEVT); 271251881Speter } 272251881Speter} 273251881Speter 274251881Speterudev_t 275251881Speterdev2udev(dev_t x) 276251881Speter{ 277251881Speter if (x == NODEV) 278251881Speter return NOUDEV; 279251881Speter return (x->si_udev); 280251881Speter} 281251881Speter 282251881Speterdev_t 283251881Speterudev2dev(udev_t x, int b) 284251881Speter{ 285251881Speter 286251881Speter if (x == NOUDEV) 287251881Speter return (NODEV); 288251881Speter switch (b) { 289251881Speter case 0: 290251881Speter return makedev(umajor(x), uminor(x)); 291251881Speter case 1: 292251881Speter return makebdev(umajor(x), uminor(x)); 293251881Speter default: 294251881Speter Debugger("udev2dev(...,X)"); 295251881Speter return NODEV; 296251881Speter } 297251881Speter} 298251881Speter 299251881Speterint 300251881Speteruminor(udev_t dev) 301251881Speter{ 302251881Speter return(dev & 0xffff00ff); 303251881Speter} 304251881Speter 305251881Speterint 306251881Speterumajor(udev_t dev) 307251881Speter{ 308251881Speter return((dev & 0xff00) >> 8); 309251881Speter} 310251881Speter 311251881Speterudev_t 312251881Spetermakeudev(int x, int y) 313251881Speter{ 314251881Speter return ((x << 8) | y); 315251881Speter} 316251881Speter 317251881Speterdev_t 318251881Spetermake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, char *fmt, ...) 319251881Speter{ 320251881Speter dev_t dev; 321251881Speter va_list ap; 322251881Speter int i; 323251881Speter 324251881Speter dev = makedev(devsw->d_maj, minor); 325251881Speter if (dev->si_flags & SI_NAMED) { 326251881Speter printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 327251881Speter dev->si_name); 328251881Speter return (dev); 329251881Speter } 330251881Speter va_start(ap, fmt); 331251881Speter i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 332251881Speter dev->si_name[i] = '\0'; 333251881Speter va_end(ap); 334251881Speter dev->si_devsw = devsw; 335251881Speter dev->si_uid = uid; 336251881Speter dev->si_gid = gid; 337251881Speter dev->si_mode = perms; 338251881Speter dev->si_flags |= SI_NAMED; 339251881Speter 340251881Speter if (devfs_create_hook) 341251881Speter devfs_create_hook(dev); 342251881Speter return (dev); 343251881Speter} 344251881Speter 345251881Speterdev_t 346251881Spetermake_dev_alias(dev_t pdev, char *fmt, ...) 347251881Speter{ 348251881Speter dev_t dev; 349251881Speter va_list ap; 350251881Speter int i; 351251881Speter 352251881Speter dev = allocdev(); 353251881Speter dev->si_flags |= SI_ALIAS; 354251881Speter dev->si_flags |= SI_NAMED; 355251881Speter dev->si_drv1 = pdev; 356251881Speter LIST_INSERT_HEAD(&pdev->si_names, dev, si_hash); 357251881Speter 358251881Speter va_start(ap, fmt); 359251881Speter i = kvprintf(fmt, NULL, dev->si_name, 32, ap); 360251881Speter dev->si_name[i] = '\0'; 361251881Speter va_end(ap); 362251881Speter 363251881Speter if (devfs_create_hook) 364251881Speter devfs_create_hook(dev); 365251881Speter return (dev); 366251881Speter} 367251881Speter 368251881Spetervoid 369251881Speterdestroy_dev(dev_t dev) 370251881Speter{ 371251881Speter 372251881Speter if (!(dev->si_flags & SI_NAMED)) { 373251881Speter printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 374251881Speter major(dev), minor(dev)); 375251881Speter return; 376251881Speter } 377251881Speter 378251881Speter if (devfs_destroy_hook) 379251881Speter devfs_destroy_hook(dev); 380251881Speter dev->si_drv1 = 0; 381251881Speter dev->si_drv2 = 0; 382251881Speter dev->si_devsw = 0; 383251881Speter dev->si_flags &= ~SI_NAMED; 384251881Speter dev->si_flags &= ~SI_ALIAS; 385251881Speter freedev(dev); 386251881Speter} 387251881Speter 388251881Speterconst char * 389251881Speterdevtoname(dev_t dev) 390251881Speter{ 391251881Speter char *p; 392251881Speter int mynor; 393251881Speter 394251881Speter if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 395251881Speter p = dev->si_name; 396251881Speter if (devsw(dev)) 397251881Speter sprintf(p, "#%s/", devsw(dev)->d_name); 398251881Speter else 399251881Speter sprintf(p, "#%d/", major(dev)); 400251881Speter p += strlen(p); 401251881Speter mynor = minor(dev); 402251881Speter if (mynor < 0 || mynor > 255) 403251881Speter sprintf(p, "%#x", (u_int)mynor); 404251881Speter else 405251881Speter sprintf(p, "%d", mynor); 406251881Speter } 407251881Speter return (dev->si_name); 408251881Speter} 409251881Speter 410251881Speterint 411251881Speterdev_stdclone(char *name, char **namep, char *stem, int *unit) 412251881Speter{ 413251881Speter int u, i; 414251881Speter 415251881Speter if (bcmp(stem, name, strlen(stem)) != 0) 416251881Speter return (0); 417251881Speter i = strlen(stem); 418251881Speter if (!isdigit(name[i])) 419251881Speter return (0); 420251881Speter u = 0; 421251881Speter while (isdigit(name[i])) { 422251881Speter u *= 10; 423251881Speter u += name[i++] - '0'; 424251881Speter } 425251881Speter *unit = u; 426251881Speter if (namep) 427251881Speter *namep = &name[i]; 428251881Speter if (name[i]) 429251881Speter return (2); 430251881Speter return (1); 431251881Speter} 432251881Speter 433251881Speter/* 434251881Speter * Helper sysctl for devname(3). We're given a {u}dev_t and return 435251881Speter * the name, if any, registered by the device driver. 436251881Speter */ 437251881Speterstatic int 438251881Spetersysctl_devname(SYSCTL_HANDLER_ARGS) 439251881Speter{ 440251881Speter int error; 441251881Speter udev_t ud; 442251881Speter dev_t dev; 443251881Speter 444251881Speter error = SYSCTL_IN(req, &ud, sizeof (ud)); 445251881Speter if (error) 446251881Speter return (error); 447251881Speter dev = makedev(umajor(ud), uminor(ud)); 448251881Speter if (dev->si_name[0] == '\0') 449251881Speter error = ENOENT; 450251881Speter else 451251881Speter error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 452251881Speter freedev(dev); 453251881Speter return (error); 454251881Speter} 455251881Speter 456251881SpeterSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 457251881Speter NULL, 0, sysctl_devname, "", "devname(3) handler"); 458251881Speter 459251881Speter