]> git.saurik.com Git - apple/xnu.git/blob - bsd/miscfs/devfs/devfs_vnops.c
xnu-4570.1.46.tar.gz
[apple/xnu.git] / bsd / miscfs / devfs / devfs_vnops.c
1 /*
2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright 1997,1998 Julian Elischer. All rights reserved.
30 * julian@freebsd.org
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions are
34 * met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright notice,
38 * this list of conditions and the following disclaimer in the documentation
39 * and/or other materials provided with the distribution.
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS
42 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
43 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44 * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR
45 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
47 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
48 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * devfs_vnops.c
54 */
55
56 /*
57 * HISTORY
58 * Clark Warner (warner_c@apple.com) Tue Feb 10 2000
59 * - Added err_copyfile to the vnode operations table
60 * Dieter Siegmund (dieter@apple.com) Thu Apr 8 14:08:19 PDT 1999
61 * - instead of duplicating specfs here, created a vnode-ops table
62 * that redirects most operations to specfs (as is done with ufs);
63 * - removed routines that made no sense
64 * - cleaned up reclaim: replaced devfs_vntodn() with a macro VTODN()
65 * - cleaned up symlink, link locking
66 * - added the devfs_lock to protect devfs data structures against
67 * driver's calling devfs_add_devswf()/etc.
68 * Dieter Siegmund (dieter@apple.com) Wed Jul 14 13:37:59 PDT 1999
69 * - free the devfs devnode in devfs_inactive(), not just in devfs_reclaim()
70 * to free up kernel memory as soon as it's available
71 * - got rid of devfsspec_{read, write}
72 * Dieter Siegmund (dieter@apple.com) Fri Sep 17 09:58:38 PDT 1999
73 * - update the mod/access times
74 */
75 /*
76 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
77 * support for mandatory and extensible security protections. This notice
78 * is included in support of clause 2.2 (b) of the Apple Public License,
79 * Version 2.0.
80 */
81
82 #include <sys/param.h>
83 #include <sys/systm.h>
84 #include <sys/namei.h>
85 #include <sys/kernel.h>
86 #include <sys/fcntl.h>
87 #include <sys/conf.h>
88 #include <sys/disklabel.h>
89 #include <sys/lock.h>
90 #include <sys/stat.h>
91 #include <sys/mount_internal.h>
92 #include <sys/proc.h>
93 #include <sys/kauth.h>
94 #include <sys/time.h>
95 #include <sys/vnode_internal.h>
96 #include <miscfs/specfs/specdev.h>
97 #include <sys/dirent.h>
98 #include <sys/vmmeter.h>
99 #include <sys/vm.h>
100 #include <sys/uio_internal.h>
101
102 #if CONFIG_MACF
103 #include <security/mac_framework.h>
104 #endif
105
106 #include "devfsdefs.h"
107 #include "devfs.h"
108
109 #if FDESC
110 #include "fdesc.h"
111 #endif /* FDESC */
112
113 static int devfs_update(struct vnode *vp, struct timeval *access,
114 struct timeval *modify);
115 void devfs_rele_node(devnode_t *);
116 static void devfs_consider_time_update(devnode_t *dnp, uint32_t just_changed_flags);
117 static boolean_t devfs_update_needed(long now_s, long last_s);
118 static boolean_t devfs_is_name_protected(struct vnode *dvp, const char *name);
119 void dn_times_locked(devnode_t * dnp, struct timeval *t1, struct timeval *t2, struct timeval *t3, uint32_t just_changed_flags);
120 void dn_times_now(devnode_t *dnp, uint32_t just_changed_flags);
121 void dn_mark_for_delayed_times_update(devnode_t *dnp, uint32_t just_changed_flags);
122
123 void
124 dn_times_locked(devnode_t * dnp, struct timeval *t1, struct timeval *t2, struct timeval *t3, uint32_t just_changed_flags)
125 {
126
127 lck_mtx_assert(&devfs_attr_mutex, LCK_MTX_ASSERT_OWNED);
128
129 if (just_changed_flags & DEVFS_UPDATE_ACCESS) {
130 dnp->dn_atime.tv_sec = t1->tv_sec;
131 dnp->dn_atime.tv_nsec = t1->tv_usec * 1000;
132 dnp->dn_access = 0;
133 } else if (dnp->dn_access) {
134 dnp->dn_atime.tv_sec = MIN(t1->tv_sec, dnp->dn_atime.tv_sec + DEVFS_LAZY_UPDATE_SECONDS);
135 dnp->dn_atime.tv_nsec = t1->tv_usec * 1000;
136 dnp->dn_access = 0;
137 }
138
139 if (just_changed_flags & DEVFS_UPDATE_MOD) {
140 dnp->dn_mtime.tv_sec = t2->tv_sec;
141 dnp->dn_mtime.tv_nsec = t2->tv_usec * 1000;
142 dnp->dn_update = 0;
143 } else if (dnp->dn_update) {
144 dnp->dn_mtime.tv_sec = MIN(t2->tv_sec, dnp->dn_mtime.tv_sec + DEVFS_LAZY_UPDATE_SECONDS);
145 dnp->dn_mtime.tv_nsec = t2->tv_usec * 1000;
146 dnp->dn_update = 0;
147 }
148
149 if (just_changed_flags & DEVFS_UPDATE_CHANGE) {
150 dnp->dn_ctime.tv_sec = t3->tv_sec;
151 dnp->dn_ctime.tv_nsec = t3->tv_usec * 1000;
152 dnp->dn_change = 0;
153 } else if (dnp->dn_change) {
154 dnp->dn_ctime.tv_sec = MIN(t3->tv_sec, dnp->dn_ctime.tv_sec + DEVFS_LAZY_UPDATE_SECONDS);
155 dnp->dn_ctime.tv_nsec = t3->tv_usec * 1000;
156 dnp->dn_change = 0;
157 }
158 }
159
160 void
161 dn_mark_for_delayed_times_update(devnode_t *dnp, uint32_t just_changed_flags)
162 {
163 if (just_changed_flags & DEVFS_UPDATE_CHANGE) {
164 dnp->dn_change = 1;
165 }
166 if (just_changed_flags & DEVFS_UPDATE_ACCESS) {
167 dnp->dn_access = 1;
168 }
169 if (just_changed_flags & DEVFS_UPDATE_MOD) {
170 dnp->dn_update = 1;
171 }
172 }
173
174 /*
175 * Update times based on pending updates and optionally a set of new changes.
176 */
177 void
178 dn_times_now(devnode_t * dnp, uint32_t just_changed_flags)
179 {
180 struct timeval now;
181
182 DEVFS_ATTR_LOCK_SPIN();
183 microtime(&now);
184 dn_times_locked(dnp, &now, &now, &now, just_changed_flags);
185 DEVFS_ATTR_UNLOCK();
186 }
187
188 /*
189 * Critical devfs devices cannot be renamed or removed.
190 * However, links to them may be moved/unlinked. So we block
191 * remove/rename on a per-name basis, rather than per-node.
192 */
193 static boolean_t
194 devfs_is_name_protected(struct vnode *dvp, const char *name)
195 {
196 /*
197 * Only names in root are protected. E.g. /dev/null is protected,
198 * but /dev/foo/null isn't.
199 */
200 if (!vnode_isvroot(dvp))
201 return FALSE;
202
203 if ((strcmp("console", name) == 0) ||
204 (strcmp("tty", name) == 0) ||
205 (strcmp("null", name) == 0) ||
206 (strcmp("zero", name) == 0) ||
207 (strcmp("klog", name) == 0)) {
208
209 return TRUE;
210 }
211
212 return FALSE;
213 }
214
215
216 /*
217 * Convert a component of a pathname into a pointer to a locked node.
218 * This is a very central and rather complicated routine.
219 * If the file system is not maintained in a strict tree hierarchy,
220 * this can result in a deadlock situation (see comments in code below).
221 *
222 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
223 * whether the name is to be looked up, created, renamed, or deleted.
224 * When CREATE, RENAME, or DELETE is specified, information usable in
225 * creating, renaming, or deleting a directory entry may be calculated.
226 * If flag has LOCKPARENT or'ed into it and the target of the pathname
227 * exists, lookup returns both the target and its parent directory locked.
228 * When creating or renaming and LOCKPARENT is specified, the target may
229 * not be ".". When deleting and LOCKPARENT is specified, the target may
230 * be "."., but the caller must check to ensure it does an vrele and DNUNLOCK
231 * instead of two DNUNLOCKs.
232 *
233 * Overall outline of devfs_lookup:
234 *
235 * check accessibility of directory
236 * null terminate the component (lookup leaves the whole string alone)
237 * look for name in cache, if found, then if at end of path
238 * and deleting or creating, drop it, else return name
239 * search for name in directory, to found or notfound
240 * notfound:
241 * if creating, return locked directory,
242 * else return error
243 * found:
244 * if at end of path and deleting, return information to allow delete
245 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target
246 * node and return info to allow rewrite
247 * if not at end, add name to cache; if at end and neither creating
248 * nor deleting, add name to cache
249 * On return to lookup, remove the null termination we put in at the start.
250 *
251 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent node unlocked.
252 */
253 static int
254 devfs_lookup(struct vnop_lookup_args *ap)
255 /*struct vnop_lookup_args {
256 struct vnode * a_dvp; directory vnode ptr
257 struct vnode ** a_vpp; where to put the result
258 struct componentname * a_cnp; the name we want
259 vfs_context_t a_context;
260 };*/
261 {
262 struct componentname *cnp = ap->a_cnp;
263 vfs_context_t ctx = cnp->cn_context;
264 struct proc *p = vfs_context_proc(ctx);
265 struct vnode *dir_vnode = ap->a_dvp;
266 struct vnode **result_vnode = ap->a_vpp;
267 devnode_t * dir_node; /* the directory we are searching */
268 devnode_t * node = NULL; /* the node we are searching for */
269 devdirent_t * nodename;
270 int flags = cnp->cn_flags;
271 int op = cnp->cn_nameiop; /* LOOKUP, CREATE, RENAME, or DELETE */
272 int wantparent = flags & (LOCKPARENT|WANTPARENT);
273 int error = 0;
274 char heldchar; /* the char at the end of the name componet */
275
276 retry:
277
278 *result_vnode = NULL; /* safe not sorry */ /*XXX*/
279
280 /* okay to look at directory vnodes ourside devfs lock as they are not aliased */
281 dir_node = VTODN(dir_vnode);
282
283 /*
284 * Make sure that our node is a directory as well.
285 */
286 if (dir_node->dn_type != DEV_DIR) {
287 return (ENOTDIR);
288 }
289
290 DEVFS_LOCK();
291 /*
292 * temporarily terminate string component
293 */
294 heldchar = cnp->cn_nameptr[cnp->cn_namelen];
295 cnp->cn_nameptr[cnp->cn_namelen] = '\0';
296
297 nodename = dev_findname(dir_node, cnp->cn_nameptr);
298 /*
299 * restore saved character
300 */
301 cnp->cn_nameptr[cnp->cn_namelen] = heldchar;
302
303 if (nodename) {
304 /* entry exists */
305 node = nodename->de_dnp;
306
307 /* Do potential vnode allocation here inside the lock
308 * to make sure that our device node has a non-NULL dn_vn
309 * associated with it. The device node might otherwise
310 * get deleted out from under us (see devfs_dn_free()).
311 */
312 error = devfs_dntovn(node, result_vnode, p);
313 }
314 DEVFS_UNLOCK();
315
316 if (error) {
317 if (error == EAGAIN)
318 goto retry;
319 return error;
320 }
321 if (!nodename) {
322 /*
323 * we haven't called devfs_dntovn if we get here
324 * we have not taken a reference on the node.. no
325 * vnode_put is necessary on these error returns
326 *
327 * If it doesn't exist and we're not the last component,
328 * or we're at the last component, but we're not creating
329 * or renaming, return ENOENT.
330 */
331 if (!(flags & ISLASTCN) || !(op == CREATE || op == RENAME)) {
332 return ENOENT;
333 }
334 /*
335 * We return with the directory locked, so that
336 * the parameters we set up above will still be
337 * valid if we actually decide to add a new entry.
338 * We return ni_vp == NULL to indicate that the entry
339 * does not currently exist; we leave a pointer to
340 * the (locked) directory vnode in namei_data->ni_dvp.
341 *
342 * NB - if the directory is unlocked, then this
343 * information cannot be used.
344 */
345 return (EJUSTRETURN);
346 }
347 /*
348 * from this point forward, we need to vnode_put the reference
349 * picked up in devfs_dntovn if we decide to return an error
350 */
351
352 /*
353 * If deleting, and at end of pathname, return
354 * parameters which can be used to remove file.
355 * If the wantparent flag isn't set, we return only
356 * the directory (in namei_data->ni_dvp), otherwise we go
357 * on and lock the node, being careful with ".".
358 */
359 if (op == DELETE && (flags & ISLASTCN)) {
360
361 /*
362 * we are trying to delete '.'. What does this mean? XXX
363 */
364 if (dir_node == node) {
365 if (*result_vnode) {
366 vnode_put(*result_vnode);
367 *result_vnode = NULL;
368 }
369 if ( ((error = vnode_get(dir_vnode)) == 0) ) {
370 *result_vnode = dir_vnode;
371 }
372 return (error);
373 }
374 return (0);
375 }
376
377 /*
378 * If rewriting (RENAME), return the vnode and the
379 * information required to rewrite the present directory
380 * Must get node of directory entry to verify it's a
381 * regular file, or empty directory.
382 */
383 if (op == RENAME && wantparent && (flags & ISLASTCN)) {
384
385 /*
386 * Careful about locking second node.
387 * This can only occur if the target is ".".
388 */
389 if (dir_node == node) {
390 error = EISDIR;
391 goto drop_ref;
392 }
393 return (0);
394 }
395
396 /*
397 * Step through the translation in the name. We do not unlock the
398 * directory because we may need it again if a symbolic link
399 * is relative to the current directory. Instead we save it
400 * unlocked as "saved_dir_node" XXX. We must get the target
401 * node before unlocking
402 * the directory to insure that the node will not be removed
403 * before we get it. We prevent deadlock by always fetching
404 * nodes from the root, moving down the directory tree. Thus
405 * when following backward pointers ".." we must unlock the
406 * parent directory before getting the requested directory.
407 * There is a potential race condition here if both the current
408 * and parent directories are removed before the lock for the
409 * node associated with ".." returns. We hope that this occurs
410 * infrequently since we cannot avoid this race condition without
411 * implementing a sophisticated deadlock detection algorithm.
412 * Note also that this simple deadlock detection scheme will not
413 * work if the file system has any hard links other than ".."
414 * that point backwards in the directory structure.
415 */
416 if ((flags & ISDOTDOT) == 0 && dir_node == node) {
417 if (*result_vnode) {
418 vnode_put(*result_vnode);
419 *result_vnode = NULL;
420 }
421 if ( (error = vnode_get(dir_vnode)) ) {
422 return (error);
423 }
424 *result_vnode = dir_vnode;
425 }
426 return (0);
427
428 drop_ref:
429 if (*result_vnode) {
430 vnode_put(*result_vnode);
431 *result_vnode = NULL;
432 }
433 return (error);
434 }
435
436 static int
437 devfs_getattr(struct vnop_getattr_args *ap)
438 /*struct vnop_getattr_args {
439 struct vnode *a_vp;
440 struct vnode_attr *a_vap;
441 kauth_cred_t a_cred;
442 struct proc *a_p;
443 } */
444 {
445 struct vnode *vp = ap->a_vp;
446 struct vnode_attr *vap = ap->a_vap;
447 devnode_t * file_node;
448 struct timeval now;
449
450
451 DEVFS_LOCK();
452 file_node = VTODN(vp);
453
454 VATTR_RETURN(vap, va_mode, file_node->dn_mode);
455
456 /*
457 * Note: for DEV_CDEV and DEV_BDEV, we return the device from
458 * the vp, not the file_node; if we getting information on a
459 * cloning device, we want the cloned information, not the template.
460 */
461 switch (file_node->dn_type)
462 {
463 case DEV_DIR:
464 #if FDESC
465 case DEV_DEVFD: /* Like a directory */
466 #endif /* FDESC */
467 VATTR_RETURN(vap, va_rdev, 0);
468 vap->va_mode |= (S_IFDIR);
469 break;
470 case DEV_CDEV:
471 VATTR_RETURN(vap, va_rdev, vp->v_rdev);
472 vap->va_mode |= (S_IFCHR);
473 break;
474 case DEV_BDEV:
475 VATTR_RETURN(vap, va_rdev, vp->v_rdev);
476 vap->va_mode |= (S_IFBLK);
477 break;
478 case DEV_SLNK:
479 VATTR_RETURN(vap, va_rdev, 0);
480 vap->va_mode |= (S_IFLNK);
481 break;
482 default:
483 VATTR_RETURN(vap, va_rdev, 0); /* default value only */
484 }
485 VATTR_RETURN(vap, va_type, vp->v_type);
486 VATTR_RETURN(vap, va_nlink, file_node->dn_links);
487 VATTR_RETURN(vap, va_uid, file_node->dn_uid);
488 VATTR_RETURN(vap, va_gid, file_node->dn_gid);
489 VATTR_RETURN(vap, va_fsid, (uintptr_t)file_node->dn_dvm);
490 VATTR_RETURN(vap, va_fileid, (uintptr_t)file_node->dn_ino);
491 VATTR_RETURN(vap, va_data_size, file_node->dn_len);
492
493 /* return an override block size (advisory) */
494 if (vp->v_type == VBLK)
495 VATTR_RETURN(vap, va_iosize, BLKDEV_IOSIZE);
496 else if (vp->v_type == VCHR)
497 VATTR_RETURN(vap, va_iosize, MAXPHYSIO);
498 else
499 VATTR_RETURN(vap, va_iosize, vp->v_mount->mnt_vfsstat.f_iosize);
500
501
502 DEVFS_ATTR_LOCK_SPIN();
503
504 microtime(&now);
505 dn_times_locked(file_node, &now, &now, &now, 0);
506
507 /* if the time is bogus, set it to the boot time */
508 if (file_node->dn_ctime.tv_sec == 0) {
509 file_node->dn_ctime.tv_sec = boottime_sec();
510 file_node->dn_ctime.tv_nsec = 0;
511 }
512 if (file_node->dn_mtime.tv_sec == 0)
513 file_node->dn_mtime = file_node->dn_ctime;
514 if (file_node->dn_atime.tv_sec == 0)
515 file_node->dn_atime = file_node->dn_ctime;
516 VATTR_RETURN(vap, va_change_time, file_node->dn_ctime);
517 VATTR_RETURN(vap, va_modify_time, file_node->dn_mtime);
518 VATTR_RETURN(vap, va_access_time, file_node->dn_atime);
519
520 DEVFS_ATTR_UNLOCK();
521
522 VATTR_RETURN(vap, va_gen, 0);
523 VATTR_RETURN(vap, va_filerev, 0);
524 VATTR_RETURN(vap, va_acl, NULL);
525
526 /* Hide the root so Finder doesn't display it */
527 if (vnode_isvroot(vp)) {
528 VATTR_RETURN(vap, va_flags, UF_HIDDEN);
529 } else {
530 VATTR_RETURN(vap, va_flags, 0);
531 }
532
533 DEVFS_UNLOCK();
534
535 return 0;
536 }
537
538 static int
539 devfs_setattr(struct vnop_setattr_args *ap)
540 /*struct vnop_setattr_args {
541 struct vnode *a_vp;
542 struct vnode_attr *a_vap;
543 vfs_context_t a_context;
544 } */
545 {
546 struct vnode *vp = ap->a_vp;
547 struct vnode_attr *vap = ap->a_vap;
548 int error = 0;
549 devnode_t * file_node;
550 struct timeval atimeval, mtimeval;
551
552 DEVFS_LOCK();
553
554 file_node = VTODN(vp);
555 /*
556 * Go through the fields and update if set.
557 */
558 if (VATTR_IS_ACTIVE(vap, va_access_time) || VATTR_IS_ACTIVE(vap, va_modify_time)) {
559
560
561 if (VATTR_IS_ACTIVE(vap, va_access_time))
562 file_node->dn_access = 1;
563 if (VATTR_IS_ACTIVE(vap, va_modify_time)) {
564 file_node->dn_change = 1;
565 file_node->dn_update = 1;
566 }
567 atimeval.tv_sec = vap->va_access_time.tv_sec;
568 atimeval.tv_usec = vap->va_access_time.tv_nsec / 1000;
569 mtimeval.tv_sec = vap->va_modify_time.tv_sec;
570 mtimeval.tv_usec = vap->va_modify_time.tv_nsec / 1000;
571
572 if ( (error = devfs_update(vp, &atimeval, &mtimeval)) )
573 goto exit;
574 }
575 VATTR_SET_SUPPORTED(vap, va_access_time);
576 VATTR_SET_SUPPORTED(vap, va_change_time);
577
578 /*
579 * Change the permissions.
580 */
581 if (VATTR_IS_ACTIVE(vap, va_mode)) {
582 file_node->dn_mode &= ~07777;
583 file_node->dn_mode |= vap->va_mode & 07777;
584 }
585 VATTR_SET_SUPPORTED(vap, va_mode);
586
587 /*
588 * Change the owner.
589 */
590 if (VATTR_IS_ACTIVE(vap, va_uid))
591 file_node->dn_uid = vap->va_uid;
592 VATTR_SET_SUPPORTED(vap, va_uid);
593
594 /*
595 * Change the group.
596 */
597 if (VATTR_IS_ACTIVE(vap, va_gid))
598 file_node->dn_gid = vap->va_gid;
599 VATTR_SET_SUPPORTED(vap, va_gid);
600 exit:
601 DEVFS_UNLOCK();
602
603 return error;
604 }
605
606 #if CONFIG_MACF
607 static int
608 devfs_setlabel(struct vnop_setlabel_args *ap)
609 /* struct vnop_setlabel_args {
610 struct vnodeop_desc *a_desc;
611 struct vnode *a_vp;
612 struct label *a_vl;
613 vfs_context_t a_context;
614 } */
615 {
616 struct vnode *vp;
617 struct devnode *de;
618
619 vp = ap->a_vp;
620 de = VTODN(vp);
621
622 mac_vnode_label_update(ap->a_context, vp, ap->a_vl);
623 mac_devfs_label_update(vp->v_mount, de, vp);
624
625 return (0);
626 }
627 #endif
628
629 static int
630 devfs_read(struct vnop_read_args *ap)
631 /* struct vnop_read_args {
632 struct vnode *a_vp;
633 struct uio *a_uio;
634 int a_ioflag;
635 vfs_context_t a_context;
636 } */
637 {
638 devnode_t * dn_p = VTODN(ap->a_vp);
639
640 switch (ap->a_vp->v_type) {
641 case VDIR: {
642 dn_p->dn_access = 1;
643
644 return VNOP_READDIR(ap->a_vp, ap->a_uio, 0, NULL, NULL, ap->a_context);
645 }
646 default: {
647 printf("devfs_read(): bad file type %d", ap->a_vp->v_type);
648 return(EINVAL);
649 }
650 }
651 }
652
653 static int
654 devfs_close(struct vnop_close_args *ap)
655 /* struct vnop_close_args {
656 struct vnode *a_vp;
657 int a_fflag;
658 vfs_context_t a_context;
659 } */
660 {
661 struct vnode * vp = ap->a_vp;
662 devnode_t * dnp;
663
664 if (vnode_isinuse(vp, 1)) {
665 DEVFS_LOCK();
666 dnp = VTODN(vp);
667 if (dnp)
668 dn_times_now(dnp, 0);
669 DEVFS_UNLOCK();
670 }
671 return (0);
672 }
673
674 static int
675 devfsspec_close(struct vnop_close_args *ap)
676 /* struct vnop_close_args {
677 struct vnode *a_vp;
678 int a_fflag;
679 vfs_context_t a_context;
680 } */
681 {
682 struct vnode * vp = ap->a_vp;
683 devnode_t * dnp;
684
685 if (vnode_isinuse(vp, 0)) {
686 DEVFS_LOCK();
687 dnp = VTODN(vp);
688 if (dnp)
689 dn_times_now(dnp, 0);
690 DEVFS_UNLOCK();
691 }
692
693 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_close), ap));
694 }
695
696 static boolean_t
697 devfs_update_needed(long now_s, long last_s)
698 {
699 if (now_s > last_s) {
700 if (now_s - last_s >= DEVFS_LAZY_UPDATE_SECONDS) {
701 return TRUE;
702 }
703 }
704
705 return FALSE;
706 }
707
708 /*
709 * Given a set of time updates required [to happen at some point], check
710 * either make those changes (and resolve other pending updates) or mark
711 * the devnode for a subsequent update.
712 */
713 static void
714 devfs_consider_time_update(devnode_t *dnp, uint32_t just_changed_flags)
715 {
716 struct timeval now;
717 long now_s;
718
719 microtime(&now);
720 now_s = now.tv_sec;
721
722 if (dnp->dn_change || (just_changed_flags & DEVFS_UPDATE_CHANGE)) {
723 if (devfs_update_needed(now_s, dnp->dn_ctime.tv_sec)) {
724 dn_times_now(dnp, just_changed_flags);
725 return;
726 }
727 }
728 if (dnp->dn_access || (just_changed_flags & DEVFS_UPDATE_ACCESS)) {
729 if (devfs_update_needed(now_s, dnp->dn_atime.tv_sec)) {
730 dn_times_now(dnp, just_changed_flags);
731 return;
732 }
733 }
734 if (dnp->dn_update || (just_changed_flags & DEVFS_UPDATE_MOD)) {
735 if (devfs_update_needed(now_s, dnp->dn_mtime.tv_sec)) {
736 dn_times_now(dnp, just_changed_flags);
737 return;
738 }
739 }
740
741 /* Not going to do anything now--mark for later update */
742 dn_mark_for_delayed_times_update(dnp, just_changed_flags);
743
744 return;
745 }
746
747 static int
748 devfsspec_read(struct vnop_read_args *ap)
749 /* struct vnop_read_args {
750 struct vnode *a_vp;
751 struct uio *a_uio;
752 int a_ioflag;
753 kauth_cred_t a_cred;
754 } */
755 {
756 devnode_t * dnp = VTODN(ap->a_vp);
757
758 devfs_consider_time_update(dnp, DEVFS_UPDATE_ACCESS);
759
760 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_read), ap));
761 }
762
763 static int
764 devfsspec_write(struct vnop_write_args *ap)
765 /* struct vnop_write_args {
766 struct vnode *a_vp;
767 struct uio *a_uio;
768 int a_ioflag;
769 vfs_context_t a_context;
770 } */
771 {
772 devnode_t * dnp = VTODN(ap->a_vp);
773
774 devfs_consider_time_update(dnp, DEVFS_UPDATE_CHANGE | DEVFS_UPDATE_MOD);
775
776 return (VOCALL (spec_vnodeop_p, VOFFSET(vnop_write), ap));
777 }
778
779 /*
780 * Write data to a file or directory.
781 */
782 static int
783 devfs_write(struct vnop_write_args *ap)
784 /* struct vnop_write_args {
785 struct vnode *a_vp;
786 struct uio *a_uio;
787 int a_ioflag;
788 kauth_cred_t a_cred;
789 } */
790 {
791 switch (ap->a_vp->v_type) {
792 case VDIR:
793 return(EISDIR);
794 default:
795 printf("devfs_write(): bad file type %d", ap->a_vp->v_type);
796 return (EINVAL);
797 }
798 }
799
800 /*
801 * Deviates from UFS naming convention because there is a KPI function
802 * called devfs_remove().
803 */
804 static int
805 devfs_vnop_remove(struct vnop_remove_args *ap)
806 /* struct vnop_remove_args {
807 struct vnode *a_dvp;
808 struct vnode *a_vp;
809 struct componentname *a_cnp;
810 } */
811 {
812 struct vnode *vp = ap->a_vp;
813 struct vnode *dvp = ap->a_dvp;
814 struct componentname *cnp = ap->a_cnp;
815 devnode_t * tp;
816 devnode_t * tdp;
817 devdirent_t * tnp;
818 int doingdirectory = 0;
819 int error = 0;
820
821 /*
822 * assume that the name is null terminated as they
823 * are the end of the path. Get pointers to all our
824 * devfs structures.
825 */
826
827 DEVFS_LOCK();
828
829 tp = VTODN(vp);
830 tdp = VTODN(dvp);
831
832
833 tnp = dev_findname(tdp, cnp->cn_nameptr);
834
835 if (tnp == NULL) {
836 error = ENOENT;
837 goto abort;
838 }
839
840 /*
841 * Don't allow removing critical devfs devices
842 */
843 if (devfs_is_name_protected(dvp, cnp->cn_nameptr)) {
844 error = EINVAL;
845 goto abort;
846 }
847
848 /*
849 * Make sure that we don't try do something stupid
850 */
851 if ((tp->dn_type) == DEV_DIR) {
852 /*
853 * Avoid ".", "..", and aliases of "." for obvious reasons.
854 */
855 if ( (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.')
856 || (cnp->cn_flags&ISDOTDOT) ) {
857 error = EINVAL;
858 goto abort;
859 }
860 doingdirectory++;
861 }
862
863 /***********************************
864 * Start actually doing things.... *
865 ***********************************/
866 devfs_consider_time_update(tdp, DEVFS_UPDATE_CHANGE | DEVFS_UPDATE_MOD);
867
868 /*
869 * Target must be empty if a directory and have no links
870 * to it. Also, ensure source and target are compatible
871 * (both directories, or both not directories).
872 */
873 if (( doingdirectory) && (tp->dn_links > 2)) {
874 error = ENOTEMPTY;
875 goto abort;
876 }
877 dev_free_name(tnp);
878 abort:
879 DEVFS_UNLOCK();
880
881 return (error);
882 }
883
884 /*
885 */
886 static int
887 devfs_link(struct vnop_link_args *ap)
888 /*struct vnop_link_args {
889 struct vnode *a_tdvp;
890 struct vnode *a_vp;
891 struct componentname *a_cnp;
892 vfs_context_t a_context;
893 } */
894 {
895 struct vnode *vp = ap->a_vp;
896 struct vnode *tdvp = ap->a_tdvp;
897 struct componentname *cnp = ap->a_cnp;
898 devnode_t * fp;
899 devnode_t * tdp;
900 devdirent_t * tnp;
901 int error = 0;
902
903 /*
904 * First catch an arbitrary restriction for this FS
905 */
906 if (cnp->cn_namelen > DEVMAXNAMESIZE) {
907 error = ENAMETOOLONG;
908 goto out1;
909 }
910
911 /*
912 * Lock our directories and get our name pointers
913 * assume that the names are null terminated as they
914 * are the end of the path. Get pointers to all our
915 * devfs structures.
916 */
917 /* can lookup dnode safely for tdvp outside of devfs lock as it is not aliased */
918 tdp = VTODN(tdvp);
919
920 if (tdvp->v_mount != vp->v_mount) {
921 return (EXDEV);
922 }
923 DEVFS_LOCK();
924
925 fp = VTODN(vp);
926
927 /***********************************
928 * Start actually doing things.... *
929 ***********************************/
930 dn_times_now(fp, DEVFS_UPDATE_CHANGE);
931
932 if (!error) {
933 error = dev_add_name(cnp->cn_nameptr, tdp, NULL, fp, &tnp);
934 }
935 out1:
936 DEVFS_UNLOCK();
937
938 return (error);
939 }
940
941 /*
942 * Rename system call. Seems overly complicated to me...
943 * rename("foo", "bar");
944 * is essentially
945 * unlink("bar");
946 * link("foo", "bar");
947 * unlink("foo");
948 * but ``atomically''.
949 *
950 * When the target exists, both the directory
951 * and target vnodes are locked.
952 * the source and source-parent vnodes are referenced
953 *
954 *
955 * Basic algorithm is:
956 *
957 * 1) Bump link count on source while we're linking it to the
958 * target. This also ensure the inode won't be deleted out
959 * from underneath us while we work (it may be truncated by
960 * a concurrent `trunc' or `open' for creation).
961 * 2) Link source to destination. If destination already exists,
962 * delete it first.
963 * 3) Unlink source reference to node if still around. If a
964 * directory was moved and the parent of the destination
965 * is different from the source, patch the ".." entry in the
966 * directory.
967 */
968 static int
969 devfs_rename(struct vnop_rename_args *ap)
970 /*struct vnop_rename_args {
971 struct vnode *a_fdvp;
972 struct vnode *a_fvp;
973 struct componentname *a_fcnp;
974 struct vnode *a_tdvp;
975 struct vnode *a_tvp;
976 struct componentname *a_tcnp;
977 vfs_context_t a_context;
978 } */
979 {
980 struct vnode *tvp = ap->a_tvp;
981 struct vnode *tdvp = ap->a_tdvp;
982 struct vnode *fvp = ap->a_fvp;
983 struct vnode *fdvp = ap->a_fdvp;
984 struct componentname *tcnp = ap->a_tcnp;
985 struct componentname *fcnp = ap->a_fcnp;
986 devnode_t *fp, *fdp, *tp, *tdp;
987 devdirent_t *fnp,*tnp;
988 int doingdirectory = 0;
989 int error = 0;
990
991 DEVFS_LOCK();
992 /*
993 * First catch an arbitrary restriction for this FS
994 */
995 if (tcnp->cn_namelen > DEVMAXNAMESIZE) {
996 error = ENAMETOOLONG;
997 goto out;
998 }
999
1000 /*
1001 * assume that the names are null terminated as they
1002 * are the end of the path. Get pointers to all our
1003 * devfs structures.
1004 */
1005 tdp = VTODN(tdvp);
1006 fdp = VTODN(fdvp);
1007 fp = VTODN(fvp);
1008
1009 fnp = dev_findname(fdp, fcnp->cn_nameptr);
1010
1011 if (fnp == NULL) {
1012 error = ENOENT;
1013 goto out;
1014 }
1015 tp = NULL;
1016 tnp = NULL;
1017
1018 if (tvp) {
1019 tnp = dev_findname(tdp, tcnp->cn_nameptr);
1020
1021 if (tnp == NULL) {
1022 error = ENOENT;
1023 goto out;
1024 }
1025 tp = VTODN(tvp);
1026 }
1027
1028 /*
1029 * Make sure that we don't try do something stupid
1030 */
1031 if ((fp->dn_type) == DEV_DIR) {
1032 /*
1033 * Avoid ".", "..", and aliases of "." for obvious reasons.
1034 */
1035 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.')
1036 || (fcnp->cn_flags&ISDOTDOT)
1037 || (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.')
1038 || (tcnp->cn_flags&ISDOTDOT)
1039 || (tdp == fp )) {
1040 error = EINVAL;
1041 goto out;
1042 }
1043 doingdirectory++;
1044 }
1045
1046 /*
1047 * Don't allow renaming critical devfs devices
1048 */
1049 if (devfs_is_name_protected(fdvp, fcnp->cn_nameptr) ||
1050 devfs_is_name_protected(tdvp, tcnp->cn_nameptr)) {
1051 error = EINVAL;
1052 goto out;
1053 }
1054
1055 /*
1056 * If ".." must be changed (ie the directory gets a new
1057 * parent) then the source directory must not be in the
1058 * directory hierarchy above the target, as this would
1059 * orphan everything below the source directory. Also
1060 * the user must have write permission in the source so
1061 * as to be able to change "..".
1062 */
1063 if (doingdirectory && (tdp != fdp)) {
1064 devnode_t * tmp, *ntmp;
1065 tmp = tdp;
1066 do {
1067 if(tmp == fp) {
1068 /* XXX unlock stuff here probably */
1069 error = EINVAL;
1070 goto out;
1071 }
1072 ntmp = tmp;
1073 } while ((tmp = tmp->dn_typeinfo.Dir.parent) != ntmp);
1074 }
1075
1076 /***********************************
1077 * Start actually doing things.... *
1078 ***********************************/
1079 dn_times_now(fp, DEVFS_UPDATE_CHANGE);
1080
1081 /*
1082 * Check if just deleting a link name.
1083 */
1084 if (fvp == tvp) {
1085 if (fvp->v_type == VDIR) {
1086 error = EINVAL;
1087 goto out;
1088 }
1089 /* Release destination completely. */
1090 dev_free_name(fnp);
1091
1092 DEVFS_UNLOCK();
1093 return 0;
1094 }
1095 /*
1096 * 1) Bump link count while we're moving stuff
1097 * around. If we crash somewhere before
1098 * completing our work, too bad :)
1099 */
1100 fp->dn_links++;
1101 /*
1102 * If the target exists zap it (unless it's a non-empty directory)
1103 * We could do that as well but won't
1104 */
1105 if (tp) {
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
1122 dev_free_name(fnp);
1123 bad:
1124 fp->dn_links--; /* we added one earlier*/
1125 out:
1126 DEVFS_UNLOCK();
1127 return (error);
1128 }
1129
1130 static int
1131 devfs_mkdir(struct vnop_mkdir_args *ap)
1132 /*struct vnop_mkdir_args {
1133 struct vnode *a_dvp;
1134 struct vnode **a_vpp;
1135 struct componentname *a_cnp;
1136 struct vnode_attr *a_vap;
1137 vfs_context_t a_context;
1138 } */
1139 {
1140 struct componentname * cnp = ap->a_cnp;
1141 vfs_context_t ctx = cnp->cn_context;
1142 struct proc *p = vfs_context_proc(ctx);
1143 int error = 0;
1144 devnode_t * dir_p;
1145 devdirent_t * nm_p;
1146 devnode_t * dev_p;
1147 struct vnode_attr * vap = ap->a_vap;
1148 struct vnode * * vpp = ap->a_vpp;
1149
1150 DEVFS_LOCK();
1151
1152 dir_p = VTODN(ap->a_dvp);
1153 error = dev_add_entry(cnp->cn_nameptr, dir_p, DEV_DIR,
1154 NULL, NULL, NULL, &nm_p);
1155 if (error) {
1156 goto failure;
1157 }
1158 dev_p = nm_p->de_dnp;
1159 dev_p->dn_uid = dir_p->dn_uid;
1160 dev_p->dn_gid = dir_p->dn_gid;
1161 dev_p->dn_mode = vap->va_mode;
1162 dn_copy_times(dev_p, dir_p);
1163
1164 error = devfs_dntovn(dev_p, vpp, p);
1165 failure:
1166 DEVFS_UNLOCK();
1167
1168 return error;
1169 }
1170
1171 /*
1172 * An rmdir is a special type of remove, which we already support; we wrap
1173 * and reexpress the arguments to call devfs_remove directly. The only
1174 * different argument is flags, which we do not set, since it's ignored.
1175 */
1176 static int
1177 devfs_rmdir(struct vnop_rmdir_args *ap)
1178 /* struct vnop_rmdir_args {
1179 struct vnode *a_dvp;
1180 struct vnode *a_vp;
1181 struct componentname *a_cnp;
1182 vfs_context_t a_context;
1183 } */
1184 {
1185 struct vnop_remove_args ra;
1186
1187 ra.a_dvp = ap->a_dvp;
1188 ra.a_vp = ap->a_vp;
1189 ra.a_cnp = ap->a_cnp;
1190 ra.a_flags = 0; /* XXX */
1191 ra.a_context = ap->a_context;
1192
1193 return devfs_vnop_remove(&ra);
1194 }
1195
1196
1197 static int
1198 devfs_symlink(struct vnop_symlink_args *ap)
1199 /*struct vnop_symlink_args {
1200 struct vnode *a_dvp;
1201 struct vnode **a_vpp;
1202 struct componentname *a_cnp;
1203 struct vnode_attr *a_vap;
1204 char *a_target;
1205 vfs_context_t a_context;
1206 } */
1207 {
1208 int error;
1209 devdirent_t *newent;
1210
1211 DEVFS_LOCK();
1212 error = devfs_make_symlink(VTODN(ap->a_dvp), ap->a_cnp->cn_nameptr, ap->a_vap->va_mode, ap->a_target, &newent);
1213
1214 if (error == 0) {
1215 error = devfs_dntovn(newent->de_dnp, ap->a_vpp, vfs_context_proc(ap->a_context));
1216 }
1217
1218 DEVFS_UNLOCK();
1219
1220 return error;
1221
1222 }
1223
1224 /* Called with devfs locked */
1225 int
1226 devfs_make_symlink(devnode_t *dir_p, char *name, int mode, char *target, devdirent_t **newent)
1227 {
1228 int error = 0;
1229 devnode_type_t typeinfo;
1230 devdirent_t * nm_p;
1231 devnode_t * dev_p;
1232
1233 typeinfo.Slnk.name = target;
1234 typeinfo.Slnk.namelen = strlen(target);
1235
1236 error = dev_add_entry(name, dir_p, DEV_SLNK,
1237 &typeinfo, NULL, NULL, &nm_p);
1238 if (error) {
1239 goto failure;
1240 }
1241 dev_p = nm_p->de_dnp;
1242 dev_p->dn_uid = dir_p->dn_uid;
1243 dev_p->dn_gid = dir_p->dn_gid;
1244 dev_p->dn_mode = mode;
1245 dn_copy_times(dev_p, dir_p);
1246
1247 if (newent) {
1248 *newent = nm_p;
1249 }
1250
1251 failure:
1252
1253 return error;
1254 }
1255
1256 /*
1257 * Mknod vnode call
1258 */
1259 static int
1260 devfs_mknod(struct vnop_mknod_args *ap)
1261 /* struct vnop_mknod_args {
1262 struct vnode *a_dvp;
1263 struct vnode **a_vpp;
1264 struct componentname *a_cnp;
1265 struct vnode_attr *a_vap;
1266 vfs_context_t a_context;
1267 } */
1268 {
1269 struct componentname * cnp = ap->a_cnp;
1270 vfs_context_t ctx = cnp->cn_context;
1271 struct proc *p = vfs_context_proc(ctx);
1272 devnode_t * dev_p;
1273 devdirent_t * devent;
1274 devnode_t * dir_p; /* devnode for parent directory */
1275 struct vnode * dvp = ap->a_dvp;
1276 int error = 0;
1277 devnode_type_t typeinfo;
1278 struct vnode_attr * vap = ap->a_vap;
1279 struct vnode ** vpp = ap->a_vpp;
1280
1281 *vpp = NULL;
1282 if (!(vap->va_type == VBLK) && !(vap->va_type == VCHR)) {
1283 return (EINVAL); /* only support mknod of special files */
1284 }
1285 typeinfo.dev = vap->va_rdev;
1286
1287 DEVFS_LOCK();
1288
1289 dir_p = VTODN(dvp);
1290
1291 error = dev_add_entry(cnp->cn_nameptr, dir_p,
1292 (vap->va_type == VBLK) ? DEV_BDEV : DEV_CDEV,
1293 &typeinfo, NULL, NULL, &devent);
1294 if (error) {
1295 goto failure;
1296 }
1297 dev_p = devent->de_dnp;
1298 error = devfs_dntovn(dev_p, vpp, p);
1299 if (error)
1300 goto failure;
1301 dev_p->dn_uid = vap->va_uid;
1302 dev_p->dn_gid = vap->va_gid;
1303 dev_p->dn_mode = vap->va_mode;
1304 VATTR_SET_SUPPORTED(vap, va_uid);
1305 VATTR_SET_SUPPORTED(vap, va_gid);
1306 VATTR_SET_SUPPORTED(vap, va_mode);
1307 failure:
1308 DEVFS_UNLOCK();
1309
1310 return (error);
1311 }
1312
1313 /*
1314 * Vnode op for readdir
1315 */
1316 static int
1317 devfs_readdir(struct vnop_readdir_args *ap)
1318 /*struct vnop_readdir_args {
1319 struct vnode *a_vp;
1320 struct uio *a_uio;
1321 int a_flags;
1322 int *a_eofflag;
1323 int *a_numdirent;
1324 vfs_context_t a_context;
1325 } */
1326 {
1327 struct vnode *vp = ap->a_vp;
1328 struct uio *uio = ap->a_uio;
1329 struct dirent dirent;
1330 devnode_t * dir_node;
1331 devdirent_t * name_node;
1332 const char *name;
1333 int error = 0;
1334 int reclen;
1335 int nodenumber;
1336 int startpos,pos;
1337
1338 if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF))
1339 return (EINVAL);
1340
1341 /* set up refs to dir */
1342 dir_node = VTODN(vp);
1343 if (dir_node->dn_type != DEV_DIR)
1344 return(ENOTDIR);
1345 pos = 0;
1346 startpos = uio->uio_offset;
1347
1348 DEVFS_LOCK();
1349
1350 name_node = dir_node->dn_typeinfo.Dir.dirlist;
1351 nodenumber = 0;
1352
1353 while ((name_node || (nodenumber < 2)) && (uio_resid(uio) > 0))
1354 {
1355 switch(nodenumber)
1356 {
1357 case 0:
1358 dirent.d_fileno = dir_node->dn_ino;
1359 name = ".";
1360 dirent.d_namlen = 1;
1361 dirent.d_type = DT_DIR;
1362 break;
1363 case 1:
1364 if(dir_node->dn_typeinfo.Dir.parent)
1365 dirent.d_fileno = dir_node->dn_typeinfo.Dir.parent->dn_ino;
1366 else
1367 dirent.d_fileno = dir_node->dn_ino;
1368 name = "..";
1369 dirent.d_namlen = 2;
1370 dirent.d_type = DT_DIR;
1371 break;
1372 default:
1373 dirent.d_fileno = name_node->de_dnp->dn_ino;
1374 dirent.d_namlen = strlen(name_node->de_name);
1375 name = name_node->de_name;
1376 switch(name_node->de_dnp->dn_type) {
1377 case DEV_BDEV:
1378 dirent.d_type = DT_BLK;
1379 break;
1380 case DEV_CDEV:
1381 dirent.d_type = DT_CHR;
1382 break;
1383 case DEV_DIR:
1384 dirent.d_type = DT_DIR;
1385 break;
1386 case DEV_SLNK:
1387 dirent.d_type = DT_LNK;
1388 break;
1389 default:
1390 dirent.d_type = DT_UNKNOWN;
1391 }
1392 }
1393 #define GENERIC_DIRSIZ(dp) \
1394 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
1395
1396 reclen = dirent.d_reclen = GENERIC_DIRSIZ(&dirent);
1397
1398 if(pos >= startpos) /* made it to the offset yet? */
1399 {
1400 if (uio_resid(uio) < reclen) /* will it fit? */
1401 break;
1402 strlcpy(dirent.d_name, name, DEVMAXNAMESIZE);
1403 if ((error = uiomove ((caddr_t)&dirent,
1404 dirent.d_reclen, uio)) != 0)
1405 break;
1406 }
1407 pos += reclen;
1408 if((nodenumber >1) && name_node)
1409 name_node = name_node->de_next;
1410 nodenumber++;
1411 }
1412 DEVFS_UNLOCK();
1413 uio->uio_offset = pos;
1414
1415 devfs_consider_time_update(dir_node, DEVFS_UPDATE_ACCESS);
1416
1417 return (error);
1418 }
1419
1420
1421 /*
1422 */
1423 static int
1424 devfs_readlink(struct vnop_readlink_args *ap)
1425 /*struct vnop_readlink_args {
1426 struct vnode *a_vp;
1427 struct uio *a_uio;
1428 vfs_context_t a_context;
1429 } */
1430 {
1431 struct vnode *vp = ap->a_vp;
1432 struct uio *uio = ap->a_uio;
1433 devnode_t * lnk_node;
1434 int error = 0;
1435
1436 /* set up refs to dir */
1437 lnk_node = VTODN(vp);
1438
1439 if (lnk_node->dn_type != DEV_SLNK) {
1440 error = EINVAL;
1441 goto out;
1442 }
1443 error = uiomove(lnk_node->dn_typeinfo.Slnk.name,
1444 lnk_node->dn_typeinfo.Slnk.namelen, uio);
1445 out:
1446 return error;
1447 }
1448
1449 static int
1450 devfs_reclaim(struct vnop_reclaim_args *ap)
1451 /*struct vnop_reclaim_args {
1452 struct vnode *a_vp;
1453 } */
1454 {
1455 struct vnode * vp = ap->a_vp;
1456 devnode_t * dnp;
1457
1458 DEVFS_LOCK();
1459
1460 dnp = VTODN(vp);
1461
1462 if (dnp) {
1463 /* If this is a cloning device, it didn't have a dn_vn anyway */
1464 dnp->dn_vn = NULL;
1465 vnode_clearfsnode(vp);
1466
1467 /* This could delete the node, if we are the last vnode */
1468 devfs_rele_node(dnp);
1469 }
1470 DEVFS_UNLOCK();
1471
1472 return(0);
1473 }
1474
1475
1476 /*
1477 * Get configurable pathname variables.
1478 */
1479 static int
1480 devs_vnop_pathconf(
1481 struct vnop_pathconf_args /* {
1482 struct vnode *a_vp;
1483 int a_name;
1484 int *a_retval;
1485 vfs_context_t a_context;
1486 } */ *ap)
1487 {
1488 switch (ap->a_name) {
1489 case _PC_LINK_MAX:
1490 /* arbitrary limit matching HFS; devfs has no hard limit */
1491 *ap->a_retval = 32767;
1492 break;
1493 case _PC_NAME_MAX:
1494 *ap->a_retval = DEVMAXNAMESIZE - 1; /* includes NUL */
1495 break;
1496 case _PC_PATH_MAX:
1497 *ap->a_retval = DEVMAXPATHSIZE - 1; /* XXX nonconformant */
1498 break;
1499 case _PC_CHOWN_RESTRICTED:
1500 *ap->a_retval = 200112; /* _POSIX_CHOWN_RESTRICTED */
1501 break;
1502 case _PC_NO_TRUNC:
1503 *ap->a_retval = 0;
1504 break;
1505 case _PC_CASE_SENSITIVE:
1506 *ap->a_retval = 1;
1507 break;
1508 case _PC_CASE_PRESERVING:
1509 *ap->a_retval = 1;
1510 break;
1511 default:
1512 return (EINVAL);
1513 }
1514
1515 return (0);
1516 }
1517
1518
1519
1520 /**************************************************************************\
1521 * pseudo ops *
1522 \**************************************************************************/
1523
1524 /*
1525 *
1526 * struct vnop_inactive_args {
1527 * struct vnode *a_vp;
1528 * vfs_context_t a_context;
1529 * }
1530 */
1531
1532 static int
1533 devfs_inactive(__unused struct vnop_inactive_args *ap)
1534 {
1535 vnode_t vp = ap->a_vp;
1536 devnode_t *dnp = VTODN(vp);
1537
1538 /*
1539 * Cloned vnodes are not linked in anywhere, so they
1540 * can just be recycled.
1541 */
1542 if (dnp->dn_clone != NULL) {
1543 vnode_recycle(vp);
1544 }
1545
1546 return (0);
1547 }
1548
1549 /*
1550 * called with DEVFS_LOCK held
1551 */
1552 static int
1553 devfs_update(struct vnode *vp, struct timeval *access, struct timeval *modify)
1554 {
1555 devnode_t * ip;
1556 struct timeval now;
1557
1558 ip = VTODN(vp);
1559 if (vp->v_mount->mnt_flag & MNT_RDONLY) {
1560 ip->dn_access = 0;
1561 ip->dn_change = 0;
1562 ip->dn_update = 0;
1563
1564 return (0);
1565 }
1566
1567 DEVFS_ATTR_LOCK_SPIN();
1568 microtime(&now);
1569 dn_times_locked(ip, access, modify, &now, DEVFS_UPDATE_ACCESS | DEVFS_UPDATE_MOD);
1570 DEVFS_ATTR_UNLOCK();
1571
1572 return (0);
1573 }
1574
1575 #define VOPFUNC int (*)(void *)
1576
1577 /* The following ops are used by directories and symlinks */
1578 int (**devfs_vnodeop_p)(void *);
1579 static struct vnodeopv_entry_desc devfs_vnodeop_entries[] = {
1580 { &vnop_default_desc, (VOPFUNC)vn_default_error },
1581 { &vnop_lookup_desc, (VOPFUNC)devfs_lookup }, /* lookup */
1582 { &vnop_create_desc, (VOPFUNC)err_create }, /* create */
1583 { &vnop_whiteout_desc, (VOPFUNC)err_whiteout }, /* whiteout */
1584 { &vnop_mknod_desc, (VOPFUNC)devfs_mknod }, /* mknod */
1585 { &vnop_open_desc, (VOPFUNC)nop_open }, /* open */
1586 { &vnop_close_desc, (VOPFUNC)devfs_close }, /* close */
1587 { &vnop_getattr_desc, (VOPFUNC)devfs_getattr }, /* getattr */
1588 { &vnop_setattr_desc, (VOPFUNC)devfs_setattr }, /* setattr */
1589 { &vnop_read_desc, (VOPFUNC)devfs_read }, /* read */
1590 { &vnop_write_desc, (VOPFUNC)devfs_write }, /* write */
1591 { &vnop_ioctl_desc, (VOPFUNC)err_ioctl }, /* ioctl */
1592 { &vnop_select_desc, (VOPFUNC)err_select }, /* select */
1593 { &vnop_revoke_desc, (VOPFUNC)err_revoke }, /* revoke */
1594 { &vnop_mmap_desc, (VOPFUNC)err_mmap }, /* mmap */
1595 { &vnop_fsync_desc, (VOPFUNC)nop_fsync }, /* fsync */
1596 { &vnop_remove_desc, (VOPFUNC)devfs_vnop_remove }, /* remove */
1597 { &vnop_link_desc, (VOPFUNC)devfs_link }, /* link */
1598 { &vnop_rename_desc, (VOPFUNC)devfs_rename }, /* rename */
1599 { &vnop_mkdir_desc, (VOPFUNC)devfs_mkdir }, /* mkdir */
1600 { &vnop_rmdir_desc, (VOPFUNC)devfs_rmdir }, /* rmdir */
1601 { &vnop_symlink_desc, (VOPFUNC)devfs_symlink }, /* symlink */
1602 { &vnop_readdir_desc, (VOPFUNC)devfs_readdir }, /* readdir */
1603 { &vnop_readlink_desc, (VOPFUNC)devfs_readlink }, /* readlink */
1604 { &vnop_inactive_desc, (VOPFUNC)devfs_inactive }, /* inactive */
1605 { &vnop_reclaim_desc, (VOPFUNC)devfs_reclaim }, /* reclaim */
1606 { &vnop_strategy_desc, (VOPFUNC)err_strategy }, /* strategy */
1607 { &vnop_pathconf_desc, (VOPFUNC)devs_vnop_pathconf }, /* pathconf */
1608 { &vnop_advlock_desc, (VOPFUNC)err_advlock }, /* advlock */
1609 { &vnop_bwrite_desc, (VOPFUNC)err_bwrite },
1610 { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */
1611 { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */
1612 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */
1613 { &vnop_blktooff_desc, (VOPFUNC)err_blktooff }, /* blktooff */
1614 { &vnop_offtoblk_desc, (VOPFUNC)err_offtoblk }, /* offtoblk */
1615 { &vnop_blockmap_desc, (VOPFUNC)err_blockmap }, /* blockmap */
1616 #if CONFIG_MACF
1617 { &vnop_setlabel_desc, (VOPFUNC)devfs_setlabel }, /* setlabel */
1618 #endif
1619 { (struct vnodeop_desc*)NULL, (int(*)(void *))NULL }
1620 };
1621 struct vnodeopv_desc devfs_vnodeop_opv_desc =
1622 { &devfs_vnodeop_p, devfs_vnodeop_entries };
1623
1624 /* The following ops are used by the device nodes */
1625 int (**devfs_spec_vnodeop_p)(void *);
1626 static struct vnodeopv_entry_desc devfs_spec_vnodeop_entries[] = {
1627 { &vnop_default_desc, (VOPFUNC)vn_default_error },
1628 { &vnop_lookup_desc, (VOPFUNC)spec_lookup }, /* lookup */
1629 { &vnop_create_desc, (VOPFUNC)spec_create }, /* create */
1630 { &vnop_mknod_desc, (VOPFUNC)spec_mknod }, /* mknod */
1631 { &vnop_open_desc, (VOPFUNC)spec_open }, /* open */
1632 { &vnop_close_desc, (VOPFUNC)devfsspec_close }, /* close */
1633 { &vnop_getattr_desc, (VOPFUNC)devfs_getattr }, /* getattr */
1634 { &vnop_setattr_desc, (VOPFUNC)devfs_setattr }, /* setattr */
1635 { &vnop_read_desc, (VOPFUNC)devfsspec_read }, /* read */
1636 { &vnop_write_desc, (VOPFUNC)devfsspec_write }, /* write */
1637 { &vnop_ioctl_desc, (VOPFUNC)spec_ioctl }, /* ioctl */
1638 { &vnop_select_desc, (VOPFUNC)spec_select }, /* select */
1639 { &vnop_revoke_desc, (VOPFUNC)spec_revoke }, /* revoke */
1640 { &vnop_mmap_desc, (VOPFUNC)spec_mmap }, /* mmap */
1641 { &vnop_fsync_desc, (VOPFUNC)spec_fsync }, /* fsync */
1642 { &vnop_remove_desc, (VOPFUNC)devfs_vnop_remove }, /* remove */
1643 { &vnop_link_desc, (VOPFUNC)devfs_link }, /* link */
1644 { &vnop_rename_desc, (VOPFUNC)spec_rename }, /* rename */
1645 { &vnop_mkdir_desc, (VOPFUNC)spec_mkdir }, /* mkdir */
1646 { &vnop_rmdir_desc, (VOPFUNC)spec_rmdir }, /* rmdir */
1647 { &vnop_symlink_desc, (VOPFUNC)spec_symlink }, /* symlink */
1648 { &vnop_readdir_desc, (VOPFUNC)spec_readdir }, /* readdir */
1649 { &vnop_readlink_desc, (VOPFUNC)spec_readlink }, /* readlink */
1650 { &vnop_inactive_desc, (VOPFUNC)devfs_inactive }, /* inactive */
1651 { &vnop_reclaim_desc, (VOPFUNC)devfs_reclaim }, /* reclaim */
1652 { &vnop_strategy_desc, (VOPFUNC)spec_strategy }, /* strategy */
1653 { &vnop_pathconf_desc, (VOPFUNC)spec_pathconf }, /* pathconf */
1654 { &vnop_advlock_desc, (VOPFUNC)spec_advlock }, /* advlock */
1655 { &vnop_bwrite_desc, (VOPFUNC)vn_bwrite },
1656 { &vnop_pagein_desc, (VOPFUNC)err_pagein }, /* Pagein */
1657 { &vnop_pageout_desc, (VOPFUNC)err_pageout }, /* Pageout */
1658 { &vnop_copyfile_desc, (VOPFUNC)err_copyfile }, /* Copyfile */
1659 { &vnop_blktooff_desc, (VOPFUNC)spec_blktooff }, /* blktooff */
1660 { &vnop_blktooff_desc, (VOPFUNC)spec_offtoblk }, /* blkofftoblk */
1661 { &vnop_blockmap_desc, (VOPFUNC)spec_blockmap }, /* blockmap */
1662 #if CONFIG_MACF
1663 { &vnop_setlabel_desc, (VOPFUNC)devfs_setlabel }, /* setlabel */
1664 #endif
1665 { (struct vnodeop_desc*)NULL, (int(*)(void *))NULL }
1666 };
1667 struct vnodeopv_desc devfs_spec_vnodeop_opv_desc =
1668 { &devfs_spec_vnodeop_p, devfs_spec_vnodeop_entries };
1669
1670
1671 #if FDESC
1672 int (**devfs_devfd_vnodeop_p)(void*);
1673 static struct vnodeopv_entry_desc devfs_devfd_vnodeop_entries[] = {
1674 { &vnop_default_desc, (VOPFUNC)vn_default_error },
1675 { &vnop_lookup_desc, (VOPFUNC)devfs_devfd_lookup}, /* lookup */
1676 { &vnop_open_desc, (VOPFUNC)nop_open }, /* open */
1677 { &vnop_close_desc, (VOPFUNC)devfs_close }, /* close */
1678 { &vnop_getattr_desc, (VOPFUNC)devfs_getattr }, /* getattr */
1679 { &vnop_setattr_desc, (VOPFUNC)devfs_setattr }, /* setattr */
1680 { &vnop_revoke_desc, (VOPFUNC)err_revoke }, /* revoke */
1681 { &vnop_fsync_desc, (VOPFUNC)nop_fsync }, /* fsync */
1682 { &vnop_readdir_desc, (VOPFUNC)devfs_devfd_readdir}, /* readdir */
1683 { &vnop_inactive_desc, (VOPFUNC)devfs_inactive }, /* inactive */
1684 { &vnop_reclaim_desc, (VOPFUNC)devfs_reclaim }, /* reclaim */
1685 { &vnop_pathconf_desc, (VOPFUNC)devs_vnop_pathconf }, /* pathconf */
1686 #if CONFIG_MACF
1687 { &vnop_setlabel_desc, (VOPFUNC)devfs_setlabel }, /* setlabel */
1688 #endif
1689 { (struct vnodeop_desc*)NULL, (int(*)(void *))NULL }
1690 };
1691 struct vnodeopv_desc devfs_devfd_vnodeop_opv_desc =
1692 { &devfs_devfd_vnodeop_p, devfs_devfd_vnodeop_entries};
1693 #endif /* FDESC */
1694
1695