The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linprocfs/linprocfs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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/shm.h>
   70 #include <sys/smp.h>
   71 #include <sys/socket.h>
   72 #include <sys/syscallsubr.h>
   73 #include <sys/sysctl.h>
   74 #include <sys/sysent.h>
   75 #include <sys/systm.h>
   76 #include <sys/time.h>
   77 #include <sys/tty.h>
   78 #include <sys/user.h>
   79 #include <sys/uuid.h>
   80 #include <sys/vmmeter.h>
   81 #include <sys/vnode.h>
   82 #include <sys/bus.h>
   83 
   84 #include <net/if.h>
   85 #include <net/if_var.h>
   86 #include <net/if_types.h>
   87 
   88 #include <vm/vm.h>
   89 #include <vm/vm_extern.h>
   90 #include <vm/pmap.h>
   91 #include <vm/vm_map.h>
   92 #include <vm/vm_param.h>
   93 #include <vm/vm_object.h>
   94 #include <vm/swap_pager.h>
   95 
   96 #include <machine/clock.h>
   97 
   98 #include <geom/geom.h>
   99 #include <geom/geom_int.h>
  100 
  101 #if defined(__i386__) || defined(__amd64__)
  102 #include <machine/cputypes.h>
  103 #include <machine/md_var.h>
  104 #endif /* __i386__ || __amd64__ */
  105 
  106 #include <compat/linux/linux.h>
  107 #include <compat/linux/linux_mib.h>
  108 #include <compat/linux/linux_misc.h>
  109 #include <compat/linux/linux_util.h>
  110 #include <fs/pseudofs/pseudofs.h>
  111 #include <fs/procfs/procfs.h>
  112 
  113 /*
  114  * Various conversion macros
  115  */
  116 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz)))        /* ticks to jiffies */
  117 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz)))      /* ticks to centiseconds */
  118 #define T2S(x) ((x) / (stathz ? stathz : hz))           /* ticks to seconds */
  119 #define B2K(x) ((x) >> 10)                              /* bytes to kbytes */
  120 #define B2P(x) ((x) >> PAGE_SHIFT)                      /* bytes to pages */
  121 #define P2B(x) ((x) << PAGE_SHIFT)                      /* pages to bytes */
  122 #define P2K(x) ((x) << (PAGE_SHIFT - 10))               /* pages to kbytes */
  123 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
  124 
  125 /**
  126  * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
  127  *
  128  * The linux procfs state field displays one of the characters RSDZTW to
  129  * denote running, sleeping in an interruptible wait, waiting in an
  130  * uninterruptible disk sleep, a zombie process, process is being traced
  131  * or stopped, or process is paging respectively.
  132  *
  133  * Our struct kinfo_proc contains the variable ki_stat which contains a
  134  * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
  135  *
  136  * This character array is used with ki_stati-1 as an index and tries to
  137  * map our states to suitable linux states.
  138  */
  139 static char linux_state[] = "RRSTZDD";
  140 
  141 /*
  142  * Filler function for proc/meminfo
  143  */
  144 static int
  145 linprocfs_domeminfo(PFS_FILL_ARGS)
  146 {
  147         unsigned long memtotal;         /* total memory in bytes */
  148         unsigned long memfree;          /* free memory in bytes */
  149         unsigned long cached;           /* page cache */
  150         unsigned long buffers;          /* buffer cache */
  151         unsigned long long swaptotal;   /* total swap space in bytes */
  152         unsigned long long swapused;    /* used swap space in bytes */
  153         unsigned long long swapfree;    /* free swap space in bytes */
  154         size_t sz;
  155         int error, i, j;
  156 
  157         memtotal = physmem * PAGE_SIZE;
  158         memfree = (unsigned long)vm_free_count() * PAGE_SIZE;
  159         swap_pager_status(&i, &j);
  160         swaptotal = (unsigned long long)i * PAGE_SIZE;
  161         swapused = (unsigned long long)j * PAGE_SIZE;
  162         swapfree = swaptotal - swapused;
  163 
  164         /*
  165          * This value may exclude wired pages, but we have no good way of
  166          * accounting for that.
  167          */
  168         cached =
  169             (vm_active_count() + vm_inactive_count() + vm_laundry_count()) *
  170             PAGE_SIZE;
  171 
  172         sz = sizeof(buffers);
  173         error = kernel_sysctlbyname(curthread, "vfs.bufspace", &buffers, &sz,
  174             NULL, 0, 0, 0);
  175         if (error != 0)
  176                 buffers = 0;
  177 
  178         sbuf_printf(sb,
  179             "MemTotal: %9lu kB\n"
  180             "MemFree:  %9lu kB\n"
  181             "Buffers:  %9lu kB\n"
  182             "Cached:   %9lu kB\n"
  183             "SwapTotal:%9llu kB\n"
  184             "SwapFree: %9llu kB\n",
  185             B2K(memtotal), B2K(memfree), B2K(buffers),
  186             B2K(cached), B2K(swaptotal), B2K(swapfree));
  187 
  188         return (0);
  189 }
  190 
  191 #if defined(__i386__) || defined(__amd64__)
  192 /*
  193  * Filler function for proc/cpuinfo (i386 & amd64 version)
  194  */
  195 static int
  196 linprocfs_docpuinfo(PFS_FILL_ARGS)
  197 {
  198         int hw_model[2];
  199         char model[128];
  200         uint64_t freq;
  201         size_t size;
  202         u_int cache_size[4];
  203         int fqmhz, fqkhz;
  204         int i, j;
  205 
  206         /*
  207          * We default the flags to include all non-conflicting flags,
  208          * and the Intel versions of conflicting flags.
  209          */
  210         static char *cpu_feature_names[] = {
  211                 /*  0 */ "fpu", "vme", "de", "pse",
  212                 /*  4 */ "tsc", "msr", "pae", "mce",
  213                 /*  8 */ "cx8", "apic", "", "sep",
  214                 /* 12 */ "mtrr", "pge", "mca", "cmov",
  215                 /* 16 */ "pat", "pse36", "pn", "clflush",
  216                 /* 20 */ "", "dts", "acpi", "mmx",
  217                 /* 24 */ "fxsr", "sse", "sse2", "ss",
  218                 /* 28 */ "ht", "tm", "ia64", "pbe"
  219         };
  220 
  221         static char *amd_feature_names[] = {
  222                 /*  0 */ "", "", "", "",
  223                 /*  4 */ "", "", "", "",
  224                 /*  8 */ "", "", "", "syscall",
  225                 /* 12 */ "", "", "", "",
  226                 /* 16 */ "", "", "", "mp",
  227                 /* 20 */ "nx", "", "mmxext", "",
  228                 /* 24 */ "", "fxsr_opt", "pdpe1gb", "rdtscp",
  229                 /* 28 */ "", "lm", "3dnowext", "3dnow"
  230         };
  231 
  232         static char *cpu_feature2_names[] = {
  233                 /*  0 */ "pni", "pclmulqdq", "dtes64", "monitor",
  234                 /*  4 */ "ds_cpl", "vmx", "smx", "est",
  235                 /*  8 */ "tm2", "ssse3", "cid", "sdbg",
  236                 /* 12 */ "fma", "cx16", "xtpr", "pdcm",
  237                 /* 16 */ "", "pcid", "dca", "sse4_1",
  238                 /* 20 */ "sse4_2", "x2apic", "movbe", "popcnt",
  239                 /* 24 */ "tsc_deadline_timer", "aes", "xsave", "",
  240                 /* 28 */ "avx", "f16c", "rdrand", "hypervisor"
  241         };
  242 
  243         static char *amd_feature2_names[] = {
  244                 /*  0 */ "lahf_lm", "cmp_legacy", "svm", "extapic",
  245                 /*  4 */ "cr8_legacy", "abm", "sse4a", "misalignsse",
  246                 /*  8 */ "3dnowprefetch", "osvw", "ibs", "xop",
  247                 /* 12 */ "skinit", "wdt", "", "lwp",
  248                 /* 16 */ "fma4", "tce", "", "nodeid_msr",
  249                 /* 20 */ "", "tbm", "topoext", "perfctr_core",
  250                 /* 24 */ "perfctr_nb", "", "bpext", "ptsc",
  251                 /* 28 */ "perfctr_llc", "mwaitx", "", ""
  252         };
  253 
  254         static char *cpu_stdext_feature_names[] = {
  255                 /*  0 */ "fsgsbase", "tsc_adjust", "", "bmi1",
  256                 /*  4 */ "hle", "avx2", "", "smep",
  257                 /*  8 */ "bmi2", "erms", "invpcid", "rtm",
  258                 /* 12 */ "cqm", "", "mpx", "rdt_a",
  259                 /* 16 */ "avx512f", "avx512dq", "rdseed", "adx",
  260                 /* 20 */ "smap", "avx512ifma", "", "clflushopt",
  261                 /* 24 */ "clwb", "intel_pt", "avx512pf", "avx512er",
  262                 /* 28 */ "avx512cd", "sha_ni", "avx512bw", "avx512vl"
  263         };
  264 
  265         static char *power_flags[] = {
  266                 "ts",           "fid",          "vid",
  267                 "ttp",          "tm",           "stc",
  268                 "100mhzsteps",  "hwpstate",     "",
  269                 "cpb",          "eff_freq_ro",  "proc_feedback",
  270                 "acc_power",
  271         };
  272 
  273         hw_model[0] = CTL_HW;
  274         hw_model[1] = HW_MODEL;
  275         model[0] = '\0';
  276         size = sizeof(model);
  277         if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
  278                 strcpy(model, "unknown");
  279 #ifdef __i386__
  280         switch (cpu_vendor_id) {
  281         case CPU_VENDOR_AMD:
  282                 if (cpu_class < CPUCLASS_686)
  283                         cpu_feature_names[16] = "fcmov";
  284                 break;
  285         case CPU_VENDOR_CYRIX:
  286                 cpu_feature_names[24] = "cxmmx";
  287                 break;
  288         }
  289 #endif
  290         if (cpu_exthigh >= 0x80000006)
  291                 do_cpuid(0x80000006, cache_size);
  292         else
  293                 memset(cache_size, 0, sizeof(cache_size));
  294         for (i = 0; i < mp_ncpus; ++i) {
  295                 fqmhz = 0;
  296                 fqkhz = 0;
  297                 freq = atomic_load_acq_64(&tsc_freq);
  298                 if (freq != 0) {
  299                         fqmhz = (freq + 4999) / 1000000;
  300                         fqkhz = ((freq + 4999) / 10000) % 100;
  301                 }
  302                 sbuf_printf(sb,
  303                     "processor\t: %d\n"
  304                     "vendor_id\t: %.20s\n"
  305                     "cpu family\t: %u\n"
  306                     "model\t\t: %u\n"
  307                     "model name\t: %s\n"
  308                     "stepping\t: %u\n"
  309                     "cpu MHz\t\t: %d.%02d\n"
  310                     "cache size\t: %d KB\n"
  311                     "physical id\t: %d\n"
  312                     "siblings\t: %d\n"
  313                     "core id\t\t: %d\n"
  314                     "cpu cores\t: %d\n"
  315                     "apicid\t\t: %d\n"
  316                     "initial apicid\t: %d\n"
  317                     "fpu\t\t: %s\n"
  318                     "fpu_exception\t: %s\n"
  319                     "cpuid level\t: %d\n"
  320                     "wp\t\t: %s\n",
  321                     i, cpu_vendor, CPUID_TO_FAMILY(cpu_id),
  322                     CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING,
  323                     fqmhz, fqkhz,
  324                     (cache_size[2] >> 16), 0, mp_ncpus, i, mp_ncpus,
  325                     i, i, /*cpu_id & CPUID_LOCAL_APIC_ID ??*/
  326                     (cpu_feature & CPUID_FPU) ? "yes" : "no", "yes",
  327                     CPUID_TO_FAMILY(cpu_id), "yes");
  328                 sbuf_cat(sb, "flags\t\t:");
  329                 for (j = 0; j < nitems(cpu_feature_names); j++)
  330                         if (cpu_feature & (1 << j) &&
  331                             cpu_feature_names[j][0] != '\0')
  332                                 sbuf_printf(sb, " %s", cpu_feature_names[j]);
  333                 for (j = 0; j < nitems(amd_feature_names); j++)
  334                         if (amd_feature & (1 << j) &&
  335                             amd_feature_names[j][0] != '\0')
  336                                 sbuf_printf(sb, " %s", amd_feature_names[j]);
  337                 for (j = 0; j < nitems(cpu_feature2_names); j++)
  338                         if (cpu_feature2 & (1 << j) &&
  339                             cpu_feature2_names[j][0] != '\0')
  340                                 sbuf_printf(sb, " %s", cpu_feature2_names[j]);
  341                 for (j = 0; j < nitems(amd_feature2_names); j++)
  342                         if (amd_feature2 & (1 << j) &&
  343                             amd_feature2_names[j][0] != '\0')
  344                                 sbuf_printf(sb, " %s", amd_feature2_names[j]);
  345                 for (j = 0; j < nitems(cpu_stdext_feature_names); j++)
  346                         if (cpu_stdext_feature & (1 << j) &&
  347                             cpu_stdext_feature_names[j][0] != '\0')
  348                                 sbuf_printf(sb, " %s",
  349                                     cpu_stdext_feature_names[j]);
  350                 sbuf_cat(sb, "\n");
  351                 sbuf_printf(sb,
  352                     "bugs\t\t: %s\n"
  353                     "bogomips\t: %d.%02d\n"
  354                     "clflush size\t: %d\n"
  355                     "cache_alignment\t: %d\n"
  356                     "address sizes\t: %d bits physical, %d bits virtual\n",
  357 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
  358                     (has_f00f_bug) ? "Intel F00F" : "",
  359 #else
  360                     "",
  361 #endif
  362                     fqmhz * 2, fqkhz,
  363                     cpu_clflush_line_size, cpu_clflush_line_size,
  364                     cpu_maxphyaddr,
  365                     (cpu_maxphyaddr > 32) ? 48 : 0);
  366                 sbuf_cat(sb, "power management: ");
  367                 for (j = 0; j < nitems(power_flags); j++)
  368                         if (amd_pminfo & (1 << j))
  369                                 sbuf_printf(sb, " %s", power_flags[j]);
  370                 sbuf_cat(sb, "\n\n");
  371 
  372                 /* XXX per-cpu vendor / class / model / id? */
  373         }
  374         sbuf_cat(sb, "\n");
  375 
  376         return (0);
  377 }
  378 #else
  379 /* ARM64TODO: implement non-stubbed linprocfs_docpuinfo */
  380 static int
  381 linprocfs_docpuinfo(PFS_FILL_ARGS)
  382 {
  383         int i;
  384 
  385         for (i = 0; i < mp_ncpus; ++i) {
  386                 sbuf_printf(sb,
  387                     "processor\t: %d\n"
  388                     "BogoMIPS\t: %d.%02d\n",
  389                     i, 0, 0);
  390                 sbuf_cat(sb, "Features\t: ");
  391                 sbuf_cat(sb, "\n");
  392                 sbuf_printf(sb,
  393                     "CPU implementer\t: \n"
  394                     "CPU architecture: \n"
  395                     "CPU variant\t: 0x%x\n"
  396                     "CPU part\t: 0x%x\n"
  397                     "CPU revision\t: %d\n",
  398                     0, 0, 0);
  399                 sbuf_cat(sb, "\n");
  400         }
  401 
  402         return (0);
  403 }
  404 #endif /* __i386__ || __amd64__ */
  405 
  406 static const char *path_slash_sys = "/sys";
  407 static const char *fstype_sysfs = "sysfs";
  408 
  409 static int
  410 _mtab_helper(const struct pfs_node *pn, const struct statfs *sp,
  411     const char **mntfrom, const char **mntto, const char **fstype)
  412 {
  413         /* determine device name */
  414         *mntfrom = sp->f_mntfromname;
  415 
  416         /* determine mount point */
  417         *mntto = sp->f_mntonname;
  418 
  419         /* determine fs type */
  420         *fstype = sp->f_fstypename;
  421         if (strcmp(*fstype, pn->pn_info->pi_name) == 0)
  422                 *mntfrom = *fstype = "proc";
  423         else if (strcmp(*fstype, "procfs") == 0)
  424                 return (ECANCELED);
  425 
  426         if (strcmp(*fstype, "autofs") == 0) {
  427                 /*
  428                  * FreeBSD uses eg "map -hosts", whereas Linux
  429                  * expects just "-hosts".
  430                  */
  431                 if (strncmp(*mntfrom, "map ", 4) == 0)
  432                         *mntfrom += 4;
  433         }
  434 
  435         if (strcmp(*fstype, "linsysfs") == 0) {
  436                 *mntfrom = path_slash_sys;
  437                 *fstype = fstype_sysfs;
  438         } else {
  439                 /* For Linux msdosfs is called vfat */
  440                 if (strcmp(*fstype, "msdosfs") == 0)
  441                         *fstype = "vfat";
  442         }
  443         return (0);
  444 }
  445 
  446 static void
  447 _sbuf_mntoptions_helper(struct sbuf *sb, uint64_t f_flags)
  448 {
  449         sbuf_cat(sb, (f_flags & MNT_RDONLY) ? "ro" : "rw");
  450 #define ADD_OPTION(opt, name) \
  451         if (f_flags & (opt)) sbuf_cat(sb, "," name);
  452         ADD_OPTION(MNT_SYNCHRONOUS,     "sync");
  453         ADD_OPTION(MNT_NOEXEC,          "noexec");
  454         ADD_OPTION(MNT_NOSUID,          "nosuid");
  455         ADD_OPTION(MNT_UNION,           "union");
  456         ADD_OPTION(MNT_ASYNC,           "async");
  457         ADD_OPTION(MNT_SUIDDIR,         "suiddir");
  458         ADD_OPTION(MNT_NOSYMFOLLOW,     "nosymfollow");
  459         ADD_OPTION(MNT_NOATIME,         "noatime");
  460 #undef ADD_OPTION
  461 }
  462 
  463 /*
  464  * Filler function for proc/mtab and proc/<pid>/mounts.
  465  *
  466  * /proc/mtab doesn't exist in Linux' procfs, but is included here so
  467  * users can symlink /compat/linux/etc/mtab to /proc/mtab
  468  */
  469 static int
  470 linprocfs_domtab(PFS_FILL_ARGS)
  471 {
  472         struct nameidata nd;
  473         const char *lep, *mntto, *mntfrom, *fstype;
  474         char *dlep, *flep;
  475         size_t lep_len;
  476         int error;
  477         struct statfs *buf, *sp;
  478         size_t count;
  479 
  480         /* resolve symlinks etc. in the emulation tree prefix */
  481         /*
  482          * Ideally, this would use the current chroot rather than some
  483          * hardcoded path.
  484          */
  485         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
  486         flep = NULL;
  487         error = namei(&nd);
  488         lep = linux_emul_path;
  489         if (error == 0) {
  490                 if (vn_fullpath(nd.ni_vp, &dlep, &flep) == 0)
  491                         lep = dlep;
  492                 vrele(nd.ni_vp);
  493         }
  494         lep_len = strlen(lep);
  495 
  496         buf = NULL;
  497         error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
  498             UIO_SYSSPACE, MNT_WAIT);
  499         if (error != 0) {
  500                 free(buf, M_TEMP);
  501                 free(flep, M_TEMP);
  502                 return (error);
  503         }
  504 
  505         for (sp = buf; count > 0; sp++, count--) {
  506                 error = _mtab_helper(pn, sp, &mntfrom, &mntto, &fstype);
  507                 if (error != 0) {
  508                         MPASS(error == ECANCELED);
  509                         continue;
  510                 }
  511 
  512                 /* determine mount point */
  513                 if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
  514                         mntto += lep_len;
  515 
  516                 sbuf_printf(sb, "%s %s %s ", mntfrom, mntto, fstype);
  517                 _sbuf_mntoptions_helper(sb, sp->f_flags);
  518                 /* a real Linux mtab will also show NFS options */
  519                 sbuf_printf(sb, " 0 0\n");
  520         }
  521 
  522         free(buf, M_TEMP);
  523         free(flep, M_TEMP);
  524         return (error);
  525 }
  526 
  527 static int
  528 linprocfs_doprocmountinfo(PFS_FILL_ARGS)
  529 {
  530         struct nameidata nd;
  531         const char *mntfrom, *mntto, *fstype;
  532         const char *lep;
  533         char *dlep, *flep;
  534         struct statfs *buf, *sp;
  535         size_t count, lep_len;
  536         int error;
  537 
  538         /*
  539          * Ideally, this would use the current chroot rather than some
  540          * hardcoded path.
  541          */
  542         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
  543         flep = NULL;
  544         error = namei(&nd);
  545         lep = linux_emul_path;
  546         if (error == 0) {
  547                 if (vn_fullpath(nd.ni_vp, &dlep, &flep) == 0)
  548                         lep = dlep;
  549                 vrele(nd.ni_vp);
  550         }
  551         lep_len = strlen(lep);
  552 
  553         buf = NULL;
  554         error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
  555             UIO_SYSSPACE, MNT_WAIT);
  556         if (error != 0)
  557                 goto out;
  558 
  559         for (sp = buf; count > 0; sp++, count--) {
  560                 error = _mtab_helper(pn, sp, &mntfrom, &mntto, &fstype);
  561                 if (error != 0) {
  562                         MPASS(error == ECANCELED);
  563                         continue;
  564                 }
  565 
  566                 if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
  567                         mntto += lep_len;
  568 #if 0
  569                 /*
  570                  * If the prefix is a chroot, and this mountpoint is not under
  571                  * the prefix, we should skip it.  Leave it for now for
  572                  * consistency with procmtab above.
  573                  */
  574                 else
  575                         continue;
  576 #endif
  577 
  578                 /*
  579                  * (1) mount id
  580                  *
  581                  * (2) parent mount id -- we don't have this cheaply, so
  582                  * provide a dummy value
  583                  *
  584                  * (3) major:minor -- ditto
  585                  *
  586                  * (4) root filesystem mount -- probably a namespaces thing
  587                  *
  588                  * (5) mountto path
  589                  */
  590                 sbuf_printf(sb, "%u 0 0:0 / %s ",
  591                     sp->f_fsid.val[0] ^ sp->f_fsid.val[1], mntto);
  592                 /* (6) mount options */
  593                 _sbuf_mntoptions_helper(sb, sp->f_flags);
  594                 /*
  595                  * (7) zero or more optional fields -- again, namespace related
  596                  *
  597                  * (8) End of variable length fields separator ("-")
  598                  *
  599                  * (9) fstype
  600                  *
  601                  * (10) mount from
  602                  *
  603                  * (11) "superblock" options -- like (6), but different
  604                  * semantics in Linux
  605                  */
  606                 sbuf_printf(sb, " - %s %s %s\n", fstype, mntfrom,
  607                     (sp->f_flags & MNT_RDONLY) ? "ro" : "rw");
  608         }
  609 
  610         error = 0;
  611 out:
  612         free(buf, M_TEMP);
  613         free(flep, M_TEMP);
  614         return (error);
  615 }
  616 
  617 /*
  618  * Filler function for proc/partitions
  619  */
  620 static int
  621 linprocfs_dopartitions(PFS_FILL_ARGS)
  622 {
  623         struct g_class *cp;
  624         struct g_geom *gp;
  625         struct g_provider *pp;
  626         int major, minor;
  627 
  628         g_topology_lock();
  629         sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
  630             "ruse wio wmerge wsect wuse running use aveq\n");
  631 
  632         LIST_FOREACH(cp, &g_classes, class) {
  633                 if (strcmp(cp->name, "DISK") == 0 ||
  634                     strcmp(cp->name, "PART") == 0)
  635                         LIST_FOREACH(gp, &cp->geom, geom) {
  636                                 LIST_FOREACH(pp, &gp->provider, provider) {
  637                                         if (linux_driver_get_major_minor(
  638                                             pp->name, &major, &minor) != 0) {
  639                                                 major = 0;
  640                                                 minor = 0;
  641                                         }
  642                                         sbuf_printf(sb, "%d %d %lld %s "
  643                                             "%d %d %d %d %d "
  644                                              "%d %d %d %d %d %d\n",
  645                                              major, minor,
  646                                              (long long)pp->mediasize, pp->name,
  647                                              0, 0, 0, 0, 0,
  648                                              0, 0, 0, 0, 0, 0);
  649                                 }
  650                         }
  651         }
  652         g_topology_unlock();
  653 
  654         return (0);
  655 }
  656 
  657 /*
  658  * Filler function for proc/stat
  659  *
  660  * Output depends on kernel version:
  661  *
  662  * v2.5.40 <=
  663  *   user nice system idle
  664  * v2.5.41
  665  *   user nice system idle iowait
  666  * v2.6.11
  667  *   user nice system idle iowait irq softirq steal
  668  * v2.6.24
  669  *   user nice system idle iowait irq softirq steal guest
  670  * v2.6.33 >=
  671  *   user nice system idle iowait irq softirq steal guest guest_nice
  672  */
  673 static int
  674 linprocfs_dostat(PFS_FILL_ARGS)
  675 {
  676         struct pcpu *pcpu;
  677         long cp_time[CPUSTATES];
  678         long *cp;
  679         struct timeval boottime;
  680         int i;
  681         char *zero_pad;
  682         bool has_intr = true;
  683 
  684         if (linux_kernver(td) >= LINUX_KERNVER(2,6,33)) {
  685                 zero_pad = " 0 0 0 0\n";
  686         } else if (linux_kernver(td) >= LINUX_KERNVER(2,6,24)) {
  687                 zero_pad = " 0 0 0\n";
  688         } else if (linux_kernver(td) >= LINUX_KERNVER(2,6,11)) {
  689                 zero_pad = " 0 0\n";
  690         } else if (linux_kernver(td) >= LINUX_KERNVER(2,5,41)) {
  691                 has_intr = false;
  692                 zero_pad = " 0\n";
  693         } else {
  694                 has_intr = false;
  695                 zero_pad = "\n";
  696         }
  697 
  698         read_cpu_time(cp_time);
  699         getboottime(&boottime);
  700         /* Parameters common to all versions */
  701         sbuf_printf(sb, "cpu %lu %lu %lu %lu",
  702             T2J(cp_time[CP_USER]),
  703             T2J(cp_time[CP_NICE]),
  704             T2J(cp_time[CP_SYS]),
  705             T2J(cp_time[CP_IDLE]));
  706 
  707         /* Print interrupt stats if available */
  708         if (has_intr) {
  709                 sbuf_printf(sb, " 0 %lu", T2J(cp_time[CP_INTR]));
  710         }
  711 
  712         /* Pad out remaining fields depending on version */
  713         sbuf_printf(sb, "%s", zero_pad);
  714 
  715         CPU_FOREACH(i) {
  716                 pcpu = pcpu_find(i);
  717                 cp = pcpu->pc_cp_time;
  718                 sbuf_printf(sb, "cpu%d %lu %lu %lu %lu", i,
  719                     T2J(cp[CP_USER]),
  720                     T2J(cp[CP_NICE]),
  721                     T2J(cp[CP_SYS]),
  722                     T2J(cp[CP_IDLE]));
  723 
  724                 if (has_intr) {
  725                         sbuf_printf(sb, " 0 %lu", T2J(cp[CP_INTR]));
  726                 }
  727 
  728                 sbuf_printf(sb, "%s", zero_pad);
  729         }
  730         sbuf_printf(sb,
  731             "disk 0 0 0 0\n"
  732             "page %ju %ju\n"
  733             "swap %ju %ju\n"
  734             "intr %ju\n"
  735             "ctxt %ju\n"
  736             "btime %lld\n",
  737             (uintmax_t)VM_CNT_FETCH(v_vnodepgsin),
  738             (uintmax_t)VM_CNT_FETCH(v_vnodepgsout),
  739             (uintmax_t)VM_CNT_FETCH(v_swappgsin),
  740             (uintmax_t)VM_CNT_FETCH(v_swappgsout),
  741             (uintmax_t)VM_CNT_FETCH(v_intr),
  742             (uintmax_t)VM_CNT_FETCH(v_swtch),
  743             (long long)boottime.tv_sec);
  744         return (0);
  745 }
  746 
  747 static int
  748 linprocfs_doswaps(PFS_FILL_ARGS)
  749 {
  750         struct xswdev xsw;
  751         uintmax_t total, used;
  752         int n;
  753         char devname[SPECNAMELEN + 1];
  754 
  755         sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
  756         for (n = 0; ; n++) {
  757                 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
  758                         break;
  759                 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
  760                 used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
  761 
  762                 /*
  763                  * The space and not tab after the device name is on
  764                  * purpose.  Linux does so.
  765                  */
  766                 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
  767                     devname, total, used);
  768         }
  769         return (0);
  770 }
  771 
  772 /*
  773  * Filler function for proc/uptime
  774  */
  775 static int
  776 linprocfs_douptime(PFS_FILL_ARGS)
  777 {
  778         long cp_time[CPUSTATES];
  779         struct timeval tv;
  780 
  781         getmicrouptime(&tv);
  782         read_cpu_time(cp_time);
  783         sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
  784             (long long)tv.tv_sec, tv.tv_usec / 10000,
  785             T2S(cp_time[CP_IDLE] / mp_ncpus),
  786             T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
  787         return (0);
  788 }
  789 
  790 /*
  791  * Get OS build date
  792  */
  793 static void
  794 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
  795 {
  796 #if 0
  797         char osbuild[256];
  798         char *cp1, *cp2;
  799 
  800         strncpy(osbuild, version, 256);
  801         osbuild[255] = '\0';
  802         cp1 = strstr(osbuild, "\n");
  803         cp2 = strstr(osbuild, ":");
  804         if (cp1 && cp2) {
  805                 *cp1 = *cp2 = '\0';
  806                 cp1 = strstr(osbuild, "#");
  807         } else
  808                 cp1 = NULL;
  809         if (cp1)
  810                 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
  811         else
  812 #endif
  813                 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
  814 }
  815 
  816 /*
  817  * Get OS builder
  818  */
  819 static void
  820 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
  821 {
  822 #if 0
  823         char builder[256];
  824         char *cp;
  825 
  826         cp = strstr(version, "\n    ");
  827         if (cp) {
  828                 strncpy(builder, cp + 5, 256);
  829                 builder[255] = '\0';
  830                 cp = strstr(builder, ":");
  831                 if (cp)
  832                         *cp = '\0';
  833         }
  834         if (cp)
  835                 sbuf_cat(sb, builder);
  836         else
  837 #endif
  838                 sbuf_cat(sb, "des@freebsd.org");
  839 }
  840 
  841 /*
  842  * Filler function for proc/version
  843  */
  844 static int
  845 linprocfs_doversion(PFS_FILL_ARGS)
  846 {
  847         char osname[LINUX_MAX_UTSNAME];
  848         char osrelease[LINUX_MAX_UTSNAME];
  849 
  850         linux_get_osname(td, osname);
  851         linux_get_osrelease(td, osrelease);
  852         sbuf_printf(sb, "%s version %s (", osname, osrelease);
  853         linprocfs_osbuilder(td, sb);
  854         sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
  855         linprocfs_osbuild(td, sb);
  856         sbuf_cat(sb, "\n");
  857 
  858         return (0);
  859 }
  860 
  861 /*
  862  * Filler function for proc/loadavg
  863  */
  864 static int
  865 linprocfs_doloadavg(PFS_FILL_ARGS)
  866 {
  867 
  868         sbuf_printf(sb,
  869             "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
  870             (int)(averunnable.ldavg[0] / averunnable.fscale),
  871             (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
  872             (int)(averunnable.ldavg[1] / averunnable.fscale),
  873             (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
  874             (int)(averunnable.ldavg[2] / averunnable.fscale),
  875             (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
  876             1,                          /* number of running tasks */
  877             nprocs,                     /* number of tasks */
  878             lastpid                     /* the last pid */
  879         );
  880         return (0);
  881 }
  882 
  883 static int
  884 linprocfs_get_tty_nr(struct proc *p)
  885 {
  886         struct session *sp;
  887         const char *ttyname;
  888         int error, major, minor, nr;
  889 
  890         PROC_LOCK_ASSERT(p, MA_OWNED);
  891         sx_assert(&proctree_lock, SX_LOCKED);
  892 
  893         if ((p->p_flag & P_CONTROLT) == 0)
  894                 return (-1);
  895 
  896         sp = p->p_pgrp->pg_session;
  897         if (sp == NULL)
  898                 return (-1);
  899 
  900         ttyname = devtoname(sp->s_ttyp->t_dev);
  901         error = linux_driver_get_major_minor(ttyname, &major, &minor);
  902         if (error != 0)
  903                 return (-1);
  904 
  905         nr = makedev(major, minor);
  906         return (nr);
  907 }
  908 
  909 /*
  910  * Filler function for proc/pid/stat
  911  */
  912 static int
  913 linprocfs_doprocstat(PFS_FILL_ARGS)
  914 {
  915         struct kinfo_proc kp;
  916         struct timeval boottime;
  917         char state;
  918         static int ratelimit = 0;
  919         int tty_nr;
  920         vm_offset_t startcode, startdata;
  921 
  922         getboottime(&boottime);
  923         sx_slock(&proctree_lock);
  924         PROC_LOCK(p);
  925         fill_kinfo_proc(p, &kp);
  926         tty_nr = linprocfs_get_tty_nr(p);
  927         sx_sunlock(&proctree_lock);
  928         if (p->p_vmspace) {
  929            startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
  930            startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
  931         } else {
  932            startcode = 0;
  933            startdata = 0;
  934         }
  935         sbuf_printf(sb, "%d", p->p_pid);
  936 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
  937         PS_ADD("comm",          "(%s)", p->p_comm);
  938         if (kp.ki_stat > sizeof(linux_state)) {
  939                 state = 'R';
  940 
  941                 if (ratelimit == 0) {
  942                         printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
  943                             kp.ki_stat, sizeof(linux_state));
  944                         ++ratelimit;
  945                 }
  946         } else
  947                 state = linux_state[kp.ki_stat - 1];
  948         PS_ADD("state",         "%c",   state);
  949         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
  950         PS_ADD("pgrp",          "%d",   p->p_pgid);
  951         PS_ADD("session",       "%d",   p->p_session->s_sid);
  952         PROC_UNLOCK(p);
  953         PS_ADD("tty",           "%d",   tty_nr);
  954         PS_ADD("tpgid",         "%d",   kp.ki_tpgid);
  955         PS_ADD("flags",         "%u",   0); /* XXX */
  956         PS_ADD("minflt",        "%lu",  kp.ki_rusage.ru_minflt);
  957         PS_ADD("cminflt",       "%lu",  kp.ki_rusage_ch.ru_minflt);
  958         PS_ADD("majflt",        "%lu",  kp.ki_rusage.ru_majflt);
  959         PS_ADD("cmajflt",       "%lu",  kp.ki_rusage_ch.ru_majflt);
  960         PS_ADD("utime",         "%ld",  TV2J(&kp.ki_rusage.ru_utime));
  961         PS_ADD("stime",         "%ld",  TV2J(&kp.ki_rusage.ru_stime));
  962         PS_ADD("cutime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_utime));
  963         PS_ADD("cstime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_stime));
  964         PS_ADD("priority",      "%d",   kp.ki_pri.pri_user);
  965         PS_ADD("nice",          "%d",   kp.ki_nice); /* 19 (nicest) to -19 */
  966         PS_ADD("",             "%d",   0); /* removed field */
  967         PS_ADD("itrealvalue",   "%d",   0); /* XXX */
  968         PS_ADD("starttime",     "%lu",  TV2J(&kp.ki_start) - TV2J(&boottime));
  969         PS_ADD("vsize",         "%ju",  P2K((uintmax_t)kp.ki_size));
  970         PS_ADD("rss",           "%ju",  (uintmax_t)kp.ki_rssize);
  971         PS_ADD("rlim",          "%lu",  kp.ki_rusage.ru_maxrss);
  972         PS_ADD("startcode",     "%ju",  (uintmax_t)startcode);
  973         PS_ADD("endcode",       "%ju",  (uintmax_t)startdata);
  974         PS_ADD("startstack",    "%u",   0); /* XXX */
  975         PS_ADD("kstkesp",       "%u",   0); /* XXX */
  976         PS_ADD("kstkeip",       "%u",   0); /* XXX */
  977         PS_ADD("signal",        "%u",   0); /* XXX */
  978         PS_ADD("blocked",       "%u",   0); /* XXX */
  979         PS_ADD("sigignore",     "%u",   0); /* XXX */
  980         PS_ADD("sigcatch",      "%u",   0); /* XXX */
  981         PS_ADD("wchan",         "%u",   0); /* XXX */
  982         PS_ADD("nswap",         "%lu",  kp.ki_rusage.ru_nswap);
  983         PS_ADD("cnswap",        "%lu",  kp.ki_rusage_ch.ru_nswap);
  984         PS_ADD("exitsignal",    "%d",   0); /* XXX */
  985         PS_ADD("processor",     "%u",   kp.ki_lastcpu);
  986         PS_ADD("rt_priority",   "%u",   0); /* XXX */ /* >= 2.5.19 */
  987         PS_ADD("policy",        "%u",   kp.ki_pri.pri_class); /* >= 2.5.19 */
  988 #undef PS_ADD
  989         sbuf_putc(sb, '\n');
  990 
  991         return (0);
  992 }
  993 
  994 /*
  995  * Filler function for proc/pid/statm
  996  */
  997 static int
  998 linprocfs_doprocstatm(PFS_FILL_ARGS)
  999 {
 1000         struct kinfo_proc kp;
 1001         segsz_t lsize;
 1002 
 1003         sx_slock(&proctree_lock);
 1004         PROC_LOCK(p);
 1005         fill_kinfo_proc(p, &kp);
 1006         PROC_UNLOCK(p);
 1007         sx_sunlock(&proctree_lock);
 1008 
 1009         /*
 1010          * See comments in linprocfs_doprocstatus() regarding the
 1011          * computation of lsize.
 1012          */
 1013         /* size resident share trs drs lrs dt */
 1014         sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
 1015         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
 1016         sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
 1017         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
 1018         sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
 1019         lsize = B2P(kp.ki_size) - kp.ki_dsize -
 1020             kp.ki_ssize - kp.ki_tsize - 1;
 1021         sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
 1022         sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
 1023 
 1024         return (0);
 1025 }
 1026 
 1027 /*
 1028  * Filler function for proc/pid/status
 1029  */
 1030 static int
 1031 linprocfs_doprocstatus(PFS_FILL_ARGS)
 1032 {
 1033         struct kinfo_proc kp;
 1034         char *state;
 1035         segsz_t lsize;
 1036         struct thread *td2;
 1037         struct sigacts *ps;
 1038         l_sigset_t siglist, sigignore, sigcatch;
 1039         int i;
 1040 
 1041         sx_slock(&proctree_lock);
 1042         PROC_LOCK(p);
 1043         td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
 1044 
 1045         if (P_SHOULDSTOP(p)) {
 1046                 state = "T (stopped)";
 1047         } else {
 1048                 switch(p->p_state) {
 1049                 case PRS_NEW:
 1050                         state = "I (idle)";
 1051                         break;
 1052                 case PRS_NORMAL:
 1053                         if (p->p_flag & P_WEXIT) {
 1054                                 state = "X (exiting)";
 1055                                 break;
 1056                         }
 1057                         switch(td2->td_state) {
 1058                         case TDS_INHIBITED:
 1059                                 state = "S (sleeping)";
 1060                                 break;
 1061                         case TDS_RUNQ:
 1062                         case TDS_RUNNING:
 1063                                 state = "R (running)";
 1064                                 break;
 1065                         default:
 1066                                 state = "? (unknown)";
 1067                                 break;
 1068                         }
 1069                         break;
 1070                 case PRS_ZOMBIE:
 1071                         state = "Z (zombie)";
 1072                         break;
 1073                 default:
 1074                         state = "? (unknown)";
 1075                         break;
 1076                 }
 1077         }
 1078 
 1079         fill_kinfo_proc(p, &kp);
 1080         sx_sunlock(&proctree_lock);
 1081 
 1082         sbuf_printf(sb, "Name:\t%s\n",          p->p_comm); /* XXX escape */
 1083         sbuf_printf(sb, "State:\t%s\n",         state);
 1084 
 1085         /*
 1086          * Credentials
 1087          */
 1088         sbuf_printf(sb, "Tgid:\t%d\n",          p->p_pid);
 1089         sbuf_printf(sb, "Pid:\t%d\n",           p->p_pid);
 1090         sbuf_printf(sb, "PPid:\t%d\n",          kp.ki_ppid );
 1091         sbuf_printf(sb, "TracerPid:\t%d\n",     kp.ki_tracer );
 1092         sbuf_printf(sb, "Uid:\t%d %d %d %d\n",  p->p_ucred->cr_ruid,
 1093                                                 p->p_ucred->cr_uid,
 1094                                                 p->p_ucred->cr_svuid,
 1095                                                 /* FreeBSD doesn't have fsuid */
 1096                                                 p->p_ucred->cr_uid);
 1097         sbuf_printf(sb, "Gid:\t%d %d %d %d\n",  p->p_ucred->cr_rgid,
 1098                                                 p->p_ucred->cr_gid,
 1099                                                 p->p_ucred->cr_svgid,
 1100                                                 /* FreeBSD doesn't have fsgid */
 1101                                                 p->p_ucred->cr_gid);
 1102         sbuf_cat(sb, "Groups:\t");
 1103         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
 1104                 sbuf_printf(sb, "%d ",          p->p_ucred->cr_groups[i]);
 1105         PROC_UNLOCK(p);
 1106         sbuf_putc(sb, '\n');
 1107 
 1108         /*
 1109          * Memory
 1110          *
 1111          * While our approximation of VmLib may not be accurate (I
 1112          * don't know of a simple way to verify it, and I'm not sure
 1113          * it has much meaning anyway), I believe it's good enough.
 1114          *
 1115          * The same code that could (I think) accurately compute VmLib
 1116          * could also compute VmLck, but I don't really care enough to
 1117          * implement it. Submissions are welcome.
 1118          */
 1119         sbuf_printf(sb, "VmSize:\t%8ju kB\n",   B2K((uintmax_t)kp.ki_size));
 1120         sbuf_printf(sb, "VmLck:\t%8u kB\n",     P2K(0)); /* XXX */
 1121         sbuf_printf(sb, "VmRSS:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_rssize));
 1122         sbuf_printf(sb, "VmData:\t%8ju kB\n",   P2K((uintmax_t)kp.ki_dsize));
 1123         sbuf_printf(sb, "VmStk:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_ssize));
 1124         sbuf_printf(sb, "VmExe:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_tsize));
 1125         lsize = B2P(kp.ki_size) - kp.ki_dsize -
 1126             kp.ki_ssize - kp.ki_tsize - 1;
 1127         sbuf_printf(sb, "VmLib:\t%8ju kB\n",    P2K((uintmax_t)lsize));
 1128 
 1129         /*
 1130          * Signal masks
 1131          */
 1132         PROC_LOCK(p);
 1133         bsd_to_linux_sigset(&p->p_siglist, &siglist);
 1134         ps = p->p_sigacts;
 1135         mtx_lock(&ps->ps_mtx);
 1136         bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
 1137         bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
 1138         mtx_unlock(&ps->ps_mtx);
 1139         PROC_UNLOCK(p);
 1140 
 1141         sbuf_printf(sb, "SigPnd:\t%016jx\n",    siglist.__mask);
 1142         /*
 1143          * XXX. SigBlk - target thread's signal mask, td_sigmask.
 1144          * To implement SigBlk pseudofs should support proc/tid dir entries.
 1145          */
 1146         sbuf_printf(sb, "SigBlk:\t%016x\n",     0);
 1147         sbuf_printf(sb, "SigIgn:\t%016jx\n",    sigignore.__mask);
 1148         sbuf_printf(sb, "SigCgt:\t%016jx\n",    sigcatch.__mask);
 1149 
 1150         /*
 1151          * Linux also prints the capability masks, but we don't have
 1152          * capabilities yet, and when we do get them they're likely to
 1153          * be meaningless to Linux programs, so we lie. XXX
 1154          */
 1155         sbuf_printf(sb, "CapInh:\t%016x\n",     0);
 1156         sbuf_printf(sb, "CapPrm:\t%016x\n",     0);
 1157         sbuf_printf(sb, "CapEff:\t%016x\n",     0);
 1158 
 1159         return (0);
 1160 }
 1161 
 1162 /*
 1163  * Filler function for proc/pid/cwd
 1164  */
 1165 static int
 1166 linprocfs_doproccwd(PFS_FILL_ARGS)
 1167 {
 1168         struct pwd *pwd;
 1169         char *fullpath = "unknown";
 1170         char *freepath = NULL;
 1171 
 1172         pwd = pwd_hold(td);
 1173         vn_fullpath(pwd->pwd_cdir, &fullpath, &freepath);
 1174         sbuf_printf(sb, "%s", fullpath);
 1175         if (freepath)
 1176                 free(freepath, M_TEMP);
 1177         pwd_drop(pwd);
 1178         return (0);
 1179 }
 1180 
 1181 /*
 1182  * Filler function for proc/pid/root
 1183  */
 1184 static int
 1185 linprocfs_doprocroot(PFS_FILL_ARGS)
 1186 {
 1187         struct pwd *pwd;
 1188         struct vnode *vp;
 1189         char *fullpath = "unknown";
 1190         char *freepath = NULL;
 1191 
 1192         pwd = pwd_hold(td);
 1193         vp = jailed(p->p_ucred) ? pwd->pwd_jdir : pwd->pwd_rdir;
 1194         vn_fullpath(vp, &fullpath, &freepath);
 1195         sbuf_printf(sb, "%s", fullpath);
 1196         if (freepath)
 1197                 free(freepath, M_TEMP);
 1198         pwd_drop(pwd);
 1199         return (0);
 1200 }
 1201 
 1202 /*
 1203  * Filler function for proc/pid/cmdline
 1204  */
 1205 static int
 1206 linprocfs_doproccmdline(PFS_FILL_ARGS)
 1207 {
 1208         int ret;
 1209 
 1210         PROC_LOCK(p);
 1211         if ((ret = p_cansee(td, p)) != 0) {
 1212                 PROC_UNLOCK(p);
 1213                 return (ret);
 1214         }
 1215 
 1216         /*
 1217          * Mimic linux behavior and pass only processes with usermode
 1218          * address space as valid.  Return zero silently otherwize.
 1219          */
 1220         if (p->p_vmspace == &vmspace0) {
 1221                 PROC_UNLOCK(p);
 1222                 return (0);
 1223         }
 1224         if (p->p_args != NULL) {
 1225                 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
 1226                 PROC_UNLOCK(p);
 1227                 return (0);
 1228         }
 1229 
 1230         if ((p->p_flag & P_SYSTEM) != 0) {
 1231                 PROC_UNLOCK(p);
 1232                 return (0);
 1233         }
 1234 
 1235         PROC_UNLOCK(p);
 1236 
 1237         ret = proc_getargv(td, p, sb);
 1238         return (ret);
 1239 }
 1240 
 1241 /*
 1242  * Filler function for proc/pid/environ
 1243  */
 1244 static int
 1245 linprocfs_doprocenviron(PFS_FILL_ARGS)
 1246 {
 1247 
 1248         /*
 1249          * Mimic linux behavior and pass only processes with usermode
 1250          * address space as valid.  Return zero silently otherwize.
 1251          */
 1252         if (p->p_vmspace == &vmspace0)
 1253                 return (0);
 1254 
 1255         return (proc_getenvv(td, p, sb));
 1256 }
 1257 
 1258 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
 1259 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
 1260 static char vdso_str[] = "      [vdso]";
 1261 static char stack_str[] = "      [stack]";
 1262 
 1263 /*
 1264  * Filler function for proc/pid/maps
 1265  */
 1266 static int
 1267 linprocfs_doprocmaps(PFS_FILL_ARGS)
 1268 {
 1269         struct vmspace *vm;
 1270         vm_map_t map;
 1271         vm_map_entry_t entry, tmp_entry;
 1272         vm_object_t obj, tobj, lobj;
 1273         vm_offset_t e_start, e_end;
 1274         vm_ooffset_t off;
 1275         vm_prot_t e_prot;
 1276         unsigned int last_timestamp;
 1277         char *name = "", *freename = NULL;
 1278         const char *l_map_str;
 1279         ino_t ino;
 1280         int ref_count, shadow_count, flags;
 1281         int error;
 1282         struct vnode *vp;
 1283         struct vattr vat;
 1284         bool private;
 1285 
 1286         PROC_LOCK(p);
 1287         error = p_candebug(td, p);
 1288         PROC_UNLOCK(p);
 1289         if (error)
 1290                 return (error);
 1291 
 1292         if (uio->uio_rw != UIO_READ)
 1293                 return (EOPNOTSUPP);
 1294 
 1295         error = 0;
 1296         vm = vmspace_acquire_ref(p);
 1297         if (vm == NULL)
 1298                 return (ESRCH);
 1299 
 1300         if (SV_CURPROC_FLAG(SV_LP64))
 1301                 l_map_str = l64_map_str;
 1302         else
 1303                 l_map_str = l32_map_str;
 1304         map = &vm->vm_map;
 1305         vm_map_lock_read(map);
 1306         VM_MAP_ENTRY_FOREACH(entry, map) {
 1307                 name = "";
 1308                 freename = NULL;
 1309                 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
 1310                         continue;
 1311                 e_prot = entry->protection;
 1312                 e_start = entry->start;
 1313                 e_end = entry->end;
 1314                 obj = entry->object.vm_object;
 1315                 off = entry->offset;
 1316                 for (lobj = tobj = obj; tobj != NULL;
 1317                     lobj = tobj, tobj = tobj->backing_object) {
 1318                         VM_OBJECT_RLOCK(tobj);
 1319                         off += lobj->backing_object_offset;
 1320                         if (lobj != obj)
 1321                                 VM_OBJECT_RUNLOCK(lobj);
 1322                 }
 1323                 private = (entry->eflags & MAP_ENTRY_COW) != 0 || obj == NULL ||
 1324                     (obj->flags & OBJ_ANON) != 0;
 1325                 last_timestamp = map->timestamp;
 1326                 vm_map_unlock_read(map);
 1327                 ino = 0;
 1328                 if (lobj) {
 1329                         vp = vm_object_vnode(lobj);
 1330                         if (vp != NULL)
 1331                                 vref(vp);
 1332                         if (lobj != obj)
 1333                                 VM_OBJECT_RUNLOCK(lobj);
 1334                         flags = obj->flags;
 1335                         ref_count = obj->ref_count;
 1336                         shadow_count = obj->shadow_count;
 1337                         VM_OBJECT_RUNLOCK(obj);
 1338                         if (vp != NULL) {
 1339                                 vn_fullpath(vp, &name, &freename);
 1340                                 vn_lock(vp, LK_SHARED | LK_RETRY);
 1341                                 VOP_GETATTR(vp, &vat, td->td_ucred);
 1342                                 ino = vat.va_fileid;
 1343                                 vput(vp);
 1344                         } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
 1345                                 if (e_start == p->p_sysent->sv_shared_page_base)
 1346                                         name = vdso_str;
 1347                                 if (e_end == p->p_sysent->sv_usrstack)
 1348                                         name = stack_str;
 1349                         }
 1350                 } else {
 1351                         flags = 0;
 1352                         ref_count = 0;
 1353                         shadow_count = 0;
 1354                 }
 1355 
 1356                 /*
 1357                  * format:
 1358                  *  start, end, access, offset, major, minor, inode, name.
 1359                  */
 1360                 error = sbuf_printf(sb, l_map_str,
 1361                     (u_long)e_start, (u_long)e_end,
 1362                     (e_prot & VM_PROT_READ)?"r":"-",
 1363                     (e_prot & VM_PROT_WRITE)?"w":"-",
 1364                     (e_prot & VM_PROT_EXECUTE)?"x":"-",
 1365                     private ? "p" : "s",
 1366                     (u_long)off,
 1367                     0,
 1368                     0,
 1369                     (u_long)ino,
 1370                     *name ? "     " : " ",
 1371                     name
 1372                     );
 1373                 if (freename)
 1374                         free(freename, M_TEMP);
 1375                 vm_map_lock_read(map);
 1376                 if (error == -1) {
 1377                         error = 0;
 1378                         break;
 1379                 }
 1380                 if (last_timestamp != map->timestamp) {
 1381                         /*
 1382                          * Look again for the entry because the map was
 1383                          * modified while it was unlocked.  Specifically,
 1384                          * the entry may have been clipped, merged, or deleted.
 1385                          */
 1386                         vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
 1387                         entry = tmp_entry;
 1388                 }
 1389         }
 1390         vm_map_unlock_read(map);
 1391         vmspace_free(vm);
 1392 
 1393         return (error);
 1394 }
 1395 
 1396 /*
 1397  * Filler function for proc/pid/mem
 1398  */
 1399 static int
 1400 linprocfs_doprocmem(PFS_FILL_ARGS)
 1401 {
 1402         ssize_t resid;
 1403         int error;
 1404 
 1405         resid = uio->uio_resid;
 1406         error = procfs_doprocmem(PFS_FILL_ARGNAMES);
 1407 
 1408         if (uio->uio_rw == UIO_READ && resid != uio->uio_resid)
 1409                 return (0);
 1410 
 1411         if (error == EFAULT)
 1412                 error = EIO;
 1413 
 1414         return (error);
 1415 }
 1416 
 1417 /*
 1418  * Criteria for interface name translation
 1419  */
 1420 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
 1421 
 1422 static int
 1423 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
 1424 {
 1425         struct ifnet *ifscan;
 1426         int ethno;
 1427 
 1428         IFNET_RLOCK_ASSERT();
 1429 
 1430         /* Short-circuit non ethernet interfaces */
 1431         if (!IFP_IS_ETH(ifp))
 1432                 return (strlcpy(buffer, ifp->if_xname, buflen));
 1433 
 1434         /* Determine the (relative) unit number for ethernet interfaces */
 1435         ethno = 0;
 1436         CK_STAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
 1437                 if (ifscan == ifp)
 1438                         return (snprintf(buffer, buflen, "eth%d", ethno));
 1439                 if (IFP_IS_ETH(ifscan))
 1440                         ethno++;
 1441         }
 1442 
 1443         return (0);
 1444 }
 1445 
 1446 /*
 1447  * Filler function for proc/net/dev
 1448  */
 1449 static int
 1450 linprocfs_donetdev(PFS_FILL_ARGS)
 1451 {
 1452         char ifname[16]; /* XXX LINUX_IFNAMSIZ */
 1453         struct ifnet *ifp;
 1454 
 1455         sbuf_printf(sb, "%6s|%58s|%s\n"
 1456             "%6s|%58s|%58s\n",
 1457             "Inter-", "   Receive", "  Transmit",
 1458             " face",
 1459             "bytes    packets errs drop fifo frame compressed multicast",
 1460             "bytes    packets errs drop fifo colls carrier compressed");
 1461 
 1462         CURVNET_SET(TD_TO_VNET(curthread));
 1463         IFNET_RLOCK();
 1464         CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
 1465                 linux_ifname(ifp, ifname, sizeof ifname);
 1466                 sbuf_printf(sb, "%6.6s: ", ifname);
 1467                 sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
 1468                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
 1469                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
 1470                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
 1471                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
 1472                                                         /* rx_missed_errors */
 1473                     0UL,                                /* rx_fifo_errors */
 1474                     0UL,                                /* rx_length_errors +
 1475                                                          * rx_over_errors +
 1476                                                          * rx_crc_errors +
 1477                                                          * rx_frame_errors */
 1478                     0UL,                                /* rx_compressed */
 1479                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
 1480                                                         /* XXX-BZ rx only? */
 1481                 sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
 1482                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
 1483                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
 1484                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
 1485                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
 1486                     0UL,                                /* tx_fifo_errors */
 1487                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
 1488                     0UL,                                /* tx_carrier_errors +
 1489                                                          * tx_aborted_errors +
 1490                                                          * tx_window_errors +
 1491                                                          * tx_heartbeat_errors*/
 1492                     0UL);                               /* tx_compressed */
 1493         }
 1494         IFNET_RUNLOCK();
 1495         CURVNET_RESTORE();
 1496 
 1497         return (0);
 1498 }
 1499 
 1500 /*
 1501  * Filler function for proc/sys/kernel/osrelease
 1502  */
 1503 static int
 1504 linprocfs_doosrelease(PFS_FILL_ARGS)
 1505 {
 1506         char osrelease[LINUX_MAX_UTSNAME];
 1507 
 1508         linux_get_osrelease(td, osrelease);
 1509         sbuf_printf(sb, "%s\n", osrelease);
 1510 
 1511         return (0);
 1512 }
 1513 
 1514 /*
 1515  * Filler function for proc/sys/kernel/ostype
 1516  */
 1517 static int
 1518 linprocfs_doostype(PFS_FILL_ARGS)
 1519 {
 1520         char osname[LINUX_MAX_UTSNAME];
 1521 
 1522         linux_get_osname(td, osname);
 1523         sbuf_printf(sb, "%s\n", osname);
 1524 
 1525         return (0);
 1526 }
 1527 
 1528 /*
 1529  * Filler function for proc/sys/kernel/version
 1530  */
 1531 static int
 1532 linprocfs_doosbuild(PFS_FILL_ARGS)
 1533 {
 1534 
 1535         linprocfs_osbuild(td, sb);
 1536         sbuf_cat(sb, "\n");
 1537         return (0);
 1538 }
 1539 
 1540 /*
 1541  * Filler function for proc/sys/kernel/msgmax
 1542  */
 1543 static int
 1544 linprocfs_domsgmax(PFS_FILL_ARGS)
 1545 {
 1546 
 1547         sbuf_printf(sb, "%d\n", msginfo.msgmax);
 1548         return (0);
 1549 }
 1550 
 1551 /*
 1552  * Filler function for proc/sys/kernel/msgmni
 1553  */
 1554 static int
 1555 linprocfs_domsgmni(PFS_FILL_ARGS)
 1556 {
 1557 
 1558         sbuf_printf(sb, "%d\n", msginfo.msgmni);
 1559         return (0);
 1560 }
 1561 
 1562 /*
 1563  * Filler function for proc/sys/kernel/msgmnb
 1564  */
 1565 static int
 1566 linprocfs_domsgmnb(PFS_FILL_ARGS)
 1567 {
 1568 
 1569         sbuf_printf(sb, "%d\n", msginfo.msgmnb);
 1570         return (0);
 1571 }
 1572 
 1573 /*
 1574  * Filler function for proc/sys/kernel/ngroups_max
 1575  *
 1576  * Note that in Linux it defaults to 65536, not 1023.
 1577  */
 1578 static int
 1579 linprocfs_dongroups_max(PFS_FILL_ARGS)
 1580 {
 1581 
 1582         sbuf_printf(sb, "%d\n", ngroups_max);
 1583         return (0);
 1584 }
 1585 
 1586 /*
 1587  * Filler function for proc/sys/kernel/pid_max
 1588  */
 1589 static int
 1590 linprocfs_dopid_max(PFS_FILL_ARGS)
 1591 {
 1592 
 1593         sbuf_printf(sb, "%i\n", PID_MAX);
 1594         return (0);
 1595 }
 1596 
 1597 /*
 1598  * Filler function for proc/sys/kernel/sem
 1599  */
 1600 static int
 1601 linprocfs_dosem(PFS_FILL_ARGS)
 1602 {
 1603 
 1604         sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
 1605             seminfo.semopm, seminfo.semmni);
 1606         return (0);
 1607 }
 1608 
 1609 /*
 1610  * Filler function for proc/sys/kernel/shmall
 1611  */
 1612 static int
 1613 linprocfs_doshmall(PFS_FILL_ARGS)
 1614 {
 1615 
 1616         sbuf_printf(sb, "%lu\n", shminfo.shmall);
 1617         return (0);
 1618 }
 1619 
 1620 /*
 1621  * Filler function for proc/sys/kernel/shmmax
 1622  */
 1623 static int
 1624 linprocfs_doshmmax(PFS_FILL_ARGS)
 1625 {
 1626 
 1627         sbuf_printf(sb, "%lu\n", shminfo.shmmax);
 1628         return (0);
 1629 }
 1630 
 1631 /*
 1632  * Filler function for proc/sys/kernel/shmmni
 1633  */
 1634 static int
 1635 linprocfs_doshmmni(PFS_FILL_ARGS)
 1636 {
 1637 
 1638         sbuf_printf(sb, "%lu\n", shminfo.shmmni);
 1639         return (0);
 1640 }
 1641 
 1642 /*
 1643  * Filler function for proc/sys/kernel/tainted
 1644  */
 1645 static int
 1646 linprocfs_dotainted(PFS_FILL_ARGS)
 1647 {
 1648 
 1649         sbuf_printf(sb, "\n");
 1650         return (0);
 1651 }
 1652 
 1653 /*
 1654  * Filler function for proc/sys/vm/min_free_kbytes
 1655  *
 1656  * This mirrors the approach in illumos to return zero for reads. Effectively,
 1657  * it says, no memory is kept in reserve for "atomic allocations". This class
 1658  * of allocation can be used at times when a thread cannot be suspended.
 1659  */
 1660 static int
 1661 linprocfs_dominfree(PFS_FILL_ARGS)
 1662 {
 1663 
 1664         sbuf_printf(sb, "%d\n", 0);
 1665         return (0);
 1666 }
 1667 
 1668 /*
 1669  * Filler function for proc/scsi/device_info
 1670  */
 1671 static int
 1672 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
 1673 {
 1674 
 1675         return (0);
 1676 }
 1677 
 1678 /*
 1679  * Filler function for proc/scsi/scsi
 1680  */
 1681 static int
 1682 linprocfs_doscsiscsi(PFS_FILL_ARGS)
 1683 {
 1684 
 1685         return (0);
 1686 }
 1687 
 1688 /*
 1689  * Filler function for proc/devices
 1690  */
 1691 static int
 1692 linprocfs_dodevices(PFS_FILL_ARGS)
 1693 {
 1694         char *char_devices;
 1695         sbuf_printf(sb, "Character devices:\n");
 1696 
 1697         char_devices = linux_get_char_devices();
 1698         sbuf_printf(sb, "%s", char_devices);
 1699         linux_free_get_char_devices(char_devices);
 1700 
 1701         sbuf_printf(sb, "\nBlock devices:\n");
 1702 
 1703         return (0);
 1704 }
 1705 
 1706 /*
 1707  * Filler function for proc/cmdline
 1708  */
 1709 static int
 1710 linprocfs_docmdline(PFS_FILL_ARGS)
 1711 {
 1712 
 1713         sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
 1714         sbuf_printf(sb, " ro root=302\n");
 1715         return (0);
 1716 }
 1717 
 1718 /*
 1719  * Filler function for proc/filesystems
 1720  */
 1721 static int
 1722 linprocfs_dofilesystems(PFS_FILL_ARGS)
 1723 {
 1724         struct vfsconf *vfsp;
 1725 
 1726         vfsconf_slock();
 1727         TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
 1728                 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
 1729                         sbuf_printf(sb, "nodev");
 1730                 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
 1731         }
 1732         vfsconf_sunlock();
 1733         return(0);
 1734 }
 1735 
 1736 /*
 1737  * Filler function for proc/modules
 1738  */
 1739 static int
 1740 linprocfs_domodules(PFS_FILL_ARGS)
 1741 {
 1742 #if 0
 1743         struct linker_file *lf;
 1744 
 1745         TAILQ_FOREACH(lf, &linker_files, link) {
 1746                 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
 1747                     (unsigned long)lf->size, lf->refs);
 1748         }
 1749 #endif
 1750         return (0);
 1751 }
 1752 
 1753 /*
 1754  * Filler function for proc/pid/fd
 1755  */
 1756 static int
 1757 linprocfs_dofdescfs(PFS_FILL_ARGS)
 1758 {
 1759 
 1760         if (p == curproc)
 1761                 sbuf_printf(sb, "/dev/fd");
 1762         else
 1763                 sbuf_printf(sb, "unknown");
 1764         return (0);
 1765 }
 1766 
 1767 /*
 1768  * Filler function for proc/pid/limits
 1769  */
 1770 static const struct linux_rlimit_ident {
 1771         const char      *desc;
 1772         const char      *unit;
 1773         unsigned int    rlim_id;
 1774 } linux_rlimits_ident[] = {
 1775         { "Max cpu time",       "seconds",      RLIMIT_CPU },
 1776         { "Max file size",      "bytes",        RLIMIT_FSIZE },
 1777         { "Max data size",      "bytes",        RLIMIT_DATA },
 1778         { "Max stack size",     "bytes",        RLIMIT_STACK },
 1779         { "Max core file size",  "bytes",       RLIMIT_CORE },
 1780         { "Max resident set",   "bytes",        RLIMIT_RSS },
 1781         { "Max processes",      "processes",    RLIMIT_NPROC },
 1782         { "Max open files",     "files",        RLIMIT_NOFILE },
 1783         { "Max locked memory",  "bytes",        RLIMIT_MEMLOCK },
 1784         { "Max address space",  "bytes",        RLIMIT_AS },
 1785         { "Max file locks",     "locks",        LINUX_RLIMIT_LOCKS },
 1786         { "Max pending signals", "signals",     LINUX_RLIMIT_SIGPENDING },
 1787         { "Max msgqueue size",  "bytes",        LINUX_RLIMIT_MSGQUEUE },
 1788         { "Max nice priority",          "",     LINUX_RLIMIT_NICE },
 1789         { "Max realtime priority",      "",     LINUX_RLIMIT_RTPRIO },
 1790         { "Max realtime timeout",       "us",   LINUX_RLIMIT_RTTIME },
 1791         { 0, 0, 0 }
 1792 };
 1793 
 1794 static int
 1795 linprocfs_doproclimits(PFS_FILL_ARGS)
 1796 {
 1797         const struct linux_rlimit_ident *li;
 1798         struct plimit *limp;
 1799         struct rlimit rl;
 1800         ssize_t size;
 1801         int res, error;
 1802 
 1803         error = 0;
 1804 
 1805         PROC_LOCK(p);
 1806         limp = lim_hold(p->p_limit);
 1807         PROC_UNLOCK(p);
 1808         size = sizeof(res);
 1809         sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit",
 1810                         "Hard Limit", "Units");
 1811         for (li = linux_rlimits_ident; li->desc != NULL; ++li) {
 1812                 switch (li->rlim_id)
 1813                 {
 1814                 case LINUX_RLIMIT_LOCKS:
 1815                         /* FALLTHROUGH */
 1816                 case LINUX_RLIMIT_RTTIME:
 1817                         rl.rlim_cur = RLIM_INFINITY;
 1818                         break;
 1819                 case LINUX_RLIMIT_SIGPENDING:
 1820                         error = kernel_sysctlbyname(td,
 1821                             "kern.sigqueue.max_pending_per_proc",
 1822                             &res, &size, 0, 0, 0, 0);
 1823                         if (error != 0)
 1824                                 goto out;
 1825                         rl.rlim_cur = res;
 1826                         rl.rlim_max = res;
 1827                         break;
 1828                 case LINUX_RLIMIT_MSGQUEUE:
 1829                         error = kernel_sysctlbyname(td,
 1830                             "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
 1831                         if (error != 0)
 1832                                 goto out;
 1833                         rl.rlim_cur = res;
 1834                         rl.rlim_max = res;
 1835                         break;
 1836                 case LINUX_RLIMIT_NICE:
 1837                         /* FALLTHROUGH */
 1838                 case LINUX_RLIMIT_RTPRIO:
 1839                         rl.rlim_cur = 0;
 1840                         rl.rlim_max = 0;
 1841                         break;
 1842                 default:
 1843                         rl = limp->pl_rlimit[li->rlim_id];
 1844                         break;
 1845                 }
 1846                 if (rl.rlim_cur == RLIM_INFINITY)
 1847                         sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
 1848                             li->desc, "unlimited", "unlimited", li->unit);
 1849                 else
 1850                         sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n",
 1851                             li->desc, (unsigned long long)rl.rlim_cur,
 1852                             (unsigned long long)rl.rlim_max, li->unit);
 1853         }
 1854 out:
 1855         lim_free(limp);
 1856         return (error);
 1857 }
 1858 
 1859 /*
 1860  * The point of the following two functions is to work around
 1861  * an assertion in Chromium; see kern/240991 for details.
 1862  */
 1863 static int
 1864 linprocfs_dotaskattr(PFS_ATTR_ARGS)
 1865 {
 1866 
 1867         vap->va_nlink = 3;
 1868         return (0);
 1869 }
 1870 
 1871 /*
 1872  * Filler function for proc/<pid>/task/.dummy
 1873  */
 1874 static int
 1875 linprocfs_dotaskdummy(PFS_FILL_ARGS)
 1876 {
 1877 
 1878         return (0);
 1879 }
 1880 
 1881 /*
 1882  * Filler function for proc/sys/kernel/random/uuid
 1883  */
 1884 static int
 1885 linprocfs_douuid(PFS_FILL_ARGS)
 1886 {
 1887         struct uuid uuid;
 1888 
 1889         kern_uuidgen(&uuid, 1);
 1890         sbuf_printf_uuid(sb, &uuid);
 1891         sbuf_printf(sb, "\n");
 1892         return(0);
 1893 }
 1894 
 1895 /*
 1896  * Filler function for proc/pid/auxv
 1897  */
 1898 static int
 1899 linprocfs_doauxv(PFS_FILL_ARGS)
 1900 {
 1901         struct sbuf *asb;
 1902         off_t buflen, resid;
 1903         int error;
 1904 
 1905         /*
 1906          * Mimic linux behavior and pass only processes with usermode
 1907          * address space as valid. Return zero silently otherwise.
 1908          */
 1909         if (p->p_vmspace == &vmspace0)
 1910                 return (0);
 1911 
 1912         if (uio->uio_resid == 0)
 1913                 return (0);
 1914         if (uio->uio_offset < 0 || uio->uio_resid < 0)
 1915                 return (EINVAL);
 1916 
 1917         asb = sbuf_new_auto();
 1918         if (asb == NULL)
 1919                 return (ENOMEM);
 1920         error = proc_getauxv(td, p, asb);
 1921         if (error == 0)
 1922                 error = sbuf_finish(asb);
 1923 
 1924         resid = sbuf_len(asb) - uio->uio_offset;
 1925         if (resid > uio->uio_resid)
 1926                 buflen = uio->uio_resid;
 1927         else
 1928                 buflen = resid;
 1929         if (buflen > IOSIZE_MAX)
 1930                 return (EINVAL);
 1931         if (buflen > maxphys)
 1932                 buflen = maxphys;
 1933         if (resid <= 0)
 1934                 return (0);
 1935 
 1936         if (error == 0)
 1937                 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
 1938         sbuf_delete(asb);
 1939         return (error);
 1940 }
 1941 
 1942 /*
 1943  * Constructor
 1944  */
 1945 static int
 1946 linprocfs_init(PFS_INIT_ARGS)
 1947 {
 1948         struct pfs_node *root;
 1949         struct pfs_node *dir;
 1950         struct pfs_node *sys;
 1951 
 1952         root = pi->pi_root;
 1953 
 1954         /* /proc/... */
 1955         pfs_create_file(root, "cmdline", &linprocfs_docmdline,
 1956             NULL, NULL, NULL, PFS_RD);
 1957         pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
 1958             NULL, NULL, NULL, PFS_RD);
 1959         pfs_create_file(root, "devices", &linprocfs_dodevices,
 1960             NULL, NULL, NULL, PFS_RD);
 1961         pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
 1962             NULL, NULL, NULL, PFS_RD);
 1963         pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
 1964             NULL, NULL, NULL, PFS_RD);
 1965         pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
 1966             NULL, NULL, NULL, PFS_RD);
 1967         pfs_create_file(root, "modules", &linprocfs_domodules,
 1968             NULL, NULL, NULL, PFS_RD);
 1969         pfs_create_file(root, "mounts", &linprocfs_domtab,
 1970             NULL, NULL, NULL, PFS_RD);
 1971         pfs_create_file(root, "mtab", &linprocfs_domtab,
 1972             NULL, NULL, NULL, PFS_RD);
 1973         pfs_create_file(root, "partitions", &linprocfs_dopartitions,
 1974             NULL, NULL, NULL, PFS_RD);
 1975         pfs_create_link(root, "self", &procfs_docurproc,
 1976             NULL, NULL, NULL, 0);
 1977         pfs_create_file(root, "stat", &linprocfs_dostat,
 1978             NULL, NULL, NULL, PFS_RD);
 1979         pfs_create_file(root, "swaps", &linprocfs_doswaps,
 1980             NULL, NULL, NULL, PFS_RD);
 1981         pfs_create_file(root, "uptime", &linprocfs_douptime,
 1982             NULL, NULL, NULL, PFS_RD);
 1983         pfs_create_file(root, "version", &linprocfs_doversion,
 1984             NULL, NULL, NULL, PFS_RD);
 1985 
 1986         /* /proc/bus/... */
 1987         dir = pfs_create_dir(root, "bus", NULL, NULL, NULL, 0);
 1988         dir = pfs_create_dir(dir, "pci", NULL, NULL, NULL, 0);
 1989         dir = pfs_create_dir(dir, "devices", NULL, NULL, NULL, 0);
 1990 
 1991         /* /proc/net/... */
 1992         dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
 1993         pfs_create_file(dir, "dev", &linprocfs_donetdev,
 1994             NULL, NULL, NULL, PFS_RD);
 1995 
 1996         /* /proc/<pid>/... */
 1997         dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
 1998         pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
 1999             NULL, NULL, NULL, PFS_RD);
 2000         pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
 2001             NULL, NULL, NULL, 0);
 2002         pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
 2003             NULL, &procfs_candebug, NULL, PFS_RD);
 2004         pfs_create_link(dir, "exe", &procfs_doprocfile,
 2005             NULL, &procfs_notsystem, NULL, 0);
 2006         pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
 2007             NULL, NULL, NULL, PFS_RD | PFS_AUTODRAIN);
 2008         pfs_create_file(dir, "mem", &linprocfs_doprocmem,
 2009             procfs_attr_rw, &procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
 2010         pfs_create_file(dir, "mountinfo", &linprocfs_doprocmountinfo,
 2011             NULL, NULL, NULL, PFS_RD);
 2012         pfs_create_file(dir, "mounts", &linprocfs_domtab,
 2013             NULL, NULL, NULL, PFS_RD);
 2014         pfs_create_link(dir, "root", &linprocfs_doprocroot,
 2015             NULL, NULL, NULL, 0);
 2016         pfs_create_file(dir, "stat", &linprocfs_doprocstat,
 2017             NULL, NULL, NULL, PFS_RD);
 2018         pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
 2019             NULL, NULL, NULL, PFS_RD);
 2020         pfs_create_file(dir, "status", &linprocfs_doprocstatus,
 2021             NULL, NULL, NULL, PFS_RD);
 2022         pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
 2023             NULL, NULL, NULL, 0);
 2024         pfs_create_file(dir, "auxv", &linprocfs_doauxv,
 2025             NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
 2026         pfs_create_file(dir, "limits", &linprocfs_doproclimits,
 2027             NULL, NULL, NULL, PFS_RD);
 2028 
 2029         /* /proc/<pid>/task/... */
 2030         dir = pfs_create_dir(dir, "task", linprocfs_dotaskattr, NULL, NULL, 0);
 2031         pfs_create_file(dir, ".dummy", &linprocfs_dotaskdummy,
 2032             NULL, NULL, NULL, PFS_RD);
 2033 
 2034         /* /proc/scsi/... */
 2035         dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
 2036         pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
 2037             NULL, NULL, NULL, PFS_RD);
 2038         pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
 2039             NULL, NULL, NULL, PFS_RD);
 2040 
 2041         /* /proc/sys/... */
 2042         sys = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
 2043 
 2044         /* /proc/sys/kernel/... */
 2045         dir = pfs_create_dir(sys, "kernel", NULL, NULL, NULL, 0);
 2046         pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
 2047             NULL, NULL, NULL, PFS_RD);
 2048         pfs_create_file(dir, "ostype", &linprocfs_doostype,
 2049             NULL, NULL, NULL, PFS_RD);
 2050         pfs_create_file(dir, "version", &linprocfs_doosbuild,
 2051             NULL, NULL, NULL, PFS_RD);
 2052         pfs_create_file(dir, "msgmax", &linprocfs_domsgmax,
 2053             NULL, NULL, NULL, PFS_RD);
 2054         pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
 2055             NULL, NULL, NULL, PFS_RD);
 2056         pfs_create_file(dir, "msgmnb", &linprocfs_domsgmnb,
 2057             NULL, NULL, NULL, PFS_RD);
 2058         pfs_create_file(dir, "ngroups_max", &linprocfs_dongroups_max,
 2059             NULL, NULL, NULL, PFS_RD);
 2060         pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
 2061             NULL, NULL, NULL, PFS_RD);
 2062         pfs_create_file(dir, "sem", &linprocfs_dosem,
 2063             NULL, NULL, NULL, PFS_RD);
 2064         pfs_create_file(dir, "shmall", &linprocfs_doshmall,
 2065             NULL, NULL, NULL, PFS_RD);
 2066         pfs_create_file(dir, "shmmax", &linprocfs_doshmmax,
 2067             NULL, NULL, NULL, PFS_RD);
 2068         pfs_create_file(dir, "shmmni", &linprocfs_doshmmni,
 2069             NULL, NULL, NULL, PFS_RD);
 2070         pfs_create_file(dir, "tainted", &linprocfs_dotainted,
 2071             NULL, NULL, NULL, PFS_RD);
 2072 
 2073         /* /proc/sys/kernel/random/... */
 2074         dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
 2075         pfs_create_file(dir, "uuid", &linprocfs_douuid,
 2076             NULL, NULL, NULL, PFS_RD);
 2077 
 2078         /* /proc/sys/vm/.... */
 2079         dir = pfs_create_dir(sys, "vm", NULL, NULL, NULL, 0);
 2080         pfs_create_file(dir, "min_free_kbytes", &linprocfs_dominfree,
 2081             NULL, NULL, NULL, PFS_RD);
 2082 
 2083         return (0);
 2084 }
 2085 
 2086 /*
 2087  * Destructor
 2088  */
 2089 static int
 2090 linprocfs_uninit(PFS_INIT_ARGS)
 2091 {
 2092 
 2093         /* nothing to do, pseudofs will GC */
 2094         return (0);
 2095 }
 2096 
 2097 PSEUDOFS(linprocfs, 1, VFCF_JAIL);
 2098 #if defined(__aarch64__) || defined(__amd64__)
 2099 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
 2100 #else
 2101 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
 2102 #endif
 2103 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
 2104 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
 2105 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
 2106 MODULE_DEPEND(linprocfs, sysvshm, 1, 1, 1);

Cache object: e3a8bf47b7256e8e3519c95757442562


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.