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