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