|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.