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