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