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