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