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