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