]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/linprocfs/linprocfs.c
Use atomic load & store for TSC frequency. It may be overkill for amd64 but
[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         uint64_t freq;
225         size_t size;
226         int class, fqmhz, fqkhz;
227         int i;
228
229         /*
230          * We default the flags to include all non-conflicting flags,
231          * and the Intel versions of conflicting flags.
232          */
233         static char *flags[] = {
234                 "fpu",      "vme",     "de",       "pse",      "tsc",
235                 "msr",      "pae",     "mce",      "cx8",      "apic",
236                 "sep",      "sep",     "mtrr",     "pge",      "mca",
237                 "cmov",     "pat",     "pse36",    "pn",       "b19",
238                 "b20",      "b21",     "mmxext",   "mmx",      "fxsr",
239                 "xmm",      "sse2",    "b27",      "b28",      "b29",
240                 "3dnowext", "3dnow"
241         };
242
243         switch (cpu_class) {
244 #ifdef __i386__
245         case CPUCLASS_286:
246                 class = 2;
247                 break;
248         case CPUCLASS_386:
249                 class = 3;
250                 break;
251         case CPUCLASS_486:
252                 class = 4;
253                 break;
254         case CPUCLASS_586:
255                 class = 5;
256                 break;
257         case CPUCLASS_686:
258                 class = 6;
259                 break;
260         default:
261                 class = 0;
262                 break;
263 #else /* __amd64__ */
264         default:
265                 class = 15;
266                 break;
267 #endif
268         }
269
270         hw_model[0] = CTL_HW;
271         hw_model[1] = HW_MODEL;
272         model[0] = '\0';
273         size = sizeof(model);
274         if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
275                 strcpy(model, "unknown");
276         for (i = 0; i < mp_ncpus; ++i) {
277                 sbuf_printf(sb,
278                     "processor\t: %d\n"
279                     "vendor_id\t: %.20s\n"
280                     "cpu family\t: %u\n"
281                     "model\t\t: %u\n"
282                     "model name\t: %s\n"
283                     "stepping\t: %u\n\n",
284                     i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
285                     CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING);
286                 /* XXX per-cpu vendor / class / model / id? */
287         }
288
289         sbuf_cat(sb, "flags\t\t:");
290
291 #ifdef __i386__
292         switch (cpu_vendor_id) {
293         case CPU_VENDOR_AMD:
294                 if (class < 6)
295                         flags[16] = "fcmov";
296                 break;
297         case CPU_VENDOR_CYRIX:
298                 flags[24] = "cxmmx";
299                 break;
300         }
301 #endif
302
303         for (i = 0; i < 32; i++)
304                 if (cpu_feature & (1 << i))
305                         sbuf_printf(sb, " %s", flags[i]);
306         sbuf_cat(sb, "\n");
307         freq = atomic_load_acq_64(&tsc_freq);
308         if (freq != 0) {
309                 fqmhz = (freq + 4999) / 1000000;
310                 fqkhz = ((freq + 4999) / 10000) % 100;
311                 sbuf_printf(sb,
312                     "cpu MHz\t\t: %d.%02d\n"
313                     "bogomips\t: %d.%02d\n",
314                     fqmhz, fqkhz, fqmhz, fqkhz);
315         }
316
317         return (0);
318 }
319 #endif /* __i386__ || __amd64__ */
320
321 /*
322  * Filler function for proc/mtab
323  *
324  * This file doesn't exist in Linux' procfs, but is included here so
325  * users can symlink /compat/linux/etc/mtab to /proc/mtab
326  */
327 static int
328 linprocfs_domtab(PFS_FILL_ARGS)
329 {
330         struct nameidata nd;
331         struct mount *mp;
332         const char *lep;
333         char *dlep, *flep, *mntto, *mntfrom, *fstype;
334         size_t lep_len;
335         int error;
336
337         /* resolve symlinks etc. in the emulation tree prefix */
338         NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
339         flep = NULL;
340         error = namei(&nd);
341         lep = linux_emul_path;
342         if (error == 0) {
343                 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
344                         lep = dlep;
345                 vrele(nd.ni_vp);
346                 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
347         }
348         lep_len = strlen(lep);
349
350         mtx_lock(&mountlist_mtx);
351         error = 0;
352         TAILQ_FOREACH(mp, &mountlist, mnt_list) {
353                 /* determine device name */
354                 mntfrom = mp->mnt_stat.f_mntfromname;
355
356                 /* determine mount point */
357                 mntto = mp->mnt_stat.f_mntonname;
358                 if (strncmp(mntto, lep, lep_len) == 0 &&
359                     mntto[lep_len] == '/')
360                         mntto += lep_len;
361
362                 /* determine fs type */
363                 fstype = mp->mnt_stat.f_fstypename;
364                 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
365                         mntfrom = fstype = "proc";
366                 else if (strcmp(fstype, "procfs") == 0)
367                         continue;
368
369                 if (strcmp(fstype, "linsysfs") == 0) {
370                         sbuf_printf(sb, "/sys %s sysfs %s", mntto,
371                             mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
372                 } else {
373                         /* For Linux msdosfs is called vfat */
374                         if (strcmp(fstype, "msdosfs") == 0)
375                                 fstype = "vfat";
376                         sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
377                             mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
378                 }
379 #define ADD_OPTION(opt, name) \
380         if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
381                 ADD_OPTION(MNT_SYNCHRONOUS,     "sync");
382                 ADD_OPTION(MNT_NOEXEC,          "noexec");
383                 ADD_OPTION(MNT_NOSUID,          "nosuid");
384                 ADD_OPTION(MNT_UNION,           "union");
385                 ADD_OPTION(MNT_ASYNC,           "async");
386                 ADD_OPTION(MNT_SUIDDIR,         "suiddir");
387                 ADD_OPTION(MNT_NOSYMFOLLOW,     "nosymfollow");
388                 ADD_OPTION(MNT_NOATIME,         "noatime");
389 #undef ADD_OPTION
390                 /* a real Linux mtab will also show NFS options */
391                 sbuf_printf(sb, " 0 0\n");
392         }
393         mtx_unlock(&mountlist_mtx);
394         if (flep != NULL)
395                 free(flep, M_TEMP);
396         return (error);
397 }
398
399 /*
400  * Filler function for proc/partitions
401  *
402  */
403 static int
404 linprocfs_dopartitions(PFS_FILL_ARGS)
405 {
406         struct g_class *cp;
407         struct g_geom *gp;
408         struct g_provider *pp;
409         struct nameidata nd;
410         const char *lep;
411         char  *dlep, *flep;
412         size_t lep_len;
413         int error;
414         int major, minor;
415
416         /* resolve symlinks etc. in the emulation tree prefix */
417         NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
418         flep = NULL;
419         error = namei(&nd);
420         lep = linux_emul_path;
421         if (error == 0) {
422                 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
423                         lep = dlep;
424                 vrele(nd.ni_vp);
425                 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
426         }
427         lep_len = strlen(lep);
428
429         g_topology_lock();
430         error = 0;
431         sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
432             "ruse wio wmerge wsect wuse running use aveq\n");
433
434         LIST_FOREACH(cp, &g_classes, class) {
435                 if (strcmp(cp->name, "DISK") == 0 ||
436                     strcmp(cp->name, "PART") == 0)
437                         LIST_FOREACH(gp, &cp->geom, geom) {
438                                 LIST_FOREACH(pp, &gp->provider, provider) {
439                                         if (linux_driver_get_major_minor(
440                                             pp->name, &major, &minor) != 0) {
441                                                 major = 0;
442                                                 minor = 0;
443                                         }
444                                         sbuf_printf(sb, "%d %d %lld %s "
445                                             "%d %d %d %d %d "
446                                              "%d %d %d %d %d %d\n",
447                                              major, minor,
448                                              (long long)pp->mediasize, pp->name,
449                                              0, 0, 0, 0, 0,
450                                              0, 0, 0, 0, 0, 0);
451                                 }
452                         }
453         }
454         g_topology_unlock();
455
456         if (flep != NULL)
457                 free(flep, M_TEMP);
458         return (error);
459 }
460
461
462 /*
463  * Filler function for proc/stat
464  */
465 static int
466 linprocfs_dostat(PFS_FILL_ARGS)
467 {
468         struct pcpu *pcpu;
469         long cp_time[CPUSTATES];
470         long *cp;
471         int i;
472
473         read_cpu_time(cp_time);
474         sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
475             T2J(cp_time[CP_USER]),
476             T2J(cp_time[CP_NICE]),
477             T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
478             T2J(cp_time[CP_IDLE]));
479         CPU_FOREACH(i) {
480                 pcpu = pcpu_find(i);
481                 cp = pcpu->pc_cp_time;
482                 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
483                     T2J(cp[CP_USER]),
484                     T2J(cp[CP_NICE]),
485                     T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
486                     T2J(cp[CP_IDLE]));
487         }
488         sbuf_printf(sb,
489             "disk 0 0 0 0\n"
490             "page %u %u\n"
491             "swap %u %u\n"
492             "intr %u\n"
493             "ctxt %u\n"
494             "btime %lld\n",
495             cnt.v_vnodepgsin,
496             cnt.v_vnodepgsout,
497             cnt.v_swappgsin,
498             cnt.v_swappgsout,
499             cnt.v_intr,
500             cnt.v_swtch,
501             (long long)boottime.tv_sec);
502         return (0);
503 }
504
505 /*
506  * Filler function for proc/uptime
507  */
508 static int
509 linprocfs_douptime(PFS_FILL_ARGS)
510 {
511         long cp_time[CPUSTATES];
512         struct timeval tv;
513
514         getmicrouptime(&tv);
515         read_cpu_time(cp_time);
516         sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
517             (long long)tv.tv_sec, tv.tv_usec / 10000,
518             T2S(cp_time[CP_IDLE] / mp_ncpus),
519             T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
520         return (0);
521 }
522
523 /*
524  * Get OS build date
525  */
526 static void
527 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
528 {
529 #if 0
530         char osbuild[256];
531         char *cp1, *cp2;
532
533         strncpy(osbuild, version, 256);
534         osbuild[255] = '\0';
535         cp1 = strstr(osbuild, "\n");
536         cp2 = strstr(osbuild, ":");
537         if (cp1 && cp2) {
538                 *cp1 = *cp2 = '\0';
539                 cp1 = strstr(osbuild, "#");
540         } else
541                 cp1 = NULL;
542         if (cp1)
543                 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
544         else
545 #endif
546                 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
547 }
548
549 /*
550  * Get OS builder
551  */
552 static void
553 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
554 {
555 #if 0
556         char builder[256];
557         char *cp;
558
559         cp = strstr(version, "\n    ");
560         if (cp) {
561                 strncpy(builder, cp + 5, 256);
562                 builder[255] = '\0';
563                 cp = strstr(builder, ":");
564                 if (cp)
565                         *cp = '\0';
566         }
567         if (cp)
568                 sbuf_cat(sb, builder);
569         else
570 #endif
571                 sbuf_cat(sb, "des@freebsd.org");
572 }
573
574 /*
575  * Filler function for proc/version
576  */
577 static int
578 linprocfs_doversion(PFS_FILL_ARGS)
579 {
580         char osname[LINUX_MAX_UTSNAME];
581         char osrelease[LINUX_MAX_UTSNAME];
582
583         linux_get_osname(td, osname);
584         linux_get_osrelease(td, osrelease);
585         sbuf_printf(sb, "%s version %s (", osname, osrelease);
586         linprocfs_osbuilder(td, sb);
587         sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
588         linprocfs_osbuild(td, sb);
589         sbuf_cat(sb, "\n");
590
591         return (0);
592 }
593
594 /*
595  * Filler function for proc/loadavg
596  */
597 static int
598 linprocfs_doloadavg(PFS_FILL_ARGS)
599 {
600
601         sbuf_printf(sb,
602             "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
603             (int)(averunnable.ldavg[0] / averunnable.fscale),
604             (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
605             (int)(averunnable.ldavg[1] / averunnable.fscale),
606             (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
607             (int)(averunnable.ldavg[2] / averunnable.fscale),
608             (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
609             1,                          /* number of running tasks */
610             nprocs,                     /* number of tasks */
611             lastpid                     /* the last pid */
612         );
613         return (0);
614 }
615
616 /*
617  * Filler function for proc/pid/stat
618  */
619 static int
620 linprocfs_doprocstat(PFS_FILL_ARGS)
621 {
622         struct kinfo_proc kp;
623         char state;
624         static int ratelimit = 0;
625         vm_offset_t startcode, startdata;
626
627         PROC_LOCK(p);
628         fill_kinfo_proc(p, &kp);
629         if (p->p_vmspace) {
630            startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
631            startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
632         } else {
633            startcode = 0;
634            startdata = 0;
635         };
636         sbuf_printf(sb, "%d", p->p_pid);
637 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
638         PS_ADD("comm",          "(%s)", p->p_comm);
639         if (kp.ki_stat > sizeof(linux_state)) {
640                 state = 'R';
641
642                 if (ratelimit == 0) {
643                         printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
644                             kp.ki_stat, sizeof(linux_state));
645                         ++ratelimit;
646                 }
647         } else
648                 state = linux_state[kp.ki_stat - 1];
649         PS_ADD("state",         "%c",   state);
650         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
651         PS_ADD("pgrp",          "%d",   p->p_pgid);
652         PS_ADD("session",       "%d",   p->p_session->s_sid);
653         PROC_UNLOCK(p);
654         PS_ADD("tty",           "%d",   kp.ki_tdev);
655         PS_ADD("tpgid",         "%d",   kp.ki_tpgid);
656         PS_ADD("flags",         "%u",   0); /* XXX */
657         PS_ADD("minflt",        "%lu",  kp.ki_rusage.ru_minflt);
658         PS_ADD("cminflt",       "%lu",  kp.ki_rusage_ch.ru_minflt);
659         PS_ADD("majflt",        "%lu",  kp.ki_rusage.ru_majflt);
660         PS_ADD("cmajflt",       "%lu",  kp.ki_rusage_ch.ru_majflt);
661         PS_ADD("utime",         "%ld",  TV2J(&kp.ki_rusage.ru_utime));
662         PS_ADD("stime",         "%ld",  TV2J(&kp.ki_rusage.ru_stime));
663         PS_ADD("cutime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_utime));
664         PS_ADD("cstime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_stime));
665         PS_ADD("priority",      "%d",   kp.ki_pri.pri_user);
666         PS_ADD("nice",          "%d",   kp.ki_nice); /* 19 (nicest) to -19 */
667         PS_ADD("0",             "%d",   0); /* removed field */
668         PS_ADD("itrealvalue",   "%d",   0); /* XXX */
669         PS_ADD("starttime",     "%lu",  TV2J(&kp.ki_start) - TV2J(&boottime));
670         PS_ADD("vsize",         "%ju",  P2K((uintmax_t)kp.ki_size));
671         PS_ADD("rss",           "%ju",  (uintmax_t)kp.ki_rssize);
672         PS_ADD("rlim",          "%lu",  kp.ki_rusage.ru_maxrss);
673         PS_ADD("startcode",     "%ju",  (uintmax_t)startcode);
674         PS_ADD("endcode",       "%ju",  (uintmax_t)startdata);
675         PS_ADD("startstack",    "%u",   0); /* XXX */
676         PS_ADD("kstkesp",       "%u",   0); /* XXX */
677         PS_ADD("kstkeip",       "%u",   0); /* XXX */
678         PS_ADD("signal",        "%u",   0); /* XXX */
679         PS_ADD("blocked",       "%u",   0); /* XXX */
680         PS_ADD("sigignore",     "%u",   0); /* XXX */
681         PS_ADD("sigcatch",      "%u",   0); /* XXX */
682         PS_ADD("wchan",         "%u",   0); /* XXX */
683         PS_ADD("nswap",         "%lu",  kp.ki_rusage.ru_nswap);
684         PS_ADD("cnswap",        "%lu",  kp.ki_rusage_ch.ru_nswap);
685         PS_ADD("exitsignal",    "%d",   0); /* XXX */
686         PS_ADD("processor",     "%u",   kp.ki_lastcpu);
687         PS_ADD("rt_priority",   "%u",   0); /* XXX */ /* >= 2.5.19 */
688         PS_ADD("policy",        "%u",   kp.ki_pri.pri_class); /* >= 2.5.19 */
689 #undef PS_ADD
690         sbuf_putc(sb, '\n');
691
692         return (0);
693 }
694
695 /*
696  * Filler function for proc/pid/statm
697  */
698 static int
699 linprocfs_doprocstatm(PFS_FILL_ARGS)
700 {
701         struct kinfo_proc kp;
702         segsz_t lsize;
703
704         PROC_LOCK(p);
705         fill_kinfo_proc(p, &kp);
706         PROC_UNLOCK(p);
707
708         /*
709          * See comments in linprocfs_doprocstatus() regarding the
710          * computation of lsize.
711          */
712         /* size resident share trs drs lrs dt */
713         sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
714         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
715         sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
716         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
717         sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
718         lsize = B2P(kp.ki_size) - kp.ki_dsize -
719             kp.ki_ssize - kp.ki_tsize - 1;
720         sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
721         sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
722
723         return (0);
724 }
725
726 /*
727  * Filler function for proc/pid/status
728  */
729 static int
730 linprocfs_doprocstatus(PFS_FILL_ARGS)
731 {
732         struct kinfo_proc kp;
733         char *state;
734         segsz_t lsize;
735         struct thread *td2;
736         struct sigacts *ps;
737         int i;
738
739         PROC_LOCK(p);
740         td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
741
742         if (P_SHOULDSTOP(p)) {
743                 state = "T (stopped)";
744         } else {
745                 switch(p->p_state) {
746                 case PRS_NEW:
747                         state = "I (idle)";
748                         break;
749                 case PRS_NORMAL:
750                         if (p->p_flag & P_WEXIT) {
751                                 state = "X (exiting)";
752                                 break;
753                         }
754                         switch(td2->td_state) {
755                         case TDS_INHIBITED:
756                                 state = "S (sleeping)";
757                                 break;
758                         case TDS_RUNQ:
759                         case TDS_RUNNING:
760                                 state = "R (running)";
761                                 break;
762                         default:
763                                 state = "? (unknown)";
764                                 break;
765                         }
766                         break;
767                 case PRS_ZOMBIE:
768                         state = "Z (zombie)";
769                         break;
770                 default:
771                         state = "? (unknown)";
772                         break;
773                 }
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 (SV_PROC_FLAG(p, 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"
1219             "%6s|%58s|%58s\n",
1220             "Inter-", "   Receive", "  Transmit",
1221             " face",
1222             "bytes    packets errs drop fifo frame compressed multicast",
1223             "bytes    packets errs drop fifo colls carrier compressed");
1224
1225         CURVNET_SET(TD_TO_VNET(curthread));
1226         IFNET_RLOCK();
1227         TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1228                 linux_ifname(ifp, ifname, sizeof ifname);
1229                 sbuf_printf(sb, "%6.6s: ", ifname);
1230                 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
1231                     ifp->if_ibytes,     /* rx_bytes */
1232                     ifp->if_ipackets,   /* rx_packets */
1233                     ifp->if_ierrors,    /* rx_errors */
1234                     ifp->if_iqdrops,    /* rx_dropped +
1235                                          * rx_missed_errors */
1236                     0UL,                /* rx_fifo_errors */
1237                     0UL,                /* rx_length_errors +
1238                                          * rx_over_errors +
1239                                          * rx_crc_errors +
1240                                          * rx_frame_errors */
1241                     0UL,                /* rx_compressed */
1242                     ifp->if_imcasts);   /* multicast, XXX-BZ rx only? */
1243                 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
1244                     ifp->if_obytes,     /* tx_bytes */
1245                     ifp->if_opackets,   /* tx_packets */
1246                     ifp->if_oerrors,    /* tx_errors */
1247                     0UL,                /* tx_dropped */
1248                     0UL,                /* tx_fifo_errors */
1249                     ifp->if_collisions, /* collisions */
1250                     0UL,                /* tx_carrier_errors +
1251                                          * tx_aborted_errors +
1252                                          * tx_window_errors +
1253                                          * tx_heartbeat_errors */
1254                     0UL);               /* tx_compressed */
1255         }
1256         IFNET_RUNLOCK();
1257         CURVNET_RESTORE();
1258
1259         return (0);
1260 }
1261
1262 /*
1263  * Filler function for proc/sys/kernel/osrelease
1264  */
1265 static int
1266 linprocfs_doosrelease(PFS_FILL_ARGS)
1267 {
1268         char osrelease[LINUX_MAX_UTSNAME];
1269
1270         linux_get_osrelease(td, osrelease);
1271         sbuf_printf(sb, "%s\n", osrelease);
1272
1273         return (0);
1274 }
1275
1276 /*
1277  * Filler function for proc/sys/kernel/ostype
1278  */
1279 static int
1280 linprocfs_doostype(PFS_FILL_ARGS)
1281 {
1282         char osname[LINUX_MAX_UTSNAME];
1283
1284         linux_get_osname(td, osname);
1285         sbuf_printf(sb, "%s\n", osname);
1286
1287         return (0);
1288 }
1289
1290 /*
1291  * Filler function for proc/sys/kernel/version
1292  */
1293 static int
1294 linprocfs_doosbuild(PFS_FILL_ARGS)
1295 {
1296
1297         linprocfs_osbuild(td, sb);
1298         sbuf_cat(sb, "\n");
1299         return (0);
1300 }
1301
1302 /*
1303  * Filler function for proc/sys/kernel/msgmni
1304  */
1305 static int
1306 linprocfs_domsgmni(PFS_FILL_ARGS)
1307 {
1308
1309         sbuf_printf(sb, "%d\n", msginfo.msgmni);
1310         return (0);
1311 }
1312
1313 /*
1314  * Filler function for proc/sys/kernel/pid_max
1315  */
1316 static int
1317 linprocfs_dopid_max(PFS_FILL_ARGS)
1318 {
1319
1320         sbuf_printf(sb, "%i\n", PID_MAX);
1321         return (0);
1322 }
1323
1324 /*
1325  * Filler function for proc/sys/kernel/sem
1326  */
1327 static int
1328 linprocfs_dosem(PFS_FILL_ARGS)
1329 {
1330
1331         sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1332             seminfo.semopm, seminfo.semmni);
1333         return (0);
1334 }
1335
1336 /*
1337  * Filler function for proc/scsi/device_info
1338  */
1339 static int
1340 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1341 {
1342
1343         return (0);
1344 }
1345
1346 /*
1347  * Filler function for proc/scsi/scsi
1348  */
1349 static int
1350 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1351 {
1352
1353         return (0);
1354 }
1355
1356 extern struct cdevsw *cdevsw[];
1357
1358 /*
1359  * Filler function for proc/devices
1360  */
1361 static int
1362 linprocfs_dodevices(PFS_FILL_ARGS)
1363 {
1364         char *char_devices;
1365         sbuf_printf(sb, "Character devices:\n");
1366
1367         char_devices = linux_get_char_devices();
1368         sbuf_printf(sb, "%s", char_devices);
1369         linux_free_get_char_devices(char_devices);
1370
1371         sbuf_printf(sb, "\nBlock devices:\n");
1372
1373         return (0);
1374 }
1375
1376 /*
1377  * Filler function for proc/cmdline
1378  */
1379 static int
1380 linprocfs_docmdline(PFS_FILL_ARGS)
1381 {
1382
1383         sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1384         sbuf_printf(sb, " ro root=302\n");
1385         return (0);
1386 }
1387
1388 /*
1389  * Filler function for proc/filesystems
1390  */
1391 static int
1392 linprocfs_dofilesystems(PFS_FILL_ARGS)
1393 {
1394         struct vfsconf *vfsp;
1395
1396         mtx_lock(&Giant);
1397         TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1398                 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1399                         sbuf_printf(sb, "nodev");
1400                 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1401         }
1402         mtx_unlock(&Giant);
1403         return(0);
1404 }
1405
1406 #if 0
1407 /*
1408  * Filler function for proc/modules
1409  */
1410 static int
1411 linprocfs_domodules(PFS_FILL_ARGS)
1412 {
1413         struct linker_file *lf;
1414
1415         TAILQ_FOREACH(lf, &linker_files, link) {
1416                 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1417                     (unsigned long)lf->size, lf->refs);
1418         }
1419         return (0);
1420 }
1421 #endif
1422
1423 /*
1424  * Filler function for proc/pid/fd
1425  */
1426 static int
1427 linprocfs_dofdescfs(PFS_FILL_ARGS)
1428 {
1429
1430         if (p == curproc)
1431                 sbuf_printf(sb, "/dev/fd");
1432         else
1433                 sbuf_printf(sb, "unknown");
1434         return (0);
1435 }
1436
1437 /*
1438  * Constructor
1439  */
1440 static int
1441 linprocfs_init(PFS_INIT_ARGS)
1442 {
1443         struct pfs_node *root;
1444         struct pfs_node *dir;
1445
1446         root = pi->pi_root;
1447
1448         /* /proc/... */
1449         pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1450             NULL, NULL, NULL, PFS_RD);
1451         pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1452             NULL, NULL, NULL, PFS_RD);
1453         pfs_create_file(root, "devices", &linprocfs_dodevices,
1454             NULL, NULL, NULL, PFS_RD);
1455         pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1456             NULL, NULL, NULL, PFS_RD);
1457         pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1458             NULL, NULL, NULL, PFS_RD);
1459         pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1460             NULL, NULL, NULL, PFS_RD);
1461 #if 0
1462         pfs_create_file(root, "modules", &linprocfs_domodules,
1463             NULL, NULL, NULL, PFS_RD);
1464 #endif
1465         pfs_create_file(root, "mounts", &linprocfs_domtab,
1466             NULL, NULL, NULL, PFS_RD);
1467         pfs_create_file(root, "mtab", &linprocfs_domtab,
1468             NULL, NULL, NULL, PFS_RD);
1469         pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1470             NULL, NULL, NULL, PFS_RD);
1471         pfs_create_link(root, "self", &procfs_docurproc,
1472             NULL, NULL, NULL, 0);
1473         pfs_create_file(root, "stat", &linprocfs_dostat,
1474             NULL, NULL, NULL, PFS_RD);
1475         pfs_create_file(root, "uptime", &linprocfs_douptime,
1476             NULL, NULL, NULL, PFS_RD);
1477         pfs_create_file(root, "version", &linprocfs_doversion,
1478             NULL, NULL, NULL, PFS_RD);
1479
1480         /* /proc/net/... */
1481         dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1482         pfs_create_file(dir, "dev", &linprocfs_donetdev,
1483             NULL, NULL, NULL, PFS_RD);
1484
1485         /* /proc/<pid>/... */
1486         dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1487         pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1488             NULL, NULL, NULL, PFS_RD);
1489         pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1490             NULL, NULL, NULL, 0);
1491         pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1492             NULL, NULL, NULL, PFS_RD);
1493         pfs_create_link(dir, "exe", &procfs_doprocfile,
1494             NULL, &procfs_notsystem, NULL, 0);
1495         pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1496             NULL, NULL, NULL, PFS_RD);
1497         pfs_create_file(dir, "mem", &procfs_doprocmem,
1498             &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1499         pfs_create_link(dir, "root", &linprocfs_doprocroot,
1500             NULL, NULL, NULL, 0);
1501         pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1502             NULL, NULL, NULL, PFS_RD);
1503         pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1504             NULL, NULL, NULL, PFS_RD);
1505         pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1506             NULL, NULL, NULL, PFS_RD);
1507         pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1508             NULL, NULL, NULL, 0);
1509
1510         /* /proc/scsi/... */
1511         dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1512         pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1513             NULL, NULL, NULL, PFS_RD);
1514         pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1515             NULL, NULL, NULL, PFS_RD);
1516
1517         /* /proc/sys/... */
1518         dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1519         /* /proc/sys/kernel/... */
1520         dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1521         pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1522             NULL, NULL, NULL, PFS_RD);
1523         pfs_create_file(dir, "ostype", &linprocfs_doostype,
1524             NULL, NULL, NULL, PFS_RD);
1525         pfs_create_file(dir, "version", &linprocfs_doosbuild,
1526             NULL, NULL, NULL, PFS_RD);
1527         pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1528             NULL, NULL, NULL, PFS_RD);
1529         pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1530             NULL, NULL, NULL, PFS_RD);
1531         pfs_create_file(dir, "sem", &linprocfs_dosem,
1532             NULL, NULL, NULL, PFS_RD);
1533
1534         return (0);
1535 }
1536
1537 /*
1538  * Destructor
1539  */
1540 static int
1541 linprocfs_uninit(PFS_INIT_ARGS)
1542 {
1543
1544         /* nothing to do, pseudofs will GC */
1545         return (0);
1546 }
1547
1548 PSEUDOFS(linprocfs, 1);
1549 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1550 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1551 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1552 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);