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