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