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