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 struct pcpu *pcpu; 378 long cp_time[CPUSTATES]; 379 long *cp; 380 int i; 381 382 read_cpu_time(cp_time); 383 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n", 384 T2J(cp_time[CP_USER]), 385 T2J(cp_time[CP_NICE]), 386 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/), 387 T2J(cp_time[CP_IDLE])); 388 for (i = 0; i <= mp_maxid; ++i) { 389 if (CPU_ABSENT(i)) 390 continue; 391 pcpu = pcpu_find(i); 392 cp = pcpu->pc_cp_time; 393 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i, 394 T2J(cp[CP_USER]), 395 T2J(cp[CP_NICE]), 396 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/), 397 T2J(cp[CP_IDLE])); 398 } 399 sbuf_printf(sb, 400 "disk 0 0 0 0\n" 401 "page %u %u\n" 402 "swap %u %u\n" 403 "intr %u\n" 404 "ctxt %u\n" 405 "btime %lld\n", 406 cnt.v_vnodepgsin, 407 cnt.v_vnodepgsout, 408 cnt.v_swappgsin, 409 cnt.v_swappgsout, 410 cnt.v_intr, 411 cnt.v_swtch, 412 (long long)boottime.tv_sec); 413 return (0); 414 } 415 416 /* 417 * Filler function for proc/uptime 418 */ 419 static int 420 linprocfs_douptime(PFS_FILL_ARGS) 421 { 422 long cp_time[CPUSTATES]; 423 struct timeval tv; 424 425 getmicrouptime(&tv); 426 read_cpu_time(cp_time); 427 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n", 428 (long long)tv.tv_sec, tv.tv_usec / 10000, 429 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100); 430 return (0); 431 } 432 433 /* 434 * Get OS build date 435 */ 436 static void 437 linprocfs_osbuild(struct thread *td, struct sbuf *sb) 438 { 439 #if 0 440 char osbuild[256]; 441 char *cp1, *cp2; 442 443 strncpy(osbuild, version, 256); 444 osbuild[255] = '\0'; 445 cp1 = strstr(osbuild, "\n"); 446 cp2 = strstr(osbuild, ":"); 447 if (cp1 && cp2) { 448 *cp1 = *cp2 = '\0'; 449 cp1 = strstr(osbuild, "#"); 450 } else 451 cp1 = NULL; 452 if (cp1) 453 sbuf_printf(sb, "%s%s", cp1, cp2 + 1); 454 else 455 #endif 456 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977"); 457 } 458 459 /* 460 * Get OS builder 461 */ 462 static void 463 linprocfs_osbuilder(struct thread *td, struct sbuf *sb) 464 { 465 #if 0 466 char builder[256]; 467 char *cp; 468 469 cp = strstr(version, "\n "); 470 if (cp) { 471 strncpy(builder, cp + 5, 256); 472 builder[255] = '\0'; 473 cp = strstr(builder, ":"); 474 if (cp) 475 *cp = '\0'; 476 } 477 if (cp) 478 sbuf_cat(sb, builder); 479 else 480 #endif 481 sbuf_cat(sb, "des@freebsd.org"); 482 } 483 484 /* 485 * Filler function for proc/version 486 */ 487 static int 488 linprocfs_doversion(PFS_FILL_ARGS) 489 { 490 char osname[LINUX_MAX_UTSNAME]; 491 char osrelease[LINUX_MAX_UTSNAME]; 492 493 linux_get_osname(td, osname); 494 linux_get_osrelease(td, osrelease); 495 sbuf_printf(sb, "%s version %s (", osname, osrelease); 496 linprocfs_osbuilder(td, sb); 497 sbuf_cat(sb, ") (gcc version " __VERSION__ ") "); 498 linprocfs_osbuild(td, sb); 499 sbuf_cat(sb, "\n"); 500 501 return (0); 502 } 503 504 /* 505 * Filler function for proc/loadavg 506 */ 507 static int 508 linprocfs_doloadavg(PFS_FILL_ARGS) 509 { 510 511 sbuf_printf(sb, 512 "%d.%02d %d.%02d %d.%02d %d/%d %d\n", 513 (int)(averunnable.ldavg[0] / averunnable.fscale), 514 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100), 515 (int)(averunnable.ldavg[1] / averunnable.fscale), 516 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100), 517 (int)(averunnable.ldavg[2] / averunnable.fscale), 518 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100), 519 1, /* number of running tasks */ 520 nprocs, /* number of tasks */ 521 lastpid /* the last pid */ 522 ); 523 return (0); 524 } 525 526 /* 527 * Filler function for proc/pid/stat 528 */ 529 static int 530 linprocfs_doprocstat(PFS_FILL_ARGS) 531 { 532 struct kinfo_proc kp; 533 char state; 534 static int ratelimit = 0; 535 536 PROC_LOCK(p); 537 fill_kinfo_proc(p, &kp); 538 sbuf_printf(sb, "%d", p->p_pid); 539 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg) 540 PS_ADD("comm", "(%s)", p->p_comm); 541 if (kp.ki_stat > sizeof(linux_state)) { 542 state = 'R'; 543 544 if (ratelimit == 0) { 545 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n", 546 kp.ki_stat, sizeof(linux_state)); 547 ++ratelimit; 548 } 549 } else 550 state = linux_state[kp.ki_stat - 1]; 551 PS_ADD("state", "%c", state); 552 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0); 553 PS_ADD("pgrp", "%d", p->p_pgid); 554 PS_ADD("session", "%d", p->p_session->s_sid); 555 PROC_UNLOCK(p); 556 PS_ADD("tty", "%d", 0); /* XXX */ 557 PS_ADD("tpgid", "%d", kp.ki_tpgid); 558 PS_ADD("flags", "%u", 0); /* XXX */ 559 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt); 560 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt); 561 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt); 562 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt); 563 PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime))); 564 PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime))); 565 PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime))); 566 PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime))); 567 PS_ADD("priority", "%d", kp.ki_pri.pri_user); 568 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */ 569 PS_ADD("0", "%d", 0); /* removed field */ 570 PS_ADD("itrealvalue", "%d", 0); /* XXX */ 571 /* XXX: starttime is not right, it is the _same_ for _every_ process. 572 It should be the number of jiffies between system boot and process 573 start. */ 574 PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start))); 575 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size)); 576 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize); 577 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss); 578 PS_ADD("startcode", "%u", (unsigned)0); 579 PS_ADD("endcode", "%u", 0); /* XXX */ 580 PS_ADD("startstack", "%u", 0); /* XXX */ 581 PS_ADD("kstkesp", "%u", 0); /* XXX */ 582 PS_ADD("kstkeip", "%u", 0); /* XXX */ 583 PS_ADD("signal", "%u", 0); /* XXX */ 584 PS_ADD("blocked", "%u", 0); /* XXX */ 585 PS_ADD("sigignore", "%u", 0); /* XXX */ 586 PS_ADD("sigcatch", "%u", 0); /* XXX */ 587 PS_ADD("wchan", "%u", 0); /* XXX */ 588 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap); 589 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap); 590 PS_ADD("exitsignal", "%d", 0); /* XXX */ 591 PS_ADD("processor", "%u", kp.ki_lastcpu); 592 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */ 593 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */ 594 #undef PS_ADD 595 sbuf_putc(sb, '\n'); 596 597 return (0); 598 } 599 600 /* 601 * Filler function for proc/pid/statm 602 */ 603 static int 604 linprocfs_doprocstatm(PFS_FILL_ARGS) 605 { 606 struct kinfo_proc kp; 607 segsz_t lsize; 608 609 PROC_LOCK(p); 610 fill_kinfo_proc(p, &kp); 611 PROC_UNLOCK(p); 612 613 /* 614 * See comments in linprocfs_doprocstatus() regarding the 615 * computation of lsize. 616 */ 617 /* size resident share trs drs lrs dt */ 618 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size)); 619 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize); 620 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */ 621 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize); 622 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize)); 623 lsize = B2P(kp.ki_size) - kp.ki_dsize - 624 kp.ki_ssize - kp.ki_tsize - 1; 625 sbuf_printf(sb, "%ju ", (uintmax_t)lsize); 626 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */ 627 628 return (0); 629 } 630 631 /* 632 * Filler function for proc/pid/status 633 */ 634 static int 635 linprocfs_doprocstatus(PFS_FILL_ARGS) 636 { 637 struct kinfo_proc kp; 638 char *state; 639 segsz_t lsize; 640 struct thread *td2; 641 struct sigacts *ps; 642 int i; 643 644 PROC_LOCK(p); 645 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */ 646 647 if (P_SHOULDSTOP(p)) { 648 state = "T (stopped)"; 649 } else { 650 PROC_SLOCK(p); 651 switch(p->p_state) { 652 case PRS_NEW: 653 state = "I (idle)"; 654 break; 655 case PRS_NORMAL: 656 if (p->p_flag & P_WEXIT) { 657 state = "X (exiting)"; 658 break; 659 } 660 switch(td2->td_state) { 661 case TDS_INHIBITED: 662 state = "S (sleeping)"; 663 break; 664 case TDS_RUNQ: 665 case TDS_RUNNING: 666 state = "R (running)"; 667 break; 668 default: 669 state = "? (unknown)"; 670 break; 671 } 672 break; 673 case PRS_ZOMBIE: 674 state = "Z (zombie)"; 675 break; 676 default: 677 state = "? (unknown)"; 678 break; 679 } 680 PROC_SUNLOCK(p); 681 } 682 683 fill_kinfo_proc(p, &kp); 684 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */ 685 sbuf_printf(sb, "State:\t%s\n", state); 686 687 /* 688 * Credentials 689 */ 690 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid); 691 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ? 692 p->p_pptr->p_pid : 0); 693 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid, 694 p->p_ucred->cr_uid, 695 p->p_ucred->cr_svuid, 696 /* FreeBSD doesn't have fsuid */ 697 p->p_ucred->cr_uid); 698 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid, 699 p->p_ucred->cr_gid, 700 p->p_ucred->cr_svgid, 701 /* FreeBSD doesn't have fsgid */ 702 p->p_ucred->cr_gid); 703 sbuf_cat(sb, "Groups:\t"); 704 for (i = 0; i < p->p_ucred->cr_ngroups; i++) 705 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]); 706 PROC_UNLOCK(p); 707 sbuf_putc(sb, '\n'); 708 709 /* 710 * Memory 711 * 712 * While our approximation of VmLib may not be accurate (I 713 * don't know of a simple way to verify it, and I'm not sure 714 * it has much meaning anyway), I believe it's good enough. 715 * 716 * The same code that could (I think) accurately compute VmLib 717 * could also compute VmLck, but I don't really care enough to 718 * implement it. Submissions are welcome. 719 */ 720 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size)); 721 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */ 722 sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize)); 723 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize)); 724 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize)); 725 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize)); 726 lsize = B2P(kp.ki_size) - kp.ki_dsize - 727 kp.ki_ssize - kp.ki_tsize - 1; 728 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize)); 729 730 /* 731 * Signal masks 732 * 733 * We support up to 128 signals, while Linux supports 32, 734 * but we only define 32 (the same 32 as Linux, to boot), so 735 * just show the lower 32 bits of each mask. XXX hack. 736 * 737 * NB: on certain platforms (Sparc at least) Linux actually 738 * supports 64 signals, but this code is a long way from 739 * running on anything but i386, so ignore that for now. 740 */ 741 PROC_LOCK(p); 742 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]); 743 /* 744 * I can't seem to find out where the signal mask is in 745 * relation to struct proc, so SigBlk is left unimplemented. 746 */ 747 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */ 748 ps = p->p_sigacts; 749 mtx_lock(&ps->ps_mtx); 750 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]); 751 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]); 752 mtx_unlock(&ps->ps_mtx); 753 PROC_UNLOCK(p); 754 755 /* 756 * Linux also prints the capability masks, but we don't have 757 * capabilities yet, and when we do get them they're likely to 758 * be meaningless to Linux programs, so we lie. XXX 759 */ 760 sbuf_printf(sb, "CapInh:\t%016x\n", 0); 761 sbuf_printf(sb, "CapPrm:\t%016x\n", 0); 762 sbuf_printf(sb, "CapEff:\t%016x\n", 0); 763 764 return (0); 765 } 766 767 768 /* 769 * Filler function for proc/pid/cwd 770 */ 771 static int 772 linprocfs_doproccwd(PFS_FILL_ARGS) 773 { 774 char *fullpath = "unknown"; 775 char *freepath = NULL; 776 777 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath); 778 sbuf_printf(sb, "%s", fullpath); 779 if (freepath) 780 free(freepath, M_TEMP); 781 return (0); 782 } 783 784 /* 785 * Filler function for proc/pid/root 786 */ 787 static int 788 linprocfs_doprocroot(PFS_FILL_ARGS) 789 { 790 struct vnode *rvp; 791 char *fullpath = "unknown"; 792 char *freepath = NULL; 793 794 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir; 795 vn_fullpath(td, rvp, &fullpath, &freepath); 796 sbuf_printf(sb, "%s", fullpath); 797 if (freepath) 798 free(freepath, M_TEMP); 799 return (0); 800 } 801 802 /* 803 * Filler function for proc/pid/cmdline 804 */ 805 static int 806 linprocfs_doproccmdline(PFS_FILL_ARGS) 807 { 808 struct ps_strings pstr; 809 char **ps_argvstr; 810 int error, i; 811 812 /* 813 * If we are using the ps/cmdline caching, use that. Otherwise 814 * revert back to the old way which only implements full cmdline 815 * for the currept process and just p->p_comm for all other 816 * processes. 817 * Note that if the argv is no longer available, we deliberately 818 * don't fall back on p->p_comm or return an error: the authentic 819 * Linux behaviour is to return zero-length in this case. 820 */ 821 822 PROC_LOCK(p); 823 if (p->p_args && p_cansee(td, p) == 0) { 824 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length); 825 PROC_UNLOCK(p); 826 } else if (p != td->td_proc) { 827 PROC_UNLOCK(p); 828 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm); 829 } else { 830 PROC_UNLOCK(p); 831 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr, 832 sizeof(pstr)); 833 if (error) 834 return (error); 835 if (pstr.ps_nargvstr > ARG_MAX) 836 return (E2BIG); 837 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *), 838 M_TEMP, M_WAITOK); 839 error = copyin((void *)pstr.ps_argvstr, ps_argvstr, 840 pstr.ps_nargvstr * sizeof(char *)); 841 if (error) { 842 free(ps_argvstr, M_TEMP); 843 return (error); 844 } 845 for (i = 0; i < pstr.ps_nargvstr; i++) { 846 sbuf_copyin(sb, ps_argvstr[i], 0); 847 sbuf_printf(sb, "%c", '\0'); 848 } 849 free(ps_argvstr, M_TEMP); 850 } 851 852 return (0); 853 } 854 855 /* 856 * Filler function for proc/pid/environ 857 */ 858 static int 859 linprocfs_doprocenviron(PFS_FILL_ARGS) 860 { 861 862 sbuf_printf(sb, "doprocenviron\n%c", '\0'); 863 return (0); 864 } 865 866 /* 867 * Filler function for proc/pid/maps 868 */ 869 static int 870 linprocfs_doprocmaps(PFS_FILL_ARGS) 871 { 872 char mebuffer[512]; 873 vm_map_t map = &p->p_vmspace->vm_map; 874 vm_map_entry_t entry, tmp_entry; 875 vm_object_t obj, tobj, lobj; 876 vm_offset_t saved_end; 877 vm_ooffset_t off = 0; 878 char *name = "", *freename = NULL; 879 size_t len; 880 ino_t ino; 881 unsigned int last_timestamp; 882 int ref_count, shadow_count, flags; 883 int error; 884 struct vnode *vp; 885 struct vattr vat; 886 int locked; 887 888 PROC_LOCK(p); 889 error = p_candebug(td, p); 890 PROC_UNLOCK(p); 891 if (error) 892 return (error); 893 894 if (uio->uio_rw != UIO_READ) 895 return (EOPNOTSUPP); 896 897 if (uio->uio_offset != 0) 898 return (0); 899 900 error = 0; 901 vm_map_lock_read(map); 902 for (entry = map->header.next; 903 ((uio->uio_resid > 0) && (entry != &map->header)); 904 entry = entry->next) { 905 name = ""; 906 freename = NULL; 907 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) 908 continue; 909 saved_end = entry->end; 910 obj = entry->object.vm_object; 911 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { 912 VM_OBJECT_LOCK(tobj); 913 if (lobj != obj) 914 VM_OBJECT_UNLOCK(lobj); 915 lobj = tobj; 916 } 917 ino = 0; 918 if (lobj) { 919 off = IDX_TO_OFF(lobj->size); 920 if (lobj->type == OBJT_VNODE) { 921 vp = lobj->handle; 922 if (vp) 923 vref(vp); 924 } 925 else 926 vp = NULL; 927 if (lobj != obj) 928 VM_OBJECT_UNLOCK(lobj); 929 flags = obj->flags; 930 ref_count = obj->ref_count; 931 shadow_count = obj->shadow_count; 932 VM_OBJECT_UNLOCK(obj); 933 if (vp) { 934 vn_fullpath(td, vp, &name, &freename); 935 locked = VFS_LOCK_GIANT(vp->v_mount); 936 vn_lock(vp, LK_SHARED | LK_RETRY); 937 VOP_GETATTR(vp, &vat, td->td_ucred, td); 938 ino = vat.va_fileid; 939 vput(vp); 940 VFS_UNLOCK_GIANT(locked); 941 } 942 } else { 943 flags = 0; 944 ref_count = 0; 945 shadow_count = 0; 946 } 947 948 /* 949 * format: 950 * start, end, access, offset, major, minor, inode, name. 951 */ 952 snprintf(mebuffer, sizeof mebuffer, 953 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n", 954 (u_long)entry->start, (u_long)entry->end, 955 (entry->protection & VM_PROT_READ)?"r":"-", 956 (entry->protection & VM_PROT_WRITE)?"w":"-", 957 (entry->protection & VM_PROT_EXECUTE)?"x":"-", 958 "p", 959 (u_long)off, 960 0, 961 0, 962 (u_long)ino, 963 *name ? " " : "", 964 name 965 ); 966 if (freename) 967 free(freename, M_TEMP); 968 len = strlen(mebuffer); 969 if (len > uio->uio_resid) 970 len = uio->uio_resid; /* 971 * XXX We should probably return 972 * EFBIG here, as in procfs. 973 */ 974 last_timestamp = map->timestamp; 975 vm_map_unlock_read(map); 976 error = uiomove(mebuffer, len, uio); 977 vm_map_lock_read(map); 978 if (error) 979 break; 980 if (last_timestamp + 1 != map->timestamp) { 981 /* 982 * Look again for the entry because the map was 983 * modified while it was unlocked. Specifically, 984 * the entry may have been clipped, merged, or deleted. 985 */ 986 vm_map_lookup_entry(map, saved_end - 1, &tmp_entry); 987 entry = tmp_entry; 988 } 989 } 990 vm_map_unlock_read(map); 991 992 return (error); 993 } 994 995 /* 996 * Filler function for proc/net/dev 997 */ 998 static int 999 linprocfs_donetdev(PFS_FILL_ARGS) 1000 { 1001 char ifname[16]; /* XXX LINUX_IFNAMSIZ */ 1002 struct ifnet *ifp; 1003 1004 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n", 1005 "Inter-", " Receive", " Transmit", " face", 1006 "bytes packets errs drop fifo frame compressed", 1007 "bytes packets errs drop fifo frame compressed"); 1008 1009 IFNET_RLOCK(); 1010 TAILQ_FOREACH(ifp, &ifnet, if_link) { 1011 linux_ifname(ifp, ifname, sizeof ifname); 1012 sbuf_printf(sb, "%6.6s:", ifname); 1013 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ", 1014 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 1015 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", 1016 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL); 1017 } 1018 IFNET_RUNLOCK(); 1019 1020 return (0); 1021 } 1022 1023 /* 1024 * Filler function for proc/sys/kernel/osrelease 1025 */ 1026 static int 1027 linprocfs_doosrelease(PFS_FILL_ARGS) 1028 { 1029 char osrelease[LINUX_MAX_UTSNAME]; 1030 1031 linux_get_osrelease(td, osrelease); 1032 sbuf_printf(sb, "%s\n", osrelease); 1033 1034 return (0); 1035 } 1036 1037 /* 1038 * Filler function for proc/sys/kernel/ostype 1039 */ 1040 static int 1041 linprocfs_doostype(PFS_FILL_ARGS) 1042 { 1043 char osname[LINUX_MAX_UTSNAME]; 1044 1045 linux_get_osname(td, osname); 1046 sbuf_printf(sb, "%s\n", osname); 1047 1048 return (0); 1049 } 1050 1051 /* 1052 * Filler function for proc/sys/kernel/version 1053 */ 1054 static int 1055 linprocfs_doosbuild(PFS_FILL_ARGS) 1056 { 1057 1058 linprocfs_osbuild(td, sb); 1059 sbuf_cat(sb, "\n"); 1060 return (0); 1061 } 1062 1063 /* 1064 * Filler function for proc/sys/kernel/msgmni 1065 */ 1066 static int 1067 linprocfs_domsgmni(PFS_FILL_ARGS) 1068 { 1069 1070 sbuf_printf(sb, "%d\n", msginfo.msgmni); 1071 return (0); 1072 } 1073 1074 /* 1075 * Filler function for proc/sys/kernel/pid_max 1076 */ 1077 static int 1078 linprocfs_dopid_max(PFS_FILL_ARGS) 1079 { 1080 1081 sbuf_printf(sb, "%i\n", PID_MAX); 1082 return (0); 1083 } 1084 1085 /* 1086 * Filler function for proc/sys/kernel/sem 1087 */ 1088 static int 1089 linprocfs_dosem(PFS_FILL_ARGS) 1090 { 1091 1092 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns, 1093 seminfo.semopm, seminfo.semmni); 1094 return (0); 1095 } 1096 1097 /* 1098 * Filler function for proc/scsi/device_info 1099 */ 1100 static int 1101 linprocfs_doscsidevinfo(PFS_FILL_ARGS) 1102 { 1103 1104 return (0); 1105 } 1106 1107 /* 1108 * Filler function for proc/scsi/scsi 1109 */ 1110 static int 1111 linprocfs_doscsiscsi(PFS_FILL_ARGS) 1112 { 1113 1114 return (0); 1115 } 1116 1117 extern struct cdevsw *cdevsw[]; 1118 1119 /* 1120 * Filler function for proc/devices 1121 */ 1122 static int 1123 linprocfs_dodevices(PFS_FILL_ARGS) 1124 { 1125 char *char_devices; 1126 sbuf_printf(sb, "Character devices:\n"); 1127 1128 char_devices = linux_get_char_devices(); 1129 sbuf_printf(sb, "%s", char_devices); 1130 linux_free_get_char_devices(char_devices); 1131 1132 sbuf_printf(sb, "\nBlock devices:\n"); 1133 1134 return (0); 1135 } 1136 1137 /* 1138 * Filler function for proc/cmdline 1139 */ 1140 static int 1141 linprocfs_docmdline(PFS_FILL_ARGS) 1142 { 1143 1144 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname); 1145 sbuf_printf(sb, " ro root=302\n"); 1146 return (0); 1147 } 1148 1149 #if 0 1150 /* 1151 * Filler function for proc/modules 1152 */ 1153 static int 1154 linprocfs_domodules(PFS_FILL_ARGS) 1155 { 1156 struct linker_file *lf; 1157 1158 TAILQ_FOREACH(lf, &linker_files, link) { 1159 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename, 1160 (unsigned long)lf->size, lf->refs); 1161 } 1162 return (0); 1163 } 1164 #endif 1165 1166 /* 1167 * Constructor 1168 */ 1169 static int 1170 linprocfs_init(PFS_INIT_ARGS) 1171 { 1172 struct pfs_node *root; 1173 struct pfs_node *dir; 1174 1175 root = pi->pi_root; 1176 1177 /* /proc/... */ 1178 pfs_create_file(root, "cmdline", &linprocfs_docmdline, 1179 NULL, NULL, NULL, PFS_RD); 1180 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo, 1181 NULL, NULL, NULL, PFS_RD); 1182 pfs_create_file(root, "devices", &linprocfs_dodevices, 1183 NULL, NULL, NULL, PFS_RD); 1184 pfs_create_file(root, "loadavg", &linprocfs_doloadavg, 1185 NULL, NULL, NULL, PFS_RD); 1186 pfs_create_file(root, "meminfo", &linprocfs_domeminfo, 1187 NULL, NULL, NULL, PFS_RD); 1188 #if 0 1189 pfs_create_file(root, "modules", &linprocfs_domodules, 1190 NULL, NULL, NULL, PFS_RD); 1191 #endif 1192 pfs_create_file(root, "mounts", &linprocfs_domtab, 1193 NULL, NULL, NULL, PFS_RD); 1194 pfs_create_file(root, "mtab", &linprocfs_domtab, 1195 NULL, NULL, NULL, PFS_RD); 1196 pfs_create_link(root, "self", &procfs_docurproc, 1197 NULL, NULL, NULL, 0); 1198 pfs_create_file(root, "stat", &linprocfs_dostat, 1199 NULL, NULL, NULL, PFS_RD); 1200 pfs_create_file(root, "uptime", &linprocfs_douptime, 1201 NULL, NULL, NULL, PFS_RD); 1202 pfs_create_file(root, "version", &linprocfs_doversion, 1203 NULL, NULL, NULL, PFS_RD); 1204 1205 /* /proc/net/... */ 1206 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0); 1207 pfs_create_file(dir, "dev", &linprocfs_donetdev, 1208 NULL, NULL, NULL, PFS_RD); 1209 1210 /* /proc/<pid>/... */ 1211 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP); 1212 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline, 1213 NULL, NULL, NULL, PFS_RD); 1214 pfs_create_link(dir, "cwd", &linprocfs_doproccwd, 1215 NULL, NULL, NULL, 0); 1216 pfs_create_file(dir, "environ", &linprocfs_doprocenviron, 1217 NULL, NULL, NULL, PFS_RD); 1218 pfs_create_link(dir, "exe", &procfs_doprocfile, 1219 NULL, &procfs_notsystem, NULL, 0); 1220 pfs_create_file(dir, "maps", &linprocfs_doprocmaps, 1221 NULL, NULL, NULL, PFS_RD); 1222 pfs_create_file(dir, "mem", &procfs_doprocmem, 1223 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW); 1224 pfs_create_link(dir, "root", &linprocfs_doprocroot, 1225 NULL, NULL, NULL, 0); 1226 pfs_create_file(dir, "stat", &linprocfs_doprocstat, 1227 NULL, NULL, NULL, PFS_RD); 1228 pfs_create_file(dir, "statm", &linprocfs_doprocstatm, 1229 NULL, NULL, NULL, PFS_RD); 1230 pfs_create_file(dir, "status", &linprocfs_doprocstatus, 1231 NULL, NULL, NULL, PFS_RD); 1232 1233 /* /proc/scsi/... */ 1234 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0); 1235 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo, 1236 NULL, NULL, NULL, PFS_RD); 1237 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi, 1238 NULL, NULL, NULL, PFS_RD); 1239 1240 /* /proc/sys/... */ 1241 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0); 1242 /* /proc/sys/kernel/... */ 1243 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0); 1244 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease, 1245 NULL, NULL, NULL, PFS_RD); 1246 pfs_create_file(dir, "ostype", &linprocfs_doostype, 1247 NULL, NULL, NULL, PFS_RD); 1248 pfs_create_file(dir, "version", &linprocfs_doosbuild, 1249 NULL, NULL, NULL, PFS_RD); 1250 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni, 1251 NULL, NULL, NULL, PFS_RD); 1252 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max, 1253 NULL, NULL, NULL, PFS_RD); 1254 pfs_create_file(dir, "sem", &linprocfs_dosem, 1255 NULL, NULL, NULL, PFS_RD); 1256 1257 return (0); 1258 } 1259 1260 /* 1261 * Destructor 1262 */ 1263 static int 1264 linprocfs_uninit(PFS_INIT_ARGS) 1265 { 1266 1267 /* nothing to do, pseudofs will GC */ 1268 return (0); 1269 } 1270 1271 PSEUDOFS(linprocfs, 1); 1272 MODULE_DEPEND(linprocfs, linux, 1, 1, 1); 1273 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1); 1274 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1); 1275 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1); 1276