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