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