Annotation of XNU/bsd/miscfs/devfs/devfs_tree.c, revision 1.1.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.