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