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