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