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