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