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