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

Cache object: 049c7baeb61c526dd42dd364ed627690


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