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 = i * PAGE_SIZE; 148 swapused = 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_NODEV, "nodev"); 399 ADD_OPTION(MNT_UNION, "union"); 400 ADD_OPTION(MNT_ASYNC, "async"); 401 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 402 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 403 ADD_OPTION(MNT_NOATIME, "noatime"); 404 #undef ADD_OPTION 405 /* a real Linux mtab will also show NFS options */ 406 sbuf_printf(sb, " 0 0\n"); 407 } 408 mtx_unlock(&mountlist_mtx); 409 if (flep != NULL) 410 free(flep, M_TEMP); 411 return (error); 412 } 413 414 /* 415 * Filler function for proc/stat 416 */ 417 static int 418 linprocfs_dostat(PFS_FILL_ARGS) 419 { 420 int i; 421 422 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 423 T2J(cp_time[CP_USER]), 424 T2J(cp_time[CP_NICE]), 425 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 426 T2J(cp_time[CP_IDLE])); 427 for (i = 0; i < mp_ncpus; ++i) 428 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 429 T2J(cp_time[CP_USER]) / mp_ncpus, 430 T2J(cp_time[CP_NICE]) / mp_ncpus, 431 T2J(cp_time[CP_SYS]) / mp_ncpus, 432 T2J(cp_time[CP_IDLE]) / mp_ncpus); 433 sbuf_printf(sb, 434 "disk 0 0 0 0\n" 435 "page %u %u\n" 436 "swap %u %u\n" 437 "intr %u\n" 438 "ctxt %u\n" 439 "btime %lld\n", 440 cnt.v_vnodepgsin, 441 cnt.v_vnodepgsout, 442 cnt.v_swappgsin, 443 cnt.v_swappgsout, 444 cnt.v_intr, 445 cnt.v_swtch, 446 (long long)boottime.tv_sec); 447 return (0); 448 } 449 450 /* 451 * Filler function for proc/uptime 452 */ 453 static int 454 linprocfs_douptime(PFS_FILL_ARGS) 455 { 456 struct timeval tv; 457 458 getmicrouptime(&tv); 459 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 460 (long long)tv.tv_sec, tv.tv_usec / 10000, 461 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 462 return (0); 463 } 464 465 /* 466 * Filler function for proc/version 467 */ 468 static int 469 linprocfs_doversion(PFS_FILL_ARGS) 470 { 471 char osname[LINUX_MAX_UTSNAME]; 472 char osrelease[LINUX_MAX_UTSNAME]; 473 474 linux_get_osname(td, osname); 475 linux_get_osrelease(td, osrelease); 476 477 sbuf_printf(sb, 478 "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 479 " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease); 480 return (0); 481 } 482 483 /* 484 * Filler function for proc/loadavg 485 */ 486 static int 487 linprocfs_doloadavg(PFS_FILL_ARGS) 488 { 489 sbuf_printf(sb, 490 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 491 (int)(averunnable.ldavg[0] / averunnable.fscale), 492 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 493 (int)(averunnable.ldavg[1] / averunnable.fscale), 494 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 495 (int)(averunnable.ldavg[2] / averunnable.fscale), 496 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 497 1, /* number of running tasks */ 498 nprocs, /* number of tasks */ 499 lastpid /* the last pid */ 500 ); 501 502 return (0); 503 } 504 505 /* 506 * Filler function for proc/pid/stat 507 */ 508 static int 509 linprocfs_doprocstat(PFS_FILL_ARGS) 510 { 511 struct kinfo_proc kp; 512 513 PROC_LOCK(p); 514 fill_kinfo_proc(p, &kp); 515 sbuf_printf(sb, "%d", p->p_pid); 516 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 517 PS_ADD("comm", "(%s)", p->p_comm); 518 PS_ADD("statr", "%c", '0'); /* XXX */ 519 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 520 PS_ADD("pgrp", "%d", p->p_pgid); 521 PS_ADD("session", "%d", p->p_session->s_sid); 522 PROC_UNLOCK(p); 523 PS_ADD("tty", "%d", 0); /* XXX */ 524 PS_ADD("tpgid", "%d", 0); /* XXX */ 525 PS_ADD("flags", "%u", 0); /* XXX */ 526 PS_ADD("minflt", "%u", 0); /* XXX */ 527 PS_ADD("cminflt", "%u", 0); /* XXX */ 528 PS_ADD("majflt", "%u", 0); /* XXX */ 529 PS_ADD("cminflt", "%u", 0); /* XXX */ 530 PS_ADD("utime", "%d", 0); /* XXX */ 531 PS_ADD("stime", "%d", 0); /* XXX */ 532 PS_ADD("cutime", "%d", 0); /* XXX */ 533 PS_ADD("cstime", "%d", 0); /* XXX */ 534 PS_ADD("counter", "%d", 0); /* XXX */ 535 PS_ADD("priority", "%d", 0); /* XXX */ 536 PS_ADD("timeout", "%u", 0); /* XXX */ 537 PS_ADD("itrealvalue", "%u", 0); /* XXX */ 538 PS_ADD("starttime", "%d", 0); /* XXX */ 539 PS_ADD("vsize", "%ju", (uintmax_t)kp.ki_size); 540 PS_ADD("rss", "%ju", P2K((uintmax_t)kp.ki_rssize)); 541 PS_ADD("rlim", "%u", 0); /* XXX */ 542 PS_ADD("startcode", "%u", (unsigned)0); 543 PS_ADD("endcode", "%u", 0); /* XXX */ 544 PS_ADD("startstack", "%u", 0); /* XXX */ 545 PS_ADD("esp", "%u", 0); /* XXX */ 546 PS_ADD("eip", "%u", 0); /* XXX */ 547 PS_ADD("signal", "%d", 0); /* XXX */ 548 PS_ADD("blocked", "%d", 0); /* XXX */ 549 PS_ADD("sigignore", "%d", 0); /* XXX */ 550 PS_ADD("sigcatch", "%d", 0); /* XXX */ 551 PS_ADD("wchan", "%u", 0); /* XXX */ 552 PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 553 PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 554 PS_ADD("exitsignal", "%d", 0); /* XXX */ 555 PS_ADD("processor", "%d", 0); /* XXX */ 556 #undef PS_ADD 557 sbuf_putc(sb, '\n'); 558 559 return (0); 560 } 561 562 /* 563 * Filler function for proc/pid/statm 564 */ 565 static int 566 linprocfs_doprocstatm(PFS_FILL_ARGS) 567 { 568 struct kinfo_proc kp; 569 segsz_t lsize; 570 571 PROC_LOCK(p); 572 fill_kinfo_proc(p, &kp); 573 PROC_UNLOCK(p); 574 575 /* 576 * See comments in linprocfs_doprocstatus() regarding the 577 * computation of lsize. 578 */ 579 /* size resident share trs drs lrs dt */ 580 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 581 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 582 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 583 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 584 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 585 lsize = B2P(kp.ki_size) - kp.ki_dsize - 586 kp.ki_ssize - kp.ki_tsize - 1; 587 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 588 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 589 590 return (0); 591 } 592 593 /* 594 * Filler function for proc/pid/status 595 */ 596 static int 597 linprocfs_doprocstatus(PFS_FILL_ARGS) 598 { 599 struct kinfo_proc kp; 600 char *state; 601 segsz_t lsize; 602 struct thread *td2; 603 struct sigacts *ps; 604 int i; 605 606 PROC_LOCK(p); 607 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 608 609 if (P_SHOULDSTOP(p)) { 610 state = "T (stopped)"; 611 } else { 612 mtx_lock_spin(&sched_lock); 613 switch(p->p_state) { 614 case PRS_NEW: 615 state = "I (idle)"; 616 break; 617 case PRS_NORMAL: 618 if (p->p_flag & P_WEXIT) { 619 state = "X (exiting)"; 620 break; 621 } 622 switch(td2->td_state) { 623 case TDS_INHIBITED: 624 state = "S (sleeping)"; 625 break; 626 case TDS_RUNQ: 627 case TDS_RUNNING: 628 state = "R (running)"; 629 break; 630 default: 631 state = "? (unknown)"; 632 break; 633 } 634 break; 635 case PRS_ZOMBIE: 636 state = "Z (zombie)"; 637 break; 638 default: 639 state = "? (unknown)"; 640 break; 641 } 642 mtx_unlock_spin(&sched_lock); 643 } 644 645 fill_kinfo_proc(p, &kp); 646 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 647 sbuf_printf(sb, "State:\t%s\n", state); 648 649 /* 650 * Credentials 651 */ 652 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 653 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 654 p->p_pptr->p_pid : 0); 655 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 656 p->p_ucred->cr_uid, 657 p->p_ucred->cr_svuid, 658 /* FreeBSD doesn't have fsuid */ 659 p->p_ucred->cr_uid); 660 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 661 p->p_ucred->cr_gid, 662 p->p_ucred->cr_svgid, 663 /* FreeBSD doesn't have fsgid */ 664 p->p_ucred->cr_gid); 665 sbuf_cat(sb, "Groups:\t"); 666 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 667 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 668 PROC_UNLOCK(p); 669 sbuf_putc(sb, '\n'); 670 671 /* 672 * Memory 673 * 674 * While our approximation of VmLib may not be accurate (I 675 * don't know of a simple way to verify it, and I'm not sure 676 * it has much meaning anyway), I believe it's good enough. 677 * 678 * The same code that could (I think) accurately compute VmLib 679 * could also compute VmLck, but I don't really care enough to 680 * implement it. Submissions are welcome. 681 */ 682 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 683 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 684 sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 685 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 686 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 687 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 688 lsize = B2P(kp.ki_size) - kp.ki_dsize - 689 kp.ki_ssize - kp.ki_tsize - 1; 690 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 691 692 /* 693 * Signal masks 694 * 695 * We support up to 128 signals, while Linux supports 32, 696 * but we only define 32 (the same 32 as Linux, to boot), so 697 * just show the lower 32 bits of each mask. XXX hack. 698 * 699 * NB: on certain platforms (Sparc at least) Linux actually 700 * supports 64 signals, but this code is a long way from 701 * running on anything but i386, so ignore that for now. 702 */ 703 PROC_LOCK(p); 704 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 705 /* 706 * I can't seem to find out where the signal mask is in 707 * relation to struct proc, so SigBlk is left unimplemented. 708 */ 709 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 710 ps = p->p_sigacts; 711 mtx_lock(&ps->ps_mtx); 712 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 713 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 714 mtx_unlock(&ps->ps_mtx); 715 PROC_UNLOCK(p); 716 717 /* 718 * Linux also prints the capability masks, but we don't have 719 * capabilities yet, and when we do get them they're likely to 720 * be meaningless to Linux programs, so we lie. XXX 721 */ 722 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 723 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 724 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 725 726 return (0); 727 } 728 729 730 /* 731 * Filler function for proc/pid/cwd 732 */ 733 static int 734 linprocfs_doproccwd(PFS_FILL_ARGS) 735 { 736 char *fullpath = "unknown"; 737 char *freepath = NULL; 738 739 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 740 sbuf_printf(sb, "%s", fullpath); 741 if (freepath) 742 free(freepath, M_TEMP); 743 return (0); 744 } 745 746 /* 747 * Filler function for proc/pid/root 748 */ 749 static int 750 linprocfs_doprocroot(PFS_FILL_ARGS) 751 { 752 struct vnode *rvp; 753 char *fullpath = "unknown"; 754 char *freepath = NULL; 755 756 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 757 vn_fullpath(td, rvp, &fullpath, &freepath); 758 sbuf_printf(sb, "%s", fullpath); 759 if (freepath) 760 free(freepath, M_TEMP); 761 return (0); 762 } 763 764 /* 765 * Filler function for proc/pid/cmdline 766 */ 767 static int 768 linprocfs_doproccmdline(PFS_FILL_ARGS) 769 { 770 struct ps_strings pstr; 771 char **ps_argvstr; 772 int error, i; 773 774 /* 775 * If we are using the ps/cmdline caching, use that. Otherwise 776 * revert back to the old way which only implements full cmdline 777 * for the currept process and just p->p_comm for all other 778 * processes. 779 * Note that if the argv is no longer available, we deliberately 780 * don't fall back on p->p_comm or return an error: the authentic 781 * Linux behaviour is to return zero-length in this case. 782 */ 783 784 PROC_LOCK(p); 785 if (p->p_args && p_cansee(td, p) == 0) { 786 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 787 PROC_UNLOCK(p); 788 } else if (p != td->td_proc) { 789 PROC_UNLOCK(p); 790 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 791 } else { 792 PROC_UNLOCK(p); 793 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 794 sizeof(pstr)); 795 if (error) 796 return (error); 797 if (pstr.ps_nargvstr > ARG_MAX) 798 return (E2BIG); 799 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 800 M_TEMP, M_WAITOK); 801 error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 802 pstr.ps_nargvstr * sizeof(char *)); 803 if (error) { 804 free(ps_argvstr, M_TEMP); 805 return (error); 806 } 807 for (i = 0; i < pstr.ps_nargvstr; i++) { 808 sbuf_copyin(sb, ps_argvstr[i], 0); 809 sbuf_printf(sb, "%c", '\0'); 810 } 811 free(ps_argvstr, M_TEMP); 812 } 813 814 return (0); 815 } 816 817 /* 818 * Filler function for proc/pid/environ 819 */ 820 static int 821 linprocfs_doprocenviron(PFS_FILL_ARGS) 822 { 823 sbuf_printf(sb, "doprocenviron\n%c", '\0'); 824 825 return (0); 826 } 827 828 /* 829 * Filler function for proc/pid/maps 830 */ 831 static int 832 linprocfs_doprocmaps(PFS_FILL_ARGS) 833 { 834 char mebuffer[512]; 835 vm_map_t map = &p->p_vmspace->vm_map; 836 vm_map_entry_t entry; 837 vm_object_t obj, tobj, lobj; 838 vm_ooffset_t off = 0; 839 char *name = "", *freename = NULL; 840 size_t len; 841 ino_t ino; 842 int ref_count, shadow_count, flags; 843 int error; 844 struct vnode *vp; 845 struct vattr vat; 846 847 PROC_LOCK(p); 848 error = p_candebug(td, p); 849 PROC_UNLOCK(p); 850 if (error) 851 return (error); 852 853 if (uio->uio_rw != UIO_READ) 854 return (EOPNOTSUPP); 855 856 if (uio->uio_offset != 0) 857 return (0); 858 859 error = 0; 860 if (map != &curthread->td_proc->p_vmspace->vm_map) 861 vm_map_lock_read(map); 862 for (entry = map->header.next; 863 ((uio->uio_resid > 0) && (entry != &map->header)); 864 entry = entry->next) { 865 name = ""; 866 freename = NULL; 867 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 868 continue; 869 obj = entry->object.vm_object; 870 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) 871 lobj = tobj; 872 ino = 0; 873 if (lobj) { 874 vp = lobj->handle; 875 VM_OBJECT_LOCK(lobj); 876 off = IDX_TO_OFF(lobj->size); 877 if (lobj->type == OBJT_VNODE && lobj->handle) { 878 vn_fullpath(td, vp, &name, &freename); 879 VOP_GETATTR(vp, &vat, td->td_ucred, td); 880 ino = vat.va_fileid; 881 } 882 flags = obj->flags; 883 ref_count = obj->ref_count; 884 shadow_count = obj->shadow_count; 885 VM_OBJECT_UNLOCK(lobj); 886 } else { 887 flags = 0; 888 ref_count = 0; 889 shadow_count = 0; 890 } 891 892 /* 893 * format: 894 * start, end, access, offset, major, minor, inode, name. 895 */ 896 snprintf(mebuffer, sizeof mebuffer, 897 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 898 (u_long)entry->start, (u_long)entry->end, 899 (entry->protection & VM_PROT_READ)?"r":"-", 900 (entry->protection & VM_PROT_WRITE)?"w":"-", 901 (entry->protection & VM_PROT_EXECUTE)?"x":"-", 902 "p", 903 (u_long)off, 904 0, 905 0, 906 (u_long)ino, 907 *name ? " " : "", 908 name 909 ); 910 if (freename) 911 free(freename, M_TEMP); 912 len = strlen(mebuffer); 913 if (len > uio->uio_resid) 914 len = uio->uio_resid; /* 915 * XXX We should probably return 916 * EFBIG here, as in procfs. 917 */ 918 error = uiomove(mebuffer, len, uio); 919 if (error) 920 break; 921 } 922 if (map != &curthread->td_proc->p_vmspace->vm_map) 923 vm_map_unlock_read(map); 924 925 return (error); 926 } 927 928 /* 929 * Filler function for proc/net/dev 930 */ 931 static int 932 linprocfs_donetdev(PFS_FILL_ARGS) 933 { 934 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 935 struct ifnet *ifp; 936 937 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 938 "Inter-", " Receive", " Transmit", " face", 939 "bytes packets errs drop fifo frame compressed", 940 "bytes packets errs drop fifo frame compressed"); 941 942 IFNET_RLOCK(); 943 TAILQ_FOREACH(ifp, &ifnet, if_link) { 944 linux_ifname(ifp, ifname, sizeof ifname); 945 sbuf_printf(sb, "%6.6s:", ifname); 946 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 947 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 948 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 949 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 950 } 951 IFNET_RUNLOCK(); 952 953 return (0); 954 } 955 956 #if 0 957 extern struct cdevsw *cdevsw[]; 958 959 /* 960 * Filler function for proc/devices 961 */ 962 static int 963 linprocfs_dodevices(PFS_FILL_ARGS) 964 { 965 int i; 966 967 sbuf_printf(sb, "Character devices:\n"); 968 969 for (i = 0; i < NUMCDEVSW; i++) 970 if (cdevsw[i] != NULL) 971 sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 972 973 sbuf_printf(sb, "\nBlock devices:\n"); 974 975 return (0); 976 } 977 #endif 978 979 /* 980 * Filler function for proc/cmdline 981 */ 982 static int 983 linprocfs_docmdline(PFS_FILL_ARGS) 984 { 985 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 986 sbuf_printf(sb, " ro root=302\n"); 987 return (0); 988 } 989 990 #if 0 991 /* 992 * Filler function for proc/modules 993 */ 994 static int 995 linprocfs_domodules(PFS_FILL_ARGS) 996 { 997 struct linker_file *lf; 998 999 TAILQ_FOREACH(lf, &linker_files, link) { 1000 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1001 (unsigned long)lf->size, lf->refs); 1002 } 1003 return (0); 1004 } 1005 #endif 1006 1007 /* 1008 * Constructor 1009 */ 1010 static int 1011 linprocfs_init(PFS_INIT_ARGS) 1012 { 1013 struct pfs_node *root; 1014 struct pfs_node *dir; 1015 1016 root = pi->pi_root; 1017 1018 /* /proc/... */ 1019 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1020 NULL, NULL, PFS_RD); 1021 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1022 NULL, NULL, PFS_RD); 1023 #if 0 1024 pfs_create_file(root, "devices", &linprocfs_dodevices, 1025 NULL, NULL, PFS_RD); 1026 #endif 1027 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1028 NULL, NULL, PFS_RD); 1029 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1030 NULL, NULL, PFS_RD); 1031 #if 0 1032 pfs_create_file(root, "modules", &linprocfs_domodules, 1033 NULL, NULL, PFS_RD); 1034 #endif 1035 pfs_create_file(root, "mtab", &linprocfs_domtab, 1036 NULL, NULL, PFS_RD); 1037 pfs_create_link(root, "self", &procfs_docurproc, 1038 NULL, NULL, 0); 1039 pfs_create_file(root, "stat", &linprocfs_dostat, 1040 NULL, NULL, PFS_RD); 1041 pfs_create_file(root, "uptime", &linprocfs_douptime, 1042 NULL, NULL, PFS_RD); 1043 pfs_create_file(root, "version", &linprocfs_doversion, 1044 NULL, NULL, PFS_RD); 1045 1046 /* /proc/net/... */ 1047 dir = pfs_create_dir(root, "net", NULL, NULL, 0); 1048 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1049 NULL, NULL, PFS_RD); 1050 1051 /* /proc/<pid>/... */ 1052 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 1053 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1054 NULL, NULL, PFS_RD); 1055 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1056 NULL, NULL, 0); 1057 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1058 NULL, NULL, PFS_RD); 1059 pfs_create_link(dir, "exe", &procfs_doprocfile, 1060 NULL, &procfs_notsystem, 0); 1061 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1062 NULL, NULL, PFS_RD); 1063 pfs_create_file(dir, "mem", &procfs_doprocmem, 1064 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 1065 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1066 NULL, NULL, 0); 1067 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1068 NULL, NULL, PFS_RD); 1069 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1070 NULL, NULL, PFS_RD); 1071 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1072 NULL, NULL, PFS_RD); 1073 1074 return (0); 1075 } 1076 1077 /* 1078 * Destructor 1079 */ 1080 static int 1081 linprocfs_uninit(PFS_INIT_ARGS) 1082 { 1083 1084 /* nothing to do, pseudofs will GC */ 1085 return (0); 1086 } 1087 1088 PSEUDOFS(linprocfs, 1); 1089 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1090 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1091