Annotation of XNU/bsd/miscfs/devfs/devfs_tree.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: 
        !            23: /*
        !            24:  * Copyright 1997,1998 Julian Elischer.  All rights reserved.
        !            25:  * [email protected]
        !            26:  * 
        !            27:  * Redistribution and use in source and binary forms, with or without
        !            28:  * modification, are permitted provided that the following conditions are
        !            29:  * met:
        !            30:  *  1. Redistributions of source code must retain the above copyright
        !            31:  *     notice, this list of conditions and the following disclaimer.
        !            32:  *  2. Redistributions in binary form must reproduce the above copyright notice,
        !            33:  *     this list of conditions and the following disclaimer in the documentation
        !            34:  *     and/or other materials provided with the distribution.
        !            35:  * 
        !            36:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
        !            37:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            38:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
        !            39:  * DISCLAIMED.  IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR
        !            40:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            41:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
        !            42:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
        !            43:  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            44:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            45:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            46:  * SUCH DAMAGE.
        !            47:  * 
        !            48:  * devfs_tree.c
        !            49:  */
        !            50: 
        !            51: /*
        !            52:  * HISTORY
        !            53:  *  Dieter Siegmund ([email protected]) Thu Apr  8 14:08:19 PDT 1999
        !            54:  *  - removed mounting of "hidden" mountpoint
        !            55:  *  - fixed problem in which devnode->dn_vn pointer was not
        !            56:  *    updated with the vnode returned from checkalias()
        !            57:  *  - replaced devfs_vntodn() with a macro VTODN()
        !            58:  *  - rewrote dev_finddir() to not use recursion
        !            59:  *  - added locking to avoid data structure corruption (DEVFS_(UN)LOCK())
        !            60:  *  Dieter Siegmund ([email protected]) Wed Jul 14 13:37:59 PDT 1999
        !            61:  *  - fixed problem with devfs_dntovn() checking the v_id against the
        !            62:  *    value cached in the device node; a union mount on top of us causes
        !            63:  *    the v_id to get incremented thus, we would end up returning a new
        !            64:  *    vnode instead of the existing one that has the mounted_here
        !            65:  *    field filled in; the net effect was that the filesystem mounted
        !            66:  *    on top of us would never show up
        !            67:  *  - added devfs_stats to store how many data structures are actually 
        !            68:  *    allocated
        !            69:  */
        !            70: 
        !            71: /* SPLIT_DEVS means each devfs uses a different devnode for the same device */
        !            72: /* Otherwise the same device always ends up at the same vnode even if  */
        !            73: /* reached througgh a different devfs instance. The practical difference */
        !            74: /* is that with the same vnode, chmods and chowns show up on all instances of */
        !            75: /* a device. (etc) */
        !            76: 
        !            77: #define SPLIT_DEVS 1 /* maybe make this an option */
        !            78: /*#define SPLIT_DEVS 1*/
        !            79: 
        !            80: #include <sys/param.h>
        !            81: #include <sys/systm.h>
        !            82: #include <sys/kernel.h>
        !            83: #include <sys/conf.h>
        !            84: #include <sys/malloc.h>
        !            85: #include <sys/mount.h>
        !            86: #include <sys/proc.h>
        !            87: #include <sys/vnode.h>
        !            88: #include <stdarg.h>
        !            89: 
        !            90: #include "devfs.h"
        !            91: #include "devfsdefs.h"
        !            92: 
        !            93: struct lock__bsd__     devfs_lock;             /* the "big switch" */
        !            94: devdirent_t *          dev_root = NULL;        /* root of backing tree */
        !            95: struct devfs_stats     devfs_stats;            /* hold stats */
        !            96: 
        !            97: #ifdef HIDDEN_MOUNTPOINT
        !            98: static struct mount *devfs_hidden_mount;
        !            99: #endif HIDDEN_MOINTPOINT
        !           100: 
        !           101: static int devfs_ready = 0;
        !           102: 
        !           103: #define NOCREATE       FALSE
        !           104: #define CREATE         TRUE
        !           105: 
        !           106: /*
        !           107:  * Set up the root directory node in the backing plane
        !           108:  * This is happenning before the vfs system has been
        !           109:  * set up yet, so be careful about what we reference..
        !           110:  * Notice that the ops are by indirection.. as they haven't
        !           111:  * been set up yet!
        !           112:  * DEVFS has a hidden mountpoint that is used as the anchor point
        !           113:  * for the internal 'blueprint' version of the dev filesystem tree.
        !           114:  */
        !           115: /*proto*/
        !           116: int
        !           117: devfs_sinit(void)
        !           118: {
        !           119:        lockinit(&devfs_lock, PINOD, "devfs", 0, 0);
        !           120:         if (dev_add_entry("root", NULL, DEV_DIR, NULL, NULL, NULL, 
        !           121:                          &dev_root)) {
        !           122:            printf("devfs_sinit: dev_add_entry failed ");
        !           123:            return (EOPNOTSUPP);
        !           124:        }
        !           125: #ifdef HIDDEN_MOUNTPOINT
        !           126:        MALLOC(devfs_hidden_mount, struct mount *, sizeof(struct mount),
        !           127:               M_MOUNT, M_NOWAIT);
        !           128:        bzero(devfs_hidden_mount,sizeof(struct mount));
        !           129:        devfs_mount(devfs_hidden_mount,"dummy",NULL,NULL,NULL);
        !           130:        dev_root->de_dnp->dn_dvm 
        !           131:            = (struct devfsmount *)devfs_hidden_mount->mnt_data;
        !           132: #endif HIDDEN_MOUNTPOINT
        !           133:        devfs_ready = 1;
        !           134:        return (0);
        !           135: }
        !           136: 
        !           137: /***********************************************************************\
        !           138: *************************************************************************
        !           139: *      Routines used to find our way to a point in the tree            *
        !           140: *************************************************************************
        !           141: \***********************************************************************/
        !           142: 
        !           143: 
        !           144: /***************************************************************\
        !           145: * Search down the linked list off a dir to find "name"         *
        !           146: * return the devnode_t * for that node.
        !           147: \***************************************************************/
        !           148: /*proto*/
        !           149: devdirent_t *
        !           150: dev_findname(devnode_t * dir,char *name)
        !           151: {
        !           152:        devdirent_t * newfp;
        !           153:        if (dir->dn_type != DEV_DIR) return 0;/*XXX*/ /* printf?*/
        !           154: 
        !           155:        if (name[0] == '.')
        !           156:        {
        !           157:                if(name[1] == 0)
        !           158:                {
        !           159:                        return dir->dn_typeinfo.Dir.myname;
        !           160:                }
        !           161:                if((name[1] == '.') && (name[2] == 0))
        !           162:                {
        !           163:                        /* for root, .. == . */
        !           164:                        return dir->dn_typeinfo.Dir.parent->dn_typeinfo.Dir.myname;
        !           165:                }
        !           166:        }
        !           167:        newfp = dir->dn_typeinfo.Dir.dirlist;
        !           168:        while(newfp)
        !           169:        {
        !           170:                if(!(strcmp(name,newfp->de_name)))
        !           171:                        return newfp;
        !           172:                newfp = newfp->de_next;
        !           173:        }
        !           174:        return NULL;
        !           175: }
        !           176: 
        !           177: #if 0
        !           178: /***********************************************************************\
        !           179: * Given a starting node (0 for root) and a pathname, return the node   *
        !           180: * for the end item on the path. It MUST BE A DIRECTORY. If the 'CREATE'        *
        !           181: * option is true, then create any missing nodes in the path and create *
        !           182: * and return the final node as well.                                   *
        !           183: * This is used to set up a directory, before making nodes in it..      *
        !           184: *                                                                      *
        !           185: * Warning: This function is RECURSIVE.                                 *
        !           186: \***********************************************************************/
        !           187: int
        !           188: dev_finddir(char * orig_path,  /* find this dir (err if not dir) */
        !           189:            devnode_t * dirnode,        /* starting point */
        !           190:            int create,         /* create path? */
        !           191:            devnode_t * * dn_pp)        /* returned */
        !           192: {
        !           193:        devdirent_t *   dirent_p;
        !           194:        devnode_t *     dnp = NULL;
        !           195:        char    pathbuf[DEVMAXPATHSIZE];
        !           196:        char    *path;
        !           197:        char    *name;
        !           198:        register char *cp;
        !           199:        int     retval;
        !           200: 
        !           201: 
        !           202:        /***************************************\
        !           203:        * If no parent directory is given       *
        !           204:        * then start at the root of the tree    *
        !           205:        \***************************************/
        !           206:        if(!dirnode) dirnode = dev_root->de_dnp;
        !           207: 
        !           208:        /***************************************\
        !           209:        * Sanity Checks                         *
        !           210:        \***************************************/
        !           211:        if (dirnode->dn_type != DEV_DIR) return ENOTDIR;
        !           212:        if(strlen(orig_path) > (DEVMAXPATHSIZE - 1)) return ENAMETOOLONG;
        !           213: 
        !           214: 
        !           215:        path = pathbuf;
        !           216:        strcpy(path,orig_path);
        !           217: 
        !           218:        /***************************************\
        !           219:        * always absolute, skip leading /       *
        !           220:        *  get rid of / or // or /// etc.       *
        !           221:        \***************************************/
        !           222:        while(*path == '/') path++;
        !           223: 
        !           224:        /***************************************\
        !           225:        * If nothing left, then parent was it.. *
        !           226:        \***************************************/
        !           227:        if ( *path == '\0' ) {
        !           228:                *dn_pp = dirnode;
        !           229:                return 0;
        !           230:        }
        !           231: 
        !           232:        /***************************************\
        !           233:        * find the next segment of the name     *
        !           234:        \***************************************/
        !           235:        cp = name = path;
        !           236:        while((*cp != '/') && (*cp != 0)) {
        !           237:                cp++;
        !           238:        }
        !           239: 
        !           240:        /***********************************************\
        !           241:        * Check to see if it's the last component       *
        !           242:        \***********************************************/
        !           243:        if(*cp) {
        !           244:                path = cp + 1;  /* path refers to the rest */
        !           245:                *cp = 0;        /* name is now a separate string */
        !           246:                if(!(*path)) {
        !           247:                        path = (char *)0; /* was trailing slash */
        !           248:                }
        !           249:        } else {
        !           250:                path = NULL;    /* no more to do */
        !           251:        }
        !           252: 
        !           253:        /***************************************\
        !           254:        * Start scanning along the linked list  *
        !           255:        \***************************************/
        !           256:        dirent_p = dev_findname(dirnode,name);
        !           257:        if(dirent_p) {  /* check it's a directory */
        !           258:                dnp = dirent_p->de_dnp;
        !           259:                if(dnp->dn_type != DEV_DIR) return ENOTDIR;
        !           260:        } else {
        !           261:                /***************************************\
        !           262:                * The required element does not exist   *
        !           263:                * So we will add it if asked to.        *
        !           264:                \***************************************/
        !           265:                if(!create) return ENOENT;
        !           266: 
        !           267:                if((retval = dev_add_entry(name, dirnode, 
        !           268:                                           DEV_DIR, NULL, NULL, NULL, 
        !           269:                                           &dirent_p)) != 0) {
        !           270:                        return retval;
        !           271:                }
        !           272:                dnp = dirent_p->de_dnp;
        !           273:                devfs_propogate(dirnode->dn_typeinfo.Dir.myname,dirent_p);
        !           274:        }
        !           275:        if(path != NULL) {      /* decide whether to recurse more or return */
        !           276:                return (dev_finddir(path,dnp,create,dn_pp));
        !           277:        } else {
        !           278:                *dn_pp = dnp;
        !           279:                return 0;
        !           280:        }
        !           281: }
        !           282: #endif 0
        !           283: /***********************************************************************\
        !           284: * Given a starting node (0 for root) and a pathname, return the node   *
        !           285: * for the end item on the path. It MUST BE A DIRECTORY. If the 'CREATE'        *
        !           286: * option is true, then create any missing nodes in the path and create *
        !           287: * and return the final node as well.                                   *
        !           288: * This is used to set up a directory, before making nodes in it..      *
        !           289: \***********************************************************************/
        !           290: /* proto */
        !           291: int
        !           292: dev_finddir(char * path, 
        !           293:            devnode_t * dirnode,
        !           294:            int create, 
        !           295:            devnode_t * * dn_pp)
        !           296: {
        !           297:        devnode_t *     dnp = NULL;
        !           298:        int             error = 0;
        !           299:        char *          scan;
        !           300: 
        !           301: 
        !           302:        if (!dirnode) /* dirnode == NULL means start at root */
        !           303:            dirnode = dev_root->de_dnp;
        !           304: 
        !           305:        if (dirnode->dn_type != DEV_DIR) 
        !           306:            return ENOTDIR;
        !           307: 
        !           308:        if (strlen(path) > (DEVMAXPATHSIZE - 1)) 
        !           309:            return ENAMETOOLONG;
        !           310: 
        !           311:        scan = path;
        !           312: 
        !           313:        while (*scan == '/') 
        !           314:            scan++;
        !           315: 
        !           316:        *dn_pp = NULL;
        !           317: 
        !           318:        while (1) {
        !           319:            char                component[DEVMAXPATHSIZE];
        !           320:            devdirent_t *       dirent_p;
        !           321:            char *              start;
        !           322: 
        !           323:            if (*scan == 0) { 
        !           324:                /* we hit the end of the string, we're done */
        !           325:                *dn_pp = dirnode;
        !           326:                break;
        !           327:            }
        !           328:            start = scan;
        !           329:            while (*scan != '/' && *scan)
        !           330:                scan++;
        !           331: 
        !           332:            strncpy(component, start, scan - start);
        !           333:            if (*scan == '/')
        !           334:                scan++;
        !           335: 
        !           336:            dirent_p = dev_findname(dirnode, component);
        !           337:            if (dirent_p) {
        !           338:                dnp = dirent_p->de_dnp;
        !           339:                if (dnp->dn_type != DEV_DIR) {
        !           340:                    error = ENOTDIR;
        !           341:                    break;
        !           342:                }
        !           343:            }
        !           344:            else {
        !           345:                if (!create) {
        !           346:                    error = ENOENT;
        !           347:                    break;
        !           348:                }
        !           349:                error = dev_add_entry(component, dirnode, 
        !           350:                                       DEV_DIR, NULL, NULL, NULL, &dirent_p);
        !           351:                if (error)
        !           352:                    break;
        !           353:                dnp = dirent_p->de_dnp;
        !           354:                devfs_propogate(dirnode->dn_typeinfo.Dir.myname, dirent_p);
        !           355:            }
        !           356:            dirnode = dnp; /* continue relative to this directory */
        !           357:        }
        !           358:        return (error);
        !           359: }
        !           360: 
        !           361: 
        !           362: /***********************************************************************\
        !           363: * Add a new NAME element to the devfs                                  *
        !           364: * If we're creating a root node, then dirname is NULL                  *
        !           365: * Basically this creates a new namespace entry for the device node     *
        !           366: *                                                                      *
        !           367: * Creates a name node, and links it to the supplied node               *
        !           368: \***********************************************************************/
        !           369: /*proto*/
        !           370: int
        !           371: dev_add_name(char * name, devnode_t * dirnode, devdirent_t * back, 
        !           372:     devnode_t * dnp, devdirent_t * *dirent_pp)
        !           373: {
        !           374:        devdirent_t *   dirent_p = NULL;
        !           375: 
        !           376:        if(dirnode != NULL ) {
        !           377:                if(dirnode->dn_type != DEV_DIR) return(ENOTDIR);
        !           378:        
        !           379:                if( dev_findname(dirnode,name))
        !           380:                        return(EEXIST);
        !           381:        }
        !           382:        /*
        !           383:         * make sure the name is legal
        !           384:         * slightly misleading in the case of NULL
        !           385:         */
        !           386:        if (!name || (strlen(name) > (DEVMAXNAMESIZE - 1)))
        !           387:            return (ENAMETOOLONG);
        !           388: 
        !           389:        /*
        !           390:         * Allocate and fill out a new directory entry 
        !           391:         */
        !           392:        MALLOC(dirent_p, devdirent_t *, sizeof(devdirent_t), 
        !           393:               M_DEVFSNAME, M_NOWAIT);
        !           394:        if (!dirent_p) {
        !           395:            return ENOMEM;
        !           396:        }
        !           397:        bzero(dirent_p,sizeof(devdirent_t));
        !           398: 
        !           399:        /* inherrit our parent's mount info */ /*XXX*/
        !           400:        /* a kludge but.... */
        !           401:        if(dirnode && ( dnp->dn_dvm == NULL)) {
        !           402:                dnp->dn_dvm = dirnode->dn_dvm;
        !           403:                /* if(!dnp->dn_dvm) printf("parent had null dvm "); */
        !           404:        }
        !           405: 
        !           406:        /*
        !           407:         * Link the two together
        !           408:         * include the implicit link in the count of links to the devnode..
        !           409:         * this stops it from being accidentally freed later.
        !           410:         */
        !           411:        dirent_p->de_dnp = dnp;
        !           412:        dnp->dn_links++ ; /* implicit from our own name-node */
        !           413: 
        !           414:        /* 
        !           415:         * Make sure that we can find all the links that reference a node
        !           416:         * so that we can get them all if we need to zap the node.
        !           417:         */
        !           418:        if(dnp->dn_linklist) {
        !           419:                dirent_p->de_nextlink = dnp->dn_linklist;
        !           420:                dirent_p->de_prevlinkp = dirent_p->de_nextlink->de_prevlinkp;
        !           421:                dirent_p->de_nextlink->de_prevlinkp = &(dirent_p->de_nextlink);
        !           422:                *dirent_p->de_prevlinkp = dirent_p;
        !           423:        } else {
        !           424:                dirent_p->de_nextlink = dirent_p;
        !           425:                dirent_p->de_prevlinkp = &(dirent_p->de_nextlink);
        !           426:        }
        !           427:        dnp->dn_linklist = dirent_p;
        !           428: 
        !           429:        /*
        !           430:         * If the node is a directory, then we need to handle the 
        !           431:         * creation of the .. link.
        !           432:         * A NULL dirnode indicates a root node, so point to ourself.
        !           433:         */
        !           434:        if(dnp->dn_type == DEV_DIR) {
        !           435:                dnp->dn_typeinfo.Dir.myname = dirent_p;
        !           436:                /*
        !           437:                 * If we are unlinking from an old dir, decrement its links
        !           438:                 * as we point our '..' elsewhere
        !           439:                 * Note: it's up to the calling code to remove the 
        !           440:                 * us from the original directory's list
        !           441:                 */
        !           442:                if(dnp->dn_typeinfo.Dir.parent) {
        !           443:                        dnp->dn_typeinfo.Dir.parent->dn_links--;
        !           444:                }
        !           445:                if(dirnode) {
        !           446:                        dnp->dn_typeinfo.Dir.parent = dirnode;
        !           447:                } else {
        !           448:                        dnp->dn_typeinfo.Dir.parent = dnp;
        !           449:                }
        !           450:                dnp->dn_typeinfo.Dir.parent->dn_links++; /* account for the new '..' */
        !           451:        }
        !           452: 
        !           453:        /*
        !           454:         * put the name into the directory entry.
        !           455:         */
        !           456:        strcpy(dirent_p->de_name, name);
        !           457: 
        !           458: 
        !           459:        /*
        !           460:         * Check if we are not making a root node..
        !           461:         * (i.e. have parent)
        !           462:         */
        !           463:        if(dirnode) {
        !           464:                /*
        !           465:                 * Put it on the END of the linked list of directory entries
        !           466:                 */
        !           467:                int len;
        !           468: 
        !           469:                dirent_p->de_parent = dirnode; /* null for root */
        !           470:                dirent_p->de_prevp = dirnode->dn_typeinfo.Dir.dirlast;
        !           471:                dirent_p->de_next = *(dirent_p->de_prevp); /* should be NULL */ 
        !           472:                                                        /*right?*/
        !           473:                *(dirent_p->de_prevp) = dirent_p;
        !           474:                dirnode->dn_typeinfo.Dir.dirlast = &(dirent_p->de_next);
        !           475:                dirnode->dn_typeinfo.Dir.entrycount++;
        !           476:                dirnode->dn_len += strlen(name) + 8;/*ok, ok?*/
        !           477:        }
        !           478: 
        !           479:        *dirent_pp = dirent_p;
        !           480:        DEVFS_INCR_ENTRIES();
        !           481:        return 0 ;
        !           482: }
        !           483: 
        !           484: 
        !           485: /***********************************************************************\
        !           486: * Add a new element to the devfs plane.                                *
        !           487: *                                                                      *
        !           488: * Creates a new dev_node to go with it if the prototype should not be  *
        !           489: * reused. (Is a DIR, or we select SPLIT_DEVS at compile time)          *
        !           490: * typeinfo gives us info to make our node if we don't have a prototype.        *
        !           491: * If typeinfo is null and proto exists, then the typeinfo field of     *
        !           492: * the proto is used intead in the CREATE case.                         *
        !           493: * note the 'links' count is 0 (except if a dir)                                *
        !           494: * but it is only cleared on a transition                               *
        !           495: * so this is ok till we link it to something                           *
        !           496: * Even in SPLIT_DEVS mode,                                             *
        !           497: * if the node already exists on the wanted plane, just return it       *
        !           498: \***********************************************************************/
        !           499: /*proto*/
        !           500: int
        !           501: dev_add_node(int entrytype, devnode_type_t * typeinfo, devnode_t * proto,
        !           502:             devnode_t * *dn_pp, struct devfsmount *dvm)
        !           503: {
        !           504:        devnode_t *     dnp = NULL;
        !           505: 
        !           506: #if defined SPLIT_DEVS
        !           507:        /*
        !           508:         * If we have a prototype, then check if there is already a sibling
        !           509:         * on the mount plane we are looking at, if so, just return it.
        !           510:         */
        !           511:        if (proto) {
        !           512:                dnp = proto->dn_nextsibling;
        !           513:                while( dnp != proto) {
        !           514:                        if (dnp->dn_dvm == dvm) {
        !           515:                                *dn_pp = dnp;
        !           516:                                return (0);
        !           517:                        }
        !           518:                        dnp = dnp->dn_nextsibling;
        !           519:                }
        !           520:                if (typeinfo == NULL)
        !           521:                        typeinfo = &(proto->dn_typeinfo);
        !           522:        }
        !           523: #else  /* SPLIT_DEVS */
        !           524:        if ( proto ) {
        !           525:                switch (proto->type) {
        !           526:                        case DEV_BDEV:
        !           527:                        case DEV_CDEV:
        !           528:                                *dn_pp = proto;
        !           529:                                return 0;
        !           530:                }
        !           531:        }
        !           532: #endif /* SPLIT_DEVS */
        !           533:        MALLOC(dnp, devnode_t *, sizeof(devnode_t), M_DEVFSNODE, M_NOWAIT);
        !           534:        if (!dnp) {
        !           535:            return ENOMEM;
        !           536:        }
        !           537: 
        !           538:        /*
        !           539:         * If we have a proto, that means that we are duplicating some
        !           540:         * other device, which can only happen if we are not at the back plane
        !           541:         */
        !           542:        if(proto) {
        !           543:                bcopy(proto, dnp, sizeof(devnode_t));
        !           544:                dnp->dn_links = 0;
        !           545:                dnp->dn_linklist = NULL;
        !           546:                dnp->dn_vn = NULL;
        !           547:                dnp->dn_len = 0;
        !           548:                /* add to END of siblings list */
        !           549:                dnp->dn_prevsiblingp = proto->dn_prevsiblingp;
        !           550:                *(dnp->dn_prevsiblingp) = dnp;
        !           551:                dnp->dn_nextsibling = proto;
        !           552:                proto->dn_prevsiblingp = &(dnp->dn_nextsibling);
        !           553:        } else {
        !           554:                struct timeval tv;
        !           555: 
        !           556:                /* 
        !           557:                 * We have no prototype, so start off with a clean slate
        !           558:                 */
        !           559:                tv = time;
        !           560:                bzero(dnp,sizeof(devnode_t));
        !           561:                dnp->dn_type = entrytype;
        !           562:                dnp->dn_nextsibling = dnp;
        !           563:                dnp->dn_prevsiblingp = &(dnp->dn_nextsibling);
        !           564:                dnp->dn_atime.tv_sec = tv.tv_sec;
        !           565:                dnp->dn_mtime.tv_sec = tv.tv_sec;
        !           566:                dnp->dn_ctime.tv_sec = tv.tv_sec;
        !           567:        }
        !           568:        dnp->dn_dvm = dvm;
        !           569: 
        !           570:        /*
        !           571:         * fill out the dev node according to type
        !           572:         */
        !           573:        switch(entrytype) {
        !           574:        case DEV_DIR:
        !           575:                /*
        !           576:                 * As it's a directory, make sure
        !           577:                 * it has a null entries list
        !           578:                 */
        !           579:                dnp->dn_typeinfo.Dir.dirlast = &(dnp->dn_typeinfo.Dir.dirlist);
        !           580:                dnp->dn_typeinfo.Dir.dirlist = (devdirent_t *)0;
        !           581:                dnp->dn_typeinfo.Dir.entrycount = 0;
        !           582:                /*  until we know better, it has a null parent pointer*/
        !           583:                dnp->dn_typeinfo.Dir.parent = NULL;
        !           584:                dnp->dn_links++; /* for .*/
        !           585:                dnp->dn_typeinfo.Dir.myname = NULL;
        !           586:                /*
        !           587:                 * make sure that the ops associated with it are the ops
        !           588:                 * that we use (by default) for directories
        !           589:                 */
        !           590:                dnp->dn_ops = &devfs_vnodeop_p;
        !           591:                dnp->dn_mode |= 0555;   /* default perms */
        !           592:                break;
        !           593:        case DEV_SLNK:
        !           594:                /*
        !           595:                 * As it's a symlink allocate and store the link info
        !           596:                 * Symlinks should only ever be created by the user,
        !           597:                 * so they are not on the back plane and should not be 
        !           598:                 * propogated forward.. a bit like directories in that way..
        !           599:                 * A symlink only exists on one plane and has its own
        !           600:                 * node.. therefore we might be on any random plane.
        !           601:                 */
        !           602:                MALLOC(dnp->dn_typeinfo.Slnk.name, char *, 
        !           603:                       typeinfo->Slnk.namelen+1,
        !           604:                       M_DEVFSNODE, M_NOWAIT);
        !           605:                if (!dnp->dn_typeinfo.Slnk.name) {
        !           606:                        FREE(dnp,M_DEVFSNODE);
        !           607:                        return ENOMEM;
        !           608:                }
        !           609:                strncpy(dnp->dn_typeinfo.Slnk.name, typeinfo->Slnk.name,
        !           610:                        typeinfo->Slnk.namelen);
        !           611:                dnp->dn_typeinfo.Slnk.name[typeinfo->Slnk.namelen] = '\0';
        !           612:                dnp->dn_typeinfo.Slnk.namelen = typeinfo->Slnk.namelen;
        !           613:                DEVFS_INCR_STRINGSPACE(dnp->dn_typeinfo.Slnk.namelen + 1);
        !           614:                dnp->dn_ops = &devfs_vnodeop_p;
        !           615:                dnp->dn_mode |= 0555;   /* default perms */
        !           616:                break;
        !           617:        case DEV_CDEV:
        !           618:        case DEV_BDEV:
        !           619:                /*
        !           620:                 * Make sure it has DEVICE type ops
        !           621:                 * and device specific fields are correct
        !           622:                 */
        !           623:                dnp->dn_ops = &devfs_spec_vnodeop_p;
        !           624:                dnp->dn_typeinfo.dev = typeinfo->dev;
        !           625:                break;
        !           626:        default:
        !           627:                return EINVAL;
        !           628:        }
        !           629: 
        !           630:        *dn_pp = dnp;
        !           631:        DEVFS_INCR_NODES();
        !           632:        return 0 ;
        !           633: }
        !           634: 
        !           635: 
        !           636: /*proto*/
        !           637: void
        !           638: devnode_free(devnode_t * dnp)
        !           639: {
        !           640:     if (dnp->dn_type == DEV_SLNK) {
        !           641:         DEVFS_DECR_STRINGSPACE(dnp->dn_typeinfo.Slnk.namelen + 1);
        !           642:        FREE(dnp->dn_typeinfo.Slnk.name,M_DEVFSNODE);
        !           643:     }
        !           644:     FREE(dnp, M_DEVFSNODE);
        !           645:     DEVFS_DECR_NODES();
        !           646:     return;
        !           647: }
        !           648: 
        !           649: /*proto*/
        !           650: void
        !           651: devfs_dn_free(devnode_t * dnp)
        !           652: {
        !           653:        if(--dnp->dn_links <= 0 ) /* can be -1 for initial free, on error */
        !           654:        {
        !           655:                /*probably need to do other cleanups XXX */
        !           656:                if (dnp->dn_nextsibling != dnp) {
        !           657:                        devnode_t * *   prevp = dnp->dn_prevsiblingp;
        !           658:                        *prevp = dnp->dn_nextsibling;
        !           659:                        dnp->dn_nextsibling->dn_prevsiblingp = prevp;
        !           660:                        
        !           661:                }
        !           662:                if (dnp->dn_vn == NULL) {
        !           663: #if 0
        !           664:                    printf("devfs_dn_free: free'ing %x\n", (unsigned int)dnp);
        !           665: #endif 0
        !           666:                    devnode_free(dnp); /* no accesses/references */
        !           667:                }
        !           668:                else {
        !           669: #if 0
        !           670:                    printf("devfs_dn_free: marking %x for deletion\n",
        !           671:                           (unsigned int)dnp);
        !           672: #endif 0
        !           673:                    dnp->dn_delete = TRUE;
        !           674:                }
        !           675:        }
        !           676: }
        !           677: 
        !           678: /***********************************************************************\
        !           679: *      Front Node Operations                                           * 
        !           680: *      Add or delete a chain of front nodes                            *
        !           681: \***********************************************************************/
        !           682: 
        !           683: /***********************************************************************\
        !           684: * Given a directory backing node, and a child backing node, add the    *
        !           685: * appropriate front nodes to the front nodes of the directory to       *
        !           686: * represent the child node to the user                                 *
        !           687: *                                                                      *
        !           688: * on failure, front nodes will either be correct or not exist for each *
        !           689: * front dir, however dirs completed will not be stripped of completed  *
        !           690: * frontnodes on failure of a later frontnode                           *
        !           691: *                                                                      *
        !           692: * This allows a new node to be propogated through all mounted planes   *
        !           693: *                                                                      *
        !           694: \***********************************************************************/
        !           695: /*proto*/
        !           696: int
        !           697: devfs_propogate(devdirent_t * parent,devdirent_t * child)
        !           698: {
        !           699:        int     error;
        !           700:        devdirent_t * newnmp;
        !           701:        devnode_t *     dnp = child->de_dnp;
        !           702:        devnode_t *     pdnp = parent->de_dnp;
        !           703:        devnode_t *     adnp = parent->de_dnp;
        !           704:        int type = child->de_dnp->dn_type;
        !           705: 
        !           706:        /***********************************************\
        !           707:        * Find the other instances of the parent node   *
        !           708:        \***********************************************/
        !           709:        for (adnp = pdnp->dn_nextsibling;
        !           710:                adnp != pdnp;
        !           711:                adnp = adnp->dn_nextsibling)
        !           712:        {
        !           713:                /*
        !           714:                 * Make the node, using the original as a prototype)
        !           715:                 * if the node already exists on that plane it won't be
        !           716:                 * re-made..
        !           717:                 */
        !           718:                if ((error = dev_add_entry(child->de_name, adnp, type,
        !           719:                                           NULL, dnp, adnp->dn_dvm, 
        !           720:                                           &newnmp)) != 0) {
        !           721:                        printf("duplicating %s failed\n",child->de_name);
        !           722:                }
        !           723:        }
        !           724:        return 0;       /* for now always succeed */
        !           725: }
        !           726: 
        !           727: /***********************************************************************
        !           728:  * remove all instances of this devicename [for backing nodes..]
        !           729:  * note.. if there is another link to the node (non dir nodes only)
        !           730:  * then the devfs_node will still exist as the ref count will be non-0
        !           731:  * removing a directory node will remove all sup-nodes on all planes (ZAP)
        !           732:  *
        !           733:  * Used by device drivers to remove nodes that are no longer relevant
        !           734:  * The argument is the 'cookie' they were given when they created the node
        !           735:  * this function is exported.. see devfs.h
        !           736:  ***********************************************************************/
        !           737: void
        !           738: devfs_remove(void *dirent_p)
        !           739: {
        !           740:        devnode_t * dnp = ((devdirent_t *)dirent_p)->de_dnp;
        !           741:        devnode_t * dnp2;
        !           742: 
        !           743:        if (!devfs_ready)
        !           744:            printf("devfs_remove: not ready for devices!\n");
        !           745: 
        !           746:        DEVFS_LOCK(0);
        !           747: 
        !           748:        /* keep removing the next sibling till only we exist. */
        !           749:        while((dnp2 = dnp->dn_nextsibling) != dnp) {
        !           750: 
        !           751:                /*
        !           752:                 * Keep removing the next front node till no more exist
        !           753:                 */
        !           754:                dnp->dn_nextsibling = dnp2->dn_nextsibling; 
        !           755:                dnp->dn_nextsibling->dn_prevsiblingp = &(dnp->dn_nextsibling);
        !           756:                dnp2->dn_nextsibling = dnp2;
        !           757:                dnp2->dn_prevsiblingp = &(dnp2->dn_nextsibling);
        !           758:                while(dnp2->dn_linklist)
        !           759:                {
        !           760:                        dev_free_name(dnp2->dn_linklist);
        !           761:                }
        !           762:        }
        !           763: 
        !           764:        /*
        !           765:         * then free the main node
        !           766:         * If we are not running in SPLIT_DEVS mode, then
        !           767:         * THIS is what gets rid of the propogated nodes.
        !           768:         */
        !           769:        while(dnp->dn_linklist)
        !           770:        {
        !           771:                dev_free_name(dnp->dn_linklist);
        !           772:        }
        !           773:        DEVFS_UNLOCK(0);
        !           774:        return ;
        !           775: }
        !           776: 
        !           777: 
        !           778: /***************************************************************
        !           779:  * duplicate the backing tree into a tree of nodes hung off the
        !           780:  * mount point given as the argument. Do this by
        !           781:  * calling dev_dup_entry which recurses all the way
        !           782:  * up the tree..
        !           783:  **************************************************************/
        !           784: /*proto*/
        !           785: int
        !           786: dev_dup_plane(struct devfsmount *devfs_mp_p)
        !           787: {
        !           788:        devdirent_t *   new;
        !           789:        int             error = 0;
        !           790: 
        !           791:        if ((error = dev_dup_entry(NULL, dev_root, &new, devfs_mp_p)))
        !           792:            return error;
        !           793:        devfs_mp_p->plane_root = new;
        !           794:        return error;
        !           795: }
        !           796: 
        !           797: 
        !           798: 
        !           799: /***************************************************************\
        !           800: * Free a whole plane
        !           801: \***************************************************************/
        !           802: /*proto*/
        !           803: void
        !           804: devfs_free_plane(struct devfsmount *devfs_mp_p)
        !           805: {
        !           806:        devdirent_t * dirent_p;
        !           807: 
        !           808:        dirent_p = devfs_mp_p->plane_root;
        !           809:        if(dirent_p) {
        !           810:                dev_free_hier(dirent_p);
        !           811:                dev_free_name(dirent_p);
        !           812:        }
        !           813:        devfs_mp_p->plane_root = NULL;
        !           814: }
        !           815: 
        !           816: /***************************************************************\
        !           817: * Create and link in a new front element..                     *
        !           818: * Parent can be 0 for a root node                              *
        !           819: * Not presently usable to make a symlink XXX                   *
        !           820: * (Ok, symlinks don't propogate)
        !           821: * recursively will create subnodes corresponding to equivalent *
        !           822: * child nodes in the base level                                        *
        !           823: \***************************************************************/
        !           824: /*proto*/
        !           825: int
        !           826: dev_dup_entry(devnode_t * parent, devdirent_t * back, devdirent_t * *dnm_pp,
        !           827:              struct devfsmount *dvm)
        !           828: {
        !           829:        devdirent_t *   entry_p;
        !           830:        devdirent_t *   newback;
        !           831:        devdirent_t *   newfront;
        !           832:        int     error;
        !           833:        devnode_t *     dnp = back->de_dnp;
        !           834:        int type = dnp->dn_type;
        !           835: 
        !           836:        /*
        !           837:         * go get the node made (if we need to)
        !           838:         * use the back one as a prototype
        !           839:         */
        !           840:        if ((error = dev_add_entry(back->de_name, parent, type,
        !           841:                                NULL, dnp,
        !           842:                                parent?parent->dn_dvm:dvm, &entry_p)) != 0) {
        !           843:                printf("duplicating %s failed\n",back->de_name);
        !           844:        }
        !           845: 
        !           846:        /*
        !           847:         * If we have just made the root, then insert the pointer to the
        !           848:         * mount information
        !           849:         */
        !           850:        if(dvm) {
        !           851:                entry_p->de_dnp->dn_dvm = dvm;
        !           852:        }
        !           853: 
        !           854:        /*
        !           855:         * If it is a directory, then recurse down all the other
        !           856:         * subnodes in it....
        !           857:         * note that this time we don't pass on the mount info..
        !           858:         */
        !           859:        if (type == DEV_DIR)
        !           860:        {
        !           861:                for(newback = back->de_dnp->dn_typeinfo.Dir.dirlist;
        !           862:                                newback; newback = newback->de_next)
        !           863:                {
        !           864:                        if((error = dev_dup_entry(entry_p->de_dnp,
        !           865:                                            newback, &newfront, NULL)) != 0)
        !           866:                        {
        !           867:                                break; /* back out with an error */
        !           868:                        }
        !           869:                }
        !           870:        }
        !           871:        *dnm_pp = entry_p;
        !           872:        return error;
        !           873: }
        !           874: 
        !           875: /***************************************************************\
        !           876: * Free a name node                                             *
        !           877: * remember that if there are other names pointing to the       *
        !           878: * dev_node then it may not get freed yet                       *
        !           879: * can handle if there is no dnp                                *
        !           880: \***************************************************************/
        !           881: /*proto*/
        !           882: int
        !           883: dev_free_name(devdirent_t * dirent_p)
        !           884: {
        !           885:        devnode_t *     parent = dirent_p->de_parent;
        !           886:        devnode_t *     dnp = dirent_p->de_dnp;
        !           887: 
        !           888:        if(dnp) {
        !           889:                if(dnp->dn_type == DEV_DIR)
        !           890:                {
        !           891:                        devnode_t * p;
        !           892: 
        !           893:                        if(dnp->dn_typeinfo.Dir.dirlist)
        !           894:                                return (ENOTEMPTY);
        !           895:                        p = dnp->dn_typeinfo.Dir.parent;
        !           896:                        devfs_dn_free(dnp);     /* account for '.' */
        !           897:                        devfs_dn_free(p);       /* '..' */
        !           898:                }
        !           899:                /*
        !           900:                 * unlink us from the list of links for this node
        !           901:                 * If we are the only link, it's easy!
        !           902:                 * if we are a DIR of course there should not be any
        !           903:                 * other links.
        !           904:                 */
        !           905:                if(dirent_p->de_nextlink == dirent_p) {
        !           906:                                dnp->dn_linklist = NULL;
        !           907:                } else {
        !           908:                        if(dnp->dn_linklist == dirent_p) {
        !           909:                                dnp->dn_linklist = dirent_p->de_nextlink;
        !           910:                        }
        !           911:                        dirent_p->de_nextlink->de_prevlinkp 
        !           912:                            = dirent_p->de_prevlinkp;
        !           913:                        *dirent_p->de_prevlinkp = dirent_p->de_nextlink;
        !           914:                }
        !           915:                devfs_dn_free(dnp);
        !           916:        }
        !           917: 
        !           918:        /*
        !           919:         * unlink ourselves from the directory on this plane
        !           920:         */
        !           921:        if(parent) /* if not fs root */
        !           922:        {
        !           923:                if( (*dirent_p->de_prevp = dirent_p->de_next) )/* yes, assign */
        !           924:                {
        !           925:                        dirent_p->de_next->de_prevp = dirent_p->de_prevp;
        !           926:                }
        !           927:                else
        !           928:                {
        !           929:                        parent->dn_typeinfo.Dir.dirlast
        !           930:                                = dirent_p->de_prevp;
        !           931:                }
        !           932:                parent->dn_typeinfo.Dir.entrycount--;
        !           933:                parent->dn_len -= strlen(dirent_p->de_name) + 8;
        !           934:        }
        !           935: 
        !           936:        DEVFS_DECR_ENTRIES();
        !           937:        FREE(dirent_p,M_DEVFSNAME);
        !           938:        return 0;
        !           939: }
        !           940: 
        !           941: /***************************************************************\
        !           942: * Free a hierarchy starting at a directory node name                   *
        !           943: * remember that if there are other names pointing to the       *
        !           944: * dev_node then it may not get freed yet                       *
        !           945: * can handle if there is no dnp                                *
        !           946: * leave the node itself allocated.                             *
        !           947: \***************************************************************/
        !           948: /*proto*/
        !           949: void
        !           950: dev_free_hier(devdirent_t * dirent_p)
        !           951: {
        !           952:        devnode_t *     dnp = dirent_p->de_dnp;
        !           953: 
        !           954:        if(dnp) {
        !           955:                if(dnp->dn_type == DEV_DIR)
        !           956:                {
        !           957:                        while(dnp->dn_typeinfo.Dir.dirlist)
        !           958:                        {
        !           959:                                dev_free_hier(dnp->dn_typeinfo.Dir.dirlist);
        !           960:                                dev_free_name(dnp->dn_typeinfo.Dir.dirlist);
        !           961:                        }
        !           962:                }
        !           963:        }
        !           964: }
        !           965: 
        !           966: /***************************************************************\
        !           967: * given a dev_node, find the appropriate vnode if one is already
        !           968: * associated, or get a new one and associate it with the dev_node
        !           969: \***************************************************************/
        !           970: /*proto*/
        !           971: int
        !           972: devfs_dntovn(devnode_t * dnp, struct vnode **vn_pp, struct proc * p)
        !           973: {
        !           974:        struct vnode *vn_p, *nvp;
        !           975:        int error = 0;
        !           976: 
        !           977:        *vn_pp = NULL;
        !           978:        vn_p = dnp->dn_vn;
        !           979:        if (vn_p) { /* already has a vnode */
        !           980:            *vn_pp = vn_p;
        !           981:            return(vget(vn_p, LK_EXCLUSIVE, p));
        !           982:        }
        !           983:        if (!(error = getnewvnode(VT_DEVFS, dnp->dn_dvm->mount,
        !           984:                                  *(dnp->dn_ops), &vn_p))) {
        !           985:                switch(dnp->dn_type) {
        !           986:                case    DEV_SLNK:
        !           987:                        vn_p->v_type = VLNK;
        !           988:                        break;
        !           989:                case    DEV_DIR:
        !           990:                        if (dnp->dn_typeinfo.Dir.parent == dnp) {
        !           991:                                vn_p->v_flag |= VROOT;
        !           992:                        }
        !           993:                        vn_p->v_type = VDIR;
        !           994:                        break;
        !           995:                case    DEV_BDEV:
        !           996:                case    DEV_CDEV:
        !           997:                        vn_p->v_type 
        !           998:                            = (dnp->dn_type == DEV_BDEV) ? VBLK : VCHR;
        !           999:                        if ((nvp = checkalias(vn_p, dnp->dn_typeinfo.dev,
        !          1000:                                              dnp->dn_dvm->mount)) != NULL) {
        !          1001:                            vput(vn_p);
        !          1002:                            vn_p = nvp;
        !          1003:                        }
        !          1004:                        break;
        !          1005:                }
        !          1006:                vn_p->v_mount  = dnp->dn_dvm->mount;/* XXX Duplicated */
        !          1007:                *vn_pp = vn_p;
        !          1008:                vn_p->v_data = (void *)dnp;
        !          1009:                dnp->dn_vn = vn_p;
        !          1010:                error = vn_lock(vn_p, LK_EXCLUSIVE | LK_RETRY, p);
        !          1011:        }
        !          1012:        return error;
        !          1013: }
        !          1014: 
        !          1015: /***********************************************************************\
        !          1016: * add a whole device, with no prototype.. make name element and node   *
        !          1017: * Used for adding the original device entries                          *
        !          1018: \***********************************************************************/
        !          1019: /*proto*/
        !          1020: int
        !          1021: dev_add_entry(char *name, devnode_t * parent, int type, devnode_type_t * typeinfo,
        !          1022:              devnode_t * proto, struct devfsmount *dvm, devdirent_t * *nm_pp)
        !          1023: {
        !          1024:        devnode_t *     dnp;
        !          1025:        int     error = 0;
        !          1026: 
        !          1027:        if ((error = dev_add_node(type, typeinfo, proto, &dnp, 
        !          1028:                        (parent?parent->dn_dvm:dvm))) != 0)
        !          1029:        {
        !          1030:                printf("devfs: %s: base node allocation failed (Errno=%d)\n",
        !          1031:                        name,error);
        !          1032:                return error;
        !          1033:        }
        !          1034:        if ((error = dev_add_name(name ,parent ,NULL, dnp, nm_pp)) != 0)
        !          1035:        {
        !          1036:                devfs_dn_free(dnp); /* 1->0 for dir, 0->(-1) for other */
        !          1037:                printf("devfs: %s: name slot allocation failed (Errno=%d)\n",
        !          1038:                       name,error);
        !          1039:                
        !          1040:        }
        !          1041:        return error;
        !          1042: }
        !          1043: 
        !          1044: #include <sys/subr_prf.h>
        !          1045: 
        !          1046: /*
        !          1047:  * Function: devfs_make_node
        !          1048:  *
        !          1049:  * Purpose
        !          1050:  *   Create a device node with the given pathname in the devfs namespace.
        !          1051:  *
        !          1052:  * Parameters:
        !          1053:  *   dev       - the dev_t value to associate
        !          1054:  *   chrblk    - block or character device (DEVFS_CHAR or DEVFS_BLOCK)
        !          1055:  *   uid, gid  - ownership
        !          1056:  *   perms     - permissions
        !          1057:  *   fmt, ...  - path format string with printf args to format the path name
        !          1058:  * Returns:
        !          1059:  *   A handle to a device node if successful, NULL otherwise.
        !          1060:  */
        !          1061: void *
        !          1062: devfs_make_node(dev_t dev, int chrblk, uid_t uid,
        !          1063:                gid_t gid, int perms, char *fmt, ...)
        !          1064: {
        !          1065:        devdirent_t *   new_dev = NULL;
        !          1066:        devnode_t *     dnp;    /* devnode for parent directory */
        !          1067:        devnode_type_t  typeinfo;
        !          1068: 
        !          1069:        char *name, *path, buf[256]; /* XXX */
        !          1070:        char * b_ptr = buf;
        !          1071:        int i;
        !          1072:        va_list ap;
        !          1073: 
        !          1074:        if (!devfs_ready) {
        !          1075:            printf("devfs_make_node: not ready for devices!\n");
        !          1076:            return (NULL);
        !          1077:        }
        !          1078: 
        !          1079:        if (chrblk != DEVFS_CHAR && chrblk != DEVFS_BLOCK)
        !          1080:            return (NULL);
        !          1081: 
        !          1082:        va_start(ap, fmt);
        !          1083:        prf(fmt, ap, TOSTR, (struct tty *)&b_ptr);
        !          1084:        va_end(ap);
        !          1085:        *b_ptr = 0;
        !          1086: 
        !          1087:        name = NULL;
        !          1088: 
        !          1089:        for(i=strlen(buf); i>0; i--)
        !          1090:                if(buf[i] == '/') {
        !          1091:                        name=&buf[i];
        !          1092:                        buf[i]=0;
        !          1093:                        break;
        !          1094:                }
        !          1095: 
        !          1096:        if (name) {
        !          1097:                *name++ = '\0';
        !          1098:                path = buf;
        !          1099:        } else {
        !          1100:                name = buf;
        !          1101:                path = "/";
        !          1102:        }
        !          1103: 
        !          1104:        DEVFS_LOCK(0);
        !          1105:        /* find/create directory path ie. mkdir -p */
        !          1106:        if (dev_finddir(path, NULL, CREATE, &dnp) == 0) {
        !          1107:            typeinfo.dev = dev;
        !          1108:            if (dev_add_entry(name, dnp, 
        !          1109:                              (chrblk == DEVFS_CHAR) ? DEV_CDEV : DEV_BDEV, 
        !          1110:                              &typeinfo, NULL, NULL, &new_dev) == 0) {
        !          1111:                new_dev->de_dnp->dn_gid = gid;
        !          1112:                new_dev->de_dnp->dn_uid = uid;
        !          1113:                new_dev->de_dnp->dn_mode |= perms;
        !          1114:                devfs_propogate(dnp->dn_typeinfo.Dir.myname, new_dev);
        !          1115:            }
        !          1116:        }
        !          1117:        DEVFS_UNLOCK(0);
        !          1118:        return new_dev;
        !          1119: }
        !          1120: 
        !          1121: /*
        !          1122:  * Function: devfs_make_link
        !          1123:  *
        !          1124:  * Purpose:
        !          1125:  *   Create a link to a previously created device node.
        !          1126:  *
        !          1127:  * Returns:
        !          1128:  *   0 if successful, -1 if failed
        !          1129:  */
        !          1130: int
        !          1131: devfs_make_link(void *original, char *fmt, ...)
        !          1132: {
        !          1133:        devdirent_t *   new_dev = NULL;
        !          1134:        devdirent_t *   orig = (devdirent_t *) original;
        !          1135:        devnode_t *     dirnode;        /* devnode for parent directory */
        !          1136: 
        !          1137:         va_list ap;
        !          1138:         char *p, buf[256]; /* XXX */
        !          1139:        char * b_ptr = buf;
        !          1140:         int i;
        !          1141: 
        !          1142:        if (!devfs_ready) {
        !          1143:            printf("devfs_make_link: not ready for devices!\n");
        !          1144:            return (-1);
        !          1145:        }
        !          1146: 
        !          1147:        va_start(ap, fmt);
        !          1148:        prf(fmt, ap, TOSTR, (struct tty *)&b_ptr);
        !          1149:        va_end(ap);
        !          1150:        *b_ptr = 0;
        !          1151: 
        !          1152:         p = NULL;
        !          1153: 
        !          1154:         for(i=strlen(buf); i>0; i--)
        !          1155:                 if(buf[i] == '/') {
        !          1156:                         p=&buf[i];
        !          1157:                         buf[i]=0;
        !          1158:                         break;
        !          1159:                 }
        !          1160:        DEVFS_LOCK(0);
        !          1161:         if (p) {
        !          1162:            *p++ = '\0';
        !          1163:            if (dev_finddir(buf, NULL, CREATE, &dirnode)
        !          1164:                || dev_add_name(p, dirnode, NULL, orig->de_dnp, &new_dev))
        !          1165:                goto fail;
        !          1166:        } else {
        !          1167:            if (dev_finddir("", NULL, CREATE, &dirnode)
        !          1168:                || dev_add_name(buf, dirnode, NULL, orig->de_dnp, &new_dev))
        !          1169:                goto fail;
        !          1170:        }
        !          1171:        devfs_propogate(dirnode->dn_typeinfo.Dir.myname, new_dev);
        !          1172:  fail:
        !          1173:        DEVFS_UNLOCK(0);
        !          1174:        return ((new_dev != NULL) ? 0 : -1);
        !          1175: }
        !          1176: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.