linux emulation - Major update
[dragonfly.git] / sys / emulation / linux / i386 / linprocfs / linprocfs_misc.c
blob6aa0591be7d6908040512cb8f9ff414e54263964
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>
58 #include <vm/vm.h>
59 #include <vm/pmap.h>
60 #include <vm/vm_map.h>
61 #include <vm/vm_param.h>
62 #include <vm/vm_object.h>
63 #include <vm/swap_pager.h>
64 #include <sys/vmmeter.h>
65 #include <sys/exec.h>
67 #include <machine/clock.h>
68 #include <machine/cputypes.h>
69 #include <machine/inttypes.h>
70 #include <machine/md_var.h>
71 #include <machine/vmparam.h>
73 #include "linprocfs.h"
74 #include "../linux.h"
75 #include "../../linux_ioctl.h"
76 #include "../../linux_mib.h"
79 * Various conversion macros
81 #define T2J(x) (((x) * 100) / (stathz ? stathz : hz)) /* ticks to jiffies */
82 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
83 #define B2K(x) ((unsigned long)((x) >> 10)) /* bytes to kbytes */
84 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
85 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
87 int
88 linprocfs_domeminfo(struct proc *curp, struct proc *p, struct pfsnode *pfs,
89 struct uio *uio)
91 char *ps;
92 char psbuf[512]; /* XXX - conservative */
93 unsigned long memtotal; /* total memory in bytes */
94 unsigned long memused; /* used memory in bytes */
95 unsigned long memfree; /* free memory in bytes */
96 unsigned long memshared; /* shared memory ??? */
97 unsigned long buffers, cached; /* buffer / cache memory ??? */
98 unsigned long long swaptotal; /* total swap space in bytes */
99 unsigned long long swapused; /* used swap space in bytes */
100 unsigned long long swapfree; /* free swap space in bytes */
101 vm_object_t object;
103 if (uio->uio_rw != UIO_READ)
104 return (EOPNOTSUPP);
106 memtotal = Maxmem * PAGE_SIZE;
108 * The correct thing here would be:
110 memfree = vmstats.v_free_count * PAGE_SIZE;
111 memused = memtotal - memfree;
113 * but it might mislead linux binaries into thinking there
114 * is very little memory left, so we cheat and tell them that
115 * all memory that isn't wired down is free.
117 memused = vmstats.v_wire_count * PAGE_SIZE;
118 memfree = memtotal - memused;
119 if (swapblist == NULL) {
120 swaptotal = 0;
121 swapfree = 0;
122 } else {
123 swaptotal = swapblist->bl_blocks * 1024LL; /* XXX why 1024? */
124 swapfree = (unsigned long long)swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
126 swapused = swaptotal - swapfree;
127 memshared = 0;
128 for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
129 object = TAILQ_NEXT(object, object_list)) {
130 if (object->type == OBJT_MARKER)
131 continue;
132 if (object->shadow_count > 1)
133 memshared += object->resident_page_count;
135 memshared *= PAGE_SIZE;
137 * We'd love to be able to write:
139 buffers = bufspace;
141 * but bufspace is internal to vfs_bio.c and we don't feel
142 * like unstaticizing it just for linprocfs's sake.
144 buffers = 0;
145 cached = vmstats.v_cache_count * PAGE_SIZE;
147 ps = psbuf;
148 ps += ksprintf(ps,
149 " total: used: free: shared: buffers: cached:\n"
150 "Mem: %lu %lu %lu %lu %lu %lu\n"
151 "Swap: %llu %llu %llu\n"
152 "MemTotal: %9lu kB\n"
153 "MemFree: %9lu kB\n"
154 "MemShared:%9lu kB\n"
155 "Buffers: %9lu kB\n"
156 "Cached: %9lu kB\n"
157 "SwapTotal:%9lu kB\n"
158 "SwapFree: %9lu kB\n",
159 memtotal, memused, memfree, memshared, buffers, cached,
160 swaptotal, swapused, swapfree,
161 B2K(memtotal), B2K(memfree),
162 B2K(memshared), B2K(buffers), B2K(cached),
163 B2K(swaptotal), B2K(swapfree));
165 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
169 linprocfs_docpuinfo(struct proc *curp, struct proc *p, struct pfsnode *pfs,
170 struct uio *uio)
172 char *ps;
173 char psbuf[512]; /* XXX - conservative */
174 int class;
175 int i;
176 #if 0
177 extern char *cpu_model; /* Yuck */
178 #endif
179 /* We default the flags to include all non-conflicting flags,
180 and the Intel versions of conflicting flags. Note the space
181 before each name; that is significant, and should be
182 preserved. */
184 static char *flags[] = {
185 "fpu", "vme", "de", "pse", "tsc",
186 "msr", "pae", "mce", "cx8", "apic",
187 "sep", "sep", "mtrr", "pge", "mca",
188 "cmov", "pat", "pse36", "pn", "b19",
189 "b20", "b21", "mmxext", "mmx", "fxsr",
190 "xmm", "b26", "b27", "b28", "b29",
191 "3dnowext", "3dnow"
194 if (uio->uio_rw != UIO_READ)
195 return (EOPNOTSUPP);
197 switch (cpu_class) {
198 case CPUCLASS_286:
199 class = 2;
200 break;
201 case CPUCLASS_386:
202 class = 3;
203 break;
204 case CPUCLASS_486:
205 class = 4;
206 break;
207 case CPUCLASS_586:
208 class = 5;
209 break;
210 case CPUCLASS_686:
211 class = 6;
212 break;
213 default:
214 class = 0;
215 break;
218 ps = psbuf;
219 ps += ksprintf(ps,
220 "processor\t: %d\n"
221 "vendor_id\t: %.20s\n"
222 "cpu family\t: %d\n"
223 "model\t\t: %d\n"
224 "stepping\t: %d\n",
225 0, cpu_vendor, class, cpu, cpu_id & 0xf);
227 ps += ksprintf(ps,
228 "flags\t\t:");
230 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
231 flags[16] = "fcmov";
232 } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
233 flags[24] = "cxmmx";
236 for (i = 0; i < 32; i++)
237 if (cpu_feature & (1 << i))
238 ps += ksprintf(ps, " %s", flags[i]);
239 ps += ksprintf(ps, "\n");
240 if (class >= 5) {
241 ps += ksprintf(ps,
242 "cpu MHz\t\t: %d.%02d\n"
243 "bogomips\t: %d.%02d\n",
244 (int)((tsc_frequency + 4999) / 1000000),
245 (int)((tsc_frequency + 4999) / 10000) % 100,
246 (int)((tsc_frequency + 4999) / 1000000),
247 (int)((tsc_frequency + 4999) / 10000) % 100);
250 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
253 static unsigned int
254 cpucnt(int offset)
256 int i;
257 int count = 0;
259 for (i = 0; i < ncpus; ++i) {
260 struct globaldata *gd = globaldata_find(i);
261 count += *(unsigned int *)((char *)&gd->gd_cnt + offset);
263 return(count);
267 linprocfs_dostat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
268 struct uio *uio)
270 char *ps;
271 char psbuf[512];
273 ps = psbuf;
274 ps += ksprintf(ps,
275 "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n"
276 "disk 0 0 0 0\n"
277 "page %u %u\n"
278 "swap %u %u\n"
279 "intr %u\n"
280 "ctxt %u\n"
281 "btime %ld\n",
282 T2J(cpu_time.cp_user),
283 T2J(cpu_time.cp_nice),
284 T2J(cpu_time.cp_sys /*+ cpu_time[CP_INTR]*/),
285 T2J(cpu_time.cp_idle),
286 cpucnt(offsetof(struct vmmeter, v_vnodepgsin)),
287 cpucnt(offsetof(struct vmmeter, v_vnodepgsout)),
288 cpucnt(offsetof(struct vmmeter, v_swappgsin)),
289 cpucnt(offsetof(struct vmmeter, v_swappgsout)),
290 cpucnt(offsetof(struct vmmeter, v_intr)),
291 cpucnt(offsetof(struct vmmeter, v_swtch)),
292 boottime.tv_sec);
293 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
297 linprocfs_douptime(struct proc *curp, struct proc *p, struct pfsnode *pfs,
298 struct uio *uio)
300 char *ps;
301 char psbuf[64];
302 struct timeval tv;
304 getmicrouptime(&tv);
305 ps = psbuf;
306 ps += ksprintf(ps, "%ld.%02ld %"PRIu64".%02"PRIu64"\n",
307 tv.tv_sec, tv.tv_usec / 10000,
308 T2S(cpu_time.cp_idle), T2J(cpu_time.cp_idle) % 100);
309 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
313 linprocfs_doversion(struct proc *curp, struct proc *p, struct pfsnode *pfs,
314 struct uio *uio)
316 char *ps;
317 size_t xlen;
319 ps = version; /* XXX not entirely correct */
320 for (xlen = 0; ps[xlen] != '\n'; ++xlen)
321 /* nothing */ ;
322 ++xlen;
323 return (uiomove_frombuf(ps, xlen, uio));
326 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
328 linprocfs_dostatm(struct proc *curp, struct proc *p, struct pfsnode *pfs,
329 struct uio *uio)
331 char *ps, psbuf[1024];
332 struct kinfo_proc kp;
334 fill_kinfo_proc(p, &kp);
336 ps = psbuf;
337 ps += ksprintf(ps, "%d", p->p_pid);
338 #define PS_ADD(name, fmt, arg) ps += ksprintf(ps, " " fmt, arg)
339 PS_ADD("", "%ju", B2P((uintmax_t)(kp.kp_vm_tsize + kp.kp_vm_dsize + kp.kp_vm_ssize)));
340 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_rssize);
341 PS_ADD("", "%ju", (uintmax_t)0); /* XXX */
342 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_tsize);
343 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_dsize);
344 PS_ADD("", "%ju", (uintmax_t)kp.kp_vm_ssize);
345 PS_ADD("", "%ju", (uintmax_t)0); /* XXX */
346 #undef PS_ADD
347 ps += ksprintf(ps, "\n");
349 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
352 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
354 linprocfs_doprocstat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
355 struct uio *uio)
357 vm_map_t map = &p->p_vmspace->vm_map;
358 vm_map_entry_t entry;
359 vm_offset_t start, end;
360 char *ps, psbuf[1024];
361 struct kinfo_proc kp;
363 fill_kinfo_proc(p, &kp);
365 start = 0;
366 end = 0;
367 vm_map_lock_read(map);
368 for (entry = map->header.next; entry != &map->header;
369 entry = entry->next) {
370 if (entry->maptype != VM_MAPTYPE_NORMAL &&
371 entry->maptype != VM_MAPTYPE_VPAGETABLE) {
372 continue;
374 /* Assuming that text is the first entry */
375 start = entry->start;
376 end = entry->end;
378 vm_map_unlock_read(map);
380 ps = psbuf;
381 ps += ksprintf(ps, "%d", p->p_pid);
382 #define PS_ADD(name, fmt, arg) ps += ksprintf(ps, " " fmt, arg)
383 PS_ADD("comm", "(%s)", p->p_comm);
384 PS_ADD("statr", "%c", '0'); /* XXX */
385 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
386 PS_ADD("pgrp", "%d", p->p_pgid);
387 PS_ADD("session", "%d", p->p_session->s_sid);
388 PS_ADD("tty", "%d", 0); /* XXX */
389 PS_ADD("tpgid", "%d", kp.kp_tpgid); /* XXX */
390 PS_ADD("flags", "%u", 0); /* XXX */
391 PS_ADD("minflt", "%lu", kp.kp_ru.ru_minflt); /* XXX */
392 PS_ADD("cminflt", "%lu", kp.kp_cru.ru_minflt); /* XXX */
393 PS_ADD("majflt", "%lu", kp.kp_ru.ru_majflt); /* XXX */
394 PS_ADD("cmajflt", "%lu", kp.kp_cru.ru_majflt); /* XXX */
395 PS_ADD("utime", "%d", T2J(tvtohz_high(&kp.kp_ru.ru_utime))); /* XXX */
396 PS_ADD("stime", "%d", T2J(tvtohz_high(&kp.kp_ru.ru_stime))); /* XXX */
397 PS_ADD("cutime", "%d", T2J(tvtohz_high(&kp.kp_cru.ru_utime))); /* XXX */
398 PS_ADD("cstime", "%d", T2J(tvtohz_high(&kp.kp_cru.ru_stime))); /* XXX */
399 PS_ADD("priority", "%d", 0); /* XXX */
400 PS_ADD("nice", "%d", kp.kp_nice);
401 PS_ADD("timeout", "%u", 0); /* XXX */
402 PS_ADD("itrealvalue", "%u", 0); /* XXX */
403 PS_ADD("starttime", "%d", T2J(tvtohz_high(&kp.kp_start))); /* XXX */
404 PS_ADD("vsize", "%ju", P2K((uintmax_t)(kp.kp_vm_tsize + kp.kp_vm_dsize + kp.kp_vm_ssize))); /* XXX: not sure */
405 PS_ADD("rss", "%ju", (uintmax_t)kp.kp_vm_rssize); /* XXX */
406 PS_ADD("rlim", "%lu", kp.kp_ru.ru_maxrss); /* XXX */
407 PS_ADD("startcode", "%lu", start); /* XXX */
408 PS_ADD("endcode", "%lu", end); /* XXX */
409 PS_ADD("startstack", "%lu", (u_long)p->p_vmspace->vm_minsaddr); /* XXX */
410 PS_ADD("kstkesp", "%u", 0); /* XXX */
411 PS_ADD("kstkeip", "%u", 0); /* XXX */
412 PS_ADD("signal", "%d", 0); /* XXX */
413 PS_ADD("blocked", "%d", 0); /* XXX */
414 PS_ADD("sigignore", "%d", 0); /* XXX */
415 PS_ADD("sigcatch", "%d", 0); /* XXX */
416 PS_ADD("wchan", "%u", 0); /* XXX */
417 PS_ADD("nswap", "%lu", kp.kp_ru.ru_nswap); /* XXX */
418 PS_ADD("cnswap", "%lu", kp.kp_cru.ru_nswap); /* XXX */
419 PS_ADD("exitsignal", "%d", 0); /* XXX */
420 PS_ADD("processor", "%u", kp.kp_lwp.kl_cpuid); /* XXX */
421 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
422 PS_ADD("policy", "%u", kp.kp_nice); /* XXX */ /* >= 2.5.19 */
423 #undef PS_ADD
424 ps += ksprintf(ps, "\n");
426 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
430 * Map process state to descriptive letter. Note that this does not
431 * quite correspond to what Linux outputs, but it's close enough.
433 static char *state_str[] = {
434 "? (unknown)",
435 "I (idle)",
436 "R (running)",
437 "T (stopped)",
438 "Z (zombie)",
439 "S (sleeping)",
440 "W (waiting)",
441 "M (mutex)"
445 linprocfs_doprocstatus(struct proc *curp, struct proc *p, struct pfsnode *pfs,
446 struct uio *uio)
448 char *ps, psbuf[1024];
449 char *state;
450 int i;
452 ps = psbuf;
454 if (p->p_stat > sizeof state_str / sizeof *state_str)
455 state = state_str[0];
456 else
457 state = state_str[(int)p->p_stat];
459 #define PS_ADD ps += ksprintf
460 PS_ADD(ps, "Name:\t%s\n", p->p_comm); /* XXX escape */
461 PS_ADD(ps, "State:\t%s\n", state);
464 * Credentials
466 PS_ADD(ps, "Pid:\t%d\n", p->p_pid);
467 PS_ADD(ps, "PPid:\t%d\n", p->p_pptr ? p->p_pptr->p_pid : 0);
468 PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
469 p->p_ucred->cr_uid,
470 p->p_ucred->cr_svuid,
471 /* FreeBSD doesn't have fsuid */
472 p->p_ucred->cr_uid);
473 PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
474 p->p_ucred->cr_gid,
475 p->p_ucred->cr_svgid,
476 /* FreeBSD doesn't have fsgid */
477 p->p_ucred->cr_gid);
478 PS_ADD(ps, "Groups:\t");
479 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
480 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
481 PS_ADD(ps, "\n");
484 * Memory
486 PS_ADD(ps, "VmSize:\t%8lu kB\n", B2K(p->p_vmspace->vm_map.size));
487 PS_ADD(ps, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
488 /* XXX vm_rssize seems to always be zero, how can this be? */
489 PS_ADD(ps, "VmRss:\t%8u kB\n", P2K(p->p_vmspace->vm_rssize));
490 PS_ADD(ps, "VmData:\t%8u kB\n", P2K(p->p_vmspace->vm_dsize));
491 PS_ADD(ps, "VmStk:\t%8u kB\n", P2K(p->p_vmspace->vm_ssize));
492 PS_ADD(ps, "VmExe:\t%8u kB\n", P2K(p->p_vmspace->vm_tsize));
493 PS_ADD(ps, "VmLib:\t%8u kB\n", P2K(0)); /* XXX */
496 * Signal masks
498 * We support up to 128 signals, while Linux supports 32,
499 * but we only define 32 (the same 32 as Linux, to boot), so
500 * just show the lower 32 bits of each mask. XXX hack.
502 * NB: on certain platforms (Sparc at least) Linux actually
503 * supports 64 signals, but this code is a long way from
504 * running on anything but i386, so ignore that for now.
506 PS_ADD(ps, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
507 PS_ADD(ps, "SigBlk:\t%08x\n", 0); /* XXX */
508 PS_ADD(ps, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]);
509 PS_ADD(ps, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]);
512 * Linux also prints the capability masks, but we don't have
513 * capabilities yet, and when we do get them they're likely to
514 * be meaningless to Linux programs, so we lie. XXX
516 PS_ADD(ps, "CapInh:\t%016x\n", 0);
517 PS_ADD(ps, "CapPrm:\t%016x\n", 0);
518 PS_ADD(ps, "CapEff:\t%016x\n", 0);
519 #undef PS_ADD
521 return (uiomove_frombuf(psbuf, ps - psbuf, uio));
525 linprocfs_doloadavg(struct proc *curp, struct proc *p,
526 struct pfsnode *pfs, struct uio *uio)
528 char *ps, psbuf[512];
530 ps = psbuf;
531 ps += ksprintf(ps, "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
532 (int)(averunnable.ldavg[0] / averunnable.fscale),
533 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
534 (int)(averunnable.ldavg[1] / averunnable.fscale),
535 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
536 (int)(averunnable.ldavg[2] / averunnable.fscale),
537 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
538 1, /* number of running tasks */
539 -1, /* number of tasks */
540 1 /* The last pid, just kidding */
542 return(uiomove_frombuf(psbuf, ps - psbuf, uio));
546 linprocfs_donetdev(struct proc *curp, struct proc *p, struct pfsnode *pfs,
547 struct uio *uio)
549 struct sbuf *sb;
550 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
551 struct ifnet *ifp;
552 int error;
554 sb = sbuf_new_auto();
556 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
557 "Inter-", " Receive", " Transmit", " face",
558 "bytes packets errs drop fifo frame compressed",
559 "bytes packets errs drop fifo frame compressed");
561 crit_enter();
562 TAILQ_FOREACH(ifp, &ifnet, if_link) {
563 linux_ifname(ifp, ifname, sizeof ifname);
564 sbuf_printf(sb, "%6.6s:", ifname);
565 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
566 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
567 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
568 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
570 crit_exit();
571 sbuf_finish(sb);
572 error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
573 sbuf_delete(sb);
574 return (error);
578 linprocfs_dodevices(struct proc *curp, struct proc *p, struct pfsnode *pfs,
579 struct uio *uio)
581 return 0;
585 linprocfs_doosrelease(struct proc *curp, struct proc *p, struct pfsnode *pfs,
586 struct uio *uio)
588 char *osrelease;
590 osrelease = linux_get_osrelease(curthread);
591 return(uiomove_frombuf(osrelease, strlen(osrelease)+1, uio));
595 linprocfs_doostype(struct proc *curp, struct proc *p, struct pfsnode *pfs,
596 struct uio *uio)
598 char *osname;
600 osname = linux_get_osname(curthread);
601 return(uiomove_frombuf(osname, strlen(osname)+1, uio));
605 linprocfs_dopidmax(struct proc *curp, struct proc *p, struct pfsnode *pfs,
606 struct uio *uio)
608 char buf[32];
610 ksnprintf(buf, sizeof(buf), "%d", PID_MAX);
611 return(uiomove_frombuf(buf, strlen(buf)+1, uio));
612 return 0;
616 linprocfs_domaps(struct proc *curp, struct proc *p, struct pfsnode *pfs,
617 struct uio *uio)
619 int len;
620 int error;
621 vm_map_t map = &p->p_vmspace->vm_map;
622 vm_map_entry_t entry;
623 vm_ooffset_t off = 0;
624 char mebuffer[256];
625 char *name = "", *freename = NULL;
626 struct vnode *vp;
627 struct vattr vat;
628 int major, minor;
629 ino_t ino;
631 if (uio->uio_rw != UIO_READ)
632 return (EOPNOTSUPP);
634 if (uio->uio_offset != 0)
635 return (0);
637 error = 0;
638 vm_map_lock_read(map);
639 for (entry = map->header.next;
640 ((uio->uio_resid > 0) && (entry != &map->header));
641 entry = entry->next) {
642 vm_object_t obj, tobj, lobj;
643 vm_offset_t ostart;
644 name = "";
645 freename = NULL;
646 ino = 0;
647 if (entry->maptype != VM_MAPTYPE_NORMAL &&
648 entry->maptype != VM_MAPTYPE_VPAGETABLE) {
649 continue;
652 * Use map->hint as a poor man's ripout detector.
654 map->hint = entry;
655 ostart = entry->start;
656 obj = entry->object.vm_object;
658 for( lobj = tobj = obj; tobj; tobj = tobj->backing_object)
659 lobj = tobj;
661 if (lobj) {
662 off = IDX_TO_OFF(lobj->size);
663 if (lobj->type == OBJT_VNODE) {
664 vp = lobj->handle;
665 if (vp)
666 vref(vp);
667 } else {
668 vp = NULL;
671 if (vp) {
672 vn_fullpath(curproc, vp, &name, &freename);
673 vn_lock(vp, LK_SHARED | LK_RETRY);
674 VOP_GETATTR(vp, &vat);
675 ino = vat.va_fileid;
676 major = vat.va_rmajor;
677 minor = vat.va_rminor;
678 vput(vp);
681 if (freename == NULL) {
682 if (entry->eflags & MAP_ENTRY_STACK)
683 name = "[stack]";
687 * format:
688 * start-end access offset major:minor inode [.text file]
690 ksnprintf(mebuffer, sizeof(mebuffer),
691 "%08lx-%08lx %s%s%s%s %08llx %02x:%02x %llu%s%s\n",
692 (u_long)entry->start, (u_long)entry->end,
693 (entry->protection & VM_PROT_READ)?"r":"-",
694 (entry->protection & VM_PROT_WRITE)?"w":"-",
695 (entry->protection & VM_PROT_EXECUTE)?"x":"-",
696 "p",
697 off, /* offset */
698 0, /* major */
699 0, /* minor */
700 ino, /* inode */
701 *name ? " " : "",
702 name);
704 if (freename)
705 kfree(freename, M_TEMP);
707 len = strlen(mebuffer);
708 if (len > uio->uio_resid) {
709 error = EFBIG;
710 break;
714 * We cannot safely hold the map locked while accessing
715 * userspace as a VM fault might recurse the locked map.
717 vm_map_unlock_read(map);
718 error = uiomove(mebuffer, len, uio);
719 vm_map_lock_read(map);
720 if (error)
721 break;
724 * We use map->hint as a poor man's ripout detector. If
725 * it does not match the entry we set it to prior to
726 * unlocking the map the entry MIGHT now be stale. In
727 * this case we do an expensive lookup to find our place
728 * in the iteration again.
730 if (map->hint != entry) {
731 vm_map_entry_t reentry;
733 vm_map_lookup_entry(map, ostart, &reentry);
734 entry = reentry;
737 vm_map_unlock_read(map);
739 return error;