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), 284 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING); 285 /* XXX per-cpu vendor / class / model / id? */ 286 } 287 288 sbuf_cat(sb, "flags\t\t:"); 289 290 #ifdef __i386__ 291 switch (cpu_vendor_id) { 292 case CPU_VENDOR_AMD: 293 if (class < 6) 294 flags[16] = "fcmov"; 295 break; 296 case CPU_VENDOR_CYRIX: 297 flags[24] = "cxmmx"; 298 break; 299 } 300 #endif 301 302 for (i = 0; i < 32; i++) 303 if (cpu_feature & (1 << i)) 304 sbuf_printf(sb, " %s", flags[i]); 305 sbuf_cat(sb, "\n"); 306 if (class >= 5) { 307 fqmhz = (tsc_freq + 4999) / 1000000; 308 fqkhz = ((tsc_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 | MPSAFE, 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 VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 345 } 346 lep_len = strlen(lep); 347 348 mtx_lock(&mountlist_mtx); 349 error = 0; 350 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 351 /* determine device name */ 352 mntfrom = mp->mnt_stat.f_mntfromname; 353 354 /* determine mount point */ 355 mntto = mp->mnt_stat.f_mntonname; 356 if (strncmp(mntto, lep, lep_len) == 0 && 357 mntto[lep_len] == '/') 358 mntto += lep_len; 359 360 /* determine fs type */ 361 fstype = mp->mnt_stat.f_fstypename; 362 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 363 mntfrom = fstype = "proc"; 364 else if (strcmp(fstype, "procfs") == 0) 365 continue; 366 367 if (strcmp(fstype, "linsysfs") == 0) { 368 sbuf_printf(sb, "/sys %s sysfs %s", mntto, 369 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 370 } else { 371 /* For Linux msdosfs is called vfat */ 372 if (strcmp(fstype, "msdosfs") == 0) 373 fstype = "vfat"; 374 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 375 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 376 } 377 #define ADD_OPTION(opt, name) \ 378 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 379 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 380 ADD_OPTION(MNT_NOEXEC, "noexec"); 381 ADD_OPTION(MNT_NOSUID, "nosuid"); 382 ADD_OPTION(MNT_UNION, "union"); 383 ADD_OPTION(MNT_ASYNC, "async"); 384 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 385 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 386 ADD_OPTION(MNT_NOATIME, "noatime"); 387 #undef ADD_OPTION 388 /* a real Linux mtab will also show NFS options */ 389 sbuf_printf(sb, " 0 0\n"); 390 } 391 mtx_unlock(&mountlist_mtx); 392 if (flep != NULL) 393 free(flep, M_TEMP); 394 return (error); 395 } 396 397 /* 398 * Filler function for proc/partitions 399 * 400 */ 401 static int 402 linprocfs_dopartitions(PFS_FILL_ARGS) 403 { 404 struct g_class *cp; 405 struct g_geom *gp; 406 struct g_provider *pp; 407 struct nameidata nd; 408 const char *lep; 409 char *dlep, *flep; 410 size_t lep_len; 411 int error; 412 int major, minor; 413 414 /* resolve symlinks etc. in the emulation tree prefix */ 415 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 416 flep = NULL; 417 error = namei(&nd); 418 lep = linux_emul_path; 419 if (error == 0) { 420 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 421 lep = dlep; 422 vrele(nd.ni_vp); 423 VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 424 } 425 lep_len = strlen(lep); 426 427 g_topology_lock(); 428 error = 0; 429 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect " 430 "ruse wio wmerge wsect wuse running use aveq\n"); 431 432 LIST_FOREACH(cp, &g_classes, class) { 433 if (strcmp(cp->name, "DISK") == 0 || 434 strcmp(cp->name, "PART") == 0) 435 LIST_FOREACH(gp, &cp->geom, geom) { 436 LIST_FOREACH(pp, &gp->provider, provider) { 437 if (linux_driver_get_major_minor( 438 pp->name, &major, &minor) != 0) { 439 major = 0; 440 minor = 0; 441 } 442 sbuf_printf(sb, "%d %d %lld %s " 443 "%d %d %d %d %d " 444 "%d %d %d %d %d %d\n", 445 major, minor, 446 (long long)pp->mediasize, pp->name, 447 0, 0, 0, 0, 0, 448 0, 0, 0, 0, 0, 0); 449 } 450 } 451 } 452 g_topology_unlock(); 453 454 if (flep != NULL) 455 free(flep, M_TEMP); 456 return (error); 457 } 458 459 460 /* 461 * Filler function for proc/stat 462 */ 463 static int 464 linprocfs_dostat(PFS_FILL_ARGS) 465 { 466 struct pcpu *pcpu; 467 long cp_time[CPUSTATES]; 468 long *cp; 469 int i; 470 471 read_cpu_time(cp_time); 472 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 473 T2J(cp_time[CP_USER]), 474 T2J(cp_time[CP_NICE]), 475 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 476 T2J(cp_time[CP_IDLE])); 477 CPU_FOREACH(i) { 478 pcpu = pcpu_find(i); 479 cp = pcpu->pc_cp_time; 480 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 481 T2J(cp[CP_USER]), 482 T2J(cp[CP_NICE]), 483 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 484 T2J(cp[CP_IDLE])); 485 } 486 sbuf_printf(sb, 487 "disk 0 0 0 0\n" 488 "page %u %u\n" 489 "swap %u %u\n" 490 "intr %u\n" 491 "ctxt %u\n" 492 "btime %lld\n", 493 cnt.v_vnodepgsin, 494 cnt.v_vnodepgsout, 495 cnt.v_swappgsin, 496 cnt.v_swappgsout, 497 cnt.v_intr, 498 cnt.v_swtch, 499 (long long)boottime.tv_sec); 500 return (0); 501 } 502 503 /* 504 * Filler function for proc/uptime 505 */ 506 static int 507 linprocfs_douptime(PFS_FILL_ARGS) 508 { 509 long cp_time[CPUSTATES]; 510 struct timeval tv; 511 512 getmicrouptime(&tv); 513 read_cpu_time(cp_time); 514 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n", 515 (long long)tv.tv_sec, tv.tv_usec / 10000, 516 T2S(cp_time[CP_IDLE] / mp_ncpus), 517 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100); 518 return (0); 519 } 520 521 /* 522 * Get OS build date 523 */ 524 static void 525 linprocfs_osbuild(struct thread *td, struct sbuf *sb) 526 { 527 #if 0 528 char osbuild[256]; 529 char *cp1, *cp2; 530 531 strncpy(osbuild, version, 256); 532 osbuild[255] = '\0'; 533 cp1 = strstr(osbuild, "\n"); 534 cp2 = strstr(osbuild, ":"); 535 if (cp1 && cp2) { 536 *cp1 = *cp2 = '\0'; 537 cp1 = strstr(osbuild, "#"); 538 } else 539 cp1 = NULL; 540 if (cp1) 541 sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 542 else 543 #endif 544 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 545 } 546 547 /* 548 * Get OS builder 549 */ 550 static void 551 linprocfs_osbuilder(struct thread *td, struct sbuf *sb) 552 { 553 #if 0 554 char builder[256]; 555 char *cp; 556 557 cp = strstr(version, "\n "); 558 if (cp) { 559 strncpy(builder, cp + 5, 256); 560 builder[255] = '\0'; 561 cp = strstr(builder, ":"); 562 if (cp) 563 *cp = '\0'; 564 } 565 if (cp) 566 sbuf_cat(sb, builder); 567 else 568 #endif 569 sbuf_cat(sb, "des@freebsd.org"); 570 } 571 572 /* 573 * Filler function for proc/version 574 */ 575 static int 576 linprocfs_doversion(PFS_FILL_ARGS) 577 { 578 char osname[LINUX_MAX_UTSNAME]; 579 char osrelease[LINUX_MAX_UTSNAME]; 580 581 linux_get_osname(td, osname); 582 linux_get_osrelease(td, osrelease); 583 sbuf_printf(sb, "%s version %s (", osname, osrelease); 584 linprocfs_osbuilder(td, sb); 585 sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 586 linprocfs_osbuild(td, sb); 587 sbuf_cat(sb, "\n"); 588 589 return (0); 590 } 591 592 /* 593 * Filler function for proc/loadavg 594 */ 595 static int 596 linprocfs_doloadavg(PFS_FILL_ARGS) 597 { 598 599 sbuf_printf(sb, 600 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 601 (int)(averunnable.ldavg[0] / averunnable.fscale), 602 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 603 (int)(averunnable.ldavg[1] / averunnable.fscale), 604 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 605 (int)(averunnable.ldavg[2] / averunnable.fscale), 606 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 607 1, /* number of running tasks */ 608 nprocs, /* number of tasks */ 609 lastpid /* the last pid */ 610 ); 611 return (0); 612 } 613 614 /* 615 * Filler function for proc/pid/stat 616 */ 617 static int 618 linprocfs_doprocstat(PFS_FILL_ARGS) 619 { 620 struct kinfo_proc kp; 621 char state; 622 static int ratelimit = 0; 623 vm_offset_t startcode, startdata; 624 625 PROC_LOCK(p); 626 fill_kinfo_proc(p, &kp); 627 if (p->p_vmspace) { 628 startcode = (vm_offset_t)p->p_vmspace->vm_taddr; 629 startdata = (vm_offset_t)p->p_vmspace->vm_daddr; 630 } else { 631 startcode = 0; 632 startdata = 0; 633 }; 634 sbuf_printf(sb, "%d", p->p_pid); 635 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 636 PS_ADD("comm", "(%s)", p->p_comm); 637 if (kp.ki_stat > sizeof(linux_state)) { 638 state = 'R'; 639 640 if (ratelimit == 0) { 641 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 642 kp.ki_stat, sizeof(linux_state)); 643 ++ratelimit; 644 } 645 } else 646 state = linux_state[kp.ki_stat - 1]; 647 PS_ADD("state", "%c", state); 648 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 649 PS_ADD("pgrp", "%d", p->p_pgid); 650 PS_ADD("session", "%d", p->p_session->s_sid); 651 PROC_UNLOCK(p); 652 PS_ADD("tty", "%d", kp.ki_tdev); 653 PS_ADD("tpgid", "%d", kp.ki_tpgid); 654 PS_ADD("flags", "%u", 0); /* XXX */ 655 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 656 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 657 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 658 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 659 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime)); 660 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime)); 661 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime)); 662 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime)); 663 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 664 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 665 PS_ADD("0", "%d", 0); /* removed field */ 666 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 667 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime)); 668 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 669 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 670 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 671 PS_ADD("startcode", "%ju", (uintmax_t)startcode); 672 PS_ADD("endcode", "%ju", (uintmax_t)startdata); 673 PS_ADD("startstack", "%u", 0); /* XXX */ 674 PS_ADD("kstkesp", "%u", 0); /* XXX */ 675 PS_ADD("kstkeip", "%u", 0); /* XXX */ 676 PS_ADD("signal", "%u", 0); /* XXX */ 677 PS_ADD("blocked", "%u", 0); /* XXX */ 678 PS_ADD("sigignore", "%u", 0); /* XXX */ 679 PS_ADD("sigcatch", "%u", 0); /* XXX */ 680 PS_ADD("wchan", "%u", 0); /* XXX */ 681 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 682 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 683 PS_ADD("exitsignal", "%d", 0); /* XXX */ 684 PS_ADD("processor", "%u", kp.ki_lastcpu); 685 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 686 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 687 #undef PS_ADD 688 sbuf_putc(sb, '\n'); 689 690 return (0); 691 } 692 693 /* 694 * Filler function for proc/pid/statm 695 */ 696 static int 697 linprocfs_doprocstatm(PFS_FILL_ARGS) 698 { 699 struct kinfo_proc kp; 700 segsz_t lsize; 701 702 PROC_LOCK(p); 703 fill_kinfo_proc(p, &kp); 704 PROC_UNLOCK(p); 705 706 /* 707 * See comments in linprocfs_doprocstatus() regarding the 708 * computation of lsize. 709 */ 710 /* size resident share trs drs lrs dt */ 711 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 712 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 713 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 714 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 715 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 716 lsize = B2P(kp.ki_size) - kp.ki_dsize - 717 kp.ki_ssize - kp.ki_tsize - 1; 718 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 719 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 720 721 return (0); 722 } 723 724 /* 725 * Filler function for proc/pid/status 726 */ 727 static int 728 linprocfs_doprocstatus(PFS_FILL_ARGS) 729 { 730 struct kinfo_proc kp; 731 char *state; 732 segsz_t lsize; 733 struct thread *td2; 734 struct sigacts *ps; 735 int i; 736 737 PROC_LOCK(p); 738 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 739 740 if (P_SHOULDSTOP(p)) { 741 state = "T (stopped)"; 742 } else { 743 PROC_SLOCK(p); 744 switch(p->p_state) { 745 case PRS_NEW: 746 state = "I (idle)"; 747 break; 748 case PRS_NORMAL: 749 if (p->p_flag & P_WEXIT) { 750 state = "X (exiting)"; 751 break; 752 } 753 switch(td2->td_state) { 754 case TDS_INHIBITED: 755 state = "S (sleeping)"; 756 break; 757 case TDS_RUNQ: 758 case TDS_RUNNING: 759 state = "R (running)"; 760 break; 761 default: 762 state = "? (unknown)"; 763 break; 764 } 765 break; 766 case PRS_ZOMBIE: 767 state = "Z (zombie)"; 768 break; 769 default: 770 state = "? (unknown)"; 771 break; 772 } 773 PROC_SUNLOCK(p); 774 } 775 776 fill_kinfo_proc(p, &kp); 777 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 778 sbuf_printf(sb, "State:\t%s\n", state); 779 780 /* 781 * Credentials 782 */ 783 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 784 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 785 p->p_pptr->p_pid : 0); 786 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 787 p->p_ucred->cr_uid, 788 p->p_ucred->cr_svuid, 789 /* FreeBSD doesn't have fsuid */ 790 p->p_ucred->cr_uid); 791 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 792 p->p_ucred->cr_gid, 793 p->p_ucred->cr_svgid, 794 /* FreeBSD doesn't have fsgid */ 795 p->p_ucred->cr_gid); 796 sbuf_cat(sb, "Groups:\t"); 797 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 798 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 799 PROC_UNLOCK(p); 800 sbuf_putc(sb, '\n'); 801 802 /* 803 * Memory 804 * 805 * While our approximation of VmLib may not be accurate (I 806 * don't know of a simple way to verify it, and I'm not sure 807 * it has much meaning anyway), I believe it's good enough. 808 * 809 * The same code that could (I think) accurately compute VmLib 810 * could also compute VmLck, but I don't really care enough to 811 * implement it. Submissions are welcome. 812 */ 813 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 814 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 815 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 816 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 817 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 818 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 819 lsize = B2P(kp.ki_size) - kp.ki_dsize - 820 kp.ki_ssize - kp.ki_tsize - 1; 821 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 822 823 /* 824 * Signal masks 825 * 826 * We support up to 128 signals, while Linux supports 32, 827 * but we only define 32 (the same 32 as Linux, to boot), so 828 * just show the lower 32 bits of each mask. XXX hack. 829 * 830 * NB: on certain platforms (Sparc at least) Linux actually 831 * supports 64 signals, but this code is a long way from 832 * running on anything but i386, so ignore that for now. 833 */ 834 PROC_LOCK(p); 835 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 836 /* 837 * I can't seem to find out where the signal mask is in 838 * relation to struct proc, so SigBlk is left unimplemented. 839 */ 840 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 841 ps = p->p_sigacts; 842 mtx_lock(&ps->ps_mtx); 843 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 844 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 845 mtx_unlock(&ps->ps_mtx); 846 PROC_UNLOCK(p); 847 848 /* 849 * Linux also prints the capability masks, but we don't have 850 * capabilities yet, and when we do get them they're likely to 851 * be meaningless to Linux programs, so we lie. XXX 852 */ 853 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 854 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 855 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 856 857 return (0); 858 } 859 860 861 /* 862 * Filler function for proc/pid/cwd 863 */ 864 static int 865 linprocfs_doproccwd(PFS_FILL_ARGS) 866 { 867 char *fullpath = "unknown"; 868 char *freepath = NULL; 869 870 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 871 sbuf_printf(sb, "%s", fullpath); 872 if (freepath) 873 free(freepath, M_TEMP); 874 return (0); 875 } 876 877 /* 878 * Filler function for proc/pid/root 879 */ 880 static int 881 linprocfs_doprocroot(PFS_FILL_ARGS) 882 { 883 struct vnode *rvp; 884 char *fullpath = "unknown"; 885 char *freepath = NULL; 886 887 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 888 vn_fullpath(td, rvp, &fullpath, &freepath); 889 sbuf_printf(sb, "%s", fullpath); 890 if (freepath) 891 free(freepath, M_TEMP); 892 return (0); 893 } 894 895 #define MAX_ARGV_STR 512 /* Max number of argv-like strings */ 896 #define UIO_CHUNK_SZ 256 /* Max chunk size (bytes) for uiomove */ 897 898 static int 899 linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb, 900 void (*resolver)(const struct ps_strings, u_long *, int *)) 901 { 902 struct iovec iov; 903 struct uio tmp_uio; 904 struct ps_strings pss; 905 int ret, i, n_elements, elm_len; 906 u_long addr, pbegin; 907 char **env_vector, *envp; 908 char env_string[UIO_CHUNK_SZ]; 909 #ifdef COMPAT_FREEBSD32 910 struct freebsd32_ps_strings pss32; 911 uint32_t *env_vector32; 912 #endif 913 914 #define UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td) \ 915 do { \ 916 iov.iov_base = (caddr_t)(base); \ 917 iov.iov_len = (len); \ 918 uio.uio_iov = &(iov); \ 919 uio.uio_iovcnt = (cnt); \ 920 uio.uio_offset = (off_t)(offset); \ 921 uio.uio_resid = (sz); \ 922 uio.uio_segflg = (flg); \ 923 uio.uio_rw = (rw); \ 924 uio.uio_td = (td); \ 925 } while (0) 926 927 env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK); 928 929 #ifdef COMPAT_FREEBSD32 930 env_vector32 = NULL; 931 if ((p->p_sysent->sv_flags & SV_ILP32) != 0) { 932 env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR, 933 M_TEMP, M_WAITOK); 934 elm_len = sizeof(int32_t); 935 envp = (char *)env_vector32; 936 937 UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1, 938 (off_t)(p->p_sysent->sv_psstrings), 939 sizeof(pss32), UIO_SYSSPACE, UIO_READ, td); 940 ret = proc_rwmem(p, &tmp_uio); 941 if (ret != 0) 942 goto done; 943 pss.ps_argvstr = PTRIN(pss32.ps_argvstr); 944 pss.ps_nargvstr = pss32.ps_nargvstr; 945 pss.ps_envstr = PTRIN(pss32.ps_envstr); 946 pss.ps_nenvstr = pss32.ps_nenvstr; 947 } else { 948 #endif 949 elm_len = sizeof(char *); 950 envp = (char *)env_vector; 951 952 UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1, 953 (off_t)(p->p_sysent->sv_psstrings), 954 sizeof(pss), UIO_SYSSPACE, UIO_READ, td); 955 ret = proc_rwmem(p, &tmp_uio); 956 if (ret != 0) 957 goto done; 958 #ifdef COMPAT_FREEBSD32 959 } 960 #endif 961 962 /* Get the array address and the number of elements */ 963 resolver(pss, &addr, &n_elements); 964 965 /* Consistent with lib/libkvm/kvm_proc.c */ 966 if (n_elements > MAX_ARGV_STR) { 967 ret = E2BIG; 968 goto done; 969 } 970 971 UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1, 972 (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td); 973 ret = proc_rwmem(p, &tmp_uio); 974 if (ret != 0) 975 goto done; 976 #ifdef COMPAT_FREEBSD32 977 if (env_vector32 != NULL) { 978 for (i = 0; i < n_elements; i++) 979 env_vector[i] = PTRIN(env_vector32[i]); 980 } 981 #endif 982 983 /* Now we can iterate through the list of strings */ 984 for (i = 0; i < n_elements; i++) { 985 pbegin = (vm_offset_t)env_vector[i]; 986 for (;;) { 987 UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string), 988 1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td); 989 ret = proc_rwmem(p, &tmp_uio); 990 if (ret != 0) 991 goto done; 992 993 if (!strvalid(env_string, UIO_CHUNK_SZ)) { 994 /* 995 * We didn't find the end of the string. 996 * Add the string to the buffer and move 997 * the pointer. But do not allow strings 998 * of unlimited length. 999 */ 1000 sbuf_bcat(sb, env_string, UIO_CHUNK_SZ); 1001 if (sbuf_len(sb) >= ARG_MAX) { 1002 ret = E2BIG; 1003 goto done; 1004 } 1005 pbegin += UIO_CHUNK_SZ; 1006 } else { 1007 sbuf_cat(sb, env_string); 1008 break; 1009 } 1010 } 1011 sbuf_bcat(sb, "", 1); 1012 } 1013 #undef UIO_HELPER 1014 1015 done: 1016 free(env_vector, M_TEMP); 1017 #ifdef COMPAT_FREEBSD32 1018 free(env_vector32, M_TEMP); 1019 #endif 1020 return (ret); 1021 } 1022 1023 static void 1024 ps_string_argv(const struct ps_strings ps, u_long *addr, int *n) 1025 { 1026 1027 *addr = (u_long) ps.ps_argvstr; 1028 *n = ps.ps_nargvstr; 1029 } 1030 1031 static void 1032 ps_string_env(const struct ps_strings ps, u_long *addr, int *n) 1033 { 1034 1035 *addr = (u_long) ps.ps_envstr; 1036 *n = ps.ps_nenvstr; 1037 } 1038 1039 /* 1040 * Filler function for proc/pid/cmdline 1041 */ 1042 static int 1043 linprocfs_doproccmdline(PFS_FILL_ARGS) 1044 { 1045 int ret; 1046 1047 PROC_LOCK(p); 1048 if ((ret = p_cansee(td, p)) != 0) { 1049 PROC_UNLOCK(p); 1050 return (ret); 1051 } 1052 if (p->p_args != NULL) { 1053 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 1054 PROC_UNLOCK(p); 1055 return (0); 1056 } 1057 PROC_UNLOCK(p); 1058 1059 ret = linprocfs_doargv(td, p, sb, ps_string_argv); 1060 return (ret); 1061 } 1062 1063 /* 1064 * Filler function for proc/pid/environ 1065 */ 1066 static int 1067 linprocfs_doprocenviron(PFS_FILL_ARGS) 1068 { 1069 int ret; 1070 1071 PROC_LOCK(p); 1072 if ((ret = p_cansee(td, p)) != 0) { 1073 PROC_UNLOCK(p); 1074 return (ret); 1075 } 1076 PROC_UNLOCK(p); 1077 1078 ret = linprocfs_doargv(td, p, sb, ps_string_env); 1079 return (ret); 1080 } 1081 1082 /* 1083 * Filler function for proc/pid/maps 1084 */ 1085 static int 1086 linprocfs_doprocmaps(PFS_FILL_ARGS) 1087 { 1088 struct vmspace *vm; 1089 vm_map_t map; 1090 vm_map_entry_t entry, tmp_entry; 1091 vm_object_t obj, tobj, lobj; 1092 vm_offset_t e_start, e_end; 1093 vm_ooffset_t off = 0; 1094 vm_prot_t e_prot; 1095 unsigned int last_timestamp; 1096 char *name = "", *freename = NULL; 1097 ino_t ino; 1098 int ref_count, shadow_count, flags; 1099 int error; 1100 struct vnode *vp; 1101 struct vattr vat; 1102 int locked; 1103 1104 PROC_LOCK(p); 1105 error = p_candebug(td, p); 1106 PROC_UNLOCK(p); 1107 if (error) 1108 return (error); 1109 1110 if (uio->uio_rw != UIO_READ) 1111 return (EOPNOTSUPP); 1112 1113 error = 0; 1114 vm = vmspace_acquire_ref(p); 1115 if (vm == NULL) 1116 return (ESRCH); 1117 map = &vm->vm_map; 1118 vm_map_lock_read(map); 1119 for (entry = map->header.next; entry != &map->header; 1120 entry = entry->next) { 1121 name = ""; 1122 freename = NULL; 1123 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 1124 continue; 1125 e_prot = entry->protection; 1126 e_start = entry->start; 1127 e_end = entry->end; 1128 obj = entry->object.vm_object; 1129 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 1130 VM_OBJECT_LOCK(tobj); 1131 if (lobj != obj) 1132 VM_OBJECT_UNLOCK(lobj); 1133 lobj = tobj; 1134 } 1135 last_timestamp = map->timestamp; 1136 vm_map_unlock_read(map); 1137 ino = 0; 1138 if (lobj) { 1139 off = IDX_TO_OFF(lobj->size); 1140 if (lobj->type == OBJT_VNODE) { 1141 vp = lobj->handle; 1142 if (vp) 1143 vref(vp); 1144 } 1145 else 1146 vp = NULL; 1147 if (lobj != obj) 1148 VM_OBJECT_UNLOCK(lobj); 1149 flags = obj->flags; 1150 ref_count = obj->ref_count; 1151 shadow_count = obj->shadow_count; 1152 VM_OBJECT_UNLOCK(obj); 1153 if (vp) { 1154 vn_fullpath(td, vp, &name, &freename); 1155 locked = VFS_LOCK_GIANT(vp->v_mount); 1156 vn_lock(vp, LK_SHARED | LK_RETRY); 1157 VOP_GETATTR(vp, &vat, td->td_ucred); 1158 ino = vat.va_fileid; 1159 vput(vp); 1160 VFS_UNLOCK_GIANT(locked); 1161 } 1162 } else { 1163 flags = 0; 1164 ref_count = 0; 1165 shadow_count = 0; 1166 } 1167 1168 /* 1169 * format: 1170 * start, end, access, offset, major, minor, inode, name. 1171 */ 1172 error = sbuf_printf(sb, 1173 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 1174 (u_long)e_start, (u_long)e_end, 1175 (e_prot & VM_PROT_READ)?"r":"-", 1176 (e_prot & VM_PROT_WRITE)?"w":"-", 1177 (e_prot & VM_PROT_EXECUTE)?"x":"-", 1178 "p", 1179 (u_long)off, 1180 0, 1181 0, 1182 (u_long)ino, 1183 *name ? " " : "", 1184 name 1185 ); 1186 if (freename) 1187 free(freename, M_TEMP); 1188 vm_map_lock_read(map); 1189 if (error == -1) { 1190 error = 0; 1191 break; 1192 } 1193 if (last_timestamp != map->timestamp) { 1194 /* 1195 * Look again for the entry because the map was 1196 * modified while it was unlocked. Specifically, 1197 * the entry may have been clipped, merged, or deleted. 1198 */ 1199 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1200 entry = tmp_entry; 1201 } 1202 } 1203 vm_map_unlock_read(map); 1204 vmspace_free(vm); 1205 1206 return (error); 1207 } 1208 1209 /* 1210 * Filler function for proc/net/dev 1211 */ 1212 static int 1213 linprocfs_donetdev(PFS_FILL_ARGS) 1214 { 1215 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1216 struct ifnet *ifp; 1217 1218 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 1219 "Inter-", " Receive", " Transmit", " face", 1220 "bytes packets errs drop fifo frame compressed", 1221 "bytes packets errs drop fifo frame compressed"); 1222 1223 CURVNET_SET(TD_TO_VNET(curthread)); 1224 IFNET_RLOCK(); 1225 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1226 linux_ifname(ifp, ifname, sizeof ifname); 1227 sbuf_printf(sb, "%6.6s:", ifname); 1228 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1229 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 1230 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1231 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 1232 } 1233 IFNET_RUNLOCK(); 1234 CURVNET_RESTORE(); 1235 1236 return (0); 1237 } 1238 1239 /* 1240 * Filler function for proc/sys/kernel/osrelease 1241 */ 1242 static int 1243 linprocfs_doosrelease(PFS_FILL_ARGS) 1244 { 1245 char osrelease[LINUX_MAX_UTSNAME]; 1246 1247 linux_get_osrelease(td, osrelease); 1248 sbuf_printf(sb, "%s\n", osrelease); 1249 1250 return (0); 1251 } 1252 1253 /* 1254 * Filler function for proc/sys/kernel/ostype 1255 */ 1256 static int 1257 linprocfs_doostype(PFS_FILL_ARGS) 1258 { 1259 char osname[LINUX_MAX_UTSNAME]; 1260 1261 linux_get_osname(td, osname); 1262 sbuf_printf(sb, "%s\n", osname); 1263 1264 return (0); 1265 } 1266 1267 /* 1268 * Filler function for proc/sys/kernel/version 1269 */ 1270 static int 1271 linprocfs_doosbuild(PFS_FILL_ARGS) 1272 { 1273 1274 linprocfs_osbuild(td, sb); 1275 sbuf_cat(sb, "\n"); 1276 return (0); 1277 } 1278 1279 /* 1280 * Filler function for proc/sys/kernel/msgmni 1281 */ 1282 static int 1283 linprocfs_domsgmni(PFS_FILL_ARGS) 1284 { 1285 1286 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1287 return (0); 1288 } 1289 1290 /* 1291 * Filler function for proc/sys/kernel/pid_max 1292 */ 1293 static int 1294 linprocfs_dopid_max(PFS_FILL_ARGS) 1295 { 1296 1297 sbuf_printf(sb, "%i\n", PID_MAX); 1298 return (0); 1299 } 1300 1301 /* 1302 * Filler function for proc/sys/kernel/sem 1303 */ 1304 static int 1305 linprocfs_dosem(PFS_FILL_ARGS) 1306 { 1307 1308 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1309 seminfo.semopm, seminfo.semmni); 1310 return (0); 1311 } 1312 1313 /* 1314 * Filler function for proc/scsi/device_info 1315 */ 1316 static int 1317 linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1318 { 1319 1320 return (0); 1321 } 1322 1323 /* 1324 * Filler function for proc/scsi/scsi 1325 */ 1326 static int 1327 linprocfs_doscsiscsi(PFS_FILL_ARGS) 1328 { 1329 1330 return (0); 1331 } 1332 1333 extern struct cdevsw *cdevsw[]; 1334 1335 /* 1336 * Filler function for proc/devices 1337 */ 1338 static int 1339 linprocfs_dodevices(PFS_FILL_ARGS) 1340 { 1341 char *char_devices; 1342 sbuf_printf(sb, "Character devices:\n"); 1343 1344 char_devices = linux_get_char_devices(); 1345 sbuf_printf(sb, "%s", char_devices); 1346 linux_free_get_char_devices(char_devices); 1347 1348 sbuf_printf(sb, "\nBlock devices:\n"); 1349 1350 return (0); 1351 } 1352 1353 /* 1354 * Filler function for proc/cmdline 1355 */ 1356 static int 1357 linprocfs_docmdline(PFS_FILL_ARGS) 1358 { 1359 1360 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1361 sbuf_printf(sb, " ro root=302\n"); 1362 return (0); 1363 } 1364 1365 /* 1366 * Filler function for proc/filesystems 1367 */ 1368 static int 1369 linprocfs_dofilesystems(PFS_FILL_ARGS) 1370 { 1371 struct vfsconf *vfsp; 1372 1373 mtx_lock(&Giant); 1374 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 1375 if (vfsp->vfc_flags & VFCF_SYNTHETIC) 1376 sbuf_printf(sb, "nodev"); 1377 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name); 1378 } 1379 mtx_unlock(&Giant); 1380 return(0); 1381 } 1382 1383 #if 0 1384 /* 1385 * Filler function for proc/modules 1386 */ 1387 static int 1388 linprocfs_domodules(PFS_FILL_ARGS) 1389 { 1390 struct linker_file *lf; 1391 1392 TAILQ_FOREACH(lf, &linker_files, link) { 1393 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1394 (unsigned long)lf->size, lf->refs); 1395 } 1396 return (0); 1397 } 1398 #endif 1399 1400 /* 1401 * Filler function for proc/pid/fd 1402 */ 1403 static int 1404 linprocfs_dofdescfs(PFS_FILL_ARGS) 1405 { 1406 1407 if (p == curproc) 1408 sbuf_printf(sb, "/dev/fd"); 1409 else 1410 sbuf_printf(sb, "unknown"); 1411 return (0); 1412 } 1413 1414 /* 1415 * Constructor 1416 */ 1417 static int 1418 linprocfs_init(PFS_INIT_ARGS) 1419 { 1420 struct pfs_node *root; 1421 struct pfs_node *dir; 1422 1423 root = pi->pi_root; 1424 1425 /* /proc/... */ 1426 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1427 NULL, NULL, NULL, PFS_RD); 1428 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1429 NULL, NULL, NULL, PFS_RD); 1430 pfs_create_file(root, "devices", &linprocfs_dodevices, 1431 NULL, NULL, NULL, PFS_RD); 1432 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1433 NULL, NULL, NULL, PFS_RD); 1434 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1435 NULL, NULL, NULL, PFS_RD); 1436 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1437 NULL, NULL, NULL, PFS_RD); 1438 #if 0 1439 pfs_create_file(root, "modules", &linprocfs_domodules, 1440 NULL, NULL, NULL, PFS_RD); 1441 #endif 1442 pfs_create_file(root, "mounts", &linprocfs_domtab, 1443 NULL, NULL, NULL, PFS_RD); 1444 pfs_create_file(root, "mtab", &linprocfs_domtab, 1445 NULL, NULL, NULL, PFS_RD); 1446 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1447 NULL, NULL, NULL, PFS_RD); 1448 pfs_create_link(root, "self", &procfs_docurproc, 1449 NULL, NULL, NULL, 0); 1450 pfs_create_file(root, "stat", &linprocfs_dostat, 1451 NULL, NULL, NULL, PFS_RD); 1452 pfs_create_file(root, "uptime", &linprocfs_douptime, 1453 NULL, NULL, NULL, PFS_RD); 1454 pfs_create_file(root, "version", &linprocfs_doversion, 1455 NULL, NULL, NULL, PFS_RD); 1456 1457 /* /proc/net/... */ 1458 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1459 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1460 NULL, NULL, NULL, PFS_RD); 1461 1462 /* /proc/<pid>/... */ 1463 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1464 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1465 NULL, NULL, NULL, PFS_RD); 1466 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1467 NULL, NULL, NULL, 0); 1468 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1469 NULL, NULL, NULL, PFS_RD); 1470 pfs_create_link(dir, "exe", &procfs_doprocfile, 1471 NULL, &procfs_notsystem, NULL, 0); 1472 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1473 NULL, NULL, NULL, PFS_RD); 1474 pfs_create_file(dir, "mem", &procfs_doprocmem, 1475 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1476 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1477 NULL, NULL, NULL, 0); 1478 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1479 NULL, NULL, NULL, PFS_RD); 1480 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1481 NULL, NULL, NULL, PFS_RD); 1482 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1483 NULL, NULL, NULL, PFS_RD); 1484 pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1485 NULL, NULL, NULL, 0); 1486 1487 /* /proc/scsi/... */ 1488 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1489 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1490 NULL, NULL, NULL, PFS_RD); 1491 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1492 NULL, NULL, NULL, PFS_RD); 1493 1494 /* /proc/sys/... */ 1495 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1496 /* /proc/sys/kernel/... */ 1497 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1498 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1499 NULL, NULL, NULL, PFS_RD); 1500 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1501 NULL, NULL, NULL, PFS_RD); 1502 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1503 NULL, NULL, NULL, PFS_RD); 1504 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1505 NULL, NULL, NULL, PFS_RD); 1506 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1507 NULL, NULL, NULL, PFS_RD); 1508 pfs_create_file(dir, "sem", &linprocfs_dosem, 1509 NULL, NULL, NULL, PFS_RD); 1510 1511 return (0); 1512 } 1513 1514 /* 1515 * Destructor 1516 */ 1517 static int 1518 linprocfs_uninit(PFS_INIT_ARGS) 1519 { 1520 1521 /* nothing to do, pseudofs will GC */ 1522 return (0); 1523 } 1524 1525 PSEUDOFS(linprocfs, 1); 1526 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1527 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1528 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1529 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1530