kernel/linprocfs: Implement /proc/devices.
[dragonfly.git] / sys / emulation / linux / i386 / linprocfs / linprocfs_misc.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
3 * Copyright (c) 1999 Pierre Beyssac
4 * Copyright (c) 1993 Jan-Simon Pendry
5 * Copyright (c) 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
40 *
41 * $FreeBSD: src/sys/i386/linux/linprocfs/linprocfs_misc.c,v 1.3.2.8 2001/06/25 19:46:47 pirzyk Exp $
42 */
43
44#include <sys/param.h>
45#include <sys/blist.h>
984263bc 46#include <sys/kernel.h>
9eea7f0c 47#include <sys/kinfo.h>
984263bc 48#include <sys/proc.h>
b91ea118 49#include <sys/jail.h>
984263bc
MD
50#include <sys/resourcevar.h>
51#include <sys/systm.h>
52#include <sys/tty.h>
53#include <sys/vnode.h>
54#include <sys/lock.h>
a1f82243 55#include <sys/sbuf.h>
a3c5067f 56#include <sys/mount.h>
9cccdbd4 57#include <sys/sysctl.h>
984263bc
MD
58
59#include <vm/vm.h>
60#include <vm/pmap.h>
61#include <vm/vm_map.h>
62#include <vm/vm_param.h>
63#include <vm/vm_object.h>
64#include <vm/swap_pager.h>
65#include <sys/vmmeter.h>
66#include <sys/exec.h>
b5fa004e 67#include <sys/devfs.h>
984263bc
MD
68
69#include <machine/clock.h>
70#include <machine/cputypes.h>
b91ea118 71#include <machine/inttypes.h>
984263bc 72#include <machine/md_var.h>
a1f82243 73#include <machine/vmparam.h>
984263bc 74
1f2de5d4 75#include "linprocfs.h"
a1f82243
AH
76#include "../linux.h"
77#include "../../linux_ioctl.h"
78#include "../../linux_mib.h"
984263bc
MD
79
80/*
81 * Various conversion macros
82 */
e5a22113 83#define T2J(x) (((x) * 100) / (stathz ? stathz : hz)) /* ticks to jiffies */
984263bc 84#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
09b0da94 85#define B2K(x) ((unsigned long)((x) >> 10)) /* bytes to kbytes */
984263bc
MD
86#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
87#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
88
89int
2da2a8af
SW
90linprocfs_domeminfo(struct proc *curp, struct proc *p, struct pfsnode *pfs,
91 struct uio *uio)
984263bc
MD
92{
93 char *ps;
984263bc
MD
94 char psbuf[512]; /* XXX - conservative */
95 unsigned long memtotal; /* total memory in bytes */
96 unsigned long memused; /* used memory in bytes */
97 unsigned long memfree; /* free memory in bytes */
98 unsigned long memshared; /* shared memory ??? */
99 unsigned long buffers, cached; /* buffer / cache memory ??? */
09b0da94
MD
100 unsigned long long swaptotal; /* total swap space in bytes */
101 unsigned long long swapused; /* used swap space in bytes */
102 unsigned long long swapfree; /* free swap space in bytes */
984263bc
MD
103 vm_object_t object;
104
105 if (uio->uio_rw != UIO_READ)
106 return (EOPNOTSUPP);
107
31c33cf2 108 memtotal = Maxmem * PAGE_SIZE;
984263bc
MD
109 /*
110 * The correct thing here would be:
111 *
12e4aaff 112 memfree = vmstats.v_free_count * PAGE_SIZE;
984263bc
MD
113 memused = memtotal - memfree;
114 *
115 * but it might mislead linux binaries into thinking there
116 * is very little memory left, so we cheat and tell them that
117 * all memory that isn't wired down is free.
118 */
12e4aaff 119 memused = vmstats.v_wire_count * PAGE_SIZE;
984263bc
MD
120 memfree = memtotal - memused;
121 if (swapblist == NULL) {
122 swaptotal = 0;
123 swapfree = 0;
124 } else {
09b0da94
MD
125 swaptotal = swapblist->bl_blocks * 1024LL; /* XXX why 1024? */
126 swapfree = (unsigned long long)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
984263bc
MD
127 }
128 swapused = swaptotal - swapfree;
129 memshared = 0;
2de4f77e
MD
130
131 lwkt_gettoken(&vmobj_token);
984263bc 132 for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
00a3fdca
MD
133 object = TAILQ_NEXT(object, object_list)) {
134 if (object->type == OBJT_MARKER)
135 continue;
984263bc
MD
136 if (object->shadow_count > 1)
137 memshared += object->resident_page_count;
00a3fdca 138 }
2de4f77e 139 lwkt_reltoken(&vmobj_token);
984263bc
MD
140 memshared *= PAGE_SIZE;
141 /*
142 * We'd love to be able to write:
143 *
144 buffers = bufspace;
145 *
146 * but bufspace is internal to vfs_bio.c and we don't feel
147 * like unstaticizing it just for linprocfs's sake.
148 */
149 buffers = 0;
12e4aaff 150 cached = vmstats.v_cache_count * PAGE_SIZE;
984263bc
MD
151
152 ps = psbuf;
f8c7a42d 153 ps += ksprintf(ps,
984263bc
MD
154 " total: used: free: shared: buffers: cached:\n"
155 "Mem: %lu %lu %lu %lu %lu %lu\n"
156 "Swap: %llu %llu %llu\n"
157 "MemTotal: %9lu kB\n"
158 "MemFree: %9lu kB\n"
159 "MemShared:%9lu kB\n"
160 "Buffers: %9lu kB\n"
161 "Cached: %9lu kB\n"
e5a22113
DR
162 "SwapTotal:%9lu kB\n"
163 "SwapFree: %9lu kB\n",
984263bc
MD
164 memtotal, memused, memfree, memshared, buffers, cached,
165 swaptotal, swapused, swapfree,
166 B2K(memtotal), B2K(memfree),
167 B2K(memshared), B2K(buffers), B2K(cached),
168 B2K(swaptotal), B2K(swapfree));
169
e5a22113 170 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
984263bc
MD
171}
172
173int
2da2a8af
SW
174linprocfs_docpuinfo(struct proc *curp, struct proc *p, struct pfsnode *pfs,
175 struct uio *uio)
984263bc
MD
176{
177 char *ps;
9cccdbd4
AH
178 char psbuf[8192];
179 char hwmodel[128];
180 size_t modellen = sizeof(hwmodel);
181 int mib[] = { CTL_HW, HW_MODEL };
984263bc 182 int class;
9cccdbd4 183 int cpu;
984263bc 184 int i;
9cccdbd4 185 int error;
984263bc
MD
186#if 0
187 extern char *cpu_model; /* Yuck */
188#endif
189 /* We default the flags to include all non-conflicting flags,
190 and the Intel versions of conflicting flags. Note the space
191 before each name; that is significant, and should be
192 preserved. */
193
194 static char *flags[] = {
195 "fpu", "vme", "de", "pse", "tsc",
196 "msr", "pae", "mce", "cx8", "apic",
197 "sep", "sep", "mtrr", "pge", "mca",
198 "cmov", "pat", "pse36", "pn", "b19",
199 "b20", "b21", "mmxext", "mmx", "fxsr",
200 "xmm", "b26", "b27", "b28", "b29",
201 "3dnowext", "3dnow"
202 };
203
204 if (uio->uio_rw != UIO_READ)
205 return (EOPNOTSUPP);
206
207 switch (cpu_class) {
208 case CPUCLASS_286:
209 class = 2;
210 break;
211 case CPUCLASS_386:
212 class = 3;
213 break;
214 case CPUCLASS_486:
215 class = 4;
216 break;
217 case CPUCLASS_586:
218 class = 5;
219 break;
220 case CPUCLASS_686:
221 class = 6;
222 break;
223 default:
224 class = 0;
225 break;
226 }
227
228 ps = psbuf;
9cccdbd4
AH
229
230 error = kernel_sysctl(mib, 2, hwmodel, &modellen, NULL, 0, NULL);
231 if (error)
232 strcpy(hwmodel, "unknown");
233
234 for (cpu = 0; cpu < ncpus; cpu++) {
235 ps += ksprintf(ps,
236 "processor\t: %d\n"
237 "vendor_id\t: %.20s\n"
238 "cpu family\t: %d\n"
239 "model\t\t: %d\n"
240 "model name\t: %s\n"
241 "stepping\t: %d\n",
242 cpu, cpu_vendor, class, cpu, hwmodel, cpu_id & 0xf);
243 }
984263bc 244
f8c7a42d 245 ps += ksprintf(ps,
984263bc
MD
246 "flags\t\t:");
247
86b7a03a 248 if (cpu_vendor_id == CPU_VENDOR_AMD && (class < 6)) {
984263bc 249 flags[16] = "fcmov";
86b7a03a 250 } else if (cpu_vendor_id == CPU_VENDOR_CYRIX) {
984263bc
MD
251 flags[24] = "cxmmx";
252 }
253
254 for (i = 0; i < 32; i++)
255 if (cpu_feature & (1 << i))
f8c7a42d
MD
256 ps += ksprintf(ps, " %s", flags[i]);
257 ps += ksprintf(ps, "\n");
984263bc 258 if (class >= 5) {
f8c7a42d 259 ps += ksprintf(ps,
984263bc
MD
260 "cpu MHz\t\t: %d.%02d\n"
261 "bogomips\t: %d.%02d\n",
870b0161
MD
262 (int)((tsc_frequency + 4999) / 1000000),
263 (int)((tsc_frequency + 4999) / 10000) % 100,
264 (int)((tsc_frequency + 4999) / 1000000),
265 (int)((tsc_frequency + 4999) / 10000) % 100);
984263bc
MD
266 }
267
e5a22113 268 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
984263bc
MD
269}
270
12e4aaff
MD
271static unsigned int
272cpucnt(int offset)
273{
274 int i;
275 int count = 0;
276
277 for (i = 0; i < ncpus; ++i) {
278 struct globaldata *gd = globaldata_find(i);
279 count += *(unsigned int *)((char *)&gd->gd_cnt + offset);
280 }
281 return(count);
282}
283
a3c5067f
AH
284static int
285linprocfs_domounts_callback(struct mount *mp, void *data)
286{
287 struct statfs *st;
288 struct sbuf *sb = (struct sbuf *)data;
289 char *to, *from, *fs;
290
291 st = &mp->mnt_stat;
292
293 from = st->f_mntfromname;
294 to = st->f_mntonname;
295 fs = st->f_fstypename;
296
297 if (!strcmp(st->f_fstypename, "linprocfs"))
298 fs = "proc";
299 else if (!strcmp(st->f_fstypename, "ext2fs"))
300 fs = "ext2";
301 else if (!strcmp(st->f_fstypename, "msdos"))
302 fs = "vfat";
303 else if (!strcmp(st->f_fstypename, "msdosfs"))
304 fs = "vfat";
305
306 sbuf_printf(sb, "%s %s %s %s", from, to, fs,
307 st->f_flags & MNT_RDONLY ? "ro" : "rw");
308
309#define OPT_ADD(name, flag) if (st->f_flags & (flag)) sbuf_printf(sb, "," name)
310 OPT_ADD("sync", MNT_SYNCHRONOUS);
311 OPT_ADD("noexec", MNT_NOEXEC);
312 OPT_ADD("nosuid", MNT_NOSUID);
313 OPT_ADD("nodev", MNT_NODEV);
314 OPT_ADD("async", MNT_ASYNC);
315 OPT_ADD("suiddir", MNT_SUIDDIR);
316 OPT_ADD("nosymfollow", MNT_NOSYMFOLLOW);
317 OPT_ADD("noatime", MNT_NOATIME);
318#undef OPT_ADD
319
320 sbuf_printf(sb, " 0 0\n");
321
322 return 0;
323}
324
325int
326linprocfs_domounts(struct proc *curp, struct proc *p, struct pfsnode *pfs,
327 struct uio *uio)
328{
329 struct sbuf *sb;
330 int error;
331
332 sb = sbuf_new_auto();
333
334 error = mountlist_scan(linprocfs_domounts_callback, sb, MNTSCAN_FORWARD);
335
336 sbuf_finish(sb);
337 if (error == 0)
338 error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
339 sbuf_delete(sb);
340 return (error);
341}
342
984263bc 343int
2da2a8af
SW
344linprocfs_dostat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
345 struct uio *uio)
984263bc
MD
346{
347 char *ps;
9cccdbd4
AH
348 char psbuf[8192];
349 int cpu;
984263bc
MD
350
351 ps = psbuf;
f8c7a42d 352 ps += ksprintf(ps,
9cccdbd4
AH
353 "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n",
354 T2J(cpu_time.cp_user),
355 T2J(cpu_time.cp_nice),
356 T2J(cpu_time.cp_sys),
357 T2J(cpu_time.cp_idle));
358
359 for (cpu = 0; cpu < ncpus; cpu++) {
360 ps += ksprintf(ps,
361 "cpu%d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n",
362 cpu,
363 T2J(cputime_percpu[cpu].cp_user),
364 T2J(cputime_percpu[cpu].cp_nice),
365 T2J(cputime_percpu[cpu].cp_sys),
366 T2J(cputime_percpu[cpu].cp_idle));
367 }
368
369 ps += ksprintf(ps,
984263bc
MD
370 "disk 0 0 0 0\n"
371 "page %u %u\n"
372 "swap %u %u\n"
373 "intr %u\n"
374 "ctxt %u\n"
375 "btime %ld\n",
12e4aaff
MD
376 cpucnt(offsetof(struct vmmeter, v_vnodepgsin)),
377 cpucnt(offsetof(struct vmmeter, v_vnodepgsout)),
378 cpucnt(offsetof(struct vmmeter, v_swappgsin)),
379 cpucnt(offsetof(struct vmmeter, v_swappgsout)),
380 cpucnt(offsetof(struct vmmeter, v_intr)),
381 cpucnt(offsetof(struct vmmeter, v_swtch)),
984263bc 382 boottime.tv_sec);
9cccdbd4 383
e5a22113 384 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
984263bc
MD
385}
386
387int
2da2a8af
SW
388linprocfs_douptime(struct proc *curp, struct proc *p, struct pfsnode *pfs,
389 struct uio *uio)
984263bc
MD
390{
391 char *ps;
984263bc
MD
392 char psbuf[64];
393 struct timeval tv;
394
395 getmicrouptime(&tv);
396 ps = psbuf;
f8c7a42d 397 ps += ksprintf(ps, "%ld.%02ld %"PRIu64".%02"PRIu64"\n",
984263bc 398 tv.tv_sec, tv.tv_usec / 10000,
9eea7f0c 399 T2S(cpu_time.cp_idle), T2J(cpu_time.cp_idle) % 100);
e5a22113 400 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
984263bc
MD
401}
402
403int
2da2a8af
SW
404linprocfs_doversion(struct proc *curp, struct proc *p, struct pfsnode *pfs,
405 struct uio *uio)
984263bc
MD
406{
407 char *ps;
e54488bb 408 size_t xlen;
984263bc
MD
409
410 ps = version; /* XXX not entirely correct */
411 for (xlen = 0; ps[xlen] != '\n'; ++xlen)
412 /* nothing */ ;
413 ++xlen;
e5a22113 414 return (uiomove_frombuf(ps, xlen, uio));
984263bc
MD
415}
416
a1f82243
AH
417#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
418int
419linprocfs_dostatm(struct proc *curp, struct proc *p, struct pfsnode *pfs,
420 struct uio *uio)
421{
422 char *ps, psbuf[1024];
423 struct kinfo_proc kp;
424
b0c15cdf 425 lwkt_gettoken(&p->p_token);
a1f82243
AH
426 fill_kinfo_proc(p, &kp);
427
428 ps = psbuf;
429 ps += ksprintf(ps, "%d", p->p_pid);
430#define PS_ADD(name, fmt, arg) ps += ksprintf(ps, " " fmt, arg)
431 PS_ADD("", "%ju", B2P((uintmax_t)(kp.kp_vm_tsize + kp.kp_vm_dsize + kp.kp_vm_ssize)));
432 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_rssize);
433 PS_ADD("", "%ju", (uintmax_t)0); /* XXX */
434 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_tsize);
435 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_dsize);
436 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_ssize);
437 PS_ADD("", "%ju", (uintmax_t)0); /* XXX */
438#undef PS_ADD
439 ps += ksprintf(ps, "\n");
b0c15cdf 440 lwkt_reltoken(&p->p_token);
a1f82243
AH
441
442 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
443}
444
445#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
984263bc 446int
2da2a8af
SW
447linprocfs_doprocstat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
448 struct uio *uio)
984263bc 449{
a1f82243
AH
450 vm_map_t map = &p->p_vmspace->vm_map;
451 vm_map_entry_t entry;
452 vm_offset_t start, end;
984263bc 453 char *ps, psbuf[1024];
a1f82243
AH
454 struct kinfo_proc kp;
455
b0c15cdf 456 lwkt_gettoken(&p->p_token);
a1f82243
AH
457 fill_kinfo_proc(p, &kp);
458
459 start = 0;
460 end = 0;
461 vm_map_lock_read(map);
462 for (entry = map->header.next; entry != &map->header;
463 entry = entry->next) {
464 if (entry->maptype != VM_MAPTYPE_NORMAL &&
465 entry->maptype != VM_MAPTYPE_VPAGETABLE) {
466 continue;
467 }
468 /* Assuming that text is the first entry */
469 start = entry->start;
470 end = entry->end;
471 }
472 vm_map_unlock_read(map);
984263bc
MD
473
474 ps = psbuf;
f8c7a42d
MD
475 ps += ksprintf(ps, "%d", p->p_pid);
476#define PS_ADD(name, fmt, arg) ps += ksprintf(ps, " " fmt, arg)
984263bc
MD
477 PS_ADD("comm", "(%s)", p->p_comm);
478 PS_ADD("statr", "%c", '0'); /* XXX */
479 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
480 PS_ADD("pgrp", "%d", p->p_pgid);
481 PS_ADD("session", "%d", p->p_session->s_sid);
482 PS_ADD("tty", "%d", 0); /* XXX */
a1f82243 483 PS_ADD("tpgid", "%d", kp.kp_tpgid); /* XXX */
984263bc 484 PS_ADD("flags", "%u", 0); /* XXX */
a1f82243
AH
485 PS_ADD("minflt", "%lu", kp.kp_ru.ru_minflt); /* XXX */
486 PS_ADD("cminflt", "%lu", kp.kp_cru.ru_minflt); /* XXX */
487 PS_ADD("majflt", "%lu", kp.kp_ru.ru_majflt); /* XXX */
488 PS_ADD("cmajflt", "%lu", kp.kp_cru.ru_majflt); /* XXX */
489 PS_ADD("utime", "%d", T2J(tvtohz_high(&kp.kp_ru.ru_utime))); /* XXX */
490 PS_ADD("stime", "%d", T2J(tvtohz_high(&kp.kp_ru.ru_stime))); /* XXX */
491 PS_ADD("cutime", "%d", T2J(tvtohz_high(&kp.kp_cru.ru_utime))); /* XXX */
492 PS_ADD("cstime", "%d", T2J(tvtohz_high(&kp.kp_cru.ru_stime))); /* XXX */
984263bc 493 PS_ADD("priority", "%d", 0); /* XXX */
a1f82243 494 PS_ADD("nice", "%d", kp.kp_nice);
984263bc
MD
495 PS_ADD("timeout", "%u", 0); /* XXX */
496 PS_ADD("itrealvalue", "%u", 0); /* XXX */
a1f82243
AH
497 PS_ADD("starttime", "%d", T2J(tvtohz_high(&kp.kp_start))); /* XXX */
498 PS_ADD("vsize", "%ju", P2K((uintmax_t)(kp.kp_vm_tsize + kp.kp_vm_dsize + kp.kp_vm_ssize))); /* XXX: not sure */
499 PS_ADD("rss", "%ju", (uintmax_t)kp.kp_vm_rssize); /* XXX */
500 PS_ADD("rlim", "%lu", kp.kp_ru.ru_maxrss); /* XXX */
501 PS_ADD("startcode", "%lu", start); /* XXX */
502 PS_ADD("endcode", "%lu", end); /* XXX */
503 PS_ADD("startstack", "%lu", (u_long)p->p_vmspace->vm_minsaddr); /* XXX */
984263bc
MD
504 PS_ADD("kstkesp", "%u", 0); /* XXX */
505 PS_ADD("kstkeip", "%u", 0); /* XXX */
506 PS_ADD("signal", "%d", 0); /* XXX */
507 PS_ADD("blocked", "%d", 0); /* XXX */
508 PS_ADD("sigignore", "%d", 0); /* XXX */
509 PS_ADD("sigcatch", "%d", 0); /* XXX */
510 PS_ADD("wchan", "%u", 0); /* XXX */
a1f82243
AH
511 PS_ADD("nswap", "%lu", kp.kp_ru.ru_nswap); /* XXX */
512 PS_ADD("cnswap", "%lu", kp.kp_cru.ru_nswap); /* XXX */
513 PS_ADD("exitsignal", "%d", 0); /* XXX */
514 PS_ADD("processor", "%u", kp.kp_lwp.kl_cpuid); /* XXX */
515 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
516 PS_ADD("policy", "%u", kp.kp_nice); /* XXX */ /* >= 2.5.19 */
984263bc 517#undef PS_ADD
f8c7a42d 518 ps += ksprintf(ps, "\n");
b0c15cdf 519 lwkt_reltoken(&p->p_token);
984263bc 520
e5a22113 521 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
984263bc
MD
522}
523
524/*
525 * Map process state to descriptive letter. Note that this does not
526 * quite correspond to what Linux outputs, but it's close enough.
527 */
528static char *state_str[] = {
529 "? (unknown)",
530 "I (idle)",
531 "R (running)",
984263bc
MD
532 "T (stopped)",
533 "Z (zombie)",
164b8401 534 "S (sleeping)",
984263bc
MD
535 "W (waiting)",
536 "M (mutex)"
537};
538
539int
2da2a8af
SW
540linprocfs_doprocstatus(struct proc *curp, struct proc *p, struct pfsnode *pfs,
541 struct uio *uio)
984263bc
MD
542{
543 char *ps, psbuf[1024];
544 char *state;
e5a22113 545 int i;
984263bc
MD
546
547 ps = psbuf;
548
b0c15cdf 549 lwkt_gettoken(&p->p_token);
b370aff7 550 if (p->p_stat > NELEM(state_str))
984263bc
MD
551 state = state_str[0];
552 else
553 state = state_str[(int)p->p_stat];
554
f8c7a42d 555#define PS_ADD ps += ksprintf
984263bc
MD
556 PS_ADD(ps, "Name:\t%s\n", p->p_comm); /* XXX escape */
557 PS_ADD(ps, "State:\t%s\n", state);
558
559 /*
560 * Credentials
561 */
562 PS_ADD(ps, "Pid:\t%d\n", p->p_pid);
563 PS_ADD(ps, "PPid:\t%d\n", p->p_pptr ? p->p_pptr->p_pid : 0);
41c20dac 564 PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
984263bc 565 p->p_ucred->cr_uid,
41c20dac 566 p->p_ucred->cr_svuid,
984263bc
MD
567 /* FreeBSD doesn't have fsuid */
568 p->p_ucred->cr_uid);
41c20dac 569 PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
984263bc 570 p->p_ucred->cr_gid,
41c20dac 571 p->p_ucred->cr_svgid,
984263bc
MD
572 /* FreeBSD doesn't have fsgid */
573 p->p_ucred->cr_gid);
574 PS_ADD(ps, "Groups:\t");
575 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
576 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
577 PS_ADD(ps, "\n");
578
579 /*
580 * Memory
581 */
09b0da94 582 PS_ADD(ps, "VmSize:\t%8lu kB\n", B2K(p->p_vmspace->vm_map.size));
984263bc
MD
583 PS_ADD(ps, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
584 /* XXX vm_rssize seems to always be zero, how can this be? */
585 PS_ADD(ps, "VmRss:\t%8u kB\n", P2K(p->p_vmspace->vm_rssize));
586 PS_ADD(ps, "VmData:\t%8u kB\n", P2K(p->p_vmspace->vm_dsize));
587 PS_ADD(ps, "VmStk:\t%8u kB\n", P2K(p->p_vmspace->vm_ssize));
588 PS_ADD(ps, "VmExe:\t%8u kB\n", P2K(p->p_vmspace->vm_tsize));
589 PS_ADD(ps, "VmLib:\t%8u kB\n", P2K(0)); /* XXX */
590
591 /*
592 * Signal masks
593 *
594 * We support up to 128 signals, while Linux supports 32,
595 * but we only define 32 (the same 32 as Linux, to boot), so
596 * just show the lower 32 bits of each mask. XXX hack.
597 *
598 * NB: on certain platforms (Sparc at least) Linux actually
599 * supports 64 signals, but this code is a long way from
600 * running on anything but i386, so ignore that for now.
601 */
602 PS_ADD(ps, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
603 PS_ADD(ps, "SigBlk:\t%08x\n", 0); /* XXX */
604 PS_ADD(ps, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]);
605 PS_ADD(ps, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]);
606
607 /*
608 * Linux also prints the capability masks, but we don't have
609 * capabilities yet, and when we do get them they're likely to
610 * be meaningless to Linux programs, so we lie. XXX
611 */
612 PS_ADD(ps, "CapInh:\t%016x\n", 0);
613 PS_ADD(ps, "CapPrm:\t%016x\n", 0);
614 PS_ADD(ps, "CapEff:\t%016x\n", 0);
615#undef PS_ADD
b0c15cdf 616 lwkt_reltoken(&p->p_token);
984263bc 617
e5a22113 618 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
984263bc
MD
619}
620
09b0da94
MD
621int
622linprocfs_doloadavg(struct proc *curp, struct proc *p,
623 struct pfsnode *pfs, struct uio *uio)
624{
625 char *ps, psbuf[512];
09b0da94
MD
626
627 ps = psbuf;
f8c7a42d 628 ps += ksprintf(ps, "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
09b0da94
MD
629 (int)(averunnable.ldavg[0] / averunnable.fscale),
630 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
631 (int)(averunnable.ldavg[1] / averunnable.fscale),
632 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
633 (int)(averunnable.ldavg[2] / averunnable.fscale),
634 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
635 1, /* number of running tasks */
636 -1, /* number of tasks */
67d32fb2 637 1 /* The last pid, just kidding */
09b0da94 638 );
9bbc4e5c 639 return(uiomove_frombuf(psbuf, ps - psbuf, uio));
09b0da94
MD
640}
641
a1f82243
AH
642int
643linprocfs_donetdev(struct proc *curp, struct proc *p, struct pfsnode *pfs,
644 struct uio *uio)
645{
646 struct sbuf *sb;
647 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
648 struct ifnet *ifp;
649 int error;
650
651 sb = sbuf_new_auto();
652
653 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
654 "Inter-", " Receive", " Transmit", " face",
655 "bytes packets errs drop fifo frame compressed",
656 "bytes packets errs drop fifo frame compressed");
657
658 crit_enter();
659 TAILQ_FOREACH(ifp, &ifnet, if_link) {
660 linux_ifname(ifp, ifname, sizeof ifname);
661 sbuf_printf(sb, "%6.6s:", ifname);
662 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
663 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
664 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
665 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
666 }
667 crit_exit();
668 sbuf_finish(sb);
669 error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
670 sbuf_delete(sb);
671 return (error);
672}
673
b5fa004e
SW
674static void
675linprocfs_dodevices_callback(char *name, cdev_t dev, bool is_alias, void *arg)
676{
677 struct sbuf *sb = arg;
678
679 sbuf_printf(sb, "%3d %s\n", dev->si_umajor, name);
680}
681
a1f82243
AH
682int
683linprocfs_dodevices(struct proc *curp, struct proc *p, struct pfsnode *pfs,
b5fa004e 684 struct uio *uio)
a1f82243 685{
b5fa004e
SW
686 struct sbuf *sb;
687 int error;
688
689 sb = sbuf_new_auto();
690 sbuf_printf(sb, "Character devices:\n");
691 devfs_scan_callback(linprocfs_dodevices_callback, sb);
692 sbuf_printf(sb, "\nBlock devices:\n");
693 sbuf_finish(sb);
694 error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
695 sbuf_delete(sb);
696 return (error);
a1f82243
AH
697}
698
699int
700linprocfs_doosrelease(struct proc *curp, struct proc *p, struct pfsnode *pfs,
701 struct uio *uio)
702{
703 char *osrelease;
704
705 osrelease = linux_get_osrelease(curthread);
706 return(uiomove_frombuf(osrelease, strlen(osrelease)+1, uio));
707}
708
709int
710linprocfs_doostype(struct proc *curp, struct proc *p, struct pfsnode *pfs,
711 struct uio *uio)
712{
713 char *osname;
714
715 osname = linux_get_osname(curthread);
716 return(uiomove_frombuf(osname, strlen(osname)+1, uio));
717}
718
719int
720linprocfs_dopidmax(struct proc *curp, struct proc *p, struct pfsnode *pfs,
721 struct uio *uio)
722{
723 char buf[32];
724
725 ksnprintf(buf, sizeof(buf), "%d", PID_MAX);
726 return(uiomove_frombuf(buf, strlen(buf)+1, uio));
a1f82243
AH
727}
728
729int
730linprocfs_domaps(struct proc *curp, struct proc *p, struct pfsnode *pfs,
731 struct uio *uio)
732{
a1f82243
AH
733 int error;
734 vm_map_t map = &p->p_vmspace->vm_map;
735 vm_map_entry_t entry;
736 vm_ooffset_t off = 0;
3c792b83 737 struct sbuf *sb;
a1f82243
AH
738 char *name = "", *freename = NULL;
739 struct vnode *vp;
740 struct vattr vat;
741 int major, minor;
742 ino_t ino;
743
744 if (uio->uio_rw != UIO_READ)
745 return (EOPNOTSUPP);
746
3c792b83
AH
747 sb = sbuf_new_auto();
748
a1f82243
AH
749 error = 0;
750 vm_map_lock_read(map);
751 for (entry = map->header.next;
752 ((uio->uio_resid > 0) && (entry != &map->header));
753 entry = entry->next) {
754 vm_object_t obj, tobj, lobj;
755 vm_offset_t ostart;
756 name = "";
757 freename = NULL;
758 ino = 0;
759 if (entry->maptype != VM_MAPTYPE_NORMAL &&
760 entry->maptype != VM_MAPTYPE_VPAGETABLE) {
761 continue;
762 }
763 /*
764 * Use map->hint as a poor man's ripout detector.
765 */
766 map->hint = entry;
767 ostart = entry->start;
a1f82243 768
b12defdc
MD
769 /*
770 * Find the bottom-most object, leaving the base object
771 * and the bottom-most object held (but only one hold
772 * if they happen to be the same).
773 */
774 obj = entry->object.vm_object;
3eeee238
SW
775 if (obj)
776 vm_object_hold(obj);
b12defdc
MD
777
778 lobj = obj;
779 while (lobj && (tobj = lobj->backing_object) != NULL) {
780 KKASSERT(tobj != obj);
781 vm_object_hold(tobj);
782 if (tobj == lobj->backing_object) {
783 if (lobj != obj) {
784 vm_object_lock_swap();
785 vm_object_drop(lobj);
786 }
787 lobj = tobj;
788 } else {
789 vm_object_drop(tobj);
790 }
791 }
a1f82243
AH
792
793 if (lobj) {
794 off = IDX_TO_OFF(lobj->size);
795 if (lobj->type == OBJT_VNODE) {
796 vp = lobj->handle;
797 if (vp)
798 vref(vp);
799 } else {
800 vp = NULL;
801 }
802
803 if (vp) {
3c792b83 804 vn_fullpath(curproc, vp, &name, &freename, 1);
a1f82243
AH
805 vn_lock(vp, LK_SHARED | LK_RETRY);
806 VOP_GETATTR(vp, &vat);
807 ino = vat.va_fileid;
808 major = vat.va_rmajor;
809 minor = vat.va_rminor;
810 vput(vp);
811 }
812 }
813 if (freename == NULL) {
814 if (entry->eflags & MAP_ENTRY_STACK)
815 name = "[stack]";
816 }
817
b12defdc
MD
818 if (lobj != obj)
819 vm_object_drop(lobj);
3eeee238
SW
820 if (obj)
821 vm_object_drop(obj);
b12defdc 822
a1f82243 823 /*
3c792b83
AH
824 * We cannot safely hold the map locked while accessing
825 * userspace as a VM fault might recurse the locked map.
826 */
827 vm_map_unlock_read(map);
828
829 /*
a1f82243
AH
830 * format:
831 * start-end access offset major:minor inode [.text file]
832 */
3c792b83 833 error = sbuf_printf(sb,
a1f82243
AH
834 "%08lx-%08lx %s%s%s%s %08llx %02x:%02x %llu%s%s\n",
835 (u_long)entry->start, (u_long)entry->end,
836 (entry->protection & VM_PROT_READ)?"r":"-",
837 (entry->protection & VM_PROT_WRITE)?"w":"-",
838 (entry->protection & VM_PROT_EXECUTE)?"x":"-",
839 "p",
840 off, /* offset */
841 0, /* major */
842 0, /* minor */
843 ino, /* inode */
3c792b83
AH
844 (name && *name) ? " " : "",
845 name ? name : "");
846 if (error == -1)
847 error = ENOMEM;
a1f82243
AH
848 if (freename)
849 kfree(freename, M_TEMP);
850
a1f82243
AH
851 vm_map_lock_read(map);
852 if (error)
853 break;
854
855 /*
856 * We use map->hint as a poor man's ripout detector. If
857 * it does not match the entry we set it to prior to
858 * unlocking the map the entry MIGHT now be stale. In
859 * this case we do an expensive lookup to find our place
860 * in the iteration again.
861 */
862 if (map->hint != entry) {
863 vm_map_entry_t reentry;
864
865 vm_map_lookup_entry(map, ostart, &reentry);
866 entry = reentry;
867 }
868 }
869 vm_map_unlock_read(map);
870
3c792b83
AH
871 sbuf_finish(sb);
872 if (error == 0)
5a0bce27
SG
873 error = uiomove_frombuf(sbuf_data(sb) + uio->uio_offset,
874 sbuf_len(sb) - uio->uio_offset, uio);
3c792b83 875 sbuf_delete(sb);
a1f82243
AH
876 return error;
877}