xref: /netbsd-src/sys/miscfs/procfs/procfs_linux.c (revision 78b530bb67e2d313c060ab72129301c684235015)
1*78b530bbSpgoyette /*      $NetBSD: procfs_linux.c,v 1.90 2024/09/14 01:37:42 pgoyette Exp $      */
24e000b75Sfvdl 
34e000b75Sfvdl /*
44e000b75Sfvdl  * Copyright (c) 2001 Wasabi Systems, Inc.
54e000b75Sfvdl  * All rights reserved.
64e000b75Sfvdl  *
74e000b75Sfvdl  * Written by Frank van der Linden for Wasabi Systems, Inc.
84e000b75Sfvdl  *
94e000b75Sfvdl  * Redistribution and use in source and binary forms, with or without
104e000b75Sfvdl  * modification, are permitted provided that the following conditions
114e000b75Sfvdl  * are met:
124e000b75Sfvdl  * 1. Redistributions of source code must retain the above copyright
134e000b75Sfvdl  *    notice, this list of conditions and the following disclaimer.
144e000b75Sfvdl  * 2. Redistributions in binary form must reproduce the above copyright
154e000b75Sfvdl  *    notice, this list of conditions and the following disclaimer in the
164e000b75Sfvdl  *    documentation and/or other materials provided with the distribution.
174e000b75Sfvdl  * 3. All advertising materials mentioning features or use of this software
184e000b75Sfvdl  *    must display the following acknowledgement:
194e000b75Sfvdl  *      This product includes software developed for the NetBSD Project by
204e000b75Sfvdl  *      Wasabi Systems, Inc.
214e000b75Sfvdl  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
224e000b75Sfvdl  *    or promote products derived from this software without specific prior
234e000b75Sfvdl  *    written permission.
244e000b75Sfvdl  *
254e000b75Sfvdl  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
264e000b75Sfvdl  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
274e000b75Sfvdl  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
284e000b75Sfvdl  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
294e000b75Sfvdl  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
304e000b75Sfvdl  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
314e000b75Sfvdl  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
324e000b75Sfvdl  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
334e000b75Sfvdl  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
344e000b75Sfvdl  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
354e000b75Sfvdl  * POSSIBILITY OF SUCH DAMAGE.
364e000b75Sfvdl  */
374e000b75Sfvdl 
38e4b00f43Slukem #include <sys/cdefs.h>
39*78b530bbSpgoyette __KERNEL_RCSID(0, "$NetBSD: procfs_linux.c,v 1.90 2024/09/14 01:37:42 pgoyette Exp $");
4087f98fe2Schristos 
4187f98fe2Schristos #if defined(_KERNEL_OPT)
4287f98fe2Schristos #include "opt_sysv.h"
43*78b530bbSpgoyette #include "opt_mqueue.h"
4487f98fe2Schristos #endif
45e4b00f43Slukem 
464e000b75Sfvdl #include <sys/param.h>
474e000b75Sfvdl #include <sys/systm.h>
480a1cb031Smartin #include <sys/atomic.h>
494e000b75Sfvdl #include <sys/time.h>
505918ad37Smatt #include <sys/cpu.h>
514e000b75Sfvdl #include <sys/kernel.h>
524e000b75Sfvdl #include <sys/proc.h>
534e000b75Sfvdl #include <sys/vnode.h>
549897a542Schristos #include <sys/exec.h>
55210944c7Schristos #include <sys/resource.h>
56210944c7Schristos #include <sys/resourcevar.h>
57210944c7Schristos #include <sys/signal.h>
58210944c7Schristos #include <sys/signalvar.h>
59210944c7Schristos #include <sys/tty.h>
60845beaccSjdolecek #include <sys/malloc.h>
61845beaccSjdolecek #include <sys/mount.h>
62a540ef29Smanu #include <sys/conf.h>
63e656d3b0Sjmcneill #include <sys/sysctl.h>
64cab865c6Schristos #include <sys/kauth.h>
65dce4e18dSchristos #include <sys/filedesc.h>
6687f98fe2Schristos #ifdef SYSVMSG
6787f98fe2Schristos #include <sys/msg.h>
6887f98fe2Schristos #endif
6987f98fe2Schristos #ifdef SYSVSEM
7087f98fe2Schristos #include <sys/sem.h>
7187f98fe2Schristos #endif
7287f98fe2Schristos #ifdef SYSVSHM
7387f98fe2Schristos #include <sys/shm.h>
7487f98fe2Schristos #endif
75*78b530bbSpgoyette #ifdef MQUEUE
760124a941Schristos #include <sys/mqueue.h>
77*78b530bbSpgoyette #endif
784e000b75Sfvdl 
794e000b75Sfvdl #include <miscfs/procfs/procfs.h>
80736a4d9bSad 
819897a542Schristos #include <compat/linux/common/linux_exec.h>
82e656d3b0Sjmcneill #include <compat/linux32/common/linux32_sysctl.h>
834e000b75Sfvdl 
84210944c7Schristos #include <uvm/uvm.h>
859fc45356Sriastradh #include <uvm/uvm_extern.h>
864e000b75Sfvdl 
87a540ef29Smanu extern struct devsw_conv *devsw_conv;
88a540ef29Smanu extern int max_devsw_convs;
89*78b530bbSpgoyette #ifdef MQUEUE
900124a941Schristos extern u_int mq_open_max;
910124a941Schristos extern u_int mq_max_msgsize;
920124a941Schristos extern u_int mq_def_maxmsg;
930124a941Schristos extern u_int mq_max_maxmsg;
94*78b530bbSpgoyette #endif
950124a941Schristos 
96a540ef29Smanu 
974e000b75Sfvdl #define PGTOB(p)	((unsigned long)(p) << PAGE_SHIFT)
984e000b75Sfvdl #define PGTOKB(p)	((unsigned long)(p) << (PAGE_SHIFT - 10))
994e000b75Sfvdl 
10026bb1685Schristos #define LBFSZ (8 * 1024)
10126bb1685Schristos 
1024dbe5ed7Sagc static void
10345fbe545Schs get_proc_size_info(struct proc *p, struct vm_map *map, unsigned long *stext,
10445fbe545Schs     unsigned long *etext, unsigned long *sstack)
1054dbe5ed7Sagc {
1064dbe5ed7Sagc 	struct vm_map_entry *entry;
1074dbe5ed7Sagc 
1084dbe5ed7Sagc 	*stext = 0;
1094dbe5ed7Sagc 	*etext = 0;
1104dbe5ed7Sagc 	*sstack = 0;
1114dbe5ed7Sagc 
1124dbe5ed7Sagc 	vm_map_lock_read(map);
1134dbe5ed7Sagc 
1144dbe5ed7Sagc 	for (entry = map->header.next; entry != &map->header;
1154dbe5ed7Sagc 	    entry = entry->next) {
1164dbe5ed7Sagc 		if (UVM_ET_ISSUBMAP(entry))
1174dbe5ed7Sagc 			continue;
1184dbe5ed7Sagc 		/* assume text is the first entry */
1194dbe5ed7Sagc 		if (*stext == *etext) {
1204dbe5ed7Sagc 			*stext = entry->start;
1214dbe5ed7Sagc 			*etext = entry->end;
1224dbe5ed7Sagc 			break;
1234dbe5ed7Sagc 		}
1244dbe5ed7Sagc 	}
125c252921eSjmcneill #if defined(LINUX_USRSTACK32) && defined(USRSTACK32)
126dfdca25eSchristos 	if (strcmp(p->p_emul->e_name, "linux32") == 0 &&
127dfdca25eSchristos 	    LINUX_USRSTACK32 < USRSTACK32)
128dfdca25eSchristos 		*sstack = (unsigned long)LINUX_USRSTACK32;
129dfdca25eSchristos 	else
130dfdca25eSchristos #endif
1314dbe5ed7Sagc #ifdef LINUX_USRSTACK
1324dbe5ed7Sagc 	if (strcmp(p->p_emul->e_name, "linux") == 0 &&
1334dbe5ed7Sagc 	    LINUX_USRSTACK < USRSTACK)
1344dbe5ed7Sagc 		*sstack = (unsigned long)LINUX_USRSTACK;
1354dbe5ed7Sagc 	else
1364dbe5ed7Sagc #endif
137dfdca25eSchristos #ifdef	USRSTACK32
138dfdca25eSchristos 	if (strstr(p->p_emul->e_name, "32") != NULL)
139dfdca25eSchristos 		*sstack = (unsigned long)USRSTACK32;
140dfdca25eSchristos 	else
141dfdca25eSchristos #endif
1424dbe5ed7Sagc 		*sstack = (unsigned long)USRSTACK;
1434dbe5ed7Sagc 
1444dbe5ed7Sagc 	/*
1454dbe5ed7Sagc 	 * jdk 1.6 compares low <= addr && addr < high
1464dbe5ed7Sagc 	 * if we put addr == high, then the test fails
1474dbe5ed7Sagc 	 * so eat one page.
1484dbe5ed7Sagc 	 */
1494dbe5ed7Sagc 	*sstack -= PAGE_SIZE;
1504dbe5ed7Sagc 
1514dbe5ed7Sagc 	vm_map_unlock_read(map);
1524dbe5ed7Sagc }
1534dbe5ed7Sagc 
1544e000b75Sfvdl /*
1554e000b75Sfvdl  * Linux compatible /proc/meminfo. Only active when the -o linux
1564e000b75Sfvdl  * mountflag is used.
1574e000b75Sfvdl  */
1584e000b75Sfvdl int
159168cd830Schristos procfs_domeminfo(struct lwp *curl, struct proc *p,
160168cd830Schristos     struct pfsnode *pfs, struct uio *uio)
1614e000b75Sfvdl {
16226bb1685Schristos 	char *bf;
1638bcb745dSitojun 	int len;
16426bb1685Schristos 	int error = 0;
165a98966d3Sad 	long filepg, anonpg, execpg, freepg;
1664e000b75Sfvdl 
16726bb1685Schristos 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
16826bb1685Schristos 
169ba90a6baSad 	/* uvm_availmem() will sync the counters if needed. */
1704b8a875aSad 	freepg = (long)uvm_availmem(true);
171ba90a6baSad 	filepg = (long)(cpu_count_get(CPU_COUNT_FILECLEAN) +
172ba90a6baSad 	    cpu_count_get(CPU_COUNT_FILEDIRTY) +
173ba90a6baSad 	    cpu_count_get(CPU_COUNT_FILEUNKNOWN) -
174ba90a6baSad 	    cpu_count_get(CPU_COUNT_EXECPAGES));
175ba90a6baSad 	anonpg = (long)(cpu_count_get(CPU_COUNT_ANONCLEAN) +
176ba90a6baSad 	    cpu_count_get(CPU_COUNT_ANONDIRTY) +
177ba90a6baSad 	    cpu_count_get(CPU_COUNT_ANONUNKNOWN));
178a98966d3Sad 	execpg = (long)cpu_count_get(CPU_COUNT_EXECPAGES);
179a98966d3Sad 
18026bb1685Schristos 	len = snprintf(bf, LBFSZ,
1814e000b75Sfvdl 		"        total:    used:    free:  shared: buffers: cached:\n"
1824e000b75Sfvdl 		"Mem:  %8lu %8lu %8lu %8lu %8lu %8lu\n"
1834e000b75Sfvdl 		"Swap: %8lu %8lu %8lu\n"
1844e000b75Sfvdl 		"MemTotal:  %8lu kB\n"
1854e000b75Sfvdl 		"MemFree:   %8lu kB\n"
1864e000b75Sfvdl 		"MemShared: %8lu kB\n"
1874e000b75Sfvdl 		"Buffers:   %8lu kB\n"
1884e000b75Sfvdl 		"Cached:    %8lu kB\n"
1894e000b75Sfvdl 		"SwapTotal: %8lu kB\n"
1904e000b75Sfvdl 		"SwapFree:  %8lu kB\n",
1914e000b75Sfvdl 		PGTOB(uvmexp.npages),
192a98966d3Sad 		PGTOB(uvmexp.npages - freepg),
193a98966d3Sad 		PGTOB(freepg),
1944e000b75Sfvdl 		0L,
195a98966d3Sad 		PGTOB(filepg),
196a98966d3Sad 		PGTOB(anonpg + filepg + execpg),
1974e000b75Sfvdl 		PGTOB(uvmexp.swpages),
1984e000b75Sfvdl 		PGTOB(uvmexp.swpginuse),
1994e000b75Sfvdl 		PGTOB(uvmexp.swpages - uvmexp.swpginuse),
2004e000b75Sfvdl 		PGTOKB(uvmexp.npages),
201a98966d3Sad 		PGTOKB(freepg),
2024e000b75Sfvdl 		0L,
203a98966d3Sad 		PGTOKB(freepg),
204a98966d3Sad 		PGTOKB(anonpg + filepg + execpg),
2054e000b75Sfvdl 		PGTOKB(uvmexp.swpages),
2064e000b75Sfvdl 		PGTOKB(uvmexp.swpages - uvmexp.swpginuse));
2074e000b75Sfvdl 
2084e000b75Sfvdl 	if (len == 0)
20926bb1685Schristos 		goto out;
2104e000b75Sfvdl 
21126bb1685Schristos 	error = uiomove_frombuf(bf, len, uio);
21226bb1685Schristos out:
21326bb1685Schristos 	free(bf, M_TEMP);
21426bb1685Schristos 	return error;
2154e000b75Sfvdl }
2164e000b75Sfvdl 
217210944c7Schristos /*
218a540ef29Smanu  * Linux compatible /proc/devices. Only active when the -o linux
219a540ef29Smanu  * mountflag is used.
220a540ef29Smanu  */
221a540ef29Smanu int
222168cd830Schristos procfs_dodevices(struct lwp *curl, struct proc *p,
223168cd830Schristos     struct pfsnode *pfs, struct uio *uio)
224a540ef29Smanu {
22526bb1685Schristos 	char *bf;
226a540ef29Smanu 	int offset = 0;
22726bb1685Schristos 	int i, error = ENAMETOOLONG;
228a540ef29Smanu 
229a6877176Selad 	/* XXX elad - may need filtering. */
230a6877176Selad 
23126bb1685Schristos 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
23226bb1685Schristos 
23326bb1685Schristos 	offset += snprintf(&bf[offset], LBFSZ - offset, "Character devices:\n");
23426bb1685Schristos 	if (offset >= LBFSZ)
23526bb1685Schristos 		goto out;
236a540ef29Smanu 
2378583cae2Spooka 	mutex_enter(&device_lock);
238a540ef29Smanu 	for (i = 0; i < max_devsw_convs; i++) {
239a540ef29Smanu 		if ((devsw_conv[i].d_name == NULL) ||
240a540ef29Smanu 		    (devsw_conv[i].d_cmajor == -1))
241a540ef29Smanu 			continue;
242a540ef29Smanu 
24326bb1685Schristos 		offset += snprintf(&bf[offset], LBFSZ - offset,
244a540ef29Smanu 		    "%3d %s\n", devsw_conv[i].d_cmajor, devsw_conv[i].d_name);
245d18c6ca4Sad 		if (offset >= LBFSZ) {
2468583cae2Spooka 			mutex_exit(&device_lock);
24726bb1685Schristos 			goto out;
248a540ef29Smanu 		}
249d18c6ca4Sad 	}
250a540ef29Smanu 
25126bb1685Schristos 	offset += snprintf(&bf[offset], LBFSZ - offset, "\nBlock devices:\n");
252d18c6ca4Sad 	if (offset >= LBFSZ) {
2538583cae2Spooka 		mutex_exit(&device_lock);
25426bb1685Schristos 		goto out;
255d18c6ca4Sad 	}
256a540ef29Smanu 
257a540ef29Smanu 	for (i = 0; i < max_devsw_convs; i++) {
258a540ef29Smanu 		if ((devsw_conv[i].d_name == NULL) ||
259a540ef29Smanu 		    (devsw_conv[i].d_bmajor == -1))
260a540ef29Smanu 			continue;
261a540ef29Smanu 
26226bb1685Schristos 		offset += snprintf(&bf[offset], LBFSZ - offset,
263a540ef29Smanu 		    "%3d %s\n", devsw_conv[i].d_bmajor, devsw_conv[i].d_name);
264d18c6ca4Sad 		if (offset >= LBFSZ) {
2658583cae2Spooka 			mutex_exit(&device_lock);
26626bb1685Schristos 			goto out;
267a540ef29Smanu 		}
268d18c6ca4Sad 	}
2698583cae2Spooka 	mutex_exit(&device_lock);
270a540ef29Smanu 
27126bb1685Schristos 	error = uiomove_frombuf(bf, offset, uio);
27226bb1685Schristos out:
27326bb1685Schristos 	free(bf, M_TEMP);
27426bb1685Schristos 	return error;
275a540ef29Smanu }
276a540ef29Smanu 
277a540ef29Smanu /*
2784dbe5ed7Sagc  * Linux compatible /proc/stat. Only active when the -o linux
2794dbe5ed7Sagc  * mountflag is used.
2804dbe5ed7Sagc  */
2814dbe5ed7Sagc int
2824dbe5ed7Sagc procfs_docpustat(struct lwp *curl, struct proc *p,
2834dbe5ed7Sagc     struct pfsnode *pfs, struct uio *uio)
2844dbe5ed7Sagc {
2854dbe5ed7Sagc 	char		*bf;
2864dbe5ed7Sagc 	int	 	 error;
2874dbe5ed7Sagc 	int	 	 len;
28815a3a67eSagc #if defined(MULTIPROCESSOR)
28915a3a67eSagc         struct cpu_info *ci;
29015a3a67eSagc         CPU_INFO_ITERATOR cii;
29115a3a67eSagc #endif
29212003e87Sagc 	int	 	 i;
2934dbe5ed7Sagc 
2944dbe5ed7Sagc 	error = ENAMETOOLONG;
2954dbe5ed7Sagc 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
2964dbe5ed7Sagc 
2974dbe5ed7Sagc 	len = snprintf(bf, LBFSZ,
298905b715aSdogcow 		"cpu %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
2994dbe5ed7Sagc 		curcpu()->ci_schedstate.spc_cp_time[CP_USER],
3004dbe5ed7Sagc 		curcpu()->ci_schedstate.spc_cp_time[CP_NICE],
3014dbe5ed7Sagc 		curcpu()->ci_schedstate.spc_cp_time[CP_SYS] /*+ [CP_INTR]*/,
3024dbe5ed7Sagc 		curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]);
3034dbe5ed7Sagc 	if (len == 0)
3044dbe5ed7Sagc 		goto out;
3054dbe5ed7Sagc 
30615a3a67eSagc #if defined(MULTIPROCESSOR)
30712003e87Sagc #define ALLCPUS	CPU_INFO_FOREACH(cii, ci)
30812003e87Sagc #define CPUNAME	ci
30912003e87Sagc #else
31012003e87Sagc #define ALLCPUS	; i < 1 ;
31112003e87Sagc #define CPUNAME	curcpu()
31212003e87Sagc #endif
31312003e87Sagc 
3144dbe5ed7Sagc 	i = 0;
31512003e87Sagc 	for (ALLCPUS) {
3164dbe5ed7Sagc 		len += snprintf(&bf[len], LBFSZ - len,
317905b715aSdogcow 			"cpu%d %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
318905b715aSdogcow 			"\n", i,
31912003e87Sagc 			CPUNAME->ci_schedstate.spc_cp_time[CP_USER],
32012003e87Sagc 			CPUNAME->ci_schedstate.spc_cp_time[CP_NICE],
32112003e87Sagc 			CPUNAME->ci_schedstate.spc_cp_time[CP_SYS],
32212003e87Sagc 			CPUNAME->ci_schedstate.spc_cp_time[CP_IDLE]);
3234dbe5ed7Sagc 		if (len >= LBFSZ)
3244dbe5ed7Sagc 			goto out;
3254dbe5ed7Sagc 		i += 1;
3264dbe5ed7Sagc 	}
3274dbe5ed7Sagc 
328ba90a6baSad 	cpu_count_sync(true);
329a98966d3Sad 
330d6c967bbSthorpej 	struct timeval btv;
331d6c967bbSthorpej 	getmicroboottime(&btv);
332d6c967bbSthorpej 
3334dbe5ed7Sagc 	len += snprintf(&bf[len], LBFSZ - len,
3344dbe5ed7Sagc 			"disk 0 0 0 0\n"
3354dbe5ed7Sagc 			"page %u %u\n"
3364dbe5ed7Sagc 			"swap %u %u\n"
337a98966d3Sad 			"intr %"PRId64"\n"
338a98966d3Sad 			"ctxt %"PRId64"\n"
3396a66466fSmatt 			"btime %"PRId64"\n",
3404dbe5ed7Sagc 			uvmexp.pageins, uvmexp.pdpageouts,
3414dbe5ed7Sagc 			uvmexp.pgswapin, uvmexp.pgswapout,
342a98966d3Sad 			cpu_count_get(CPU_COUNT_NINTR),
343a98966d3Sad 			cpu_count_get(CPU_COUNT_NSWTCH),
344d6c967bbSthorpej 			btv.tv_sec);
3454dbe5ed7Sagc 	if (len >= LBFSZ)
3464dbe5ed7Sagc 		goto out;
3474dbe5ed7Sagc 
3484dbe5ed7Sagc 	error = uiomove_frombuf(bf, len, uio);
3494dbe5ed7Sagc out:
3504dbe5ed7Sagc 	free(bf, M_TEMP);
3514dbe5ed7Sagc 	return error;
3524dbe5ed7Sagc }
3534dbe5ed7Sagc 
3544dbe5ed7Sagc /*
3554dbe5ed7Sagc  * Linux compatible /proc/loadavg. Only active when the -o linux
3564dbe5ed7Sagc  * mountflag is used.
3574dbe5ed7Sagc  */
3584dbe5ed7Sagc int
3594dbe5ed7Sagc procfs_doloadavg(struct lwp *curl, struct proc *p,
3604dbe5ed7Sagc     struct pfsnode *pfs, struct uio *uio)
3614dbe5ed7Sagc {
3624dbe5ed7Sagc 	char	*bf;
3634dbe5ed7Sagc 	int 	 error;
3644dbe5ed7Sagc 	int 	 len;
3654dbe5ed7Sagc 
3664dbe5ed7Sagc 	error = ENAMETOOLONG;
3674dbe5ed7Sagc 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
3684dbe5ed7Sagc 
3694dbe5ed7Sagc 	averunnable.fscale = FSCALE;
3704dbe5ed7Sagc 	len = snprintf(bf, LBFSZ,
3714dbe5ed7Sagc 	        "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
3724dbe5ed7Sagc 		(int)(averunnable.ldavg[0] / averunnable.fscale),
3734dbe5ed7Sagc 		(int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
3744dbe5ed7Sagc 		(int)(averunnable.ldavg[1] / averunnable.fscale),
3754dbe5ed7Sagc 		(int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
3764dbe5ed7Sagc 		(int)(averunnable.ldavg[2] / averunnable.fscale),
3774dbe5ed7Sagc 		(int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
3784dbe5ed7Sagc 		1,		/* number of ONPROC processes */
379a29147faSthorpej 		atomic_load_relaxed(&nprocs),
3804dbe5ed7Sagc 		30000);		/* last pid */
3814dbe5ed7Sagc 	if (len == 0)
3824dbe5ed7Sagc 		goto out;
3834dbe5ed7Sagc 
3844dbe5ed7Sagc 	error = uiomove_frombuf(bf, len, uio);
3854dbe5ed7Sagc out:
3864dbe5ed7Sagc 	free(bf, M_TEMP);
3874dbe5ed7Sagc 	return error;
3884dbe5ed7Sagc }
3894dbe5ed7Sagc 
3904dbe5ed7Sagc /*
3914dbe5ed7Sagc  * Linux compatible /proc/<pid>/statm. Only active when the -o linux
3924dbe5ed7Sagc  * mountflag is used.
3934dbe5ed7Sagc  */
3944dbe5ed7Sagc int
3954dbe5ed7Sagc procfs_do_pid_statm(struct lwp *curl, struct lwp *l,
3964dbe5ed7Sagc     struct pfsnode *pfs, struct uio *uio)
3974dbe5ed7Sagc {
39815a3a67eSagc 	struct vmspace	*vm;
3994dbe5ed7Sagc 	struct proc	*p = l->l_proc;
4004dbe5ed7Sagc 	char		*bf;
4014dbe5ed7Sagc 	int	 	 error;
4024dbe5ed7Sagc 	int	 	 len;
4033bb28e76Smlelstv 	struct kinfo_proc2 ki;
4044dbe5ed7Sagc 
4054dbe5ed7Sagc 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
4064dbe5ed7Sagc 
40715a3a67eSagc 	/* XXX - we use values from vmspace, since dsl says that ru figures
40815a3a67eSagc 	   are always 0 except for zombies. See kvm_proc.c::kvm_getproc2() */
40915a3a67eSagc 	if ((error = proc_vmspace_getref(p, &vm)) != 0) {
410f1a59086Sagc 		goto out;
41115a3a67eSagc 	}
4124dbe5ed7Sagc 
4130eaaa024Sad 	mutex_enter(&proc_lock);
4143bb28e76Smlelstv 	mutex_enter(p->p_lock);
4153bb28e76Smlelstv 
4163bb28e76Smlelstv 	/* retrieve RSS size */
4173fb8db10Smaxv 	memset(&ki, 0, sizeof(ki));
418dea54605Schristos 	fill_kproc2(p, &ki, false, false);
4193bb28e76Smlelstv 
4203bb28e76Smlelstv 	mutex_exit(p->p_lock);
4210eaaa024Sad 	mutex_exit(&proc_lock);
42215a3a67eSagc 
423a501df5aSdholland 	uvmspace_free(vm);
424a501df5aSdholland 
4253bb28e76Smlelstv 	len = snprintf(bf, LBFSZ,
4263bb28e76Smlelstv 	        "%lu %lu %lu %lu %lu %lu %lu\n",
4273bb28e76Smlelstv 		(unsigned long)(ki.p_vm_msize),	/* size */
4283bb28e76Smlelstv 		(unsigned long)(ki.p_vm_rssize),/* resident */
4293bb28e76Smlelstv 		(unsigned long)(ki.p_uru_ixrss),/* shared */
4303bb28e76Smlelstv 		(unsigned long)(ki.p_vm_tsize),	/* text */
4313bb28e76Smlelstv 		(unsigned long) 0,		/* library (unused) */
4323bb28e76Smlelstv 		(unsigned long)(ki.p_vm_dsize + ki.p_vm_ssize),	/* data+stack */
4333bb28e76Smlelstv 		(unsigned long) 0);		/* dirty */
4343bb28e76Smlelstv 
4354dbe5ed7Sagc 	if (len == 0)
4364dbe5ed7Sagc 		goto out;
4374dbe5ed7Sagc 
4384dbe5ed7Sagc 	error = uiomove_frombuf(bf, len, uio);
4394dbe5ed7Sagc out:
4404dbe5ed7Sagc 	free(bf, M_TEMP);
4414dbe5ed7Sagc 	return error;
4424dbe5ed7Sagc }
4434dbe5ed7Sagc 
444684c8bf8Snjoly #define UTIME2TICKS(s,u)	(((uint64_t)(s) * 1000000 + (u)) / 10000)
44515a3a67eSagc 
4464dbe5ed7Sagc /*
447210944c7Schristos  * Linux compatible /proc/<pid>/stat. Only active when the -o linux
448210944c7Schristos  * mountflag is used.
449210944c7Schristos  */
450210944c7Schristos int
451168cd830Schristos procfs_do_pid_stat(struct lwp *curl, struct lwp *l,
452168cd830Schristos     struct pfsnode *pfs, struct uio *uio)
453210944c7Schristos {
45426bb1685Schristos 	char *bf;
455f36aa0cdSchristos 	struct proc *p = l->l_proc;
4568bcb745dSitojun 	int len;
457210944c7Schristos 	struct rusage *cru = &p->p_stats->p_cru;
458210944c7Schristos 	unsigned long stext = 0, etext = 0, sstack = 0;
459b07ec3fcSad 	struct timeval rt;
460f1a59086Sagc 	struct vmspace	*vm;
461684c8bf8Snjoly 	struct kinfo_proc2 ki;
4626647020bSmaxv 	int error;
46326bb1685Schristos 
46426bb1685Schristos 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
465210944c7Schristos 
466f1a59086Sagc 	if ((error = proc_vmspace_getref(p, &vm)) != 0) {
467f1a59086Sagc 		goto out;
468f1a59086Sagc 	}
469f1a59086Sagc 
47045fbe545Schs 	get_proc_size_info(p, &vm->vm_map, &stext, &etext, &sstack);
471b07ec3fcSad 
4720eaaa024Sad 	mutex_enter(&proc_lock);
473284c2b9aSad 	mutex_enter(p->p_lock);
474b07ec3fcSad 
4753fb8db10Smaxv 	memset(&ki, 0, sizeof(ki));
476dea54605Schristos 	fill_kproc2(p, &ki, false, false);
477b07ec3fcSad 	calcru(p, NULL, NULL, NULL, &rt);
478210944c7Schristos 
47926bb1685Schristos 	len = snprintf(bf, LBFSZ,
480684c8bf8Snjoly 	    "%d (%s) %c %d %d %d %u %d "
481210944c7Schristos 	    "%u "
482684c8bf8Snjoly 	    "%"PRIu64" %lu %"PRIu64" %lu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" "
483684c8bf8Snjoly 	    "%d %d %"PRIu64" "
484684c8bf8Snjoly 	    "%lld %"PRIu64" %"PRId64" %lu %"PRIu64" "
485210944c7Schristos 	    "%lu %lu %lu "
486210944c7Schristos 	    "%u %u "
487210944c7Schristos 	    "%u %u %u %u "
488684c8bf8Snjoly 	    "%"PRIu64" %"PRIu64" %"PRIu64" %d %"PRIu64"\n",
489210944c7Schristos 
490684c8bf8Snjoly 	    ki.p_pid,						/* 1 pid */
491684c8bf8Snjoly 	    ki.p_comm,						/* 2 tcomm */
492684c8bf8Snjoly 	    "0RRSTZXR8"[(ki.p_stat > 8) ? 0 : (int)ki.p_stat],	/* 3 state */
493684c8bf8Snjoly 	    ki.p_ppid,						/* 4 ppid */
494684c8bf8Snjoly 	    ki.p__pgid,						/* 5 pgrp */
495684c8bf8Snjoly 	    ki.p_sid,						/* 6 sid */
496684c8bf8Snjoly 	    (ki.p_tdev != (uint32_t)NODEV) ? ki.p_tdev : 0,	/* 7 tty_nr */
497684c8bf8Snjoly 	    ki.p_tpgid,						/* 8 tty_pgrp */
498210944c7Schristos 
499684c8bf8Snjoly 	    ki.p_flag,						/* 9 flags */
500210944c7Schristos 
501684c8bf8Snjoly 	    ki.p_uru_minflt,					/* 10 min_flt */
502210944c7Schristos 	    cru->ru_minflt,
503684c8bf8Snjoly 	    ki.p_uru_majflt,					/* 12 maj_flt */
504210944c7Schristos 	    cru->ru_majflt,
505684c8bf8Snjoly 	    UTIME2TICKS(ki.p_uutime_sec, ki.p_uutime_usec),	/* 14 utime */
506684c8bf8Snjoly 	    UTIME2TICKS(ki.p_ustime_sec, ki.p_ustime_usec),	/* 15 stime */
507684c8bf8Snjoly 	    UTIME2TICKS(cru->ru_utime.tv_sec, cru->ru_utime.tv_usec), /* 16 cutime */
508684c8bf8Snjoly 	    UTIME2TICKS(cru->ru_stime.tv_sec, cru->ru_stime.tv_usec), /* 17 cstime */
509210944c7Schristos 
510684c8bf8Snjoly 	    ki.p_priority,				/* XXX: 18 priority */
511684c8bf8Snjoly 	    ki.p_nice - NZERO,				/* 19 nice */
512684c8bf8Snjoly 	    ki.p_nlwps,					/* 20 num_threads */
513210944c7Schristos 
514461a86f9Schristos 	    (long long)rt.tv_sec,
515684c8bf8Snjoly 	    UTIME2TICKS(ki.p_ustart_sec, ki.p_ustart_usec), /* 22 start_time */
516684c8bf8Snjoly 	    ki.p_vm_msize,				/* 23 vsize */
517684c8bf8Snjoly 	    PGTOKB(ki.p_vm_rssize),			/* 24 rss */
518684c8bf8Snjoly 	    p->p_rlimit[RLIMIT_RSS].rlim_cur,		/* 25 rsslim */
519210944c7Schristos 
520684c8bf8Snjoly 	    stext,					/* 26 start_code */
521684c8bf8Snjoly 	    etext,					/* 27 end_code */
522684c8bf8Snjoly 	    sstack,					/* 28 start_stack */
523210944c7Schristos 
524684c8bf8Snjoly 	    0,						/* XXX: 29 esp */
525684c8bf8Snjoly 	    0,						/* XXX: 30 eip */
526684c8bf8Snjoly 
527684c8bf8Snjoly 	    ki.p_siglist.__bits[0],			/* XXX: 31 pending */
528684c8bf8Snjoly 	    0,						/* XXX: 32 blocked */
529684c8bf8Snjoly 	    ki.p_sigignore.__bits[0],		/* 33 sigign */
530684c8bf8Snjoly 	    ki.p_sigcatch.__bits[0],		/* 34 sigcatch */
531684c8bf8Snjoly 
532684c8bf8Snjoly 	    ki.p_wchan,					/* 35 wchan */
533684c8bf8Snjoly 	    ki.p_uru_nvcsw,
534684c8bf8Snjoly 	    ki.p_uru_nivcsw,
535684c8bf8Snjoly 	    ki.p_exitsig,				/* 38 exit_signal */
536684c8bf8Snjoly 	    ki.p_cpuid);				/* 39 task_cpu */
537210944c7Schristos 
538284c2b9aSad 	mutex_exit(p->p_lock);
5390eaaa024Sad 	mutex_exit(&proc_lock);
540b07ec3fcSad 
541a501df5aSdholland 	uvmspace_free(vm);
542a501df5aSdholland 
543210944c7Schristos 	if (len == 0)
54426bb1685Schristos 		goto out;
545210944c7Schristos 
54626bb1685Schristos 	error = uiomove_frombuf(bf, len, uio);
54726bb1685Schristos out:
54826bb1685Schristos 	free(bf, M_TEMP);
54926bb1685Schristos 	return error;
550210944c7Schristos }
551210944c7Schristos 
5524e000b75Sfvdl int
553168cd830Schristos procfs_docpuinfo(struct lwp *curl, struct proc *p,
554168cd830Schristos     struct pfsnode *pfs, struct uio *uio)
5554e000b75Sfvdl {
55616c9d42fSchristos 	size_t len = LBFSZ;
55716c9d42fSchristos 	char *bf = NULL;
5581a63592aSchristos 	int error;
5591a63592aSchristos 
56016c9d42fSchristos 	do {
56116c9d42fSchristos 		if (bf)
56216c9d42fSchristos 			free(bf, M_TEMP);
56316c9d42fSchristos 		bf = malloc(len, M_TEMP, M_WAITOK);
56416c9d42fSchristos 	} while (procfs_getcpuinfstr(bf, &len) < 0);
5654e000b75Sfvdl 
5661a63592aSchristos 	if (len == 0) {
5671a63592aSchristos 		error = 0;
5681a63592aSchristos 		goto done;
5691a63592aSchristos 	}
5704e000b75Sfvdl 
571c107ef9eSchristos 	error = uiomove_frombuf(bf, len, uio);
5721a63592aSchristos done:
573c107ef9eSchristos 	free(bf, M_TEMP);
5741a63592aSchristos 	return error;
5754e000b75Sfvdl }
576a2d850baSjrf 
577a2d850baSjrf int
578168cd830Schristos procfs_douptime(struct lwp *curl, struct proc *p,
579168cd830Schristos     struct pfsnode *pfs, struct uio *uio)
580a2d850baSjrf {
58126bb1685Schristos 	char *bf;
5828bcb745dSitojun 	int len;
583a2d850baSjrf 	struct timeval runtime;
584a2d850baSjrf 	u_int64_t idle;
58526bb1685Schristos 	int error = 0;
58626bb1685Schristos 
58726bb1685Schristos 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
588a2d850baSjrf 
5892294b0bcSyamt 	microuptime(&runtime);
590a2d850baSjrf 	idle = curcpu()->ci_schedstate.spc_cp_time[CP_IDLE];
59126bb1685Schristos 	len = snprintf(bf, LBFSZ,
592461a86f9Schristos 	    "%lld.%02lu %" PRIu64 ".%02" PRIu64 "\n",
593461a86f9Schristos 	    (long long)runtime.tv_sec, (long)runtime.tv_usec / 10000,
594a2d850baSjrf 	    idle / hz, (((idle % hz) * 100) / hz) % 100);
595a2d850baSjrf 
596a2d850baSjrf 	if (len == 0)
59726bb1685Schristos 		goto out;
598a2d850baSjrf 
59926bb1685Schristos 	error = uiomove_frombuf(bf, len, uio);
60026bb1685Schristos out:
60126bb1685Schristos 	free(bf, M_TEMP);
60226bb1685Schristos 	return error;
603a2d850baSjrf }
604845beaccSjdolecek 
605dce4e18dSchristos static int
606dce4e18dSchristos procfs_format_sfs(char **mtab, size_t *mlen, char *buf, size_t blen,
607dce4e18dSchristos     const struct statvfs *sfs, struct lwp *curl, int suser)
608845beaccSjdolecek {
609845beaccSjdolecek 	const char *fsname;
610845beaccSjdolecek 
611845beaccSjdolecek 	/* Linux uses different names for some filesystems */
612dce4e18dSchristos 	fsname = sfs->f_fstypename;
613845beaccSjdolecek 	if (strcmp(fsname, "procfs") == 0)
614845beaccSjdolecek 		fsname = "proc";
615845beaccSjdolecek 	else if (strcmp(fsname, "ext2fs") == 0)
616845beaccSjdolecek 		fsname = "ext2";
617845beaccSjdolecek 
618dce4e18dSchristos 	blen = snprintf(buf, blen, "%s %s %s %s%s%s%s%s%s 0 0\n",
619dce4e18dSchristos 	    sfs->f_mntfromname, sfs->f_mntonname, fsname,
620dce4e18dSchristos 	    (sfs->f_flag & ST_RDONLY) ? "ro" : "rw",
621dce4e18dSchristos 	    (sfs->f_flag & ST_NOSUID) ? ",nosuid" : "",
622dce4e18dSchristos 	    (sfs->f_flag & ST_NOEXEC) ? ",noexec" : "",
623dce4e18dSchristos 	    (sfs->f_flag & ST_NODEV) ? ",nodev" : "",
624dce4e18dSchristos 	    (sfs->f_flag & ST_SYNCHRONOUS) ? ",sync" : "",
625dce4e18dSchristos 	    (sfs->f_flag & ST_NOATIME) ? ",noatime" : "");
626845beaccSjdolecek 
627dce4e18dSchristos 	*mtab = realloc(*mtab, *mlen + blen, M_TEMP, M_WAITOK);
628dce4e18dSchristos 	memcpy(*mtab + *mlen, buf, blen);
629dce4e18dSchristos 	*mlen += blen;
630dce4e18dSchristos 	return sfs->f_mntonname[0] == '/' && sfs->f_mntonname[1] == '\0';
631dce4e18dSchristos }
632dce4e18dSchristos 
633dce4e18dSchristos int
634dce4e18dSchristos procfs_domounts(struct lwp *curl, struct proc *p,
635dce4e18dSchristos     struct pfsnode *pfs, struct uio *uio)
636dce4e18dSchristos {
637dce4e18dSchristos 	char *bf, *mtab = NULL;
638dce4e18dSchristos 	size_t mtabsz = 0;
639769f0c92Shannken 	mount_iterator_t *iter;
640769f0c92Shannken 	struct mount *mp;
6418ddb33d2Schristos 	int error = 0, root = 0;
642dce4e18dSchristos 	struct cwdinfo *cwdi = curl->l_proc->p_cwdi;
64346b290a0Srin 	struct statvfs *sfs;
644dce4e18dSchristos 
645dce4e18dSchristos 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
646dce4e18dSchristos 
64746b290a0Srin 	sfs = malloc(sizeof(*sfs), M_TEMP, M_WAITOK);
648769f0c92Shannken 	mountlist_iterator_init(&iter);
649769f0c92Shannken 	while ((mp = mountlist_iterator_next(iter)) != NULL) {
65046b290a0Srin 		if ((error = dostatvfs(mp, sfs, curl, MNT_WAIT, 0)) == 0)
651dce4e18dSchristos 			root |= procfs_format_sfs(&mtab, &mtabsz, bf, LBFSZ,
65246b290a0Srin 			    sfs, curl, 0);
653845beaccSjdolecek 	}
654769f0c92Shannken 	mountlist_iterator_destroy(iter);
65546b290a0Srin 	free(sfs, M_TEMP);
656dce4e18dSchristos 
657dce4e18dSchristos 	/*
658dce4e18dSchristos 	 * If we are inside a chroot that is not itself a mount point,
659dce4e18dSchristos 	 * fake a root entry.
660dce4e18dSchristos 	 */
661dce4e18dSchristos 	if (!root && cwdi->cwdi_rdir)
662dce4e18dSchristos 		(void)procfs_format_sfs(&mtab, &mtabsz, bf, LBFSZ,
663dce4e18dSchristos 		    &cwdi->cwdi_rdir->v_mount->mnt_stat, curl, 1);
664dce4e18dSchristos 
66526bb1685Schristos 	free(bf, M_TEMP);
666845beaccSjdolecek 
667845beaccSjdolecek 	if (mtabsz > 0) {
668845beaccSjdolecek 		error = uiomove_frombuf(mtab, mtabsz, uio);
669845beaccSjdolecek 		free(mtab, M_TEMP);
670845beaccSjdolecek 	}
671845beaccSjdolecek 
672845beaccSjdolecek 	return error;
673845beaccSjdolecek }
674e656d3b0Sjmcneill 
675e656d3b0Sjmcneill /*
676e656d3b0Sjmcneill  * Linux compatible /proc/version. Only active when the -o linux
677e656d3b0Sjmcneill  * mountflag is used.
678e656d3b0Sjmcneill  */
679e656d3b0Sjmcneill int
680e656d3b0Sjmcneill procfs_doversion(struct lwp *curl, struct proc *p,
681e656d3b0Sjmcneill     struct pfsnode *pfs, struct uio *uio)
682e656d3b0Sjmcneill {
683e656d3b0Sjmcneill 	char *bf;
684e656d3b0Sjmcneill 	char lostype[20], losrelease[20], lversion[80];
685e656d3b0Sjmcneill 	const char *postype, *posrelease, *pversion;
686e656d3b0Sjmcneill 	const char *emulname = curlwp->l_proc->p_emul->e_name;
687e656d3b0Sjmcneill 	int len;
688e656d3b0Sjmcneill 	int error = 0;
689e656d3b0Sjmcneill 	int nm[4];
690e656d3b0Sjmcneill 	size_t buflen;
691e656d3b0Sjmcneill 
692e656d3b0Sjmcneill 	CTASSERT(EMUL_LINUX_KERN_OSTYPE == EMUL_LINUX32_KERN_OSTYPE);
693e656d3b0Sjmcneill 	CTASSERT(EMUL_LINUX_KERN_OSRELEASE == EMUL_LINUX32_KERN_OSRELEASE);
694e656d3b0Sjmcneill 	CTASSERT(EMUL_LINUX_KERN_VERSION == EMUL_LINUX32_KERN_VERSION);
695e656d3b0Sjmcneill 
696e656d3b0Sjmcneill 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
697e656d3b0Sjmcneill 
698e656d3b0Sjmcneill 	sysctl_lock(false);
699e656d3b0Sjmcneill 
700e656d3b0Sjmcneill 	if (strncmp(emulname, "linux", 5) == 0) {
701e656d3b0Sjmcneill 		/*
702e656d3b0Sjmcneill 		 * Lookup the emulation ostype, osrelease, and version.
703e656d3b0Sjmcneill 		 * Since compat_linux and compat_linux32 can be built as
704e656d3b0Sjmcneill 		 * modules, we use sysctl to obtain the values instead of
705e656d3b0Sjmcneill 		 * using the symbols directly.
706e656d3b0Sjmcneill 		 */
707e656d3b0Sjmcneill 
708e656d3b0Sjmcneill 		if (strcmp(emulname, "linux32") == 0) {
709e656d3b0Sjmcneill 			nm[0] = CTL_EMUL;
710e656d3b0Sjmcneill 			nm[1] = EMUL_LINUX32;
711e656d3b0Sjmcneill 			nm[2] = EMUL_LINUX32_KERN;
712e656d3b0Sjmcneill 		} else {
713e656d3b0Sjmcneill 			nm[0] = CTL_EMUL;
714e656d3b0Sjmcneill 			nm[1] = EMUL_LINUX;
715e656d3b0Sjmcneill 			nm[2] = EMUL_LINUX_KERN;
716e656d3b0Sjmcneill 		}
717e656d3b0Sjmcneill 
718e656d3b0Sjmcneill 		nm[3] = EMUL_LINUX_KERN_OSTYPE;
719e656d3b0Sjmcneill 		buflen = sizeof(lostype);
720e656d3b0Sjmcneill 		error = sysctl_dispatch(nm, __arraycount(nm),
721e656d3b0Sjmcneill 		    lostype, &buflen,
722e656d3b0Sjmcneill 		    NULL, 0, NULL, NULL, NULL);
723e656d3b0Sjmcneill 		if (error)
724e656d3b0Sjmcneill 			goto out;
725e656d3b0Sjmcneill 
726e656d3b0Sjmcneill 		nm[3] = EMUL_LINUX_KERN_OSRELEASE;
727e656d3b0Sjmcneill 		buflen = sizeof(losrelease);
728e656d3b0Sjmcneill 		error = sysctl_dispatch(nm, __arraycount(nm),
729e656d3b0Sjmcneill 		    losrelease, &buflen,
730e656d3b0Sjmcneill 		    NULL, 0, NULL, NULL, NULL);
731e656d3b0Sjmcneill 		if (error)
732e656d3b0Sjmcneill 			goto out;
733e656d3b0Sjmcneill 
734e656d3b0Sjmcneill 		nm[3] = EMUL_LINUX_KERN_VERSION;
735e656d3b0Sjmcneill 		buflen = sizeof(lversion);
736e656d3b0Sjmcneill 		error = sysctl_dispatch(nm, __arraycount(nm),
737e656d3b0Sjmcneill 		    lversion, &buflen,
738e656d3b0Sjmcneill 		    NULL, 0, NULL, NULL, NULL);
739e656d3b0Sjmcneill 		if (error)
740e656d3b0Sjmcneill 			goto out;
741e656d3b0Sjmcneill 
742e656d3b0Sjmcneill 		postype = lostype;
743e656d3b0Sjmcneill 		posrelease = losrelease;
744e656d3b0Sjmcneill 		pversion = lversion;
745e656d3b0Sjmcneill 	} else {
746e656d3b0Sjmcneill 		postype = ostype;
747e656d3b0Sjmcneill 		posrelease = osrelease;
748e656d3b0Sjmcneill 		strlcpy(lversion, version, sizeof(lversion));
749e656d3b0Sjmcneill 		if (strchr(lversion, '\n'))
750e656d3b0Sjmcneill 			*strchr(lversion, '\n') = '\0';
751e656d3b0Sjmcneill 		pversion = lversion;
752e656d3b0Sjmcneill 	}
753e656d3b0Sjmcneill 
754e656d3b0Sjmcneill 	len = snprintf(bf, LBFSZ,
755e656d3b0Sjmcneill 		"%s version %s (%s@localhost) (gcc version %s) %s\n",
756e656d3b0Sjmcneill 		postype, posrelease, emulname,
757e656d3b0Sjmcneill #ifdef __VERSION__
758e656d3b0Sjmcneill 		__VERSION__,
759e656d3b0Sjmcneill #else
760e656d3b0Sjmcneill 		"unknown",
761e656d3b0Sjmcneill #endif
762e656d3b0Sjmcneill 		pversion);
763e656d3b0Sjmcneill 
764e656d3b0Sjmcneill 	if (len == 0)
765e656d3b0Sjmcneill 		goto out;
766e656d3b0Sjmcneill 
767e656d3b0Sjmcneill 	error = uiomove_frombuf(bf, len, uio);
768e656d3b0Sjmcneill out:
769e656d3b0Sjmcneill 	free(bf, M_TEMP);
770e656d3b0Sjmcneill 	sysctl_unlock();
771e656d3b0Sjmcneill 	return error;
772e656d3b0Sjmcneill }
77387f98fe2Schristos 
77487f98fe2Schristos int
77587f98fe2Schristos procfs_dosysvipc_msg(struct lwp *curl, struct proc *p,
77687f98fe2Schristos     struct pfsnode *pfs, struct uio *uio)
77787f98fe2Schristos {
77887f98fe2Schristos 	char *bf;
77987f98fe2Schristos 	int offset = 0;
78087f98fe2Schristos 	int error = EFBIG;
78187f98fe2Schristos 
78287f98fe2Schristos 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
78387f98fe2Schristos 
78487f98fe2Schristos 	offset += snprintf(bf, LBFSZ,
78587f98fe2Schristos 	    "%10s %10s %4s  %10s %10s %5s %5s %5s %5s %5s %5s %10s %10s %10s\n",
78687f98fe2Schristos 	    "key", "msqid", "perms", "cbytes", "qnum", "lspid", "lrpid",
78787f98fe2Schristos 	    "uid", "gid", "cuid", "cgid", "stime", "rtime", "ctime");
78887f98fe2Schristos 	if (offset >= LBFSZ)
78987f98fe2Schristos 		goto out;
79087f98fe2Schristos 
79187f98fe2Schristos #ifdef SYSVMSG
79287f98fe2Schristos 	for (int id = 0; id < msginfo.msgmni; id++)
79387f98fe2Schristos 		if (msqs[id].msq_u.msg_qbytes > 0) {
79487f98fe2Schristos 			offset += snprintf(&bf[offset], LBFSZ - offset,
79587f98fe2Schristos 			    "%10d %10d  %4o  %10zu %10lu %5u %5u %5u %5u %5u %5u %10lld %10lld %10lld\n",
79687f98fe2Schristos 			    (int) msqs[id].msq_u.msg_perm._key,
79787f98fe2Schristos 			    IXSEQ_TO_IPCID(id, msqs[id].msq_u.msg_perm),
79887f98fe2Schristos 			    msqs[id].msq_u.msg_perm.mode,
79987f98fe2Schristos 			    msqs[id].msq_u._msg_cbytes,
80087f98fe2Schristos 			    msqs[id].msq_u.msg_qnum,
80187f98fe2Schristos 			    msqs[id].msq_u.msg_lspid,
80287f98fe2Schristos 			    msqs[id].msq_u.msg_lrpid,
80387f98fe2Schristos 			    msqs[id].msq_u.msg_perm.uid,
80487f98fe2Schristos 			    msqs[id].msq_u.msg_perm.gid,
80587f98fe2Schristos 			    msqs[id].msq_u.msg_perm.cuid,
80687f98fe2Schristos 			    msqs[id].msq_u.msg_perm.cgid,
80787f98fe2Schristos 			    (long long)msqs[id].msq_u.msg_stime,
80887f98fe2Schristos 			    (long long)msqs[id].msq_u.msg_rtime,
80987f98fe2Schristos 			    (long long)msqs[id].msq_u.msg_ctime);
81087f98fe2Schristos 			if (offset >= LBFSZ)
81187f98fe2Schristos 				goto out;
81287f98fe2Schristos 		}
81387f98fe2Schristos #endif
81487f98fe2Schristos 
81587f98fe2Schristos 	error = uiomove_frombuf(bf, offset, uio);
81687f98fe2Schristos out:
81787f98fe2Schristos 	free(bf, M_TEMP);
81887f98fe2Schristos 	return error;
81987f98fe2Schristos }
82087f98fe2Schristos 
82187f98fe2Schristos int
82287f98fe2Schristos procfs_dosysvipc_sem(struct lwp *curl, struct proc *p,
82387f98fe2Schristos     struct pfsnode *pfs, struct uio *uio)
82487f98fe2Schristos {
82587f98fe2Schristos 	char *bf;
82687f98fe2Schristos 	int offset = 0;
82787f98fe2Schristos 	int error = EFBIG;
82887f98fe2Schristos 
82987f98fe2Schristos 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
83087f98fe2Schristos 
83187f98fe2Schristos 	offset += snprintf(bf, LBFSZ,
83287f98fe2Schristos 	    "%10s %10s %4s %10s %5s %5s %5s %5s %10s %10s\n",
83387f98fe2Schristos 	    "key", "semid", "perms", "nsems", "uid", "gid", "cuid", "cgid",
83487f98fe2Schristos 	    "otime", "ctime");
83587f98fe2Schristos 	if (offset >= LBFSZ)
83687f98fe2Schristos 		goto out;
83787f98fe2Schristos 
83887f98fe2Schristos #ifdef SYSVSEM
83987f98fe2Schristos 	for (int id = 0; id < seminfo.semmni; id++)
84087f98fe2Schristos 		if ((sema[id].sem_perm.mode & SEM_ALLOC) != 0) {
84187f98fe2Schristos 			offset += snprintf(&bf[offset], LBFSZ - offset,
84287f98fe2Schristos 			    "%10d %10d  %4o %10u %5u %5u %5u %5u %10lld %10lld\n",
84387f98fe2Schristos 			    (int) sema[id].sem_perm._key,
84487f98fe2Schristos 			    IXSEQ_TO_IPCID(id, sema[id].sem_perm),
84587f98fe2Schristos 			    sema[id].sem_perm.mode,
84687f98fe2Schristos 			    sema[id].sem_nsems,
84787f98fe2Schristos 			    sema[id].sem_perm.uid,
84887f98fe2Schristos 			    sema[id].sem_perm.gid,
84987f98fe2Schristos 			    sema[id].sem_perm.cuid,
85087f98fe2Schristos 			    sema[id].sem_perm.cgid,
85187f98fe2Schristos 			    (long long)sema[id].sem_otime,
85287f98fe2Schristos 			    (long long)sema[id].sem_ctime);
85387f98fe2Schristos 			if (offset >= LBFSZ)
85487f98fe2Schristos 				goto out;
85587f98fe2Schristos 		}
85687f98fe2Schristos #endif
85787f98fe2Schristos 
85887f98fe2Schristos 	error = uiomove_frombuf(bf, offset, uio);
85987f98fe2Schristos out:
86087f98fe2Schristos 	free(bf, M_TEMP);
86187f98fe2Schristos 	return error;
86287f98fe2Schristos }
86387f98fe2Schristos 
86487f98fe2Schristos int
86587f98fe2Schristos procfs_dosysvipc_shm(struct lwp *curl, struct proc *p,
86687f98fe2Schristos     struct pfsnode *pfs, struct uio *uio)
86787f98fe2Schristos {
86887f98fe2Schristos 	char *bf;
86987f98fe2Schristos 	int offset = 0;
87087f98fe2Schristos 	int error = EFBIG;
87187f98fe2Schristos 
87287f98fe2Schristos 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
87387f98fe2Schristos 
87487f98fe2Schristos 	offset += snprintf(bf, LBFSZ,
87587f98fe2Schristos 	    "%10s %10s %s %21s %5s %5s %5s %5s %5s %5s %5s %10s %10s %10s %21s %21s\n",
87687f98fe2Schristos 	    "key", "shmid", "perms", "size", "cpid", "lpid", "nattch", "uid",
87787f98fe2Schristos 	    "gid", "cuid", "cgid", "atime", "dtime", "ctime", "rss", "swap");
87887f98fe2Schristos 	if (offset >= LBFSZ)
87987f98fe2Schristos 		goto out;
88087f98fe2Schristos 
88187f98fe2Schristos #ifdef SYSVSHM
88287f98fe2Schristos 	for (unsigned int id = 0; id < shminfo.shmmni; id++)
88387f98fe2Schristos 		if ((shmsegs[id].shm_perm.mode & SHMSEG_ALLOCATED) != 0) {
88487f98fe2Schristos 			offset += snprintf(&bf[offset], LBFSZ - offset,
88587f98fe2Schristos 			    "%10d %10d  %4o %21zu %5u %5u  %5u %5u %5u %5u %5u %10lld %10lld %10lld %21d %21d\n",
88687f98fe2Schristos 			    (int) shmsegs[id].shm_perm._key,
88787f98fe2Schristos 			    IXSEQ_TO_IPCID(id, shmsegs[id].shm_perm),
88887f98fe2Schristos 			    shmsegs[id].shm_perm.mode,
88987f98fe2Schristos 			    shmsegs[id].shm_segsz,
89087f98fe2Schristos 			    shmsegs[id].shm_cpid,
89187f98fe2Schristos 			    shmsegs[id].shm_lpid,
89287f98fe2Schristos 			    shmsegs[id].shm_nattch,
89387f98fe2Schristos 			    shmsegs[id].shm_perm.uid,
89487f98fe2Schristos 			    shmsegs[id].shm_perm.gid,
89587f98fe2Schristos 			    shmsegs[id].shm_perm.cuid,
89687f98fe2Schristos 			    shmsegs[id].shm_perm.cgid,
89787f98fe2Schristos 			    (long long)shmsegs[id].shm_atime,
89887f98fe2Schristos 			    (long long)shmsegs[id].shm_dtime,
89987f98fe2Schristos 			    (long long)shmsegs[id].shm_ctime,
90087f98fe2Schristos 			    0, 0);	/* XXX rss & swp are not supported */
90187f98fe2Schristos 			if (offset >= LBFSZ)
90287f98fe2Schristos 				goto out;
90387f98fe2Schristos 		}
90487f98fe2Schristos #endif
90587f98fe2Schristos 
90687f98fe2Schristos 	error = uiomove_frombuf(bf, offset, uio);
90787f98fe2Schristos out:
90887f98fe2Schristos 	free(bf, M_TEMP);
90987f98fe2Schristos 	return error;
91087f98fe2Schristos }
9110124a941Schristos 
912*78b530bbSpgoyette #ifdef MQUEUE
913*78b530bbSpgoyette #define print_uint(value, uio) PFS_print_uint(value, uio);
914*78b530bbSpgoyette 
9150124a941Schristos static int
916*78b530bbSpgoyette PFS_print_uint(unsigned int value, struct uio *uio)
9170124a941Schristos {
9180124a941Schristos 	char *bf;
9190124a941Schristos 	int offset = 0;
9200124a941Schristos 	int error = EFBIG;
9210124a941Schristos 
9220124a941Schristos 	bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
9230124a941Schristos 	offset += snprintf(bf, LBFSZ, "%u\n", value);
9240124a941Schristos 	if (offset >= LBFSZ)
9250124a941Schristos 		goto out;
9260124a941Schristos 
9270124a941Schristos 	error = uiomove_frombuf(bf, offset, uio);
9280124a941Schristos out:
9290124a941Schristos 	free(bf, M_TEMP);
9300124a941Schristos 	return error;
9310124a941Schristos }
932*78b530bbSpgoyette #else
933*78b530bbSpgoyette 
934*78b530bbSpgoyette #define print_uint(value, uio) EINVAL
935*78b530bbSpgoyette 
936*78b530bbSpgoyette #endif
9370124a941Schristos 
9380124a941Schristos int
9390124a941Schristos procfs_domq_msg_def(struct lwp *curl, struct proc *p,
9400124a941Schristos     struct pfsnode *pfs, struct uio *uio)
9410124a941Schristos {
9420124a941Schristos 	return print_uint(mq_def_maxmsg, uio);
9430124a941Schristos }
9440124a941Schristos 
9450124a941Schristos int
9460124a941Schristos procfs_domq_msg_max(struct lwp *curl, struct proc *p,
9470124a941Schristos     struct pfsnode *pfs, struct uio *uio)
9480124a941Schristos {
9490124a941Schristos 	return print_uint(mq_max_maxmsg, uio);
9500124a941Schristos }
9510124a941Schristos 
9520124a941Schristos int
9530124a941Schristos procfs_domq_siz_def(struct lwp *curl, struct proc *p,
9540124a941Schristos     struct pfsnode *pfs, struct uio *uio)
9550124a941Schristos {
9560124a941Schristos 	return print_uint(MQ_DEF_MSGSIZE, uio);
9570124a941Schristos }
9580124a941Schristos 
9590124a941Schristos int
9600124a941Schristos procfs_domq_siz_max(struct lwp *curl, struct proc *p,
9610124a941Schristos     struct pfsnode *pfs, struct uio *uio)
9620124a941Schristos {
9630124a941Schristos 	return print_uint(mq_max_msgsize, uio);
9640124a941Schristos }
9650124a941Schristos 
9660124a941Schristos int
9670124a941Schristos procfs_domq_qmax(struct lwp *curl, struct proc *p,
9680124a941Schristos     struct pfsnode *pfs, struct uio *uio)
9690124a941Schristos {
9700124a941Schristos 	return print_uint(mq_open_max, uio);
9710124a941Schristos }
972