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

Cache object: f2cfe59520a4922ca80fa0eb2e44cea7


[ 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.