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