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