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