]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - sys/compat/linprocfs/linprocfs.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / sys / compat / linprocfs / linprocfs.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
42 #include "opt_compat.h"
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD$");
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/ptrace.h>
65 #include <sys/resourcevar.h>
66 #include <sys/sbuf.h>
67 #include <sys/sem.h>
68 #include <sys/smp.h>
69 #include <sys/socket.h>
70 #include <sys/sysctl.h>
71 #include <sys/systm.h>
72 #include <sys/time.h>
73 #include <sys/tty.h>
74 #include <sys/user.h>
75 #include <sys/vmmeter.h>
76 #include <sys/vnode.h>
77 #include <sys/bus.h>
78
79 #include <net/if.h>
80 #include <net/vnet.h>
81
82 #include <vm/vm.h>
83 #include <vm/vm_extern.h>
84 #include <vm/pmap.h>
85 #include <vm/vm_map.h>
86 #include <vm/vm_param.h>
87 #include <vm/vm_object.h>
88 #include <vm/swap_pager.h>
89
90 #include <machine/clock.h>
91
92 #include <geom/geom.h>
93 #include <geom/geom_int.h>
94
95 #if defined(__i386__) || defined(__amd64__)
96 #include <machine/cputypes.h>
97 #include <machine/md_var.h>
98 #endif /* __i386__ || __amd64__ */
99
100 #ifdef COMPAT_FREEBSD32
101 #include <compat/freebsd32/freebsd32_util.h>
102 #endif
103
104 #ifdef COMPAT_LINUX32                           /* XXX */
105 #include <machine/../linux32/linux.h>
106 #else
107 #include <machine/../linux/linux.h>
108 #endif
109 #include <compat/linux/linux_ioctl.h>
110 #include <compat/linux/linux_mib.h>
111 #include <compat/linux/linux_util.h>
112 #include <fs/pseudofs/pseudofs.h>
113 #include <fs/procfs/procfs.h>
114
115 /*
116  * Various conversion macros
117  */
118 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz)))        /* ticks to jiffies */
119 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz)))      /* ticks to centiseconds */
120 #define T2S(x) ((x) / (stathz ? stathz : hz))           /* ticks to seconds */
121 #define B2K(x) ((x) >> 10)                              /* bytes to kbytes */
122 #define B2P(x) ((x) >> PAGE_SHIFT)                      /* bytes to pages */
123 #define P2B(x) ((x) << PAGE_SHIFT)                      /* pages to bytes */
124 #define P2K(x) ((x) << (PAGE_SHIFT - 10))               /* pages to kbytes */
125 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
126
127 /**
128  * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
129  *
130  * The linux procfs state field displays one of the characters RSDZTW to
131  * denote running, sleeping in an interruptible wait, waiting in an
132  * uninterruptible disk sleep, a zombie process, process is being traced
133  * or stopped, or process is paging respectively.
134  *
135  * Our struct kinfo_proc contains the variable ki_stat which contains a
136  * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
137  *
138  * This character array is used with ki_stati-1 as an index and tries to
139  * map our states to suitable linux states.
140  */
141 static char linux_state[] = "RRSTZDD";
142
143 /*
144  * Filler function for proc/meminfo
145  */
146 static int
147 linprocfs_domeminfo(PFS_FILL_ARGS)
148 {
149         unsigned long memtotal;         /* total memory in bytes */
150         unsigned long memused;          /* used memory in bytes */
151         unsigned long memfree;          /* free memory in bytes */
152         unsigned long memshared;        /* shared memory ??? */
153         unsigned long buffers, cached;  /* buffer / cache memory ??? */
154         unsigned long long swaptotal;   /* total swap space in bytes */
155         unsigned long long swapused;    /* used swap space in bytes */
156         unsigned long long swapfree;    /* free swap space in bytes */
157         vm_object_t object;
158         int i, j;
159
160         memtotal = physmem * PAGE_SIZE;
161         /*
162          * The correct thing here would be:
163          *
164         memfree = cnt.v_free_count * PAGE_SIZE;
165         memused = memtotal - memfree;
166          *
167          * but it might mislead linux binaries into thinking there
168          * is very little memory left, so we cheat and tell them that
169          * all memory that isn't wired down is free.
170          */
171         memused = cnt.v_wire_count * PAGE_SIZE;
172         memfree = memtotal - memused;
173         swap_pager_status(&i, &j);
174         swaptotal = (unsigned long long)i * PAGE_SIZE;
175         swapused = (unsigned long long)j * PAGE_SIZE;
176         swapfree = swaptotal - swapused;
177         memshared = 0;
178         mtx_lock(&vm_object_list_mtx);
179         TAILQ_FOREACH(object, &vm_object_list, object_list)
180                 if (object->shadow_count > 1)
181                         memshared += object->resident_page_count;
182         mtx_unlock(&vm_object_list_mtx);
183         memshared *= PAGE_SIZE;
184         /*
185          * We'd love to be able to write:
186          *
187         buffers = bufspace;
188          *
189          * but bufspace is internal to vfs_bio.c and we don't feel
190          * like unstaticizing it just for linprocfs's sake.
191          */
192         buffers = 0;
193         cached = cnt.v_cache_count * PAGE_SIZE;
194
195         sbuf_printf(sb,
196             "        total:    used:    free:  shared: buffers:  cached:\n"
197             "Mem:  %lu %lu %lu %lu %lu %lu\n"
198             "Swap: %llu %llu %llu\n"
199             "MemTotal: %9lu kB\n"
200             "MemFree:  %9lu kB\n"
201             "MemShared:%9lu kB\n"
202             "Buffers:  %9lu kB\n"
203             "Cached:   %9lu kB\n"
204             "SwapTotal:%9llu kB\n"
205             "SwapFree: %9llu kB\n",
206             memtotal, memused, memfree, memshared, buffers, cached,
207             swaptotal, swapused, swapfree,
208             B2K(memtotal), B2K(memfree),
209             B2K(memshared), B2K(buffers), B2K(cached),
210             B2K(swaptotal), B2K(swapfree));
211
212         return (0);
213 }
214
215 #if defined(__i386__) || defined(__amd64__)
216 /*
217  * Filler function for proc/cpuinfo (i386 & amd64 version)
218  */
219 static int
220 linprocfs_docpuinfo(PFS_FILL_ARGS)
221 {
222         int hw_model[2];
223         char model[128];
224         uint64_t freq;
225         size_t size;
226         int class, fqmhz, fqkhz;
227         int i;
228
229         /*
230          * We default the flags to include all non-conflicting flags,
231          * and the Intel versions of conflicting flags.
232          */
233         static char *flags[] = {
234                 "fpu",      "vme",     "de",       "pse",      "tsc",
235                 "msr",      "pae",     "mce",      "cx8",      "apic",
236                 "sep",      "sep",     "mtrr",     "pge",      "mca",
237                 "cmov",     "pat",     "pse36",    "pn",       "b19",
238                 "b20",      "b21",     "mmxext",   "mmx",      "fxsr",
239                 "xmm",      "sse2",    "b27",      "b28",      "b29",
240                 "3dnowext", "3dnow"
241         };
242
243         switch (cpu_class) {
244 #ifdef __i386__
245         case CPUCLASS_286:
246                 class = 2;
247                 break;
248         case CPUCLASS_386:
249                 class = 3;
250                 break;
251         case CPUCLASS_486:
252                 class = 4;
253                 break;
254         case CPUCLASS_586:
255                 class = 5;
256                 break;
257         case CPUCLASS_686:
258                 class = 6;
259                 break;
260         default:
261                 class = 0;
262                 break;
263 #else /* __amd64__ */
264         default:
265                 class = 15;
266                 break;
267 #endif
268         }
269
270         hw_model[0] = CTL_HW;
271         hw_model[1] = HW_MODEL;
272         model[0] = '\0';
273         size = sizeof(model);
274         if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
275                 strcpy(model, "unknown");
276         for (i = 0; i < mp_ncpus; ++i) {
277                 sbuf_printf(sb,
278                     "processor\t: %d\n"
279                     "vendor_id\t: %.20s\n"
280                     "cpu family\t: %u\n"
281                     "model\t\t: %u\n"
282                     "model name\t: %s\n"
283                     "stepping\t: %u\n\n",
284                     i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
285                     CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
286                 /* XXX per-cpu vendor / class / model / id? */
287         }
288
289         sbuf_cat(sb, "flags\t\t:");
290
291 #ifdef __i386__
292         switch (cpu_vendor_id) {
293         case CPU_VENDOR_AMD:
294                 if (class < 6)
295                         flags[16] = "fcmov";
296                 break;
297         case CPU_VENDOR_CYRIX:
298                 flags[24] = "cxmmx";
299                 break;
300         }
301 #endif
302
303         for (i = 0; i < 32; i++)
304                 if (cpu_feature & (1 << i))
305                         sbuf_printf(sb, " %s", flags[i]);
306         sbuf_cat(sb, "\n");
307         freq = atomic_load_acq_64(&tsc_freq);
308         if (freq != 0) {
309                 fqmhz = (freq + 4999) / 1000000;
310                 fqkhz = ((freq + 4999) / 10000) % 100;
311                 sbuf_printf(sb,
312                     "cpu MHz\t\t: %d.%02d\n"
313                     "bogomips\t: %d.%02d\n",
314                     fqmhz, fqkhz, fqmhz, fqkhz);
315         }
316
317         return (0);
318 }
319 #endif /* __i386__ || __amd64__ */
320
321 /*
322  * Filler function for proc/mtab
323  *
324  * This file doesn't exist in Linux' procfs, but is included here so
325  * users can symlink /compat/linux/etc/mtab to /proc/mtab
326  */
327 static int
328 linprocfs_domtab(PFS_FILL_ARGS)
329 {
330         struct nameidata nd;
331         struct mount *mp;
332         const char *lep;
333         char *dlep, *flep, *mntto, *mntfrom, *fstype;
334         size_t lep_len;
335         int error;
336
337         /* resolve symlinks etc. in the emulation tree prefix */
338         NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
339         flep = NULL;
340         error = namei(&nd);
341         lep = linux_emul_path;
342         if (error == 0) {
343                 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
344                         lep = dlep;
345                 vrele(nd.ni_vp);
346                 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
347         }
348         lep_len = strlen(lep);
349
350         mtx_lock(&mountlist_mtx);
351         error = 0;
352         TAILQ_FOREACH(mp, &mountlist, mnt_list) {
353                 /* determine device name */
354                 mntfrom = mp->mnt_stat.f_mntfromname;
355
356                 /* determine mount point */
357                 mntto = mp->mnt_stat.f_mntonname;
358                 if (strncmp(mntto, lep, lep_len) == 0 &&
359                     mntto[lep_len] == '/')
360                         mntto += lep_len;
361
362                 /* determine fs type */
363                 fstype = mp->mnt_stat.f_fstypename;
364                 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
365                         mntfrom = fstype = "proc";
366                 else if (strcmp(fstype, "procfs") == 0)
367                         continue;
368
369                 if (strcmp(fstype, "linsysfs") == 0) {
370                         sbuf_printf(sb, "/sys %s sysfs %s", mntto,
371                             mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
372                 } else {
373                         /* For Linux msdosfs is called vfat */
374                         if (strcmp(fstype, "msdosfs") == 0)
375                                 fstype = "vfat";
376                         sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
377                             mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
378                 }
379 #define ADD_OPTION(opt, name) \
380         if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
381                 ADD_OPTION(MNT_SYNCHRONOUS,     "sync");
382                 ADD_OPTION(MNT_NOEXEC,          "noexec");
383                 ADD_OPTION(MNT_NOSUID,          "nosuid");
384                 ADD_OPTION(MNT_UNION,           "union");
385                 ADD_OPTION(MNT_ASYNC,           "async");
386                 ADD_OPTION(MNT_SUIDDIR,         "suiddir");
387                 ADD_OPTION(MNT_NOSYMFOLLOW,     "nosymfollow");
388                 ADD_OPTION(MNT_NOATIME,         "noatime");
389 #undef ADD_OPTION
390                 /* a real Linux mtab will also show NFS options */
391                 sbuf_printf(sb, " 0 0\n");
392         }
393         mtx_unlock(&mountlist_mtx);
394         if (flep != NULL)
395                 free(flep, M_TEMP);
396         return (error);
397 }
398
399 /*
400  * Filler function for proc/partitions
401  *
402  */
403 static int
404 linprocfs_dopartitions(PFS_FILL_ARGS)
405 {
406         struct g_class *cp;
407         struct g_geom *gp;
408         struct g_provider *pp;
409         struct nameidata nd;
410         const char *lep;
411         char  *dlep, *flep;
412         size_t lep_len;
413         int error;
414         int major, minor;
415
416         /* resolve symlinks etc. in the emulation tree prefix */
417         NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
418         flep = NULL;
419         error = namei(&nd);
420         lep = linux_emul_path;
421         if (error == 0) {
422                 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
423                         lep = dlep;
424                 vrele(nd.ni_vp);
425                 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
426         }
427         lep_len = strlen(lep);
428
429         g_topology_lock();
430         error = 0;
431         sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
432             "ruse wio wmerge wsect wuse running use aveq\n");
433
434         LIST_FOREACH(cp, &g_classes, class) {
435                 if (strcmp(cp->name, "DISK") == 0 ||
436                     strcmp(cp->name, "PART") == 0)
437                         LIST_FOREACH(gp, &cp->geom, geom) {
438                                 LIST_FOREACH(pp, &gp->provider, provider) {
439                                         if (linux_driver_get_major_minor(
440                                             pp->name, &major, &minor) != 0) {
441                                                 major = 0;
442                                                 minor = 0;
443                                         }
444                                         sbuf_printf(sb, "%d %d %lld %s "
445                                             "%d %d %d %d %d "
446                                              "%d %d %d %d %d %d\n",
447                                              major, minor,
448                                              (long long)pp->mediasize, pp->name,
449                                              0, 0, 0, 0, 0,
450                                              0, 0, 0, 0, 0, 0);
451                                 }
452                         }
453         }
454         g_topology_unlock();
455
456         if (flep != NULL)
457                 free(flep, M_TEMP);
458         return (error);
459 }
460
461
462 /*
463  * Filler function for proc/stat
464  */
465 static int
466 linprocfs_dostat(PFS_FILL_ARGS)
467 {
468         struct pcpu *pcpu;
469         long cp_time[CPUSTATES];
470         long *cp;
471         int i;
472
473         read_cpu_time(cp_time);
474         sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
475             T2J(cp_time[CP_USER]),
476             T2J(cp_time[CP_NICE]),
477             T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
478             T2J(cp_time[CP_IDLE]));
479         CPU_FOREACH(i) {
480                 pcpu = pcpu_find(i);
481                 cp = pcpu->pc_cp_time;
482                 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
483                     T2J(cp[CP_USER]),
484                     T2J(cp[CP_NICE]),
485                     T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
486                     T2J(cp[CP_IDLE]));
487         }
488         sbuf_printf(sb,
489             "disk 0 0 0 0\n"
490             "page %u %u\n"
491             "swap %u %u\n"
492             "intr %u\n"
493             "ctxt %u\n"
494             "btime %lld\n",
495             cnt.v_vnodepgsin,
496             cnt.v_vnodepgsout,
497             cnt.v_swappgsin,
498             cnt.v_swappgsout,
499             cnt.v_intr,
500             cnt.v_swtch,
501             (long long)boottime.tv_sec);
502         return (0);
503 }
504
505 static int
506 linprocfs_doswaps(PFS_FILL_ARGS)
507 {
508         struct xswdev xsw;
509         uintmax_t total, used;
510         int n;
511         char devname[SPECNAMELEN + 1];
512
513         sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
514         mtx_lock(&Giant);
515         for (n = 0; ; n++) {
516                 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
517                         break;
518                 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
519                 used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
520
521                 /*
522                  * The space and not tab after the device name is on
523                  * purpose.  Linux does so.
524                  */
525                 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
526                     devname, total, used);
527         }
528         mtx_unlock(&Giant);
529         return (0);
530 }
531
532 /*
533  * Filler function for proc/uptime
534  */
535 static int
536 linprocfs_douptime(PFS_FILL_ARGS)
537 {
538         long cp_time[CPUSTATES];
539         struct timeval tv;
540
541         getmicrouptime(&tv);
542         read_cpu_time(cp_time);
543         sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
544             (long long)tv.tv_sec, tv.tv_usec / 10000,
545             T2S(cp_time[CP_IDLE] / mp_ncpus),
546             T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
547         return (0);
548 }
549
550 /*
551  * Get OS build date
552  */
553 static void
554 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
555 {
556 #if 0
557         char osbuild[256];
558         char *cp1, *cp2;
559
560         strncpy(osbuild, version, 256);
561         osbuild[255] = '\0';
562         cp1 = strstr(osbuild, "\n");
563         cp2 = strstr(osbuild, ":");
564         if (cp1 && cp2) {
565                 *cp1 = *cp2 = '\0';
566                 cp1 = strstr(osbuild, "#");
567         } else
568                 cp1 = NULL;
569         if (cp1)
570                 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
571         else
572 #endif
573                 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
574 }
575
576 /*
577  * Get OS builder
578  */
579 static void
580 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
581 {
582 #if 0
583         char builder[256];
584         char *cp;
585
586         cp = strstr(version, "\n    ");
587         if (cp) {
588                 strncpy(builder, cp + 5, 256);
589                 builder[255] = '\0';
590                 cp = strstr(builder, ":");
591                 if (cp)
592                         *cp = '\0';
593         }
594         if (cp)
595                 sbuf_cat(sb, builder);
596         else
597 #endif
598                 sbuf_cat(sb, "des@freebsd.org");
599 }
600
601 /*
602  * Filler function for proc/version
603  */
604 static int
605 linprocfs_doversion(PFS_FILL_ARGS)
606 {
607         char osname[LINUX_MAX_UTSNAME];
608         char osrelease[LINUX_MAX_UTSNAME];
609
610         linux_get_osname(td, osname);
611         linux_get_osrelease(td, osrelease);
612         sbuf_printf(sb, "%s version %s (", osname, osrelease);
613         linprocfs_osbuilder(td, sb);
614         sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
615         linprocfs_osbuild(td, sb);
616         sbuf_cat(sb, "\n");
617
618         return (0);
619 }
620
621 /*
622  * Filler function for proc/loadavg
623  */
624 static int
625 linprocfs_doloadavg(PFS_FILL_ARGS)
626 {
627
628         sbuf_printf(sb,
629             "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
630             (int)(averunnable.ldavg[0] / averunnable.fscale),
631             (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
632             (int)(averunnable.ldavg[1] / averunnable.fscale),
633             (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
634             (int)(averunnable.ldavg[2] / averunnable.fscale),
635             (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
636             1,                          /* number of running tasks */
637             nprocs,                     /* number of tasks */
638             lastpid                     /* the last pid */
639         );
640         return (0);
641 }
642
643 /*
644  * Filler function for proc/pid/stat
645  */
646 static int
647 linprocfs_doprocstat(PFS_FILL_ARGS)
648 {
649         struct kinfo_proc kp;
650         char state;
651         static int ratelimit = 0;
652         vm_offset_t startcode, startdata;
653
654         PROC_LOCK(p);
655         fill_kinfo_proc(p, &kp);
656         if (p->p_vmspace) {
657            startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
658            startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
659         } else {
660            startcode = 0;
661            startdata = 0;
662         };
663         sbuf_printf(sb, "%d", p->p_pid);
664 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
665         PS_ADD("comm",          "(%s)", p->p_comm);
666         if (kp.ki_stat > sizeof(linux_state)) {
667                 state = 'R';
668
669                 if (ratelimit == 0) {
670                         printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
671                             kp.ki_stat, sizeof(linux_state));
672                         ++ratelimit;
673                 }
674         } else
675                 state = linux_state[kp.ki_stat - 1];
676         PS_ADD("state",         "%c",   state);
677         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
678         PS_ADD("pgrp",          "%d",   p->p_pgid);
679         PS_ADD("session",       "%d",   p->p_session->s_sid);
680         PROC_UNLOCK(p);
681         PS_ADD("tty",           "%d",   kp.ki_tdev);
682         PS_ADD("tpgid",         "%d",   kp.ki_tpgid);
683         PS_ADD("flags",         "%u",   0); /* XXX */
684         PS_ADD("minflt",        "%lu",  kp.ki_rusage.ru_minflt);
685         PS_ADD("cminflt",       "%lu",  kp.ki_rusage_ch.ru_minflt);
686         PS_ADD("majflt",        "%lu",  kp.ki_rusage.ru_majflt);
687         PS_ADD("cmajflt",       "%lu",  kp.ki_rusage_ch.ru_majflt);
688         PS_ADD("utime",         "%ld",  TV2J(&kp.ki_rusage.ru_utime));
689         PS_ADD("stime",         "%ld",  TV2J(&kp.ki_rusage.ru_stime));
690         PS_ADD("cutime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_utime));
691         PS_ADD("cstime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_stime));
692         PS_ADD("priority",      "%d",   kp.ki_pri.pri_user);
693         PS_ADD("nice",          "%d",   kp.ki_nice); /* 19 (nicest) to -19 */
694         PS_ADD("0",             "%d",   0); /* removed field */
695         PS_ADD("itrealvalue",   "%d",   0); /* XXX */
696         PS_ADD("starttime",     "%lu",  TV2J(&kp.ki_start) - TV2J(&boottime));
697         PS_ADD("vsize",         "%ju",  P2K((uintmax_t)kp.ki_size));
698         PS_ADD("rss",           "%ju",  (uintmax_t)kp.ki_rssize);
699         PS_ADD("rlim",          "%lu",  kp.ki_rusage.ru_maxrss);
700         PS_ADD("startcode",     "%ju",  (uintmax_t)startcode);
701         PS_ADD("endcode",       "%ju",  (uintmax_t)startdata);
702         PS_ADD("startstack",    "%u",   0); /* XXX */
703         PS_ADD("kstkesp",       "%u",   0); /* XXX */
704         PS_ADD("kstkeip",       "%u",   0); /* XXX */
705         PS_ADD("signal",        "%u",   0); /* XXX */
706         PS_ADD("blocked",       "%u",   0); /* XXX */
707         PS_ADD("sigignore",     "%u",   0); /* XXX */
708         PS_ADD("sigcatch",      "%u",   0); /* XXX */
709         PS_ADD("wchan",         "%u",   0); /* XXX */
710         PS_ADD("nswap",         "%lu",  kp.ki_rusage.ru_nswap);
711         PS_ADD("cnswap",        "%lu",  kp.ki_rusage_ch.ru_nswap);
712         PS_ADD("exitsignal",    "%d",   0); /* XXX */
713         PS_ADD("processor",     "%u",   kp.ki_lastcpu);
714         PS_ADD("rt_priority",   "%u",   0); /* XXX */ /* >= 2.5.19 */
715         PS_ADD("policy",        "%u",   kp.ki_pri.pri_class); /* >= 2.5.19 */
716 #undef PS_ADD
717         sbuf_putc(sb, '\n');
718
719         return (0);
720 }
721
722 /*
723  * Filler function for proc/pid/statm
724  */
725 static int
726 linprocfs_doprocstatm(PFS_FILL_ARGS)
727 {
728         struct kinfo_proc kp;
729         segsz_t lsize;
730
731         PROC_LOCK(p);
732         fill_kinfo_proc(p, &kp);
733         PROC_UNLOCK(p);
734
735         /*
736          * See comments in linprocfs_doprocstatus() regarding the
737          * computation of lsize.
738          */
739         /* size resident share trs drs lrs dt */
740         sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
741         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
742         sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
743         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
744         sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
745         lsize = B2P(kp.ki_size) - kp.ki_dsize -
746             kp.ki_ssize - kp.ki_tsize - 1;
747         sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
748         sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
749
750         return (0);
751 }
752
753 /*
754  * Filler function for proc/pid/status
755  */
756 static int
757 linprocfs_doprocstatus(PFS_FILL_ARGS)
758 {
759         struct kinfo_proc kp;
760         char *state;
761         segsz_t lsize;
762         struct thread *td2;
763         struct sigacts *ps;
764         int i;
765
766         PROC_LOCK(p);
767         td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
768
769         if (P_SHOULDSTOP(p)) {
770                 state = "T (stopped)";
771         } else {
772                 switch(p->p_state) {
773                 case PRS_NEW:
774                         state = "I (idle)";
775                         break;
776                 case PRS_NORMAL:
777                         if (p->p_flag & P_WEXIT) {
778                                 state = "X (exiting)";
779                                 break;
780                         }
781                         switch(td2->td_state) {
782                         case TDS_INHIBITED:
783                                 state = "S (sleeping)";
784                                 break;
785                         case TDS_RUNQ:
786                         case TDS_RUNNING:
787                                 state = "R (running)";
788                                 break;
789                         default:
790                                 state = "? (unknown)";
791                                 break;
792                         }
793                         break;
794                 case PRS_ZOMBIE:
795                         state = "Z (zombie)";
796                         break;
797                 default:
798                         state = "? (unknown)";
799                         break;
800                 }
801         }
802
803         fill_kinfo_proc(p, &kp);
804         sbuf_printf(sb, "Name:\t%s\n",          p->p_comm); /* XXX escape */
805         sbuf_printf(sb, "State:\t%s\n",         state);
806
807         /*
808          * Credentials
809          */
810         sbuf_printf(sb, "Pid:\t%d\n",           p->p_pid);
811         sbuf_printf(sb, "PPid:\t%d\n",          p->p_pptr ?
812                                                 p->p_pptr->p_pid : 0);
813         sbuf_printf(sb, "Uid:\t%d %d %d %d\n",  p->p_ucred->cr_ruid,
814                                                 p->p_ucred->cr_uid,
815                                                 p->p_ucred->cr_svuid,
816                                                 /* FreeBSD doesn't have fsuid */
817                                                 p->p_ucred->cr_uid);
818         sbuf_printf(sb, "Gid:\t%d %d %d %d\n",  p->p_ucred->cr_rgid,
819                                                 p->p_ucred->cr_gid,
820                                                 p->p_ucred->cr_svgid,
821                                                 /* FreeBSD doesn't have fsgid */
822                                                 p->p_ucred->cr_gid);
823         sbuf_cat(sb, "Groups:\t");
824         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
825                 sbuf_printf(sb, "%d ",          p->p_ucred->cr_groups[i]);
826         PROC_UNLOCK(p);
827         sbuf_putc(sb, '\n');
828
829         /*
830          * Memory
831          *
832          * While our approximation of VmLib may not be accurate (I
833          * don't know of a simple way to verify it, and I'm not sure
834          * it has much meaning anyway), I believe it's good enough.
835          *
836          * The same code that could (I think) accurately compute VmLib
837          * could also compute VmLck, but I don't really care enough to
838          * implement it. Submissions are welcome.
839          */
840         sbuf_printf(sb, "VmSize:\t%8ju kB\n",   B2K((uintmax_t)kp.ki_size));
841         sbuf_printf(sb, "VmLck:\t%8u kB\n",     P2K(0)); /* XXX */
842         sbuf_printf(sb, "VmRSS:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_rssize));
843         sbuf_printf(sb, "VmData:\t%8ju kB\n",   P2K((uintmax_t)kp.ki_dsize));
844         sbuf_printf(sb, "VmStk:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_ssize));
845         sbuf_printf(sb, "VmExe:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_tsize));
846         lsize = B2P(kp.ki_size) - kp.ki_dsize -
847             kp.ki_ssize - kp.ki_tsize - 1;
848         sbuf_printf(sb, "VmLib:\t%8ju kB\n",    P2K((uintmax_t)lsize));
849
850         /*
851          * Signal masks
852          *
853          * We support up to 128 signals, while Linux supports 32,
854          * but we only define 32 (the same 32 as Linux, to boot), so
855          * just show the lower 32 bits of each mask. XXX hack.
856          *
857          * NB: on certain platforms (Sparc at least) Linux actually
858          * supports 64 signals, but this code is a long way from
859          * running on anything but i386, so ignore that for now.
860          */
861         PROC_LOCK(p);
862         sbuf_printf(sb, "SigPnd:\t%08x\n",      p->p_siglist.__bits[0]);
863         /*
864          * I can't seem to find out where the signal mask is in
865          * relation to struct proc, so SigBlk is left unimplemented.
866          */
867         sbuf_printf(sb, "SigBlk:\t%08x\n",      0); /* XXX */
868         ps = p->p_sigacts;
869         mtx_lock(&ps->ps_mtx);
870         sbuf_printf(sb, "SigIgn:\t%08x\n",      ps->ps_sigignore.__bits[0]);
871         sbuf_printf(sb, "SigCgt:\t%08x\n",      ps->ps_sigcatch.__bits[0]);
872         mtx_unlock(&ps->ps_mtx);
873         PROC_UNLOCK(p);
874
875         /*
876          * Linux also prints the capability masks, but we don't have
877          * capabilities yet, and when we do get them they're likely to
878          * be meaningless to Linux programs, so we lie. XXX
879          */
880         sbuf_printf(sb, "CapInh:\t%016x\n",     0);
881         sbuf_printf(sb, "CapPrm:\t%016x\n",     0);
882         sbuf_printf(sb, "CapEff:\t%016x\n",     0);
883
884         return (0);
885 }
886
887
888 /*
889  * Filler function for proc/pid/cwd
890  */
891 static int
892 linprocfs_doproccwd(PFS_FILL_ARGS)
893 {
894         char *fullpath = "unknown";
895         char *freepath = NULL;
896
897         vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
898         sbuf_printf(sb, "%s", fullpath);
899         if (freepath)
900                 free(freepath, M_TEMP);
901         return (0);
902 }
903
904 /*
905  * Filler function for proc/pid/root
906  */
907 static int
908 linprocfs_doprocroot(PFS_FILL_ARGS)
909 {
910         struct vnode *rvp;
911         char *fullpath = "unknown";
912         char *freepath = NULL;
913
914         rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
915         vn_fullpath(td, rvp, &fullpath, &freepath);
916         sbuf_printf(sb, "%s", fullpath);
917         if (freepath)
918                 free(freepath, M_TEMP);
919         return (0);
920 }
921
922 #define MAX_ARGV_STR    512     /* Max number of argv-like strings */
923 #define UIO_CHUNK_SZ    256     /* Max chunk size (bytes) for uiomove */
924
925 static int
926 linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb,
927     void (*resolver)(const struct ps_strings, u_long *, int *))
928 {
929         struct iovec iov;
930         struct uio tmp_uio;
931         struct ps_strings pss;
932         int ret, i, n_elements, elm_len;
933         u_long addr, pbegin;
934         char **env_vector, *envp;
935         char env_string[UIO_CHUNK_SZ];
936 #ifdef COMPAT_FREEBSD32
937         struct freebsd32_ps_strings pss32;
938         uint32_t *env_vector32;
939 #endif
940
941 #define UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td)   \
942 do {                                                                    \
943         iov.iov_base = (caddr_t)(base);                                 \
944         iov.iov_len = (len);                                            \
945         uio.uio_iov = &(iov);                                           \
946         uio.uio_iovcnt = (cnt);                                         \
947         uio.uio_offset = (off_t)(offset);                               \
948         uio.uio_resid = (sz);                                           \
949         uio.uio_segflg = (flg);                                         \
950         uio.uio_rw = (rw);                                              \
951         uio.uio_td = (td);                                              \
952 } while (0)
953
954         env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK);
955
956 #ifdef COMPAT_FREEBSD32
957         env_vector32 = NULL;
958         if (SV_PROC_FLAG(p, SV_ILP32) != 0) {
959                 env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR,
960                     M_TEMP, M_WAITOK);
961                 elm_len = sizeof(int32_t);
962                 envp = (char *)env_vector32;
963
964                 UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1,
965                     (off_t)(p->p_sysent->sv_psstrings),
966                     sizeof(pss32), UIO_SYSSPACE, UIO_READ, td);
967                 ret = proc_rwmem(p, &tmp_uio);
968                 if (ret != 0)
969                         goto done;
970                 pss.ps_argvstr = PTRIN(pss32.ps_argvstr);
971                 pss.ps_nargvstr = pss32.ps_nargvstr;
972                 pss.ps_envstr = PTRIN(pss32.ps_envstr);
973                 pss.ps_nenvstr = pss32.ps_nenvstr;
974         } else {
975 #endif
976                 elm_len = sizeof(char *);
977                 envp = (char *)env_vector;
978
979                 UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1,
980                     (off_t)(p->p_sysent->sv_psstrings),
981                     sizeof(pss), UIO_SYSSPACE, UIO_READ, td);
982                 ret = proc_rwmem(p, &tmp_uio);
983                 if (ret != 0)
984                         goto done;
985 #ifdef COMPAT_FREEBSD32
986         }
987 #endif
988
989         /* Get the array address and the number of elements */
990         resolver(pss, &addr, &n_elements);
991
992         /* Consistent with lib/libkvm/kvm_proc.c */
993         if (n_elements > MAX_ARGV_STR) {
994                 ret = E2BIG;
995                 goto done;
996         }
997
998         UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1,
999             (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
1000         ret = proc_rwmem(p, &tmp_uio);
1001         if (ret != 0)
1002                 goto done;
1003 #ifdef COMPAT_FREEBSD32
1004         if (env_vector32 != NULL) {
1005                 for (i = 0; i < n_elements; i++)
1006                         env_vector[i] = PTRIN(env_vector32[i]);
1007         }
1008 #endif
1009
1010         /* Now we can iterate through the list of strings */
1011         for (i = 0; i < n_elements; i++) {
1012                 pbegin = (vm_offset_t)env_vector[i];
1013                 for (;;) {
1014                         UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string),
1015                             1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
1016                         ret = proc_rwmem(p, &tmp_uio);
1017                         if (ret != 0)
1018                                 goto done;
1019
1020                         if (!strvalid(env_string, UIO_CHUNK_SZ)) {
1021                                 /*
1022                                  * We didn't find the end of the string.
1023                                  * Add the string to the buffer and move
1024                                  * the pointer.  But do not allow strings
1025                                  * of unlimited length.
1026                                  */
1027                                 sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
1028                                 if (sbuf_len(sb) >= ARG_MAX) {
1029                                         ret = E2BIG;
1030                                         goto done;
1031                                 }
1032                                 pbegin += UIO_CHUNK_SZ;
1033                         } else {
1034                                 sbuf_cat(sb, env_string);
1035                                 break;
1036                         }
1037                 }
1038                 sbuf_bcat(sb, "", 1);
1039         }
1040 #undef UIO_HELPER
1041
1042 done:
1043         free(env_vector, M_TEMP);
1044 #ifdef COMPAT_FREEBSD32
1045         free(env_vector32, M_TEMP);
1046 #endif
1047         return (ret);
1048 }
1049
1050 static void
1051 ps_string_argv(const struct ps_strings ps, u_long *addr, int *n)
1052 {
1053
1054         *addr = (u_long) ps.ps_argvstr;
1055         *n = ps.ps_nargvstr;
1056 }
1057
1058 static void
1059 ps_string_env(const struct ps_strings ps, u_long *addr, int *n)
1060 {
1061
1062         *addr = (u_long) ps.ps_envstr;
1063         *n = ps.ps_nenvstr;
1064 }
1065
1066 /*
1067  * Filler function for proc/pid/cmdline
1068  */
1069 static int
1070 linprocfs_doproccmdline(PFS_FILL_ARGS)
1071 {
1072         int ret;
1073
1074         PROC_LOCK(p);
1075         if ((ret = p_cansee(td, p)) != 0) {
1076                 PROC_UNLOCK(p);
1077                 return (ret);
1078         }
1079
1080         /*
1081          * Mimic linux behavior and pass only processes with usermode
1082          * address space as valid.  Return zero silently otherwize.
1083          */
1084         if (p->p_vmspace == &vmspace0) {
1085                 PROC_UNLOCK(p);
1086                 return (0);
1087         }
1088         if (p->p_args != NULL) {
1089                 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
1090                 PROC_UNLOCK(p);
1091                 return (0);
1092         }
1093         PROC_UNLOCK(p);
1094
1095         ret = linprocfs_doargv(td, p, sb, ps_string_argv);
1096         return (ret);
1097 }
1098
1099 /*
1100  * Filler function for proc/pid/environ
1101  */
1102 static int
1103 linprocfs_doprocenviron(PFS_FILL_ARGS)
1104 {
1105         int ret;
1106
1107         PROC_LOCK(p);
1108         if ((ret = p_cansee(td, p)) != 0) {
1109                 PROC_UNLOCK(p);
1110                 return (ret);
1111         }
1112
1113         /*
1114          * Mimic linux behavior and pass only processes with usermode
1115          * address space as valid.  Return zero silently otherwize.
1116          */
1117         if (p->p_vmspace == &vmspace0) {
1118                 PROC_UNLOCK(p);
1119                 return (0);
1120         }
1121         PROC_UNLOCK(p);
1122
1123         ret = linprocfs_doargv(td, p, sb, ps_string_env);
1124         return (ret);
1125 }
1126
1127 /*
1128  * Filler function for proc/pid/maps
1129  */
1130 static int
1131 linprocfs_doprocmaps(PFS_FILL_ARGS)
1132 {
1133         struct vmspace *vm;
1134         vm_map_t map;
1135         vm_map_entry_t entry, tmp_entry;
1136         vm_object_t obj, tobj, lobj;
1137         vm_offset_t e_start, e_end;
1138         vm_ooffset_t off = 0;
1139         vm_prot_t e_prot;
1140         unsigned int last_timestamp;
1141         char *name = "", *freename = NULL;
1142         ino_t ino;
1143         int ref_count, shadow_count, flags;
1144         int error;
1145         struct vnode *vp;
1146         struct vattr vat;
1147         int locked;
1148
1149         PROC_LOCK(p);
1150         error = p_candebug(td, p);
1151         PROC_UNLOCK(p);
1152         if (error)
1153                 return (error);
1154
1155         if (uio->uio_rw != UIO_READ)
1156                 return (EOPNOTSUPP);
1157
1158         error = 0;
1159         vm = vmspace_acquire_ref(p);
1160         if (vm == NULL)
1161                 return (ESRCH);
1162         map = &vm->vm_map;
1163         vm_map_lock_read(map);
1164         for (entry = map->header.next; entry != &map->header;
1165             entry = entry->next) {
1166                 name = "";
1167                 freename = NULL;
1168                 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1169                         continue;
1170                 e_prot = entry->protection;
1171                 e_start = entry->start;
1172                 e_end = entry->end;
1173                 obj = entry->object.vm_object;
1174                 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1175                         VM_OBJECT_LOCK(tobj);
1176                         if (lobj != obj)
1177                                 VM_OBJECT_UNLOCK(lobj);
1178                         lobj = tobj;
1179                 }
1180                 last_timestamp = map->timestamp;
1181                 vm_map_unlock_read(map);
1182                 ino = 0;
1183                 if (lobj) {
1184                         off = IDX_TO_OFF(lobj->size);
1185                         if (lobj->type == OBJT_VNODE) {
1186                                 vp = lobj->handle;
1187                                 if (vp)
1188                                         vref(vp);
1189                         }
1190                         else
1191                                 vp = NULL;
1192                         if (lobj != obj)
1193                                 VM_OBJECT_UNLOCK(lobj);
1194                         flags = obj->flags;
1195                         ref_count = obj->ref_count;
1196                         shadow_count = obj->shadow_count;
1197                         VM_OBJECT_UNLOCK(obj);
1198                         if (vp) {
1199                                 vn_fullpath(td, vp, &name, &freename);
1200                                 locked = VFS_LOCK_GIANT(vp->v_mount);
1201                                 vn_lock(vp, LK_SHARED | LK_RETRY);
1202                                 VOP_GETATTR(vp, &vat, td->td_ucred);
1203                                 ino = vat.va_fileid;
1204                                 vput(vp);
1205                                 VFS_UNLOCK_GIANT(locked);
1206                         }
1207                 } else {
1208                         flags = 0;
1209                         ref_count = 0;
1210                         shadow_count = 0;
1211                 }
1212
1213                 /*
1214                  * format:
1215                  *  start, end, access, offset, major, minor, inode, name.
1216                  */
1217                 error = sbuf_printf(sb,
1218                     "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
1219                     (u_long)e_start, (u_long)e_end,
1220                     (e_prot & VM_PROT_READ)?"r":"-",
1221                     (e_prot & VM_PROT_WRITE)?"w":"-",
1222                     (e_prot & VM_PROT_EXECUTE)?"x":"-",
1223                     "p",
1224                     (u_long)off,
1225                     0,
1226                     0,
1227                     (u_long)ino,
1228                     *name ? "     " : "",
1229                     name
1230                     );
1231                 if (freename)
1232                         free(freename, M_TEMP);
1233                 vm_map_lock_read(map);
1234                 if (error == -1) {
1235                         error = 0;
1236                         break;
1237                 }
1238                 if (last_timestamp != map->timestamp) {
1239                         /*
1240                          * Look again for the entry because the map was
1241                          * modified while it was unlocked.  Specifically,
1242                          * the entry may have been clipped, merged, or deleted.
1243                          */
1244                         vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1245                         entry = tmp_entry;
1246                 }
1247         }
1248         vm_map_unlock_read(map);
1249         vmspace_free(vm);
1250
1251         return (error);
1252 }
1253
1254 /*
1255  * Filler function for proc/net/dev
1256  */
1257 static int
1258 linprocfs_donetdev(PFS_FILL_ARGS)
1259 {
1260         char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1261         struct ifnet *ifp;
1262
1263         sbuf_printf(sb, "%6s|%58s|%s\n"
1264             "%6s|%58s|%58s\n",
1265             "Inter-", "   Receive", "  Transmit",
1266             " face",
1267             "bytes    packets errs drop fifo frame compressed multicast",
1268             "bytes    packets errs drop fifo colls carrier compressed");
1269
1270         CURVNET_SET(TD_TO_VNET(curthread));
1271         IFNET_RLOCK();
1272         TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1273                 linux_ifname(ifp, ifname, sizeof ifname);
1274                 sbuf_printf(sb, "%6.6s: ", ifname);
1275                 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1276                     ifp->if_ibytes,     /* rx_bytes */
1277                     ifp->if_ipackets,   /* rx_packets */
1278                     ifp->if_ierrors,    /* rx_errors */
1279                     ifp->if_iqdrops,    /* rx_dropped +
1280                                          * rx_missed_errors */
1281                     0UL,                /* rx_fifo_errors */
1282                     0UL,                /* rx_length_errors +
1283                                          * rx_over_errors +
1284                                          * rx_crc_errors +
1285                                          * rx_frame_errors */
1286                     0UL,                /* rx_compressed */
1287                     ifp->if_imcasts);   /* multicast, XXX-BZ rx only? */
1288                 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1289                     ifp->if_obytes,     /* tx_bytes */
1290                     ifp->if_opackets,   /* tx_packets */
1291                     ifp->if_oerrors,    /* tx_errors */
1292                     0UL,                /* tx_dropped */
1293                     0UL,                /* tx_fifo_errors */
1294                     ifp->if_collisions, /* collisions */
1295                     0UL,                /* tx_carrier_errors +
1296                                          * tx_aborted_errors +
1297                                          * tx_window_errors +
1298                                          * tx_heartbeat_errors */
1299                     0UL);               /* tx_compressed */
1300         }
1301         IFNET_RUNLOCK();
1302         CURVNET_RESTORE();
1303
1304         return (0);
1305 }
1306
1307 /*
1308  * Filler function for proc/sys/kernel/osrelease
1309  */
1310 static int
1311 linprocfs_doosrelease(PFS_FILL_ARGS)
1312 {
1313         char osrelease[LINUX_MAX_UTSNAME];
1314
1315         linux_get_osrelease(td, osrelease);
1316         sbuf_printf(sb, "%s\n", osrelease);
1317
1318         return (0);
1319 }
1320
1321 /*
1322  * Filler function for proc/sys/kernel/ostype
1323  */
1324 static int
1325 linprocfs_doostype(PFS_FILL_ARGS)
1326 {
1327         char osname[LINUX_MAX_UTSNAME];
1328
1329         linux_get_osname(td, osname);
1330         sbuf_printf(sb, "%s\n", osname);
1331
1332         return (0);
1333 }
1334
1335 /*
1336  * Filler function for proc/sys/kernel/version
1337  */
1338 static int
1339 linprocfs_doosbuild(PFS_FILL_ARGS)
1340 {
1341
1342         linprocfs_osbuild(td, sb);
1343         sbuf_cat(sb, "\n");
1344         return (0);
1345 }
1346
1347 /*
1348  * Filler function for proc/sys/kernel/msgmni
1349  */
1350 static int
1351 linprocfs_domsgmni(PFS_FILL_ARGS)
1352 {
1353
1354         sbuf_printf(sb, "%d\n", msginfo.msgmni);
1355         return (0);
1356 }
1357
1358 /*
1359  * Filler function for proc/sys/kernel/pid_max
1360  */
1361 static int
1362 linprocfs_dopid_max(PFS_FILL_ARGS)
1363 {
1364
1365         sbuf_printf(sb, "%i\n", PID_MAX);
1366         return (0);
1367 }
1368
1369 /*
1370  * Filler function for proc/sys/kernel/sem
1371  */
1372 static int
1373 linprocfs_dosem(PFS_FILL_ARGS)
1374 {
1375
1376         sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1377             seminfo.semopm, seminfo.semmni);
1378         return (0);
1379 }
1380
1381 /*
1382  * Filler function for proc/scsi/device_info
1383  */
1384 static int
1385 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1386 {
1387
1388         return (0);
1389 }
1390
1391 /*
1392  * Filler function for proc/scsi/scsi
1393  */
1394 static int
1395 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1396 {
1397
1398         return (0);
1399 }
1400
1401 extern struct cdevsw *cdevsw[];
1402
1403 /*
1404  * Filler function for proc/devices
1405  */
1406 static int
1407 linprocfs_dodevices(PFS_FILL_ARGS)
1408 {
1409         char *char_devices;
1410         sbuf_printf(sb, "Character devices:\n");
1411
1412         char_devices = linux_get_char_devices();
1413         sbuf_printf(sb, "%s", char_devices);
1414         linux_free_get_char_devices(char_devices);
1415
1416         sbuf_printf(sb, "\nBlock devices:\n");
1417
1418         return (0);
1419 }
1420
1421 /*
1422  * Filler function for proc/cmdline
1423  */
1424 static int
1425 linprocfs_docmdline(PFS_FILL_ARGS)
1426 {
1427
1428         sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1429         sbuf_printf(sb, " ro root=302\n");
1430         return (0);
1431 }
1432
1433 /*
1434  * Filler function for proc/filesystems
1435  */
1436 static int
1437 linprocfs_dofilesystems(PFS_FILL_ARGS)
1438 {
1439         struct vfsconf *vfsp;
1440
1441         mtx_lock(&Giant);
1442         TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1443                 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1444                         sbuf_printf(sb, "nodev");
1445                 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1446         }
1447         mtx_unlock(&Giant);
1448         return(0);
1449 }
1450
1451 #if 0
1452 /*
1453  * Filler function for proc/modules
1454  */
1455 static int
1456 linprocfs_domodules(PFS_FILL_ARGS)
1457 {
1458         struct linker_file *lf;
1459
1460         TAILQ_FOREACH(lf, &linker_files, link) {
1461                 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1462                     (unsigned long)lf->size, lf->refs);
1463         }
1464         return (0);
1465 }
1466 #endif
1467
1468 /*
1469  * Filler function for proc/pid/fd
1470  */
1471 static int
1472 linprocfs_dofdescfs(PFS_FILL_ARGS)
1473 {
1474
1475         if (p == curproc)
1476                 sbuf_printf(sb, "/dev/fd");
1477         else
1478                 sbuf_printf(sb, "unknown");
1479         return (0);
1480 }
1481
1482 /*
1483  * Constructor
1484  */
1485 static int
1486 linprocfs_init(PFS_INIT_ARGS)
1487 {
1488         struct pfs_node *root;
1489         struct pfs_node *dir;
1490
1491         root = pi->pi_root;
1492
1493         /* /proc/... */
1494         pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1495             NULL, NULL, NULL, PFS_RD);
1496         pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1497             NULL, NULL, NULL, PFS_RD);
1498         pfs_create_file(root, "devices", &linprocfs_dodevices,
1499             NULL, NULL, NULL, PFS_RD);
1500         pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1501             NULL, NULL, NULL, PFS_RD);
1502         pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1503             NULL, NULL, NULL, PFS_RD);
1504         pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1505             NULL, NULL, NULL, PFS_RD);
1506 #if 0
1507         pfs_create_file(root, "modules", &linprocfs_domodules,
1508             NULL, NULL, NULL, PFS_RD);
1509 #endif
1510         pfs_create_file(root, "mounts", &linprocfs_domtab,
1511             NULL, NULL, NULL, PFS_RD);
1512         pfs_create_file(root, "mtab", &linprocfs_domtab,
1513             NULL, NULL, NULL, PFS_RD);
1514         pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1515             NULL, NULL, NULL, PFS_RD);
1516         pfs_create_link(root, "self", &procfs_docurproc,
1517             NULL, NULL, NULL, 0);
1518         pfs_create_file(root, "stat", &linprocfs_dostat,
1519             NULL, NULL, NULL, PFS_RD);
1520         pfs_create_file(root, "swaps", &linprocfs_doswaps,
1521             NULL, NULL, NULL, PFS_RD);
1522         pfs_create_file(root, "uptime", &linprocfs_douptime,
1523             NULL, NULL, NULL, PFS_RD);
1524         pfs_create_file(root, "version", &linprocfs_doversion,
1525             NULL, NULL, NULL, PFS_RD);
1526
1527         /* /proc/net/... */
1528         dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1529         pfs_create_file(dir, "dev", &linprocfs_donetdev,
1530             NULL, NULL, NULL, PFS_RD);
1531
1532         /* /proc/<pid>/... */
1533         dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1534         pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1535             NULL, NULL, NULL, PFS_RD);
1536         pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1537             NULL, NULL, NULL, 0);
1538         pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1539             NULL, NULL, NULL, PFS_RD);
1540         pfs_create_link(dir, "exe", &procfs_doprocfile,
1541             NULL, &procfs_notsystem, NULL, 0);
1542         pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1543             NULL, NULL, NULL, PFS_RD);
1544         pfs_create_file(dir, "mem", &procfs_doprocmem,
1545             &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1546         pfs_create_link(dir, "root", &linprocfs_doprocroot,
1547             NULL, NULL, NULL, 0);
1548         pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1549             NULL, NULL, NULL, PFS_RD);
1550         pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1551             NULL, NULL, NULL, PFS_RD);
1552         pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1553             NULL, NULL, NULL, PFS_RD);
1554         pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1555             NULL, NULL, NULL, 0);
1556
1557         /* /proc/scsi/... */
1558         dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1559         pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1560             NULL, NULL, NULL, PFS_RD);
1561         pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1562             NULL, NULL, NULL, PFS_RD);
1563
1564         /* /proc/sys/... */
1565         dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1566         /* /proc/sys/kernel/... */
1567         dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1568         pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1569             NULL, NULL, NULL, PFS_RD);
1570         pfs_create_file(dir, "ostype", &linprocfs_doostype,
1571             NULL, NULL, NULL, PFS_RD);
1572         pfs_create_file(dir, "version", &linprocfs_doosbuild,
1573             NULL, NULL, NULL, PFS_RD);
1574         pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1575             NULL, NULL, NULL, PFS_RD);
1576         pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1577             NULL, NULL, NULL, PFS_RD);
1578         pfs_create_file(dir, "sem", &linprocfs_dosem,
1579             NULL, NULL, NULL, PFS_RD);
1580
1581         return (0);
1582 }
1583
1584 /*
1585  * Destructor
1586  */
1587 static int
1588 linprocfs_uninit(PFS_INIT_ARGS)
1589 {
1590
1591         /* nothing to do, pseudofs will GC */
1592         return (0);
1593 }
1594
1595 PSEUDOFS(linprocfs, 1);
1596 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1597 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1598 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1599 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);