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