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