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