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