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