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/sbuf.h> 65 #include <sys/sem.h> 66 #include <sys/smp.h> 67 #include <sys/socket.h> 68 #include <sys/syscallsubr.h> 69 #include <sys/sysctl.h> 70 #include <sys/sysent.h> 71 #include <sys/systm.h> 72 #include <sys/time.h> 73 #include <sys/tty.h> 74 #include <sys/user.h> 75 #include <sys/uuid.h> 76 #include <sys/vmmeter.h> 77 #include <sys/vnode.h> 78 #include <sys/bus.h> 79 80 #include <net/if.h> 81 #include <net/if_var.h> 82 #include <net/if_types.h> 83 84 #include <vm/vm.h> 85 #include <vm/vm_extern.h> 86 #include <vm/pmap.h> 87 #include <vm/vm_map.h> 88 #include <vm/vm_param.h> 89 #include <vm/vm_object.h> 90 #include <vm/swap_pager.h> 91 92 #include <machine/clock.h> 93 94 #include <geom/geom.h> 95 #include <geom/geom_int.h> 96 97 #if defined(__i386__) || defined(__amd64__) 98 #include <machine/cputypes.h> 99 #include <machine/md_var.h> 100 #endif /* __i386__ || __amd64__ */ 101 102 #include <compat/linux/linux.h> 103 #include <compat/linux/linux_mib.h> 104 #include <compat/linux/linux_misc.h> 105 #include <compat/linux/linux_util.h> 106 #include <fs/pseudofs/pseudofs.h> 107 #include <fs/procfs/procfs.h> 108 109 /* 110 * Various conversion macros 111 */ 112 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to jiffies */ 113 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz))) /* ticks to centiseconds */ 114 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 115 #define B2K(x) ((x) >> 10) /* bytes to kbytes */ 116 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 117 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 118 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 119 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000) 120 121 /** 122 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 123 * 124 * The linux procfs state field displays one of the characters RSDZTW to 125 * denote running, sleeping in an interruptible wait, waiting in an 126 * uninterruptible disk sleep, a zombie process, process is being traced 127 * or stopped, or process is paging respectively. 128 * 129 * Our struct kinfo_proc contains the variable ki_stat which contains a 130 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 131 * 132 * This character array is used with ki_stati-1 as an index and tries to 133 * map our states to suitable linux states. 134 */ 135 static char linux_state[] = "RRSTZDD"; 136 137 /* 138 * Filler function for proc/meminfo 139 */ 140 static int 141 linprocfs_domeminfo(PFS_FILL_ARGS) 142 { 143 unsigned long memtotal; /* total memory in bytes */ 144 unsigned long memused; /* used memory in bytes */ 145 unsigned long memfree; /* free memory in bytes */ 146 unsigned long memshared; /* shared memory ??? */ 147 unsigned long buffers, cached; /* buffer / cache memory ??? */ 148 unsigned long long swaptotal; /* total swap space in bytes */ 149 unsigned long long swapused; /* used swap space in bytes */ 150 unsigned long long swapfree; /* free swap space in bytes */ 151 vm_object_t object; 152 int i, j; 153 154 memtotal = physmem * PAGE_SIZE; 155 /* 156 * The correct thing here would be: 157 * 158 memfree = vm_cnt.v_free_count * PAGE_SIZE; 159 memused = memtotal - memfree; 160 * 161 * but it might mislead linux binaries into thinking there 162 * is very little memory left, so we cheat and tell them that 163 * all memory that isn't wired down is free. 164 */ 165 memused = vm_cnt.v_wire_count * PAGE_SIZE; 166 memfree = memtotal - memused; 167 swap_pager_status(&i, &j); 168 swaptotal = (unsigned long long)i * PAGE_SIZE; 169 swapused = (unsigned long long)j * PAGE_SIZE; 170 swapfree = swaptotal - swapused; 171 memshared = 0; 172 mtx_lock(&vm_object_list_mtx); 173 TAILQ_FOREACH(object, &vm_object_list, object_list) 174 if (object->shadow_count > 1) 175 memshared += object->resident_page_count; 176 mtx_unlock(&vm_object_list_mtx); 177 memshared *= PAGE_SIZE; 178 /* 179 * We'd love to be able to write: 180 * 181 buffers = bufspace; 182 * 183 * but bufspace is internal to vfs_bio.c and we don't feel 184 * like unstaticizing it just for linprocfs's sake. 185 */ 186 buffers = 0; 187 cached = vm_cnt.v_cache_count * PAGE_SIZE; 188 189 sbuf_printf(sb, 190 " total: used: free: shared: buffers: cached:\n" 191 "Mem: %lu %lu %lu %lu %lu %lu\n" 192 "Swap: %llu %llu %llu\n" 193 "MemTotal: %9lu kB\n" 194 "MemFree: %9lu kB\n" 195 "MemShared:%9lu kB\n" 196 "Buffers: %9lu kB\n" 197 "Cached: %9lu kB\n" 198 "SwapTotal:%9llu kB\n" 199 "SwapFree: %9llu kB\n", 200 memtotal, memused, memfree, memshared, buffers, cached, 201 swaptotal, swapused, swapfree, 202 B2K(memtotal), B2K(memfree), 203 B2K(memshared), B2K(buffers), B2K(cached), 204 B2K(swaptotal), B2K(swapfree)); 205 206 return (0); 207 } 208 209 #if defined(__i386__) || defined(__amd64__) 210 /* 211 * Filler function for proc/cpuinfo (i386 & amd64 version) 212 */ 213 static int 214 linprocfs_docpuinfo(PFS_FILL_ARGS) 215 { 216 int hw_model[2]; 217 char model[128]; 218 uint64_t freq; 219 size_t size; 220 int class, fqmhz, fqkhz; 221 int i; 222 223 /* 224 * We default the flags to include all non-conflicting flags, 225 * and the Intel versions of conflicting flags. 226 */ 227 static char *flags[] = { 228 "fpu", "vme", "de", "pse", "tsc", 229 "msr", "pae", "mce", "cx8", "apic", 230 "sep", "sep", "mtrr", "pge", "mca", 231 "cmov", "pat", "pse36", "pn", "b19", 232 "b20", "b21", "mmxext", "mmx", "fxsr", 233 "xmm", "sse2", "b27", "b28", "b29", 234 "3dnowext", "3dnow" 235 }; 236 237 switch (cpu_class) { 238 #ifdef __i386__ 239 case CPUCLASS_286: 240 class = 2; 241 break; 242 case CPUCLASS_386: 243 class = 3; 244 break; 245 case CPUCLASS_486: 246 class = 4; 247 break; 248 case CPUCLASS_586: 249 class = 5; 250 break; 251 case CPUCLASS_686: 252 class = 6; 253 break; 254 default: 255 class = 0; 256 break; 257 #else /* __amd64__ */ 258 default: 259 class = 15; 260 break; 261 #endif 262 } 263 264 hw_model[0] = CTL_HW; 265 hw_model[1] = HW_MODEL; 266 model[0] = '\0'; 267 size = sizeof(model); 268 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 269 strcpy(model, "unknown"); 270 for (i = 0; i < mp_ncpus; ++i) { 271 sbuf_printf(sb, 272 "processor\t: %d\n" 273 "vendor_id\t: %.20s\n" 274 "cpu family\t: %u\n" 275 "model\t\t: %u\n" 276 "model name\t: %s\n" 277 "stepping\t: %u\n\n", 278 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id), 279 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING); 280 /* XXX per-cpu vendor / class / model / id? */ 281 } 282 283 sbuf_cat(sb, "flags\t\t:"); 284 285 #ifdef __i386__ 286 switch (cpu_vendor_id) { 287 case CPU_VENDOR_AMD: 288 if (class < 6) 289 flags[16] = "fcmov"; 290 break; 291 case CPU_VENDOR_CYRIX: 292 flags[24] = "cxmmx"; 293 break; 294 } 295 #endif 296 297 for (i = 0; i < 32; i++) 298 if (cpu_feature & (1 << i)) 299 sbuf_printf(sb, " %s", flags[i]); 300 sbuf_cat(sb, "\n"); 301 freq = atomic_load_acq_64(&tsc_freq); 302 if (freq != 0) { 303 fqmhz = (freq + 4999) / 1000000; 304 fqkhz = ((freq + 4999) / 10000) % 100; 305 sbuf_printf(sb, 306 "cpu MHz\t\t: %d.%02d\n" 307 "bogomips\t: %d.%02d\n", 308 fqmhz, fqkhz, fqmhz, fqkhz); 309 } 310 311 return (0); 312 } 313 #endif /* __i386__ || __amd64__ */ 314 315 /* 316 * Filler function for proc/mtab 317 * 318 * This file doesn't exist in Linux' procfs, but is included here so 319 * users can symlink /compat/linux/etc/mtab to /proc/mtab 320 */ 321 static int 322 linprocfs_domtab(PFS_FILL_ARGS) 323 { 324 struct nameidata nd; 325 const char *lep; 326 char *dlep, *flep, *mntto, *mntfrom, *fstype; 327 size_t lep_len; 328 int error; 329 struct statfs *buf, *sp; 330 size_t count; 331 332 /* resolve symlinks etc. in the emulation tree prefix */ 333 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td); 334 flep = NULL; 335 error = namei(&nd); 336 lep = linux_emul_path; 337 if (error == 0) { 338 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 339 lep = dlep; 340 vrele(nd.ni_vp); 341 } 342 lep_len = strlen(lep); 343 344 buf = NULL; 345 error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count, 346 UIO_SYSSPACE, MNT_WAIT); 347 if (error != 0) { 348 free(buf, M_TEMP); 349 free(flep, M_TEMP); 350 return (error); 351 } 352 353 for (sp = buf; count > 0; sp++, count--) { 354 /* determine device name */ 355 mntfrom = sp->f_mntfromname; 356 357 /* determine mount point */ 358 mntto = sp->f_mntonname; 359 if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/') 360 mntto += lep_len; 361 362 /* determine fs type */ 363 fstype = sp->f_fstypename; 364 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 365 mntfrom = fstype = "proc"; 366 else if (strcmp(fstype, "procfs") == 0) 367 continue; 368 369 if (strcmp(fstype, "linsysfs") == 0) { 370 sbuf_printf(sb, "/sys %s sysfs %s", mntto, 371 sp->f_flags & MNT_RDONLY ? "ro" : "rw"); 372 } else { 373 /* For Linux msdosfs is called vfat */ 374 if (strcmp(fstype, "msdosfs") == 0) 375 fstype = "vfat"; 376 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 377 sp->f_flags & MNT_RDONLY ? "ro" : "rw"); 378 } 379 #define ADD_OPTION(opt, name) \ 380 if (sp->f_flags & (opt)) sbuf_printf(sb, "," name); 381 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 382 ADD_OPTION(MNT_NOEXEC, "noexec"); 383 ADD_OPTION(MNT_NOSUID, "nosuid"); 384 ADD_OPTION(MNT_UNION, "union"); 385 ADD_OPTION(MNT_ASYNC, "async"); 386 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 387 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 388 ADD_OPTION(MNT_NOATIME, "noatime"); 389 #undef ADD_OPTION 390 /* a real Linux mtab will also show NFS options */ 391 sbuf_printf(sb, " 0 0\n"); 392 } 393 394 free(buf, M_TEMP); 395 free(flep, M_TEMP); 396 return (error); 397 } 398 399 /* 400 * Filler function for proc/partitions 401 */ 402 static int 403 linprocfs_dopartitions(PFS_FILL_ARGS) 404 { 405 struct g_class *cp; 406 struct g_geom *gp; 407 struct g_provider *pp; 408 int major, minor; 409 410 g_topology_lock(); 411 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect " 412 "ruse wio wmerge wsect wuse running use aveq\n"); 413 414 LIST_FOREACH(cp, &g_classes, class) { 415 if (strcmp(cp->name, "DISK") == 0 || 416 strcmp(cp->name, "PART") == 0) 417 LIST_FOREACH(gp, &cp->geom, geom) { 418 LIST_FOREACH(pp, &gp->provider, provider) { 419 if (linux_driver_get_major_minor( 420 pp->name, &major, &minor) != 0) { 421 major = 0; 422 minor = 0; 423 } 424 sbuf_printf(sb, "%d %d %lld %s " 425 "%d %d %d %d %d " 426 "%d %d %d %d %d %d\n", 427 major, minor, 428 (long long)pp->mediasize, pp->name, 429 0, 0, 0, 0, 0, 430 0, 0, 0, 0, 0, 0); 431 } 432 } 433 } 434 g_topology_unlock(); 435 436 return (0); 437 } 438 439 440 /* 441 * Filler function for proc/stat 442 */ 443 static int 444 linprocfs_dostat(PFS_FILL_ARGS) 445 { 446 struct pcpu *pcpu; 447 long cp_time[CPUSTATES]; 448 long *cp; 449 int i; 450 451 read_cpu_time(cp_time); 452 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 453 T2J(cp_time[CP_USER]), 454 T2J(cp_time[CP_NICE]), 455 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 456 T2J(cp_time[CP_IDLE])); 457 CPU_FOREACH(i) { 458 pcpu = pcpu_find(i); 459 cp = pcpu->pc_cp_time; 460 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 461 T2J(cp[CP_USER]), 462 T2J(cp[CP_NICE]), 463 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 464 T2J(cp[CP_IDLE])); 465 } 466 sbuf_printf(sb, 467 "disk 0 0 0 0\n" 468 "page %u %u\n" 469 "swap %u %u\n" 470 "intr %u\n" 471 "ctxt %u\n" 472 "btime %lld\n", 473 vm_cnt.v_vnodepgsin, 474 vm_cnt.v_vnodepgsout, 475 vm_cnt.v_swappgsin, 476 vm_cnt.v_swappgsout, 477 vm_cnt.v_intr, 478 vm_cnt.v_swtch, 479 (long long)boottime.tv_sec); 480 return (0); 481 } 482 483 static int 484 linprocfs_doswaps(PFS_FILL_ARGS) 485 { 486 struct xswdev xsw; 487 uintmax_t total, used; 488 int n; 489 char devname[SPECNAMELEN + 1]; 490 491 sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n"); 492 mtx_lock(&Giant); 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 mtx_unlock(&Giant); 507 return (0); 508 } 509 510 /* 511 * Filler function for proc/uptime 512 */ 513 static int 514 linprocfs_douptime(PFS_FILL_ARGS) 515 { 516 long cp_time[CPUSTATES]; 517 struct timeval tv; 518 519 getmicrouptime(&tv); 520 read_cpu_time(cp_time); 521 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n", 522 (long long)tv.tv_sec, tv.tv_usec / 10000, 523 T2S(cp_time[CP_IDLE] / mp_ncpus), 524 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100); 525 return (0); 526 } 527 528 /* 529 * Get OS build date 530 */ 531 static void 532 linprocfs_osbuild(struct thread *td, struct sbuf *sb) 533 { 534 #if 0 535 char osbuild[256]; 536 char *cp1, *cp2; 537 538 strncpy(osbuild, version, 256); 539 osbuild[255] = '\0'; 540 cp1 = strstr(osbuild, "\n"); 541 cp2 = strstr(osbuild, ":"); 542 if (cp1 && cp2) { 543 *cp1 = *cp2 = '\0'; 544 cp1 = strstr(osbuild, "#"); 545 } else 546 cp1 = NULL; 547 if (cp1) 548 sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 549 else 550 #endif 551 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 552 } 553 554 /* 555 * Get OS builder 556 */ 557 static void 558 linprocfs_osbuilder(struct thread *td, struct sbuf *sb) 559 { 560 #if 0 561 char builder[256]; 562 char *cp; 563 564 cp = strstr(version, "\n "); 565 if (cp) { 566 strncpy(builder, cp + 5, 256); 567 builder[255] = '\0'; 568 cp = strstr(builder, ":"); 569 if (cp) 570 *cp = '\0'; 571 } 572 if (cp) 573 sbuf_cat(sb, builder); 574 else 575 #endif 576 sbuf_cat(sb, "des@freebsd.org"); 577 } 578 579 /* 580 * Filler function for proc/version 581 */ 582 static int 583 linprocfs_doversion(PFS_FILL_ARGS) 584 { 585 char osname[LINUX_MAX_UTSNAME]; 586 char osrelease[LINUX_MAX_UTSNAME]; 587 588 linux_get_osname(td, osname); 589 linux_get_osrelease(td, osrelease); 590 sbuf_printf(sb, "%s version %s (", osname, osrelease); 591 linprocfs_osbuilder(td, sb); 592 sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 593 linprocfs_osbuild(td, sb); 594 sbuf_cat(sb, "\n"); 595 596 return (0); 597 } 598 599 /* 600 * Filler function for proc/loadavg 601 */ 602 static int 603 linprocfs_doloadavg(PFS_FILL_ARGS) 604 { 605 606 sbuf_printf(sb, 607 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 608 (int)(averunnable.ldavg[0] / averunnable.fscale), 609 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 610 (int)(averunnable.ldavg[1] / averunnable.fscale), 611 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 612 (int)(averunnable.ldavg[2] / averunnable.fscale), 613 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 614 1, /* number of running tasks */ 615 nprocs, /* number of tasks */ 616 lastpid /* the last pid */ 617 ); 618 return (0); 619 } 620 621 /* 622 * Filler function for proc/pid/stat 623 */ 624 static int 625 linprocfs_doprocstat(PFS_FILL_ARGS) 626 { 627 struct kinfo_proc kp; 628 char state; 629 static int ratelimit = 0; 630 vm_offset_t startcode, startdata; 631 632 sx_slock(&proctree_lock); 633 PROC_LOCK(p); 634 fill_kinfo_proc(p, &kp); 635 sx_sunlock(&proctree_lock); 636 if (p->p_vmspace) { 637 startcode = (vm_offset_t)p->p_vmspace->vm_taddr; 638 startdata = (vm_offset_t)p->p_vmspace->vm_daddr; 639 } else { 640 startcode = 0; 641 startdata = 0; 642 }; 643 sbuf_printf(sb, "%d", p->p_pid); 644 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 645 PS_ADD("comm", "(%s)", p->p_comm); 646 if (kp.ki_stat > sizeof(linux_state)) { 647 state = 'R'; 648 649 if (ratelimit == 0) { 650 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 651 kp.ki_stat, sizeof(linux_state)); 652 ++ratelimit; 653 } 654 } else 655 state = linux_state[kp.ki_stat - 1]; 656 PS_ADD("state", "%c", state); 657 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 658 PS_ADD("pgrp", "%d", p->p_pgid); 659 PS_ADD("session", "%d", p->p_session->s_sid); 660 PROC_UNLOCK(p); 661 PS_ADD("tty", "%ju", (uintmax_t)kp.ki_tdev); 662 PS_ADD("tpgid", "%d", kp.ki_tpgid); 663 PS_ADD("flags", "%u", 0); /* XXX */ 664 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 665 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 666 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 667 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 668 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime)); 669 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime)); 670 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime)); 671 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime)); 672 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 673 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 674 PS_ADD("0", "%d", 0); /* removed field */ 675 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 676 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime)); 677 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 678 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 679 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 680 PS_ADD("startcode", "%ju", (uintmax_t)startcode); 681 PS_ADD("endcode", "%ju", (uintmax_t)startdata); 682 PS_ADD("startstack", "%u", 0); /* XXX */ 683 PS_ADD("kstkesp", "%u", 0); /* XXX */ 684 PS_ADD("kstkeip", "%u", 0); /* XXX */ 685 PS_ADD("signal", "%u", 0); /* XXX */ 686 PS_ADD("blocked", "%u", 0); /* XXX */ 687 PS_ADD("sigignore", "%u", 0); /* XXX */ 688 PS_ADD("sigcatch", "%u", 0); /* XXX */ 689 PS_ADD("wchan", "%u", 0); /* XXX */ 690 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 691 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 692 PS_ADD("exitsignal", "%d", 0); /* XXX */ 693 PS_ADD("processor", "%u", kp.ki_lastcpu); 694 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 695 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 696 #undef PS_ADD 697 sbuf_putc(sb, '\n'); 698 699 return (0); 700 } 701 702 /* 703 * Filler function for proc/pid/statm 704 */ 705 static int 706 linprocfs_doprocstatm(PFS_FILL_ARGS) 707 { 708 struct kinfo_proc kp; 709 segsz_t lsize; 710 711 sx_slock(&proctree_lock); 712 PROC_LOCK(p); 713 fill_kinfo_proc(p, &kp); 714 PROC_UNLOCK(p); 715 sx_sunlock(&proctree_lock); 716 717 /* 718 * See comments in linprocfs_doprocstatus() regarding the 719 * computation of lsize. 720 */ 721 /* size resident share trs drs lrs dt */ 722 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 723 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 724 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 725 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 726 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 727 lsize = B2P(kp.ki_size) - kp.ki_dsize - 728 kp.ki_ssize - kp.ki_tsize - 1; 729 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 730 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 731 732 return (0); 733 } 734 735 /* 736 * Filler function for proc/pid/status 737 */ 738 static int 739 linprocfs_doprocstatus(PFS_FILL_ARGS) 740 { 741 struct kinfo_proc kp; 742 char *state; 743 segsz_t lsize; 744 struct thread *td2; 745 struct sigacts *ps; 746 l_sigset_t siglist, sigignore, sigcatch; 747 int i; 748 749 sx_slock(&proctree_lock); 750 PROC_LOCK(p); 751 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 752 753 if (P_SHOULDSTOP(p)) { 754 state = "T (stopped)"; 755 } else { 756 switch(p->p_state) { 757 case PRS_NEW: 758 state = "I (idle)"; 759 break; 760 case PRS_NORMAL: 761 if (p->p_flag & P_WEXIT) { 762 state = "X (exiting)"; 763 break; 764 } 765 switch(td2->td_state) { 766 case TDS_INHIBITED: 767 state = "S (sleeping)"; 768 break; 769 case TDS_RUNQ: 770 case TDS_RUNNING: 771 state = "R (running)"; 772 break; 773 default: 774 state = "? (unknown)"; 775 break; 776 } 777 break; 778 case PRS_ZOMBIE: 779 state = "Z (zombie)"; 780 break; 781 default: 782 state = "? (unknown)"; 783 break; 784 } 785 } 786 787 fill_kinfo_proc(p, &kp); 788 sx_sunlock(&proctree_lock); 789 790 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 791 sbuf_printf(sb, "State:\t%s\n", state); 792 793 /* 794 * Credentials 795 */ 796 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 797 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 798 p->p_pptr->p_pid : 0); 799 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 800 p->p_ucred->cr_uid, 801 p->p_ucred->cr_svuid, 802 /* FreeBSD doesn't have fsuid */ 803 p->p_ucred->cr_uid); 804 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 805 p->p_ucred->cr_gid, 806 p->p_ucred->cr_svgid, 807 /* FreeBSD doesn't have fsgid */ 808 p->p_ucred->cr_gid); 809 sbuf_cat(sb, "Groups:\t"); 810 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 811 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 812 PROC_UNLOCK(p); 813 sbuf_putc(sb, '\n'); 814 815 /* 816 * Memory 817 * 818 * While our approximation of VmLib may not be accurate (I 819 * don't know of a simple way to verify it, and I'm not sure 820 * it has much meaning anyway), I believe it's good enough. 821 * 822 * The same code that could (I think) accurately compute VmLib 823 * could also compute VmLck, but I don't really care enough to 824 * implement it. Submissions are welcome. 825 */ 826 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 827 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 828 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 829 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 830 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 831 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 832 lsize = B2P(kp.ki_size) - kp.ki_dsize - 833 kp.ki_ssize - kp.ki_tsize - 1; 834 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 835 836 /* 837 * Signal masks 838 */ 839 PROC_LOCK(p); 840 bsd_to_linux_sigset(&p->p_siglist, &siglist); 841 ps = p->p_sigacts; 842 mtx_lock(&ps->ps_mtx); 843 bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore); 844 bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch); 845 mtx_unlock(&ps->ps_mtx); 846 PROC_UNLOCK(p); 847 848 sbuf_printf(sb, "SigPnd:\t%016jx\n", siglist.__mask); 849 /* 850 * XXX. SigBlk - target thread's signal mask, td_sigmask. 851 * To implement SigBlk pseudofs should support proc/tid dir entries. 852 */ 853 sbuf_printf(sb, "SigBlk:\t%016x\n", 0); 854 sbuf_printf(sb, "SigIgn:\t%016jx\n", sigignore.__mask); 855 sbuf_printf(sb, "SigCgt:\t%016jx\n", sigcatch.__mask); 856 857 /* 858 * Linux also prints the capability masks, but we don't have 859 * capabilities yet, and when we do get them they're likely to 860 * be meaningless to Linux programs, so we lie. XXX 861 */ 862 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 863 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 864 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 865 866 return (0); 867 } 868 869 870 /* 871 * Filler function for proc/pid/cwd 872 */ 873 static int 874 linprocfs_doproccwd(PFS_FILL_ARGS) 875 { 876 char *fullpath = "unknown"; 877 char *freepath = NULL; 878 879 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 880 sbuf_printf(sb, "%s", fullpath); 881 if (freepath) 882 free(freepath, M_TEMP); 883 return (0); 884 } 885 886 /* 887 * Filler function for proc/pid/root 888 */ 889 static int 890 linprocfs_doprocroot(PFS_FILL_ARGS) 891 { 892 struct vnode *rvp; 893 char *fullpath = "unknown"; 894 char *freepath = NULL; 895 896 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 897 vn_fullpath(td, rvp, &fullpath, &freepath); 898 sbuf_printf(sb, "%s", fullpath); 899 if (freepath) 900 free(freepath, M_TEMP); 901 return (0); 902 } 903 904 /* 905 * Filler function for proc/pid/cmdline 906 */ 907 static int 908 linprocfs_doproccmdline(PFS_FILL_ARGS) 909 { 910 int ret; 911 912 PROC_LOCK(p); 913 if ((ret = p_cansee(td, p)) != 0) { 914 PROC_UNLOCK(p); 915 return (ret); 916 } 917 918 /* 919 * Mimic linux behavior and pass only processes with usermode 920 * address space as valid. Return zero silently otherwize. 921 */ 922 if (p->p_vmspace == &vmspace0) { 923 PROC_UNLOCK(p); 924 return (0); 925 } 926 if (p->p_args != NULL) { 927 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 928 PROC_UNLOCK(p); 929 return (0); 930 } 931 932 if ((p->p_flag & P_SYSTEM) != 0) { 933 PROC_UNLOCK(p); 934 return (0); 935 } 936 937 PROC_UNLOCK(p); 938 939 ret = proc_getargv(td, p, sb); 940 return (ret); 941 } 942 943 /* 944 * Filler function for proc/pid/environ 945 */ 946 static int 947 linprocfs_doprocenviron(PFS_FILL_ARGS) 948 { 949 int ret; 950 951 PROC_LOCK(p); 952 if ((ret = p_candebug(td, p)) != 0) { 953 PROC_UNLOCK(p); 954 return (ret); 955 } 956 957 /* 958 * Mimic linux behavior and pass only processes with usermode 959 * address space as valid. Return zero silently otherwize. 960 */ 961 if (p->p_vmspace == &vmspace0) { 962 PROC_UNLOCK(p); 963 return (0); 964 } 965 966 if ((p->p_flag & P_SYSTEM) != 0) { 967 PROC_UNLOCK(p); 968 return (0); 969 } 970 971 PROC_UNLOCK(p); 972 973 ret = proc_getenvv(td, p, sb); 974 return (ret); 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 if (lobj->type == OBJT_VNODE) { 1046 vp = lobj->handle; 1047 if (vp) 1048 vref(vp); 1049 } 1050 else 1051 vp = NULL; 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) { 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 mtx_lock(&Giant); 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 mtx_unlock(&Giant); 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 /* 1374 * Filler function for proc/sys/kernel/random/uuid 1375 */ 1376 static int 1377 linprocfs_douuid(PFS_FILL_ARGS) 1378 { 1379 struct uuid uuid; 1380 1381 kern_uuidgen(&uuid, 1); 1382 sbuf_printf_uuid(sb, &uuid); 1383 sbuf_printf(sb, "\n"); 1384 return(0); 1385 } 1386 1387 /* 1388 * Filler function for proc/pid/auxv 1389 */ 1390 static int 1391 linprocfs_doauxv(PFS_FILL_ARGS) 1392 { 1393 struct sbuf *asb; 1394 off_t buflen, resid; 1395 int error; 1396 1397 /* 1398 * Mimic linux behavior and pass only processes with usermode 1399 * address space as valid. Return zero silently otherwise. 1400 */ 1401 if (p->p_vmspace == &vmspace0) 1402 return (0); 1403 1404 if (uio->uio_resid == 0) 1405 return (0); 1406 if (uio->uio_offset < 0 || uio->uio_resid < 0) 1407 return (EINVAL); 1408 1409 asb = sbuf_new_auto(); 1410 if (asb == NULL) 1411 return (ENOMEM); 1412 error = proc_getauxv(td, p, asb); 1413 if (error == 0) 1414 error = sbuf_finish(asb); 1415 1416 resid = sbuf_len(asb) - uio->uio_offset; 1417 if (resid > uio->uio_resid) 1418 buflen = uio->uio_resid; 1419 else 1420 buflen = resid; 1421 if (buflen > IOSIZE_MAX) 1422 return (EINVAL); 1423 if (buflen > MAXPHYS) 1424 buflen = MAXPHYS; 1425 if (resid <= 0) 1426 return (0); 1427 1428 if (error == 0) 1429 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio); 1430 sbuf_delete(asb); 1431 return (error); 1432 } 1433 1434 /* 1435 * Constructor 1436 */ 1437 static int 1438 linprocfs_init(PFS_INIT_ARGS) 1439 { 1440 struct pfs_node *root; 1441 struct pfs_node *dir; 1442 1443 root = pi->pi_root; 1444 1445 /* /proc/... */ 1446 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1447 NULL, NULL, NULL, PFS_RD); 1448 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1449 NULL, NULL, NULL, PFS_RD); 1450 pfs_create_file(root, "devices", &linprocfs_dodevices, 1451 NULL, NULL, NULL, PFS_RD); 1452 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1453 NULL, NULL, NULL, PFS_RD); 1454 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1455 NULL, NULL, NULL, PFS_RD); 1456 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1457 NULL, NULL, NULL, PFS_RD); 1458 #if 0 1459 pfs_create_file(root, "modules", &linprocfs_domodules, 1460 NULL, NULL, NULL, PFS_RD); 1461 #endif 1462 pfs_create_file(root, "mounts", &linprocfs_domtab, 1463 NULL, NULL, NULL, PFS_RD); 1464 pfs_create_file(root, "mtab", &linprocfs_domtab, 1465 NULL, NULL, NULL, PFS_RD); 1466 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1467 NULL, NULL, NULL, PFS_RD); 1468 pfs_create_link(root, "self", &procfs_docurproc, 1469 NULL, NULL, NULL, 0); 1470 pfs_create_file(root, "stat", &linprocfs_dostat, 1471 NULL, NULL, NULL, PFS_RD); 1472 pfs_create_file(root, "swaps", &linprocfs_doswaps, 1473 NULL, NULL, NULL, PFS_RD); 1474 pfs_create_file(root, "uptime", &linprocfs_douptime, 1475 NULL, NULL, NULL, PFS_RD); 1476 pfs_create_file(root, "version", &linprocfs_doversion, 1477 NULL, NULL, NULL, PFS_RD); 1478 1479 /* /proc/net/... */ 1480 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1481 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1482 NULL, NULL, NULL, PFS_RD); 1483 1484 /* /proc/<pid>/... */ 1485 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1486 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1487 NULL, NULL, NULL, PFS_RD); 1488 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1489 NULL, NULL, NULL, 0); 1490 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1491 NULL, NULL, NULL, PFS_RD); 1492 pfs_create_link(dir, "exe", &procfs_doprocfile, 1493 NULL, &procfs_notsystem, NULL, 0); 1494 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1495 NULL, NULL, NULL, PFS_RD); 1496 pfs_create_file(dir, "mem", &procfs_doprocmem, 1497 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1498 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1499 NULL, NULL, NULL, 0); 1500 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1501 NULL, NULL, NULL, PFS_RD); 1502 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1503 NULL, NULL, NULL, PFS_RD); 1504 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1505 NULL, NULL, NULL, PFS_RD); 1506 pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1507 NULL, NULL, NULL, 0); 1508 pfs_create_file(dir, "auxv", &linprocfs_doauxv, 1509 NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD); 1510 1511 /* /proc/scsi/... */ 1512 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1513 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1514 NULL, NULL, NULL, PFS_RD); 1515 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1516 NULL, NULL, NULL, PFS_RD); 1517 1518 /* /proc/sys/... */ 1519 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1520 /* /proc/sys/kernel/... */ 1521 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1522 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1523 NULL, NULL, NULL, PFS_RD); 1524 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1525 NULL, NULL, NULL, PFS_RD); 1526 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1527 NULL, NULL, NULL, PFS_RD); 1528 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1529 NULL, NULL, NULL, PFS_RD); 1530 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1531 NULL, NULL, NULL, PFS_RD); 1532 pfs_create_file(dir, "sem", &linprocfs_dosem, 1533 NULL, NULL, NULL, PFS_RD); 1534 1535 /* /proc/sys/kernel/random/... */ 1536 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0); 1537 pfs_create_file(dir, "uuid", &linprocfs_douuid, 1538 NULL, NULL, NULL, PFS_RD); 1539 1540 return (0); 1541 } 1542 1543 /* 1544 * Destructor 1545 */ 1546 static int 1547 linprocfs_uninit(PFS_INIT_ARGS) 1548 { 1549 1550 /* nothing to do, pseudofs will GC */ 1551 return (0); 1552 } 1553 1554 PSEUDOFS(linprocfs, 1, 0); 1555 #if defined(__amd64__) 1556 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1); 1557 #else 1558 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1559 #endif 1560 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1561 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1562 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1563