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 "opt_compat.h" 43 44 #include <sys/cdefs.h> 45 __FBSDID("$FreeBSD$"); 46 47 #include <sys/param.h> 48 #include <sys/queue.h> 49 #include <sys/blist.h> 50 #include <sys/conf.h> 51 #include <sys/exec.h> 52 #include <sys/fcntl.h> 53 #include <sys/filedesc.h> 54 #include <sys/jail.h> 55 #include <sys/kernel.h> 56 #include <sys/linker.h> 57 #include <sys/lock.h> 58 #include <sys/malloc.h> 59 #include <sys/mount.h> 60 #include <sys/msg.h> 61 #include <sys/mutex.h> 62 #include <sys/namei.h> 63 #include <sys/proc.h> 64 #include <sys/resourcevar.h> 65 #include <sys/sbuf.h> 66 #include <sys/sem.h> 67 #include <sys/smp.h> 68 #include <sys/socket.h> 69 #include <sys/sysctl.h> 70 #include <sys/systm.h> 71 #include <sys/time.h> 72 #include <sys/tty.h> 73 #include <sys/user.h> 74 #include <sys/vmmeter.h> 75 #include <sys/vnode.h> 76 #include <sys/vimage.h> 77 78 #include <net/if.h> 79 #include <net/vnet.h> 80 81 #include <vm/vm.h> 82 #include <vm/vm_extern.h> 83 #include <vm/pmap.h> 84 #include <vm/vm_map.h> 85 #include <vm/vm_param.h> 86 #include <vm/vm_object.h> 87 #include <vm/swap_pager.h> 88 89 #include <machine/clock.h> 90 91 #if defined(__i386__) || defined(__amd64__) 92 #include <machine/cputypes.h> 93 #include <machine/md_var.h> 94 #endif /* __i386__ || __amd64__ */ 95 96 #ifdef COMPAT_LINUX32 /* XXX */ 97 #include <machine/../linux32/linux.h> 98 #else 99 #include <machine/../linux/linux.h> 100 #endif 101 #include <compat/linux/linux_ioctl.h> 102 #include <compat/linux/linux_mib.h> 103 #include <compat/linux/linux_util.h> 104 #include <fs/pseudofs/pseudofs.h> 105 #include <fs/procfs/procfs.h> 106 107 /* 108 * Various conversion macros 109 */ 110 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */ 111 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */ 112 #define B2K(x) ((x) >> 10) /* bytes to kbytes */ 113 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */ 114 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */ 115 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */ 116 117 /** 118 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state 119 * 120 * The linux procfs state field displays one of the characters RSDZTW to 121 * denote running, sleeping in an interruptible wait, waiting in an 122 * uninterruptible disk sleep, a zombie process, process is being traced 123 * or stopped, or process is paging respectively. 124 * 125 * Our struct kinfo_proc contains the variable ki_stat which contains a 126 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK. 127 * 128 * This character array is used with ki_stati-1 as an index and tries to 129 * map our states to suitable linux states. 130 */ 131 static char linux_state[] = "RRSTZDD"; 132 133 /* 134 * Filler function for proc/meminfo 135 */ 136 static int 137 linprocfs_domeminfo(PFS_FILL_ARGS) 138 { 139 unsigned long memtotal; /* total memory in bytes */ 140 unsigned long memused; /* used memory in bytes */ 141 unsigned long memfree; /* free memory in bytes */ 142 unsigned long memshared; /* shared memory ??? */ 143 unsigned long buffers, cached; /* buffer / cache memory ??? */ 144 unsigned long long swaptotal; /* total swap space in bytes */ 145 unsigned long long swapused; /* used swap space in bytes */ 146 unsigned long long swapfree; /* free swap space in bytes */ 147 vm_object_t object; 148 int i, j; 149 150 memtotal = physmem * PAGE_SIZE; 151 /* 152 * The correct thing here would be: 153 * 154 memfree = cnt.v_free_count * PAGE_SIZE; 155 memused = memtotal - memfree; 156 * 157 * but it might mislead linux binaries into thinking there 158 * is very little memory left, so we cheat and tell them that 159 * all memory that isn't wired down is free. 160 */ 161 memused = cnt.v_wire_count * PAGE_SIZE; 162 memfree = memtotal - memused; 163 swap_pager_status(&i, &j); 164 swaptotal = (unsigned long long)i * PAGE_SIZE; 165 swapused = (unsigned long long)j * PAGE_SIZE; 166 swapfree = swaptotal - swapused; 167 memshared = 0; 168 mtx_lock(&vm_object_list_mtx); 169 TAILQ_FOREACH(object, &vm_object_list, object_list) 170 if (object->shadow_count > 1) 171 memshared += object->resident_page_count; 172 mtx_unlock(&vm_object_list_mtx); 173 memshared *= PAGE_SIZE; 174 /* 175 * We'd love to be able to write: 176 * 177 buffers = bufspace; 178 * 179 * but bufspace is internal to vfs_bio.c and we don't feel 180 * like unstaticizing it just for linprocfs's sake. 181 */ 182 buffers = 0; 183 cached = cnt.v_cache_count * PAGE_SIZE; 184 185 sbuf_printf(sb, 186 " total: used: free: shared: buffers: cached:\n" 187 "Mem: %lu %lu %lu %lu %lu %lu\n" 188 "Swap: %llu %llu %llu\n" 189 "MemTotal: %9lu kB\n" 190 "MemFree: %9lu kB\n" 191 "MemShared:%9lu kB\n" 192 "Buffers: %9lu kB\n" 193 "Cached: %9lu kB\n" 194 "SwapTotal:%9llu kB\n" 195 "SwapFree: %9llu kB\n", 196 memtotal, memused, memfree, memshared, buffers, cached, 197 swaptotal, swapused, swapfree, 198 B2K(memtotal), B2K(memfree), 199 B2K(memshared), B2K(buffers), B2K(cached), 200 B2K(swaptotal), B2K(swapfree)); 201 202 return (0); 203 } 204 205 #if defined(__i386__) || defined(__amd64__) 206 /* 207 * Filler function for proc/cpuinfo (i386 & amd64 version) 208 */ 209 static int 210 linprocfs_docpuinfo(PFS_FILL_ARGS) 211 { 212 int hw_model[2]; 213 char model[128]; 214 size_t size; 215 int class, fqmhz, fqkhz; 216 int i; 217 218 /* 219 * We default the flags to include all non-conflicting flags, 220 * and the Intel versions of conflicting flags. 221 */ 222 static char *flags[] = { 223 "fpu", "vme", "de", "pse", "tsc", 224 "msr", "pae", "mce", "cx8", "apic", 225 "sep", "sep", "mtrr", "pge", "mca", 226 "cmov", "pat", "pse36", "pn", "b19", 227 "b20", "b21", "mmxext", "mmx", "fxsr", 228 "xmm", "sse2", "b27", "b28", "b29", 229 "3dnowext", "3dnow" 230 }; 231 232 switch (cpu_class) { 233 #ifdef __i386__ 234 case CPUCLASS_286: 235 class = 2; 236 break; 237 case CPUCLASS_386: 238 class = 3; 239 break; 240 case CPUCLASS_486: 241 class = 4; 242 break; 243 case CPUCLASS_586: 244 class = 5; 245 break; 246 case CPUCLASS_686: 247 class = 6; 248 break; 249 default: 250 class = 0; 251 break; 252 #else /* __amd64__ */ 253 default: 254 class = 15; 255 break; 256 #endif 257 } 258 259 hw_model[0] = CTL_HW; 260 hw_model[1] = HW_MODEL; 261 model[0] = '\0'; 262 size = sizeof(model); 263 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0) 264 strcpy(model, "unknown"); 265 for (i = 0; i < mp_ncpus; ++i) { 266 sbuf_printf(sb, 267 "processor\t: %d\n" 268 "vendor_id\t: %.20s\n" 269 "cpu family\t: %d\n" 270 "model\t\t: %d\n" 271 "model name\t: %s\n" 272 "stepping\t: %d\n", 273 i, cpu_vendor, class, cpu, model, cpu_id & 0xf); 274 /* XXX per-cpu vendor / class / model / id? */ 275 } 276 277 sbuf_cat(sb, "flags\t\t:"); 278 279 #ifdef __i386__ 280 switch (cpu_vendor_id) { 281 case CPU_VENDOR_AMD: 282 if (class < 6) 283 flags[16] = "fcmov"; 284 break; 285 case CPU_VENDOR_CYRIX: 286 flags[24] = "cxmmx"; 287 break; 288 } 289 #endif 290 291 for (i = 0; i < 32; i++) 292 if (cpu_feature & (1 << i)) 293 sbuf_printf(sb, " %s", flags[i]); 294 sbuf_cat(sb, "\n"); 295 if (class >= 5) { 296 fqmhz = (tsc_freq + 4999) / 1000000; 297 fqkhz = ((tsc_freq + 4999) / 10000) % 100; 298 sbuf_printf(sb, 299 "cpu MHz\t\t: %d.%02d\n" 300 "bogomips\t: %d.%02d\n", 301 fqmhz, fqkhz, fqmhz, fqkhz); 302 } 303 304 return (0); 305 } 306 #endif /* __i386__ || __amd64__ */ 307 308 /* 309 * Filler function for proc/mtab 310 * 311 * This file doesn't exist in Linux' procfs, but is included here so 312 * users can symlink /compat/linux/etc/mtab to /proc/mtab 313 */ 314 static int 315 linprocfs_domtab(PFS_FILL_ARGS) 316 { 317 struct nameidata nd; 318 struct mount *mp; 319 const char *lep; 320 char *dlep, *flep, *mntto, *mntfrom, *fstype; 321 size_t lep_len; 322 int error; 323 324 /* resolve symlinks etc. in the emulation tree prefix */ 325 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td); 326 flep = NULL; 327 error = namei(&nd); 328 lep = linux_emul_path; 329 if (error == 0) { 330 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0) 331 lep = dlep; 332 vrele(nd.ni_vp); 333 VFS_UNLOCK_GIANT(NDHASGIANT(&nd)); 334 } 335 lep_len = strlen(lep); 336 337 mtx_lock(&mountlist_mtx); 338 error = 0; 339 TAILQ_FOREACH(mp, &mountlist, mnt_list) { 340 /* determine device name */ 341 mntfrom = mp->mnt_stat.f_mntfromname; 342 343 /* determine mount point */ 344 mntto = mp->mnt_stat.f_mntonname; 345 if (strncmp(mntto, lep, lep_len) == 0 && 346 mntto[lep_len] == '/') 347 mntto += lep_len; 348 349 /* determine fs type */ 350 fstype = mp->mnt_stat.f_fstypename; 351 if (strcmp(fstype, pn->pn_info->pi_name) == 0) 352 mntfrom = fstype = "proc"; 353 else if (strcmp(fstype, "procfs") == 0) 354 continue; 355 356 if (strcmp(fstype, "linsysfs") == 0) { 357 sbuf_printf(sb, "/sys %s sysfs %s", mntto, 358 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 359 } else { 360 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype, 361 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw"); 362 } 363 #define ADD_OPTION(opt, name) \ 364 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name); 365 ADD_OPTION(MNT_SYNCHRONOUS, "sync"); 366 ADD_OPTION(MNT_NOEXEC, "noexec"); 367 ADD_OPTION(MNT_NOSUID, "nosuid"); 368 ADD_OPTION(MNT_UNION, "union"); 369 ADD_OPTION(MNT_ASYNC, "async"); 370 ADD_OPTION(MNT_SUIDDIR, "suiddir"); 371 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow"); 372 ADD_OPTION(MNT_NOATIME, "noatime"); 373 #undef ADD_OPTION 374 /* a real Linux mtab will also show NFS options */ 375 sbuf_printf(sb, " 0 0\n"); 376 } 377 mtx_unlock(&mountlist_mtx); 378 if (flep != NULL) 379 free(flep, M_TEMP); 380 return (error); 381 } 382 383 /* 384 * Filler function for proc/stat 385 */ 386 static int 387 linprocfs_dostat(PFS_FILL_ARGS) 388 { 389 struct pcpu *pcpu; 390 long cp_time[CPUSTATES]; 391 long *cp; 392 int i; 393 394 read_cpu_time(cp_time); 395 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 396 T2J(cp_time[CP_USER]), 397 T2J(cp_time[CP_NICE]), 398 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 399 T2J(cp_time[CP_IDLE])); 400 for (i = 0; i <= mp_maxid; ++i) { 401 if (CPU_ABSENT(i)) 402 continue; 403 pcpu = pcpu_find(i); 404 cp = pcpu->pc_cp_time; 405 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 406 T2J(cp[CP_USER]), 407 T2J(cp[CP_NICE]), 408 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 409 T2J(cp[CP_IDLE])); 410 } 411 sbuf_printf(sb, 412 "disk 0 0 0 0\n" 413 "page %u %u\n" 414 "swap %u %u\n" 415 "intr %u\n" 416 "ctxt %u\n" 417 "btime %lld\n", 418 cnt.v_vnodepgsin, 419 cnt.v_vnodepgsout, 420 cnt.v_swappgsin, 421 cnt.v_swappgsout, 422 cnt.v_intr, 423 cnt.v_swtch, 424 (long long)boottime.tv_sec); 425 return (0); 426 } 427 428 /* 429 * Filler function for proc/uptime 430 */ 431 static int 432 linprocfs_douptime(PFS_FILL_ARGS) 433 { 434 long cp_time[CPUSTATES]; 435 struct timeval tv; 436 437 getmicrouptime(&tv); 438 read_cpu_time(cp_time); 439 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 440 (long long)tv.tv_sec, tv.tv_usec / 10000, 441 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 442 return (0); 443 } 444 445 /* 446 * Get OS build date 447 */ 448 static void 449 linprocfs_osbuild(struct thread *td, struct sbuf *sb) 450 { 451 #if 0 452 char osbuild[256]; 453 char *cp1, *cp2; 454 455 strncpy(osbuild, version, 256); 456 osbuild[255] = '\0'; 457 cp1 = strstr(osbuild, "\n"); 458 cp2 = strstr(osbuild, ":"); 459 if (cp1 && cp2) { 460 *cp1 = *cp2 = '\0'; 461 cp1 = strstr(osbuild, "#"); 462 } else 463 cp1 = NULL; 464 if (cp1) 465 sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 466 else 467 #endif 468 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 469 } 470 471 /* 472 * Get OS builder 473 */ 474 static void 475 linprocfs_osbuilder(struct thread *td, struct sbuf *sb) 476 { 477 #if 0 478 char builder[256]; 479 char *cp; 480 481 cp = strstr(version, "\n "); 482 if (cp) { 483 strncpy(builder, cp + 5, 256); 484 builder[255] = '\0'; 485 cp = strstr(builder, ":"); 486 if (cp) 487 *cp = '\0'; 488 } 489 if (cp) 490 sbuf_cat(sb, builder); 491 else 492 #endif 493 sbuf_cat(sb, "des@freebsd.org"); 494 } 495 496 /* 497 * Filler function for proc/version 498 */ 499 static int 500 linprocfs_doversion(PFS_FILL_ARGS) 501 { 502 char osname[LINUX_MAX_UTSNAME]; 503 char osrelease[LINUX_MAX_UTSNAME]; 504 505 linux_get_osname(td, osname); 506 linux_get_osrelease(td, osrelease); 507 sbuf_printf(sb, "%s version %s (", osname, osrelease); 508 linprocfs_osbuilder(td, sb); 509 sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 510 linprocfs_osbuild(td, sb); 511 sbuf_cat(sb, "\n"); 512 513 return (0); 514 } 515 516 /* 517 * Filler function for proc/loadavg 518 */ 519 static int 520 linprocfs_doloadavg(PFS_FILL_ARGS) 521 { 522 523 sbuf_printf(sb, 524 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 525 (int)(averunnable.ldavg[0] / averunnable.fscale), 526 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 527 (int)(averunnable.ldavg[1] / averunnable.fscale), 528 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 529 (int)(averunnable.ldavg[2] / averunnable.fscale), 530 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 531 1, /* number of running tasks */ 532 nprocs, /* number of tasks */ 533 lastpid /* the last pid */ 534 ); 535 return (0); 536 } 537 538 /* 539 * Filler function for proc/pid/stat 540 */ 541 static int 542 linprocfs_doprocstat(PFS_FILL_ARGS) 543 { 544 struct kinfo_proc kp; 545 char state; 546 static int ratelimit = 0; 547 548 PROC_LOCK(p); 549 fill_kinfo_proc(p, &kp); 550 sbuf_printf(sb, "%d", p->p_pid); 551 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 552 PS_ADD("comm", "(%s)", p->p_comm); 553 if (kp.ki_stat > sizeof(linux_state)) { 554 state = 'R'; 555 556 if (ratelimit == 0) { 557 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 558 kp.ki_stat, sizeof(linux_state)); 559 ++ratelimit; 560 } 561 } else 562 state = linux_state[kp.ki_stat - 1]; 563 PS_ADD("state", "%c", state); 564 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 565 PS_ADD("pgrp", "%d", p->p_pgid); 566 PS_ADD("session", "%d", p->p_session->s_sid); 567 PROC_UNLOCK(p); 568 PS_ADD("tty", "%d", 0); /* XXX */ 569 PS_ADD("tpgid", "%d", kp.ki_tpgid); 570 PS_ADD("flags", "%u", 0); /* XXX */ 571 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 572 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 573 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 574 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 575 PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 576 PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 577 PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 578 PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 579 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 580 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 581 PS_ADD("0", "%d", 0); /* removed field */ 582 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 583 /* XXX: starttime is not right, it is the _same_ for _every_ process. 584 It should be the number of jiffies between system boot and process 585 start. */ 586 PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 587 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 588 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 589 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 590 PS_ADD("startcode", "%u", (unsigned)0); 591 PS_ADD("endcode", "%u", 0); /* XXX */ 592 PS_ADD("startstack", "%u", 0); /* XXX */ 593 PS_ADD("kstkesp", "%u", 0); /* XXX */ 594 PS_ADD("kstkeip", "%u", 0); /* XXX */ 595 PS_ADD("signal", "%u", 0); /* XXX */ 596 PS_ADD("blocked", "%u", 0); /* XXX */ 597 PS_ADD("sigignore", "%u", 0); /* XXX */ 598 PS_ADD("sigcatch", "%u", 0); /* XXX */ 599 PS_ADD("wchan", "%u", 0); /* XXX */ 600 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 601 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 602 PS_ADD("exitsignal", "%d", 0); /* XXX */ 603 PS_ADD("processor", "%u", kp.ki_lastcpu); 604 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 605 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 606 #undef PS_ADD 607 sbuf_putc(sb, '\n'); 608 609 return (0); 610 } 611 612 /* 613 * Filler function for proc/pid/statm 614 */ 615 static int 616 linprocfs_doprocstatm(PFS_FILL_ARGS) 617 { 618 struct kinfo_proc kp; 619 segsz_t lsize; 620 621 PROC_LOCK(p); 622 fill_kinfo_proc(p, &kp); 623 PROC_UNLOCK(p); 624 625 /* 626 * See comments in linprocfs_doprocstatus() regarding the 627 * computation of lsize. 628 */ 629 /* size resident share trs drs lrs dt */ 630 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 631 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 632 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 633 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 634 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 635 lsize = B2P(kp.ki_size) - kp.ki_dsize - 636 kp.ki_ssize - kp.ki_tsize - 1; 637 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 638 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 639 640 return (0); 641 } 642 643 /* 644 * Filler function for proc/pid/status 645 */ 646 static int 647 linprocfs_doprocstatus(PFS_FILL_ARGS) 648 { 649 struct kinfo_proc kp; 650 char *state; 651 segsz_t lsize; 652 struct thread *td2; 653 struct sigacts *ps; 654 int i; 655 656 PROC_LOCK(p); 657 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 658 659 if (P_SHOULDSTOP(p)) { 660 state = "T (stopped)"; 661 } else { 662 PROC_SLOCK(p); 663 switch(p->p_state) { 664 case PRS_NEW: 665 state = "I (idle)"; 666 break; 667 case PRS_NORMAL: 668 if (p->p_flag & P_WEXIT) { 669 state = "X (exiting)"; 670 break; 671 } 672 switch(td2->td_state) { 673 case TDS_INHIBITED: 674 state = "S (sleeping)"; 675 break; 676 case TDS_RUNQ: 677 case TDS_RUNNING: 678 state = "R (running)"; 679 break; 680 default: 681 state = "? (unknown)"; 682 break; 683 } 684 break; 685 case PRS_ZOMBIE: 686 state = "Z (zombie)"; 687 break; 688 default: 689 state = "? (unknown)"; 690 break; 691 } 692 PROC_SUNLOCK(p); 693 } 694 695 fill_kinfo_proc(p, &kp); 696 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 697 sbuf_printf(sb, "State:\t%s\n", state); 698 699 /* 700 * Credentials 701 */ 702 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 703 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 704 p->p_pptr->p_pid : 0); 705 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 706 p->p_ucred->cr_uid, 707 p->p_ucred->cr_svuid, 708 /* FreeBSD doesn't have fsuid */ 709 p->p_ucred->cr_uid); 710 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 711 p->p_ucred->cr_gid, 712 p->p_ucred->cr_svgid, 713 /* FreeBSD doesn't have fsgid */ 714 p->p_ucred->cr_gid); 715 sbuf_cat(sb, "Groups:\t"); 716 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 717 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 718 PROC_UNLOCK(p); 719 sbuf_putc(sb, '\n'); 720 721 /* 722 * Memory 723 * 724 * While our approximation of VmLib may not be accurate (I 725 * don't know of a simple way to verify it, and I'm not sure 726 * it has much meaning anyway), I believe it's good enough. 727 * 728 * The same code that could (I think) accurately compute VmLib 729 * could also compute VmLck, but I don't really care enough to 730 * implement it. Submissions are welcome. 731 */ 732 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 733 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 734 sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 735 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 736 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 737 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 738 lsize = B2P(kp.ki_size) - kp.ki_dsize - 739 kp.ki_ssize - kp.ki_tsize - 1; 740 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 741 742 /* 743 * Signal masks 744 * 745 * We support up to 128 signals, while Linux supports 32, 746 * but we only define 32 (the same 32 as Linux, to boot), so 747 * just show the lower 32 bits of each mask. XXX hack. 748 * 749 * NB: on certain platforms (Sparc at least) Linux actually 750 * supports 64 signals, but this code is a long way from 751 * running on anything but i386, so ignore that for now. 752 */ 753 PROC_LOCK(p); 754 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 755 /* 756 * I can't seem to find out where the signal mask is in 757 * relation to struct proc, so SigBlk is left unimplemented. 758 */ 759 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 760 ps = p->p_sigacts; 761 mtx_lock(&ps->ps_mtx); 762 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 763 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 764 mtx_unlock(&ps->ps_mtx); 765 PROC_UNLOCK(p); 766 767 /* 768 * Linux also prints the capability masks, but we don't have 769 * capabilities yet, and when we do get them they're likely to 770 * be meaningless to Linux programs, so we lie. XXX 771 */ 772 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 773 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 774 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 775 776 return (0); 777 } 778 779 780 /* 781 * Filler function for proc/pid/cwd 782 */ 783 static int 784 linprocfs_doproccwd(PFS_FILL_ARGS) 785 { 786 char *fullpath = "unknown"; 787 char *freepath = NULL; 788 789 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 790 sbuf_printf(sb, "%s", fullpath); 791 if (freepath) 792 free(freepath, M_TEMP); 793 return (0); 794 } 795 796 /* 797 * Filler function for proc/pid/root 798 */ 799 static int 800 linprocfs_doprocroot(PFS_FILL_ARGS) 801 { 802 struct vnode *rvp; 803 char *fullpath = "unknown"; 804 char *freepath = NULL; 805 806 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 807 vn_fullpath(td, rvp, &fullpath, &freepath); 808 sbuf_printf(sb, "%s", fullpath); 809 if (freepath) 810 free(freepath, M_TEMP); 811 return (0); 812 } 813 814 /* 815 * Filler function for proc/pid/cmdline 816 */ 817 static int 818 linprocfs_doproccmdline(PFS_FILL_ARGS) 819 { 820 struct ps_strings pstr; 821 char **ps_argvstr; 822 int error, i; 823 824 /* 825 * If we are using the ps/cmdline caching, use that. Otherwise 826 * revert back to the old way which only implements full cmdline 827 * for the currept process and just p->p_comm for all other 828 * processes. 829 * Note that if the argv is no longer available, we deliberately 830 * don't fall back on p->p_comm or return an error: the authentic 831 * Linux behaviour is to return zero-length in this case. 832 */ 833 834 PROC_LOCK(p); 835 if (p->p_args && p_cansee(td, p) == 0) { 836 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 837 PROC_UNLOCK(p); 838 } else if (p != td->td_proc) { 839 PROC_UNLOCK(p); 840 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 841 } else { 842 PROC_UNLOCK(p); 843 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 844 sizeof(pstr)); 845 if (error) 846 return (error); 847 if (pstr.ps_nargvstr > ARG_MAX) 848 return (E2BIG); 849 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 850 M_TEMP, M_WAITOK); 851 error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 852 pstr.ps_nargvstr * sizeof(char *)); 853 if (error) { 854 free(ps_argvstr, M_TEMP); 855 return (error); 856 } 857 for (i = 0; i < pstr.ps_nargvstr; i++) { 858 sbuf_copyin(sb, ps_argvstr[i], 0); 859 sbuf_printf(sb, "%c", '\0'); 860 } 861 free(ps_argvstr, M_TEMP); 862 } 863 864 return (0); 865 } 866 867 /* 868 * Filler function for proc/pid/environ 869 */ 870 static int 871 linprocfs_doprocenviron(PFS_FILL_ARGS) 872 { 873 874 sbuf_printf(sb, "doprocenviron\n%c", '\0'); 875 return (0); 876 } 877 878 /* 879 * Filler function for proc/pid/maps 880 */ 881 static int 882 linprocfs_doprocmaps(PFS_FILL_ARGS) 883 { 884 struct vmspace *vm; 885 vm_map_t map; 886 vm_map_entry_t entry, tmp_entry; 887 vm_object_t obj, tobj, lobj; 888 vm_offset_t e_start, e_end; 889 vm_ooffset_t off = 0; 890 vm_prot_t e_prot; 891 unsigned int last_timestamp; 892 char *name = "", *freename = NULL; 893 ino_t ino; 894 int ref_count, shadow_count, flags; 895 int error; 896 struct vnode *vp; 897 struct vattr vat; 898 int locked; 899 900 PROC_LOCK(p); 901 error = p_candebug(td, p); 902 PROC_UNLOCK(p); 903 if (error) 904 return (error); 905 906 if (uio->uio_rw != UIO_READ) 907 return (EOPNOTSUPP); 908 909 error = 0; 910 vm = vmspace_acquire_ref(p); 911 if (vm == NULL) 912 return (ESRCH); 913 map = &vm->vm_map; 914 vm_map_lock_read(map); 915 for (entry = map->header.next; entry != &map->header; 916 entry = entry->next) { 917 name = ""; 918 freename = NULL; 919 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 920 continue; 921 e_prot = entry->protection; 922 e_start = entry->start; 923 e_end = entry->end; 924 obj = entry->object.vm_object; 925 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 926 VM_OBJECT_LOCK(tobj); 927 if (lobj != obj) 928 VM_OBJECT_UNLOCK(lobj); 929 lobj = tobj; 930 } 931 last_timestamp = map->timestamp; 932 vm_map_unlock_read(map); 933 ino = 0; 934 if (lobj) { 935 off = IDX_TO_OFF(lobj->size); 936 if (lobj->type == OBJT_VNODE) { 937 vp = lobj->handle; 938 if (vp) 939 vref(vp); 940 } 941 else 942 vp = NULL; 943 if (lobj != obj) 944 VM_OBJECT_UNLOCK(lobj); 945 flags = obj->flags; 946 ref_count = obj->ref_count; 947 shadow_count = obj->shadow_count; 948 VM_OBJECT_UNLOCK(obj); 949 if (vp) { 950 vn_fullpath(td, vp, &name, &freename); 951 locked = VFS_LOCK_GIANT(vp->v_mount); 952 vn_lock(vp, LK_SHARED | LK_RETRY); 953 VOP_GETATTR(vp, &vat, td->td_ucred); 954 ino = vat.va_fileid; 955 vput(vp); 956 VFS_UNLOCK_GIANT(locked); 957 } 958 } else { 959 flags = 0; 960 ref_count = 0; 961 shadow_count = 0; 962 } 963 964 /* 965 * format: 966 * start, end, access, offset, major, minor, inode, name. 967 */ 968 error = sbuf_printf(sb, 969 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 970 (u_long)e_start, (u_long)e_end, 971 (e_prot & VM_PROT_READ)?"r":"-", 972 (e_prot & VM_PROT_WRITE)?"w":"-", 973 (e_prot & VM_PROT_EXECUTE)?"x":"-", 974 "p", 975 (u_long)off, 976 0, 977 0, 978 (u_long)ino, 979 *name ? " " : "", 980 name 981 ); 982 if (freename) 983 free(freename, M_TEMP); 984 vm_map_lock_read(map); 985 if (error == -1) { 986 error = 0; 987 break; 988 } 989 if (last_timestamp != map->timestamp) { 990 /* 991 * Look again for the entry because the map was 992 * modified while it was unlocked. Specifically, 993 * the entry may have been clipped, merged, or deleted. 994 */ 995 vm_map_lookup_entry(map, e_end - 1, &tmp_entry); 996 entry = tmp_entry; 997 } 998 } 999 vm_map_unlock_read(map); 1000 vmspace_free(vm); 1001 1002 return (error); 1003 } 1004 1005 /* 1006 * Filler function for proc/net/dev 1007 */ 1008 static int 1009 linprocfs_donetdev(PFS_FILL_ARGS) 1010 { 1011 INIT_VNET_NET(TD_TO_VNET(curthread)); 1012 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1013 struct ifnet *ifp; 1014 1015 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 1016 "Inter-", " Receive", " Transmit", " face", 1017 "bytes packets errs drop fifo frame compressed", 1018 "bytes packets errs drop fifo frame compressed"); 1019 1020 IFNET_RLOCK(); 1021 TAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1022 linux_ifname(ifp, ifname, sizeof ifname); 1023 sbuf_printf(sb, "%6.6s:", ifname); 1024 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1025 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 1026 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1027 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 1028 } 1029 IFNET_RUNLOCK(); 1030 1031 return (0); 1032 } 1033 1034 /* 1035 * Filler function for proc/sys/kernel/osrelease 1036 */ 1037 static int 1038 linprocfs_doosrelease(PFS_FILL_ARGS) 1039 { 1040 char osrelease[LINUX_MAX_UTSNAME]; 1041 1042 linux_get_osrelease(td, osrelease); 1043 sbuf_printf(sb, "%s\n", osrelease); 1044 1045 return (0); 1046 } 1047 1048 /* 1049 * Filler function for proc/sys/kernel/ostype 1050 */ 1051 static int 1052 linprocfs_doostype(PFS_FILL_ARGS) 1053 { 1054 char osname[LINUX_MAX_UTSNAME]; 1055 1056 linux_get_osname(td, osname); 1057 sbuf_printf(sb, "%s\n", osname); 1058 1059 return (0); 1060 } 1061 1062 /* 1063 * Filler function for proc/sys/kernel/version 1064 */ 1065 static int 1066 linprocfs_doosbuild(PFS_FILL_ARGS) 1067 { 1068 1069 linprocfs_osbuild(td, sb); 1070 sbuf_cat(sb, "\n"); 1071 return (0); 1072 } 1073 1074 /* 1075 * Filler function for proc/sys/kernel/msgmni 1076 */ 1077 static int 1078 linprocfs_domsgmni(PFS_FILL_ARGS) 1079 { 1080 1081 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1082 return (0); 1083 } 1084 1085 /* 1086 * Filler function for proc/sys/kernel/pid_max 1087 */ 1088 static int 1089 linprocfs_dopid_max(PFS_FILL_ARGS) 1090 { 1091 1092 sbuf_printf(sb, "%i\n", PID_MAX); 1093 return (0); 1094 } 1095 1096 /* 1097 * Filler function for proc/sys/kernel/sem 1098 */ 1099 static int 1100 linprocfs_dosem(PFS_FILL_ARGS) 1101 { 1102 1103 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1104 seminfo.semopm, seminfo.semmni); 1105 return (0); 1106 } 1107 1108 /* 1109 * Filler function for proc/scsi/device_info 1110 */ 1111 static int 1112 linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1113 { 1114 1115 return (0); 1116 } 1117 1118 /* 1119 * Filler function for proc/scsi/scsi 1120 */ 1121 static int 1122 linprocfs_doscsiscsi(PFS_FILL_ARGS) 1123 { 1124 1125 return (0); 1126 } 1127 1128 extern struct cdevsw *cdevsw[]; 1129 1130 /* 1131 * Filler function for proc/devices 1132 */ 1133 static int 1134 linprocfs_dodevices(PFS_FILL_ARGS) 1135 { 1136 char *char_devices; 1137 sbuf_printf(sb, "Character devices:\n"); 1138 1139 char_devices = linux_get_char_devices(); 1140 sbuf_printf(sb, "%s", char_devices); 1141 linux_free_get_char_devices(char_devices); 1142 1143 sbuf_printf(sb, "\nBlock devices:\n"); 1144 1145 return (0); 1146 } 1147 1148 /* 1149 * Filler function for proc/cmdline 1150 */ 1151 static int 1152 linprocfs_docmdline(PFS_FILL_ARGS) 1153 { 1154 1155 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1156 sbuf_printf(sb, " ro root=302\n"); 1157 return (0); 1158 } 1159 1160 #if 0 1161 /* 1162 * Filler function for proc/modules 1163 */ 1164 static int 1165 linprocfs_domodules(PFS_FILL_ARGS) 1166 { 1167 struct linker_file *lf; 1168 1169 TAILQ_FOREACH(lf, &linker_files, link) { 1170 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1171 (unsigned long)lf->size, lf->refs); 1172 } 1173 return (0); 1174 } 1175 #endif 1176 1177 /* 1178 * Constructor 1179 */ 1180 static int 1181 linprocfs_init(PFS_INIT_ARGS) 1182 { 1183 struct pfs_node *root; 1184 struct pfs_node *dir; 1185 1186 root = pi->pi_root; 1187 1188 /* /proc/... */ 1189 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1190 NULL, NULL, NULL, PFS_RD); 1191 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1192 NULL, NULL, NULL, PFS_RD); 1193 pfs_create_file(root, "devices", &linprocfs_dodevices, 1194 NULL, NULL, NULL, PFS_RD); 1195 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1196 NULL, NULL, NULL, PFS_RD); 1197 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1198 NULL, NULL, NULL, PFS_RD); 1199 #if 0 1200 pfs_create_file(root, "modules", &linprocfs_domodules, 1201 NULL, NULL, NULL, PFS_RD); 1202 #endif 1203 pfs_create_file(root, "mounts", &linprocfs_domtab, 1204 NULL, NULL, NULL, PFS_RD); 1205 pfs_create_file(root, "mtab", &linprocfs_domtab, 1206 NULL, NULL, NULL, PFS_RD); 1207 pfs_create_link(root, "self", &procfs_docurproc, 1208 NULL, NULL, NULL, 0); 1209 pfs_create_file(root, "stat", &linprocfs_dostat, 1210 NULL, NULL, NULL, PFS_RD); 1211 pfs_create_file(root, "uptime", &linprocfs_douptime, 1212 NULL, NULL, NULL, PFS_RD); 1213 pfs_create_file(root, "version", &linprocfs_doversion, 1214 NULL, NULL, NULL, PFS_RD); 1215 1216 /* /proc/net/... */ 1217 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1218 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1219 NULL, NULL, NULL, PFS_RD); 1220 1221 /* /proc/<pid>/... */ 1222 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1223 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1224 NULL, NULL, NULL, PFS_RD); 1225 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1226 NULL, NULL, NULL, 0); 1227 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1228 NULL, NULL, NULL, PFS_RD); 1229 pfs_create_link(dir, "exe", &procfs_doprocfile, 1230 NULL, &procfs_notsystem, NULL, 0); 1231 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1232 NULL, NULL, NULL, PFS_RD); 1233 pfs_create_file(dir, "mem", &procfs_doprocmem, 1234 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1235 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1236 NULL, NULL, NULL, 0); 1237 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1238 NULL, NULL, NULL, PFS_RD); 1239 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1240 NULL, NULL, NULL, PFS_RD); 1241 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1242 NULL, NULL, NULL, PFS_RD); 1243 1244 /* /proc/scsi/... */ 1245 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1246 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1247 NULL, NULL, NULL, PFS_RD); 1248 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1249 NULL, NULL, NULL, PFS_RD); 1250 1251 /* /proc/sys/... */ 1252 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1253 /* /proc/sys/kernel/... */ 1254 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1255 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1256 NULL, NULL, NULL, PFS_RD); 1257 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1258 NULL, NULL, NULL, PFS_RD); 1259 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1260 NULL, NULL, NULL, PFS_RD); 1261 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1262 NULL, NULL, NULL, PFS_RD); 1263 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1264 NULL, NULL, NULL, PFS_RD); 1265 pfs_create_file(dir, "sem", &linprocfs_dosem, 1266 NULL, NULL, NULL, PFS_RD); 1267 1268 return (0); 1269 } 1270 1271 /* 1272 * Destructor 1273 */ 1274 static int 1275 linprocfs_uninit(PFS_INIT_ARGS) 1276 { 1277 1278 /* nothing to do, pseudofs will GC */ 1279 return (0); 1280 } 1281 1282 PSEUDOFS(linprocfs, 1); 1283 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1284 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1285 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1286 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1287