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