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