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