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