Deleted Added
full compact
devfs_vnops.c (111119) devfs_vnops.c (111741)
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);