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