xref: /netbsd-src/usr.bin/fstat/misc.c (revision ff3504bd371b0b43d3b66e98af7faf70eb1f4ea6)
1*ff3504bdSriastradh /*	$NetBSD: misc.c,v 1.27 2023/07/29 08:46:47 riastradh Exp $	*/
2380fafb7Schristos 
3380fafb7Schristos /*-
4380fafb7Schristos  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5380fafb7Schristos  * All rights reserved.
6380fafb7Schristos  *
7380fafb7Schristos  * This code is derived from software contributed to The NetBSD Foundation
8380fafb7Schristos  * by Christos Zoulas
9380fafb7Schristos  *
10380fafb7Schristos  * Redistribution and use in source and binary forms, with or without
11380fafb7Schristos  * modification, are permitted provided that the following conditions
12380fafb7Schristos  * are met:
13380fafb7Schristos  * 1. Redistributions of source code must retain the above copyright
14380fafb7Schristos  *    notice, this list of conditions and the following disclaimer.
15380fafb7Schristos  * 2. Redistributions in binary form must reproduce the above copyright
16380fafb7Schristos  *    notice, this list of conditions and the following disclaimer in the
17380fafb7Schristos  *    documentation and/or other materials provided with the distribution.
18380fafb7Schristos  *
19380fafb7Schristos  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20380fafb7Schristos  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21380fafb7Schristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22380fafb7Schristos  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23380fafb7Schristos  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24380fafb7Schristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25380fafb7Schristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26380fafb7Schristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27380fafb7Schristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28380fafb7Schristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29380fafb7Schristos  * POSSIBILITY OF SUCH DAMAGE.
30380fafb7Schristos  */
31380fafb7Schristos 
32380fafb7Schristos #include <sys/cdefs.h>
33*ff3504bdSriastradh __RCSID("$NetBSD: misc.c,v 1.27 2023/07/29 08:46:47 riastradh Exp $");
34380fafb7Schristos 
358dd0b445Schristos #include <stdbool.h>
36380fafb7Schristos #include <sys/param.h>
37f73facbcSchristos #include <sys/types.h>
38380fafb7Schristos #include <sys/time.h>
39380fafb7Schristos #include <sys/stat.h>
408dd0b445Schristos #include <sys/condvar.h>
418dd0b445Schristos #include <sys/selinfo.h>
428dd0b445Schristos #include <sys/filedesc.h>
438dd0b445Schristos #define _KERNEL
448dd0b445Schristos #include <sys/mqueue.h>
458dd0b445Schristos #include <sys/eventvar.h>
468dd0b445Schristos #undef _KERNEL
47380fafb7Schristos #include <sys/proc.h>
48380fafb7Schristos #define _KERNEL
49380fafb7Schristos #include <sys/file.h>
5068e270a2Sthorpej #define copyin_t int
510548a80aSchristos #define copyout_t int
520548a80aSchristos #include <sys/ksem.h>
533d7bb1daSchristos #define _LIB_LIBKERN_LIBKERN_H_
543d7bb1daSchristos #define mutex_enter(a)
553d7bb1daSchristos #define mutex_exit(a)
56380fafb7Schristos #undef _KERNEL
57ea6af427Stls #include <sys/cprng.h>
58380fafb7Schristos #include <sys/vnode.h>
59*ff3504bdSriastradh #include <sys/memfd.h>
60380fafb7Schristos #include <sys/mount.h>
61380fafb7Schristos 
62380fafb7Schristos #include <net/bpfdesc.h>
63380fafb7Schristos 
64baa8677bSisaki #include <dev/audio/audiodef.h>
65baa8677bSisaki #include <dev/audio/audio_if.h>
66baa8677bSisaki 
67380fafb7Schristos #include <err.h>
683d7bb1daSchristos #include <util.h>
690548a80aSchristos #include <string.h>
70380fafb7Schristos #include <kvm.h>
71380fafb7Schristos #include "fstat.h"
72380fafb7Schristos 
73380fafb7Schristos static struct nlist nl[] = {
7448bd4d9cSchristos #define NL_BPF		0
75380fafb7Schristos     { .n_name = "bpf_fileops", },
7648bd4d9cSchristos #define NL_CRYPTO	1
7748bd4d9cSchristos     { .n_name = "cryptofops" },
7848bd4d9cSchristos #define NL_DMIO		2
7948bd4d9cSchristos     { .n_name = "dmio_fileops", },
8048bd4d9cSchristos #define NL_DRVCTL	3
8148bd4d9cSchristos     { .n_name = "drvctl_fileops", },
8248bd4d9cSchristos #define NL_DTV_DEMUX	4
8348bd4d9cSchristos     { .n_name = "dtv_demux_fileops", },
8448bd4d9cSchristos #define NL_FILEMON	5
8548bd4d9cSchristos     { .n_name = "filemon_fileops", },
8648bd4d9cSchristos #define NL_KQUEUE	6
8748bd4d9cSchristos     { .n_name = "kqueueops" },
8848bd4d9cSchristos #define NL_MQUEUE	7
8948bd4d9cSchristos     { .n_name = "mqops" },
9048bd4d9cSchristos #define NL_PIPE		8
9148bd4d9cSchristos     { .n_name = "pipeops" },
9248bd4d9cSchristos #define NL_PUTTER	9
9348bd4d9cSchristos     { .n_name = "putter_fileops", },
942732a80bSchristos #define NL_RND		10
952732a80bSchristos     { .n_name = "rnd_fileops", },
962732a80bSchristos #define NL_SEM		11
9748bd4d9cSchristos     { .n_name = "semops", },
982732a80bSchristos #define NL_SOCKET	12
9948bd4d9cSchristos     { .n_name = "socketops" },
1002732a80bSchristos #define NL_SVR4_NET	13
10148bd4d9cSchristos     { .n_name = "svr4_netops" },
1022732a80bSchristos #define NL_SVR4_32_NET	14
10348bd4d9cSchristos     { .n_name = "svr4_32_netops" },
1042732a80bSchristos #define NL_TAP		15
105380fafb7Schristos     { .n_name = "tap_fileops", },
1062732a80bSchristos #define NL_VNOPS	16
10748bd4d9cSchristos     { .n_name = "vnops" },
1082732a80bSchristos #define NL_XENEVT	17
10948bd4d9cSchristos     { .n_name = "xenevt_fileops" },
110911089b5Snat #define NL_AUDIO	18
111911089b5Snat     { .n_name = "audio_fileops" },
112911089b5Snat #define NL_PAD		19
113911089b5Snat     { .n_name = "pad_fileops" },
1147eace3daSchristos #define NL_MEMFD	20
1157eace3daSchristos     { .n_name = "memfd_fileops" },
1167eace3daSchristos #define NL_MAX		21
117380fafb7Schristos     { .n_name = NULL }
118380fafb7Schristos };
119380fafb7Schristos 
12090baf4f2Schristos extern int vflg;
12190baf4f2Schristos 
122380fafb7Schristos 
123380fafb7Schristos static int
p_bpf(struct file * f)124380fafb7Schristos p_bpf(struct file *f)
125380fafb7Schristos {
126380fafb7Schristos 	struct bpf_d bpf;
127f51d1f25Schristos 	struct bpf_if bi;
128f51d1f25Schristos 	struct ifnet ifn;
129f51d1f25Schristos 
130f51d1f25Schristos 	strlcpy(ifn.if_xname, "???", sizeof(ifn.if_xname));
131380fafb7Schristos 
132380fafb7Schristos 	if (!KVM_READ(f->f_data, &bpf, sizeof(bpf))) {
133380fafb7Schristos 		dprintf("can't read bpf at %p for pid %d", f->f_data, Pid);
134380fafb7Schristos 		return 0;
135380fafb7Schristos 	}
136f51d1f25Schristos 	if (bpf.bd_bif != NULL) {
137f51d1f25Schristos 		if (!KVM_READ(bpf.bd_bif, &bi, sizeof(bi)))
138f51d1f25Schristos 			dprintf("can't read bpf interface at %p for pid %d",
139f51d1f25Schristos 			    bpf.bd_bif, Pid);
140f51d1f25Schristos 		if (bi.bif_ifp != NULL)
141f51d1f25Schristos 			if (!KVM_READ(bi.bif_ifp, &ifn, sizeof(ifn)))
142f51d1f25Schristos 				dprintf("can't read net interfsace"
143f51d1f25Schristos 				    " at %p for pid %d", bi.bif_ifp, Pid);
144f51d1f25Schristos 	}
145f51d1f25Schristos 	(void)printf("* bpf@%s rec=%lu, dr=%lu, cap=%lu, pid=%lu", ifn.if_xname,
146380fafb7Schristos 	    bpf.bd_rcount, bpf.bd_dcount, bpf.bd_ccount,
147380fafb7Schristos 	    (unsigned long)bpf.bd_pid);
148380fafb7Schristos 	if (bpf.bd_promisc)
149380fafb7Schristos 		(void)printf(", promisc");
150380fafb7Schristos 	if (bpf.bd_immediate)
151380fafb7Schristos 		(void)printf(", immed");
152204f26c6Smsaitoh 	if (bpf.bd_direction == BPF_D_IN)
153204f26c6Smsaitoh 		(void)printf(", in");
154204f26c6Smsaitoh 	else if (bpf.bd_direction == BPF_D_INOUT)
155204f26c6Smsaitoh 		(void)printf(", inout");
156204f26c6Smsaitoh 	else if (bpf.bd_direction == BPF_D_OUT)
157204f26c6Smsaitoh 		(void)printf(", out");
1584d1ae9a9Salnsn 	if (bpf.bd_jitcode != NULL)
1594d1ae9a9Salnsn 		(void)printf(", jit");
160380fafb7Schristos 	if (bpf.bd_async)
161380fafb7Schristos 		(void)printf(", asyncgrp=%lu", (unsigned long)bpf.bd_pgid);
162380fafb7Schristos 	if (bpf.bd_state == BPF_IDLE)
163380fafb7Schristos 		(void)printf(", idle");
164380fafb7Schristos 	else if (bpf.bd_state == BPF_WAITING)
165380fafb7Schristos 		(void)printf(", waiting");
166380fafb7Schristos 	else if (bpf.bd_state == BPF_TIMED_OUT)
167380fafb7Schristos 		(void)printf(", timeout");
168ebe962e4Schristos 	oprint(f, "\n");
169380fafb7Schristos 	return 0;
170380fafb7Schristos }
171380fafb7Schristos 
172380fafb7Schristos static int
p_sem(struct file * f)1730548a80aSchristos p_sem(struct file *f)
1740548a80aSchristos {
1750548a80aSchristos 	ksem_t ks;
1760548a80aSchristos 	if (!KVM_READ(f->f_data, &ks, sizeof(ks))) {
1770548a80aSchristos 		dprintf("can't read sem at %p for pid %d", f->f_data, Pid);
1780548a80aSchristos 		return 0;
1790548a80aSchristos 	}
1800548a80aSchristos 	(void)printf("* ksem ref=%u, value=%u, waiters=%u, flags=0x%x, "
1810548a80aSchristos 	    "mode=%o, uid=%u, gid=%u", ks.ks_ref, ks.ks_value, ks.ks_waiters,
1820548a80aSchristos 	    ks.ks_flags, ks.ks_mode, ks.ks_uid, ks.ks_gid);
1830548a80aSchristos 	if (ks.ks_name && ks.ks_namelen) {
1840548a80aSchristos 		char buf[64];
1850548a80aSchristos 		if (ks.ks_namelen >= sizeof(buf))
1860548a80aSchristos 			ks.ks_namelen = sizeof(buf) - 1;
1870548a80aSchristos 		if (!KVM_READ(ks.ks_name, buf, ks.ks_namelen)) {
1880548a80aSchristos 			dprintf("can't read sem name at %p for pid %d",
1890548a80aSchristos 			    ks.ks_name, Pid);
1900548a80aSchristos 		} else {
1910548a80aSchristos 			buf[ks.ks_namelen] = '\0';
192ebe962e4Schristos 			(void)printf(", name=%s", buf);
193ebe962e4Schristos 			oprint(f, "\n");
1940548a80aSchristos 			return 0;
1950548a80aSchristos 		}
1960548a80aSchristos 	}
197ebe962e4Schristos 	oprint(f, "\n");
1980548a80aSchristos 	return 0;
1990548a80aSchristos }
2000548a80aSchristos 
2010548a80aSchristos static int
p_mqueue(struct file * f)202380fafb7Schristos p_mqueue(struct file *f)
203380fafb7Schristos {
204380fafb7Schristos 	struct mqueue mq;
205380fafb7Schristos 
206380fafb7Schristos 	if (!KVM_READ(f->f_data, &mq, sizeof(mq))) {
207380fafb7Schristos 		dprintf("can't read mqueue at %p for pid %d", f->f_data, Pid);
208380fafb7Schristos 		return 0;
209380fafb7Schristos 	}
210ebe962e4Schristos 	(void)printf("* mqueue \"%s\"", mq.mq_name);
211ebe962e4Schristos 	oprint(f, "\n");
212380fafb7Schristos 	return 0;
213380fafb7Schristos }
2148dd0b445Schristos 
2158dd0b445Schristos static int
p_kqueue(struct file * f)2168dd0b445Schristos p_kqueue(struct file *f)
2178dd0b445Schristos {
2188dd0b445Schristos 	struct kqueue kq;
2198dd0b445Schristos 
2208dd0b445Schristos 	if (!KVM_READ(f->f_data, &kq, sizeof(kq))) {
2218dd0b445Schristos 		dprintf("can't read kqueue at %p for pid %d", f->f_data, Pid);
2228dd0b445Schristos 		return 0;
2238dd0b445Schristos 	}
224ebe962e4Schristos 	(void)printf("* kqueue pending %d", kq.kq_count);
225ebe962e4Schristos 	oprint(f, "\n");
2268dd0b445Schristos 	return 0;
2278dd0b445Schristos }
228380fafb7Schristos 
229baa8677bSisaki static int
p_audio(struct file * f)230baa8677bSisaki p_audio(struct file *f)
231baa8677bSisaki {
232baa8677bSisaki 	struct audio_file af;
233baa8677bSisaki 	const char *devname;
234baa8677bSisaki 	const char *modename;
235baa8677bSisaki 
236baa8677bSisaki 	if (!KVM_READ(f->f_data, &af, sizeof(af))) {
237baa8677bSisaki 		dprintf("can't read audio_file at %p for pid %d",
238baa8677bSisaki 		    f->f_data, Pid);
239baa8677bSisaki 		return 0;
240baa8677bSisaki 	}
241baa8677bSisaki 
242baa8677bSisaki 	if (ISDEVAUDIO(af.dev)) {
243baa8677bSisaki 		devname = "audio";
244baa8677bSisaki 	} else if (ISDEVSOUND(af.dev)) {
245baa8677bSisaki 		devname = "sound";
246baa8677bSisaki 	} else if (ISDEVAUDIOCTL(af.dev)) {
247baa8677bSisaki 		devname = "audioctl";
248baa8677bSisaki 	} else if (ISDEVMIXER(af.dev)) {
249baa8677bSisaki 		devname = "mixer";
250baa8677bSisaki 	} else {
251baa8677bSisaki 		devname = "???";
252baa8677bSisaki 	}
253baa8677bSisaki 
254baa8677bSisaki 	if (af.ptrack && af.rtrack) {
255baa8677bSisaki 		modename = "playback, record";
256baa8677bSisaki 	} else if (af.ptrack) {
257baa8677bSisaki 		modename = "playback";
258baa8677bSisaki 	} else if (af.rtrack) {
259baa8677bSisaki 		modename = "record";
260baa8677bSisaki 	} else {
261baa8677bSisaki 		modename = "-";
262baa8677bSisaki 	}
263baa8677bSisaki 
264baa8677bSisaki 	(void)printf("* audio@%s%d %s", devname, AUDIOUNIT(af.dev), modename);
265baa8677bSisaki 	oprint(f, "\n");
266baa8677bSisaki 	return 0;
267baa8677bSisaki }
268baa8677bSisaki 
2697eace3daSchristos static int
p_memfd_seal(int seen,int all,int target,const char * name)2707eace3daSchristos p_memfd_seal(int seen, int all, int target, const char *name)
2717eace3daSchristos {
2727eace3daSchristos 	if (all & target)
2737eace3daSchristos 		(void)printf("%s%s", (seen ? "|" : ""), name);
2747eace3daSchristos 
2757eace3daSchristos 	return seen || (all & target);
2767eace3daSchristos }
2777eace3daSchristos 
2787eace3daSchristos static int
p_memfd(struct file * f)2797eace3daSchristos p_memfd(struct file *f)
2807eace3daSchristos {
2817eace3daSchristos 	int seal_yet = 0;
2827eace3daSchristos 	struct memfd mfd;
2837eace3daSchristos 
2847eace3daSchristos 	if (!KVM_READ(f->f_data, &mfd, sizeof(mfd))) {
2857eace3daSchristos 		dprintf("can't read memfd at %p for pid %d", f->f_data, Pid);
2867eace3daSchristos 		return 0;
2877eace3daSchristos 	}
2887eace3daSchristos 	(void)printf("* %s, seals=", mfd.mfd_name);
2897eace3daSchristos 	if (mfd.mfd_seals == 0)
2907eace3daSchristos 		(void)printf("0");
2917eace3daSchristos 	else {
2927eace3daSchristos 		seal_yet = p_memfd_seal(seal_yet, mfd.mfd_seals, F_SEAL_SEAL, "F_SEAL_SEAL");
2937eace3daSchristos 		seal_yet = p_memfd_seal(seal_yet, mfd.mfd_seals, F_SEAL_SHRINK, "F_SEAL_SHRINK");
2947eace3daSchristos 		seal_yet = p_memfd_seal(seal_yet, mfd.mfd_seals, F_SEAL_GROW, "F_SEAL_GROW");
2957eace3daSchristos 		seal_yet = p_memfd_seal(seal_yet, mfd.mfd_seals, F_SEAL_WRITE, "F_SEAL_WRITE");
2967eace3daSchristos 		seal_yet = p_memfd_seal(seal_yet, mfd.mfd_seals, F_SEAL_FUTURE_WRITE, "F_SEAL_FUTURE_WRITE");
2977eace3daSchristos 	}
2987eace3daSchristos 
2997eace3daSchristos 	oprint(f, "\n");
3007eace3daSchristos 	return 0;
3017eace3daSchristos }
3027eace3daSchristos 
303380fafb7Schristos int
pmisc(struct file * f,const char * name)304380fafb7Schristos pmisc(struct file *f, const char *name)
305380fafb7Schristos {
306380fafb7Schristos 	size_t i;
307380fafb7Schristos 	if (nl[0].n_value == 0) {
308380fafb7Schristos 		int n;
309380fafb7Schristos 		if ((n = KVM_NLIST(nl)) == -1)
310380fafb7Schristos 			errx(1, "Cannot list kernel symbols (%s)",
311380fafb7Schristos 			    KVM_GETERR());
3120548a80aSchristos 		else if (n != 0 && vflg) {
3130548a80aSchristos 			char buf[1024];
3140548a80aSchristos 			buf[0] = '\0';
3150548a80aSchristos 			for (struct nlist *l = nl; l->n_name != NULL; l++) {
3160548a80aSchristos 				if (l->n_value != 0)
3170548a80aSchristos 					continue;
3180548a80aSchristos 				strlcat(buf, ", ", sizeof(buf));
3190548a80aSchristos 				strlcat(buf, l->n_name, sizeof(buf));
3200548a80aSchristos 			}
3210548a80aSchristos 			warnx("Could not find %d symbols: %s", n, buf + 2);
3220548a80aSchristos 		}
323380fafb7Schristos 	}
324380fafb7Schristos 	for (i = 0; i < NL_MAX; i++)
325dadffc77Slukem 		if ((uintptr_t)f->f_ops == nl[i].n_value)
326380fafb7Schristos 			break;
327380fafb7Schristos 	switch (i) {
328380fafb7Schristos 	case NL_BPF:
329380fafb7Schristos 		return p_bpf(f);
330380fafb7Schristos 	case NL_MQUEUE:
331380fafb7Schristos 		return p_mqueue(f);
3328dd0b445Schristos 	case NL_KQUEUE:
3338dd0b445Schristos 		return p_kqueue(f);
3342732a80bSchristos 	case NL_RND:
335485ee481Schristos 		printf("* random %p", f->f_data);
336485ee481Schristos 		break;
3370548a80aSchristos 	case NL_SEM:
3380548a80aSchristos 		return p_sem(f);
339380fafb7Schristos 	case NL_TAP:
340ebe962e4Schristos 		printf("* tap %lu", (unsigned long)(intptr_t)f->f_data);
341ebe962e4Schristos 		break;
342380fafb7Schristos 	case NL_CRYPTO:
343ebe962e4Schristos 		printf("* crypto %p", f->f_data);
344ebe962e4Schristos 		break;
345911089b5Snat 	case NL_AUDIO:
346baa8677bSisaki 		return p_audio(f);
347911089b5Snat 	case NL_PAD:
348ebe962e4Schristos 		printf("* pad %p", f->f_data);
349ebe962e4Schristos 		break;
3507eace3daSchristos 	case NL_MEMFD:
3517eace3daSchristos 		return p_memfd(f);
35248bd4d9cSchristos 	case NL_MAX:
353ebe962e4Schristos 		printf("* %s ops=%p %p", name, f->f_ops, f->f_data);
354ebe962e4Schristos 		break;
35548bd4d9cSchristos 	default:
356ebe962e4Schristos 		printf("* %s %p", nl[i].n_name, f->f_data);
357ebe962e4Schristos 		break;
358380fafb7Schristos 	}
359ebe962e4Schristos 	oprint(f, "\n");
360ebe962e4Schristos 	return 0;
361380fafb7Schristos }
362