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