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 * $FreeBSD$ 42 */ 43 44 #include <sys/param.h> 45 #include <sys/queue.h> 46 #include <sys/blist.h> 47 #include <sys/conf.h> 48 #include <sys/dkstat.h> 49 #include <sys/exec.h> 50 #include <sys/jail.h> 51 #include <sys/kernel.h> 52 #include <sys/linker.h> 53 #include <sys/lock.h> 54 #include <sys/malloc.h> 55 #include <sys/mount.h> 56 #include <sys/mutex.h> 57 #include <sys/namei.h> 58 #include <sys/proc.h> 59 #include <sys/resourcevar.h> 60 #include <sys/sbuf.h> 61 #include <sys/socket.h> 62 #include <sys/sysctl.h> 63 #include <sys/systm.h> 64 #include <sys/tty.h> 65 #include <sys/user.h> 66 #include <sys/vmmeter.h> 67 #include <sys/vnode.h> 68 69 #include <net/if.h> 70 71 #include <vm/vm.h> 72 #include <vm/pmap.h> 73 #include <vm/vm_map.h> 74 #include <vm/vm_param.h> 75 #include <vm/vm_object.h> 76 #include <vm/swap_pager.h> 77 78 #include <machine/clock.h> 79 80 #ifdef __alpha__ 81 #include <machine/alpha_cpu.h> 82 #include <machine/cpuconf.h> 83 #include <machine/rpb.h> 84 extern int ncpus; 85 #endif /* __alpha__ */ 86 87 #ifdef __i386__ 88 #include <machine/cputypes.h> 89 #include <machine/md_var.h> 90 #endif /* __i386__ */ 91 92 #include <machine/../linux/linux.h> 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 u_quad_t swaptotal; /* total swap space in bytes */ 121 u_quad_t swapused; /* used swap space in bytes */ 122 u_quad_t swapfree; /* free swap space in bytes */ 123 vm_object_t object; 124 125 memtotal = physmem * PAGE_SIZE; 126 /* 127 * The correct thing here would be: 128 * 129 memfree = cnt.v_free_count * PAGE_SIZE; 130 memused = memtotal - memfree; 131 * 132 * but it might mislead linux binaries into thinking there 133 * is very little memory left, so we cheat and tell them that 134 * all memory that isn't wired down is free. 135 */ 136 memused = cnt.v_wire_count * PAGE_SIZE; 137 memfree = memtotal - memused; 138 if (swapblist == NULL) { 139 swaptotal = 0; 140 swapfree = 0; 141 } else { 142 swaptotal = (u_quad_t)swapblist->bl_blocks * 1024; /* XXX why 1024? */ 143 swapfree = (u_quad_t)swapblist->bl_root->u.bmu_avail * PAGE_SIZE; 144 } 145 swapused = swaptotal - swapfree; 146 memshared = 0; 147 TAILQ_FOREACH(object, &vm_object_list, object_list) 148 if (object->shadow_count > 1) 149 memshared += object->resident_page_count; 150 memshared *= PAGE_SIZE; 151 /* 152 * We'd love to be able to write: 153 * 154 buffers = bufspace; 155 * 156 * but bufspace is internal to vfs_bio.c and we don't feel 157 * like unstaticizing it just for linprocfs's sake. 158 */ 159 buffers = 0; 160 cached = cnt.v_cache_count * PAGE_SIZE; 161 162 sbuf_printf(sb, 163 " total: used: free: shared: buffers: cached:\n" 164 "Mem: %lu %lu %lu %lu %lu %lu\n" 165 "Swap: %llu %llu %llu\n" 166 "MemTotal: %9lu kB\n" 167 "MemFree: %9lu kB\n" 168 "MemShared:%9lu kB\n" 169 "Buffers: %9lu kB\n" 170 "Cached: %9lu kB\n" 171 "SwapTotal:%9llu kB\n" 172 "SwapFree: %9llu kB\n", 173 memtotal, memused, memfree, memshared, buffers, cached, 174 swaptotal, swapused, swapfree, 175 B2K(memtotal), B2K(memfree), 176 B2K(memshared), B2K(buffers), B2K(cached), 177 B2K(swaptotal), B2K(swapfree)); 178 179 return (0); 180 } 181 182 #ifdef __alpha__ 183 /* 184 * Filler function for proc/cpuinfo (Alpha version) 185 */ 186 static int 187 linprocfs_docpuinfo(PFS_FILL_ARGS) 188 { 189 u_int64_t type, major; 190 struct pcs *pcsp; 191 const char *model, *sysname; 192 193 static const char *cpuname[] = { 194 "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56", 195 "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL" 196 }; 197 198 pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id); 199 type = pcsp->pcs_proc_type; 200 major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT; 201 if (major < sizeof(cpuname)/sizeof(char *)) { 202 model = cpuname[major - 1]; 203 } else { 204 model = "unknown"; 205 } 206 207 sysname = alpha_dsr_sysname(); 208 209 sbuf_printf(sb, 210 "cpu\t\t\t: Alpha\n" 211 "cpu model\t\t: %s\n" 212 "cpu variation\t\t: %ld\n" 213 "cpu revision\t\t: %ld\n" 214 "cpu serial number\t: %s\n" 215 "system type\t\t: %s\n" 216 "system variation\t: %s\n" 217 "system revision\t\t: %ld\n" 218 "system serial number\t: %s\n" 219 "cycle frequency [Hz]\t: %lu\n" 220 "timer frequency [Hz]\t: %lu\n" 221 "page size [bytes]\t: %ld\n" 222 "phys. address bits\t: %ld\n" 223 "max. addr. space #\t: %ld\n" 224 "BogoMIPS\t\t: %lu.%02lu\n" 225 "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" 226 "user unaligned acc\t: %ld (pc=%lx,va=%lx)\n" 227 "platform string\t\t: %s\n" 228 "cpus detected\t\t: %d\n" 229 , 230 model, 231 pcsp->pcs_proc_var, 232 *(int *)hwrpb->rpb_revision, 233 " ", 234 " ", 235 "0", 236 0, 237 " ", 238 hwrpb->rpb_cc_freq, 239 hz, 240 hwrpb->rpb_page_size, 241 hwrpb->rpb_phys_addr_size, 242 hwrpb->rpb_max_asn, 243 0, 0, 244 0, 0, 0, 245 0, 0, 0, 246 sysname, 247 ncpus); 248 return (0); 249 } 250 #endif /* __alpha__ */ 251 252 #ifdef __i386__ 253 /* 254 * Filler function for proc/cpuinfo (i386 version) 255 */ 256 static int 257 linprocfs_docpuinfo(PFS_FILL_ARGS) 258 { 259 int class, i, fqmhz, fqkhz; 260 261 /* 262 * We default the flags to include all non-conflicting flags, 263 * and the Intel versions of conflicting flags. 264 */ 265 static char *flags[] = { 266 "fpu", "vme", "de", "pse", "tsc", 267 "msr", "pae", "mce", "cx8", "apic", 268 "sep", "sep", "mtrr", "pge", "mca", 269 "cmov", "pat", "pse36", "pn", "b19", 270 "b20", "b21", "mmxext", "mmx", "fxsr", 271 "xmm", "b26", "b27", "b28", "b29", 272 "3dnowext", "3dnow" 273 }; 274 275 switch (cpu_class) { 276 case CPUCLASS_286: 277 class = 2; 278 break; 279 case CPUCLASS_386: 280 class = 3; 281 break; 282 case CPUCLASS_486: 283 class = 4; 284 break; 285 case CPUCLASS_586: 286 class = 5; 287 break; 288 case CPUCLASS_686: 289 class = 6; 290 break; 291 default: 292 class = 0; 293 break; 294 } 295 296 sbuf_printf(sb, 297 "processor\t: %d\n" 298 "vendor_id\t: %.20s\n" 299 "cpu family\t: %d\n" 300 "model\t\t: %d\n" 301 "stepping\t: %d\n", 302 0, cpu_vendor, class, cpu, cpu_id & 0xf); 303 304 sbuf_cat(sb, 305 "flags\t\t:"); 306 307 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 308 flags[16] = "fcmov"; 309 } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 310 flags[24] = "cxmmx"; 311 } 312 313 for (i = 0; i < 32; i++) 314 if (cpu_feature & (1 << i)) 315 sbuf_printf(sb, " %s", flags[i]); 316 sbuf_cat(sb, "\n"); 317 if (class >= 5) { 318 fqmhz = (tsc_freq + 4999) / 1000000; 319 fqkhz = ((tsc_freq + 4999) / 10000) % 100; 320 sbuf_printf(sb, 321 "cpu MHz\t\t: %d.%02d\n" 322 "bogomips\t: %d.%02d\n", 323 fqmhz, fqkhz, fqmhz, fqkhz); 324 } 325 326 return (0); 327 } 328 #endif /* __i386__ */ 329 330 /* 331 * Filler function for proc/mtab 332 * 333 * This file doesn't exist in Linux' procfs, but is included here so 334 * users can symlink /compat/linux/etc/mtab to /proc/mtab 335 */ 336 static int 337 linprocfs_domtab(PFS_FILL_ARGS) 338 { 339 struct nameidata nd; 340 struct mount *mp; 341 const char *lep; 342 char *dlep, *flep, *mntto, *mntfrom, *fstype; 343 size_t lep_len; 344 int error; 345 346 /* resolve symlinks etc. in the emulation tree prefix */ 347 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 348 flep = NULL; 349 if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) == -1) 350 lep = linux_emul_path; 351 else 352 lep = dlep; 353 lep_len = strlen(lep); 354 355 mtx_lock(&mountlist_mtx); 356 error = 0; 357 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 358 error = VFS_STATFS(mp, &mp->mnt_stat, td); 359 if (error) 360 break; 361 362 /* determine device name */ 363 mntfrom = mp->mnt_stat.f_mntfromname; 364 365 /* determine mount point */ 366 mntto = mp->mnt_stat.f_mntonname; 367 if (strncmp(mntto, lep, lep_len) == 0 && 368 mntto[lep_len] == '/') 369 mntto += lep_len; 370 371 /* determine fs type */ 372 fstype = mp->mnt_stat.f_fstypename; 373 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 374 mntfrom = fstype = "proc"; 375 else if (strcmp(fstype, "procfs") == 0) 376 continue; 377 378 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 379 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 380 #define ADD_OPTION(opt, name) \ 381 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 382 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 383 ADD_OPTION(MNT_NOEXEC, "noexec"); 384 ADD_OPTION(MNT_NOSUID, "nosuid"); 385 ADD_OPTION(MNT_NODEV, "nodev"); 386 ADD_OPTION(MNT_UNION, "union"); 387 ADD_OPTION(MNT_ASYNC, "async"); 388 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 389 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 390 ADD_OPTION(MNT_NOATIME, "noatime"); 391 #undef ADD_OPTION 392 /* a real Linux mtab will also show NFS options */ 393 sbuf_printf(sb, " 0 0\n"); 394 } 395 mtx_unlock(&mountlist_mtx); 396 if (flep != NULL) 397 free(flep, M_TEMP); 398 return (error); 399 } 400 401 /* 402 * Filler function for proc/stat 403 */ 404 static int 405 linprocfs_dostat(PFS_FILL_ARGS) 406 { 407 sbuf_printf(sb, 408 "cpu %ld %ld %ld %ld\n" 409 "disk 0 0 0 0\n" 410 "page %u %u\n" 411 "swap %u %u\n" 412 "intr %u\n" 413 "ctxt %u\n" 414 "btime %lld\n", 415 T2J(cp_time[CP_USER]), 416 T2J(cp_time[CP_NICE]), 417 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 418 T2J(cp_time[CP_IDLE]), 419 cnt.v_vnodepgsin, 420 cnt.v_vnodepgsout, 421 cnt.v_swappgsin, 422 cnt.v_swappgsout, 423 cnt.v_intr, 424 cnt.v_swtch, 425 (quad_t)boottime.tv_sec); 426 return (0); 427 } 428 429 /* 430 * Filler function for proc/uptime 431 */ 432 static int 433 linprocfs_douptime(PFS_FILL_ARGS) 434 { 435 struct timeval tv; 436 437 getmicrouptime(&tv); 438 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 439 (quad_t)tv.tv_sec, tv.tv_usec / 10000, 440 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 441 return (0); 442 } 443 444 /* 445 * Filler function for proc/version 446 */ 447 static int 448 linprocfs_doversion(PFS_FILL_ARGS) 449 { 450 char osname[LINUX_MAX_UTSNAME]; 451 char osrelease[LINUX_MAX_UTSNAME]; 452 453 linux_get_osname(td->td_proc, osname); 454 linux_get_osrelease(td->td_proc, osrelease); 455 456 sbuf_printf(sb, 457 "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 458 " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease); 459 return (0); 460 } 461 462 /* 463 * Filler function for proc/loadavg 464 */ 465 static int 466 linprocfs_doloadavg(PFS_FILL_ARGS) 467 { 468 sbuf_printf(sb, 469 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 470 (int)(averunnable.ldavg[0] / averunnable.fscale), 471 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 472 (int)(averunnable.ldavg[1] / averunnable.fscale), 473 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 474 (int)(averunnable.ldavg[2] / averunnable.fscale), 475 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 476 1, /* number of running tasks */ 477 nprocs, /* number of tasks */ 478 lastpid /* the last pid */ 479 ); 480 481 return (0); 482 } 483 484 /* 485 * Filler function for proc/pid/stat 486 */ 487 static int 488 linprocfs_doprocstat(PFS_FILL_ARGS) 489 { 490 struct kinfo_proc kp; 491 492 PROC_LOCK(p); 493 fill_kinfo_proc(p, &kp); 494 sbuf_printf(sb, "%d", p->p_pid); 495 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 496 PS_ADD("comm", "(%s)", p->p_comm); 497 PS_ADD("statr", "%c", '0'); /* XXX */ 498 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 499 PS_ADD("pgrp", "%d", p->p_pgid); 500 PS_ADD("session", "%d", p->p_session->s_sid); 501 PROC_UNLOCK(p); 502 PS_ADD("tty", "%d", 0); /* XXX */ 503 PS_ADD("tpgid", "%d", 0); /* XXX */ 504 PS_ADD("flags", "%u", 0); /* XXX */ 505 PS_ADD("minflt", "%u", 0); /* XXX */ 506 PS_ADD("cminflt", "%u", 0); /* XXX */ 507 PS_ADD("majflt", "%u", 0); /* XXX */ 508 PS_ADD("cminflt", "%u", 0); /* XXX */ 509 PS_ADD("utime", "%d", 0); /* XXX */ 510 PS_ADD("stime", "%d", 0); /* XXX */ 511 PS_ADD("cutime", "%d", 0); /* XXX */ 512 PS_ADD("cstime", "%d", 0); /* XXX */ 513 PS_ADD("counter", "%d", 0); /* XXX */ 514 PS_ADD("priority", "%d", 0); /* XXX */ 515 PS_ADD("timeout", "%u", 0); /* XXX */ 516 PS_ADD("itrealvalue", "%u", 0); /* XXX */ 517 PS_ADD("starttime", "%d", 0); /* XXX */ 518 PS_ADD("vsize", "%u", kp.ki_size); 519 PS_ADD("rss", "%u", P2K(kp.ki_rssize)); 520 PS_ADD("rlim", "%u", 0); /* XXX */ 521 PS_ADD("startcode", "%u", (unsigned)0); 522 PS_ADD("endcode", "%u", 0); /* XXX */ 523 PS_ADD("startstack", "%u", 0); /* XXX */ 524 PS_ADD("esp", "%u", 0); /* XXX */ 525 PS_ADD("eip", "%u", 0); /* XXX */ 526 PS_ADD("signal", "%d", 0); /* XXX */ 527 PS_ADD("blocked", "%d", 0); /* XXX */ 528 PS_ADD("sigignore", "%d", 0); /* XXX */ 529 PS_ADD("sigcatch", "%d", 0); /* XXX */ 530 PS_ADD("wchan", "%u", 0); /* XXX */ 531 PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */ 532 PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */ 533 PS_ADD("exitsignal", "%d", 0); /* XXX */ 534 PS_ADD("processor", "%d", 0); /* XXX */ 535 #undef PS_ADD 536 sbuf_putc(sb, '\n'); 537 538 return (0); 539 } 540 541 /* 542 * Filler function for proc/pid/status 543 */ 544 static int 545 linprocfs_doprocstatus(PFS_FILL_ARGS) 546 { 547 struct kinfo_proc kp; 548 char *state; 549 segsz_t lsize; 550 struct thread *td2; 551 int i; 552 553 mtx_lock_spin(&sched_lock); 554 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 555 556 if (P_SHOULDSTOP(p)) { 557 state = "T (stopped)"; 558 } else { 559 switch(p->p_state) { 560 case PRS_NEW: 561 state = "I (idle)"; 562 break; 563 case PRS_NORMAL: 564 if (p->p_flag & P_WEXIT) { 565 state = "X (exiting)"; 566 break; 567 } 568 switch(td2->td_state) { 569 case TDS_INHIBITED: 570 state = "S (sleeping)"; 571 break; 572 case TDS_RUNQ: 573 case TDS_RUNNING: 574 state = "R (running)"; 575 break; 576 default: 577 state = "? (unknown)"; 578 break; 579 } 580 break; 581 case PRS_ZOMBIE: 582 state = "Z (zombie)"; 583 break; 584 default: 585 state = "? (unknown)"; 586 break; 587 } 588 } 589 mtx_unlock_spin(&sched_lock); 590 591 PROC_LOCK(p); 592 fill_kinfo_proc(p, &kp); 593 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 594 sbuf_printf(sb, "State:\t%s\n", state); 595 596 /* 597 * Credentials 598 */ 599 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 600 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 601 p->p_pptr->p_pid : 0); 602 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 603 p->p_ucred->cr_uid, 604 p->p_ucred->cr_svuid, 605 /* FreeBSD doesn't have fsuid */ 606 p->p_ucred->cr_uid); 607 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 608 p->p_ucred->cr_gid, 609 p->p_ucred->cr_svgid, 610 /* FreeBSD doesn't have fsgid */ 611 p->p_ucred->cr_gid); 612 sbuf_cat(sb, "Groups:\t"); 613 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 614 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 615 PROC_UNLOCK(p); 616 sbuf_putc(sb, '\n'); 617 618 /* 619 * Memory 620 * 621 * While our approximation of VmLib may not be accurate (I 622 * don't know of a simple way to verify it, and I'm not sure 623 * it has much meaning anyway), I believe it's good enough. 624 * 625 * The same code that could (I think) accurately compute VmLib 626 * could also compute VmLck, but I don't really care enough to 627 * implement it. Submissions are welcome. 628 */ 629 sbuf_printf(sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size)); 630 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 631 sbuf_printf(sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize)); 632 sbuf_printf(sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize)); 633 sbuf_printf(sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize)); 634 sbuf_printf(sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize)); 635 lsize = B2P(kp.ki_size) - kp.ki_dsize - 636 kp.ki_ssize - kp.ki_tsize - 1; 637 sbuf_printf(sb, "VmLib:\t%8u kB\n", P2K(lsize)); 638 639 /* 640 * Signal masks 641 * 642 * We support up to 128 signals, while Linux supports 32, 643 * but we only define 32 (the same 32 as Linux, to boot), so 644 * just show the lower 32 bits of each mask. XXX hack. 645 * 646 * NB: on certain platforms (Sparc at least) Linux actually 647 * supports 64 signals, but this code is a long way from 648 * running on anything but i386, so ignore that for now. 649 */ 650 PROC_LOCK(p); 651 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 652 /* 653 * I can't seem to find out where the signal mask is in 654 * relation to struct proc, so SigBlk is left unimplemented. 655 */ 656 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 657 sbuf_printf(sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); 658 sbuf_printf(sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); 659 PROC_UNLOCK(p); 660 661 /* 662 * Linux also prints the capability masks, but we don't have 663 * capabilities yet, and when we do get them they're likely to 664 * be meaningless to Linux programs, so we lie. XXX 665 */ 666 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 667 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 668 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 669 670 return (0); 671 } 672 673 /* 674 * Filler function for proc/pid/cmdline 675 */ 676 static int 677 linprocfs_doproccmdline(PFS_FILL_ARGS) 678 { 679 struct ps_strings pstr; 680 int error, i; 681 682 /* 683 * If we are using the ps/cmdline caching, use that. Otherwise 684 * revert back to the old way which only implements full cmdline 685 * for the currept process and just p->p_comm for all other 686 * processes. 687 * Note that if the argv is no longer available, we deliberately 688 * don't fall back on p->p_comm or return an error: the authentic 689 * Linux behaviour is to return zero-length in this case. 690 */ 691 692 PROC_LOCK(p); 693 if (p->p_args && (ps_argsopen || !p_cansee(td, p))) { 694 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 695 PROC_UNLOCK(p); 696 } else if (p != td->td_proc) { 697 PROC_UNLOCK(p); 698 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 699 } else { 700 PROC_UNLOCK(p); 701 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 702 sizeof(pstr)); 703 if (error) 704 return (error); 705 for (i = 0; i < pstr.ps_nargvstr; i++) { 706 sbuf_copyin(sb, pstr.ps_argvstr[i], 0); 707 sbuf_printf(sb, "%c", '\0'); 708 } 709 } 710 711 return (0); 712 } 713 714 /* 715 * Filler function for proc/net/dev 716 */ 717 static int 718 linprocfs_donetdev(PFS_FILL_ARGS) 719 { 720 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 721 struct ifnet *ifp; 722 723 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 724 "Inter-", " Receive", " Transmit", " face", 725 "bytes packets errs drop fifo frame compressed", 726 "bytes packets errs drop fifo frame compressed"); 727 728 TAILQ_FOREACH(ifp, &ifnet, if_link) { 729 linux_ifname(ifp, ifname, sizeof ifname); 730 sbuf_printf(sb, "%6.6s:", ifname); 731 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 732 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 733 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 734 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 735 } 736 737 return (0); 738 } 739 740 #if 0 741 extern struct cdevsw *cdevsw[]; 742 743 /* 744 * Filler function for proc/devices 745 */ 746 static int 747 linprocfs_dodevices(PFS_FILL_ARGS) 748 { 749 int i; 750 751 sbuf_printf(sb, "Character devices:\n"); 752 753 for (i = 0; i < NUMCDEVSW; i++) 754 if (cdevsw[i] != NULL) 755 sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 756 757 sbuf_printf(sb, "\nBlock devices:\n"); 758 759 return (0); 760 } 761 #endif 762 763 /* 764 * Filler function for proc/cmdline 765 */ 766 static int 767 linprocfs_docmdline(PFS_FILL_ARGS) 768 { 769 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 770 sbuf_printf(sb, " ro root=302\n"); 771 return (0); 772 } 773 774 #if 0 775 /* 776 * Filler function for proc/modules 777 */ 778 static int 779 linprocfs_domodules(PFS_FILL_ARGS) 780 { 781 struct linker_file *lf; 782 783 TAILQ_FOREACH(lf, &linker_files, link) { 784 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 785 (unsigned long)lf->size, lf->refs); 786 } 787 return (0); 788 } 789 #endif 790 791 /* 792 * Constructor 793 */ 794 static int 795 linprocfs_init(PFS_INIT_ARGS) 796 { 797 struct pfs_node *root; 798 struct pfs_node *dir; 799 800 root = pi->pi_root; 801 802 #define PFS_CREATE_FILE(name) \ 803 pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD) 804 PFS_CREATE_FILE(cmdline); 805 PFS_CREATE_FILE(cpuinfo); 806 #if 0 807 PFS_CREATE_FILE(devices); 808 #endif 809 PFS_CREATE_FILE(loadavg); 810 PFS_CREATE_FILE(meminfo); 811 #if 0 812 PFS_CREATE_FILE(modules); 813 #endif 814 PFS_CREATE_FILE(mtab); 815 PFS_CREATE_FILE(stat); 816 PFS_CREATE_FILE(uptime); 817 PFS_CREATE_FILE(version); 818 #undef PFS_CREATE_FILE 819 pfs_create_link(root, "self", &procfs_docurproc, 820 NULL, NULL, 0); 821 822 dir = pfs_create_dir(root, "net", NULL, NULL, 0); 823 pfs_create_file(dir, "dev", &linprocfs_donetdev, 824 NULL, NULL, PFS_RD); 825 826 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 827 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 828 NULL, NULL, PFS_RD); 829 pfs_create_link(dir, "exe", &procfs_doprocfile, 830 NULL, &procfs_notsystem, 0); 831 pfs_create_file(dir, "mem", &procfs_doprocmem, 832 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 833 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 834 NULL, NULL, PFS_RD); 835 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 836 NULL, NULL, PFS_RD); 837 838 return (0); 839 } 840 841 /* 842 * Destructor 843 */ 844 static int 845 linprocfs_uninit(PFS_INIT_ARGS) 846 { 847 848 /* nothing to do, pseudofs will GC */ 849 return (0); 850 } 851 852 PSEUDOFS(linprocfs, 1); 853 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 854 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 855