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: releng/11.1/sys/compat/linprocfs/linprocfs.c 320693 2017-07-05 19:24:53Z markj $");
   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         PS_ADD("tty",           "%ju",  (uintmax_t)kp.ki_tdev);
  622         PS_ADD("tpgid",         "%d",   kp.ki_tpgid);
  623         PS_ADD("flags",         "%u",   0); /* XXX */
  624         PS_ADD("minflt",        "%lu",  kp.ki_rusage.ru_minflt);
  625         PS_ADD("cminflt",       "%lu",  kp.ki_rusage_ch.ru_minflt);
  626         PS_ADD("majflt",        "%lu",  kp.ki_rusage.ru_majflt);
  627         PS_ADD("cmajflt",       "%lu",  kp.ki_rusage_ch.ru_majflt);
  628         PS_ADD("utime",         "%ld",  TV2J(&kp.ki_rusage.ru_utime));
  629         PS_ADD("stime",         "%ld",  TV2J(&kp.ki_rusage.ru_stime));
  630         PS_ADD("cutime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_utime));
  631         PS_ADD("cstime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_stime));
  632         PS_ADD("priority",      "%d",   kp.ki_pri.pri_user);
  633         PS_ADD("nice",          "%d",   kp.ki_nice); /* 19 (nicest) to -19 */
  634         PS_ADD("",             "%d",   0); /* removed field */
  635         PS_ADD("itrealvalue",   "%d",   0); /* XXX */
  636         PS_ADD("starttime",     "%lu",  TV2J(&kp.ki_start) - TV2J(&boottime));
  637         PS_ADD("vsize",         "%ju",  P2K((uintmax_t)kp.ki_size));
  638         PS_ADD("rss",           "%ju",  (uintmax_t)kp.ki_rssize);
  639         PS_ADD("rlim",          "%lu",  kp.ki_rusage.ru_maxrss);
  640         PS_ADD("startcode",     "%ju",  (uintmax_t)startcode);
  641         PS_ADD("endcode",       "%ju",  (uintmax_t)startdata);
  642         PS_ADD("startstack",    "%u",   0); /* XXX */
  643         PS_ADD("kstkesp",       "%u",   0); /* XXX */
  644         PS_ADD("kstkeip",       "%u",   0); /* XXX */
  645         PS_ADD("signal",        "%u",   0); /* XXX */
  646         PS_ADD("blocked",       "%u",   0); /* XXX */
  647         PS_ADD("sigignore",     "%u",   0); /* XXX */
  648         PS_ADD("sigcatch",      "%u",   0); /* XXX */
  649         PS_ADD("wchan",         "%u",   0); /* XXX */
  650         PS_ADD("nswap",         "%lu",  kp.ki_rusage.ru_nswap);
  651         PS_ADD("cnswap",        "%lu",  kp.ki_rusage_ch.ru_nswap);
  652         PS_ADD("exitsignal",    "%d",   0); /* XXX */
  653         PS_ADD("processor",     "%u",   kp.ki_lastcpu);
  654         PS_ADD("rt_priority",   "%u",   0); /* XXX */ /* >= 2.5.19 */
  655         PS_ADD("policy",        "%u",   kp.ki_pri.pri_class); /* >= 2.5.19 */
  656 #undef PS_ADD
  657         sbuf_putc(sb, '\n');
  658 
  659         return (0);
  660 }
  661 
  662 /*
  663  * Filler function for proc/pid/statm
  664  */
  665 static int
  666 linprocfs_doprocstatm(PFS_FILL_ARGS)
  667 {
  668         struct kinfo_proc kp;
  669         segsz_t lsize;
  670 
  671         sx_slock(&proctree_lock);
  672         PROC_LOCK(p);
  673         fill_kinfo_proc(p, &kp);
  674         PROC_UNLOCK(p);
  675         sx_sunlock(&proctree_lock);
  676 
  677         /*
  678          * See comments in linprocfs_doprocstatus() regarding the
  679          * computation of lsize.
  680          */
  681         /* size resident share trs drs lrs dt */
  682         sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
  683         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
  684         sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
  685         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
  686         sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
  687         lsize = B2P(kp.ki_size) - kp.ki_dsize -
  688             kp.ki_ssize - kp.ki_tsize - 1;
  689         sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
  690         sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
  691 
  692         return (0);
  693 }
  694 
  695 /*
  696  * Filler function for proc/pid/status
  697  */
  698 static int
  699 linprocfs_doprocstatus(PFS_FILL_ARGS)
  700 {
  701         struct kinfo_proc kp;
  702         char *state;
  703         segsz_t lsize;
  704         struct thread *td2;
  705         struct sigacts *ps;
  706         l_sigset_t siglist, sigignore, sigcatch;
  707         int i;
  708 
  709         sx_slock(&proctree_lock);
  710         PROC_LOCK(p);
  711         td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
  712 
  713         if (P_SHOULDSTOP(p)) {
  714                 state = "T (stopped)";
  715         } else {
  716                 switch(p->p_state) {
  717                 case PRS_NEW:
  718                         state = "I (idle)";
  719                         break;
  720                 case PRS_NORMAL:
  721                         if (p->p_flag & P_WEXIT) {
  722                                 state = "X (exiting)";
  723                                 break;
  724                         }
  725                         switch(td2->td_state) {
  726                         case TDS_INHIBITED:
  727                                 state = "S (sleeping)";
  728                                 break;
  729                         case TDS_RUNQ:
  730                         case TDS_RUNNING:
  731                                 state = "R (running)";
  732                                 break;
  733                         default:
  734                                 state = "? (unknown)";
  735                                 break;
  736                         }
  737                         break;
  738                 case PRS_ZOMBIE:
  739                         state = "Z (zombie)";
  740                         break;
  741                 default:
  742                         state = "? (unknown)";
  743                         break;
  744                 }
  745         }
  746 
  747         fill_kinfo_proc(p, &kp);
  748         sx_sunlock(&proctree_lock);
  749 
  750         sbuf_printf(sb, "Name:\t%s\n",          p->p_comm); /* XXX escape */
  751         sbuf_printf(sb, "State:\t%s\n",         state);
  752 
  753         /*
  754          * Credentials
  755          */
  756         sbuf_printf(sb, "Pid:\t%d\n",           p->p_pid);
  757         sbuf_printf(sb, "PPid:\t%d\n",          p->p_pptr ?
  758                                                 p->p_pptr->p_pid : 0);
  759         sbuf_printf(sb, "Uid:\t%d %d %d %d\n",  p->p_ucred->cr_ruid,
  760                                                 p->p_ucred->cr_uid,
  761                                                 p->p_ucred->cr_svuid,
  762                                                 /* FreeBSD doesn't have fsuid */
  763                                                 p->p_ucred->cr_uid);
  764         sbuf_printf(sb, "Gid:\t%d %d %d %d\n",  p->p_ucred->cr_rgid,
  765                                                 p->p_ucred->cr_gid,
  766                                                 p->p_ucred->cr_svgid,
  767                                                 /* FreeBSD doesn't have fsgid */
  768                                                 p->p_ucred->cr_gid);
  769         sbuf_cat(sb, "Groups:\t");
  770         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
  771                 sbuf_printf(sb, "%d ",          p->p_ucred->cr_groups[i]);
  772         PROC_UNLOCK(p);
  773         sbuf_putc(sb, '\n');
  774 
  775         /*
  776          * Memory
  777          *
  778          * While our approximation of VmLib may not be accurate (I
  779          * don't know of a simple way to verify it, and I'm not sure
  780          * it has much meaning anyway), I believe it's good enough.
  781          *
  782          * The same code that could (I think) accurately compute VmLib
  783          * could also compute VmLck, but I don't really care enough to
  784          * implement it. Submissions are welcome.
  785          */
  786         sbuf_printf(sb, "VmSize:\t%8ju kB\n",   B2K((uintmax_t)kp.ki_size));
  787         sbuf_printf(sb, "VmLck:\t%8u kB\n",     P2K(0)); /* XXX */
  788         sbuf_printf(sb, "VmRSS:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_rssize));
  789         sbuf_printf(sb, "VmData:\t%8ju kB\n",   P2K((uintmax_t)kp.ki_dsize));
  790         sbuf_printf(sb, "VmStk:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_ssize));
  791         sbuf_printf(sb, "VmExe:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_tsize));
  792         lsize = B2P(kp.ki_size) - kp.ki_dsize -
  793             kp.ki_ssize - kp.ki_tsize - 1;
  794         sbuf_printf(sb, "VmLib:\t%8ju kB\n",    P2K((uintmax_t)lsize));
  795 
  796         /*
  797          * Signal masks
  798          */
  799         PROC_LOCK(p);
  800         bsd_to_linux_sigset(&p->p_siglist, &siglist);
  801         ps = p->p_sigacts;
  802         mtx_lock(&ps->ps_mtx);
  803         bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
  804         bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
  805         mtx_unlock(&ps->ps_mtx);
  806         PROC_UNLOCK(p);
  807 
  808         sbuf_printf(sb, "SigPnd:\t%016jx\n",    siglist.__mask);
  809         /*
  810          * XXX. SigBlk - target thread's signal mask, td_sigmask.
  811          * To implement SigBlk pseudofs should support proc/tid dir entries.
  812          */
  813         sbuf_printf(sb, "SigBlk:\t%016x\n",     0);
  814         sbuf_printf(sb, "SigIgn:\t%016jx\n",    sigignore.__mask);
  815         sbuf_printf(sb, "SigCgt:\t%016jx\n",    sigcatch.__mask);
  816 
  817         /*
  818          * Linux also prints the capability masks, but we don't have
  819          * capabilities yet, and when we do get them they're likely to
  820          * be meaningless to Linux programs, so we lie. XXX
  821          */
  822         sbuf_printf(sb, "CapInh:\t%016x\n",     0);
  823         sbuf_printf(sb, "CapPrm:\t%016x\n",     0);
  824         sbuf_printf(sb, "CapEff:\t%016x\n",     0);
  825 
  826         return (0);
  827 }
  828 
  829 
  830 /*
  831  * Filler function for proc/pid/cwd
  832  */
  833 static int
  834 linprocfs_doproccwd(PFS_FILL_ARGS)
  835 {
  836         struct filedesc *fdp;
  837         struct vnode *vp;
  838         char *fullpath = "unknown";
  839         char *freepath = NULL;
  840 
  841         fdp = p->p_fd;
  842         FILEDESC_SLOCK(fdp);
  843         vp = fdp->fd_cdir;
  844         if (vp != NULL)
  845                 VREF(vp);
  846         FILEDESC_SUNLOCK(fdp);
  847         vn_fullpath(td, vp, &fullpath, &freepath);
  848         if (vp != NULL)
  849                 vrele(vp);
  850         sbuf_printf(sb, "%s", fullpath);
  851         if (freepath)
  852                 free(freepath, M_TEMP);
  853         return (0);
  854 }
  855 
  856 /*
  857  * Filler function for proc/pid/root
  858  */
  859 static int
  860 linprocfs_doprocroot(PFS_FILL_ARGS)
  861 {
  862         struct filedesc *fdp;
  863         struct vnode *vp;
  864         char *fullpath = "unknown";
  865         char *freepath = NULL;
  866 
  867         fdp = p->p_fd;
  868         FILEDESC_SLOCK(fdp);
  869         vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
  870         if (vp != NULL)
  871                 VREF(vp);
  872         FILEDESC_SUNLOCK(fdp);
  873         vn_fullpath(td, vp, &fullpath, &freepath);
  874         if (vp != NULL)
  875                 vrele(vp);
  876         sbuf_printf(sb, "%s", fullpath);
  877         if (freepath)
  878                 free(freepath, M_TEMP);
  879         return (0);
  880 }
  881 
  882 /*
  883  * Filler function for proc/pid/cmdline
  884  */
  885 static int
  886 linprocfs_doproccmdline(PFS_FILL_ARGS)
  887 {
  888         int ret;
  889 
  890         PROC_LOCK(p);
  891         if ((ret = p_cansee(td, p)) != 0) {
  892                 PROC_UNLOCK(p);
  893                 return (ret);
  894         }
  895 
  896         /*
  897          * Mimic linux behavior and pass only processes with usermode
  898          * address space as valid.  Return zero silently otherwize.
  899          */
  900         if (p->p_vmspace == &vmspace0) {
  901                 PROC_UNLOCK(p);
  902                 return (0);
  903         }
  904         if (p->p_args != NULL) {
  905                 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
  906                 PROC_UNLOCK(p);
  907                 return (0);
  908         }
  909 
  910         if ((p->p_flag & P_SYSTEM) != 0) {
  911                 PROC_UNLOCK(p);
  912                 return (0);
  913         }
  914 
  915         PROC_UNLOCK(p);
  916 
  917         ret = proc_getargv(td, p, sb);
  918         return (ret);
  919 }
  920 
  921 /*
  922  * Filler function for proc/pid/environ
  923  */
  924 static int
  925 linprocfs_doprocenviron(PFS_FILL_ARGS)
  926 {
  927 
  928         /*
  929          * Mimic linux behavior and pass only processes with usermode
  930          * address space as valid.  Return zero silently otherwize.
  931          */
  932         if (p->p_vmspace == &vmspace0)
  933                 return (0);
  934 
  935         return (proc_getenvv(td, p, sb));
  936 }
  937 
  938 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
  939 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
  940 static char vdso_str[] = "      [vdso]";
  941 static char stack_str[] = "      [stack]";
  942 
  943 /*
  944  * Filler function for proc/pid/maps
  945  */
  946 static int
  947 linprocfs_doprocmaps(PFS_FILL_ARGS)
  948 {
  949         struct vmspace *vm;
  950         vm_map_t map;
  951         vm_map_entry_t entry, tmp_entry;
  952         vm_object_t obj, tobj, lobj;
  953         vm_offset_t e_start, e_end;
  954         vm_ooffset_t off = 0;
  955         vm_prot_t e_prot;
  956         unsigned int last_timestamp;
  957         char *name = "", *freename = NULL;
  958         const char *l_map_str;
  959         ino_t ino;
  960         int ref_count, shadow_count, flags;
  961         int error;
  962         struct vnode *vp;
  963         struct vattr vat;
  964 
  965         PROC_LOCK(p);
  966         error = p_candebug(td, p);
  967         PROC_UNLOCK(p);
  968         if (error)
  969                 return (error);
  970 
  971         if (uio->uio_rw != UIO_READ)
  972                 return (EOPNOTSUPP);
  973 
  974         error = 0;
  975         vm = vmspace_acquire_ref(p);
  976         if (vm == NULL)
  977                 return (ESRCH);
  978 
  979         if (SV_CURPROC_FLAG(SV_LP64))
  980                 l_map_str = l64_map_str;
  981         else
  982                 l_map_str = l32_map_str;
  983         map = &vm->vm_map;
  984         vm_map_lock_read(map);
  985         for (entry = map->header.next; entry != &map->header;
  986             entry = entry->next) {
  987                 name = "";
  988                 freename = NULL;
  989                 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
  990                         continue;
  991                 e_prot = entry->protection;
  992                 e_start = entry->start;
  993                 e_end = entry->end;
  994                 obj = entry->object.vm_object;
  995                 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
  996                         VM_OBJECT_RLOCK(tobj);
  997                         if (lobj != obj)
  998                                 VM_OBJECT_RUNLOCK(lobj);
  999                         lobj = tobj;
 1000                 }
 1001                 last_timestamp = map->timestamp;
 1002                 vm_map_unlock_read(map);
 1003                 ino = 0;
 1004                 if (lobj) {
 1005                         off = IDX_TO_OFF(lobj->size);
 1006                         vp = vm_object_vnode(lobj);
 1007                         if (vp != NULL)
 1008                                 vref(vp);
 1009                         if (lobj != obj)
 1010                                 VM_OBJECT_RUNLOCK(lobj);
 1011                         flags = obj->flags;
 1012                         ref_count = obj->ref_count;
 1013                         shadow_count = obj->shadow_count;
 1014                         VM_OBJECT_RUNLOCK(obj);
 1015                         if (vp != NULL) {
 1016                                 vn_fullpath(td, vp, &name, &freename);
 1017                                 vn_lock(vp, LK_SHARED | LK_RETRY);
 1018                                 VOP_GETATTR(vp, &vat, td->td_ucred);
 1019                                 ino = vat.va_fileid;
 1020                                 vput(vp);
 1021                         } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
 1022                                 if (e_start == p->p_sysent->sv_shared_page_base)
 1023                                         name = vdso_str;
 1024                                 if (e_end == p->p_sysent->sv_usrstack)
 1025                                         name = stack_str;
 1026                         }
 1027                 } else {
 1028                         flags = 0;
 1029                         ref_count = 0;
 1030                         shadow_count = 0;
 1031                 }
 1032 
 1033                 /*
 1034                  * format:
 1035                  *  start, end, access, offset, major, minor, inode, name.
 1036                  */
 1037                 error = sbuf_printf(sb, l_map_str,
 1038                     (u_long)e_start, (u_long)e_end,
 1039                     (e_prot & VM_PROT_READ)?"r":"-",
 1040                     (e_prot & VM_PROT_WRITE)?"w":"-",
 1041                     (e_prot & VM_PROT_EXECUTE)?"x":"-",
 1042                     "p",
 1043                     (u_long)off,
 1044                     0,
 1045                     0,
 1046                     (u_long)ino,
 1047                     *name ? "     " : "",
 1048                     name
 1049                     );
 1050                 if (freename)
 1051                         free(freename, M_TEMP);
 1052                 vm_map_lock_read(map);
 1053                 if (error == -1) {
 1054                         error = 0;
 1055                         break;
 1056                 }
 1057                 if (last_timestamp != map->timestamp) {
 1058                         /*
 1059                          * Look again for the entry because the map was
 1060                          * modified while it was unlocked.  Specifically,
 1061                          * the entry may have been clipped, merged, or deleted.
 1062                          */
 1063                         vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
 1064                         entry = tmp_entry;
 1065                 }
 1066         }
 1067         vm_map_unlock_read(map);
 1068         vmspace_free(vm);
 1069 
 1070         return (error);
 1071 }
 1072 
 1073 /*
 1074  * Criteria for interface name translation
 1075  */
 1076 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
 1077 
 1078 static int
 1079 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
 1080 {
 1081         struct ifnet *ifscan;
 1082         int ethno;
 1083 
 1084         IFNET_RLOCK_ASSERT();
 1085 
 1086         /* Short-circuit non ethernet interfaces */
 1087         if (!IFP_IS_ETH(ifp))
 1088                 return (strlcpy(buffer, ifp->if_xname, buflen));
 1089 
 1090         /* Determine the (relative) unit number for ethernet interfaces */
 1091         ethno = 0;
 1092         TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
 1093                 if (ifscan == ifp)
 1094                         return (snprintf(buffer, buflen, "eth%d", ethno));
 1095                 if (IFP_IS_ETH(ifscan))
 1096                         ethno++;
 1097         }
 1098 
 1099         return (0);
 1100 }
 1101 
 1102 /*
 1103  * Filler function for proc/net/dev
 1104  */
 1105 static int
 1106 linprocfs_donetdev(PFS_FILL_ARGS)
 1107 {
 1108         char ifname[16]; /* XXX LINUX_IFNAMSIZ */
 1109         struct ifnet *ifp;
 1110 
 1111         sbuf_printf(sb, "%6s|%58s|%s\n"
 1112             "%6s|%58s|%58s\n",
 1113             "Inter-", "   Receive", "  Transmit",
 1114             " face",
 1115             "bytes    packets errs drop fifo frame compressed multicast",
 1116             "bytes    packets errs drop fifo colls carrier compressed");
 1117 
 1118         CURVNET_SET(TD_TO_VNET(curthread));
 1119         IFNET_RLOCK();
 1120         TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
 1121                 linux_ifname(ifp, ifname, sizeof ifname);
 1122                 sbuf_printf(sb, "%6.6s: ", ifname);
 1123                 sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
 1124                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
 1125                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
 1126                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
 1127                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
 1128                                                         /* rx_missed_errors */
 1129                     0UL,                                /* rx_fifo_errors */
 1130                     0UL,                                /* rx_length_errors +
 1131                                                          * rx_over_errors +
 1132                                                          * rx_crc_errors +
 1133                                                          * rx_frame_errors */
 1134                     0UL,                                /* rx_compressed */
 1135                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
 1136                                                         /* XXX-BZ rx only? */
 1137                 sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
 1138                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
 1139                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
 1140                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
 1141                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
 1142                     0UL,                                /* tx_fifo_errors */
 1143                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
 1144                     0UL,                                /* tx_carrier_errors +
 1145                                                          * tx_aborted_errors +
 1146                                                          * tx_window_errors +
 1147                                                          * tx_heartbeat_errors*/
 1148                     0UL);                               /* tx_compressed */
 1149         }
 1150         IFNET_RUNLOCK();
 1151         CURVNET_RESTORE();
 1152 
 1153         return (0);
 1154 }
 1155 
 1156 /*
 1157  * Filler function for proc/sys/kernel/osrelease
 1158  */
 1159 static int
 1160 linprocfs_doosrelease(PFS_FILL_ARGS)
 1161 {
 1162         char osrelease[LINUX_MAX_UTSNAME];
 1163 
 1164         linux_get_osrelease(td, osrelease);
 1165         sbuf_printf(sb, "%s\n", osrelease);
 1166 
 1167         return (0);
 1168 }
 1169 
 1170 /*
 1171  * Filler function for proc/sys/kernel/ostype
 1172  */
 1173 static int
 1174 linprocfs_doostype(PFS_FILL_ARGS)
 1175 {
 1176         char osname[LINUX_MAX_UTSNAME];
 1177 
 1178         linux_get_osname(td, osname);
 1179         sbuf_printf(sb, "%s\n", osname);
 1180 
 1181         return (0);
 1182 }
 1183 
 1184 /*
 1185  * Filler function for proc/sys/kernel/version
 1186  */
 1187 static int
 1188 linprocfs_doosbuild(PFS_FILL_ARGS)
 1189 {
 1190 
 1191         linprocfs_osbuild(td, sb);
 1192         sbuf_cat(sb, "\n");
 1193         return (0);
 1194 }
 1195 
 1196 /*
 1197  * Filler function for proc/sys/kernel/msgmni
 1198  */
 1199 static int
 1200 linprocfs_domsgmni(PFS_FILL_ARGS)
 1201 {
 1202 
 1203         sbuf_printf(sb, "%d\n", msginfo.msgmni);
 1204         return (0);
 1205 }
 1206 
 1207 /*
 1208  * Filler function for proc/sys/kernel/pid_max
 1209  */
 1210 static int
 1211 linprocfs_dopid_max(PFS_FILL_ARGS)
 1212 {
 1213 
 1214         sbuf_printf(sb, "%i\n", PID_MAX);
 1215         return (0);
 1216 }
 1217 
 1218 /*
 1219  * Filler function for proc/sys/kernel/sem
 1220  */
 1221 static int
 1222 linprocfs_dosem(PFS_FILL_ARGS)
 1223 {
 1224 
 1225         sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
 1226             seminfo.semopm, seminfo.semmni);
 1227         return (0);
 1228 }
 1229 
 1230 /*
 1231  * Filler function for proc/scsi/device_info
 1232  */
 1233 static int
 1234 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
 1235 {
 1236 
 1237         return (0);
 1238 }
 1239 
 1240 /*
 1241  * Filler function for proc/scsi/scsi
 1242  */
 1243 static int
 1244 linprocfs_doscsiscsi(PFS_FILL_ARGS)
 1245 {
 1246 
 1247         return (0);
 1248 }
 1249 
 1250 /*
 1251  * Filler function for proc/devices
 1252  */
 1253 static int
 1254 linprocfs_dodevices(PFS_FILL_ARGS)
 1255 {
 1256         char *char_devices;
 1257         sbuf_printf(sb, "Character devices:\n");
 1258 
 1259         char_devices = linux_get_char_devices();
 1260         sbuf_printf(sb, "%s", char_devices);
 1261         linux_free_get_char_devices(char_devices);
 1262 
 1263         sbuf_printf(sb, "\nBlock devices:\n");
 1264 
 1265         return (0);
 1266 }
 1267 
 1268 /*
 1269  * Filler function for proc/cmdline
 1270  */
 1271 static int
 1272 linprocfs_docmdline(PFS_FILL_ARGS)
 1273 {
 1274 
 1275         sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
 1276         sbuf_printf(sb, " ro root=302\n");
 1277         return (0);
 1278 }
 1279 
 1280 /*
 1281  * Filler function for proc/filesystems
 1282  */
 1283 static int
 1284 linprocfs_dofilesystems(PFS_FILL_ARGS)
 1285 {
 1286         struct vfsconf *vfsp;
 1287 
 1288         vfsconf_slock();
 1289         TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
 1290                 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
 1291                         sbuf_printf(sb, "nodev");
 1292                 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
 1293         }
 1294         vfsconf_sunlock();
 1295         return(0);
 1296 }
 1297 
 1298 #if 0
 1299 /*
 1300  * Filler function for proc/modules
 1301  */
 1302 static int
 1303 linprocfs_domodules(PFS_FILL_ARGS)
 1304 {
 1305         struct linker_file *lf;
 1306 
 1307         TAILQ_FOREACH(lf, &linker_files, link) {
 1308                 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
 1309                     (unsigned long)lf->size, lf->refs);
 1310         }
 1311         return (0);
 1312 }
 1313 #endif
 1314 
 1315 /*
 1316  * Filler function for proc/pid/fd
 1317  */
 1318 static int
 1319 linprocfs_dofdescfs(PFS_FILL_ARGS)
 1320 {
 1321 
 1322         if (p == curproc)
 1323                 sbuf_printf(sb, "/dev/fd");
 1324         else
 1325                 sbuf_printf(sb, "unknown");
 1326         return (0);
 1327 }
 1328 
 1329 /*
 1330  * Filler function for proc/pid/limits
 1331  */
 1332 static const struct linux_rlimit_ident {
 1333         const char      *desc;
 1334         const char      *unit;
 1335         unsigned int    rlim_id;
 1336 } linux_rlimits_ident[] = {
 1337         { "Max cpu time",       "seconds",      RLIMIT_CPU },
 1338         { "Max file size",      "bytes",        RLIMIT_FSIZE },
 1339         { "Max data size",      "bytes",        RLIMIT_DATA },
 1340         { "Max stack size",     "bytes",        RLIMIT_STACK },
 1341         { "Max core file size",  "bytes",       RLIMIT_CORE },
 1342         { "Max resident set",   "bytes",        RLIMIT_RSS },
 1343         { "Max processes",      "processes",    RLIMIT_NPROC },
 1344         { "Max open files",     "files",        RLIMIT_NOFILE },
 1345         { "Max locked memory",  "bytes",        RLIMIT_MEMLOCK },
 1346         { "Max address space",  "bytes",        RLIMIT_AS },
 1347         { "Max file locks",     "locks",        LINUX_RLIMIT_LOCKS },
 1348         { "Max pending signals", "signals",     LINUX_RLIMIT_SIGPENDING },
 1349         { "Max msgqueue size",  "bytes",        LINUX_RLIMIT_MSGQUEUE },
 1350         { "Max nice priority",          "",     LINUX_RLIMIT_NICE },
 1351         { "Max realtime priority",      "",     LINUX_RLIMIT_RTPRIO },
 1352         { "Max realtime timeout",       "us",   LINUX_RLIMIT_RTTIME },
 1353         { 0, 0, 0 }
 1354 };
 1355 
 1356 static int
 1357 linprocfs_doproclimits(PFS_FILL_ARGS)
 1358 {
 1359         const struct linux_rlimit_ident *li;
 1360         struct plimit *limp;
 1361         struct rlimit rl;
 1362         ssize_t size;
 1363         int res, error;
 1364 
 1365         error = 0;
 1366 
 1367         PROC_LOCK(p);
 1368         limp = lim_hold(p->p_limit);
 1369         PROC_UNLOCK(p);
 1370         size = sizeof(res);
 1371         sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit",
 1372                         "Hard Limit", "Units");
 1373         for (li = linux_rlimits_ident; li->desc != NULL; ++li) {
 1374                 switch (li->rlim_id)
 1375                 {
 1376                 case LINUX_RLIMIT_LOCKS:
 1377                         /* FALLTHROUGH */
 1378                 case LINUX_RLIMIT_RTTIME:
 1379                         rl.rlim_cur = RLIM_INFINITY;
 1380                         break;
 1381                 case LINUX_RLIMIT_SIGPENDING:
 1382                         error = kernel_sysctlbyname(td,
 1383                             "kern.sigqueue.max_pending_per_proc",
 1384                             &res, &size, 0, 0, 0, 0);
 1385                         if (error != 0)
 1386                                 goto out;
 1387                         rl.rlim_cur = res;
 1388                         rl.rlim_max = res;
 1389                         break;
 1390                 case LINUX_RLIMIT_MSGQUEUE:
 1391                         error = kernel_sysctlbyname(td,
 1392                             "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
 1393                         if (error != 0)
 1394                                 goto out;
 1395                         rl.rlim_cur = res;
 1396                         rl.rlim_max = res;
 1397                         break;
 1398                 case LINUX_RLIMIT_NICE:
 1399                         /* FALLTHROUGH */
 1400                 case LINUX_RLIMIT_RTPRIO:
 1401                         rl.rlim_cur = 0;
 1402                         rl.rlim_max = 0;
 1403                         break;
 1404                 default:
 1405                         rl = limp->pl_rlimit[li->rlim_id];
 1406                         break;
 1407                 }
 1408                 if (rl.rlim_cur == RLIM_INFINITY)
 1409                         sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
 1410                             li->desc, "unlimited", "unlimited", li->unit);
 1411                 else
 1412                         sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n",
 1413                             li->desc, (unsigned long long)rl.rlim_cur,
 1414                             (unsigned long long)rl.rlim_max, li->unit);
 1415         }
 1416 out:
 1417         lim_free(limp);
 1418         return (error);
 1419 }
 1420 
 1421 /*
 1422  * Filler function for proc/sys/kernel/random/uuid
 1423  */
 1424 static int
 1425 linprocfs_douuid(PFS_FILL_ARGS)
 1426 {
 1427         struct uuid uuid;
 1428 
 1429         kern_uuidgen(&uuid, 1);
 1430         sbuf_printf_uuid(sb, &uuid);
 1431         sbuf_printf(sb, "\n");
 1432         return(0);
 1433 }
 1434 
 1435 /*
 1436  * Filler function for proc/pid/auxv
 1437  */
 1438 static int
 1439 linprocfs_doauxv(PFS_FILL_ARGS)
 1440 {
 1441         struct sbuf *asb;
 1442         off_t buflen, resid;
 1443         int error;
 1444 
 1445         /*
 1446          * Mimic linux behavior and pass only processes with usermode
 1447          * address space as valid. Return zero silently otherwise.
 1448          */
 1449         if (p->p_vmspace == &vmspace0)
 1450                 return (0);
 1451 
 1452         if (uio->uio_resid == 0)
 1453                 return (0);
 1454         if (uio->uio_offset < 0 || uio->uio_resid < 0)
 1455                 return (EINVAL);
 1456 
 1457         asb = sbuf_new_auto();
 1458         if (asb == NULL)
 1459                 return (ENOMEM);
 1460         error = proc_getauxv(td, p, asb);
 1461         if (error == 0)
 1462                 error = sbuf_finish(asb);
 1463 
 1464         resid = sbuf_len(asb) - uio->uio_offset;
 1465         if (resid > uio->uio_resid)
 1466                 buflen = uio->uio_resid;
 1467         else
 1468                 buflen = resid;
 1469         if (buflen > IOSIZE_MAX)
 1470                 return (EINVAL);
 1471         if (buflen > MAXPHYS)
 1472                 buflen = MAXPHYS;
 1473         if (resid <= 0)
 1474                 return (0);
 1475 
 1476         if (error == 0)
 1477                 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
 1478         sbuf_delete(asb);
 1479         return (error);
 1480 }
 1481 
 1482 /*
 1483  * Constructor
 1484  */
 1485 static int
 1486 linprocfs_init(PFS_INIT_ARGS)
 1487 {
 1488         struct pfs_node *root;
 1489         struct pfs_node *dir;
 1490 
 1491         root = pi->pi_root;
 1492 
 1493         /* /proc/... */
 1494         pfs_create_file(root, "cmdline", &linprocfs_docmdline,
 1495             NULL, NULL, NULL, PFS_RD);
 1496         pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
 1497             NULL, NULL, NULL, PFS_RD);
 1498         pfs_create_file(root, "devices", &linprocfs_dodevices,
 1499             NULL, NULL, NULL, PFS_RD);
 1500         pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
 1501             NULL, NULL, NULL, PFS_RD);
 1502         pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
 1503             NULL, NULL, NULL, PFS_RD);
 1504         pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
 1505             NULL, NULL, NULL, PFS_RD);
 1506 #if 0
 1507         pfs_create_file(root, "modules", &linprocfs_domodules,
 1508             NULL, NULL, NULL, PFS_RD);
 1509 #endif
 1510         pfs_create_file(root, "mounts", &linprocfs_domtab,
 1511             NULL, NULL, NULL, PFS_RD);
 1512         pfs_create_file(root, "mtab", &linprocfs_domtab,
 1513             NULL, NULL, NULL, PFS_RD);
 1514         pfs_create_file(root, "partitions", &linprocfs_dopartitions,
 1515             NULL, NULL, NULL, PFS_RD);
 1516         pfs_create_link(root, "self", &procfs_docurproc,
 1517             NULL, NULL, NULL, 0);
 1518         pfs_create_file(root, "stat", &linprocfs_dostat,
 1519             NULL, NULL, NULL, PFS_RD);
 1520         pfs_create_file(root, "swaps", &linprocfs_doswaps,
 1521             NULL, NULL, NULL, PFS_RD);
 1522         pfs_create_file(root, "uptime", &linprocfs_douptime,
 1523             NULL, NULL, NULL, PFS_RD);
 1524         pfs_create_file(root, "version", &linprocfs_doversion,
 1525             NULL, NULL, NULL, PFS_RD);
 1526 
 1527         /* /proc/net/... */
 1528         dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
 1529         pfs_create_file(dir, "dev", &linprocfs_donetdev,
 1530             NULL, NULL, NULL, PFS_RD);
 1531 
 1532         /* /proc/<pid>/... */
 1533         dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
 1534         pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
 1535             NULL, NULL, NULL, PFS_RD);
 1536         pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
 1537             NULL, NULL, NULL, 0);
 1538         pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
 1539             NULL, &procfs_candebug, NULL, PFS_RD);
 1540         pfs_create_link(dir, "exe", &procfs_doprocfile,
 1541             NULL, &procfs_notsystem, NULL, 0);
 1542         pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
 1543             NULL, NULL, NULL, PFS_RD);
 1544         pfs_create_file(dir, "mem", &procfs_doprocmem,
 1545             &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
 1546         pfs_create_file(dir, "mounts", &linprocfs_domtab,
 1547             NULL, NULL, NULL, PFS_RD);
 1548         pfs_create_link(dir, "root", &linprocfs_doprocroot,
 1549             NULL, NULL, NULL, 0);
 1550         pfs_create_file(dir, "stat", &linprocfs_doprocstat,
 1551             NULL, NULL, NULL, PFS_RD);
 1552         pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
 1553             NULL, NULL, NULL, PFS_RD);
 1554         pfs_create_file(dir, "status", &linprocfs_doprocstatus,
 1555             NULL, NULL, NULL, PFS_RD);
 1556         pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
 1557             NULL, NULL, NULL, 0);
 1558         pfs_create_file(dir, "auxv", &linprocfs_doauxv,
 1559             NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
 1560         pfs_create_file(dir, "limits", &linprocfs_doproclimits,
 1561             NULL, NULL, NULL, PFS_RD);
 1562 
 1563         /* /proc/scsi/... */
 1564         dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
 1565         pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
 1566             NULL, NULL, NULL, PFS_RD);
 1567         pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
 1568             NULL, NULL, NULL, PFS_RD);
 1569 
 1570         /* /proc/sys/... */
 1571         dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
 1572         /* /proc/sys/kernel/... */
 1573         dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
 1574         pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
 1575             NULL, NULL, NULL, PFS_RD);
 1576         pfs_create_file(dir, "ostype", &linprocfs_doostype,
 1577             NULL, NULL, NULL, PFS_RD);
 1578         pfs_create_file(dir, "version", &linprocfs_doosbuild,
 1579             NULL, NULL, NULL, PFS_RD);
 1580         pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
 1581             NULL, NULL, NULL, PFS_RD);
 1582         pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
 1583             NULL, NULL, NULL, PFS_RD);
 1584         pfs_create_file(dir, "sem", &linprocfs_dosem,
 1585             NULL, NULL, NULL, PFS_RD);
 1586 
 1587         /* /proc/sys/kernel/random/... */
 1588         dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
 1589         pfs_create_file(dir, "uuid", &linprocfs_douuid,
 1590             NULL, NULL, NULL, PFS_RD);
 1591 
 1592         return (0);
 1593 }
 1594 
 1595 /*
 1596  * Destructor
 1597  */
 1598 static int
 1599 linprocfs_uninit(PFS_INIT_ARGS)
 1600 {
 1601 
 1602         /* nothing to do, pseudofs will GC */
 1603         return (0);
 1604 }
 1605 
 1606 PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS);
 1607 #if defined(__amd64__)
 1608 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
 1609 #else
 1610 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
 1611 #endif
 1612 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
 1613 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
 1614 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);

Cache object: 6da0b10a52e76070f97b009848b7b77f


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