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