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