linprocfs.c revision 299221
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 <sys/cdefs.h> 43__FBSDID("$FreeBSD: stable/10/sys/compat/linprocfs/linprocfs.c 299221 2016-05-07 19:05:39Z dchagin $"); 44 45#include <sys/param.h> 46#include <sys/queue.h> 47#include <sys/systm.h> 48#include <sys/blist.h> 49#include <sys/conf.h> 50#include <sys/exec.h> 51#include <sys/fcntl.h> 52#include <sys/filedesc.h> 53#include <sys/jail.h> 54#include <sys/kernel.h> 55#include <sys/limits.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/resource.h> 67#include <sys/sbuf.h> 68#include <sys/sem.h> 69#include <sys/smp.h> 70#include <sys/socket.h> 71#include <sys/sysctl.h> 72#include <sys/sysent.h> 73#include <sys/systm.h> 74#include <sys/time.h> 75#include <sys/tty.h> 76#include <sys/user.h> 77#include <sys/uuid.h> 78#include <sys/vmmeter.h> 79#include <sys/vnode.h> 80#include <sys/bus.h> 81 82#include <net/if.h> 83#include <net/if_types.h> 84 85#include <vm/vm.h> 86#include <vm/vm_extern.h> 87#include <vm/pmap.h> 88#include <vm/vm_map.h> 89#include <vm/vm_param.h> 90#include <vm/vm_object.h> 91#include <vm/swap_pager.h> 92 93#include <machine/clock.h> 94 95#include <geom/geom.h> 96#include <geom/geom_int.h> 97 98#if defined(__i386__) || defined(__amd64__) 99#include <machine/cputypes.h> 100#include <machine/md_var.h> 101#endif /* __i386__ || __amd64__ */ 102 103#include <compat/linux/linux.h> 104#include <compat/linux/linux_mib.h> 105#include <compat/linux/linux_misc.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 uint64_t freq; 220 size_t size; 221 int class, fqmhz, fqkhz; 222 int i; 223 224 /* 225 * We default the flags to include all non-conflicting flags, 226 * and the Intel versions of conflicting flags. 227 */ 228 static char *flags[] = { 229 "fpu", "vme", "de", "pse", "tsc", 230 "msr", "pae", "mce", "cx8", "apic", 231 "sep", "sep", "mtrr", "pge", "mca", 232 "cmov", "pat", "pse36", "pn", "b19", 233 "b20", "b21", "mmxext", "mmx", "fxsr", 234 "xmm", "sse2", "b27", "b28", "b29", 235 "3dnowext", "3dnow" 236 }; 237 238 switch (cpu_class) { 239#ifdef __i386__ 240 case CPUCLASS_286: 241 class = 2; 242 break; 243 case CPUCLASS_386: 244 class = 3; 245 break; 246 case CPUCLASS_486: 247 class = 4; 248 break; 249 case CPUCLASS_586: 250 class = 5; 251 break; 252 case CPUCLASS_686: 253 class = 6; 254 break; 255 default: 256 class = 0; 257 break; 258#else /* __amd64__ */ 259 default: 260 class = 15; 261 break; 262#endif 263 } 264 265 hw_model[0] = CTL_HW; 266 hw_model[1] = HW_MODEL; 267 model[0] = '\0'; 268 size = sizeof(model); 269 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 270 strcpy(model, "unknown"); 271 for (i = 0; i < mp_ncpus; ++i) { 272 sbuf_printf(sb, 273 "processor\t: %d\n" 274 "vendor_id\t: %.20s\n" 275 "cpu family\t: %u\n" 276 "model\t\t: %u\n" 277 "model name\t: %s\n" 278 "stepping\t: %u\n\n", 279 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id), 280 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING); 281 /* XXX per-cpu vendor / class / model / id? */ 282 } 283 284 sbuf_cat(sb, "flags\t\t:"); 285 286#ifdef __i386__ 287 switch (cpu_vendor_id) { 288 case CPU_VENDOR_AMD: 289 if (class < 6) 290 flags[16] = "fcmov"; 291 break; 292 case CPU_VENDOR_CYRIX: 293 flags[24] = "cxmmx"; 294 break; 295 } 296#endif 297 298 for (i = 0; i < 32; i++) 299 if (cpu_feature & (1 << i)) 300 sbuf_printf(sb, " %s", flags[i]); 301 sbuf_cat(sb, "\n"); 302 freq = atomic_load_acq_64(&tsc_freq); 303 if (freq != 0) { 304 fqmhz = (freq + 4999) / 1000000; 305 fqkhz = ((freq + 4999) / 10000) % 100; 306 sbuf_printf(sb, 307 "cpu MHz\t\t: %d.%02d\n" 308 "bogomips\t: %d.%02d\n", 309 fqmhz, fqkhz, fqmhz, fqkhz); 310 } 311 312 return (0); 313} 314#endif /* __i386__ || __amd64__ */ 315 316/* 317 * Filler function for proc/mtab 318 * 319 * This file doesn't exist in Linux' procfs, but is included here so 320 * users can symlink /compat/linux/etc/mtab to /proc/mtab 321 */ 322static int 323linprocfs_domtab(PFS_FILL_ARGS) 324{ 325 struct nameidata nd; 326 struct mount *mp; 327 const char *lep; 328 char *dlep, *flep, *mntto, *mntfrom, *fstype; 329 size_t lep_len; 330 int error; 331 332 /* resolve symlinks etc. in the emulation tree prefix */ 333 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 334 flep = NULL; 335 error = namei(&nd); 336 lep = linux_emul_path; 337 if (error == 0) { 338 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 339 lep = dlep; 340 vrele(nd.ni_vp); 341 } 342 lep_len = strlen(lep); 343 344 mtx_lock(&mountlist_mtx); 345 error = 0; 346 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 347 /* determine device name */ 348 mntfrom = mp->mnt_stat.f_mntfromname; 349 350 /* determine mount point */ 351 mntto = mp->mnt_stat.f_mntonname; 352 if (strncmp(mntto, lep, lep_len) == 0 && 353 mntto[lep_len] == '/') 354 mntto += lep_len; 355 356 /* determine fs type */ 357 fstype = mp->mnt_stat.f_fstypename; 358 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 359 mntfrom = fstype = "proc"; 360 else if (strcmp(fstype, "procfs") == 0) 361 continue; 362 363 if (strcmp(fstype, "linsysfs") == 0) { 364 sbuf_printf(sb, "/sys %s sysfs %s", mntto, 365 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 366 } else { 367 /* For Linux msdosfs is called vfat */ 368 if (strcmp(fstype, "msdosfs") == 0) 369 fstype = "vfat"; 370 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 371 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 372 } 373#define ADD_OPTION(opt, name) \ 374 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 375 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 376 ADD_OPTION(MNT_NOEXEC, "noexec"); 377 ADD_OPTION(MNT_NOSUID, "nosuid"); 378 ADD_OPTION(MNT_UNION, "union"); 379 ADD_OPTION(MNT_ASYNC, "async"); 380 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 381 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 382 ADD_OPTION(MNT_NOATIME, "noatime"); 383#undef ADD_OPTION 384 /* a real Linux mtab will also show NFS options */ 385 sbuf_printf(sb, " 0 0\n"); 386 } 387 mtx_unlock(&mountlist_mtx); 388 free(flep, M_TEMP); 389 return (error); 390} 391 392/* 393 * Filler function for proc/partitions 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 int major, minor; 402 403 g_topology_lock(); 404 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect " 405 "ruse wio wmerge wsect wuse running use aveq\n"); 406 407 LIST_FOREACH(cp, &g_classes, class) { 408 if (strcmp(cp->name, "DISK") == 0 || 409 strcmp(cp->name, "PART") == 0) 410 LIST_FOREACH(gp, &cp->geom, geom) { 411 LIST_FOREACH(pp, &gp->provider, provider) { 412 if (linux_driver_get_major_minor( 413 pp->name, &major, &minor) != 0) { 414 major = 0; 415 minor = 0; 416 } 417 sbuf_printf(sb, "%d %d %lld %s " 418 "%d %d %d %d %d " 419 "%d %d %d %d %d %d\n", 420 major, minor, 421 (long long)pp->mediasize, pp->name, 422 0, 0, 0, 0, 0, 423 0, 0, 0, 0, 0, 0); 424 } 425 } 426 } 427 g_topology_unlock(); 428 429 return (0); 430} 431 432 433/* 434 * Filler function for proc/stat 435 */ 436static int 437linprocfs_dostat(PFS_FILL_ARGS) 438{ 439 struct pcpu *pcpu; 440 long cp_time[CPUSTATES]; 441 long *cp; 442 int i; 443 444 read_cpu_time(cp_time); 445 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 446 T2J(cp_time[CP_USER]), 447 T2J(cp_time[CP_NICE]), 448 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 449 T2J(cp_time[CP_IDLE])); 450 CPU_FOREACH(i) { 451 pcpu = pcpu_find(i); 452 cp = pcpu->pc_cp_time; 453 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 454 T2J(cp[CP_USER]), 455 T2J(cp[CP_NICE]), 456 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 457 T2J(cp[CP_IDLE])); 458 } 459 sbuf_printf(sb, 460 "disk 0 0 0 0\n" 461 "page %u %u\n" 462 "swap %u %u\n" 463 "intr %u\n" 464 "ctxt %u\n" 465 "btime %lld\n", 466 cnt.v_vnodepgsin, 467 cnt.v_vnodepgsout, 468 cnt.v_swappgsin, 469 cnt.v_swappgsout, 470 cnt.v_intr, 471 cnt.v_swtch, 472 (long long)boottime.tv_sec); 473 return (0); 474} 475 476static int 477linprocfs_doswaps(PFS_FILL_ARGS) 478{ 479 struct xswdev xsw; 480 uintmax_t total, used; 481 int n; 482 char devname[SPECNAMELEN + 1]; 483 484 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n"); 485 mtx_lock(&Giant); 486 for (n = 0; ; n++) { 487 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0) 488 break; 489 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024; 490 used = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024; 491 492 /* 493 * The space and not tab after the device name is on 494 * purpose. Linux does so. 495 */ 496 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n", 497 devname, total, used); 498 } 499 mtx_unlock(&Giant); 500 return (0); 501} 502 503/* 504 * Filler function for proc/uptime 505 */ 506static int 507linprocfs_douptime(PFS_FILL_ARGS) 508{ 509 long cp_time[CPUSTATES]; 510 struct timeval tv; 511 512 getmicrouptime(&tv); 513 read_cpu_time(cp_time); 514 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n", 515 (long long)tv.tv_sec, tv.tv_usec / 10000, 516 T2S(cp_time[CP_IDLE] / mp_ncpus), 517 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100); 518 return (0); 519} 520 521/* 522 * Get OS build date 523 */ 524static void 525linprocfs_osbuild(struct thread *td, struct sbuf *sb) 526{ 527#if 0 528 char osbuild[256]; 529 char *cp1, *cp2; 530 531 strncpy(osbuild, version, 256); 532 osbuild[255] = '\0'; 533 cp1 = strstr(osbuild, "\n"); 534 cp2 = strstr(osbuild, ":"); 535 if (cp1 && cp2) { 536 *cp1 = *cp2 = '\0'; 537 cp1 = strstr(osbuild, "#"); 538 } else 539 cp1 = NULL; 540 if (cp1) 541 sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 542 else 543#endif 544 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 545} 546 547/* 548 * Get OS builder 549 */ 550static void 551linprocfs_osbuilder(struct thread *td, struct sbuf *sb) 552{ 553#if 0 554 char builder[256]; 555 char *cp; 556 557 cp = strstr(version, "\n "); 558 if (cp) { 559 strncpy(builder, cp + 5, 256); 560 builder[255] = '\0'; 561 cp = strstr(builder, ":"); 562 if (cp) 563 *cp = '\0'; 564 } 565 if (cp) 566 sbuf_cat(sb, builder); 567 else 568#endif 569 sbuf_cat(sb, "des@freebsd.org"); 570} 571 572/* 573 * Filler function for proc/version 574 */ 575static int 576linprocfs_doversion(PFS_FILL_ARGS) 577{ 578 char osname[LINUX_MAX_UTSNAME]; 579 char osrelease[LINUX_MAX_UTSNAME]; 580 581 linux_get_osname(td, osname); 582 linux_get_osrelease(td, osrelease); 583 sbuf_printf(sb, "%s version %s (", osname, osrelease); 584 linprocfs_osbuilder(td, sb); 585 sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 586 linprocfs_osbuild(td, sb); 587 sbuf_cat(sb, "\n"); 588 589 return (0); 590} 591 592/* 593 * Filler function for proc/loadavg 594 */ 595static int 596linprocfs_doloadavg(PFS_FILL_ARGS) 597{ 598 599 sbuf_printf(sb, 600 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 601 (int)(averunnable.ldavg[0] / averunnable.fscale), 602 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 603 (int)(averunnable.ldavg[1] / averunnable.fscale), 604 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 605 (int)(averunnable.ldavg[2] / averunnable.fscale), 606 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 607 1, /* number of running tasks */ 608 nprocs, /* number of tasks */ 609 lastpid /* the last pid */ 610 ); 611 return (0); 612} 613 614/* 615 * Filler function for proc/pid/stat 616 */ 617static int 618linprocfs_doprocstat(PFS_FILL_ARGS) 619{ 620 struct kinfo_proc kp; 621 char state; 622 static int ratelimit = 0; 623 vm_offset_t startcode, startdata; 624 625 PROC_LOCK(p); 626 fill_kinfo_proc(p, &kp); 627 if (p->p_vmspace) { 628 startcode = (vm_offset_t)p->p_vmspace->vm_taddr; 629 startdata = (vm_offset_t)p->p_vmspace->vm_daddr; 630 } else { 631 startcode = 0; 632 startdata = 0; 633 }; 634 sbuf_printf(sb, "%d", p->p_pid); 635#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 636 PS_ADD("comm", "(%s)", p->p_comm); 637 if (kp.ki_stat > sizeof(linux_state)) { 638 state = 'R'; 639 640 if (ratelimit == 0) { 641 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 642 kp.ki_stat, sizeof(linux_state)); 643 ++ratelimit; 644 } 645 } else 646 state = linux_state[kp.ki_stat - 1]; 647 PS_ADD("state", "%c", state); 648 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 649 PS_ADD("pgrp", "%d", p->p_pgid); 650 PS_ADD("session", "%d", p->p_session->s_sid); 651 PROC_UNLOCK(p); 652 PS_ADD("tty", "%d", kp.ki_tdev); 653 PS_ADD("tpgid", "%d", kp.ki_tpgid); 654 PS_ADD("flags", "%u", 0); /* XXX */ 655 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 656 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 657 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 658 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 659 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime)); 660 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime)); 661 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime)); 662 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime)); 663 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 664 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 665 PS_ADD("0", "%d", 0); /* removed field */ 666 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 667 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime)); 668 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 669 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 670 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 671 PS_ADD("startcode", "%ju", (uintmax_t)startcode); 672 PS_ADD("endcode", "%ju", (uintmax_t)startdata); 673 PS_ADD("startstack", "%u", 0); /* XXX */ 674 PS_ADD("kstkesp", "%u", 0); /* XXX */ 675 PS_ADD("kstkeip", "%u", 0); /* XXX */ 676 PS_ADD("signal", "%u", 0); /* XXX */ 677 PS_ADD("blocked", "%u", 0); /* XXX */ 678 PS_ADD("sigignore", "%u", 0); /* XXX */ 679 PS_ADD("sigcatch", "%u", 0); /* XXX */ 680 PS_ADD("wchan", "%u", 0); /* XXX */ 681 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 682 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 683 PS_ADD("exitsignal", "%d", 0); /* XXX */ 684 PS_ADD("processor", "%u", kp.ki_lastcpu); 685 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 686 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 687#undef PS_ADD 688 sbuf_putc(sb, '\n'); 689 690 return (0); 691} 692 693/* 694 * Filler function for proc/pid/statm 695 */ 696static int 697linprocfs_doprocstatm(PFS_FILL_ARGS) 698{ 699 struct kinfo_proc kp; 700 segsz_t lsize; 701 702 PROC_LOCK(p); 703 fill_kinfo_proc(p, &kp); 704 PROC_UNLOCK(p); 705 706 /* 707 * See comments in linprocfs_doprocstatus() regarding the 708 * computation of lsize. 709 */ 710 /* size resident share trs drs lrs dt */ 711 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 712 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 713 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 714 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 715 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 716 lsize = B2P(kp.ki_size) - kp.ki_dsize - 717 kp.ki_ssize - kp.ki_tsize - 1; 718 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 719 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 720 721 return (0); 722} 723 724/* 725 * Filler function for proc/pid/status 726 */ 727static int 728linprocfs_doprocstatus(PFS_FILL_ARGS) 729{ 730 struct kinfo_proc kp; 731 char *state; 732 segsz_t lsize; 733 struct thread *td2; 734 struct sigacts *ps; 735 l_sigset_t siglist, sigignore, sigcatch; 736 int i; 737 738 PROC_LOCK(p); 739 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 740 741 if (P_SHOULDSTOP(p)) { 742 state = "T (stopped)"; 743 } else { 744 switch(p->p_state) { 745 case PRS_NEW: 746 state = "I (idle)"; 747 break; 748 case PRS_NORMAL: 749 if (p->p_flag & P_WEXIT) { 750 state = "X (exiting)"; 751 break; 752 } 753 switch(td2->td_state) { 754 case TDS_INHIBITED: 755 state = "S (sleeping)"; 756 break; 757 case TDS_RUNQ: 758 case TDS_RUNNING: 759 state = "R (running)"; 760 break; 761 default: 762 state = "? (unknown)"; 763 break; 764 } 765 break; 766 case PRS_ZOMBIE: 767 state = "Z (zombie)"; 768 break; 769 default: 770 state = "? (unknown)"; 771 break; 772 } 773 } 774 775 fill_kinfo_proc(p, &kp); 776 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 777 sbuf_printf(sb, "State:\t%s\n", state); 778 779 /* 780 * Credentials 781 */ 782 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 783 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 784 p->p_pptr->p_pid : 0); 785 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 786 p->p_ucred->cr_uid, 787 p->p_ucred->cr_svuid, 788 /* FreeBSD doesn't have fsuid */ 789 p->p_ucred->cr_uid); 790 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 791 p->p_ucred->cr_gid, 792 p->p_ucred->cr_svgid, 793 /* FreeBSD doesn't have fsgid */ 794 p->p_ucred->cr_gid); 795 sbuf_cat(sb, "Groups:\t"); 796 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 797 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 798 PROC_UNLOCK(p); 799 sbuf_putc(sb, '\n'); 800 801 /* 802 * Memory 803 * 804 * While our approximation of VmLib may not be accurate (I 805 * don't know of a simple way to verify it, and I'm not sure 806 * it has much meaning anyway), I believe it's good enough. 807 * 808 * The same code that could (I think) accurately compute VmLib 809 * could also compute VmLck, but I don't really care enough to 810 * implement it. Submissions are welcome. 811 */ 812 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 813 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 814 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 815 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 816 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 817 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 818 lsize = B2P(kp.ki_size) - kp.ki_dsize - 819 kp.ki_ssize - kp.ki_tsize - 1; 820 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 821 822 /* 823 * Signal masks 824 */ 825 PROC_LOCK(p); 826 bsd_to_linux_sigset(&p->p_siglist, &siglist); 827 ps = p->p_sigacts; 828 mtx_lock(&ps->ps_mtx); 829 bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore); 830 bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch); 831 mtx_unlock(&ps->ps_mtx); 832 PROC_UNLOCK(p); 833 834 sbuf_printf(sb, "SigPnd:\t%016jx\n", siglist.__mask); 835 /* 836 * XXX. SigBlk - target thread's signal mask, td_sigmask. 837 * To implement SigBlk pseudofs should support proc/tid dir entries. 838 */ 839 sbuf_printf(sb, "SigBlk:\t%016x\n", 0); 840 sbuf_printf(sb, "SigIgn:\t%016jx\n", sigignore.__mask); 841 sbuf_printf(sb, "SigCgt:\t%016jx\n", sigcatch.__mask); 842 843 /* 844 * Linux also prints the capability masks, but we don't have 845 * capabilities yet, and when we do get them they're likely to 846 * be meaningless to Linux programs, so we lie. XXX 847 */ 848 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 849 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 850 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 851 852 return (0); 853} 854 855 856/* 857 * Filler function for proc/pid/cwd 858 */ 859static int 860linprocfs_doproccwd(PFS_FILL_ARGS) 861{ 862 struct filedesc *fdp; 863 struct vnode *vp; 864 char *fullpath = "unknown"; 865 char *freepath = NULL; 866 867 fdp = p->p_fd; 868 FILEDESC_SLOCK(fdp); 869 vp = fdp->fd_cdir; 870 if (vp != NULL) 871 VREF(vp); 872 FILEDESC_SUNLOCK(fdp); 873 vn_fullpath(td, vp, &fullpath, &freepath); 874 if (vp != NULL) 875 vrele(vp); 876 sbuf_printf(sb, "%s", fullpath); 877 if (freepath) 878 free(freepath, M_TEMP); 879 return (0); 880} 881 882/* 883 * Filler function for proc/pid/root 884 */ 885static int 886linprocfs_doprocroot(PFS_FILL_ARGS) 887{ 888 struct filedesc *fdp; 889 struct vnode *vp; 890 char *fullpath = "unknown"; 891 char *freepath = NULL; 892 893 fdp = p->p_fd; 894 FILEDESC_SLOCK(fdp); 895 vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir; 896 if (vp != NULL) 897 VREF(vp); 898 FILEDESC_SUNLOCK(fdp); 899 vn_fullpath(td, vp, &fullpath, &freepath); 900 if (vp != NULL) 901 vrele(vp); 902 sbuf_printf(sb, "%s", fullpath); 903 if (freepath) 904 free(freepath, M_TEMP); 905 return (0); 906} 907 908/* 909 * Filler function for proc/pid/cmdline 910 */ 911static int 912linprocfs_doproccmdline(PFS_FILL_ARGS) 913{ 914 int ret; 915 916 PROC_LOCK(p); 917 if ((ret = p_cansee(td, p)) != 0) { 918 PROC_UNLOCK(p); 919 return (ret); 920 } 921 922 /* 923 * Mimic linux behavior and pass only processes with usermode 924 * address space as valid. Return zero silently otherwize. 925 */ 926 if (p->p_vmspace == &vmspace0) { 927 PROC_UNLOCK(p); 928 return (0); 929 } 930 if (p->p_args != NULL) { 931 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 932 PROC_UNLOCK(p); 933 return (0); 934 } 935 936 if ((p->p_flag & P_SYSTEM) != 0) { 937 PROC_UNLOCK(p); 938 return (0); 939 } 940 941 PROC_UNLOCK(p); 942 943 ret = proc_getargv(td, p, sb); 944 return (ret); 945} 946 947/* 948 * Filler function for proc/pid/environ 949 */ 950static int 951linprocfs_doprocenviron(PFS_FILL_ARGS) 952{ 953 954 /* 955 * Mimic linux behavior and pass only processes with usermode 956 * address space as valid. Return zero silently otherwize. 957 */ 958 if (p->p_vmspace == &vmspace0) 959 return (0); 960 961 return (proc_getenvv(td, p, sb)); 962} 963 964static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n"; 965static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n"; 966static char vdso_str[] = " [vdso]"; 967static char stack_str[] = " [stack]"; 968 969/* 970 * Filler function for proc/pid/maps 971 */ 972static int 973linprocfs_doprocmaps(PFS_FILL_ARGS) 974{ 975 struct vmspace *vm; 976 vm_map_t map; 977 vm_map_entry_t entry, tmp_entry; 978 vm_object_t obj, tobj, lobj; 979 vm_offset_t e_start, e_end; 980 vm_ooffset_t off = 0; 981 vm_prot_t e_prot; 982 unsigned int last_timestamp; 983 char *name = "", *freename = NULL; 984 const char *l_map_str; 985 ino_t ino; 986 int ref_count, shadow_count, flags; 987 int error; 988 struct vnode *vp; 989 struct vattr vat; 990 991 PROC_LOCK(p); 992 error = p_candebug(td, p); 993 PROC_UNLOCK(p); 994 if (error) 995 return (error); 996 997 if (uio->uio_rw != UIO_READ) 998 return (EOPNOTSUPP); 999 1000 error = 0; 1001 vm = vmspace_acquire_ref(p); 1002 if (vm == NULL) 1003 return (ESRCH); 1004 1005 if (SV_CURPROC_FLAG(SV_LP64)) 1006 l_map_str = l64_map_str; 1007 else 1008 l_map_str = l32_map_str; 1009 map = &vm->vm_map; 1010 vm_map_lock_read(map); 1011 for (entry = map->header.next; entry != &map->header; 1012 entry = entry->next) { 1013 name = ""; 1014 freename = NULL; 1015 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 1016 continue; 1017 e_prot = entry->protection; 1018 e_start = entry->start; 1019 e_end = entry->end; 1020 obj = entry->object.vm_object; 1021 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 1022 VM_OBJECT_RLOCK(tobj); 1023 if (lobj != obj) 1024 VM_OBJECT_RUNLOCK(lobj); 1025 lobj = tobj; 1026 } 1027 last_timestamp = map->timestamp; 1028 vm_map_unlock_read(map); 1029 ino = 0; 1030 if (lobj) { 1031 off = IDX_TO_OFF(lobj->size); 1032 vp = vm_object_vnode(lobj); 1033 if (vp != NULL) 1034 vref(vp); 1035 if (lobj != obj) 1036 VM_OBJECT_RUNLOCK(lobj); 1037 flags = obj->flags; 1038 ref_count = obj->ref_count; 1039 shadow_count = obj->shadow_count; 1040 VM_OBJECT_RUNLOCK(obj); 1041 if (vp != NULL) { 1042 vn_fullpath(td, vp, &name, &freename); 1043 vn_lock(vp, LK_SHARED | LK_RETRY); 1044 VOP_GETATTR(vp, &vat, td->td_ucred); 1045 ino = vat.va_fileid; 1046 vput(vp); 1047 } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) { 1048 if (e_start == p->p_sysent->sv_shared_page_base) 1049 name = vdso_str; 1050 if (e_end == p->p_sysent->sv_usrstack) 1051 name = stack_str; 1052 } 1053 } else { 1054 flags = 0; 1055 ref_count = 0; 1056 shadow_count = 0; 1057 } 1058 1059 /* 1060 * format: 1061 * start, end, access, offset, major, minor, inode, name. 1062 */ 1063 error = sbuf_printf(sb, l_map_str, 1064 (u_long)e_start, (u_long)e_end, 1065 (e_prot & VM_PROT_READ)?"r":"-", 1066 (e_prot & VM_PROT_WRITE)?"w":"-", 1067 (e_prot & VM_PROT_EXECUTE)?"x":"-", 1068 "p", 1069 (u_long)off, 1070 0, 1071 0, 1072 (u_long)ino, 1073 *name ? " " : "", 1074 name 1075 ); 1076 if (freename) 1077 free(freename, M_TEMP); 1078 vm_map_lock_read(map); 1079 if (error == -1) { 1080 error = 0; 1081 break; 1082 } 1083 if (last_timestamp != map->timestamp) { 1084 /* 1085 * Look again for the entry because the map was 1086 * modified while it was unlocked. Specifically, 1087 * the entry may have been clipped, merged, or deleted. 1088 */ 1089 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1090 entry = tmp_entry; 1091 } 1092 } 1093 vm_map_unlock_read(map); 1094 vmspace_free(vm); 1095 1096 return (error); 1097} 1098 1099/* 1100 * Criteria for interface name translation 1101 */ 1102#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER) 1103 1104static int 1105linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen) 1106{ 1107 struct ifnet *ifscan; 1108 int ethno; 1109 1110 IFNET_RLOCK_ASSERT(); 1111 1112 /* Short-circuit non ethernet interfaces */ 1113 if (!IFP_IS_ETH(ifp)) 1114 return (strlcpy(buffer, ifp->if_xname, buflen)); 1115 1116 /* Determine the (relative) unit number for ethernet interfaces */ 1117 ethno = 0; 1118 TAILQ_FOREACH(ifscan, &V_ifnet, if_link) { 1119 if (ifscan == ifp) 1120 return (snprintf(buffer, buflen, "eth%d", ethno)); 1121 if (IFP_IS_ETH(ifscan)) 1122 ethno++; 1123 } 1124 1125 return (0); 1126} 1127 1128/* 1129 * Filler function for proc/net/dev 1130 */ 1131static int 1132linprocfs_donetdev(PFS_FILL_ARGS) 1133{ 1134 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1135 struct ifnet *ifp; 1136 1137 sbuf_printf(sb, "%6s|%58s|%s\n" 1138 "%6s|%58s|%58s\n", 1139 "Inter-", " Receive", " Transmit", 1140 " face", 1141 "bytes packets errs drop fifo frame compressed multicast", 1142 "bytes packets errs drop fifo colls carrier compressed"); 1143 1144 CURVNET_SET(TD_TO_VNET(curthread)); 1145 IFNET_RLOCK(); 1146 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1147 linux_ifname(ifp, ifname, sizeof ifname); 1148 sbuf_printf(sb, "%6.6s: ", ifname); 1149 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1150 ifp->if_ibytes, /* rx_bytes */ 1151 ifp->if_ipackets, /* rx_packets */ 1152 ifp->if_ierrors, /* rx_errors */ 1153 ifp->if_iqdrops, /* rx_dropped + 1154 * rx_missed_errors */ 1155 0UL, /* rx_fifo_errors */ 1156 0UL, /* rx_length_errors + 1157 * rx_over_errors + 1158 * rx_crc_errors + 1159 * rx_frame_errors */ 1160 0UL, /* rx_compressed */ 1161 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */ 1162 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1163 ifp->if_obytes, /* tx_bytes */ 1164 ifp->if_opackets, /* tx_packets */ 1165 ifp->if_oerrors, /* tx_errors */ 1166 0UL, /* tx_dropped */ 1167 0UL, /* tx_fifo_errors */ 1168 ifp->if_collisions, /* collisions */ 1169 0UL, /* tx_carrier_errors + 1170 * tx_aborted_errors + 1171 * tx_window_errors + 1172 * tx_heartbeat_errors */ 1173 0UL); /* tx_compressed */ 1174 } 1175 IFNET_RUNLOCK(); 1176 CURVNET_RESTORE(); 1177 1178 return (0); 1179} 1180 1181/* 1182 * Filler function for proc/sys/kernel/osrelease 1183 */ 1184static int 1185linprocfs_doosrelease(PFS_FILL_ARGS) 1186{ 1187 char osrelease[LINUX_MAX_UTSNAME]; 1188 1189 linux_get_osrelease(td, osrelease); 1190 sbuf_printf(sb, "%s\n", osrelease); 1191 1192 return (0); 1193} 1194 1195/* 1196 * Filler function for proc/sys/kernel/ostype 1197 */ 1198static int 1199linprocfs_doostype(PFS_FILL_ARGS) 1200{ 1201 char osname[LINUX_MAX_UTSNAME]; 1202 1203 linux_get_osname(td, osname); 1204 sbuf_printf(sb, "%s\n", osname); 1205 1206 return (0); 1207} 1208 1209/* 1210 * Filler function for proc/sys/kernel/version 1211 */ 1212static int 1213linprocfs_doosbuild(PFS_FILL_ARGS) 1214{ 1215 1216 linprocfs_osbuild(td, sb); 1217 sbuf_cat(sb, "\n"); 1218 return (0); 1219} 1220 1221/* 1222 * Filler function for proc/sys/kernel/msgmni 1223 */ 1224static int 1225linprocfs_domsgmni(PFS_FILL_ARGS) 1226{ 1227 1228 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1229 return (0); 1230} 1231 1232/* 1233 * Filler function for proc/sys/kernel/pid_max 1234 */ 1235static int 1236linprocfs_dopid_max(PFS_FILL_ARGS) 1237{ 1238 1239 sbuf_printf(sb, "%i\n", PID_MAX); 1240 return (0); 1241} 1242 1243/* 1244 * Filler function for proc/sys/kernel/sem 1245 */ 1246static int 1247linprocfs_dosem(PFS_FILL_ARGS) 1248{ 1249 1250 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1251 seminfo.semopm, seminfo.semmni); 1252 return (0); 1253} 1254 1255/* 1256 * Filler function for proc/scsi/device_info 1257 */ 1258static int 1259linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1260{ 1261 1262 return (0); 1263} 1264 1265/* 1266 * Filler function for proc/scsi/scsi 1267 */ 1268static int 1269linprocfs_doscsiscsi(PFS_FILL_ARGS) 1270{ 1271 1272 return (0); 1273} 1274 1275/* 1276 * Filler function for proc/devices 1277 */ 1278static int 1279linprocfs_dodevices(PFS_FILL_ARGS) 1280{ 1281 char *char_devices; 1282 sbuf_printf(sb, "Character devices:\n"); 1283 1284 char_devices = linux_get_char_devices(); 1285 sbuf_printf(sb, "%s", char_devices); 1286 linux_free_get_char_devices(char_devices); 1287 1288 sbuf_printf(sb, "\nBlock devices:\n"); 1289 1290 return (0); 1291} 1292 1293/* 1294 * Filler function for proc/cmdline 1295 */ 1296static int 1297linprocfs_docmdline(PFS_FILL_ARGS) 1298{ 1299 1300 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1301 sbuf_printf(sb, " ro root=302\n"); 1302 return (0); 1303} 1304 1305/* 1306 * Filler function for proc/filesystems 1307 */ 1308static int 1309linprocfs_dofilesystems(PFS_FILL_ARGS) 1310{ 1311 struct vfsconf *vfsp; 1312 1313 mtx_lock(&Giant); 1314 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 1315 if (vfsp->vfc_flags & VFCF_SYNTHETIC) 1316 sbuf_printf(sb, "nodev"); 1317 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name); 1318 } 1319 mtx_unlock(&Giant); 1320 return(0); 1321} 1322 1323#if 0 1324/* 1325 * Filler function for proc/modules 1326 */ 1327static int 1328linprocfs_domodules(PFS_FILL_ARGS) 1329{ 1330 struct linker_file *lf; 1331 1332 TAILQ_FOREACH(lf, &linker_files, link) { 1333 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1334 (unsigned long)lf->size, lf->refs); 1335 } 1336 return (0); 1337} 1338#endif 1339 1340/* 1341 * Filler function for proc/pid/fd 1342 */ 1343static int 1344linprocfs_dofdescfs(PFS_FILL_ARGS) 1345{ 1346 1347 if (p == curproc) 1348 sbuf_printf(sb, "/dev/fd"); 1349 else 1350 sbuf_printf(sb, "unknown"); 1351 return (0); 1352} 1353 1354/* 1355 * Filler function for proc/pid/limits 1356 */ 1357static const struct linux_rlimit_ident { 1358 const char *desc; 1359 const char *unit; 1360 unsigned int rlim_id; 1361} linux_rlimits_ident[] = { 1362 { "Max cpu time", "seconds", RLIMIT_CPU }, 1363 { "Max file size", "bytes", RLIMIT_FSIZE }, 1364 { "Max data size", "bytes", RLIMIT_DATA }, 1365 { "Max stack size", "bytes", RLIMIT_STACK }, 1366 { "Max core file size", "bytes", RLIMIT_CORE }, 1367 { "Max resident set", "bytes", RLIMIT_RSS }, 1368 { "Max processes", "processes", RLIMIT_NPROC }, 1369 { "Max open files", "files", RLIMIT_NOFILE }, 1370 { "Max locked memory", "bytes", RLIMIT_MEMLOCK }, 1371 { "Max address space", "bytes", RLIMIT_AS }, 1372 { "Max file locks", "locks", LINUX_RLIMIT_LOCKS }, 1373 { "Max pending signals", "signals", LINUX_RLIMIT_SIGPENDING }, 1374 { "Max msgqueue size", "bytes", LINUX_RLIMIT_MSGQUEUE }, 1375 { "Max nice priority", "", LINUX_RLIMIT_NICE }, 1376 { "Max realtime priority", "", LINUX_RLIMIT_RTPRIO }, 1377 { "Max realtime timeout", "us", LINUX_RLIMIT_RTTIME }, 1378 { 0, 0, 0 } 1379}; 1380 1381static int 1382linprocfs_doproclimits(PFS_FILL_ARGS) 1383{ 1384 const struct linux_rlimit_ident *li; 1385 struct plimit *limp; 1386 struct rlimit rl; 1387 ssize_t size; 1388 int res, error; 1389 1390 error = 0; 1391 1392 PROC_LOCK(p); 1393 limp = lim_hold(p->p_limit); 1394 PROC_UNLOCK(p); 1395 size = sizeof(res); 1396 sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit", 1397 "Hard Limit", "Units"); 1398 for (li = linux_rlimits_ident; li->desc != NULL; ++li) { 1399 switch (li->rlim_id) 1400 { 1401 case LINUX_RLIMIT_LOCKS: 1402 /* FALLTHROUGH */ 1403 case LINUX_RLIMIT_RTTIME: 1404 rl.rlim_cur = RLIM_INFINITY; 1405 break; 1406 case LINUX_RLIMIT_SIGPENDING: 1407 error = kernel_sysctlbyname(td, 1408 "kern.sigqueue.max_pending_per_proc", 1409 &res, &size, 0, 0, 0, 0); 1410 if (error != 0) 1411 goto out; 1412 rl.rlim_cur = res; 1413 rl.rlim_max = res; 1414 break; 1415 case LINUX_RLIMIT_MSGQUEUE: 1416 error = kernel_sysctlbyname(td, 1417 "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0); 1418 if (error != 0) 1419 goto out; 1420 rl.rlim_cur = res; 1421 rl.rlim_max = res; 1422 break; 1423 case LINUX_RLIMIT_NICE: 1424 /* FALLTHROUGH */ 1425 case LINUX_RLIMIT_RTPRIO: 1426 rl.rlim_cur = 0; 1427 rl.rlim_max = 0; 1428 break; 1429 default: 1430 rl = limp->pl_rlimit[li->rlim_id]; 1431 break; 1432 } 1433 if (rl.rlim_cur == RLIM_INFINITY) 1434 sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n", 1435 li->desc, "unlimited", "unlimited", li->unit); 1436 else 1437 sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n", 1438 li->desc, (unsigned long long)rl.rlim_cur, 1439 (unsigned long long)rl.rlim_max, li->unit); 1440 } 1441out: 1442 lim_free(limp); 1443 return (error); 1444} 1445 1446/* 1447 * Filler function for proc/sys/kernel/random/uuid 1448 */ 1449static int 1450linprocfs_douuid(PFS_FILL_ARGS) 1451{ 1452 struct uuid uuid; 1453 1454 kern_uuidgen(&uuid, 1); 1455 sbuf_printf_uuid(sb, &uuid); 1456 sbuf_printf(sb, "\n"); 1457 return(0); 1458} 1459 1460/* 1461 * Filler function for proc/pid/auxv 1462 */ 1463static int 1464linprocfs_doauxv(PFS_FILL_ARGS) 1465{ 1466 struct sbuf *asb; 1467 off_t buflen, resid; 1468 int error; 1469 1470 /* 1471 * Mimic linux behavior and pass only processes with usermode 1472 * address space as valid. Return zero silently otherwise. 1473 */ 1474 if (p->p_vmspace == &vmspace0) 1475 return (0); 1476 1477 if (uio->uio_resid == 0) 1478 return (0); 1479 if (uio->uio_offset < 0 || uio->uio_resid < 0) 1480 return (EINVAL); 1481 1482 asb = sbuf_new_auto(); 1483 if (asb == NULL) 1484 return (ENOMEM); 1485 error = proc_getauxv(td, p, asb); 1486 if (error == 0) 1487 error = sbuf_finish(asb); 1488 1489 resid = sbuf_len(asb) - uio->uio_offset; 1490 if (resid > uio->uio_resid) 1491 buflen = uio->uio_resid; 1492 else 1493 buflen = resid; 1494 if (buflen > IOSIZE_MAX) 1495 return (EINVAL); 1496 if (buflen > MAXPHYS) 1497 buflen = MAXPHYS; 1498 if (resid <= 0) 1499 return (0); 1500 1501 if (error == 0) 1502 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio); 1503 sbuf_delete(asb); 1504 return (error); 1505} 1506 1507/* 1508 * Constructor 1509 */ 1510static int 1511linprocfs_init(PFS_INIT_ARGS) 1512{ 1513 struct pfs_node *root; 1514 struct pfs_node *dir; 1515 1516 root = pi->pi_root; 1517 1518 /* /proc/... */ 1519 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1520 NULL, NULL, NULL, PFS_RD); 1521 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1522 NULL, NULL, NULL, PFS_RD); 1523 pfs_create_file(root, "devices", &linprocfs_dodevices, 1524 NULL, NULL, NULL, PFS_RD); 1525 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1526 NULL, NULL, NULL, PFS_RD); 1527 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1528 NULL, NULL, NULL, PFS_RD); 1529 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1530 NULL, NULL, NULL, PFS_RD); 1531#if 0 1532 pfs_create_file(root, "modules", &linprocfs_domodules, 1533 NULL, NULL, NULL, PFS_RD); 1534#endif 1535 pfs_create_file(root, "mounts", &linprocfs_domtab, 1536 NULL, NULL, NULL, PFS_RD); 1537 pfs_create_file(root, "mtab", &linprocfs_domtab, 1538 NULL, NULL, NULL, PFS_RD); 1539 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1540 NULL, NULL, NULL, PFS_RD); 1541 pfs_create_link(root, "self", &procfs_docurproc, 1542 NULL, NULL, NULL, 0); 1543 pfs_create_file(root, "stat", &linprocfs_dostat, 1544 NULL, NULL, NULL, PFS_RD); 1545 pfs_create_file(root, "swaps", &linprocfs_doswaps, 1546 NULL, NULL, NULL, PFS_RD); 1547 pfs_create_file(root, "uptime", &linprocfs_douptime, 1548 NULL, NULL, NULL, PFS_RD); 1549 pfs_create_file(root, "version", &linprocfs_doversion, 1550 NULL, NULL, NULL, PFS_RD); 1551 1552 /* /proc/net/... */ 1553 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1554 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1555 NULL, NULL, NULL, PFS_RD); 1556 1557 /* /proc/<pid>/... */ 1558 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1559 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1560 NULL, NULL, NULL, PFS_RD); 1561 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1562 NULL, NULL, NULL, 0); 1563 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1564 NULL, &procfs_candebug, NULL, PFS_RD); 1565 pfs_create_link(dir, "exe", &procfs_doprocfile, 1566 NULL, &procfs_notsystem, NULL, 0); 1567 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1568 NULL, NULL, NULL, PFS_RD); 1569 pfs_create_file(dir, "mem", &procfs_doprocmem, 1570 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1571 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1572 NULL, NULL, NULL, 0); 1573 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1574 NULL, NULL, NULL, PFS_RD); 1575 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1576 NULL, NULL, NULL, PFS_RD); 1577 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1578 NULL, NULL, NULL, PFS_RD); 1579 pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1580 NULL, NULL, NULL, 0); 1581 pfs_create_file(dir, "auxv", &linprocfs_doauxv, 1582 NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD); 1583 pfs_create_file(dir, "limits", &linprocfs_doproclimits, 1584 NULL, NULL, NULL, PFS_RD); 1585 1586 /* /proc/scsi/... */ 1587 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1588 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1589 NULL, NULL, NULL, PFS_RD); 1590 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1591 NULL, NULL, NULL, PFS_RD); 1592 1593 /* /proc/sys/... */ 1594 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1595 /* /proc/sys/kernel/... */ 1596 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1597 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1598 NULL, NULL, NULL, PFS_RD); 1599 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1600 NULL, NULL, NULL, PFS_RD); 1601 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1602 NULL, NULL, NULL, PFS_RD); 1603 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1604 NULL, NULL, NULL, PFS_RD); 1605 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1606 NULL, NULL, NULL, PFS_RD); 1607 pfs_create_file(dir, "sem", &linprocfs_dosem, 1608 NULL, NULL, NULL, PFS_RD); 1609 1610 /* /proc/sys/kernel/random/... */ 1611 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0); 1612 pfs_create_file(dir, "uuid", &linprocfs_douuid, 1613 NULL, NULL, NULL, PFS_RD); 1614 1615 return (0); 1616} 1617 1618/* 1619 * Destructor 1620 */ 1621static int 1622linprocfs_uninit(PFS_INIT_ARGS) 1623{ 1624 1625 /* nothing to do, pseudofs will GC */ 1626 return (0); 1627} 1628 1629PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS); 1630#if defined(__amd64__) 1631MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1); 1632#else 1633MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1634#endif 1635MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1636MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1637MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1638