Initial import from FreeBSD RELENG_4:
[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/dkstat.h>
47 #include <sys/jail.h>
48 #include <sys/kernel.h>
49 #include <sys/proc.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
56 #include <vm/vm.h>
57 #include <vm/pmap.h>
58 #include <vm/vm_map.h>
59 #include <vm/vm_param.h>
60 #include <vm/vm_object.h>
61 #include <vm/swap_pager.h>
62 #include <sys/vmmeter.h>
63 #include <sys/exec.h>
64
65 #include <machine/clock.h>
66 #include <machine/cputypes.h>
67 #include <machine/md_var.h>
68
69 #include <i386/linux/linprocfs/linprocfs.h>
70
71 /*
72  * Various conversion macros
73  */
74 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */
75 #define T2S(x) ((x) / (stathz ? stathz : hz))           /* ticks to seconds */
76 #define B2K(x) ((x) >> 10)                              /* bytes to kbytes */
77 #define P2B(x) ((x) << PAGE_SHIFT)                      /* pages to bytes */
78 #define P2K(x) ((x) << (PAGE_SHIFT - 10))               /* pages to kbytes */
79
80 int
81 linprocfs_domeminfo(curp, p, pfs, uio)
82         struct proc *curp;
83         struct proc *p;
84         struct pfsnode *pfs;
85         struct uio *uio;
86 {
87         char *ps;
88         int xlen;
89         char psbuf[512];                /* XXX - conservative */
90         unsigned long memtotal;         /* total memory in bytes */
91         unsigned long memused;          /* used memory in bytes */
92         unsigned long memfree;          /* free memory in bytes */
93         unsigned long memshared;        /* shared memory ??? */
94         unsigned long buffers, cached;  /* buffer / cache memory ??? */
95         unsigned long long swaptotal;   /* total swap space in bytes */
96         unsigned long long swapused;            /* used swap space in bytes */
97         unsigned long long swapfree;            /* free swap space in bytes */
98         vm_object_t object;
99
100         if (uio->uio_rw != UIO_READ)
101                 return (EOPNOTSUPP);
102
103         memtotal = physmem * PAGE_SIZE;
104         /*
105          * The correct thing here would be:
106          *
107         memfree = cnt.v_free_count * PAGE_SIZE;
108         memused = memtotal - memfree;
109          *
110          * but it might mislead linux binaries into thinking there
111          * is very little memory left, so we cheat and tell them that
112          * all memory that isn't wired down is free.
113          */
114         memused = cnt.v_wire_count * PAGE_SIZE;
115         memfree = memtotal - memused;
116         if (swapblist == NULL) {
117                 swaptotal = 0;
118                 swapfree = 0;
119         } else {
120                 swaptotal = (unsigned long long) swapblist->bl_blocks * 1024ULL; /* XXX why 1024? */
121                 swapfree = (unsigned long long) swapblist->bl_root->u.bmu_avail * PAGE_SIZE;
122         }
123         swapused = swaptotal - swapfree;
124         memshared = 0;
125         for (object = TAILQ_FIRST(&vm_object_list); object != NULL;
126             object = TAILQ_NEXT(object, object_list))
127                 if (object->shadow_count > 1)
128                         memshared += object->resident_page_count;
129         memshared *= PAGE_SIZE;
130         /*
131          * We'd love to be able to write:
132          *
133         buffers = bufspace;
134          *
135          * but bufspace is internal to vfs_bio.c and we don't feel
136          * like unstaticizing it just for linprocfs's sake.
137          */
138         buffers = 0;
139         cached = cnt.v_cache_count * PAGE_SIZE;
140
141         ps = psbuf;
142         ps += sprintf(ps,
143                 "        total:    used:    free:  shared: buffers:  cached:\n"
144                 "Mem:  %lu %lu %lu %lu %lu %lu\n"
145                 "Swap: %llu %llu %llu\n"
146                 "MemTotal: %9lu kB\n"
147                 "MemFree:  %9lu kB\n"
148                 "MemShared:%9lu kB\n"
149                 "Buffers:  %9lu kB\n"
150                 "Cached:   %9lu kB\n"
151                 "SwapTotal:%9llu kB\n"
152                 "SwapFree: %9llu kB\n",
153                 memtotal, memused, memfree, memshared, buffers, cached,
154                 swaptotal, swapused, swapfree,
155                 B2K(memtotal), B2K(memfree),
156                 B2K(memshared), B2K(buffers), B2K(cached),
157                 B2K(swaptotal), B2K(swapfree));
158
159         xlen = ps - psbuf;
160         xlen -= uio->uio_offset;
161         ps = psbuf + uio->uio_offset;
162         xlen = imin(xlen, uio->uio_resid);
163         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
164 }
165
166 int
167 linprocfs_docpuinfo(curp, p, pfs, uio)
168         struct proc *curp;
169         struct proc *p;
170         struct pfsnode *pfs;
171         struct uio *uio;
172 {
173         char *ps;
174         int xlen;
175         char psbuf[512];                /* XXX - conservative */
176         int class;
177         int i;
178 #if 0
179         extern char *cpu_model;         /* Yuck */
180 #endif
181         /* We default the flags to include all non-conflicting flags,
182            and the Intel versions of conflicting flags.  Note the space
183            before each name; that is significant, and should be 
184            preserved. */
185
186         static char *flags[] = {
187                 "fpu",      "vme",     "de",       "pse",      "tsc",
188                 "msr",      "pae",     "mce",      "cx8",      "apic",
189                 "sep",      "sep",     "mtrr",     "pge",      "mca",
190                 "cmov",     "pat",     "pse36",    "pn",       "b19",
191                 "b20",      "b21",     "mmxext",   "mmx",      "fxsr",
192                 "xmm",      "b26",     "b27",      "b28",      "b29",
193                 "3dnowext", "3dnow"
194         };
195
196         if (uio->uio_rw != UIO_READ)
197                 return (EOPNOTSUPP);
198
199         switch (cpu_class) {
200         case CPUCLASS_286:
201                 class = 2;
202                 break;
203         case CPUCLASS_386:
204                 class = 3;
205                 break;
206         case CPUCLASS_486:
207                 class = 4;
208                 break;
209         case CPUCLASS_586:
210                 class = 5;
211                 break;
212         case CPUCLASS_686:
213                 class = 6;
214                 break;
215         default:
216                 class = 0;
217                 break;
218         }
219
220         ps = psbuf;
221         ps += sprintf(ps,
222                         "processor\t: %d\n"
223                         "vendor_id\t: %.20s\n"
224                         "cpu family\t: %d\n"
225                         "model\t\t: %d\n"
226                         "stepping\t: %d\n",
227                         0, cpu_vendor, class, cpu, cpu_id & 0xf);
228
229         ps += sprintf(ps,
230                         "flags\t\t:");
231
232         if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
233                 flags[16] = "fcmov";
234         } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
235                 flags[24] = "cxmmx";
236         }
237         
238         for (i = 0; i < 32; i++)
239                 if (cpu_feature & (1 << i))
240                         ps += sprintf(ps, " %s", flags[i]);
241         ps += sprintf(ps, "\n");
242         if (class >= 5) {
243                 ps += sprintf(ps,
244                         "cpu MHz\t\t: %d.%02d\n"
245                         "bogomips\t: %d.%02d\n",
246                         (tsc_freq + 4999) / 1000000,
247                         ((tsc_freq + 4999) / 10000) % 100,
248                         (tsc_freq + 4999) / 1000000,
249                         ((tsc_freq + 4999) / 10000) % 100);
250         }
251         
252         xlen = ps - psbuf;
253         xlen -= uio->uio_offset;
254         ps = psbuf + uio->uio_offset;
255         xlen = imin(xlen, uio->uio_resid);
256         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
257 }
258
259 int
260 linprocfs_dostat(curp, p, pfs, uio)
261         struct proc *curp;
262         struct proc *p;
263         struct pfsnode *pfs;
264         struct uio *uio;
265 {
266         char *ps;
267         char psbuf[512];
268         int xlen;
269
270         ps = psbuf;
271         ps += sprintf(ps,
272                       "cpu %ld %ld %ld %ld\n"
273                       "disk 0 0 0 0\n"
274                       "page %u %u\n"
275                       "swap %u %u\n"
276                       "intr %u\n"
277                       "ctxt %u\n"
278                       "btime %ld\n",
279                       T2J(cp_time[CP_USER]),
280                       T2J(cp_time[CP_NICE]),
281                       T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
282                       T2J(cp_time[CP_IDLE]),
283                       cnt.v_vnodepgsin,
284                       cnt.v_vnodepgsout,
285                       cnt.v_swappgsin,
286                       cnt.v_swappgsout,
287                       cnt.v_intr,
288                       cnt.v_swtch,
289                       boottime.tv_sec);
290         xlen = ps - psbuf;
291         xlen -= uio->uio_offset;
292         ps = psbuf + uio->uio_offset;
293         xlen = imin(xlen, uio->uio_resid);
294         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
295 }
296
297 int
298 linprocfs_douptime(curp, p, pfs, uio)
299         struct proc *curp;
300         struct proc *p;
301         struct pfsnode *pfs;
302         struct uio *uio;
303 {
304         char *ps;
305         int xlen;
306         char psbuf[64];
307         struct timeval tv;
308
309         getmicrouptime(&tv);
310         ps = psbuf;
311         ps += sprintf(ps, "%ld.%02ld %ld.%02ld\n",
312                       tv.tv_sec, tv.tv_usec / 10000,
313                       T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
314         xlen = ps - psbuf;
315         xlen -= uio->uio_offset;
316         ps = psbuf + uio->uio_offset;
317         xlen = imin(xlen, uio->uio_resid);
318         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
319 }
320
321 int
322 linprocfs_doversion(curp, p, pfs, uio)
323         struct proc *curp;
324         struct proc *p;
325         struct pfsnode *pfs;
326         struct uio *uio;
327 {
328         char *ps;
329         int xlen;
330
331         ps = version; /* XXX not entirely correct */
332         for (xlen = 0; ps[xlen] != '\n'; ++xlen)
333                 /* nothing */ ;
334         ++xlen;
335         xlen -= uio->uio_offset;
336         ps += uio->uio_offset;
337         xlen = imin(xlen, uio->uio_resid);
338         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
339 }
340
341 int
342 linprocfs_doprocstat(curp, p, pfs, uio)
343         struct proc *curp;
344         struct proc *p;
345         struct pfsnode *pfs;
346         struct uio *uio;
347 {
348         char *ps, psbuf[1024];
349         int xlen;
350
351         ps = psbuf;
352         ps += sprintf(ps, "%d", p->p_pid);
353 #define PS_ADD(name, fmt, arg) ps += sprintf(ps, " " fmt, arg)
354         PS_ADD("comm",          "(%s)", p->p_comm);
355         PS_ADD("statr",         "%c",   '0'); /* XXX */
356         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
357         PS_ADD("pgrp",          "%d",   p->p_pgid);
358         PS_ADD("session",       "%d",   p->p_session->s_sid);
359         PS_ADD("tty",           "%d",   0); /* XXX */
360         PS_ADD("tpgid",         "%d",   0); /* XXX */
361         PS_ADD("flags",         "%u",   0); /* XXX */
362         PS_ADD("minflt",        "%u",   0); /* XXX */
363         PS_ADD("cminflt",       "%u",   0); /* XXX */
364         PS_ADD("majflt",        "%u",   0); /* XXX */
365         PS_ADD("cminflt",       "%u",   0); /* XXX */
366         PS_ADD("utime",         "%d",   0); /* XXX */
367         PS_ADD("stime",         "%d",   0); /* XXX */
368         PS_ADD("cutime",        "%d",   0); /* XXX */
369         PS_ADD("cstime",        "%d",   0); /* XXX */
370         PS_ADD("counter",       "%d",   0); /* XXX */
371         PS_ADD("priority",      "%d",   0); /* XXX */
372         PS_ADD("timeout",       "%u",   0); /* XXX */
373         PS_ADD("itrealvalue",   "%u",   0); /* XXX */
374         PS_ADD("starttime",     "%d",   0); /* XXX */
375         PS_ADD("vsize",         "%u",   0); /* XXX */
376         PS_ADD("rss",           "%u",   0); /* XXX */
377         PS_ADD("rlim",          "%u",   0); /* XXX */
378         PS_ADD("startcode",     "%u",   0); /* XXX */
379         PS_ADD("endcode",       "%u",   0); /* XXX */
380         PS_ADD("startstack",    "%u",   0); /* XXX */
381         PS_ADD("kstkesp",       "%u",   0); /* XXX */
382         PS_ADD("kstkeip",       "%u",   0); /* XXX */
383         PS_ADD("signal",        "%d",   0); /* XXX */
384         PS_ADD("blocked",       "%d",   0); /* XXX */
385         PS_ADD("sigignore",     "%d",   0); /* XXX */
386         PS_ADD("sigcatch",      "%d",   0); /* XXX */
387         PS_ADD("wchan",         "%u",   0); /* XXX */
388 #undef PS_ADD
389         ps += sprintf(ps, "\n");
390         
391         xlen = ps - psbuf;
392         xlen -= uio->uio_offset;
393         ps = psbuf + uio->uio_offset;
394         xlen = imin(xlen, uio->uio_resid);
395         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
396 }
397
398 /*
399  * Map process state to descriptive letter. Note that this does not
400  * quite correspond to what Linux outputs, but it's close enough.
401  */
402 static char *state_str[] = {
403         "? (unknown)",
404         "I (idle)",
405         "R (running)",
406         "S (sleeping)",
407         "T (stopped)",
408         "Z (zombie)",
409         "W (waiting)",
410         "M (mutex)"
411 };
412
413 int
414 linprocfs_doprocstatus(curp, p, pfs, uio)
415         struct proc *curp;
416         struct proc *p;
417         struct pfsnode *pfs;
418         struct uio *uio;
419 {
420         char *ps, psbuf[1024];
421         char *state;
422         int i, xlen;
423
424         ps = psbuf;
425
426         if (p->p_stat > sizeof state_str / sizeof *state_str)
427                 state = state_str[0];
428         else
429                 state = state_str[(int)p->p_stat];
430
431 #define PS_ADD ps += sprintf
432         PS_ADD(ps, "Name:\t%s\n",         p->p_comm); /* XXX escape */
433         PS_ADD(ps, "State:\t%s\n",        state);
434
435         /*
436          * Credentials
437          */
438         PS_ADD(ps, "Pid:\t%d\n",          p->p_pid);
439         PS_ADD(ps, "PPid:\t%d\n",         p->p_pptr ? p->p_pptr->p_pid : 0);
440         PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_cred->p_ruid,
441                                           p->p_ucred->cr_uid,
442                                           p->p_cred->p_svuid,
443                                           /* FreeBSD doesn't have fsuid */
444                                           p->p_ucred->cr_uid);
445         PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_cred->p_rgid,
446                                           p->p_ucred->cr_gid,
447                                           p->p_cred->p_svgid,
448                                           /* FreeBSD doesn't have fsgid */
449                                           p->p_ucred->cr_gid);
450         PS_ADD(ps, "Groups:\t");
451         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
452                 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
453         PS_ADD(ps, "\n");
454         
455         /*
456          * Memory
457          */
458         PS_ADD(ps, "VmSize:\t%8u kB\n",   B2K(p->p_vmspace->vm_map.size));
459         PS_ADD(ps, "VmLck:\t%8u kB\n",    P2K(0)); /* XXX */
460         /* XXX vm_rssize seems to always be zero, how can this be? */
461         PS_ADD(ps, "VmRss:\t%8u kB\n",    P2K(p->p_vmspace->vm_rssize));
462         PS_ADD(ps, "VmData:\t%8u kB\n",   P2K(p->p_vmspace->vm_dsize));
463         PS_ADD(ps, "VmStk:\t%8u kB\n",    P2K(p->p_vmspace->vm_ssize));
464         PS_ADD(ps, "VmExe:\t%8u kB\n",    P2K(p->p_vmspace->vm_tsize));
465         PS_ADD(ps, "VmLib:\t%8u kB\n",    P2K(0)); /* XXX */
466
467         /*
468          * Signal masks
469          *
470          * We support up to 128 signals, while Linux supports 32,
471          * but we only define 32 (the same 32 as Linux, to boot), so
472          * just show the lower 32 bits of each mask. XXX hack.
473          *
474          * NB: on certain platforms (Sparc at least) Linux actually
475          * supports 64 signals, but this code is a long way from
476          * running on anything but i386, so ignore that for now.
477          */
478         PS_ADD(ps, "SigPnd:\t%08x\n",     p->p_siglist.__bits[0]);
479         PS_ADD(ps, "SigBlk:\t%08x\n",     0); /* XXX */
480         PS_ADD(ps, "SigIgn:\t%08x\n",     p->p_sigignore.__bits[0]);
481         PS_ADD(ps, "SigCgt:\t%08x\n",     p->p_sigcatch.__bits[0]);
482         
483         /*
484          * Linux also prints the capability masks, but we don't have
485          * capabilities yet, and when we do get them they're likely to
486          * be meaningless to Linux programs, so we lie. XXX
487          */
488         PS_ADD(ps, "CapInh:\t%016x\n",    0);
489         PS_ADD(ps, "CapPrm:\t%016x\n",    0);
490         PS_ADD(ps, "CapEff:\t%016x\n",    0);
491 #undef PS_ADD
492         
493         xlen = ps - psbuf;
494         xlen -= uio->uio_offset;
495         ps = psbuf + uio->uio_offset;
496         xlen = imin(xlen, uio->uio_resid);
497         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
498 }
499
500 int
501 linprocfs_doloadavg(curp, p, pfs, uio)
502         struct proc *curp;
503         struct proc *p;
504         struct pfsnode *pfs;
505         struct uio *uio;
506 {
507      char *ps, psbuf[512];
508      int xlen;
509         extern int nextpid;
510
511         ps=psbuf;
512
513         ps += sprintf(ps,
514                 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
515                 (int)(averunnable.ldavg[0] / averunnable.fscale),
516                 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
517                 (int)(averunnable.ldavg[1] / averunnable.fscale),
518                 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
519                 (int)(averunnable.ldavg[2] / averunnable.fscale),
520                 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
521                 1,                      /* number of running tasks */
522                 -1,                     /* number of tasks */
523                 nextpid         /* The last pid */
524         );
525
526         xlen = ps - psbuf;
527         xlen -= uio->uio_offset;
528         ps = psbuf + uio->uio_offset;
529         xlen = imin(xlen, uio->uio_resid);
530      return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
531 }