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