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


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

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

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

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

Cache object: 2bb9d838f00ab5faac448015fb0872ac


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