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 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 } 773 774 fill_kinfo_proc(p, &kp); 775 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 776 sbuf_printf(sb, "State:\t%s\n", state); 777 778 /* 779 * Credentials 780 */ 781 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 782 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 783 p->p_pptr->p_pid : 0); 784 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 785 p->p_ucred->cr_uid, 786 p->p_ucred->cr_svuid, 787 /* FreeBSD doesn't have fsuid */ 788 p->p_ucred->cr_uid); 789 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 790 p->p_ucred->cr_gid, 791 p->p_ucred->cr_svgid, 792 /* FreeBSD doesn't have fsgid */ 793 p->p_ucred->cr_gid); 794 sbuf_cat(sb, "Groups:\t"); 795 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 796 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 797 PROC_UNLOCK(p); 798 sbuf_putc(sb, '\n'); 799 800 /* 801 * Memory 802 * 803 * While our approximation of VmLib may not be accurate (I 804 * don't know of a simple way to verify it, and I'm not sure 805 * it has much meaning anyway), I believe it's good enough. 806 * 807 * The same code that could (I think) accurately compute VmLib 808 * could also compute VmLck, but I don't really care enough to 809 * implement it. Submissions are welcome. 810 */ 811 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 812 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 813 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 814 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 815 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 816 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 817 lsize = B2P(kp.ki_size) - kp.ki_dsize - 818 kp.ki_ssize - kp.ki_tsize - 1; 819 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 820 821 /* 822 * Signal masks 823 * 824 * We support up to 128 signals, while Linux supports 32, 825 * but we only define 32 (the same 32 as Linux, to boot), so 826 * just show the lower 32 bits of each mask. XXX hack. 827 * 828 * NB: on certain platforms (Sparc at least) Linux actually 829 * supports 64 signals, but this code is a long way from 830 * running on anything but i386, so ignore that for now. 831 */ 832 PROC_LOCK(p); 833 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 834 /* 835 * I can't seem to find out where the signal mask is in 836 * relation to struct proc, so SigBlk is left unimplemented. 837 */ 838 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 839 ps = p->p_sigacts; 840 mtx_lock(&ps->ps_mtx); 841 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 842 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 843 mtx_unlock(&ps->ps_mtx); 844 PROC_UNLOCK(p); 845 846 /* 847 * Linux also prints the capability masks, but we don't have 848 * capabilities yet, and when we do get them they're likely to 849 * be meaningless to Linux programs, so we lie. XXX 850 */ 851 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 852 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 853 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 854 855 return (0); 856 } 857 858 859 /* 860 * Filler function for proc/pid/cwd 861 */ 862 static int 863 linprocfs_doproccwd(PFS_FILL_ARGS) 864 { 865 char *fullpath = "unknown"; 866 char *freepath = NULL; 867 868 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 869 sbuf_printf(sb, "%s", fullpath); 870 if (freepath) 871 free(freepath, M_TEMP); 872 return (0); 873 } 874 875 /* 876 * Filler function for proc/pid/root 877 */ 878 static int 879 linprocfs_doprocroot(PFS_FILL_ARGS) 880 { 881 struct vnode *rvp; 882 char *fullpath = "unknown"; 883 char *freepath = NULL; 884 885 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 886 vn_fullpath(td, rvp, &fullpath, &freepath); 887 sbuf_printf(sb, "%s", fullpath); 888 if (freepath) 889 free(freepath, M_TEMP); 890 return (0); 891 } 892 893 #define MAX_ARGV_STR 512 /* Max number of argv-like strings */ 894 #define UIO_CHUNK_SZ 256 /* Max chunk size (bytes) for uiomove */ 895 896 static int 897 linprocfs_doargv(struct thread *td, struct proc *p, struct sbuf *sb, 898 void (*resolver)(const struct ps_strings, u_long *, int *)) 899 { 900 struct iovec iov; 901 struct uio tmp_uio; 902 struct ps_strings pss; 903 int ret, i, n_elements, elm_len; 904 u_long addr, pbegin; 905 char **env_vector, *envp; 906 char env_string[UIO_CHUNK_SZ]; 907 #ifdef COMPAT_FREEBSD32 908 struct freebsd32_ps_strings pss32; 909 uint32_t *env_vector32; 910 #endif 911 912 #define UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td) \ 913 do { \ 914 iov.iov_base = (caddr_t)(base); \ 915 iov.iov_len = (len); \ 916 uio.uio_iov = &(iov); \ 917 uio.uio_iovcnt = (cnt); \ 918 uio.uio_offset = (off_t)(offset); \ 919 uio.uio_resid = (sz); \ 920 uio.uio_segflg = (flg); \ 921 uio.uio_rw = (rw); \ 922 uio.uio_td = (td); \ 923 } while (0) 924 925 env_vector = malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK); 926 927 #ifdef COMPAT_FREEBSD32 928 env_vector32 = NULL; 929 if (SV_PROC_FLAG(p, SV_ILP32) != 0) { 930 env_vector32 = malloc(sizeof(*env_vector32) * MAX_ARGV_STR, 931 M_TEMP, M_WAITOK); 932 elm_len = sizeof(int32_t); 933 envp = (char *)env_vector32; 934 935 UIO_HELPER(tmp_uio, iov, &pss32, sizeof(pss32), 1, 936 (off_t)(p->p_sysent->sv_psstrings), 937 sizeof(pss32), UIO_SYSSPACE, UIO_READ, td); 938 ret = proc_rwmem(p, &tmp_uio); 939 if (ret != 0) 940 goto done; 941 pss.ps_argvstr = PTRIN(pss32.ps_argvstr); 942 pss.ps_nargvstr = pss32.ps_nargvstr; 943 pss.ps_envstr = PTRIN(pss32.ps_envstr); 944 pss.ps_nenvstr = pss32.ps_nenvstr; 945 } else { 946 #endif 947 elm_len = sizeof(char *); 948 envp = (char *)env_vector; 949 950 UIO_HELPER(tmp_uio, iov, &pss, sizeof(pss), 1, 951 (off_t)(p->p_sysent->sv_psstrings), 952 sizeof(pss), UIO_SYSSPACE, UIO_READ, td); 953 ret = proc_rwmem(p, &tmp_uio); 954 if (ret != 0) 955 goto done; 956 #ifdef COMPAT_FREEBSD32 957 } 958 #endif 959 960 /* Get the array address and the number of elements */ 961 resolver(pss, &addr, &n_elements); 962 963 /* Consistent with lib/libkvm/kvm_proc.c */ 964 if (n_elements > MAX_ARGV_STR) { 965 ret = E2BIG; 966 goto done; 967 } 968 969 UIO_HELPER(tmp_uio, iov, envp, n_elements * elm_len, 1, 970 (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td); 971 ret = proc_rwmem(p, &tmp_uio); 972 if (ret != 0) 973 goto done; 974 #ifdef COMPAT_FREEBSD32 975 if (env_vector32 != NULL) { 976 for (i = 0; i < n_elements; i++) 977 env_vector[i] = PTRIN(env_vector32[i]); 978 } 979 #endif 980 981 /* Now we can iterate through the list of strings */ 982 for (i = 0; i < n_elements; i++) { 983 pbegin = (vm_offset_t)env_vector[i]; 984 for (;;) { 985 UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string), 986 1, pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td); 987 ret = proc_rwmem(p, &tmp_uio); 988 if (ret != 0) 989 goto done; 990 991 if (!strvalid(env_string, UIO_CHUNK_SZ)) { 992 /* 993 * We didn't find the end of the string. 994 * Add the string to the buffer and move 995 * the pointer. But do not allow strings 996 * of unlimited length. 997 */ 998 sbuf_bcat(sb, env_string, UIO_CHUNK_SZ); 999 if (sbuf_len(sb) >= ARG_MAX) { 1000 ret = E2BIG; 1001 goto done; 1002 } 1003 pbegin += UIO_CHUNK_SZ; 1004 } else { 1005 sbuf_cat(sb, env_string); 1006 break; 1007 } 1008 } 1009 sbuf_bcat(sb, "", 1); 1010 } 1011 #undef UIO_HELPER 1012 1013 done: 1014 free(env_vector, M_TEMP); 1015 #ifdef COMPAT_FREEBSD32 1016 free(env_vector32, M_TEMP); 1017 #endif 1018 return (ret); 1019 } 1020 1021 static void 1022 ps_string_argv(const struct ps_strings ps, u_long *addr, int *n) 1023 { 1024 1025 *addr = (u_long) ps.ps_argvstr; 1026 *n = ps.ps_nargvstr; 1027 } 1028 1029 static void 1030 ps_string_env(const struct ps_strings ps, u_long *addr, int *n) 1031 { 1032 1033 *addr = (u_long) ps.ps_envstr; 1034 *n = ps.ps_nenvstr; 1035 } 1036 1037 /* 1038 * Filler function for proc/pid/cmdline 1039 */ 1040 static int 1041 linprocfs_doproccmdline(PFS_FILL_ARGS) 1042 { 1043 int ret; 1044 1045 PROC_LOCK(p); 1046 if ((ret = p_cansee(td, p)) != 0) { 1047 PROC_UNLOCK(p); 1048 return (ret); 1049 } 1050 if (p->p_args != NULL) { 1051 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 1052 PROC_UNLOCK(p); 1053 return (0); 1054 } 1055 PROC_UNLOCK(p); 1056 1057 ret = linprocfs_doargv(td, p, sb, ps_string_argv); 1058 return (ret); 1059 } 1060 1061 /* 1062 * Filler function for proc/pid/environ 1063 */ 1064 static int 1065 linprocfs_doprocenviron(PFS_FILL_ARGS) 1066 { 1067 int ret; 1068 1069 PROC_LOCK(p); 1070 if ((ret = p_cansee(td, p)) != 0) { 1071 PROC_UNLOCK(p); 1072 return (ret); 1073 } 1074 PROC_UNLOCK(p); 1075 1076 ret = linprocfs_doargv(td, p, sb, ps_string_env); 1077 return (ret); 1078 } 1079 1080 /* 1081 * Filler function for proc/pid/maps 1082 */ 1083 static int 1084 linprocfs_doprocmaps(PFS_FILL_ARGS) 1085 { 1086 struct vmspace *vm; 1087 vm_map_t map; 1088 vm_map_entry_t entry, tmp_entry; 1089 vm_object_t obj, tobj, lobj; 1090 vm_offset_t e_start, e_end; 1091 vm_ooffset_t off = 0; 1092 vm_prot_t e_prot; 1093 unsigned int last_timestamp; 1094 char *name = "", *freename = NULL; 1095 ino_t ino; 1096 int ref_count, shadow_count, flags; 1097 int error; 1098 struct vnode *vp; 1099 struct vattr vat; 1100 int locked; 1101 1102 PROC_LOCK(p); 1103 error = p_candebug(td, p); 1104 PROC_UNLOCK(p); 1105 if (error) 1106 return (error); 1107 1108 if (uio->uio_rw != UIO_READ) 1109 return (EOPNOTSUPP); 1110 1111 error = 0; 1112 vm = vmspace_acquire_ref(p); 1113 if (vm == NULL) 1114 return (ESRCH); 1115 map = &vm->vm_map; 1116 vm_map_lock_read(map); 1117 for (entry = map->header.next; entry != &map->header; 1118 entry = entry->next) { 1119 name = ""; 1120 freename = NULL; 1121 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 1122 continue; 1123 e_prot = entry->protection; 1124 e_start = entry->start; 1125 e_end = entry->end; 1126 obj = entry->object.vm_object; 1127 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 1128 VM_OBJECT_LOCK(tobj); 1129 if (lobj != obj) 1130 VM_OBJECT_UNLOCK(lobj); 1131 lobj = tobj; 1132 } 1133 last_timestamp = map->timestamp; 1134 vm_map_unlock_read(map); 1135 ino = 0; 1136 if (lobj) { 1137 off = IDX_TO_OFF(lobj->size); 1138 if (lobj->type == OBJT_VNODE) { 1139 vp = lobj->handle; 1140 if (vp) 1141 vref(vp); 1142 } 1143 else 1144 vp = NULL; 1145 if (lobj != obj) 1146 VM_OBJECT_UNLOCK(lobj); 1147 flags = obj->flags; 1148 ref_count = obj->ref_count; 1149 shadow_count = obj->shadow_count; 1150 VM_OBJECT_UNLOCK(obj); 1151 if (vp) { 1152 vn_fullpath(td, vp, &name, &freename); 1153 locked = VFS_LOCK_GIANT(vp->v_mount); 1154 vn_lock(vp, LK_SHARED | LK_RETRY); 1155 VOP_GETATTR(vp, &vat, td->td_ucred); 1156 ino = vat.va_fileid; 1157 vput(vp); 1158 VFS_UNLOCK_GIANT(locked); 1159 } 1160 } else { 1161 flags = 0; 1162 ref_count = 0; 1163 shadow_count = 0; 1164 } 1165 1166 /* 1167 * format: 1168 * start, end, access, offset, major, minor, inode, name. 1169 */ 1170 error = sbuf_printf(sb, 1171 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 1172 (u_long)e_start, (u_long)e_end, 1173 (e_prot & VM_PROT_READ)?"r":"-", 1174 (e_prot & VM_PROT_WRITE)?"w":"-", 1175 (e_prot & VM_PROT_EXECUTE)?"x":"-", 1176 "p", 1177 (u_long)off, 1178 0, 1179 0, 1180 (u_long)ino, 1181 *name ? " " : "", 1182 name 1183 ); 1184 if (freename) 1185 free(freename, M_TEMP); 1186 vm_map_lock_read(map); 1187 if (error == -1) { 1188 error = 0; 1189 break; 1190 } 1191 if (last_timestamp != map->timestamp) { 1192 /* 1193 * Look again for the entry because the map was 1194 * modified while it was unlocked. Specifically, 1195 * the entry may have been clipped, merged, or deleted. 1196 */ 1197 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1198 entry = tmp_entry; 1199 } 1200 } 1201 vm_map_unlock_read(map); 1202 vmspace_free(vm); 1203 1204 return (error); 1205 } 1206 1207 /* 1208 * Filler function for proc/net/dev 1209 */ 1210 static int 1211 linprocfs_donetdev(PFS_FILL_ARGS) 1212 { 1213 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1214 struct ifnet *ifp; 1215 1216 sbuf_printf(sb, "%6s|%58s|%s\n" 1217 "%6s|%58s|%58s\n", 1218 "Inter-", " Receive", " Transmit", 1219 " face", 1220 "bytes packets errs drop fifo frame compressed multicast", 1221 "bytes packets errs drop fifo colls carrier 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, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1229 ifp->if_ibytes, /* rx_bytes */ 1230 ifp->if_ipackets, /* rx_packets */ 1231 ifp->if_ierrors, /* rx_errors */ 1232 ifp->if_iqdrops, /* rx_dropped + 1233 * rx_missed_errors */ 1234 0UL, /* rx_fifo_errors */ 1235 0UL, /* rx_length_errors + 1236 * rx_over_errors + 1237 * rx_crc_errors + 1238 * rx_frame_errors */ 1239 0UL, /* rx_compressed */ 1240 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */ 1241 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1242 ifp->if_obytes, /* tx_bytes */ 1243 ifp->if_opackets, /* tx_packets */ 1244 ifp->if_oerrors, /* tx_errors */ 1245 0UL, /* tx_dropped */ 1246 0UL, /* tx_fifo_errors */ 1247 ifp->if_collisions, /* collisions */ 1248 0UL, /* tx_carrier_errors + 1249 * tx_aborted_errors + 1250 * tx_window_errors + 1251 * tx_heartbeat_errors */ 1252 0UL); /* tx_compressed */ 1253 } 1254 IFNET_RUNLOCK(); 1255 CURVNET_RESTORE(); 1256 1257 return (0); 1258 } 1259 1260 /* 1261 * Filler function for proc/sys/kernel/osrelease 1262 */ 1263 static int 1264 linprocfs_doosrelease(PFS_FILL_ARGS) 1265 { 1266 char osrelease[LINUX_MAX_UTSNAME]; 1267 1268 linux_get_osrelease(td, osrelease); 1269 sbuf_printf(sb, "%s\n", osrelease); 1270 1271 return (0); 1272 } 1273 1274 /* 1275 * Filler function for proc/sys/kernel/ostype 1276 */ 1277 static int 1278 linprocfs_doostype(PFS_FILL_ARGS) 1279 { 1280 char osname[LINUX_MAX_UTSNAME]; 1281 1282 linux_get_osname(td, osname); 1283 sbuf_printf(sb, "%s\n", osname); 1284 1285 return (0); 1286 } 1287 1288 /* 1289 * Filler function for proc/sys/kernel/version 1290 */ 1291 static int 1292 linprocfs_doosbuild(PFS_FILL_ARGS) 1293 { 1294 1295 linprocfs_osbuild(td, sb); 1296 sbuf_cat(sb, "\n"); 1297 return (0); 1298 } 1299 1300 /* 1301 * Filler function for proc/sys/kernel/msgmni 1302 */ 1303 static int 1304 linprocfs_domsgmni(PFS_FILL_ARGS) 1305 { 1306 1307 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1308 return (0); 1309 } 1310 1311 /* 1312 * Filler function for proc/sys/kernel/pid_max 1313 */ 1314 static int 1315 linprocfs_dopid_max(PFS_FILL_ARGS) 1316 { 1317 1318 sbuf_printf(sb, "%i\n", PID_MAX); 1319 return (0); 1320 } 1321 1322 /* 1323 * Filler function for proc/sys/kernel/sem 1324 */ 1325 static int 1326 linprocfs_dosem(PFS_FILL_ARGS) 1327 { 1328 1329 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1330 seminfo.semopm, seminfo.semmni); 1331 return (0); 1332 } 1333 1334 /* 1335 * Filler function for proc/scsi/device_info 1336 */ 1337 static int 1338 linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1339 { 1340 1341 return (0); 1342 } 1343 1344 /* 1345 * Filler function for proc/scsi/scsi 1346 */ 1347 static int 1348 linprocfs_doscsiscsi(PFS_FILL_ARGS) 1349 { 1350 1351 return (0); 1352 } 1353 1354 extern struct cdevsw *cdevsw[]; 1355 1356 /* 1357 * Filler function for proc/devices 1358 */ 1359 static int 1360 linprocfs_dodevices(PFS_FILL_ARGS) 1361 { 1362 char *char_devices; 1363 sbuf_printf(sb, "Character devices:\n"); 1364 1365 char_devices = linux_get_char_devices(); 1366 sbuf_printf(sb, "%s", char_devices); 1367 linux_free_get_char_devices(char_devices); 1368 1369 sbuf_printf(sb, "\nBlock devices:\n"); 1370 1371 return (0); 1372 } 1373 1374 /* 1375 * Filler function for proc/cmdline 1376 */ 1377 static int 1378 linprocfs_docmdline(PFS_FILL_ARGS) 1379 { 1380 1381 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1382 sbuf_printf(sb, " ro root=302\n"); 1383 return (0); 1384 } 1385 1386 /* 1387 * Filler function for proc/filesystems 1388 */ 1389 static int 1390 linprocfs_dofilesystems(PFS_FILL_ARGS) 1391 { 1392 struct vfsconf *vfsp; 1393 1394 mtx_lock(&Giant); 1395 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 1396 if (vfsp->vfc_flags & VFCF_SYNTHETIC) 1397 sbuf_printf(sb, "nodev"); 1398 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name); 1399 } 1400 mtx_unlock(&Giant); 1401 return(0); 1402 } 1403 1404 #if 0 1405 /* 1406 * Filler function for proc/modules 1407 */ 1408 static int 1409 linprocfs_domodules(PFS_FILL_ARGS) 1410 { 1411 struct linker_file *lf; 1412 1413 TAILQ_FOREACH(lf, &linker_files, link) { 1414 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1415 (unsigned long)lf->size, lf->refs); 1416 } 1417 return (0); 1418 } 1419 #endif 1420 1421 /* 1422 * Filler function for proc/pid/fd 1423 */ 1424 static int 1425 linprocfs_dofdescfs(PFS_FILL_ARGS) 1426 { 1427 1428 if (p == curproc) 1429 sbuf_printf(sb, "/dev/fd"); 1430 else 1431 sbuf_printf(sb, "unknown"); 1432 return (0); 1433 } 1434 1435 /* 1436 * Constructor 1437 */ 1438 static int 1439 linprocfs_init(PFS_INIT_ARGS) 1440 { 1441 struct pfs_node *root; 1442 struct pfs_node *dir; 1443 1444 root = pi->pi_root; 1445 1446 /* /proc/... */ 1447 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1448 NULL, NULL, NULL, PFS_RD); 1449 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1450 NULL, NULL, NULL, PFS_RD); 1451 pfs_create_file(root, "devices", &linprocfs_dodevices, 1452 NULL, NULL, NULL, PFS_RD); 1453 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1454 NULL, NULL, NULL, PFS_RD); 1455 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1456 NULL, NULL, NULL, PFS_RD); 1457 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1458 NULL, NULL, NULL, PFS_RD); 1459 #if 0 1460 pfs_create_file(root, "modules", &linprocfs_domodules, 1461 NULL, NULL, NULL, PFS_RD); 1462 #endif 1463 pfs_create_file(root, "mounts", &linprocfs_domtab, 1464 NULL, NULL, NULL, PFS_RD); 1465 pfs_create_file(root, "mtab", &linprocfs_domtab, 1466 NULL, NULL, NULL, PFS_RD); 1467 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1468 NULL, NULL, NULL, PFS_RD); 1469 pfs_create_link(root, "self", &procfs_docurproc, 1470 NULL, NULL, NULL, 0); 1471 pfs_create_file(root, "stat", &linprocfs_dostat, 1472 NULL, NULL, NULL, PFS_RD); 1473 pfs_create_file(root, "uptime", &linprocfs_douptime, 1474 NULL, NULL, NULL, PFS_RD); 1475 pfs_create_file(root, "version", &linprocfs_doversion, 1476 NULL, NULL, NULL, PFS_RD); 1477 1478 /* /proc/net/... */ 1479 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1480 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1481 NULL, NULL, NULL, PFS_RD); 1482 1483 /* /proc/<pid>/... */ 1484 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1485 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1486 NULL, NULL, NULL, PFS_RD); 1487 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1488 NULL, NULL, NULL, 0); 1489 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1490 NULL, NULL, NULL, PFS_RD); 1491 pfs_create_link(dir, "exe", &procfs_doprocfile, 1492 NULL, &procfs_notsystem, NULL, 0); 1493 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1494 NULL, NULL, NULL, PFS_RD); 1495 pfs_create_file(dir, "mem", &procfs_doprocmem, 1496 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1497 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1498 NULL, NULL, NULL, 0); 1499 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1500 NULL, NULL, NULL, PFS_RD); 1501 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1502 NULL, NULL, NULL, PFS_RD); 1503 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1504 NULL, NULL, NULL, PFS_RD); 1505 pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1506 NULL, NULL, NULL, 0); 1507 1508 /* /proc/scsi/... */ 1509 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1510 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1511 NULL, NULL, NULL, PFS_RD); 1512 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1513 NULL, NULL, NULL, PFS_RD); 1514 1515 /* /proc/sys/... */ 1516 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1517 /* /proc/sys/kernel/... */ 1518 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1519 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1520 NULL, NULL, NULL, PFS_RD); 1521 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1522 NULL, NULL, NULL, PFS_RD); 1523 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1524 NULL, NULL, NULL, PFS_RD); 1525 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1526 NULL, NULL, NULL, PFS_RD); 1527 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1528 NULL, NULL, NULL, PFS_RD); 1529 pfs_create_file(dir, "sem", &linprocfs_dosem, 1530 NULL, NULL, NULL, PFS_RD); 1531 1532 return (0); 1533 } 1534 1535 /* 1536 * Destructor 1537 */ 1538 static int 1539 linprocfs_uninit(PFS_INIT_ARGS) 1540 { 1541 1542 /* nothing to do, pseudofs will GC */ 1543 return (0); 1544 } 1545 1546 PSEUDOFS(linprocfs, 1); 1547 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1548 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1549 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1550 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1551