1/* 2 * Copyright (c) 2000-2010 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_vfsops.c 54 * 55 */ 56/* 57 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 58 * support for mandatory and extensible security protections. This notice 59 * is included in support of clause 2.2 (b) of the Apple Public License, 60 * Version 2.0. 61 */ 62/* 63 * HISTORY 64 * Dieter Siegmund (dieter@apple.com) Wed Jul 14 13:37:59 PDT 1999 65 * - modified devfs_statfs() to use devfs_stats to calculate the 66 * amount of memory used by devfs 67 */ 68 69 70#include <sys/param.h> 71#include <sys/systm.h> 72#include <sys/kernel.h> 73#include <sys/vnode_internal.h> 74#include <sys/proc.h> 75#include <sys/kauth.h> 76#include <sys/mount_internal.h> 77#include <sys/malloc.h> 78 79#include <libkern/OSAtomic.h> 80 81#if CONFIG_MACF 82#include <security/mac_framework.h> 83#endif 84 85#include "devfs.h" 86#include "devfsdefs.h" 87 88#if FDESC 89#include "fdesc.h" 90#endif /* FDESC */ 91 92 93static int devfs_statfs( struct mount *mp, struct vfsstatfs *sbp, vfs_context_t ctx); 94static int devfs_vfs_getattr(mount_t mp, struct vfs_attr *fsap, vfs_context_t ctx); 95 96#if CONFIG_DEV_KMEM 97extern boolean_t dev_kmem_enabled; 98#endif 99 100/*- 101 * Called from the generic VFS startups. 102 * This is the second stage of DEVFS initialisation. 103 * The probed devices have already been loaded and the 104 * basic structure of the DEVFS created. 105 * We take the oportunity to mount the hidden DEVFS layer, so that 106 * devices from devfs get sync'd. 107 */ 108static int 109devfs_init(__unused struct vfsconf *vfsp) 110{ 111 if (devfs_sinit()) 112 return (ENOTSUP); 113 devfs_make_node(makedev(0, 0), DEVFS_CHAR, 114 UID_ROOT, GID_WHEEL, 0622, "console"); 115 devfs_make_node(makedev(2, 0), DEVFS_CHAR, 116 UID_ROOT, GID_WHEEL, 0666, "tty"); 117#if CONFIG_DEV_KMEM 118 if (dev_kmem_enabled) { 119 /* (3,0) reserved for /dev/mem physical memory */ 120 devfs_make_node(makedev(3, 1), DEVFS_CHAR, 121 UID_ROOT, GID_KMEM, 0640, "kmem"); 122 } 123#endif 124 devfs_make_node(makedev(3, 2), DEVFS_CHAR, 125 UID_ROOT, GID_WHEEL, 0666, "null"); 126 devfs_make_node(makedev(3, 3), DEVFS_CHAR, 127 UID_ROOT, GID_WHEEL, 0666, "zero"); 128 devfs_make_node(makedev(6, 0), DEVFS_CHAR, 129 UID_ROOT, GID_WHEEL, 0600, "klog"); 130 131#if FDESC 132 devfs_fdesc_init(); 133#endif 134 135 return 0; 136} 137 138/*- 139 * mp - pointer to 'mount' structure 140 * path - addr in user space of mount point (ie /usr or whatever) 141 * data - addr in user space of mount params including the 142 * name of the block special file to treat as a filesystem. 143 * (NOT USED) 144 * ndp - namei data pointer (NOT USED) 145 * p - proc pointer 146 * devfs is special in that it doesn't require any device to be mounted.. 147 * It makes up its data as it goes along. 148 * it must be mounted during single user.. until it is, only std{in/out/err} 149 * and the root filesystem are available. 150 */ 151/*proto*/ 152int 153devfs_mount(struct mount *mp, __unused vnode_t devvp, __unused user_addr_t data, vfs_context_t ctx) 154{ 155 struct devfsmount *devfs_mp_p; /* devfs specific mount info */ 156 int error; 157 158 /*- 159 * If they just want to update, we don't need to do anything. 160 */ 161 if (mp->mnt_flag & MNT_UPDATE) 162 { 163 return 0; 164 } 165 166 /* Advisory locking should be handled at the VFS layer */ 167 vfs_setlocklocal(mp); 168 169 /*- 170 * Well, it's not an update, it's a real mount request. 171 * Time to get dirty. 172 * HERE we should check to see if we are already mounted here. 173 */ 174 175 MALLOC(devfs_mp_p, struct devfsmount *, sizeof(struct devfsmount), 176 M_DEVFSMNT, M_WAITOK); 177 if (devfs_mp_p == NULL) 178 return (ENOMEM); 179 bzero(devfs_mp_p,sizeof(*devfs_mp_p)); 180 devfs_mp_p->mount = mp; 181 182 /*- 183 * Fill out some fields 184 */ 185 mp->mnt_data = (qaddr_t)devfs_mp_p; 186 mp->mnt_vfsstat.f_fsid.val[0] = (int32_t)(uintptr_t)devfs_mp_p; 187 mp->mnt_vfsstat.f_fsid.val[1] = vfs_typenum(mp); 188 mp->mnt_flag |= MNT_LOCAL; 189 190 DEVFS_LOCK(); 191 error = dev_dup_plane(devfs_mp_p); 192 DEVFS_UNLOCK(); 193 194 if (error) { 195 mp->mnt_data = (qaddr_t)0; 196 FREE((caddr_t)devfs_mp_p, M_DEVFSMNT); 197 return (error); 198 } else 199 DEVFS_INCR_MOUNTS(); 200 201 /*- 202 * Copy in the name of the directory the filesystem 203 * is to be mounted on. 204 * And we clear the remainder of the character strings 205 * to be tidy. 206 */ 207 208 bzero(mp->mnt_vfsstat.f_mntfromname, MAXPATHLEN); 209 bcopy("devfs",mp->mnt_vfsstat.f_mntfromname, 5); 210 (void)devfs_statfs(mp, &mp->mnt_vfsstat, ctx); 211 212 return 0; 213} 214 215 216static int 217devfs_start(__unused struct mount *mp, __unused int flags, __unused vfs_context_t ctx) 218{ 219 return 0; 220} 221 222/*- 223 * Unmount the filesystem described by mp. 224 */ 225static int 226devfs_unmount( struct mount *mp, int mntflags, __unused vfs_context_t ctx) 227{ 228 struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data; 229 int flags = 0; 230 int force = 0; 231 int error; 232 233 if (mntflags & MNT_FORCE) { 234 flags |= FORCECLOSE; 235 force = 1; 236 } 237 error = vflush(mp, NULLVP, flags); 238 if (error && !force) 239 return error; 240 241 DEVFS_LOCK(); 242 devfs_free_plane(devfs_mp_p); 243 DEVFS_UNLOCK(); 244 245 DEVFS_DECR_MOUNTS(); 246 247 FREE((caddr_t)devfs_mp_p, M_DEVFSMNT); 248 mp->mnt_data = (qaddr_t)0; 249 mp->mnt_flag &= ~MNT_LOCAL; 250 251 return 0; 252} 253 254/* return the address of the root vnode in *vpp */ 255static int 256devfs_root(struct mount *mp, struct vnode **vpp, __unused vfs_context_t ctx) 257{ 258 struct devfsmount *devfs_mp_p = (struct devfsmount *)(mp->mnt_data); 259 int error; 260 261 DEVFS_LOCK(); 262 /* last parameter to devfs_dntovn() is ignored */ 263 error = devfs_dntovn(devfs_mp_p->plane_root->de_dnp, vpp, NULL); 264 DEVFS_UNLOCK(); 265 266 return error; 267} 268 269static int 270devfs_statfs( struct mount *mp, struct vfsstatfs *sbp, __unused vfs_context_t ctx) 271{ 272 struct devfsmount *devfs_mp_p = (struct devfsmount *)mp->mnt_data; 273 274 /*- 275 * Fill in the stat block. 276 */ 277 //sbp->f_type = mp->mnt_vfsstat.f_type; 278 sbp->f_flags = 0; /* XXX */ 279 sbp->f_bsize = 512; 280 sbp->f_iosize = 512; 281 sbp->f_blocks = (devfs_stats.mounts * sizeof(struct devfsmount) 282 + devfs_stats.nodes * sizeof(devnode_t) 283 + devfs_stats.entries * sizeof(devdirent_t) 284 + devfs_stats.stringspace 285 ) / sbp->f_bsize; 286 sbp->f_bfree = 0; 287 sbp->f_bavail = 0; 288 sbp->f_files = devfs_stats.nodes; 289 sbp->f_ffree = 0; 290 sbp->f_fsid.val[0] = (int32_t)(uintptr_t)devfs_mp_p; 291 sbp->f_fsid.val[1] = vfs_typenum(mp); 292 293 return 0; 294} 295 296static int 297devfs_vfs_getattr(__unused mount_t mp, struct vfs_attr *fsap, __unused vfs_context_t ctx) 298{ 299 VFSATTR_RETURN(fsap, f_objcount, devfs_stats.nodes); 300 VFSATTR_RETURN(fsap, f_maxobjcount, devfs_stats.nodes); 301 VFSATTR_RETURN(fsap, f_bsize, 512); 302 VFSATTR_RETURN(fsap, f_iosize, 512); 303 if (VFSATTR_IS_ACTIVE(fsap, f_blocks) || VFSATTR_IS_ACTIVE(fsap, f_bused)) { 304 fsap->f_blocks = (devfs_stats.mounts * sizeof(struct devfsmount) 305 + devfs_stats.nodes * sizeof(devnode_t) 306 + devfs_stats.entries * sizeof(devdirent_t) 307 + devfs_stats.stringspace 308 ) / fsap->f_bsize; 309 fsap->f_bused = fsap->f_blocks; 310 VFSATTR_SET_SUPPORTED(fsap, f_blocks); 311 VFSATTR_SET_SUPPORTED(fsap, f_bused); 312 } 313 VFSATTR_RETURN(fsap, f_bfree, 0); 314 VFSATTR_RETURN(fsap, f_bavail, 0); 315 VFSATTR_RETURN(fsap, f_files, devfs_stats.nodes); 316 VFSATTR_RETURN(fsap, f_ffree, 0); 317 VFSATTR_RETURN(fsap, f_fssubtype, 0); 318 319 if (VFSATTR_IS_ACTIVE(fsap, f_capabilities)) { 320 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] = 321 VOL_CAP_FMT_SYMBOLICLINKS | 322 VOL_CAP_FMT_HARDLINKS | 323 VOL_CAP_FMT_NO_ROOT_TIMES | 324 VOL_CAP_FMT_CASE_SENSITIVE | 325 VOL_CAP_FMT_CASE_PRESERVING | 326 VOL_CAP_FMT_FAST_STATFS | 327 VOL_CAP_FMT_2TB_FILESIZE | 328 VOL_CAP_FMT_HIDDEN_FILES; 329 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] = 330 VOL_CAP_INT_ATTRLIST ; 331 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED1] = 0; 332 fsap->f_capabilities.capabilities[VOL_CAPABILITIES_RESERVED2] = 0; 333 334 fsap->f_capabilities.valid[VOL_CAPABILITIES_FORMAT] = 335 VOL_CAP_FMT_PERSISTENTOBJECTIDS | 336 VOL_CAP_FMT_SYMBOLICLINKS | 337 VOL_CAP_FMT_HARDLINKS | 338 VOL_CAP_FMT_JOURNAL | 339 VOL_CAP_FMT_JOURNAL_ACTIVE | 340 VOL_CAP_FMT_NO_ROOT_TIMES | 341 VOL_CAP_FMT_SPARSE_FILES | 342 VOL_CAP_FMT_ZERO_RUNS | 343 VOL_CAP_FMT_CASE_SENSITIVE | 344 VOL_CAP_FMT_CASE_PRESERVING | 345 VOL_CAP_FMT_FAST_STATFS | 346 VOL_CAP_FMT_2TB_FILESIZE | 347 VOL_CAP_FMT_OPENDENYMODES | 348 VOL_CAP_FMT_HIDDEN_FILES | 349 VOL_CAP_FMT_PATH_FROM_ID | 350 VOL_CAP_FMT_NO_VOLUME_SIZES; 351 fsap->f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] = 352 VOL_CAP_INT_SEARCHFS | 353 VOL_CAP_INT_ATTRLIST | 354 VOL_CAP_INT_NFSEXPORT | 355 VOL_CAP_INT_READDIRATTR | 356 VOL_CAP_INT_EXCHANGEDATA | 357 VOL_CAP_INT_COPYFILE | 358 VOL_CAP_INT_ALLOCATE | 359 VOL_CAP_INT_VOL_RENAME | 360 VOL_CAP_INT_ADVLOCK | 361 VOL_CAP_INT_FLOCK | 362 VOL_CAP_INT_EXTENDED_SECURITY | 363 VOL_CAP_INT_USERACCESS | 364 VOL_CAP_INT_MANLOCK | 365 VOL_CAP_INT_EXTENDED_ATTR | 366 VOL_CAP_INT_NAMEDSTREAMS; 367 fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED1] = 0; 368 fsap->f_capabilities.valid[VOL_CAPABILITIES_RESERVED2] = 0; 369 370 VFSATTR_SET_SUPPORTED(fsap, f_capabilities); 371 } 372 373 if (VFSATTR_IS_ACTIVE(fsap, f_attributes)) { 374 fsap->f_attributes.validattr.commonattr = 375 ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | 376 ATTR_CMN_OBJTYPE | ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | 377 ATTR_CMN_PAROBJID | 378 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | 379 ATTR_CMN_OWNERID | ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | 380 ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS | ATTR_CMN_FILEID; 381 fsap->f_attributes.validattr.volattr = 382 ATTR_VOL_FSTYPE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | 383 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | 384 ATTR_VOL_OBJCOUNT | ATTR_VOL_MAXOBJCOUNT | 385 ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | 386 ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | 387 ATTR_VOL_ATTRIBUTES; 388 fsap->f_attributes.validattr.dirattr = 389 ATTR_DIR_LINKCOUNT | ATTR_DIR_MOUNTSTATUS; 390 fsap->f_attributes.validattr.fileattr = 391 ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | 392 ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_DEVTYPE | 393 ATTR_FILE_DATALENGTH; 394 fsap->f_attributes.validattr.forkattr = 0; 395 396 fsap->f_attributes.nativeattr.commonattr = 397 ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | 398 ATTR_CMN_OBJTYPE | ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | 399 ATTR_CMN_PAROBJID | 400 ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | 401 ATTR_CMN_OWNERID | ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | 402 ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS | ATTR_CMN_FILEID; 403 fsap->f_attributes.nativeattr.volattr = 404 ATTR_VOL_FSTYPE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | 405 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | 406 ATTR_VOL_OBJCOUNT | ATTR_VOL_MAXOBJCOUNT | 407 ATTR_VOL_MOUNTPOINT | ATTR_VOL_MOUNTFLAGS | 408 ATTR_VOL_MOUNTEDDEVICE | ATTR_VOL_CAPABILITIES | 409 ATTR_VOL_ATTRIBUTES; 410 fsap->f_attributes.nativeattr.dirattr = 411 ATTR_DIR_MOUNTSTATUS; 412 fsap->f_attributes.nativeattr.fileattr = 413 ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | 414 ATTR_FILE_IOBLOCKSIZE | ATTR_FILE_DEVTYPE | 415 ATTR_FILE_DATALENGTH; 416 fsap->f_attributes.nativeattr.forkattr = 0; 417 418 VFSATTR_SET_SUPPORTED(fsap, f_attributes); 419 } 420 421 return 0; 422} 423 424static int 425devfs_sync(__unused struct mount *mp, __unused int waitfor, __unused vfs_context_t ctx) 426{ 427 return (0); 428} 429 430 431static int 432devfs_vget(__unused struct mount *mp, __unused ino64_t ino, __unused struct vnode **vpp, __unused vfs_context_t ctx) 433{ 434 return ENOTSUP; 435} 436 437/************************************************************* 438 * The concept of exporting a kernel generated devfs is stupid 439 * So don't handle filehandles 440 */ 441 442static int 443devfs_fhtovp (__unused struct mount *mp, __unused int fhlen, __unused unsigned char *fhp, __unused struct vnode **vpp, __unused vfs_context_t ctx) 444{ 445 return (EINVAL); 446} 447 448 449static int 450devfs_vptofh (__unused struct vnode *vp, __unused int *fhlenp, __unused unsigned char *fhp, __unused vfs_context_t ctx) 451{ 452 return (EINVAL); 453} 454 455static int 456devfs_sysctl(__unused int *name, __unused u_int namelen, __unused user_addr_t oldp, 457 __unused size_t *oldlenp, __unused user_addr_t newp, 458 __unused size_t newlen, __unused vfs_context_t ctx) 459{ 460 return (ENOTSUP); 461} 462 463#include <sys/namei.h> 464 465/* 466 * Function: devfs_kernel_mount 467 * Purpose: 468 * Mount devfs at the given mount point from within the kernel. 469 */ 470int 471devfs_kernel_mount(char * mntname) 472{ 473 int error; 474 vfs_context_t ctx = vfs_context_kernel(); 475 char fsname[] = "devfs"; 476 477 error = kernel_mount(fsname, NULLVP, NULLVP, mntname, NULL, 0, MNT_DONTBROWSE, KERNEL_MOUNT_NOAUTH, ctx); 478 if (error) { 479 printf("devfs_kernel_mount: kernel_mount failed: %d\n", error); 480 return (error); 481 } 482 483 return (0); 484} 485 486struct vfsops devfs_vfsops = { 487 devfs_mount, 488 devfs_start, 489 devfs_unmount, 490 devfs_root, 491 NULL, /* quotactl */ 492 devfs_vfs_getattr, 493 devfs_sync, 494 devfs_vget, 495 devfs_fhtovp, 496 devfs_vptofh, 497 devfs_init, 498 devfs_sysctl, 499 NULL, 500 {NULL} 501}; 502