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