]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/linprocfs/linprocfs.c
Merge lld release_80 branch r351543, and resolve conflicts.
[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 #else
321 /* ARM64TODO: implement non-stubbed linprocfs_docpuinfo */
322 static int
323 linprocfs_docpuinfo(PFS_FILL_ARGS)
324 {
325         int i;
326
327         for (i = 0; i < mp_ncpus; ++i) {
328                 sbuf_printf(sb,
329                     "processor\t: %d\n"
330                     "BogoMIPS\t: %d.%02d\n",
331                     i, 0, 0);
332                 sbuf_cat(sb, "Features\t: ");
333                 sbuf_cat(sb, "\n");
334                 sbuf_printf(sb,
335                     "CPU implementer\t: \n"
336                     "CPU architecture: \n"
337                     "CPU variant\t: 0x%x\n"
338                     "CPU part\t: 0x%x\n"
339                     "CPU revision\t: %d\n",
340                     0, 0, 0);
341                 sbuf_cat(sb, "\n");
342         }
343
344         return (0);
345 }
346 #endif /* __i386__ || __amd64__ */
347
348 /*
349  * Filler function for proc/mtab
350  *
351  * This file doesn't exist in Linux' procfs, but is included here so
352  * users can symlink /compat/linux/etc/mtab to /proc/mtab
353  */
354 static int
355 linprocfs_domtab(PFS_FILL_ARGS)
356 {
357         struct nameidata nd;
358         const char *lep;
359         char *dlep, *flep, *mntto, *mntfrom, *fstype;
360         size_t lep_len;
361         int error;
362         struct statfs *buf, *sp;
363         size_t count;
364
365         /* resolve symlinks etc. in the emulation tree prefix */
366         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
367         flep = NULL;
368         error = namei(&nd);
369         lep = linux_emul_path;
370         if (error == 0) {
371                 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
372                         lep = dlep;
373                 vrele(nd.ni_vp);
374         }
375         lep_len = strlen(lep);
376
377         buf = NULL;
378         error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
379             UIO_SYSSPACE, MNT_WAIT);
380         if (error != 0) {
381                 free(buf, M_TEMP);
382                 free(flep, M_TEMP);
383                 return (error);
384         }
385
386         for (sp = buf; count > 0; sp++, count--) {
387                 /* determine device name */
388                 mntfrom = sp->f_mntfromname;
389
390                 /* determine mount point */
391                 mntto = sp->f_mntonname;
392                 if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
393                         mntto += lep_len;
394
395                 /* determine fs type */
396                 fstype = sp->f_fstypename;
397                 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
398                         mntfrom = fstype = "proc";
399                 else if (strcmp(fstype, "procfs") == 0)
400                         continue;
401
402                 if (strcmp(fstype, "linsysfs") == 0) {
403                         sbuf_printf(sb, "/sys %s sysfs %s", mntto,
404                             sp->f_flags & MNT_RDONLY ? "ro" : "rw");
405                 } else {
406                         /* For Linux msdosfs is called vfat */
407                         if (strcmp(fstype, "msdosfs") == 0)
408                                 fstype = "vfat";
409                         sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
410                             sp->f_flags & MNT_RDONLY ? "ro" : "rw");
411                 }
412 #define ADD_OPTION(opt, name) \
413         if (sp->f_flags & (opt)) sbuf_printf(sb, "," name);
414                 ADD_OPTION(MNT_SYNCHRONOUS,     "sync");
415                 ADD_OPTION(MNT_NOEXEC,          "noexec");
416                 ADD_OPTION(MNT_NOSUID,          "nosuid");
417                 ADD_OPTION(MNT_UNION,           "union");
418                 ADD_OPTION(MNT_ASYNC,           "async");
419                 ADD_OPTION(MNT_SUIDDIR,         "suiddir");
420                 ADD_OPTION(MNT_NOSYMFOLLOW,     "nosymfollow");
421                 ADD_OPTION(MNT_NOATIME,         "noatime");
422 #undef ADD_OPTION
423                 /* a real Linux mtab will also show NFS options */
424                 sbuf_printf(sb, " 0 0\n");
425         }
426
427         free(buf, M_TEMP);
428         free(flep, M_TEMP);
429         return (error);
430 }
431
432 /*
433  * Filler function for proc/partitions
434  */
435 static int
436 linprocfs_dopartitions(PFS_FILL_ARGS)
437 {
438         struct g_class *cp;
439         struct g_geom *gp;
440         struct g_provider *pp;
441         int major, minor;
442
443         g_topology_lock();
444         sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
445             "ruse wio wmerge wsect wuse running use aveq\n");
446
447         LIST_FOREACH(cp, &g_classes, class) {
448                 if (strcmp(cp->name, "DISK") == 0 ||
449                     strcmp(cp->name, "PART") == 0)
450                         LIST_FOREACH(gp, &cp->geom, geom) {
451                                 LIST_FOREACH(pp, &gp->provider, provider) {
452                                         if (linux_driver_get_major_minor(
453                                             pp->name, &major, &minor) != 0) {
454                                                 major = 0;
455                                                 minor = 0;
456                                         }
457                                         sbuf_printf(sb, "%d %d %lld %s "
458                                             "%d %d %d %d %d "
459                                              "%d %d %d %d %d %d\n",
460                                              major, minor,
461                                              (long long)pp->mediasize, pp->name,
462                                              0, 0, 0, 0, 0,
463                                              0, 0, 0, 0, 0, 0);
464                                 }
465                         }
466         }
467         g_topology_unlock();
468
469         return (0);
470 }
471
472 /*
473  * Filler function for proc/stat
474  *
475  * Output depends on kernel version:
476  *
477  * v2.5.40 <=
478  *   user nice system idle
479  * v2.5.41
480  *   user nice system idle iowait
481  * v2.6.11
482  *   user nice system idle iowait irq softirq steal
483  * v2.6.24
484  *   user nice system idle iowait irq softirq steal guest
485  * v2.6.33 >=
486  *   user nice system idle iowait irq softirq steal guest guest_nice
487  */
488 static int
489 linprocfs_dostat(PFS_FILL_ARGS)
490 {
491         struct pcpu *pcpu;
492         long cp_time[CPUSTATES];
493         long *cp;
494         struct timeval boottime;
495         int i;
496         char *zero_pad;
497         bool has_intr = true;
498
499         if (linux_kernver(td) >= LINUX_KERNVER(2,6,33)) {
500                 zero_pad = " 0 0 0 0\n";
501         } else if (linux_kernver(td) >= LINUX_KERNVER(2,6,24)) {
502                 zero_pad = " 0 0 0\n";
503         } else if (linux_kernver(td) >= LINUX_KERNVER(2,6,11)) {
504                 zero_pad = " 0 0\n";
505         } else if (linux_kernver(td) >= LINUX_KERNVER(2,5,41)) {
506                 has_intr = false;
507                 zero_pad = " 0\n";
508         } else {
509                 has_intr = false;
510                 zero_pad = "\n";
511         }
512
513         read_cpu_time(cp_time);
514         getboottime(&boottime);
515         /* Parameters common to all versions */
516         sbuf_printf(sb, "cpu %lu %lu %lu %lu",
517             T2J(cp_time[CP_USER]),
518             T2J(cp_time[CP_NICE]),
519             T2J(cp_time[CP_SYS]),
520             T2J(cp_time[CP_IDLE]));
521
522         /* Print interrupt stats if available */
523         if (has_intr) {
524                 sbuf_printf(sb, " 0 %lu", T2J(cp_time[CP_INTR]));
525         }
526
527         /* Pad out remaining fields depending on version */
528         sbuf_printf(sb, "%s", zero_pad);
529
530         CPU_FOREACH(i) {
531                 pcpu = pcpu_find(i);
532                 cp = pcpu->pc_cp_time;
533                 sbuf_printf(sb, "cpu%d %lu %lu %lu %lu", i,
534                     T2J(cp[CP_USER]),
535                     T2J(cp[CP_NICE]),
536                     T2J(cp[CP_SYS]),
537                     T2J(cp[CP_IDLE]));
538
539                 if (has_intr) {
540                         sbuf_printf(sb, " 0 %lu", T2J(cp[CP_INTR]));
541                 }
542
543                 sbuf_printf(sb, "%s", zero_pad);
544         }
545         sbuf_printf(sb,
546             "disk 0 0 0 0\n"
547             "page %ju %ju\n"
548             "swap %ju %ju\n"
549             "intr %ju\n"
550             "ctxt %ju\n"
551             "btime %lld\n",
552             (uintmax_t)VM_CNT_FETCH(v_vnodepgsin),
553             (uintmax_t)VM_CNT_FETCH(v_vnodepgsout),
554             (uintmax_t)VM_CNT_FETCH(v_swappgsin),
555             (uintmax_t)VM_CNT_FETCH(v_swappgsout),
556             (uintmax_t)VM_CNT_FETCH(v_intr),
557             (uintmax_t)VM_CNT_FETCH(v_swtch),
558             (long long)boottime.tv_sec);
559         return (0);
560 }
561
562 static int
563 linprocfs_doswaps(PFS_FILL_ARGS)
564 {
565         struct xswdev xsw;
566         uintmax_t total, used;
567         int n;
568         char devname[SPECNAMELEN + 1];
569
570         sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
571         for (n = 0; ; n++) {
572                 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
573                         break;
574                 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
575                 used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
576
577                 /*
578                  * The space and not tab after the device name is on
579                  * purpose.  Linux does so.
580                  */
581                 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
582                     devname, total, used);
583         }
584         return (0);
585 }
586
587 /*
588  * Filler function for proc/uptime
589  */
590 static int
591 linprocfs_douptime(PFS_FILL_ARGS)
592 {
593         long cp_time[CPUSTATES];
594         struct timeval tv;
595
596         getmicrouptime(&tv);
597         read_cpu_time(cp_time);
598         sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
599             (long long)tv.tv_sec, tv.tv_usec / 10000,
600             T2S(cp_time[CP_IDLE] / mp_ncpus),
601             T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
602         return (0);
603 }
604
605 /*
606  * Get OS build date
607  */
608 static void
609 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
610 {
611 #if 0
612         char osbuild[256];
613         char *cp1, *cp2;
614
615         strncpy(osbuild, version, 256);
616         osbuild[255] = '\0';
617         cp1 = strstr(osbuild, "\n");
618         cp2 = strstr(osbuild, ":");
619         if (cp1 && cp2) {
620                 *cp1 = *cp2 = '\0';
621                 cp1 = strstr(osbuild, "#");
622         } else
623                 cp1 = NULL;
624         if (cp1)
625                 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
626         else
627 #endif
628                 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
629 }
630
631 /*
632  * Get OS builder
633  */
634 static void
635 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
636 {
637 #if 0
638         char builder[256];
639         char *cp;
640
641         cp = strstr(version, "\n    ");
642         if (cp) {
643                 strncpy(builder, cp + 5, 256);
644                 builder[255] = '\0';
645                 cp = strstr(builder, ":");
646                 if (cp)
647                         *cp = '\0';
648         }
649         if (cp)
650                 sbuf_cat(sb, builder);
651         else
652 #endif
653                 sbuf_cat(sb, "des@freebsd.org");
654 }
655
656 /*
657  * Filler function for proc/version
658  */
659 static int
660 linprocfs_doversion(PFS_FILL_ARGS)
661 {
662         char osname[LINUX_MAX_UTSNAME];
663         char osrelease[LINUX_MAX_UTSNAME];
664
665         linux_get_osname(td, osname);
666         linux_get_osrelease(td, osrelease);
667         sbuf_printf(sb, "%s version %s (", osname, osrelease);
668         linprocfs_osbuilder(td, sb);
669         sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
670         linprocfs_osbuild(td, sb);
671         sbuf_cat(sb, "\n");
672
673         return (0);
674 }
675
676 /*
677  * Filler function for proc/loadavg
678  */
679 static int
680 linprocfs_doloadavg(PFS_FILL_ARGS)
681 {
682
683         sbuf_printf(sb,
684             "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
685             (int)(averunnable.ldavg[0] / averunnable.fscale),
686             (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
687             (int)(averunnable.ldavg[1] / averunnable.fscale),
688             (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
689             (int)(averunnable.ldavg[2] / averunnable.fscale),
690             (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
691             1,                          /* number of running tasks */
692             nprocs,                     /* number of tasks */
693             lastpid                     /* the last pid */
694         );
695         return (0);
696 }
697
698 /*
699  * Filler function for proc/pid/stat
700  */
701 static int
702 linprocfs_doprocstat(PFS_FILL_ARGS)
703 {
704         struct kinfo_proc kp;
705         struct timeval boottime;
706         char state;
707         static int ratelimit = 0;
708         vm_offset_t startcode, startdata;
709
710         getboottime(&boottime);
711         sx_slock(&proctree_lock);
712         PROC_LOCK(p);
713         fill_kinfo_proc(p, &kp);
714         sx_sunlock(&proctree_lock);
715         if (p->p_vmspace) {
716            startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
717            startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
718         } else {
719            startcode = 0;
720            startdata = 0;
721         }
722         sbuf_printf(sb, "%d", p->p_pid);
723 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
724         PS_ADD("comm",          "(%s)", p->p_comm);
725         if (kp.ki_stat > sizeof(linux_state)) {
726                 state = 'R';
727
728                 if (ratelimit == 0) {
729                         printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
730                             kp.ki_stat, sizeof(linux_state));
731                         ++ratelimit;
732                 }
733         } else
734                 state = linux_state[kp.ki_stat - 1];
735         PS_ADD("state",         "%c",   state);
736         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
737         PS_ADD("pgrp",          "%d",   p->p_pgid);
738         PS_ADD("session",       "%d",   p->p_session->s_sid);
739         PROC_UNLOCK(p);
740         PS_ADD("tty",           "%ju",  (uintmax_t)kp.ki_tdev);
741         PS_ADD("tpgid",         "%d",   kp.ki_tpgid);
742         PS_ADD("flags",         "%u",   0); /* XXX */
743         PS_ADD("minflt",        "%lu",  kp.ki_rusage.ru_minflt);
744         PS_ADD("cminflt",       "%lu",  kp.ki_rusage_ch.ru_minflt);
745         PS_ADD("majflt",        "%lu",  kp.ki_rusage.ru_majflt);
746         PS_ADD("cmajflt",       "%lu",  kp.ki_rusage_ch.ru_majflt);
747         PS_ADD("utime",         "%ld",  TV2J(&kp.ki_rusage.ru_utime));
748         PS_ADD("stime",         "%ld",  TV2J(&kp.ki_rusage.ru_stime));
749         PS_ADD("cutime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_utime));
750         PS_ADD("cstime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_stime));
751         PS_ADD("priority",      "%d",   kp.ki_pri.pri_user);
752         PS_ADD("nice",          "%d",   kp.ki_nice); /* 19 (nicest) to -19 */
753         PS_ADD("0",             "%d",   0); /* removed field */
754         PS_ADD("itrealvalue",   "%d",   0); /* XXX */
755         PS_ADD("starttime",     "%lu",  TV2J(&kp.ki_start) - TV2J(&boottime));
756         PS_ADD("vsize",         "%ju",  P2K((uintmax_t)kp.ki_size));
757         PS_ADD("rss",           "%ju",  (uintmax_t)kp.ki_rssize);
758         PS_ADD("rlim",          "%lu",  kp.ki_rusage.ru_maxrss);
759         PS_ADD("startcode",     "%ju",  (uintmax_t)startcode);
760         PS_ADD("endcode",       "%ju",  (uintmax_t)startdata);
761         PS_ADD("startstack",    "%u",   0); /* XXX */
762         PS_ADD("kstkesp",       "%u",   0); /* XXX */
763         PS_ADD("kstkeip",       "%u",   0); /* XXX */
764         PS_ADD("signal",        "%u",   0); /* XXX */
765         PS_ADD("blocked",       "%u",   0); /* XXX */
766         PS_ADD("sigignore",     "%u",   0); /* XXX */
767         PS_ADD("sigcatch",      "%u",   0); /* XXX */
768         PS_ADD("wchan",         "%u",   0); /* XXX */
769         PS_ADD("nswap",         "%lu",  kp.ki_rusage.ru_nswap);
770         PS_ADD("cnswap",        "%lu",  kp.ki_rusage_ch.ru_nswap);
771         PS_ADD("exitsignal",    "%d",   0); /* XXX */
772         PS_ADD("processor",     "%u",   kp.ki_lastcpu);
773         PS_ADD("rt_priority",   "%u",   0); /* XXX */ /* >= 2.5.19 */
774         PS_ADD("policy",        "%u",   kp.ki_pri.pri_class); /* >= 2.5.19 */
775 #undef PS_ADD
776         sbuf_putc(sb, '\n');
777
778         return (0);
779 }
780
781 /*
782  * Filler function for proc/pid/statm
783  */
784 static int
785 linprocfs_doprocstatm(PFS_FILL_ARGS)
786 {
787         struct kinfo_proc kp;
788         segsz_t lsize;
789
790         sx_slock(&proctree_lock);
791         PROC_LOCK(p);
792         fill_kinfo_proc(p, &kp);
793         PROC_UNLOCK(p);
794         sx_sunlock(&proctree_lock);
795
796         /*
797          * See comments in linprocfs_doprocstatus() regarding the
798          * computation of lsize.
799          */
800         /* size resident share trs drs lrs dt */
801         sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
802         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
803         sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
804         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
805         sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
806         lsize = B2P(kp.ki_size) - kp.ki_dsize -
807             kp.ki_ssize - kp.ki_tsize - 1;
808         sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
809         sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
810
811         return (0);
812 }
813
814 /*
815  * Filler function for proc/pid/status
816  */
817 static int
818 linprocfs_doprocstatus(PFS_FILL_ARGS)
819 {
820         struct kinfo_proc kp;
821         char *state;
822         segsz_t lsize;
823         struct thread *td2;
824         struct sigacts *ps;
825         l_sigset_t siglist, sigignore, sigcatch;
826         int i;
827
828         sx_slock(&proctree_lock);
829         PROC_LOCK(p);
830         td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
831
832         if (P_SHOULDSTOP(p)) {
833                 state = "T (stopped)";
834         } else {
835                 switch(p->p_state) {
836                 case PRS_NEW:
837                         state = "I (idle)";
838                         break;
839                 case PRS_NORMAL:
840                         if (p->p_flag & P_WEXIT) {
841                                 state = "X (exiting)";
842                                 break;
843                         }
844                         switch(td2->td_state) {
845                         case TDS_INHIBITED:
846                                 state = "S (sleeping)";
847                                 break;
848                         case TDS_RUNQ:
849                         case TDS_RUNNING:
850                                 state = "R (running)";
851                                 break;
852                         default:
853                                 state = "? (unknown)";
854                                 break;
855                         }
856                         break;
857                 case PRS_ZOMBIE:
858                         state = "Z (zombie)";
859                         break;
860                 default:
861                         state = "? (unknown)";
862                         break;
863                 }
864         }
865
866         fill_kinfo_proc(p, &kp);
867         sx_sunlock(&proctree_lock);
868
869         sbuf_printf(sb, "Name:\t%s\n",          p->p_comm); /* XXX escape */
870         sbuf_printf(sb, "State:\t%s\n",         state);
871
872         /*
873          * Credentials
874          */
875         sbuf_printf(sb, "Pid:\t%d\n",           p->p_pid);
876         sbuf_printf(sb, "PPid:\t%d\n",          kp.ki_ppid );
877         sbuf_printf(sb, "TracerPid:\t%d\n",     kp.ki_tracer );
878         sbuf_printf(sb, "Uid:\t%d %d %d %d\n",  p->p_ucred->cr_ruid,
879                                                 p->p_ucred->cr_uid,
880                                                 p->p_ucred->cr_svuid,
881                                                 /* FreeBSD doesn't have fsuid */
882                                                 p->p_ucred->cr_uid);
883         sbuf_printf(sb, "Gid:\t%d %d %d %d\n",  p->p_ucred->cr_rgid,
884                                                 p->p_ucred->cr_gid,
885                                                 p->p_ucred->cr_svgid,
886                                                 /* FreeBSD doesn't have fsgid */
887                                                 p->p_ucred->cr_gid);
888         sbuf_cat(sb, "Groups:\t");
889         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
890                 sbuf_printf(sb, "%d ",          p->p_ucred->cr_groups[i]);
891         PROC_UNLOCK(p);
892         sbuf_putc(sb, '\n');
893
894         /*
895          * Memory
896          *
897          * While our approximation of VmLib may not be accurate (I
898          * don't know of a simple way to verify it, and I'm not sure
899          * it has much meaning anyway), I believe it's good enough.
900          *
901          * The same code that could (I think) accurately compute VmLib
902          * could also compute VmLck, but I don't really care enough to
903          * implement it. Submissions are welcome.
904          */
905         sbuf_printf(sb, "VmSize:\t%8ju kB\n",   B2K((uintmax_t)kp.ki_size));
906         sbuf_printf(sb, "VmLck:\t%8u kB\n",     P2K(0)); /* XXX */
907         sbuf_printf(sb, "VmRSS:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_rssize));
908         sbuf_printf(sb, "VmData:\t%8ju kB\n",   P2K((uintmax_t)kp.ki_dsize));
909         sbuf_printf(sb, "VmStk:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_ssize));
910         sbuf_printf(sb, "VmExe:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_tsize));
911         lsize = B2P(kp.ki_size) - kp.ki_dsize -
912             kp.ki_ssize - kp.ki_tsize - 1;
913         sbuf_printf(sb, "VmLib:\t%8ju kB\n",    P2K((uintmax_t)lsize));
914
915         /*
916          * Signal masks
917          */
918         PROC_LOCK(p);
919         bsd_to_linux_sigset(&p->p_siglist, &siglist);
920         ps = p->p_sigacts;
921         mtx_lock(&ps->ps_mtx);
922         bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
923         bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
924         mtx_unlock(&ps->ps_mtx);
925         PROC_UNLOCK(p);
926
927         sbuf_printf(sb, "SigPnd:\t%016jx\n",    siglist.__mask);
928         /*
929          * XXX. SigBlk - target thread's signal mask, td_sigmask.
930          * To implement SigBlk pseudofs should support proc/tid dir entries.
931          */
932         sbuf_printf(sb, "SigBlk:\t%016x\n",     0);
933         sbuf_printf(sb, "SigIgn:\t%016jx\n",    sigignore.__mask);
934         sbuf_printf(sb, "SigCgt:\t%016jx\n",    sigcatch.__mask);
935
936         /*
937          * Linux also prints the capability masks, but we don't have
938          * capabilities yet, and when we do get them they're likely to
939          * be meaningless to Linux programs, so we lie. XXX
940          */
941         sbuf_printf(sb, "CapInh:\t%016x\n",     0);
942         sbuf_printf(sb, "CapPrm:\t%016x\n",     0);
943         sbuf_printf(sb, "CapEff:\t%016x\n",     0);
944
945         return (0);
946 }
947
948
949 /*
950  * Filler function for proc/pid/cwd
951  */
952 static int
953 linprocfs_doproccwd(PFS_FILL_ARGS)
954 {
955         struct filedesc *fdp;
956         struct vnode *vp;
957         char *fullpath = "unknown";
958         char *freepath = NULL;
959
960         fdp = p->p_fd;
961         FILEDESC_SLOCK(fdp);
962         vp = fdp->fd_cdir;
963         if (vp != NULL)
964                 VREF(vp);
965         FILEDESC_SUNLOCK(fdp);
966         vn_fullpath(td, vp, &fullpath, &freepath);
967         if (vp != NULL)
968                 vrele(vp);
969         sbuf_printf(sb, "%s", fullpath);
970         if (freepath)
971                 free(freepath, M_TEMP);
972         return (0);
973 }
974
975 /*
976  * Filler function for proc/pid/root
977  */
978 static int
979 linprocfs_doprocroot(PFS_FILL_ARGS)
980 {
981         struct filedesc *fdp;
982         struct vnode *vp;
983         char *fullpath = "unknown";
984         char *freepath = NULL;
985
986         fdp = p->p_fd;
987         FILEDESC_SLOCK(fdp);
988         vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
989         if (vp != NULL)
990                 VREF(vp);
991         FILEDESC_SUNLOCK(fdp);
992         vn_fullpath(td, vp, &fullpath, &freepath);
993         if (vp != NULL)
994                 vrele(vp);
995         sbuf_printf(sb, "%s", fullpath);
996         if (freepath)
997                 free(freepath, M_TEMP);
998         return (0);
999 }
1000
1001 /*
1002  * Filler function for proc/pid/cmdline
1003  */
1004 static int
1005 linprocfs_doproccmdline(PFS_FILL_ARGS)
1006 {
1007         int ret;
1008
1009         PROC_LOCK(p);
1010         if ((ret = p_cansee(td, p)) != 0) {
1011                 PROC_UNLOCK(p);
1012                 return (ret);
1013         }
1014
1015         /*
1016          * Mimic linux behavior and pass only processes with usermode
1017          * address space as valid.  Return zero silently otherwize.
1018          */
1019         if (p->p_vmspace == &vmspace0) {
1020                 PROC_UNLOCK(p);
1021                 return (0);
1022         }
1023         if (p->p_args != NULL) {
1024                 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
1025                 PROC_UNLOCK(p);
1026                 return (0);
1027         }
1028
1029         if ((p->p_flag & P_SYSTEM) != 0) {
1030                 PROC_UNLOCK(p);
1031                 return (0);
1032         }
1033
1034         PROC_UNLOCK(p);
1035
1036         ret = proc_getargv(td, p, sb);
1037         return (ret);
1038 }
1039
1040 /*
1041  * Filler function for proc/pid/environ
1042  */
1043 static int
1044 linprocfs_doprocenviron(PFS_FILL_ARGS)
1045 {
1046
1047         /*
1048          * Mimic linux behavior and pass only processes with usermode
1049          * address space as valid.  Return zero silently otherwize.
1050          */
1051         if (p->p_vmspace == &vmspace0)
1052                 return (0);
1053
1054         return (proc_getenvv(td, p, sb));
1055 }
1056
1057 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
1058 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
1059 static char vdso_str[] = "      [vdso]";
1060 static char stack_str[] = "      [stack]";
1061
1062 /*
1063  * Filler function for proc/pid/maps
1064  */
1065 static int
1066 linprocfs_doprocmaps(PFS_FILL_ARGS)
1067 {
1068         struct vmspace *vm;
1069         vm_map_t map;
1070         vm_map_entry_t entry, tmp_entry;
1071         vm_object_t obj, tobj, lobj;
1072         vm_offset_t e_start, e_end;
1073         vm_ooffset_t off = 0;
1074         vm_prot_t e_prot;
1075         unsigned int last_timestamp;
1076         char *name = "", *freename = NULL;
1077         const char *l_map_str;
1078         ino_t ino;
1079         int ref_count, shadow_count, flags;
1080         int error;
1081         struct vnode *vp;
1082         struct vattr vat;
1083
1084         PROC_LOCK(p);
1085         error = p_candebug(td, p);
1086         PROC_UNLOCK(p);
1087         if (error)
1088                 return (error);
1089
1090         if (uio->uio_rw != UIO_READ)
1091                 return (EOPNOTSUPP);
1092
1093         error = 0;
1094         vm = vmspace_acquire_ref(p);
1095         if (vm == NULL)
1096                 return (ESRCH);
1097
1098         if (SV_CURPROC_FLAG(SV_LP64))
1099                 l_map_str = l64_map_str;
1100         else
1101                 l_map_str = l32_map_str;
1102         map = &vm->vm_map;
1103         vm_map_lock_read(map);
1104         for (entry = map->header.next; entry != &map->header;
1105             entry = entry->next) {
1106                 name = "";
1107                 freename = NULL;
1108                 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1109                         continue;
1110                 e_prot = entry->protection;
1111                 e_start = entry->start;
1112                 e_end = entry->end;
1113                 obj = entry->object.vm_object;
1114                 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1115                         VM_OBJECT_RLOCK(tobj);
1116                         if (lobj != obj)
1117                                 VM_OBJECT_RUNLOCK(lobj);
1118                         lobj = tobj;
1119                 }
1120                 last_timestamp = map->timestamp;
1121                 vm_map_unlock_read(map);
1122                 ino = 0;
1123                 if (lobj) {
1124                         off = IDX_TO_OFF(lobj->size);
1125                         vp = vm_object_vnode(lobj);
1126                         if (vp != NULL)
1127                                 vref(vp);
1128                         if (lobj != obj)
1129                                 VM_OBJECT_RUNLOCK(lobj);
1130                         flags = obj->flags;
1131                         ref_count = obj->ref_count;
1132                         shadow_count = obj->shadow_count;
1133                         VM_OBJECT_RUNLOCK(obj);
1134                         if (vp != NULL) {
1135                                 vn_fullpath(td, vp, &name, &freename);
1136                                 vn_lock(vp, LK_SHARED | LK_RETRY);
1137                                 VOP_GETATTR(vp, &vat, td->td_ucred);
1138                                 ino = vat.va_fileid;
1139                                 vput(vp);
1140                         } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1141                                 if (e_start == p->p_sysent->sv_shared_page_base)
1142                                         name = vdso_str;
1143                                 if (e_end == p->p_sysent->sv_usrstack)
1144                                         name = stack_str;
1145                         }
1146                 } else {
1147                         flags = 0;
1148                         ref_count = 0;
1149                         shadow_count = 0;
1150                 }
1151
1152                 /*
1153                  * format:
1154                  *  start, end, access, offset, major, minor, inode, name.
1155                  */
1156                 error = sbuf_printf(sb, l_map_str,
1157                     (u_long)e_start, (u_long)e_end,
1158                     (e_prot & VM_PROT_READ)?"r":"-",
1159                     (e_prot & VM_PROT_WRITE)?"w":"-",
1160                     (e_prot & VM_PROT_EXECUTE)?"x":"-",
1161                     "p",
1162                     (u_long)off,
1163                     0,
1164                     0,
1165                     (u_long)ino,
1166                     *name ? "     " : "",
1167                     name
1168                     );
1169                 if (freename)
1170                         free(freename, M_TEMP);
1171                 vm_map_lock_read(map);
1172                 if (error == -1) {
1173                         error = 0;
1174                         break;
1175                 }
1176                 if (last_timestamp != map->timestamp) {
1177                         /*
1178                          * Look again for the entry because the map was
1179                          * modified while it was unlocked.  Specifically,
1180                          * the entry may have been clipped, merged, or deleted.
1181                          */
1182                         vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1183                         entry = tmp_entry;
1184                 }
1185         }
1186         vm_map_unlock_read(map);
1187         vmspace_free(vm);
1188
1189         return (error);
1190 }
1191
1192 /*
1193  * Criteria for interface name translation
1194  */
1195 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1196
1197 static int
1198 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1199 {
1200         struct ifnet *ifscan;
1201         int ethno;
1202
1203         IFNET_RLOCK_ASSERT();
1204
1205         /* Short-circuit non ethernet interfaces */
1206         if (!IFP_IS_ETH(ifp))
1207                 return (strlcpy(buffer, ifp->if_xname, buflen));
1208
1209         /* Determine the (relative) unit number for ethernet interfaces */
1210         ethno = 0;
1211         CK_STAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1212                 if (ifscan == ifp)
1213                         return (snprintf(buffer, buflen, "eth%d", ethno));
1214                 if (IFP_IS_ETH(ifscan))
1215                         ethno++;
1216         }
1217
1218         return (0);
1219 }
1220
1221 /*
1222  * Filler function for proc/net/dev
1223  */
1224 static int
1225 linprocfs_donetdev(PFS_FILL_ARGS)
1226 {
1227         char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1228         struct ifnet *ifp;
1229
1230         sbuf_printf(sb, "%6s|%58s|%s\n"
1231             "%6s|%58s|%58s\n",
1232             "Inter-", "   Receive", "  Transmit",
1233             " face",
1234             "bytes    packets errs drop fifo frame compressed multicast",
1235             "bytes    packets errs drop fifo colls carrier compressed");
1236
1237         CURVNET_SET(TD_TO_VNET(curthread));
1238         IFNET_RLOCK();
1239         CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1240                 linux_ifname(ifp, ifname, sizeof ifname);
1241                 sbuf_printf(sb, "%6.6s: ", ifname);
1242                 sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1243                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1244                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1245                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1246                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
1247                                                         /* rx_missed_errors */
1248                     0UL,                                /* rx_fifo_errors */
1249                     0UL,                                /* rx_length_errors +
1250                                                          * rx_over_errors +
1251                                                          * rx_crc_errors +
1252                                                          * rx_frame_errors */
1253                     0UL,                                /* rx_compressed */
1254                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1255                                                         /* XXX-BZ rx only? */
1256                 sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1257                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1258                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1259                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1260                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1261                     0UL,                                /* tx_fifo_errors */
1262                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1263                     0UL,                                /* tx_carrier_errors +
1264                                                          * tx_aborted_errors +
1265                                                          * tx_window_errors +
1266                                                          * tx_heartbeat_errors*/
1267                     0UL);                               /* tx_compressed */
1268         }
1269         IFNET_RUNLOCK();
1270         CURVNET_RESTORE();
1271
1272         return (0);
1273 }
1274
1275 /*
1276  * Filler function for proc/sys/kernel/osrelease
1277  */
1278 static int
1279 linprocfs_doosrelease(PFS_FILL_ARGS)
1280 {
1281         char osrelease[LINUX_MAX_UTSNAME];
1282
1283         linux_get_osrelease(td, osrelease);
1284         sbuf_printf(sb, "%s\n", osrelease);
1285
1286         return (0);
1287 }
1288
1289 /*
1290  * Filler function for proc/sys/kernel/ostype
1291  */
1292 static int
1293 linprocfs_doostype(PFS_FILL_ARGS)
1294 {
1295         char osname[LINUX_MAX_UTSNAME];
1296
1297         linux_get_osname(td, osname);
1298         sbuf_printf(sb, "%s\n", osname);
1299
1300         return (0);
1301 }
1302
1303 /*
1304  * Filler function for proc/sys/kernel/version
1305  */
1306 static int
1307 linprocfs_doosbuild(PFS_FILL_ARGS)
1308 {
1309
1310         linprocfs_osbuild(td, sb);
1311         sbuf_cat(sb, "\n");
1312         return (0);
1313 }
1314
1315 /*
1316  * Filler function for proc/sys/kernel/msgmni
1317  */
1318 static int
1319 linprocfs_domsgmni(PFS_FILL_ARGS)
1320 {
1321
1322         sbuf_printf(sb, "%d\n", msginfo.msgmni);
1323         return (0);
1324 }
1325
1326 /*
1327  * Filler function for proc/sys/kernel/pid_max
1328  */
1329 static int
1330 linprocfs_dopid_max(PFS_FILL_ARGS)
1331 {
1332
1333         sbuf_printf(sb, "%i\n", PID_MAX);
1334         return (0);
1335 }
1336
1337 /*
1338  * Filler function for proc/sys/kernel/sem
1339  */
1340 static int
1341 linprocfs_dosem(PFS_FILL_ARGS)
1342 {
1343
1344         sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1345             seminfo.semopm, seminfo.semmni);
1346         return (0);
1347 }
1348
1349 /*
1350  * Filler function for proc/sys/vm/min_free_kbytes
1351  *
1352  * This mirrors the approach in illumos to return zero for reads. Effectively,
1353  * it says, no memory is kept in reserve for "atomic allocations". This class
1354  * of allocation can be used at times when a thread cannot be suspended.
1355  */
1356 static int
1357 linprocfs_dominfree(PFS_FILL_ARGS)
1358 {
1359
1360         sbuf_printf(sb, "%d\n", 0);
1361         return (0);
1362 }
1363
1364 /*
1365  * Filler function for proc/scsi/device_info
1366  */
1367 static int
1368 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1369 {
1370
1371         return (0);
1372 }
1373
1374 /*
1375  * Filler function for proc/scsi/scsi
1376  */
1377 static int
1378 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1379 {
1380
1381         return (0);
1382 }
1383
1384 /*
1385  * Filler function for proc/devices
1386  */
1387 static int
1388 linprocfs_dodevices(PFS_FILL_ARGS)
1389 {
1390         char *char_devices;
1391         sbuf_printf(sb, "Character devices:\n");
1392
1393         char_devices = linux_get_char_devices();
1394         sbuf_printf(sb, "%s", char_devices);
1395         linux_free_get_char_devices(char_devices);
1396
1397         sbuf_printf(sb, "\nBlock devices:\n");
1398
1399         return (0);
1400 }
1401
1402 /*
1403  * Filler function for proc/cmdline
1404  */
1405 static int
1406 linprocfs_docmdline(PFS_FILL_ARGS)
1407 {
1408
1409         sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1410         sbuf_printf(sb, " ro root=302\n");
1411         return (0);
1412 }
1413
1414 /*
1415  * Filler function for proc/filesystems
1416  */
1417 static int
1418 linprocfs_dofilesystems(PFS_FILL_ARGS)
1419 {
1420         struct vfsconf *vfsp;
1421
1422         vfsconf_slock();
1423         TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1424                 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1425                         sbuf_printf(sb, "nodev");
1426                 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1427         }
1428         vfsconf_sunlock();
1429         return(0);
1430 }
1431
1432 #if 0
1433 /*
1434  * Filler function for proc/modules
1435  */
1436 static int
1437 linprocfs_domodules(PFS_FILL_ARGS)
1438 {
1439         struct linker_file *lf;
1440
1441         TAILQ_FOREACH(lf, &linker_files, link) {
1442                 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1443                     (unsigned long)lf->size, lf->refs);
1444         }
1445         return (0);
1446 }
1447 #endif
1448
1449 /*
1450  * Filler function for proc/pid/fd
1451  */
1452 static int
1453 linprocfs_dofdescfs(PFS_FILL_ARGS)
1454 {
1455
1456         if (p == curproc)
1457                 sbuf_printf(sb, "/dev/fd");
1458         else
1459                 sbuf_printf(sb, "unknown");
1460         return (0);
1461 }
1462
1463 /*
1464  * Filler function for proc/pid/limits
1465  */
1466 static const struct linux_rlimit_ident {
1467         const char      *desc;
1468         const char      *unit;
1469         unsigned int    rlim_id;
1470 } linux_rlimits_ident[] = {
1471         { "Max cpu time",       "seconds",      RLIMIT_CPU },
1472         { "Max file size",      "bytes",        RLIMIT_FSIZE },
1473         { "Max data size",      "bytes",        RLIMIT_DATA },
1474         { "Max stack size",     "bytes",        RLIMIT_STACK },
1475         { "Max core file size",  "bytes",       RLIMIT_CORE },
1476         { "Max resident set",   "bytes",        RLIMIT_RSS },
1477         { "Max processes",      "processes",    RLIMIT_NPROC },
1478         { "Max open files",     "files",        RLIMIT_NOFILE },
1479         { "Max locked memory",  "bytes",        RLIMIT_MEMLOCK },
1480         { "Max address space",  "bytes",        RLIMIT_AS },
1481         { "Max file locks",     "locks",        LINUX_RLIMIT_LOCKS },
1482         { "Max pending signals", "signals",     LINUX_RLIMIT_SIGPENDING },
1483         { "Max msgqueue size",  "bytes",        LINUX_RLIMIT_MSGQUEUE },
1484         { "Max nice priority",          "",     LINUX_RLIMIT_NICE },
1485         { "Max realtime priority",      "",     LINUX_RLIMIT_RTPRIO },
1486         { "Max realtime timeout",       "us",   LINUX_RLIMIT_RTTIME },
1487         { 0, 0, 0 }
1488 };
1489
1490 static int
1491 linprocfs_doproclimits(PFS_FILL_ARGS)
1492 {
1493         const struct linux_rlimit_ident *li;
1494         struct plimit *limp;
1495         struct rlimit rl;
1496         ssize_t size;
1497         int res, error;
1498
1499         error = 0;
1500
1501         PROC_LOCK(p);
1502         limp = lim_hold(p->p_limit);
1503         PROC_UNLOCK(p);
1504         size = sizeof(res);
1505         sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit",
1506                         "Hard Limit", "Units");
1507         for (li = linux_rlimits_ident; li->desc != NULL; ++li) {
1508                 switch (li->rlim_id)
1509                 {
1510                 case LINUX_RLIMIT_LOCKS:
1511                         /* FALLTHROUGH */
1512                 case LINUX_RLIMIT_RTTIME:
1513                         rl.rlim_cur = RLIM_INFINITY;
1514                         break;
1515                 case LINUX_RLIMIT_SIGPENDING:
1516                         error = kernel_sysctlbyname(td,
1517                             "kern.sigqueue.max_pending_per_proc",
1518                             &res, &size, 0, 0, 0, 0);
1519                         if (error != 0)
1520                                 goto out;
1521                         rl.rlim_cur = res;
1522                         rl.rlim_max = res;
1523                         break;
1524                 case LINUX_RLIMIT_MSGQUEUE:
1525                         error = kernel_sysctlbyname(td,
1526                             "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
1527                         if (error != 0)
1528                                 goto out;
1529                         rl.rlim_cur = res;
1530                         rl.rlim_max = res;
1531                         break;
1532                 case LINUX_RLIMIT_NICE:
1533                         /* FALLTHROUGH */
1534                 case LINUX_RLIMIT_RTPRIO:
1535                         rl.rlim_cur = 0;
1536                         rl.rlim_max = 0;
1537                         break;
1538                 default:
1539                         rl = limp->pl_rlimit[li->rlim_id];
1540                         break;
1541                 }
1542                 if (rl.rlim_cur == RLIM_INFINITY)
1543                         sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
1544                             li->desc, "unlimited", "unlimited", li->unit);
1545                 else
1546                         sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n",
1547                             li->desc, (unsigned long long)rl.rlim_cur,
1548                             (unsigned long long)rl.rlim_max, li->unit);
1549         }
1550 out:
1551         lim_free(limp);
1552         return (error);
1553 }
1554
1555 /*
1556  * Filler function for proc/sys/kernel/random/uuid
1557  */
1558 static int
1559 linprocfs_douuid(PFS_FILL_ARGS)
1560 {
1561         struct uuid uuid;
1562
1563         kern_uuidgen(&uuid, 1);
1564         sbuf_printf_uuid(sb, &uuid);
1565         sbuf_printf(sb, "\n");
1566         return(0);
1567 }
1568
1569 /*
1570  * Filler function for proc/pid/auxv
1571  */
1572 static int
1573 linprocfs_doauxv(PFS_FILL_ARGS)
1574 {
1575         struct sbuf *asb;
1576         off_t buflen, resid;
1577         int error;
1578
1579         /*
1580          * Mimic linux behavior and pass only processes with usermode
1581          * address space as valid. Return zero silently otherwise.
1582          */
1583         if (p->p_vmspace == &vmspace0)
1584                 return (0);
1585
1586         if (uio->uio_resid == 0)
1587                 return (0);
1588         if (uio->uio_offset < 0 || uio->uio_resid < 0)
1589                 return (EINVAL);
1590
1591         asb = sbuf_new_auto();
1592         if (asb == NULL)
1593                 return (ENOMEM);
1594         error = proc_getauxv(td, p, asb);
1595         if (error == 0)
1596                 error = sbuf_finish(asb);
1597
1598         resid = sbuf_len(asb) - uio->uio_offset;
1599         if (resid > uio->uio_resid)
1600                 buflen = uio->uio_resid;
1601         else
1602                 buflen = resid;
1603         if (buflen > IOSIZE_MAX)
1604                 return (EINVAL);
1605         if (buflen > MAXPHYS)
1606                 buflen = MAXPHYS;
1607         if (resid <= 0)
1608                 return (0);
1609
1610         if (error == 0)
1611                 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1612         sbuf_delete(asb);
1613         return (error);
1614 }
1615
1616 /*
1617  * Constructor
1618  */
1619 static int
1620 linprocfs_init(PFS_INIT_ARGS)
1621 {
1622         struct pfs_node *root;
1623         struct pfs_node *dir;
1624         struct pfs_node *sys;
1625
1626         root = pi->pi_root;
1627
1628         /* /proc/... */
1629         pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1630             NULL, NULL, NULL, PFS_RD);
1631         pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1632             NULL, NULL, NULL, PFS_RD);
1633         pfs_create_file(root, "devices", &linprocfs_dodevices,
1634             NULL, NULL, NULL, PFS_RD);
1635         pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1636             NULL, NULL, NULL, PFS_RD);
1637         pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1638             NULL, NULL, NULL, PFS_RD);
1639         pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1640             NULL, NULL, NULL, PFS_RD);
1641 #if 0
1642         pfs_create_file(root, "modules", &linprocfs_domodules,
1643             NULL, NULL, NULL, PFS_RD);
1644 #endif
1645         pfs_create_file(root, "mounts", &linprocfs_domtab,
1646             NULL, NULL, NULL, PFS_RD);
1647         pfs_create_file(root, "mtab", &linprocfs_domtab,
1648             NULL, NULL, NULL, PFS_RD);
1649         pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1650             NULL, NULL, NULL, PFS_RD);
1651         pfs_create_link(root, "self", &procfs_docurproc,
1652             NULL, NULL, NULL, 0);
1653         pfs_create_file(root, "stat", &linprocfs_dostat,
1654             NULL, NULL, NULL, PFS_RD);
1655         pfs_create_file(root, "swaps", &linprocfs_doswaps,
1656             NULL, NULL, NULL, PFS_RD);
1657         pfs_create_file(root, "uptime", &linprocfs_douptime,
1658             NULL, NULL, NULL, PFS_RD);
1659         pfs_create_file(root, "version", &linprocfs_doversion,
1660             NULL, NULL, NULL, PFS_RD);
1661
1662         /* /proc/net/... */
1663         dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1664         pfs_create_file(dir, "dev", &linprocfs_donetdev,
1665             NULL, NULL, NULL, PFS_RD);
1666
1667         /* /proc/<pid>/... */
1668         dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1669         pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1670             NULL, NULL, NULL, PFS_RD);
1671         pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1672             NULL, NULL, NULL, 0);
1673         pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1674             NULL, &procfs_candebug, NULL, PFS_RD);
1675         pfs_create_link(dir, "exe", &procfs_doprocfile,
1676             NULL, &procfs_notsystem, NULL, 0);
1677         pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1678             NULL, NULL, NULL, PFS_RD);
1679         pfs_create_file(dir, "mem", &procfs_doprocmem,
1680             procfs_attr_rw, &procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
1681         pfs_create_file(dir, "mounts", &linprocfs_domtab,
1682             NULL, NULL, NULL, PFS_RD);
1683         pfs_create_link(dir, "root", &linprocfs_doprocroot,
1684             NULL, NULL, NULL, 0);
1685         pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1686             NULL, NULL, NULL, PFS_RD);
1687         pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1688             NULL, NULL, NULL, PFS_RD);
1689         pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1690             NULL, NULL, NULL, PFS_RD);
1691         pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1692             NULL, NULL, NULL, 0);
1693         pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1694             NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1695         pfs_create_file(dir, "limits", &linprocfs_doproclimits,
1696             NULL, NULL, NULL, PFS_RD);
1697
1698         /* /proc/scsi/... */
1699         dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1700         pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1701             NULL, NULL, NULL, PFS_RD);
1702         pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1703             NULL, NULL, NULL, PFS_RD);
1704
1705         /* /proc/sys/... */
1706         sys = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1707         /* /proc/sys/kernel/... */
1708         dir = pfs_create_dir(sys, "kernel", NULL, NULL, NULL, 0);
1709         pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1710             NULL, NULL, NULL, PFS_RD);
1711         pfs_create_file(dir, "ostype", &linprocfs_doostype,
1712             NULL, NULL, NULL, PFS_RD);
1713         pfs_create_file(dir, "version", &linprocfs_doosbuild,
1714             NULL, NULL, NULL, PFS_RD);
1715         pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1716             NULL, NULL, NULL, PFS_RD);
1717         pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1718             NULL, NULL, NULL, PFS_RD);
1719         pfs_create_file(dir, "sem", &linprocfs_dosem,
1720             NULL, NULL, NULL, PFS_RD);
1721
1722         /* /proc/sys/kernel/random/... */
1723         dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1724         pfs_create_file(dir, "uuid", &linprocfs_douuid,
1725             NULL, NULL, NULL, PFS_RD);
1726
1727         /* /proc/sys/vm/.... */
1728         dir = pfs_create_dir(sys, "vm", NULL, NULL, NULL, 0);
1729         pfs_create_file(dir, "min_free_kbytes", &linprocfs_dominfree,
1730             NULL, NULL, NULL, PFS_RD);
1731
1732         return (0);
1733 }
1734
1735 /*
1736  * Destructor
1737  */
1738 static int
1739 linprocfs_uninit(PFS_INIT_ARGS)
1740 {
1741
1742         /* nothing to do, pseudofs will GC */
1743         return (0);
1744 }
1745
1746 PSEUDOFS(linprocfs, 1, VFCF_JAIL);
1747 #if defined(__aarch64__) || defined(__amd64__)
1748 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1749 #else
1750 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1751 #endif
1752 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1753 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1754 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);