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


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

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

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

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

Cache object: 32bb4fbd2ea2f4a765003b9abeca7a98


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