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