linprocfs.c revision 212723
1/*- 2 * Copyright (c) 2000 Dag-Erling Co��dan Sm��rgrav 3 * Copyright (c) 1999 Pierre Beyssac 4 * Copyright (c) 1993 Jan-Simon Pendry 5 * Copyright (c) 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Jan-Simon Pendry. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94 40 */ 41 42#include "opt_compat.h" 43 44#include <sys/cdefs.h> 45__FBSDID("$FreeBSD: head/sys/compat/linprocfs/linprocfs.c 212723 2010-09-16 07:56:34Z des $"); 46 47#include <sys/param.h> 48#include <sys/queue.h> 49#include <sys/blist.h> 50#include <sys/conf.h> 51#include <sys/exec.h> 52#include <sys/fcntl.h> 53#include <sys/filedesc.h> 54#include <sys/jail.h> 55#include <sys/kernel.h> 56#include <sys/linker.h> 57#include <sys/lock.h> 58#include <sys/malloc.h> 59#include <sys/mount.h> 60#include <sys/msg.h> 61#include <sys/mutex.h> 62#include <sys/namei.h> 63#include <sys/proc.h> 64#include <sys/resourcevar.h> 65#include <sys/sbuf.h> 66#include <sys/sem.h> 67#include <sys/smp.h> 68#include <sys/socket.h> 69#include <sys/sysctl.h> 70#include <sys/systm.h> 71#include <sys/time.h> 72#include <sys/tty.h> 73#include <sys/user.h> 74#include <sys/vmmeter.h> 75#include <sys/vnode.h> 76#include <sys/bus.h> 77 78#include <net/if.h> 79#include <net/vnet.h> 80 81#include <vm/vm.h> 82#include <vm/vm_extern.h> 83#include <vm/pmap.h> 84#include <vm/vm_map.h> 85#include <vm/vm_param.h> 86#include <vm/vm_object.h> 87#include <vm/swap_pager.h> 88 89#include <machine/clock.h> 90 91#include <geom/geom.h> 92#include <geom/geom_int.h> 93 94#if defined(__i386__) || defined(__amd64__) 95#include <machine/cputypes.h> 96#include <machine/md_var.h> 97#endif /* __i386__ || __amd64__ */ 98 99#ifdef COMPAT_LINUX32 /* XXX */ 100#include <machine/../linux32/linux.h> 101#else 102#include <machine/../linux/linux.h> 103#endif 104#include <compat/linux/linux_ioctl.h> 105#include <compat/linux/linux_mib.h> 106#include <compat/linux/linux_util.h> 107#include <fs/pseudofs/pseudofs.h> 108#include <fs/procfs/procfs.h> 109 110/* 111 * Various conversion macros 112 */ 113#define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */ 114#define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */ 115#define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 116#define B2K(x) ((x) >> 10) /* bytes to kbytes */ 117#define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 118#define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 119#define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 120#define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000) 121 122/** 123 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 124 * 125 * The linux procfs state field displays one of the characters RSDZTW to 126 * denote running, sleeping in an interruptible wait, waiting in an 127 * uninterruptible disk sleep, a zombie process, process is being traced 128 * or stopped, or process is paging respectively. 129 * 130 * Our struct kinfo_proc contains the variable ki_stat which contains a 131 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 132 * 133 * This character array is used with ki_stati-1 as an index and tries to 134 * map our states to suitable linux states. 135 */ 136static char linux_state[] = "RRSTZDD"; 137 138/* 139 * Filler function for proc/meminfo 140 */ 141static int 142linprocfs_domeminfo(PFS_FILL_ARGS) 143{ 144 unsigned long memtotal; /* total memory in bytes */ 145 unsigned long memused; /* used memory in bytes */ 146 unsigned long memfree; /* free memory in bytes */ 147 unsigned long memshared; /* shared memory ??? */ 148 unsigned long buffers, cached; /* buffer / cache memory ??? */ 149 unsigned long long swaptotal; /* total swap space in bytes */ 150 unsigned long long swapused; /* used swap space in bytes */ 151 unsigned long long swapfree; /* free swap space in bytes */ 152 vm_object_t object; 153 int i, j; 154 155 memtotal = physmem * PAGE_SIZE; 156 /* 157 * The correct thing here would be: 158 * 159 memfree = cnt.v_free_count * PAGE_SIZE; 160 memused = memtotal - memfree; 161 * 162 * but it might mislead linux binaries into thinking there 163 * is very little memory left, so we cheat and tell them that 164 * all memory that isn't wired down is free. 165 */ 166 memused = cnt.v_wire_count * PAGE_SIZE; 167 memfree = memtotal - memused; 168 swap_pager_status(&i, &j); 169 swaptotal = (unsigned long long)i * PAGE_SIZE; 170 swapused = (unsigned long long)j * PAGE_SIZE; 171 swapfree = swaptotal - swapused; 172 memshared = 0; 173 mtx_lock(&vm_object_list_mtx); 174 TAILQ_FOREACH(object, &vm_object_list, object_list) 175 if (object->shadow_count > 1) 176 memshared += object->resident_page_count; 177 mtx_unlock(&vm_object_list_mtx); 178 memshared *= PAGE_SIZE; 179 /* 180 * We'd love to be able to write: 181 * 182 buffers = bufspace; 183 * 184 * but bufspace is internal to vfs_bio.c and we don't feel 185 * like unstaticizing it just for linprocfs's sake. 186 */ 187 buffers = 0; 188 cached = cnt.v_cache_count * PAGE_SIZE; 189 190 sbuf_printf(sb, 191 " total: used: free: shared: buffers: cached:\n" 192 "Mem: %lu %lu %lu %lu %lu %lu\n" 193 "Swap: %llu %llu %llu\n" 194 "MemTotal: %9lu kB\n" 195 "MemFree: %9lu kB\n" 196 "MemShared:%9lu kB\n" 197 "Buffers: %9lu kB\n" 198 "Cached: %9lu kB\n" 199 "SwapTotal:%9llu kB\n" 200 "SwapFree: %9llu kB\n", 201 memtotal, memused, memfree, memshared, buffers, cached, 202 swaptotal, swapused, swapfree, 203 B2K(memtotal), B2K(memfree), 204 B2K(memshared), B2K(buffers), B2K(cached), 205 B2K(swaptotal), B2K(swapfree)); 206 207 return (0); 208} 209 210#if defined(__i386__) || defined(__amd64__) 211/* 212 * Filler function for proc/cpuinfo (i386 & amd64 version) 213 */ 214static int 215linprocfs_docpuinfo(PFS_FILL_ARGS) 216{ 217 int hw_model[2]; 218 char model[128]; 219 size_t size; 220 int class, fqmhz, fqkhz; 221 int i; 222 223 /* 224 * We default the flags to include all non-conflicting flags, 225 * and the Intel versions of conflicting flags. 226 */ 227 static char *flags[] = { 228 "fpu", "vme", "de", "pse", "tsc", 229 "msr", "pae", "mce", "cx8", "apic", 230 "sep", "sep", "mtrr", "pge", "mca", 231 "cmov", "pat", "pse36", "pn", "b19", 232 "b20", "b21", "mmxext", "mmx", "fxsr", 233 "xmm", "sse2", "b27", "b28", "b29", 234 "3dnowext", "3dnow" 235 }; 236 237 switch (cpu_class) { 238#ifdef __i386__ 239 case CPUCLASS_286: 240 class = 2; 241 break; 242 case CPUCLASS_386: 243 class = 3; 244 break; 245 case CPUCLASS_486: 246 class = 4; 247 break; 248 case CPUCLASS_586: 249 class = 5; 250 break; 251 case CPUCLASS_686: 252 class = 6; 253 break; 254 default: 255 class = 0; 256 break; 257#else /* __amd64__ */ 258 default: 259 class = 15; 260 break; 261#endif 262 } 263 264 hw_model[0] = CTL_HW; 265 hw_model[1] = HW_MODEL; 266 model[0] = '\0'; 267 size = sizeof(model); 268 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 269 strcpy(model, "unknown"); 270 for (i = 0; i < mp_ncpus; ++i) { 271 sbuf_printf(sb, 272 "processor\t: %d\n" 273 "vendor_id\t: %.20s\n" 274 "cpu family\t: %d\n" 275 "model\t\t: %d\n" 276 "model name\t: %s\n" 277 "stepping\t: %d\n\n", 278 i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 279 /* XXX per-cpu vendor / class / model / id? */ 280 } 281 282 sbuf_cat(sb, "flags\t\t:"); 283 284#ifdef __i386__ 285 switch (cpu_vendor_id) { 286 case CPU_VENDOR_AMD: 287 if (class < 6) 288 flags[16] = "fcmov"; 289 break; 290 case CPU_VENDOR_CYRIX: 291 flags[24] = "cxmmx"; 292 break; 293 } 294#endif 295 296 for (i = 0; i < 32; i++) 297 if (cpu_feature & (1 << i)) 298 sbuf_printf(sb, " %s", flags[i]); 299 sbuf_cat(sb, "\n"); 300 if (class >= 5) { 301 fqmhz = (tsc_freq + 4999) / 1000000; 302 fqkhz = ((tsc_freq + 4999) / 10000) % 100; 303 sbuf_printf(sb, 304 "cpu MHz\t\t: %d.%02d\n" 305 "bogomips\t: %d.%02d\n", 306 fqmhz, fqkhz, fqmhz, fqkhz); 307 } 308 309 return (0); 310} 311#endif /* __i386__ || __amd64__ */ 312 313/* 314 * Filler function for proc/mtab 315 * 316 * This file doesn't exist in Linux' procfs, but is included here so 317 * users can symlink /compat/linux/etc/mtab to /proc/mtab 318 */ 319static int 320linprocfs_domtab(PFS_FILL_ARGS) 321{ 322 struct nameidata nd; 323 struct mount *mp; 324 const char *lep; 325 char *dlep, *flep, *mntto, *mntfrom, *fstype; 326 size_t lep_len; 327 int error; 328 329 /* resolve symlinks etc. in the emulation tree prefix */ 330 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 331 flep = NULL; 332 error = namei(&nd); 333 lep = linux_emul_path; 334 if (error == 0) { 335 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 336 lep = dlep; 337 vrele(nd.ni_vp); 338 VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 339 } 340 lep_len = strlen(lep); 341 342 mtx_lock(&mountlist_mtx); 343 error = 0; 344 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 345 /* determine device name */ 346 mntfrom = mp->mnt_stat.f_mntfromname; 347 348 /* determine mount point */ 349 mntto = mp->mnt_stat.f_mntonname; 350 if (strncmp(mntto, lep, lep_len) == 0 && 351 mntto[lep_len] == '/') 352 mntto += lep_len; 353 354 /* determine fs type */ 355 fstype = mp->mnt_stat.f_fstypename; 356 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 357 mntfrom = fstype = "proc"; 358 else if (strcmp(fstype, "procfs") == 0) 359 continue; 360 361 if (strcmp(fstype, "linsysfs") == 0) { 362 sbuf_printf(sb, "/sys %s sysfs %s", mntto, 363 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 364 } else { 365 /* For Linux msdosfs is called vfat */ 366 if (strcmp(fstype, "msdosfs") == 0) 367 fstype = "vfat"; 368 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 369 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 370 } 371#define ADD_OPTION(opt, name) \ 372 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 373 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 374 ADD_OPTION(MNT_NOEXEC, "noexec"); 375 ADD_OPTION(MNT_NOSUID, "nosuid"); 376 ADD_OPTION(MNT_UNION, "union"); 377 ADD_OPTION(MNT_ASYNC, "async"); 378 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 379 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 380 ADD_OPTION(MNT_NOATIME, "noatime"); 381#undef ADD_OPTION 382 /* a real Linux mtab will also show NFS options */ 383 sbuf_printf(sb, " 0 0\n"); 384 } 385 mtx_unlock(&mountlist_mtx); 386 if (flep != NULL) 387 free(flep, M_TEMP); 388 return (error); 389} 390 391/* 392 * Filler function for proc/partitions 393 * 394 */ 395static int 396linprocfs_dopartitions(PFS_FILL_ARGS) 397{ 398 struct g_class *cp; 399 struct g_geom *gp; 400 struct g_provider *pp; 401 struct nameidata nd; 402 const char *lep; 403 char *dlep, *flep; 404 size_t lep_len; 405 int error; 406 int major, minor; 407 408 /* resolve symlinks etc. in the emulation tree prefix */ 409 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 410 flep = NULL; 411 error = namei(&nd); 412 lep = linux_emul_path; 413 if (error == 0) { 414 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 415 lep = dlep; 416 vrele(nd.ni_vp); 417 VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 418 } 419 lep_len = strlen(lep); 420 421 g_topology_lock(); 422 error = 0; 423 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect " 424 "ruse wio wmerge wsect wuse running use aveq\n"); 425 426 LIST_FOREACH(cp, &g_classes, class) { 427 if (strcmp(cp->name, "DISK") == 0 || 428 strcmp(cp->name, "PART") == 0) 429 LIST_FOREACH(gp, &cp->geom, geom) { 430 LIST_FOREACH(pp, &gp->provider, provider) { 431 if (linux_driver_get_major_minor( 432 pp->name, &major, &minor) != 0) { 433 major = 0; 434 minor = 0; 435 } 436 sbuf_printf(sb, "%d %d %lld %s " 437 "%d %d %d %d %d " 438 "%d %d %d %d %d %d\n", 439 major, minor, 440 (long long)pp->mediasize, pp->name, 441 0, 0, 0, 0, 0, 442 0, 0, 0, 0, 0, 0); 443 } 444 } 445 } 446 g_topology_unlock(); 447 448 if (flep != NULL) 449 free(flep, M_TEMP); 450 return (error); 451} 452 453 454/* 455 * Filler function for proc/stat 456 */ 457static int 458linprocfs_dostat(PFS_FILL_ARGS) 459{ 460 struct pcpu *pcpu; 461 long cp_time[CPUSTATES]; 462 long *cp; 463 int i; 464 465 read_cpu_time(cp_time); 466 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 467 T2J(cp_time[CP_USER]), 468 T2J(cp_time[CP_NICE]), 469 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 470 T2J(cp_time[CP_IDLE])); 471 CPU_FOREACH(i) { 472 pcpu = pcpu_find(i); 473 cp = pcpu->pc_cp_time; 474 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 475 T2J(cp[CP_USER]), 476 T2J(cp[CP_NICE]), 477 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 478 T2J(cp[CP_IDLE])); 479 } 480 sbuf_printf(sb, 481 "disk 0 0 0 0\n" 482 "page %u %u\n" 483 "swap %u %u\n" 484 "intr %u\n" 485 "ctxt %u\n" 486 "btime %lld\n", 487 cnt.v_vnodepgsin, 488 cnt.v_vnodepgsout, 489 cnt.v_swappgsin, 490 cnt.v_swappgsout, 491 cnt.v_intr, 492 cnt.v_swtch, 493 (long long)boottime.tv_sec); 494 return (0); 495} 496 497/* 498 * Filler function for proc/uptime 499 */ 500static int 501linprocfs_douptime(PFS_FILL_ARGS) 502{ 503 long cp_time[CPUSTATES]; 504 struct timeval tv; 505 506 getmicrouptime(&tv); 507 read_cpu_time(cp_time); 508 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n", 509 (long long)tv.tv_sec, tv.tv_usec / 10000, 510 T2S(cp_time[CP_IDLE] / mp_ncpus), 511 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100); 512 return (0); 513} 514 515/* 516 * Get OS build date 517 */ 518static void 519linprocfs_osbuild(struct thread *td, struct sbuf *sb) 520{ 521#if 0 522 char osbuild[256]; 523 char *cp1, *cp2; 524 525 strncpy(osbuild, version, 256); 526 osbuild[255] = '\0'; 527 cp1 = strstr(osbuild, "\n"); 528 cp2 = strstr(osbuild, ":"); 529 if (cp1 && cp2) { 530 *cp1 = *cp2 = '\0'; 531 cp1 = strstr(osbuild, "#"); 532 } else 533 cp1 = NULL; 534 if (cp1) 535 sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 536 else 537#endif 538 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 539} 540 541/* 542 * Get OS builder 543 */ 544static void 545linprocfs_osbuilder(struct thread *td, struct sbuf *sb) 546{ 547#if 0 548 char builder[256]; 549 char *cp; 550 551 cp = strstr(version, "\n "); 552 if (cp) { 553 strncpy(builder, cp + 5, 256); 554 builder[255] = '\0'; 555 cp = strstr(builder, ":"); 556 if (cp) 557 *cp = '\0'; 558 } 559 if (cp) 560 sbuf_cat(sb, builder); 561 else 562#endif 563 sbuf_cat(sb, "des@freebsd.org"); 564} 565 566/* 567 * Filler function for proc/version 568 */ 569static int 570linprocfs_doversion(PFS_FILL_ARGS) 571{ 572 char osname[LINUX_MAX_UTSNAME]; 573 char osrelease[LINUX_MAX_UTSNAME]; 574 575 linux_get_osname(td, osname); 576 linux_get_osrelease(td, osrelease); 577 sbuf_printf(sb, "%s version %s (", osname, osrelease); 578 linprocfs_osbuilder(td, sb); 579 sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 580 linprocfs_osbuild(td, sb); 581 sbuf_cat(sb, "\n"); 582 583 return (0); 584} 585 586/* 587 * Filler function for proc/loadavg 588 */ 589static int 590linprocfs_doloadavg(PFS_FILL_ARGS) 591{ 592 593 sbuf_printf(sb, 594 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 595 (int)(averunnable.ldavg[0] / averunnable.fscale), 596 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 597 (int)(averunnable.ldavg[1] / averunnable.fscale), 598 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 599 (int)(averunnable.ldavg[2] / averunnable.fscale), 600 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 601 1, /* number of running tasks */ 602 nprocs, /* number of tasks */ 603 lastpid /* the last pid */ 604 ); 605 return (0); 606} 607 608/* 609 * Filler function for proc/pid/stat 610 */ 611static int 612linprocfs_doprocstat(PFS_FILL_ARGS) 613{ 614 struct kinfo_proc kp; 615 char state; 616 static int ratelimit = 0; 617 vm_offset_t startcode, startdata; 618 619 PROC_LOCK(p); 620 fill_kinfo_proc(p, &kp); 621 if (p->p_vmspace) { 622 startcode = (vm_offset_t)p->p_vmspace->vm_taddr; 623 startdata = (vm_offset_t)p->p_vmspace->vm_daddr; 624 } else { 625 startcode = 0; 626 startdata = 0; 627 }; 628 sbuf_printf(sb, "%d", p->p_pid); 629#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 630 PS_ADD("comm", "(%s)", p->p_comm); 631 if (kp.ki_stat > sizeof(linux_state)) { 632 state = 'R'; 633 634 if (ratelimit == 0) { 635 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 636 kp.ki_stat, sizeof(linux_state)); 637 ++ratelimit; 638 } 639 } else 640 state = linux_state[kp.ki_stat - 1]; 641 PS_ADD("state", "%c", state); 642 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 643 PS_ADD("pgrp", "%d", p->p_pgid); 644 PS_ADD("session", "%d", p->p_session->s_sid); 645 PROC_UNLOCK(p); 646 PS_ADD("tty", "%d", kp.ki_tdev); 647 PS_ADD("tpgid", "%d", kp.ki_tpgid); 648 PS_ADD("flags", "%u", 0); /* XXX */ 649 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 650 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 651 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 652 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 653 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime)); 654 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime)); 655 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime)); 656 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime)); 657 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 658 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 659 PS_ADD("0", "%d", 0); /* removed field */ 660 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 661 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime)); 662 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 663 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 664 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 665 PS_ADD("startcode", "%ju", (uintmax_t)startcode); 666 PS_ADD("endcode", "%ju", (uintmax_t)startdata); 667 PS_ADD("startstack", "%u", 0); /* XXX */ 668 PS_ADD("kstkesp", "%u", 0); /* XXX */ 669 PS_ADD("kstkeip", "%u", 0); /* XXX */ 670 PS_ADD("signal", "%u", 0); /* XXX */ 671 PS_ADD("blocked", "%u", 0); /* XXX */ 672 PS_ADD("sigignore", "%u", 0); /* XXX */ 673 PS_ADD("sigcatch", "%u", 0); /* XXX */ 674 PS_ADD("wchan", "%u", 0); /* XXX */ 675 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 676 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 677 PS_ADD("exitsignal", "%d", 0); /* XXX */ 678 PS_ADD("processor", "%u", kp.ki_lastcpu); 679 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 680 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 681#undef PS_ADD 682 sbuf_putc(sb, '\n'); 683 684 return (0); 685} 686 687/* 688 * Filler function for proc/pid/statm 689 */ 690static int 691linprocfs_doprocstatm(PFS_FILL_ARGS) 692{ 693 struct kinfo_proc kp; 694 segsz_t lsize; 695 696 PROC_LOCK(p); 697 fill_kinfo_proc(p, &kp); 698 PROC_UNLOCK(p); 699 700 /* 701 * See comments in linprocfs_doprocstatus() regarding the 702 * computation of lsize. 703 */ 704 /* size resident share trs drs lrs dt */ 705 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 706 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 707 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 708 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 709 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 710 lsize = B2P(kp.ki_size) - kp.ki_dsize - 711 kp.ki_ssize - kp.ki_tsize - 1; 712 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 713 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 714 715 return (0); 716} 717 718/* 719 * Filler function for proc/pid/status 720 */ 721static int 722linprocfs_doprocstatus(PFS_FILL_ARGS) 723{ 724 struct kinfo_proc kp; 725 char *state; 726 segsz_t lsize; 727 struct thread *td2; 728 struct sigacts *ps; 729 int i; 730 731 PROC_LOCK(p); 732 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 733 734 if (P_SHOULDSTOP(p)) { 735 state = "T (stopped)"; 736 } else { 737 PROC_SLOCK(p); 738 switch(p->p_state) { 739 case PRS_NEW: 740 state = "I (idle)"; 741 break; 742 case PRS_NORMAL: 743 if (p->p_flag & P_WEXIT) { 744 state = "X (exiting)"; 745 break; 746 } 747 switch(td2->td_state) { 748 case TDS_INHIBITED: 749 state = "S (sleeping)"; 750 break; 751 case TDS_RUNQ: 752 case TDS_RUNNING: 753 state = "R (running)"; 754 break; 755 default: 756 state = "? (unknown)"; 757 break; 758 } 759 break; 760 case PRS_ZOMBIE: 761 state = "Z (zombie)"; 762 break; 763 default: 764 state = "? (unknown)"; 765 break; 766 } 767 PROC_SUNLOCK(p); 768 } 769 770 fill_kinfo_proc(p, &kp); 771 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 772 sbuf_printf(sb, "State:\t%s\n", state); 773 774 /* 775 * Credentials 776 */ 777 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 778 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 779 p->p_pptr->p_pid : 0); 780 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 781 p->p_ucred->cr_uid, 782 p->p_ucred->cr_svuid, 783 /* FreeBSD doesn't have fsuid */ 784 p->p_ucred->cr_uid); 785 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 786 p->p_ucred->cr_gid, 787 p->p_ucred->cr_svgid, 788 /* FreeBSD doesn't have fsgid */ 789 p->p_ucred->cr_gid); 790 sbuf_cat(sb, "Groups:\t"); 791 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 792 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 793 PROC_UNLOCK(p); 794 sbuf_putc(sb, '\n'); 795 796 /* 797 * Memory 798 * 799 * While our approximation of VmLib may not be accurate (I 800 * don't know of a simple way to verify it, and I'm not sure 801 * it has much meaning anyway), I believe it's good enough. 802 * 803 * The same code that could (I think) accurately compute VmLib 804 * could also compute VmLck, but I don't really care enough to 805 * implement it. Submissions are welcome. 806 */ 807 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 808 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 809 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 810 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 811 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 812 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 813 lsize = B2P(kp.ki_size) - kp.ki_dsize - 814 kp.ki_ssize - kp.ki_tsize - 1; 815 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 816 817 /* 818 * Signal masks 819 * 820 * We support up to 128 signals, while Linux supports 32, 821 * but we only define 32 (the same 32 as Linux, to boot), so 822 * just show the lower 32 bits of each mask. XXX hack. 823 * 824 * NB: on certain platforms (Sparc at least) Linux actually 825 * supports 64 signals, but this code is a long way from 826 * running on anything but i386, so ignore that for now. 827 */ 828 PROC_LOCK(p); 829 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 830 /* 831 * I can't seem to find out where the signal mask is in 832 * relation to struct proc, so SigBlk is left unimplemented. 833 */ 834 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 835 ps = p->p_sigacts; 836 mtx_lock(&ps->ps_mtx); 837 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 838 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 839 mtx_unlock(&ps->ps_mtx); 840 PROC_UNLOCK(p); 841 842 /* 843 * Linux also prints the capability masks, but we don't have 844 * capabilities yet, and when we do get them they're likely to 845 * be meaningless to Linux programs, so we lie. XXX 846 */ 847 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 848 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 849 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 850 851 return (0); 852} 853 854 855/* 856 * Filler function for proc/pid/cwd 857 */ 858static int 859linprocfs_doproccwd(PFS_FILL_ARGS) 860{ 861 char *fullpath = "unknown"; 862 char *freepath = NULL; 863 864 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 865 sbuf_printf(sb, "%s", fullpath); 866 if (freepath) 867 free(freepath, M_TEMP); 868 return (0); 869} 870 871/* 872 * Filler function for proc/pid/root 873 */ 874static int 875linprocfs_doprocroot(PFS_FILL_ARGS) 876{ 877 struct vnode *rvp; 878 char *fullpath = "unknown"; 879 char *freepath = NULL; 880 881 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 882 vn_fullpath(td, rvp, &fullpath, &freepath); 883 sbuf_printf(sb, "%s", fullpath); 884 if (freepath) 885 free(freepath, M_TEMP); 886 return (0); 887} 888 889/* 890 * Filler function for proc/pid/cmdline 891 */ 892static int 893linprocfs_doproccmdline(PFS_FILL_ARGS) 894{ 895 struct ps_strings pstr; 896 char **ps_argvstr; 897 int error, i; 898 899 /* 900 * If we are using the ps/cmdline caching, use that. Otherwise 901 * revert back to the old way which only implements full cmdline 902 * for the currept process and just p->p_comm for all other 903 * processes. 904 * Note that if the argv is no longer available, we deliberately 905 * don't fall back on p->p_comm or return an error: the authentic 906 * Linux behaviour is to return zero-length in this case. 907 */ 908 909 PROC_LOCK(p); 910 if (p->p_args && p_cansee(td, p) == 0) { 911 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 912 PROC_UNLOCK(p); 913 } else if (p != td->td_proc) { 914 PROC_UNLOCK(p); 915 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 916 } else { 917 PROC_UNLOCK(p); 918 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 919 sizeof(pstr)); 920 if (error) 921 return (error); 922 if (pstr.ps_nargvstr > ARG_MAX) 923 return (E2BIG); 924 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 925 M_TEMP, M_WAITOK); 926 error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 927 pstr.ps_nargvstr * sizeof(char *)); 928 if (error) { 929 free(ps_argvstr, M_TEMP); 930 return (error); 931 } 932 for (i = 0; i < pstr.ps_nargvstr; i++) { 933 sbuf_copyin(sb, ps_argvstr[i], 0); 934 sbuf_printf(sb, "%c", '\0'); 935 } 936 free(ps_argvstr, M_TEMP); 937 } 938 939 return (0); 940} 941 942extern int proc_rwmem(struct proc *p, struct uio *uio); 943 944#define MAX_ARGV_STR 512 /* Max number of argv-like strings */ 945#define UIO_CHUNK_SZ 256 /* Max chunk size (bytes) for uiomove */ 946 947static int 948linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb, 949 void (*resolver)(const struct ps_strings, u_long *, int *)) 950{ 951 struct iovec iov; 952 struct uio tmp_uio; 953 struct ps_strings pss; 954 int ret, i, n_elements, found_end; 955 u_long addr; 956 char* env_vector[MAX_ARGV_STR]; 957 char env_string[UIO_CHUNK_SZ]; 958 char *pbegin; 959 960 961 962#define UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td) \ 963do { \ 964 iov.iov_base = (caddr_t)(base); \ 965 iov.iov_len = (len); \ 966 uio.uio_iov = &(iov); \ 967 uio.uio_iovcnt = (cnt); \ 968 uio.uio_offset = (off_t)(offset); \ 969 uio.uio_resid = (sz); \ 970 uio.uio_segflg = (flg); \ 971 uio.uio_rw = (rw); \ 972 uio.uio_td = (td); \ 973} while (0) 974 975 UIO_HELPER(tmp_uio, iov, &pss, sizeof(struct ps_strings), 1, 976 (off_t)(p->p_sysent->sv_psstrings), sizeof(struct ps_strings), 977 UIO_SYSSPACE, UIO_READ, td); 978 979 ret = proc_rwmem(p, &tmp_uio); 980 if (ret != 0) 981 return ret; 982 983 /* Get the array address and the number of elements */ 984 resolver(pss, &addr, &n_elements); 985 986 /* Consistent with lib/libkvm/kvm_proc.c */ 987 if (n_elements > MAX_ARGV_STR || (u_long)addr < VM_MIN_ADDRESS || 988 (u_long)addr >= VM_MAXUSER_ADDRESS) { 989 /* What error code should we return? */ 990 return 0; 991 } 992 993 UIO_HELPER(tmp_uio, iov, env_vector, MAX_ARGV_STR, 1, 994 (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td); 995 996 ret = proc_rwmem(p, &tmp_uio); 997 if (ret != 0) 998 return ret; 999 1000 /* Now we can iterate through the list of strings */ 1001 for (i = 0; i < n_elements; i++) { 1002 found_end = 0; 1003 pbegin = env_vector[i]; 1004 while(!found_end) { 1005 UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string), 1, 1006 (vm_offset_t) pbegin, iov.iov_len, UIO_SYSSPACE, 1007 UIO_READ, td); 1008 1009 ret = proc_rwmem(p, &tmp_uio); 1010 if (ret != 0) 1011 return ret; 1012 1013 if (!strvalid(env_string, UIO_CHUNK_SZ)) { 1014 /* 1015 * We didn't find the end of the string 1016 * Add the string to the buffer and move 1017 * the pointer 1018 */ 1019 sbuf_bcat(sb, env_string, UIO_CHUNK_SZ); 1020 pbegin = &(*pbegin) + UIO_CHUNK_SZ; 1021 } else { 1022 found_end = 1; 1023 } 1024 } 1025 sbuf_printf(sb, "%s", env_string); 1026 } 1027 1028#undef UIO_HELPER 1029 1030 return (0); 1031} 1032 1033static void 1034ps_string_env(const struct ps_strings ps, u_long *addr, int *n) 1035{ 1036 1037 *addr = (u_long) ps.ps_envstr; 1038 *n = ps.ps_nenvstr; 1039} 1040 1041/* 1042 * Filler function for proc/pid/environ 1043 */ 1044static int 1045linprocfs_doprocenviron(PFS_FILL_ARGS) 1046{ 1047 int ret; 1048 1049 PROC_LOCK(p); 1050 1051 if ((ret = p_cansee(td, p)) != 0) { 1052 PROC_UNLOCK(p); 1053 return ret; 1054 } 1055 1056 ret = linprocfs_doargv(td, p, sb, ps_string_env); 1057 PROC_UNLOCK(p); 1058 return (ret); 1059} 1060 1061/* 1062 * Filler function for proc/pid/maps 1063 */ 1064static int 1065linprocfs_doprocmaps(PFS_FILL_ARGS) 1066{ 1067 struct vmspace *vm; 1068 vm_map_t map; 1069 vm_map_entry_t entry, tmp_entry; 1070 vm_object_t obj, tobj, lobj; 1071 vm_offset_t e_start, e_end; 1072 vm_ooffset_t off = 0; 1073 vm_prot_t e_prot; 1074 unsigned int last_timestamp; 1075 char *name = "", *freename = NULL; 1076 ino_t ino; 1077 int ref_count, shadow_count, flags; 1078 int error; 1079 struct vnode *vp; 1080 struct vattr vat; 1081 int locked; 1082 1083 PROC_LOCK(p); 1084 error = p_candebug(td, p); 1085 PROC_UNLOCK(p); 1086 if (error) 1087 return (error); 1088 1089 if (uio->uio_rw != UIO_READ) 1090 return (EOPNOTSUPP); 1091 1092 error = 0; 1093 vm = vmspace_acquire_ref(p); 1094 if (vm == NULL) 1095 return (ESRCH); 1096 map = &vm->vm_map; 1097 vm_map_lock_read(map); 1098 for (entry = map->header.next; entry != &map->header; 1099 entry = entry->next) { 1100 name = ""; 1101 freename = NULL; 1102 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 1103 continue; 1104 e_prot = entry->protection; 1105 e_start = entry->start; 1106 e_end = entry->end; 1107 obj = entry->object.vm_object; 1108 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 1109 VM_OBJECT_LOCK(tobj); 1110 if (lobj != obj) 1111 VM_OBJECT_UNLOCK(lobj); 1112 lobj = tobj; 1113 } 1114 last_timestamp = map->timestamp; 1115 vm_map_unlock_read(map); 1116 ino = 0; 1117 if (lobj) { 1118 off = IDX_TO_OFF(lobj->size); 1119 if (lobj->type == OBJT_VNODE) { 1120 vp = lobj->handle; 1121 if (vp) 1122 vref(vp); 1123 } 1124 else 1125 vp = NULL; 1126 if (lobj != obj) 1127 VM_OBJECT_UNLOCK(lobj); 1128 flags = obj->flags; 1129 ref_count = obj->ref_count; 1130 shadow_count = obj->shadow_count; 1131 VM_OBJECT_UNLOCK(obj); 1132 if (vp) { 1133 vn_fullpath(td, vp, &name, &freename); 1134 locked = VFS_LOCK_GIANT(vp->v_mount); 1135 vn_lock(vp, LK_SHARED | LK_RETRY); 1136 VOP_GETATTR(vp, &vat, td->td_ucred); 1137 ino = vat.va_fileid; 1138 vput(vp); 1139 VFS_UNLOCK_GIANT(locked); 1140 } 1141 } else { 1142 flags = 0; 1143 ref_count = 0; 1144 shadow_count = 0; 1145 } 1146 1147 /* 1148 * format: 1149 * start, end, access, offset, major, minor, inode, name. 1150 */ 1151 error = sbuf_printf(sb, 1152 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 1153 (u_long)e_start, (u_long)e_end, 1154 (e_prot & VM_PROT_READ)?"r":"-", 1155 (e_prot & VM_PROT_WRITE)?"w":"-", 1156 (e_prot & VM_PROT_EXECUTE)?"x":"-", 1157 "p", 1158 (u_long)off, 1159 0, 1160 0, 1161 (u_long)ino, 1162 *name ? " " : "", 1163 name 1164 ); 1165 if (freename) 1166 free(freename, M_TEMP); 1167 vm_map_lock_read(map); 1168 if (error == -1) { 1169 error = 0; 1170 break; 1171 } 1172 if (last_timestamp != map->timestamp) { 1173 /* 1174 * Look again for the entry because the map was 1175 * modified while it was unlocked. Specifically, 1176 * the entry may have been clipped, merged, or deleted. 1177 */ 1178 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1179 entry = tmp_entry; 1180 } 1181 } 1182 vm_map_unlock_read(map); 1183 vmspace_free(vm); 1184 1185 return (error); 1186} 1187 1188/* 1189 * Filler function for proc/net/dev 1190 */ 1191static int 1192linprocfs_donetdev(PFS_FILL_ARGS) 1193{ 1194 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1195 struct ifnet *ifp; 1196 1197 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 1198 "Inter-", " Receive", " Transmit", " face", 1199 "bytes packets errs drop fifo frame compressed", 1200 "bytes packets errs drop fifo frame compressed"); 1201 1202 CURVNET_SET(TD_TO_VNET(curthread)); 1203 IFNET_RLOCK(); 1204 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1205 linux_ifname(ifp, ifname, sizeof ifname); 1206 sbuf_printf(sb, "%6.6s:", ifname); 1207 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1208 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 1209 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1210 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 1211 } 1212 IFNET_RUNLOCK(); 1213 CURVNET_RESTORE(); 1214 1215 return (0); 1216} 1217 1218/* 1219 * Filler function for proc/sys/kernel/osrelease 1220 */ 1221static int 1222linprocfs_doosrelease(PFS_FILL_ARGS) 1223{ 1224 char osrelease[LINUX_MAX_UTSNAME]; 1225 1226 linux_get_osrelease(td, osrelease); 1227 sbuf_printf(sb, "%s\n", osrelease); 1228 1229 return (0); 1230} 1231 1232/* 1233 * Filler function for proc/sys/kernel/ostype 1234 */ 1235static int 1236linprocfs_doostype(PFS_FILL_ARGS) 1237{ 1238 char osname[LINUX_MAX_UTSNAME]; 1239 1240 linux_get_osname(td, osname); 1241 sbuf_printf(sb, "%s\n", osname); 1242 1243 return (0); 1244} 1245 1246/* 1247 * Filler function for proc/sys/kernel/version 1248 */ 1249static int 1250linprocfs_doosbuild(PFS_FILL_ARGS) 1251{ 1252 1253 linprocfs_osbuild(td, sb); 1254 sbuf_cat(sb, "\n"); 1255 return (0); 1256} 1257 1258/* 1259 * Filler function for proc/sys/kernel/msgmni 1260 */ 1261static int 1262linprocfs_domsgmni(PFS_FILL_ARGS) 1263{ 1264 1265 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1266 return (0); 1267} 1268 1269/* 1270 * Filler function for proc/sys/kernel/pid_max 1271 */ 1272static int 1273linprocfs_dopid_max(PFS_FILL_ARGS) 1274{ 1275 1276 sbuf_printf(sb, "%i\n", PID_MAX); 1277 return (0); 1278} 1279 1280/* 1281 * Filler function for proc/sys/kernel/sem 1282 */ 1283static int 1284linprocfs_dosem(PFS_FILL_ARGS) 1285{ 1286 1287 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1288 seminfo.semopm, seminfo.semmni); 1289 return (0); 1290} 1291 1292/* 1293 * Filler function for proc/scsi/device_info 1294 */ 1295static int 1296linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1297{ 1298 1299 return (0); 1300} 1301 1302/* 1303 * Filler function for proc/scsi/scsi 1304 */ 1305static int 1306linprocfs_doscsiscsi(PFS_FILL_ARGS) 1307{ 1308 1309 return (0); 1310} 1311 1312extern struct cdevsw *cdevsw[]; 1313 1314/* 1315 * Filler function for proc/devices 1316 */ 1317static int 1318linprocfs_dodevices(PFS_FILL_ARGS) 1319{ 1320 char *char_devices; 1321 sbuf_printf(sb, "Character devices:\n"); 1322 1323 char_devices = linux_get_char_devices(); 1324 sbuf_printf(sb, "%s", char_devices); 1325 linux_free_get_char_devices(char_devices); 1326 1327 sbuf_printf(sb, "\nBlock devices:\n"); 1328 1329 return (0); 1330} 1331 1332/* 1333 * Filler function for proc/cmdline 1334 */ 1335static int 1336linprocfs_docmdline(PFS_FILL_ARGS) 1337{ 1338 1339 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1340 sbuf_printf(sb, " ro root=302\n"); 1341 return (0); 1342} 1343 1344/* 1345 * Filler function for proc/filesystems 1346 */ 1347static int 1348linprocfs_dofilesystems(PFS_FILL_ARGS) 1349{ 1350 struct vfsconf *vfsp; 1351 1352 mtx_lock(&Giant); 1353 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 1354 if (vfsp->vfc_flags & VFCF_SYNTHETIC) 1355 sbuf_printf(sb, "nodev"); 1356 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name); 1357 } 1358 mtx_unlock(&Giant); 1359 return(0); 1360} 1361 1362#if 0 1363/* 1364 * Filler function for proc/modules 1365 */ 1366static int 1367linprocfs_domodules(PFS_FILL_ARGS) 1368{ 1369 struct linker_file *lf; 1370 1371 TAILQ_FOREACH(lf, &linker_files, link) { 1372 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1373 (unsigned long)lf->size, lf->refs); 1374 } 1375 return (0); 1376} 1377#endif 1378 1379/* 1380 * Filler function for proc/pid/fd 1381 */ 1382static int 1383linprocfs_dofdescfs(PFS_FILL_ARGS) 1384{ 1385 1386 if (p == curproc) 1387 sbuf_printf(sb, "/dev/fd"); 1388 else 1389 sbuf_printf(sb, "unknown"); 1390 return (0); 1391} 1392 1393/* 1394 * Constructor 1395 */ 1396static int 1397linprocfs_init(PFS_INIT_ARGS) 1398{ 1399 struct pfs_node *root; 1400 struct pfs_node *dir; 1401 1402 root = pi->pi_root; 1403 1404 /* /proc/... */ 1405 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1406 NULL, NULL, NULL, PFS_RD); 1407 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1408 NULL, NULL, NULL, PFS_RD); 1409 pfs_create_file(root, "devices", &linprocfs_dodevices, 1410 NULL, NULL, NULL, PFS_RD); 1411 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1412 NULL, NULL, NULL, PFS_RD); 1413 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1414 NULL, NULL, NULL, PFS_RD); 1415 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1416 NULL, NULL, NULL, PFS_RD); 1417#if 0 1418 pfs_create_file(root, "modules", &linprocfs_domodules, 1419 NULL, NULL, NULL, PFS_RD); 1420#endif 1421 pfs_create_file(root, "mounts", &linprocfs_domtab, 1422 NULL, NULL, NULL, PFS_RD); 1423 pfs_create_file(root, "mtab", &linprocfs_domtab, 1424 NULL, NULL, NULL, PFS_RD); 1425 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1426 NULL, NULL, NULL, PFS_RD); 1427 pfs_create_link(root, "self", &procfs_docurproc, 1428 NULL, NULL, NULL, 0); 1429 pfs_create_file(root, "stat", &linprocfs_dostat, 1430 NULL, NULL, NULL, PFS_RD); 1431 pfs_create_file(root, "uptime", &linprocfs_douptime, 1432 NULL, NULL, NULL, PFS_RD); 1433 pfs_create_file(root, "version", &linprocfs_doversion, 1434 NULL, NULL, NULL, PFS_RD); 1435 1436 /* /proc/net/... */ 1437 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1438 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1439 NULL, NULL, NULL, PFS_RD); 1440 1441 /* /proc/<pid>/... */ 1442 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1443 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1444 NULL, NULL, NULL, PFS_RD); 1445 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1446 NULL, NULL, NULL, 0); 1447 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1448 NULL, NULL, NULL, PFS_RD); 1449 pfs_create_link(dir, "exe", &procfs_doprocfile, 1450 NULL, &procfs_notsystem, NULL, 0); 1451 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1452 NULL, NULL, NULL, PFS_RD); 1453 pfs_create_file(dir, "mem", &procfs_doprocmem, 1454 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1455 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1456 NULL, NULL, NULL, 0); 1457 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1458 NULL, NULL, NULL, PFS_RD); 1459 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1460 NULL, NULL, NULL, PFS_RD); 1461 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1462 NULL, NULL, NULL, PFS_RD); 1463 pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1464 NULL, NULL, NULL, 0); 1465 1466 /* /proc/scsi/... */ 1467 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1468 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1469 NULL, NULL, NULL, PFS_RD); 1470 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1471 NULL, NULL, NULL, PFS_RD); 1472 1473 /* /proc/sys/... */ 1474 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1475 /* /proc/sys/kernel/... */ 1476 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1477 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1478 NULL, NULL, NULL, PFS_RD); 1479 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1480 NULL, NULL, NULL, PFS_RD); 1481 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1482 NULL, NULL, NULL, PFS_RD); 1483 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1484 NULL, NULL, NULL, PFS_RD); 1485 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1486 NULL, NULL, NULL, PFS_RD); 1487 pfs_create_file(dir, "sem", &linprocfs_dosem, 1488 NULL, NULL, NULL, PFS_RD); 1489 1490 return (0); 1491} 1492 1493/* 1494 * Destructor 1495 */ 1496static int 1497linprocfs_uninit(PFS_INIT_ARGS) 1498{ 1499 1500 /* nothing to do, pseudofs will GC */ 1501 return (0); 1502} 1503 1504PSEUDOFS(linprocfs, 1); 1505MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1506MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1507MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1508MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1509