linprocfs.c revision 223182
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: head/sys/compat/linprocfs/linprocfs.c 223182 2011-06-17 07:30:56Z pluknet $"); 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 */ 141static char linux_state[] = "RRSTZDD"; 142 143/* 144 * Filler function for proc/meminfo 145 */ 146static int 147linprocfs_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 */ 219static int 220linprocfs_docpuinfo(PFS_FILL_ARGS) 221{ 222 int hw_model[2]; 223 char model[128]; 224 uint64_t freq; 225 size_t size; 226 int class, fqmhz, fqkhz; 227 int i; 228 229 /* 230 * We default the flags to include all non-conflicting flags, 231 * and the Intel versions of conflicting flags. 232 */ 233 static char *flags[] = { 234 "fpu", "vme", "de", "pse", "tsc", 235 "msr", "pae", "mce", "cx8", "apic", 236 "sep", "sep", "mtrr", "pge", "mca", 237 "cmov", "pat", "pse36", "pn", "b19", 238 "b20", "b21", "mmxext", "mmx", "fxsr", 239 "xmm", "sse2", "b27", "b28", "b29", 240 "3dnowext", "3dnow" 241 }; 242 243 switch (cpu_class) { 244#ifdef __i386__ 245 case CPUCLASS_286: 246 class = 2; 247 break; 248 case CPUCLASS_386: 249 class = 3; 250 break; 251 case CPUCLASS_486: 252 class = 4; 253 break; 254 case CPUCLASS_586: 255 class = 5; 256 break; 257 case CPUCLASS_686: 258 class = 6; 259 break; 260 default: 261 class = 0; 262 break; 263#else /* __amd64__ */ 264 default: 265 class = 15; 266 break; 267#endif 268 } 269 270 hw_model[0] = CTL_HW; 271 hw_model[1] = HW_MODEL; 272 model[0] = '\0'; 273 size = sizeof(model); 274 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 275 strcpy(model, "unknown"); 276 for (i = 0; i < mp_ncpus; ++i) { 277 sbuf_printf(sb, 278 "processor\t: %d\n" 279 "vendor_id\t: %.20s\n" 280 "cpu family\t: %u\n" 281 "model\t\t: %u\n" 282 "model name\t: %s\n" 283 "stepping\t: %u\n\n", 284 i, cpu_vendor, CPUID_TO_FAMILY(cpu_id), 285 CPUID_TO_MODEL(cpu_id), model, cpu_id & CPUID_STEPPING); 286 /* XXX per-cpu vendor / class / model / id? */ 287 } 288 289 sbuf_cat(sb, "flags\t\t:"); 290 291#ifdef __i386__ 292 switch (cpu_vendor_id) { 293 case CPU_VENDOR_AMD: 294 if (class < 6) 295 flags[16] = "fcmov"; 296 break; 297 case CPU_VENDOR_CYRIX: 298 flags[24] = "cxmmx"; 299 break; 300 } 301#endif 302 303 for (i = 0; i < 32; i++) 304 if (cpu_feature & (1 << i)) 305 sbuf_printf(sb, " %s", flags[i]); 306 sbuf_cat(sb, "\n"); 307 freq = atomic_load_acq_64(&tsc_freq); 308 if (freq != 0) { 309 fqmhz = (freq + 4999) / 1000000; 310 fqkhz = ((freq + 4999) / 10000) % 100; 311 sbuf_printf(sb, 312 "cpu MHz\t\t: %d.%02d\n" 313 "bogomips\t: %d.%02d\n", 314 fqmhz, fqkhz, fqmhz, fqkhz); 315 } 316 317 return (0); 318} 319#endif /* __i386__ || __amd64__ */ 320 321/* 322 * Filler function for proc/mtab 323 * 324 * This file doesn't exist in Linux' procfs, but is included here so 325 * users can symlink /compat/linux/etc/mtab to /proc/mtab 326 */ 327static int 328linprocfs_domtab(PFS_FILL_ARGS) 329{ 330 struct nameidata nd; 331 struct mount *mp; 332 const char *lep; 333 char *dlep, *flep, *mntto, *mntfrom, *fstype; 334 size_t lep_len; 335 int error; 336 337 /* resolve symlinks etc. in the emulation tree prefix */ 338 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 339 flep = NULL; 340 error = namei(&nd); 341 lep = linux_emul_path; 342 if (error == 0) { 343 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 344 lep = dlep; 345 vrele(nd.ni_vp); 346 VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 347 } 348 lep_len = strlen(lep); 349 350 mtx_lock(&mountlist_mtx); 351 error = 0; 352 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 353 /* determine device name */ 354 mntfrom = mp->mnt_stat.f_mntfromname; 355 356 /* determine mount point */ 357 mntto = mp->mnt_stat.f_mntonname; 358 if (strncmp(mntto, lep, lep_len) == 0 && 359 mntto[lep_len] == '/') 360 mntto += lep_len; 361 362 /* determine fs type */ 363 fstype = mp->mnt_stat.f_fstypename; 364 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 365 mntfrom = fstype = "proc"; 366 else if (strcmp(fstype, "procfs") == 0) 367 continue; 368 369 if (strcmp(fstype, "linsysfs") == 0) { 370 sbuf_printf(sb, "/sys %s sysfs %s", mntto, 371 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 372 } else { 373 /* For Linux msdosfs is called vfat */ 374 if (strcmp(fstype, "msdosfs") == 0) 375 fstype = "vfat"; 376 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 377 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 378 } 379#define ADD_OPTION(opt, name) \ 380 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 381 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 382 ADD_OPTION(MNT_NOEXEC, "noexec"); 383 ADD_OPTION(MNT_NOSUID, "nosuid"); 384 ADD_OPTION(MNT_UNION, "union"); 385 ADD_OPTION(MNT_ASYNC, "async"); 386 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 387 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 388 ADD_OPTION(MNT_NOATIME, "noatime"); 389#undef ADD_OPTION 390 /* a real Linux mtab will also show NFS options */ 391 sbuf_printf(sb, " 0 0\n"); 392 } 393 mtx_unlock(&mountlist_mtx); 394 if (flep != NULL) 395 free(flep, M_TEMP); 396 return (error); 397} 398 399/* 400 * Filler function for proc/partitions 401 * 402 */ 403static int 404linprocfs_dopartitions(PFS_FILL_ARGS) 405{ 406 struct g_class *cp; 407 struct g_geom *gp; 408 struct g_provider *pp; 409 struct nameidata nd; 410 const char *lep; 411 char *dlep, *flep; 412 size_t lep_len; 413 int error; 414 int major, minor; 415 416 /* resolve symlinks etc. in the emulation tree prefix */ 417 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 418 flep = NULL; 419 error = namei(&nd); 420 lep = linux_emul_path; 421 if (error == 0) { 422 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 423 lep = dlep; 424 vrele(nd.ni_vp); 425 VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 426 } 427 lep_len = strlen(lep); 428 429 g_topology_lock(); 430 error = 0; 431 sbuf_printf(sb, "major minor #blocks name rio rmerge rsect " 432 "ruse wio wmerge wsect wuse running use aveq\n"); 433 434 LIST_FOREACH(cp, &g_classes, class) { 435 if (strcmp(cp->name, "DISK") == 0 || 436 strcmp(cp->name, "PART") == 0) 437 LIST_FOREACH(gp, &cp->geom, geom) { 438 LIST_FOREACH(pp, &gp->provider, provider) { 439 if (linux_driver_get_major_minor( 440 pp->name, &major, &minor) != 0) { 441 major = 0; 442 minor = 0; 443 } 444 sbuf_printf(sb, "%d %d %lld %s " 445 "%d %d %d %d %d " 446 "%d %d %d %d %d %d\n", 447 major, minor, 448 (long long)pp->mediasize, pp->name, 449 0, 0, 0, 0, 0, 450 0, 0, 0, 0, 0, 0); 451 } 452 } 453 } 454 g_topology_unlock(); 455 456 if (flep != NULL) 457 free(flep, M_TEMP); 458 return (error); 459} 460 461 462/* 463 * Filler function for proc/stat 464 */ 465static int 466linprocfs_dostat(PFS_FILL_ARGS) 467{ 468 struct pcpu *pcpu; 469 long cp_time[CPUSTATES]; 470 long *cp; 471 int i; 472 473 read_cpu_time(cp_time); 474 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 475 T2J(cp_time[CP_USER]), 476 T2J(cp_time[CP_NICE]), 477 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 478 T2J(cp_time[CP_IDLE])); 479 CPU_FOREACH(i) { 480 pcpu = pcpu_find(i); 481 cp = pcpu->pc_cp_time; 482 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 483 T2J(cp[CP_USER]), 484 T2J(cp[CP_NICE]), 485 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 486 T2J(cp[CP_IDLE])); 487 } 488 sbuf_printf(sb, 489 "disk 0 0 0 0\n" 490 "page %u %u\n" 491 "swap %u %u\n" 492 "intr %u\n" 493 "ctxt %u\n" 494 "btime %lld\n", 495 cnt.v_vnodepgsin, 496 cnt.v_vnodepgsout, 497 cnt.v_swappgsin, 498 cnt.v_swappgsout, 499 cnt.v_intr, 500 cnt.v_swtch, 501 (long long)boottime.tv_sec); 502 return (0); 503} 504 505/* 506 * Filler function for proc/uptime 507 */ 508static int 509linprocfs_douptime(PFS_FILL_ARGS) 510{ 511 long cp_time[CPUSTATES]; 512 struct timeval tv; 513 514 getmicrouptime(&tv); 515 read_cpu_time(cp_time); 516 sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n", 517 (long long)tv.tv_sec, tv.tv_usec / 10000, 518 T2S(cp_time[CP_IDLE] / mp_ncpus), 519 T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100); 520 return (0); 521} 522 523/* 524 * Get OS build date 525 */ 526static void 527linprocfs_osbuild(struct thread *td, struct sbuf *sb) 528{ 529#if 0 530 char osbuild[256]; 531 char *cp1, *cp2; 532 533 strncpy(osbuild, version, 256); 534 osbuild[255] = '\0'; 535 cp1 = strstr(osbuild, "\n"); 536 cp2 = strstr(osbuild, ":"); 537 if (cp1 && cp2) { 538 *cp1 = *cp2 = '\0'; 539 cp1 = strstr(osbuild, "#"); 540 } else 541 cp1 = NULL; 542 if (cp1) 543 sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 544 else 545#endif 546 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 547} 548 549/* 550 * Get OS builder 551 */ 552static void 553linprocfs_osbuilder(struct thread *td, struct sbuf *sb) 554{ 555#if 0 556 char builder[256]; 557 char *cp; 558 559 cp = strstr(version, "\n "); 560 if (cp) { 561 strncpy(builder, cp + 5, 256); 562 builder[255] = '\0'; 563 cp = strstr(builder, ":"); 564 if (cp) 565 *cp = '\0'; 566 } 567 if (cp) 568 sbuf_cat(sb, builder); 569 else 570#endif 571 sbuf_cat(sb, "des@freebsd.org"); 572} 573 574/* 575 * Filler function for proc/version 576 */ 577static int 578linprocfs_doversion(PFS_FILL_ARGS) 579{ 580 char osname[LINUX_MAX_UTSNAME]; 581 char osrelease[LINUX_MAX_UTSNAME]; 582 583 linux_get_osname(td, osname); 584 linux_get_osrelease(td, osrelease); 585 sbuf_printf(sb, "%s version %s (", osname, osrelease); 586 linprocfs_osbuilder(td, sb); 587 sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 588 linprocfs_osbuild(td, sb); 589 sbuf_cat(sb, "\n"); 590 591 return (0); 592} 593 594/* 595 * Filler function for proc/loadavg 596 */ 597static int 598linprocfs_doloadavg(PFS_FILL_ARGS) 599{ 600 601 sbuf_printf(sb, 602 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 603 (int)(averunnable.ldavg[0] / averunnable.fscale), 604 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 605 (int)(averunnable.ldavg[1] / averunnable.fscale), 606 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 607 (int)(averunnable.ldavg[2] / averunnable.fscale), 608 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 609 1, /* number of running tasks */ 610 nprocs, /* number of tasks */ 611 lastpid /* the last pid */ 612 ); 613 return (0); 614} 615 616/* 617 * Filler function for proc/pid/stat 618 */ 619static int 620linprocfs_doprocstat(PFS_FILL_ARGS) 621{ 622 struct kinfo_proc kp; 623 char state; 624 static int ratelimit = 0; 625 vm_offset_t startcode, startdata; 626 627 PROC_LOCK(p); 628 fill_kinfo_proc(p, &kp); 629 if (p->p_vmspace) { 630 startcode = (vm_offset_t)p->p_vmspace->vm_taddr; 631 startdata = (vm_offset_t)p->p_vmspace->vm_daddr; 632 } else { 633 startcode = 0; 634 startdata = 0; 635 }; 636 sbuf_printf(sb, "%d", p->p_pid); 637#define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 638 PS_ADD("comm", "(%s)", p->p_comm); 639 if (kp.ki_stat > sizeof(linux_state)) { 640 state = 'R'; 641 642 if (ratelimit == 0) { 643 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 644 kp.ki_stat, sizeof(linux_state)); 645 ++ratelimit; 646 } 647 } else 648 state = linux_state[kp.ki_stat - 1]; 649 PS_ADD("state", "%c", state); 650 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 651 PS_ADD("pgrp", "%d", p->p_pgid); 652 PS_ADD("session", "%d", p->p_session->s_sid); 653 PROC_UNLOCK(p); 654 PS_ADD("tty", "%d", kp.ki_tdev); 655 PS_ADD("tpgid", "%d", kp.ki_tpgid); 656 PS_ADD("flags", "%u", 0); /* XXX */ 657 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 658 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 659 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 660 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 661 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime)); 662 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime)); 663 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime)); 664 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime)); 665 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 666 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 667 PS_ADD("0", "%d", 0); /* removed field */ 668 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 669 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime)); 670 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 671 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 672 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 673 PS_ADD("startcode", "%ju", (uintmax_t)startcode); 674 PS_ADD("endcode", "%ju", (uintmax_t)startdata); 675 PS_ADD("startstack", "%u", 0); /* XXX */ 676 PS_ADD("kstkesp", "%u", 0); /* XXX */ 677 PS_ADD("kstkeip", "%u", 0); /* XXX */ 678 PS_ADD("signal", "%u", 0); /* XXX */ 679 PS_ADD("blocked", "%u", 0); /* XXX */ 680 PS_ADD("sigignore", "%u", 0); /* XXX */ 681 PS_ADD("sigcatch", "%u", 0); /* XXX */ 682 PS_ADD("wchan", "%u", 0); /* XXX */ 683 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 684 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 685 PS_ADD("exitsignal", "%d", 0); /* XXX */ 686 PS_ADD("processor", "%u", kp.ki_lastcpu); 687 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 688 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 689#undef PS_ADD 690 sbuf_putc(sb, '\n'); 691 692 return (0); 693} 694 695/* 696 * Filler function for proc/pid/statm 697 */ 698static int 699linprocfs_doprocstatm(PFS_FILL_ARGS) 700{ 701 struct kinfo_proc kp; 702 segsz_t lsize; 703 704 PROC_LOCK(p); 705 fill_kinfo_proc(p, &kp); 706 PROC_UNLOCK(p); 707 708 /* 709 * See comments in linprocfs_doprocstatus() regarding the 710 * computation of lsize. 711 */ 712 /* size resident share trs drs lrs dt */ 713 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 714 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 715 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 716 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 717 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 718 lsize = B2P(kp.ki_size) - kp.ki_dsize - 719 kp.ki_ssize - kp.ki_tsize - 1; 720 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 721 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 722 723 return (0); 724} 725 726/* 727 * Filler function for proc/pid/status 728 */ 729static int 730linprocfs_doprocstatus(PFS_FILL_ARGS) 731{ 732 struct kinfo_proc kp; 733 char *state; 734 segsz_t lsize; 735 struct thread *td2; 736 struct sigacts *ps; 737 int i; 738 739 PROC_LOCK(p); 740 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 741 742 if (P_SHOULDSTOP(p)) { 743 state = "T (stopped)"; 744 } else { 745 switch(p->p_state) { 746 case PRS_NEW: 747 state = "I (idle)"; 748 break; 749 case PRS_NORMAL: 750 if (p->p_flag & P_WEXIT) { 751 state = "X (exiting)"; 752 break; 753 } 754 switch(td2->td_state) { 755 case TDS_INHIBITED: 756 state = "S (sleeping)"; 757 break; 758 case TDS_RUNQ: 759 case TDS_RUNNING: 760 state = "R (running)"; 761 break; 762 default: 763 state = "? (unknown)"; 764 break; 765 } 766 break; 767 case PRS_ZOMBIE: 768 state = "Z (zombie)"; 769 break; 770 default: 771 state = "? (unknown)"; 772 break; 773 } 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 */ 864static int 865linprocfs_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 */ 880static int 881linprocfs_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 898static int 899linprocfs_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) \ 915do { \ 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 (SV_PROC_FLAG(p, 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 1015done: 1016 free(env_vector, M_TEMP); 1017#ifdef COMPAT_FREEBSD32 1018 free(env_vector32, M_TEMP); 1019#endif 1020 return (ret); 1021} 1022 1023static void 1024ps_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 1031static void 1032ps_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 */ 1042static int 1043linprocfs_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 1053 /* 1054 * Mimic linux behavior and pass only processes with usermode 1055 * address space as valid. Return zero silently otherwize. 1056 */ 1057 if (p->p_vmspace == &vmspace0) { 1058 PROC_UNLOCK(p); 1059 return (0); 1060 } 1061 if (p->p_args != NULL) { 1062 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 1063 PROC_UNLOCK(p); 1064 return (0); 1065 } 1066 PROC_UNLOCK(p); 1067 1068 ret = linprocfs_doargv(td, p, sb, ps_string_argv); 1069 return (ret); 1070} 1071 1072/* 1073 * Filler function for proc/pid/environ 1074 */ 1075static int 1076linprocfs_doprocenviron(PFS_FILL_ARGS) 1077{ 1078 int ret; 1079 1080 PROC_LOCK(p); 1081 if ((ret = p_cansee(td, p)) != 0) { 1082 PROC_UNLOCK(p); 1083 return (ret); 1084 } 1085 1086 /* 1087 * Mimic linux behavior and pass only processes with usermode 1088 * address space as valid. Return zero silently otherwize. 1089 */ 1090 if (p->p_vmspace == &vmspace0) { 1091 PROC_UNLOCK(p); 1092 return (0); 1093 } 1094 PROC_UNLOCK(p); 1095 1096 ret = linprocfs_doargv(td, p, sb, ps_string_env); 1097 return (ret); 1098} 1099 1100/* 1101 * Filler function for proc/pid/maps 1102 */ 1103static int 1104linprocfs_doprocmaps(PFS_FILL_ARGS) 1105{ 1106 struct vmspace *vm; 1107 vm_map_t map; 1108 vm_map_entry_t entry, tmp_entry; 1109 vm_object_t obj, tobj, lobj; 1110 vm_offset_t e_start, e_end; 1111 vm_ooffset_t off = 0; 1112 vm_prot_t e_prot; 1113 unsigned int last_timestamp; 1114 char *name = "", *freename = NULL; 1115 ino_t ino; 1116 int ref_count, shadow_count, flags; 1117 int error; 1118 struct vnode *vp; 1119 struct vattr vat; 1120 int locked; 1121 1122 PROC_LOCK(p); 1123 error = p_candebug(td, p); 1124 PROC_UNLOCK(p); 1125 if (error) 1126 return (error); 1127 1128 if (uio->uio_rw != UIO_READ) 1129 return (EOPNOTSUPP); 1130 1131 error = 0; 1132 vm = vmspace_acquire_ref(p); 1133 if (vm == NULL) 1134 return (ESRCH); 1135 map = &vm->vm_map; 1136 vm_map_lock_read(map); 1137 for (entry = map->header.next; entry != &map->header; 1138 entry = entry->next) { 1139 name = ""; 1140 freename = NULL; 1141 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 1142 continue; 1143 e_prot = entry->protection; 1144 e_start = entry->start; 1145 e_end = entry->end; 1146 obj = entry->object.vm_object; 1147 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 1148 VM_OBJECT_LOCK(tobj); 1149 if (lobj != obj) 1150 VM_OBJECT_UNLOCK(lobj); 1151 lobj = tobj; 1152 } 1153 last_timestamp = map->timestamp; 1154 vm_map_unlock_read(map); 1155 ino = 0; 1156 if (lobj) { 1157 off = IDX_TO_OFF(lobj->size); 1158 if (lobj->type == OBJT_VNODE) { 1159 vp = lobj->handle; 1160 if (vp) 1161 vref(vp); 1162 } 1163 else 1164 vp = NULL; 1165 if (lobj != obj) 1166 VM_OBJECT_UNLOCK(lobj); 1167 flags = obj->flags; 1168 ref_count = obj->ref_count; 1169 shadow_count = obj->shadow_count; 1170 VM_OBJECT_UNLOCK(obj); 1171 if (vp) { 1172 vn_fullpath(td, vp, &name, &freename); 1173 locked = VFS_LOCK_GIANT(vp->v_mount); 1174 vn_lock(vp, LK_SHARED | LK_RETRY); 1175 VOP_GETATTR(vp, &vat, td->td_ucred); 1176 ino = vat.va_fileid; 1177 vput(vp); 1178 VFS_UNLOCK_GIANT(locked); 1179 } 1180 } else { 1181 flags = 0; 1182 ref_count = 0; 1183 shadow_count = 0; 1184 } 1185 1186 /* 1187 * format: 1188 * start, end, access, offset, major, minor, inode, name. 1189 */ 1190 error = sbuf_printf(sb, 1191 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 1192 (u_long)e_start, (u_long)e_end, 1193 (e_prot & VM_PROT_READ)?"r":"-", 1194 (e_prot & VM_PROT_WRITE)?"w":"-", 1195 (e_prot & VM_PROT_EXECUTE)?"x":"-", 1196 "p", 1197 (u_long)off, 1198 0, 1199 0, 1200 (u_long)ino, 1201 *name ? " " : "", 1202 name 1203 ); 1204 if (freename) 1205 free(freename, M_TEMP); 1206 vm_map_lock_read(map); 1207 if (error == -1) { 1208 error = 0; 1209 break; 1210 } 1211 if (last_timestamp != map->timestamp) { 1212 /* 1213 * Look again for the entry because the map was 1214 * modified while it was unlocked. Specifically, 1215 * the entry may have been clipped, merged, or deleted. 1216 */ 1217 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1218 entry = tmp_entry; 1219 } 1220 } 1221 vm_map_unlock_read(map); 1222 vmspace_free(vm); 1223 1224 return (error); 1225} 1226 1227/* 1228 * Filler function for proc/net/dev 1229 */ 1230static int 1231linprocfs_donetdev(PFS_FILL_ARGS) 1232{ 1233 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1234 struct ifnet *ifp; 1235 1236 sbuf_printf(sb, "%6s|%58s|%s\n" 1237 "%6s|%58s|%58s\n", 1238 "Inter-", " Receive", " Transmit", 1239 " face", 1240 "bytes packets errs drop fifo frame compressed multicast", 1241 "bytes packets errs drop fifo colls carrier compressed"); 1242 1243 CURVNET_SET(TD_TO_VNET(curthread)); 1244 IFNET_RLOCK(); 1245 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1246 linux_ifname(ifp, ifname, sizeof ifname); 1247 sbuf_printf(sb, "%6.6s: ", ifname); 1248 sbuf_printf(sb, "%7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1249 ifp->if_ibytes, /* rx_bytes */ 1250 ifp->if_ipackets, /* rx_packets */ 1251 ifp->if_ierrors, /* rx_errors */ 1252 ifp->if_iqdrops, /* rx_dropped + 1253 * rx_missed_errors */ 1254 0UL, /* rx_fifo_errors */ 1255 0UL, /* rx_length_errors + 1256 * rx_over_errors + 1257 * rx_crc_errors + 1258 * rx_frame_errors */ 1259 0UL, /* rx_compressed */ 1260 ifp->if_imcasts); /* multicast, XXX-BZ rx only? */ 1261 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1262 ifp->if_obytes, /* tx_bytes */ 1263 ifp->if_opackets, /* tx_packets */ 1264 ifp->if_oerrors, /* tx_errors */ 1265 0UL, /* tx_dropped */ 1266 0UL, /* tx_fifo_errors */ 1267 ifp->if_collisions, /* collisions */ 1268 0UL, /* tx_carrier_errors + 1269 * tx_aborted_errors + 1270 * tx_window_errors + 1271 * tx_heartbeat_errors */ 1272 0UL); /* tx_compressed */ 1273 } 1274 IFNET_RUNLOCK(); 1275 CURVNET_RESTORE(); 1276 1277 return (0); 1278} 1279 1280/* 1281 * Filler function for proc/sys/kernel/osrelease 1282 */ 1283static int 1284linprocfs_doosrelease(PFS_FILL_ARGS) 1285{ 1286 char osrelease[LINUX_MAX_UTSNAME]; 1287 1288 linux_get_osrelease(td, osrelease); 1289 sbuf_printf(sb, "%s\n", osrelease); 1290 1291 return (0); 1292} 1293 1294/* 1295 * Filler function for proc/sys/kernel/ostype 1296 */ 1297static int 1298linprocfs_doostype(PFS_FILL_ARGS) 1299{ 1300 char osname[LINUX_MAX_UTSNAME]; 1301 1302 linux_get_osname(td, osname); 1303 sbuf_printf(sb, "%s\n", osname); 1304 1305 return (0); 1306} 1307 1308/* 1309 * Filler function for proc/sys/kernel/version 1310 */ 1311static int 1312linprocfs_doosbuild(PFS_FILL_ARGS) 1313{ 1314 1315 linprocfs_osbuild(td, sb); 1316 sbuf_cat(sb, "\n"); 1317 return (0); 1318} 1319 1320/* 1321 * Filler function for proc/sys/kernel/msgmni 1322 */ 1323static int 1324linprocfs_domsgmni(PFS_FILL_ARGS) 1325{ 1326 1327 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1328 return (0); 1329} 1330 1331/* 1332 * Filler function for proc/sys/kernel/pid_max 1333 */ 1334static int 1335linprocfs_dopid_max(PFS_FILL_ARGS) 1336{ 1337 1338 sbuf_printf(sb, "%i\n", PID_MAX); 1339 return (0); 1340} 1341 1342/* 1343 * Filler function for proc/sys/kernel/sem 1344 */ 1345static int 1346linprocfs_dosem(PFS_FILL_ARGS) 1347{ 1348 1349 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1350 seminfo.semopm, seminfo.semmni); 1351 return (0); 1352} 1353 1354/* 1355 * Filler function for proc/scsi/device_info 1356 */ 1357static int 1358linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1359{ 1360 1361 return (0); 1362} 1363 1364/* 1365 * Filler function for proc/scsi/scsi 1366 */ 1367static int 1368linprocfs_doscsiscsi(PFS_FILL_ARGS) 1369{ 1370 1371 return (0); 1372} 1373 1374extern struct cdevsw *cdevsw[]; 1375 1376/* 1377 * Filler function for proc/devices 1378 */ 1379static int 1380linprocfs_dodevices(PFS_FILL_ARGS) 1381{ 1382 char *char_devices; 1383 sbuf_printf(sb, "Character devices:\n"); 1384 1385 char_devices = linux_get_char_devices(); 1386 sbuf_printf(sb, "%s", char_devices); 1387 linux_free_get_char_devices(char_devices); 1388 1389 sbuf_printf(sb, "\nBlock devices:\n"); 1390 1391 return (0); 1392} 1393 1394/* 1395 * Filler function for proc/cmdline 1396 */ 1397static int 1398linprocfs_docmdline(PFS_FILL_ARGS) 1399{ 1400 1401 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1402 sbuf_printf(sb, " ro root=302\n"); 1403 return (0); 1404} 1405 1406/* 1407 * Filler function for proc/filesystems 1408 */ 1409static int 1410linprocfs_dofilesystems(PFS_FILL_ARGS) 1411{ 1412 struct vfsconf *vfsp; 1413 1414 mtx_lock(&Giant); 1415 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 1416 if (vfsp->vfc_flags & VFCF_SYNTHETIC) 1417 sbuf_printf(sb, "nodev"); 1418 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name); 1419 } 1420 mtx_unlock(&Giant); 1421 return(0); 1422} 1423 1424#if 0 1425/* 1426 * Filler function for proc/modules 1427 */ 1428static int 1429linprocfs_domodules(PFS_FILL_ARGS) 1430{ 1431 struct linker_file *lf; 1432 1433 TAILQ_FOREACH(lf, &linker_files, link) { 1434 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1435 (unsigned long)lf->size, lf->refs); 1436 } 1437 return (0); 1438} 1439#endif 1440 1441/* 1442 * Filler function for proc/pid/fd 1443 */ 1444static int 1445linprocfs_dofdescfs(PFS_FILL_ARGS) 1446{ 1447 1448 if (p == curproc) 1449 sbuf_printf(sb, "/dev/fd"); 1450 else 1451 sbuf_printf(sb, "unknown"); 1452 return (0); 1453} 1454 1455/* 1456 * Constructor 1457 */ 1458static int 1459linprocfs_init(PFS_INIT_ARGS) 1460{ 1461 struct pfs_node *root; 1462 struct pfs_node *dir; 1463 1464 root = pi->pi_root; 1465 1466 /* /proc/... */ 1467 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1468 NULL, NULL, NULL, PFS_RD); 1469 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1470 NULL, NULL, NULL, PFS_RD); 1471 pfs_create_file(root, "devices", &linprocfs_dodevices, 1472 NULL, NULL, NULL, PFS_RD); 1473 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1474 NULL, NULL, NULL, PFS_RD); 1475 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1476 NULL, NULL, NULL, PFS_RD); 1477 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1478 NULL, NULL, NULL, PFS_RD); 1479#if 0 1480 pfs_create_file(root, "modules", &linprocfs_domodules, 1481 NULL, NULL, NULL, PFS_RD); 1482#endif 1483 pfs_create_file(root, "mounts", &linprocfs_domtab, 1484 NULL, NULL, NULL, PFS_RD); 1485 pfs_create_file(root, "mtab", &linprocfs_domtab, 1486 NULL, NULL, NULL, PFS_RD); 1487 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1488 NULL, NULL, NULL, PFS_RD); 1489 pfs_create_link(root, "self", &procfs_docurproc, 1490 NULL, NULL, NULL, 0); 1491 pfs_create_file(root, "stat", &linprocfs_dostat, 1492 NULL, NULL, NULL, PFS_RD); 1493 pfs_create_file(root, "uptime", &linprocfs_douptime, 1494 NULL, NULL, NULL, PFS_RD); 1495 pfs_create_file(root, "version", &linprocfs_doversion, 1496 NULL, NULL, NULL, PFS_RD); 1497 1498 /* /proc/net/... */ 1499 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1500 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1501 NULL, NULL, NULL, PFS_RD); 1502 1503 /* /proc/<pid>/... */ 1504 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1505 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1506 NULL, NULL, NULL, PFS_RD); 1507 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1508 NULL, NULL, NULL, 0); 1509 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1510 NULL, NULL, NULL, PFS_RD); 1511 pfs_create_link(dir, "exe", &procfs_doprocfile, 1512 NULL, &procfs_notsystem, NULL, 0); 1513 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1514 NULL, NULL, NULL, PFS_RD); 1515 pfs_create_file(dir, "mem", &procfs_doprocmem, 1516 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1517 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1518 NULL, NULL, NULL, 0); 1519 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1520 NULL, NULL, NULL, PFS_RD); 1521 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1522 NULL, NULL, NULL, PFS_RD); 1523 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1524 NULL, NULL, NULL, PFS_RD); 1525 pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1526 NULL, NULL, NULL, 0); 1527 1528 /* /proc/scsi/... */ 1529 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1530 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1531 NULL, NULL, NULL, PFS_RD); 1532 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1533 NULL, NULL, NULL, PFS_RD); 1534 1535 /* /proc/sys/... */ 1536 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1537 /* /proc/sys/kernel/... */ 1538 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1539 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1540 NULL, NULL, NULL, PFS_RD); 1541 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1542 NULL, NULL, NULL, PFS_RD); 1543 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1544 NULL, NULL, NULL, PFS_RD); 1545 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1546 NULL, NULL, NULL, PFS_RD); 1547 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1548 NULL, NULL, NULL, PFS_RD); 1549 pfs_create_file(dir, "sem", &linprocfs_dosem, 1550 NULL, NULL, NULL, PFS_RD); 1551 1552 return (0); 1553} 1554 1555/* 1556 * Destructor 1557 */ 1558static int 1559linprocfs_uninit(PFS_INIT_ARGS) 1560{ 1561 1562 /* nothing to do, pseudofs will GC */ 1563 return (0); 1564} 1565 1566PSEUDOFS(linprocfs, 1); 1567MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1568MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1569MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1570MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1571