kern_conf.c revision 125846
111126Sjulian/*- 2103722Sphk * Copyright (c) 1999-2002 Poul-Henning Kamp 311126Sjulian * All rights reserved. 411126Sjulian * 511126Sjulian * Redistribution and use in source and binary forms, with or without 611126Sjulian * modification, are permitted provided that the following conditions 711126Sjulian * are met: 811126Sjulian * 1. Redistributions of source code must retain the above copyright 911126Sjulian * notice, this list of conditions and the following disclaimer. 1011126Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1111126Sjulian * notice, this list of conditions and the following disclaimer in the 1211126Sjulian * documentation and/or other materials provided with the distribution. 1311126Sjulian * 14103722Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15103722Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1611126Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17103722Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1811126Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1911126Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2011126Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2111126Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2211126Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2311126Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2411126Sjulian * SUCH DAMAGE. 2511126Sjulian */ 2611126Sjulian 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_conf.c 125846 2004-02-15 10:35:33Z phk $"); 29116182Sobrien 3011126Sjulian#include <sys/param.h> 3148936Sphk#include <sys/kernel.h> 3283366Sjulian#include <sys/systm.h> 33111179Sphk#include <sys/bio.h> 3490737Sgreen#include <sys/lock.h> 3590737Sgreen#include <sys/mutex.h> 3636735Sdfr#include <sys/sysctl.h> 3748936Sphk#include <sys/module.h> 3811126Sjulian#include <sys/malloc.h> 3912954Sjulian#include <sys/conf.h> 4048936Sphk#include <sys/vnode.h> 41120514Sphk#include <sys/queue.h> 4265374Sphk#include <sys/poll.h> 43126078Sphk#include <sys/ctype.h> 44147982Srwatson#include <machine/stdarg.h> 4549535Sphk 4611126Sjulianstatic MALLOC_DEFINE(M_DEVT, "dev_t", "dev_t storage"); 47149144Sphk 48149144Sphk/* Built at compile time from sys/conf/majors */ 49131996Sphkextern unsigned char reserved_majors[256]; 5048936Sphk 51150342Sphk/* 52142242Sphk * This is the number of hash-buckets. Experiements with 'real-life' 53147982Srwatson * udev_t's show that a prime halfway between two powers of two works 54147982Srwatson * best. 55147982Srwatson */ 56126082Sphk#define DEVT_HASH 83 57170950Skib 58170950Skib/* The number of dev_t's we can create before malloc(9) kick in. */ 59170950Skib#define DEVT_STASH 50 60135600Sphk 61135600Sphkstatic struct cdev devt_stash[DEVT_STASH]; 62126082Sphk 63151450Sjhbstatic LIST_HEAD(, cdev) dev_hash[DEVT_HASH]; 64126082Sphk 65126082Sphkstatic LIST_HEAD(, cdev) dev_free; 66126082Sphk 67170950Skibstatic int free_devt; 68170950SkibSYSCTL_INT(_debug, OID_AUTO, free_devt, CTLFLAG_RW, &free_devt, 0, ""); 69170950Skib 70170950Skibint 71170950Skibnullop(void) 72170950Skib{ 73170950Skib 74170950Skib return (0); 75170950Skib} 76170950Skib 77170950Skibint 78170950Skibeopnotsupp(void) 79170950Skib{ 80170950Skib 81170950Skib return (EOPNOTSUPP); 82170950Skib} 83170950Skib 84170950Skibstatic int 85170950Skibenxio(void) 86170950Skib{ 87170950Skib return (ENXIO); 88170950Skib} 89170950Skib 90170950Skibstatic int 91170950Skibenodev(void) 92135600Sphk{ 93135600Sphk return (ENODEV); 94126082Sphk} 95135704Sphk 96126082Sphk/* Define a dead_cdevsw for use when devices leave unexpectedly. */ 97126082Sphk 98126082Sphk#define dead_open (d_open_t *)enxio 99126082Sphk#define dead_close (d_close_t *)enxio 100144385Sphk#define dead_read (d_read_t *)enxio 101144385Sphk#define dead_write (d_write_t *)enxio 102144385Sphk#define dead_ioctl (d_ioctl_t *)enxio 103144385Sphk#define dead_poll (d_poll_t *)enodev 104144385Sphk#define dead_mmap (d_mmap_t *)enodev 105144385Sphk 106144385Sphkstatic void 107144385Sphkdead_strategy(struct bio *bp) 108144385Sphk{ 109144385Sphk 110144384Sphk biofinish(bp, NULL, ENXIO); 111126082Sphk} 112135704Sphk 113142232Sphk#define dead_dump (dumper_t *)enxio 114126082Sphk#define dead_kqfilter (d_kqfilter_t *)enxio 115126082Sphk 116126082Sphkstatic struct cdevsw dead_cdevsw = { 117126082Sphk .d_open = dead_open, 118142242Sphk .d_close = dead_close, 119126082Sphk .d_read = dead_read, 120142242Sphk .d_write = dead_write, 121135600Sphk .d_ioctl = dead_ioctl, 122136014Sphk .d_poll = dead_poll, 123136014Sphk .d_mmap = dead_mmap, 124126082Sphk .d_strategy = dead_strategy, 125126082Sphk .d_name = "dead", 126126082Sphk .d_maj = 255, 127150342Sphk .d_dump = dead_dump, 128142242Sphk .d_kqfilter = dead_kqfilter 129142242Sphk}; 130150342Sphk 131150342Sphk/* Default methods if driver does not specify method */ 132150342Sphk 133154029Sbz#define null_open (d_open_t *)nullop 134126082Sphk#define null_close (d_close_t *)nullop 135136014Sphk#define no_read (d_read_t *)enodev 136136014Sphk#define no_write (d_write_t *)enodev 137136014Sphk#define no_ioctl (d_ioctl_t *)enodev 138136014Sphk#define no_mmap (d_mmap_t *)enodev 139150342Sphk 140126082Sphkstatic int 141136014Sphkno_kqfilter(dev_t dev __unused, struct knote *kn __unused) 142135704Sphk{ 143135704Sphk 144135704Sphk return (1); 145135704Sphk} 146126082Sphk 147135704Sphkstatic void 148135704Sphkno_strategy(struct bio *bp) 149135704Sphk{ 150135704Sphk 151135704Sphk biofinish(bp, NULL, ENODEV); 152135704Sphk} 153135704Sphk 154135704Sphkstatic int 155135704Sphkno_poll(dev_t dev __unused, int events, struct thread *td __unused) 156163529Skib{ 157163529Skib /* 158163529Skib * Return true for read/write. If the user asked for something 159163529Skib * special, return POLLNVAL, so that clients have a way of 160163529Skib * determining reliably whether or not the extended 161163529Skib * functionality is present without hard-coding knowledge 162163529Skib * of specific filesystem implementations. 163163529Skib * Stay in sync with vop_nopoll(). 164163529Skib */ 165163529Skib if (events & ~POLLSTANDARD) 166163529Skib return (POLLNVAL); 167163529Skib 168163529Skib return (events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)); 169163529Skib} 170163529Skib 171163529Skib#define no_dump (dumper_t *)enodev 172163529Skib 173163529Skibstruct cdevsw * 174135704Sphkdevsw(dev_t dev) 175135704Sphk{ 176135704Sphk if (dev->si_devsw) 177135704Sphk return (dev->si_devsw); 178135704Sphk return (&dead_cdevsw); 179135704Sphk} 180135704Sphk 181135704Sphk/* 182135704Sphk * dev_t and u_dev_t primitives 183135704Sphk */ 184120514Sphk 185120514Sphkint 186120514Sphkmajor(dev_t x) 18785603Sphk{ 188120514Sphk if (x == NODEV) 189120514Sphk return NOUDEV; 190120514Sphk return((x->si_udev >> 8) & 0xff); 191120514Sphk} 192120514Sphk 193120514Sphkint 194120514Sphkminor(dev_t x) 195120514Sphk{ 196120514Sphk if (x == NODEV) 197120514Sphk return NOUDEV; 198111179Sphk return(x->si_udev & 0xffff00ff); 199111179Sphk} 200111179Sphk 201111179Sphkint 202111179Sphkdev2unit(dev_t x) 203111179Sphk{ 204120514Sphk int i; 205120514Sphk 206120514Sphk if (x == NODEV) 207120514Sphk return NOUDEV; 208120514Sphk i = minor(x); 209120514Sphk return ((i & 0xff) | (i >> 8)); 210120514Sphk} 211120514Sphk 212111179Sphkint 213111179Sphkunit2minor(int unit) 214111179Sphk{ 215111179Sphk 216111179Sphk KASSERT(unit <= 0xffffff, ("Invalid unit (%d) in unit2minor", unit)); 217120514Sphk return ((unit & 0xff) | ((unit << 8) & ~0xffff)); 218120514Sphk} 219111179Sphk 220111179Sphkstatic dev_t 221111179Sphkallocdev(void) 222111179Sphk{ 223111179Sphk static int stashed; 224111179Sphk struct cdev *si; 225111179Sphk 226111179Sphk if (LIST_FIRST(&dev_free)) { 227111220Sphk si = LIST_FIRST(&dev_free); 228111179Sphk LIST_REMOVE(si, si_hash); 229111179Sphk } else if (stashed >= DEVT_STASH) { 230111179Sphk MALLOC(si, struct cdev *, sizeof(*si), M_DEVT, 231126080Sphk M_USE_RESERVE | M_ZERO | M_WAITOK); 232126080Sphk } else { 233111815Sphk si = devt_stash + stashed++; 234111815Sphk bzero(si, sizeof *si); 235111815Sphk si->si_flags |= SI_STASHED; 236111815Sphk } 237111815Sphk si->__si_namebuf[0] = '\0'; 238111815Sphk si->si_name = si->__si_namebuf; 239111815Sphk LIST_INIT(&si->si_children); 240111815Sphk TAILQ_INIT(&si->si_snapshots); 241111815Sphk return (si); 242111815Sphk} 243111815Sphk 244111179Sphkdev_t 245111179Sphkmakedev(int x, int y) 246120514Sphk{ 247111179Sphk struct cdev *si; 248120514Sphk udev_t udev; 249120514Sphk int hash; 250120514Sphk 251120514Sphk if (x == umajor(NOUDEV) && y == uminor(NOUDEV)) 252120514Sphk panic("makedev of NOUDEV"); 253120514Sphk udev = (x << 8) | y; 254133741Sjmg hash = udev % DEVT_HASH; 255120514Sphk LIST_FOREACH(si, &dev_hash[hash], si_hash) { 256120514Sphk if (si->si_udev == udev) 257120514Sphk return (si); 258120514Sphk } 259120514Sphk si = allocdev(); 260120514Sphk si->si_udev = udev; 261120514Sphk LIST_INSERT_HEAD(&dev_hash[hash], si, si_hash); 262120514Sphk return (si); 263120514Sphk} 264130585Sphk 265120514Sphkvoid 266120514Sphkfreedev(dev_t dev) 267120514Sphk{ 268120514Sphk 269120514Sphk if (!free_devt) 270120514Sphk return; 271120514Sphk if (SLIST_FIRST(&dev->si_hlist)) 272120514Sphk return; 273120514Sphk if (dev->si_devsw || dev->si_drv1 || dev->si_drv2) 274120514Sphk return; 275120514Sphk LIST_REMOVE(dev, si_hash); 276120514Sphk if (dev->si_flags & SI_STASHED) { 277120514Sphk bzero(dev, sizeof(*dev)); 278120514Sphk dev->si_flags |= SI_STASHED; 279120514Sphk LIST_INSERT_HEAD(&dev_free, dev, si_hash); 280120514Sphk } else { 281120514Sphk FREE(dev, M_DEVT); 282149177Sphk } 283149177Sphk} 284149177Sphk 285149177Sphkudev_t 286149177Sphkdev2udev(dev_t x) 287149177Sphk{ 288149177Sphk if (x == NODEV) 289149177Sphk return NOUDEV; 290149177Sphk return (x->si_udev); 291149177Sphk} 292149177Sphk 293149177Sphkdev_t 294149177Sphkudev2dev(udev_t x, int b) 295170152Skib{ 296149177Sphk 297149177Sphk if (x == NOUDEV) 298149177Sphk return (NODEV); 299149177Sphk switch (b) { 300149177Sphk case 0: 301170152Skib return makedev(umajor(x), uminor(x)); 302149177Sphk case 1: 303149177Sphk return (NODEV); 304149177Sphk default: 305149177Sphk Debugger("udev2dev(...,X)"); 306149177Sphk return NODEV; 307149177Sphk } 308149177Sphk} 309149177Sphk 310149177Sphkint 311149177Sphkuminor(udev_t dev) 312149177Sphk{ 313149177Sphk return(dev & 0xffff00ff); 314149177Sphk} 315149177Sphk 316149177Sphkint 317149177Sphkumajor(udev_t dev) 318149177Sphk{ 319149177Sphk return((dev & 0xff00) >> 8); 320149177Sphk} 321149177Sphk 322149177Sphkudev_t 323149177Sphkmakeudev(int x, int y) 324149177Sphk{ 325149177Sphk return ((x << 8) | y); 326149177Sphk} 327149177Sphk 328149177Sphkstatic void 329149177Sphkprep_cdevsw(struct cdevsw *devsw) 330149177Sphk{ 331149177Sphk int i; 332149177Sphk 333149177Sphk if (devsw->d_open == NULL) devsw->d_open = null_open; 334149177Sphk if (devsw->d_close == NULL) devsw->d_close = null_close; 335149177Sphk if (devsw->d_read == NULL) devsw->d_read = no_read; 336149177Sphk if (devsw->d_write == NULL) devsw->d_write = no_write; 337149177Sphk if (devsw->d_ioctl == NULL) devsw->d_ioctl = no_ioctl; 338149177Sphk if (devsw->d_poll == NULL) devsw->d_poll = no_poll; 339149177Sphk if (devsw->d_mmap == NULL) devsw->d_mmap = no_mmap; 340149177Sphk if (devsw->d_strategy == NULL) devsw->d_strategy = no_strategy; 341149177Sphk if (devsw->d_dump == NULL) devsw->d_dump = no_dump; 342149177Sphk if (devsw->d_kqfilter == NULL) devsw->d_kqfilter = no_kqfilter; 343149177Sphk 344149177Sphk if (devsw->d_maj == MAJOR_AUTO) { 345149177Sphk for (i = NUMCDEVSW - 1; i > 0; i--) 346149177Sphk if (reserved_majors[i] != i) 347149177Sphk break; 348149177Sphk KASSERT(i > 0, ("Out of major numbers (%s)", devsw->d_name)); 349149177Sphk devsw->d_maj = i; 350149177Sphk reserved_majors[i] = i; 351149177Sphk } else { 352149177Sphk if (devsw->d_maj == 256) /* XXX: tty_cons.c is magic */ 353149177Sphk devsw->d_maj = 0; 354149177Sphk KASSERT(devsw->d_maj >= 0 && devsw->d_maj < 256, 355149177Sphk ("Invalid major (%d) in make_dev", devsw->d_maj)); 356149177Sphk if (reserved_majors[devsw->d_maj] != devsw->d_maj) { 357149177Sphk printf("WARNING: driver \"%s\" used %s %d\n", 358149177Sphk devsw->d_name, "unreserved major device number", 359149177Sphk devsw->d_maj); 360149177Sphk reserved_majors[devsw->d_maj] = devsw->d_maj; 361149177Sphk } 362149177Sphk } 363149177Sphk} 364149177Sphk 365149177Sphkdev_t 366149177Sphkmake_dev(struct cdevsw *devsw, int minor, uid_t uid, gid_t gid, int perms, const char *fmt, ...) 367149177Sphk{ 368149177Sphk dev_t dev; 369149177Sphk va_list ap; 370149177Sphk int i; 371149177Sphk 372149177Sphk KASSERT((minor & ~0xffff00ff) == 0, 373149177Sphk ("Invalid minor (0x%x) in make_dev", minor)); 374149177Sphk 375149177Sphk prep_cdevsw(devsw); 376149177Sphk dev = makedev(devsw->d_maj, minor); 377149177Sphk if (dev->si_flags & SI_CHEAPCLONE && 378149177Sphk dev->si_flags & SI_NAMED && 379149177Sphk dev->si_devsw == devsw) { 380149177Sphk /* 381149177Sphk * This is allowed as it removes races and generally 382149177Sphk * simplifies cloning devices. 383149177Sphk */ 384149177Sphk return (dev); 385149177Sphk } 386149177Sphk if (dev->si_flags & SI_NAMED) { 387149177Sphk printf( "WARNING: Driver mistake: repeat make_dev(\"%s\")\n", 388149177Sphk dev->si_name); 389149177Sphk panic("don't do that"); 390149177Sphk } 391149177Sphk va_start(ap, fmt); 392149177Sphk i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 393149177Sphk if (i > (sizeof dev->__si_namebuf - 1)) { 394149177Sphk printf("WARNING: Device name truncated! (%s)", 395149177Sphk dev->__si_namebuf); 396149177Sphk } 397149177Sphk va_end(ap); 398149177Sphk dev->si_devsw = devsw; 399149177Sphk dev->si_uid = uid; 400149177Sphk dev->si_gid = gid; 40147640Sphk dev->si_mode = perms; 402130936Sle dev->si_flags |= SI_NAMED; 40347028Sphk 40447028Sphk devfs_create(dev); 40547028Sphk return (dev); 406130585Sphk} 40747028Sphk 408130640Sphkint 409130640Sphkdev_named(dev_t pdev, const char *name) 410143631Sphk{ 41147028Sphk dev_t cdev; 41247028Sphk 41349826Sphk if (strcmp(devtoname(pdev), name) == 0) 414130585Sphk return (1); 41549826Sphk LIST_FOREACH(cdev, &pdev->si_children, si_siblings) 41649826Sphk if (strcmp(devtoname(cdev), name) == 0) 417130640Sphk return (1); 418130640Sphk return (0); 419140964Sphk} 42049826Sphk 42149826Sphkvoid 422143282Sphkdev_depends(dev_t pdev, dev_t cdev) 423143282Sphk{ 424140963Sphk 425140963Sphk cdev->si_parent = pdev; 426140969Sphk cdev->si_flags |= SI_CHILD; 427143282Sphk LIST_INSERT_HEAD(&pdev->si_children, cdev, si_siblings); 428140963Sphk} 429140963Sphk 430140963Sphkdev_t 43166067Sphkmake_dev_alias(dev_t pdev, const char *fmt, ...) 43266067Sphk{ 43366067Sphk dev_t dev; 43474522Sphk va_list ap; 43566067Sphk int i; 43666067Sphk 43766067Sphk dev = allocdev(); 438130585Sphk dev->si_flags |= SI_ALIAS; 439144281Sphk dev->si_flags |= SI_NAMED; 44047028Sphk dev_depends(pdev, dev); 441140733Sphk va_start(ap, fmt); 442130640Sphk i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap); 44348936Sphk if (i > (sizeof dev->__si_namebuf - 1)) { 444140733Sphk printf("WARNING: Device name truncated! (%s)", 445144292Sphk dev->__si_namebuf); 446144281Sphk } 447143631Sphk va_end(ap); 448170950Skib 449140733Sphk devfs_create(dev); 450140733Sphk return (dev); 45148936Sphk} 452143631Sphk 453150342Sphkvoid 454144281Sphkdestroy_dev(dev_t dev) 455125850Sbde{ 45647028Sphk 45747028Sphk if (!(dev->si_flags & SI_NAMED)) { 45847028Sphk printf( "WARNING: Driver mistake: destroy_dev on %d/%d\n", 459130640Sphk major(dev), minor(dev)); 46047028Sphk panic("don't do that"); 461140969Sphk } 46247028Sphk 46347028Sphk devfs_destroy(dev); 46447028Sphk if (dev->si_flags & SI_CHILD) { 465130640Sphk LIST_REMOVE(dev, si_siblings); 46647028Sphk dev->si_flags &= ~SI_CHILD; 467140969Sphk } 46847028Sphk while (!LIST_EMPTY(&dev->si_children)) 46947028Sphk destroy_dev(LIST_FIRST(&dev->si_children)); 470125846Sphk dev->si_drv1 = 0; 471144292Sphk dev->si_drv2 = 0; 47249535Sphk dev->si_devsw = 0; 473149324Sphk bzero(&dev->__si_u, sizeof(dev->__si_u)); 47449535Sphk dev->si_flags &= ~SI_NAMED; 475149324Sphk dev->si_flags &= ~SI_ALIAS; 476149324Sphk freedev(dev); 477149324Sphk} 478149324Sphk 479149324Sphkconst char * 480149324Sphkdevtoname(dev_t dev) 481126156Sphk{ 482126082Sphk char *p; 483126082Sphk int mynor; 484126082Sphk 485126077Sphk if (dev->si_name[0] == '#' || dev->si_name[0] == '\0') { 486126077Sphk p = dev->si_name; 487149177Sphk if (devsw(dev)) 488126077Sphk sprintf(p, "#%s/", devsw(dev)->d_name); 489149177Sphk else 490149177Sphk sprintf(p, "#%d/", major(dev)); 491149177Sphk p += strlen(p); 492149177Sphk mynor = minor(dev); 493135600Sphk if (mynor < 0 || mynor > 255) 494126082Sphk sprintf(p, "%#x", (u_int)mynor); 495143746Sphk else 496126082Sphk sprintf(p, "%d", mynor); 497126082Sphk } 498154266Salfred return (dev->si_name); 499154266Salfred} 500126082Sphk 501126082Sphkint 502126082Sphkdev_stdclone(char *name, char **namep, const char *stem, int *unit) 503126082Sphk{ 504126082Sphk int u, i; 505126082Sphk 506126082Sphk i = strlen(stem); 507126082Sphk if (bcmp(stem, name, i) != 0) 508126082Sphk return (0); 509126082Sphk if (!isdigit(name[i])) 510126082Sphk return (0); 511126082Sphk u = 0; 512126078Sphk if (name[i] == '0' && isdigit(name[i+1])) 513129943Sphk return (0); 514126078Sphk while (isdigit(name[i])) { 515126078Sphk u *= 10; 516126078Sphk u += name[i++] - '0'; 517126078Sphk } 518126078Sphk if (u > 0xffffff) 519126078Sphk return (0); 520149177Sphk *unit = u; 521149177Sphk if (namep) 522149177Sphk *namep = &name[i]; 523149177Sphk if (name[i]) 524149177Sphk return (2); 525149177Sphk return (1); 526149177Sphk} 527149177Sphk 528149177Sphk/* 529149177Sphk * Helper sysctl for devname(3). We're given a {u}dev_t and return 530149177Sphk * the name, if any, registered by the device driver. 531149177Sphk */ 532149177Sphkstatic int 533149177Sphksysctl_devname(SYSCTL_HANDLER_ARGS) 534149177Sphk{ 535149177Sphk int error; 536149177Sphk udev_t ud; 537149177Sphk dev_t dev; 538149177Sphk 539149177Sphk error = SYSCTL_IN(req, &ud, sizeof (ud)); 540149177Sphk if (error) 541149177Sphk return (error); 542149177Sphk if (ud == NOUDEV) 543149177Sphk return(EINVAL); 544149177Sphk dev = makedev(umajor(ud), uminor(ud)); 545149177Sphk if (dev->si_name[0] == '\0') 546149177Sphk error = ENOENT; 547149177Sphk else 548120514Sphk error = SYSCTL_OUT(req, dev->si_name, strlen(dev->si_name) + 1); 549126082Sphk freedev(dev); 550126082Sphk return (error); 551126082Sphk} 552126082Sphk 553126082SphkSYSCTL_PROC(_kern, OID_AUTO, devname, CTLTYPE_OPAQUE|CTLFLAG_RW|CTLFLAG_ANYBODY, 554135600Sphk NULL, 0, sysctl_devname, "", "devname(3) handler"); 555125846Sphk