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