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