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