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