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
procfs_open(void * v)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
procfs_close(void * v)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
procfs_inactive(void * v)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
procfs_reclaim(void * v)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
procfs_pathconf(void * v)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
procfs_print(void * v)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
procfs_dir(pfstype t,struct lwp * caller,struct proc * target,char ** bpp,char * path,size_t len)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
procfs_getattr(void * v)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
procfs_setattr(void * v)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
procfs_access(void * v)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
procfs_lookup(void * v)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
procfs_validfile(struct lwp * l,struct mount * mp)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
procfs_validfile_linux(struct lwp * l,struct mount * mp)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
procfs_root_readdir_callback(struct proc * p,void * arg)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
procfs_readdir(void * v)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
procfs_readlink(void * v)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
procfs_getpages(void * v)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
atoi(const char * b,size_t len)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
fttodt(file_t * fp)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