1/* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 2000 5 * Poul-Henning Kamp. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * Jan-Simon Pendry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95 32 * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43 33 *
| 1/* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 2000 5 * Poul-Henning Kamp. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * Jan-Simon Pendry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)kernfs_vnops.c 8.15 (Berkeley) 5/21/95 32 * From: FreeBSD: src/sys/miscfs/kernfs/kernfs_vnops.c 1.43 33 *
|
34 * $FreeBSD: head/sys/fs/devfs/devfs_vnops.c 111119 2003-02-19 05:47:46Z imp $
| 34 * $FreeBSD: head/sys/fs/devfs/devfs_vnops.c 111741 2003-03-02 15:50:23Z des $
|
35 */ 36 37/* 38 * TODO: 39 * remove empty directories 40 * mknod: hunt down DE_DELETED, compare name, reinstantiate. 41 * mkdir: want it ? 42 */ 43 44#include <opt_devfs.h> 45#include <opt_mac.h> 46 47#include <sys/param.h> 48#include <sys/systm.h> 49#include <sys/conf.h> 50#include <sys/dirent.h> 51#include <sys/kernel.h> 52#include <sys/lock.h> 53#include <sys/mac.h> 54#include <sys/malloc.h> 55#include <sys/mount.h> 56#include <sys/namei.h> 57#include <sys/proc.h> 58#include <sys/time.h> 59#include <sys/unistd.h> 60#include <sys/vnode.h> 61 62#include <fs/devfs/devfs.h> 63 64static int devfs_access(struct vop_access_args *ap); 65static int devfs_getattr(struct vop_getattr_args *ap); 66static int devfs_ioctl(struct vop_ioctl_args *ap); 67static int devfs_lookupx(struct vop_lookup_args *ap); 68static int devfs_mknod(struct vop_mknod_args *ap); 69static int devfs_pathconf(struct vop_pathconf_args *ap); 70static int devfs_read(struct vop_read_args *ap); 71static int devfs_readdir(struct vop_readdir_args *ap); 72static int devfs_readlink(struct vop_readlink_args *ap); 73static int devfs_reclaim(struct vop_reclaim_args *ap); 74static int devfs_remove(struct vop_remove_args *ap); 75static int devfs_revoke(struct vop_revoke_args *ap); 76static int devfs_setattr(struct vop_setattr_args *ap); 77#ifdef MAC 78static int devfs_setlabel(struct vop_setlabel_args *ap); 79#endif 80static int devfs_symlink(struct vop_symlink_args *ap); 81 82static vop_t **devfs_vnodeop_p; 83static vop_t **devfs_specop_p; 84 85/* 86 * Construct the fully qualified path name relative to the mountpoint 87 */ 88static char * 89devfs_fqpn(char *buf, struct vnode *dvp, struct componentname *cnp) 90{ 91 int i; 92 struct devfs_dirent *de, *dd; 93 struct devfs_mount *dmp; 94 95 dmp = VFSTODEVFS(dvp->v_mount); 96 dd = dvp->v_data; 97 i = SPECNAMELEN; 98 buf[i] = '\0'; 99 i -= cnp->cn_namelen; 100 if (i < 0) 101 return (NULL); 102 bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen); 103 de = dd; 104 while (de != dmp->dm_basedir) { 105 i--; 106 if (i < 0) 107 return (NULL); 108 buf[i] = '/'; 109 i -= de->de_dirent->d_namlen; 110 if (i < 0) 111 return (NULL); 112 bcopy(de->de_dirent->d_name, buf + i, 113 de->de_dirent->d_namlen); 114 de = TAILQ_FIRST(&de->de_dlist); /* "." */ 115 de = TAILQ_NEXT(de, de_list); /* ".." */ 116 de = de->de_dir; 117 } 118 return (buf + i); 119} 120 121int 122devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td) 123{ 124 int error; 125 struct vnode *vp; 126 dev_t dev; 127 128 if (td == NULL) 129 td = curthread; /* XXX */ 130loop: 131 vp = de->de_vnode; 132 if (vp != NULL) { 133 if (vget(vp, LK_EXCLUSIVE, td ? td : curthread)) 134 goto loop; 135 *vpp = vp; 136 return (0); 137 } 138 if (de->de_dirent->d_type == DT_CHR) { 139 dev = *devfs_itod(de->de_inode); 140 if (dev == NULL) 141 return (ENOENT); 142 } else { 143 dev = NODEV; 144 } 145 error = getnewvnode("devfs", mp, devfs_vnodeop_p, &vp); 146 if (error != 0) { 147 printf("devfs_allocv: failed to allocate new vnode\n"); 148 return (error); 149 } 150 151 if (de->de_dirent->d_type == DT_CHR) { 152 vp->v_type = VCHR; 153 vp = addaliasu(vp, dev->si_udev); 154 vp->v_op = devfs_specop_p; 155 } else if (de->de_dirent->d_type == DT_DIR) { 156 vp->v_type = VDIR; 157 } else if (de->de_dirent->d_type == DT_LNK) { 158 vp->v_type = VLNK; 159 } else { 160 vp->v_type = VBAD; 161 } 162 vp->v_data = de; 163 de->de_vnode = vp; 164 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 165#ifdef MAC 166 mac_associate_vnode_devfs(mp, de, vp); 167#endif 168 *vpp = vp; 169 return (0); 170} 171 172static int 173devfs_access(ap) 174 struct vop_access_args /* { 175 struct vnode *a_vp; 176 int a_mode; 177 struct ucred *a_cred; 178 struct thread *a_td; 179 } */ *ap; 180{ 181 struct vnode *vp = ap->a_vp; 182 struct devfs_dirent *de; 183 int error; 184 185 de = vp->v_data; 186 if (vp->v_type == VDIR) 187 de = de->de_dir; 188 189 error = vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid, 190 ap->a_mode, ap->a_cred, NULL); 191 if (!error) 192 return (error); 193 if (error != EACCES) 194 return (error); 195 /* We do, however, allow access to the controlling terminal */ 196 if (!(ap->a_td->td_proc->p_flag & P_CONTROLT)) 197 return (error); 198 if (ap->a_td->td_proc->p_session->s_ttyvp == de->de_vnode) 199 return (0); 200 return (error); 201} 202 203static int 204devfs_getattr(ap) 205 struct vop_getattr_args /* { 206 struct vnode *a_vp; 207 struct vattr *a_vap; 208 struct ucred *a_cred; 209 struct thread *a_td; 210 } */ *ap; 211{ 212 struct vnode *vp = ap->a_vp; 213 struct vattr *vap = ap->a_vap; 214 int error = 0; 215 struct devfs_dirent *de; 216 dev_t dev; 217 218 de = vp->v_data; 219 if (vp->v_type == VDIR) 220 de = de->de_dir; 221 bzero((caddr_t) vap, sizeof(*vap)); 222 vattr_null(vap); 223 vap->va_uid = de->de_uid; 224 vap->va_gid = de->de_gid; 225 vap->va_mode = de->de_mode; 226 if (vp->v_type == VLNK) 227 vap->va_size = de->de_dirent->d_namlen; 228 else if (vp->v_type == VDIR) 229 vap->va_size = vap->va_bytes = DEV_BSIZE; 230 else 231 vap->va_size = 0; 232 if (vp->v_type != VDIR) 233 vap->va_bytes = 0; 234 vap->va_blocksize = DEV_BSIZE; 235 vap->va_type = vp->v_type; 236 237#define fix(aa) \ 238 do { \ 239 if ((aa).tv_sec == 0) { \ 240 (aa).tv_sec = boottime.tv_sec; \ 241 (aa).tv_nsec = boottime.tv_usec * 1000; \ 242 } \ 243 } while (0) 244 245 if (vp->v_type != VCHR) { 246 fix(de->de_atime); 247 vap->va_atime = de->de_atime; 248 fix(de->de_mtime); 249 vap->va_mtime = de->de_mtime; 250 fix(de->de_ctime); 251 vap->va_ctime = de->de_ctime; 252 } else { 253 dev = vp->v_rdev; 254 fix(dev->si_atime); 255 vap->va_atime = dev->si_atime; 256 fix(dev->si_mtime); 257 vap->va_mtime = dev->si_mtime; 258 fix(dev->si_ctime); 259 vap->va_ctime = dev->si_ctime; 260 vap->va_rdev = dev->si_udev; 261 } 262 vap->va_gen = 0; 263 vap->va_flags = 0; 264 vap->va_nlink = de->de_links; 265 vap->va_fileid = de->de_inode; 266 267 return (error); 268} 269 270static int 271devfs_ioctl(ap) 272 struct vop_ioctl_args /* { 273 struct vnode *a_vp; 274 u_long a_command; 275 caddr_t a_data; 276 int a_fflag; 277 struct ucred *a_cred; 278 struct thread *a_td; 279 } */ *ap; 280{ 281 int error; 282 283 error = devfs_rules_ioctl(ap->a_vp->v_mount, ap->a_command, ap->a_data, 284 ap->a_td); 285 return (error); 286} 287 288static int 289devfs_lookupx(ap) 290 struct vop_lookup_args /* { 291 struct vnode * a_dvp; 292 struct vnode ** a_vpp; 293 struct componentname * a_cnp; 294 } */ *ap; 295{ 296 struct componentname *cnp; 297 struct vnode *dvp, **vpp; 298 struct thread *td; 299 struct devfs_dirent *de, *dd; 300 struct devfs_mount *dmp; 301 dev_t cdev, *cpdev; 302 int error, cloned, flags, nameiop; 303 char specname[SPECNAMELEN + 1], *pname; 304 305 cnp = ap->a_cnp; 306 vpp = ap->a_vpp; 307 dvp = ap->a_dvp; 308 pname = cnp->cn_nameptr; 309 td = cnp->cn_thread; 310 flags = cnp->cn_flags; 311 nameiop = cnp->cn_nameiop; 312 dmp = VFSTODEVFS(dvp->v_mount); 313 cloned = 0; 314 dd = dvp->v_data; 315 316 *vpp = NULLVP; 317 cnp->cn_flags &= ~PDIRUNLOCK; 318 319 if ((flags & ISLASTCN) && nameiop == RENAME) 320 return (EOPNOTSUPP); 321 322 if (dvp->v_type != VDIR) 323 return (ENOTDIR); 324 325 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) 326 return (EIO); 327 328 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td); 329 if (error) 330 return (error); 331 332 if (cnp->cn_namelen == 1 && *pname == '.') { 333 if ((flags & ISLASTCN) && nameiop != LOOKUP) 334 return (EINVAL); 335 *vpp = dvp; 336 VREF(dvp); 337 return (0); 338 } 339 340 if (flags & ISDOTDOT) { 341 if ((flags & ISLASTCN) && nameiop != LOOKUP) 342 return (EINVAL); 343 VOP_UNLOCK(dvp, 0, td); 344 cnp->cn_flags |= PDIRUNLOCK; 345 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 346 de = TAILQ_NEXT(de, de_list); /* ".." */ 347 de = de->de_dir; 348 error = devfs_allocv(de, dvp->v_mount, vpp, td); 349 if (error || ((flags & LOCKPARENT) && (flags & ISLASTCN))) { 350 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 351 cnp->cn_flags &= ~PDIRUNLOCK; 352 } 353 return (error); 354 } 355 356 devfs_populate(dmp); 357 dd = dvp->v_data; 358 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 359 if (cnp->cn_namelen != de->de_dirent->d_namlen) 360 continue; 361 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 362 de->de_dirent->d_namlen) != 0) 363 continue; 364 if (de->de_flags & DE_WHITEOUT) 365 goto notfound; 366 goto found; 367 } 368 369 if (nameiop == DELETE) 370 goto notfound; 371 372 /* 373 * OK, we didn't have an entry for the name we were asked for 374 * so we try to see if anybody can create it on demand. 375 */ 376 pname = devfs_fqpn(specname, dvp, cnp); 377 if (pname == NULL) 378 goto notfound; 379 380 cdev = NODEV; 381 EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev); 382 if (cdev == NODEV) 383 goto notfound; 384 385 devfs_populate(dmp); 386 dd = dvp->v_data; 387 388 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 389 cpdev = devfs_itod(de->de_inode); 390 if (cpdev != NULL && cdev == *cpdev) 391 goto found; 392 continue; 393 } 394 395notfound: 396 397 if ((nameiop == CREATE || nameiop == RENAME) && 398 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 399 cnp->cn_flags |= SAVENAME; 400 if (!(flags & LOCKPARENT)) { 401 VOP_UNLOCK(dvp, 0, td); 402 cnp->cn_flags |= PDIRUNLOCK; 403 } 404 return (EJUSTRETURN); 405 } 406 return (ENOENT); 407 408 409found: 410 411 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 412 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 413 if (error) 414 return (error); 415 if (*vpp == dvp) { 416 VREF(dvp); 417 *vpp = dvp; 418 return (0); 419 } 420 error = devfs_allocv(de, dvp->v_mount, vpp, td); 421 if (error) 422 return (error); 423 if (!(flags & LOCKPARENT)) { 424 VOP_UNLOCK(dvp, 0, td); 425 cnp->cn_flags |= PDIRUNLOCK; 426 } 427 return (0); 428 } 429 error = devfs_allocv(de, dvp->v_mount, vpp, td); 430 if (error) 431 return (error); 432 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) { 433 VOP_UNLOCK(dvp, 0, td); 434 cnp->cn_flags |= PDIRUNLOCK; 435 } 436 return (0); 437} 438 439static int 440devfs_lookup(struct vop_lookup_args *ap) 441{ 442 int j; 443 struct devfs_mount *dmp; 444 445 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 446 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 447 j = devfs_lookupx(ap); 448 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 449 return (j); 450} 451 452static int 453devfs_mknod(struct vop_mknod_args *ap) 454/* 455struct vop_mknod_args { 456 struct vnodeop_desc *a_desc; 457 struct vnode *a_dvp; 458 struct vnode **a_vpp; 459 struct componentname *a_cnp; 460 struct vattr *a_vap; 461}; 462*/ 463{ 464 struct componentname *cnp; 465 struct vnode *dvp, **vpp; 466 struct thread *td; 467 struct devfs_dirent *dd, *de; 468 struct devfs_mount *dmp; 469 int cloned, flags, nameiop; 470 int error; 471 472 dvp = ap->a_dvp; 473 dmp = VFSTODEVFS(dvp->v_mount); 474 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 475 476 cnp = ap->a_cnp; 477 vpp = ap->a_vpp; 478 td = cnp->cn_thread; 479 flags = cnp->cn_flags; 480 nameiop = cnp->cn_nameiop; 481 cloned = 0; 482 dd = dvp->v_data; 483 484 error = ENOENT; 485 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 486 if (cnp->cn_namelen != de->de_dirent->d_namlen) 487 continue; 488 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 489 de->de_dirent->d_namlen) != 0) 490 continue; 491 if (de->de_flags & DE_WHITEOUT) 492 break; 493 goto notfound; 494 } 495 if (de == NULL) 496 goto notfound; 497 de->de_flags &= ~DE_WHITEOUT; 498 error = devfs_allocv(de, dvp->v_mount, vpp, td); 499notfound: 500 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 501 return (error); 502} 503 504 505static int 506devfs_pathconf(ap) 507 struct vop_pathconf_args /* { 508 struct vnode *a_vp; 509 int a_name; 510 int *a_retval; 511 } */ *ap; 512{ 513 514 switch (ap->a_name) { 515 case _PC_NAME_MAX: 516 *ap->a_retval = NAME_MAX; 517 return (0); 518 case _PC_PATH_MAX: 519 *ap->a_retval = PATH_MAX; 520 return (0); 521 case _PC_MAC_PRESENT: 522#ifdef MAC 523 /* 524 * If MAC is enabled, devfs automatically supports 525 * trivial non-persistant label storage. 526 */ 527 *ap->a_retval = 1; 528#else 529 *ap->a_retval = 0; 530#endif 531 return (0); 532 default: 533 return (vop_stdpathconf(ap)); 534 } 535 /* NOTREACHED */ 536} 537 538static int 539devfs_read(ap) 540 struct vop_read_args /* { 541 struct vnode *a_vp; 542 struct uio *a_uio; 543 int a_ioflag; 544 struct ucred *a_cred; 545 } */ *ap; 546{ 547 548 if (ap->a_vp->v_type != VDIR) 549 return (EINVAL); 550 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 551} 552 553static int 554devfs_readdir(ap) 555 struct vop_readdir_args /* { 556 struct vnode *a_vp; 557 struct uio *a_uio; 558 struct ucred *a_cred; 559 int *a_eofflag; 560 int *a_ncookies; 561 u_long **a_cookies; 562 } */ *ap; 563{ 564 int error; 565 struct uio *uio; 566 struct dirent *dp; 567 struct devfs_dirent *dd; 568 struct devfs_dirent *de; 569 struct devfs_mount *dmp; 570 off_t off, oldoff; 571 int ncookies = 0; 572 u_long *cookiebuf, *cookiep; 573 struct dirent *dps, *dpe; 574 575 if (ap->a_vp->v_type != VDIR) 576 return (ENOTDIR); 577 578 uio = ap->a_uio; 579 if (uio->uio_offset < 0) 580 return (EINVAL); 581 582 dmp = VFSTODEVFS(ap->a_vp->v_mount); 583 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 584 devfs_populate(dmp); 585 error = 0; 586 de = ap->a_vp->v_data; 587 off = 0; 588 oldoff = uio->uio_offset; 589 TAILQ_FOREACH(dd, &de->de_dlist, de_list) { 590 if (dd->de_flags & DE_WHITEOUT) 591 continue; 592 if (dd->de_dirent->d_type == DT_DIR) 593 de = dd->de_dir; 594 else 595 de = dd; 596 dp = dd->de_dirent; 597 if (dp->d_reclen > uio->uio_resid) 598 break; 599 dp->d_fileno = de->de_inode; 600 if (off >= uio->uio_offset) { 601 ncookies++;
| 35 */ 36 37/* 38 * TODO: 39 * remove empty directories 40 * mknod: hunt down DE_DELETED, compare name, reinstantiate. 41 * mkdir: want it ? 42 */ 43 44#include <opt_devfs.h> 45#include <opt_mac.h> 46 47#include <sys/param.h> 48#include <sys/systm.h> 49#include <sys/conf.h> 50#include <sys/dirent.h> 51#include <sys/kernel.h> 52#include <sys/lock.h> 53#include <sys/mac.h> 54#include <sys/malloc.h> 55#include <sys/mount.h> 56#include <sys/namei.h> 57#include <sys/proc.h> 58#include <sys/time.h> 59#include <sys/unistd.h> 60#include <sys/vnode.h> 61 62#include <fs/devfs/devfs.h> 63 64static int devfs_access(struct vop_access_args *ap); 65static int devfs_getattr(struct vop_getattr_args *ap); 66static int devfs_ioctl(struct vop_ioctl_args *ap); 67static int devfs_lookupx(struct vop_lookup_args *ap); 68static int devfs_mknod(struct vop_mknod_args *ap); 69static int devfs_pathconf(struct vop_pathconf_args *ap); 70static int devfs_read(struct vop_read_args *ap); 71static int devfs_readdir(struct vop_readdir_args *ap); 72static int devfs_readlink(struct vop_readlink_args *ap); 73static int devfs_reclaim(struct vop_reclaim_args *ap); 74static int devfs_remove(struct vop_remove_args *ap); 75static int devfs_revoke(struct vop_revoke_args *ap); 76static int devfs_setattr(struct vop_setattr_args *ap); 77#ifdef MAC 78static int devfs_setlabel(struct vop_setlabel_args *ap); 79#endif 80static int devfs_symlink(struct vop_symlink_args *ap); 81 82static vop_t **devfs_vnodeop_p; 83static vop_t **devfs_specop_p; 84 85/* 86 * Construct the fully qualified path name relative to the mountpoint 87 */ 88static char * 89devfs_fqpn(char *buf, struct vnode *dvp, struct componentname *cnp) 90{ 91 int i; 92 struct devfs_dirent *de, *dd; 93 struct devfs_mount *dmp; 94 95 dmp = VFSTODEVFS(dvp->v_mount); 96 dd = dvp->v_data; 97 i = SPECNAMELEN; 98 buf[i] = '\0'; 99 i -= cnp->cn_namelen; 100 if (i < 0) 101 return (NULL); 102 bcopy(cnp->cn_nameptr, buf + i, cnp->cn_namelen); 103 de = dd; 104 while (de != dmp->dm_basedir) { 105 i--; 106 if (i < 0) 107 return (NULL); 108 buf[i] = '/'; 109 i -= de->de_dirent->d_namlen; 110 if (i < 0) 111 return (NULL); 112 bcopy(de->de_dirent->d_name, buf + i, 113 de->de_dirent->d_namlen); 114 de = TAILQ_FIRST(&de->de_dlist); /* "." */ 115 de = TAILQ_NEXT(de, de_list); /* ".." */ 116 de = de->de_dir; 117 } 118 return (buf + i); 119} 120 121int 122devfs_allocv(struct devfs_dirent *de, struct mount *mp, struct vnode **vpp, struct thread *td) 123{ 124 int error; 125 struct vnode *vp; 126 dev_t dev; 127 128 if (td == NULL) 129 td = curthread; /* XXX */ 130loop: 131 vp = de->de_vnode; 132 if (vp != NULL) { 133 if (vget(vp, LK_EXCLUSIVE, td ? td : curthread)) 134 goto loop; 135 *vpp = vp; 136 return (0); 137 } 138 if (de->de_dirent->d_type == DT_CHR) { 139 dev = *devfs_itod(de->de_inode); 140 if (dev == NULL) 141 return (ENOENT); 142 } else { 143 dev = NODEV; 144 } 145 error = getnewvnode("devfs", mp, devfs_vnodeop_p, &vp); 146 if (error != 0) { 147 printf("devfs_allocv: failed to allocate new vnode\n"); 148 return (error); 149 } 150 151 if (de->de_dirent->d_type == DT_CHR) { 152 vp->v_type = VCHR; 153 vp = addaliasu(vp, dev->si_udev); 154 vp->v_op = devfs_specop_p; 155 } else if (de->de_dirent->d_type == DT_DIR) { 156 vp->v_type = VDIR; 157 } else if (de->de_dirent->d_type == DT_LNK) { 158 vp->v_type = VLNK; 159 } else { 160 vp->v_type = VBAD; 161 } 162 vp->v_data = de; 163 de->de_vnode = vp; 164 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 165#ifdef MAC 166 mac_associate_vnode_devfs(mp, de, vp); 167#endif 168 *vpp = vp; 169 return (0); 170} 171 172static int 173devfs_access(ap) 174 struct vop_access_args /* { 175 struct vnode *a_vp; 176 int a_mode; 177 struct ucred *a_cred; 178 struct thread *a_td; 179 } */ *ap; 180{ 181 struct vnode *vp = ap->a_vp; 182 struct devfs_dirent *de; 183 int error; 184 185 de = vp->v_data; 186 if (vp->v_type == VDIR) 187 de = de->de_dir; 188 189 error = vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid, 190 ap->a_mode, ap->a_cred, NULL); 191 if (!error) 192 return (error); 193 if (error != EACCES) 194 return (error); 195 /* We do, however, allow access to the controlling terminal */ 196 if (!(ap->a_td->td_proc->p_flag & P_CONTROLT)) 197 return (error); 198 if (ap->a_td->td_proc->p_session->s_ttyvp == de->de_vnode) 199 return (0); 200 return (error); 201} 202 203static int 204devfs_getattr(ap) 205 struct vop_getattr_args /* { 206 struct vnode *a_vp; 207 struct vattr *a_vap; 208 struct ucred *a_cred; 209 struct thread *a_td; 210 } */ *ap; 211{ 212 struct vnode *vp = ap->a_vp; 213 struct vattr *vap = ap->a_vap; 214 int error = 0; 215 struct devfs_dirent *de; 216 dev_t dev; 217 218 de = vp->v_data; 219 if (vp->v_type == VDIR) 220 de = de->de_dir; 221 bzero((caddr_t) vap, sizeof(*vap)); 222 vattr_null(vap); 223 vap->va_uid = de->de_uid; 224 vap->va_gid = de->de_gid; 225 vap->va_mode = de->de_mode; 226 if (vp->v_type == VLNK) 227 vap->va_size = de->de_dirent->d_namlen; 228 else if (vp->v_type == VDIR) 229 vap->va_size = vap->va_bytes = DEV_BSIZE; 230 else 231 vap->va_size = 0; 232 if (vp->v_type != VDIR) 233 vap->va_bytes = 0; 234 vap->va_blocksize = DEV_BSIZE; 235 vap->va_type = vp->v_type; 236 237#define fix(aa) \ 238 do { \ 239 if ((aa).tv_sec == 0) { \ 240 (aa).tv_sec = boottime.tv_sec; \ 241 (aa).tv_nsec = boottime.tv_usec * 1000; \ 242 } \ 243 } while (0) 244 245 if (vp->v_type != VCHR) { 246 fix(de->de_atime); 247 vap->va_atime = de->de_atime; 248 fix(de->de_mtime); 249 vap->va_mtime = de->de_mtime; 250 fix(de->de_ctime); 251 vap->va_ctime = de->de_ctime; 252 } else { 253 dev = vp->v_rdev; 254 fix(dev->si_atime); 255 vap->va_atime = dev->si_atime; 256 fix(dev->si_mtime); 257 vap->va_mtime = dev->si_mtime; 258 fix(dev->si_ctime); 259 vap->va_ctime = dev->si_ctime; 260 vap->va_rdev = dev->si_udev; 261 } 262 vap->va_gen = 0; 263 vap->va_flags = 0; 264 vap->va_nlink = de->de_links; 265 vap->va_fileid = de->de_inode; 266 267 return (error); 268} 269 270static int 271devfs_ioctl(ap) 272 struct vop_ioctl_args /* { 273 struct vnode *a_vp; 274 u_long a_command; 275 caddr_t a_data; 276 int a_fflag; 277 struct ucred *a_cred; 278 struct thread *a_td; 279 } */ *ap; 280{ 281 int error; 282 283 error = devfs_rules_ioctl(ap->a_vp->v_mount, ap->a_command, ap->a_data, 284 ap->a_td); 285 return (error); 286} 287 288static int 289devfs_lookupx(ap) 290 struct vop_lookup_args /* { 291 struct vnode * a_dvp; 292 struct vnode ** a_vpp; 293 struct componentname * a_cnp; 294 } */ *ap; 295{ 296 struct componentname *cnp; 297 struct vnode *dvp, **vpp; 298 struct thread *td; 299 struct devfs_dirent *de, *dd; 300 struct devfs_mount *dmp; 301 dev_t cdev, *cpdev; 302 int error, cloned, flags, nameiop; 303 char specname[SPECNAMELEN + 1], *pname; 304 305 cnp = ap->a_cnp; 306 vpp = ap->a_vpp; 307 dvp = ap->a_dvp; 308 pname = cnp->cn_nameptr; 309 td = cnp->cn_thread; 310 flags = cnp->cn_flags; 311 nameiop = cnp->cn_nameiop; 312 dmp = VFSTODEVFS(dvp->v_mount); 313 cloned = 0; 314 dd = dvp->v_data; 315 316 *vpp = NULLVP; 317 cnp->cn_flags &= ~PDIRUNLOCK; 318 319 if ((flags & ISLASTCN) && nameiop == RENAME) 320 return (EOPNOTSUPP); 321 322 if (dvp->v_type != VDIR) 323 return (ENOTDIR); 324 325 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) 326 return (EIO); 327 328 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td); 329 if (error) 330 return (error); 331 332 if (cnp->cn_namelen == 1 && *pname == '.') { 333 if ((flags & ISLASTCN) && nameiop != LOOKUP) 334 return (EINVAL); 335 *vpp = dvp; 336 VREF(dvp); 337 return (0); 338 } 339 340 if (flags & ISDOTDOT) { 341 if ((flags & ISLASTCN) && nameiop != LOOKUP) 342 return (EINVAL); 343 VOP_UNLOCK(dvp, 0, td); 344 cnp->cn_flags |= PDIRUNLOCK; 345 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 346 de = TAILQ_NEXT(de, de_list); /* ".." */ 347 de = de->de_dir; 348 error = devfs_allocv(de, dvp->v_mount, vpp, td); 349 if (error || ((flags & LOCKPARENT) && (flags & ISLASTCN))) { 350 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 351 cnp->cn_flags &= ~PDIRUNLOCK; 352 } 353 return (error); 354 } 355 356 devfs_populate(dmp); 357 dd = dvp->v_data; 358 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 359 if (cnp->cn_namelen != de->de_dirent->d_namlen) 360 continue; 361 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 362 de->de_dirent->d_namlen) != 0) 363 continue; 364 if (de->de_flags & DE_WHITEOUT) 365 goto notfound; 366 goto found; 367 } 368 369 if (nameiop == DELETE) 370 goto notfound; 371 372 /* 373 * OK, we didn't have an entry for the name we were asked for 374 * so we try to see if anybody can create it on demand. 375 */ 376 pname = devfs_fqpn(specname, dvp, cnp); 377 if (pname == NULL) 378 goto notfound; 379 380 cdev = NODEV; 381 EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev); 382 if (cdev == NODEV) 383 goto notfound; 384 385 devfs_populate(dmp); 386 dd = dvp->v_data; 387 388 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 389 cpdev = devfs_itod(de->de_inode); 390 if (cpdev != NULL && cdev == *cpdev) 391 goto found; 392 continue; 393 } 394 395notfound: 396 397 if ((nameiop == CREATE || nameiop == RENAME) && 398 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 399 cnp->cn_flags |= SAVENAME; 400 if (!(flags & LOCKPARENT)) { 401 VOP_UNLOCK(dvp, 0, td); 402 cnp->cn_flags |= PDIRUNLOCK; 403 } 404 return (EJUSTRETURN); 405 } 406 return (ENOENT); 407 408 409found: 410 411 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 412 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 413 if (error) 414 return (error); 415 if (*vpp == dvp) { 416 VREF(dvp); 417 *vpp = dvp; 418 return (0); 419 } 420 error = devfs_allocv(de, dvp->v_mount, vpp, td); 421 if (error) 422 return (error); 423 if (!(flags & LOCKPARENT)) { 424 VOP_UNLOCK(dvp, 0, td); 425 cnp->cn_flags |= PDIRUNLOCK; 426 } 427 return (0); 428 } 429 error = devfs_allocv(de, dvp->v_mount, vpp, td); 430 if (error) 431 return (error); 432 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) { 433 VOP_UNLOCK(dvp, 0, td); 434 cnp->cn_flags |= PDIRUNLOCK; 435 } 436 return (0); 437} 438 439static int 440devfs_lookup(struct vop_lookup_args *ap) 441{ 442 int j; 443 struct devfs_mount *dmp; 444 445 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 446 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 447 j = devfs_lookupx(ap); 448 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 449 return (j); 450} 451 452static int 453devfs_mknod(struct vop_mknod_args *ap) 454/* 455struct vop_mknod_args { 456 struct vnodeop_desc *a_desc; 457 struct vnode *a_dvp; 458 struct vnode **a_vpp; 459 struct componentname *a_cnp; 460 struct vattr *a_vap; 461}; 462*/ 463{ 464 struct componentname *cnp; 465 struct vnode *dvp, **vpp; 466 struct thread *td; 467 struct devfs_dirent *dd, *de; 468 struct devfs_mount *dmp; 469 int cloned, flags, nameiop; 470 int error; 471 472 dvp = ap->a_dvp; 473 dmp = VFSTODEVFS(dvp->v_mount); 474 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 475 476 cnp = ap->a_cnp; 477 vpp = ap->a_vpp; 478 td = cnp->cn_thread; 479 flags = cnp->cn_flags; 480 nameiop = cnp->cn_nameiop; 481 cloned = 0; 482 dd = dvp->v_data; 483 484 error = ENOENT; 485 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 486 if (cnp->cn_namelen != de->de_dirent->d_namlen) 487 continue; 488 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 489 de->de_dirent->d_namlen) != 0) 490 continue; 491 if (de->de_flags & DE_WHITEOUT) 492 break; 493 goto notfound; 494 } 495 if (de == NULL) 496 goto notfound; 497 de->de_flags &= ~DE_WHITEOUT; 498 error = devfs_allocv(de, dvp->v_mount, vpp, td); 499notfound: 500 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 501 return (error); 502} 503 504 505static int 506devfs_pathconf(ap) 507 struct vop_pathconf_args /* { 508 struct vnode *a_vp; 509 int a_name; 510 int *a_retval; 511 } */ *ap; 512{ 513 514 switch (ap->a_name) { 515 case _PC_NAME_MAX: 516 *ap->a_retval = NAME_MAX; 517 return (0); 518 case _PC_PATH_MAX: 519 *ap->a_retval = PATH_MAX; 520 return (0); 521 case _PC_MAC_PRESENT: 522#ifdef MAC 523 /* 524 * If MAC is enabled, devfs automatically supports 525 * trivial non-persistant label storage. 526 */ 527 *ap->a_retval = 1; 528#else 529 *ap->a_retval = 0; 530#endif 531 return (0); 532 default: 533 return (vop_stdpathconf(ap)); 534 } 535 /* NOTREACHED */ 536} 537 538static int 539devfs_read(ap) 540 struct vop_read_args /* { 541 struct vnode *a_vp; 542 struct uio *a_uio; 543 int a_ioflag; 544 struct ucred *a_cred; 545 } */ *ap; 546{ 547 548 if (ap->a_vp->v_type != VDIR) 549 return (EINVAL); 550 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 551} 552 553static int 554devfs_readdir(ap) 555 struct vop_readdir_args /* { 556 struct vnode *a_vp; 557 struct uio *a_uio; 558 struct ucred *a_cred; 559 int *a_eofflag; 560 int *a_ncookies; 561 u_long **a_cookies; 562 } */ *ap; 563{ 564 int error; 565 struct uio *uio; 566 struct dirent *dp; 567 struct devfs_dirent *dd; 568 struct devfs_dirent *de; 569 struct devfs_mount *dmp; 570 off_t off, oldoff; 571 int ncookies = 0; 572 u_long *cookiebuf, *cookiep; 573 struct dirent *dps, *dpe; 574 575 if (ap->a_vp->v_type != VDIR) 576 return (ENOTDIR); 577 578 uio = ap->a_uio; 579 if (uio->uio_offset < 0) 580 return (EINVAL); 581 582 dmp = VFSTODEVFS(ap->a_vp->v_mount); 583 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 584 devfs_populate(dmp); 585 error = 0; 586 de = ap->a_vp->v_data; 587 off = 0; 588 oldoff = uio->uio_offset; 589 TAILQ_FOREACH(dd, &de->de_dlist, de_list) { 590 if (dd->de_flags & DE_WHITEOUT) 591 continue; 592 if (dd->de_dirent->d_type == DT_DIR) 593 de = dd->de_dir; 594 else 595 de = dd; 596 dp = dd->de_dirent; 597 if (dp->d_reclen > uio->uio_resid) 598 break; 599 dp->d_fileno = de->de_inode; 600 if (off >= uio->uio_offset) { 601 ncookies++;
|
602 error = uiomove((caddr_t)dp, dp->d_reclen, uio);
| 602 error = uiomove(dp, dp->d_reclen, uio);
|
603 if (error) 604 break; 605 } 606 off += dp->d_reclen; 607 } 608 if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) { 609 MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long), 610 M_TEMP, M_WAITOK); 611 cookiep = cookiebuf; 612 dps = (struct dirent *)((char *)uio->uio_iov->iov_base - 613 (uio->uio_offset - oldoff)); 614 dpe = (struct dirent *) uio->uio_iov->iov_base; 615 for( dp = dps; 616 dp < dpe; 617 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { 618 oldoff += dp->d_reclen; 619 *cookiep++ = (u_long) oldoff; 620 } 621 *ap->a_ncookies = ncookies; 622 *ap->a_cookies = cookiebuf; 623 } 624 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 625 uio->uio_offset = off; 626 return (error); 627} 628 629static int 630devfs_readlink(ap) 631 struct vop_readlink_args /* { 632 struct vnode *a_vp; 633 struct uio *a_uio; 634 struct ucred *a_cead; 635 } */ *ap; 636{ 637 int error; 638 struct devfs_dirent *de; 639 640 de = ap->a_vp->v_data; 641 error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio); 642 return (error); 643} 644 645static int 646devfs_reclaim(ap) 647 struct vop_reclaim_args /* { 648 struct vnode *a_vp; 649 } */ *ap; 650{ 651 struct vnode *vp = ap->a_vp; 652 struct devfs_dirent *de; 653 int i; 654 655 de = vp->v_data; 656 if (de != NULL) 657 de->de_vnode = NULL; 658 vp->v_data = NULL; 659 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) { 660 i = vcount(vp); 661 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 && 662 (vp->v_rdev->si_flags & SI_NAMED)) 663 destroy_dev(vp->v_rdev); 664 } 665 return (0); 666} 667 668static int 669devfs_remove(ap) 670 struct vop_remove_args /* { 671 struct vnode *a_dvp; 672 struct vnode *a_vp; 673 struct componentname *a_cnp; 674 } */ *ap; 675{ 676 struct vnode *vp = ap->a_vp; 677 struct devfs_dirent *dd; 678 struct devfs_dirent *de; 679 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 680 681 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 682 dd = ap->a_dvp->v_data; 683 de = vp->v_data; 684 if (de->de_dirent->d_type == DT_LNK) { 685 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 686 if (de->de_vnode) 687 de->de_vnode->v_data = NULL; 688#ifdef MAC 689 mac_destroy_devfsdirent(de); 690#endif 691 FREE(de, M_DEVFS); 692 } else { 693 de->de_flags |= DE_WHITEOUT; 694 } 695 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 696 return (0); 697} 698 699/* 700 * Revoke is called on a tty when a terminal session ends. The vnode 701 * is orphaned by setting v_op to deadfs so we need to let go of it 702 * as well so that we create a new one next time around. 703 */ 704static int 705devfs_revoke(ap) 706 struct vop_revoke_args /* { 707 struct vnode *a_vp; 708 int a_flags; 709 } */ *ap; 710{ 711 struct vnode *vp = ap->a_vp; 712 struct devfs_dirent *de; 713 714 de = vp->v_data; 715 de->de_vnode = NULL; 716 vop_revoke(ap); 717 return (0); 718} 719 720static int 721devfs_setattr(ap) 722 struct vop_setattr_args /* { 723 struct vnode *a_vp; 724 struct vattr *a_vap; 725 struct ucred *a_cred; 726 struct proc *a_p; 727 } */ *ap; 728{ 729 struct devfs_dirent *de; 730 struct vattr *vap; 731 struct vnode *vp; 732 int c, error; 733 uid_t uid; 734 gid_t gid; 735 736 vap = ap->a_vap; 737 vp = ap->a_vp; 738 if ((vap->va_type != VNON) || 739 (vap->va_nlink != VNOVAL) || 740 (vap->va_fsid != VNOVAL) || 741 (vap->va_fileid != VNOVAL) || 742 (vap->va_blocksize != VNOVAL) || 743 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 744 (vap->va_rdev != VNOVAL) || 745 ((int)vap->va_bytes != VNOVAL) || 746 (vap->va_gen != VNOVAL)) { 747 return (EINVAL); 748 } 749 750 de = vp->v_data; 751 if (vp->v_type == VDIR) 752 de = de->de_dir; 753 754 error = c = 0; 755 if (vap->va_uid == (uid_t)VNOVAL) 756 uid = de->de_uid; 757 else 758 uid = vap->va_uid; 759 if (vap->va_gid == (gid_t)VNOVAL) 760 gid = de->de_gid; 761 else 762 gid = vap->va_gid; 763 if (uid != de->de_uid || gid != de->de_gid) { 764 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 765 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 766 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)) != 0) 767 return (error); 768 de->de_uid = uid; 769 de->de_gid = gid; 770 c = 1; 771 } 772 773 if (vap->va_mode != (mode_t)VNOVAL) { 774 if ((ap->a_cred->cr_uid != de->de_uid) && 775 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT))) 776 return (error); 777 de->de_mode = vap->va_mode; 778 c = 1; 779 } 780 781 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 782 /* See the comment in ufs_vnops::ufs_setattr(). */ 783 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) && 784 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 785 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 786 return (error); 787 if (vap->va_atime.tv_sec != VNOVAL) { 788 if (vp->v_type == VCHR) 789 vp->v_rdev->si_atime = vap->va_atime; 790 else 791 de->de_atime = vap->va_atime; 792 } 793 if (vap->va_mtime.tv_sec != VNOVAL) { 794 if (vp->v_type == VCHR) 795 vp->v_rdev->si_mtime = vap->va_mtime; 796 else 797 de->de_mtime = vap->va_mtime; 798 } 799 c = 1; 800 } 801 802 if (c) { 803 if (vp->v_type == VCHR) 804 vfs_timestamp(&vp->v_rdev->si_ctime); 805 else 806 vfs_timestamp(&de->de_mtime); 807 } 808 return (0); 809} 810 811#ifdef MAC 812static int 813devfs_setlabel(ap) 814 struct vop_setlabel_args /* { 815 struct vnode *a_vp; 816 struct mac *a_label; 817 struct ucred *a_cred; 818 struct thread *a_td; 819 } */ *ap; 820{ 821 struct vnode *vp; 822 struct devfs_dirent *de; 823 824 vp = ap->a_vp; 825 de = vp->v_data; 826 827 mac_relabel_vnode(ap->a_cred, vp, ap->a_label); 828 mac_update_devfsdirent(vp->v_mount, de, vp); 829 830 return (0); 831} 832#endif 833 834static int 835devfs_symlink(ap) 836 struct vop_symlink_args /* { 837 struct vnode *a_dvp; 838 struct vnode **a_vpp; 839 struct componentname *a_cnp; 840 struct vattr *a_vap; 841 char *a_target; 842 } */ *ap; 843{ 844 int i, error; 845 struct devfs_dirent *dd; 846 struct devfs_dirent *de; 847 struct devfs_mount *dmp; 848 849 error = suser(ap->a_cnp->cn_thread); 850 if (error) 851 return(error); 852 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 853 dd = ap->a_dvp->v_data; 854 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 855 de->de_uid = 0; 856 de->de_gid = 0; 857 de->de_mode = 0755; 858 de->de_inode = dmp->dm_inode++; 859 de->de_dirent->d_type = DT_LNK; 860 i = strlen(ap->a_target) + 1; 861 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 862 bcopy(ap->a_target, de->de_symlink, i); 863 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 864#ifdef MAC 865 mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de); 866#endif 867 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 868 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 869 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 870 return (0); 871} 872 873static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 874 { &vop_default_desc, (vop_t *) vop_defaultop }, 875 { &vop_access_desc, (vop_t *) devfs_access }, 876 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 877 { &vop_ioctl_desc, (vop_t *) devfs_ioctl }, 878 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 879 { &vop_mknod_desc, (vop_t *) devfs_mknod }, 880 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 881 { &vop_print_desc, (vop_t *) vop_null }, 882 { &vop_read_desc, (vop_t *) devfs_read }, 883 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 884 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 885 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 886 { &vop_remove_desc, (vop_t *) devfs_remove }, 887 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 888 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 889#ifdef MAC 890 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 891#endif 892 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 893 { NULL, NULL } 894}; 895static struct vnodeopv_desc devfs_vnodeop_opv_desc = 896 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 897 898VNODEOP_SET(devfs_vnodeop_opv_desc); 899 900static struct vnodeopv_entry_desc devfs_specop_entries[] = { 901 { &vop_default_desc, (vop_t *) spec_vnoperate }, 902 { &vop_access_desc, (vop_t *) devfs_access }, 903 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 904 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 905 { &vop_print_desc, (vop_t *) vop_null }, 906 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 907 { &vop_remove_desc, (vop_t *) devfs_remove }, 908 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 909 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 910#ifdef MAC 911 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 912#endif 913 { NULL, NULL } 914}; 915static struct vnodeopv_desc devfs_specop_opv_desc = 916 { &devfs_specop_p, devfs_specop_entries }; 917 918VNODEOP_SET(devfs_specop_opv_desc);
| 603 if (error) 604 break; 605 } 606 off += dp->d_reclen; 607 } 608 if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) { 609 MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long), 610 M_TEMP, M_WAITOK); 611 cookiep = cookiebuf; 612 dps = (struct dirent *)((char *)uio->uio_iov->iov_base - 613 (uio->uio_offset - oldoff)); 614 dpe = (struct dirent *) uio->uio_iov->iov_base; 615 for( dp = dps; 616 dp < dpe; 617 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { 618 oldoff += dp->d_reclen; 619 *cookiep++ = (u_long) oldoff; 620 } 621 *ap->a_ncookies = ncookies; 622 *ap->a_cookies = cookiebuf; 623 } 624 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 625 uio->uio_offset = off; 626 return (error); 627} 628 629static int 630devfs_readlink(ap) 631 struct vop_readlink_args /* { 632 struct vnode *a_vp; 633 struct uio *a_uio; 634 struct ucred *a_cead; 635 } */ *ap; 636{ 637 int error; 638 struct devfs_dirent *de; 639 640 de = ap->a_vp->v_data; 641 error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio); 642 return (error); 643} 644 645static int 646devfs_reclaim(ap) 647 struct vop_reclaim_args /* { 648 struct vnode *a_vp; 649 } */ *ap; 650{ 651 struct vnode *vp = ap->a_vp; 652 struct devfs_dirent *de; 653 int i; 654 655 de = vp->v_data; 656 if (de != NULL) 657 de->de_vnode = NULL; 658 vp->v_data = NULL; 659 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) { 660 i = vcount(vp); 661 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 && 662 (vp->v_rdev->si_flags & SI_NAMED)) 663 destroy_dev(vp->v_rdev); 664 } 665 return (0); 666} 667 668static int 669devfs_remove(ap) 670 struct vop_remove_args /* { 671 struct vnode *a_dvp; 672 struct vnode *a_vp; 673 struct componentname *a_cnp; 674 } */ *ap; 675{ 676 struct vnode *vp = ap->a_vp; 677 struct devfs_dirent *dd; 678 struct devfs_dirent *de; 679 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 680 681 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 682 dd = ap->a_dvp->v_data; 683 de = vp->v_data; 684 if (de->de_dirent->d_type == DT_LNK) { 685 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 686 if (de->de_vnode) 687 de->de_vnode->v_data = NULL; 688#ifdef MAC 689 mac_destroy_devfsdirent(de); 690#endif 691 FREE(de, M_DEVFS); 692 } else { 693 de->de_flags |= DE_WHITEOUT; 694 } 695 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 696 return (0); 697} 698 699/* 700 * Revoke is called on a tty when a terminal session ends. The vnode 701 * is orphaned by setting v_op to deadfs so we need to let go of it 702 * as well so that we create a new one next time around. 703 */ 704static int 705devfs_revoke(ap) 706 struct vop_revoke_args /* { 707 struct vnode *a_vp; 708 int a_flags; 709 } */ *ap; 710{ 711 struct vnode *vp = ap->a_vp; 712 struct devfs_dirent *de; 713 714 de = vp->v_data; 715 de->de_vnode = NULL; 716 vop_revoke(ap); 717 return (0); 718} 719 720static int 721devfs_setattr(ap) 722 struct vop_setattr_args /* { 723 struct vnode *a_vp; 724 struct vattr *a_vap; 725 struct ucred *a_cred; 726 struct proc *a_p; 727 } */ *ap; 728{ 729 struct devfs_dirent *de; 730 struct vattr *vap; 731 struct vnode *vp; 732 int c, error; 733 uid_t uid; 734 gid_t gid; 735 736 vap = ap->a_vap; 737 vp = ap->a_vp; 738 if ((vap->va_type != VNON) || 739 (vap->va_nlink != VNOVAL) || 740 (vap->va_fsid != VNOVAL) || 741 (vap->va_fileid != VNOVAL) || 742 (vap->va_blocksize != VNOVAL) || 743 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 744 (vap->va_rdev != VNOVAL) || 745 ((int)vap->va_bytes != VNOVAL) || 746 (vap->va_gen != VNOVAL)) { 747 return (EINVAL); 748 } 749 750 de = vp->v_data; 751 if (vp->v_type == VDIR) 752 de = de->de_dir; 753 754 error = c = 0; 755 if (vap->va_uid == (uid_t)VNOVAL) 756 uid = de->de_uid; 757 else 758 uid = vap->va_uid; 759 if (vap->va_gid == (gid_t)VNOVAL) 760 gid = de->de_gid; 761 else 762 gid = vap->va_gid; 763 if (uid != de->de_uid || gid != de->de_gid) { 764 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 765 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 766 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)) != 0) 767 return (error); 768 de->de_uid = uid; 769 de->de_gid = gid; 770 c = 1; 771 } 772 773 if (vap->va_mode != (mode_t)VNOVAL) { 774 if ((ap->a_cred->cr_uid != de->de_uid) && 775 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT))) 776 return (error); 777 de->de_mode = vap->va_mode; 778 c = 1; 779 } 780 781 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 782 /* See the comment in ufs_vnops::ufs_setattr(). */ 783 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) && 784 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 785 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 786 return (error); 787 if (vap->va_atime.tv_sec != VNOVAL) { 788 if (vp->v_type == VCHR) 789 vp->v_rdev->si_atime = vap->va_atime; 790 else 791 de->de_atime = vap->va_atime; 792 } 793 if (vap->va_mtime.tv_sec != VNOVAL) { 794 if (vp->v_type == VCHR) 795 vp->v_rdev->si_mtime = vap->va_mtime; 796 else 797 de->de_mtime = vap->va_mtime; 798 } 799 c = 1; 800 } 801 802 if (c) { 803 if (vp->v_type == VCHR) 804 vfs_timestamp(&vp->v_rdev->si_ctime); 805 else 806 vfs_timestamp(&de->de_mtime); 807 } 808 return (0); 809} 810 811#ifdef MAC 812static int 813devfs_setlabel(ap) 814 struct vop_setlabel_args /* { 815 struct vnode *a_vp; 816 struct mac *a_label; 817 struct ucred *a_cred; 818 struct thread *a_td; 819 } */ *ap; 820{ 821 struct vnode *vp; 822 struct devfs_dirent *de; 823 824 vp = ap->a_vp; 825 de = vp->v_data; 826 827 mac_relabel_vnode(ap->a_cred, vp, ap->a_label); 828 mac_update_devfsdirent(vp->v_mount, de, vp); 829 830 return (0); 831} 832#endif 833 834static int 835devfs_symlink(ap) 836 struct vop_symlink_args /* { 837 struct vnode *a_dvp; 838 struct vnode **a_vpp; 839 struct componentname *a_cnp; 840 struct vattr *a_vap; 841 char *a_target; 842 } */ *ap; 843{ 844 int i, error; 845 struct devfs_dirent *dd; 846 struct devfs_dirent *de; 847 struct devfs_mount *dmp; 848 849 error = suser(ap->a_cnp->cn_thread); 850 if (error) 851 return(error); 852 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 853 dd = ap->a_dvp->v_data; 854 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 855 de->de_uid = 0; 856 de->de_gid = 0; 857 de->de_mode = 0755; 858 de->de_inode = dmp->dm_inode++; 859 de->de_dirent->d_type = DT_LNK; 860 i = strlen(ap->a_target) + 1; 861 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 862 bcopy(ap->a_target, de->de_symlink, i); 863 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 864#ifdef MAC 865 mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de); 866#endif 867 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 868 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 869 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 870 return (0); 871} 872 873static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 874 { &vop_default_desc, (vop_t *) vop_defaultop }, 875 { &vop_access_desc, (vop_t *) devfs_access }, 876 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 877 { &vop_ioctl_desc, (vop_t *) devfs_ioctl }, 878 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 879 { &vop_mknod_desc, (vop_t *) devfs_mknod }, 880 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 881 { &vop_print_desc, (vop_t *) vop_null }, 882 { &vop_read_desc, (vop_t *) devfs_read }, 883 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 884 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 885 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 886 { &vop_remove_desc, (vop_t *) devfs_remove }, 887 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 888 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 889#ifdef MAC 890 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 891#endif 892 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 893 { NULL, NULL } 894}; 895static struct vnodeopv_desc devfs_vnodeop_opv_desc = 896 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 897 898VNODEOP_SET(devfs_vnodeop_opv_desc); 899 900static struct vnodeopv_entry_desc devfs_specop_entries[] = { 901 { &vop_default_desc, (vop_t *) spec_vnoperate }, 902 { &vop_access_desc, (vop_t *) devfs_access }, 903 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 904 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 905 { &vop_print_desc, (vop_t *) vop_null }, 906 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 907 { &vop_remove_desc, (vop_t *) devfs_remove }, 908 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 909 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 910#ifdef MAC 911 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 912#endif 913 { NULL, NULL } 914}; 915static struct vnodeopv_desc devfs_specop_opv_desc = 916 { &devfs_specop_p, devfs_specop_entries }; 917 918VNODEOP_SET(devfs_specop_opv_desc);
|