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 = 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 = 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 = 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 cnt.v_vnodepgsin, 490 cnt.v_vnodepgsout, 491 cnt.v_swappgsin, 492 cnt.v_swappgsout, 493 cnt.v_intr, 494 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 PROC_LOCK(p); 649 fill_kinfo_proc(p, &kp); 650 if (p->p_vmspace) { 651 startcode = (vm_offset_t)p->p_vmspace->vm_taddr; 652 startdata = (vm_offset_t)p->p_vmspace->vm_daddr; 653 } else { 654 startcode = 0; 655 startdata = 0; 656 }; 657 sbuf_printf(sb, "%d", p->p_pid); 658 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 659 PS_ADD("comm", "(%s)", p->p_comm); 660 if (kp.ki_stat > sizeof(linux_state)) { 661 state = 'R'; 662 663 if (ratelimit == 0) { 664 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 665 kp.ki_stat, sizeof(linux_state)); 666 ++ratelimit; 667 } 668 } else 669 state = linux_state[kp.ki_stat - 1]; 670 PS_ADD("state", "%c", state); 671 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 672 PS_ADD("pgrp", "%d", p->p_pgid); 673 PS_ADD("session", "%d", p->p_session->s_sid); 674 PROC_UNLOCK(p); 675 PS_ADD("tty", "%d", kp.ki_tdev); 676 PS_ADD("tpgid", "%d", kp.ki_tpgid); 677 PS_ADD("flags", "%u", 0); /* XXX */ 678 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 679 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 680 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 681 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 682 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime)); 683 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime)); 684 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime)); 685 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime)); 686 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 687 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 688 PS_ADD("0", "%d", 0); /* removed field */ 689 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 690 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime)); 691 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 692 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 693 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 694 PS_ADD("startcode", "%ju", (uintmax_t)startcode); 695 PS_ADD("endcode", "%ju", (uintmax_t)startdata); 696 PS_ADD("startstack", "%u", 0); /* XXX */ 697 PS_ADD("kstkesp", "%u", 0); /* XXX */ 698 PS_ADD("kstkeip", "%u", 0); /* XXX */ 699 PS_ADD("signal", "%u", 0); /* XXX */ 700 PS_ADD("blocked", "%u", 0); /* XXX */ 701 PS_ADD("sigignore", "%u", 0); /* XXX */ 702 PS_ADD("sigcatch", "%u", 0); /* XXX */ 703 PS_ADD("wchan", "%u", 0); /* XXX */ 704 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 705 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 706 PS_ADD("exitsignal", "%d", 0); /* XXX */ 707 PS_ADD("processor", "%u", kp.ki_lastcpu); 708 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 709 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 710 #undef PS_ADD 711 sbuf_putc(sb, '\n'); 712 713 return (0); 714 } 715 716 /* 717 * Filler function for proc/pid/statm 718 */ 719 static int 720 linprocfs_doprocstatm(PFS_FILL_ARGS) 721 { 722 struct kinfo_proc kp; 723 segsz_t lsize; 724 725 PROC_LOCK(p); 726 fill_kinfo_proc(p, &kp); 727 PROC_UNLOCK(p); 728 729 /* 730 * See comments in linprocfs_doprocstatus() regarding the 731 * computation of lsize. 732 */ 733 /* size resident share trs drs lrs dt */ 734 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 735 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 736 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 737 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 738 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 739 lsize = B2P(kp.ki_size) - kp.ki_dsize - 740 kp.ki_ssize - kp.ki_tsize - 1; 741 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 742 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 743 744 return (0); 745 } 746 747 /* 748 * Filler function for proc/pid/status 749 */ 750 static int 751 linprocfs_doprocstatus(PFS_FILL_ARGS) 752 { 753 struct kinfo_proc kp; 754 char *state; 755 segsz_t lsize; 756 struct thread *td2; 757 struct sigacts *ps; 758 int i; 759 760 PROC_LOCK(p); 761 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 762 763 if (P_SHOULDSTOP(p)) { 764 state = "T (stopped)"; 765 } else { 766 switch(p->p_state) { 767 case PRS_NEW: 768 state = "I (idle)"; 769 break; 770 case PRS_NORMAL: 771 if (p->p_flag & P_WEXIT) { 772 state = "X (exiting)"; 773 break; 774 } 775 switch(td2->td_state) { 776 case TDS_INHIBITED: 777 state = "S (sleeping)"; 778 break; 779 case TDS_RUNQ: 780 case TDS_RUNNING: 781 state = "R (running)"; 782 break; 783 default: 784 state = "? (unknown)"; 785 break; 786 } 787 break; 788 case PRS_ZOMBIE: 789 state = "Z (zombie)"; 790 break; 791 default: 792 state = "? (unknown)"; 793 break; 794 } 795 } 796 797 fill_kinfo_proc(p, &kp); 798 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 799 sbuf_printf(sb, "State:\t%s\n", state); 800 801 /* 802 * Credentials 803 */ 804 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 805 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 806 p->p_pptr->p_pid : 0); 807 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 808 p->p_ucred->cr_uid, 809 p->p_ucred->cr_svuid, 810 /* FreeBSD doesn't have fsuid */ 811 p->p_ucred->cr_uid); 812 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 813 p->p_ucred->cr_gid, 814 p->p_ucred->cr_svgid, 815 /* FreeBSD doesn't have fsgid */ 816 p->p_ucred->cr_gid); 817 sbuf_cat(sb, "Groups:\t"); 818 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 819 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 820 PROC_UNLOCK(p); 821 sbuf_putc(sb, '\n'); 822 823 /* 824 * Memory 825 * 826 * While our approximation of VmLib may not be accurate (I 827 * don't know of a simple way to verify it, and I'm not sure 828 * it has much meaning anyway), I believe it's good enough. 829 * 830 * The same code that could (I think) accurately compute VmLib 831 * could also compute VmLck, but I don't really care enough to 832 * implement it. Submissions are welcome. 833 */ 834 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 835 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 836 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 837 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 838 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 839 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 840 lsize = B2P(kp.ki_size) - kp.ki_dsize - 841 kp.ki_ssize - kp.ki_tsize - 1; 842 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 843 844 /* 845 * Signal masks 846 * 847 * We support up to 128 signals, while Linux supports 32, 848 * but we only define 32 (the same 32 as Linux, to boot), so 849 * just show the lower 32 bits of each mask. XXX hack. 850 * 851 * NB: on certain platforms (Sparc at least) Linux actually 852 * supports 64 signals, but this code is a long way from 853 * running on anything but i386, so ignore that for now. 854 */ 855 PROC_LOCK(p); 856 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 857 /* 858 * I can't seem to find out where the signal mask is in 859 * relation to struct proc, so SigBlk is left unimplemented. 860 */ 861 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 862 ps = p->p_sigacts; 863 mtx_lock(&ps->ps_mtx); 864 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 865 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 866 mtx_unlock(&ps->ps_mtx); 867 PROC_UNLOCK(p); 868 869 /* 870 * Linux also prints the capability masks, but we don't have 871 * capabilities yet, and when we do get them they're likely to 872 * be meaningless to Linux programs, so we lie. XXX 873 */ 874 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 875 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 876 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 877 878 return (0); 879 } 880 881 882 /* 883 * Filler function for proc/pid/cwd 884 */ 885 static int 886 linprocfs_doproccwd(PFS_FILL_ARGS) 887 { 888 char *fullpath = "unknown"; 889 char *freepath = NULL; 890 891 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 892 sbuf_printf(sb, "%s", fullpath); 893 if (freepath) 894 free(freepath, M_TEMP); 895 return (0); 896 } 897 898 /* 899 * Filler function for proc/pid/root 900 */ 901 static int 902 linprocfs_doprocroot(PFS_FILL_ARGS) 903 { 904 struct vnode *rvp; 905 char *fullpath = "unknown"; 906 char *freepath = NULL; 907 908 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 909 vn_fullpath(td, rvp, &fullpath, &freepath); 910 sbuf_printf(sb, "%s", fullpath); 911 if (freepath) 912 free(freepath, M_TEMP); 913 return (0); 914 } 915 916 /* 917 * Filler function for proc/pid/cmdline 918 */ 919 static int 920 linprocfs_doproccmdline(PFS_FILL_ARGS) 921 { 922 int ret; 923 924 PROC_LOCK(p); 925 if ((ret = p_cansee(td, p)) != 0) { 926 PROC_UNLOCK(p); 927 return (ret); 928 } 929 930 /* 931 * Mimic linux behavior and pass only processes with usermode 932 * address space as valid. Return zero silently otherwize. 933 */ 934 if (p->p_vmspace == &vmspace0) { 935 PROC_UNLOCK(p); 936 return (0); 937 } 938 if (p->p_args != NULL) { 939 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 940 PROC_UNLOCK(p); 941 return (0); 942 } 943 944 if ((p->p_flag & P_SYSTEM) != 0) { 945 PROC_UNLOCK(p); 946 return (0); 947 } 948 949 PROC_UNLOCK(p); 950 951 ret = proc_getargv(td, p, sb); 952 return (ret); 953 } 954 955 /* 956 * Filler function for proc/pid/environ 957 */ 958 static int 959 linprocfs_doprocenviron(PFS_FILL_ARGS) 960 { 961 int ret; 962 963 PROC_LOCK(p); 964 if ((ret = p_candebug(td, p)) != 0) { 965 PROC_UNLOCK(p); 966 return (ret); 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 PROC_UNLOCK(p); 975 return (0); 976 } 977 978 if ((p->p_flag & P_SYSTEM) != 0) { 979 PROC_UNLOCK(p); 980 return (0); 981 } 982 983 PROC_UNLOCK(p); 984 985 ret = proc_getenvv(td, p, sb); 986 return (ret); 987 } 988 989 /* 990 * Filler function for proc/pid/maps 991 */ 992 static int 993 linprocfs_doprocmaps(PFS_FILL_ARGS) 994 { 995 struct vmspace *vm; 996 vm_map_t map; 997 vm_map_entry_t entry, tmp_entry; 998 vm_object_t obj, tobj, lobj; 999 vm_offset_t e_start, e_end; 1000 vm_ooffset_t off = 0; 1001 vm_prot_t e_prot; 1002 unsigned int last_timestamp; 1003 char *name = "", *freename = NULL; 1004 ino_t ino; 1005 int ref_count, shadow_count, flags; 1006 int error; 1007 struct vnode *vp; 1008 struct vattr vat; 1009 1010 PROC_LOCK(p); 1011 error = p_candebug(td, p); 1012 PROC_UNLOCK(p); 1013 if (error) 1014 return (error); 1015 1016 if (uio->uio_rw != UIO_READ) 1017 return (EOPNOTSUPP); 1018 1019 error = 0; 1020 vm = vmspace_acquire_ref(p); 1021 if (vm == NULL) 1022 return (ESRCH); 1023 map = &vm->vm_map; 1024 vm_map_lock_read(map); 1025 for (entry = map->header.next; entry != &map->header; 1026 entry = entry->next) { 1027 name = ""; 1028 freename = NULL; 1029 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 1030 continue; 1031 e_prot = entry->protection; 1032 e_start = entry->start; 1033 e_end = entry->end; 1034 obj = entry->object.vm_object; 1035 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 1036 VM_OBJECT_RLOCK(tobj); 1037 if (lobj != obj) 1038 VM_OBJECT_RUNLOCK(lobj); 1039 lobj = tobj; 1040 } 1041 last_timestamp = map->timestamp; 1042 vm_map_unlock_read(map); 1043 ino = 0; 1044 if (lobj) { 1045 off = IDX_TO_OFF(lobj->size); 1046 if (lobj->type == OBJT_VNODE) { 1047 vp = lobj->handle; 1048 if (vp) 1049 vref(vp); 1050 } 1051 else 1052 vp = NULL; 1053 if (lobj != obj) 1054 VM_OBJECT_RUNLOCK(lobj); 1055 flags = obj->flags; 1056 ref_count = obj->ref_count; 1057 shadow_count = obj->shadow_count; 1058 VM_OBJECT_RUNLOCK(obj); 1059 if (vp) { 1060 vn_fullpath(td, vp, &name, &freename); 1061 vn_lock(vp, LK_SHARED | LK_RETRY); 1062 VOP_GETATTR(vp, &vat, td->td_ucred); 1063 ino = vat.va_fileid; 1064 vput(vp); 1065 } 1066 } else { 1067 flags = 0; 1068 ref_count = 0; 1069 shadow_count = 0; 1070 } 1071 1072 /* 1073 * format: 1074 * start, end, access, offset, major, minor, inode, name. 1075 */ 1076 error = sbuf_printf(sb, 1077 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 1078 (u_long)e_start, (u_long)e_end, 1079 (e_prot & VM_PROT_READ)?"r":"-", 1080 (e_prot & VM_PROT_WRITE)?"w":"-", 1081 (e_prot & VM_PROT_EXECUTE)?"x":"-", 1082 "p", 1083 (u_long)off, 1084 0, 1085 0, 1086 (u_long)ino, 1087 *name ? " " : "", 1088 name 1089 ); 1090 if (freename) 1091 free(freename, M_TEMP); 1092 vm_map_lock_read(map); 1093 if (error == -1) { 1094 error = 0; 1095 break; 1096 } 1097 if (last_timestamp != map->timestamp) { 1098 /* 1099 * Look again for the entry because the map was 1100 * modified while it was unlocked. Specifically, 1101 * the entry may have been clipped, merged, or deleted. 1102 */ 1103 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1104 entry = tmp_entry; 1105 } 1106 } 1107 vm_map_unlock_read(map); 1108 vmspace_free(vm); 1109 1110 return (error); 1111 } 1112 1113 /* 1114 * Filler function for proc/net/dev 1115 */ 1116 static int 1117 linprocfs_donetdev(PFS_FILL_ARGS) 1118 { 1119 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1120 struct ifnet *ifp; 1121 1122 sbuf_printf(sb, "%6s|%58s|%s\n" 1123 "%6s|%58s|%58s\n", 1124 "Inter-", " Receive", " Transmit", 1125 " face", 1126 "bytes packets errs drop fifo frame compressed multicast", 1127 "bytes packets errs drop fifo colls carrier compressed"); 1128 1129 CURVNET_SET(TD_TO_VNET(curthread)); 1130 IFNET_RLOCK(); 1131 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1132 linux_ifname(ifp, ifname, sizeof ifname); 1133 sbuf_printf(sb, "%6.6s: ", ifname); 1134 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1135 ifp->if_ibytes, /* rx_bytes */ 1136 ifp->if_ipackets, /* rx_packets */ 1137 ifp->if_ierrors, /* rx_errors */ 1138 ifp->if_iqdrops, /* rx_dropped + 1139 * rx_missed_errors */ 1140 0UL, /* rx_fifo_errors */ 1141 0UL, /* rx_length_errors + 1142 * rx_over_errors + 1143 * rx_crc_errors + 1144 * rx_frame_errors */ 1145 0UL, /* rx_compressed */ 1146 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */ 1147 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1148 ifp->if_obytes, /* tx_bytes */ 1149 ifp->if_opackets, /* tx_packets */ 1150 ifp->if_oerrors, /* tx_errors */ 1151 0UL, /* tx_dropped */ 1152 0UL, /* tx_fifo_errors */ 1153 ifp->if_collisions, /* collisions */ 1154 0UL, /* tx_carrier_errors + 1155 * tx_aborted_errors + 1156 * tx_window_errors + 1157 * tx_heartbeat_errors */ 1158 0UL); /* tx_compressed */ 1159 } 1160 IFNET_RUNLOCK(); 1161 CURVNET_RESTORE(); 1162 1163 return (0); 1164 } 1165 1166 /* 1167 * Filler function for proc/sys/kernel/osrelease 1168 */ 1169 static int 1170 linprocfs_doosrelease(PFS_FILL_ARGS) 1171 { 1172 char osrelease[LINUX_MAX_UTSNAME]; 1173 1174 linux_get_osrelease(td, osrelease); 1175 sbuf_printf(sb, "%s\n", osrelease); 1176 1177 return (0); 1178 } 1179 1180 /* 1181 * Filler function for proc/sys/kernel/ostype 1182 */ 1183 static int 1184 linprocfs_doostype(PFS_FILL_ARGS) 1185 { 1186 char osname[LINUX_MAX_UTSNAME]; 1187 1188 linux_get_osname(td, osname); 1189 sbuf_printf(sb, "%s\n", osname); 1190 1191 return (0); 1192 } 1193 1194 /* 1195 * Filler function for proc/sys/kernel/version 1196 */ 1197 static int 1198 linprocfs_doosbuild(PFS_FILL_ARGS) 1199 { 1200 1201 linprocfs_osbuild(td, sb); 1202 sbuf_cat(sb, "\n"); 1203 return (0); 1204 } 1205 1206 /* 1207 * Filler function for proc/sys/kernel/msgmni 1208 */ 1209 static int 1210 linprocfs_domsgmni(PFS_FILL_ARGS) 1211 { 1212 1213 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1214 return (0); 1215 } 1216 1217 /* 1218 * Filler function for proc/sys/kernel/pid_max 1219 */ 1220 static int 1221 linprocfs_dopid_max(PFS_FILL_ARGS) 1222 { 1223 1224 sbuf_printf(sb, "%i\n", PID_MAX); 1225 return (0); 1226 } 1227 1228 /* 1229 * Filler function for proc/sys/kernel/sem 1230 */ 1231 static int 1232 linprocfs_dosem(PFS_FILL_ARGS) 1233 { 1234 1235 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1236 seminfo.semopm, seminfo.semmni); 1237 return (0); 1238 } 1239 1240 /* 1241 * Filler function for proc/scsi/device_info 1242 */ 1243 static int 1244 linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1245 { 1246 1247 return (0); 1248 } 1249 1250 /* 1251 * Filler function for proc/scsi/scsi 1252 */ 1253 static int 1254 linprocfs_doscsiscsi(PFS_FILL_ARGS) 1255 { 1256 1257 return (0); 1258 } 1259 1260 extern struct cdevsw *cdevsw[]; 1261 1262 /* 1263 * Filler function for proc/devices 1264 */ 1265 static int 1266 linprocfs_dodevices(PFS_FILL_ARGS) 1267 { 1268 char *char_devices; 1269 sbuf_printf(sb, "Character devices:\n"); 1270 1271 char_devices = linux_get_char_devices(); 1272 sbuf_printf(sb, "%s", char_devices); 1273 linux_free_get_char_devices(char_devices); 1274 1275 sbuf_printf(sb, "\nBlock devices:\n"); 1276 1277 return (0); 1278 } 1279 1280 /* 1281 * Filler function for proc/cmdline 1282 */ 1283 static int 1284 linprocfs_docmdline(PFS_FILL_ARGS) 1285 { 1286 1287 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1288 sbuf_printf(sb, " ro root=302\n"); 1289 return (0); 1290 } 1291 1292 /* 1293 * Filler function for proc/filesystems 1294 */ 1295 static int 1296 linprocfs_dofilesystems(PFS_FILL_ARGS) 1297 { 1298 struct vfsconf *vfsp; 1299 1300 mtx_lock(&Giant); 1301 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 1302 if (vfsp->vfc_flags & VFCF_SYNTHETIC) 1303 sbuf_printf(sb, "nodev"); 1304 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name); 1305 } 1306 mtx_unlock(&Giant); 1307 return(0); 1308 } 1309 1310 #if 0 1311 /* 1312 * Filler function for proc/modules 1313 */ 1314 static int 1315 linprocfs_domodules(PFS_FILL_ARGS) 1316 { 1317 struct linker_file *lf; 1318 1319 TAILQ_FOREACH(lf, &linker_files, link) { 1320 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1321 (unsigned long)lf->size, lf->refs); 1322 } 1323 return (0); 1324 } 1325 #endif 1326 1327 /* 1328 * Filler function for proc/pid/fd 1329 */ 1330 static int 1331 linprocfs_dofdescfs(PFS_FILL_ARGS) 1332 { 1333 1334 if (p == curproc) 1335 sbuf_printf(sb, "/dev/fd"); 1336 else 1337 sbuf_printf(sb, "unknown"); 1338 return (0); 1339 } 1340 1341 1342 /* 1343 * Filler function for proc/sys/kernel/random/uuid 1344 */ 1345 static int 1346 linprocfs_douuid(PFS_FILL_ARGS) 1347 { 1348 struct uuid uuid; 1349 1350 kern_uuidgen(&uuid, 1); 1351 sbuf_printf_uuid(sb, &uuid); 1352 sbuf_printf(sb, "\n"); 1353 return(0); 1354 } 1355 1356 1357 /* 1358 * Constructor 1359 */ 1360 static int 1361 linprocfs_init(PFS_INIT_ARGS) 1362 { 1363 struct pfs_node *root; 1364 struct pfs_node *dir; 1365 1366 root = pi->pi_root; 1367 1368 /* /proc/... */ 1369 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1370 NULL, NULL, NULL, PFS_RD); 1371 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1372 NULL, NULL, NULL, PFS_RD); 1373 pfs_create_file(root, "devices", &linprocfs_dodevices, 1374 NULL, NULL, NULL, PFS_RD); 1375 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1376 NULL, NULL, NULL, PFS_RD); 1377 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1378 NULL, NULL, NULL, PFS_RD); 1379 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1380 NULL, NULL, NULL, PFS_RD); 1381 #if 0 1382 pfs_create_file(root, "modules", &linprocfs_domodules, 1383 NULL, NULL, NULL, PFS_RD); 1384 #endif 1385 pfs_create_file(root, "mounts", &linprocfs_domtab, 1386 NULL, NULL, NULL, PFS_RD); 1387 pfs_create_file(root, "mtab", &linprocfs_domtab, 1388 NULL, NULL, NULL, PFS_RD); 1389 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1390 NULL, NULL, NULL, PFS_RD); 1391 pfs_create_link(root, "self", &procfs_docurproc, 1392 NULL, NULL, NULL, 0); 1393 pfs_create_file(root, "stat", &linprocfs_dostat, 1394 NULL, NULL, NULL, PFS_RD); 1395 pfs_create_file(root, "swaps", &linprocfs_doswaps, 1396 NULL, NULL, NULL, PFS_RD); 1397 pfs_create_file(root, "uptime", &linprocfs_douptime, 1398 NULL, NULL, NULL, PFS_RD); 1399 pfs_create_file(root, "version", &linprocfs_doversion, 1400 NULL, NULL, NULL, PFS_RD); 1401 1402 /* /proc/net/... */ 1403 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1404 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1405 NULL, NULL, NULL, PFS_RD); 1406 1407 /* /proc/<pid>/... */ 1408 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1409 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1410 NULL, NULL, NULL, PFS_RD); 1411 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1412 NULL, NULL, NULL, 0); 1413 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1414 NULL, NULL, NULL, PFS_RD); 1415 pfs_create_link(dir, "exe", &procfs_doprocfile, 1416 NULL, &procfs_notsystem, NULL, 0); 1417 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1418 NULL, NULL, NULL, PFS_RD); 1419 pfs_create_file(dir, "mem", &procfs_doprocmem, 1420 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1421 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1422 NULL, NULL, NULL, 0); 1423 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1424 NULL, NULL, NULL, PFS_RD); 1425 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1426 NULL, NULL, NULL, PFS_RD); 1427 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1428 NULL, NULL, NULL, PFS_RD); 1429 pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1430 NULL, NULL, NULL, 0); 1431 1432 /* /proc/scsi/... */ 1433 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1434 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1435 NULL, NULL, NULL, PFS_RD); 1436 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1437 NULL, NULL, NULL, PFS_RD); 1438 1439 /* /proc/sys/... */ 1440 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1441 /* /proc/sys/kernel/... */ 1442 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1443 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1444 NULL, NULL, NULL, PFS_RD); 1445 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1446 NULL, NULL, NULL, PFS_RD); 1447 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1448 NULL, NULL, NULL, PFS_RD); 1449 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1450 NULL, NULL, NULL, PFS_RD); 1451 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1452 NULL, NULL, NULL, PFS_RD); 1453 pfs_create_file(dir, "sem", &linprocfs_dosem, 1454 NULL, NULL, NULL, PFS_RD); 1455 1456 /* /proc/sys/kernel/random/... */ 1457 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0); 1458 pfs_create_file(dir, "uuid", &linprocfs_douuid, 1459 NULL, NULL, NULL, PFS_RD); 1460 1461 return (0); 1462 } 1463 1464 /* 1465 * Destructor 1466 */ 1467 static int 1468 linprocfs_uninit(PFS_INIT_ARGS) 1469 { 1470 1471 /* nothing to do, pseudofs will GC */ 1472 return (0); 1473 } 1474 1475 PSEUDOFS(linprocfs, 1, 0); 1476 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1477 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1478 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1479 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1480