linprocfs - Introduce /proc/mounts
[dragonfly.git] / sys / emulation / linux / i386 / linprocfs / linprocfs_misc.c
blob04ed5b6abca1aa9c0a42c7fbb15821034a11049f
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.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry.
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.
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.
39 * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
41 * $FreeBSD: src/sys/i386/linux/linprocfs/linprocfs_misc.c,v 1.3.2.8 2001/06/25 19:46:47 pirzyk Exp $
42 * $DragonFly: src/sys/emulation/linux/i386/linprocfs/linprocfs_misc.c,v 1.19 2008/05/10 17:24:05 dillon Exp $
45 #include <sys/param.h>
46 #include <sys/blist.h>
47 #include <sys/kernel.h>
48 #include <sys/kinfo.h>
49 #include <sys/proc.h>
50 #include <sys/jail.h>
51 #include <sys/resourcevar.h>
52 #include <sys/systm.h>
53 #include <sys/tty.h>
54 #include <sys/vnode.h>
55 #include <sys/lock.h>
56 #include <sys/sbuf.h>
57 #include <sys/mount.h>
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>
68 #include <machine/clock.h>
69 #include <machine/cputypes.h>
70 #include <machine/inttypes.h>
71 #include <machine/md_var.h>
72 #include <machine/vmparam.h>
74 #include "linprocfs.h"
75 #include "../linux.h"
76 #include "../../linux_ioctl.h"
77 #include "../../linux_mib.h"
80 * Various conversion macros
82 #define T2J(x) (((x) * 100) / (stathz ? stathz : hz)) /* ticks to jiffies */
83 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
84 #define B2K(x) ((unsigned long)((x) >> 10)) /* bytes to kbytes */
85 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
86 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
88 int
89 linprocfs_domeminfo(struct proc *curp, struct proc *p, struct pfsnode *pfs,
90 struct uio *uio)
92 char *ps;
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 ??? */
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 */
102 vm_object_t object;
104 if (uio->uio_rw != UIO_READ)
105 return (EOPNOTSUPP);
107 memtotal = Maxmem * PAGE_SIZE;
109 * The correct thing here would be:
111 memfree = vmstats.v_free_count * PAGE_SIZE;
112 memused = memtotal - memfree;
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.
118 memused = vmstats.v_wire_count * PAGE_SIZE;
119 memfree = memtotal - memused;
120 if (swapblist == NULL) {
121 swaptotal = 0;
122 swapfree = 0;
123 } else {
124 swaptotal = swapblist->bl_blocks * 1024LL; /* XXX why 1024? */
125 swapfree = (unsigned long long)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
127 swapused = swaptotal - swapfree;
128 memshared = 0;
129 for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
130 object = TAILQ_NEXT(object, object_list)) {
131 if (object->type == OBJT_MARKER)
132 continue;
133 if (object->shadow_count > 1)
134 memshared += object->resident_page_count;
136 memshared *= PAGE_SIZE;
138 * We'd love to be able to write:
140 buffers = bufspace;
142 * but bufspace is internal to vfs_bio.c and we don't feel
143 * like unstaticizing it just for linprocfs's sake.
145 buffers = 0;
146 cached = vmstats.v_cache_count * PAGE_SIZE;
148 ps = psbuf;
149 ps += ksprintf(ps,
150 " total: used: free: shared: buffers: cached:\n"
151 "Mem: %lu %lu %lu %lu %lu %lu\n"
152 "Swap: %llu %llu %llu\n"
153 "MemTotal: %9lu kB\n"
154 "MemFree: %9lu kB\n"
155 "MemShared:%9lu kB\n"
156 "Buffers: %9lu kB\n"
157 "Cached: %9lu kB\n"
158 "SwapTotal:%9lu kB\n"
159 "SwapFree: %9lu kB\n",
160 memtotal, memused, memfree, memshared, buffers, cached,
161 swaptotal, swapused, swapfree,
162 B2K(memtotal), B2K(memfree),
163 B2K(memshared), B2K(buffers), B2K(cached),
164 B2K(swaptotal), B2K(swapfree));
166 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
170 linprocfs_docpuinfo(struct proc *curp, struct proc *p, struct pfsnode *pfs,
171 struct uio *uio)
173 char *ps;
174 char psbuf[512]; /* XXX - conservative */
175 int class;
176 int i;
177 #if 0
178 extern char *cpu_model; /* Yuck */
179 #endif
180 /* We default the flags to include all non-conflicting flags,
181 and the Intel versions of conflicting flags. Note the space
182 before each name; that is significant, and should be
183 preserved. */
185 static char *flags[] = {
186 "fpu", "vme", "de", "pse", "tsc",
187 "msr", "pae", "mce", "cx8", "apic",
188 "sep", "sep", "mtrr", "pge", "mca",
189 "cmov", "pat", "pse36", "pn", "b19",
190 "b20", "b21", "mmxext", "mmx", "fxsr",
191 "xmm", "b26", "b27", "b28", "b29",
192 "3dnowext", "3dnow"
195 if (uio->uio_rw != UIO_READ)
196 return (EOPNOTSUPP);
198 switch (cpu_class) {
199 case CPUCLASS_286:
200 class = 2;
201 break;
202 case CPUCLASS_386:
203 class = 3;
204 break;
205 case CPUCLASS_486:
206 class = 4;
207 break;
208 case CPUCLASS_586:
209 class = 5;
210 break;
211 case CPUCLASS_686:
212 class = 6;
213 break;
214 default:
215 class = 0;
216 break;
219 ps = psbuf;
220 ps += ksprintf(ps,
221 "processor\t: %d\n"
222 "vendor_id\t: %.20s\n"
223 "cpu family\t: %d\n"
224 "model\t\t: %d\n"
225 "stepping\t: %d\n",
226 0, cpu_vendor, class, cpu, cpu_id & 0xf);
228 ps += ksprintf(ps,
229 "flags\t\t:");
231 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
232 flags[16] = "fcmov";
233 } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
234 flags[24] = "cxmmx";
237 for (i = 0; i < 32; i++)
238 if (cpu_feature & (1 << i))
239 ps += ksprintf(ps, " %s", flags[i]);
240 ps += ksprintf(ps, "\n");
241 if (class >= 5) {
242 ps += ksprintf(ps,
243 "cpu MHz\t\t: %d.%02d\n"
244 "bogomips\t: %d.%02d\n",
245 (int)((tsc_frequency + 4999) / 1000000),
246 (int)((tsc_frequency + 4999) / 10000) % 100,
247 (int)((tsc_frequency + 4999) / 1000000),
248 (int)((tsc_frequency + 4999) / 10000) % 100);
251 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
254 static unsigned int
255 cpucnt(int offset)
257 int i;
258 int count = 0;
260 for (i = 0; i < ncpus; ++i) {
261 struct globaldata *gd = globaldata_find(i);
262 count += *(unsigned int *)((char *)&gd->gd_cnt + offset);
264 return(count);
267 static int
268 linprocfs_domounts_callback(struct mount *mp, void *data)
270 struct statfs *st;
271 struct sbuf *sb = (struct sbuf *)data;
272 char *to, *from, *fs;
274 st = &mp->mnt_stat;
276 from = st->f_mntfromname;
277 to = st->f_mntonname;
278 fs = st->f_fstypename;
280 if (!strcmp(st->f_fstypename, "linprocfs"))
281 fs = "proc";
282 else if (!strcmp(st->f_fstypename, "ext2fs"))
283 fs = "ext2";
284 else if (!strcmp(st->f_fstypename, "msdos"))
285 fs = "vfat";
286 else if (!strcmp(st->f_fstypename, "msdosfs"))
287 fs = "vfat";
289 sbuf_printf(sb, "%s %s %s %s", from, to, fs,
290 st->f_flags & MNT_RDONLY ? "ro" : "rw");
292 #define OPT_ADD(name, flag) if (st->f_flags & (flag)) sbuf_printf(sb, "," name)
293 OPT_ADD("sync", MNT_SYNCHRONOUS);
294 OPT_ADD("noexec", MNT_NOEXEC);
295 OPT_ADD("nosuid", MNT_NOSUID);
296 OPT_ADD("nodev", MNT_NODEV);
297 OPT_ADD("async", MNT_ASYNC);
298 OPT_ADD("suiddir", MNT_SUIDDIR);
299 OPT_ADD("nosymfollow", MNT_NOSYMFOLLOW);
300 OPT_ADD("noatime", MNT_NOATIME);
301 #undef OPT_ADD
303 sbuf_printf(sb, " 0 0\n");
305 return 0;
309 linprocfs_domounts(struct proc *curp, struct proc *p, struct pfsnode *pfs,
310 struct uio *uio)
312 struct sbuf *sb;
313 int error;
315 sb = sbuf_new_auto();
317 error = mountlist_scan(linprocfs_domounts_callback, sb, MNTSCAN_FORWARD);
319 sbuf_finish(sb);
320 if (error == 0)
321 error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
322 sbuf_delete(sb);
323 return (error);
327 linprocfs_dostat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
328 struct uio *uio)
330 char *ps;
331 char psbuf[512];
333 ps = psbuf;
334 ps += ksprintf(ps,
335 "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n"
336 "disk 0 0 0 0\n"
337 "page %u %u\n"
338 "swap %u %u\n"
339 "intr %u\n"
340 "ctxt %u\n"
341 "btime %ld\n",
342 T2J(cpu_time.cp_user),
343 T2J(cpu_time.cp_nice),
344 T2J(cpu_time.cp_sys /*+ cpu_time[CP_INTR]*/),
345 T2J(cpu_time.cp_idle),
346 cpucnt(offsetof(struct vmmeter, v_vnodepgsin)),
347 cpucnt(offsetof(struct vmmeter, v_vnodepgsout)),
348 cpucnt(offsetof(struct vmmeter, v_swappgsin)),
349 cpucnt(offsetof(struct vmmeter, v_swappgsout)),
350 cpucnt(offsetof(struct vmmeter, v_intr)),
351 cpucnt(offsetof(struct vmmeter, v_swtch)),
352 boottime.tv_sec);
353 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
357 linprocfs_douptime(struct proc *curp, struct proc *p, struct pfsnode *pfs,
358 struct uio *uio)
360 char *ps;
361 char psbuf[64];
362 struct timeval tv;
364 getmicrouptime(&tv);
365 ps = psbuf;
366 ps += ksprintf(ps, "%ld.%02ld %"PRIu64".%02"PRIu64"\n",
367 tv.tv_sec, tv.tv_usec / 10000,
368 T2S(cpu_time.cp_idle), T2J(cpu_time.cp_idle) % 100);
369 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
373 linprocfs_doversion(struct proc *curp, struct proc *p, struct pfsnode *pfs,
374 struct uio *uio)
376 char *ps;
377 size_t xlen;
379 ps = version; /* XXX not entirely correct */
380 for (xlen = 0; ps[xlen] != '\n'; ++xlen)
381 /* nothing */ ;
382 ++xlen;
383 return (uiomove_frombuf(ps, xlen, uio));
386 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
388 linprocfs_dostatm(struct proc *curp, struct proc *p, struct pfsnode *pfs,
389 struct uio *uio)
391 char *ps, psbuf[1024];
392 struct kinfo_proc kp;
394 fill_kinfo_proc(p, &kp);
396 ps = psbuf;
397 ps += ksprintf(ps, "%d", p->p_pid);
398 #define PS_ADD(name, fmt, arg) ps += ksprintf(ps, " " fmt, arg)
399 PS_ADD("", "%ju", B2P((uintmax_t)(kp.kp_vm_tsize + kp.kp_vm_dsize + kp.kp_vm_ssize)));
400 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_rssize);
401 PS_ADD("", "%ju", (uintmax_t)0); /* XXX */
402 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_tsize);
403 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_dsize);
404 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_ssize);
405 PS_ADD("", "%ju", (uintmax_t)0); /* XXX */
406 #undef PS_ADD
407 ps += ksprintf(ps, "\n");
409 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
412 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
414 linprocfs_doprocstat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
415 struct uio *uio)
417 vm_map_t map = &p->p_vmspace->vm_map;
418 vm_map_entry_t entry;
419 vm_offset_t start, end;
420 char *ps, psbuf[1024];
421 struct kinfo_proc kp;
423 fill_kinfo_proc(p, &kp);
425 start = 0;
426 end = 0;
427 vm_map_lock_read(map);
428 for (entry = map->header.next; entry != &map->header;
429 entry = entry->next) {
430 if (entry->maptype != VM_MAPTYPE_NORMAL &&
431 entry->maptype != VM_MAPTYPE_VPAGETABLE) {
432 continue;
434 /* Assuming that text is the first entry */
435 start = entry->start;
436 end = entry->end;
438 vm_map_unlock_read(map);
440 ps = psbuf;
441 ps += ksprintf(ps, "%d", p->p_pid);
442 #define PS_ADD(name, fmt, arg) ps += ksprintf(ps, " " fmt, arg)
443 PS_ADD("comm", "(%s)", p->p_comm);
444 PS_ADD("statr", "%c", '0'); /* XXX */
445 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
446 PS_ADD("pgrp", "%d", p->p_pgid);
447 PS_ADD("session", "%d", p->p_session->s_sid);
448 PS_ADD("tty", "%d", 0); /* XXX */
449 PS_ADD("tpgid", "%d", kp.kp_tpgid); /* XXX */
450 PS_ADD("flags", "%u", 0); /* XXX */
451 PS_ADD("minflt", "%lu", kp.kp_ru.ru_minflt); /* XXX */
452 PS_ADD("cminflt", "%lu", kp.kp_cru.ru_minflt); /* XXX */
453 PS_ADD("majflt", "%lu", kp.kp_ru.ru_majflt); /* XXX */
454 PS_ADD("cmajflt", "%lu", kp.kp_cru.ru_majflt); /* XXX */
455 PS_ADD("utime", "%d", T2J(tvtohz_high(&kp.kp_ru.ru_utime))); /* XXX */
456 PS_ADD("stime", "%d", T2J(tvtohz_high(&kp.kp_ru.ru_stime))); /* XXX */
457 PS_ADD("cutime", "%d", T2J(tvtohz_high(&kp.kp_cru.ru_utime))); /* XXX */
458 PS_ADD("cstime", "%d", T2J(tvtohz_high(&kp.kp_cru.ru_stime))); /* XXX */
459 PS_ADD("priority", "%d", 0); /* XXX */
460 PS_ADD("nice", "%d", kp.kp_nice);
461 PS_ADD("timeout", "%u", 0); /* XXX */
462 PS_ADD("itrealvalue", "%u", 0); /* XXX */
463 PS_ADD("starttime", "%d", T2J(tvtohz_high(&kp.kp_start))); /* XXX */
464 PS_ADD("vsize", "%ju", P2K((uintmax_t)(kp.kp_vm_tsize + kp.kp_vm_dsize + kp.kp_vm_ssize))); /* XXX: not sure */
465 PS_ADD("rss", "%ju", (uintmax_t)kp.kp_vm_rssize); /* XXX */
466 PS_ADD("rlim", "%lu", kp.kp_ru.ru_maxrss); /* XXX */
467 PS_ADD("startcode", "%lu", start); /* XXX */
468 PS_ADD("endcode", "%lu", end); /* XXX */
469 PS_ADD("startstack", "%lu", (u_long)p->p_vmspace->vm_minsaddr); /* XXX */
470 PS_ADD("kstkesp", "%u", 0); /* XXX */
471 PS_ADD("kstkeip", "%u", 0); /* XXX */
472 PS_ADD("signal", "%d", 0); /* XXX */
473 PS_ADD("blocked", "%d", 0); /* XXX */
474 PS_ADD("sigignore", "%d", 0); /* XXX */
475 PS_ADD("sigcatch", "%d", 0); /* XXX */
476 PS_ADD("wchan", "%u", 0); /* XXX */
477 PS_ADD("nswap", "%lu", kp.kp_ru.ru_nswap); /* XXX */
478 PS_ADD("cnswap", "%lu", kp.kp_cru.ru_nswap); /* XXX */
479 PS_ADD("exitsignal", "%d", 0); /* XXX */
480 PS_ADD("processor", "%u", kp.kp_lwp.kl_cpuid); /* XXX */
481 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
482 PS_ADD("policy", "%u", kp.kp_nice); /* XXX */ /* >= 2.5.19 */
483 #undef PS_ADD
484 ps += ksprintf(ps, "\n");
486 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
490 * Map process state to descriptive letter. Note that this does not
491 * quite correspond to what Linux outputs, but it's close enough.
493 static char *state_str[] = {
494 "? (unknown)",
495 "I (idle)",
496 "R (running)",
497 "T (stopped)",
498 "Z (zombie)",
499 "S (sleeping)",
500 "W (waiting)",
501 "M (mutex)"
505 linprocfs_doprocstatus(struct proc *curp, struct proc *p, struct pfsnode *pfs,
506 struct uio *uio)
508 char *ps, psbuf[1024];
509 char *state;
510 int i;
512 ps = psbuf;
514 if (p->p_stat > sizeof state_str / sizeof *state_str)
515 state = state_str[0];
516 else
517 state = state_str[(int)p->p_stat];
519 #define PS_ADD ps += ksprintf
520 PS_ADD(ps, "Name:\t%s\n", p->p_comm); /* XXX escape */
521 PS_ADD(ps, "State:\t%s\n", state);
524 * Credentials
526 PS_ADD(ps, "Pid:\t%d\n", p->p_pid);
527 PS_ADD(ps, "PPid:\t%d\n", p->p_pptr ? p->p_pptr->p_pid : 0);
528 PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
529 p->p_ucred->cr_uid,
530 p->p_ucred->cr_svuid,
531 /* FreeBSD doesn't have fsuid */
532 p->p_ucred->cr_uid);
533 PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
534 p->p_ucred->cr_gid,
535 p->p_ucred->cr_svgid,
536 /* FreeBSD doesn't have fsgid */
537 p->p_ucred->cr_gid);
538 PS_ADD(ps, "Groups:\t");
539 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
540 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
541 PS_ADD(ps, "\n");
544 * Memory
546 PS_ADD(ps, "VmSize:\t%8lu kB\n", B2K(p->p_vmspace->vm_map.size));
547 PS_ADD(ps, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
548 /* XXX vm_rssize seems to always be zero, how can this be? */
549 PS_ADD(ps, "VmRss:\t%8u kB\n", P2K(p->p_vmspace->vm_rssize));
550 PS_ADD(ps, "VmData:\t%8u kB\n", P2K(p->p_vmspace->vm_dsize));
551 PS_ADD(ps, "VmStk:\t%8u kB\n", P2K(p->p_vmspace->vm_ssize));
552 PS_ADD(ps, "VmExe:\t%8u kB\n", P2K(p->p_vmspace->vm_tsize));
553 PS_ADD(ps, "VmLib:\t%8u kB\n", P2K(0)); /* XXX */
556 * Signal masks
558 * We support up to 128 signals, while Linux supports 32,
559 * but we only define 32 (the same 32 as Linux, to boot), so
560 * just show the lower 32 bits of each mask. XXX hack.
562 * NB: on certain platforms (Sparc at least) Linux actually
563 * supports 64 signals, but this code is a long way from
564 * running on anything but i386, so ignore that for now.
566 PS_ADD(ps, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
567 PS_ADD(ps, "SigBlk:\t%08x\n", 0); /* XXX */
568 PS_ADD(ps, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]);
569 PS_ADD(ps, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]);
572 * Linux also prints the capability masks, but we don't have
573 * capabilities yet, and when we do get them they're likely to
574 * be meaningless to Linux programs, so we lie. XXX
576 PS_ADD(ps, "CapInh:\t%016x\n", 0);
577 PS_ADD(ps, "CapPrm:\t%016x\n", 0);
578 PS_ADD(ps, "CapEff:\t%016x\n", 0);
579 #undef PS_ADD
581 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
585 linprocfs_doloadavg(struct proc *curp, struct proc *p,
586 struct pfsnode *pfs, struct uio *uio)
588 char *ps, psbuf[512];
590 ps = psbuf;
591 ps += ksprintf(ps, "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
592 (int)(averunnable.ldavg[0] / averunnable.fscale),
593 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
594 (int)(averunnable.ldavg[1] / averunnable.fscale),
595 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
596 (int)(averunnable.ldavg[2] / averunnable.fscale),
597 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
598 1, /* number of running tasks */
599 -1, /* number of tasks */
600 1 /* The last pid, just kidding */
602 return(uiomove_frombuf(psbuf, ps - psbuf, uio));
606 linprocfs_donetdev(struct proc *curp, struct proc *p, struct pfsnode *pfs,
607 struct uio *uio)
609 struct sbuf *sb;
610 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
611 struct ifnet *ifp;
612 int error;
614 sb = sbuf_new_auto();
616 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
617 "Inter-", " Receive", " Transmit", " face",
618 "bytes packets errs drop fifo frame compressed",
619 "bytes packets errs drop fifo frame compressed");
621 crit_enter();
622 TAILQ_FOREACH(ifp, &ifnet, if_link) {
623 linux_ifname(ifp, ifname, sizeof ifname);
624 sbuf_printf(sb, "%6.6s:", ifname);
625 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
626 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
627 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
628 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
630 crit_exit();
631 sbuf_finish(sb);
632 error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
633 sbuf_delete(sb);
634 return (error);
638 linprocfs_dodevices(struct proc *curp, struct proc *p, struct pfsnode *pfs,
639 struct uio *uio)
641 return 0;
645 linprocfs_doosrelease(struct proc *curp, struct proc *p, struct pfsnode *pfs,
646 struct uio *uio)
648 char *osrelease;
650 osrelease = linux_get_osrelease(curthread);
651 return(uiomove_frombuf(osrelease, strlen(osrelease)+1, uio));
655 linprocfs_doostype(struct proc *curp, struct proc *p, struct pfsnode *pfs,
656 struct uio *uio)
658 char *osname;
660 osname = linux_get_osname(curthread);
661 return(uiomove_frombuf(osname, strlen(osname)+1, uio));
665 linprocfs_dopidmax(struct proc *curp, struct proc *p, struct pfsnode *pfs,
666 struct uio *uio)
668 char buf[32];
670 ksnprintf(buf, sizeof(buf), "%d", PID_MAX);
671 return(uiomove_frombuf(buf, strlen(buf)+1, uio));
672 return 0;
676 linprocfs_domaps(struct proc *curp, struct proc *p, struct pfsnode *pfs,
677 struct uio *uio)
679 int len;
680 int error;
681 vm_map_t map = &p->p_vmspace->vm_map;
682 vm_map_entry_t entry;
683 vm_ooffset_t off = 0;
684 char mebuffer[256];
685 char *name = "", *freename = NULL;
686 struct vnode *vp;
687 struct vattr vat;
688 int major, minor;
689 ino_t ino;
691 if (uio->uio_rw != UIO_READ)
692 return (EOPNOTSUPP);
694 if (uio->uio_offset != 0)
695 return (0);
697 error = 0;
698 vm_map_lock_read(map);
699 for (entry = map->header.next;
700 ((uio->uio_resid > 0) && (entry != &map->header));
701 entry = entry->next) {
702 vm_object_t obj, tobj, lobj;
703 vm_offset_t ostart;
704 name = "";
705 freename = NULL;
706 ino = 0;
707 if (entry->maptype != VM_MAPTYPE_NORMAL &&
708 entry->maptype != VM_MAPTYPE_VPAGETABLE) {
709 continue;
712 * Use map->hint as a poor man's ripout detector.
714 map->hint = entry;
715 ostart = entry->start;
716 obj = entry->object.vm_object;
718 for( lobj = tobj = obj; tobj; tobj = tobj->backing_object)
719 lobj = tobj;
721 if (lobj) {
722 off = IDX_TO_OFF(lobj->size);
723 if (lobj->type == OBJT_VNODE) {
724 vp = lobj->handle;
725 if (vp)
726 vref(vp);
727 } else {
728 vp = NULL;
731 if (vp) {
732 vn_fullpath(curproc, vp, &name, &freename);
733 vn_lock(vp, LK_SHARED | LK_RETRY);
734 VOP_GETATTR(vp, &vat);
735 ino = vat.va_fileid;
736 major = vat.va_rmajor;
737 minor = vat.va_rminor;
738 vput(vp);
741 if (freename == NULL) {
742 if (entry->eflags & MAP_ENTRY_STACK)
743 name = "[stack]";
747 * format:
748 * start-end access offset major:minor inode [.text file]
750 ksnprintf(mebuffer, sizeof(mebuffer),
751 "%08lx-%08lx %s%s%s%s %08llx %02x:%02x %llu%s%s\n",
752 (u_long)entry->start, (u_long)entry->end,
753 (entry->protection & VM_PROT_READ)?"r":"-",
754 (entry->protection & VM_PROT_WRITE)?"w":"-",
755 (entry->protection & VM_PROT_EXECUTE)?"x":"-",
756 "p",
757 off, /* offset */
758 0, /* major */
759 0, /* minor */
760 ino, /* inode */
761 *name ? " " : "",
762 name);
764 if (freename)
765 kfree(freename, M_TEMP);
767 len = strlen(mebuffer);
768 if (len > uio->uio_resid) {
769 error = EFBIG;
770 break;
774 * We cannot safely hold the map locked while accessing
775 * userspace as a VM fault might recurse the locked map.
777 vm_map_unlock_read(map);
778 error = uiomove(mebuffer, len, uio);
779 vm_map_lock_read(map);
780 if (error)
781 break;
784 * We use map->hint as a poor man's ripout detector. If
785 * it does not match the entry we set it to prior to
786 * unlocking the map the entry MIGHT now be stale. In
787 * this case we do an expensive lookup to find our place
788 * in the iteration again.
790 if (map->hint != entry) {
791 vm_map_entry_t reentry;
793 vm_map_lookup_entry(map, ostart, &reentry);
794 entry = reentry;
797 vm_map_unlock_read(map);
799 return error;