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