Merge branch 'master' into net80211-update
[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  * $DragonFly: src/sys/emulation/linux/i386/linprocfs/linprocfs_misc.c,v 1.19 2008/05/10 17:24:05 dillon Exp $
43  */
44
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>
58 #include <sys/sysctl.h>
59
60 #include <vm/vm.h>
61 #include <vm/pmap.h>
62 #include <vm/vm_map.h>
63 #include <vm/vm_param.h>
64 #include <vm/vm_object.h>
65 #include <vm/swap_pager.h>
66 #include <sys/vmmeter.h>
67 #include <sys/exec.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         vm_object_t object;
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         for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
131             object = TAILQ_NEXT(object, object_list)) {
132                 if (object->type == OBJT_MARKER)
133                         continue;
134                 if (object->shadow_count > 1)
135                         memshared += object->resident_page_count;
136         }
137         memshared *= PAGE_SIZE;
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 (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
246                 flags[16] = "fcmov";
247         } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
248                 flags[24] = "cxmmx";
249         }
250         
251         for (i = 0; i < 32; i++)
252                 if (cpu_feature & (1 << i))
253                         ps += ksprintf(ps, " %s", flags[i]);
254         ps += ksprintf(ps, "\n");
255         if (class >= 5) {
256                 ps += ksprintf(ps,
257                         "cpu MHz\t\t: %d.%02d\n"
258                         "bogomips\t: %d.%02d\n",
259                         (int)((tsc_frequency + 4999) / 1000000),
260                         (int)((tsc_frequency + 4999) / 10000) % 100,
261                         (int)((tsc_frequency + 4999) / 1000000),
262                         (int)((tsc_frequency + 4999) / 10000) % 100);
263         }
264         
265         return (uiomove_frombuf(psbuf, ps - psbuf, uio));
266 }
267
268 static unsigned int
269 cpucnt(int offset)
270 {
271     int i;
272     int count = 0;
273
274     for (i = 0; i < ncpus; ++i) {
275         struct globaldata *gd = globaldata_find(i);
276         count += *(unsigned int *)((char *)&gd->gd_cnt + offset);
277     }
278     return(count);
279 }
280
281 static int
282 linprocfs_domounts_callback(struct mount *mp, void *data)
283 {
284         struct statfs *st;
285         struct sbuf *sb = (struct sbuf *)data;
286         char *to, *from, *fs;
287
288         st = &mp->mnt_stat;
289
290         from = st->f_mntfromname;
291         to = st->f_mntonname;
292         fs = st->f_fstypename;
293
294         if (!strcmp(st->f_fstypename, "linprocfs"))
295                 fs = "proc";
296         else if (!strcmp(st->f_fstypename, "ext2fs"))
297                 fs = "ext2";
298         else if (!strcmp(st->f_fstypename, "msdos"))
299                 fs = "vfat";
300         else if (!strcmp(st->f_fstypename, "msdosfs"))
301                 fs = "vfat";
302
303         sbuf_printf(sb, "%s %s %s %s", from, to, fs,
304             st->f_flags & MNT_RDONLY ? "ro" : "rw");
305
306 #define OPT_ADD(name, flag) if (st->f_flags & (flag)) sbuf_printf(sb, "," name)
307         OPT_ADD("sync",         MNT_SYNCHRONOUS);
308         OPT_ADD("noexec",       MNT_NOEXEC);
309         OPT_ADD("nosuid",       MNT_NOSUID);
310         OPT_ADD("nodev",        MNT_NODEV);
311         OPT_ADD("async",        MNT_ASYNC);
312         OPT_ADD("suiddir",      MNT_SUIDDIR);
313         OPT_ADD("nosymfollow",  MNT_NOSYMFOLLOW);
314         OPT_ADD("noatime",      MNT_NOATIME);
315 #undef OPT_ADD
316
317         sbuf_printf(sb, " 0 0\n");
318
319         return 0;
320 }
321
322 int
323 linprocfs_domounts(struct proc *curp, struct proc *p, struct pfsnode *pfs,
324                     struct uio *uio)
325 {
326         struct sbuf *sb;
327         int error;
328
329         sb = sbuf_new_auto();
330
331         error = mountlist_scan(linprocfs_domounts_callback, sb, MNTSCAN_FORWARD);
332
333         sbuf_finish(sb);
334         if (error == 0)
335                 error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
336         sbuf_delete(sb);
337         return (error);
338 }
339
340 int
341 linprocfs_dostat(struct proc *curp, struct proc *p, struct pfsnode *pfs,
342                  struct uio *uio)
343 {
344         char *ps;
345         char psbuf[8192];
346         int cpu;
347
348         ps = psbuf;
349         ps += ksprintf(ps,
350                       "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n",
351                       T2J(cpu_time.cp_user),
352                       T2J(cpu_time.cp_nice),
353                       T2J(cpu_time.cp_sys),
354                       T2J(cpu_time.cp_idle));
355
356         for (cpu = 0; cpu < ncpus; cpu++) {
357                 ps += ksprintf(ps,
358                       "cpu%d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n",
359                       cpu,
360                       T2J(cputime_percpu[cpu].cp_user),
361                       T2J(cputime_percpu[cpu].cp_nice),
362                       T2J(cputime_percpu[cpu].cp_sys),
363                       T2J(cputime_percpu[cpu].cp_idle));                        
364         }
365
366         ps += ksprintf(ps,
367                       "disk 0 0 0 0\n"
368                       "page %u %u\n"
369                       "swap %u %u\n"
370                       "intr %u\n"
371                       "ctxt %u\n"
372                       "btime %ld\n",
373                       cpucnt(offsetof(struct vmmeter, v_vnodepgsin)),
374                       cpucnt(offsetof(struct vmmeter, v_vnodepgsout)),
375                       cpucnt(offsetof(struct vmmeter, v_swappgsin)),
376                       cpucnt(offsetof(struct vmmeter, v_swappgsout)),
377                       cpucnt(offsetof(struct vmmeter, v_intr)),
378                       cpucnt(offsetof(struct vmmeter, v_swtch)),
379                       boottime.tv_sec);
380
381         return (uiomove_frombuf(psbuf, ps - psbuf, uio));
382 }
383
384 int
385 linprocfs_douptime(struct proc *curp, struct proc *p, struct pfsnode *pfs,
386                    struct uio *uio)
387 {
388         char *ps;
389         char psbuf[64];
390         struct timeval tv;
391
392         getmicrouptime(&tv);
393         ps = psbuf;
394         ps += ksprintf(ps, "%ld.%02ld %"PRIu64".%02"PRIu64"\n",
395                       tv.tv_sec, tv.tv_usec / 10000,
396                       T2S(cpu_time.cp_idle), T2J(cpu_time.cp_idle) % 100);
397         return (uiomove_frombuf(psbuf, ps - psbuf, uio));
398 }
399
400 int
401 linprocfs_doversion(struct proc *curp, struct proc *p, struct pfsnode *pfs,
402                     struct uio *uio)
403 {
404         char *ps;
405         size_t xlen;
406
407         ps = version; /* XXX not entirely correct */
408         for (xlen = 0; ps[xlen] != '\n'; ++xlen)
409                 /* nothing */ ;
410         ++xlen;
411         return (uiomove_frombuf(ps, xlen, uio));
412 }
413
414 #define B2P(x) ((x) >> PAGE_SHIFT)                      /* bytes to pages */
415 int
416 linprocfs_dostatm(struct proc *curp, struct proc *p, struct pfsnode *pfs,
417                     struct uio *uio)
418 {
419         char *ps, psbuf[1024];
420         struct kinfo_proc kp;
421
422         fill_kinfo_proc(p, &kp);
423
424         ps = psbuf;
425         ps += ksprintf(ps, "%d", p->p_pid);
426 #define PS_ADD(name, fmt, arg) ps += ksprintf(ps, " " fmt, arg)
427         PS_ADD("",      "%ju",  B2P((uintmax_t)(kp.kp_vm_tsize + kp.kp_vm_dsize + kp.kp_vm_ssize)));
428         PS_ADD("",      "%ju",  (uintmax_t)kp.kp_vm_rssize);
429         PS_ADD("",      "%ju",  (uintmax_t)0); /* XXX */
430         PS_ADD("",      "%ju",  (uintmax_t)kp.kp_vm_tsize);
431         PS_ADD("",      "%ju",  (uintmax_t)kp.kp_vm_dsize);
432         PS_ADD("",      "%ju",  (uintmax_t)kp.kp_vm_ssize);
433         PS_ADD("",      "%ju",  (uintmax_t)0); /* XXX */
434 #undef  PS_ADD
435         ps += ksprintf(ps, "\n");
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         fill_kinfo_proc(p, &kp);
452
453         start = 0;
454         end = 0;
455         vm_map_lock_read(map);
456         for (entry = map->header.next; entry != &map->header;
457                 entry = entry->next) {
458                 if (entry->maptype != VM_MAPTYPE_NORMAL &&
459                     entry->maptype != VM_MAPTYPE_VPAGETABLE) {
460                         continue;
461                 }
462                 /* Assuming that text is the first entry */
463                 start = entry->start;
464                 end = entry->end;
465         }
466         vm_map_unlock_read(map);
467
468         ps = psbuf;
469         ps += ksprintf(ps, "%d", p->p_pid);
470 #define PS_ADD(name, fmt, arg) ps += ksprintf(ps, " " fmt, arg)
471         PS_ADD("comm",          "(%s)", p->p_comm);
472         PS_ADD("statr",         "%c",   '0'); /* XXX */
473         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
474         PS_ADD("pgrp",          "%d",   p->p_pgid);
475         PS_ADD("session",       "%d",   p->p_session->s_sid);
476         PS_ADD("tty",           "%d",   0); /* XXX */
477         PS_ADD("tpgid",         "%d",   kp.kp_tpgid); /* XXX */
478         PS_ADD("flags",         "%u",   0); /* XXX */
479         PS_ADD("minflt",        "%lu",  kp.kp_ru.ru_minflt); /* XXX */
480         PS_ADD("cminflt",       "%lu",  kp.kp_cru.ru_minflt); /* XXX */
481         PS_ADD("majflt",        "%lu",  kp.kp_ru.ru_majflt); /* XXX */
482         PS_ADD("cmajflt",       "%lu",  kp.kp_cru.ru_majflt); /* XXX */
483         PS_ADD("utime",         "%d",   T2J(tvtohz_high(&kp.kp_ru.ru_utime))); /* XXX */
484         PS_ADD("stime",         "%d",   T2J(tvtohz_high(&kp.kp_ru.ru_stime))); /* XXX */
485         PS_ADD("cutime",        "%d",   T2J(tvtohz_high(&kp.kp_cru.ru_utime))); /* XXX */
486         PS_ADD("cstime",        "%d",   T2J(tvtohz_high(&kp.kp_cru.ru_stime))); /* XXX */
487         PS_ADD("priority",      "%d",   0); /* XXX */
488         PS_ADD("nice",          "%d",   kp.kp_nice);
489         PS_ADD("timeout",       "%u",   0); /* XXX */
490         PS_ADD("itrealvalue",   "%u",   0); /* XXX */
491         PS_ADD("starttime",     "%d",   T2J(tvtohz_high(&kp.kp_start))); /* XXX */
492         PS_ADD("vsize",         "%ju",  P2K((uintmax_t)(kp.kp_vm_tsize + kp.kp_vm_dsize + kp.kp_vm_ssize))); /* XXX: not sure */
493         PS_ADD("rss",           "%ju",  (uintmax_t)kp.kp_vm_rssize); /* XXX */
494         PS_ADD("rlim",          "%lu",  kp.kp_ru.ru_maxrss); /* XXX */
495         PS_ADD("startcode",     "%lu",  start); /* XXX */
496         PS_ADD("endcode",       "%lu",  end); /* XXX */
497         PS_ADD("startstack",    "%lu",  (u_long)p->p_vmspace->vm_minsaddr); /* XXX */
498         PS_ADD("kstkesp",       "%u",   0); /* XXX */
499         PS_ADD("kstkeip",       "%u",   0); /* XXX */
500         PS_ADD("signal",        "%d",   0); /* XXX */
501         PS_ADD("blocked",       "%d",   0); /* XXX */
502         PS_ADD("sigignore",     "%d",   0); /* XXX */
503         PS_ADD("sigcatch",      "%d",   0); /* XXX */
504         PS_ADD("wchan",         "%u",   0); /* XXX */
505         PS_ADD("nswap",         "%lu",  kp.kp_ru.ru_nswap); /* XXX */
506         PS_ADD("cnswap",        "%lu",  kp.kp_cru.ru_nswap); /* XXX */
507         PS_ADD("exitsignal",    "%d",   0); /* XXX */
508         PS_ADD("processor",     "%u",   kp.kp_lwp.kl_cpuid); /* XXX */
509         PS_ADD("rt_priority",   "%u",   0); /* XXX */ /* >= 2.5.19 */
510         PS_ADD("policy",        "%u",   kp.kp_nice); /* XXX */ /* >= 2.5.19 */
511 #undef PS_ADD
512         ps += ksprintf(ps, "\n");
513         
514         return (uiomove_frombuf(psbuf, ps - psbuf, uio));
515 }
516
517 /*
518  * Map process state to descriptive letter. Note that this does not
519  * quite correspond to what Linux outputs, but it's close enough.
520  */
521 static char *state_str[] = {
522         "? (unknown)",
523         "I (idle)",
524         "R (running)",
525         "T (stopped)",
526         "Z (zombie)",
527         "S (sleeping)",
528         "W (waiting)",
529         "M (mutex)"
530 };
531
532 int
533 linprocfs_doprocstatus(struct proc *curp, struct proc *p, struct pfsnode *pfs,
534                        struct uio *uio)
535 {
536         char *ps, psbuf[1024];
537         char *state;
538         int i;
539
540         ps = psbuf;
541
542         if (p->p_stat > sizeof state_str / sizeof *state_str)
543                 state = state_str[0];
544         else
545                 state = state_str[(int)p->p_stat];
546
547 #define PS_ADD ps += ksprintf
548         PS_ADD(ps, "Name:\t%s\n",         p->p_comm); /* XXX escape */
549         PS_ADD(ps, "State:\t%s\n",        state);
550
551         /*
552          * Credentials
553          */
554         PS_ADD(ps, "Pid:\t%d\n",          p->p_pid);
555         PS_ADD(ps, "PPid:\t%d\n",         p->p_pptr ? p->p_pptr->p_pid : 0);
556         PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
557                                           p->p_ucred->cr_uid,
558                                           p->p_ucred->cr_svuid,
559                                           /* FreeBSD doesn't have fsuid */
560                                           p->p_ucred->cr_uid);
561         PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
562                                           p->p_ucred->cr_gid,
563                                           p->p_ucred->cr_svgid,
564                                           /* FreeBSD doesn't have fsgid */
565                                           p->p_ucred->cr_gid);
566         PS_ADD(ps, "Groups:\t");
567         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
568                 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
569         PS_ADD(ps, "\n");
570         
571         /*
572          * Memory
573          */
574         PS_ADD(ps, "VmSize:\t%8lu kB\n",  B2K(p->p_vmspace->vm_map.size));
575         PS_ADD(ps, "VmLck:\t%8u kB\n",    P2K(0)); /* XXX */
576         /* XXX vm_rssize seems to always be zero, how can this be? */
577         PS_ADD(ps, "VmRss:\t%8u kB\n",    P2K(p->p_vmspace->vm_rssize));
578         PS_ADD(ps, "VmData:\t%8u kB\n",   P2K(p->p_vmspace->vm_dsize));
579         PS_ADD(ps, "VmStk:\t%8u kB\n",    P2K(p->p_vmspace->vm_ssize));
580         PS_ADD(ps, "VmExe:\t%8u kB\n",    P2K(p->p_vmspace->vm_tsize));
581         PS_ADD(ps, "VmLib:\t%8u kB\n",    P2K(0)); /* XXX */
582
583         /*
584          * Signal masks
585          *
586          * We support up to 128 signals, while Linux supports 32,
587          * but we only define 32 (the same 32 as Linux, to boot), so
588          * just show the lower 32 bits of each mask. XXX hack.
589          *
590          * NB: on certain platforms (Sparc at least) Linux actually
591          * supports 64 signals, but this code is a long way from
592          * running on anything but i386, so ignore that for now.
593          */
594         PS_ADD(ps, "SigPnd:\t%08x\n",     p->p_siglist.__bits[0]);
595         PS_ADD(ps, "SigBlk:\t%08x\n",     0); /* XXX */
596         PS_ADD(ps, "SigIgn:\t%08x\n",     p->p_sigignore.__bits[0]);
597         PS_ADD(ps, "SigCgt:\t%08x\n",     p->p_sigcatch.__bits[0]);
598         
599         /*
600          * Linux also prints the capability masks, but we don't have
601          * capabilities yet, and when we do get them they're likely to
602          * be meaningless to Linux programs, so we lie. XXX
603          */
604         PS_ADD(ps, "CapInh:\t%016x\n",    0);
605         PS_ADD(ps, "CapPrm:\t%016x\n",    0);
606         PS_ADD(ps, "CapEff:\t%016x\n",    0);
607 #undef PS_ADD
608         
609         return (uiomove_frombuf(psbuf, ps - psbuf, uio));
610 }
611
612 int
613 linprocfs_doloadavg(struct proc *curp, struct proc *p,
614                     struct pfsnode *pfs, struct uio *uio)
615 {
616         char *ps, psbuf[512];
617
618         ps = psbuf;
619         ps += ksprintf(ps, "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
620             (int)(averunnable.ldavg[0] / averunnable.fscale),
621             (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
622             (int)(averunnable.ldavg[1] / averunnable.fscale),
623             (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
624             (int)(averunnable.ldavg[2] / averunnable.fscale),
625             (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
626             1,                      /* number of running tasks */
627             -1,                     /* number of tasks */
628             1         /* The last pid, just kidding */
629         );
630         return(uiomove_frombuf(psbuf, ps - psbuf, uio));
631 }
632
633 int
634 linprocfs_donetdev(struct proc *curp, struct proc *p, struct pfsnode *pfs,
635                    struct uio *uio)
636 {
637         struct sbuf *sb;
638         char ifname[16]; /* XXX LINUX_IFNAMSIZ */
639         struct ifnet *ifp;
640         int error;
641
642         sb = sbuf_new_auto();
643
644         sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
645             "Inter-", "   Receive", "  Transmit", " face",
646             "bytes    packets errs drop fifo frame compressed",
647             "bytes    packets errs drop fifo frame compressed");
648
649         crit_enter();
650         TAILQ_FOREACH(ifp, &ifnet, if_link) {
651                 linux_ifname(ifp, ifname, sizeof ifname);
652                 sbuf_printf(sb, "%6.6s:", ifname);
653                 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
654                     0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
655                 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
656                     0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
657         }
658         crit_exit();
659         sbuf_finish(sb);
660         error = uiomove_frombuf(sbuf_data(sb), sbuf_len(sb), uio);
661         sbuf_delete(sb);
662         return (error);
663 }
664
665 int
666 linprocfs_dodevices(struct proc *curp, struct proc *p, struct pfsnode *pfs,
667                    struct uio *uio)
668 {
669         return 0;
670 }
671
672 int
673 linprocfs_doosrelease(struct proc *curp, struct proc *p, struct pfsnode *pfs,
674                    struct uio *uio)
675 {
676         char *osrelease;
677
678         osrelease = linux_get_osrelease(curthread);
679         return(uiomove_frombuf(osrelease, strlen(osrelease)+1, uio));
680 }
681
682 int
683 linprocfs_doostype(struct proc *curp, struct proc *p, struct pfsnode *pfs,
684                    struct uio *uio)
685 {
686         char *osname;
687
688         osname = linux_get_osname(curthread);
689         return(uiomove_frombuf(osname, strlen(osname)+1, uio));
690 }
691
692 int
693 linprocfs_dopidmax(struct proc *curp, struct proc *p, struct pfsnode *pfs,
694                    struct uio *uio)
695 {
696         char buf[32];
697
698         ksnprintf(buf, sizeof(buf), "%d", PID_MAX);
699         return(uiomove_frombuf(buf, strlen(buf)+1, uio));
700         return 0;
701 }
702
703 int
704 linprocfs_domaps(struct proc *curp, struct proc *p, struct pfsnode *pfs,
705              struct uio *uio)
706 {
707         int len;
708         int error;
709         vm_map_t map = &p->p_vmspace->vm_map;
710         vm_map_entry_t entry;
711         vm_ooffset_t off = 0;
712         char mebuffer[256];
713         char *name = "", *freename = NULL;
714         struct vnode *vp;
715         struct vattr vat;
716         int major, minor;
717         ino_t ino;
718
719         if (uio->uio_rw != UIO_READ)
720                 return (EOPNOTSUPP);
721
722         if (uio->uio_offset != 0)
723                 return (0);
724         
725         error = 0;
726         vm_map_lock_read(map);
727         for (entry = map->header.next;
728                 ((uio->uio_resid > 0) && (entry != &map->header));
729                 entry = entry->next) {
730                 vm_object_t obj, tobj, lobj;
731                 vm_offset_t ostart;
732                 name = "";
733                 freename = NULL;
734                 ino = 0;
735                 if (entry->maptype != VM_MAPTYPE_NORMAL &&
736                     entry->maptype != VM_MAPTYPE_VPAGETABLE) {
737                         continue;
738                 }
739                 /*
740                  * Use map->hint as a poor man's ripout detector.
741                  */
742                 map->hint = entry;
743                 ostart = entry->start;
744                 obj = entry->object.vm_object;
745
746                 for( lobj = tobj = obj; tobj; tobj = tobj->backing_object)
747                         lobj = tobj;
748
749                 if (lobj) {
750                         off = IDX_TO_OFF(lobj->size);
751                         if (lobj->type == OBJT_VNODE) {
752                                 vp = lobj->handle;
753                                 if (vp)
754                                         vref(vp);
755                         } else {
756                                 vp = NULL;
757                         }
758                         
759                         if (vp) {
760                                 vn_fullpath(curproc, vp, &name, &freename);
761                                 vn_lock(vp, LK_SHARED | LK_RETRY);
762                                 VOP_GETATTR(vp, &vat);
763                                 ino = vat.va_fileid;
764                                 major = vat.va_rmajor;
765                                 minor = vat.va_rminor;
766                                 vput(vp);
767                         }
768                 }
769                 if (freename == NULL) {
770                         if (entry->eflags & MAP_ENTRY_STACK)
771                                 name = "[stack]";
772                 }
773
774                 /*
775                  * format:
776                  *  start-end access offset major:minor inode [.text file]
777                  */
778                 ksnprintf(mebuffer, sizeof(mebuffer),
779                     "%08lx-%08lx %s%s%s%s %08llx %02x:%02x %llu%s%s\n",
780                     (u_long)entry->start, (u_long)entry->end,
781                     (entry->protection & VM_PROT_READ)?"r":"-",
782                     (entry->protection & VM_PROT_WRITE)?"w":"-",
783                     (entry->protection & VM_PROT_EXECUTE)?"x":"-",
784                     "p",
785                     off,        /* offset */
786                     0,          /* major */
787                     0,          /* minor */
788                     ino,        /* inode */
789                     *name ? "     " : "",
790                     name);
791
792                 if (freename)
793                         kfree(freename, M_TEMP);
794
795                 len = strlen(mebuffer);
796                 if (len > uio->uio_resid) {
797                         error = EFBIG;
798                         break;
799                 }
800
801                 /*
802                  * We cannot safely hold the map locked while accessing
803                  * userspace as a VM fault might recurse the locked map.
804                  */
805                 vm_map_unlock_read(map);
806                 error = uiomove(mebuffer, len, uio);
807                 vm_map_lock_read(map);
808                 if (error)
809                         break;
810
811                 /*
812                  * We use map->hint as a poor man's ripout detector.  If
813                  * it does not match the entry we set it to prior to
814                  * unlocking the map the entry MIGHT now be stale.  In
815                  * this case we do an expensive lookup to find our place
816                  * in the iteration again.
817                  */
818                 if (map->hint != entry) {
819                         vm_map_entry_t reentry;
820                 
821                         vm_map_lookup_entry(map, ostart, &reentry);
822                         entry = reentry;
823                 }
824         }
825         vm_map_unlock_read(map);
826
827         return error;
828 }