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