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/5.2/sys/compat/linprocfs/linprocfs.c 138283 2004-12-01 21:34:43Z cperciva $");
   44 
   45 #include <sys/param.h>
   46 #include <sys/queue.h>
   47 #include <sys/blist.h>
   48 #include <sys/conf.h>
   49 #include <sys/exec.h>
   50 #include <sys/filedesc.h>
   51 #include <sys/jail.h>
   52 #include <sys/kernel.h>
   53 #include <sys/linker.h>
   54 #include <sys/lock.h>
   55 #include <sys/malloc.h>
   56 #include <sys/mount.h>
   57 #include <sys/mutex.h>
   58 #include <sys/namei.h>
   59 #include <sys/proc.h>
   60 #include <sys/resourcevar.h>
   61 #include <sys/sbuf.h>
   62 #include <sys/socket.h>
   63 #include <sys/sysctl.h>
   64 #include <sys/systm.h>
   65 #include <sys/tty.h>
   66 #include <sys/user.h>
   67 #include <sys/vmmeter.h>
   68 #include <sys/vnode.h>
   69 
   70 #include <net/if.h>
   71 
   72 #include <vm/vm.h>
   73 #include <vm/pmap.h>
   74 #include <vm/vm_map.h>
   75 #include <vm/vm_param.h>
   76 #include <vm/vm_object.h>
   77 #include <vm/swap_pager.h>
   78 
   79 #include <machine/clock.h>
   80 
   81 #ifdef __alpha__
   82 #include <machine/alpha_cpu.h>
   83 #include <machine/cpuconf.h>
   84 #include <machine/rpb.h>
   85 extern int ncpus;
   86 #endif /* __alpha__ */
   87 
   88 #ifdef __i386__
   89 #include <machine/cputypes.h>
   90 #include <machine/md_var.h>
   91 #endif /* __i386__ */
   92 
   93 #include <machine/../linux/linux.h>
   94 #include <compat/linux/linux_ioctl.h>
   95 #include <compat/linux/linux_mib.h>
   96 #include <compat/linux/linux_util.h>
   97 #include <fs/pseudofs/pseudofs.h>
   98 #include <fs/procfs/procfs.h>
   99 
  100 /*
  101  * Various conversion macros
  102  */
  103 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */
  104 #define T2S(x) ((x) / (stathz ? stathz : hz))           /* ticks to seconds */
  105 #define B2K(x) ((x) >> 10)                              /* bytes to kbytes */
  106 #define B2P(x) ((x) >> PAGE_SHIFT)                      /* bytes to pages */
  107 #define P2B(x) ((x) << PAGE_SHIFT)                      /* pages to bytes */
  108 #define P2K(x) ((x) << (PAGE_SHIFT - 10))               /* pages to kbytes */
  109 
  110 /*
  111  * Filler function for proc/meminfo
  112  */
  113 static int
  114 linprocfs_domeminfo(PFS_FILL_ARGS)
  115 {
  116         unsigned long memtotal;         /* total memory in bytes */
  117         unsigned long memused;          /* used memory in bytes */
  118         unsigned long memfree;          /* free memory in bytes */
  119         unsigned long memshared;        /* shared memory ??? */
  120         unsigned long buffers, cached;  /* buffer / cache memory ??? */
  121         unsigned long long swaptotal;   /* total swap space in bytes */
  122         unsigned long long swapused;    /* used swap space in bytes */
  123         unsigned long long swapfree;    /* free swap space in bytes */
  124         vm_object_t object;
  125         int i, j;
  126 
  127         memtotal = physmem * PAGE_SIZE;
  128         /*
  129          * The correct thing here would be:
  130          *
  131         memfree = cnt.v_free_count * PAGE_SIZE;
  132         memused = memtotal - memfree;
  133          *
  134          * but it might mislead linux binaries into thinking there
  135          * is very little memory left, so we cheat and tell them that
  136          * all memory that isn't wired down is free.
  137          */
  138         memused = cnt.v_wire_count * PAGE_SIZE;
  139         memfree = memtotal - memused;
  140         swap_pager_status(&i, &j);
  141         swaptotal = i * PAGE_SIZE;
  142         swapused = j * PAGE_SIZE;
  143         swapfree = swaptotal - swapused;
  144         memshared = 0;
  145         TAILQ_FOREACH(object, &vm_object_list, object_list)
  146                 if (object->shadow_count > 1)
  147                         memshared += object->resident_page_count;
  148         memshared *= PAGE_SIZE;
  149         /*
  150          * We'd love to be able to write:
  151          *
  152         buffers = bufspace;
  153          *
  154          * but bufspace is internal to vfs_bio.c and we don't feel
  155          * like unstaticizing it just for linprocfs's sake.
  156          */
  157         buffers = 0;
  158         cached = cnt.v_cache_count * PAGE_SIZE;
  159 
  160         sbuf_printf(sb,
  161             "        total:    used:    free:  shared: buffers:  cached:\n"
  162             "Mem:  %lu %lu %lu %lu %lu %lu\n"
  163             "Swap: %llu %llu %llu\n"
  164             "MemTotal: %9lu kB\n"
  165             "MemFree:  %9lu kB\n"
  166             "MemShared:%9lu kB\n"
  167             "Buffers:  %9lu kB\n"
  168             "Cached:   %9lu kB\n"
  169             "SwapTotal:%9llu kB\n"
  170             "SwapFree: %9llu kB\n",
  171             memtotal, memused, memfree, memshared, buffers, cached,
  172             swaptotal, swapused, swapfree,
  173             B2K(memtotal), B2K(memfree),
  174             B2K(memshared), B2K(buffers), B2K(cached),
  175             B2K(swaptotal), B2K(swapfree));
  176 
  177         return (0);
  178 }
  179 
  180 #ifdef __alpha__
  181 extern struct rpb *hwrpb;
  182 /*
  183  * Filler function for proc/cpuinfo (Alpha version)
  184  */
  185 static int
  186 linprocfs_docpuinfo(PFS_FILL_ARGS)
  187 {
  188         u_int64_t type, major;
  189         struct pcs *pcsp;
  190         const char *model, *sysname;
  191 
  192         static const char *cpuname[] = {
  193                 "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
  194                 "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
  195         };
  196 
  197         pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
  198         type = pcsp->pcs_proc_type;
  199         major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
  200         if (major < sizeof(cpuname)/sizeof(char *)) {
  201                 model = cpuname[major - 1];
  202         } else {
  203                 model = "unknown";
  204         }
  205 
  206         sysname = alpha_dsr_sysname();
  207 
  208         sbuf_printf(sb,
  209             "cpu\t\t\t: Alpha\n"
  210             "cpu model\t\t: %s\n"
  211             "cpu variation\t\t: %ld\n"
  212             "cpu revision\t\t: %d\n"
  213             "cpu serial number\t: %s\n"
  214             "system type\t\t: %s\n"
  215             "system variation\t: %s\n"
  216             "system revision\t\t: %d\n"
  217             "system serial number\t: %s\n"
  218             "cycle frequency [Hz]\t: %lu\n"
  219             "timer frequency [Hz]\t: %u\n"
  220             "page size [bytes]\t: %ld\n"
  221             "phys. address bits\t: %ld\n"
  222             "max. addr. space #\t: %ld\n"
  223             "BogoMIPS\t\t: %u.%02u\n"
  224             "kernel unaligned acc\t: %d (pc=%x,va=%x)\n"
  225             "user unaligned acc\t: %d (pc=%x,va=%x)\n"
  226             "platform string\t\t: %s\n"
  227             "cpus detected\t\t: %d\n"
  228             ,
  229             model,
  230             pcsp->pcs_proc_var,
  231             *(int *)hwrpb->rpb_revision,
  232             " ",
  233             " ",
  234             "",
  235             0,
  236             " ",
  237             hwrpb->rpb_cc_freq,
  238             hz,
  239             hwrpb->rpb_page_size,
  240             hwrpb->rpb_phys_addr_size,
  241             hwrpb->rpb_max_asn,
  242             0, 0,
  243             0, 0, 0,
  244             0, 0, 0,
  245             sysname,
  246             ncpus);
  247         return (0);
  248 }
  249 #endif /* __alpha__ */
  250 
  251 #ifdef __i386__
  252 /*
  253  * Filler function for proc/cpuinfo (i386 version)
  254  */
  255 static int
  256 linprocfs_docpuinfo(PFS_FILL_ARGS)
  257 {
  258         int class, fqmhz, fqkhz, ncpu;
  259         int name[2], olen, plen;
  260         int i;
  261 
  262         name[0] = CTL_HW;
  263         name[1] = HW_NCPU;
  264         if (kernel_sysctl(td, name, 2, &ncpu, &olen, NULL, 0, &plen) != 0)
  265                 ncpu = 1;
  266 
  267         /*
  268          * We default the flags to include all non-conflicting flags,
  269          * and the Intel versions of conflicting flags.
  270          */
  271         static char *flags[] = {
  272                 "fpu",      "vme",     "de",       "pse",      "tsc",
  273                 "msr",      "pae",     "mce",      "cx8",      "apic",
  274                 "sep",      "sep",     "mtrr",     "pge",      "mca",
  275                 "cmov",     "pat",     "pse36",    "pn",       "b19",
  276                 "b20",      "b21",     "mmxext",   "mmx",      "fxsr",
  277                 "xmm",      "b26",     "b27",      "b28",      "b29",
  278                 "3dnowext", "3dnow"
  279         };
  280 
  281         switch (cpu_class) {
  282         case CPUCLASS_286:
  283                 class = 2;
  284                 break;
  285         case CPUCLASS_386:
  286                 class = 3;
  287                 break;
  288         case CPUCLASS_486:
  289                 class = 4;
  290                 break;
  291         case CPUCLASS_586:
  292                 class = 5;
  293                 break;
  294         case CPUCLASS_686:
  295                 class = 6;
  296                 break;
  297         default:
  298                 class = 0;
  299                 break;
  300         }
  301 
  302         for (i = 0; i < ncpu; ++i) {
  303                 sbuf_printf(sb,
  304                     "processor\t: %d\n"
  305                     "vendor_id\t: %.20s\n"
  306                     "cpu family\t: %d\n"
  307                     "model\t\t: %d\n"
  308                     "stepping\t: %d\n",
  309                     i, cpu_vendor, class, cpu, cpu_id & 0xf);
  310                 /* XXX per-cpu vendor / class / id? */
  311         }
  312 
  313         sbuf_cat(sb,
  314             "flags\t\t:");
  315 
  316         if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
  317                 flags[16] = "fcmov";
  318         } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
  319                 flags[24] = "cxmmx";
  320         }
  321 
  322         for (i = 0; i < 32; i++)
  323                 if (cpu_feature & (1 << i))
  324                         sbuf_printf(sb, " %s", flags[i]);
  325         sbuf_cat(sb, "\n");
  326         if (class >= 5) {
  327                 fqmhz = (tsc_freq + 4999) / 1000000;
  328                 fqkhz = ((tsc_freq + 4999) / 10000) % 100;
  329                 sbuf_printf(sb,
  330                     "cpu MHz\t\t: %d.%02d\n"
  331                     "bogomips\t: %d.%02d\n",
  332                     fqmhz, fqkhz, fqmhz, fqkhz);
  333         }
  334 
  335         return (0);
  336 }
  337 #endif /* __i386__ */
  338 
  339 /*
  340  * Filler function for proc/mtab
  341  *
  342  * This file doesn't exist in Linux' procfs, but is included here so
  343  * users can symlink /compat/linux/etc/mtab to /proc/mtab
  344  */
  345 static int
  346 linprocfs_domtab(PFS_FILL_ARGS)
  347 {
  348         struct nameidata nd;
  349         struct mount *mp;
  350         const char *lep;
  351         char *dlep, *flep, *mntto, *mntfrom, *fstype;
  352         size_t lep_len;
  353         int error;
  354 
  355         /* resolve symlinks etc. in the emulation tree prefix */
  356         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
  357         flep = NULL;
  358         if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) == -1)
  359                 lep = linux_emul_path;
  360         else
  361                 lep = dlep;
  362         lep_len = strlen(lep);
  363 
  364         mtx_lock(&mountlist_mtx);
  365         error = 0;
  366         TAILQ_FOREACH(mp, &mountlist, mnt_list) {
  367                 error = VFS_STATFS(mp, &mp->mnt_stat, td);
  368                 if (error)
  369                         break;
  370 
  371                 /* determine device name */
  372                 mntfrom = mp->mnt_stat.f_mntfromname;
  373 
  374                 /* determine mount point */
  375                 mntto = mp->mnt_stat.f_mntonname;
  376                 if (strncmp(mntto, lep, lep_len) == 0 &&
  377                     mntto[lep_len] == '/')
  378                         mntto += lep_len;
  379 
  380                 /* determine fs type */
  381                 fstype = mp->mnt_stat.f_fstypename;
  382                 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
  383                         mntfrom = fstype = "proc";
  384                 else if (strcmp(fstype, "procfs") == 0)
  385                         continue;
  386 
  387                 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
  388                     mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
  389 #define ADD_OPTION(opt, name) \
  390         if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
  391                 ADD_OPTION(MNT_SYNCHRONOUS,     "sync");
  392                 ADD_OPTION(MNT_NOEXEC,          "noexec");
  393                 ADD_OPTION(MNT_NOSUID,          "nosuid");
  394                 ADD_OPTION(MNT_NODEV,           "nodev");
  395                 ADD_OPTION(MNT_UNION,           "union");
  396                 ADD_OPTION(MNT_ASYNC,           "async");
  397                 ADD_OPTION(MNT_SUIDDIR,         "suiddir");
  398                 ADD_OPTION(MNT_NOSYMFOLLOW,     "nosymfollow");
  399                 ADD_OPTION(MNT_NOATIME,         "noatime");
  400 #undef ADD_OPTION
  401                 /* a real Linux mtab will also show NFS options */
  402                 sbuf_printf(sb, " 0 0\n");
  403         }
  404         mtx_unlock(&mountlist_mtx);
  405         if (flep != NULL)
  406                 free(flep, M_TEMP);
  407         return (error);
  408 }
  409 
  410 /*
  411  * Filler function for proc/stat
  412  */
  413 static int
  414 linprocfs_dostat(PFS_FILL_ARGS)
  415 {
  416         size_t olen, plen;
  417         int name[2];
  418         int i, ncpu;
  419 
  420         name[0] = CTL_HW;
  421         name[1] = HW_NCPU;
  422         if (kernel_sysctl(td, name, 2, &ncpu, &olen, NULL, 0, &plen) != 0)
  423                 ncpu = 1;
  424         sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
  425             T2J(cp_time[CP_USER]),
  426             T2J(cp_time[CP_NICE]),
  427             T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
  428             T2J(cp_time[CP_IDLE]));
  429         if (ncpu > 1)
  430                 for (i = 0; i < ncpu; ++i)
  431                         sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
  432                             T2J(cp_time[CP_USER]) / ncpu,
  433                             T2J(cp_time[CP_NICE]) / ncpu,
  434                             T2J(cp_time[CP_SYS]) / ncpu,
  435                             T2J(cp_time[CP_IDLE]) / ncpu);
  436         sbuf_printf(sb,
  437             "disk 0 0 0 0\n"
  438             "page %u %u\n"
  439             "swap %u %u\n"
  440             "intr %u\n"
  441             "ctxt %u\n"
  442             "btime %lld\n",
  443             cnt.v_vnodepgsin,
  444             cnt.v_vnodepgsout,
  445             cnt.v_swappgsin,
  446             cnt.v_swappgsout,
  447             cnt.v_intr,
  448             cnt.v_swtch,
  449             (long long)boottime.tv_sec);
  450         return (0);
  451 }
  452 
  453 /*
  454  * Filler function for proc/uptime
  455  */
  456 static int
  457 linprocfs_douptime(PFS_FILL_ARGS)
  458 {
  459         struct timeval tv;
  460 
  461         getmicrouptime(&tv);
  462         sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
  463             (long long)tv.tv_sec, tv.tv_usec / 10000,
  464             T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
  465         return (0);
  466 }
  467 
  468 /*
  469  * Filler function for proc/version
  470  */
  471 static int
  472 linprocfs_doversion(PFS_FILL_ARGS)
  473 {
  474         char osname[LINUX_MAX_UTSNAME];
  475         char osrelease[LINUX_MAX_UTSNAME];
  476 
  477         linux_get_osname(td, osname);
  478         linux_get_osrelease(td, osrelease);
  479 
  480         sbuf_printf(sb,
  481             "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
  482             " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
  483         return (0);
  484 }
  485 
  486 /*
  487  * Filler function for proc/loadavg
  488  */
  489 static int
  490 linprocfs_doloadavg(PFS_FILL_ARGS)
  491 {
  492         sbuf_printf(sb,
  493             "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
  494             (int)(averunnable.ldavg[0] / averunnable.fscale),
  495             (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
  496             (int)(averunnable.ldavg[1] / averunnable.fscale),
  497             (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
  498             (int)(averunnable.ldavg[2] / averunnable.fscale),
  499             (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
  500             1,                          /* number of running tasks */
  501             nprocs,                     /* number of tasks */
  502             lastpid                     /* the last pid */
  503         );
  504 
  505         return (0);
  506 }
  507 
  508 /*
  509  * Filler function for proc/pid/stat
  510  */
  511 static int
  512 linprocfs_doprocstat(PFS_FILL_ARGS)
  513 {
  514         struct kinfo_proc kp;
  515 
  516         PROC_LOCK(p);
  517         fill_kinfo_proc(p, &kp);
  518         sbuf_printf(sb, "%d", p->p_pid);
  519 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
  520         PS_ADD("comm",          "(%s)", p->p_comm);
  521         PS_ADD("statr",         "%c",   ''); /* XXX */
  522         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
  523         PS_ADD("pgrp",          "%d",   p->p_pgid);
  524         PS_ADD("session",       "%d",   p->p_session->s_sid);
  525         PROC_UNLOCK(p);
  526         PS_ADD("tty",           "%d",   0); /* XXX */
  527         PS_ADD("tpgid",         "%d",   0); /* XXX */
  528         PS_ADD("flags",         "%u",   0); /* XXX */
  529         PS_ADD("minflt",        "%u",   0); /* XXX */
  530         PS_ADD("cminflt",       "%u",   0); /* XXX */
  531         PS_ADD("majflt",        "%u",   0); /* XXX */
  532         PS_ADD("cminflt",       "%u",   0); /* XXX */
  533         PS_ADD("utime",         "%d",   0); /* XXX */
  534         PS_ADD("stime",         "%d",   0); /* XXX */
  535         PS_ADD("cutime",        "%d",   0); /* XXX */
  536         PS_ADD("cstime",        "%d",   0); /* XXX */
  537         PS_ADD("counter",       "%d",   0); /* XXX */
  538         PS_ADD("priority",      "%d",   0); /* XXX */
  539         PS_ADD("timeout",       "%u",   0); /* XXX */
  540         PS_ADD("itrealvalue",   "%u",   0); /* XXX */
  541         PS_ADD("starttime",     "%d",   0); /* XXX */
  542         PS_ADD("vsize",         "%ju",  (uintmax_t)kp.ki_size);
  543         PS_ADD("rss",           "%ju",  P2K((uintmax_t)kp.ki_rssize));
  544         PS_ADD("rlim",          "%u",   0); /* XXX */
  545         PS_ADD("startcode",     "%u",   (unsigned)0);
  546         PS_ADD("endcode",       "%u",   0); /* XXX */
  547         PS_ADD("startstack",    "%u",   0); /* XXX */
  548         PS_ADD("esp",           "%u",   0); /* XXX */
  549         PS_ADD("eip",           "%u",   0); /* XXX */
  550         PS_ADD("signal",        "%d",   0); /* XXX */
  551         PS_ADD("blocked",       "%d",   0); /* XXX */
  552         PS_ADD("sigignore",     "%d",   0); /* XXX */
  553         PS_ADD("sigcatch",      "%d",   0); /* XXX */
  554         PS_ADD("wchan",         "%u",   0); /* XXX */
  555         PS_ADD("nswap",         "%lu",  (long unsigned)0); /* XXX */
  556         PS_ADD("cnswap",        "%lu",  (long unsigned)0); /* XXX */
  557         PS_ADD("exitsignal",    "%d",   0); /* XXX */
  558         PS_ADD("processor",     "%d",   0); /* XXX */
  559 #undef PS_ADD
  560         sbuf_putc(sb, '\n');
  561 
  562         return (0);
  563 }
  564 
  565 /*
  566  * Filler function for proc/pid/statm
  567  */
  568 static int
  569 linprocfs_doprocstatm(PFS_FILL_ARGS)
  570 {
  571         struct kinfo_proc kp;
  572         segsz_t lsize;
  573 
  574         PROC_LOCK(p);
  575         fill_kinfo_proc(p, &kp);
  576         PROC_UNLOCK(p);
  577 
  578         /*
  579          * See comments in linprocfs_doprocstatus() regarding the
  580          * computation of lsize.
  581          */
  582         /* size resident share trs drs lrs dt */
  583         sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
  584         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
  585         sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
  586         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
  587         sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
  588         lsize = B2P(kp.ki_size) - kp.ki_dsize -
  589             kp.ki_ssize - kp.ki_tsize - 1;
  590         sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
  591         sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
  592 
  593         return (0);
  594 }
  595 
  596 /*
  597  * Filler function for proc/pid/status
  598  */
  599 static int
  600 linprocfs_doprocstatus(PFS_FILL_ARGS)
  601 {
  602         struct kinfo_proc kp;
  603         char *state;
  604         segsz_t lsize;
  605         struct thread *td2;
  606         struct sigacts *ps;
  607         int i;
  608 
  609         PROC_LOCK(p);
  610         td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
  611 
  612         if (P_SHOULDSTOP(p)) {
  613                 state = "T (stopped)";
  614         } else {
  615                 mtx_lock_spin(&sched_lock);
  616                 switch(p->p_state) {
  617                 case PRS_NEW:
  618                         state = "I (idle)";
  619                         break;
  620                 case PRS_NORMAL:
  621                         if (p->p_flag & P_WEXIT) {
  622                                 state = "X (exiting)";
  623                                 break;
  624                         }
  625                         switch(td2->td_state) {
  626                         case TDS_INHIBITED:
  627                                 state = "S (sleeping)";
  628                                 break;
  629                         case TDS_RUNQ:
  630                         case TDS_RUNNING:
  631                                 state = "R (running)";
  632                                 break;
  633                         default:
  634                                 state = "? (unknown)";
  635                                 break;
  636                         }
  637                         break;
  638                 case PRS_ZOMBIE:
  639                         state = "Z (zombie)";
  640                         break;
  641                 default:
  642                         state = "? (unknown)";
  643                         break;
  644                 }
  645                 mtx_unlock_spin(&sched_lock);
  646         }
  647 
  648         fill_kinfo_proc(p, &kp);
  649         sbuf_printf(sb, "Name:\t%s\n",          p->p_comm); /* XXX escape */
  650         sbuf_printf(sb, "State:\t%s\n",         state);
  651 
  652         /*
  653          * Credentials
  654          */
  655         sbuf_printf(sb, "Pid:\t%d\n",           p->p_pid);
  656         sbuf_printf(sb, "PPid:\t%d\n",          p->p_pptr ?
  657                                                 p->p_pptr->p_pid : 0);
  658         sbuf_printf(sb, "Uid:\t%d %d %d %d\n",  p->p_ucred->cr_ruid,
  659                                                 p->p_ucred->cr_uid,
  660                                                 p->p_ucred->cr_svuid,
  661                                                 /* FreeBSD doesn't have fsuid */
  662                                                 p->p_ucred->cr_uid);
  663         sbuf_printf(sb, "Gid:\t%d %d %d %d\n",  p->p_ucred->cr_rgid,
  664                                                 p->p_ucred->cr_gid,
  665                                                 p->p_ucred->cr_svgid,
  666                                                 /* FreeBSD doesn't have fsgid */
  667                                                 p->p_ucred->cr_gid);
  668         sbuf_cat(sb, "Groups:\t");
  669         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
  670                 sbuf_printf(sb, "%d ",          p->p_ucred->cr_groups[i]);
  671         PROC_UNLOCK(p);
  672         sbuf_putc(sb, '\n');
  673 
  674         /*
  675          * Memory
  676          *
  677          * While our approximation of VmLib may not be accurate (I
  678          * don't know of a simple way to verify it, and I'm not sure
  679          * it has much meaning anyway), I believe it's good enough.
  680          *
  681          * The same code that could (I think) accurately compute VmLib
  682          * could also compute VmLck, but I don't really care enough to
  683          * implement it. Submissions are welcome.
  684          */
  685         sbuf_printf(sb, "VmSize:\t%8ju kB\n",   B2K((uintmax_t)kp.ki_size));
  686         sbuf_printf(sb, "VmLck:\t%8u kB\n",     P2K(0)); /* XXX */
  687         sbuf_printf(sb, "VmRss:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_rssize));
  688         sbuf_printf(sb, "VmData:\t%8ju kB\n",   P2K((uintmax_t)kp.ki_dsize));
  689         sbuf_printf(sb, "VmStk:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_ssize));
  690         sbuf_printf(sb, "VmExe:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_tsize));
  691         lsize = B2P(kp.ki_size) - kp.ki_dsize -
  692             kp.ki_ssize - kp.ki_tsize - 1;
  693         sbuf_printf(sb, "VmLib:\t%8ju kB\n",    P2K((uintmax_t)lsize));
  694 
  695         /*
  696          * Signal masks
  697          *
  698          * We support up to 128 signals, while Linux supports 32,
  699          * but we only define 32 (the same 32 as Linux, to boot), so
  700          * just show the lower 32 bits of each mask. XXX hack.
  701          *
  702          * NB: on certain platforms (Sparc at least) Linux actually
  703          * supports 64 signals, but this code is a long way from
  704          * running on anything but i386, so ignore that for now.
  705          */
  706         PROC_LOCK(p);
  707         sbuf_printf(sb, "SigPnd:\t%08x\n",      p->p_siglist.__bits[0]);
  708         /*
  709          * I can't seem to find out where the signal mask is in
  710          * relation to struct proc, so SigBlk is left unimplemented.
  711          */
  712         sbuf_printf(sb, "SigBlk:\t%08x\n",      0); /* XXX */
  713         ps = p->p_sigacts;
  714         mtx_lock(&ps->ps_mtx);
  715         sbuf_printf(sb, "SigIgn:\t%08x\n",      ps->ps_sigignore.__bits[0]);
  716         sbuf_printf(sb, "SigCgt:\t%08x\n",      ps->ps_sigcatch.__bits[0]);
  717         mtx_unlock(&ps->ps_mtx);
  718         PROC_UNLOCK(p);
  719 
  720         /*
  721          * Linux also prints the capability masks, but we don't have
  722          * capabilities yet, and when we do get them they're likely to
  723          * be meaningless to Linux programs, so we lie. XXX
  724          */
  725         sbuf_printf(sb, "CapInh:\t%016x\n",     0);
  726         sbuf_printf(sb, "CapPrm:\t%016x\n",     0);
  727         sbuf_printf(sb, "CapEff:\t%016x\n",     0);
  728 
  729         return (0);
  730 }
  731 
  732 
  733 /*
  734  * Filler function for proc/pid/cwd
  735  */
  736 static int
  737 linprocfs_doproccwd(PFS_FILL_ARGS)
  738 {
  739         char *fullpath = "unknown";
  740         char *freepath = NULL;
  741 
  742         vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
  743         sbuf_printf(sb, "%s", fullpath);
  744         if (freepath)
  745                 free(freepath, M_TEMP);
  746         return (0);
  747 }
  748 
  749 /*
  750  * Filler function for proc/pid/root
  751  */
  752 static int
  753 linprocfs_doprocroot(PFS_FILL_ARGS)
  754 {
  755         struct vnode *rvp;
  756         char *fullpath = "unknown";
  757         char *freepath = NULL;
  758 
  759         rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
  760         vn_fullpath(td, rvp, &fullpath, &freepath);
  761         sbuf_printf(sb, "%s", fullpath);
  762         if (freepath)
  763                 free(freepath, M_TEMP);
  764         return (0);
  765 }
  766 
  767 /*
  768  * Filler function for proc/pid/cmdline
  769  */
  770 static int
  771 linprocfs_doproccmdline(PFS_FILL_ARGS)
  772 {
  773         struct ps_strings pstr;
  774         char **ps_argvstr;
  775         int error, i;
  776 
  777         /*
  778          * If we are using the ps/cmdline caching, use that.  Otherwise
  779          * revert back to the old way which only implements full cmdline
  780          * for the currept process and just p->p_comm for all other
  781          * processes.
  782          * Note that if the argv is no longer available, we deliberately
  783          * don't fall back on p->p_comm or return an error: the authentic
  784          * Linux behaviour is to return zero-length in this case.
  785          */
  786 
  787         PROC_LOCK(p);
  788         if (p->p_args && (ps_argsopen || !p_cansee(td, p))) {
  789                 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
  790                 PROC_UNLOCK(p);
  791         } else if (p != td->td_proc) {
  792                 PROC_UNLOCK(p);
  793                 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
  794         } else {
  795                 PROC_UNLOCK(p);
  796                 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
  797                     sizeof(pstr));
  798                 if (error)
  799                         return (error);
  800                 if (pstr.ps_nargvstr > ARG_MAX)
  801                         return (E2BIG);
  802                 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
  803                     M_TEMP, M_WAITOK);
  804                 error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
  805                     pstr.ps_nargvstr * sizeof(char *));
  806                 if (error) {
  807                         free(ps_argvstr, M_TEMP);
  808                         return (error);
  809                 }
  810                 for (i = 0; i < pstr.ps_nargvstr; i++) {
  811                         sbuf_copyin(sb, ps_argvstr[i], 0);
  812                         sbuf_printf(sb, "%c", '\0');
  813                 }
  814                 free(ps_argvstr, M_TEMP);
  815         }
  816 
  817         return (0);
  818 }
  819 
  820 /*
  821  * Filler function for proc/pid/environ
  822  */
  823 static int
  824 linprocfs_doprocenviron(PFS_FILL_ARGS)
  825 {
  826         sbuf_printf(sb, "doprocenviron\n%c", '\0');
  827 
  828         return (0);
  829 }
  830 
  831 /*
  832  * Filler function for proc/pid/maps
  833  */
  834 static int
  835 linprocfs_doprocmaps(PFS_FILL_ARGS)
  836 {
  837         char mebuffer[512];
  838         vm_map_t map = &p->p_vmspace->vm_map;
  839         vm_map_entry_t entry;
  840         vm_object_t obj, tobj, lobj;
  841         vm_ooffset_t off = 0;
  842         char *name = "", *freename = NULL;
  843         size_t len;
  844         ino_t ino;
  845         int ref_count, shadow_count, flags;
  846         int error;
  847         
  848         PROC_LOCK(p);
  849         error = p_candebug(td, p);
  850         PROC_UNLOCK(p);
  851         if (error)
  852                 return (error);
  853         
  854         if (uio->uio_rw != UIO_READ)
  855                 return (EOPNOTSUPP);
  856         
  857         if (uio->uio_offset != 0)
  858                 return (0);
  859         
  860         error = 0;
  861         if (map != &curthread->td_proc->p_vmspace->vm_map)
  862                 vm_map_lock_read(map);
  863         for (entry = map->header.next;
  864             ((uio->uio_resid > 0) && (entry != &map->header));
  865             entry = entry->next) {
  866                 name = "";
  867                 freename = NULL;
  868                 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
  869                         continue;
  870                 obj = entry->object.vm_object;
  871                 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
  872                         lobj = tobj;
  873                 ino = 0;
  874                 if (lobj) {
  875                         VM_OBJECT_LOCK(lobj);
  876                         off = IDX_TO_OFF(lobj->size);
  877                         if (lobj->type == OBJT_VNODE && lobj->handle) {
  878                                 vn_fullpath(td, (struct vnode *)lobj->handle,
  879                                     &name, &freename);
  880                                 ino = ((struct vnode *)
  881                                     lobj->handle)->v_cachedid;
  882                         }
  883                         flags = obj->flags;
  884                         ref_count = obj->ref_count;
  885                         shadow_count = obj->shadow_count;
  886                         VM_OBJECT_UNLOCK(lobj);
  887                 } else {
  888                         flags = 0;
  889                         ref_count = 0;
  890                         shadow_count = 0;
  891                 }
  892                 
  893                 /*
  894                  * format:
  895                  *  start, end, access, offset, major, minor, inode, name.
  896                  */
  897                 snprintf(mebuffer, sizeof mebuffer,
  898                     "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
  899                     (u_long)entry->start, (u_long)entry->end,
  900                     (entry->protection & VM_PROT_READ)?"r":"-",
  901                     (entry->protection & VM_PROT_WRITE)?"w":"-",
  902                     (entry->protection & VM_PROT_EXECUTE)?"x":"-",
  903                     "p",
  904                     (u_long)off,
  905                     0,
  906                     0,
  907                     (u_long)ino,
  908                     *name ? "     " : "",
  909                     name
  910                     );
  911                 if (freename)
  912                         free(freename, M_TEMP);
  913                 len = strlen(mebuffer);
  914                 if (len > uio->uio_resid)
  915                         len = uio->uio_resid; /*
  916                                                * XXX We should probably return
  917                                                * EFBIG here, as in procfs.
  918                                                */
  919                 error = uiomove(mebuffer, len, uio);
  920                 if (error)
  921                         break;
  922         }
  923         if (map != &curthread->td_proc->p_vmspace->vm_map)
  924                 vm_map_unlock_read(map);
  925         
  926         return (error);
  927 }       
  928         
  929 /*
  930  * Filler function for proc/net/dev
  931  */
  932 static int
  933 linprocfs_donetdev(PFS_FILL_ARGS)
  934 {
  935         char ifname[16]; /* XXX LINUX_IFNAMSIZ */
  936         struct ifnet *ifp;
  937 
  938         sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
  939             "Inter-", "   Receive", "  Transmit", " face",
  940             "bytes    packets errs drop fifo frame compressed",
  941             "bytes    packets errs drop fifo frame compressed");
  942 
  943         IFNET_RLOCK();
  944         TAILQ_FOREACH(ifp, &ifnet, if_link) {
  945                 linux_ifname(ifp, ifname, sizeof ifname);
  946                         sbuf_printf(sb, "%6.6s:", ifname);
  947                 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
  948                     0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
  949                 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
  950                     0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
  951         }
  952         IFNET_RUNLOCK();
  953 
  954         return (0);
  955 }
  956 
  957 #if 0
  958 extern struct cdevsw *cdevsw[];
  959 
  960 /*
  961  * Filler function for proc/devices
  962  */
  963 static int
  964 linprocfs_dodevices(PFS_FILL_ARGS)
  965 {
  966         int i;
  967 
  968         sbuf_printf(sb, "Character devices:\n");
  969 
  970         for (i = 0; i < NUMCDEVSW; i++)
  971                 if (cdevsw[i] != NULL)
  972                         sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
  973 
  974         sbuf_printf(sb, "\nBlock devices:\n");
  975 
  976         return (0);
  977 }
  978 #endif
  979 
  980 /*
  981  * Filler function for proc/cmdline
  982  */
  983 static int
  984 linprocfs_docmdline(PFS_FILL_ARGS)
  985 {
  986         sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
  987         sbuf_printf(sb, " ro root=302\n");
  988         return (0);
  989 }
  990 
  991 #if 0
  992 /*
  993  * Filler function for proc/modules
  994  */
  995 static int
  996 linprocfs_domodules(PFS_FILL_ARGS)
  997 {
  998         struct linker_file *lf;
  999 
 1000         TAILQ_FOREACH(lf, &linker_files, link) {
 1001                 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
 1002                     (unsigned long)lf->size, lf->refs);
 1003         }
 1004         return (0);
 1005 }
 1006 #endif
 1007 
 1008 /*
 1009  * Constructor
 1010  */
 1011 static int
 1012 linprocfs_init(PFS_INIT_ARGS)
 1013 {
 1014         struct pfs_node *root;
 1015         struct pfs_node *dir;
 1016 
 1017         root = pi->pi_root;
 1018 
 1019         /* /proc/... */
 1020         pfs_create_file(root, "cmdline", &linprocfs_docmdline,
 1021             NULL, NULL, PFS_RD);
 1022         pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
 1023             NULL, NULL, PFS_RD);
 1024 #if 0
 1025         pfs_create_file(root, "devices", &linprocfs_dodevices,
 1026             NULL, NULL, PFS_RD);
 1027 #endif
 1028         pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
 1029             NULL, NULL, PFS_RD);
 1030         pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
 1031             NULL, NULL, PFS_RD);
 1032 #if 0
 1033         pfs_create_file(root, "modules", &linprocfs_domodules,
 1034             NULL, NULL, PFS_RD);
 1035 #endif
 1036         pfs_create_file(root, "mtab", &linprocfs_domtab,
 1037             NULL, NULL, PFS_RD);
 1038         pfs_create_link(root, "self", &procfs_docurproc,
 1039             NULL, NULL, 0);
 1040         pfs_create_file(root, "stat", &linprocfs_dostat,
 1041             NULL, NULL, PFS_RD);
 1042         pfs_create_file(root, "uptime", &linprocfs_douptime,
 1043             NULL, NULL, PFS_RD);
 1044         pfs_create_file(root, "version", &linprocfs_doversion,
 1045             NULL, NULL, PFS_RD);
 1046 
 1047         /* /proc/net/... */
 1048         dir = pfs_create_dir(root, "net", NULL, NULL, 0);
 1049         pfs_create_file(dir, "dev", &linprocfs_donetdev,
 1050             NULL, NULL, PFS_RD);
 1051 
 1052         /* /proc/<pid>/... */
 1053         dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
 1054         pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
 1055             NULL, NULL, PFS_RD);
 1056         pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
 1057             NULL, NULL, 0);
 1058         pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
 1059             NULL, NULL, PFS_RD);
 1060         pfs_create_link(dir, "exe", &procfs_doprocfile,
 1061             NULL, &procfs_notsystem, 0);
 1062         pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
 1063             NULL, NULL, PFS_RD);
 1064         pfs_create_file(dir, "mem", &procfs_doprocmem,
 1065             &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
 1066         pfs_create_link(dir, "root", &linprocfs_doprocroot,
 1067             NULL, NULL, 0);
 1068         pfs_create_file(dir, "stat", &linprocfs_doprocstat,
 1069             NULL, NULL, PFS_RD);
 1070         pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
 1071             NULL, NULL, PFS_RD);
 1072         pfs_create_file(dir, "status", &linprocfs_doprocstatus,
 1073             NULL, NULL, PFS_RD);
 1074 
 1075         return (0);
 1076 }
 1077 
 1078 /*
 1079  * Destructor
 1080  */
 1081 static int
 1082 linprocfs_uninit(PFS_INIT_ARGS)
 1083 {
 1084 
 1085         /* nothing to do, pseudofs will GC */
 1086         return (0);
 1087 }
 1088 
 1089 PSEUDOFS(linprocfs, 1);
 1090 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
 1091 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);

Cache object: b3d03a9afef109bcfcb005839e11ca55


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