diff options
author | phk <phk@FreeBSD.org> | 2000-08-20 21:34:39 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2000-08-20 21:34:39 +0000 |
commit | b648921accec69a7e5c83e915ded3037cbca7f3d (patch) | |
tree | fa2e43c05e3c1d31732408f806d72db091c03d14 /sys/miscfs/devfs/devfs_tree.c | |
parent | 1c624ac57c791b6df4b51eb86e04dc404052c700 (diff) | |
download | FreeBSD-src-b648921accec69a7e5c83e915ded3037cbca7f3d.zip FreeBSD-src-b648921accec69a7e5c83e915ded3037cbca7f3d.tar.gz |
Remove all traces of Julians DEVFS (incl from kern/subr_diskslice.c)
Remove old DEVFS support fields from dev_t.
Make uid, gid & mode members of dev_t and set them in make_dev().
Use correct uid, gid & mode in make_dev in disk minilayer.
Add support for registering alias names for a dev_t using the
new function make_dev_alias(). These will show up as symlinks
in DEVFS.
Use makedev() rather than make_dev() for MFSs magic devices to prevent
DEVFS from noticing this abuse.
Add a field for DEVFS inode number in dev_t.
Add new DEVFS in fs/devfs.
Add devfs cloning to:
disk minilayer (ie: ad(4), sd(4), cd(4) etc etc)
md(4), tun(4), bpf(4), fd(4)
If DEVFS add -d flag to /sbin/inits args to make it mount devfs.
Add commented out DEVFS to GENERIC
Diffstat (limited to 'sys/miscfs/devfs/devfs_tree.c')
-rw-r--r-- | sys/miscfs/devfs/devfs_tree.c | 1297 |
1 files changed, 0 insertions, 1297 deletions
diff --git a/sys/miscfs/devfs/devfs_tree.c b/sys/miscfs/devfs/devfs_tree.c deleted file mode 100644 index d47917a..0000000 --- a/sys/miscfs/devfs/devfs_tree.c +++ /dev/null @@ -1,1297 +0,0 @@ - -/* - * Copyright 1997,1998 Julian Elischer. All rights reserved. - * julian@freebsd.org - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - - -/* SPLIT_DEVS means each devfs uses a different vnode for the same device */ -/* Otherwise the same device always ends up at the same vnode even if */ -/* reached througgh a different devfs instance. The practical difference */ -/* is that with the same vnode, chmods and chowns show up on all instances of */ -/* a device. (etc) */ - -#define SPLIT_DEVS 1 /* maybe make this an option */ -/*#define SPLIT_DEVS 1*/ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/conf.h> -#include <sys/malloc.h> -#include <sys/mount.h> -#include <sys/proc.h> -#include <sys/vnode.h> -#include <sys/devfsext.h> - -#include <machine/stdarg.h> - -#include <miscfs/devfs/devfsdefs.h> - - -static MALLOC_DEFINE(M_DEVFSNODE, "DEVFS node", "DEVFS node"); -static MALLOC_DEFINE(M_DEVFSNAME, "DEVFS name", "DEVFS name"); - -static void devfs_add_to_tree(dev_t dev, uid_t uid, gid_t gid, int perms); -devnm_p dev_root; /* root of the backing tree */ -static struct mount *devfs_hidden_mount; -int devfs_up_and_going; - -/* - * Set up the root directory node in the backing plane - * This is happenning before the vfs system has been - * set up yet, so be careful about what we reference.. - * Notice that the ops are by indirection.. as they haven't - * been set up yet! - * DEVFS has a hidden mountpoint that is used as the anchor point - * for the internal 'blueprint' version of the dev filesystem tree. - */ -/*proto*/ -void -devfs_sinit(void *junk) -{ - int retval; /* we will discard this */ - - /* - * call the right routine at the right time with the right args.... - */ - retval = dev_add_entry("root", NULL, DEV_DIR, NULL, NULL, NULL, &dev_root); - devfs_create_hook = devfs_add_to_tree; -#ifdef PARANOID - if(retval) panic("devfs_sinit: dev_add_entry failed "); -#endif - devfs_hidden_mount = (struct mount *)malloc(sizeof(struct mount), - M_MOUNT,M_NOWAIT); -#ifdef PARANOID - if(!devfs_hidden_mount) panic("devfs_sinit: malloc failed"); -#endif - bzero(devfs_hidden_mount,sizeof(struct mount)); - devfs_mount(devfs_hidden_mount,"dummy",NULL,NULL,NULL); - dev_root->dnp->dvm = (struct devfsmount *)devfs_hidden_mount->mnt_data; - devfs_up_and_going = 1; - printf("DEVFS: ready for devices\n"); - /* part 2 of this is done later */ -} -SYSINIT(devfs, SI_SUB_DEVFS, SI_ORDER_FIRST, devfs_sinit, NULL) - - -/***********************************************************************\ -************************************************************************* -* Routines used to find our way to a point in the tree * -************************************************************************* -\***********************************************************************/ - - -/***************************************************************\ -* Search down the linked list off a dir to find "name" * -* return the dn_p for that node. -\***************************************************************/ -/*proto*/ -devnm_p -dev_findname(dn_p dir,char *name) -{ - devnm_p newfp; - DBPRINT((" dev_findname(%s)\n",name)); - if(dir->type != DEV_DIR) return 0;/*XXX*/ /* printf?*/ - - if(name[0] == '.') - { - if(name[1] == 0) - { - return dir->by.Dir.myname; - } - if((name[1] == '.') && (name[2] == 0)) - { - /* for root, .. == . */ - return dir->by.Dir.parent->by.Dir.myname; - } - } - newfp = dir->by.Dir.dirlist; - while(newfp) - { - if(!(strcmp(name,newfp->name))) - return newfp; - newfp = newfp->next; - } - return NULL; -} - -/***********************************************************************\ -* Given a starting node (0 for root) and a pathname, return the node * -* for the end item on the path. It MUST BE A DIRECTORY. If the 'CREATE' * -* option is true, then create any missing nodes in the path and create * -* and return the final node as well. * -* This is used to set up a directory, before making nodes in it.. * -* * -* Warning: This function is RECURSIVE. * -* char *orig_path, find this dir (err if not dir) * -* dn_p dirnode, starting point (0 = root) * -* int create, create path if not found * -* dn_p *dn_pp) where to return the node of the dir * -\***********************************************************************/ -/*proto*/ -int -dev_finddir(char *orig_path, dn_p dirnode, int create, dn_p *dn_pp) -{ - devnm_p devnmp; - dn_p dnp; - char pathbuf[DEVMAXPATHSIZE]; - char *path; - char *name; - register char *cp; - int retval; - - - DBPRINT(("dev_finddir\n")); - /***************************************\ - * If no parent directory is given * - * then start at the root of the tree * - \***************************************/ - if(!dirnode) dirnode = dev_root->dnp; - - /***************************************\ - * Sanity Checks * - \***************************************/ - if(dirnode->type != DEV_DIR) return ENOTDIR; - if(strlen(orig_path) > (DEVMAXPATHSIZE - 1)) return ENAMETOOLONG; - - - path = pathbuf; - strcpy(path,orig_path); - - /***************************************\ - * always absolute, skip leading / * - * get rid of / or // or /// etc. * - \***************************************/ - while(*path == '/') path++; - - /***************************************\ - * If nothing left, then parent was it.. * - \***************************************/ - if ( *path == '\0' ) { - *dn_pp = dirnode; - return 0; - } - - /***************************************\ - * find the next segment of the name * - \***************************************/ - cp = name = path; - while((*cp != '/') && (*cp != 0)) { - cp++; - } - - /***********************************************\ - * Check to see if it's the last component * - \***********************************************/ - if(*cp) { - path = cp + 1; /* path refers to the rest */ - *cp = 0; /* name is now a separate string */ - if(!(*path)) { - path = (char *)0; /* was trailing slash */ - } - } else { - path = NULL; /* no more to do */ - } - - /***************************************\ - * Start scanning along the linked list * - \***************************************/ - devnmp = dev_findname(dirnode,name); - if(devnmp) { /* check it's a directory */ - dnp = devnmp->dnp; - if(dnp->type != DEV_DIR) return ENOTDIR; - } else { - /***************************************\ - * The required element does not exist * - * So we will add it if asked to. * - \***************************************/ - if(!create) return ENOENT; - - if((retval = dev_add_entry(name, dirnode, DEV_DIR, - NULL, NULL, NULL, &devnmp)) != 0) { - return retval; - } - dnp = devnmp->dnp; - devfs_propogate(dirnode->by.Dir.myname,devnmp); - } - if(path != NULL) { /* decide whether to recurse more or return */ - return (dev_finddir(path,dnp,create,dn_pp)); - } else { - *dn_pp = dnp; - return 0; - } -} - - -/***********************************************************************\ -* Add a new NAME element to the devfs * -* If we're creating a root node, then dirname is NULL * -* Basically this creates a new namespace entry for the device node * -* * -* Creates a name node, and links it to the supplied node * -\***********************************************************************/ -/*proto*/ -int -dev_add_name(char *name, dn_p dirnode, devnm_p back, dn_p dnp, - devnm_p *devnm_pp) -{ - devnm_p devnmp; - - DBPRINT(("dev_add_name\n")); - if(dirnode != NULL ) { - if(dirnode->type != DEV_DIR) return(ENOTDIR); - - if( dev_findname(dirnode,name)) - return(EEXIST); - } - /* - * make sure the name is legal - * slightly misleading in the case of NULL - */ - if( !name || (strlen(name) > (DEVMAXNAMESIZE - 1))) - return (ENAMETOOLONG); - - /* - * Allocate and fill out a new directory entry - */ - if(!(devnmp = (devnm_p)malloc(sizeof(devnm_t), - M_DEVFSNAME, M_NOWAIT))) { - return ENOMEM; - } - bzero(devnmp,sizeof(devnm_t)); - - /* inherrit our parent's mount info */ /*XXX*/ - /* a kludge but.... */ - if(dirnode && ( dnp->dvm == NULL)) { - dnp->dvm = dirnode->dvm; - if(!dnp->dvm) printf("parent had null dvm "); - } - - /* - * Link the two together - * include the implicit link in the count of links to the devnode.. - * this stops it from being accidentally freed later. - */ - devnmp->dnp = dnp; - dnp->links++ ; /* implicit from our own name-node */ - - /* - * Make sure that we can find all the links that reference a node - * so that we can get them all if we need to zap the node. - */ - if(dnp->linklist) { - devnmp->nextlink = dnp->linklist; - devnmp->prevlinkp = devnmp->nextlink->prevlinkp; - devnmp->nextlink->prevlinkp = &(devnmp->nextlink); - *devnmp->prevlinkp = devnmp; - dnp->linklist = devnmp; - } else { - devnmp->nextlink = devnmp; - devnmp->prevlinkp = &(devnmp->nextlink); - dnp->linklist = devnmp; - } - - /* - * If the node is a directory, then we need to handle the - * creation of the .. link. - * A NULL dirnode indicates a root node, so point to ourself. - */ - if(dnp->type == DEV_DIR) { - dnp->by.Dir.myname = devnmp; - /* - * If we are unlinking from an old dir, decrement its links - * as we point our '..' elsewhere - * Note: it's up to the calling code to remove the - * us from the original directory's list - */ - if(dnp->by.Dir.parent) { - dnp->by.Dir.parent->links--; - } - if(dirnode) { - dnp->by.Dir.parent = dirnode; - } else { - dnp->by.Dir.parent = dnp; - } - dnp->by.Dir.parent->links++; /* account for the new '..' */ - } - - /* - * put the name into the directory entry. - */ - strcpy(devnmp->name, name); - - - /* - * Check if we are not making a root node.. - * (i.e. have parent) - */ - if(dirnode) { - /* - * Put it on the END of the linked list of directory entries - */ - devnmp->parent = dirnode; /* null for root */ - devnmp->prevp = dirnode->by.Dir.dirlast; - devnmp->next = *(devnmp->prevp); /* should be NULL */ /*right?*/ - *(devnmp->prevp) = devnmp; - dirnode->by.Dir.dirlast = &(devnmp->next); - dirnode->by.Dir.entrycount++; - dirnode->len += strlen(name) + 8;/*ok, ok?*/ - } - - *devnm_pp = devnmp; - return 0 ; -} - - -/***********************************************************************\ -* Add a new element to the devfs plane. * -* * -* Creates a new dev_node to go with it if the prototype should not be * -* reused. (Is a DIR, or we select SPLIT_DEVS at compile time) * -* 'by' gives us info to make our node if we don't have a prototype. * -* If 'by is null and proto exists, then the 'by' field of * -* the proto is used intead in the CREATE case. * -* note the 'links' count is 0 (except if a dir) * -* but it is only cleared on a transition * -* so this is ok till we link it to something * -* Even in SPLIT_DEVS mode, * -* if the node already exists on the wanted plane, just return it * -\***********************************************************************/ -/*proto*/ -int -dev_add_node(int entrytype, union typeinfo *by, dn_p proto, - dn_p *dn_pp,struct devfsmount *dvm) -{ - dn_p dnp; - - DBPRINT(("dev_add_node\n")); -#if defined SPLIT_DEVS - /* - * If we have a prototype, then check if there is already a sibling - * on the mount plane we are looking at, if so, just return it. - */ - if (proto) { - dnp = proto->nextsibling; - while( dnp != proto) { - if (dnp->dvm == dvm) { - *dn_pp = dnp; - return (0); - } - dnp = dnp->nextsibling; - } - if (by == NULL) - by = &(proto->by); - } -#else /* SPLIT_DEVS */ - if ( proto ) { - switch (proto->type) { - case DEV_BDEV: - case DEV_CDEV: - case DEV_DDEV: - *dn_pp = proto; - return 0; - } - } -#endif /* SPLIT_DEVS */ - if(!(dnp = (dn_p)malloc(sizeof(devnode_t), - M_DEVFSNODE, M_NOWAIT))) - { - return ENOMEM; - } - - /* - * If we have a proto, that means that we are duplicating some - * other device, which can only happen if we are not at the back plane - */ - if(proto) { - bcopy(proto, dnp, sizeof(devnode_t)); - dnp->links = 0; - dnp->linklist = NULL; - dnp->vn = NULL; - dnp->len = 0; - /* add to END of siblings list */ - dnp->prevsiblingp = proto->prevsiblingp; - *(dnp->prevsiblingp) = dnp; - dnp->nextsibling = proto; - proto->prevsiblingp = &(dnp->nextsibling); - } else { - /* - * We have no prototype, so start off with a clean slate - */ - bzero(dnp,sizeof(devnode_t)); - dnp->type = entrytype; - getnanotime(&(dnp->ctime)); - dnp->mtime = dnp->ctime; - dnp->atime = dnp->ctime; - dnp->nextsibling = dnp; - dnp->prevsiblingp = &(dnp->nextsibling); - } - dnp->dvm = dvm; - - /* - * fill out the dev node according to type - */ - switch(entrytype) { - case DEV_DIR: - /* - * As it's a directory, make sure - * it has a null entries list - */ - dnp->by.Dir.dirlast = &(dnp->by.Dir.dirlist); - dnp->by.Dir.dirlist = (devnm_p)0; - dnp->by.Dir.entrycount = 0; - /* until we know better, it has a null parent pointer*/ - dnp->by.Dir.parent = NULL; - dnp->links++; /* for .*/ - dnp->by.Dir.myname = NULL; - /* - * make sure that the ops associated with it are the ops - * that we use (by default) for directories - */ - dnp->ops = &devfs_vnodeop_p; - dnp->mode |= 0555; /* default perms */ - break; - case DEV_SLNK: - /* - * As it's a symlink allocate and store the link info - * Symlinks should only ever be created by the user, - * so they are not on the back plane and should not be - * propogated forward.. a bit like directories in that way.. - * A symlink only exists on one plane and has its own - * node.. therefore we might be on any random plane. - */ - dnp->by.Slnk.name = malloc(by->Slnk.namelen+1, - M_DEVFSNODE, M_NOWAIT); - if (!dnp->by.Slnk.name) { - free(dnp,M_DEVFSNODE); - return ENOMEM; - } - strncpy(dnp->by.Slnk.name,by->Slnk.name,by->Slnk.namelen); - dnp->by.Slnk.namelen = by->Slnk.namelen; - dnp->ops = &devfs_vnodeop_p; - dnp->mode |= 0555; /* default perms */ - break; - case DEV_BDEV: - /* - * Make sure it has DEVICE type ops - * and device specific fields are correct - */ - dnp->ops = &devfs_spec_vnodeop_p; - dnp->by.dev.dev = by->dev.dev; - break; - case DEV_CDEV: - /* - * Make sure it has DEVICE type ops - * and device specific fields are correct - */ - dnp->ops = &devfs_spec_vnodeop_p; - dnp->by.dev.dev = by->dev.dev; - break; - case DEV_DDEV: - /* - * store the address of (the address of) the ops - * and the magic cookie to use with them - */ - dnp->by.Ddev.arg = by->Ddev.arg; - dnp->by.Ddev.ops = by->Ddev.ops; - dnp->ops = by->Ddev.ops; - break; - default: - return EINVAL; - } - - *dn_pp = dnp; - return 0 ; -} - - -/*proto*/ -int -dev_touch(devnm_p key) /* update the node for this dev */ -{ - DBPRINT(("dev_touch\n")); - getnanotime(&(key->dnp->mtime)); - return 0; /*XXX*/ -} - -/*proto*/ -void -devfs_dn_free(dn_p dnp) -{ - if(--dnp->links <= 0 ) /* can be -1 for initial free, on error */ - { - /*probably need to do other cleanups XXX */ - if (dnp->nextsibling != dnp) { - dn_p* prevp = dnp->prevsiblingp; - *prevp = dnp->nextsibling; - dnp->nextsibling->prevsiblingp = prevp; - - } - if(dnp->type == DEV_SLNK) { - free(dnp->by.Slnk.name,M_DEVFSNODE); - } - devfs_dropvnode(dnp); - free (dnp, M_DEVFSNODE); - } -} - -/***********************************************************************\ -* Front Node Operations * -* Add or delete a chain of front nodes * -\***********************************************************************/ - -/***********************************************************************\ -* Given a directory backing node, and a child backing node, add the * -* appropriate front nodes to the front nodes of the directory to * -* represent the child node to the user * -* * -* on failure, front nodes will either be correct or not exist for each * -* front dir, however dirs completed will not be stripped of completed * -* frontnodes on failure of a later frontnode * -* * -* This allows a new node to be propogated through all mounted planes * -* * -\***********************************************************************/ -/*proto*/ -int -devfs_propogate(devnm_p parent,devnm_p child) -{ - int error; - devnm_p newnmp; - dn_p dnp = child->dnp; - dn_p pdnp = parent->dnp; - dn_p adnp = parent->dnp; - int type = child->dnp->type; - - DBPRINT((" devfs_propogate\n")); - /***********************************************\ - * Find the other instances of the parent node * - \***********************************************/ - for (adnp = pdnp->nextsibling; - adnp != pdnp; - adnp = adnp->nextsibling) - { - /* - * Make the node, using the original as a prototype) - * if the node already exists on that plane it won't be - * re-made.. - */ - if ((error = dev_add_entry(child->name, adnp, type, - NULL, dnp, adnp->dvm, &newnmp)) != 0) { - printf("duplicating %s failed\n",child->name); - } - } - return 0; /* for now always succeed */ -} - -/*********************************************************************** - * remove all instances of this devicename [for backing nodes..] - * note.. if there is another link to the node (non dir nodes only) - * then the devfs_node will still exist as the ref count will be non-0 - * removing a directory node will remove all sup-nodes on all planes (ZAP) - * - * Used by device drivers to remove nodes that are no longer relevant - * The argument is the 'cookie' they were given when they created the node - * this function is exported.. see sys/devfsext.h - ***********************************************************************/ -void -devfs_remove_dev(void *devnmp) -{ - dn_p dnp = ((devnm_p)devnmp)->dnp; - dn_p dnp2; - - DBPRINT(("devfs_remove_dev\n")); - /* keep removing the next sibling till only we exist. */ - while((dnp2 = dnp->nextsibling) != dnp) { - - /* - * Keep removing the next front node till no more exist - */ - dnp->nextsibling = dnp2->nextsibling; - dnp->nextsibling->prevsiblingp = &(dnp->nextsibling); - dnp2->nextsibling = dnp2; - dnp2->prevsiblingp = &(dnp2->nextsibling); - while(dnp2->linklist) - { - dev_free_name(dnp2->linklist); - } - } - - /* - * then free the main node - * If we are not running in SPLIT_DEVS mode, then - * THIS is what gets rid of the propogated nodes. - */ - while(dnp->linklist) - { - dev_free_name(dnp->linklist); - } - return ; -} - - -/*************************************************************** - * duplicate the backing tree into a tree of nodes hung off the - * mount point given as the argument. Do this by - * calling dev_dup_entry which recurses all the way - * up the tree.. - * If we are the first plane, just return the base root - **************************************************************/ -/*proto*/ -int -dev_dup_plane(struct devfsmount *devfs_mp_p) -{ - devnm_p new; - int error = 0; - - DBPRINT((" dev_dup_plane\n")); - if(devfs_up_and_going) { - if((error = dev_dup_entry(NULL, dev_root, &new, devfs_mp_p)) != 0) { - return error; - } - } else { /* we are doing the dummy mount during initialisation.. */ - new = dev_root; - } - devfs_mp_p->plane_root = new; - - return error; -} - - - -/***************************************************************\ -* Free a whole plane -\***************************************************************/ -/*proto*/ -void -devfs_free_plane(struct devfsmount *devfs_mp_p) -{ - devnm_p devnmp; - - DBPRINT((" devfs_free_plane\n")); - devnmp = devfs_mp_p->plane_root; - if(devnmp) { - dev_free_hier(devnmp); - dev_free_name(devnmp); - } - devfs_mp_p->plane_root = NULL; -} - -/***************************************************************\ -* Create and link in a new front element.. * -* Parent can be 0 for a root node * -* Not presently usable to make a symlink XXX * -* (Ok, symlinks don't propogate) -* recursively will create subnodes corresponding to equivalent * -* child nodes in the base level * -\***************************************************************/ -/*proto*/ -int -dev_dup_entry(dn_p parent, devnm_p back, devnm_p *dnm_pp, - struct devfsmount *dvm) -{ - devnm_p newnmp; - devnm_p newback; - devnm_p newfront; - int error; - dn_p dnp = back->dnp; - int type = dnp->type; - - DBPRINT((" dev_dup_entry\n")); - /* - * go get the node made (if we need to) - * use the back one as a prototype - */ - if ((error = dev_add_entry(back->name, parent, type, - NULL, dnp, - parent?parent->dvm:dvm, &newnmp)) != 0) { - printf("duplicating %s failed\n",back->name); - } - - /* - * If we have just made the root, then insert the pointer to the - * mount information - */ - if(dvm) { - newnmp->dnp->dvm = dvm; - } - - /* - * If it is a directory, then recurse down all the other - * subnodes in it.... - * note that this time we don't pass on the mount info.. - */ - if (type == DEV_DIR) - { - for(newback = back->dnp->by.Dir.dirlist; - newback; newback = newback->next) - { - if((error = dev_dup_entry(newnmp->dnp, - newback, &newfront, NULL)) != 0) - { - break; /* back out with an error */ - } - } - } - *dnm_pp = newnmp; - return error; -} - -/***************************************************************\ -* Free a name node * -* remember that if there are other names pointing to the * -* dev_node then it may not get freed yet * -* can handle if there is no dnp * -\***************************************************************/ -/*proto*/ -int -dev_free_name(devnm_p devnmp) -{ - dn_p parent = devnmp->parent; - dn_p dnp = devnmp->dnp; - - DBPRINT((" dev_free_name\n")); - if(dnp) { - if(dnp->type == DEV_DIR) - { - if(dnp->by.Dir.dirlist) - return (ENOTEMPTY); - devfs_dn_free(dnp); /* account for '.' */ - devfs_dn_free(dnp->by.Dir.parent); /* '..' */ - } - /* - * unlink us from the list of links for this node - * If we are the only link, it's easy! - * if we are a DIR of course there should not be any - * other links. - */ - if(devnmp->nextlink == devnmp) { - dnp->linklist = NULL; - } else { - if(dnp->linklist == devnmp) { - dnp->linklist = devnmp->nextlink; - } - devnmp->nextlink->prevlinkp = devnmp->prevlinkp; - *devnmp->prevlinkp = devnmp->nextlink; - } - devfs_dn_free(dnp); - } - - /* - * unlink ourselves from the directory on this plane - */ - if(parent) /* if not fs root */ - { - if( (*devnmp->prevp = devnmp->next) )/* yes, assign */ - { - devnmp->next->prevp = devnmp->prevp; - } - else - { - parent->by.Dir.dirlast - = devnmp->prevp; - } - parent->by.Dir.entrycount--; - parent->len -= strlen(devnmp->name) + 8; - } - - /***************************************************************\ - * If the front node has its own devnode structure, * - * then free it. * - \***************************************************************/ - free(devnmp,M_DEVFSNAME); - return 0; -} - -/***************************************************************\ -* Free a hierarchy starting at a directory node name * -* remember that if there are other names pointing to the * -* dev_node then it may not get freed yet * -* can handle if there is no dnp * -* leave the node itself allocated. * -\***************************************************************/ -/*proto*/ -void -dev_free_hier(devnm_p devnmp) -{ - dn_p dnp = devnmp->dnp; - - DBPRINT((" dev_free_hier\n")); - if(dnp) { - if(dnp->type == DEV_DIR) - { - while(dnp->by.Dir.dirlist) - { - dev_free_hier(dnp->by.Dir.dirlist); - dev_free_name(dnp->by.Dir.dirlist); - } - } - } -} - -/*******************************************************\ -********************************************************* -* ROUTINES to control the connection between devfs * -* nodes and the system's vnodes * -********************************************************* -\*******************************************************/ - -/*******************************************************\ -* Theoretically this could be called for any kind of * -* vnode, however in practice it must be a DEVFS vnode * -\*******************************************************/ -/*proto*/ -int -devfs_vntodn(struct vnode *vn_p, dn_p *dn_pp) -{ - -DBPRINT((" vntodn ")); - if(vn_p->v_tag != VT_DEVFS) - { - printf("bad-tag2 "); - Debugger("bad-tag "); - return(EINVAL); - } -#if 0 - /* - * XXX: This is actually a "normal" case when vclean calls us without - * XXX: incrementing the reference count first. - */ - if(vn_p->v_usecount == 0) - { - printf("No references! "); - } -#endif - switch(vn_p->v_type) { - case VBAD: - printf("bad-type2 (VBAD)"); - return(EINVAL); -#if 0 - case VNON: - printf("bad-type2 (VNON)"); - return(EINVAL); -#endif - default: - break; - } - *dn_pp = (dn_p)vn_p->v_data; - - return(0); -} - -/***************************************************************\ -* given a dev_node, find the appropriate vnode if one is already* -* associated, or get a new one an associate it with the dev_node* -* need to check about vnode references.. should we increment it?* -\***************************************************************/ -/*proto*/ -int -devfs_dntovn(dn_p dnp, struct vnode **vn_pp) -{ - struct vnode *vn_p; - int error = 0; - struct proc *p = curproc; /* XXX */ - - vn_p = dnp->vn; -DBPRINT(("dntovn ")); - if( vn_p) - { - if(vn_p->v_id != dnp->vn_id) - { -#if 0 - /* XXX: This is `normal'... */ - printf("bad-id "); -#endif - goto skip; - } - if(vn_p->v_tag != VT_DEVFS) - { -#if 0 - /* XXX: This is `normal'... */ - printf("bad-tag "); -#endif - goto skip; - } - if(vn_p->v_op != *(dnp->ops)) - { - printf("bad-ops "); - goto skip; - } - if((dn_p)(vn_p->v_data) != dnp) - { - printf("bad-rev_link "); - goto skip; - } - if(vn_p->v_type != VNON) - { - vget(vn_p, LK_EXCLUSIVE, p); - *vn_pp = vn_p; - return(0); - } - else - { - printf("bad-type"); - } -skip: - vn_p = (struct vnode *) 0; - } - if(!(error = getnewvnode(VT_DEVFS, - dnp->dvm->mount, - *(dnp->ops), - &vn_p))) - { - dnp->vn = vn_p; - dnp->vn_id = vn_p->v_id; - *vn_pp = vn_p; -DBPRINT(("(New vnode)")); - switch(dnp->type) - { - case DEV_SLNK: - vn_p->v_type = VLNK; - break; - case DEV_DIR: - if(dnp->by.Dir.parent == dnp) - { - vn_p->v_flag |= VROOT; - } - vn_p->v_type = VDIR; - break; - case DEV_BDEV: - vn_p->v_type = VBLK; - addalias(vn_p, dnp->by.dev.dev); - break; - case DEV_CDEV: - vn_p->v_type = VCHR; - addalias(vn_p, dnp->by.dev.dev); - break; - case DEV_DDEV: - break; - } - if ( vn_p) - { - vn_p->v_mount = dnp->dvm->mount;/* XXX Duplicated */ - *vn_pp = vn_p; - vn_p->v_data = (void *)dnp; - } - else - { - error = EINVAL; - } - vn_lock(vn_p, LK_EXCLUSIVE | LK_RETRY, p); - } - return error; -} - -/***********************************************************************\ -* add a whole device, with no prototype.. make name element and node * -* Used for adding the original device entries * -\***********************************************************************/ -/*proto*/ -int -dev_add_entry(char *name, dn_p parent, int type, union typeinfo *by, - dn_p proto, struct devfsmount *dvm, devnm_p *nm_pp) -{ - dn_p dnp; - int error = 0; - - DBPRINT((" devfs_add_entry\n")); - if ((error = dev_add_node(type, by, proto, &dnp, - (parent?parent->dvm:dvm))) != 0) - { - printf("Device %s: base node allocation failed (Errno=%d)\n", - name,error); - return error; - } - if ((error = dev_add_name(name ,parent ,NULL, dnp, nm_pp)) != 0) - { - devfs_dn_free(dnp); /* 1->0 for dir, 0->(-1) for other */ - printf("Device %s: name slot allocation failed (Errno=%d)\n", - name,error); - - } - return error; -} - -static void -devfs_add_to_tree(dev_t dev, uid_t uid, gid_t gid, int perms) -{ - - struct cdevsw *devsw = dev->si_devsw; - - dev->si_devfs = devfs_add_devswf(dev->si_devsw, minor(dev), DV_CHR, - uid, gid, perms, "%s", dev->si_name ); - - /* XXX HACK .. name may not start in 'r' */ - if ((devsw->d_bmaj != -1) - && (dev->si_name[0] == 'r') - && ((devsw->d_flags & D_TYPEMASK) == D_DISK)) { - dev->si_bdevfs = devfs_add_devswf(devsw, minor(dev), DV_BLK, - uid, gid, perms, dev->si_name + 1); - } -} -/***********************************************************************\ -* Add the named device entry into the given directory, and make it * -* The appropriate type... (called (sometimes indirectly) by drivers..) * -* this function is exported.. see sys/devfsext.h * -* Has the capacity to take printf type arguments to format the device * -* names * -\***********************************************************************/ -void * -devfs_add_devswf(void *devsw, int minor, int chrblk, uid_t uid, - gid_t gid, int perms, char *fmt, ...) -{ - int major; - devnm_p new_dev; - dn_p dnp; /* devnode for parent directory */ - int retval; - union typeinfo by; - struct cdevsw *cd; - - va_list ap; - char *name, *path, buf[256]; /* XXX */ - int i; - - va_start(ap, fmt); - i = kvprintf(fmt, NULL, (void*)buf, 32, ap); - va_end(ap); - buf[i] = '\0'; - name = NULL; - - for(i=strlen(buf); i>0; i--) - if(buf[i] == '/') { - name=&buf[i]; - buf[i]=0; - break; - } - - if (name) { - *name++ = '\0'; - path = buf; - } else { - name = buf; - path = "/"; - } - - DBPRINT(("dev_add\n")); - retval = dev_finddir(path,NULL,1,&dnp); - if (retval) return 0; - switch(chrblk) - { - case DV_CHR: - cd = devsw; - major = cd->d_maj; - if ( major == -1 ) return NULL; - by.dev.dev = makedev(major, minor); - if( dev_add_entry(name, dnp, DEV_CDEV, &by, NULL, NULL, &new_dev)) - return NULL; - break; - case DV_BLK: - cd = devsw; - major = cd->d_bmaj; - if ( major == -1 ) return NULL; - by.dev.dev = makebdev(major, minor); - if( dev_add_entry(name, dnp, DEV_BDEV, &by, NULL, NULL, &new_dev)) - return NULL; - break; - default: - return NULL; - } - new_dev->dnp->gid = gid; - new_dev->dnp->uid = uid; - new_dev->dnp->mode |= perms; - devfs_propogate(dnp->by.Dir.myname,new_dev); - return new_dev; -} - -/***********************************************************************\ -* Add the named device entry into the given directory, and make it * -* a link to the already created device given as an arg.. * -* this function is exported.. see sys/devfsext.h * -\***********************************************************************/ -void * -devfs_makelink(void *original, char *fmt, ...) -{ - devnm_p new_dev; - devnm_p orig = (devnm_p) original; - dn_p dirnode; /* devnode for parent directory */ - int retval; - - va_list ap; - char *p, buf[256]; /* XXX */ - int i; - - va_start(ap, fmt); - i = kvprintf(fmt, NULL, (void*)buf, 32, ap); - va_end(ap); - buf[i] = '\0'; - p = NULL; - - for(i=strlen(buf); i>0; i--) - if(buf[i] == '/') { - p=&buf[i]; - buf[i]=0; - break; - } - - DBPRINT(("dev_add\n")); - - /* - * The DEV_CDEV below is not used other than it must NOT be DEV_DIR - * the correctness of original should be checked.. - */ - - if (p) { - *p++ = '\0'; - retval = dev_finddir(buf,NULL,1,&dirnode); - if (retval) return 0; - if( dev_add_name(p, dirnode, NULL, orig->dnp, &new_dev)) - return NULL; - } else { - retval = dev_finddir("/",NULL,1,&dirnode); - if (retval) return 0; - if( dev_add_name(buf, dirnode, NULL, orig->dnp, &new_dev)) - return NULL; - } - devfs_propogate(dirnode->by.Dir.myname,new_dev); - return new_dev; -} - -/* - * internal kernel call to open a device. Return either 0 or an open vnode. - */ -struct vnode * -devfs_open_device(char *path, int type) -{ - register char *lastslash; - char *nextpart; - devnm_p nm_p; - dn_p dirnode; - struct vnode *vn; - - /* - * If the caller didn't supply a full path, ignore and be - * noisy about it. - */ - if (*path != '/') { - printf (__FUNCTION__ ": caller supplied bad path\n"); - return (NULL); - } - - /* - * find the last '/'. Unfortunatly rindex() while being in - * libkern source, is not being compiled.. do it by hand. - * lastslash = strrchr(path,(int)'c'); - * There will be at LEAST one '/'. - */ - { - register char *p = path; /* don't destroy path */ - - for (lastslash = NULL;*p; ++p) { - if (*p == '/') - lastslash = p; - } - } - dirnode = dev_root->dnp; - if(lastslash != path) { - /* find the directory we need */ - *lastslash = '\0'; - if (dev_finddir(path, dirnode, NULL, &dirnode) != 0) { - *lastslash = '/'; - return (NULL); - } - /* ok we found the directory, put the slash back */ - *lastslash = '/'; - } - nextpart = ++lastslash; - if (*nextpart == '\0') - return (NULL); - /* - * Now only return true if it exists and is the right type. - */ - if ((nm_p = dev_findname(dirnode, nextpart)) == NULL) { - return (NULL); - } - switch(type) { - case DV_BLK: - if( nm_p->dnp->type != DEV_BDEV) - return (NULL); - break; - case DV_CHR: - if( nm_p->dnp->type != DEV_CDEV) - return (NULL); - break; - } - - if ( devfs_dntovn(nm_p->dnp, &vn)) - return (NULL); - -#if 0 - if ( VOP_OPEN(vn, FREAD, proc0.p_ucred, &proc0)) { - vput(vn); - return (NULL); - } -#endif - return (vn); -} - -/* - * internal kernel call to close a devfs device. - * It should have been openned by th ecall above. - * try not mix it with user-openned vnodes. - * Frees the vnode. - */ -void -devfs_close_device(struct vnode *vn) -{ -#if 0 - VOP_CLOSE(vn, 0, proc0.p_ucred, &proc0) ; -#endif - vput(vn); -} - -#if 0 -/* - * Little utility routine for compatibilty. - * Returns the dev_t that a devfs vnode represents. - * should go away after dev_t go away :). - */ -dev_t -devfs_vntodev(struct vnode *vn) -{ - register dn_p dnp; - dnp = (dn_p)vn->v_data; - switch (dnp->type) { - case DEV_BDEV: - return (dnp->by.dev.dev); - break; - case DEV_CDEV: - return (dnp->by.dev.dev); - break; - } - panic ("bad devfs DEVICE vnode"); -} -#endif |