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