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