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