|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Copyright 1997,1998 Julian Elischer. All rights reserved.
24: * [email protected]
25: *
26: * Redistribution and use in source and binary forms, with or without
27: * modification, are permitted provided that the following conditions are
28: * met:
29: * 1. Redistributions of source code must retain the above copyright
30: * notice, this list of conditions and the following disclaimer.
31: * 2. Redistributions in binary form must reproduce the above copyright notice,
32: * this list of conditions and the following disclaimer in the documentation
33: * and/or other materials provided with the distribution.
34: *
35: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
36: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
37: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38: * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR
39: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
42: * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45: * SUCH DAMAGE.
46: *
47: * devfs_vnops.c
48: */
49:
50: /*
51: * HISTORY
52: * Clark Warner ([email protected]) Tue Feb 10 2000
53: * - Added err_copyfile to the vnode operations table
54: * Dieter Siegmund ([email protected]) Thu Apr 8 14:08:19 PDT 1999
55: * - instead of duplicating specfs here, created a vnode-ops table
56: * that redirects most operations to specfs (as is done with ufs);
57: * - removed routines that made no sense
58: * - cleaned up reclaim: replaced devfs_vntodn() with a macro VTODN()
59: * - cleaned up symlink, link locking
60: * - added the devfs_lock to protect devfs data structures against
61: * driver's calling devfs_add_devswf()/etc.
62: * Dieter Siegmund ([email protected]) Wed Jul 14 13:37:59 PDT 1999
63: * - free the devfs devnode in devfs_inactive(), not just in devfs_reclaim()
64: * to free up kernel memory as soon as it's available
65: * - got rid of devfsspec_{read, write}
66: * Dieter Siegmund ([email protected]) Fri Sep 17 09:58:38 PDT 1999
67: * - update the mod/access times
68: */
69:
70: #include <sys/param.h>
71: #include <sys/systm.h>
72: #include <sys/buf.h>
73: #include <sys/namei.h>
74: #include <sys/kernel.h>
75: #include <sys/fcntl.h>
76: #include <sys/conf.h>
77: #include <sys/disklabel.h>
78: #include <sys/lock.h>
79: #include <sys/stat.h>
80: #include <sys/mount.h>
81: #include <sys/proc.h>
82: #include <sys/time.h>
83: #include <sys/vnode.h>
84: #include <miscfs/specfs/specdev.h>
85: #include <sys/dirent.h>
86: #include <sys/vmmeter.h>
87: #include <sys/vm.h>
88:
89: #include "devfsdefs.h"
90:
91: /*
92: * Convert a component of a pathname into a pointer to a locked node.
93: * This is a very central and rather complicated routine.
94: * If the file system is not maintained in a strict tree hierarchy,
95: * this can result in a deadlock situation (see comments in code below).
96: *
97: * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
98: * whether the name is to be looked up, created, renamed, or deleted.
99: * When CREATE, RENAME, or DELETE is specified, information usable in
100: * creating, renaming, or deleting a directory entry may be calculated.
101: * If flag has LOCKPARENT or'ed into it and the target of the pathname
102: * exists, lookup returns both the target and its parent directory locked.
103: * When creating or renaming and LOCKPARENT is specified, the target may
104: * not be ".". When deleting and LOCKPARENT is specified, the target may
105: * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK
106: * instead of two DNUNLOCKs.
107: *
108: * Overall outline of devfs_lookup:
109: *
110: * check accessibility of directory
111: * null terminate the component (lookup leaves the whole string alone)
112: * look for name in cache, if found, then if at end of path
113: * and deleting or creating, drop it, else return name
114: * search for name in directory, to found or notfound
115: * notfound:
116: * if creating, return locked directory,
117: * else return error
118: * found:
119: * if at end of path and deleting, return information to allow delete
120: * if at end of path and rewriting (RENAME and LOCKPARENT), lock target
121: * node and return info to allow rewrite
122: * if not at end, add name to cache; if at end and neither creating
123: * nor deleting, add name to cache
124: * On return to lookup, remove the null termination we put in at the start.
125: *
126: * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked.
127: */
128: static int
129: devfs_lookup(struct vop_lookup_args *ap)
130: /*struct vop_lookup_args {
131: struct vnode * a_dvp; directory vnode ptr
132: struct vnode ** a_vpp; where to put the result
133: struct componentname * a_cnp; the name we want
134: };*/
135: {
136: struct componentname *cnp = ap->a_cnp;
137: struct vnode *dir_vnode = ap->a_dvp;
138: struct vnode **result_vnode = ap->a_vpp;
139: devnode_t * dir_node; /* the directory we are searching */
140: devnode_t * node = NULL; /* the node we are searching for */
141: devdirent_t * nodename;
142: int flags = cnp->cn_flags;
143: int op = cnp->cn_nameiop; /* LOOKUP, CREATE, RENAME, or DELETE */
144: int lockparent = flags & LOCKPARENT;
145: int wantparent = flags & (LOCKPARENT|WANTPARENT);
146: int error = 0;
147: struct proc *p = cnp->cn_proc;
148: char heldchar; /* the char at the end of the name componet */
149:
150: *result_vnode = NULL; /* safe not sorry */ /*XXX*/
151:
152: if (dir_vnode->v_usecount == 0)
153: printf("devfs_lookup: dir had no refs ");
154: dir_node = VTODN(dir_vnode);
155:
156: /*
157: * Check accessiblity of directory.
158: */
159: if (dir_node->dn_type != DEV_DIR) {
160: return (ENOTDIR);
161: }
162:
163: if ((error = VOP_ACCESS(dir_vnode, VEXEC, cnp->cn_cred, p)) != 0) {
164: return (error);
165: }
166:
167: /* temporarily terminate string component */
168: heldchar = cnp->cn_nameptr[cnp->cn_namelen];
169: cnp->cn_nameptr[cnp->cn_namelen] = '\0';
170: DEVFS_LOCK(p);
171: nodename = dev_findname(dir_node,cnp->cn_nameptr);
172: if (nodename) {
173: /* entry exists */
174: node = nodename->de_dnp;
175: node->dn_last_lookup = nodename; /* for unlink */
176: /* Do potential vnode allocation here inside the lock
177: * to make sure that our device node has a non-NULL dn_vn
178: * associated with it. The device node might otherwise
179: * get deleted out from under us (see devfs_dn_free()).
180: */
181: error = devfs_dntovn(node, result_vnode, p);
182: }
183: DEVFS_UNLOCK(p);
184: /* restore saved character */
185: cnp->cn_nameptr[cnp->cn_namelen] = heldchar;
186:
187: if (error)
188: return (error);
189:
190: if (!nodename) { /* no entry */
191: /* If it doesn't exist and we're not the last component,
192: * or we're at the last component, but we're not creating
193: * or renaming, return ENOENT.
194: */
195: if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) {
196: return ENOENT;
197: }
198: /*
199: * Access for write is interpreted as allowing
200: * creation of files in the directory.
201: */
202: if ((error = VOP_ACCESS(dir_vnode, VWRITE,
203: cnp->cn_cred, p)) != 0)
204: {
205: return (error);
206: }
207: /*
208: * We return with the directory locked, so that
209: * the parameters we set up above will still be
210: * valid if we actually decide to add a new entry.
211: * We return ni_vp == NULL to indicate that the entry
212: * does not currently exist; we leave a pointer to
213: * the (locked) directory vnode in namei_data->ni_dvp.
214: * The pathname buffer is saved so that the name
215: * can be obtained later.
216: *
217: * NB - if the directory is unlocked, then this
218: * information cannot be used.
219: */
220: cnp->cn_flags |= SAVENAME;
221: if (!lockparent)
222: VOP_UNLOCK(dir_vnode, 0, p);
223: return (EJUSTRETURN);
224: }
225:
226: /*
227: * If deleting, and at end of pathname, return
228: * parameters which can be used to remove file.
229: * If the wantparent flag isn't set, we return only
230: * the directory (in namei_data->ni_dvp), otherwise we go
231: * on and lock the node, being careful with ".".
232: */
233: if (op == DELETE && (flags & ISLASTCN)) {
234: /*
235: * Write access to directory required to delete files.
236: */
237: if ((error = VOP_ACCESS(dir_vnode, VWRITE,
238: cnp->cn_cred, p)) != 0)
239: return (error);
240: /*
241: * we are trying to delete '.'. What does this mean? XXX
242: */
243: if (dir_node == node) {
244: VREF(dir_vnode);
245: *result_vnode = dir_vnode;
246: return (0);
247: }
248: #ifdef NOTYET
249: /*
250: * If directory is "sticky", then user must own
251: * the directory, or the file in it, else she
252: * may not delete it (unless she's root). This
253: * implements append-only directories.
254: */
255: if ((dir_node->mode & ISVTX) &&
256: cnp->cn_cred->cr_uid != 0 &&
257: cnp->cn_cred->cr_uid != dir_node->uid &&
258: cnp->cn_cred->cr_uid != node->uid) {
259: VOP_UNLOCK(*result_vnode, 0, p);
260: return (EPERM);
261: }
262: #endif
263: if (!lockparent)
264: VOP_UNLOCK(dir_vnode, 0, p);
265: return (0);
266: }
267:
268: /*
269: * If rewriting (RENAME), return the vnode and the
270: * information required to rewrite the present directory
271: * Must get node of directory entry to verify it's a
272: * regular file, or empty directory.
273: */
274: if (op == RENAME && wantparent && (flags & ISLASTCN)) {
275: /*
276: * Are we allowed to change the holding directory?
277: */
278: if ((error = VOP_ACCESS(dir_vnode, VWRITE,
279: cnp->cn_cred, p)) != 0)
280: return (error);
281: /*
282: * Careful about locking second node.
283: * This can only occur if the target is ".".
284: */
285: if (dir_node == node)
286: return (EISDIR);
287: /* hmm save the 'from' name (we need to delete it) */
288: cnp->cn_flags |= SAVENAME;
289: if (!lockparent)
290: VOP_UNLOCK(dir_vnode, 0, p);
291: return (0);
292: }
293:
294: /*
295: * Step through the translation in the name. We do not unlock the
296: * directory because we may need it again if a symbolic link
297: * is relative to the current directory. Instead we save it
298: * unlocked as "saved_dir_node" XXX. We must get the target
299: * node before unlocking
300: * the directory to insure that the node will not be removed
301: * before we get it. We prevent deadlock by always fetching
302: * nodes from the root, moving down the directory tree. Thus
303: * when following backward pointers ".." we must unlock the
304: * parent directory before getting the requested directory.
305: * There is a potential race condition here if both the current
306: * and parent directories are removed before the lock for the
307: * node associated with ".." returns. We hope that this occurs
308: * infrequently since we cannot avoid this race condition without
309: * implementing a sophisticated deadlock detection algorithm.
310: * Note also that this simple deadlock detection scheme will not
311: * work if the file system has any hard links other than ".."
312: * that point backwards in the directory structure.
313: */
314: if (flags & ISDOTDOT) {
315: VOP_UNLOCK(dir_vnode, 0, p); /* race to get the node */
316: if (lockparent && (flags & ISLASTCN))
317: vn_lock(dir_vnode, LK_EXCLUSIVE | LK_RETRY, p);
318: } else if (dir_node == node) {
319: #if 0
320: /*
321: * this next statement is wrong: we already did a vget in
322: * devfs_dntovn(); DWS 4/16/1999
323: */
324: VREF(dir_vnode); /* we want ourself, ie "." */
325: #endif
326: *result_vnode = dir_vnode;
327: } else {
328: if (!lockparent || (flags & ISLASTCN))
329: VOP_UNLOCK(dir_vnode, 0, p);
330: }
331:
332: return (0);
333: }
334:
335: static int
336: devfs_access(struct vop_access_args *ap)
337: /*struct vop_access_args {
338: struct vnode *a_vp;
339: int a_mode;
340: struct ucred *a_cred;
341: struct proc *a_p;
342: } */
343: {
344: /*
345: * mode is filled with a combination of VREAD, VWRITE,
346: * and/or VEXEC bits turned on. In an octal number these
347: * are the Y in 0Y00.
348: */
349: struct vnode *vp = ap->a_vp;
350: int mode = ap->a_mode;
351: struct ucred *cred = ap->a_cred;
352: devnode_t * file_node;
353: gid_t *gp;
354: int i;
355: struct proc *p = ap->a_p;
356:
357: file_node = VTODN(vp);
358: /*
359: * if we are not running as a process, we are in the
360: * kernel and we DO have permission
361: */
362: if (p == NULL)
363: return 0;
364:
365: /*
366: * Access check is based on only one of owner, group, public.
367: * If not owner, then check group. If not a member of the
368: * group, then check public access.
369: */
370: if (cred->cr_uid != file_node->dn_uid)
371: {
372: /* failing that.. try groups */
373: mode >>= 3;
374: gp = cred->cr_groups;
375: for (i = 0; i < cred->cr_ngroups; i++, gp++)
376: {
377: if (file_node->dn_gid == *gp)
378: {
379: goto found;
380: }
381: }
382: /* failing that.. try general access */
383: mode >>= 3;
384: found:
385: ;
386: }
387: if ((file_node->dn_mode & mode) == mode)
388: return (0);
389: /*
390: * Root gets to do anything.
391: * but only use suser prives as a last resort
392: * (Use of super powers is recorded in ap->a_p->p_acflag)
393: */
394: if( suser(cred, &ap->a_p->p_acflag) == 0) /* XXX what if no proc? */
395: return 0;
396: return (EACCES);
397: }
398:
399: static int
400: devfs_getattr(struct vop_getattr_args *ap)
401: /*struct vop_getattr_args {
402: struct vnode *a_vp;
403: struct vattr *a_vap;
404: struct ucred *a_cred;
405: struct proc *a_p;
406: } */
407: {
408: struct vnode *vp = ap->a_vp;
409: struct vattr *vap = ap->a_vap;
410: devnode_t * file_node;
411: struct timeval tv;
412:
413: file_node = VTODN(vp);
414: tv = time;
415: dn_times(file_node, tv, tv);
416: vap->va_rdev = 0;/* default value only */
417: vap->va_mode = file_node->dn_mode;
418: switch (file_node->dn_type)
419: {
420: case DEV_DIR:
421: vap->va_rdev = (dev_t)file_node->dn_dvm;
422: vap->va_mode |= (S_IFDIR);
423: break;
424: case DEV_CDEV:
425: vap->va_rdev = file_node->dn_typeinfo.dev;
426: vap->va_mode |= (S_IFCHR);
427: break;
428: case DEV_BDEV:
429: vap->va_rdev = file_node->dn_typeinfo.dev;
430: vap->va_mode |= (S_IFBLK);
431: break;
432: case DEV_SLNK:
433: vap->va_mode |= (S_IFLNK);
434: break;
435: }
436: vap->va_type = vp->v_type;
437: vap->va_nlink = file_node->dn_links;
438: vap->va_uid = file_node->dn_uid;
439: vap->va_gid = file_node->dn_gid;
440: vap->va_fsid = (int32_t)(void *)file_node->dn_dvm;
441: vap->va_fileid = (int32_t)(void *)file_node;
442: vap->va_size = file_node->dn_len; /* now a u_quad_t */
443: /* this doesn't belong here */
444: if (vp->v_type == VBLK)
445: vap->va_blocksize = BLKDEV_IOSIZE;
446: else if (vp->v_type == VCHR)
447: vap->va_blocksize = MAXPHYSIO;
448: else
449: vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
450: /* if the time is bogus, set it to the boot time */
451: if (file_node->dn_ctime.tv_sec == 0)
452: file_node->dn_ctime.tv_sec = boottime.tv_sec;
453: if (file_node->dn_mtime.tv_sec == 0)
454: file_node->dn_mtime.tv_sec = boottime.tv_sec;
455: if (file_node->dn_atime.tv_sec == 0)
456: file_node->dn_atime.tv_sec = boottime.tv_sec;
457: vap->va_ctime = file_node->dn_ctime;
458: vap->va_mtime = file_node->dn_mtime;
459: vap->va_atime = file_node->dn_atime;
460: vap->va_gen = 0;
461: vap->va_flags = 0;
462: vap->va_bytes = file_node->dn_len; /* u_quad_t */
463: vap->va_filerev = 0; /* XXX */ /* u_quad_t */
464: vap->va_vaflags = 0; /* XXX */
465: return 0;
466: }
467:
468: static int
469: devfs_setattr(struct vop_setattr_args *ap)
470: /*struct vop_setattr_args {
471: struct vnode *a_vp;
472: struct vattr *a_vap;
473: struct ucred *a_cred;
474: struct proc *a_p;
475: } */
476: {
477: struct vnode *vp = ap->a_vp;
478: struct vattr *vap = ap->a_vap;
479: struct ucred *cred = ap->a_cred;
480: struct proc *p = ap->a_p;
481: int error = 0;
482: gid_t *gp;
483: int i;
484: devnode_t * file_node;
485: struct timeval atimeval, mtimeval;
486:
487: if (vap->va_flags != VNOVAL) /* XXX needs to be implemented */
488: return (EOPNOTSUPP);
489:
490: file_node = VTODN(vp);
491:
492: if ((vap->va_type != VNON) ||
493: (vap->va_nlink != VNOVAL) ||
494: (vap->va_fsid != VNOVAL) ||
495: (vap->va_fileid != VNOVAL) ||
496: (vap->va_blocksize != VNOVAL) ||
497: (vap->va_rdev != VNOVAL) ||
498: (vap->va_bytes != VNOVAL) ||
499: (vap->va_gen != VNOVAL ))
500: {
501: return EINVAL;
502: }
503:
504: /*
505: * Go through the fields and update iff not VNOVAL.
506: */
507: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
508: if (cred->cr_uid != file_node->dn_uid &&
509: (error = suser(cred, &p->p_acflag)) &&
510: ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
511: (error = VOP_ACCESS(vp, VWRITE, cred, p))))
512: return (error);
513: if (vap->va_atime.tv_sec != VNOVAL)
514: file_node->dn_flags |= DN_ACCESS;
515: if (vap->va_mtime.tv_sec != VNOVAL)
516: file_node->dn_flags |= DN_CHANGE | DN_UPDATE;
517: atimeval.tv_sec = vap->va_atime.tv_sec;
518: atimeval.tv_usec = vap->va_atime.tv_nsec / 1000;
519: mtimeval.tv_sec = vap->va_mtime.tv_sec;
520: mtimeval.tv_usec = vap->va_mtime.tv_nsec / 1000;
521: if (error = VOP_UPDATE(vp, &atimeval, &mtimeval, 1))
522: return (error);
523: }
524:
525: /*
526: * Change the permissions.. must be root or owner to do this.
527: */
528: if (vap->va_mode != (u_short)VNOVAL) {
529: if ((cred->cr_uid != file_node->dn_uid)
530: && (error = suser(cred, &p->p_acflag)))
531: return (error);
532: file_node->dn_mode &= ~07777;
533: file_node->dn_mode |= vap->va_mode & 07777;
534: }
535:
536: /*
537: * Change the owner.. must be root to do this.
538: */
539: if (vap->va_uid != (uid_t)VNOVAL) {
540: if (error = suser(cred, &p->p_acflag))
541: return (error);
542: file_node->dn_uid = vap->va_uid;
543: }
544:
545: /*
546: * Change the group.. must be root or owner to do this.
547: * If we are the owner, we must be in the target group too.
548: * don't use suser() unless you have to as it reports
549: * whether you needed suser powers or not.
550: */
551: if (vap->va_gid != (gid_t)VNOVAL) {
552: if (cred->cr_uid == file_node->dn_uid){
553: gp = cred->cr_groups;
554: for (i = 0; i < cred->cr_ngroups; i++, gp++) {
555: if (vap->va_gid == *gp)
556: goto cando;
557: }
558: }
559: /*
560: * we can't do it with normal privs,
561: * do we have an ace up our sleeve?
562: */
563: if (error = suser(cred, &p->p_acflag))
564: return (error);
565: cando:
566: file_node->dn_gid = vap->va_gid;
567: }
568: #if 0
569: /*
570: * Copied from somewhere else
571: * but only kept as a marker and reminder of the fact that
572: * flags should be handled some day
573: */
574: if (vap->va_flags != VNOVAL) {
575: if (error = suser(cred, &p->p_acflag))
576: return error;
577: if (cred->cr_uid == 0)
578: ;
579: else {
580: }
581: }
582: #endif
583: return error;
584: }
585:
586: static int
587: devfs_read(struct vop_read_args *ap)
588: /*struct vop_read_args {
589: struct vnode *a_vp;
590: struct uio *a_uio;
591: int a_ioflag;
592: struct ucred *a_cred;
593: } */
594: {
595: devnode_t * dn_p = VTODN(ap->a_vp);
596:
597: switch (ap->a_vp->v_type) {
598: case VDIR: {
599: dn_p->dn_flags |= DN_ACCESS;
600: return VOP_READDIR(ap->a_vp, ap->a_uio, ap->a_cred,
601: NULL, NULL, NULL);
602: }
603: default: {
604: printf("devfs_read(): bad file type %d", ap->a_vp->v_type);
605: return(EINVAL);
606: break;
607: }
608: }
609: return (0); /* not reached */
610: }
611:
612: static int
613: devfs_close(ap)
614: struct vop_close_args /* {
615: struct vnode *a_vp;
616: int a_fflag;
617: struct ucred *a_cred;
618: struct proc *a_p;
619: } */ *ap;
620: {
621: struct vnode * vp = ap->a_vp;
622: register devnode_t * dnp = VTODN(vp);
623:
624: simple_lock(&vp->v_interlock);
625: if (vp->v_usecount > 1)
626: dn_times(dnp, time, time);
627: simple_unlock(&vp->v_interlock);
628: return (0);
629: }
630:
631: static int
632: devfsspec_close(ap)
633: struct vop_close_args /* {
634: struct vnode *a_vp;
635: int a_fflag;
636: struct ucred *a_cred;
637: struct proc *a_p;
638: } */ *ap;
639: {
640: struct vnode * vp = ap->a_vp;
641: register devnode_t * dnp = VTODN(vp);
642:
643: simple_lock(&vp->v_interlock);
644: if (vp->v_usecount > 1)
645: dn_times(dnp, time, time);
646: simple_unlock(&vp->v_interlock);
647: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
648: }
649:
650: static int
651: devfsspec_read(struct vop_read_args *ap)
652: /*struct vop_read_args {
653: struct vnode *a_vp;
654: struct uio *a_uio;
655: int a_ioflag;
656: struct ucred *a_cred;
657: } */
658: {
659: VTODN(ap->a_vp)->dn_flags |= DN_ACCESS;
660: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
661: }
662:
663: static int
664: devfsspec_write(struct vop_write_args *ap)
665: /*struct vop_write_args {
666: struct vnode *a_vp;
667: struct uio *a_uio;
668: int a_ioflag;
669: struct ucred *a_cred;
670: } */
671: {
672: VTODN(ap->a_vp)->dn_flags |= DN_CHANGE | DN_UPDATE;
673: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
674: }
675:
676: /*
677: * Write data to a file or directory.
678: */
679: static int
680: devfs_write(struct vop_write_args *ap)
681: /*struct vop_write_args {
682: struct vnode *a_vp;
683: struct uio *a_uio;
684: int a_ioflag;
685: struct ucred *a_cred;
686: } */
687: {
688: switch (ap->a_vp->v_type) {
689: case VDIR:
690: return(EISDIR);
691: default:
692: printf("devfs_write(): bad file type %d", ap->a_vp->v_type);
693: return (EINVAL);
694: }
695: return 0; /* not reached */
696: }
697:
698: static int
699: devfs_remove(struct vop_remove_args *ap)
700: /*struct vop_remove_args {
701: struct vnode *a_dvp;
702: struct vnode *a_vp;
703: struct componentname *a_cnp;
704: } */
705: {
706: struct vnode *vp = ap->a_vp;
707: struct vnode *dvp = ap->a_dvp;
708: struct componentname *cnp = ap->a_cnp;
709: devnode_t * tp;
710: devnode_t * tdp;
711: devdirent_t * tnp;
712: int doingdirectory = 0;
713: int error = 0;
714: uid_t ouruid = cnp->cn_cred->cr_uid;
715: struct proc *p = cnp->cn_proc;
716:
717: /*
718: * Lock our directories and get our name pointers
719: * assume that the names are null terminated as they
720: * are the end of the path. Get pointers to all our
721: * devfs structures.
722: */
723: tp = VTODN(vp);
724: tdp = VTODN(dvp);
725: /*
726: * Assuming we are atomic, dev_lookup left this for us
727: */
728: tnp = tp->dn_last_lookup;
729:
730: /*
731: * Check we are doing legal things WRT the new flags
732: */
733: if ((tp->dn_flags & (IMMUTABLE | APPEND))
734: || (tdp->dn_flags & APPEND) /*XXX eh?*/ ) {
735: error = EPERM;
736: goto abort;
737: }
738:
739: /*
740: * Make sure that we don't try do something stupid
741: */
742: if ((tp->dn_type) == DEV_DIR) {
743: /*
744: * Avoid ".", "..", and aliases of "." for obvious reasons.
745: */
746: if ( (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')
747: || (cnp->cn_flags&ISDOTDOT) ) {
748: error = EINVAL;
749: goto abort;
750: }
751: doingdirectory++;
752: }
753:
754: /***********************************
755: * Start actually doing things.... *
756: ***********************************/
757: tdp->dn_flags |= DN_CHANGE | DN_UPDATE;
758:
759: /*
760: * own the parent directory, or the destination of the rename,
761: * otherwise the destination may not be changed (except by
762: * root). This implements append-only directories.
763: * XXX shoudn't this be in generic code?
764: */
765: if ((tdp->dn_mode & S_ISTXT)
766: && ouruid != 0
767: && ouruid != tdp->dn_uid
768: && ouruid != tp->dn_uid ) {
769: error = EPERM;
770: goto abort;
771: }
772: /*
773: * Target must be empty if a directory and have no links
774: * to it. Also, ensure source and target are compatible
775: * (both directories, or both not directories).
776: */
777: if (( doingdirectory) && (tp->dn_links > 2)) {
778: error = ENOTEMPTY;
779: goto abort;
780: }
781: DEVFS_LOCK(p);
782: dev_free_name(tnp);
783: DEVFS_UNLOCK(p);
784: abort:
785: if (dvp == vp)
786: vrele(vp);
787: else
788: vput(vp);
789: vput(dvp);
790: return (error);
791: }
792:
793: /*
794: */
795: static int
796: devfs_link(struct vop_link_args *ap)
797: /*struct vop_link_args {
798: struct vnode *a_tdvp;
799: struct vnode *a_vp;
800: struct componentname *a_cnp;
801: } */
802: {
803: struct vnode *vp = ap->a_vp;
804: struct vnode *tdvp = ap->a_tdvp;
805: struct componentname *cnp = ap->a_cnp;
806: struct proc *p = cnp->cn_proc;
807: devnode_t * fp;
808: devnode_t * tdp;
809: devdirent_t * tnp;
810: int error = 0;
811: struct timeval tv;
812:
813: /*
814: * First catch an arbitrary restriction for this FS
815: */
816: if (cnp->cn_namelen > DEVMAXNAMESIZE) {
817: error = ENAMETOOLONG;
818: goto out1;
819: }
820:
821: /*
822: * Lock our directories and get our name pointers
823: * assume that the names are null terminated as they
824: * are the end of the path. Get pointers to all our
825: * devfs structures.
826: */
827: tdp = VTODN(tdvp);
828: fp = VTODN(vp);
829:
830: if (tdvp->v_mount != vp->v_mount) {
831: error = EXDEV;
832: VOP_ABORTOP(tdvp, cnp);
833: goto out2;
834: }
835: if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
836: VOP_ABORTOP(tdvp, cnp);
837: goto out2;
838: }
839:
840: /*
841: * Check we are doing legal things WRT the new flags
842: */
843: if (fp->dn_flags & (IMMUTABLE | APPEND)) {
844: VOP_ABORTOP(tdvp, cnp);
845: error = EPERM;
846: goto out1;
847: }
848:
849: /***********************************
850: * Start actually doing things.... *
851: ***********************************/
852: fp->dn_flags |= DN_CHANGE;
853: tv = time;
854: error = VOP_UPDATE(vp, &tv, &tv, 1);
855: if (!error) {
856: DEVFS_LOCK(p);
857: error = dev_add_name(cnp->cn_nameptr, tdp, NULL, fp, &tnp);
858: DEVFS_UNLOCK(p);
859: }
860: out1:
861: if (tdvp != vp)
862: VOP_UNLOCK(vp, 0, p);
863: out2:
864: vput(tdvp);
865: return (error);
866: }
867:
868: /*
869: * Check if source directory is in the path of the target directory.
870: * Target is supplied locked, source is unlocked.
871: * The target is always vput before returning.
872: */
873: int
874: devfs_checkpath(source, target)
875: devnode_t *source, *target;
876: {
877: int error = 0;
878: devnode_t * ntmp;
879: devnode_t * tmp;
880: struct vnode *vp;
881:
882: vp = target->dn_vn;
883: tmp = target;
884:
885: do {
886: if (tmp == source) {
887: error = EINVAL;
888: break;
889: }
890: ntmp = tmp;
891: } while ((tmp = tmp->dn_typeinfo.Dir.parent) != ntmp);
892:
893: if (vp != NULL)
894: vput(vp);
895: return (error);
896: }
897:
898: /*
899: * Rename system call. Seems overly complicated to me...
900: * rename("foo", "bar");
901: * is essentially
902: * unlink("bar");
903: * link("foo", "bar");
904: * unlink("foo");
905: * but ``atomically''.
906: *
907: * When the target exists, both the directory
908: * and target vnodes are locked.
909: * the source and source-parent vnodes are referenced
910: *
911: *
912: * Basic algorithm is:
913: *
914: * 1) Bump link count on source while we're linking it to the
915: * target. This also ensure the inode won't be deleted out
916: * from underneath us while we work (it may be truncated by
917: * a concurrent `trunc' or `open' for creation).
918: * 2) Link source to destination. If destination already exists,
919: * delete it first.
920: * 3) Unlink source reference to node if still around. If a
921: * directory was moved and the parent of the destination
922: * is different from the source, patch the ".." entry in the
923: * directory.
924: */
925: static int
926: devfs_rename(struct vop_rename_args *ap)
927: /*struct vop_rename_args {
928: struct vnode *a_fdvp;
929: struct vnode *a_fvp;
930: struct componentname *a_fcnp;
931: struct vnode *a_tdvp;
932: struct vnode *a_tvp;
933: struct componentname *a_tcnp;
934: } */
935: {
936: struct vnode *tvp = ap->a_tvp;
937: struct vnode *tdvp = ap->a_tdvp;
938: struct vnode *fvp = ap->a_fvp;
939: struct vnode *fdvp = ap->a_fdvp;
940: struct componentname *tcnp = ap->a_tcnp;
941: struct componentname *fcnp = ap->a_fcnp;
942: struct proc *p = fcnp->cn_proc;
943: devnode_t *fp, *fdp, *tp, *tdp;
944: devdirent_t *fnp,*tnp;
945: int doingdirectory = 0;
946: int error = 0;
947: struct timeval tv;
948:
949: /*
950: * First catch an arbitrary restriction for this FS
951: */
952: if(tcnp->cn_namelen > DEVMAXNAMESIZE) {
953: error = ENAMETOOLONG;
954: goto abortit;
955: }
956:
957: /*
958: * Lock our directories and get our name pointers
959: * assume that the names are null terminated as they
960: * are the end of the path. Get pointers to all our
961: * devfs structures.
962: */
963: tdp = VTODN(tdvp);
964: fdp = VTODN(fdvp);
965: fp = VTODN(fvp);
966: fnp = fp->dn_last_lookup;
967: tp = NULL;
968: tnp = NULL;
969: if (tvp) {
970: tp = VTODN(tvp);
971: tnp = tp->dn_last_lookup;
972: }
973:
974: /*
975: * trying to move it out of devfs?
976: * if we move a dir across mnt points. we need to fix all
977: * the mountpoint pointers! XXX
978: * so for now keep dirs within the same mount
979: */
980: if ((fvp->v_mount != tdvp->v_mount) ||
981: (tvp && (fvp->v_mount != tvp->v_mount))) {
982: error = EXDEV;
983: abortit:
984: VOP_ABORTOP(tdvp, tcnp);
985: if (tdvp == tvp) /* eh? */
986: vrele(tdvp);
987: else
988: vput(tdvp);
989: if (tvp)
990: vput(tvp);
991: VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
992: vrele(fdvp);
993: vrele(fvp);
994: return (error);
995: }
996:
997: /*
998: * Check we are doing legal things WRT the new flags
999: */
1000: if ((tp && (tp->dn_flags & (IMMUTABLE | APPEND)))
1001: || (fp->dn_flags & (IMMUTABLE | APPEND))
1002: || (fdp->dn_flags & APPEND)) {
1003: error = EPERM;
1004: goto abortit;
1005: }
1006:
1007: /*
1008: * Make sure that we don't try do something stupid
1009: */
1010: if ((fp->dn_type) == DEV_DIR) {
1011: /*
1012: * Avoid ".", "..", and aliases of "." for obvious reasons.
1013: */
1014: if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')
1015: || (fcnp->cn_flags&ISDOTDOT)
1016: || (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.')
1017: || (tcnp->cn_flags&ISDOTDOT)
1018: || (tdp == fp )) {
1019: error = EINVAL;
1020: goto abortit;
1021: }
1022: doingdirectory++;
1023: }
1024:
1025: /*
1026: * If ".." must be changed (ie the directory gets a new
1027: * parent) then the source directory must not be in the
1028: * directory hierarchy above the target, as this would
1029: * orphan everything below the source directory. Also
1030: * the user must have write permission in the source so
1031: * as to be able to change "..".
1032: */
1033: if (doingdirectory && (tdp != fdp)) {
1034: devnode_t * tmp, *ntmp;
1035: error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
1036: tmp = tdp;
1037: do {
1038: if(tmp == fp) {
1039: /* XXX unlock stuff here probably */
1040: error = EINVAL;
1041: goto out;
1042: }
1043: ntmp = tmp;
1044: } while ((tmp = tmp->dn_typeinfo.Dir.parent) != ntmp);
1045: }
1046:
1047: /***********************************
1048: * Start actually doing things.... *
1049: ***********************************/
1050: fp->dn_flags |= DN_CHANGE;
1051: tv = time;
1052: if (error = VOP_UPDATE(fvp, &tv, &tv, 1)) {
1053: VOP_UNLOCK(fvp, 0, p);
1054: goto bad;
1055: }
1056: /*
1057: * Check if just deleting a link name.
1058: */
1059: if (fvp == tvp) {
1060: if (fvp->v_type == VDIR) {
1061: error = EINVAL;
1062: goto abortit;
1063: }
1064:
1065: /* Release destination completely. */
1066: VOP_ABORTOP(tdvp, tcnp);
1067: vput(tdvp);
1068: vput(tvp);
1069:
1070: /* Delete source. */
1071: VOP_ABORTOP(fdvp, fcnp); /*XXX*/
1072: vrele(fdvp);
1073: vrele(fvp);
1074: dev_free_name(fnp);
1075: return 0;
1076: }
1077:
1078: vrele(fdvp);
1079:
1080: /*
1081: * 1) Bump link count while we're moving stuff
1082: * around. If we crash somewhere before
1083: * completing our work, too bad :)
1084: */
1085: fp->dn_links++;
1086: /*
1087: * If the target exists zap it (unless it's a non-empty directory)
1088: * We could do that as well but won't
1089: */
1090: if (tp) {
1091: int ouruid = tcnp->cn_cred->cr_uid;
1092: /*
1093: * If the parent directory is "sticky", then the user must
1094: * own the parent directory, or the destination of the rename,
1095: * otherwise the destination may not be changed (except by
1096: * root). This implements append-only directories.
1097: * XXX shoudn't this be in generic code?
1098: */
1099: if ((tdp->dn_mode & S_ISTXT)
1100: && ouruid != 0
1101: && ouruid != tdp->dn_uid
1102: && ouruid != tp->dn_uid ) {
1103: error = EPERM;
1104: goto bad;
1105: }
1106: /*
1107: * Target must be empty if a directory and have no links
1108: * to it. Also, ensure source and target are compatible
1109: * (both directories, or both not directories).
1110: */
1111: if (( doingdirectory) && (tp->dn_links > 2)) {
1112: error = ENOTEMPTY;
1113: goto bad;
1114: }
1115: dev_free_name(tnp);
1116: tp = NULL;
1117: }
1118: dev_add_name(tcnp->cn_nameptr,tdp,NULL,fp,&tnp);
1119: fnp->de_dnp = NULL;
1120: fp->dn_links--; /* one less link to it.. */
1121: dev_free_name(fnp);
1122: fp->dn_links--; /* we added one earlier*/
1123: if (tdp)
1124: vput(tdvp);
1125: if (tp)
1126: vput(fvp);
1127: vrele(fvp);
1128: return (error);
1129:
1130: bad:
1131: if (tp)
1132: vput(tvp);
1133: vput(tdvp);
1134: out:
1135: if (vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p) == 0) {
1136: fp->dn_links--; /* we added one earlier*/
1137: vput(fvp);
1138: } else
1139: vrele(fvp);
1140: return (error);
1141: }
1142:
1143: static int
1144: devfs_symlink(struct vop_symlink_args *ap)
1145: /*struct vop_symlink_args {
1146: struct vnode *a_dvp;
1147: struct vnode **a_vpp;
1148: struct componentname *a_cnp;
1149: struct vattr *a_vap;
1150: char *a_target;
1151: } */
1152: {
1153: struct componentname * cnp = ap->a_cnp;
1154: struct vnode *vp = NULL;
1155: int error = 0;
1156: devnode_t * dir_p;
1157: devnode_type_t typeinfo;
1158: devdirent_t * nm_p;
1159: devnode_t * dev_p;
1160: struct vattr * vap = ap->a_vap;
1161: struct vnode * * vpp = ap->a_vpp;
1162: struct proc *p = cnp->cn_proc;
1163: struct timeval tv;
1164:
1165: dir_p = VTODN(ap->a_dvp);
1166: typeinfo.Slnk.name = ap->a_target;
1167: typeinfo.Slnk.namelen = strlen(ap->a_target);
1168: DEVFS_LOCK(p);
1169: error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_SLNK,
1170: &typeinfo, NULL, NULL, &nm_p);
1171: DEVFS_UNLOCK(p);
1172: if (error) {
1173: goto failure;
1174: }
1175:
1176: dev_p = nm_p->de_dnp;
1177: dev_p->dn_uid = dir_p->dn_uid;
1178: dev_p->dn_gid = dir_p->dn_gid;
1179: dev_p->dn_mode = vap->va_mode;
1180: dn_copy_times(dev_p, dir_p);
1181: error = devfs_dntovn(dev_p, vpp, p);
1182: if (error)
1183: goto failure;
1184: vp = *vpp;
1185: vput(vp);
1186: failure:
1187: if ((cnp->cn_flags & SAVESTART) == 0)
1188: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1189: vput(ap->a_dvp);
1190: return error;
1191: }
1192:
1193: /*
1194: * Mknod vnode call
1195: */
1196: /* ARGSUSED */
1197: int
1198: devfs_mknod(ap)
1199: struct vop_mknod_args /* {
1200: struct vnode *a_dvp;
1201: struct vnode **a_vpp;
1202: struct componentname *a_cnp;
1203: struct vattr *a_vap;
1204: } */ *ap;
1205: {
1206: struct componentname * cnp = ap->a_cnp;
1207: devnode_t * dev_p;
1208: devdirent_t * devent;
1209: devnode_t * dir_p; /* devnode for parent directory */
1210: struct vnode * dvp = ap->a_dvp;
1211: int error = 0;
1212: devnode_type_t typeinfo;
1213: struct vattr * vap = ap->a_vap;
1214: struct vnode ** vpp = ap->a_vpp;
1215: struct proc * p = cnp->cn_proc;
1216:
1217: *vpp = NULL;
1218: if (!vap->va_type == VBLK && !vap->va_type == VCHR) {
1219: error = EINVAL; /* only support mknod of special files */
1220: goto failure;
1221: }
1222: dir_p = VTODN(dvp);
1223: typeinfo.dev = vap->va_rdev;
1224: DEVFS_LOCK(p);
1225: error = dev_add_entry(cnp->cn_nameptr, dir_p,
1226: (vap->va_type == VBLK) ? DEV_BDEV : DEV_CDEV,
1227: &typeinfo, NULL, NULL, &devent);
1228: DEVFS_UNLOCK(p);
1229: if (error) {
1230: goto failure;
1231: }
1232: dev_p = devent->de_dnp;
1233: error = devfs_dntovn(dev_p, vpp, p);
1234: if (error)
1235: goto failure;
1236: dev_p->dn_uid = cnp->cn_cred->cr_uid;
1237: dev_p->dn_gid = dir_p->dn_gid;
1238: dev_p->dn_mode = vap->va_mode;
1239: failure:
1240: if (*vpp) {
1241: vput(*vpp);
1242: *vpp = 0;
1243: }
1244: if ((cnp->cn_flags & SAVESTART) == 0)
1245: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1246: vput(dvp);
1247: return (error);
1248: }
1249:
1250: /*
1251: * Vnode op for readdir
1252: */
1253: static int
1254: devfs_readdir(struct vop_readdir_args *ap)
1255: /*struct vop_readdir_args {
1256: struct vnode *a_vp;
1257: struct uio *a_uio;
1258: struct ucred *a_cred;
1259: int *eofflag;
1260: int *ncookies;
1261: u_int **cookies;
1262: } */
1263: {
1264: struct vnode *vp = ap->a_vp;
1265: struct uio *uio = ap->a_uio;
1266: struct dirent dirent;
1267: devnode_t * dir_node;
1268: devdirent_t * name_node;
1269: char *name;
1270: int error = 0;
1271: int reclen;
1272: int nodenumber;
1273: int startpos,pos;
1274: struct proc * p = uio->uio_procp;
1275:
1276: /* set up refs to dir */
1277: dir_node = VTODN(vp);
1278: if(dir_node->dn_type != DEV_DIR)
1279: return(ENOTDIR);
1280:
1281: pos = 0;
1282: startpos = uio->uio_offset;
1283: DEVFS_LOCK(p);
1284: name_node = dir_node->dn_typeinfo.Dir.dirlist;
1285: nodenumber = 0;
1286: dir_node->dn_flags |= DN_ACCESS;
1287:
1288: while ((name_node || (nodenumber < 2)) && (uio->uio_resid > 0))
1289: {
1290: switch(nodenumber)
1291: {
1292: case 0:
1293: dirent.d_fileno = (int32_t)(void *)dir_node;
1294: name = ".";
1295: dirent.d_namlen = 1;
1296: dirent.d_type = DT_DIR;
1297: break;
1298: case 1:
1299: if(dir_node->dn_typeinfo.Dir.parent)
1300: dirent.d_fileno
1301: = (int32_t)dir_node->dn_typeinfo.Dir.parent;
1302: else
1303: dirent.d_fileno = (u_int32_t)dir_node;
1304: name = "..";
1305: dirent.d_namlen = 2;
1306: dirent.d_type = DT_DIR;
1307: break;
1308: default:
1309: dirent.d_fileno = (int32_t)(void *)name_node->de_dnp;
1310: dirent.d_namlen = strlen(name_node->de_name);
1311: name = name_node->de_name;
1312: switch(name_node->de_dnp->dn_type) {
1313: case DEV_BDEV:
1314: dirent.d_type = DT_BLK;
1315: break;
1316: case DEV_CDEV:
1317: dirent.d_type = DT_CHR;
1318: break;
1319: case DEV_DIR:
1320: dirent.d_type = DT_DIR;
1321: break;
1322: case DEV_SLNK:
1323: dirent.d_type = DT_LNK;
1324: break;
1325: default:
1326: dirent.d_type = DT_UNKNOWN;
1327: }
1328: }
1329: #define GENERIC_DIRSIZ(dp) \
1330: ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
1331:
1332: reclen = dirent.d_reclen = GENERIC_DIRSIZ(&dirent);
1333:
1334: if(pos >= startpos) /* made it to the offset yet? */
1335: {
1336: if (uio->uio_resid < reclen) /* will it fit? */
1337: break;
1338: strcpy( dirent.d_name,name);
1339: if ((error = uiomove ((caddr_t)&dirent,
1340: dirent.d_reclen, uio)) != 0)
1341: break;
1342: }
1343: pos += reclen;
1344: if((nodenumber >1) && name_node)
1345: name_node = name_node->de_next;
1346: nodenumber++;
1347: }
1348: DEVFS_UNLOCK(p);
1349: uio->uio_offset = pos;
1350:
1351: return (error);
1352: }
1353:
1354:
1355: /*
1356: */
1357: static int
1358: devfs_readlink(struct vop_readlink_args *ap)
1359: /*struct vop_readlink_args {
1360: struct vnode *a_vp;
1361: struct uio *a_uio;
1362: struct ucred *a_cred;
1363: } */
1364: {
1365: struct vnode *vp = ap->a_vp;
1366: struct uio *uio = ap->a_uio;
1367: devnode_t * lnk_node;
1368: int error = 0;
1369:
1370: /* set up refs to dir */
1371: lnk_node = VTODN(vp);
1372: if(lnk_node->dn_type != DEV_SLNK)
1373: return(EINVAL);
1374: if ((error = VOP_ACCESS(vp, VREAD, ap->a_cred, NULL)) != 0) { /* XXX */
1375: return error;
1376: }
1377: error = uiomove(lnk_node->dn_typeinfo.Slnk.name,
1378: lnk_node->dn_typeinfo.Slnk.namelen, uio);
1379: return error;
1380: }
1381:
1382: static int
1383: devfs_abortop(struct vop_abortop_args *ap)
1384: /*struct vop_abortop_args {
1385: struct vnode *a_dvp;
1386: struct componentname *a_cnp;
1387: } */
1388: {
1389: if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) {
1390: FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI);
1391: }
1392: return 0;
1393: }
1394:
1395:
1396: static int
1397: devfs_reclaim(struct vop_reclaim_args *ap)
1398: /*struct vop_reclaim_args {
1399: struct vnode *a_vp;
1400: } */
1401: {
1402: struct vnode * vp = ap->a_vp;
1403: devnode_t * dnp = VTODN(vp);
1404:
1405: if (dnp) {
1406: /*
1407: * do the same as devfs_inactive in case it is not called
1408: * before us (can that ever happen?)
1409: */
1410: dnp->dn_vn = NULL;
1411: vp->v_data = NULL;
1412: if (dnp->dn_delete) {
1413: devnode_free(dnp);
1414: }
1415: }
1416: return(0);
1417: }
1418:
1419: /*
1420: * Print out the contents of a /devfs vnode.
1421: */
1422: static int
1423: devfs_print(struct vop_print_args *ap)
1424: /*struct vop_print_args {
1425: struct vnode *a_vp;
1426: } */
1427: {
1428:
1429: return (0);
1430: }
1431:
1432: /**************************************************************************\
1433: * pseudo ops *
1434: \**************************************************************************/
1435:
1436: /*
1437: *
1438: * struct vop_inactive_args {
1439: * struct vnode *a_vp;
1440: * struct proc *a_p;
1441: * }
1442: */
1443:
1444: static int
1445: devfs_inactive(struct vop_inactive_args *ap)
1446: {
1447: struct vnode * vp = ap->a_vp;
1448: devnode_t * dnp = VTODN(vp);
1449:
1450: if (dnp) {
1451: dnp->dn_vn = NULL;
1452: vp->v_data = NULL;
1453: if (dnp->dn_delete) {
1454: devnode_free(dnp);
1455: }
1456: }
1457: VOP_UNLOCK(vp, 0, ap->a_p);
1458: return (0);
1459: }
1460:
1461: int
1462: devfs_update(ap)
1463: struct vop_update_args /* {
1464: struct vnode *a_vp;
1465: struct timeval *a_access;
1466: struct timeval *a_modify;
1467: int a_waitfor;
1468: } */ *ap;
1469: {
1470: register struct fs *fs;
1471: int error;
1472: devnode_t * ip;
1473:
1474: ip = VTODN(ap->a_vp);
1475: if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY) {
1476: ip->dn_flags &=
1477: ~(DN_ACCESS | DN_CHANGE | DN_MODIFIED | DN_UPDATE);
1478: return (0);
1479: }
1480: if ((ip->dn_flags &
1481: (DN_ACCESS | DN_CHANGE | DN_MODIFIED | DN_UPDATE)) == 0)
1482: return (0);
1483: dn_times(ip, time, time);
1484: return (0);
1485: }
1486:
1487: /* The following ops are used by directories and symlinks */
1488: int (**devfs_vnodeop_p)();
1489: static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
1490: { &vop_default_desc, vn_default_error },
1491: { &vop_lookup_desc, devfs_lookup }, /* lookup */
1492: { &vop_create_desc, err_create }, /* create */
1493: { &vop_whiteout_desc, err_whiteout }, /* whiteout */
1494: { &vop_mknod_desc, devfs_mknod }, /* mknod */
1495: { &vop_open_desc, nop_open }, /* open */
1496: { &vop_close_desc, devfs_close }, /* close */
1497: { &vop_access_desc, devfs_access }, /* access */
1498: { &vop_getattr_desc, devfs_getattr }, /* getattr */
1499: { &vop_setattr_desc, devfs_setattr }, /* setattr */
1500: { &vop_read_desc, devfs_read }, /* read */
1501: { &vop_write_desc, devfs_write }, /* write */
1502: { &vop_lease_desc, nop_lease }, /* lease */
1503: { &vop_ioctl_desc, err_ioctl }, /* ioctl */
1504: { &vop_select_desc, err_select }, /* select */
1505: { &vop_revoke_desc, err_revoke }, /* revoke */
1506: { &vop_mmap_desc, err_mmap }, /* mmap */
1507: { &vop_fsync_desc, nop_fsync }, /* fsync */
1508: { &vop_seek_desc, err_seek }, /* seek */
1509: { &vop_remove_desc, devfs_remove }, /* remove */
1510: { &vop_link_desc, devfs_link }, /* link */
1511: { &vop_rename_desc, devfs_rename }, /* rename */
1512: { &vop_mkdir_desc, err_mkdir }, /* mkdir */
1513: { &vop_rmdir_desc, err_rmdir }, /* rmdir */
1514: { &vop_symlink_desc, devfs_symlink }, /* symlink */
1515: { &vop_readdir_desc, devfs_readdir }, /* readdir */
1516: { &vop_readlink_desc, devfs_readlink }, /* readlink */
1517: { &vop_abortop_desc, devfs_abortop }, /* abortop */
1518: { &vop_inactive_desc, devfs_inactive }, /* inactive */
1519: { &vop_reclaim_desc, devfs_reclaim }, /* reclaim */
1520: { &vop_lock_desc, nop_lock }, /* lock */
1521: { &vop_unlock_desc, nop_unlock }, /* unlock */
1522: { &vop_bmap_desc, err_bmap }, /* bmap */
1523: { &vop_strategy_desc, err_strategy }, /* strategy */
1524: { &vop_print_desc, err_print }, /* print */
1525: { &vop_islocked_desc, nop_islocked }, /* islocked */
1526: { &vop_pathconf_desc, err_pathconf }, /* pathconf */
1527: { &vop_advlock_desc, err_advlock }, /* advlock */
1528: { &vop_blkatoff_desc, err_blkatoff }, /* blkatoff */
1529: { &vop_valloc_desc, err_valloc }, /* valloc */
1530: { &vop_reallocblks_desc, err_reallocblks }, /* reallocblks */
1531: { &vop_vfree_desc, err_vfree }, /* vfree */
1532: { &vop_truncate_desc, err_truncate }, /* truncate */
1533: { &vop_update_desc, devfs_update }, /* update */
1534: { &vop_bwrite_desc, err_bwrite },
1535: { &vop_pagein_desc, err_pagein }, /* Pagein */
1536: { &vop_pageout_desc, err_pageout }, /* Pageout */
1537: { &vop_copyfile_desc, err_copyfile }, /* Copyfile */
1538: { (struct vnodeop_desc*)NULL, (int(*)())NULL }
1539: };
1540: struct vnodeopv_desc devfs_vnodeop_opv_desc =
1541: { &devfs_vnodeop_p, devfs_vnodeop_entries };
1542:
1543: /* The following ops are used by the device nodes */
1544: int (**devfs_spec_vnodeop_p)();
1545: static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = {
1546: { &vop_default_desc, vn_default_error },
1547: { &vop_lookup_desc, spec_lookup }, /* lookup */
1548: { &vop_create_desc, spec_create }, /* create */
1549: { &vop_mknod_desc, spec_mknod }, /* mknod */
1550: { &vop_open_desc, spec_open }, /* open */
1551: { &vop_close_desc, devfsspec_close }, /* close */
1552: { &vop_access_desc, devfs_access }, /* access */
1553: { &vop_getattr_desc, devfs_getattr }, /* getattr */
1554: { &vop_setattr_desc, devfs_setattr }, /* setattr */
1555: { &vop_read_desc, devfsspec_read }, /* read */
1556: { &vop_write_desc, devfsspec_write }, /* write */
1557: { &vop_lease_desc, spec_lease_check }, /* lease */
1558: { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
1559: { &vop_select_desc, spec_select }, /* select */
1560: { &vop_revoke_desc, spec_revoke }, /* revoke */
1561: { &vop_mmap_desc, spec_mmap }, /* mmap */
1562: { &vop_fsync_desc, spec_fsync }, /* fsync */
1563: { &vop_seek_desc, spec_seek }, /* seek */
1564: { &vop_remove_desc, devfs_remove }, /* remove */
1565: { &vop_link_desc, devfs_link }, /* link */
1566: { &vop_rename_desc, spec_rename }, /* rename */
1567: { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
1568: { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
1569: { &vop_symlink_desc, spec_symlink }, /* symlink */
1570: { &vop_readdir_desc, spec_readdir }, /* readdir */
1571: { &vop_readlink_desc, spec_readlink }, /* readlink */
1572: { &vop_abortop_desc, spec_abortop }, /* abortop */
1573: { &vop_inactive_desc, devfs_inactive }, /* inactive */
1574: { &vop_reclaim_desc, devfs_reclaim }, /* reclaim */
1575: { &vop_lock_desc, nop_lock }, /* lock */
1576: { &vop_unlock_desc, nop_unlock }, /* unlock */
1577: { &vop_bmap_desc, spec_bmap }, /* bmap */
1578: { &vop_strategy_desc, spec_strategy }, /* strategy */
1579: { &vop_print_desc, devfs_print }, /* print */
1580: { &vop_islocked_desc, nop_islocked }, /* islocked */
1581: { &vop_pathconf_desc, spec_pathconf }, /* pathconf */
1582: { &vop_advlock_desc, spec_advlock }, /* advlock */
1583: { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
1584: { &vop_valloc_desc, spec_valloc }, /* valloc */
1585: { &vop_reallocblks_desc, spec_reallocblks }, /* reallocblks */
1586: { &vop_vfree_desc, nop_vfree }, /* vfree */
1587: { &vop_truncate_desc, spec_truncate }, /* truncate */
1588: { &vop_update_desc, devfs_update }, /* update */
1589: { &vop_bwrite_desc, vn_bwrite },
1590: #ifdef NeXT
1591: { &vop_devblocksize_desc, spec_devblocksize }, /* devblocksize */
1592: #endif /* NeXT */
1593: { &vop_pagein_desc, spec_pagein }, /* Pagein */
1594: { &vop_pageout_desc, spec_pageout }, /* Pageout */
1595: { &vop_copyfile_desc, err_copyfile }, /* Copyfile */
1596: { (struct vnodeop_desc*)NULL, (int(*)())NULL }
1597: };
1598: struct vnodeopv_desc devfs_spec_vnodeop_opv_desc =
1599: { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries };
1600:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.