1997-10-16 07:28:50 +00:00
|
|
|
|
/*#define SPLIT_DEVS 1*/
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* Written by Julian Elischer (julian@DIALix.oz.au)
|
|
|
|
|
*
|
1997-10-16 07:28:50 +00:00
|
|
|
|
* $Header: /home/ncvs/src/sys/miscfs/devfs/devfs_tree.c,v 1.46 1997/10/16 06:29:27 julian Exp $
|
1995-09-06 08:26:51 +00:00
|
|
|
|
*/
|
|
|
|
|
|
1996-10-28 11:36:06 +00:00
|
|
|
|
#include "opt_devfs.h"
|
|
|
|
|
|
1996-09-10 08:32:01 +00:00
|
|
|
|
#include <sys/param.h>
|
|
|
|
|
#include <sys/systm.h>
|
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
|
#include <sys/conf.h>
|
1997-10-12 20:26:33 +00:00
|
|
|
|
#include <sys/malloc.h>
|
1996-09-10 08:32:01 +00:00
|
|
|
|
#include <sys/mount.h>
|
1997-02-12 16:19:11 +00:00
|
|
|
|
#include <sys/proc.h>
|
1997-04-10 14:35:32 +00:00
|
|
|
|
#include <sys/time.h>
|
1996-09-10 08:32:01 +00:00
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
|
#include <sys/devfsext.h>
|
|
|
|
|
|
1996-09-29 15:00:37 +00:00
|
|
|
|
#include <machine/stdarg.h>
|
|
|
|
|
|
1996-09-10 08:32:01 +00:00
|
|
|
|
#include <miscfs/devfs/devfsdefs.h>
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
1997-10-11 18:31:40 +00:00
|
|
|
|
|
1997-10-12 20:26:33 +00:00
|
|
|
|
static MALLOC_DEFINE(M_DEVFSNODE, "DEVFS node", "DEVFS node");
|
|
|
|
|
static MALLOC_DEFINE(M_DEVFSNAME, "DEVFS name", "DEVFS name");
|
1997-10-11 18:31:40 +00:00
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
devnm_p dev_root; /* root of the backing tree */
|
|
|
|
|
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!
|
1997-07-14 04:53:52 +00:00
|
|
|
|
* DEVFS has a hidden mountpoint that is used as the anchor point
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* for the internal 'blueprint' version of the dev filesystem tree.
|
1995-09-06 08:26:51 +00:00
|
|
|
|
*/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
void
|
1996-04-07 01:15:03 +00:00
|
|
|
|
devfs_sinit(void *junk)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
|
|
|
|
int retval; /* we will discard this */
|
1996-06-12 05:08:34 +00:00
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* call the right routine at the right time with the right args....
|
|
|
|
|
*/
|
1996-11-21 07:19:00 +00:00
|
|
|
|
retval = dev_add_entry("root", NULL, DEV_DIR, NULL, NULL, NULL, &dev_root);
|
1995-09-06 09:29:19 +00:00
|
|
|
|
#ifdef PARANOID
|
1995-09-09 12:51:56 +00:00
|
|
|
|
if(retval) panic("devfs_sinit: dev_add_entry failed ");
|
1995-09-06 09:29:19 +00:00
|
|
|
|
#endif
|
1995-09-06 08:26:51 +00:00
|
|
|
|
devfs_hidden_mount = (struct mount *)malloc(sizeof(struct mount),
|
|
|
|
|
M_MOUNT,M_NOWAIT);
|
|
|
|
|
#ifdef PARANOID
|
1995-09-06 09:29:19 +00:00
|
|
|
|
if(!devfs_hidden_mount) panic("devfs_sinit: malloc failed");
|
1995-09-06 08:26:51 +00:00
|
|
|
|
#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");
|
1997-10-16 06:29:27 +00:00
|
|
|
|
/* part 2 of this is done later */
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
1996-11-21 07:19:00 +00:00
|
|
|
|
SYSINIT(devfs, SI_SUB_DEVFS, SI_ORDER_FIRST, devfs_sinit, NULL)
|
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
|
|
|
|
/***********************************************************************\
|
1995-09-07 06:01:36 +00:00
|
|
|
|
*************************************************************************
|
|
|
|
|
* Routines used to find our way to a point in the tree *
|
|
|
|
|
*************************************************************************
|
1995-09-06 08:26:51 +00:00
|
|
|
|
\***********************************************************************/
|
1995-09-07 06:01:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************\
|
|
|
|
|
* Search down the linked list off a dir to find "name" *
|
|
|
|
|
* return the dn_p for that node.
|
|
|
|
|
\***************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
devnm_p
|
1996-04-07 01:15:03 +00:00
|
|
|
|
dev_findname(dn_p dir,char *name)
|
1995-09-07 06:01:36 +00:00
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
1995-09-09 12:51:56 +00:00
|
|
|
|
return dir->by.Dir.myname;
|
1995-09-07 06:01:36 +00:00
|
|
|
|
}
|
|
|
|
|
if((name[1] == '.') && (name[2] == 0))
|
|
|
|
|
{
|
1995-09-09 12:51:56 +00:00
|
|
|
|
/* for root, .. == . */
|
|
|
|
|
return dir->by.Dir.parent->by.Dir.myname;
|
1995-09-07 06:01:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
newfp = dir->by.Dir.dirlist;
|
|
|
|
|
while(newfp)
|
|
|
|
|
{
|
|
|
|
|
if(!(strcmp(name,newfp->name)))
|
1995-09-09 12:51:56 +00:00
|
|
|
|
return newfp;
|
1995-09-07 06:01:36 +00:00
|
|
|
|
newfp = newfp->next;
|
|
|
|
|
}
|
1995-09-09 12:51:56 +00:00
|
|
|
|
return NULL;
|
1995-09-07 06:01:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/***********************************************************************\
|
|
|
|
|
* 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. *
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* char *orig_path, find this dir (err if not dir) *
|
1995-09-06 08:26:51 +00:00
|
|
|
|
* 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 *
|
|
|
|
|
\***********************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
int
|
1996-04-07 01:15:03 +00:00
|
|
|
|
dev_finddir(char *orig_path, dn_p dirnode, int create, dn_p *dn_pp)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
|
|
|
|
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);
|
1996-11-21 07:19:00 +00:00
|
|
|
|
|
1995-12-09 09:11:25 +00:00
|
|
|
|
/***************************************\
|
|
|
|
|
* always absolute, skip leading / *
|
|
|
|
|
* get rid of / or // or /// etc. *
|
|
|
|
|
\***************************************/
|
|
|
|
|
while(*path == '/') path++;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
|
1995-12-09 09:11:25 +00:00
|
|
|
|
/***************************************\
|
|
|
|
|
* If nothing left, then parent was it.. *
|
|
|
|
|
\***************************************/
|
|
|
|
|
if ( *path == '\0' ) {
|
|
|
|
|
*dn_pp = dirnode;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/***************************************\
|
|
|
|
|
* find the next segment of the name *
|
|
|
|
|
\***************************************/
|
|
|
|
|
cp = name = path;
|
1996-08-13 07:21:45 +00:00
|
|
|
|
while((*cp != '/') && (*cp != 0)) {
|
1995-09-06 08:26:51 +00:00
|
|
|
|
cp++;
|
|
|
|
|
}
|
1995-12-09 09:11:25 +00:00
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/***********************************************\
|
|
|
|
|
* Check to see if it's the last component *
|
|
|
|
|
\***********************************************/
|
1996-08-13 07:21:45 +00:00
|
|
|
|
if(*cp) {
|
1995-09-06 08:26:51 +00:00
|
|
|
|
path = cp + 1; /* path refers to the rest */
|
|
|
|
|
*cp = 0; /* name is now a separate string */
|
1996-11-21 07:19:00 +00:00
|
|
|
|
if(!(*path)) {
|
1995-09-06 08:26:51 +00:00
|
|
|
|
path = (char *)0; /* was trailing slash */
|
|
|
|
|
}
|
1996-08-13 07:21:45 +00:00
|
|
|
|
} else {
|
1996-11-21 07:19:00 +00:00
|
|
|
|
path = NULL; /* no more to do */
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************\
|
|
|
|
|
* Start scanning along the linked list *
|
|
|
|
|
\***************************************/
|
1995-09-09 12:51:56 +00:00
|
|
|
|
devnmp = dev_findname(dirnode,name);
|
1996-08-13 07:21:45 +00:00
|
|
|
|
if(devnmp) { /* check it's a directory */
|
1995-09-09 12:51:56 +00:00
|
|
|
|
dnp = devnmp->dnp;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
if(dnp->type != DEV_DIR) return ENOTDIR;
|
1996-08-13 07:21:45 +00:00
|
|
|
|
} else {
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/***************************************\
|
|
|
|
|
* The required element does not exist *
|
|
|
|
|
* So we will add it if asked to. *
|
|
|
|
|
\***************************************/
|
|
|
|
|
if(!create) return ENOENT;
|
|
|
|
|
|
1995-09-09 12:51:56 +00:00
|
|
|
|
if(retval = dev_add_entry(name, dirnode, DEV_DIR,
|
1996-11-21 07:19:00 +00:00
|
|
|
|
NULL, NULL, NULL, &devnmp)) {
|
1995-09-06 08:26:51 +00:00
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
dnp = devnmp->dnp;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
devfs_propogate(dirnode->by.Dir.myname,devnmp);
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
1996-11-21 07:19:00 +00:00
|
|
|
|
if(path != NULL) { /* decide whether to recurse more or return */
|
1995-09-06 08:26:51 +00:00
|
|
|
|
return (dev_finddir(path,dnp,create,dn_pp));
|
1996-08-13 07:21:45 +00:00
|
|
|
|
} else {
|
1995-09-06 08:26:51 +00:00
|
|
|
|
*dn_pp = dnp;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************\
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* Add a new NAME element to the devfs *
|
1995-09-06 08:26:51 +00:00
|
|
|
|
* If we're creating a root node, then dirname is NULL *
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* Basically this creates a new namespace entry for the device node *
|
1995-09-07 06:01:36 +00:00
|
|
|
|
* *
|
1995-09-09 12:51:56 +00:00
|
|
|
|
* Creates a name node, and links it to the supplied node *
|
1995-09-06 08:26:51 +00:00
|
|
|
|
\***********************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
int
|
|
|
|
|
dev_add_name(char *name, dn_p dirnode, devnm_p back, dn_p dnp,
|
1996-04-07 01:15:03 +00:00
|
|
|
|
devnm_p *devnm_pp)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
|
|
|
|
devnm_p devnmp;
|
|
|
|
|
|
1995-09-07 06:01:36 +00:00
|
|
|
|
DBPRINT(("dev_add_name\n"));
|
1996-11-21 07:19:00 +00:00
|
|
|
|
if(dirnode != NULL ) {
|
1995-09-06 08:26:51 +00:00
|
|
|
|
if(dirnode->type != DEV_DIR) return(ENOTDIR);
|
|
|
|
|
|
1995-09-09 12:51:56 +00:00
|
|
|
|
if( dev_findname(dirnode,name))
|
1995-09-06 08:26:51 +00:00
|
|
|
|
return(EEXIST);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* make sure the name is legal
|
|
|
|
|
* slightly misleading in the case of NULL
|
|
|
|
|
*/
|
|
|
|
|
if( !name || (strlen(name) > (DEVMAXNAMESIZE - 1)))
|
|
|
|
|
return (ENAMETOOLONG);
|
1996-11-21 07:19:00 +00:00
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* Allocate and fill out a new directory entry
|
|
|
|
|
*/
|
|
|
|
|
if(!(devnmp = (devnm_p)malloc(sizeof(devnm_t),
|
1996-08-13 07:21:45 +00:00
|
|
|
|
M_DEVFSNAME, M_NOWAIT))) {
|
1995-09-06 08:26:51 +00:00
|
|
|
|
return ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
bzero(devnmp,sizeof(devnm_t));
|
|
|
|
|
|
1995-09-09 12:51:56 +00:00
|
|
|
|
/* 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 ");
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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 */
|
1996-11-21 07:19:00 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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);
|
1997-08-26 17:17:52 +00:00
|
|
|
|
*devnmp->prevlinkp = devnmp;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
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.
|
|
|
|
|
*/
|
1995-09-09 12:51:56 +00:00
|
|
|
|
if(dnp->type == DEV_DIR) {
|
|
|
|
|
dnp->by.Dir.myname = devnmp;
|
|
|
|
|
/*
|
|
|
|
|
* If we are unlinking from an old dir, decrement it's links
|
|
|
|
|
* as we point our '..' elsewhere
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* Note: it's up to the calling code to remove the
|
1997-07-14 04:53:52 +00:00
|
|
|
|
* us from the original directory's list
|
1995-09-09 12:51:56 +00:00
|
|
|
|
*/
|
|
|
|
|
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 '..' */
|
|
|
|
|
}
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
|
|
|
|
/*
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* put the name into the directory entry.
|
1995-09-06 08:26:51 +00:00
|
|
|
|
*/
|
1996-11-21 07:19:00 +00:00
|
|
|
|
strcpy(devnmp->name, name);
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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 ;
|
|
|
|
|
}
|
|
|
|
|
|
1995-09-09 12:51:56 +00:00
|
|
|
|
|
|
|
|
|
/***********************************************************************\
|
1997-09-16 09:10:18 +00:00
|
|
|
|
* Add a new element to the devfs plane. *
|
1995-09-09 12:51:56 +00:00
|
|
|
|
* *
|
1997-09-16 09:10:18 +00:00
|
|
|
|
* 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. *
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* If 'by is null and proto exists, then the 'by' field of *
|
1997-09-16 09:10:18 +00:00
|
|
|
|
* the proto is used intead in the CREATE case. *
|
1995-09-09 12:51:56 +00:00
|
|
|
|
* 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 *
|
1997-09-16 09:10:18 +00:00
|
|
|
|
* Even in SPLIT_DEVS mode, *
|
|
|
|
|
* if the node already exists on the wanted plane, just return it *
|
1995-09-09 12:51:56 +00:00
|
|
|
|
\***********************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
int
|
1996-11-21 07:19:00 +00:00
|
|
|
|
dev_add_node(int entrytype, union typeinfo *by, dn_p proto,
|
|
|
|
|
dn_p *dn_pp,struct devfsmount *dvm)
|
1995-09-09 12:51:56 +00:00
|
|
|
|
{
|
|
|
|
|
dn_p dnp;
|
|
|
|
|
|
|
|
|
|
DBPRINT(("dev_add_node\n"));
|
1997-09-16 09:10:18 +00:00
|
|
|
|
#if defined SPLIT_DEVS
|
1996-11-21 07:19:00 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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);
|
|
|
|
|
}
|
1997-09-16 09:10:18 +00:00
|
|
|
|
#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 */
|
1995-09-09 12:51:56 +00:00
|
|
|
|
if(!(dnp = (dn_p)malloc(sizeof(devnode_t),
|
|
|
|
|
M_DEVFSNODE, M_NOWAIT)))
|
|
|
|
|
{
|
|
|
|
|
return ENOMEM;
|
|
|
|
|
}
|
1996-11-21 07:19:00 +00:00
|
|
|
|
|
1996-08-13 07:21:45 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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
|
|
|
|
|
*/
|
1995-09-09 12:51:56 +00:00
|
|
|
|
if(proto) {
|
|
|
|
|
bcopy(proto, dnp, sizeof(devnode_t));
|
|
|
|
|
dnp->links = 0;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
dnp->linklist = NULL;
|
1995-09-09 12:51:56 +00:00
|
|
|
|
dnp->vn = NULL;
|
|
|
|
|
dnp->len = 0;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
/* add to END of siblings list */
|
|
|
|
|
dnp->prevsiblingp = proto->prevsiblingp;
|
|
|
|
|
*(dnp->prevsiblingp) = dnp;
|
|
|
|
|
dnp->nextsibling = proto;
|
|
|
|
|
proto->prevsiblingp = &(dnp->nextsibling);
|
1995-09-09 12:51:56 +00:00
|
|
|
|
} else {
|
1996-08-13 07:21:45 +00:00
|
|
|
|
/*
|
|
|
|
|
* We have no prototype, so start off with a clean slate
|
|
|
|
|
*/
|
1995-09-09 12:51:56 +00:00
|
|
|
|
bzero(dnp,sizeof(devnode_t));
|
|
|
|
|
dnp->type = entrytype;
|
|
|
|
|
TIMEVAL_TO_TIMESPEC(&time,&(dnp->ctime))
|
|
|
|
|
dnp->mtime = dnp->ctime;
|
|
|
|
|
dnp->atime = dnp->ctime;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
dnp->nextsibling = dnp;
|
|
|
|
|
dnp->prevsiblingp = &(dnp->nextsibling);
|
1995-09-09 12:51:56 +00:00
|
|
|
|
}
|
1996-11-21 07:19:00 +00:00
|
|
|
|
dnp->dvm = dvm;
|
|
|
|
|
|
1995-09-09 12:51:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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;
|
1996-08-13 07:21:45 +00:00
|
|
|
|
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 it's 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;
|
1995-09-09 12:51:56 +00:00
|
|
|
|
case DEV_BDEV:
|
|
|
|
|
/*
|
|
|
|
|
* Make sure it has DEVICE type ops
|
|
|
|
|
* and device specific fields are correct
|
|
|
|
|
*/
|
|
|
|
|
dnp->ops = &dev_spec_vnodeop_p;
|
|
|
|
|
dnp->by.Bdev.bdevsw = by->Bdev.bdevsw;
|
|
|
|
|
dnp->by.Bdev.dev = by->Bdev.dev;
|
|
|
|
|
break;
|
|
|
|
|
case DEV_CDEV:
|
|
|
|
|
/*
|
|
|
|
|
* Make sure it has DEVICE type ops
|
|
|
|
|
* and device specific fields are correct
|
|
|
|
|
*/
|
|
|
|
|
dnp->ops = &dev_spec_vnodeop_p;
|
|
|
|
|
dnp->by.Cdev.cdevsw = by->Cdev.cdevsw;
|
|
|
|
|
dnp->by.Cdev.dev = by->Cdev.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;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
dnp->by.Ddev.ops = by->Ddev.ops;
|
1995-09-09 12:51:56 +00:00
|
|
|
|
dnp->ops = by->Ddev.ops;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*dn_pp = dnp;
|
|
|
|
|
return 0 ;
|
|
|
|
|
}
|
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
int
|
1996-04-07 01:15:03 +00:00
|
|
|
|
dev_touch(devnm_p key) /* update the node for this dev */
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
|
|
|
|
DBPRINT(("dev_touch\n"));
|
|
|
|
|
TIMEVAL_TO_TIMESPEC(&time,&(key->dnp->mtime))
|
|
|
|
|
return 0; /*XXX*/
|
|
|
|
|
}
|
|
|
|
|
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
|
|
|
|
void
|
|
|
|
|
devfs_dn_free(dn_p dnp)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
1995-09-09 12:51:56 +00:00
|
|
|
|
if(--dnp->links <= 0 ) /* can be -1 for initial free, on error */
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
1995-09-07 06:01:36 +00:00
|
|
|
|
/*probably need to do other cleanups XXX */
|
1997-05-03 21:19:54 +00:00
|
|
|
|
if (dnp->nextsibling != dnp) {
|
|
|
|
|
dn_p* prevp = dnp->prevsiblingp;
|
|
|
|
|
*prevp = dnp->nextsibling;
|
|
|
|
|
dnp->nextsibling->prevsiblingp = prevp;
|
|
|
|
|
|
|
|
|
|
}
|
1996-08-13 07:21:45 +00:00
|
|
|
|
if(dnp->type == DEV_SLNK) {
|
|
|
|
|
free(dnp->by.Slnk.name,M_DEVFSNODE);
|
|
|
|
|
}
|
1995-09-06 08:26:51 +00:00
|
|
|
|
devfs_dropvnode(dnp);
|
|
|
|
|
free (dnp, M_DEVFSNODE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************\
|
|
|
|
|
* Front Node Operations *
|
1995-09-07 06:01:36 +00:00
|
|
|
|
* Add or delete a chain of front nodes *
|
1995-09-06 08:26:51 +00:00
|
|
|
|
\***********************************************************************/
|
|
|
|
|
|
|
|
|
|
/***********************************************************************\
|
|
|
|
|
* 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 *
|
|
|
|
|
* *
|
1995-09-07 06:01:36 +00:00
|
|
|
|
* This allows a new node to be propogated through all mounted planes *
|
|
|
|
|
* *
|
1995-09-06 08:26:51 +00:00
|
|
|
|
\***********************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
int
|
1996-11-21 07:19:00 +00:00
|
|
|
|
devfs_propogate(devnm_p parent,devnm_p child)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
1996-01-21 09:43:31 +00:00
|
|
|
|
int error;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
devnm_p newnmp;
|
1995-09-09 12:51:56 +00:00
|
|
|
|
dn_p dnp = child->dnp;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
dn_p pdnp = parent->dnp;
|
|
|
|
|
dn_p adnp = parent->dnp;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
int type = child->dnp->type;
|
|
|
|
|
|
1996-11-21 07:19:00 +00:00
|
|
|
|
DBPRINT((" devfs_propogate\n"));
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/***********************************************\
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* Find the other instances of the parent node *
|
1995-09-06 08:26:51 +00:00
|
|
|
|
\***********************************************/
|
1996-11-21 07:19:00 +00:00
|
|
|
|
for (adnp = pdnp->nextsibling;
|
1997-08-26 17:17:52 +00:00
|
|
|
|
adnp != pdnp;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
adnp = adnp->nextsibling)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
1995-09-09 12:51:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* Make the node, using the original as a prototype)
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* if the node already exists on that plane it won't be
|
|
|
|
|
* re-made..
|
1995-09-09 12:51:56 +00:00
|
|
|
|
*/
|
1997-08-26 17:17:52 +00:00
|
|
|
|
if ( error = dev_add_entry(child->name, adnp, type,
|
1996-11-21 07:19:00 +00:00
|
|
|
|
NULL, dnp, adnp->dvm, &newnmp)) {
|
|
|
|
|
printf("duplicating %s failed\n",child->name);
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1995-09-09 12:51:56 +00:00
|
|
|
|
return 0; /* for now always succeed */
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
1995-09-09 12:51:56 +00:00
|
|
|
|
|
1995-09-07 06:01:36 +00:00
|
|
|
|
/***********************************************************************
|
|
|
|
|
* 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)
|
|
|
|
|
*
|
1996-01-21 09:03:15 +00:00
|
|
|
|
* 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
|
1995-09-07 06:01:36 +00:00
|
|
|
|
***********************************************************************/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
void
|
|
|
|
|
devfs_remove_dev(void *devnmp)
|
1995-09-07 06:01:36 +00:00
|
|
|
|
{
|
1996-11-21 07:19:00 +00:00
|
|
|
|
dn_p dnp = ((devnm_p)devnmp)->dnp;
|
|
|
|
|
dn_p dnp2;
|
|
|
|
|
|
1996-01-21 09:03:15 +00:00
|
|
|
|
DBPRINT(("devfs_remove_dev\n"));
|
1996-11-21 07:19:00 +00:00
|
|
|
|
/* 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);
|
|
|
|
|
}
|
1995-09-07 06:01:36 +00:00
|
|
|
|
}
|
1996-11-21 07:19:00 +00:00
|
|
|
|
|
1995-09-07 06:01:36 +00:00
|
|
|
|
/*
|
|
|
|
|
* then free the main node
|
1997-10-10 07:54:05 +00:00
|
|
|
|
* If we are not running in SPLIT_DEVS mode, then
|
|
|
|
|
* THIS is what gets rid of the propogated nodes.
|
1995-09-07 06:01:36 +00:00
|
|
|
|
*/
|
1997-10-10 07:54:05 +00:00
|
|
|
|
while(dnp->linklist)
|
|
|
|
|
{
|
|
|
|
|
dev_free_name(dnp->linklist);
|
|
|
|
|
}
|
1995-09-07 06:01:36 +00:00
|
|
|
|
return ;
|
|
|
|
|
}
|
1996-11-21 07:19:00 +00:00
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
1995-09-07 06:01:36 +00:00
|
|
|
|
/***************************************************************
|
|
|
|
|
* duplicate the backing tree into a tree of nodes hung off the
|
|
|
|
|
* mount point given as the argument. Do this by
|
1995-09-09 12:51:56 +00:00
|
|
|
|
* calling dev_dup_entry which recurses all the way
|
1995-09-07 06:01:36 +00:00
|
|
|
|
* up the tree..
|
|
|
|
|
* If we are the first plane, just return the base root
|
|
|
|
|
**************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
int
|
1996-04-07 01:15:03 +00:00
|
|
|
|
dev_dup_plane(struct devfsmount *devfs_mp_p)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
1995-09-07 06:01:36 +00:00
|
|
|
|
devnm_p new;
|
|
|
|
|
int error = 0;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
1995-09-07 06:01:36 +00:00
|
|
|
|
DBPRINT((" dev_dup_plane\n"));
|
|
|
|
|
if(devfs_up_and_going) {
|
1995-09-09 12:51:56 +00:00
|
|
|
|
if(error = dev_dup_entry(NULL, dev_root, &new, devfs_mp_p)) {
|
1995-09-07 06:01:36 +00:00
|
|
|
|
return error;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
1995-09-07 06:01:36 +00:00
|
|
|
|
} else { /* we are doing the dummy mount during initialisation.. */
|
|
|
|
|
new = dev_root;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
1995-09-07 06:01:36 +00:00
|
|
|
|
devfs_mp_p->plane_root = new;
|
|
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***************************************************************\
|
|
|
|
|
* Free a whole plane
|
|
|
|
|
\***************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
void
|
1996-04-07 01:15:03 +00:00
|
|
|
|
devfs_free_plane(struct devfsmount *devfs_mp_p)
|
1995-09-07 06:01:36 +00:00
|
|
|
|
{
|
|
|
|
|
devnm_p devnmp;
|
|
|
|
|
|
|
|
|
|
DBPRINT((" devfs_free_plane\n"));
|
|
|
|
|
devnmp = devfs_mp_p->plane_root;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
if(devnmp) {
|
|
|
|
|
dev_free_hier(devnmp);
|
|
|
|
|
dev_free_name(devnmp);
|
|
|
|
|
}
|
1995-09-07 06:01:36 +00:00
|
|
|
|
devfs_mp_p->plane_root = NULL;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************\
|
|
|
|
|
* Create and link in a new front element.. *
|
|
|
|
|
* Parent can be 0 for a root node *
|
|
|
|
|
* Not presently usable to make a symlink XXX *
|
1996-08-13 07:21:45 +00:00
|
|
|
|
* (Ok, symlinks don't propogate)
|
1995-09-07 06:01:36 +00:00
|
|
|
|
* recursively will create subnodes corresponding to equivalent *
|
|
|
|
|
* child nodes in the base level *
|
1995-09-06 08:26:51 +00:00
|
|
|
|
\***************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
int
|
|
|
|
|
dev_dup_entry(dn_p parent, devnm_p back, devnm_p *dnm_pp,
|
1996-04-07 01:15:03 +00:00
|
|
|
|
struct devfsmount *dvm)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
|
|
|
|
devnm_p newnmp;
|
|
|
|
|
devnm_p newback;
|
|
|
|
|
devnm_p newfront;
|
|
|
|
|
int error;
|
|
|
|
|
dn_p dnp = back->dnp;
|
1997-09-16 09:10:18 +00:00
|
|
|
|
int type = dnp->type;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
1995-09-09 12:51:56 +00:00
|
|
|
|
DBPRINT((" dev_dup_entry\n"));
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/*
|
1995-09-09 12:51:56 +00:00
|
|
|
|
* go get the node made (if we need to)
|
|
|
|
|
* use the back one as a prototype
|
1995-09-06 08:26:51 +00:00
|
|
|
|
*/
|
1997-09-16 09:10:18 +00:00
|
|
|
|
if ( error = dev_add_entry(back->name, parent, type,
|
1996-11-21 07:19:00 +00:00
|
|
|
|
NULL, dnp,
|
|
|
|
|
parent?parent->dvm:dvm, &newnmp)) {
|
|
|
|
|
printf("duplicating %s failed\n",back->name);
|
1995-09-09 12:51:56 +00:00
|
|
|
|
}
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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..
|
|
|
|
|
*/
|
1997-09-16 09:10:18 +00:00
|
|
|
|
if (type == DEV_DIR)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
|
|
|
|
for(newback = back->dnp->by.Dir.dirlist;
|
|
|
|
|
newback; newback = newback->next)
|
|
|
|
|
{
|
1995-09-09 12:51:56 +00:00
|
|
|
|
if(error = dev_dup_entry(newnmp->dnp,
|
1995-09-06 08:26:51 +00:00
|
|
|
|
newback, &newfront, NULL))
|
|
|
|
|
{
|
|
|
|
|
break; /* back out with an error */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*dnm_pp = newnmp;
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************\
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* Free a name node *
|
1995-09-07 06:01:36 +00:00
|
|
|
|
* remember that if there are other names pointing to the *
|
|
|
|
|
* dev_node then it may not get freed yet *
|
1995-09-09 12:51:56 +00:00
|
|
|
|
* can handle if there is no dnp *
|
1995-09-06 08:26:51 +00:00
|
|
|
|
\***************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-11-21 07:19:00 +00:00
|
|
|
|
int
|
1996-04-07 01:15:03 +00:00
|
|
|
|
dev_free_name(devnm_p devnmp)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
|
|
|
|
dn_p parent = devnmp->parent;
|
1995-09-09 12:51:56 +00:00
|
|
|
|
dn_p dnp = devnmp->dnp;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
|
|
|
|
DBPRINT((" dev_free_name\n"));
|
1995-09-09 12:51:56 +00:00
|
|
|
|
if(dnp) {
|
|
|
|
|
if(dnp->type == DEV_DIR)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
1996-11-21 07:19:00 +00:00
|
|
|
|
if(dnp->by.Dir.dirlist)
|
|
|
|
|
return (ENOTEMPTY);
|
|
|
|
|
devfs_dn_free(dnp); /* account for '.' */
|
1995-09-09 12:51:56 +00:00
|
|
|
|
devfs_dn_free(dnp->by.Dir.parent); /* '..' */
|
1996-11-21 07:19:00 +00:00
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* 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;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
1995-09-09 12:51:56 +00:00
|
|
|
|
devfs_dn_free(dnp);
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
1996-11-21 07:19:00 +00:00
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* unlink ourselves from the directory on this plane
|
|
|
|
|
*/
|
|
|
|
|
if(parent) /* if not fs root */
|
|
|
|
|
{
|
1996-08-13 07:21:45 +00:00
|
|
|
|
if( (*devnmp->prevp = devnmp->next) )/* yes, assign */
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
|
|
|
|
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 it's own devnode structure, *
|
|
|
|
|
* then free it. *
|
|
|
|
|
\***************************************************************/
|
|
|
|
|
free(devnmp,M_DEVFSNAME);
|
1996-11-21 07:19:00 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1995-09-07 06:01:36 +00:00
|
|
|
|
/*******************************************************\
|
|
|
|
|
*********************************************************
|
|
|
|
|
* ROUTINES to control the connection between devfs *
|
|
|
|
|
* nodes and the system's vnodes *
|
|
|
|
|
*********************************************************
|
|
|
|
|
\*******************************************************/
|
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/*******************************************************\
|
|
|
|
|
* Theoretically this could be called for any kind of *
|
|
|
|
|
* vnode, however in practice it must be a DEVFS vnode *
|
|
|
|
|
\*******************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
int
|
1996-04-07 01:15:03 +00:00
|
|
|
|
devfs_vntodn(struct vnode *vn_p, dn_p *dn_pp)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
DBPRINT((" vntodn "));
|
|
|
|
|
if(vn_p->v_tag != VT_DEVFS)
|
|
|
|
|
{
|
1995-10-10 07:12:27 +00:00
|
|
|
|
printf("bad-tag2 ");
|
1995-09-06 08:26:51 +00:00
|
|
|
|
Debugger("bad-tag ");
|
|
|
|
|
return(EINVAL);
|
|
|
|
|
}
|
1996-01-02 09:14:49 +00:00
|
|
|
|
#if 0
|
|
|
|
|
/*
|
|
|
|
|
* XXX: This is actually a "normal" case when vclean calls us without
|
|
|
|
|
* XXX: incrementing the reference count first.
|
|
|
|
|
*/
|
1995-09-06 08:26:51 +00:00
|
|
|
|
if(vn_p->v_usecount == 0)
|
|
|
|
|
{
|
1995-10-10 07:12:27 +00:00
|
|
|
|
printf("No references! ");
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
1996-01-02 09:14:49 +00:00
|
|
|
|
#endif
|
1996-08-13 07:21:45 +00:00
|
|
|
|
switch(vn_p->v_type) {
|
|
|
|
|
case VBAD:
|
|
|
|
|
printf("bad-type2 (VBAD)");
|
|
|
|
|
return(EINVAL);
|
|
|
|
|
case VNON:
|
|
|
|
|
printf("bad-type2 (VNON)");
|
1995-09-06 08:26:51 +00:00
|
|
|
|
return(EINVAL);
|
|
|
|
|
}
|
|
|
|
|
*dn_pp = (dn_p)vn_p->v_data;
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
|
1996-07-30 18:00:32 +00:00
|
|
|
|
#ifdef DEVFS_ROOT
|
1996-07-24 21:22:36 +00:00
|
|
|
|
static dn_p
|
|
|
|
|
findbdev(dev_t dev, dn_p dir)
|
|
|
|
|
{
|
|
|
|
|
devnm_p newfp;
|
|
|
|
|
dn_p dnp;
|
|
|
|
|
|
|
|
|
|
for(newfp = dir->by.Dir.dirlist;newfp;newfp=newfp->next) {
|
|
|
|
|
dnp = newfp->dnp;
|
|
|
|
|
if (dnp->type == DEV_BDEV && dnp->by.Bdev.dev == dev) {
|
|
|
|
|
return (dnp);
|
|
|
|
|
}
|
|
|
|
|
if (dnp->type == DEV_DIR) {
|
|
|
|
|
if (dnp = findbdev(dev, dnp))
|
|
|
|
|
return dnp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Create a vnode for a block device.
|
1997-09-07 16:21:11 +00:00
|
|
|
|
* Used for mounting the root file system.
|
1996-07-24 21:22:36 +00:00
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
bdevvp(dev_t dev, struct vnode **vpp)
|
|
|
|
|
{
|
|
|
|
|
dn_p dnp = 0;
|
|
|
|
|
|
1996-10-28 11:36:06 +00:00
|
|
|
|
if (dev == NODEV)
|
|
|
|
|
return(0);
|
1996-07-24 21:22:36 +00:00
|
|
|
|
dnp= findbdev(dev, dev_root->dnp);
|
|
|
|
|
if (!dnp)
|
1996-10-28 11:36:06 +00:00
|
|
|
|
return (ENOENT);
|
1996-07-24 21:22:36 +00:00
|
|
|
|
return (devfs_dntovn(dnp, vpp));
|
|
|
|
|
}
|
1996-07-30 18:00:32 +00:00
|
|
|
|
#endif /* DEVFS_ROOT */
|
1996-07-24 21:22:36 +00:00
|
|
|
|
|
1995-09-06 08:26:51 +00:00
|
|
|
|
/***************************************************************\
|
|
|
|
|
* 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?*
|
|
|
|
|
\***************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
int
|
1996-04-07 01:15:03 +00:00
|
|
|
|
devfs_dntovn(dn_p dnp, struct vnode **vn_pp)
|
1995-09-06 08:26:51 +00:00
|
|
|
|
{
|
|
|
|
|
struct vnode *vn_p, *nvp;
|
|
|
|
|
int error = 0;
|
1997-02-12 16:19:11 +00:00
|
|
|
|
struct proc *p = curproc; /* XXX */
|
1995-09-06 08:26:51 +00:00
|
|
|
|
|
|
|
|
|
vn_p = dnp->vn;
|
|
|
|
|
DBPRINT(("dntovn "));
|
|
|
|
|
if( vn_p)
|
|
|
|
|
{
|
|
|
|
|
if(vn_p->v_id != dnp->vn_id)
|
|
|
|
|
{
|
1996-01-02 09:14:49 +00:00
|
|
|
|
#if 0
|
|
|
|
|
/* XXX: This is `normal'... */
|
1995-09-06 08:26:51 +00:00
|
|
|
|
printf("bad-id ");
|
1996-01-02 09:14:49 +00:00
|
|
|
|
#endif
|
1995-09-06 08:26:51 +00:00
|
|
|
|
goto skip;
|
|
|
|
|
}
|
|
|
|
|
if(vn_p->v_tag != VT_DEVFS)
|
|
|
|
|
{
|
1996-01-02 09:14:49 +00:00
|
|
|
|
#if 0
|
|
|
|
|
/* XXX: This is `normal'... */
|
1995-09-06 08:26:51 +00:00
|
|
|
|
printf("bad-tag ");
|
1996-01-02 09:14:49 +00:00
|
|
|
|
#endif
|
1995-09-06 08:26:51 +00:00
|
|
|
|
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)
|
|
|
|
|
{
|
1997-02-12 16:19:11 +00:00
|
|
|
|
vget(vn_p, LK_EXCLUSIVE, p);
|
1995-09-06 08:26:51 +00:00
|
|
|
|
*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:
|
1996-08-13 07:21:45 +00:00
|
|
|
|
vn_p->v_type = VLNK;
|
1995-09-06 08:26:51 +00:00
|
|
|
|
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;
|
|
|
|
|
if (nvp = checkalias(vn_p,
|
|
|
|
|
dnp->by.Bdev.dev,
|
|
|
|
|
(struct mount *)0))
|
|
|
|
|
{
|
|
|
|
|
vput(vn_p);
|
|
|
|
|
vn_p = nvp;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case DEV_CDEV:
|
|
|
|
|
vn_p->v_type = VCHR;
|
|
|
|
|
if (nvp = checkalias(vn_p,
|
|
|
|
|
dnp->by.Cdev.dev,
|
|
|
|
|
(struct mount *)0))
|
|
|
|
|
{
|
|
|
|
|
vput(vn_p);
|
|
|
|
|
vn_p = nvp;
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
1997-02-12 16:19:11 +00:00
|
|
|
|
vn_lock(vn_p, LK_EXCLUSIVE | LK_RETRY, p);
|
1995-09-06 08:26:51 +00:00
|
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
1995-09-07 06:01:36 +00:00
|
|
|
|
|
|
|
|
|
/***********************************************************************\
|
1995-12-09 09:11:25 +00:00
|
|
|
|
* add a whole device, with no prototype.. make name element and node *
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* Used for adding the original device entries *
|
1995-09-09 12:51:56 +00:00
|
|
|
|
\***********************************************************************/
|
1996-04-07 01:15:03 +00:00
|
|
|
|
/*proto*/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
int
|
|
|
|
|
dev_add_entry(char *name, dn_p parent, int type, union typeinfo *by,
|
1996-11-21 07:19:00 +00:00
|
|
|
|
dn_p proto, struct devfsmount *dvm, devnm_p *nm_pp)
|
1995-09-09 12:51:56 +00:00
|
|
|
|
{
|
|
|
|
|
dn_p dnp;
|
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
|
|
DBPRINT((" devfs_add_entry\n"));
|
1996-11-21 07:19:00 +00:00
|
|
|
|
if (error = dev_add_node(type, by, proto, &dnp,
|
|
|
|
|
(parent?parent->dvm:dvm)))
|
1995-09-09 12:51:56 +00:00
|
|
|
|
{
|
1996-11-21 07:19:00 +00:00
|
|
|
|
printf("Device %s: base node allocation failed (Errno=%d)\n",
|
1996-01-21 09:43:31 +00:00
|
|
|
|
name,error);
|
1995-09-09 12:51:56 +00:00
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
if ( error = dev_add_name(name ,parent ,NULL, dnp, nm_pp))
|
|
|
|
|
{
|
|
|
|
|
devfs_dn_free(dnp); /* 1->0 for dir, 0->(-1) for other */
|
1996-11-21 07:19:00 +00:00
|
|
|
|
printf("Device %s: name slot allocation failed (Errno=%d)\n",
|
1996-01-21 09:43:31 +00:00
|
|
|
|
name,error);
|
1995-09-09 12:51:56 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************\
|
1995-09-07 06:01:36 +00:00
|
|
|
|
* Add the named device entry into the given directory, and make it *
|
1996-01-25 07:17:31 +00:00
|
|
|
|
* The appropriate type... (called (sometimes indirectly) by drivers..) *
|
|
|
|
|
* this function is exported.. see sys/devfsext.h *
|
1996-02-18 07:29:53 +00:00
|
|
|
|
* Has the capacity to take printf type arguments to format the device *
|
|
|
|
|
* names *
|
1996-01-25 07:17:31 +00:00
|
|
|
|
\***********************************************************************/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
void *
|
|
|
|
|
devfs_add_devswf(void *devsw, int minor, int chrblk, uid_t uid,
|
|
|
|
|
gid_t gid, int perms, char *fmt, ...)
|
1996-01-25 07:17:31 +00:00
|
|
|
|
{
|
1996-04-03 03:03:27 +00:00
|
|
|
|
int major;
|
|
|
|
|
devnm_p new_dev;
|
|
|
|
|
dn_p dnp; /* devnode for parent directory */
|
|
|
|
|
struct cdevsw *cd;
|
|
|
|
|
struct bdevsw *bd;
|
|
|
|
|
int retval;
|
|
|
|
|
union typeinfo by;
|
|
|
|
|
|
1996-01-25 07:17:31 +00:00
|
|
|
|
va_list ap;
|
1996-04-03 03:03:27 +00:00
|
|
|
|
char *name, *path, buf[256]; /* XXX */
|
1996-01-25 07:17:31 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
i = kvprintf(fmt, NULL, (void*)buf, 32, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
buf[i] = '\0';
|
1996-04-03 03:03:27 +00:00
|
|
|
|
name = NULL;
|
1996-01-28 10:07:55 +00:00
|
|
|
|
|
1996-03-25 21:56:59 +00:00
|
|
|
|
for(i=strlen(buf); i>0; i--)
|
|
|
|
|
if(buf[i] == '/') {
|
1996-04-03 03:03:27 +00:00
|
|
|
|
name=&buf[i];
|
1996-03-25 21:56:59 +00:00
|
|
|
|
buf[i]=0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
1996-01-28 10:07:55 +00:00
|
|
|
|
|
1996-04-03 03:03:27 +00:00
|
|
|
|
if (name) {
|
|
|
|
|
*name++ = '\0';
|
|
|
|
|
path = buf;
|
1996-01-25 07:17:31 +00:00
|
|
|
|
} else {
|
1996-04-03 03:03:27 +00:00
|
|
|
|
name = buf;
|
|
|
|
|
path = "/";
|
1996-01-25 07:17:31 +00:00
|
|
|
|
}
|
1995-11-29 10:49:16 +00:00
|
|
|
|
|
|
|
|
|
DBPRINT(("dev_add\n"));
|
|
|
|
|
retval = dev_finddir(path,NULL,1,&dnp);
|
|
|
|
|
if (retval) return 0;
|
|
|
|
|
switch(chrblk)
|
|
|
|
|
{
|
|
|
|
|
case DV_CHR:
|
1995-12-08 11:19:42 +00:00
|
|
|
|
cd = devsw;
|
|
|
|
|
major = cd->d_maj;
|
|
|
|
|
if ( major == -1 ) return NULL;
|
|
|
|
|
by.Cdev.cdevsw = cd;
|
1995-11-29 10:49:16 +00:00
|
|
|
|
by.Cdev.dev = makedev(major, minor);
|
1996-11-21 07:19:00 +00:00
|
|
|
|
if( dev_add_entry(name, dnp, DEV_CDEV, &by, NULL, NULL, &new_dev))
|
1995-11-29 10:49:16 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
break;
|
|
|
|
|
case DV_BLK:
|
1995-12-08 11:19:42 +00:00
|
|
|
|
bd = devsw;
|
|
|
|
|
major = bd->d_maj;
|
|
|
|
|
if ( major == -1 ) return NULL;
|
|
|
|
|
by.Bdev.bdevsw = bd;
|
1995-11-29 10:49:16 +00:00
|
|
|
|
by.Bdev.dev = makedev(major, minor);
|
1996-11-21 07:19:00 +00:00
|
|
|
|
if( dev_add_entry(name, dnp, DEV_BDEV, &by, NULL, NULL, &new_dev))
|
1995-09-08 04:46:14 +00:00
|
|
|
|
return NULL;
|
1995-09-07 06:01:36 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
1995-09-08 04:46:14 +00:00
|
|
|
|
return NULL;
|
1995-09-07 06:01:36 +00:00
|
|
|
|
}
|
|
|
|
|
new_dev->dnp->gid = gid;
|
|
|
|
|
new_dev->dnp->uid = uid;
|
|
|
|
|
new_dev->dnp->mode |= perms;
|
1996-11-21 07:19:00 +00:00
|
|
|
|
devfs_propogate(dnp->by.Dir.myname,new_dev);
|
1995-09-07 06:01:36 +00:00
|
|
|
|
return new_dev;
|
|
|
|
|
}
|
1995-09-09 12:51:56 +00:00
|
|
|
|
|
1995-09-08 04:46:14 +00:00
|
|
|
|
/***********************************************************************\
|
|
|
|
|
* Add the named device entry into the given directory, and make it *
|
|
|
|
|
* a link to the already created device given as an arg.. *
|
1996-01-21 09:03:15 +00:00
|
|
|
|
* this function is exported.. see sys/devfsext.h *
|
1995-09-08 04:46:14 +00:00
|
|
|
|
\***********************************************************************/
|
1996-04-06 13:34:37 +00:00
|
|
|
|
void *
|
|
|
|
|
devfs_link(void *original, char *fmt, ...)
|
1996-03-28 14:32:27 +00:00
|
|
|
|
{
|
|
|
|
|
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
|
1996-11-21 07:19:00 +00:00
|
|
|
|
* the correctness of original should be checked..
|
1996-03-28 14:32:27 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
1996-11-21 07:19:00 +00:00
|
|
|
|
devfs_propogate(dirnode->by.Dir.myname,new_dev);
|
1996-03-28 14:32:27 +00:00
|
|
|
|
return new_dev;
|
|
|
|
|
}
|
|
|
|
|
|