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