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 u_quad_t swaptotal; /* total swap space in bytes */ 120 u_quad_t swapused; /* used swap space in bytes */ 121 u_quad_t 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: %ld\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: %ld\n" 217 "system serial number\t: %s\n" 218 "cycle frequency [Hz]\t: %lu\n" 219 "timer frequency [Hz]\t: %lu\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: %lu.%02lu\n" 224 "kernel unaligned acc\t: %ld (pc=%lx,va=%lx)\n" 225 "user unaligned acc\t: %ld (pc=%lx,va=%lx)\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 (quad_t)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 (quad_t)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->td_proc, osname); 453 linux_get_osrelease(td->td_proc, 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", "%u", kp.ki_size); 518 PS_ADD("rss", "%u", P2K(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 int i; 551 552 mtx_lock_spin(&sched_lock); 553 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 554 555 if (P_SHOULDSTOP(p)) { 556 state = "T (stopped)"; 557 } else { 558 switch(p->p_state) { 559 case PRS_NEW: 560 state = "I (idle)"; 561 break; 562 case PRS_NORMAL: 563 if (p->p_flag & P_WEXIT) { 564 state = "X (exiting)"; 565 break; 566 } 567 switch(td2->td_state) { 568 case TDS_INHIBITED: 569 state = "S (sleeping)"; 570 break; 571 case TDS_RUNQ: 572 case TDS_RUNNING: 573 state = "R (running)"; 574 break; 575 default: 576 state = "? (unknown)"; 577 break; 578 } 579 break; 580 case PRS_ZOMBIE: 581 state = "Z (zombie)"; 582 break; 583 default: 584 state = "? (unknown)"; 585 break; 586 } 587 } 588 mtx_unlock_spin(&sched_lock); 589 590 PROC_LOCK(p); 591 fill_kinfo_proc(p, &kp); 592 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 593 sbuf_printf(sb, "State:\t%s\n", state); 594 595 /* 596 * Credentials 597 */ 598 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 599 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 600 p->p_pptr->p_pid : 0); 601 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 602 p->p_ucred->cr_uid, 603 p->p_ucred->cr_svuid, 604 /* FreeBSD doesn't have fsuid */ 605 p->p_ucred->cr_uid); 606 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 607 p->p_ucred->cr_gid, 608 p->p_ucred->cr_svgid, 609 /* FreeBSD doesn't have fsgid */ 610 p->p_ucred->cr_gid); 611 sbuf_cat(sb, "Groups:\t"); 612 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 613 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 614 PROC_UNLOCK(p); 615 sbuf_putc(sb, '\n'); 616 617 /* 618 * Memory 619 * 620 * While our approximation of VmLib may not be accurate (I 621 * don't know of a simple way to verify it, and I'm not sure 622 * it has much meaning anyway), I believe it's good enough. 623 * 624 * The same code that could (I think) accurately compute VmLib 625 * could also compute VmLck, but I don't really care enough to 626 * implement it. Submissions are welcome. 627 */ 628 sbuf_printf(sb, "VmSize:\t%8u kB\n", B2K(kp.ki_size)); 629 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 630 sbuf_printf(sb, "VmRss:\t%8u kB\n", P2K(kp.ki_rssize)); 631 sbuf_printf(sb, "VmData:\t%8u kB\n", P2K(kp.ki_dsize)); 632 sbuf_printf(sb, "VmStk:\t%8u kB\n", P2K(kp.ki_ssize)); 633 sbuf_printf(sb, "VmExe:\t%8u kB\n", P2K(kp.ki_tsize)); 634 lsize = B2P(kp.ki_size) - kp.ki_dsize - 635 kp.ki_ssize - kp.ki_tsize - 1; 636 sbuf_printf(sb, "VmLib:\t%8u kB\n", P2K(lsize)); 637 638 /* 639 * Signal masks 640 * 641 * We support up to 128 signals, while Linux supports 32, 642 * but we only define 32 (the same 32 as Linux, to boot), so 643 * just show the lower 32 bits of each mask. XXX hack. 644 * 645 * NB: on certain platforms (Sparc at least) Linux actually 646 * supports 64 signals, but this code is a long way from 647 * running on anything but i386, so ignore that for now. 648 */ 649 PROC_LOCK(p); 650 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 651 /* 652 * I can't seem to find out where the signal mask is in 653 * relation to struct proc, so SigBlk is left unimplemented. 654 */ 655 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 656 sbuf_printf(sb, "SigIgn:\t%08x\n", p->p_sigignore.__bits[0]); 657 sbuf_printf(sb, "SigCgt:\t%08x\n", p->p_sigcatch.__bits[0]); 658 PROC_UNLOCK(p); 659 660 /* 661 * Linux also prints the capability masks, but we don't have 662 * capabilities yet, and when we do get them they're likely to 663 * be meaningless to Linux programs, so we lie. XXX 664 */ 665 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 666 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 667 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 668 669 return (0); 670 } 671 672 /* 673 * Filler function for proc/pid/cmdline 674 */ 675 static int 676 linprocfs_doproccmdline(PFS_FILL_ARGS) 677 { 678 struct ps_strings pstr; 679 int error, i; 680 681 /* 682 * If we are using the ps/cmdline caching, use that. Otherwise 683 * revert back to the old way which only implements full cmdline 684 * for the currept process and just p->p_comm for all other 685 * processes. 686 * Note that if the argv is no longer available, we deliberately 687 * don't fall back on p->p_comm or return an error: the authentic 688 * Linux behaviour is to return zero-length in this case. 689 */ 690 691 PROC_LOCK(p); 692 if (p->p_args && (ps_argsopen || !p_cansee(td, p))) { 693 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 694 PROC_UNLOCK(p); 695 } else if (p != td->td_proc) { 696 PROC_UNLOCK(p); 697 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 698 } else { 699 PROC_UNLOCK(p); 700 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 701 sizeof(pstr)); 702 if (error) 703 return (error); 704 for (i = 0; i < pstr.ps_nargvstr; i++) { 705 sbuf_copyin(sb, pstr.ps_argvstr[i], 0); 706 sbuf_printf(sb, "%c", '\0'); 707 } 708 } 709 710 return (0); 711 } 712 713 /* 714 * Filler function for proc/net/dev 715 */ 716 static int 717 linprocfs_donetdev(PFS_FILL_ARGS) 718 { 719 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 720 struct ifnet *ifp; 721 722 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 723 "Inter-", " Receive", " Transmit", " face", 724 "bytes packets errs drop fifo frame compressed", 725 "bytes packets errs drop fifo frame compressed"); 726 727 IFNET_RLOCK(); 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 IFNET_RUNLOCK(); 737 738 return (0); 739 } 740 741 #if 0 742 extern struct cdevsw *cdevsw[]; 743 744 /* 745 * Filler function for proc/devices 746 */ 747 static int 748 linprocfs_dodevices(PFS_FILL_ARGS) 749 { 750 int i; 751 752 sbuf_printf(sb, "Character devices:\n"); 753 754 for (i = 0; i < NUMCDEVSW; i++) 755 if (cdevsw[i] != NULL) 756 sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name); 757 758 sbuf_printf(sb, "\nBlock devices:\n"); 759 760 return (0); 761 } 762 #endif 763 764 /* 765 * Filler function for proc/cmdline 766 */ 767 static int 768 linprocfs_docmdline(PFS_FILL_ARGS) 769 { 770 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 771 sbuf_printf(sb, " ro root=302\n"); 772 return (0); 773 } 774 775 #if 0 776 /* 777 * Filler function for proc/modules 778 */ 779 static int 780 linprocfs_domodules(PFS_FILL_ARGS) 781 { 782 struct linker_file *lf; 783 784 TAILQ_FOREACH(lf, &linker_files, link) { 785 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 786 (unsigned long)lf->size, lf->refs); 787 } 788 return (0); 789 } 790 #endif 791 792 /* 793 * Constructor 794 */ 795 static int 796 linprocfs_init(PFS_INIT_ARGS) 797 { 798 struct pfs_node *root; 799 struct pfs_node *dir; 800 801 root = pi->pi_root; 802 803 #define PFS_CREATE_FILE(name) \ 804 pfs_create_file(root, #name, &linprocfs_do##name, NULL, NULL, PFS_RD) 805 PFS_CREATE_FILE(cmdline); 806 PFS_CREATE_FILE(cpuinfo); 807 #if 0 808 PFS_CREATE_FILE(devices); 809 #endif 810 PFS_CREATE_FILE(loadavg); 811 PFS_CREATE_FILE(meminfo); 812 #if 0 813 PFS_CREATE_FILE(modules); 814 #endif 815 PFS_CREATE_FILE(mtab); 816 PFS_CREATE_FILE(stat); 817 PFS_CREATE_FILE(uptime); 818 PFS_CREATE_FILE(version); 819 #undef PFS_CREATE_FILE 820 pfs_create_link(root, "self", &procfs_docurproc, 821 NULL, NULL, 0); 822 823 dir = pfs_create_dir(root, "net", NULL, NULL, 0); 824 pfs_create_file(dir, "dev", &linprocfs_donetdev, 825 NULL, NULL, PFS_RD); 826 827 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 828 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 829 NULL, NULL, PFS_RD); 830 pfs_create_link(dir, "exe", &procfs_doprocfile, 831 NULL, &procfs_notsystem, 0); 832 pfs_create_file(dir, "mem", &procfs_doprocmem, 833 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 834 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 835 NULL, NULL, PFS_RD); 836 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 837 NULL, NULL, PFS_RD); 838 839 return (0); 840 } 841 842 /* 843 * Destructor 844 */ 845 static int 846 linprocfs_uninit(PFS_INIT_ARGS) 847 { 848 849 /* nothing to do, pseudofs will GC */ 850 return (0); 851 } 852 853 PSEUDOFS(linprocfs, 1); 854 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 855 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 856