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