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