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$");
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 if (kp.ki_tdev == NODEV)
622 PS_ADD("tty", "%s", "-1");
623 else
624 PS_ADD("tty", "%ju", (uintmax_t)kp.ki_tdev);
625 PS_ADD("tpgid", "%d", kp.ki_tpgid);
626 PS_ADD("flags", "%u", 0); /* XXX */
627 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
628 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
629 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
630 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
631 PS_ADD("utime", "%ld", TV2J(&kp.ki_rusage.ru_utime));
632 PS_ADD("stime", "%ld", TV2J(&kp.ki_rusage.ru_stime));
633 PS_ADD("cutime", "%ld", TV2J(&kp.ki_rusage_ch.ru_utime));
634 PS_ADD("cstime", "%ld", TV2J(&kp.ki_rusage_ch.ru_stime));
635 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
636 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
637 PS_ADD("", "%d", 0); /* removed field */
638 PS_ADD("itrealvalue", "%d", 0); /* XXX */
639 PS_ADD("starttime", "%lu", TV2J(&kp.ki_start) - TV2J(&boottime));
640 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
641 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
642 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
643 PS_ADD("startcode", "%ju", (uintmax_t)startcode);
644 PS_ADD("endcode", "%ju", (uintmax_t)startdata);
645 PS_ADD("startstack", "%u", 0); /* XXX */
646 PS_ADD("kstkesp", "%u", 0); /* XXX */
647 PS_ADD("kstkeip", "%u", 0); /* XXX */
648 PS_ADD("signal", "%u", 0); /* XXX */
649 PS_ADD("blocked", "%u", 0); /* XXX */
650 PS_ADD("sigignore", "%u", 0); /* XXX */
651 PS_ADD("sigcatch", "%u", 0); /* XXX */
652 PS_ADD("wchan", "%u", 0); /* XXX */
653 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
654 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
655 PS_ADD("exitsignal", "%d", 0); /* XXX */
656 PS_ADD("processor", "%u", kp.ki_lastcpu);
657 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
658 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
659 #undef PS_ADD
660 sbuf_putc(sb, '\n');
661
662 return (0);
663 }
664
665 /*
666 * Filler function for proc/pid/statm
667 */
668 static int
669 linprocfs_doprocstatm(PFS_FILL_ARGS)
670 {
671 struct kinfo_proc kp;
672 segsz_t lsize;
673
674 sx_slock(&proctree_lock);
675 PROC_LOCK(p);
676 fill_kinfo_proc(p, &kp);
677 PROC_UNLOCK(p);
678 sx_sunlock(&proctree_lock);
679
680 /*
681 * See comments in linprocfs_doprocstatus() regarding the
682 * computation of lsize.
683 */
684 /* size resident share trs drs lrs dt */
685 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
686 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
687 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
688 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
689 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
690 lsize = B2P(kp.ki_size) - kp.ki_dsize -
691 kp.ki_ssize - kp.ki_tsize - 1;
692 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
693 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
694
695 return (0);
696 }
697
698 /*
699 * Filler function for proc/pid/status
700 */
701 static int
702 linprocfs_doprocstatus(PFS_FILL_ARGS)
703 {
704 struct kinfo_proc kp;
705 char *state;
706 segsz_t lsize;
707 struct thread *td2;
708 struct sigacts *ps;
709 l_sigset_t siglist, sigignore, sigcatch;
710 int i;
711
712 sx_slock(&proctree_lock);
713 PROC_LOCK(p);
714 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
715
716 if (P_SHOULDSTOP(p)) {
717 state = "T (stopped)";
718 } else {
719 switch(p->p_state) {
720 case PRS_NEW:
721 state = "I (idle)";
722 break;
723 case PRS_NORMAL:
724 if (p->p_flag & P_WEXIT) {
725 state = "X (exiting)";
726 break;
727 }
728 switch(td2->td_state) {
729 case TDS_INHIBITED:
730 state = "S (sleeping)";
731 break;
732 case TDS_RUNQ:
733 case TDS_RUNNING:
734 state = "R (running)";
735 break;
736 default:
737 state = "? (unknown)";
738 break;
739 }
740 break;
741 case PRS_ZOMBIE:
742 state = "Z (zombie)";
743 break;
744 default:
745 state = "? (unknown)";
746 break;
747 }
748 }
749
750 fill_kinfo_proc(p, &kp);
751 sx_sunlock(&proctree_lock);
752
753 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
754 sbuf_printf(sb, "State:\t%s\n", state);
755
756 /*
757 * Credentials
758 */
759 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
760 sbuf_printf(sb, "PPid:\t%d\n", kp.ki_ppid );
761 sbuf_printf(sb, "TracerPid:\t%d\n", kp.ki_tracer );
762 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
763 p->p_ucred->cr_uid,
764 p->p_ucred->cr_svuid,
765 /* FreeBSD doesn't have fsuid */
766 p->p_ucred->cr_uid);
767 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
768 p->p_ucred->cr_gid,
769 p->p_ucred->cr_svgid,
770 /* FreeBSD doesn't have fsgid */
771 p->p_ucred->cr_gid);
772 sbuf_cat(sb, "Groups:\t");
773 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
774 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
775 PROC_UNLOCK(p);
776 sbuf_putc(sb, '\n');
777
778 /*
779 * Memory
780 *
781 * While our approximation of VmLib may not be accurate (I
782 * don't know of a simple way to verify it, and I'm not sure
783 * it has much meaning anyway), I believe it's good enough.
784 *
785 * The same code that could (I think) accurately compute VmLib
786 * could also compute VmLck, but I don't really care enough to
787 * implement it. Submissions are welcome.
788 */
789 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
790 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
791 sbuf_printf(sb, "VmRSS:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
792 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
793 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
794 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
795 lsize = B2P(kp.ki_size) - kp.ki_dsize -
796 kp.ki_ssize - kp.ki_tsize - 1;
797 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
798
799 /*
800 * Signal masks
801 */
802 PROC_LOCK(p);
803 bsd_to_linux_sigset(&p->p_siglist, &siglist);
804 ps = p->p_sigacts;
805 mtx_lock(&ps->ps_mtx);
806 bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
807 bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
808 mtx_unlock(&ps->ps_mtx);
809 PROC_UNLOCK(p);
810
811 sbuf_printf(sb, "SigPnd:\t%016jx\n", siglist.__mask);
812 /*
813 * XXX. SigBlk - target thread's signal mask, td_sigmask.
814 * To implement SigBlk pseudofs should support proc/tid dir entries.
815 */
816 sbuf_printf(sb, "SigBlk:\t%016x\n", 0);
817 sbuf_printf(sb, "SigIgn:\t%016jx\n", sigignore.__mask);
818 sbuf_printf(sb, "SigCgt:\t%016jx\n", sigcatch.__mask);
819
820 /*
821 * Linux also prints the capability masks, but we don't have
822 * capabilities yet, and when we do get them they're likely to
823 * be meaningless to Linux programs, so we lie. XXX
824 */
825 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
826 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
827 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
828
829 return (0);
830 }
831
832
833 /*
834 * Filler function for proc/pid/cwd
835 */
836 static int
837 linprocfs_doproccwd(PFS_FILL_ARGS)
838 {
839 struct filedesc *fdp;
840 struct vnode *vp;
841 char *fullpath = "unknown";
842 char *freepath = NULL;
843
844 fdp = p->p_fd;
845 FILEDESC_SLOCK(fdp);
846 vp = fdp->fd_cdir;
847 if (vp != NULL)
848 VREF(vp);
849 FILEDESC_SUNLOCK(fdp);
850 vn_fullpath(td, vp, &fullpath, &freepath);
851 if (vp != NULL)
852 vrele(vp);
853 sbuf_printf(sb, "%s", fullpath);
854 if (freepath)
855 free(freepath, M_TEMP);
856 return (0);
857 }
858
859 /*
860 * Filler function for proc/pid/root
861 */
862 static int
863 linprocfs_doprocroot(PFS_FILL_ARGS)
864 {
865 struct filedesc *fdp;
866 struct vnode *vp;
867 char *fullpath = "unknown";
868 char *freepath = NULL;
869
870 fdp = p->p_fd;
871 FILEDESC_SLOCK(fdp);
872 vp = jailed(p->p_ucred) ? fdp->fd_jdir : fdp->fd_rdir;
873 if (vp != NULL)
874 VREF(vp);
875 FILEDESC_SUNLOCK(fdp);
876 vn_fullpath(td, vp, &fullpath, &freepath);
877 if (vp != NULL)
878 vrele(vp);
879 sbuf_printf(sb, "%s", fullpath);
880 if (freepath)
881 free(freepath, M_TEMP);
882 return (0);
883 }
884
885 /*
886 * Filler function for proc/pid/cmdline
887 */
888 static int
889 linprocfs_doproccmdline(PFS_FILL_ARGS)
890 {
891 int ret;
892
893 PROC_LOCK(p);
894 if ((ret = p_cansee(td, p)) != 0) {
895 PROC_UNLOCK(p);
896 return (ret);
897 }
898
899 /*
900 * Mimic linux behavior and pass only processes with usermode
901 * address space as valid. Return zero silently otherwize.
902 */
903 if (p->p_vmspace == &vmspace0) {
904 PROC_UNLOCK(p);
905 return (0);
906 }
907 if (p->p_args != NULL) {
908 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
909 PROC_UNLOCK(p);
910 return (0);
911 }
912
913 if ((p->p_flag & P_SYSTEM) != 0) {
914 PROC_UNLOCK(p);
915 return (0);
916 }
917
918 PROC_UNLOCK(p);
919
920 ret = proc_getargv(td, p, sb);
921 return (ret);
922 }
923
924 /*
925 * Filler function for proc/pid/environ
926 */
927 static int
928 linprocfs_doprocenviron(PFS_FILL_ARGS)
929 {
930
931 /*
932 * Mimic linux behavior and pass only processes with usermode
933 * address space as valid. Return zero silently otherwize.
934 */
935 if (p->p_vmspace == &vmspace0)
936 return (0);
937
938 return (proc_getenvv(td, p, sb));
939 }
940
941 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
942 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
943 static char vdso_str[] = " [vdso]";
944 static char stack_str[] = " [stack]";
945
946 /*
947 * Filler function for proc/pid/maps
948 */
949 static int
950 linprocfs_doprocmaps(PFS_FILL_ARGS)
951 {
952 struct vmspace *vm;
953 vm_map_t map;
954 vm_map_entry_t entry, tmp_entry;
955 vm_object_t obj, tobj, lobj;
956 vm_offset_t e_start, e_end;
957 vm_ooffset_t off = 0;
958 vm_prot_t e_prot;
959 unsigned int last_timestamp;
960 char *name = "", *freename = NULL;
961 const char *l_map_str;
962 ino_t ino;
963 int ref_count, shadow_count, flags;
964 int error;
965 struct vnode *vp;
966 struct vattr vat;
967
968 PROC_LOCK(p);
969 error = p_candebug(td, p);
970 PROC_UNLOCK(p);
971 if (error)
972 return (error);
973
974 if (uio->uio_rw != UIO_READ)
975 return (EOPNOTSUPP);
976
977 error = 0;
978 vm = vmspace_acquire_ref(p);
979 if (vm == NULL)
980 return (ESRCH);
981
982 if (SV_CURPROC_FLAG(SV_LP64))
983 l_map_str = l64_map_str;
984 else
985 l_map_str = l32_map_str;
986 map = &vm->vm_map;
987 vm_map_lock_read(map);
988 for (entry = map->header.next; entry != &map->header;
989 entry = entry->next) {
990 name = "";
991 freename = NULL;
992 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
993 continue;
994 e_prot = entry->protection;
995 e_start = entry->start;
996 e_end = entry->end;
997 obj = entry->object.vm_object;
998 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
999 VM_OBJECT_RLOCK(tobj);
1000 if (lobj != obj)
1001 VM_OBJECT_RUNLOCK(lobj);
1002 lobj = tobj;
1003 }
1004 last_timestamp = map->timestamp;
1005 vm_map_unlock_read(map);
1006 ino = 0;
1007 if (lobj) {
1008 off = IDX_TO_OFF(lobj->size);
1009 vp = vm_object_vnode(lobj);
1010 if (vp != NULL)
1011 vref(vp);
1012 if (lobj != obj)
1013 VM_OBJECT_RUNLOCK(lobj);
1014 flags = obj->flags;
1015 ref_count = obj->ref_count;
1016 shadow_count = obj->shadow_count;
1017 VM_OBJECT_RUNLOCK(obj);
1018 if (vp != NULL) {
1019 vn_fullpath(td, vp, &name, &freename);
1020 vn_lock(vp, LK_SHARED | LK_RETRY);
1021 VOP_GETATTR(vp, &vat, td->td_ucred);
1022 ino = vat.va_fileid;
1023 vput(vp);
1024 } else if (SV_PROC_ABI(p) == SV_ABI_LINUX) {
1025 if (e_start == p->p_sysent->sv_shared_page_base)
1026 name = vdso_str;
1027 if (e_end == p->p_sysent->sv_usrstack)
1028 name = stack_str;
1029 }
1030 } else {
1031 flags = 0;
1032 ref_count = 0;
1033 shadow_count = 0;
1034 }
1035
1036 /*
1037 * format:
1038 * start, end, access, offset, major, minor, inode, name.
1039 */
1040 error = sbuf_printf(sb, l_map_str,
1041 (u_long)e_start, (u_long)e_end,
1042 (e_prot & VM_PROT_READ)?"r":"-",
1043 (e_prot & VM_PROT_WRITE)?"w":"-",
1044 (e_prot & VM_PROT_EXECUTE)?"x":"-",
1045 "p",
1046 (u_long)off,
1047 0,
1048 0,
1049 (u_long)ino,
1050 *name ? " " : "",
1051 name
1052 );
1053 if (freename)
1054 free(freename, M_TEMP);
1055 vm_map_lock_read(map);
1056 if (error == -1) {
1057 error = 0;
1058 break;
1059 }
1060 if (last_timestamp != map->timestamp) {
1061 /*
1062 * Look again for the entry because the map was
1063 * modified while it was unlocked. Specifically,
1064 * the entry may have been clipped, merged, or deleted.
1065 */
1066 vm_map_lookup_entry(map, e_end - 1, &tmp_entry);
1067 entry = tmp_entry;
1068 }
1069 }
1070 vm_map_unlock_read(map);
1071 vmspace_free(vm);
1072
1073 return (error);
1074 }
1075
1076 /*
1077 * Criteria for interface name translation
1078 */
1079 #define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER)
1080
1081 static int
1082 linux_ifname(struct ifnet *ifp, char *buffer, size_t buflen)
1083 {
1084 struct ifnet *ifscan;
1085 int ethno;
1086
1087 IFNET_RLOCK_ASSERT();
1088
1089 /* Short-circuit non ethernet interfaces */
1090 if (!IFP_IS_ETH(ifp))
1091 return (strlcpy(buffer, ifp->if_xname, buflen));
1092
1093 /* Determine the (relative) unit number for ethernet interfaces */
1094 ethno = 0;
1095 TAILQ_FOREACH(ifscan, &V_ifnet, if_link) {
1096 if (ifscan == ifp)
1097 return (snprintf(buffer, buflen, "eth%d", ethno));
1098 if (IFP_IS_ETH(ifscan))
1099 ethno++;
1100 }
1101
1102 return (0);
1103 }
1104
1105 /*
1106 * Filler function for proc/net/dev
1107 */
1108 static int
1109 linprocfs_donetdev(PFS_FILL_ARGS)
1110 {
1111 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
1112 struct ifnet *ifp;
1113
1114 sbuf_printf(sb, "%6s|%58s|%s\n"
1115 "%6s|%58s|%58s\n",
1116 "Inter-", " Receive", " Transmit",
1117 " face",
1118 "bytes packets errs drop fifo frame compressed multicast",
1119 "bytes packets errs drop fifo colls carrier compressed");
1120
1121 CURVNET_SET(TD_TO_VNET(curthread));
1122 IFNET_RLOCK();
1123 TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1124 linux_ifname(ifp, ifname, sizeof ifname);
1125 sbuf_printf(sb, "%6.6s: ", ifname);
1126 sbuf_printf(sb, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1127 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1128 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1129 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1130 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
1131 /* rx_missed_errors */
1132 0UL, /* rx_fifo_errors */
1133 0UL, /* rx_length_errors +
1134 * rx_over_errors +
1135 * rx_crc_errors +
1136 * rx_frame_errors */
1137 0UL, /* rx_compressed */
1138 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1139 /* XXX-BZ rx only? */
1140 sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1141 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1142 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1143 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1144 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1145 0UL, /* tx_fifo_errors */
1146 (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1147 0UL, /* tx_carrier_errors +
1148 * tx_aborted_errors +
1149 * tx_window_errors +
1150 * tx_heartbeat_errors*/
1151 0UL); /* tx_compressed */
1152 }
1153 IFNET_RUNLOCK();
1154 CURVNET_RESTORE();
1155
1156 return (0);
1157 }
1158
1159 /*
1160 * Filler function for proc/sys/kernel/osrelease
1161 */
1162 static int
1163 linprocfs_doosrelease(PFS_FILL_ARGS)
1164 {
1165 char osrelease[LINUX_MAX_UTSNAME];
1166
1167 linux_get_osrelease(td, osrelease);
1168 sbuf_printf(sb, "%s\n", osrelease);
1169
1170 return (0);
1171 }
1172
1173 /*
1174 * Filler function for proc/sys/kernel/ostype
1175 */
1176 static int
1177 linprocfs_doostype(PFS_FILL_ARGS)
1178 {
1179 char osname[LINUX_MAX_UTSNAME];
1180
1181 linux_get_osname(td, osname);
1182 sbuf_printf(sb, "%s\n", osname);
1183
1184 return (0);
1185 }
1186
1187 /*
1188 * Filler function for proc/sys/kernel/version
1189 */
1190 static int
1191 linprocfs_doosbuild(PFS_FILL_ARGS)
1192 {
1193
1194 linprocfs_osbuild(td, sb);
1195 sbuf_cat(sb, "\n");
1196 return (0);
1197 }
1198
1199 /*
1200 * Filler function for proc/sys/kernel/msgmni
1201 */
1202 static int
1203 linprocfs_domsgmni(PFS_FILL_ARGS)
1204 {
1205
1206 sbuf_printf(sb, "%d\n", msginfo.msgmni);
1207 return (0);
1208 }
1209
1210 /*
1211 * Filler function for proc/sys/kernel/pid_max
1212 */
1213 static int
1214 linprocfs_dopid_max(PFS_FILL_ARGS)
1215 {
1216
1217 sbuf_printf(sb, "%i\n", PID_MAX);
1218 return (0);
1219 }
1220
1221 /*
1222 * Filler function for proc/sys/kernel/sem
1223 */
1224 static int
1225 linprocfs_dosem(PFS_FILL_ARGS)
1226 {
1227
1228 sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1229 seminfo.semopm, seminfo.semmni);
1230 return (0);
1231 }
1232
1233 /*
1234 * Filler function for proc/scsi/device_info
1235 */
1236 static int
1237 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1238 {
1239
1240 return (0);
1241 }
1242
1243 /*
1244 * Filler function for proc/scsi/scsi
1245 */
1246 static int
1247 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1248 {
1249
1250 return (0);
1251 }
1252
1253 /*
1254 * Filler function for proc/devices
1255 */
1256 static int
1257 linprocfs_dodevices(PFS_FILL_ARGS)
1258 {
1259 char *char_devices;
1260 sbuf_printf(sb, "Character devices:\n");
1261
1262 char_devices = linux_get_char_devices();
1263 sbuf_printf(sb, "%s", char_devices);
1264 linux_free_get_char_devices(char_devices);
1265
1266 sbuf_printf(sb, "\nBlock devices:\n");
1267
1268 return (0);
1269 }
1270
1271 /*
1272 * Filler function for proc/cmdline
1273 */
1274 static int
1275 linprocfs_docmdline(PFS_FILL_ARGS)
1276 {
1277
1278 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1279 sbuf_printf(sb, " ro root=302\n");
1280 return (0);
1281 }
1282
1283 /*
1284 * Filler function for proc/filesystems
1285 */
1286 static int
1287 linprocfs_dofilesystems(PFS_FILL_ARGS)
1288 {
1289 struct vfsconf *vfsp;
1290
1291 vfsconf_slock();
1292 TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1293 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1294 sbuf_printf(sb, "nodev");
1295 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1296 }
1297 vfsconf_sunlock();
1298 return(0);
1299 }
1300
1301 #if 0
1302 /*
1303 * Filler function for proc/modules
1304 */
1305 static int
1306 linprocfs_domodules(PFS_FILL_ARGS)
1307 {
1308 struct linker_file *lf;
1309
1310 TAILQ_FOREACH(lf, &linker_files, link) {
1311 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1312 (unsigned long)lf->size, lf->refs);
1313 }
1314 return (0);
1315 }
1316 #endif
1317
1318 /*
1319 * Filler function for proc/pid/fd
1320 */
1321 static int
1322 linprocfs_dofdescfs(PFS_FILL_ARGS)
1323 {
1324
1325 if (p == curproc)
1326 sbuf_printf(sb, "/dev/fd");
1327 else
1328 sbuf_printf(sb, "unknown");
1329 return (0);
1330 }
1331
1332 /*
1333 * Filler function for proc/pid/limits
1334 */
1335 static const struct linux_rlimit_ident {
1336 const char *desc;
1337 const char *unit;
1338 unsigned int rlim_id;
1339 } linux_rlimits_ident[] = {
1340 { "Max cpu time", "seconds", RLIMIT_CPU },
1341 { "Max file size", "bytes", RLIMIT_FSIZE },
1342 { "Max data size", "bytes", RLIMIT_DATA },
1343 { "Max stack size", "bytes", RLIMIT_STACK },
1344 { "Max core file size", "bytes", RLIMIT_CORE },
1345 { "Max resident set", "bytes", RLIMIT_RSS },
1346 { "Max processes", "processes", RLIMIT_NPROC },
1347 { "Max open files", "files", RLIMIT_NOFILE },
1348 { "Max locked memory", "bytes", RLIMIT_MEMLOCK },
1349 { "Max address space", "bytes", RLIMIT_AS },
1350 { "Max file locks", "locks", LINUX_RLIMIT_LOCKS },
1351 { "Max pending signals", "signals", LINUX_RLIMIT_SIGPENDING },
1352 { "Max msgqueue size", "bytes", LINUX_RLIMIT_MSGQUEUE },
1353 { "Max nice priority", "", LINUX_RLIMIT_NICE },
1354 { "Max realtime priority", "", LINUX_RLIMIT_RTPRIO },
1355 { "Max realtime timeout", "us", LINUX_RLIMIT_RTTIME },
1356 { 0, 0, 0 }
1357 };
1358
1359 static int
1360 linprocfs_doproclimits(PFS_FILL_ARGS)
1361 {
1362 const struct linux_rlimit_ident *li;
1363 struct plimit *limp;
1364 struct rlimit rl;
1365 ssize_t size;
1366 int res, error;
1367
1368 error = 0;
1369
1370 PROC_LOCK(p);
1371 limp = lim_hold(p->p_limit);
1372 PROC_UNLOCK(p);
1373 size = sizeof(res);
1374 sbuf_printf(sb, "%-26s%-21s%-21s%-21s\n", "Limit", "Soft Limit",
1375 "Hard Limit", "Units");
1376 for (li = linux_rlimits_ident; li->desc != NULL; ++li) {
1377 switch (li->rlim_id)
1378 {
1379 case LINUX_RLIMIT_LOCKS:
1380 /* FALLTHROUGH */
1381 case LINUX_RLIMIT_RTTIME:
1382 rl.rlim_cur = RLIM_INFINITY;
1383 break;
1384 case LINUX_RLIMIT_SIGPENDING:
1385 error = kernel_sysctlbyname(td,
1386 "kern.sigqueue.max_pending_per_proc",
1387 &res, &size, 0, 0, 0, 0);
1388 if (error != 0)
1389 goto out;
1390 rl.rlim_cur = res;
1391 rl.rlim_max = res;
1392 break;
1393 case LINUX_RLIMIT_MSGQUEUE:
1394 error = kernel_sysctlbyname(td,
1395 "kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
1396 if (error != 0)
1397 goto out;
1398 rl.rlim_cur = res;
1399 rl.rlim_max = res;
1400 break;
1401 case LINUX_RLIMIT_NICE:
1402 /* FALLTHROUGH */
1403 case LINUX_RLIMIT_RTPRIO:
1404 rl.rlim_cur = 0;
1405 rl.rlim_max = 0;
1406 break;
1407 default:
1408 rl = limp->pl_rlimit[li->rlim_id];
1409 break;
1410 }
1411 if (rl.rlim_cur == RLIM_INFINITY)
1412 sbuf_printf(sb, "%-26s%-21s%-21s%-10s\n",
1413 li->desc, "unlimited", "unlimited", li->unit);
1414 else
1415 sbuf_printf(sb, "%-26s%-21llu%-21llu%-10s\n",
1416 li->desc, (unsigned long long)rl.rlim_cur,
1417 (unsigned long long)rl.rlim_max, li->unit);
1418 }
1419 out:
1420 lim_free(limp);
1421 return (error);
1422 }
1423
1424 /*
1425 * Filler function for proc/sys/kernel/random/uuid
1426 */
1427 static int
1428 linprocfs_douuid(PFS_FILL_ARGS)
1429 {
1430 struct uuid uuid;
1431
1432 kern_uuidgen(&uuid, 1);
1433 sbuf_printf_uuid(sb, &uuid);
1434 sbuf_printf(sb, "\n");
1435 return(0);
1436 }
1437
1438 /*
1439 * Filler function for proc/pid/auxv
1440 */
1441 static int
1442 linprocfs_doauxv(PFS_FILL_ARGS)
1443 {
1444 struct sbuf *asb;
1445 off_t buflen, resid;
1446 int error;
1447
1448 /*
1449 * Mimic linux behavior and pass only processes with usermode
1450 * address space as valid. Return zero silently otherwise.
1451 */
1452 if (p->p_vmspace == &vmspace0)
1453 return (0);
1454
1455 if (uio->uio_resid == 0)
1456 return (0);
1457 if (uio->uio_offset < 0 || uio->uio_resid < 0)
1458 return (EINVAL);
1459
1460 asb = sbuf_new_auto();
1461 if (asb == NULL)
1462 return (ENOMEM);
1463 error = proc_getauxv(td, p, asb);
1464 if (error == 0)
1465 error = sbuf_finish(asb);
1466
1467 resid = sbuf_len(asb) - uio->uio_offset;
1468 if (resid > uio->uio_resid)
1469 buflen = uio->uio_resid;
1470 else
1471 buflen = resid;
1472 if (buflen > IOSIZE_MAX)
1473 return (EINVAL);
1474 if (buflen > MAXPHYS)
1475 buflen = MAXPHYS;
1476 if (resid <= 0)
1477 return (0);
1478
1479 if (error == 0)
1480 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1481 sbuf_delete(asb);
1482 return (error);
1483 }
1484
1485 /*
1486 * Constructor
1487 */
1488 static int
1489 linprocfs_init(PFS_INIT_ARGS)
1490 {
1491 struct pfs_node *root;
1492 struct pfs_node *dir;
1493
1494 root = pi->pi_root;
1495
1496 /* /proc/... */
1497 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1498 NULL, NULL, NULL, PFS_RD);
1499 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1500 NULL, NULL, NULL, PFS_RD);
1501 pfs_create_file(root, "devices", &linprocfs_dodevices,
1502 NULL, NULL, NULL, PFS_RD);
1503 pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1504 NULL, NULL, NULL, PFS_RD);
1505 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1506 NULL, NULL, NULL, PFS_RD);
1507 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1508 NULL, NULL, NULL, PFS_RD);
1509 #if 0
1510 pfs_create_file(root, "modules", &linprocfs_domodules,
1511 NULL, NULL, NULL, PFS_RD);
1512 #endif
1513 pfs_create_file(root, "mounts", &linprocfs_domtab,
1514 NULL, NULL, NULL, PFS_RD);
1515 pfs_create_file(root, "mtab", &linprocfs_domtab,
1516 NULL, NULL, NULL, PFS_RD);
1517 pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1518 NULL, NULL, NULL, PFS_RD);
1519 pfs_create_link(root, "self", &procfs_docurproc,
1520 NULL, NULL, NULL, 0);
1521 pfs_create_file(root, "stat", &linprocfs_dostat,
1522 NULL, NULL, NULL, PFS_RD);
1523 pfs_create_file(root, "swaps", &linprocfs_doswaps,
1524 NULL, NULL, NULL, PFS_RD);
1525 pfs_create_file(root, "uptime", &linprocfs_douptime,
1526 NULL, NULL, NULL, PFS_RD);
1527 pfs_create_file(root, "version", &linprocfs_doversion,
1528 NULL, NULL, NULL, PFS_RD);
1529
1530 /* /proc/net/... */
1531 dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1532 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1533 NULL, NULL, NULL, PFS_RD);
1534
1535 /* /proc/<pid>/... */
1536 dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1537 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1538 NULL, NULL, NULL, PFS_RD);
1539 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1540 NULL, NULL, NULL, 0);
1541 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1542 NULL, &procfs_candebug, NULL, PFS_RD);
1543 pfs_create_link(dir, "exe", &procfs_doprocfile,
1544 NULL, &procfs_notsystem, NULL, 0);
1545 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1546 NULL, NULL, NULL, PFS_RD);
1547 pfs_create_file(dir, "mem", &procfs_doprocmem,
1548 &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1549 pfs_create_file(dir, "mounts", &linprocfs_domtab,
1550 NULL, NULL, NULL, PFS_RD);
1551 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1552 NULL, NULL, NULL, 0);
1553 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1554 NULL, NULL, NULL, PFS_RD);
1555 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1556 NULL, NULL, NULL, PFS_RD);
1557 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1558 NULL, NULL, NULL, PFS_RD);
1559 pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1560 NULL, NULL, NULL, 0);
1561 pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1562 NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1563 pfs_create_file(dir, "limits", &linprocfs_doproclimits,
1564 NULL, NULL, NULL, PFS_RD);
1565
1566 /* /proc/scsi/... */
1567 dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1568 pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1569 NULL, NULL, NULL, PFS_RD);
1570 pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1571 NULL, NULL, NULL, PFS_RD);
1572
1573 /* /proc/sys/... */
1574 dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1575 /* /proc/sys/kernel/... */
1576 dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1577 pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1578 NULL, NULL, NULL, PFS_RD);
1579 pfs_create_file(dir, "ostype", &linprocfs_doostype,
1580 NULL, NULL, NULL, PFS_RD);
1581 pfs_create_file(dir, "version", &linprocfs_doosbuild,
1582 NULL, NULL, NULL, PFS_RD);
1583 pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1584 NULL, NULL, NULL, PFS_RD);
1585 pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1586 NULL, NULL, NULL, PFS_RD);
1587 pfs_create_file(dir, "sem", &linprocfs_dosem,
1588 NULL, NULL, NULL, PFS_RD);
1589
1590 /* /proc/sys/kernel/random/... */
1591 dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1592 pfs_create_file(dir, "uuid", &linprocfs_douuid,
1593 NULL, NULL, NULL, PFS_RD);
1594
1595 return (0);
1596 }
1597
1598 /*
1599 * Destructor
1600 */
1601 static int
1602 linprocfs_uninit(PFS_INIT_ARGS)
1603 {
1604
1605 /* nothing to do, pseudofs will GC */
1606 return (0);
1607 }
1608
1609 PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS);
1610 #if defined(__amd64__)
1611 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1612 #else
1613 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1614 #endif
1615 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1616 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1617 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);
Cache object: f2cfe59520a4922ca80fa0eb2e44cea7
|