proc->thread stage 2: MAJOR revamping of system calls, ucred, jail API,
[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.3 2003/06/23 17:55:40 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 <i386/linux/linprocfs/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 = cnt.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 = cnt.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 = cnt.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 int
261 linprocfs_dostat(curp, p, pfs, uio)
262         struct proc *curp;
263         struct proc *p;
264         struct pfsnode *pfs;
265         struct uio *uio;
266 {
267         char *ps;
268         char psbuf[512];
269         int xlen;
270
271         ps = psbuf;
272         ps += sprintf(ps,
273                       "cpu %ld %ld %ld %ld\n"
274                       "disk 0 0 0 0\n"
275                       "page %u %u\n"
276                       "swap %u %u\n"
277                       "intr %u\n"
278                       "ctxt %u\n"
279                       "btime %ld\n",
280                       T2J(cp_time[CP_USER]),
281                       T2J(cp_time[CP_NICE]),
282                       T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
283                       T2J(cp_time[CP_IDLE]),
284                       cnt.v_vnodepgsin,
285                       cnt.v_vnodepgsout,
286                       cnt.v_swappgsin,
287                       cnt.v_swappgsout,
288                       cnt.v_intr,
289                       cnt.v_swtch,
290                       boottime.tv_sec);
291         xlen = ps - psbuf;
292         xlen -= uio->uio_offset;
293         ps = psbuf + uio->uio_offset;
294         xlen = imin(xlen, uio->uio_resid);
295         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
296 }
297
298 int
299 linprocfs_douptime(curp, p, pfs, uio)
300         struct proc *curp;
301         struct proc *p;
302         struct pfsnode *pfs;
303         struct uio *uio;
304 {
305         char *ps;
306         int xlen;
307         char psbuf[64];
308         struct timeval tv;
309
310         getmicrouptime(&tv);
311         ps = psbuf;
312         ps += sprintf(ps, "%ld.%02ld %ld.%02ld\n",
313                       tv.tv_sec, tv.tv_usec / 10000,
314                       T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
315         xlen = ps - psbuf;
316         xlen -= uio->uio_offset;
317         ps = psbuf + uio->uio_offset;
318         xlen = imin(xlen, uio->uio_resid);
319         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
320 }
321
322 int
323 linprocfs_doversion(curp, p, pfs, uio)
324         struct proc *curp;
325         struct proc *p;
326         struct pfsnode *pfs;
327         struct uio *uio;
328 {
329         char *ps;
330         int xlen;
331
332         ps = version; /* XXX not entirely correct */
333         for (xlen = 0; ps[xlen] != '\n'; ++xlen)
334                 /* nothing */ ;
335         ++xlen;
336         xlen -= uio->uio_offset;
337         ps += uio->uio_offset;
338         xlen = imin(xlen, uio->uio_resid);
339         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
340 }
341
342 int
343 linprocfs_doprocstat(curp, p, pfs, uio)
344         struct proc *curp;
345         struct proc *p;
346         struct pfsnode *pfs;
347         struct uio *uio;
348 {
349         char *ps, psbuf[1024];
350         int xlen;
351
352         ps = psbuf;
353         ps += sprintf(ps, "%d", p->p_pid);
354 #define PS_ADD(name, fmt, arg) ps += sprintf(ps, " " fmt, arg)
355         PS_ADD("comm",          "(%s)", p->p_comm);
356         PS_ADD("statr",         "%c",   '0'); /* XXX */
357         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
358         PS_ADD("pgrp",          "%d",   p->p_pgid);
359         PS_ADD("session",       "%d",   p->p_session->s_sid);
360         PS_ADD("tty",           "%d",   0); /* XXX */
361         PS_ADD("tpgid",         "%d",   0); /* XXX */
362         PS_ADD("flags",         "%u",   0); /* XXX */
363         PS_ADD("minflt",        "%u",   0); /* XXX */
364         PS_ADD("cminflt",       "%u",   0); /* XXX */
365         PS_ADD("majflt",        "%u",   0); /* XXX */
366         PS_ADD("cminflt",       "%u",   0); /* XXX */
367         PS_ADD("utime",         "%d",   0); /* XXX */
368         PS_ADD("stime",         "%d",   0); /* XXX */
369         PS_ADD("cutime",        "%d",   0); /* XXX */
370         PS_ADD("cstime",        "%d",   0); /* XXX */
371         PS_ADD("counter",       "%d",   0); /* XXX */
372         PS_ADD("priority",      "%d",   0); /* XXX */
373         PS_ADD("timeout",       "%u",   0); /* XXX */
374         PS_ADD("itrealvalue",   "%u",   0); /* XXX */
375         PS_ADD("starttime",     "%d",   0); /* XXX */
376         PS_ADD("vsize",         "%u",   0); /* XXX */
377         PS_ADD("rss",           "%u",   0); /* XXX */
378         PS_ADD("rlim",          "%u",   0); /* XXX */
379         PS_ADD("startcode",     "%u",   0); /* XXX */
380         PS_ADD("endcode",       "%u",   0); /* XXX */
381         PS_ADD("startstack",    "%u",   0); /* XXX */
382         PS_ADD("kstkesp",       "%u",   0); /* XXX */
383         PS_ADD("kstkeip",       "%u",   0); /* XXX */
384         PS_ADD("signal",        "%d",   0); /* XXX */
385         PS_ADD("blocked",       "%d",   0); /* XXX */
386         PS_ADD("sigignore",     "%d",   0); /* XXX */
387         PS_ADD("sigcatch",      "%d",   0); /* XXX */
388         PS_ADD("wchan",         "%u",   0); /* XXX */
389 #undef PS_ADD
390         ps += sprintf(ps, "\n");
391         
392         xlen = ps - psbuf;
393         xlen -= uio->uio_offset;
394         ps = psbuf + uio->uio_offset;
395         xlen = imin(xlen, uio->uio_resid);
396         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
397 }
398
399 /*
400  * Map process state to descriptive letter. Note that this does not
401  * quite correspond to what Linux outputs, but it's close enough.
402  */
403 static char *state_str[] = {
404         "? (unknown)",
405         "I (idle)",
406         "R (running)",
407         "S (sleeping)",
408         "T (stopped)",
409         "Z (zombie)",
410         "W (waiting)",
411         "M (mutex)"
412 };
413
414 int
415 linprocfs_doprocstatus(curp, p, pfs, uio)
416         struct proc *curp;
417         struct proc *p;
418         struct pfsnode *pfs;
419         struct uio *uio;
420 {
421         char *ps, psbuf[1024];
422         char *state;
423         int i, xlen;
424
425         ps = psbuf;
426
427         if (p->p_stat > sizeof state_str / sizeof *state_str)
428                 state = state_str[0];
429         else
430                 state = state_str[(int)p->p_stat];
431
432 #define PS_ADD ps += sprintf
433         PS_ADD(ps, "Name:\t%s\n",         p->p_comm); /* XXX escape */
434         PS_ADD(ps, "State:\t%s\n",        state);
435
436         /*
437          * Credentials
438          */
439         PS_ADD(ps, "Pid:\t%d\n",          p->p_pid);
440         PS_ADD(ps, "PPid:\t%d\n",         p->p_pptr ? p->p_pptr->p_pid : 0);
441         PS_ADD(ps, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
442                                           p->p_ucred->cr_uid,
443                                           p->p_ucred->cr_svuid,
444                                           /* FreeBSD doesn't have fsuid */
445                                           p->p_ucred->cr_uid);
446         PS_ADD(ps, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
447                                           p->p_ucred->cr_gid,
448                                           p->p_ucred->cr_svgid,
449                                           /* FreeBSD doesn't have fsgid */
450                                           p->p_ucred->cr_gid);
451         PS_ADD(ps, "Groups:\t");
452         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
453                 PS_ADD(ps, "%d ", p->p_ucred->cr_groups[i]);
454         PS_ADD(ps, "\n");
455         
456         /*
457          * Memory
458          */
459         PS_ADD(ps, "VmSize:\t%8u kB\n",   B2K(p->p_vmspace->vm_map.size));
460         PS_ADD(ps, "VmLck:\t%8u kB\n",    P2K(0)); /* XXX */
461         /* XXX vm_rssize seems to always be zero, how can this be? */
462         PS_ADD(ps, "VmRss:\t%8u kB\n",    P2K(p->p_vmspace->vm_rssize));
463         PS_ADD(ps, "VmData:\t%8u kB\n",   P2K(p->p_vmspace->vm_dsize));
464         PS_ADD(ps, "VmStk:\t%8u kB\n",    P2K(p->p_vmspace->vm_ssize));
465         PS_ADD(ps, "VmExe:\t%8u kB\n",    P2K(p->p_vmspace->vm_tsize));
466         PS_ADD(ps, "VmLib:\t%8u kB\n",    P2K(0)); /* XXX */
467
468         /*
469          * Signal masks
470          *
471          * We support up to 128 signals, while Linux supports 32,
472          * but we only define 32 (the same 32 as Linux, to boot), so
473          * just show the lower 32 bits of each mask. XXX hack.
474          *
475          * NB: on certain platforms (Sparc at least) Linux actually
476          * supports 64 signals, but this code is a long way from
477          * running on anything but i386, so ignore that for now.
478          */
479         PS_ADD(ps, "SigPnd:\t%08x\n",     p->p_siglist.__bits[0]);
480         PS_ADD(ps, "SigBlk:\t%08x\n",     0); /* XXX */
481         PS_ADD(ps, "SigIgn:\t%08x\n",     p->p_sigignore.__bits[0]);
482         PS_ADD(ps, "SigCgt:\t%08x\n",     p->p_sigcatch.__bits[0]);
483         
484         /*
485          * Linux also prints the capability masks, but we don't have
486          * capabilities yet, and when we do get them they're likely to
487          * be meaningless to Linux programs, so we lie. XXX
488          */
489         PS_ADD(ps, "CapInh:\t%016x\n",    0);
490         PS_ADD(ps, "CapPrm:\t%016x\n",    0);
491         PS_ADD(ps, "CapEff:\t%016x\n",    0);
492 #undef PS_ADD
493         
494         xlen = ps - psbuf;
495         xlen -= uio->uio_offset;
496         ps = psbuf + uio->uio_offset;
497         xlen = imin(xlen, uio->uio_resid);
498         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
499 }
500
501 extern int nextpid;
502
503 int
504 linprocfs_doloadavg(curp, p, pfs, uio)
505         struct proc *curp;
506         struct proc *p;
507         struct pfsnode *pfs;
508         struct uio *uio;
509 {
510         char *ps, psbuf[512];
511         int xlen;
512
513         ps=psbuf;
514
515         ps += sprintf(ps,
516                 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
517                 (int)(averunnable.ldavg[0] / averunnable.fscale),
518                 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
519                 (int)(averunnable.ldavg[1] / averunnable.fscale),
520                 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
521                 (int)(averunnable.ldavg[2] / averunnable.fscale),
522                 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
523                 1,                      /* number of running tasks */
524                 -1,                     /* number of tasks */
525                 nextpid         /* The last pid */
526         );
527
528         xlen = ps - psbuf;
529         xlen -= uio->uio_offset;
530         ps = psbuf + uio->uio_offset;
531         xlen = imin(xlen, uio->uio_resid);
532         return (xlen <= 0 ? 0 : uiomove(ps, xlen, uio));
533 }