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 #if !COMPAT_LINUX32 /* XXX */ 96 #include <machine/../linux/linux.h> 97 #else 98 #include <machine/../linux32/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 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 for (i = 0; i < pstr.ps_nargvstr; i++) { 798 sbuf_copyin(sb, pstr.ps_argvstr[i], 0); 799 sbuf_printf(sb, "%c", '\0'); 800 } 801 } 802 803 return (0); 804 } 805 806 /* 807 * Filler function for proc/pid/environ 808 */ 809 static int 810 linprocfs_doprocenviron(PFS_FILL_ARGS) 811 { 812 sbuf_printf(sb, "doprocenviron\n%c", '\0'); 813 814 return (0); 815 } 816 817 /* 818 * Filler function for proc/pid/maps 819 */ 820 static int 821 linprocfs_doprocmaps(PFS_FILL_ARGS) 822 { 823 char mebuffer[512]; 824 vm_map_t map = &p->p_vmspace->vm_map; 825 vm_map_entry_t entry; 826 vm_object_t obj, tobj, lobj; 827 vm_ooffset_t off = 0; 828 char *name = "", *freename = NULL; 829 size_t len; 830 ino_t ino; 831 int ref_count, shadow_count, flags; 832 int error; 833 834 PROC_LOCK(p); 835 error = p_candebug(td, p); 836 PROC_UNLOCK(p); 837 if (error) 838 return (error); 839 840 if (uio->uio_rw != UIO_READ) 841 return (EOPNOTSUPP); 842 843 if (uio->uio_offset != 0) 844 return (0); 845 846 error = 0; 847 if (map != &curthread->td_proc->p_vmspace->vm_map) 848 vm_map_lock_read(map); 849 for (entry = map->header.next; 850 ((uio->uio_resid > 0) && (entry != &map->header)); 851 entry = entry->next) { 852 name = ""; 853 freename = NULL; 854 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 855 continue; 856 obj = entry->object.vm_object; 857 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) 858 lobj = tobj; 859 ino = 0; 860 if (lobj) { 861 VM_OBJECT_LOCK(lobj); 862 off = IDX_TO_OFF(lobj->size); 863 if (lobj->type == OBJT_VNODE && lobj->handle) { 864 vn_fullpath(td, (struct vnode *)lobj->handle, 865 &name, &freename); 866 ino = ((struct vnode *) 867 lobj->handle)->v_cachedid; 868 } 869 flags = obj->flags; 870 ref_count = obj->ref_count; 871 shadow_count = obj->shadow_count; 872 VM_OBJECT_UNLOCK(lobj); 873 } else { 874 flags = 0; 875 ref_count = 0; 876 shadow_count = 0; 877 } 878 879 /* 880 * format: 881 * start, end, access, offset, major, minor, inode, name. 882 */ 883 snprintf(mebuffer, sizeof mebuffer, 884 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 885 (u_long)entry->start, (u_long)entry->end, 886 (entry->protection & VM_PROT_READ)?"r":"-", 887 (entry->protection & VM_PROT_WRITE)?"w":"-", 888 (entry->protection & VM_PROT_EXECUTE)?"x":"-", 889 "p", 890 (u_long)off, 891 0, 892 0, 893 (u_long)ino, 894 *name ? " " : "", 895 name 896 ); 897 if (freename) 898 free(freename, M_TEMP); 899 len = strlen(mebuffer); 900 if (len > uio->uio_resid) 901 len = uio->uio_resid; /* 902 * XXX We should probably return 903 * EFBIG here, as in procfs. 904 */ 905 error = uiomove(mebuffer, len, uio); 906 if (error) 907 break; 908 } 909 if (map != &curthread->td_proc->p_vmspace->vm_map) 910 vm_map_unlock_read(map); 911 912 return (error); 913 } 914 915 /* 916 * Filler function for proc/net/dev 917 */ 918 static int 919 linprocfs_donetdev(PFS_FILL_ARGS) 920 { 921 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 922 struct ifnet *ifp; 923 924 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 925 "Inter-", " Receive", " Transmit", " face", 926 "bytes packets errs drop fifo frame compressed", 927 "bytes packets errs drop fifo frame compressed"); 928 929 IFNET_RLOCK(); 930 TAILQ_FOREACH(ifp, &ifnet, if_link) { 931 linux_ifname(ifp, ifname, sizeof ifname); 932 sbuf_printf(sb, "%6.6s:", ifname); 933 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 934 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 935 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 936 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 937 } 938 IFNET_RUNLOCK(); 939 940 return (0); 941 } 942 943 #if 0 944 extern struct cdevsw *cdevsw[]; 945 946 /* 947 * Filler function for proc/devices 948 */ 949 static int 950 linprocfs_dodevices(PFS_FILL_ARGS) 951 { 952 int i; 953 954 sbuf_printf(sb, "Character devices:\n"); 955 956 for (i = 0; i < NUMCDEVSW; i++) 957 if (cdevsw[i] != NULL) 958 sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 959 960 sbuf_printf(sb, "\nBlock devices:\n"); 961 962 return (0); 963 } 964 #endif 965 966 /* 967 * Filler function for proc/cmdline 968 */ 969 static int 970 linprocfs_docmdline(PFS_FILL_ARGS) 971 { 972 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 973 sbuf_printf(sb, " ro root=302\n"); 974 return (0); 975 } 976 977 #if 0 978 /* 979 * Filler function for proc/modules 980 */ 981 static int 982 linprocfs_domodules(PFS_FILL_ARGS) 983 { 984 struct linker_file *lf; 985 986 TAILQ_FOREACH(lf, &linker_files, link) { 987 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 988 (unsigned long)lf->size, lf->refs); 989 } 990 return (0); 991 } 992 #endif 993 994 /* 995 * Constructor 996 */ 997 static int 998 linprocfs_init(PFS_INIT_ARGS) 999 { 1000 struct pfs_node *root; 1001 struct pfs_node *dir; 1002 1003 root = pi->pi_root; 1004 1005 /* /proc/... */ 1006 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1007 NULL, NULL, PFS_RD); 1008 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1009 NULL, NULL, PFS_RD); 1010 #if 0 1011 pfs_create_file(root, "devices", &linprocfs_dodevices, 1012 NULL, NULL, PFS_RD); 1013 #endif 1014 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1015 NULL, NULL, PFS_RD); 1016 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1017 NULL, NULL, PFS_RD); 1018 #if 0 1019 pfs_create_file(root, "modules", &linprocfs_domodules, 1020 NULL, NULL, PFS_RD); 1021 #endif 1022 pfs_create_file(root, "mtab", &linprocfs_domtab, 1023 NULL, NULL, PFS_RD); 1024 pfs_create_link(root, "self", &procfs_docurproc, 1025 NULL, NULL, 0); 1026 pfs_create_file(root, "stat", &linprocfs_dostat, 1027 NULL, NULL, PFS_RD); 1028 pfs_create_file(root, "uptime", &linprocfs_douptime, 1029 NULL, NULL, PFS_RD); 1030 pfs_create_file(root, "version", &linprocfs_doversion, 1031 NULL, NULL, PFS_RD); 1032 1033 /* /proc/net/... */ 1034 dir = pfs_create_dir(root, "net", NULL, NULL, 0); 1035 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1036 NULL, NULL, PFS_RD); 1037 1038 /* /proc/<pid>/... */ 1039 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 1040 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1041 NULL, NULL, PFS_RD); 1042 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1043 NULL, NULL, 0); 1044 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1045 NULL, NULL, PFS_RD); 1046 pfs_create_link(dir, "exe", &procfs_doprocfile, 1047 NULL, &procfs_notsystem, 0); 1048 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1049 NULL, NULL, PFS_RD); 1050 pfs_create_file(dir, "mem", &procfs_doprocmem, 1051 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 1052 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1053 NULL, NULL, 0); 1054 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1055 NULL, NULL, PFS_RD); 1056 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1057 NULL, NULL, PFS_RD); 1058 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1059 NULL, NULL, PFS_RD); 1060 1061 return (0); 1062 } 1063 1064 /* 1065 * Destructor 1066 */ 1067 static int 1068 linprocfs_uninit(PFS_INIT_ARGS) 1069 { 1070 1071 /* nothing to do, pseudofs will GC */ 1072 return (0); 1073 } 1074 1075 PSEUDOFS(linprocfs, 1); 1076 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1077 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1078