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 130585 2004-06-16 09:47:26Z phk $
| 34 * $FreeBSD: head/sys/fs/devfs/devfs_vnops.c 130640 2004-06-17 17:16:53Z phk $
|
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 struct cdev *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 {
| 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 struct cdev *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;
| 143 dev = NULL;
|
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 struct cdev *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 = strlen(de->de_symlink); 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 struct devfs_mount *dmp; 283 284 dmp = VFSTODEVFS(ap->a_vp->v_mount); 285 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 286 devfs_populate(dmp); 287 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 288 error = devfs_rules_ioctl(ap->a_vp->v_mount, ap->a_command, ap->a_data, 289 ap->a_td); 290 return (error); 291} 292 293static int 294devfs_lookupx(ap) 295 struct vop_lookup_args /* { 296 struct vnode * a_dvp; 297 struct vnode ** a_vpp; 298 struct componentname * a_cnp; 299 } */ *ap; 300{ 301 struct componentname *cnp; 302 struct vnode *dvp, **vpp; 303 struct thread *td; 304 struct devfs_dirent *de, *dd; 305 struct devfs_dirent **dde; 306 struct devfs_mount *dmp; 307 struct cdev *cdev; 308 int error, flags, nameiop; 309 char specname[SPECNAMELEN + 1], *pname; 310 311 cnp = ap->a_cnp; 312 vpp = ap->a_vpp; 313 dvp = ap->a_dvp; 314 pname = cnp->cn_nameptr; 315 td = cnp->cn_thread; 316 flags = cnp->cn_flags; 317 nameiop = cnp->cn_nameiop; 318 dmp = VFSTODEVFS(dvp->v_mount); 319 dd = dvp->v_data; 320 321 *vpp = NULLVP; 322 cnp->cn_flags &= ~PDIRUNLOCK; 323 324 if ((flags & ISLASTCN) && nameiop == RENAME) 325 return (EOPNOTSUPP); 326 327 if (dvp->v_type != VDIR) 328 return (ENOTDIR); 329 330 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) 331 return (EIO); 332 333 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td); 334 if (error) 335 return (error); 336 337 if (cnp->cn_namelen == 1 && *pname == '.') { 338 if ((flags & ISLASTCN) && nameiop != LOOKUP) 339 return (EINVAL); 340 *vpp = dvp; 341 VREF(dvp); 342 return (0); 343 } 344 345 if (flags & ISDOTDOT) { 346 if ((flags & ISLASTCN) && nameiop != LOOKUP) 347 return (EINVAL); 348 VOP_UNLOCK(dvp, 0, td); 349 cnp->cn_flags |= PDIRUNLOCK; 350 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 351 de = TAILQ_NEXT(de, de_list); /* ".." */ 352 de = de->de_dir; 353 error = devfs_allocv(de, dvp->v_mount, vpp, td); 354 if (error || ((flags & LOCKPARENT) && (flags & ISLASTCN))) { 355 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 356 cnp->cn_flags &= ~PDIRUNLOCK; 357 } 358 return (error); 359 } 360 361 devfs_populate(dmp); 362 dd = dvp->v_data; 363 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 364 if (cnp->cn_namelen != de->de_dirent->d_namlen) 365 continue; 366 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 367 de->de_dirent->d_namlen) != 0) 368 continue; 369 if (de->de_flags & DE_WHITEOUT) 370 goto notfound; 371 goto found; 372 } 373 374 if (nameiop == DELETE) 375 goto notfound; 376 377 /* 378 * OK, we didn't have an entry for the name we were asked for 379 * so we try to see if anybody can create it on demand. 380 */ 381 pname = devfs_fqpn(specname, dvp, cnp); 382 if (pname == NULL) 383 goto notfound; 384
| 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 struct cdev *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 = strlen(de->de_symlink); 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 struct devfs_mount *dmp; 283 284 dmp = VFSTODEVFS(ap->a_vp->v_mount); 285 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 286 devfs_populate(dmp); 287 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 288 error = devfs_rules_ioctl(ap->a_vp->v_mount, ap->a_command, ap->a_data, 289 ap->a_td); 290 return (error); 291} 292 293static int 294devfs_lookupx(ap) 295 struct vop_lookup_args /* { 296 struct vnode * a_dvp; 297 struct vnode ** a_vpp; 298 struct componentname * a_cnp; 299 } */ *ap; 300{ 301 struct componentname *cnp; 302 struct vnode *dvp, **vpp; 303 struct thread *td; 304 struct devfs_dirent *de, *dd; 305 struct devfs_dirent **dde; 306 struct devfs_mount *dmp; 307 struct cdev *cdev; 308 int error, flags, nameiop; 309 char specname[SPECNAMELEN + 1], *pname; 310 311 cnp = ap->a_cnp; 312 vpp = ap->a_vpp; 313 dvp = ap->a_dvp; 314 pname = cnp->cn_nameptr; 315 td = cnp->cn_thread; 316 flags = cnp->cn_flags; 317 nameiop = cnp->cn_nameiop; 318 dmp = VFSTODEVFS(dvp->v_mount); 319 dd = dvp->v_data; 320 321 *vpp = NULLVP; 322 cnp->cn_flags &= ~PDIRUNLOCK; 323 324 if ((flags & ISLASTCN) && nameiop == RENAME) 325 return (EOPNOTSUPP); 326 327 if (dvp->v_type != VDIR) 328 return (ENOTDIR); 329 330 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT)) 331 return (EIO); 332 333 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td); 334 if (error) 335 return (error); 336 337 if (cnp->cn_namelen == 1 && *pname == '.') { 338 if ((flags & ISLASTCN) && nameiop != LOOKUP) 339 return (EINVAL); 340 *vpp = dvp; 341 VREF(dvp); 342 return (0); 343 } 344 345 if (flags & ISDOTDOT) { 346 if ((flags & ISLASTCN) && nameiop != LOOKUP) 347 return (EINVAL); 348 VOP_UNLOCK(dvp, 0, td); 349 cnp->cn_flags |= PDIRUNLOCK; 350 de = TAILQ_FIRST(&dd->de_dlist); /* "." */ 351 de = TAILQ_NEXT(de, de_list); /* ".." */ 352 de = de->de_dir; 353 error = devfs_allocv(de, dvp->v_mount, vpp, td); 354 if (error || ((flags & LOCKPARENT) && (flags & ISLASTCN))) { 355 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); 356 cnp->cn_flags &= ~PDIRUNLOCK; 357 } 358 return (error); 359 } 360 361 devfs_populate(dmp); 362 dd = dvp->v_data; 363 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 364 if (cnp->cn_namelen != de->de_dirent->d_namlen) 365 continue; 366 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 367 de->de_dirent->d_namlen) != 0) 368 continue; 369 if (de->de_flags & DE_WHITEOUT) 370 goto notfound; 371 goto found; 372 } 373 374 if (nameiop == DELETE) 375 goto notfound; 376 377 /* 378 * OK, we didn't have an entry for the name we were asked for 379 * so we try to see if anybody can create it on demand. 380 */ 381 pname = devfs_fqpn(specname, dvp, cnp); 382 if (pname == NULL) 383 goto notfound; 384
|
385 cdev = NODEV;
| 385 cdev = NULL;
|
386 EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev);
| 386 EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev);
|
387 if (cdev == NODEV)
| 387 if (cdev == NULL)
|
388 goto notfound; 389 390 devfs_populate(dmp); 391 392 dde = devfs_itode(dmp, cdev->si_inode); 393 394 if (dde == NULL || *dde == NULL || *dde == DE_DELETED) 395 goto notfound; 396 397 if ((*dde)->de_flags & DE_WHITEOUT) 398 goto notfound; 399 400 de = *dde; 401 goto found; 402 403notfound: 404 405 if ((nameiop == CREATE || nameiop == RENAME) && 406 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 407 cnp->cn_flags |= SAVENAME; 408 if (!(flags & LOCKPARENT)) { 409 VOP_UNLOCK(dvp, 0, td); 410 cnp->cn_flags |= PDIRUNLOCK; 411 } 412 return (EJUSTRETURN); 413 } 414 return (ENOENT); 415 416 417found: 418 419 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 420 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 421 if (error) 422 return (error); 423 if (*vpp == dvp) { 424 VREF(dvp); 425 *vpp = dvp; 426 return (0); 427 } 428 error = devfs_allocv(de, dvp->v_mount, vpp, td); 429 if (error) 430 return (error); 431 if (!(flags & LOCKPARENT)) { 432 VOP_UNLOCK(dvp, 0, td); 433 cnp->cn_flags |= PDIRUNLOCK; 434 } 435 return (0); 436 } 437 error = devfs_allocv(de, dvp->v_mount, vpp, td); 438 if (error) 439 return (error); 440 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) { 441 VOP_UNLOCK(dvp, 0, td); 442 cnp->cn_flags |= PDIRUNLOCK; 443 } 444 return (0); 445} 446 447static int 448devfs_lookup(struct vop_lookup_args *ap) 449{ 450 int j; 451 struct devfs_mount *dmp; 452 453 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 454 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 455 j = devfs_lookupx(ap); 456 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 457 return (j); 458} 459 460static int 461devfs_mknod(struct vop_mknod_args *ap) 462/* 463struct vop_mknod_args { 464 struct vnodeop_desc *a_desc; 465 struct vnode *a_dvp; 466 struct vnode **a_vpp; 467 struct componentname *a_cnp; 468 struct vattr *a_vap; 469}; 470*/ 471{ 472 struct componentname *cnp; 473 struct vnode *dvp, **vpp; 474 struct thread *td; 475 struct devfs_dirent *dd, *de; 476 struct devfs_mount *dmp; 477 int error; 478 479 dvp = ap->a_dvp; 480 dmp = VFSTODEVFS(dvp->v_mount); 481 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 482 483 cnp = ap->a_cnp; 484 vpp = ap->a_vpp; 485 td = cnp->cn_thread; 486 dd = dvp->v_data; 487 488 error = ENOENT; 489 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 490 if (cnp->cn_namelen != de->de_dirent->d_namlen) 491 continue; 492 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 493 de->de_dirent->d_namlen) != 0) 494 continue; 495 if (de->de_flags & DE_WHITEOUT) 496 break; 497 goto notfound; 498 } 499 if (de == NULL) 500 goto notfound; 501 de->de_flags &= ~DE_WHITEOUT; 502 error = devfs_allocv(de, dvp->v_mount, vpp, td); 503notfound: 504 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 505 return (error); 506} 507 508 509static int 510devfs_pathconf(ap) 511 struct vop_pathconf_args /* { 512 struct vnode *a_vp; 513 int a_name; 514 int *a_retval; 515 } */ *ap; 516{ 517 518 switch (ap->a_name) { 519 case _PC_NAME_MAX: 520 *ap->a_retval = NAME_MAX; 521 return (0); 522 case _PC_PATH_MAX: 523 *ap->a_retval = PATH_MAX; 524 return (0); 525 case _PC_MAC_PRESENT: 526#ifdef MAC 527 /* 528 * If MAC is enabled, devfs automatically supports 529 * trivial non-persistant label storage. 530 */ 531 *ap->a_retval = 1; 532#else 533 *ap->a_retval = 0; 534#endif 535 return (0); 536 default: 537 return (vop_stdpathconf(ap)); 538 } 539 /* NOTREACHED */ 540} 541 542static int 543devfs_read(ap) 544 struct vop_read_args /* { 545 struct vnode *a_vp; 546 struct uio *a_uio; 547 int a_ioflag; 548 struct ucred *a_cred; 549 } */ *ap; 550{ 551 552 if (ap->a_vp->v_type != VDIR) 553 return (EINVAL); 554 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 555} 556 557static int 558devfs_readdir(ap) 559 struct vop_readdir_args /* { 560 struct vnode *a_vp; 561 struct uio *a_uio; 562 struct ucred *a_cred; 563 int *a_eofflag; 564 int *a_ncookies; 565 u_long **a_cookies; 566 } */ *ap; 567{ 568 int error; 569 struct uio *uio; 570 struct dirent *dp; 571 struct devfs_dirent *dd; 572 struct devfs_dirent *de; 573 struct devfs_mount *dmp; 574 off_t off, oldoff; 575 int ncookies = 0; 576 u_long *cookiebuf, *cookiep; 577 struct dirent *dps, *dpe; 578 579 if (ap->a_vp->v_type != VDIR) 580 return (ENOTDIR); 581 582 uio = ap->a_uio; 583 if (uio->uio_offset < 0) 584 return (EINVAL); 585 586 dmp = VFSTODEVFS(ap->a_vp->v_mount); 587 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 588 devfs_populate(dmp); 589 error = 0; 590 de = ap->a_vp->v_data; 591 off = 0; 592 oldoff = uio->uio_offset; 593 TAILQ_FOREACH(dd, &de->de_dlist, de_list) { 594 if (dd->de_flags & DE_WHITEOUT) 595 continue; 596 if (dd->de_dirent->d_type == DT_DIR) 597 de = dd->de_dir; 598 else 599 de = dd; 600 dp = dd->de_dirent; 601 if (dp->d_reclen > uio->uio_resid) 602 break; 603 dp->d_fileno = de->de_inode; 604 if (off >= uio->uio_offset) { 605 ncookies++; 606 error = uiomove(dp, dp->d_reclen, uio); 607 if (error) 608 break; 609 } 610 off += dp->d_reclen; 611 } 612 if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) { 613 MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long), 614 M_TEMP, M_WAITOK); 615 cookiep = cookiebuf; 616 dps = (struct dirent *)((char *)uio->uio_iov->iov_base - 617 (uio->uio_offset - oldoff)); 618 dpe = (struct dirent *) uio->uio_iov->iov_base; 619 for( dp = dps; 620 dp < dpe; 621 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { 622 oldoff += dp->d_reclen; 623 *cookiep++ = (u_long) oldoff; 624 } 625 *ap->a_ncookies = ncookies; 626 *ap->a_cookies = cookiebuf; 627 } 628 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 629 uio->uio_offset = off; 630 return (error); 631} 632 633static int 634devfs_readlink(ap) 635 struct vop_readlink_args /* { 636 struct vnode *a_vp; 637 struct uio *a_uio; 638 struct ucred *a_cead; 639 } */ *ap; 640{ 641 int error; 642 struct devfs_dirent *de; 643 644 de = ap->a_vp->v_data; 645 error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio); 646 return (error); 647} 648 649static int 650devfs_reclaim(ap) 651 struct vop_reclaim_args /* { 652 struct vnode *a_vp; 653 } */ *ap; 654{ 655 struct vnode *vp = ap->a_vp; 656 struct devfs_dirent *de; 657 int i; 658 659 de = vp->v_data; 660 if (de != NULL) 661 de->de_vnode = NULL; 662 vp->v_data = NULL;
| 388 goto notfound; 389 390 devfs_populate(dmp); 391 392 dde = devfs_itode(dmp, cdev->si_inode); 393 394 if (dde == NULL || *dde == NULL || *dde == DE_DELETED) 395 goto notfound; 396 397 if ((*dde)->de_flags & DE_WHITEOUT) 398 goto notfound; 399 400 de = *dde; 401 goto found; 402 403notfound: 404 405 if ((nameiop == CREATE || nameiop == RENAME) && 406 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) { 407 cnp->cn_flags |= SAVENAME; 408 if (!(flags & LOCKPARENT)) { 409 VOP_UNLOCK(dvp, 0, td); 410 cnp->cn_flags |= PDIRUNLOCK; 411 } 412 return (EJUSTRETURN); 413 } 414 return (ENOENT); 415 416 417found: 418 419 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) { 420 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td); 421 if (error) 422 return (error); 423 if (*vpp == dvp) { 424 VREF(dvp); 425 *vpp = dvp; 426 return (0); 427 } 428 error = devfs_allocv(de, dvp->v_mount, vpp, td); 429 if (error) 430 return (error); 431 if (!(flags & LOCKPARENT)) { 432 VOP_UNLOCK(dvp, 0, td); 433 cnp->cn_flags |= PDIRUNLOCK; 434 } 435 return (0); 436 } 437 error = devfs_allocv(de, dvp->v_mount, vpp, td); 438 if (error) 439 return (error); 440 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) { 441 VOP_UNLOCK(dvp, 0, td); 442 cnp->cn_flags |= PDIRUNLOCK; 443 } 444 return (0); 445} 446 447static int 448devfs_lookup(struct vop_lookup_args *ap) 449{ 450 int j; 451 struct devfs_mount *dmp; 452 453 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 454 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 455 j = devfs_lookupx(ap); 456 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 457 return (j); 458} 459 460static int 461devfs_mknod(struct vop_mknod_args *ap) 462/* 463struct vop_mknod_args { 464 struct vnodeop_desc *a_desc; 465 struct vnode *a_dvp; 466 struct vnode **a_vpp; 467 struct componentname *a_cnp; 468 struct vattr *a_vap; 469}; 470*/ 471{ 472 struct componentname *cnp; 473 struct vnode *dvp, **vpp; 474 struct thread *td; 475 struct devfs_dirent *dd, *de; 476 struct devfs_mount *dmp; 477 int error; 478 479 dvp = ap->a_dvp; 480 dmp = VFSTODEVFS(dvp->v_mount); 481 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 482 483 cnp = ap->a_cnp; 484 vpp = ap->a_vpp; 485 td = cnp->cn_thread; 486 dd = dvp->v_data; 487 488 error = ENOENT; 489 TAILQ_FOREACH(de, &dd->de_dlist, de_list) { 490 if (cnp->cn_namelen != de->de_dirent->d_namlen) 491 continue; 492 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name, 493 de->de_dirent->d_namlen) != 0) 494 continue; 495 if (de->de_flags & DE_WHITEOUT) 496 break; 497 goto notfound; 498 } 499 if (de == NULL) 500 goto notfound; 501 de->de_flags &= ~DE_WHITEOUT; 502 error = devfs_allocv(de, dvp->v_mount, vpp, td); 503notfound: 504 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 505 return (error); 506} 507 508 509static int 510devfs_pathconf(ap) 511 struct vop_pathconf_args /* { 512 struct vnode *a_vp; 513 int a_name; 514 int *a_retval; 515 } */ *ap; 516{ 517 518 switch (ap->a_name) { 519 case _PC_NAME_MAX: 520 *ap->a_retval = NAME_MAX; 521 return (0); 522 case _PC_PATH_MAX: 523 *ap->a_retval = PATH_MAX; 524 return (0); 525 case _PC_MAC_PRESENT: 526#ifdef MAC 527 /* 528 * If MAC is enabled, devfs automatically supports 529 * trivial non-persistant label storage. 530 */ 531 *ap->a_retval = 1; 532#else 533 *ap->a_retval = 0; 534#endif 535 return (0); 536 default: 537 return (vop_stdpathconf(ap)); 538 } 539 /* NOTREACHED */ 540} 541 542static int 543devfs_read(ap) 544 struct vop_read_args /* { 545 struct vnode *a_vp; 546 struct uio *a_uio; 547 int a_ioflag; 548 struct ucred *a_cred; 549 } */ *ap; 550{ 551 552 if (ap->a_vp->v_type != VDIR) 553 return (EINVAL); 554 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL)); 555} 556 557static int 558devfs_readdir(ap) 559 struct vop_readdir_args /* { 560 struct vnode *a_vp; 561 struct uio *a_uio; 562 struct ucred *a_cred; 563 int *a_eofflag; 564 int *a_ncookies; 565 u_long **a_cookies; 566 } */ *ap; 567{ 568 int error; 569 struct uio *uio; 570 struct dirent *dp; 571 struct devfs_dirent *dd; 572 struct devfs_dirent *de; 573 struct devfs_mount *dmp; 574 off_t off, oldoff; 575 int ncookies = 0; 576 u_long *cookiebuf, *cookiep; 577 struct dirent *dps, *dpe; 578 579 if (ap->a_vp->v_type != VDIR) 580 return (ENOTDIR); 581 582 uio = ap->a_uio; 583 if (uio->uio_offset < 0) 584 return (EINVAL); 585 586 dmp = VFSTODEVFS(ap->a_vp->v_mount); 587 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread); 588 devfs_populate(dmp); 589 error = 0; 590 de = ap->a_vp->v_data; 591 off = 0; 592 oldoff = uio->uio_offset; 593 TAILQ_FOREACH(dd, &de->de_dlist, de_list) { 594 if (dd->de_flags & DE_WHITEOUT) 595 continue; 596 if (dd->de_dirent->d_type == DT_DIR) 597 de = dd->de_dir; 598 else 599 de = dd; 600 dp = dd->de_dirent; 601 if (dp->d_reclen > uio->uio_resid) 602 break; 603 dp->d_fileno = de->de_inode; 604 if (off >= uio->uio_offset) { 605 ncookies++; 606 error = uiomove(dp, dp->d_reclen, uio); 607 if (error) 608 break; 609 } 610 off += dp->d_reclen; 611 } 612 if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) { 613 MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long), 614 M_TEMP, M_WAITOK); 615 cookiep = cookiebuf; 616 dps = (struct dirent *)((char *)uio->uio_iov->iov_base - 617 (uio->uio_offset - oldoff)); 618 dpe = (struct dirent *) uio->uio_iov->iov_base; 619 for( dp = dps; 620 dp < dpe; 621 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { 622 oldoff += dp->d_reclen; 623 *cookiep++ = (u_long) oldoff; 624 } 625 *ap->a_ncookies = ncookies; 626 *ap->a_cookies = cookiebuf; 627 } 628 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 629 uio->uio_offset = off; 630 return (error); 631} 632 633static int 634devfs_readlink(ap) 635 struct vop_readlink_args /* { 636 struct vnode *a_vp; 637 struct uio *a_uio; 638 struct ucred *a_cead; 639 } */ *ap; 640{ 641 int error; 642 struct devfs_dirent *de; 643 644 de = ap->a_vp->v_data; 645 error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio); 646 return (error); 647} 648 649static int 650devfs_reclaim(ap) 651 struct vop_reclaim_args /* { 652 struct vnode *a_vp; 653 } */ *ap; 654{ 655 struct vnode *vp = ap->a_vp; 656 struct devfs_dirent *de; 657 int i; 658 659 de = vp->v_data; 660 if (de != NULL) 661 de->de_vnode = NULL; 662 vp->v_data = NULL;
|
663 if (vp->v_rdev != NODEV && vp->v_rdev != NULL) {
| 663 if (vp->v_rdev != NULL && vp->v_rdev != NULL) {
|
664 i = vcount(vp); 665 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 && 666 (vp->v_rdev->si_flags & SI_NAMED)) 667 destroy_dev(vp->v_rdev); 668 } 669 return (0); 670} 671 672static int 673devfs_remove(ap) 674 struct vop_remove_args /* { 675 struct vnode *a_dvp; 676 struct vnode *a_vp; 677 struct componentname *a_cnp; 678 } */ *ap; 679{ 680 struct vnode *vp = ap->a_vp; 681 struct devfs_dirent *dd; 682 struct devfs_dirent *de; 683 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 684 685 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 686 dd = ap->a_dvp->v_data; 687 de = vp->v_data; 688 if (de->de_dirent->d_type == DT_LNK) { 689 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 690 if (de->de_vnode) 691 de->de_vnode->v_data = NULL; 692#ifdef MAC 693 mac_destroy_devfsdirent(de); 694#endif 695 FREE(de, M_DEVFS); 696 } else { 697 de->de_flags |= DE_WHITEOUT; 698 } 699 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 700 return (0); 701} 702 703/* 704 * Revoke is called on a tty when a terminal session ends. The vnode 705 * is orphaned by setting v_op to deadfs so we need to let go of it 706 * as well so that we create a new one next time around. 707 */ 708static int 709devfs_revoke(ap) 710 struct vop_revoke_args /* { 711 struct vnode *a_vp; 712 int a_flags; 713 } */ *ap; 714{ 715 struct vnode *vp = ap->a_vp; 716 struct devfs_dirent *de; 717 718 de = vp->v_data; 719 de->de_vnode = NULL; 720 vop_revoke(ap); 721 return (0); 722} 723 724static int 725devfs_setattr(ap) 726 struct vop_setattr_args /* { 727 struct vnode *a_vp; 728 struct vattr *a_vap; 729 struct ucred *a_cred; 730 struct proc *a_p; 731 } */ *ap; 732{ 733 struct devfs_dirent *de; 734 struct vattr *vap; 735 struct vnode *vp; 736 int c, error; 737 uid_t uid; 738 gid_t gid; 739 740 vap = ap->a_vap; 741 vp = ap->a_vp; 742 if ((vap->va_type != VNON) || 743 (vap->va_nlink != VNOVAL) || 744 (vap->va_fsid != VNOVAL) || 745 (vap->va_fileid != VNOVAL) || 746 (vap->va_blocksize != VNOVAL) || 747 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 748 (vap->va_rdev != VNOVAL) || 749 ((int)vap->va_bytes != VNOVAL) || 750 (vap->va_gen != VNOVAL)) { 751 return (EINVAL); 752 } 753 754 de = vp->v_data; 755 if (vp->v_type == VDIR) 756 de = de->de_dir; 757 758 error = c = 0; 759 if (vap->va_uid == (uid_t)VNOVAL) 760 uid = de->de_uid; 761 else 762 uid = vap->va_uid; 763 if (vap->va_gid == (gid_t)VNOVAL) 764 gid = de->de_gid; 765 else 766 gid = vap->va_gid; 767 if (uid != de->de_uid || gid != de->de_gid) { 768 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 769 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 770 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)) != 0) 771 return (error); 772 de->de_uid = uid; 773 de->de_gid = gid; 774 c = 1; 775 } 776 777 if (vap->va_mode != (mode_t)VNOVAL) { 778 if ((ap->a_cred->cr_uid != de->de_uid) && 779 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT))) 780 return (error); 781 de->de_mode = vap->va_mode; 782 c = 1; 783 } 784 785 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 786 /* See the comment in ufs_vnops::ufs_setattr(). */ 787 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) && 788 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 789 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 790 return (error); 791 if (vap->va_atime.tv_sec != VNOVAL) { 792 if (vp->v_type == VCHR) 793 vp->v_rdev->si_atime = vap->va_atime; 794 else 795 de->de_atime = vap->va_atime; 796 } 797 if (vap->va_mtime.tv_sec != VNOVAL) { 798 if (vp->v_type == VCHR) 799 vp->v_rdev->si_mtime = vap->va_mtime; 800 else 801 de->de_mtime = vap->va_mtime; 802 } 803 c = 1; 804 } 805 806 if (c) { 807 if (vp->v_type == VCHR) 808 vfs_timestamp(&vp->v_rdev->si_ctime); 809 else 810 vfs_timestamp(&de->de_mtime); 811 } 812 return (0); 813} 814 815#ifdef MAC 816static int 817devfs_setlabel(ap) 818 struct vop_setlabel_args /* { 819 struct vnode *a_vp; 820 struct mac *a_label; 821 struct ucred *a_cred; 822 struct thread *a_td; 823 } */ *ap; 824{ 825 struct vnode *vp; 826 struct devfs_dirent *de; 827 828 vp = ap->a_vp; 829 de = vp->v_data; 830 831 mac_relabel_vnode(ap->a_cred, vp, ap->a_label); 832 mac_update_devfsdirent(vp->v_mount, de, vp); 833 834 return (0); 835} 836#endif 837 838static int 839devfs_symlink(ap) 840 struct vop_symlink_args /* { 841 struct vnode *a_dvp; 842 struct vnode **a_vpp; 843 struct componentname *a_cnp; 844 struct vattr *a_vap; 845 char *a_target; 846 } */ *ap; 847{ 848 int i, error; 849 struct devfs_dirent *dd; 850 struct devfs_dirent *de; 851 struct devfs_mount *dmp; 852 853 error = suser(ap->a_cnp->cn_thread); 854 if (error) 855 return(error); 856 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 857 dd = ap->a_dvp->v_data; 858 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 859 de->de_uid = 0; 860 de->de_gid = 0; 861 de->de_mode = 0755; 862 de->de_inode = dmp->dm_inode++; 863 de->de_dirent->d_type = DT_LNK; 864 i = strlen(ap->a_target) + 1; 865 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 866 bcopy(ap->a_target, de->de_symlink, i); 867 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 868#ifdef MAC 869 mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de); 870#endif 871 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 872 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 873 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 874 return (0); 875} 876 877static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 878 { &vop_default_desc, (vop_t *) vop_defaultop }, 879 { &vop_access_desc, (vop_t *) devfs_access }, 880 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 881 { &vop_ioctl_desc, (vop_t *) devfs_ioctl }, 882 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 883 { &vop_mknod_desc, (vop_t *) devfs_mknod }, 884 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 885 { &vop_read_desc, (vop_t *) devfs_read }, 886 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 887 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 888 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 889 { &vop_remove_desc, (vop_t *) devfs_remove }, 890 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 891 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 892#ifdef MAC 893 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 894#endif 895 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 896 { NULL, NULL } 897}; 898static struct vnodeopv_desc devfs_vnodeop_opv_desc = 899 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 900 901VNODEOP_SET(devfs_vnodeop_opv_desc); 902 903static struct vnodeopv_entry_desc devfs_specop_entries[] = { 904 { &vop_default_desc, (vop_t *) spec_vnoperate }, 905 { &vop_access_desc, (vop_t *) devfs_access }, 906 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 907 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 908 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 909 { &vop_remove_desc, (vop_t *) devfs_remove }, 910 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 911 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 912#ifdef MAC 913 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 914#endif 915 { NULL, NULL } 916}; 917static struct vnodeopv_desc devfs_specop_opv_desc = 918 { &devfs_specop_p, devfs_specop_entries }; 919 920VNODEOP_SET(devfs_specop_opv_desc);
| 664 i = vcount(vp); 665 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 && 666 (vp->v_rdev->si_flags & SI_NAMED)) 667 destroy_dev(vp->v_rdev); 668 } 669 return (0); 670} 671 672static int 673devfs_remove(ap) 674 struct vop_remove_args /* { 675 struct vnode *a_dvp; 676 struct vnode *a_vp; 677 struct componentname *a_cnp; 678 } */ *ap; 679{ 680 struct vnode *vp = ap->a_vp; 681 struct devfs_dirent *dd; 682 struct devfs_dirent *de; 683 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount); 684 685 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 686 dd = ap->a_dvp->v_data; 687 de = vp->v_data; 688 if (de->de_dirent->d_type == DT_LNK) { 689 TAILQ_REMOVE(&dd->de_dlist, de, de_list); 690 if (de->de_vnode) 691 de->de_vnode->v_data = NULL; 692#ifdef MAC 693 mac_destroy_devfsdirent(de); 694#endif 695 FREE(de, M_DEVFS); 696 } else { 697 de->de_flags |= DE_WHITEOUT; 698 } 699 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 700 return (0); 701} 702 703/* 704 * Revoke is called on a tty when a terminal session ends. The vnode 705 * is orphaned by setting v_op to deadfs so we need to let go of it 706 * as well so that we create a new one next time around. 707 */ 708static int 709devfs_revoke(ap) 710 struct vop_revoke_args /* { 711 struct vnode *a_vp; 712 int a_flags; 713 } */ *ap; 714{ 715 struct vnode *vp = ap->a_vp; 716 struct devfs_dirent *de; 717 718 de = vp->v_data; 719 de->de_vnode = NULL; 720 vop_revoke(ap); 721 return (0); 722} 723 724static int 725devfs_setattr(ap) 726 struct vop_setattr_args /* { 727 struct vnode *a_vp; 728 struct vattr *a_vap; 729 struct ucred *a_cred; 730 struct proc *a_p; 731 } */ *ap; 732{ 733 struct devfs_dirent *de; 734 struct vattr *vap; 735 struct vnode *vp; 736 int c, error; 737 uid_t uid; 738 gid_t gid; 739 740 vap = ap->a_vap; 741 vp = ap->a_vp; 742 if ((vap->va_type != VNON) || 743 (vap->va_nlink != VNOVAL) || 744 (vap->va_fsid != VNOVAL) || 745 (vap->va_fileid != VNOVAL) || 746 (vap->va_blocksize != VNOVAL) || 747 (vap->va_flags != VNOVAL && vap->va_flags != 0) || 748 (vap->va_rdev != VNOVAL) || 749 ((int)vap->va_bytes != VNOVAL) || 750 (vap->va_gen != VNOVAL)) { 751 return (EINVAL); 752 } 753 754 de = vp->v_data; 755 if (vp->v_type == VDIR) 756 de = de->de_dir; 757 758 error = c = 0; 759 if (vap->va_uid == (uid_t)VNOVAL) 760 uid = de->de_uid; 761 else 762 uid = vap->va_uid; 763 if (vap->va_gid == (gid_t)VNOVAL) 764 gid = de->de_gid; 765 else 766 gid = vap->va_gid; 767 if (uid != de->de_uid || gid != de->de_gid) { 768 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid || 769 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) && 770 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT)) != 0) 771 return (error); 772 de->de_uid = uid; 773 de->de_gid = gid; 774 c = 1; 775 } 776 777 if (vap->va_mode != (mode_t)VNOVAL) { 778 if ((ap->a_cred->cr_uid != de->de_uid) && 779 (error = suser_cred(ap->a_td->td_ucred, PRISON_ROOT))) 780 return (error); 781 de->de_mode = vap->va_mode; 782 c = 1; 783 } 784 785 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { 786 /* See the comment in ufs_vnops::ufs_setattr(). */ 787 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) && 788 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 789 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td)))) 790 return (error); 791 if (vap->va_atime.tv_sec != VNOVAL) { 792 if (vp->v_type == VCHR) 793 vp->v_rdev->si_atime = vap->va_atime; 794 else 795 de->de_atime = vap->va_atime; 796 } 797 if (vap->va_mtime.tv_sec != VNOVAL) { 798 if (vp->v_type == VCHR) 799 vp->v_rdev->si_mtime = vap->va_mtime; 800 else 801 de->de_mtime = vap->va_mtime; 802 } 803 c = 1; 804 } 805 806 if (c) { 807 if (vp->v_type == VCHR) 808 vfs_timestamp(&vp->v_rdev->si_ctime); 809 else 810 vfs_timestamp(&de->de_mtime); 811 } 812 return (0); 813} 814 815#ifdef MAC 816static int 817devfs_setlabel(ap) 818 struct vop_setlabel_args /* { 819 struct vnode *a_vp; 820 struct mac *a_label; 821 struct ucred *a_cred; 822 struct thread *a_td; 823 } */ *ap; 824{ 825 struct vnode *vp; 826 struct devfs_dirent *de; 827 828 vp = ap->a_vp; 829 de = vp->v_data; 830 831 mac_relabel_vnode(ap->a_cred, vp, ap->a_label); 832 mac_update_devfsdirent(vp->v_mount, de, vp); 833 834 return (0); 835} 836#endif 837 838static int 839devfs_symlink(ap) 840 struct vop_symlink_args /* { 841 struct vnode *a_dvp; 842 struct vnode **a_vpp; 843 struct componentname *a_cnp; 844 struct vattr *a_vap; 845 char *a_target; 846 } */ *ap; 847{ 848 int i, error; 849 struct devfs_dirent *dd; 850 struct devfs_dirent *de; 851 struct devfs_mount *dmp; 852 853 error = suser(ap->a_cnp->cn_thread); 854 if (error) 855 return(error); 856 dmp = VFSTODEVFS(ap->a_dvp->v_mount); 857 dd = ap->a_dvp->v_data; 858 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen); 859 de->de_uid = 0; 860 de->de_gid = 0; 861 de->de_mode = 0755; 862 de->de_inode = dmp->dm_inode++; 863 de->de_dirent->d_type = DT_LNK; 864 i = strlen(ap->a_target) + 1; 865 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK); 866 bcopy(ap->a_target, de->de_symlink, i); 867 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread); 868#ifdef MAC 869 mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de); 870#endif 871 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list); 872 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, 0); 873 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread); 874 return (0); 875} 876 877static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = { 878 { &vop_default_desc, (vop_t *) vop_defaultop }, 879 { &vop_access_desc, (vop_t *) devfs_access }, 880 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 881 { &vop_ioctl_desc, (vop_t *) devfs_ioctl }, 882 { &vop_lookup_desc, (vop_t *) devfs_lookup }, 883 { &vop_mknod_desc, (vop_t *) devfs_mknod }, 884 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 885 { &vop_read_desc, (vop_t *) devfs_read }, 886 { &vop_readdir_desc, (vop_t *) devfs_readdir }, 887 { &vop_readlink_desc, (vop_t *) devfs_readlink }, 888 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 889 { &vop_remove_desc, (vop_t *) devfs_remove }, 890 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 891 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 892#ifdef MAC 893 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 894#endif 895 { &vop_symlink_desc, (vop_t *) devfs_symlink }, 896 { NULL, NULL } 897}; 898static struct vnodeopv_desc devfs_vnodeop_opv_desc = 899 { &devfs_vnodeop_p, devfs_vnodeop_entries }; 900 901VNODEOP_SET(devfs_vnodeop_opv_desc); 902 903static struct vnodeopv_entry_desc devfs_specop_entries[] = { 904 { &vop_default_desc, (vop_t *) spec_vnoperate }, 905 { &vop_access_desc, (vop_t *) devfs_access }, 906 { &vop_getattr_desc, (vop_t *) devfs_getattr }, 907 { &vop_pathconf_desc, (vop_t *) devfs_pathconf }, 908 { &vop_reclaim_desc, (vop_t *) devfs_reclaim }, 909 { &vop_remove_desc, (vop_t *) devfs_remove }, 910 { &vop_revoke_desc, (vop_t *) devfs_revoke }, 911 { &vop_setattr_desc, (vop_t *) devfs_setattr }, 912#ifdef MAC 913 { &vop_setlabel_desc, (vop_t *) devfs_setlabel }, 914#endif 915 { NULL, NULL } 916}; 917static struct vnodeopv_desc devfs_specop_opv_desc = 918 { &devfs_specop_p, devfs_specop_entries }; 919 920VNODEOP_SET(devfs_specop_opv_desc);
|