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

Cache object: 3c91ce7de2cbb53d097a8678ad564f53


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