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