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