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 static char vdso_str[] = " [vdso]"; 982 static char stack_str[] = " [stack]"; 983 984 /* 985 * Filler function for proc/pid/maps 986 */ 987 static int 988 linprocfs_doprocmaps(PFS_FILL_ARGS) 989 { 990 struct vmspace *vm; 991 vm_map_t map; 992 vm_map_entry_t entry, tmp_entry; 993 vm_object_t obj, tobj, lobj; 994 vm_offset_t e_start, e_end; 995 vm_ooffset_t off = 0; 996 vm_prot_t e_prot; 997 unsigned int last_timestamp; 998 char *name = "", *freename = NULL; 999 const char *l_map_str; 1000 ino_t ino; 1001 int ref_count, shadow_count, flags; 1002 int error; 1003 struct vnode *vp; 1004 struct vattr vat; 1005 1006 PROC_LOCK(p); 1007 error = p_candebug(td, p); 1008 PROC_UNLOCK(p); 1009 if (error) 1010 return (error); 1011 1012 if (uio->uio_rw != UIO_READ) 1013 return (EOPNOTSUPP); 1014 1015 error = 0; 1016 vm = vmspace_acquire_ref(p); 1017 if (vm == NULL) 1018 return (ESRCH); 1019 1020 if (SV_CURPROC_FLAG(SV_LP64)) 1021 l_map_str = l64_map_str; 1022 else 1023 l_map_str = l32_map_str; 1024 map = &vm->vm_map; 1025 vm_map_lock_read(map); 1026 for (entry = map->header.next; entry != &map->header; 1027 entry = entry->next) { 1028 name = ""; 1029 freename = NULL; 1030 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 1031 continue; 1032 e_prot = entry->protection; 1033 e_start = entry->start; 1034 e_end = entry->end; 1035 obj = entry->object.vm_object; 1036 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 1037 VM_OBJECT_RLOCK(tobj); 1038 if (lobj != obj) 1039 VM_OBJECT_RUNLOCK(lobj); 1040 lobj = tobj; 1041 } 1042 last_timestamp = map->timestamp; 1043 vm_map_unlock_read(map); 1044 ino = 0; 1045 if (lobj) { 1046 off = IDX_TO_OFF(lobj->size); 1047 if (lobj->type == OBJT_VNODE) { 1048 vp = lobj->handle; 1049 if (vp) 1050 vref(vp); 1051 } 1052 else 1053 vp = NULL; 1054 if (lobj != obj) 1055 VM_OBJECT_RUNLOCK(lobj); 1056 flags = obj->flags; 1057 ref_count = obj->ref_count; 1058 shadow_count = obj->shadow_count; 1059 VM_OBJECT_RUNLOCK(obj); 1060 if (vp) { 1061 vn_fullpath(td, vp, &name, &freename); 1062 vn_lock(vp, LK_SHARED | LK_RETRY); 1063 VOP_GETATTR(vp, &vat, td->td_ucred); 1064 ino = vat.va_fileid; 1065 vput(vp); 1066 } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) { 1067 if (e_start == p->p_sysent->sv_shared_page_base) 1068 name = vdso_str; 1069 if (e_end == p->p_sysent->sv_usrstack) 1070 name = stack_str; 1071 } 1072 } else { 1073 flags = 0; 1074 ref_count = 0; 1075 shadow_count = 0; 1076 } 1077 1078 /* 1079 * format: 1080 * start, end, access, offset, major, minor, inode, name. 1081 */ 1082 error = sbuf_printf(sb, l_map_str, 1083 (u_long)e_start, (u_long)e_end, 1084 (e_prot & VM_PROT_READ)?"r":"-", 1085 (e_prot & VM_PROT_WRITE)?"w":"-", 1086 (e_prot & VM_PROT_EXECUTE)?"x":"-", 1087 "p", 1088 (u_long)off, 1089 0, 1090 0, 1091 (u_long)ino, 1092 *name ? " " : "", 1093 name 1094 ); 1095 if (freename) 1096 free(freename, M_TEMP); 1097 vm_map_lock_read(map); 1098 if (error == -1) { 1099 error = 0; 1100 break; 1101 } 1102 if (last_timestamp != map->timestamp) { 1103 /* 1104 * Look again for the entry because the map was 1105 * modified while it was unlocked. Specifically, 1106 * the entry may have been clipped, merged, or deleted. 1107 */ 1108 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 1109 entry = tmp_entry; 1110 } 1111 } 1112 vm_map_unlock_read(map); 1113 vmspace_free(vm); 1114 1115 return (error); 1116 } 1117 1118 /* 1119 * Criteria for interface name translation 1120 */ 1121 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER) 1122 1123 static int 1124 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen) 1125 { 1126 struct ifnet *ifscan; 1127 int ethno; 1128 1129 IFNET_RLOCK_ASSERT(); 1130 1131 /* Short-circuit non ethernet interfaces */ 1132 if (!IFP_IS_ETH(ifp)) 1133 return (strlcpy(buffer, ifp->if_xname, buflen)); 1134 1135 /* Determine the (relative) unit number for ethernet interfaces */ 1136 ethno = 0; 1137 TAILQ_FOREACH(ifscan, &V_ifnet, if_link) { 1138 if (ifscan == ifp) 1139 return (snprintf(buffer, buflen, "eth%d", ethno)); 1140 if (IFP_IS_ETH(ifscan)) 1141 ethno++; 1142 } 1143 1144 return (0); 1145 } 1146 1147 /* 1148 * Filler function for proc/net/dev 1149 */ 1150 static int 1151 linprocfs_donetdev(PFS_FILL_ARGS) 1152 { 1153 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1154 struct ifnet *ifp; 1155 1156 sbuf_printf(sb, "%6s|%58s|%s\n" 1157 "%6s|%58s|%58s\n", 1158 "Inter-", " Receive", " Transmit", 1159 " face", 1160 "bytes packets errs drop fifo frame compressed multicast", 1161 "bytes packets errs drop fifo colls carrier compressed"); 1162 1163 CURVNET_SET(TD_TO_VNET(curthread)); 1164 IFNET_RLOCK(); 1165 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1166 linux_ifname(ifp, ifname, sizeof ifname); 1167 sbuf_printf(sb, "%6.6s: ", ifname); 1168 sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ", 1169 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES), 1170 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS), 1171 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS), 1172 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS), 1173 /* rx_missed_errors */ 1174 0UL, /* rx_fifo_errors */ 1175 0UL, /* rx_length_errors + 1176 * rx_over_errors + 1177 * rx_crc_errors + 1178 * rx_frame_errors */ 1179 0UL, /* rx_compressed */ 1180 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS)); 1181 /* XXX-BZ rx only? */ 1182 sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n", 1183 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES), 1184 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS), 1185 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS), 1186 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS), 1187 0UL, /* tx_fifo_errors */ 1188 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS), 1189 0UL, /* tx_carrier_errors + 1190 * tx_aborted_errors + 1191 * tx_window_errors + 1192 * tx_heartbeat_errors*/ 1193 0UL); /* tx_compressed */ 1194 } 1195 IFNET_RUNLOCK(); 1196 CURVNET_RESTORE(); 1197 1198 return (0); 1199 } 1200 1201 /* 1202 * Filler function for proc/sys/kernel/osrelease 1203 */ 1204 static int 1205 linprocfs_doosrelease(PFS_FILL_ARGS) 1206 { 1207 char osrelease[LINUX_MAX_UTSNAME]; 1208 1209 linux_get_osrelease(td, osrelease); 1210 sbuf_printf(sb, "%s\n", osrelease); 1211 1212 return (0); 1213 } 1214 1215 /* 1216 * Filler function for proc/sys/kernel/ostype 1217 */ 1218 static int 1219 linprocfs_doostype(PFS_FILL_ARGS) 1220 { 1221 char osname[LINUX_MAX_UTSNAME]; 1222 1223 linux_get_osname(td, osname); 1224 sbuf_printf(sb, "%s\n", osname); 1225 1226 return (0); 1227 } 1228 1229 /* 1230 * Filler function for proc/sys/kernel/version 1231 */ 1232 static int 1233 linprocfs_doosbuild(PFS_FILL_ARGS) 1234 { 1235 1236 linprocfs_osbuild(td, sb); 1237 sbuf_cat(sb, "\n"); 1238 return (0); 1239 } 1240 1241 /* 1242 * Filler function for proc/sys/kernel/msgmni 1243 */ 1244 static int 1245 linprocfs_domsgmni(PFS_FILL_ARGS) 1246 { 1247 1248 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1249 return (0); 1250 } 1251 1252 /* 1253 * Filler function for proc/sys/kernel/pid_max 1254 */ 1255 static int 1256 linprocfs_dopid_max(PFS_FILL_ARGS) 1257 { 1258 1259 sbuf_printf(sb, "%i\n", PID_MAX); 1260 return (0); 1261 } 1262 1263 /* 1264 * Filler function for proc/sys/kernel/sem 1265 */ 1266 static int 1267 linprocfs_dosem(PFS_FILL_ARGS) 1268 { 1269 1270 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1271 seminfo.semopm, seminfo.semmni); 1272 return (0); 1273 } 1274 1275 /* 1276 * Filler function for proc/scsi/device_info 1277 */ 1278 static int 1279 linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1280 { 1281 1282 return (0); 1283 } 1284 1285 /* 1286 * Filler function for proc/scsi/scsi 1287 */ 1288 static int 1289 linprocfs_doscsiscsi(PFS_FILL_ARGS) 1290 { 1291 1292 return (0); 1293 } 1294 1295 /* 1296 * Filler function for proc/devices 1297 */ 1298 static int 1299 linprocfs_dodevices(PFS_FILL_ARGS) 1300 { 1301 char *char_devices; 1302 sbuf_printf(sb, "Character devices:\n"); 1303 1304 char_devices = linux_get_char_devices(); 1305 sbuf_printf(sb, "%s", char_devices); 1306 linux_free_get_char_devices(char_devices); 1307 1308 sbuf_printf(sb, "\nBlock devices:\n"); 1309 1310 return (0); 1311 } 1312 1313 /* 1314 * Filler function for proc/cmdline 1315 */ 1316 static int 1317 linprocfs_docmdline(PFS_FILL_ARGS) 1318 { 1319 1320 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1321 sbuf_printf(sb, " ro root=302\n"); 1322 return (0); 1323 } 1324 1325 /* 1326 * Filler function for proc/filesystems 1327 */ 1328 static int 1329 linprocfs_dofilesystems(PFS_FILL_ARGS) 1330 { 1331 struct vfsconf *vfsp; 1332 1333 mtx_lock(&Giant); 1334 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) { 1335 if (vfsp->vfc_flags & VFCF_SYNTHETIC) 1336 sbuf_printf(sb, "nodev"); 1337 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name); 1338 } 1339 mtx_unlock(&Giant); 1340 return(0); 1341 } 1342 1343 #if 0 1344 /* 1345 * Filler function for proc/modules 1346 */ 1347 static int 1348 linprocfs_domodules(PFS_FILL_ARGS) 1349 { 1350 struct linker_file *lf; 1351 1352 TAILQ_FOREACH(lf, &linker_files, link) { 1353 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1354 (unsigned long)lf->size, lf->refs); 1355 } 1356 return (0); 1357 } 1358 #endif 1359 1360 /* 1361 * Filler function for proc/pid/fd 1362 */ 1363 static int 1364 linprocfs_dofdescfs(PFS_FILL_ARGS) 1365 { 1366 1367 if (p == curproc) 1368 sbuf_printf(sb, "/dev/fd"); 1369 else 1370 sbuf_printf(sb, "unknown"); 1371 return (0); 1372 } 1373 1374 1375 /* 1376 * Filler function for proc/sys/kernel/random/uuid 1377 */ 1378 static int 1379 linprocfs_douuid(PFS_FILL_ARGS) 1380 { 1381 struct uuid uuid; 1382 1383 kern_uuidgen(&uuid, 1); 1384 sbuf_printf_uuid(sb, &uuid); 1385 sbuf_printf(sb, "\n"); 1386 return(0); 1387 } 1388 1389 /* 1390 * Filler function for proc/pid/auxv 1391 */ 1392 static int 1393 linprocfs_doauxv(PFS_FILL_ARGS) 1394 { 1395 struct sbuf *asb; 1396 off_t buflen, resid; 1397 int error; 1398 1399 /* 1400 * Mimic linux behavior and pass only processes with usermode 1401 * address space as valid. Return zero silently otherwise. 1402 */ 1403 if (p->p_vmspace == &vmspace0) 1404 return (0); 1405 1406 if (uio->uio_resid == 0) 1407 return (0); 1408 if (uio->uio_offset < 0 || uio->uio_resid < 0) 1409 return (EINVAL); 1410 1411 asb = sbuf_new_auto(); 1412 if (asb == NULL) 1413 return (ENOMEM); 1414 error = proc_getauxv(td, p, asb); 1415 if (error == 0) 1416 error = sbuf_finish(asb); 1417 1418 resid = sbuf_len(asb) - uio->uio_offset; 1419 if (resid > uio->uio_resid) 1420 buflen = uio->uio_resid; 1421 else 1422 buflen = resid; 1423 if (buflen > IOSIZE_MAX) 1424 return (EINVAL); 1425 if (buflen > MAXPHYS) 1426 buflen = MAXPHYS; 1427 if (resid <= 0) 1428 return (0); 1429 1430 if (error == 0) 1431 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio); 1432 sbuf_delete(asb); 1433 return (error); 1434 } 1435 1436 /* 1437 * Constructor 1438 */ 1439 static int 1440 linprocfs_init(PFS_INIT_ARGS) 1441 { 1442 struct pfs_node *root; 1443 struct pfs_node *dir; 1444 1445 root = pi->pi_root; 1446 1447 /* /proc/... */ 1448 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1449 NULL, NULL, NULL, PFS_RD); 1450 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1451 NULL, NULL, NULL, PFS_RD); 1452 pfs_create_file(root, "devices", &linprocfs_dodevices, 1453 NULL, NULL, NULL, PFS_RD); 1454 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems, 1455 NULL, NULL, NULL, PFS_RD); 1456 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1457 NULL, NULL, NULL, PFS_RD); 1458 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1459 NULL, NULL, NULL, PFS_RD); 1460 #if 0 1461 pfs_create_file(root, "modules", &linprocfs_domodules, 1462 NULL, NULL, NULL, PFS_RD); 1463 #endif 1464 pfs_create_file(root, "mounts", &linprocfs_domtab, 1465 NULL, NULL, NULL, PFS_RD); 1466 pfs_create_file(root, "mtab", &linprocfs_domtab, 1467 NULL, NULL, NULL, PFS_RD); 1468 pfs_create_file(root, "partitions", &linprocfs_dopartitions, 1469 NULL, NULL, NULL, PFS_RD); 1470 pfs_create_link(root, "self", &procfs_docurproc, 1471 NULL, NULL, NULL, 0); 1472 pfs_create_file(root, "stat", &linprocfs_dostat, 1473 NULL, NULL, NULL, PFS_RD); 1474 pfs_create_file(root, "swaps", &linprocfs_doswaps, 1475 NULL, NULL, NULL, PFS_RD); 1476 pfs_create_file(root, "uptime", &linprocfs_douptime, 1477 NULL, NULL, NULL, PFS_RD); 1478 pfs_create_file(root, "version", &linprocfs_doversion, 1479 NULL, NULL, NULL, PFS_RD); 1480 1481 /* /proc/net/... */ 1482 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1483 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1484 NULL, NULL, NULL, PFS_RD); 1485 1486 /* /proc/<pid>/... */ 1487 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1488 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1489 NULL, NULL, NULL, PFS_RD); 1490 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1491 NULL, NULL, NULL, 0); 1492 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1493 NULL, NULL, NULL, PFS_RD); 1494 pfs_create_link(dir, "exe", &procfs_doprocfile, 1495 NULL, &procfs_notsystem, NULL, 0); 1496 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1497 NULL, NULL, NULL, PFS_RD); 1498 pfs_create_file(dir, "mem", &procfs_doprocmem, 1499 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1500 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1501 NULL, NULL, NULL, 0); 1502 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1503 NULL, NULL, NULL, PFS_RD); 1504 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1505 NULL, NULL, NULL, PFS_RD); 1506 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1507 NULL, NULL, NULL, PFS_RD); 1508 pfs_create_link(dir, "fd", &linprocfs_dofdescfs, 1509 NULL, NULL, NULL, 0); 1510 pfs_create_file(dir, "auxv", &linprocfs_doauxv, 1511 NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD); 1512 1513 /* /proc/scsi/... */ 1514 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1515 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1516 NULL, NULL, NULL, PFS_RD); 1517 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1518 NULL, NULL, NULL, PFS_RD); 1519 1520 /* /proc/sys/... */ 1521 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1522 /* /proc/sys/kernel/... */ 1523 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1524 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1525 NULL, NULL, NULL, PFS_RD); 1526 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1527 NULL, NULL, NULL, PFS_RD); 1528 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1529 NULL, NULL, NULL, PFS_RD); 1530 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1531 NULL, NULL, NULL, PFS_RD); 1532 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1533 NULL, NULL, NULL, PFS_RD); 1534 pfs_create_file(dir, "sem", &linprocfs_dosem, 1535 NULL, NULL, NULL, PFS_RD); 1536 1537 /* /proc/sys/kernel/random/... */ 1538 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0); 1539 pfs_create_file(dir, "uuid", &linprocfs_douuid, 1540 NULL, NULL, NULL, PFS_RD); 1541 1542 return (0); 1543 } 1544 1545 /* 1546 * Destructor 1547 */ 1548 static int 1549 linprocfs_uninit(PFS_INIT_ARGS) 1550 { 1551 1552 /* nothing to do, pseudofs will GC */ 1553 return (0); 1554 } 1555 1556 PSEUDOFS(linprocfs, 1, 0); 1557 #if defined(__amd64__) 1558 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1); 1559 #else 1560 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1561 #endif 1562 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1563 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1564 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1565