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