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