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