[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linprocfs/linprocfs.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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 
 42 #include "opt_compat.h"
 43 
 44 #include <sys/cdefs.h>
 45 __FBSDID("$FreeBSD: src/sys/compat/linprocfs/linprocfs.c,v 1.133 2008/12/29 12:45:11 kib Exp $");
 46 
 47 #include <sys/param.h>
 48 #include <sys/queue.h>
 49 #include <sys/blist.h>
 50 #include <sys/conf.h>
 51 #include <sys/exec.h>
 52 #include <sys/fcntl.h>
 53 #include <sys/filedesc.h>
 54 #include <sys/jail.h>
 55 #include <sys/kernel.h>
 56 #include <sys/linker.h>
 57 #include <sys/lock.h>
 58 #include <sys/malloc.h>
 59 #include <sys/mount.h>
 60 #include <sys/msg.h>
 61 #include <sys/mutex.h>
 62 #include <sys/namei.h>
 63 #include <sys/proc.h>
 64 #include <sys/resourcevar.h>
 65 #include <sys/sbuf.h>
 66 #include <sys/sem.h>
 67 #include <sys/smp.h>
 68 #include <sys/socket.h>
 69 #include <sys/sysctl.h>
 70 #include <sys/systm.h>
 71 #include <sys/time.h>
 72 #include <sys/tty.h>
 73 #include <sys/user.h>
 74 #include <sys/vmmeter.h>
 75 #include <sys/vnode.h>
 76 #include <sys/vimage.h>
 77 
 78 #include <net/if.h>
 79 #include <net/vnet.h>
 80 
 81 #include <vm/vm.h>
 82 #include <vm/vm_extern.h>
 83 #include <vm/pmap.h>
 84 #include <vm/vm_map.h>
 85 #include <vm/vm_param.h>
 86 #include <vm/vm_object.h>
 87 #include <vm/swap_pager.h>
 88 
 89 #include <machine/clock.h>
 90 
 91 #if defined(__i386__) || defined(__amd64__)
 92 #include <machine/cputypes.h>
 93 #include <machine/md_var.h>
 94 #endif /* __i386__ || __amd64__ */
 95 
 96 #ifdef COMPAT_LINUX32                           /* XXX */
 97 #include <machine/../linux32/linux.h>
 98 #else
 99 #include <machine/../linux/linux.h>
100 #endif
101 #include <compat/linux/linux_ioctl.h>
102 #include <compat/linux/linux_mib.h>
103 #include <compat/linux/linux_util.h>
104 #include <fs/pseudofs/pseudofs.h>
105 #include <fs/procfs/procfs.h>
106 
107 /*
108  * Various conversion macros
109  */
110 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */
111 #define T2S(x) ((x) / (stathz ? stathz : hz))           /* ticks to seconds */
112 #define B2K(x) ((x) >> 10)                              /* bytes to kbytes */
113 #define B2P(x) ((x) >> PAGE_SHIFT)                      /* bytes to pages */
114 #define P2B(x) ((x) << PAGE_SHIFT)                      /* pages to bytes */
115 #define P2K(x) ((x) << (PAGE_SHIFT - 10))               /* pages to kbytes */
116 
117 /**
118  * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
119  *
120  * The linux procfs state field displays one of the characters RSDZTW to
121  * denote running, sleeping in an interruptible wait, waiting in an
122  * uninterruptible disk sleep, a zombie process, process is being traced
123  * or stopped, or process is paging respectively.
124  *
125  * Our struct kinfo_proc contains the variable ki_stat which contains a
126  * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
127  *
128  * This character array is used with ki_stati-1 as an index and tries to
129  * map our states to suitable linux states.
130  */
131 static char linux_state[] = "RRSTZDD";
132 
133 /*
134  * Filler function for proc/meminfo
135  */
136 static int
137 linprocfs_domeminfo(PFS_FILL_ARGS)
138 {
139         unsigned long memtotal;         /* total memory in bytes */
140         unsigned long memused;          /* used memory in bytes */
141         unsigned long memfree;          /* free memory in bytes */
142         unsigned long memshared;        /* shared memory ??? */
143         unsigned long buffers, cached;  /* buffer / cache memory ??? */
144         unsigned long long swaptotal;   /* total swap space in bytes */
145         unsigned long long swapused;    /* used swap space in bytes */
146         unsigned long long swapfree;    /* free swap space in bytes */
147         vm_object_t object;
148         int i, j;
149 
150         memtotal = physmem * PAGE_SIZE;
151         /*
152          * The correct thing here would be:
153          *
154         memfree = cnt.v_free_count * PAGE_SIZE;
155         memused = memtotal - memfree;
156          *
157          * but it might mislead linux binaries into thinking there
158          * is very little memory left, so we cheat and tell them that
159          * all memory that isn't wired down is free.
160          */
161         memused = cnt.v_wire_count * PAGE_SIZE;
162         memfree = memtotal - memused;
163         swap_pager_status(&i, &j);
164         swaptotal = (unsigned long long)i * PAGE_SIZE;
165         swapused = (unsigned long long)j * PAGE_SIZE;
166         swapfree = swaptotal - swapused;
167         memshared = 0;
168         mtx_lock(&vm_object_list_mtx);
169         TAILQ_FOREACH(object, &vm_object_list, object_list)
170                 if (object->shadow_count > 1)
171                         memshared += object->resident_page_count;
172         mtx_unlock(&vm_object_list_mtx);
173         memshared *= PAGE_SIZE;
174         /*
175          * We'd love to be able to write:
176          *
177         buffers = bufspace;
178          *
179          * but bufspace is internal to vfs_bio.c and we don't feel
180          * like unstaticizing it just for linprocfs's sake.
181          */
182         buffers = 0;
183         cached = cnt.v_cache_count * PAGE_SIZE;
184 
185         sbuf_printf(sb,
186             "        total:    used:    free:  shared: buffers:  cached:\n"
187             "Mem:  %lu %lu %lu %lu %lu %lu\n"
188             "Swap: %llu %llu %llu\n"
189             "MemTotal: %9lu kB\n"
190             "MemFree:  %9lu kB\n"
191             "MemShared:%9lu kB\n"
192             "Buffers:  %9lu kB\n"
193             "Cached:   %9lu kB\n"
194             "SwapTotal:%9llu kB\n"
195             "SwapFree: %9llu kB\n",
196             memtotal, memused, memfree, memshared, buffers, cached,
197             swaptotal, swapused, swapfree,
198             B2K(memtotal), B2K(memfree),
199             B2K(memshared), B2K(buffers), B2K(cached),
200             B2K(swaptotal), B2K(swapfree));
201 
202         return (0);
203 }
204 
205 #if defined(__i386__) || defined(__amd64__)
206 /*
207  * Filler function for proc/cpuinfo (i386 & amd64 version)
208  */
209 static int
210 linprocfs_docpuinfo(PFS_FILL_ARGS)
211 {
212         int hw_model[2];
213         char model[128];
214         size_t size;
215         int class, fqmhz, fqkhz;
216         int i;
217 
218         /*
219          * We default the flags to include all non-conflicting flags,
220          * and the Intel versions of conflicting flags.
221          */
222         static char *flags[] = {
223                 "fpu",      "vme",     "de",       "pse",      "tsc",
224                 "msr",      "pae",     "mce",      "cx8",      "apic",
225                 "sep",      "sep",     "mtrr",     "pge",      "mca",
226                 "cmov",     "pat",     "pse36",    "pn",       "b19",
227                 "b20",      "b21",     "mmxext",   "mmx",      "fxsr",
228                 "xmm",      "sse2",    "b27",      "b28",      "b29",
229                 "3dnowext", "3dnow"
230         };
231 
232         switch (cpu_class) {
233 #ifdef __i386__
234         case CPUCLASS_286:
235                 class = 2;
236                 break;
237         case CPUCLASS_386:
238                 class = 3;
239                 break;
240         case CPUCLASS_486:
241                 class = 4;
242                 break;
243         case CPUCLASS_586:
244                 class = 5;
245                 break;
246         case CPUCLASS_686:
247                 class = 6;
248                 break;
249         default:
250                 class = 0;
251                 break;
252 #else /* __amd64__ */
253         default:
254                 class = 15;
255                 break;
256 #endif
257         }
258 
259         hw_model[0] = CTL_HW;
260         hw_model[1] = HW_MODEL;
261         model[0] = '\0';
262         size = sizeof(model);
263         if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
264                 strcpy(model, "unknown");
265         for (i = 0; i < mp_ncpus; ++i) {
266                 sbuf_printf(sb,
267                     "processor\t: %d\n"
268                     "vendor_id\t: %.20s\n"
269                     "cpu family\t: %d\n"
270                     "model\t\t: %d\n"
271                     "model name\t: %s\n"
272                     "stepping\t: %d\n",
273                     i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
274                 /* XXX per-cpu vendor / class / model / id? */
275         }
276 
277         sbuf_cat(sb, "flags\t\t:");
278 
279         if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
280                 flags[16] = "fcmov";
281         } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
282                 flags[24] = "cxmmx";
283         }
284 
285         for (i = 0; i < 32; i++)
286                 if (cpu_feature & (1 << i))
287                         sbuf_printf(sb, " %s", flags[i]);
288         sbuf_cat(sb, "\n");
289         if (class >= 5) {
290                 fqmhz = (tsc_freq + 4999) / 1000000;
291                 fqkhz = ((tsc_freq + 4999) / 10000) % 100;
292                 sbuf_printf(sb,
293                     "cpu MHz\t\t: %d.%02d\n"
294                     "bogomips\t: %d.%02d\n",
295                     fqmhz, fqkhz, fqmhz, fqkhz);
296         }
297 
298         return (0);
299 }
300 #endif /* __i386__ || __amd64__ */
301 
302 /*
303  * Filler function for proc/mtab
304  *
305  * This file doesn't exist in Linux' procfs, but is included here so
306  * users can symlink /compat/linux/etc/mtab to /proc/mtab
307  */
308 static int
309 linprocfs_domtab(PFS_FILL_ARGS)
310 {
311         struct nameidata nd;
312         struct mount *mp;
313         const char *lep;
314         char *dlep, *flep, *mntto, *mntfrom, *fstype;
315         size_t lep_len;
316         int error;
317 
318         /* resolve symlinks etc. in the emulation tree prefix */
319         NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
320         flep = NULL;
321         error = namei(&nd);
322         lep = linux_emul_path;
323         if (error == 0) {
324                 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
325                         lep = dlep;
326                 vrele(nd.ni_vp);
327                 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
328         }
329         lep_len = strlen(lep);
330 
331         mtx_lock(&mountlist_mtx);
332         error = 0;
333         TAILQ_FOREACH(mp, &mountlist, mnt_list) {
334                 /* determine device name */
335                 mntfrom = mp->mnt_stat.f_mntfromname;
336 
337                 /* determine mount point */
338                 mntto = mp->mnt_stat.f_mntonname;
339                 if (strncmp(mntto, lep, lep_len) == 0 &&
340                     mntto[lep_len] == '/')
341                         mntto += lep_len;
342 
343                 /* determine fs type */
344                 fstype = mp->mnt_stat.f_fstypename;
345                 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
346                         mntfrom = fstype = "proc";
347                 else if (strcmp(fstype, "procfs") == 0)
348                         continue;
349 
350                 if (strcmp(fstype, "linsysfs") == 0) {
351                         sbuf_printf(sb, "/sys %s sysfs %s", mntto,
352                             mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
353                 } else {
354                         sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
355                             mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
356                 }
357 #define ADD_OPTION(opt, name) \
358         if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
359                 ADD_OPTION(MNT_SYNCHRONOUS,     "sync");
360                 ADD_OPTION(MNT_NOEXEC,          "noexec");
361                 ADD_OPTION(MNT_NOSUID,          "nosuid");
362                 ADD_OPTION(MNT_UNION,           "union");
363                 ADD_OPTION(MNT_ASYNC,           "async");
364                 ADD_OPTION(MNT_SUIDDIR,         "suiddir");
365                 ADD_OPTION(MNT_NOSYMFOLLOW,     "nosymfollow");
366                 ADD_OPTION(MNT_NOATIME,         "noatime");
367 #undef ADD_OPTION
368                 /* a real Linux mtab will also show NFS options */
369                 sbuf_printf(sb, " 0 0\n");
370         }
371         mtx_unlock(&mountlist_mtx);
372         if (flep != NULL)
373                 free(flep, M_TEMP);
374         return (error);
375 }
376 
377 /*
378  * Filler function for proc/stat
379  */
380 static int
381 linprocfs_dostat(PFS_FILL_ARGS)
382 {
383         struct pcpu *pcpu;
384         long cp_time[CPUSTATES];
385         long *cp;
386         int i;
387 
388         read_cpu_time(cp_time);
389         sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
390             T2J(cp_time[CP_USER]),
391             T2J(cp_time[CP_NICE]),
392             T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
393             T2J(cp_time[CP_IDLE]));
394         for (i = 0; i <= mp_maxid; ++i) {
395                 if (CPU_ABSENT(i))
396                         continue;
397                 pcpu = pcpu_find(i);
398                 cp = pcpu->pc_cp_time;
399                 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
400                     T2J(cp[CP_USER]),
401                     T2J(cp[CP_NICE]),
402                     T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
403                     T2J(cp[CP_IDLE]));
404         }
405         sbuf_printf(sb,
406             "disk 0 0 0 0\n"
407             "page %u %u\n"
408             "swap %u %u\n"
409             "intr %u\n"
410             "ctxt %u\n"
411             "btime %lld\n",
412             cnt.v_vnodepgsin,
413             cnt.v_vnodepgsout,
414             cnt.v_swappgsin,
415             cnt.v_swappgsout,
416             cnt.v_intr,
417             cnt.v_swtch,
418             (long long)boottime.tv_sec);
419         return (0);
420 }
421 
422 /*
423  * Filler function for proc/uptime
424  */
425 static int
426 linprocfs_douptime(PFS_FILL_ARGS)
427 {
428         long cp_time[CPUSTATES];
429         struct timeval tv;
430 
431         getmicrouptime(&tv);
432         read_cpu_time(cp_time);
433         sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
434             (long long)tv.tv_sec, tv.tv_usec / 10000,
435             T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
436         return (0);
437 }
438 
439 /*
440  * Get OS build date
441  */
442 static void
443 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
444 {
445 #if 0
446         char osbuild[256];
447         char *cp1, *cp2;
448 
449         strncpy(osbuild, version, 256);
450         osbuild[255] = '\0';
451         cp1 = strstr(osbuild, "\n");
452         cp2 = strstr(osbuild, ":");
453         if (cp1 && cp2) {
454                 *cp1 = *cp2 = '\0';
455                 cp1 = strstr(osbuild, "#");
456         } else
457                 cp1 = NULL;
458         if (cp1)
459                 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
460         else
461 #endif
462                 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
463 }
464 
465 /*
466  * Get OS builder
467  */
468 static void
469 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
470 {
471 #if 0
472         char builder[256];
473         char *cp;
474 
475         cp = strstr(version, "\n    ");
476         if (cp) {
477                 strncpy(builder, cp + 5, 256);
478                 builder[255] = '\0';
479                 cp = strstr(builder, ":");
480                 if (cp)
481                         *cp = '\0';
482         }
483         if (cp)
484                 sbuf_cat(sb, builder);
485         else
486 #endif
487                 sbuf_cat(sb, "des@freebsd.org");
488 }
489 
490 /*
491  * Filler function for proc/version
492  */
493 static int
494 linprocfs_doversion(PFS_FILL_ARGS)
495 {
496         char osname[LINUX_MAX_UTSNAME];
497         char osrelease[LINUX_MAX_UTSNAME];
498 
499         linux_get_osname(td, osname);
500         linux_get_osrelease(td, osrelease);
501         sbuf_printf(sb, "%s version %s (", osname, osrelease);
502         linprocfs_osbuilder(td, sb);
503         sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
504         linprocfs_osbuild(td, sb);
505         sbuf_cat(sb, "\n");
506 
507         return (0);
508 }
509 
510 /*
511  * Filler function for proc/loadavg
512  */
513 static int
514 linprocfs_doloadavg(PFS_FILL_ARGS)
515 {
516 
517         sbuf_printf(sb,
518             "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
519             (int)(averunnable.ldavg[0] / averunnable.fscale),
520             (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
521             (int)(averunnable.ldavg[1] / averunnable.fscale),
522             (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
523             (int)(averunnable.ldavg[2] / averunnable.fscale),
524             (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
525             1,                          /* number of running tasks */
526             nprocs,                     /* number of tasks */
527             lastpid                     /* the last pid */
528         );
529         return (0);
530 }
531 
532 /*
533  * Filler function for proc/pid/stat
534  */
535 static int
536 linprocfs_doprocstat(PFS_FILL_ARGS)
537 {
538         struct kinfo_proc kp;
539         char state;
540         static int ratelimit = 0;
541 
542         PROC_LOCK(p);
543         fill_kinfo_proc(p, &kp);
544         sbuf_printf(sb, "%d", p->p_pid);
545 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
546         PS_ADD("comm",          "(%s)", p->p_comm);
547         if (kp.ki_stat > sizeof(linux_state)) {
548                 state = 'R';
549 
550                 if (ratelimit == 0) {
551                         printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
552                             kp.ki_stat, sizeof(linux_state));
553                         ++ratelimit;
554                 }
555         } else
556                 state = linux_state[kp.ki_stat - 1];
557         PS_ADD("state",         "%c",   state);
558         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
559         PS_ADD("pgrp",          "%d",   p->p_pgid);
560         PS_ADD("session",       "%d",   p->p_session->s_sid);
561         PROC_UNLOCK(p);
562         PS_ADD("tty",           "%d",   0); /* XXX */
563         PS_ADD("tpgid",         "%d",   kp.ki_tpgid);
564         PS_ADD("flags",         "%u",   0); /* XXX */
565         PS_ADD("minflt",        "%lu",  kp.ki_rusage.ru_minflt);
566         PS_ADD("cminflt",       "%lu",  kp.ki_rusage_ch.ru_minflt);
567         PS_ADD("majflt",        "%lu",  kp.ki_rusage.ru_majflt);
568         PS_ADD("cmajflt",       "%lu",  kp.ki_rusage_ch.ru_majflt);
569         PS_ADD("utime",         "%ld",  T2J(tvtohz(&kp.ki_rusage.ru_utime)));
570         PS_ADD("stime",         "%ld",  T2J(tvtohz(&kp.ki_rusage.ru_stime)));
571         PS_ADD("cutime",        "%ld",  T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
572         PS_ADD("cstime",        "%ld",  T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
573         PS_ADD("priority",      "%d",   kp.ki_pri.pri_user);
574         PS_ADD("nice",          "%d",   kp.ki_nice); /* 19 (nicest) to -19 */
575         PS_ADD("",             "%d",   0); /* removed field */
576         PS_ADD("itrealvalue",   "%d",   0); /* XXX */
577         /* XXX: starttime is not right, it is the _same_ for _every_ process.
578            It should be the number of jiffies between system boot and process
579            start. */
580         PS_ADD("starttime",     "%lu",  T2J(tvtohz(&kp.ki_start)));
581         PS_ADD("vsize",         "%ju",  P2K((uintmax_t)kp.ki_size));
582         PS_ADD("rss",           "%ju",  (uintmax_t)kp.ki_rssize);
583         PS_ADD("rlim",          "%lu",  kp.ki_rusage.ru_maxrss);
584         PS_ADD("startcode",     "%u",   (unsigned)0);
585         PS_ADD("endcode",       "%u",   0); /* XXX */
586         PS_ADD("startstack",    "%u",   0); /* XXX */
587         PS_ADD("kstkesp",       "%u",   0); /* XXX */
588         PS_ADD("kstkeip",       "%u",   0); /* XXX */
589         PS_ADD("signal",        "%u",   0); /* XXX */
590         PS_ADD("blocked",       "%u",   0); /* XXX */
591         PS_ADD("sigignore",     "%u",   0); /* XXX */
592         PS_ADD("sigcatch",      "%u",   0); /* XXX */
593         PS_ADD("wchan",         "%u",   0); /* XXX */
594         PS_ADD("nswap",         "%lu",  kp.ki_rusage.ru_nswap);
595         PS_ADD("cnswap",        "%lu",  kp.ki_rusage_ch.ru_nswap);
596         PS_ADD("exitsignal",    "%d",   0); /* XXX */
597         PS_ADD("processor",     "%u",   kp.ki_lastcpu);
598         PS_ADD("rt_priority",   "%u",   0); /* XXX */ /* >= 2.5.19 */
599         PS_ADD("policy",        "%u",   kp.ki_pri.pri_class); /* >= 2.5.19 */
600 #undef PS_ADD
601         sbuf_putc(sb, '\n');
602 
603         return (0);
604 }
605 
606 /*
607  * Filler function for proc/pid/statm
608  */
609 static int
610 linprocfs_doprocstatm(PFS_FILL_ARGS)
611 {
612         struct kinfo_proc kp;
613         segsz_t lsize;
614 
615         PROC_LOCK(p);
616         fill_kinfo_proc(p, &kp);
617         PROC_UNLOCK(p);
618 
619         /*
620          * See comments in linprocfs_doprocstatus() regarding the
621          * computation of lsize.
622          */
623         /* size resident share trs drs lrs dt */
624         sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
625         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
626         sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
627         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
628         sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
629         lsize = B2P(kp.ki_size) - kp.ki_dsize -
630             kp.ki_ssize - kp.ki_tsize - 1;
631         sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
632         sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
633 
634         return (0);
635 }
636 
637 /*
638  * Filler function for proc/pid/status
639  */
640 static int
641 linprocfs_doprocstatus(PFS_FILL_ARGS)
642 {
643         struct kinfo_proc kp;
644         char *state;
645         segsz_t lsize;
646         struct thread *td2;
647         struct sigacts *ps;
648         int i;
649 
650         PROC_LOCK(p);
651         td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
652 
653         if (P_SHOULDSTOP(p)) {
654                 state = "T (stopped)";
655         } else {
656                 PROC_SLOCK(p);
657                 switch(p->p_state) {
658                 case PRS_NEW:
659                         state = "I (idle)";
660                         break;
661                 case PRS_NORMAL:
662                         if (p->p_flag & P_WEXIT) {
663                                 state = "X (exiting)";
664                                 break;
665                         }
666                         switch(td2->td_state) {
667                         case TDS_INHIBITED:
668                                 state = "S (sleeping)";
669                                 break;
670                         case TDS_RUNQ:
671                         case TDS_RUNNING:
672                                 state = "R (running)";
673                                 break;
674                         default:
675                                 state = "? (unknown)";
676                                 break;
677                         }
678                         break;
679                 case PRS_ZOMBIE:
680                         state = "Z (zombie)";
681                         break;
682                 default:
683                         state = "? (unknown)";
684                         break;
685                 }
686                 PROC_SUNLOCK(p);
687         }
688 
689         fill_kinfo_proc(p, &kp);
690         sbuf_printf(sb, "Name:\t%s\n",          p->p_comm); /* XXX escape */
691         sbuf_printf(sb, "State:\t%s\n",         state);
692 
693         /*
694          * Credentials
695          */
696         sbuf_printf(sb, "Pid:\t%d\n",           p->p_pid);
697         sbuf_printf(sb, "PPid:\t%d\n",          p->p_pptr ?
698                                                 p->p_pptr->p_pid : 0);
699         sbuf_printf(sb, "Uid:\t%d %d %d %d\n",  p->p_ucred->cr_ruid,
700                                                 p->p_ucred->cr_uid,
701                                                 p->p_ucred->cr_svuid,
702                                                 /* FreeBSD doesn't have fsuid */
703                                                 p->p_ucred->cr_uid);
704         sbuf_printf(sb, "Gid:\t%d %d %d %d\n",  p->p_ucred->cr_rgid,
705                                                 p->p_ucred->cr_gid,
706                                                 p->p_ucred->cr_svgid,
707                                                 /* FreeBSD doesn't have fsgid */
708                                                 p->p_ucred->cr_gid);
709         sbuf_cat(sb, "Groups:\t");
710         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
711                 sbuf_printf(sb, "%d ",          p->p_ucred->cr_groups[i]);
712         PROC_UNLOCK(p);
713         sbuf_putc(sb, '\n');
714 
715         /*
716          * Memory
717          *
718          * While our approximation of VmLib may not be accurate (I
719          * don't know of a simple way to verify it, and I'm not sure
720          * it has much meaning anyway), I believe it's good enough.
721          *
722          * The same code that could (I think) accurately compute VmLib
723          * could also compute VmLck, but I don't really care enough to
724          * implement it. Submissions are welcome.
725          */
726         sbuf_printf(sb, "VmSize:\t%8ju kB\n",   B2K((uintmax_t)kp.ki_size));
727         sbuf_printf(sb, "VmLck:\t%8u kB\n",     P2K(0)); /* XXX */
728         sbuf_printf(sb, "VmRss:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_rssize));
729         sbuf_printf(sb, "VmData:\t%8ju kB\n",   P2K((uintmax_t)kp.ki_dsize));
730         sbuf_printf(sb, "VmStk:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_ssize));
731         sbuf_printf(sb, "VmExe:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_tsize));
732         lsize = B2P(kp.ki_size) - kp.ki_dsize -
733             kp.ki_ssize - kp.ki_tsize - 1;
734         sbuf_printf(sb, "VmLib:\t%8ju kB\n",    P2K((uintmax_t)lsize));
735 
736         /*
737          * Signal masks
738          *
739          * We support up to 128 signals, while Linux supports 32,
740          * but we only define 32 (the same 32 as Linux, to boot), so
741          * just show the lower 32 bits of each mask. XXX hack.
742          *
743          * NB: on certain platforms (Sparc at least) Linux actually
744          * supports 64 signals, but this code is a long way from
745          * running on anything but i386, so ignore that for now.
746          */
747         PROC_LOCK(p);
748         sbuf_printf(sb, "SigPnd:\t%08x\n",      p->p_siglist.__bits[0]);
749         /*
750          * I can't seem to find out where the signal mask is in
751          * relation to struct proc, so SigBlk is left unimplemented.
752          */
753         sbuf_printf(sb, "SigBlk:\t%08x\n",      0); /* XXX */
754         ps = p->p_sigacts;
755         mtx_lock(&ps->ps_mtx);
756         sbuf_printf(sb, "SigIgn:\t%08x\n",      ps->ps_sigignore.__bits[0]);
757         sbuf_printf(sb, "SigCgt:\t%08x\n",      ps->ps_sigcatch.__bits[0]);
758         mtx_unlock(&ps->ps_mtx);
759         PROC_UNLOCK(p);
760 
761         /*
762          * Linux also prints the capability masks, but we don't have
763          * capabilities yet, and when we do get them they're likely to
764          * be meaningless to Linux programs, so we lie. XXX
765          */
766         sbuf_printf(sb, "CapInh:\t%016x\n",     0);
767         sbuf_printf(sb, "CapPrm:\t%016x\n",     0);
768         sbuf_printf(sb, "CapEff:\t%016x\n",     0);
769 
770         return (0);
771 }
772 
773 
774 /*
775  * Filler function for proc/pid/cwd
776  */
777 static int
778 linprocfs_doproccwd(PFS_FILL_ARGS)
779 {
780         char *fullpath = "unknown";
781         char *freepath = NULL;
782 
783         vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
784         sbuf_printf(sb, "%s", fullpath);
785         if (freepath)
786                 free(freepath, M_TEMP);
787         return (0);
788 }
789 
790 /*
791  * Filler function for proc/pid/root
792  */
793 static int
794 linprocfs_doprocroot(PFS_FILL_ARGS)
795 {
796         struct vnode *rvp;
797         char *fullpath = "unknown";
798         char *freepath = NULL;
799 
800         rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
801         vn_fullpath(td, rvp, &fullpath, &freepath);
802         sbuf_printf(sb, "%s", fullpath);
803         if (freepath)
804                 free(freepath, M_TEMP);
805         return (0);
806 }
807 
808 /*
809  * Filler function for proc/pid/cmdline
810  */
811 static int
812 linprocfs_doproccmdline(PFS_FILL_ARGS)
813 {
814         struct ps_strings pstr;
815         char **ps_argvstr;
816         int error, i;
817 
818         /*
819          * If we are using the ps/cmdline caching, use that.  Otherwise
820          * revert back to the old way which only implements full cmdline
821          * for the currept process and just p->p_comm for all other
822          * processes.
823          * Note that if the argv is no longer available, we deliberately
824          * don't fall back on p->p_comm or return an error: the authentic
825          * Linux behaviour is to return zero-length in this case.
826          */
827 
828         PROC_LOCK(p);
829         if (p->p_args && p_cansee(td, p) == 0) {
830                 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
831                 PROC_UNLOCK(p);
832         } else if (p != td->td_proc) {
833                 PROC_UNLOCK(p);
834                 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
835         } else {
836                 PROC_UNLOCK(p);
837                 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
838                     sizeof(pstr));
839                 if (error)
840                         return (error);
841                 if (pstr.ps_nargvstr > ARG_MAX)
842                         return (E2BIG);
843                 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
844                     M_TEMP, M_WAITOK);
845                 error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
846                     pstr.ps_nargvstr * sizeof(char *));
847                 if (error) {
848                         free(ps_argvstr, M_TEMP);
849                         return (error);
850                 }
851                 for (i = 0; i < pstr.ps_nargvstr; i++) {
852                         sbuf_copyin(sb, ps_argvstr[i], 0);
853                         sbuf_printf(sb, "%c", '\0');
854                 }
855                 free(ps_argvstr, M_TEMP);
856         }
857 
858         return (0);
859 }
860 
861 /*
862  * Filler function for proc/pid/environ
863  */
864 static int
865 linprocfs_doprocenviron(PFS_FILL_ARGS)
866 {
867 
868         sbuf_printf(sb, "doprocenviron\n%c", '\0');
869         return (0);
870 }
871 
872 /*
873  * Filler function for proc/pid/maps
874  */
875 static int
876 linprocfs_doprocmaps(PFS_FILL_ARGS)
877 {
878         struct vmspace *vm;
879         vm_map_t map;
880         vm_map_entry_t entry, tmp_entry;
881         vm_object_t obj, tobj, lobj;
882         vm_offset_t e_start, e_end;
883         vm_ooffset_t off = 0;
884         vm_prot_t e_prot;
885         unsigned int last_timestamp;
886         char *name = "", *freename = NULL;
887         ino_t ino;
888         int ref_count, shadow_count, flags;
889         int error;
890         struct vnode *vp;
891         struct vattr vat;
892         int locked;
893 
894         PROC_LOCK(p);
895         error = p_candebug(td, p);
896         PROC_UNLOCK(p);
897         if (error)
898                 return (error);
899 
900         if (uio->uio_rw != UIO_READ)
901                 return (EOPNOTSUPP);
902 
903         error = 0;
904         vm = vmspace_acquire_ref(p);
905         if (vm == NULL)
906                 return (ESRCH);
907         map = &vm->vm_map;
908         vm_map_lock_read(map);
909         for (entry = map->header.next; entry != &map->header;
910             entry = entry->next) {
911                 name = "";
912                 freename = NULL;
913                 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
914                         continue;
915                 e_prot = entry->protection;
916                 e_start = entry->start;
917                 e_end = entry->end;
918                 obj = entry->object.vm_object;
919                 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
920                         VM_OBJECT_LOCK(tobj);
921                         if (lobj != obj)
922                                 VM_OBJECT_UNLOCK(lobj);
923                         lobj = tobj;
924                 }
925                 last_t