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