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