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