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