Include jail.h after proc.h to get struct ucred.
[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.10 2005/01/31 22:03:48 joerg Exp $
43  */
44
45 #include <sys/param.h>
46 #include <sys/blist.h>
47 #include <sys/dkstat.h>
48 #include <sys/kernel.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
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/inttypes.h>
69 #include <machine/md_var.h>
70
71 #include "linprocfs.h"
72
73 /*
74  * Various conversion macros
75  */
76 #define T2J(x) (((x) * 100) / (stathz ? stathz : hz))   /* ticks to jiffies */
77 #define T2S(x) ((x) / (stathz ? stathz : hz))           /* ticks to seconds */
78 #define B2K(x) ((unsigned long)((x) >> 10))                     /* bytes to kbytes */
79 #define P2B(x) ((x) << PAGE_SHIFT)                      /* pages to bytes */
80 #define P2K(x) ((x) << (PAGE_SHIFT - 10))               /* pages to kbytes */
81
82 int
83 linprocfs_domeminfo(curp, p, pfs, uio)
84         struct proc *curp;
85         struct proc *p;
86         struct pfsnode *pfs;
87         struct uio *uio;
88 {
89         char *ps;
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 = swapblist->bl_blocks * 1024LL; /* 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:%9lu kB\n"
153                 "SwapFree: %9lu 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         return (uiomove_frombuf(psbuf, ps - psbuf, uio));
161 }
162
163 int
164 linprocfs_docpuinfo(curp, p, pfs, uio)
165         struct proc *curp;
166         struct proc *p;
167         struct pfsnode *pfs;
168         struct uio *uio;
169 {
170         char *ps;
171         char psbuf[512];                /* XXX - conservative */
172         int class;
173         int i;
174 #if 0
175         extern char *cpu_model;         /* Yuck */
176 #endif
177         /* We default the flags to include all non-conflicting flags,
178            and the Intel versions of conflicting flags.  Note the space
179            before each name; that is significant, and should be 
180            preserved. */
181
182         static char *flags[] = {
183                 "fpu",      "vme",     "de",       "pse",      "tsc",
184                 "msr",      "pae",     "mce",      "cx8",      "apic",
185                 "sep",      "sep",     "mtrr",     "pge",      "mca",
186                 "cmov",     "pat",     "pse36",    "pn",       "b19",
187                 "b20",      "b21",     "mmxext",   "mmx",      "fxsr",
188                 "xmm",      "b26",     "b27",      "b28",      "b29",
189                 "3dnowext", "3dnow"
190         };
191
192         if (uio->uio_rw != UIO_READ)
193                 return (EOPNOTSUPP);
194
195         switch (cpu_class) {
196         case CPUCLASS_286:
197                 class = 2;
198                 break;
199         case CPUCLASS_386:
200                 class = 3;
201                 break;
202         case CPUCLASS_486:
203                 class = 4;
204                 break;
205         case CPUCLASS_586:
206                 class = 5;
207                 break;
208         case CPUCLASS_686:
209                 class = 6;
210                 break;
211         default:
212                 class = 0;
213                 break;
214         }
215
216         ps = psbuf;
217         ps += sprintf(ps,
218                         "processor\t: %d\n"
219                         "vendor_id\t: %.20s\n"
220                         "cpu family\t: %d\n"
221                         "model\t\t: %d\n"
222                         "stepping\t: %d\n",
223                         0, cpu_vendor, class, cpu, cpu_id & 0xf);
224
225         ps += sprintf(ps,
226                         "flags\t\t:");
227
228         if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
229                 flags[16] = "fcmov";
230         } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
231                 flags[24] = "cxmmx";
232         }
233         
234         for (i = 0; i < 32; i++)
235                 if (cpu_feature & (1 << i))
236                         ps += sprintf(ps, " %s", flags[i]);
237         ps += sprintf(ps, "\n");
238         if (class >= 5) {
239                 ps += sprintf(ps,
240                         "cpu MHz\t\t: %d.%02d\n"
241                         "bogomips\t: %d.%02d\n",
242                         (tsc_freq + 4999) / 1000000,
243                         ((tsc_freq + 4999) / 10000) % 100,
244                         (tsc_freq + 4999) / 1000000,
245                         ((tsc_freq + 4999) / 10000) % 100);
246         }
247         
248         return (uiomove_frombuf(psbuf, ps - psbuf, uio));
249 }
250
251 static unsigned int
252 cpucnt(int offset)
253 {
254     int i;
255     int count = 0;
256
257     for (i = 0; i < ncpus; ++i) {
258         struct globaldata *gd = globaldata_find(i);
259         count += *(unsigned int *)((char *)&gd->gd_cnt + offset);
260     }
261     return(count);
262 }
263
264 int
265 linprocfs_dostat(curp, p, pfs, uio)
266         struct proc *curp;
267         struct proc *p;
268         struct pfsnode *pfs;
269         struct uio *uio;
270 {
271         char *ps;
272         char psbuf[512];
273
274         ps = psbuf;
275         ps += sprintf(ps,
276                       "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n"
277                       "disk 0 0 0 0\n"
278                       "page %u %u\n"
279                       "swap %u %u\n"
280                       "intr %u\n"
281                       "ctxt %u\n"
282                       "btime %ld\n",
283                       T2J(cp_time.cp_user),
284                       T2J(cp_time.cp_nice),
285                       T2J(cp_time.cp_sys /*+ cp_time[CP_INTR]*/),
286                       T2J(cp_time.cp_idle),
287                       cpucnt(offsetof(struct vmmeter, v_vnodepgsin)),
288                       cpucnt(offsetof(struct vmmeter, v_vnodepgsout)),
289                       cpucnt(offsetof(struct vmmeter, v_swappgsin)),
290                       cpucnt(offsetof(struct vmmeter, v_swappgsout)),
291                       cpucnt(offsetof(struct vmmeter, v_intr)),
292                       cpucnt(offsetof(struct vmmeter, v_swtch)),
293                       boottime.tv_sec);
294         return (uiomove_frombuf(psbuf, ps - psbuf, 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         char psbuf[64];
306         struct timeval tv;
307
308         getmicrouptime(&tv);
309         ps = psbuf;
310         ps += sprintf(ps, "%ld.%02ld %"PRIu64".%02"PRIu64"\n",
311                       tv.tv_sec, tv.tv_usec / 10000,
312                       T2S(cp_time.cp_idle), T2J(cp_time.cp_idle) % 100);
313         return (uiomove_frombuf(psbuf, ps - psbuf, uio));
314 }
315
316 int
317 linprocfs_doversion(curp, p, pfs, uio)
318         struct proc *curp;
319         struct proc *p;
320         struct pfsnode *pfs;
321         struct uio *uio;
322 {
323         char *ps;
324         int xlen;
325
326         ps = version; /* XXX not entirely correct */
327         for (xlen = 0; ps[xlen] != '\n'; ++xlen)
328                 /* nothing */ ;
329         ++xlen;
330         return (uiomove_frombuf(ps, xlen, uio));
331 }
332
333 int
334 linprocfs_doprocstat(curp, p, pfs, uio)
335         struct proc *curp;
336         struct proc *p;
337         struct pfsnode *pfs;
338         struct uio *uio;
339 {
340         char *ps, psbuf[1024];
341
342         ps = psbuf;
343         ps += sprintf(ps, "%d", p->p_pid);
344 #define PS_ADD(name, fmt, arg) ps += sprintf(ps, " " fmt, arg)
345         PS_ADD("comm",          "(%s)", p->p_comm);
346         PS_ADD("statr",         "%c",   '0'); /* XXX */
347         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
348         PS_ADD("pgrp",          "%d",   p->p_pgid);
349         PS_ADD("session",       "%d",   p->p_session->s_sid);
350         PS_ADD("tty",           "%d",   0); /* XXX */
351         PS_ADD("tpgid",         "%d",   0); /* XXX */
352         PS_ADD("flags",         "%u",   0); /* XXX */
353         PS_ADD("minflt",        "%u",   0); /* XXX */
354         PS_ADD("cminflt",       "%u",   0); /* XXX */
355         PS_ADD("majflt",        "%u",   0); /* XXX */
356         PS_ADD("cminflt",       "%u",   0); /* XXX */
357         PS_ADD("utime",         "%d",   0); /* XXX */
358         PS_ADD("stime",         "%d",   0); /* XXX */
359         PS_ADD("cutime",        "%d",   0); /* XXX */
360         PS_ADD("cstime",        "%d",   0); /* XXX */
361         PS_ADD("counter",       "%d",   0); /* XXX */
362         PS_ADD("priority",      "%d",   0); /* XXX */
363         PS_ADD("timeout",       "%u",   0); /* XXX */
364         PS_ADD("itrealvalue",   "%u",   0); /* XXX */
365         PS_ADD("starttime",     "%d",   0); /* XXX */
366         PS_ADD("vsize",         "%u",   0); /* XXX */
367         PS_ADD("rss",           "%u",   0); /* XXX */
368         PS_ADD("rlim",          "%u",   0); /* XXX */
369         PS_ADD("startcode",     "%u",   0); /* XXX */
370         PS_ADD("endcode",       "%u",   0); /* XXX */
371         PS_ADD("startstack",    "%u",   0); /* XXX */
372         PS_ADD("kstkesp",       "%u",   0); /* XXX */
373         PS_ADD("kstkeip",       "%u",   0); /* XXX */
374         PS_ADD("signal",        "%d",   0); /* XXX */
375         PS_ADD("blocked",       "%d",   0); /* XXX */
376         PS_ADD("sigignore",     "%d",   0); /* XXX */
377         PS_ADD("sigcatch",      "%d",   0); /* XXX */
378         PS_ADD("wchan",         "%u",   0); /* XXX */
379 #undef PS_ADD
380         ps += sprintf(ps, "\n");
381         
382         return (uiomove_frombuf(psbuf, ps - psbuf, uio));
383 }
384
385 /*
386  * Map process state to descriptive letter. Note that this does not
387  * quite correspond to what Linux outputs, but it's close enough.
388  */
389 static char *state_str[] = {
390         "? (unknown)",
391         "I (idle)",
392         "R (running)",
393         "S (sleeping)",
394         "T (stopped)",
395         "Z (zombie)",
396         "W (waiting)",
397         "M (mutex)"
398 };
399
400 int
401 linprocfs_doprocstatus(curp, p, pfs, uio)
402         struct proc *curp;
403         struct proc *p;
404         struct pfsnode *pfs;
405         struct uio *uio;
406 {
407         char *ps, psbuf[1024];
408         char *state;
409         int i;
410
411         ps = psbuf;
412
413         if (p->p_stat > sizeof state_str / sizeof *state_str)
414                 state = state_str[0];
415         else
416                 state = state_str[(int)p->p_stat];
417
418 #define PS_ADD ps += sprintf
419         PS_ADD(ps, "Name:\t%s\n",         p->p_comm); /* XXX escape */
420         PS_ADD(ps, "State:\t%s\n",        state);
421
422         /*
423          * Credentials
424          */
425         PS_ADD(ps, "Pid:\t%d\n",          p->p_pid);
426         PS_ADD(ps, "PPid:\t%d\n",         p->p_pptr ? p->p_pptr->p_pid : 0);
427         PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
428                                           p->p_ucred->cr_uid,
429                                           p->p_ucred->cr_svuid,
430                                           /* FreeBSD doesn't have fsuid */
431                                           p->p_ucred->cr_uid);
432         PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
433                                           p->p_ucred->cr_gid,
434                                           p->p_ucred->cr_svgid,
435                                           /* FreeBSD doesn't have fsgid */
436                                           p->p_ucred->cr_gid);
437         PS_ADD(ps, "Groups:\t");
438         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
439                 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
440         PS_ADD(ps, "\n");
441         
442         /*
443          * Memory
444          */
445         PS_ADD(ps, "VmSize:\t%8lu kB\n",  B2K(p->p_vmspace->vm_map.size));
446         PS_ADD(ps, "VmLck:\t%8u kB\n",    P2K(0)); /* XXX */
447         /* XXX vm_rssize seems to always be zero, how can this be? */
448         PS_ADD(ps, "VmRss:\t%8u kB\n",    P2K(p->p_vmspace->vm_rssize));
449         PS_ADD(ps, "VmData:\t%8u kB\n",   P2K(p->p_vmspace->vm_dsize));
450         PS_ADD(ps, "VmStk:\t%8u kB\n",    P2K(p->p_vmspace->vm_ssize));
451         PS_ADD(ps, "VmExe:\t%8u kB\n",    P2K(p->p_vmspace->vm_tsize));
452         PS_ADD(ps, "VmLib:\t%8u kB\n",    P2K(0)); /* XXX */
453
454         /*
455          * Signal masks
456          *
457          * We support up to 128 signals, while Linux supports 32,
458          * but we only define 32 (the same 32 as Linux, to boot), so
459          * just show the lower 32 bits of each mask. XXX hack.
460          *
461          * NB: on certain platforms (Sparc at least) Linux actually
462          * supports 64 signals, but this code is a long way from
463          * running on anything but i386, so ignore that for now.
464          */
465         PS_ADD(ps, "SigPnd:\t%08x\n",     p->p_siglist.__bits[0]);
466         PS_ADD(ps, "SigBlk:\t%08x\n",     0); /* XXX */
467         PS_ADD(ps, "SigIgn:\t%08x\n",     p->p_sigignore.__bits[0]);
468         PS_ADD(ps, "SigCgt:\t%08x\n",     p->p_sigcatch.__bits[0]);
469         
470         /*
471          * Linux also prints the capability masks, but we don't have
472          * capabilities yet, and when we do get them they're likely to
473          * be meaningless to Linux programs, so we lie. XXX
474          */
475         PS_ADD(ps, "CapInh:\t%016x\n",    0);
476         PS_ADD(ps, "CapPrm:\t%016x\n",    0);
477         PS_ADD(ps, "CapEff:\t%016x\n",    0);
478 #undef PS_ADD
479         
480         return (uiomove_frombuf(psbuf, ps - psbuf, uio));
481 }
482
483 extern int nextpid;
484
485 int
486 linprocfs_doloadavg(struct proc *curp, struct proc *p,
487                     struct pfsnode *pfs, struct uio *uio)
488 {
489         char *ps, psbuf[512];
490
491         ps = psbuf;
492         ps += sprintf(ps, "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
493             (int)(averunnable.ldavg[0] / averunnable.fscale),
494             (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
495             (int)(averunnable.ldavg[1] / averunnable.fscale),
496             (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
497             (int)(averunnable.ldavg[2] / averunnable.fscale),
498             (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
499             1,                      /* number of running tasks */
500             -1,                     /* number of tasks */
501             nextpid         /* The last pid */
502         );
503         return(uiomove_frombuf(psbuf, ps - psbuf, uio));
504 }
505