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