1 /* $NetBSD: procfs_vnops.c,v 1.233 2024/07/01 01:35:53 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1993, 1995 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * Jan-Simon Pendry. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 * 63 * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 64 */ 65 66 /* 67 * Copyright (c) 1993 Jan-Simon Pendry 68 * 69 * This code is derived from software contributed to Berkeley by 70 * Jan-Simon Pendry. 71 * 72 * Redistribution and use in source and binary forms, with or without 73 * modification, are permitted provided that the following conditions 74 * are met: 75 * 1. Redistributions of source code must retain the above copyright 76 * notice, this list of conditions and the following disclaimer. 77 * 2. Redistributions in binary form must reproduce the above copyright 78 * notice, this list of conditions and the following disclaimer in the 79 * documentation and/or other materials provided with the distribution. 80 * 3. All advertising materials mentioning features or use of this software 81 * must display the following acknowledgement: 82 * This product includes software developed by the University of 83 * California, Berkeley and its contributors. 84 * 4. Neither the name of the University nor the names of its contributors 85 * may be used to endorse or promote products derived from this software 86 * without specific prior written permission. 87 * 88 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 89 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 90 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 91 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 92 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 93 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 94 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 95 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 96 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 97 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 98 * SUCH DAMAGE. 99 * 100 * @(#)procfs_vnops.c 8.18 (Berkeley) 5/21/95 101 */ 102 103 /* 104 * procfs vnode interface 105 */ 106 107 #include <sys/cdefs.h> 108 __KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.233 2024/07/01 01:35:53 christos Exp $"); 109 110 #include <sys/param.h> 111 #include <sys/atomic.h> 112 #include <sys/systm.h> 113 #include <sys/time.h> 114 #include <sys/kernel.h> 115 #include <sys/file.h> 116 #include <sys/filedesc.h> 117 #include <sys/proc.h> 118 #include <sys/vnode.h> 119 #include <sys/namei.h> 120 #include <sys/malloc.h> 121 #include <sys/mount.h> 122 #include <sys/dirent.h> 123 #include <sys/resourcevar.h> 124 #include <sys/stat.h> 125 #include <sys/ptrace.h> 126 #include <sys/kauth.h> 127 #include <sys/exec.h> 128 129 #include <uvm/uvm_extern.h> /* for PAGE_SIZE */ 130 131 #include <machine/reg.h> 132 133 #include <miscfs/genfs/genfs.h> 134 #include <miscfs/procfs/procfs.h> 135 136 /* 137 * Vnode Operations. 138 * 139 */ 140 141 static int procfs_validfile_linux(struct lwp *, struct mount *); 142 static int procfs_root_readdir_callback(struct proc *, void *); 143 static void procfs_dir(pfstype, struct lwp *, struct proc *, char **, char *, 144 size_t); 145 146 /* 147 * This is a list of the valid names in the 148 * process-specific sub-directories. It is 149 * used in procfs_lookup and procfs_readdir 150 */ 151 static const struct proc_target { 152 u_char pt_type; 153 u_char pt_namlen; 154 const char *pt_name; 155 pfstype pt_pfstype; 156 int (*pt_valid)(struct lwp *, struct mount *); 157 } proc_targets[] = { 158 #define N(s) sizeof(s)-1, s 159 /* name type validp */ 160 { DT_DIR, N("."), PFSproc, NULL }, 161 { DT_DIR, N(".."), PFSroot, NULL }, 162 { DT_DIR, N("fd"), PFSfd, NULL }, 163 { DT_DIR, N("task"), PFStask, procfs_validfile_linux }, 164 { DT_LNK, N("cwd"), PFScwd, NULL }, 165 { DT_REG, N("emul"), PFSemul, NULL }, 166 { DT_LNK, N("root"), PFSchroot, NULL }, 167 { DT_REG, N("auxv"), PFSauxv, procfs_validauxv }, 168 { DT_REG, N("cmdline"), PFScmdline, NULL }, 169 { DT_REG, N("environ"), PFSenviron, NULL }, 170 { DT_LNK, N("exe"), PFSexe, procfs_validfile }, 171 { DT_REG, N("file"), PFSfile, procfs_validfile }, 172 { DT_REG, N("fpregs"), PFSfpregs, procfs_validfpregs }, 173 { DT_REG, N("limit"), PFSlimit, NULL }, 174 { DT_REG, N("limits"), PFSlimits, procfs_validfile_linux }, 175 { DT_REG, N("map"), PFSmap, procfs_validmap }, 176 { DT_REG, N("maps"), PFSmaps, procfs_validmap }, 177 { DT_REG, N("mem"), PFSmem, NULL }, 178 { DT_REG, N("note"), PFSnote, NULL }, 179 { DT_REG, N("notepg"), PFSnotepg, NULL }, 180 { DT_REG, N("regs"), PFSregs, procfs_validregs }, 181 { DT_REG, N("stat"), PFSstat, procfs_validfile_linux }, 182 { DT_REG, N("statm"), PFSstatm, procfs_validfile_linux }, 183 { DT_REG, N("status"), PFSstatus, NULL }, 184 #ifdef __HAVE_PROCFS_MACHDEP 185 PROCFS_MACHDEP_NODETYPE_DEFNS 186 #endif 187 #undef N 188 }; 189 static const int nproc_targets = sizeof(proc_targets) / sizeof(proc_targets[0]); 190 191 /* 192 * List of files in the root directory. Note: the validate function will 193 * be called with p == NULL for these ones. 194 */ 195 static const struct proc_target proc_root_targets[] = { 196 #define N(s) sizeof(s)-1, s 197 /* name type validp */ 198 { DT_REG, N("meminfo"), PFSmeminfo, procfs_validfile_linux }, 199 { DT_REG, N("cpuinfo"), PFScpuinfo, procfs_validfile_linux }, 200 { DT_REG, N("uptime"), PFSuptime, procfs_validfile_linux }, 201 { DT_REG, N("mounts"), PFSmounts, procfs_validfile_linux }, 202 { DT_REG, N("devices"), PFSdevices, procfs_validfile_linux }, 203 { DT_REG, N("stat"), PFScpustat, procfs_validfile_linux }, 204 { DT_REG, N("loadavg"), PFSloadavg, procfs_validfile_linux }, 205 { DT_REG, N("version"), PFSversion, procfs_validfile_linux }, 206 { DT_DIR, N("sys"), PFSsys, procfs_validfile_linux }, 207 { DT_DIR, N("sysvipc"), PFSsysvipc, procfs_validfile_linux }, 208 #undef N 209 }; 210 static const int nproc_root_targets = 211 sizeof(proc_root_targets) / sizeof(proc_root_targets[0]); 212 213 /* 214 * List of files in the sys directory 215 */ 216 static const struct proc_target proc_sys_targets[] = { 217 #define N(s) sizeof(s)-1, s 218 /* name type validp */ 219 { DT_DIR, N("."), PFSsys, procfs_validfile_linux }, 220 { DT_DIR, N(".."), PFSroot, NULL }, 221 { DT_REG, N("fs"), PFSsysfs, procfs_validfile_linux }, 222 #undef N 223 }; 224 static const int nproc_sys_targets = 225 sizeof(proc_sys_targets) / sizeof(proc_sys_targets[0]); 226 227 /* 228 * List of files in the sys/fs directory 229 */ 230 static const struct proc_target proc_sysfs_targets[] = { 231 #define N(s) sizeof(s)-1, s 232 /* name type validp */ 233 { DT_DIR, N("."), PFSsysfs, procfs_validfile_linux }, 234 { DT_DIR, N(".."), PFSsys, procfs_validfile_linux }, 235 { DT_REG, N("mqueue"), PFSmqueue, procfs_validfile_linux }, 236 #undef N 237 }; 238 static const int nproc_sysfs_targets = 239 sizeof(proc_sysfs_targets) / sizeof(proc_sysfs_targets[0]); 240 241 /* 242 * List of files in the sys/fs/mqueue directory 243 */ 244 static const struct proc_target proc_mqueue_targets[] = { 245 #define N(s) sizeof(s)-1, s 246 /* name type validp */ 247 { DT_DIR, N("."), PFSmqueue, procfs_validfile_linux }, 248 { DT_DIR, N(".."), PFSsysfs, procfs_validfile_linux }, 249 { DT_REG, N("msg_default"), PFSmq_msg_def, procfs_validfile_linux }, 250 { DT_REG, N("msg_max"), PFSmq_msg_max, procfs_validfile_linux }, 251 { DT_REG, N("msgsize_default"), PFSmq_siz_def, procfs_validfile_linux }, 252 { DT_REG, N("msgsize_max"), PFSmq_siz_max, procfs_validfile_linux }, 253 { DT_REG, N("queues_max"), PFSmq_qmax, procfs_validfile_linux }, 254 #undef N 255 }; 256 static const int nproc_mqueue_targets = 257 sizeof(proc_mqueue_targets) / sizeof(proc_mqueue_targets[0]); 258 259 /* 260 * List of files in the sysvipc directory 261 */ 262 static const struct proc_target proc_sysvipc_targets[] = { 263 #define N(s) sizeof(s)-1, s 264 /* name type validp */ 265 { DT_DIR, N("."), PFSsysvipc, NULL }, 266 { DT_DIR, N(".."), PFSroot, NULL }, 267 { DT_REG, N("msg"), PFSsysvipc_msg, procfs_validfile_linux }, 268 { DT_REG, N("sem"), PFSsysvipc_sem, procfs_validfile_linux }, 269 { DT_REG, N("shm"), PFSsysvipc_shm, procfs_validfile_linux }, 270 #undef N 271 }; 272 static const int nproc_sysvipc_targets = 273 sizeof(proc_sysvipc_targets) / sizeof(proc_sysvipc_targets[0]); 274 275 int procfs_lookup(void *); 276 int procfs_open(void *); 277 int procfs_close(void *); 278 int procfs_access(void *); 279 int procfs_getattr(void *); 280 int procfs_setattr(void *); 281 int procfs_readdir(void *); 282 int procfs_readlink(void *); 283 int procfs_inactive(void *); 284 int procfs_reclaim(void *); 285 int procfs_print(void *); 286 int procfs_pathconf(void *); 287 int procfs_getpages(void *); 288 289 static uint8_t fttodt(file_t *); 290 static int atoi(const char *, size_t); 291 292 /* 293 * procfs vnode operations. 294 */ 295 int (**procfs_vnodeop_p)(void *); 296 const struct vnodeopv_entry_desc procfs_vnodeop_entries[] = { 297 { &vop_default_desc, vn_default_error }, 298 { &vop_parsepath_desc, genfs_parsepath }, /* parsepath */ 299 { &vop_lookup_desc, procfs_lookup }, /* lookup */ 300 { &vop_create_desc, genfs_eopnotsupp }, /* create */ 301 { &vop_mknod_desc, genfs_eopnotsupp }, /* mknod */ 302 { &vop_open_desc, procfs_open }, /* open */ 303 { &vop_close_desc, procfs_close }, /* close */ 304 { &vop_access_desc, procfs_access }, /* access */ 305 { &vop_accessx_desc, genfs_accessx }, /* accessx */ 306 { &vop_getattr_desc, procfs_getattr }, /* getattr */ 307 { &vop_setattr_desc, procfs_setattr }, /* setattr */ 308 { &vop_read_desc, procfs_rw }, /* read */ 309 { &vop_write_desc, procfs_rw }, /* write */ 310 { &vop_fallocate_desc, genfs_eopnotsupp }, /* fallocate */ 311 { &vop_fdiscard_desc, genfs_eopnotsupp }, /* fdiscard */ 312 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 313 { &vop_ioctl_desc, genfs_enoioctl }, /* ioctl */ 314 { &vop_poll_desc, genfs_poll }, /* poll */ 315 { &vop_kqfilter_desc, genfs_kqfilter }, /* kqfilter */ 316 { &vop_revoke_desc, genfs_revoke }, /* revoke */ 317 { &vop_fsync_desc, genfs_nullop }, /* fsync */ 318 { &vop_seek_desc, genfs_nullop }, /* seek */ 319 { &vop_remove_desc, genfs_eopnotsupp }, /* remove */ 320 { &vop_link_desc, genfs_erofs_link }, /* link */ 321 { &vop_rename_desc, genfs_eopnotsupp }, /* rename */ 322 { &vop_mkdir_desc, genfs_eopnotsupp }, /* mkdir */ 323 { &vop_rmdir_desc, genfs_eopnotsupp }, /* rmdir */ 324 { &vop_symlink_desc, genfs_erofs_symlink }, /* symlink */ 325 { &vop_readdir_desc, procfs_readdir }, /* readdir */ 326 { &vop_readlink_desc, procfs_readlink }, /* readlink */ 327 { &vop_abortop_desc, genfs_abortop }, /* abortop */ 328 { &vop_inactive_desc, procfs_inactive }, /* inactive */ 329 { &vop_reclaim_desc, procfs_reclaim }, /* reclaim */ 330 { &vop_lock_desc, genfs_lock }, /* lock */ 331 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 332 { &vop_bmap_desc, genfs_eopnotsupp }, /* bmap */ 333 { &vop_strategy_desc, genfs_badop }, /* strategy */ 334 { &vop_print_desc, procfs_print }, /* print */ 335 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 336 { &vop_pathconf_desc, procfs_pathconf }, /* pathconf */ 337 { &vop_advlock_desc, genfs_einval }, /* advlock */ 338 { &vop_getpages_desc, procfs_getpages }, /* getpages */ 339 { &vop_putpages_desc, genfs_null_putpages }, /* putpages */ 340 { NULL, NULL } 341 }; 342 const struct vnodeopv_desc procfs_vnodeop_opv_desc = 343 { &procfs_vnodeop_p, procfs_vnodeop_entries }; 344 /* 345 * set things up for doing i/o on 346 * the pfsnode (vp). (vp) is locked 347 * on entry, and should be left locked 348 * on exit. 349 * 350 * for procfs we don't need to do anything 351 * in particular for i/o. all that is done 352 * is to support exclusive open on process 353 * memory images. 354 */ 355 int 356 procfs_open(void *v) 357 { 358 struct vop_open_args /* { 359 struct vnode *a_vp; 360 int a_mode; 361 kauth_cred_t a_cred; 362 } */ *ap = v; 363 struct vnode *vp = ap->a_vp; 364 struct pfsnode *pfs = VTOPFS(vp); 365 struct lwp *l1; 366 struct proc *p2; 367 int error; 368 369 if ((error = 370 procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p2, ENOENT)) != 0) 371 return error; 372 373 l1 = curlwp; /* tracer */ 374 375 #define M2K(m) (((m) & FREAD) && ((m) & FWRITE) ? \ 376 KAUTH_REQ_PROCESS_PROCFS_RW : \ 377 (m) & FWRITE ? KAUTH_REQ_PROCESS_PROCFS_WRITE : \ 378 KAUTH_REQ_PROCESS_PROCFS_READ) 379 380 mutex_enter(p2->p_lock); 381 error = kauth_authorize_process(l1->l_cred, KAUTH_PROCESS_PROCFS, 382 p2, pfs, KAUTH_ARG(M2K(ap->a_mode)), NULL); 383 mutex_exit(p2->p_lock); 384 if (error) { 385 procfs_proc_unlock(p2); 386 return (error); 387 } 388 389 #undef M2K 390 391 switch (pfs->pfs_type) { 392 case PFSmem: 393 if (((pfs->pfs_flags & FWRITE) && (ap->a_mode & O_EXCL)) || 394 ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) { 395 error = EBUSY; 396 break; 397 } 398 399 if (!proc_isunder(p2, l1)) { 400 error = EPERM; 401 break; 402 } 403 404 if (ap->a_mode & FWRITE) 405 pfs->pfs_flags = ap->a_mode & (FWRITE|O_EXCL); 406 407 break; 408 409 case PFSregs: 410 case PFSfpregs: 411 if (!proc_isunder(p2, l1)) { 412 error = EPERM; 413 break; 414 } 415 break; 416 417 default: 418 break; 419 } 420 421 procfs_proc_unlock(p2); 422 return (error); 423 } 424 425 /* 426 * close the pfsnode (vp) after doing i/o. 427 * (vp) is not locked on entry or exit. 428 * 429 * nothing to do for procfs other than undo 430 * any exclusive open flag (see _open above). 431 */ 432 int 433 procfs_close(void *v) 434 { 435 struct vop_close_args /* { 436 struct vnode *a_vp; 437 int a_fflag; 438 kauth_cred_t a_cred; 439 } */ *ap = v; 440 struct pfsnode *pfs = VTOPFS(ap->a_vp); 441 442 switch (pfs->pfs_type) { 443 case PFSmem: 444 if ((ap->a_fflag & FWRITE) && (pfs->pfs_flags & O_EXCL)) 445 pfs->pfs_flags &= ~(FWRITE|O_EXCL); 446 break; 447 448 default: 449 break; 450 } 451 452 return (0); 453 } 454 455 /* 456 * _inactive is called when the pfsnode 457 * is vrele'd and the reference count goes 458 * to zero. (vp) will be on the vnode free 459 * list, so to get it back vget() must be 460 * used. 461 * 462 * (vp) is locked on entry, but must be unlocked on exit. 463 */ 464 int 465 procfs_inactive(void *v) 466 { 467 struct vop_inactive_v2_args /* { 468 struct vnode *a_vp; 469 bool *a_recycle; 470 } */ *ap = v; 471 struct vnode *vp = ap->a_vp; 472 struct pfsnode *pfs = VTOPFS(vp); 473 474 mutex_enter(&proc_lock); 475 *ap->a_recycle = (procfs_proc_find(vp->v_mount, pfs->pfs_pid) == NULL); 476 mutex_exit(&proc_lock); 477 478 return (0); 479 } 480 481 /* 482 * _reclaim is called when getnewvnode() 483 * wants to make use of an entry on the vnode 484 * free list. at this time the filesystem needs 485 * to free any private data and remove the node 486 * from any private lists. 487 */ 488 int 489 procfs_reclaim(void *v) 490 { 491 struct vop_reclaim_v2_args /* { 492 struct vnode *a_vp; 493 } */ *ap = v; 494 struct vnode *vp = ap->a_vp; 495 struct pfsnode *pfs = VTOPFS(vp); 496 497 VOP_UNLOCK(vp); 498 499 /* 500 * To interlock with procfs_revoke_vnodes(). 501 */ 502 mutex_enter(vp->v_interlock); 503 vp->v_data = NULL; 504 mutex_exit(vp->v_interlock); 505 procfs_hashrem(pfs); 506 kmem_free(pfs, sizeof(*pfs)); 507 return 0; 508 } 509 510 /* 511 * Return POSIX pathconf information applicable to special devices. 512 */ 513 int 514 procfs_pathconf(void *v) 515 { 516 struct vop_pathconf_args /* { 517 struct vnode *a_vp; 518 int a_name; 519 register_t *a_retval; 520 } */ *ap = v; 521 522 switch (ap->a_name) { 523 case _PC_LINK_MAX: 524 *ap->a_retval = LINK_MAX; 525 return (0); 526 case _PC_MAX_CANON: 527 *ap->a_retval = MAX_CANON; 528 return (0); 529 case _PC_MAX_INPUT: 530 *ap->a_retval = MAX_INPUT; 531 return (0); 532 case _PC_PIPE_BUF: 533 *ap->a_retval = PIPE_BUF; 534 return (0); 535 case _PC_CHOWN_RESTRICTED: 536 *ap->a_retval = 1; 537 return (0); 538 case _PC_VDISABLE: 539 *ap->a_retval = _POSIX_VDISABLE; 540 return (0); 541 case _PC_SYNC_IO: 542 *ap->a_retval = 1; 543 return (0); 544 default: 545 return genfs_pathconf(ap); 546 } 547 /* NOTREACHED */ 548 } 549 550 /* 551 * _print is used for debugging. 552 * just print a readable description 553 * of (vp). 554 */ 555 int 556 procfs_print(void *v) 557 { 558 struct vop_print_args /* { 559 struct vnode *a_vp; 560 } */ *ap = v; 561 struct pfsnode *pfs = VTOPFS(ap->a_vp); 562 563 printf("tag VT_PROCFS, type %d, pid %d, mode %x, flags %lx\n", 564 pfs->pfs_type, pfs->pfs_pid, pfs->pfs_mode, pfs->pfs_flags); 565 return 0; 566 } 567 568 /* 569 * Works out the path to the target process's current 570 * working directory or chroot. If the caller is in a chroot and 571 * can't "reach" the target's cwd or root (or some other error 572 * occurs), a "/" is returned for the path. 573 */ 574 static void 575 procfs_dir(pfstype t, struct lwp *caller, struct proc *target, char **bpp, 576 char *path, size_t len) 577 { 578 struct cwdinfo *cwdi; 579 struct vnode *vp, *rvp; 580 char *bp; 581 582 /* 583 * Lock target cwdi and take a reference to the vnode 584 * we are interested in to prevent it from disappearing 585 * before getcwd_common() below. 586 */ 587 rw_enter(&target->p_cwdi->cwdi_lock, RW_READER); 588 switch (t) { 589 case PFScwd: 590 vp = target->p_cwdi->cwdi_cdir; 591 break; 592 case PFSchroot: 593 vp = target->p_cwdi->cwdi_rdir; 594 break; 595 default: 596 rw_exit(&target->p_cwdi->cwdi_lock); 597 return; 598 } 599 if (vp != NULL) 600 vref(vp); 601 rw_exit(&target->p_cwdi->cwdi_lock); 602 603 cwdi = caller->l_proc->p_cwdi; 604 rw_enter(&cwdi->cwdi_lock, RW_READER); 605 606 rvp = cwdi->cwdi_rdir; 607 bp = bpp ? *bpp : NULL; 608 609 /* 610 * XXX: this horrible kludge avoids locking panics when 611 * attempting to lookup links that point to within procfs 612 */ 613 if (vp != NULL && vp->v_tag == VT_PROCFS) { 614 if (bpp) { 615 *--bp = '/'; 616 *bpp = bp; 617 } 618 vrele(vp); 619 rw_exit(&cwdi->cwdi_lock); 620 return; 621 } 622 623 if (rvp == NULL) 624 rvp = rootvnode; 625 if (vp == NULL || getcwd_common(vp, rvp, bp ? &bp : NULL, path, 626 len / 2, 0, caller) != 0) { 627 if (bpp) { 628 bp = *bpp; 629 *--bp = '/'; 630 } 631 } 632 633 if (bpp) 634 *bpp = bp; 635 636 if (vp != NULL) 637 vrele(vp); 638 rw_exit(&cwdi->cwdi_lock); 639 } 640 641 /* 642 * Invent attributes for pfsnode (vp) and store 643 * them in (vap). 644 * Directories lengths are returned as zero since 645 * any real length would require the genuine size 646 * to be computed, and nothing cares anyway. 647 * 648 * this is relatively minimal for procfs. 649 */ 650 int 651 procfs_getattr(void *v) 652 { 653 struct vop_getattr_args /* { 654 struct vnode *a_vp; 655 struct vattr *a_vap; 656 kauth_cred_t a_cred; 657 } */ *ap = v; 658 struct vnode *vp = ap->a_vp; 659 struct pfsnode *pfs = VTOPFS(vp); 660 struct vattr *vap = ap->a_vap; 661 struct proc *procp; 662 char *path, *bp, bf[16]; 663 int error; 664 665 /* first check the process still exists */ 666 switch (pfs->pfs_type) { 667 case PFSroot: 668 case PFScurproc: 669 case PFSself: 670 procp = NULL; 671 break; 672 673 default: 674 error = 675 procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &procp, ENOENT); 676 if (error != 0) 677 return (error); 678 break; 679 } 680 681 switch (pfs->pfs_type) { 682 case PFStask: 683 if (pfs->pfs_fd == -1) { 684 path = NULL; 685 break; 686 } 687 /*FALLTHROUGH*/ 688 case PFScwd: 689 case PFSchroot: 690 path = malloc(MAXPATHLEN + 4, M_TEMP, M_WAITOK); 691 if (path == NULL && procp != NULL) { 692 procfs_proc_unlock(procp); 693 return (ENOMEM); 694 } 695 break; 696 697 default: 698 path = NULL; 699 break; 700 } 701 702 if (procp != NULL) { 703 mutex_enter(procp->p_lock); 704 error = kauth_authorize_process(kauth_cred_get(), 705 KAUTH_PROCESS_CANSEE, procp, 706 KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL); 707 mutex_exit(procp->p_lock); 708 if (error != 0) { 709 procfs_proc_unlock(procp); 710 if (path != NULL) 711 free(path, M_TEMP); 712 return (ENOENT); 713 } 714 } 715 716 error = 0; 717 718 /* start by zeroing out the attributes */ 719 vattr_null(vap); 720 721 /* next do all the common fields */ 722 vap->va_type = ap->a_vp->v_type; 723 vap->va_mode = pfs->pfs_mode; 724 vap->va_fileid = pfs->pfs_fileno; 725 vap->va_flags = 0; 726 vap->va_blocksize = PAGE_SIZE; 727 728 /* 729 * Make all times be current TOD. 730 * 731 * It would be possible to get the process start 732 * time from the p_stats structure, but there's 733 * no "file creation" time stamp anyway, and the 734 * p_stats structure is not addressable if u. gets 735 * swapped out for that process. 736 */ 737 getnanotime(&vap->va_ctime); 738 vap->va_atime = vap->va_mtime = vap->va_ctime; 739 if (procp) 740 TIMEVAL_TO_TIMESPEC(&procp->p_stats->p_start, 741 &vap->va_birthtime); 742 else 743 getnanotime(&vap->va_birthtime); 744 745 switch (pfs->pfs_type) { 746 case PFSmem: 747 case PFSregs: 748 case PFSfpregs: 749 #if defined(__HAVE_PROCFS_MACHDEP) && defined(PROCFS_MACHDEP_PROTECT_CASES) 750 PROCFS_MACHDEP_PROTECT_CASES 751 #endif 752 /* 753 * If the process has exercised some setuid or setgid 754 * privilege, then rip away read/write permission so 755 * that only root can gain access. 756 */ 757 if (procp->p_flag & PK_SUGID) 758 vap->va_mode &= ~(S_IRUSR|S_IWUSR); 759 /* FALLTHROUGH */ 760 case PFSstatus: 761 case PFSstat: 762 case PFSnote: 763 case PFSnotepg: 764 case PFScmdline: 765 case PFSenviron: 766 case PFSemul: 767 case PFSstatm: 768 769 case PFSmap: 770 case PFSmaps: 771 case PFSlimit: 772 case PFSlimits: 773 case PFSauxv: 774 vap->va_nlink = 1; 775 vap->va_uid = kauth_cred_geteuid(procp->p_cred); 776 vap->va_gid = kauth_cred_getegid(procp->p_cred); 777 break; 778 case PFScwd: 779 case PFSchroot: 780 case PFSmeminfo: 781 case PFSdevices: 782 case PFScpuinfo: 783 case PFSuptime: 784 case PFSmounts: 785 case PFScpustat: 786 case PFSloadavg: 787 case PFSversion: 788 case PFSexe: 789 case PFSself: 790 case PFScurproc: 791 case PFSroot: 792 case PFSmq_msg_def: 793 case PFSmq_msg_max: 794 case PFSmq_siz_def: 795 case PFSmq_siz_max: 796 case PFSmq_qmax: 797 case PFSsysvipc_msg: 798 case PFSsysvipc_sem: 799 case PFSsysvipc_shm: 800 vap->va_nlink = 1; 801 vap->va_uid = vap->va_gid = 0; 802 break; 803 804 case PFSsysvipc: 805 vap->va_nlink = 5; 806 vap->va_uid = vap->va_gid = 0; 807 break; 808 809 case PFSsys: /* proc/sys only contains "fs" */ 810 case PFSsysfs: /* proc/sys/fs only contains "mqueue" */ 811 vap->va_nlink = 3; 812 vap->va_uid = vap->va_gid = 0; 813 break; 814 815 case PFSmqueue: 816 vap->va_nlink = 7; 817 vap->va_uid = vap->va_gid = 0; 818 break; 819 820 case PFSproc: 821 case PFStask: 822 case PFSfile: 823 case PFSfd: 824 break; 825 826 default: 827 panic("%s: %d/1", __func__, pfs->pfs_type); 828 } 829 830 /* 831 * now do the object specific fields 832 * 833 * The size could be set from struct reg, but it's hardly 834 * worth the trouble, and it puts some (potentially) machine 835 * dependent data into this machine-independent code. If it 836 * becomes important then this function should break out into 837 * a per-file stat function in the corresponding .c file. 838 */ 839 840 switch (pfs->pfs_type) { 841 case PFSroot: 842 vap->va_bytes = vap->va_size = DEV_BSIZE; 843 break; 844 845 case PFSself: 846 case PFScurproc: 847 vap->va_bytes = vap->va_size = 848 snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid); 849 break; 850 case PFStask: 851 if (pfs->pfs_fd != -1) { 852 vap->va_nlink = 1; 853 vap->va_uid = 0; 854 vap->va_gid = 0; 855 vap->va_bytes = vap->va_size = 856 snprintf(bf, sizeof(bf), ".."); 857 break; 858 } 859 /*FALLTHROUGH*/ 860 case PFSfd: 861 if (pfs->pfs_fd != -1) { 862 file_t *fp; 863 864 fp = fd_getfile2(procp, pfs->pfs_fd); 865 if (fp == NULL) { 866 error = EBADF; 867 break; 868 } 869 vap->va_nlink = 1; 870 vap->va_uid = kauth_cred_geteuid(fp->f_cred); 871 vap->va_gid = kauth_cred_getegid(fp->f_cred); 872 switch (fp->f_type) { 873 case DTYPE_VNODE: 874 vap->va_bytes = vap->va_size = 875 fp->f_vnode->v_size; 876 break; 877 default: 878 vap->va_bytes = vap->va_size = 0; 879 break; 880 } 881 closef(fp); 882 break; 883 } 884 /*FALLTHROUGH*/ 885 case PFSproc: 886 vap->va_nlink = 2; 887 vap->va_uid = kauth_cred_geteuid(procp->p_cred); 888 vap->va_gid = kauth_cred_getegid(procp->p_cred); 889 vap->va_bytes = vap->va_size = DEV_BSIZE; 890 break; 891 892 case PFSfile: 893 error = EOPNOTSUPP; 894 break; 895 896 case PFSmem: 897 vap->va_bytes = vap->va_size = 898 ctob(procp->p_vmspace->vm_tsize + 899 procp->p_vmspace->vm_dsize + 900 procp->p_vmspace->vm_ssize); 901 break; 902 903 case PFSauxv: 904 vap->va_bytes = vap->va_size = procp->p_execsw->es_arglen; 905 break; 906 907 #if defined(PT_GETREGS) || defined(PT_SETREGS) 908 case PFSregs: 909 vap->va_bytes = vap->va_size = sizeof(struct reg); 910 break; 911 #endif 912 913 #if defined(PT_GETFPREGS) || defined(PT_SETFPREGS) 914 case PFSfpregs: 915 vap->va_bytes = vap->va_size = sizeof(struct fpreg); 916 break; 917 #endif 918 919 case PFSstatus: 920 case PFSstat: 921 case PFSnote: 922 case PFSnotepg: 923 case PFScmdline: 924 case PFSenviron: 925 case PFSmeminfo: 926 case PFSdevices: 927 case PFScpuinfo: 928 case PFSuptime: 929 case PFSmounts: 930 case PFScpustat: 931 case PFSloadavg: 932 case PFSstatm: 933 case PFSversion: 934 case PFSsys: 935 case PFSsysfs: 936 case PFSmqueue: 937 case PFSmq_msg_def: 938 case PFSmq_msg_max: 939 case PFSmq_siz_def: 940 case PFSmq_siz_max: 941 case PFSmq_qmax: 942 case PFSsysvipc: 943 case PFSsysvipc_msg: 944 case PFSsysvipc_sem: 945 case PFSsysvipc_shm: 946 vap->va_bytes = vap->va_size = 0; 947 break; 948 case PFSlimit: 949 case PFSlimits: 950 case PFSmap: 951 case PFSmaps: 952 /* 953 * Advise a larger blocksize for the map files, so that 954 * they may be read in one pass. 955 */ 956 vap->va_blocksize = 4 * PAGE_SIZE; 957 vap->va_bytes = vap->va_size = 0; 958 break; 959 960 case PFScwd: 961 case PFSchroot: 962 bp = path + MAXPATHLEN; 963 *--bp = '\0'; 964 procfs_dir(pfs->pfs_type, curlwp, procp, &bp, path, 965 MAXPATHLEN); 966 vap->va_bytes = vap->va_size = strlen(bp); 967 break; 968 969 case PFSexe: 970 vap->va_bytes = vap->va_size = strlen(procp->p_path); 971 break; 972 973 case PFSemul: 974 vap->va_bytes = vap->va_size = strlen(procp->p_emul->e_name); 975 break; 976 977 #ifdef __HAVE_PROCFS_MACHDEP 978 PROCFS_MACHDEP_NODETYPE_CASES 979 error = procfs_machdep_getattr(ap->a_vp, vap, procp); 980 break; 981 #endif 982 983 default: 984 panic("%s: %d/2", __func__, pfs->pfs_type); 985 } 986 987 if (procp != NULL) 988 procfs_proc_unlock(procp); 989 if (path != NULL) 990 free(path, M_TEMP); 991 992 return (error); 993 } 994 995 /*ARGSUSED*/ 996 int 997 procfs_setattr(void *v) 998 { 999 /* 1000 * just fake out attribute setting 1001 * it's not good to generate an error 1002 * return, otherwise things like creat() 1003 * will fail when they try to set the 1004 * file length to 0. worse, this means 1005 * that echo $note > /proc/$pid/note will fail. 1006 */ 1007 1008 return (0); 1009 } 1010 1011 /* 1012 * implement access checking. 1013 * 1014 * actually, the check for super-user is slightly 1015 * broken since it will allow read access to write-only 1016 * objects. this doesn't cause any particular trouble 1017 * but does mean that the i/o entry points need to check 1018 * that the operation really does make sense. 1019 */ 1020 int 1021 procfs_access(void *v) 1022 { 1023 struct vop_access_args /* { 1024 struct vnode *a_vp; 1025 accmode_t a_accmode; 1026 kauth_cred_t a_cred; 1027 } */ *ap = v; 1028 struct vattr va; 1029 int error; 1030 1031 if ((error = VOP_GETATTR(ap->a_vp, &va, ap->a_cred)) != 0) 1032 return (error); 1033 1034 return kauth_authorize_vnode(ap->a_cred, 1035 KAUTH_ACCESS_ACTION(ap->a_accmode, ap->a_vp->v_type, va.va_mode), 1036 ap->a_vp, NULL, genfs_can_access(ap->a_vp, ap->a_cred, 1037 va.va_uid, va.va_gid, va.va_mode, NULL, ap->a_accmode)); 1038 } 1039 1040 /* 1041 * lookup. this is incredibly complicated in the 1042 * general case, however for most pseudo-filesystems 1043 * very little needs to be done. 1044 * 1045 * Locking isn't hard here, just poorly documented. 1046 * 1047 * If we're looking up ".", just vref the parent & return it. 1048 * 1049 * If we're looking up "..", unlock the parent, and lock "..". If everything 1050 * went ok, and we're on the last component and the caller requested the 1051 * parent locked, try to re-lock the parent. We do this to prevent lock 1052 * races. 1053 * 1054 * For anything else, get the needed node. Then unlock the parent if not 1055 * the last component or not LOCKPARENT (i.e. if we wouldn't re-lock the 1056 * parent in the .. case). 1057 * 1058 * We try to exit with the parent locked in error cases. 1059 */ 1060 int 1061 procfs_lookup(void *v) 1062 { 1063 struct vop_lookup_v2_args /* { 1064 struct vnode * a_dvp; 1065 struct vnode ** a_vpp; 1066 struct componentname * a_cnp; 1067 } */ *ap = v; 1068 struct componentname *cnp = ap->a_cnp; 1069 struct vnode **vpp = ap->a_vpp; 1070 struct vnode *dvp = ap->a_dvp; 1071 const char *pname = cnp->cn_nameptr; 1072 const struct proc_target *pt = NULL; 1073 struct vnode *fvp; 1074 pid_t pid, vnpid; 1075 struct pfsnode *pfs; 1076 struct proc *p = NULL; 1077 struct lwp *plwp; 1078 int i, error; 1079 pfstype type; 1080 1081 *vpp = NULL; 1082 1083 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred)) != 0) 1084 return (error); 1085 1086 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) 1087 return (EROFS); 1088 1089 if (cnp->cn_namelen == 1 && *pname == '.') { 1090 *vpp = dvp; 1091 vref(dvp); 1092 return (0); 1093 } 1094 1095 pfs = VTOPFS(dvp); 1096 switch (pfs->pfs_type) { 1097 case PFSroot: 1098 /* 1099 * Shouldn't get here with .. in the root node. 1100 */ 1101 if (cnp->cn_flags & ISDOTDOT) 1102 return (EIO); 1103 1104 for (i = 0; i < nproc_root_targets; i++) { 1105 pt = &proc_root_targets[i]; 1106 /* 1107 * check for node match. proc is always NULL here, 1108 * so call pt_valid with constant NULL lwp. 1109 */ 1110 if (cnp->cn_namelen == pt->pt_namlen && 1111 memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && 1112 (pt->pt_valid == NULL || 1113 (*pt->pt_valid)(NULL, dvp->v_mount))) 1114 break; 1115 } 1116 1117 if (i != nproc_root_targets) { 1118 error = procfs_allocvp(dvp->v_mount, vpp, 0, 1119 pt->pt_pfstype, -1); 1120 return (error); 1121 } 1122 1123 if (CNEQ(cnp, "curproc", 7)) { 1124 pid = curproc->p_pid; 1125 vnpid = 0; 1126 type = PFScurproc; 1127 } else if (CNEQ(cnp, "self", 4)) { 1128 pid = curproc->p_pid; 1129 vnpid = 0; 1130 type = PFSself; 1131 } else { 1132 pid = (pid_t)atoi(pname, cnp->cn_namelen); 1133 vnpid = pid; 1134 type = PFSproc; 1135 } 1136 1137 if (procfs_proc_lock(dvp->v_mount, pid, &p, ESRCH) != 0) 1138 break; 1139 error = procfs_allocvp(dvp->v_mount, vpp, vnpid, type, -1); 1140 procfs_proc_unlock(p); 1141 return (error); 1142 1143 case PFSproc: 1144 if (cnp->cn_flags & ISDOTDOT) { 1145 error = procfs_allocvp(dvp->v_mount, vpp, 0, PFSroot, 1146 -1); 1147 return (error); 1148 } 1149 1150 if (procfs_proc_lock(dvp->v_mount, pfs->pfs_pid, &p, 1151 ESRCH) != 0) 1152 break; 1153 1154 mutex_enter(p->p_lock); 1155 LIST_FOREACH(plwp, &p->p_lwps, l_sibling) { 1156 if (plwp->l_stat != LSZOMB) 1157 break; 1158 } 1159 /* Process is exiting if no-LWPS or all LWPs are LSZOMB */ 1160 if (plwp == NULL) { 1161 mutex_exit(p->p_lock); 1162 procfs_proc_unlock(p); 1163 return ESRCH; 1164 } 1165 1166 lwp_addref(plwp); 1167 mutex_exit(p->p_lock); 1168 1169 for (pt = proc_targets, i = 0; i < nproc_targets; pt++, i++) { 1170 int found; 1171 1172 found = cnp->cn_namelen == pt->pt_namlen && 1173 memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && 1174 (pt->pt_valid == NULL 1175 || (*pt->pt_valid)(plwp, dvp->v_mount)); 1176 if (found) 1177 break; 1178 } 1179 lwp_delref(plwp); 1180 1181 if (i == nproc_targets) { 1182 procfs_proc_unlock(p); 1183 break; 1184 } 1185 if (pt->pt_pfstype == PFSfile) { 1186 fvp = p->p_textvp; 1187 /* We already checked that it exists. */ 1188 vref(fvp); 1189 procfs_proc_unlock(p); 1190 *vpp = fvp; 1191 return (0); 1192 } 1193 1194 error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 1195 pt->pt_pfstype, -1); 1196 procfs_proc_unlock(p); 1197 return (error); 1198 1199 case PFSfd: { 1200 int fd; 1201 file_t *fp; 1202 1203 if ((error = procfs_proc_lock(dvp->v_mount, pfs->pfs_pid, &p, 1204 ENOENT)) != 0) 1205 return error; 1206 1207 if (cnp->cn_flags & ISDOTDOT) { 1208 error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 1209 PFSproc, -1); 1210 procfs_proc_unlock(p); 1211 return (error); 1212 } 1213 fd = atoi(pname, cnp->cn_namelen); 1214 1215 fp = fd_getfile2(p, fd); 1216 if (fp == NULL) { 1217 procfs_proc_unlock(p); 1218 return ENOENT; 1219 } 1220 fvp = fp->f_vnode; 1221 1222 /* Don't show directories */ 1223 if (fp->f_type == DTYPE_VNODE && fvp->v_type != VDIR && 1224 !procfs_proc_is_linux_compat()) { 1225 vref(fvp); 1226 closef(fp); 1227 procfs_proc_unlock(p); 1228 *vpp = fvp; 1229 return 0; 1230 } 1231 1232 closef(fp); 1233 error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 1234 PFSfd, fd); 1235 procfs_proc_unlock(p); 1236 return error; 1237 } 1238 case PFStask: { 1239 int xpid; 1240 1241 if ((error = procfs_proc_lock(dvp->v_mount, pfs->pfs_pid, &p, 1242 ENOENT)) != 0) 1243 return error; 1244 1245 if (cnp->cn_flags & ISDOTDOT) { 1246 error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 1247 PFSproc, -1); 1248 procfs_proc_unlock(p); 1249 return (error); 1250 } 1251 xpid = atoi(pname, cnp->cn_namelen); 1252 1253 if (xpid != pfs->pfs_pid) { 1254 procfs_proc_unlock(p); 1255 return ENOENT; 1256 } 1257 error = procfs_allocvp(dvp->v_mount, vpp, pfs->pfs_pid, 1258 PFStask, 0); 1259 procfs_proc_unlock(p); 1260 return error; 1261 } 1262 case PFSsys: 1263 case PFSsysfs: 1264 case PFSmqueue: 1265 case PFSsysvipc: { 1266 const struct proc_target *targets; 1267 int ntargets; 1268 pfstype parent; 1269 1270 switch (pfs->pfs_type) { 1271 case PFSsys: 1272 targets = proc_sys_targets; 1273 ntargets = nproc_sys_targets; 1274 parent = PFSroot; 1275 break; 1276 case PFSsysfs: 1277 targets = proc_sysfs_targets; 1278 ntargets = nproc_sysfs_targets; 1279 parent = PFSsys; 1280 break; 1281 case PFSmqueue: 1282 targets = proc_mqueue_targets; 1283 ntargets = nproc_mqueue_targets; 1284 parent = PFSsysfs; 1285 break; 1286 case PFSsysvipc: 1287 targets = proc_sysvipc_targets; 1288 ntargets = nproc_sysvipc_targets; 1289 parent = PFSroot; 1290 break; 1291 default: 1292 return (EINVAL); 1293 } 1294 1295 if (cnp->cn_flags & ISDOTDOT) { 1296 error = procfs_allocvp(dvp->v_mount, vpp, 0, parent, 1297 -1); 1298 return (error); 1299 } 1300 1301 for (i = 0; i < ntargets; i++) { 1302 pt = &targets[i]; 1303 /* 1304 * check for node match. proc is always NULL here, 1305 * so call pt_valid with constant NULL lwp. 1306 */ 1307 if (cnp->cn_namelen == pt->pt_namlen && 1308 memcmp(pt->pt_name, pname, cnp->cn_namelen) == 0 && 1309 (pt->pt_valid == NULL || 1310 (*pt->pt_valid)(NULL, dvp->v_mount))) 1311 break; 1312 } 1313 1314 if (i != ntargets) { 1315 error = procfs_allocvp(dvp->v_mount, vpp, 0, 1316 pt->pt_pfstype, -1); 1317 return (error); 1318 } 1319 1320 return (ENOENT); 1321 } 1322 1323 default: 1324 return (ENOTDIR); 1325 } 1326 1327 return (cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS); 1328 } 1329 1330 int 1331 procfs_validfile(struct lwp *l, struct mount *mp) 1332 { 1333 return l != NULL && l->l_proc != NULL && l->l_proc->p_textvp != NULL; 1334 } 1335 1336 static int 1337 procfs_validfile_linux(struct lwp *l, struct mount *mp) 1338 { 1339 return procfs_use_linux_compat(mp) && 1340 (l == NULL || l->l_proc == NULL || procfs_validfile(l, mp)); 1341 } 1342 1343 struct procfs_root_readdir_ctx { 1344 struct uio *uiop; 1345 off_t *cookies; 1346 int ncookies; 1347 off_t off; 1348 off_t startoff; 1349 int error; 1350 }; 1351 1352 static int 1353 procfs_root_readdir_callback(struct proc *p, void *arg) 1354 { 1355 struct procfs_root_readdir_ctx *ctxp = arg; 1356 struct dirent d; 1357 struct uio *uiop; 1358 int error; 1359 1360 uiop = ctxp->uiop; 1361 if (uiop->uio_resid < UIO_MX) 1362 return -1; /* no space */ 1363 1364 if (kauth_authorize_process(kauth_cred_get(), 1365 KAUTH_PROCESS_CANSEE, p, 1366 KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), NULL, NULL) != 0) 1367 return 0; 1368 1369 if (ctxp->off < ctxp->startoff) { 1370 ctxp->off++; 1371 return 0; 1372 } 1373 1374 memset(&d, 0, UIO_MX); 1375 d.d_reclen = UIO_MX; 1376 d.d_fileno = PROCFS_FILENO(p->p_pid, PFSproc, -1); 1377 d.d_namlen = snprintf(d.d_name, 1378 UIO_MX - offsetof(struct dirent, d_name), "%ld", (long)p->p_pid); 1379 d.d_type = DT_DIR; 1380 1381 mutex_exit(&proc_lock); 1382 error = uiomove(&d, UIO_MX, uiop); 1383 mutex_enter(&proc_lock); 1384 if (error) { 1385 ctxp->error = error; 1386 return -1; 1387 } 1388 1389 ctxp->ncookies++; 1390 if (ctxp->cookies) 1391 *(ctxp->cookies)++ = ctxp->off + 1; 1392 ctxp->off++; 1393 1394 return 0; 1395 } 1396 1397 /* 1398 * readdir returns directory entries from pfsnode (vp). 1399 * 1400 * the strategy here with procfs is to generate a single 1401 * directory entry at a time (struct dirent) and then 1402 * copy that out to userland using uiomove. a more efficient 1403 * though more complex implementation, would try to minimize 1404 * the number of calls to uiomove(). for procfs, this is 1405 * hardly worth the added code complexity. 1406 * 1407 * this should just be done through read() 1408 */ 1409 int 1410 procfs_readdir(void *v) 1411 { 1412 struct vop_readdir_args /* { 1413 struct vnode *a_vp; 1414 struct uio *a_uio; 1415 kauth_cred_t a_cred; 1416 int *a_eofflag; 1417 off_t **a_cookies; 1418 int *a_ncookies; 1419 } */ *ap = v; 1420 struct uio *uio = ap->a_uio; 1421 struct dirent d; 1422 struct pfsnode *pfs; 1423 off_t i; 1424 int error; 1425 off_t *cookies = NULL; 1426 int ncookies; 1427 struct vnode *vp; 1428 const struct proc_target *pt; 1429 struct procfs_root_readdir_ctx ctx; 1430 struct proc *p = NULL; 1431 struct lwp *l; 1432 int nfd; 1433 int nc = 0; 1434 1435 vp = ap->a_vp; 1436 pfs = VTOPFS(vp); 1437 1438 if (uio->uio_resid < UIO_MX) 1439 return (EINVAL); 1440 if (uio->uio_offset < 0) 1441 return (EINVAL); 1442 1443 error = 0; 1444 i = uio->uio_offset; 1445 memset(&d, 0, UIO_MX); 1446 d.d_reclen = UIO_MX; 1447 ncookies = uio->uio_resid / UIO_MX; 1448 1449 switch (pfs->pfs_type) { 1450 /* 1451 * this is for the process-specific sub-directories. 1452 * all that is needed to is copy out all the entries 1453 * from the procent[] table (top of this file). 1454 */ 1455 case PFSproc: { 1456 1457 if (i >= nproc_targets) 1458 return 0; 1459 1460 if (procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p, ESRCH) != 0) 1461 break; 1462 1463 if (ap->a_ncookies) { 1464 ncookies = uimin(ncookies, (nproc_targets - i)); 1465 cookies = malloc(ncookies * sizeof (off_t), 1466 M_TEMP, M_WAITOK); 1467 *ap->a_cookies = cookies; 1468 } 1469 1470 for (pt = &proc_targets[i]; 1471 uio->uio_resid >= UIO_MX && i < nproc_targets; pt++, i++) { 1472 if (pt->pt_valid) { 1473 /* XXXSMP LWP can disappear */ 1474 mutex_enter(p->p_lock); 1475 l = LIST_FIRST(&p->p_lwps); 1476 KASSERT(l != NULL); 1477 mutex_exit(p->p_lock); 1478 if ((*pt->pt_valid)(l, vp->v_mount) == 0) 1479 continue; 1480 } 1481 1482 d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, 1483 pt->pt_pfstype, -1); 1484 d.d_namlen = pt->pt_namlen; 1485 memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1); 1486 d.d_type = pt->pt_type; 1487 1488 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1489 break; 1490 if (cookies) 1491 *cookies++ = i + 1; 1492 } 1493 1494 procfs_proc_unlock(p); 1495 break; 1496 } 1497 case PFSfd: { 1498 file_t *fp; 1499 int lim; 1500 1501 if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p, 1502 ESRCH)) != 0) 1503 return error; 1504 1505 /* XXX Should this be by file as well? */ 1506 if (kauth_authorize_process(kauth_cred_get(), 1507 KAUTH_PROCESS_CANSEE, p, 1508 KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_OPENFILES), NULL, 1509 NULL) != 0) { 1510 procfs_proc_unlock(p); 1511 return ESRCH; 1512 } 1513 1514 nfd = atomic_load_consume(&p->p_fd->fd_dt)->dt_nfiles; 1515 1516 lim = uimin((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); 1517 if (i >= lim) { 1518 procfs_proc_unlock(p); 1519 return 0; 1520 } 1521 1522 if (ap->a_ncookies) { 1523 ncookies = uimin(ncookies, (nfd + 2 - i)); 1524 cookies = malloc(ncookies * sizeof (off_t), 1525 M_TEMP, M_WAITOK); 1526 *ap->a_cookies = cookies; 1527 } 1528 1529 for (; i < 2 && uio->uio_resid >= UIO_MX; i++) { 1530 pt = &proc_targets[i]; 1531 d.d_namlen = pt->pt_namlen; 1532 d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, 1533 pt->pt_pfstype, -1); 1534 (void)memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1); 1535 d.d_type = pt->pt_type; 1536 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1537 break; 1538 if (cookies) 1539 *cookies++ = i + 1; 1540 nc++; 1541 } 1542 if (error) 1543 goto out; 1544 for (; uio->uio_resid >= UIO_MX && i < nfd; i++) { 1545 /* check the descriptor exists */ 1546 if ((fp = fd_getfile2(p, i - 2)) == NULL) 1547 continue; 1548 closef(fp); 1549 1550 d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, PFSfd, i - 2); 1551 d.d_namlen = snprintf(d.d_name, sizeof(d.d_name), 1552 "%lld", (long long)(i - 2)); 1553 d.d_type = fttodt(fp); 1554 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1555 break; 1556 if (cookies) 1557 *cookies++ = i + 1; 1558 nc++; 1559 } 1560 goto out; 1561 } 1562 case PFStask: { 1563 1564 if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p, 1565 ESRCH)) != 0) 1566 return error; 1567 1568 nfd = 3; /* ., .., pid */ 1569 1570 if (ap->a_ncookies) { 1571 ncookies = uimin(ncookies, (nfd + 2 - i)); 1572 cookies = malloc(ncookies * sizeof (off_t), 1573 M_TEMP, M_WAITOK); 1574 *ap->a_cookies = cookies; 1575 } 1576 1577 for (; i < 2 && uio->uio_resid >= UIO_MX; i++) { 1578 pt = &proc_targets[i]; 1579 d.d_namlen = pt->pt_namlen; 1580 d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, 1581 pt->pt_pfstype, -1); 1582 (void)memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1); 1583 d.d_type = pt->pt_type; 1584 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1585 break; 1586 if (cookies) 1587 *cookies++ = i + 1; 1588 nc++; 1589 } 1590 if (error) 1591 goto out; 1592 for (; uio->uio_resid >= UIO_MX && i < nfd; i++) { 1593 /* check the descriptor exists */ 1594 d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, PFStask, 1595 i - 2); 1596 d.d_namlen = snprintf(d.d_name, sizeof(d.d_name), 1597 "%ld", (long)pfs->pfs_pid); 1598 d.d_type = DT_LNK; 1599 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1600 break; 1601 if (cookies) 1602 *cookies++ = i + 1; 1603 nc++; 1604 } 1605 goto out; 1606 } 1607 1608 /* 1609 * misc subdirectories 1610 */ 1611 case PFSsys: 1612 case PFSsysfs: 1613 case PFSmqueue: 1614 case PFSsysvipc: { 1615 const struct proc_target *targets; 1616 int ntargets; 1617 1618 switch (pfs->pfs_type) { 1619 case PFSsys: 1620 targets = proc_sys_targets; 1621 ntargets = nproc_sys_targets; 1622 break; 1623 case PFSsysfs: 1624 targets = proc_sysfs_targets; 1625 ntargets = nproc_sysfs_targets; 1626 break; 1627 case PFSmqueue: 1628 targets = proc_mqueue_targets; 1629 ntargets = nproc_mqueue_targets; 1630 break; 1631 case PFSsysvipc: 1632 targets = proc_sysvipc_targets; 1633 ntargets = nproc_sysvipc_targets; 1634 break; 1635 default: 1636 return (EINVAL); 1637 } 1638 1639 if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p, 1640 ESRCH)) != 0) 1641 return error; 1642 if (ap->a_ncookies) { 1643 ncookies = uimin(ncookies, (ntargets - i)); 1644 cookies = malloc(ncookies * sizeof (off_t), 1645 M_TEMP, M_WAITOK); 1646 *ap->a_cookies = cookies; 1647 } 1648 1649 for (pt = &targets[i]; 1650 uio->uio_resid >= UIO_MX && i < ntargets; pt++, i++) { 1651 if (pt->pt_valid && 1652 (*pt->pt_valid)(NULL, vp->v_mount) == 0) 1653 continue; 1654 d.d_fileno = PROCFS_FILENO(pfs->pfs_pid, 1655 pt->pt_pfstype, -1); 1656 d.d_namlen = pt->pt_namlen; 1657 memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1); 1658 d.d_type = pt->pt_type; 1659 1660 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1661 break; 1662 if (cookies) 1663 *cookies++ = i + 1; 1664 } 1665 1666 goto out; 1667 } 1668 1669 /* 1670 * this is for the root of the procfs filesystem 1671 * what is needed are special entries for "curproc" 1672 * and "self" followed by an entry for each process 1673 * on allproc. 1674 */ 1675 1676 case PFSroot: { 1677 1678 if (ap->a_ncookies) { 1679 /* 1680 * XXX Potentially allocating too much space here, 1681 * but I'm lazy. This loop needs some work. 1682 */ 1683 cookies = malloc(ncookies * sizeof (off_t), 1684 M_TEMP, M_WAITOK); 1685 *ap->a_cookies = cookies; 1686 } 1687 1688 /* 0 ... 3 are static entries. */ 1689 for (; i <= 3 && uio->uio_resid >= UIO_MX; i++) { 1690 switch (i) { 1691 case 0: /* `.' */ 1692 case 1: /* `..' */ 1693 d.d_fileno = PROCFS_FILENO(0, PFSroot, -1); 1694 d.d_namlen = i + 1; 1695 memcpy(d.d_name, "..", d.d_namlen); 1696 d.d_name[i + 1] = '\0'; 1697 d.d_type = DT_DIR; 1698 break; 1699 1700 case 2: 1701 d.d_fileno = PROCFS_FILENO(0, PFScurproc, -1); 1702 d.d_namlen = sizeof("curproc") - 1; 1703 memcpy(d.d_name, "curproc", sizeof("curproc")); 1704 d.d_type = DT_LNK; 1705 break; 1706 1707 case 3: 1708 d.d_fileno = PROCFS_FILENO(0, PFSself, -1); 1709 d.d_namlen = sizeof("self") - 1; 1710 memcpy(d.d_name, "self", sizeof("self")); 1711 d.d_type = DT_LNK; 1712 break; 1713 } 1714 1715 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1716 break; 1717 nc++; 1718 if (cookies) 1719 *cookies++ = i + 1; 1720 } 1721 if (error) 1722 break; 1723 /* 4 ... are process entries. */ 1724 ctx.uiop = uio; 1725 ctx.error = 0; 1726 ctx.off = 4; 1727 ctx.startoff = i; 1728 ctx.cookies = cookies; 1729 ctx.ncookies = nc; 1730 proclist_foreach_call(&allproc, 1731 procfs_root_readdir_callback, &ctx); 1732 cookies = ctx.cookies; 1733 nc = ctx.ncookies; 1734 error = ctx.error; 1735 if (error) 1736 break; 1737 1738 /* misc entries. */ 1739 if (i < ctx.off) 1740 i = ctx.off; 1741 if (i >= ctx.off + nproc_root_targets) 1742 break; 1743 error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &p, ESRCH); 1744 if (error) 1745 break; 1746 for (pt = &proc_root_targets[i - ctx.off]; 1747 uio->uio_resid >= UIO_MX && 1748 pt < &proc_root_targets[nproc_root_targets]; 1749 pt++, i++) { 1750 if (pt->pt_valid && 1751 (*pt->pt_valid)(NULL, vp->v_mount) == 0) 1752 continue; 1753 if (kauth_authorize_process(kauth_cred_get(), 1754 KAUTH_PROCESS_CANSEE, p, 1755 KAUTH_ARG(KAUTH_REQ_PROCESS_CANSEE_ENTRY), 1756 NULL, NULL) != 0) 1757 continue; 1758 d.d_fileno = PROCFS_FILENO(0, pt->pt_pfstype, -1); 1759 d.d_namlen = pt->pt_namlen; 1760 memcpy(d.d_name, pt->pt_name, pt->pt_namlen + 1); 1761 d.d_type = pt->pt_type; 1762 1763 if ((error = uiomove(&d, UIO_MX, uio)) != 0) 1764 break; 1765 nc++; 1766 if (cookies) 1767 *cookies++ = i + 1; 1768 } 1769 out: 1770 KASSERT(p != NULL); 1771 ncookies = nc; 1772 procfs_proc_unlock(p); 1773 break; 1774 } 1775 1776 default: 1777 error = ENOTDIR; 1778 break; 1779 } 1780 1781 if (ap->a_ncookies) { 1782 if (error) { 1783 if (cookies) 1784 free(*ap->a_cookies, M_TEMP); 1785 *ap->a_ncookies = 0; 1786 *ap->a_cookies = NULL; 1787 } else 1788 *ap->a_ncookies = ncookies; 1789 } 1790 uio->uio_offset = i; 1791 return (error); 1792 } 1793 1794 /* 1795 * readlink reads the link of `curproc' and others 1796 */ 1797 int 1798 procfs_readlink(void *v) 1799 { 1800 struct vop_readlink_args *ap = v; 1801 char bf[16]; /* should be enough */ 1802 char *bp = bf; 1803 char *path = NULL; 1804 int len = 0; 1805 int error = 0; 1806 struct vnode *vp = ap->a_vp; 1807 struct pfsnode *pfs = VTOPFS(vp); 1808 struct proc *pown = NULL; 1809 1810 if (pfs->pfs_fileno == PROCFS_FILENO(0, PFScurproc, -1)) 1811 len = snprintf(bf, sizeof(bf), "%ld", (long)curproc->p_pid); 1812 else if (pfs->pfs_fileno == PROCFS_FILENO(0, PFSself, -1)) 1813 len = snprintf(bf, sizeof(bf), "%s", "curproc"); 1814 else if (pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFStask, 0)) 1815 len = snprintf(bf, sizeof(bf), ".."); 1816 else if (pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSexe, -1)) { 1817 if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &pown, 1818 ESRCH)) != 0) 1819 return error; 1820 bp = pown->p_path; 1821 len = strlen(bp); 1822 } else if (pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFScwd, -1) || 1823 pfs->pfs_fileno == PROCFS_FILENO(pfs->pfs_pid, PFSchroot, -1)) { 1824 if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &pown, 1825 ESRCH)) != 0) 1826 return error; 1827 path = malloc(MAXPATHLEN + 4, M_TEMP, M_WAITOK); 1828 if (path == NULL) { 1829 procfs_proc_unlock(pown); 1830 return (ENOMEM); 1831 } 1832 bp = path + MAXPATHLEN; 1833 *--bp = '\0'; 1834 procfs_dir(PROCFS_TYPE(pfs->pfs_fileno), curlwp, pown, 1835 &bp, path, MAXPATHLEN); 1836 len = strlen(bp); 1837 } else { 1838 file_t *fp; 1839 struct vnode *vxp; 1840 1841 if ((error = procfs_proc_lock(vp->v_mount, pfs->pfs_pid, &pown, 1842 ESRCH)) != 0) 1843 return error; 1844 1845 fp = fd_getfile2(pown, pfs->pfs_fd); 1846 if (fp == NULL) { 1847 procfs_proc_unlock(pown); 1848 return EBADF; 1849 } 1850 1851 switch (fp->f_type) { 1852 case DTYPE_VNODE: 1853 vxp = fp->f_vnode; 1854 if (vxp->v_type != VDIR && 1855 !procfs_proc_is_linux_compat()) { 1856 error = EINVAL; 1857 break; 1858 } 1859 if ((path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK)) 1860 == NULL) { 1861 error = ENOMEM; 1862 break; 1863 } 1864 bp = path + MAXPATHLEN; 1865 *--bp = '\0'; 1866 1867 /* 1868 * XXX: kludge to avoid locking against ourselves 1869 * in getcwd() 1870 */ 1871 if (vxp->v_tag == VT_PROCFS) { 1872 *--bp = '/'; 1873 } else { 1874 rw_enter(&curproc->p_cwdi->cwdi_lock, 1875 RW_READER); 1876 vp = curproc->p_cwdi->cwdi_rdir; 1877 if (vp == NULL) 1878 vp = rootvnode; 1879 error = getcwd_common(vxp, vp, &bp, path, 1880 MAXPATHLEN / 2, 0, curlwp); 1881 rw_exit(&curproc->p_cwdi->cwdi_lock); 1882 } 1883 if (error) 1884 break; 1885 len = strlen(bp); 1886 break; 1887 1888 case DTYPE_MISC: 1889 len = snprintf(bf, sizeof(bf), "%s", "[misc]"); 1890 break; 1891 1892 case DTYPE_KQUEUE: 1893 len = snprintf(bf, sizeof(bf), "%s", "[kqueue]"); 1894 break; 1895 1896 case DTYPE_SEM: 1897 len = snprintf(bf, sizeof(bf), "%s", "[ksem]"); 1898 break; 1899 1900 default: 1901 error = EINVAL; 1902 break; 1903 } 1904 closef(fp); 1905 } 1906 1907 if (error == 0) 1908 error = uiomove(bp, len, ap->a_uio); 1909 if (pown) 1910 procfs_proc_unlock(pown); 1911 if (path) 1912 free(path, M_TEMP); 1913 return error; 1914 } 1915 1916 int 1917 procfs_getpages(void *v) 1918 { 1919 struct vop_getpages_args /* { 1920 struct vnode *a_vp; 1921 voff_t a_offset; 1922 struct vm_page **a_m; 1923 int *a_count; 1924 int a_centeridx; 1925 vm_prot_t a_access_type; 1926 int a_advice; 1927 int a_flags; 1928 } */ *ap = v; 1929 1930 if ((ap->a_flags & PGO_LOCKED) == 0) 1931 rw_exit(ap->a_vp->v_uobj.vmobjlock); 1932 1933 return (EFAULT); 1934 } 1935 1936 /* 1937 * convert decimal ascii to int 1938 */ 1939 static int 1940 atoi(const char *b, size_t len) 1941 { 1942 int p = 0; 1943 1944 while (len--) { 1945 char c = *b++; 1946 if (c < '0' || c > '9') 1947 return -1; 1948 p = 10 * p + (c - '0'); 1949 } 1950 1951 return p; 1952 } 1953 1954 /** 1955 * convert DTYPE_XXX to corresponding DT_XXX 1956 * matching what procfs_loadvnode() does. 1957 */ 1958 static uint8_t 1959 fttodt(file_t *fp) 1960 { 1961 switch (fp->f_type) { 1962 case DTYPE_VNODE: 1963 switch (fp->f_vnode->v_type) { 1964 case VREG: return DT_REG; 1965 case VDIR: return DT_LNK; /* symlink */ 1966 case VBLK: return DT_BLK; 1967 case VCHR: return DT_CHR; 1968 case VLNK: return DT_LNK; 1969 case VSOCK: return DT_SOCK; 1970 case VFIFO: return DT_FIFO; 1971 default: return DT_UNKNOWN; 1972 } 1973 case DTYPE_PIPE: return DT_FIFO; 1974 case DTYPE_SOCKET: return DT_SOCK; 1975 case DTYPE_KQUEUE: /*FALLTHROUGH*/ 1976 case DTYPE_MISC: /*FALLTHROUGH*/ 1977 case DTYPE_SEM: return DT_LNK; /* symlinks */ 1978 default: return DT_UNKNOWN; 1979 } 1980 } 1981