]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/linprocfs/linprocfs.c
UDP: further performance improvements on tx
[FreeBSD/FreeBSD.git] / sys / compat / linprocfs / linprocfs.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
5  * Copyright (c) 1999 Pierre Beyssac
6  * Copyright (c) 1993 Jan-Simon Pendry
7  * Copyright (c) 1993
8  *      The Regents of the University of California.  All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * Jan-Simon Pendry.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *      This product includes software developed by the University of
24  *      California, Berkeley and its contributors.
25  * 4. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  *
41  *      @(#)procfs_status.c     8.4 (Berkeley) 6/15/94
42  */
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/limits.h>
57 #include <sys/linker.h>
58 #include <sys/lock.h>
59 #include <sys/malloc.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/resource.h>
67 #include <sys/sbuf.h>
68 #include <sys/sem.h>
69 #include <sys/smp.h>
70 #include <sys/socket.h>
71 #include <sys/syscallsubr.h>
72 #include <sys/sysctl.h>
73 #include <sys/sysent.h>
74 #include <sys/systm.h>
75 #include <sys/time.h>
76 #include <sys/tty.h>
77 #include <sys/user.h>
78 #include <sys/uuid.h>
79 #include <sys/vmmeter.h>
80 #include <sys/vnode.h>
81 #include <sys/bus.h>
82
83 #include <net/if.h>
84 #include <net/if_var.h>
85 #include <net/if_types.h>
86
87 #include <vm/vm.h>
88 #include <vm/vm_extern.h>
89 #include <vm/pmap.h>
90 #include <vm/vm_map.h>
91 #include <vm/vm_param.h>
92 #include <vm/vm_object.h>
93 #include <vm/swap_pager.h>
94
95 #include <machine/clock.h>
96
97 #include <geom/geom.h>
98 #include <geom/geom_int.h>
99
100 #if defined(__i386__) || defined(__amd64__)
101 #include <machine/cputypes.h>
102 #include <machine/md_var.h>
103 #endif /* __i386__ || __amd64__ */
104
105 #include <compat/linux/linux.h>
106 #include <compat/linux/linux_mib.h>
107 #include <compat/linux/linux_misc.h>
108 #include <compat/linux/linux_util.h>
109 #include <fs/pseudofs/pseudofs.h>
110 #include <fs/procfs/procfs.h>
111
112 /*
113  * Various conversion macros
114  */
115 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz)))        /* ticks to jiffies */
116 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz)))      /* ticks to centiseconds */
117 #define T2S(x) ((x) / (stathz ? stathz : hz))           /* ticks to seconds */
118 #define B2K(x) ((x) >> 10)                              /* bytes to kbytes */
119 #define B2P(x) ((x) >> PAGE_SHIFT)                      /* bytes to pages */
120 #define P2B(x) ((x) << PAGE_SHIFT)                      /* pages to bytes */
121 #define P2K(x) ((x) << (PAGE_SHIFT - 10))               /* pages to kbytes */
122 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
123
124 /**
125  * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
126  *
127  * The linux procfs state field displays one of the characters RSDZTW to
128  * denote running, sleeping in an interruptible wait, waiting in an
129  * uninterruptible disk sleep, a zombie process, process is being traced
130  * or stopped, or process is paging respectively.
131  *
132  * Our struct kinfo_proc contains the variable ki_stat which contains a
133  * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
134  *
135  * This character array is used with ki_stati-1 as an index and tries to
136  * map our states to suitable linux states.
137  */
138 static char linux_state[] = "RRSTZDD";
139
140 /*
141  * Filler function for proc/meminfo
142  */
143 static int
144 linprocfs_domeminfo(PFS_FILL_ARGS)
145 {
146         unsigned long memtotal;         /* total memory in bytes */
147         unsigned long memused;          /* used memory in bytes */
148         unsigned long memfree;          /* free memory in bytes */
149         unsigned long buffers, cached;  /* buffer / cache memory ??? */
150         unsigned long long swaptotal;   /* total swap space in bytes */
151         unsigned long long swapused;    /* used swap space in bytes */
152         unsigned long long swapfree;    /* free swap space in bytes */
153         int i, j;
154
155         memtotal = physmem * PAGE_SIZE;
156         /*
157          * The correct thing here would be:
158          *
159         memfree = vm_free_count() * PAGE_SIZE;
160         memused = memtotal - memfree;
161          *
162          * but it might mislead linux binaries into thinking there
163          * is very little memory left, so we cheat and tell them that
164          * all memory that isn't wired down is free.
165          */
166         memused = vm_wire_count() * PAGE_SIZE;
167         memfree = memtotal - memused;
168         swap_pager_status(&i, &j);
169         swaptotal = (unsigned long long)i * PAGE_SIZE;
170         swapused = (unsigned long long)j * PAGE_SIZE;
171         swapfree = swaptotal - swapused;
172         /*
173          * We'd love to be able to write:
174          *
175         buffers = bufspace;
176          *
177          * but bufspace is internal to vfs_bio.c and we don't feel
178          * like unstaticizing it just for linprocfs's sake.
179          */
180         buffers = 0;
181         cached = vm_inactive_count() * PAGE_SIZE;
182
183         sbuf_printf(sb,
184             "MemTotal: %9lu kB\n"
185             "MemFree:  %9lu kB\n"
186             "Buffers:  %9lu kB\n"
187             "Cached:   %9lu kB\n"
188             "SwapTotal:%9llu kB\n"
189             "SwapFree: %9llu kB\n",
190             B2K(memtotal), B2K(memfree), B2K(buffers),
191             B2K(cached), B2K(swaptotal), B2K(swapfree));
192
193         return (0);
194 }
195
196 #if defined(__i386__) || defined(__amd64__)
197 /*
198  * Filler function for proc/cpuinfo (i386 & amd64 version)
199  */
200 static int
201 linprocfs_docpuinfo(PFS_FILL_ARGS)
202 {
203         int hw_model[2];
204         char model[128];
205         uint64_t freq;
206         size_t size;
207         u_int cache_size[4];
208         int fqmhz, fqkhz;
209         int i, j;
210
211         /*
212          * We default the flags to include all non-conflicting flags,
213          * and the Intel versions of conflicting flags.
214          */
215         static char *flags[] = {
216                 "fpu",      "vme",     "de",       "pse",      "tsc",
217                 "msr",      "pae",     "mce",      "cx8",      "apic",
218                 "sep",      "sep",     "mtrr",     "pge",      "mca",
219                 "cmov",     "pat",     "pse36",    "pn",       "b19",
220                 "b20",      "b21",     "mmxext",   "mmx",      "fxsr",
221                 "xmm",      "sse2",    "b27",      "b28",      "b29",
222                 "3dnowext", "3dnow"
223         };
224
225         static char *power_flags[] = {
226                 "ts",           "fid",          "vid",
227                 "ttp",          "tm",           "stc",
228                 "100mhzsteps",  "hwpstate",     "",
229                 "cpb",          "eff_freq_ro",  "proc_feedback",
230                 "acc_power",
231         };
232
233         hw_model[0] = CTL_HW;
234         hw_model[1] = HW_MODEL;
235         model[0] = '\0';
236         size = sizeof(model);
237         if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
238                 strcpy(model, "unknown");
239 #ifdef __i386__
240         switch (cpu_vendor_id) {
241         case CPU_VENDOR_AMD:
242                 if (cpu_class < CPUCLASS_686)
243                         flags[16] = "fcmov";
244                 break;
245         case CPU_VENDOR_CYRIX:
246                 flags[24] = "cxmmx";
247                 break;
248         }
249 #endif
250         if (cpu_exthigh >= 0x80000006)
251                 do_cpuid(0x80000006, cache_size);
252         else
253                 memset(cache_size, 0, sizeof(cache_size));
254         for (i = 0; i < mp_ncpus; ++i) {
255                 fqmhz = 0;
256                 fqkhz = 0;
257                 freq = atomic_load_acq_64(&tsc_freq);
258                 if (freq != 0) {
259                         fqmhz = (freq + 4999) / 1000000;
260                         fqkhz = ((freq + 4999) / 10000) % 100;
261                 }
262                 sbuf_printf(sb,
263                     "processor\t: %d\n"
264                     "vendor_id\t: %.20s\n"
265                     "cpu family\t: %u\n"
266                     "model\t\t: %u\n"
267                     "model name\t: %s\n"
268                     "stepping\t: %u\n"
269                     "cpu MHz\t\t: %d.%02d\n"
270                     "cache size\t: %d KB\n"
271                     "physical id\t: %d\n"
272                     "siblings\t: %d\n"
273                     "core id\t\t: %d\n"
274                     "cpu cores\t: %d\n"
275                     "apicid\t\t: %d\n"
276                     "initial apicid\t: %d\n"
277                     "fpu\t\t: %s\n"
278                     "fpu_exception\t: %s\n"
279                     "cpuid level\t: %d\n"
280                     "wp\t\t: %s\n",
281                     i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
282                     CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING,
283                     fqmhz, fqkhz,
284                     (cache_size[2] >> 16), 0, mp_ncpus, i, mp_ncpus,
285                     i, i, /*cpu_id & CPUID_LOCAL_APIC_ID ??*/
286                     (cpu_feature & CPUID_FPU) ? "yes" : "no", "yes",
287                     CPUID_TO_FAMILY(cpu_id), "yes");
288                 sbuf_cat(sb, "flags\t\t:");
289                 for (j = 0; j < nitems(flags); j++)
290                         if (cpu_feature & (1 << j))
291                                 sbuf_printf(sb, " %s", flags[j]);
292                 sbuf_cat(sb, "\n");
293                 sbuf_printf(sb,
294                     "bugs\t\t: %s\n"
295                     "bogomips\t: %d.%02d\n"
296                     "clflush size\t: %d\n"
297                     "cache_alignment\t: %d\n"
298                     "address sizes\t: %d bits physical, %d bits virtual\n",
299 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
300                     (has_f00f_bug) ? "Intel F00F" : "",
301 #else
302                     "",
303 #endif
304                     fqmhz, fqkhz,
305                     cpu_clflush_line_size, cpu_clflush_line_size,
306                     cpu_maxphyaddr,
307                     (cpu_maxphyaddr > 32) ? 48 : 0);
308                 sbuf_cat(sb, "power management: ");
309                 for (j = 0; j < nitems(power_flags); j++)
310                         if (amd_pminfo & (1 << j))
311                                 sbuf_printf(sb, " %s", power_flags[j]);
312                 sbuf_cat(sb, "\n\n");
313
314                 /* XXX per-cpu vendor / class / model / id? */
315         }
316         sbuf_cat(sb, "\n");
317
318         return (0);
319 }
320 #endif /* __i386__ || __amd64__ */
321
322 /*
323  * Filler function for proc/mtab
324  *
325  * This file doesn't exist in Linux' procfs, but is included here so
326  * users can symlink /compat/linux/etc/mtab to /proc/mtab
327  */
328 static int
329 linprocfs_domtab(PFS_FILL_ARGS)
330 {
331         struct nameidata nd;
332         const char *lep;
333         char *dlep, *flep, *mntto, *mntfrom, *fstype;
334         size_t lep_len;
335         int error;
336         struct statfs *buf, *sp;
337         size_t count;
338
339         /* resolve symlinks etc. in the emulation tree prefix */
340         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
341         flep = NULL;
342         error = namei(&nd);
343         lep = linux_emul_path;
344         if (error == 0) {
345                 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
346                         lep = dlep;
347                 vrele(nd.ni_vp);
348         }
349         lep_len = strlen(lep);
350
351         buf = NULL;
352         error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
353             UIO_SYSSPACE, MNT_WAIT);
354         if (error != 0) {
355                 free(buf, M_TEMP);
356                 free(flep, M_TEMP);
357                 return (error);
358         }
359
360         for (sp = buf; count > 0; sp++, count--) {
361                 /* determine device name */
362                 mntfrom = sp->f_mntfromname;
363
364                 /* determine mount point */
365                 mntto = sp->f_mntonname;
366                 if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
367                         mntto += lep_len;
368
369                 /* determine fs type */
370                 fstype = sp->f_fstypename;
371                 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
372                         mntfrom = fstype = "proc";
373                 else if (strcmp(fstype, "procfs") == 0)
374                         continue;
375
376                 if (strcmp(fstype, "linsysfs") == 0) {
377                         sbuf_printf(sb, "/sys %s sysfs %s", mntto,
378                             sp->f_flags & MNT_RDONLY ? "ro" : "rw");
379                 } else {
380                         /* For Linux msdosfs is called vfat */
381                         if (strcmp(fstype, "msdosfs") == 0)
382                                 fstype = "vfat";
383                         sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
384                             sp->f_flags & MNT_RDONLY ? "ro" : "rw");
385                 }
386 #define ADD_OPTION(opt, name) \
387         if (sp->f_flags & (opt)) sbuf_printf(sb, "," name);
388                 ADD_OPTION(MNT_SYNCHRONOUS,     "sync");
389                 ADD_OPTION(MNT_NOEXEC,          "noexec");
390                 ADD_OPTION(MNT_NOSUID,          "nosuid");
391                 ADD_OPTION(MNT_UNION,           "union");
392                 ADD_OPTION(MNT_ASYNC,           "async");
393                 ADD_OPTION(MNT_SUIDDIR,         "suiddir");
394                 ADD_OPTION(MNT_NOSYMFOLLOW,     "nosymfollow");
395                 ADD_OPTION(MNT_NOATIME,         "noatime");
396 #undef ADD_OPTION
397                 /* a real Linux mtab will also show NFS options */
398                 sbuf_printf(sb, " 0 0\n");
399         }
400
401         free(buf, M_TEMP);
402         free(flep, M_TEMP);
403         return (error);
404 }
405
406 /*
407  * Filler function for proc/partitions
408  */
409 static int
410 linprocfs_dopartitions(PFS_FILL_ARGS)
411 {
412         struct g_class *cp;
413         struct g_geom *gp;
414         struct g_provider *pp;
415         int major, minor;
416
417         g_topology_lock();
418         sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
419             "ruse wio wmerge wsect wuse running use aveq\n");
420
421         LIST_FOREACH(cp, &g_classes, class) {
422                 if (strcmp(cp->name, "DISK") == 0 ||
423                     strcmp(cp->name, "PART") == 0)
424                         LIST_FOREACH(gp, &cp->geom, geom) {
425                                 LIST_FOREACH(pp, &gp->provider, provider) {
426                                         if (linux_driver_get_major_minor(
427                                             pp->name, &major, &minor) != 0) {
428                                                 major = 0;
429                                                 minor = 0;
430                                         }
431                                         sbuf_printf(sb, "%d %d %lld %s "
432                                             "%d %d %d %d %d "
433                                              "%d %d %d %d %d %d\n",
434                                              major, minor,
435                                              (long long)pp->mediasize, pp->name,
436                                              0, 0, 0, 0, 0,
437                                              0, 0, 0, 0, 0, 0);
438                                 }
439                         }
440         }
441         g_topology_unlock();
442
443         return (0);
444 }
445
446
447 /*
448  * Filler function for proc/stat
449  */
450 static int
451 linprocfs_dostat(PFS_FILL_ARGS)
452 {
453         struct pcpu *pcpu;
454         long cp_time[CPUSTATES];
455         long *cp;
456         struct timeval boottime;
457         int i;
458
459         read_cpu_time(cp_time);
460         getboottime(&boottime);
461         sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
462             T2J(cp_time[CP_USER]),
463             T2J(cp_time[CP_NICE]),
464             T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
465             T2J(cp_time[CP_IDLE]));
466         CPU_FOREACH(i) {
467                 pcpu = pcpu_find(i);
468                 cp = pcpu->pc_cp_time;
469                 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
470                     T2J(cp[CP_USER]),
471                     T2J(cp[CP_NICE]),
472                     T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
473                     T2J(cp[CP_IDLE]));
474         }
475         sbuf_printf(sb,
476             "disk 0 0 0 0\n"
477             "page %ju %ju\n"
478             "swap %ju %ju\n"
479             "intr %ju\n"
480             "ctxt %ju\n"
481             "btime %lld\n",
482             (uintmax_t)VM_CNT_FETCH(v_vnodepgsin),
483             (uintmax_t)VM_CNT_FETCH(v_vnodepgsout),
484             (uintmax_t)VM_CNT_FETCH(v_swappgsin),
485             (uintmax_t)VM_CNT_FETCH(v_swappgsout),
486             (uintmax_t)VM_CNT_FETCH(v_intr),
487             (uintmax_t)VM_CNT_FETCH(v_swtch),
488             (long long)boottime.tv_sec);
489         return (0);
490 }
491
492 static int
493 linprocfs_doswaps(PFS_FILL_ARGS)
494 {
495         struct xswdev xsw;
496         uintmax_t total, used;
497         int n;
498         char devname[SPECNAMELEN + 1];
499
500         sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
501         for (n = 0; ; n++) {
502                 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
503                         break;
504                 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
505                 used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
506
507                 /*
508                  * The space and not tab after the device name is on
509                  * purpose.  Linux does so.
510                  */
511                 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
512                     devname, total, used);
513         }
514         return (0);
515 }
516
517 /*
518  * Filler function for proc/uptime
519  */
520 static int
521 linprocfs_douptime(PFS_FILL_ARGS)
522 {
523         long cp_time[CPUSTATES];
524         struct timeval tv;
525
526         getmicrouptime(&tv);
527         read_cpu_time(cp_time);
528         sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
529             (long long)tv.tv_sec, tv.tv_usec / 10000,
530             T2S(cp_time[CP_IDLE] / mp_ncpus),
531             T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
532         return (0);
533 }
534
535 /*
536  * Get OS build date
537  */
538 static void
539 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
540 {
541 #if 0
542         char osbuild[256];
543         char *cp1, *cp2;
544
545         strncpy(osbuild, version, 256);
546         osbuild[255] = '\0';
547         cp1 = strstr(osbuild, "\n");
548         cp2 = strstr(osbuild, ":");
549         if (cp1 && cp2) {
550                 *cp1 = *cp2 = '\0';
551                 cp1 = strstr(osbuild, "#");
552         } else
553                 cp1 = NULL;
554         if (cp1)
555                 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
556         else
557 #endif
558                 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
559 }
560
561 /*
562  * Get OS builder
563  */
564 static void
565 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
566 {
567 #if 0
568         char builder[256];
569         char *cp;
570
571         cp = strstr(version, "\n    ");
572         if (cp) {
573                 strncpy(builder, cp + 5, 256);
574                 builder[255] = '\0';
575                 cp = strstr(builder, ":");
576                 if (cp)
577                         *cp = '\0';
578         }
579         if (cp)
580                 sbuf_cat(sb, builder);
581         else
582 #endif
583                 sbuf_cat(sb, "des@freebsd.org");
584 }
585
586 /*
587  * Filler function for proc/version
588  */
589 static int
590 linprocfs_doversion(PFS_FILL_ARGS)
591 {
592         char osname[LINUX_MAX_UTSNAME];
593         char osrelease[LINUX_MAX_UTSNAME];
594
595         linux_get_osname(td, osname);
596         linux_get_osrelease(td, osrelease);
597         sbuf_printf(sb, "%s version %s (", osname, osrelease);
598         linprocfs_osbuilder(td, sb);
599         sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
600         linprocfs_osbuild(td, sb);
601         sbuf_cat(sb, "\n");
602
603         return (0);
604 }
605
606 /*
607  * Filler function for proc/loadavg
608  */
609 static int
610 linprocfs_doloadavg(PFS_FILL_ARGS)
611 {
612
613         sbuf_printf(sb,
614             "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
615             (int)(averunnable.ldavg[0] / averunnable.fscale),
616             (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
617             (int)(averunnable.ldavg[1] / averunnable.fscale),
618             (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
619             (int)(averunnable.ldavg[2] / averunnable.fscale),
620             (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
621             1,                          /* number of running tasks */
622             nprocs,                     /* number of tasks */
623             lastpid                     /* the last pid */
624         );
625         return (0);
626 }
627
628 /*
629  * Filler function for proc/pid/stat
630  */
631 static int
632 linprocfs_doprocstat(PFS_FILL_ARGS)
633 {
634         struct kinfo_proc kp;
635         struct timeval boottime;
636         char state;
637         static int ratelimit = 0;
638         vm_offset_t startcode, startdata;
639
640         getboottime(&boottime);
641         sx_slock(&proctree_lock);
642         PROC_LOCK(p);
643         fill_kinfo_proc(p, &kp);
644         sx_sunlock(&proctree_lock);
645         if (p->p_vmspace) {
646            startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
647            startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
648         } else {
649            startcode = 0;
650            startdata = 0;
651         }
652         sbuf_printf(sb, "%d", p->p_pid);
653 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
654         PS_ADD("comm",          "(%s)", p->p_comm);
655         if (kp.ki_stat > sizeof(linux_state)) {
656                 state = 'R';
657
658                 if (ratelimit == 0) {
659                         printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
660                             kp.ki_stat, sizeof(linux_state));
661                         ++ratelimit;
662                 }
663         } else
664                 state = linux_state[kp.ki_stat - 1];
665         PS_ADD("state",         "%c",   state);
666         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
667         PS_ADD("pgrp",          "%d",   p->p_pgid);
668         PS_ADD("session",       "%d",   p->p_session->s_sid);
669         PROC_UNLOCK(p);
670         PS_ADD("tty",           "%ju",  (uintmax_t)kp.ki_tdev);
671         PS_ADD("tpgid",         "%d",   kp.ki_tpgid);
672         PS_ADD("flags",         "%u",   0); /* XXX */
673         PS_ADD("minflt",        "%lu",  kp.ki_rusage.ru_minflt);
674         PS_ADD("cminflt",       "%lu",  kp.ki_rusage_ch.ru_minflt);
675         PS_ADD("majflt",        "%lu",  kp.ki_rusage.ru_majflt);
676         PS_ADD("cmajflt",       "%lu",  kp.ki_rusage_ch.ru_majflt);
677         PS_ADD("utime",         "%ld",  TV2J(&kp.ki_rusage.ru_utime));
678         PS_ADD("stime",         "%ld",  TV2J(&kp.ki_rusage.ru_stime));
679         PS_ADD("cutime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_utime));
680         PS_ADD("cstime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_stime));
681         PS_ADD("priority",      "%d",   kp.ki_pri.pri_user);
682         PS_ADD("nice",          "%d",   kp.ki_nice); /* 19 (nicest) to -19 */
683         PS_ADD("0",             "%d",   0); /* removed field */
684         PS_ADD("itrealvalue",   "%d",   0); /* XXX */
685         PS_ADD("starttime",     "%lu",  TV2J(&kp.ki_start) - TV2J(&boottime));
686         PS_ADD("vsize",         "%ju",  P2K((uintmax_t)kp.ki_size));
687         PS_ADD("rss",           "%ju",  (uintmax_t)kp.ki_rssize);
688         PS_ADD("rlim",          "%lu",  kp.ki_rusage.ru_maxrss);
689         PS_ADD("startcode",     "%ju",  (uintmax_t)startcode);
690         PS_ADD("endcode",       "%ju",  (uintmax_t)startdata);
691         PS_ADD("startstack",    "%u",   0); /* XXX */
692         PS_ADD("kstkesp",       "%u",   0); /* XXX */
693         PS_ADD("kstkeip",       "%u",   0); /* XXX */
694         PS_ADD("signal",        "%u",   0); /* XXX */
695         PS_ADD("blocked",       "%u",   0); /* XXX */
696         PS_ADD("sigignore",     "%u",   0); /* XXX */
697         PS_ADD("sigcatch",      "%u",   0); /* XXX */
698         PS_ADD("wchan",         "%u",   0); /* XXX */
699         PS_ADD("nswap",         "%lu",  kp.ki_rusage.ru_nswap);
700         PS_ADD("cnswap",        "%lu",  kp.ki_rusage_ch.ru_nswap);
701         PS_ADD("exitsignal",    "%d",   0); /* XXX */
702         PS_ADD("processor",     "%u",   kp.ki_lastcpu);
703         PS_ADD("rt_priority",   "%u",   0); /* XXX */ /* >= 2.5.19 */
704         PS_ADD("policy",        "%u",   kp.ki_pri.pri_class); /* >= 2.5.19 */
705 #undef PS_ADD
706         sbuf_putc(sb, '\n');
707
708         return (0);
709 }
710
711 /*
712  * Filler function for proc/pid/statm
713  */
714 static int
715 linprocfs_doprocstatm(PFS_FILL_ARGS)
716 {
717         struct kinfo_proc kp;
718         segsz_t lsize;
719
720         sx_slock(&proctree_lock);
721         PROC_LOCK(p);
722         fill_kinfo_proc(p, &kp);
723         PROC_UNLOCK(p);
724         sx_sunlock(&proctree_lock);
725
726         /*
727          * See comments in linprocfs_doprocstatus() regarding the
728          * computation of lsize.
729          */
730         /* size resident share trs drs lrs dt */
731         sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
732         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
733         sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
734         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
735         sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
736         lsize = B2P(kp.ki_size) - kp.ki_dsize -
737             kp.ki_ssize - kp.ki_tsize - 1;
738         sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
739         sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
740
741         return (0);
742 }
743
744 /*
745  * Filler function for proc/pid/status
746  */
747 static int
748 linprocfs_doprocstatus(PFS_FILL_ARGS)
749 {
750         struct kinfo_proc kp;
751         char *state;
752         segsz_t lsize;
753         struct thread *td2;
754         struct sigacts *ps;
755         l_sigset_t siglist, sigignore, sigcatch;
756         int i;
757
758         sx_slock(&proctree_lock);
759         PROC_LOCK(p);
760         td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
761
762         if (P_SHOULDSTOP(p)) {
763                 state = "T (stopped)";
764         } else {
765                 switch(p->p_state) {
766                 case PRS_NEW:
767                         state = "I (idle)";
768                         break;
769                 case PRS_NORMAL:
770                         if (p->p_flag & P_WEXIT) {
771                                 state = "X (exiting)";
772                                 break;
773                         }
774                         switch(td2->td_state) {
775                         case TDS_INHIBITED:
776                                 state = "S (sleeping)";
777                                 break;
778                         case TDS_RUNQ:
779                         case TDS_RUNNING:
780                                 state = "R (running)";
781                                 break;
782                         default:
783                                 state = "? (unknown)";
784                                 break;
785                         }
786                         break;
787                 case PRS_ZOMBIE:
788                         state = "Z (zombie)";
789                         break;
790                 default:
791                         state = "? (unknown)";
792                         break;
793                 }
794         }
795
796         fill_kinfo_proc(p, &kp);
797         sx_sunlock(&proctree_lock);
798
799         sbuf_printf(sb, "Name:\t%s\n",          p->p_comm); /* XXX escape */
800         sbuf_printf(sb, "State:\t%s\n",         state);
801
802         /*
803          * Credentials
804          */
805         sbuf_printf(sb, "Pid:\t%d\n",           p->p_pid);
806         sbuf_printf(sb, "PPid:\t%d\n",          p->p_pptr ?
807                                                 p->p_pptr->p_pid : 0);
808         sbuf_printf(sb, "Uid:\t%d %d %d %d\n",  p->p_ucred->cr_ruid,
809                                                 p->p_ucred->cr_uid,
810                                                 p->p_ucred->cr_svuid,
811                                                 /* FreeBSD doesn't have fsuid */
812                                                 p->p_ucred->cr_uid);
813         sbuf_printf(sb, "Gid:\t%d %d %d %d\n",  p->p_ucred->cr_rgid,
814                                                 p->p_ucred->cr_gid,
815                                                 p->p_ucred->cr_svgid,
816                                                 /* FreeBSD doesn't have fsgid */
817                                                 p->p_ucred->cr_gid);
818         sbuf_cat(sb, "Groups:\t");
819         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
820                 sbuf_printf(sb, "%d ",          p->p_ucred->cr_groups[i]);
821         PROC_UNLOCK(p);
822         sbuf_putc(sb, '\n');
823
824         /*
825          * Memory
826          *
827          * While our approximation of VmLib may not be accurate (I
828          * don't know of a simple way to verify it, and I'm not sure
829          * it has much meaning anyway), I believe it's good enough.
830          *
831          * The same code that could (I think) accurately compute VmLib
832          * could also compute VmLck, but I don't really care enough to
833          * implement it. Submissions are welcome.
834          */
835         sbuf_printf(sb, "VmSize:\t%8ju kB\n",   B2K((uintmax_t)kp.ki_size));
836         sbuf_printf(sb, "VmLck:\t%8u kB\n",     P2K(0)); /* XXX */
837         sbuf_printf(sb, "VmRSS:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_rssize));
838         sbuf_printf(sb, "VmData:\t%8ju kB\n",   P2K((uintmax_t)kp.ki_dsize));
839         sbuf_printf(sb, "VmStk:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_ssize));
840         sbuf_printf(sb, "VmExe:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_tsize));
841         lsize = B2P(kp.ki_size) - kp.ki_dsize -
842             kp.ki_ssize - kp.ki_tsize - 1;
843         sbuf_printf(sb, "VmLib:\t%8ju kB\n",    P2K((uintmax_t)lsize));
844
845         /*
846          * Signal masks
847          */
848         PROC_LOCK(p);
849         bsd_to_linux_sigset(&p->p_siglist, &siglist);
850         ps = p->p_sigacts;
851         mtx_lock(&ps->ps_mtx);
852         bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
853         bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
854         mtx_unlock(&ps->ps_mtx);
855         PROC_UNLOCK(p);
856
857         sbuf_printf(sb, "SigPnd:\t%016jx\n",    siglist.__mask);
858         /*
859          * XXX. SigBlk - target thread's signal mask, td_sigmask.
860          * To implement SigBlk pseudofs should support proc/tid dir entries.
861          */
862         sbuf_printf(sb, "SigBlk:\t%016x\n",     0);
863         sbuf_printf(sb, "SigIgn:\t%016jx\n",    sigignore.__mask);
864         sbuf_printf(sb, "SigCgt:\t%016jx\n",    sigcatch.__mask);
865
866         /*
867          * Linux also prints the capability masks, but we don't have
868          * capabilities yet, and when we do get them they're likely to
869          * be meaningless to Linux programs, so we lie. XXX
870          */
871         sbuf_printf(sb, "CapInh:\t%016x\n",     0);
872         sbuf_printf(sb, "CapPrm:\t%016x\n",     0);
873         sbuf_printf(sb, "CapEff:\t%016x\n",     0);
874
875         return (0);
876 }
877
878
879 /*
880  * Filler function for proc/pid/cwd
881  */
882 static int
883 linprocfs_doproccwd(PFS_FILL_ARGS)
884 {
885         struct filedesc *fdp;
886         struct vnode *vp;
887         char *fullpath = "unknown";
888         char *freepath = NULL;
889
890         fdp = p->p_fd;
891         FILEDESC_SLOCK(fdp);
892         vp = fdp->fd_cdir;
893         if (vp != NULL)
894                 VREF(vp);
895         FILEDESC_SUNLOCK(fdp);
896         vn_fullpath(td, vp, &fullpath, &freepath);
897         if (vp != NULL)
898                 vrele(vp);
899         sbuf_printf(sb, "%s", fullpath);
900         if (freepath)
901                 free(freepath, M_TEMP);
902         return (0);
903 }
904
905 /*
906  * Filler function for proc/pid/root
907  */
908 static int
909 linprocfs_doprocroot(PFS_FILL_ARGS)
910 {
911         struct filedesc *fdp;
912         struct vnode *vp;
913         char *fullpath = "unknown";
914         char *freepath = NULL;
915
916         fdp = p->p_fd;
917         FILEDESC_SLOCK(fdp);
918         vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
919         if (vp != NULL)
920                 VREF(vp);
921         FILEDESC_SUNLOCK(fdp);
922         vn_fullpath(td, vp, &fullpath, &freepath);
923         if (vp != NULL)
924                 vrele(vp);
925         sbuf_printf(sb, "%s", fullpath);
926         if (freepath)
927                 free(freepath, M_TEMP);
928         return (0);
929 }
930
931 /*
932  * Filler function for proc/pid/cmdline
933  */
934 static int
935 linprocfs_doproccmdline(PFS_FILL_ARGS)
936 {
937         int ret;
938
939         PROC_LOCK(p);
940         if ((ret = p_cansee(td, p)) != 0) {
941                 PROC_UNLOCK(p);
942                 return (ret);
943         }
944
945         /*
946          * Mimic linux behavior and pass only processes with usermode
947          * address space as valid.  Return zero silently otherwize.
948          */
949         if (p->p_vmspace == &vmspace0) {
950                 PROC_UNLOCK(p);
951                 return (0);
952         }
953         if (p->p_args != NULL) {
954                 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
955                 PROC_UNLOCK(p);
956                 return (0);
957         }
958
959         if ((p->p_flag & P_SYSTEM) != 0) {
960                 PROC_UNLOCK(p);
961                 return (0);
962         }
963
964         PROC_UNLOCK(p);
965
966         ret = proc_getargv(td, p, sb);
967         return (ret);
968 }
969
970 /*
971  * Filler function for proc/pid/environ
972  */
973 static int
974 linprocfs_doprocenviron(PFS_FILL_ARGS)
975 {
976
977         /*
978          * Mimic linux behavior and pass only processes with usermode
979          * address space as valid.  Return zero silently otherwize.
980          */
981         if (p->p_vmspace == &vmspace0)
982                 return (0);
983
984         return (proc_getenvv(td, p, sb));
985 }
986
987 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
988 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
989 static char vdso_str[] = "      [vdso]";
990 static char stack_str[] = "      [stack]";
991
992 /*
993  * Filler function for proc/pid/maps
994  */
995 static int
996 linprocfs_doprocmaps(PFS_FILL_ARGS)
997 {
998         struct vmspace *vm;
999         vm_map_t map;
1000         vm_map_entry_t entry, tmp_entry;
1001         vm_object_t obj, tobj, lobj;
1002         vm_offset_t e_start, e_end;
1003         vm_ooffset_t off = 0;
1004         vm_prot_t e_prot;
1005         unsigned int last_timestamp;
1006         char *name = "", *freename = NULL;
1007         const char *l_map_str;
1008         ino_t ino;
1009         int ref_count, shadow_count, flags;
1010         int error;
1011         struct vnode *vp;
1012         struct vattr vat;
1013
1014         PROC_LOCK(p);
1015         error = p_candebug(td, p);
1016         PROC_UNLOCK(p);
1017         if (error)
1018                 return (error);
1019
1020         if (uio->uio_rw != UIO_READ)
1021                 return (EOPNOTSUPP);
1022
1023         error = 0;
1024         vm = vmspace_acquire_ref(p);
1025         if (vm == NULL)
1026                 return (ESRCH);
1027
1028         if (SV_CURPROC_FLAG(SV_LP64))
1029                 l_map_str = l64_map_str;
1030         else
1031                 l_map_str = l32_map_str;
1032         map = &vm->vm_map;
1033         vm_map_lock_read(map);
1034         for (entry = map->header.next; entry != &map->header;
1035             entry = entry->next) {
1036                 name = "";
1037                 freename = NULL;
1038                 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1039                         continue;
1040                 e_prot = entry->protection;
1041                 e_start = entry->start;
1042                 e_end = entry->end;
1043                 obj = entry->object.vm_object;
1044                 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1045                         VM_OBJECT_RLOCK(tobj);
1046                         if (lobj != obj)
1047                                 VM_OBJECT_RUNLOCK(lobj);
1048                         lobj = tobj;
1049                 }
1050                 last_timestamp = map->timestamp;
1051                 vm_map_unlock_read(map);
1052                 ino = 0;
1053                 if (lobj) {
1054                         off = IDX_TO_OFF(lobj->size);
1055                         vp = vm_object_vnode(lobj);
1056                         if (vp != NULL)
1057                                 vref(vp);
1058                         if (lobj != obj)
1059                                 VM_OBJECT_RUNLOCK(lobj);
1060                         flags = obj->flags;
1061                         ref_count = obj->ref_count;
1062                         shadow_count = obj->shadow_count;
1063                         VM_OBJECT_RUNLOCK(obj);
1064                         if (vp != NULL) {
1065                                 vn_fullpath(td, vp, &name, &freename);
1066                                 vn_lock(vp, LK_SHARED | LK_RETRY);
1067                                 VOP_GETATTR(vp, &vat, td->td_ucred);
1068                                 ino = vat.va_fileid;
1069                                 vput(vp);
1070                         } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1071                                 if (e_start == p->p_sysent->sv_shared_page_base)
1072                                         name = vdso_str;
1073                                 if (e_end == p->p_sysent->sv_usrstack)
1074                                         name = stack_str;
1075                         }
1076                 } else {
1077                         flags = 0;
1078                         ref_count = 0;
1079                         shadow_count = 0;
1080                 }
1081
1082                 /*
1083                  * format:
1084                  *  start, end, access, offset, major, minor, inode, name.
1085                  */
1086                 error = sbuf_printf(sb, l_map_str,
1087                     (u_long)e_start, (u_long)e_end,
1088                     (e_prot & VM_PROT_READ)?"r":"-",
1089                     (e_prot & VM_PROT_WRITE)?"w":"-",
1090                     (e_prot & VM_PROT_EXECUTE)?"x":"-",
1091                     "p",
1092                     (u_long)off,
1093                     0,
1094                     0,
1095                     (u_long)ino,
1096                     *name ? "     " : "",
1097                     name
1098                     );
1099                 if (freename)
1100                         free(freename, M_TEMP);
1101                 vm_map_lock_read(map);
1102                 if (error == -1) {
1103                         error = 0;
1104                         break;
1105                 }
1106                 if (last_timestamp != map->timestamp) {
1107                         /*
1108                          * Look again for the entry because the map was
1109                          * modified while it was unlocked.  Specifically,
1110                          * the entry may have been clipped, merged, or deleted.
1111                          */
1112                         vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1113                         entry = tmp_entry;
1114                 }
1115         }
1116         vm_map_unlock_read(map);
1117         vmspace_free(vm);
1118
1119         return (error);
1120 }
1121
1122 /*
1123  * Criteria for interface name translation
1124  */
1125 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1126
1127 static int
1128 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1129 {
1130         struct ifnet *ifscan;
1131         int ethno;
1132
1133         IFNET_RLOCK_ASSERT();
1134
1135         /* Short-circuit non ethernet interfaces */
1136         if (!IFP_IS_ETH(ifp))
1137                 return (strlcpy(buffer, ifp->if_xname, buflen));
1138
1139         /* Determine the (relative) unit number for ethernet interfaces */
1140         ethno = 0;
1141         CK_STAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1142                 if (ifscan == ifp)
1143                         return (snprintf(buffer, buflen, "eth%d", ethno));
1144                 if (IFP_IS_ETH(ifscan))
1145                         ethno++;
1146         }
1147
1148         return (0);
1149 }
1150
1151 /*
1152  * Filler function for proc/net/dev
1153  */
1154 static int
1155 linprocfs_donetdev(PFS_FILL_ARGS)
1156 {
1157         char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1158         struct ifnet *ifp;
1159
1160         sbuf_printf(sb, "%6s|%58s|%s\n"
1161             "%6s|%58s|%58s\n",
1162             "Inter-", "   Receive", "  Transmit",
1163             " face",
1164             "bytes    packets errs drop fifo frame compressed multicast",
1165             "bytes    packets errs drop fifo colls carrier compressed");
1166
1167         CURVNET_SET(TD_TO_VNET(curthread));
1168         IFNET_RLOCK();
1169         CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1170                 linux_ifname(ifp, ifname, sizeof ifname);
1171                 sbuf_printf(sb, "%6.6s: ", ifname);
1172                 sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1173                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1174                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1175                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1176                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
1177                                                         /* rx_missed_errors */
1178                     0UL,                                /* rx_fifo_errors */
1179                     0UL,                                /* rx_length_errors +
1180                                                          * rx_over_errors +
1181                                                          * rx_crc_errors +
1182                                                          * rx_frame_errors */
1183                     0UL,                                /* rx_compressed */
1184                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1185                                                         /* XXX-BZ rx only? */
1186                 sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1187                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1188                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1189                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1190                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1191                     0UL,                                /* tx_fifo_errors */
1192                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1193                     0UL,                                /* tx_carrier_errors +
1194                                                          * tx_aborted_errors +
1195                                                          * tx_window_errors +
1196                                                          * tx_heartbeat_errors*/
1197                     0UL);                               /* tx_compressed */
1198         }
1199         IFNET_RUNLOCK();
1200         CURVNET_RESTORE();
1201
1202         return (0);
1203 }
1204
1205 /*
1206  * Filler function for proc/sys/kernel/osrelease
1207  */
1208 static int
1209 linprocfs_doosrelease(PFS_FILL_ARGS)
1210 {
1211         char osrelease[LINUX_MAX_UTSNAME];
1212
1213         linux_get_osrelease(td, osrelease);
1214         sbuf_printf(sb, "%s\n", osrelease);
1215
1216         return (0);
1217 }
1218
1219 /*
1220  * Filler function for proc/sys/kernel/ostype
1221  */
1222 static int
1223 linprocfs_doostype(PFS_FILL_ARGS)
1224 {
1225         char osname[LINUX_MAX_UTSNAME];
1226
1227         linux_get_osname(td, osname);
1228         sbuf_printf(sb, "%s\n", osname);
1229
1230         return (0);
1231 }
1232
1233 /*
1234  * Filler function for proc/sys/kernel/version
1235  */
1236 static int
1237 linprocfs_doosbuild(PFS_FILL_ARGS)
1238 {
1239
1240         linprocfs_osbuild(td, sb);
1241         sbuf_cat(sb, "\n");
1242         return (0);
1243 }
1244
1245 /*
1246  * Filler function for proc/sys/kernel/msgmni
1247  */
1248 static int
1249 linprocfs_domsgmni(PFS_FILL_ARGS)
1250 {
1251
1252         sbuf_printf(sb, "%d\n", msginfo.msgmni);
1253         return (0);
1254 }
1255
1256 /*
1257  * Filler function for proc/sys/kernel/pid_max
1258  */
1259 static int
1260 linprocfs_dopid_max(PFS_FILL_ARGS)
1261 {
1262
1263         sbuf_printf(sb, "%i\n", PID_MAX);
1264         return (0);
1265 }
1266
1267 /*
1268  * Filler function for proc/sys/kernel/sem
1269  */
1270 static int
1271 linprocfs_dosem(PFS_FILL_ARGS)
1272 {
1273
1274         sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1275             seminfo.semopm, seminfo.semmni);
1276         return (0);
1277 }
1278
1279 /*
1280  * Filler function for proc/scsi/device_info
1281  */
1282 static int
1283 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1284 {
1285
1286         return (0);
1287 }
1288
1289 /*
1290  * Filler function for proc/scsi/scsi
1291  */
1292 static int
1293 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1294 {
1295
1296         return (0);
1297 }
1298
1299 /*
1300  * Filler function for proc/devices
1301  */
1302 static int
1303 linprocfs_dodevices(PFS_FILL_ARGS)
1304 {
1305         char *char_devices;
1306         sbuf_printf(sb, "Character devices:\n");
1307
1308         char_devices = linux_get_char_devices();
1309         sbuf_printf(sb, "%s", char_devices);
1310         linux_free_get_char_devices(char_devices);
1311
1312         sbuf_printf(sb, "\nBlock devices:\n");
1313
1314         return (0);
1315 }
1316
1317 /*
1318  * Filler function for proc/cmdline
1319  */
1320 static int
1321 linprocfs_docmdline(PFS_FILL_ARGS)
1322 {
1323
1324         sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1325         sbuf_printf(sb, " ro root=302\n");
1326         return (0);
1327 }
1328
1329 /*
1330  * Filler function for proc/filesystems
1331  */
1332 static int
1333 linprocfs_dofilesystems(PFS_FILL_ARGS)
1334 {
1335         struct vfsconf *vfsp;
1336
1337         vfsconf_slock();
1338         TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1339                 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1340                         sbuf_printf(sb, "nodev");
1341                 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1342         }
1343         vfsconf_sunlock();
1344         return(0);
1345 }
1346
1347 #if 0
1348 /*
1349  * Filler function for proc/modules
1350  */
1351 static int
1352 linprocfs_domodules(PFS_FILL_ARGS)
1353 {
1354         struct linker_file *lf;
1355
1356         TAILQ_FOREACH(lf, &linker_files, link) {
1357                 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1358                     (unsigned long)lf->size, lf->refs);
1359         }
1360         return (0);
1361 }
1362 #endif
1363
1364 /*
1365  * Filler function for proc/pid/fd
1366  */
1367 static int
1368 linprocfs_dofdescfs(PFS_FILL_ARGS)
1369 {
1370
1371         if (p == curproc)
1372                 sbuf_printf(sb, "/dev/fd");
1373         else
1374                 sbuf_printf(sb, "unknown");
1375         return (0);
1376 }
1377
1378 /*
1379  * Filler function for proc/pid/limits
1380  */
1381 static const struct linux_rlimit_ident {
1382         const char      *desc;
1383         const char      *unit;
1384         unsigned int    rlim_id;
1385 } linux_rlimits_ident[] = {
1386         { "Max cpu time",       "seconds",      RLIMIT_CPU },
1387         { "Max file size",      "bytes",        RLIMIT_FSIZE },
1388         { "Max data size",      "bytes",        RLIMIT_DATA },
1389         { "Max stack size",     "bytes",        RLIMIT_STACK },
1390         { "Max core file size",  "bytes",       RLIMIT_CORE },
1391         { "Max resident set",   "bytes",        RLIMIT_RSS },
1392         { "Max processes",      "processes",    RLIMIT_NPROC },
1393         { "Max open files",     "files",        RLIMIT_NOFILE },
1394         { "Max locked memory",  "bytes",        RLIMIT_MEMLOCK },
1395         { "Max address space",  "bytes",        RLIMIT_AS },
1396         { "Max file locks",     "locks",        LINUX_RLIMIT_LOCKS },
1397         { "Max pending signals", "signals",     LINUX_RLIMIT_SIGPENDING },
1398         { "Max msgqueue size",  "bytes",        LINUX_RLIMIT_MSGQUEUE },
1399         { "Max nice priority",          "",     LINUX_RLIMIT_NICE },
1400         { "Max realtime priority",      "",     LINUX_RLIMIT_RTPRIO },
1401         { "Max realtime timeout",       "us",   LINUX_RLIMIT_RTTIME },
1402         { 0, 0, 0 }
1403 };
1404
1405 static int
1406 linprocfs_doproclimits(PFS_FILL_ARGS)
1407 {
1408         const struct linux_rlimit_ident *li;
1409         struct plimit *limp;
1410         struct rlimit rl;
1411         ssize_t size;
1412         int res, error;
1413
1414         error = 0;
1415
1416         PROC_LOCK(p);
1417         limp = lim_hold(p->p_limit);
1418         PROC_UNLOCK(p);
1419         size = sizeof(res);
1420         sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit",
1421                         "Hard Limit", "Units");
1422         for (li = linux_rlimits_ident; li->desc != NULL; ++li) {
1423                 switch (li->rlim_id)
1424                 {
1425                 case LINUX_RLIMIT_LOCKS:
1426                         /* FALLTHROUGH */
1427                 case LINUX_RLIMIT_RTTIME:
1428                         rl.rlim_cur = RLIM_INFINITY;
1429                         break;
1430                 case LINUX_RLIMIT_SIGPENDING:
1431                         error = kernel_sysctlbyname(td,
1432                             "kern.sigqueue.max_pending_per_proc",
1433                             &res, &size, 0, 0, 0, 0);
1434                         if (error != 0)
1435                                 goto out;
1436                         rl.rlim_cur = res;
1437                         rl.rlim_max = res;
1438                         break;
1439                 case LINUX_RLIMIT_MSGQUEUE:
1440                         error = kernel_sysctlbyname(td,
1441                             "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
1442                         if (error != 0)
1443                                 goto out;
1444                         rl.rlim_cur = res;
1445                         rl.rlim_max = res;
1446                         break;
1447                 case LINUX_RLIMIT_NICE:
1448                         /* FALLTHROUGH */
1449                 case LINUX_RLIMIT_RTPRIO:
1450                         rl.rlim_cur = 0;
1451                         rl.rlim_max = 0;
1452                         break;
1453                 default:
1454                         rl = limp->pl_rlimit[li->rlim_id];
1455                         break;
1456                 }
1457                 if (rl.rlim_cur == RLIM_INFINITY)
1458                         sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
1459                             li->desc, "unlimited", "unlimited", li->unit);
1460                 else
1461                         sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n",
1462                             li->desc, (unsigned long long)rl.rlim_cur,
1463                             (unsigned long long)rl.rlim_max, li->unit);
1464         }
1465 out:
1466         lim_free(limp);
1467         return (error);
1468 }
1469
1470 /*
1471  * Filler function for proc/sys/kernel/random/uuid
1472  */
1473 static int
1474 linprocfs_douuid(PFS_FILL_ARGS)
1475 {
1476         struct uuid uuid;
1477
1478         kern_uuidgen(&uuid, 1);
1479         sbuf_printf_uuid(sb, &uuid);
1480         sbuf_printf(sb, "\n");
1481         return(0);
1482 }
1483
1484 /*
1485  * Filler function for proc/pid/auxv
1486  */
1487 static int
1488 linprocfs_doauxv(PFS_FILL_ARGS)
1489 {
1490         struct sbuf *asb;
1491         off_t buflen, resid;
1492         int error;
1493
1494         /*
1495          * Mimic linux behavior and pass only processes with usermode
1496          * address space as valid. Return zero silently otherwise.
1497          */
1498         if (p->p_vmspace == &vmspace0)
1499                 return (0);
1500
1501         if (uio->uio_resid == 0)
1502                 return (0);
1503         if (uio->uio_offset < 0 || uio->uio_resid < 0)
1504                 return (EINVAL);
1505
1506         asb = sbuf_new_auto();
1507         if (asb == NULL)
1508                 return (ENOMEM);
1509         error = proc_getauxv(td, p, asb);
1510         if (error == 0)
1511                 error = sbuf_finish(asb);
1512
1513         resid = sbuf_len(asb) - uio->uio_offset;
1514         if (resid > uio->uio_resid)
1515                 buflen = uio->uio_resid;
1516         else
1517                 buflen = resid;
1518         if (buflen > IOSIZE_MAX)
1519                 return (EINVAL);
1520         if (buflen > MAXPHYS)
1521                 buflen = MAXPHYS;
1522         if (resid <= 0)
1523                 return (0);
1524
1525         if (error == 0)
1526                 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1527         sbuf_delete(asb);
1528         return (error);
1529 }
1530
1531 /*
1532  * Constructor
1533  */
1534 static int
1535 linprocfs_init(PFS_INIT_ARGS)
1536 {
1537         struct pfs_node *root;
1538         struct pfs_node *dir;
1539
1540         root = pi->pi_root;
1541
1542         /* /proc/... */
1543         pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1544             NULL, NULL, NULL, PFS_RD);
1545         pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1546             NULL, NULL, NULL, PFS_RD);
1547         pfs_create_file(root, "devices", &linprocfs_dodevices,
1548             NULL, NULL, NULL, PFS_RD);
1549         pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1550             NULL, NULL, NULL, PFS_RD);
1551         pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1552             NULL, NULL, NULL, PFS_RD);
1553         pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1554             NULL, NULL, NULL, PFS_RD);
1555 #if 0
1556         pfs_create_file(root, "modules", &linprocfs_domodules,
1557             NULL, NULL, NULL, PFS_RD);
1558 #endif
1559         pfs_create_file(root, "mounts", &linprocfs_domtab,
1560             NULL, NULL, NULL, PFS_RD);
1561         pfs_create_file(root, "mtab", &linprocfs_domtab,
1562             NULL, NULL, NULL, PFS_RD);
1563         pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1564             NULL, NULL, NULL, PFS_RD);
1565         pfs_create_link(root, "self", &procfs_docurproc,
1566             NULL, NULL, NULL, 0);
1567         pfs_create_file(root, "stat", &linprocfs_dostat,
1568             NULL, NULL, NULL, PFS_RD);
1569         pfs_create_file(root, "swaps", &linprocfs_doswaps,
1570             NULL, NULL, NULL, PFS_RD);
1571         pfs_create_file(root, "uptime", &linprocfs_douptime,
1572             NULL, NULL, NULL, PFS_RD);
1573         pfs_create_file(root, "version", &linprocfs_doversion,
1574             NULL, NULL, NULL, PFS_RD);
1575
1576         /* /proc/net/... */
1577         dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1578         pfs_create_file(dir, "dev", &linprocfs_donetdev,
1579             NULL, NULL, NULL, PFS_RD);
1580
1581         /* /proc/<pid>/... */
1582         dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1583         pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1584             NULL, NULL, NULL, PFS_RD);
1585         pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1586             NULL, NULL, NULL, 0);
1587         pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1588             NULL, &procfs_candebug, NULL, PFS_RD);
1589         pfs_create_link(dir, "exe", &procfs_doprocfile,
1590             NULL, &procfs_notsystem, NULL, 0);
1591         pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1592             NULL, NULL, NULL, PFS_RD);
1593         pfs_create_file(dir, "mem", &procfs_doprocmem,
1594             procfs_attr_rw, &procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
1595         pfs_create_file(dir, "mounts", &linprocfs_domtab,
1596             NULL, NULL, NULL, PFS_RD);
1597         pfs_create_link(dir, "root", &linprocfs_doprocroot,
1598             NULL, NULL, NULL, 0);
1599         pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1600             NULL, NULL, NULL, PFS_RD);
1601         pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1602             NULL, NULL, NULL, PFS_RD);
1603         pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1604             NULL, NULL, NULL, PFS_RD);
1605         pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1606             NULL, NULL, NULL, 0);
1607         pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1608             NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1609         pfs_create_file(dir, "limits", &linprocfs_doproclimits,
1610             NULL, NULL, NULL, PFS_RD);
1611
1612         /* /proc/scsi/... */
1613         dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1614         pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1615             NULL, NULL, NULL, PFS_RD);
1616         pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1617             NULL, NULL, NULL, PFS_RD);
1618
1619         /* /proc/sys/... */
1620         dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1621         /* /proc/sys/kernel/... */
1622         dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1623         pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1624             NULL, NULL, NULL, PFS_RD);
1625         pfs_create_file(dir, "ostype", &linprocfs_doostype,
1626             NULL, NULL, NULL, PFS_RD);
1627         pfs_create_file(dir, "version", &linprocfs_doosbuild,
1628             NULL, NULL, NULL, PFS_RD);
1629         pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1630             NULL, NULL, NULL, PFS_RD);
1631         pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1632             NULL, NULL, NULL, PFS_RD);
1633         pfs_create_file(dir, "sem", &linprocfs_dosem,
1634             NULL, NULL, NULL, PFS_RD);
1635
1636         /* /proc/sys/kernel/random/... */
1637         dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1638         pfs_create_file(dir, "uuid", &linprocfs_douuid,
1639             NULL, NULL, NULL, PFS_RD);
1640
1641         return (0);
1642 }
1643
1644 /*
1645  * Destructor
1646  */
1647 static int
1648 linprocfs_uninit(PFS_INIT_ARGS)
1649 {
1650
1651         /* nothing to do, pseudofs will GC */
1652         return (0);
1653 }
1654
1655 PSEUDOFS(linprocfs, 1, VFCF_JAIL);
1656 #if defined(__amd64__)
1657 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1658 #else
1659 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1660 #endif
1661 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1662 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1663 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);