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$
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
64 static int devfs_access(struct vop_access_args *ap);
65 static int devfs_getattr(struct vop_getattr_args *ap);
66 static int devfs_ioctl(struct vop_ioctl_args *ap);
67 static int devfs_lookupx(struct vop_lookup_args *ap);
68 static int devfs_mknod(struct vop_mknod_args *ap);
69 static int devfs_pathconf(struct vop_pathconf_args *ap);
70 static int devfs_read(struct vop_read_args *ap);
71 static int devfs_readdir(struct vop_readdir_args *ap);
72 static int devfs_readlink(struct vop_readlink_args *ap);
73 static int devfs_reclaim(struct vop_reclaim_args *ap);
74 static int devfs_remove(struct vop_remove_args *ap);
75 static int devfs_revoke(struct vop_revoke_args *ap);
76 static int devfs_setattr(struct vop_setattr_args *ap);
77 #ifdef MAC
78 static int devfs_setlabel(struct vop_setlabel_args *ap);
79 #endif
80 static int devfs_symlink(struct vop_symlink_args *ap);
81
82 static vop_t **devfs_vnodeop_p;
83 static vop_t **devfs_specop_p;
84
85 /*
86 * Construct the fully qualified path name relative to the mountpoint
87 */
88 static char *
89 devfs_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
121 int
122 devfs_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 KASSERT(td == curthread, ("devfs_allocv: td != curthread"));
129 loop:
130 vp = de->de_vnode;
131 if (vp != NULL) {
132 if (vget(vp, LK_EXCLUSIVE, td))
133 goto loop;
134 *vpp = vp;
135 return (0);
136 }
137 if (de->de_dirent->d_type == DT_CHR) {
138 dev = *devfs_itod(de->de_inode);
139 if (dev == NULL)
140 return (ENOENT);
141 } else {
142 dev = NULL;
143 }
144 error = getnewvnode("devfs", mp, devfs_vnodeop_p, &vp);
145 if (error != 0) {
146 printf("devfs_allocv: failed to allocate new vnode\n");
147 return (error);
148 }
149
150 if (de->de_dirent->d_type == DT_CHR) {
151 vp->v_type = VCHR;
152 vp = addaliasu(vp, dev->si_udev);
153 vp->v_op = devfs_specop_p;
154 } else if (de->de_dirent->d_type == DT_DIR) {
155 vp->v_type = VDIR;
156 } else if (de->de_dirent->d_type == DT_LNK) {
157 vp->v_type = VLNK;
158 } else {
159 vp->v_type = VBAD;
160 }
161 vp->v_data = de;
162 de->de_vnode = vp;
163 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
164 #ifdef MAC
165 mac_associate_vnode_devfs(mp, de, vp);
166 #endif
167 *vpp = vp;
168 return (0);
169 }
170
171 static int
172 devfs_access(ap)
173 struct vop_access_args /* {
174 struct vnode *a_vp;
175 int a_mode;
176 struct ucred *a_cred;
177 struct thread *a_td;
178 } */ *ap;
179 {
180 struct vnode *vp = ap->a_vp;
181 struct devfs_dirent *de;
182 int error;
183
184 de = vp->v_data;
185 if (vp->v_type == VDIR)
186 de = de->de_dir;
187
188 error = vaccess(vp->v_type, de->de_mode, de->de_uid, de->de_gid,
189 ap->a_mode, ap->a_cred, NULL);
190 if (!error)
191 return (error);
192 if (error != EACCES)
193 return (error);
194 /* We do, however, allow access to the controlling terminal */
195 if (!(ap->a_td->td_proc->p_flag & P_CONTROLT))
196 return (error);
197 if (ap->a_td->td_proc->p_session->s_ttyvp == de->de_vnode)
198 return (0);
199 return (error);
200 }
201
202 static int
203 devfs_getattr(ap)
204 struct vop_getattr_args /* {
205 struct vnode *a_vp;
206 struct vattr *a_vap;
207 struct ucred *a_cred;
208 struct thread *a_td;
209 } */ *ap;
210 {
211 struct vnode *vp = ap->a_vp;
212 struct vattr *vap = ap->a_vap;
213 int error = 0;
214 struct devfs_dirent *de;
215 struct cdev *dev;
216
217 de = vp->v_data;
218 if (vp->v_type == VDIR)
219 de = de->de_dir;
220 bzero((caddr_t) vap, sizeof(*vap));
221 vattr_null(vap);
222 vap->va_uid = de->de_uid;
223 vap->va_gid = de->de_gid;
224 vap->va_mode = de->de_mode;
225 if (vp->v_type == VLNK)
226 vap->va_size = strlen(de->de_symlink);
227 else if (vp->v_type == VDIR)
228 vap->va_size = vap->va_bytes = DEV_BSIZE;
229 else
230 vap->va_size = 0;
231 if (vp->v_type != VDIR)
232 vap->va_bytes = 0;
233 vap->va_blocksize = DEV_BSIZE;
234 vap->va_type = vp->v_type;
235
236 #define fix(aa) \
237 do { \
238 if ((aa).tv_sec == 0) { \
239 (aa).tv_sec = boottime.tv_sec; \
240 (aa).tv_nsec = boottime.tv_usec * 1000; \
241 } \
242 } while (0)
243
244 if (vp->v_type != VCHR) {
245 fix(de->de_atime);
246 vap->va_atime = de->de_atime;
247 fix(de->de_mtime);
248 vap->va_mtime = de->de_mtime;
249 fix(de->de_ctime);
250 vap->va_ctime = de->de_ctime;
251 } else {
252 dev = vp->v_rdev;
253 fix(dev->si_atime);
254 vap->va_atime = dev->si_atime;
255 fix(dev->si_mtime);
256 vap->va_mtime = dev->si_mtime;
257 fix(dev->si_ctime);
258 vap->va_ctime = dev->si_ctime;
259 vap->va_rdev = dev->si_udev;
260 }
261 vap->va_gen = 0;
262 vap->va_flags = 0;
263 vap->va_nlink = de->de_links;
264 vap->va_fileid = de->de_inode;
265
266 return (error);
267 }
268
269 static int
270 devfs_ioctl(ap)
271 struct vop_ioctl_args /* {
272 struct vnode *a_vp;
273 u_long a_command;
274 caddr_t a_data;
275 int a_fflag;
276 struct ucred *a_cred;
277 struct thread *a_td;
278 } */ *ap;
279 {
280 int error;
281 struct devfs_mount *dmp;
282
283 dmp = VFSTODEVFS(ap->a_vp->v_mount);
284 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
285 devfs_populate(dmp);
286 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
287 error = devfs_rules_ioctl(ap->a_vp->v_mount, ap->a_command, ap->a_data,
288 ap->a_td);
289 return (error);
290 }
291
292 static int
293 devfs_lookupx(ap)
294 struct vop_lookup_args /* {
295 struct vnode * a_dvp;
296 struct vnode ** a_vpp;
297 struct componentname * a_cnp;
298 } */ *ap;
299 {
300 struct componentname *cnp;
301 struct vnode *dvp, **vpp;
302 struct thread *td;
303 struct devfs_dirent *de, *dd;
304 struct devfs_dirent **dde;
305 struct devfs_mount *dmp;
306 struct cdev *cdev;
307 int error, flags, nameiop;
308 char specname[SPECNAMELEN + 1], *pname;
309
310 cnp = ap->a_cnp;
311 vpp = ap->a_vpp;
312 dvp = ap->a_dvp;
313 pname = cnp->cn_nameptr;
314 td = cnp->cn_thread;
315 flags = cnp->cn_flags;
316 nameiop = cnp->cn_nameiop;
317 dmp = VFSTODEVFS(dvp->v_mount);
318 dd = dvp->v_data;
319
320 *vpp = NULLVP;
321 cnp->cn_flags &= ~PDIRUNLOCK;
322
323 if ((flags & ISLASTCN) && nameiop == RENAME)
324 return (EOPNOTSUPP);
325
326 if (dvp->v_type != VDIR)
327 return (ENOTDIR);
328
329 if ((flags & ISDOTDOT) && (dvp->v_vflag & VV_ROOT))
330 return (EIO);
331
332 error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td);
333 if (error)
334 return (error);
335
336 if (cnp->cn_namelen == 1 && *pname == '.') {
337 if ((flags & ISLASTCN) && nameiop != LOOKUP)
338 return (EINVAL);
339 *vpp = dvp;
340 VREF(dvp);
341 return (0);
342 }
343
344 if (flags & ISDOTDOT) {
345 if ((flags & ISLASTCN) && nameiop != LOOKUP)
346 return (EINVAL);
347 VOP_UNLOCK(dvp, 0, td);
348 cnp->cn_flags |= PDIRUNLOCK;
349 de = TAILQ_FIRST(&dd->de_dlist); /* "." */
350 de = TAILQ_NEXT(de, de_list); /* ".." */
351 de = de->de_dir;
352 error = devfs_allocv(de, dvp->v_mount, vpp, td);
353 if (error || ((flags & LOCKPARENT) && (flags & ISLASTCN))) {
354 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td);
355 cnp->cn_flags &= ~PDIRUNLOCK;
356 }
357 return (error);
358 }
359
360 devfs_populate(dmp);
361 dd = dvp->v_data;
362 TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
363 if (cnp->cn_namelen != de->de_dirent->d_namlen)
364 continue;
365 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
366 de->de_dirent->d_namlen) != 0)
367 continue;
368 if (de->de_flags & DE_WHITEOUT)
369 goto notfound;
370 goto found;
371 }
372
373 if (nameiop == DELETE)
374 goto notfound;
375
376 /*
377 * OK, we didn't have an entry for the name we were asked for
378 * so we try to see if anybody can create it on demand.
379 */
380 pname = devfs_fqpn(specname, dvp, cnp);
381 if (pname == NULL)
382 goto notfound;
383
384 cdev = NULL;
385 EVENTHANDLER_INVOKE(dev_clone, pname, strlen(pname), &cdev);
386 if (cdev == NULL)
387 goto notfound;
388
389 devfs_populate(dmp);
390
391 dde = devfs_itode(dmp, cdev->si_inode);
392
393 if (dde == NULL || *dde == NULL || *dde == DE_DELETED)
394 goto notfound;
395
396 if ((*dde)->de_flags & DE_WHITEOUT)
397 goto notfound;
398
399 de = *dde;
400 goto found;
401
402 notfound:
403
404 if ((nameiop == CREATE || nameiop == RENAME) &&
405 (flags & (LOCKPARENT | WANTPARENT)) && (flags & ISLASTCN)) {
406 cnp->cn_flags |= SAVENAME;
407 if (!(flags & LOCKPARENT)) {
408 VOP_UNLOCK(dvp, 0, td);
409 cnp->cn_flags |= PDIRUNLOCK;
410 }
411 return (EJUSTRETURN);
412 }
413 return (ENOENT);
414
415
416 found:
417
418 if ((cnp->cn_nameiop == DELETE) && (flags & ISLASTCN)) {
419 error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred, td);
420 if (error)
421 return (error);
422 if (*vpp == dvp) {
423 VREF(dvp);
424 *vpp = dvp;
425 return (0);
426 }
427 error = devfs_allocv(de, dvp->v_mount, vpp, td);
428 if (error)
429 return (error);
430 if (!(flags & LOCKPARENT)) {
431 VOP_UNLOCK(dvp, 0, td);
432 cnp->cn_flags |= PDIRUNLOCK;
433 }
434 return (0);
435 }
436 error = devfs_allocv(de, dvp->v_mount, vpp, td);
437 if (error)
438 return (error);
439 if (!(flags & LOCKPARENT) || !(flags & ISLASTCN)) {
440 VOP_UNLOCK(dvp, 0, td);
441 cnp->cn_flags |= PDIRUNLOCK;
442 }
443 return (0);
444 }
445
446 static int
447 devfs_lookup(struct vop_lookup_args *ap)
448 {
449 int j;
450 struct devfs_mount *dmp;
451
452 dmp = VFSTODEVFS(ap->a_dvp->v_mount);
453 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
454 j = devfs_lookupx(ap);
455 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
456 return (j);
457 }
458
459 static int
460 devfs_mknod(struct vop_mknod_args *ap)
461 /*
462 struct vop_mknod_args {
463 struct vnodeop_desc *a_desc;
464 struct vnode *a_dvp;
465 struct vnode **a_vpp;
466 struct componentname *a_cnp;
467 struct vattr *a_vap;
468 };
469 */
470 {
471 struct componentname *cnp;
472 struct vnode *dvp, **vpp;
473 struct thread *td;
474 struct devfs_dirent *dd, *de;
475 struct devfs_mount *dmp;
476 int error;
477
478 /*
479 * The only type of node we should be creating here is a
480 * character device, for anything else return EOPNOTSUPP.
481 */
482 if (ap->a_vap->va_type != VCHR)
483 return (EOPNOTSUPP);
484 dvp = ap->a_dvp;
485 dmp = VFSTODEVFS(dvp->v_mount);
486 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
487
488 cnp = ap->a_cnp;
489 vpp = ap->a_vpp;
490 td = cnp->cn_thread;
491 dd = dvp->v_data;
492
493 error = ENOENT;
494 TAILQ_FOREACH(de, &dd->de_dlist, de_list) {
495 if (cnp->cn_namelen != de->de_dirent->d_namlen)
496 continue;
497 if (bcmp(cnp->cn_nameptr, de->de_dirent->d_name,
498 de->de_dirent->d_namlen) != 0)
499 continue;
500 if (de->de_flags & DE_WHITEOUT)
501 break;
502 goto notfound;
503 }
504 if (de == NULL)
505 goto notfound;
506 de->de_flags &= ~DE_WHITEOUT;
507 error = devfs_allocv(de, dvp->v_mount, vpp, td);
508 notfound:
509 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
510 return (error);
511 }
512
513
514 static int
515 devfs_pathconf(ap)
516 struct vop_pathconf_args /* {
517 struct vnode *a_vp;
518 int a_name;
519 int *a_retval;
520 } */ *ap;
521 {
522
523 switch (ap->a_name) {
524 case _PC_NAME_MAX:
525 *ap->a_retval = NAME_MAX;
526 return (0);
527 case _PC_PATH_MAX:
528 *ap->a_retval = PATH_MAX;
529 return (0);
530 case _PC_MAC_PRESENT:
531 #ifdef MAC
532 /*
533 * If MAC is enabled, devfs automatically supports
534 * trivial non-persistant label storage.
535 */
536 *ap->a_retval = 1;
537 #else
538 *ap->a_retval = 0;
539 #endif
540 return (0);
541 default:
542 return (vop_stdpathconf(ap));
543 }
544 /* NOTREACHED */
545 }
546
547 static int
548 devfs_read(ap)
549 struct vop_read_args /* {
550 struct vnode *a_vp;
551 struct uio *a_uio;
552 int a_ioflag;
553 struct ucred *a_cred;
554 } */ *ap;
555 {
556
557 if (ap->a_vp->v_type != VDIR)
558 return (EINVAL);
559 return (VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred, NULL, NULL, NULL));
560 }
561
562 static int
563 devfs_readdir(ap)
564 struct vop_readdir_args /* {
565 struct vnode *a_vp;
566 struct uio *a_uio;
567 struct ucred *a_cred;
568 int *a_eofflag;
569 int *a_ncookies;
570 u_long **a_cookies;
571 } */ *ap;
572 {
573 int error;
574 struct uio *uio;
575 struct dirent *dp;
576 struct devfs_dirent *dd;
577 struct devfs_dirent *de;
578 struct devfs_mount *dmp;
579 off_t off, oldoff;
580 int ncookies = 0;
581 u_long *cookiebuf, *cookiep;
582 struct dirent *dps, *dpe;
583
584 if (ap->a_vp->v_type != VDIR)
585 return (ENOTDIR);
586
587 uio = ap->a_uio;
588 if (uio->uio_offset < 0)
589 return (EINVAL);
590
591 dmp = VFSTODEVFS(ap->a_vp->v_mount);
592 lockmgr(&dmp->dm_lock, LK_SHARED, 0, curthread);
593 devfs_populate(dmp);
594 error = 0;
595 de = ap->a_vp->v_data;
596 off = 0;
597 oldoff = uio->uio_offset;
598 TAILQ_FOREACH(dd, &de->de_dlist, de_list) {
599 if (dd->de_flags & DE_WHITEOUT)
600 continue;
601 if (dd->de_dirent->d_type == DT_DIR)
602 de = dd->de_dir;
603 else
604 de = dd;
605 dp = dd->de_dirent;
606 if (dp->d_reclen > uio->uio_resid)
607 break;
608 dp->d_fileno = de->de_inode;
609 if (off >= uio->uio_offset) {
610 ncookies++;
611 error = uiomove(dp, dp->d_reclen, uio);
612 if (error)
613 break;
614 }
615 off += dp->d_reclen;
616 }
617 if( !error && ap->a_ncookies != NULL && ap->a_cookies != NULL ) {
618 MALLOC(cookiebuf, u_long *, ncookies * sizeof(u_long),
619 M_TEMP, M_WAITOK);
620 cookiep = cookiebuf;
621 dps = (struct dirent *)((char *)uio->uio_iov->iov_base -
622 (uio->uio_offset - oldoff));
623 dpe = (struct dirent *) uio->uio_iov->iov_base;
624 for( dp = dps;
625 dp < dpe;
626 dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
627 oldoff += dp->d_reclen;
628 *cookiep++ = (u_long) oldoff;
629 }
630 *ap->a_ncookies = ncookies;
631 *ap->a_cookies = cookiebuf;
632 }
633 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
634 uio->uio_offset = off;
635 return (error);
636 }
637
638 static int
639 devfs_readlink(ap)
640 struct vop_readlink_args /* {
641 struct vnode *a_vp;
642 struct uio *a_uio;
643 struct ucred *a_cead;
644 } */ *ap;
645 {
646 int error;
647 struct devfs_dirent *de;
648
649 de = ap->a_vp->v_data;
650 error = uiomove(de->de_symlink, strlen(de->de_symlink), ap->a_uio);
651 return (error);
652 }
653
654 static int
655 devfs_reclaim(ap)
656 struct vop_reclaim_args /* {
657 struct vnode *a_vp;
658 } */ *ap;
659 {
660 struct vnode *vp = ap->a_vp;
661 struct devfs_dirent *de;
662 int i;
663
664 de = vp->v_data;
665 if (de != NULL)
666 de->de_vnode = NULL;
667 vp->v_data = NULL;
668 if (vp->v_rdev != NULL && vp->v_rdev != NULL) {
669 i = vcount(vp);
670 if ((vp->v_rdev->si_flags & SI_CHEAPCLONE) && i == 0 &&
671 (vp->v_rdev->si_flags & SI_NAMED))
672 destroy_dev(vp->v_rdev);
673 }
674 return (0);
675 }
676
677 static int
678 devfs_remove(ap)
679 struct vop_remove_args /* {
680 struct vnode *a_dvp;
681 struct vnode *a_vp;
682 struct componentname *a_cnp;
683 } */ *ap;
684 {
685 struct vnode *vp = ap->a_vp;
686 struct devfs_dirent *dd;
687 struct devfs_dirent *de;
688 struct devfs_mount *dmp = VFSTODEVFS(vp->v_mount);
689
690 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, curthread);
691 dd = ap->a_dvp->v_data;
692 de = vp->v_data;
693 if (de->de_dirent->d_type == DT_LNK) {
694 TAILQ_REMOVE(&dd->de_dlist, de, de_list);
695 if (de->de_vnode)
696 de->de_vnode->v_data = NULL;
697 #ifdef MAC
698 mac_destroy_devfsdirent(de);
699 #endif
700 FREE(de, M_DEVFS);
701 } else {
702 de->de_flags |= DE_WHITEOUT;
703 }
704 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, curthread);
705 return (0);
706 }
707
708 /*
709 * Revoke is called on a tty when a terminal session ends. The vnode
710 * is orphaned by setting v_op to deadfs so we need to let go of it
711 * as well so that we create a new one next time around.
712 */
713 static int
714 devfs_revoke(ap)
715 struct vop_revoke_args /* {
716 struct vnode *a_vp;
717 int a_flags;
718 } */ *ap;
719 {
720 struct vnode *vp = ap->a_vp;
721 struct devfs_dirent *de;
722
723 de = vp->v_data;
724 de->de_vnode = NULL;
725 vop_revoke(ap);
726 return (0);
727 }
728
729 static int
730 devfs_setattr(ap)
731 struct vop_setattr_args /* {
732 struct vnode *a_vp;
733 struct vattr *a_vap;
734 struct ucred *a_cred;
735 struct proc *a_p;
736 } */ *ap;
737 {
738 struct devfs_dirent *de;
739 struct vattr *vap;
740 struct vnode *vp;
741 int c, error;
742 uid_t uid;
743 gid_t gid;
744
745 vap = ap->a_vap;
746 vp = ap->a_vp;
747 if ((vap->va_type != VNON) ||
748 (vap->va_nlink != VNOVAL) ||
749 (vap->va_fsid != VNOVAL) ||
750 (vap->va_fileid != VNOVAL) ||
751 (vap->va_blocksize != VNOVAL) ||
752 (vap->va_flags != VNOVAL && vap->va_flags != 0) ||
753 (vap->va_rdev != VNOVAL) ||
754 ((int)vap->va_bytes != VNOVAL) ||
755 (vap->va_gen != VNOVAL)) {
756 return (EINVAL);
757 }
758
759 de = vp->v_data;
760 if (vp->v_type == VDIR)
761 de = de->de_dir;
762
763 error = c = 0;
764 if (vap->va_uid == (uid_t)VNOVAL)
765 uid = de->de_uid;
766 else
767 uid = vap->va_uid;
768 if (vap->va_gid == (gid_t)VNOVAL)
769 gid = de->de_gid;
770 else
771 gid = vap->va_gid;
772 if (uid != de->de_uid || gid != de->de_gid) {
773 if (((ap->a_cred->cr_uid != de->de_uid) || uid != de->de_uid ||
774 (gid != de->de_gid && !groupmember(gid, ap->a_cred))) &&
775 (error = suser_cred(ap->a_td->td_ucred, SUSER_ALLOWJAIL)) != 0)
776 return (error);
777 de->de_uid = uid;
778 de->de_gid = gid;
779 c = 1;
780 }
781
782 if (vap->va_mode != (mode_t)VNOVAL) {
783 if ((ap->a_cred->cr_uid != de->de_uid) &&
784 (error = suser_cred(ap->a_td->td_ucred, SUSER_ALLOWJAIL)))
785 return (error);
786 de->de_mode = vap->va_mode;
787 c = 1;
788 }
789
790 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
791 /* See the comment in ufs_vnops::ufs_setattr(). */
792 if ((error = VOP_ACCESS(vp, VADMIN, ap->a_cred, ap->a_td)) &&
793 ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
794 (error = VOP_ACCESS(vp, VWRITE, ap->a_cred, ap->a_td))))
795 return (error);
796 if (vap->va_atime.tv_sec != VNOVAL) {
797 if (vp->v_type == VCHR)
798 vp->v_rdev->si_atime = vap->va_atime;
799 else
800 de->de_atime = vap->va_atime;
801 }
802 if (vap->va_mtime.tv_sec != VNOVAL) {
803 if (vp->v_type == VCHR)
804 vp->v_rdev->si_mtime = vap->va_mtime;
805 else
806 de->de_mtime = vap->va_mtime;
807 }
808 c = 1;
809 }
810
811 if (c) {
812 if (vp->v_type == VCHR)
813 vfs_timestamp(&vp->v_rdev->si_ctime);
814 else
815 vfs_timestamp(&de->de_mtime);
816 }
817 return (0);
818 }
819
820 #ifdef MAC
821 static int
822 devfs_setlabel(ap)
823 struct vop_setlabel_args /* {
824 struct vnode *a_vp;
825 struct mac *a_label;
826 struct ucred *a_cred;
827 struct thread *a_td;
828 } */ *ap;
829 {
830 struct vnode *vp;
831 struct devfs_dirent *de;
832
833 vp = ap->a_vp;
834 de = vp->v_data;
835
836 mac_relabel_vnode(ap->a_cred, vp, ap->a_label);
837 mac_update_devfsdirent(vp->v_mount, de, vp);
838
839 return (0);
840 }
841 #endif
842
843 static int
844 devfs_symlink(ap)
845 struct vop_symlink_args /* {
846 struct vnode *a_dvp;
847 struct vnode **a_vpp;
848 struct componentname *a_cnp;
849 struct vattr *a_vap;
850 char *a_target;
851 } */ *ap;
852 {
853 int i, error;
854 struct devfs_dirent *dd;
855 struct devfs_dirent *de;
856 struct devfs_mount *dmp;
857 struct thread *td;
858
859 td = ap->a_cnp->cn_thread;
860 KASSERT(td == curthread, ("devfs_symlink: td != curthread"));
861 error = suser(td);
862 if (error)
863 return(error);
864 dmp = VFSTODEVFS(ap->a_dvp->v_mount);
865 dd = ap->a_dvp->v_data;
866 de = devfs_newdirent(ap->a_cnp->cn_nameptr, ap->a_cnp->cn_namelen);
867 de->de_uid = 0;
868 de->de_gid = 0;
869 de->de_mode = 0755;
870 de->de_inode = dmp->dm_inode++;
871 de->de_dirent->d_type = DT_LNK;
872 i = strlen(ap->a_target) + 1;
873 MALLOC(de->de_symlink, char *, i, M_DEVFS, M_WAITOK);
874 bcopy(ap->a_target, de->de_symlink, i);
875 lockmgr(&dmp->dm_lock, LK_EXCLUSIVE, 0, td);
876 #ifdef MAC
877 mac_create_devfs_symlink(ap->a_cnp->cn_cred, dmp->dm_mount, dd, de);
878 #endif
879 TAILQ_INSERT_TAIL(&dd->de_dlist, de, de_list);
880 devfs_allocv(de, ap->a_dvp->v_mount, ap->a_vpp, td);
881 lockmgr(&dmp->dm_lock, LK_RELEASE, 0, td);
882 return (0);
883 }
884
885 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
886 { &vop_default_desc, (vop_t *) vop_defaultop },
887 { &vop_access_desc, (vop_t *) devfs_access },
888 { &vop_getattr_desc, (vop_t *) devfs_getattr },
889 { &vop_ioctl_desc, (vop_t *) devfs_ioctl },
890 { &vop_lookup_desc, (vop_t *) devfs_lookup },
891 { &vop_mknod_desc, (vop_t *) devfs_mknod },
892 { &vop_pathconf_desc, (vop_t *) devfs_pathconf },
893 { &vop_read_desc, (vop_t *) devfs_read },
894 { &vop_readdir_desc, (vop_t *) devfs_readdir },
895 { &vop_readlink_desc, (vop_t *) devfs_readlink },
896 { &vop_reclaim_desc, (vop_t *) devfs_reclaim },
897 { &vop_remove_desc, (vop_t *) devfs_remove },
898 { &vop_revoke_desc, (vop_t *) devfs_revoke },
899 { &vop_setattr_desc, (vop_t *) devfs_setattr },
900 #ifdef MAC
901 { &vop_setlabel_desc, (vop_t *) devfs_setlabel },
902 #endif
903 { &vop_symlink_desc, (vop_t *) devfs_symlink },
904 { NULL, NULL }
905 };
906 static struct vnodeopv_desc devfs_vnodeop_opv_desc =
907 { &devfs_vnodeop_p, devfs_vnodeop_entries };
908
909 VNODEOP_SET(devfs_vnodeop_opv_desc);
910
911 static struct vnodeopv_entry_desc devfs_specop_entries[] = {
912 { &vop_default_desc, (vop_t *) spec_vnoperate },
913 { &vop_access_desc, (vop_t *) devfs_access },
914 { &vop_getattr_desc, (vop_t *) devfs_getattr },
915 { &vop_pathconf_desc, (vop_t *) devfs_pathconf },
916 { &vop_reclaim_desc, (vop_t *) devfs_reclaim },
917 { &vop_remove_desc, (vop_t *) devfs_remove },
918 { &vop_revoke_desc, (vop_t *) devfs_revoke },
919 { &vop_setattr_desc, (vop_t *) devfs_setattr },
920 #ifdef MAC
921 { &vop_setlabel_desc, (vop_t *) devfs_setlabel },
922 #endif
923 { NULL, NULL }
924 };
925 static struct vnodeopv_desc devfs_specop_opv_desc =
926 { &devfs_specop_p, devfs_specop_entries };
927
928 VNODEOP_SET(devfs_specop_opv_desc);
Cache object: 5c55f4eeb1cbdfd3472993c0ee7cc695
|