linprocfs.c revision 159995
191174Stmm/*- 291174Stmm * Copyright (c) 2000 Dag-Erling Co�dan Sm�rgrav 391174Stmm * Copyright (c) 1999 Pierre Beyssac 491174Stmm * Copyright (c) 1993 Jan-Simon Pendry 591174Stmm * Copyright (c) 1993 691174Stmm * The Regents of the University of California. All rights reserved. 791174Stmm * 891174Stmm * This code is derived from software contributed to Berkeley by 991174Stmm * Jan-Simon Pendry. 1091174Stmm * 1191174Stmm * Redistribution and use in source and binary forms, with or without 1291174Stmm * modification, are permitted provided that the following conditions 1391174Stmm * are met: 1491174Stmm * 1. Redistributions of source code must retain the above copyright 1591174Stmm * notice, this list of conditions and the following disclaimer. 1691174Stmm * 2. Redistributions in binary form must reproduce the above copyright 1791174Stmm * notice, this list of conditions and the following disclaimer in the 1891174Stmm * documentation and/or other materials provided with the distribution. 1991174Stmm * 3. All advertising materials mentioning features or use of this software 2091174Stmm * must display the following acknowledgement: 2191174Stmm * This product includes software developed by the University of 2291174Stmm * California, Berkeley and its contributors. 2391174Stmm * 4. Neither the name of the University nor the names of its contributors 2491174Stmm * may be used to endorse or promote products derived from this software 2591174Stmm * without specific prior written permission. 2691174Stmm * 2791174Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2891174Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2991174Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3091174Stmm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3191174Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3291174Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3391174Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3491174Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3591174Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3691174Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3791174Stmm * SUCH DAMAGE. 3891174Stmm * 3991174Stmm * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94 4091174Stmm */ 4191174Stmm 4291174Stmm#include <sys/cdefs.h> 4391174Stmm__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 159995 2006-06-27 20:11:58Z netchild $"); 4491174Stmm 4591174Stmm#include <sys/param.h> 4691174Stmm#include <sys/queue.h> 4791174Stmm#include <sys/blist.h> 4891174Stmm#include <sys/conf.h> 4991174Stmm#include <sys/exec.h> 5091174Stmm#include <sys/filedesc.h> 5191174Stmm#include <sys/jail.h> 5291174Stmm#include <sys/kernel.h> 5391174Stmm#include <sys/linker.h> 5491174Stmm#include <sys/lock.h> 5591174Stmm#include <sys/malloc.h> 5691174Stmm#include <sys/mount.h> 5791174Stmm#include <sys/mutex.h> 5891174Stmm#include <sys/namei.h> 5991174Stmm#include <sys/proc.h> 6091174Stmm#include <sys/resourcevar.h> 6191174Stmm#include <sys/sbuf.h> 6291174Stmm#include <sys/smp.h> 6391174Stmm#include <sys/socket.h> 6491174Stmm#include <sys/sysctl.h> 6591174Stmm#include <sys/systm.h> 6691174Stmm#include <sys/time.h> 6791174Stmm#include <sys/tty.h> 6891174Stmm#include <sys/user.h> 6991174Stmm#include <sys/vmmeter.h> 7091174Stmm#include <sys/vnode.h> 7191174Stmm 7291174Stmm#include <net/if.h> 7391174Stmm 7491174Stmm#include <vm/vm.h> 7591174Stmm#include <vm/pmap.h> 7691174Stmm#include <vm/vm_map.h> 7791174Stmm#include <vm/vm_param.h> 7891174Stmm#include <vm/vm_object.h> 7991174Stmm#include <vm/swap_pager.h> 8091174Stmm 8191174Stmm#include <machine/clock.h> 8291174Stmm 8391174Stmm#if defined(__i386__) || defined(__amd64__) 8491174Stmm#include <machine/cputypes.h> 8591174Stmm#include <machine/md_var.h> 8691174Stmm#endif /* __i386__ || __amd64__ */ 8791174Stmm 8891174Stmm#include "opt_compat.h" 8991174Stmm#ifdef COMPAT_LINUX32 /* XXX */ 9091174Stmm#include <machine/../linux32/linux.h> 9191174Stmm#else 9291174Stmm#include <machine/../linux/linux.h> 9391174Stmm#endif 9491174Stmm#include <compat/linux/linux_ioctl.h> 9591174Stmm#include <compat/linux/linux_mib.h> 9691174Stmm#include <compat/linux/linux_util.h> 9791174Stmm#include <fs/pseudofs/pseudofs.h> 9891174Stmm#include <fs/procfs/procfs.h> 9991174Stmm 10091174Stmm/* 10191174Stmm * Various conversion macros 10291174Stmm */ 10391174Stmm#define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 10491174Stmm#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 10591174Stmm#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 10691174Stmm#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 10791174Stmm#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 10891174Stmm#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 10991174Stmm 11091174Stmm/** 11191174Stmm * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 11291174Stmm * 11391174Stmm * The linux procfs state field displays one of the characters RSDZTW to 11491174Stmm * denote running, sleeping in an interruptible wait, waiting in an 11591174Stmm * uninteruptible disk sleep, a zombie process, process is being traced 11691174Stmm * or stopped, or process is paging respectively. 11791174Stmm * 11891174Stmm * Our struct kinfo_proc contains the variable ki_stat which contains a 11991174Stmm * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 12091174Stmm * 12191174Stmm * This character array is used with ki_stati-1 as an index and tries to 12291174Stmm * map our states to suitable linux states. 12391174Stmm */ 12491174Stmmstatic char *linux_state = "RRSTZDD"; 12591174Stmm 12691174Stmm/* 12791174Stmm * Filler function for proc/meminfo 12891174Stmm */ 12991174Stmmstatic int 13091174Stmmlinprocfs_domeminfo(PFS_FILL_ARGS) 13191174Stmm{ 13291174Stmm unsigned long memtotal; /* total memory in bytes */ 13391174Stmm unsigned long memused; /* used memory in bytes */ 13491174Stmm unsigned long memfree; /* free memory in bytes */ 13591174Stmm unsigned long memshared; /* shared memory ??? */ 13691174Stmm unsigned long buffers, cached; /* buffer / cache memory ??? */ 13791174Stmm unsigned long long swaptotal; /* total swap space in bytes */ 13891174Stmm unsigned long long swapused; /* used swap space in bytes */ 13991174Stmm unsigned long long swapfree; /* free swap space in bytes */ 14091174Stmm vm_object_t object; 14191174Stmm int i, j; 14291174Stmm 14391174Stmm memtotal = physmem * PAGE_SIZE; 14491174Stmm /* 14591174Stmm * The correct thing here would be: 14691174Stmm * 14791174Stmm memfree = cnt.v_free_count * PAGE_SIZE; 14891174Stmm memused = memtotal - memfree; 14991174Stmm * 15091174Stmm * but it might mislead linux binaries into thinking there 15191174Stmm * is very little memory left, so we cheat and tell them that 15291174Stmm * all memory that isn't wired down is free. 15391174Stmm */ 15491174Stmm memused = cnt.v_wire_count * PAGE_SIZE; 15591174Stmm memfree = memtotal - memused; 15691174Stmm swap_pager_status(&i, &j); 15791174Stmm swaptotal = (unsigned long long)i * PAGE_SIZE; 15891174Stmm swapused = (unsigned long long)j * PAGE_SIZE; 15992889Sobrien swapfree = swaptotal - swapused; 16091174Stmm memshared = 0; 16192889Sobrien mtx_lock(&vm_object_list_mtx); 16292889Sobrien TAILQ_FOREACH(object, &vm_object_list, object_list) 16392889Sobrien if (object->shadow_count > 1) 16491174Stmm memshared += object->resident_page_count; 16591174Stmm mtx_unlock(&vm_object_list_mtx); 16691174Stmm memshared *= PAGE_SIZE; 16791174Stmm /* 16891174Stmm * We'd love to be able to write: 16991174Stmm * 17091174Stmm buffers = bufspace; 17191174Stmm * 17291174Stmm * but bufspace is internal to vfs_bio.c and we don't feel 17391174Stmm * like unstaticizing it just for linprocfs's sake. 17491174Stmm */ 17591174Stmm buffers = 0; 17691174Stmm cached = cnt.v_cache_count * PAGE_SIZE; 17791174Stmm 17891174Stmm sbuf_printf(sb, 17991174Stmm " total: used: free: shared: buffers: cached:\n" 18091174Stmm "Mem: %lu %lu %lu %lu %lu %lu\n" 18191174Stmm "Swap: %llu %llu %llu\n" 18291174Stmm "MemTotal: %9lu kB\n" 18391174Stmm "MemFree: %9lu kB\n" 18491174Stmm "MemShared:%9lu kB\n" 18591174Stmm "Buffers: %9lu kB\n" 18691174Stmm "Cached: %9lu kB\n" 18791174Stmm "SwapTotal:%9llu kB\n" 18891174Stmm "SwapFree: %9llu kB\n", 18991174Stmm memtotal, memused, memfree, memshared, buffers, cached, 19091174Stmm swaptotal, swapused, swapfree, 19191174Stmm B2K(memtotal), B2K(memfree), 19291174Stmm B2K(memshared), B2K(buffers), B2K(cached), 19391174Stmm B2K(swaptotal), B2K(swapfree)); 19491174Stmm 19591174Stmm return (0); 19691174Stmm} 19791174Stmm 19891174Stmm#if defined(__i386__) || defined(__amd64__) 19991174Stmm/* 20091174Stmm * Filler function for proc/cpuinfo (i386 & amd64 version) 20191174Stmm */ 20291174Stmmstatic int 20391174Stmmlinprocfs_docpuinfo(PFS_FILL_ARGS) 20491174Stmm{ 20591174Stmm int hw_model[2]; 20691174Stmm char model[128]; 20791174Stmm size_t size; 20891174Stmm int class, fqmhz, fqkhz; 20991174Stmm int i; 21091174Stmm 21191174Stmm /* 21291174Stmm * We default the flags to include all non-conflicting flags, 21391174Stmm * and the Intel versions of conflicting flags. 21491174Stmm */ 21591174Stmm static char *flags[] = { 21691174Stmm "fpu", "vme", "de", "pse", "tsc", 21791174Stmm "msr", "pae", "mce", "cx8", "apic", 21891174Stmm "sep", "sep", "mtrr", "pge", "mca", 21991174Stmm "cmov", "pat", "pse36", "pn", "b19", 22091174Stmm "b20", "b21", "mmxext", "mmx", "fxsr", 22191174Stmm "xmm", "b26", "b27", "b28", "b29", 22291174Stmm "3dnowext", "3dnow" 22391174Stmm }; 22491174Stmm 22591174Stmm switch (cpu_class) { 22691174Stmm#ifdef __i386__ 22791174Stmm case CPUCLASS_286: 22891174Stmm class = 2; 22991174Stmm break; 23091174Stmm case CPUCLASS_386: 23191174Stmm class = 3; 23291174Stmm break; 23391174Stmm case CPUCLASS_486: 23491174Stmm class = 4; 23591174Stmm break; 23691174Stmm case CPUCLASS_586: 23791174Stmm class = 5; 23891174Stmm break; 23991174Stmm case CPUCLASS_686: 24091174Stmm class = 6; 24191174Stmm break; 24291174Stmm default: 24391174Stmm class = 0; 24491174Stmm break; 24591174Stmm#else /* __amd64__ */ 24691174Stmm default: 24791174Stmm class = 15; 24891174Stmm break; 24991174Stmm#endif 25091174Stmm } 25191174Stmm 25291174Stmm hw_model[0] = CTL_HW; 25391174Stmm hw_model[1] = HW_MODEL; 25491174Stmm model[0] = '\0'; 25591174Stmm size = sizeof(model); 25691174Stmm if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 25791174Stmm strcpy(model, "unknown"); 25891174Stmm for (i = 0; i < mp_ncpus; ++i) { 25991174Stmm sbuf_printf(sb, 26091174Stmm "processor\t: %d\n" 26191174Stmm "vendor_id\t: %.20s\n" 26291174Stmm "cpu family\t: %d\n" 26391174Stmm "model\t\t: %d\n" 26491174Stmm "model name\t: %s\n" 26591174Stmm "stepping\t: %d\n", 26691174Stmm i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 26791174Stmm /* XXX per-cpu vendor / class / model / id? */ 26891174Stmm } 26991174Stmm 27091174Stmm sbuf_cat(sb, 27191174Stmm "flags\t\t:"); 272 273 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) { 274 flags[16] = "fcmov"; 275 } else if (!strcmp(cpu_vendor, "CyrixInstead")) { 276 flags[24] = "cxmmx"; 277 } 278 279 for (i = 0; i < 32; i++) 280 if (cpu_feature & (1 << i)) 281 sbuf_printf(sb, " %s", flags[i]); 282 sbuf_cat(sb, "\n"); 283 if (class >= 5) { 284 fqmhz = (tsc_freq + 4999) / 1000000; 285 fqkhz = ((tsc_freq + 4999) / 10000) % 100; 286 sbuf_printf(sb, 287 "cpu MHz\t\t: %d.%02d\n" 288 "bogomips\t: %d.%02d\n", 289 fqmhz, fqkhz, fqmhz, fqkhz); 290 } 291 292 return (0); 293} 294#endif /* __i386__ || __amd64__ */ 295 296/* 297 * Filler function for proc/mtab 298 * 299 * This file doesn't exist in Linux' procfs, but is included here so 300 * users can symlink /compat/linux/etc/mtab to /proc/mtab 301 */ 302static int 303linprocfs_domtab(PFS_FILL_ARGS) 304{ 305 struct nameidata nd; 306 struct mount *mp; 307 const char *lep; 308 char *dlep, *flep, *mntto, *mntfrom, *fstype; 309 size_t lep_len; 310 int error; 311 312 /* resolve symlinks etc. in the emulation tree prefix */ 313 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 314 flep = NULL; 315 if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0) 316 lep = linux_emul_path; 317 else 318 lep = dlep; 319 lep_len = strlen(lep); 320 321 mtx_lock(&mountlist_mtx); 322 error = 0; 323 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 324 /* determine device name */ 325 mntfrom = mp->mnt_stat.f_mntfromname; 326 327 /* determine mount point */ 328 mntto = mp->mnt_stat.f_mntonname; 329 if (strncmp(mntto, lep, lep_len) == 0 && 330 mntto[lep_len] == '/') 331 mntto += lep_len; 332 333 /* determine fs type */ 334 fstype = mp->mnt_stat.f_fstypename; 335 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 336 mntfrom = fstype = "proc"; 337 else if (strcmp(fstype, "procfs") == 0) 338 continue; 339 340 if (strcmp(fstype, "linsysfs") == 0) { 341 sbuf_printf(sb, "/sys %s sysfs %s", mntto, 342 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 343 } else { 344 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 345 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 346 } 347#define ADD_OPTION(opt, name) \ 348 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 349 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 350 ADD_OPTION(MNT_NOEXEC, "noexec"); 351 ADD_OPTION(MNT_NOSUID, "nosuid"); 352 ADD_OPTION(MNT_UNION, "union"); 353 ADD_OPTION(MNT_ASYNC, "async"); 354 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 355 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 356 ADD_OPTION(MNT_NOATIME, "noatime"); 357#undef ADD_OPTION 358 /* a real Linux mtab will also show NFS options */ 359 sbuf_printf(sb, " 0 0\n"); 360 } 361 mtx_unlock(&mountlist_mtx); 362 if (flep != NULL) 363 free(flep, M_TEMP); 364 return (error); 365} 366 367/* 368 * Filler function for proc/stat 369 */ 370static int 371linprocfs_dostat(PFS_FILL_ARGS) 372{ 373 int i; 374 375 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 376 T2J(cp_time[CP_USER]), 377 T2J(cp_time[CP_NICE]), 378 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 379 T2J(cp_time[CP_IDLE])); 380 for (i = 0; i < mp_ncpus; ++i) 381 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 382 T2J(cp_time[CP_USER]) / mp_ncpus, 383 T2J(cp_time[CP_NICE]) / mp_ncpus, 384 T2J(cp_time[CP_SYS]) / mp_ncpus, 385 T2J(cp_time[CP_IDLE]) / mp_ncpus); 386 sbuf_printf(sb, 387 "disk 0 0 0 0\n" 388 "page %u %u\n" 389 "swap %u %u\n" 390 "intr %u\n" 391 "ctxt %u\n" 392 "btime %lld\n", 393 cnt.v_vnodepgsin, 394 cnt.v_vnodepgsout, 395 cnt.v_swappgsin, 396 cnt.v_swappgsout, 397 cnt.v_intr, 398 cnt.v_swtch, 399 (long long)boottime.tv_sec); 400 return (0); 401} 402 403/* 404 * Filler function for proc/uptime 405 */ 406static int 407linprocfs_douptime(PFS_FILL_ARGS) 408{ 409 struct timeval tv; 410 411 getmicrouptime(&tv); 412 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 413 (long long)tv.tv_sec, tv.tv_usec / 10000, 414 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 415 return (0); 416} 417 418/* 419 * Filler function for proc/version 420 */ 421static int 422linprocfs_doversion(PFS_FILL_ARGS) 423{ 424 char osname[LINUX_MAX_UTSNAME]; 425 char osrelease[LINUX_MAX_UTSNAME]; 426 427 linux_get_osname(td, osname); 428 linux_get_osrelease(td, osrelease); 429 430 sbuf_printf(sb, 431 "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")" 432 " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease); 433 return (0); 434} 435 436/* 437 * Filler function for proc/loadavg 438 */ 439static int 440linprocfs_doloadavg(PFS_FILL_ARGS) 441{ 442 sbuf_printf(sb, 443 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 444 (int)(averunnable.ldavg[0] / averunnable.fscale), 445 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 446 (int)(averunnable.ldavg[1] / averunnable.fscale), 447 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 448 (int)(averunnable.ldavg[2] / averunnable.fscale), 449 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 450 1, /* number of running tasks */ 451 nprocs, /* number of tasks */ 452 lastpid /* the last pid */ 453 ); 454 455 return (0); 456} 457 458/* 459 * Filler function for proc/pid/stat 460 */ 461static int 462linprocfs_doprocstat(PFS_FILL_ARGS) 463{ 464 struct kinfo_proc kp; 465 466 PROC_LOCK(p); 467 fill_kinfo_proc(p, &kp); 468 sbuf_printf(sb, "%d", p->p_pid); 469#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 470 PS_ADD("comm", "(%s)", p->p_comm); 471 KASSERT(kp.ki_stat <= sizeof(linux_state), 472 ("linprocfs: don't know how to handle unknown FreeBSD state")); 473 PS_ADD("state", "%c", linux_state[kp.ki_stat - 1]); 474 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 475 PS_ADD("pgrp", "%d", p->p_pgid); 476 PS_ADD("session", "%d", p->p_session->s_sid); 477 PROC_UNLOCK(p); 478 PS_ADD("tty", "%d", 0); /* XXX */ 479 PS_ADD("tpgid", "%d", kp.ki_tpgid); 480 PS_ADD("flags", "%u", 0); /* XXX */ 481 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 482 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 483 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 484 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 485 PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 486 PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 487 PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 488 PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 489 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 490 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 491 PS_ADD("0", "%d", 0); /* removed field */ 492 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 493 /* XXX: starttime is not right, it is the _same_ for _every_ process. 494 It should be the number of jiffies between system boot and process 495 start. */ 496 PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 497 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 498 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 499 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 500 PS_ADD("startcode", "%u", (unsigned)0); 501 PS_ADD("endcode", "%u", 0); /* XXX */ 502 PS_ADD("startstack", "%u", 0); /* XXX */ 503 PS_ADD("kstkesp", "%u", 0); /* XXX */ 504 PS_ADD("kstkeip", "%u", 0); /* XXX */ 505 PS_ADD("signal", "%u", 0); /* XXX */ 506 PS_ADD("blocked", "%u", 0); /* XXX */ 507 PS_ADD("sigignore", "%u", 0); /* XXX */ 508 PS_ADD("sigcatch", "%u", 0); /* XXX */ 509 PS_ADD("wchan", "%u", 0); /* XXX */ 510 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 511 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 512 PS_ADD("exitsignal", "%d", 0); /* XXX */ 513 PS_ADD("processor", "%u", kp.ki_lastcpu); 514 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 515 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 516#undef PS_ADD 517 sbuf_putc(sb, '\n'); 518 519 return (0); 520} 521 522/* 523 * Filler function for proc/pid/statm 524 */ 525static int 526linprocfs_doprocstatm(PFS_FILL_ARGS) 527{ 528 struct kinfo_proc kp; 529 segsz_t lsize; 530 531 PROC_LOCK(p); 532 fill_kinfo_proc(p, &kp); 533 PROC_UNLOCK(p); 534 535 /* 536 * See comments in linprocfs_doprocstatus() regarding the 537 * computation of lsize. 538 */ 539 /* size resident share trs drs lrs dt */ 540 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 541 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 542 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 543 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 544 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 545 lsize = B2P(kp.ki_size) - kp.ki_dsize - 546 kp.ki_ssize - kp.ki_tsize - 1; 547 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 548 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 549 550 return (0); 551} 552 553/* 554 * Filler function for proc/pid/status 555 */ 556static int 557linprocfs_doprocstatus(PFS_FILL_ARGS) 558{ 559 struct kinfo_proc kp; 560 char *state; 561 segsz_t lsize; 562 struct thread *td2; 563 struct sigacts *ps; 564 int i; 565 566 PROC_LOCK(p); 567 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 568 569 if (P_SHOULDSTOP(p)) { 570 state = "T (stopped)"; 571 } else { 572 mtx_lock_spin(&sched_lock); 573 switch(p->p_state) { 574 case PRS_NEW: 575 state = "I (idle)"; 576 break; 577 case PRS_NORMAL: 578 if (p->p_flag & P_WEXIT) { 579 state = "X (exiting)"; 580 break; 581 } 582 switch(td2->td_state) { 583 case TDS_INHIBITED: 584 state = "S (sleeping)"; 585 break; 586 case TDS_RUNQ: 587 case TDS_RUNNING: 588 state = "R (running)"; 589 break; 590 default: 591 state = "? (unknown)"; 592 break; 593 } 594 break; 595 case PRS_ZOMBIE: 596 state = "Z (zombie)"; 597 break; 598 default: 599 state = "? (unknown)"; 600 break; 601 } 602 mtx_unlock_spin(&sched_lock); 603 } 604 605 fill_kinfo_proc(p, &kp); 606 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 607 sbuf_printf(sb, "State:\t%s\n", state); 608 609 /* 610 * Credentials 611 */ 612 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 613 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 614 p->p_pptr->p_pid : 0); 615 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 616 p->p_ucred->cr_uid, 617 p->p_ucred->cr_svuid, 618 /* FreeBSD doesn't have fsuid */ 619 p->p_ucred->cr_uid); 620 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 621 p->p_ucred->cr_gid, 622 p->p_ucred->cr_svgid, 623 /* FreeBSD doesn't have fsgid */ 624 p->p_ucred->cr_gid); 625 sbuf_cat(sb, "Groups:\t"); 626 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 627 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 628 PROC_UNLOCK(p); 629 sbuf_putc(sb, '\n'); 630 631 /* 632 * Memory 633 * 634 * While our approximation of VmLib may not be accurate (I 635 * don't know of a simple way to verify it, and I'm not sure 636 * it has much meaning anyway), I believe it's good enough. 637 * 638 * The same code that could (I think) accurately compute VmLib 639 * could also compute VmLck, but I don't really care enough to 640 * implement it. Submissions are welcome. 641 */ 642 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 643 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 644 sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 645 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 646 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 647 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 648 lsize = B2P(kp.ki_size) - kp.ki_dsize - 649 kp.ki_ssize - kp.ki_tsize - 1; 650 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 651 652 /* 653 * Signal masks 654 * 655 * We support up to 128 signals, while Linux supports 32, 656 * but we only define 32 (the same 32 as Linux, to boot), so 657 * just show the lower 32 bits of each mask. XXX hack. 658 * 659 * NB: on certain platforms (Sparc at least) Linux actually 660 * supports 64 signals, but this code is a long way from 661 * running on anything but i386, so ignore that for now. 662 */ 663 PROC_LOCK(p); 664 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 665 /* 666 * I can't seem to find out where the signal mask is in 667 * relation to struct proc, so SigBlk is left unimplemented. 668 */ 669 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 670 ps = p->p_sigacts; 671 mtx_lock(&ps->ps_mtx); 672 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 673 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 674 mtx_unlock(&ps->ps_mtx); 675 PROC_UNLOCK(p); 676 677 /* 678 * Linux also prints the capability masks, but we don't have 679 * capabilities yet, and when we do get them they're likely to 680 * be meaningless to Linux programs, so we lie. XXX 681 */ 682 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 683 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 684 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 685 686 return (0); 687} 688 689 690/* 691 * Filler function for proc/pid/cwd 692 */ 693static int 694linprocfs_doproccwd(PFS_FILL_ARGS) 695{ 696 char *fullpath = "unknown"; 697 char *freepath = NULL; 698 699 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 700 sbuf_printf(sb, "%s", fullpath); 701 if (freepath) 702 free(freepath, M_TEMP); 703 return (0); 704} 705 706/* 707 * Filler function for proc/pid/root 708 */ 709static int 710linprocfs_doprocroot(PFS_FILL_ARGS) 711{ 712 struct vnode *rvp; 713 char *fullpath = "unknown"; 714 char *freepath = NULL; 715 716 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 717 vn_fullpath(td, rvp, &fullpath, &freepath); 718 sbuf_printf(sb, "%s", fullpath); 719 if (freepath) 720 free(freepath, M_TEMP); 721 return (0); 722} 723 724/* 725 * Filler function for proc/pid/cmdline 726 */ 727static int 728linprocfs_doproccmdline(PFS_FILL_ARGS) 729{ 730 struct ps_strings pstr; 731 char **ps_argvstr; 732 int error, i; 733 734 /* 735 * If we are using the ps/cmdline caching, use that. Otherwise 736 * revert back to the old way which only implements full cmdline 737 * for the currept process and just p->p_comm for all other 738 * processes. 739 * Note that if the argv is no longer available, we deliberately 740 * don't fall back on p->p_comm or return an error: the authentic 741 * Linux behaviour is to return zero-length in this case. 742 */ 743 744 PROC_LOCK(p); 745 if (p->p_args && p_cansee(td, p) == 0) { 746 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 747 PROC_UNLOCK(p); 748 } else if (p != td->td_proc) { 749 PROC_UNLOCK(p); 750 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 751 } else { 752 PROC_UNLOCK(p); 753 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 754 sizeof(pstr)); 755 if (error) 756 return (error); 757 if (pstr.ps_nargvstr > ARG_MAX) 758 return (E2BIG); 759 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 760 M_TEMP, M_WAITOK); 761 error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 762 pstr.ps_nargvstr * sizeof(char *)); 763 if (error) { 764 free(ps_argvstr, M_TEMP); 765 return (error); 766 } 767 for (i = 0; i < pstr.ps_nargvstr; i++) { 768 sbuf_copyin(sb, ps_argvstr[i], 0); 769 sbuf_printf(sb, "%c", '\0'); 770 } 771 free(ps_argvstr, M_TEMP); 772 } 773 774 return (0); 775} 776 777/* 778 * Filler function for proc/pid/environ 779 */ 780static int 781linprocfs_doprocenviron(PFS_FILL_ARGS) 782{ 783 sbuf_printf(sb, "doprocenviron\n%c", '\0'); 784 785 return (0); 786} 787 788/* 789 * Filler function for proc/pid/maps 790 */ 791static int 792linprocfs_doprocmaps(PFS_FILL_ARGS) 793{ 794 char mebuffer[512]; 795 vm_map_t map = &p->p_vmspace->vm_map; 796 vm_map_entry_t entry; 797 vm_object_t obj, tobj, lobj; 798 vm_ooffset_t off = 0; 799 char *name = "", *freename = NULL; 800 size_t len; 801 ino_t ino; 802 int ref_count, shadow_count, flags; 803 int error; 804 struct vnode *vp; 805 struct vattr vat; 806 807 PROC_LOCK(p); 808 error = p_candebug(td, p); 809 PROC_UNLOCK(p); 810 if (error) 811 return (error); 812 813 if (uio->uio_rw != UIO_READ) 814 return (EOPNOTSUPP); 815 816 if (uio->uio_offset != 0) 817 return (0); 818 819 error = 0; 820 if (map != &curthread->td_proc->p_vmspace->vm_map) 821 vm_map_lock_read(map); 822 for (entry = map->header.next; 823 ((uio->uio_resid > 0) && (entry != &map->header)); 824 entry = entry->next) { 825 name = ""; 826 freename = NULL; 827 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 828 continue; 829 obj = entry->object.vm_object; 830 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) 831 lobj = tobj; 832 ino = 0; 833 if (lobj) { 834 vp = lobj->handle; 835 VM_OBJECT_LOCK(lobj); 836 off = IDX_TO_OFF(lobj->size); 837 if (lobj->type == OBJT_VNODE && lobj->handle) { 838 vn_fullpath(td, vp, &name, &freename); 839 VOP_GETATTR(vp, &vat, td->td_ucred, td); 840 ino = vat.va_fileid; 841 } 842 flags = obj->flags; 843 ref_count = obj->ref_count; 844 shadow_count = obj->shadow_count; 845 VM_OBJECT_UNLOCK(lobj); 846 } else { 847 flags = 0; 848 ref_count = 0; 849 shadow_count = 0; 850 } 851 852 /* 853 * format: 854 * start, end, access, offset, major, minor, inode, name. 855 */ 856 snprintf(mebuffer, sizeof mebuffer, 857 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 858 (u_long)entry->start, (u_long)entry->end, 859 (entry->protection & VM_PROT_READ)?"r":"-", 860 (entry->protection & VM_PROT_WRITE)?"w":"-", 861 (entry->protection & VM_PROT_EXECUTE)?"x":"-", 862 "p", 863 (u_long)off, 864 0, 865 0, 866 (u_long)ino, 867 *name ? " " : "", 868 name 869 ); 870 if (freename) 871 free(freename, M_TEMP); 872 len = strlen(mebuffer); 873 if (len > uio->uio_resid) 874 len = uio->uio_resid; /* 875 * XXX We should probably return 876 * EFBIG here, as in procfs. 877 */ 878 error = uiomove(mebuffer, len, uio); 879 if (error) 880 break; 881 } 882 if (map != &curthread->td_proc->p_vmspace->vm_map) 883 vm_map_unlock_read(map); 884 885 return (error); 886} 887 888/* 889 * Filler function for proc/net/dev 890 */ 891static int 892linprocfs_donetdev(PFS_FILL_ARGS) 893{ 894 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 895 struct ifnet *ifp; 896 897 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 898 "Inter-", " Receive", " Transmit", " face", 899 "bytes packets errs drop fifo frame compressed", 900 "bytes packets errs drop fifo frame compressed"); 901 902 IFNET_RLOCK(); 903 TAILQ_FOREACH(ifp, &ifnet, if_link) { 904 linux_ifname(ifp, ifname, sizeof ifname); 905 sbuf_printf(sb, "%6.6s:", ifname); 906 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 907 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 908 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 909 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 910 } 911 IFNET_RUNLOCK(); 912 913 return (0); 914} 915 916/* 917 * Filler function for proc/scsi/device_info 918 */ 919static int 920linprocfs_doscsidevinfo(PFS_FILL_ARGS) 921{ 922 return (0); 923} 924 925/* 926 * Filler function for proc/scsi/scsi 927 */ 928static int 929linprocfs_doscsiscsi(PFS_FILL_ARGS) 930{ 931 return (0); 932} 933 934extern struct cdevsw *cdevsw[]; 935 936/* 937 * Filler function for proc/devices 938 */ 939static int 940linprocfs_dodevices(PFS_FILL_ARGS) 941{ 942 char *char_devices; 943 sbuf_printf(sb, "Character devices:\n"); 944 945 char_devices = linux_get_char_devices(); 946 sbuf_printf(sb, "%s", char_devices); 947 linux_free_get_char_devices(char_devices); 948 949 sbuf_printf(sb, "\nBlock devices:\n"); 950 951 return (0); 952} 953 954/* 955 * Filler function for proc/cmdline 956 */ 957static int 958linprocfs_docmdline(PFS_FILL_ARGS) 959{ 960 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 961 sbuf_printf(sb, " ro root=302\n"); 962 return (0); 963} 964 965#if 0 966/* 967 * Filler function for proc/modules 968 */ 969static int 970linprocfs_domodules(PFS_FILL_ARGS) 971{ 972 struct linker_file *lf; 973 974 TAILQ_FOREACH(lf, &linker_files, link) { 975 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 976 (unsigned long)lf->size, lf->refs); 977 } 978 return (0); 979} 980#endif 981 982/* 983 * Constructor 984 */ 985static int 986linprocfs_init(PFS_INIT_ARGS) 987{ 988 struct pfs_node *root; 989 struct pfs_node *dir; 990 991 root = pi->pi_root; 992 993 /* /proc/... */ 994 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 995 NULL, NULL, PFS_RD); 996 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 997 NULL, NULL, PFS_RD); 998 pfs_create_file(root, "devices", &linprocfs_dodevices, 999 NULL, NULL, PFS_RD); 1000 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1001 NULL, NULL, PFS_RD); 1002 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1003 NULL, NULL, PFS_RD); 1004#if 0 1005 pfs_create_file(root, "modules", &linprocfs_domodules, 1006 NULL, NULL, PFS_RD); 1007#endif 1008 pfs_create_file(root, "mounts", &linprocfs_domtab, 1009 NULL, NULL, PFS_RD); 1010 pfs_create_file(root, "mtab", &linprocfs_domtab, 1011 NULL, NULL, PFS_RD); 1012 pfs_create_link(root, "self", &procfs_docurproc, 1013 NULL, NULL, 0); 1014 pfs_create_file(root, "stat", &linprocfs_dostat, 1015 NULL, NULL, PFS_RD); 1016 pfs_create_file(root, "uptime", &linprocfs_douptime, 1017 NULL, NULL, PFS_RD); 1018 pfs_create_file(root, "version", &linprocfs_doversion, 1019 NULL, NULL, PFS_RD); 1020 1021 /* /proc/net/... */ 1022 dir = pfs_create_dir(root, "net", NULL, NULL, 0); 1023 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1024 NULL, NULL, PFS_RD); 1025 1026 /* /proc/<pid>/... */ 1027 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP); 1028 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1029 NULL, NULL, PFS_RD); 1030 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1031 NULL, NULL, 0); 1032 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1033 NULL, NULL, PFS_RD); 1034 pfs_create_link(dir, "exe", &procfs_doprocfile, 1035 NULL, &procfs_notsystem, 0); 1036 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1037 NULL, NULL, PFS_RD); 1038 pfs_create_file(dir, "mem", &procfs_doprocmem, 1039 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW); 1040 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1041 NULL, NULL, 0); 1042 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1043 NULL, NULL, PFS_RD); 1044 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1045 NULL, NULL, PFS_RD); 1046 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1047 NULL, NULL, PFS_RD); 1048 1049 /* /proc/scsi/... */ 1050 dir = pfs_create_dir(root, "scsi", NULL, NULL, 0); 1051 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1052 NULL, NULL, PFS_RD); 1053 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1054 NULL, NULL, PFS_RD); 1055 return (0); 1056} 1057 1058/* 1059 * Destructor 1060 */ 1061static int 1062linprocfs_uninit(PFS_INIT_ARGS) 1063{ 1064 1065 /* nothing to do, pseudofs will GC */ 1066 return (0); 1067} 1068 1069PSEUDOFS(linprocfs, 1); 1070MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1071MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1072