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