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