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/filedesc.h>
51 #include <sys/jail.h>
52 #include <sys/kernel.h>
53 #include <sys/linker.h>
54 #include <sys/lock.h>
55 #include <sys/malloc.h>
56 #include <sys/mount.h>
57 #include <sys/mutex.h>
58 #include <sys/namei.h>
59 #include <sys/proc.h>
60 #include <sys/resourcevar.h>
61 #include <sys/sbuf.h>
62 #include <sys/smp.h>
63 #include <sys/socket.h>
64 #include <sys/sysctl.h>
65 #include <sys/systm.h>
66 #include <sys/tty.h>
67 #include <sys/user.h>
68 #include <sys/vmmeter.h>
69 #include <sys/vnode.h>
70
71 #include <net/if.h>
72
73 #include <vm/vm.h>
74 #include <vm/pmap.h>
75 #include <vm/vm_map.h>
76 #include <vm/vm_param.h>
77 #include <vm/vm_object.h>
78 #include <vm/swap_pager.h>
79
80 #include <machine/clock.h>
81
82 #ifdef __alpha__
83 #include <machine/alpha_cpu.h>
84 #include <machine/cpuconf.h>
85 #include <machine/rpb.h>
86 extern int ncpus;
87 #endif /* __alpha__ */
88
89 #if defined(__i386__) || defined(__amd64__)
90 #include <machine/cputypes.h>
91 #include <machine/md_var.h>
92 #endif /* __i386__ || __amd64__ */
93
94 #include "opt_compat.h"
95 #ifdef COMPAT_LINUX32 /* XXX */
96 #include <machine/../linux32/linux.h>
97 #else
98 #include <machine/../linux/linux.h>
99 #endif
100 #include <compat/linux/linux_ioctl.h>
101 #include <compat/linux/linux_mib.h>
102 #include <compat/linux/linux_util.h>
103 #include <fs/pseudofs/pseudofs.h>
104 #include <fs/procfs/procfs.h>
105
106 /*
107 * Various conversion macros
108 */
109 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */
110 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
111 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
112 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
113 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
114 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
115
116 /*
117 * Filler function for proc/meminfo
118 */
119 static int
120 linprocfs_domeminfo(PFS_FILL_ARGS)
121 {
122 unsigned long memtotal; /* total memory in bytes */
123 unsigned long memused; /* used memory in bytes */
124 unsigned long memfree; /* free memory in bytes */
125 unsigned long memshared; /* shared memory ??? */
126 unsigned long buffers, cached; /* buffer / cache memory ??? */
127 unsigned long long swaptotal; /* total swap space in bytes */
128 unsigned long long swapused; /* used swap space in bytes */
129 unsigned long long swapfree; /* free swap space in bytes */
130 vm_object_t object;
131 int i, j;
132
133 memtotal = physmem * PAGE_SIZE;
134 /*
135 * The correct thing here would be:
136 *
137 memfree = cnt.v_free_count * PAGE_SIZE;
138 memused = memtotal - memfree;
139 *
140 * but it might mislead linux binaries into thinking there
141 * is very little memory left, so we cheat and tell them that
142 * all memory that isn't wired down is free.
143 */
144 memused = cnt.v_wire_count * PAGE_SIZE;
145 memfree = memtotal - memused;
146 swap_pager_status(&i, &j);
147 swaptotal = (unsigned long long)i * PAGE_SIZE;
148 swapused = (unsigned long long)j * PAGE_SIZE;
149 swapfree = swaptotal - swapused;
150 memshared = 0;
151 mtx_lock(&vm_object_list_mtx);
152 TAILQ_FOREACH(object, &vm_object_list, object_list)
153 if (object->shadow_count > 1)
154 memshared += object->resident_page_count;
155 mtx_unlock(&vm_object_list_mtx);
156 memshared *= PAGE_SIZE;
157 /*
158 * We'd love to be able to write:
159 *
160 buffers = bufspace;
161 *
162 * but bufspace is internal to vfs_bio.c and we don't feel
163 * like unstaticizing it just for linprocfs's sake.
164 */
165 buffers = 0;
166 cached = cnt.v_cache_count * PAGE_SIZE;
167
168 sbuf_printf(sb,
169 " total: used: free: shared: buffers: cached:\n"
170 "Mem: %lu %lu %lu %lu %lu %lu\n"
171 "Swap: %llu %llu %llu\n"
172 "MemTotal: %9lu kB\n"
173 "MemFree: %9lu kB\n"
174 "MemShared:%9lu kB\n"
175 "Buffers: %9lu kB\n"
176 "Cached: %9lu kB\n"
177 "SwapTotal:%9llu kB\n"
178 "SwapFree: %9llu kB\n",
179 memtotal, memused, memfree, memshared, buffers, cached,
180 swaptotal, swapused, swapfree,
181 B2K(memtotal), B2K(memfree),
182 B2K(memshared), B2K(buffers), B2K(cached),
183 B2K(swaptotal), B2K(swapfree));
184
185 return (0);
186 }
187
188 #ifdef __alpha__
189 extern struct rpb *hwrpb;
190 /*
191 * Filler function for proc/cpuinfo (Alpha version)
192 */
193 static int
194 linprocfs_docpuinfo(PFS_FILL_ARGS)
195 {
196 u_int64_t type, major;
197 struct pcs *pcsp;
198 const char *model, *sysname;
199
200 static const char *cpuname[] = {
201 "EV3", "EV4", "Simulate", "LCA4", "EV5", "EV45", "EV56",
202 "EV6", "PCA56", "PCA57", "EV67", "EV68CB", "EV68AL"
203 };
204
205 pcsp = LOCATE_PCS(hwrpb, hwrpb->rpb_primary_cpu_id);
206 type = pcsp->pcs_proc_type;
207 major = (type & PCS_PROC_MAJOR) >> PCS_PROC_MAJORSHIFT;
208 if (major < sizeof(cpuname)/sizeof(char *)) {
209 model = cpuname[major - 1];
210 } else {
211 model = "unknown";
212 }
213
214 sysname = alpha_dsr_sysname();
215
216 sbuf_printf(sb,
217 "cpu\t\t\t: Alpha\n"
218 "cpu model\t\t: %s\n"
219 "cpu variation\t\t: %ld\n"
220 "cpu revision\t\t: %d\n"
221 "cpu serial number\t: %s\n"
222 "system type\t\t: %s\n"
223 "system variation\t: %s\n"
224 "system revision\t\t: %d\n"
225 "system serial number\t: %s\n"
226 "cycle frequency [Hz]\t: %lu\n"
227 "timer frequency [Hz]\t: %u\n"
228 "page size [bytes]\t: %ld\n"
229 "phys. address bits\t: %ld\n"
230 "max. addr. space #\t: %ld\n"
231 "BogoMIPS\t\t: %u.%02u\n"
232 "kernel unaligned acc\t: %d (pc=%x,va=%x)\n"
233 "user unaligned acc\t: %d (pc=%x,va=%x)\n"
234 "platform string\t\t: %s\n"
235 "cpus detected\t\t: %d\n"
236 ,
237 model,
238 pcsp->pcs_proc_var,
239 *(int *)hwrpb->rpb_revision,
240 " ",
241 " ",
242 "",
243 0,
244 " ",
245 hwrpb->rpb_cc_freq,
246 hz,
247 hwrpb->rpb_page_size,
248 hwrpb->rpb_phys_addr_size,
249 hwrpb->rpb_max_asn,
250 0, 0,
251 0, 0, 0,
252 0, 0, 0,
253 sysname,
254 ncpus);
255 return (0);
256 }
257 #endif /* __alpha__ */
258
259 #if defined(__i386__) || defined(__amd64__)
260 /*
261 * Filler function for proc/cpuinfo (i386 & amd64 version)
262 */
263 static int
264 linprocfs_docpuinfo(PFS_FILL_ARGS)
265 {
266 int class, fqmhz, fqkhz;
267 int i;
268
269 /*
270 * We default the flags to include all non-conflicting flags,
271 * and the Intel versions of conflicting flags.
272 */
273 static char *flags[] = {
274 "fpu", "vme", "de", "pse", "tsc",
275 "msr", "pae", "mce", "cx8", "apic",
276 "sep", "sep", "mtrr", "pge", "mca",
277 "cmov", "pat", "pse36", "pn", "b19",
278 "b20", "b21", "mmxext", "mmx", "fxsr",
279 "xmm", "b26", "b27", "b28", "b29",
280 "3dnowext", "3dnow"
281 };
282
283 switch (cpu_class) {
284 #ifdef __i386__
285 case CPUCLASS_286:
286 class = 2;
287 break;
288 case CPUCLASS_386:
289 class = 3;
290 break;
291 case CPUCLASS_486:
292 class = 4;
293 break;
294 case CPUCLASS_586:
295 class = 5;
296 break;
297 case CPUCLASS_686:
298 class = 6;
299 break;
300 default:
301 class = 0;
302 break;
303 #else
304 default:
305 class = 6;
306 break;
307 #endif
308 }
309
310 for (i = 0; i < mp_ncpus; ++i) {
311 sbuf_printf(sb,
312 "processor\t: %d\n"
313 "vendor_id\t: %.20s\n"
314 "cpu family\t: %d\n"
315 "model\t\t: %d\n"
316 "stepping\t: %d\n",
317 i, cpu_vendor, class, cpu, cpu_id & 0xf);
318 /* XXX per-cpu vendor / class / id? */
319 }
320
321 sbuf_cat(sb,
322 "flags\t\t:");
323
324 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
325 flags[16] = "fcmov";
326 } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
327 flags[24] = "cxmmx";
328 }
329
330 for (i = 0; i < 32; i++)
331 if (cpu_feature & (1 << i))
332 sbuf_printf(sb, " %s", flags[i]);
333 sbuf_cat(sb, "\n");
334 if (class >= 5) {
335 fqmhz = (tsc_freq + 4999) / 1000000;
336 fqkhz = ((tsc_freq + 4999) / 10000) % 100;
337 sbuf_printf(sb,
338 "cpu MHz\t\t: %d.%02d\n"
339 "bogomips\t: %d.%02d\n",
340 fqmhz, fqkhz, fqmhz, fqkhz);
341 }
342
343 return (0);
344 }
345 #endif /* __i386__ || __amd64__ */
346
347 /*
348 * Filler function for proc/mtab
349 *
350 * This file doesn't exist in Linux' procfs, but is included here so
351 * users can symlink /compat/linux/etc/mtab to /proc/mtab
352 */
353 static int
354 linprocfs_domtab(PFS_FILL_ARGS)
355 {
356 struct nameidata nd;
357 struct mount *mp;
358 const char *lep;
359 char *dlep, *flep, *mntto, *mntfrom, *fstype;
360 size_t lep_len;
361 int error;
362
363 /* resolve symlinks etc. in the emulation tree prefix */
364 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
365 flep = NULL;
366 if (namei(&nd) != 0 || vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
367 lep = linux_emul_path;
368 else
369 lep = dlep;
370 lep_len = strlen(lep);
371
372 mtx_lock(&mountlist_mtx);
373 error = 0;
374 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
375 /* determine device name */
376 mntfrom = mp->mnt_stat.f_mntfromname;
377
378 /* determine mount point */
379 mntto = mp->mnt_stat.f_mntonname;
380 if (strncmp(mntto, lep, lep_len) == 0 &&
381 mntto[lep_len] == '/')
382 mntto += lep_len;
383
384 /* determine fs type */
385 fstype = mp->mnt_stat.f_fstypename;
386 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
387 mntfrom = fstype = "proc";
388 else if (strcmp(fstype, "procfs") == 0)
389 continue;
390
391 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
392 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
393 #define ADD_OPTION(opt, name) \
394 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
395 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
396 ADD_OPTION(MNT_NOEXEC, "noexec");
397 ADD_OPTION(MNT_NOSUID, "nosuid");
398 ADD_OPTION(MNT_NODEV, "nodev");
399 ADD_OPTION(MNT_UNION, "union");
400 ADD_OPTION(MNT_ASYNC, "async");
401 ADD_OPTION(MNT_SUIDDIR, "suiddir");
402 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
403 ADD_OPTION(MNT_NOATIME, "noatime");
404 #undef ADD_OPTION
405 /* a real Linux mtab will also show NFS options */
406 sbuf_printf(sb, " 0 0\n");
407 }
408 mtx_unlock(&mountlist_mtx);
409 if (flep != NULL)
410 free(flep, M_TEMP);
411 return (error);
412 }
413
414 /*
415 * Filler function for proc/stat
416 */
417 static int
418 linprocfs_dostat(PFS_FILL_ARGS)
419 {
420 int i;
421
422 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
423 T2J(cp_time[CP_USER]),
424 T2J(cp_time[CP_NICE]),
425 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
426 T2J(cp_time[CP_IDLE]));
427 for (i = 0; i < mp_ncpus; ++i)
428 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
429 T2J(cp_time[CP_USER]) / mp_ncpus,
430 T2J(cp_time[CP_NICE]) / mp_ncpus,
431 T2J(cp_time[CP_SYS]) / mp_ncpus,
432 T2J(cp_time[CP_IDLE]) / mp_ncpus);
433 sbuf_printf(sb,
434 "disk 0 0 0 0\n"
435 "page %u %u\n"
436 "swap %u %u\n"
437 "intr %u\n"
438 "ctxt %u\n"
439 "btime %lld\n",
440 cnt.v_vnodepgsin,
441 cnt.v_vnodepgsout,
442 cnt.v_swappgsin,
443 cnt.v_swappgsout,
444 cnt.v_intr,
445 cnt.v_swtch,
446 (long long)boottime.tv_sec);
447 return (0);
448 }
449
450 /*
451 * Filler function for proc/uptime
452 */
453 static int
454 linprocfs_douptime(PFS_FILL_ARGS)
455 {
456 struct timeval tv;
457
458 getmicrouptime(&tv);
459 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
460 (long long)tv.tv_sec, tv.tv_usec / 10000,
461 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
462 return (0);
463 }
464
465 /*
466 * Filler function for proc/version
467 */
468 static int
469 linprocfs_doversion(PFS_FILL_ARGS)
470 {
471 char osname[LINUX_MAX_UTSNAME];
472 char osrelease[LINUX_MAX_UTSNAME];
473
474 linux_get_osname(td, osname);
475 linux_get_osrelease(td, osrelease);
476
477 sbuf_printf(sb,
478 "%s version %s (des@freebsd.org) (gcc version " __VERSION__ ")"
479 " #4 Sun Dec 18 04:30:00 CET 1977\n", osname, osrelease);
480 return (0);
481 }
482
483 /*
484 * Filler function for proc/loadavg
485 */
486 static int
487 linprocfs_doloadavg(PFS_FILL_ARGS)
488 {
489 sbuf_printf(sb,
490 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
491 (int)(averunnable.ldavg[0] / averunnable.fscale),
492 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
493 (int)(averunnable.ldavg[1] / averunnable.fscale),
494 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
495 (int)(averunnable.ldavg[2] / averunnable.fscale),
496 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
497 1, /* number of running tasks */
498 nprocs, /* number of tasks */
499 lastpid /* the last pid */
500 );
501
502 return (0);
503 }
504
505 /*
506 * Filler function for proc/pid/stat
507 */
508 static int
509 linprocfs_doprocstat(PFS_FILL_ARGS)
510 {
511 struct kinfo_proc kp;
512
513 PROC_LOCK(p);
514 fill_kinfo_proc(p, &kp);
515 sbuf_printf(sb, "%d", p->p_pid);
516 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
517 PS_ADD("comm", "(%s)", p->p_comm);
518 PS_ADD("statr", "%c", ''); /* XXX */
519 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
520 PS_ADD("pgrp", "%d", p->p_pgid);
521 PS_ADD("session", "%d", p->p_session->s_sid);
522 PROC_UNLOCK(p);
523 PS_ADD("tty", "%d", 0); /* XXX */
524 PS_ADD("tpgid", "%d", 0); /* XXX */
525 PS_ADD("flags", "%u", 0); /* XXX */
526 PS_ADD("minflt", "%u", 0); /* XXX */
527 PS_ADD("cminflt", "%u", 0); /* XXX */
528 PS_ADD("majflt", "%u", 0); /* XXX */
529 PS_ADD("cminflt", "%u", 0); /* XXX */
530 PS_ADD("utime", "%d", 0); /* XXX */
531 PS_ADD("stime", "%d", 0); /* XXX */
532 PS_ADD("cutime", "%d", 0); /* XXX */
533 PS_ADD("cstime", "%d", 0); /* XXX */
534 PS_ADD("counter", "%d", 0); /* XXX */
535 PS_ADD("priority", "%d", 0); /* XXX */
536 PS_ADD("timeout", "%u", 0); /* XXX */
537 PS_ADD("itrealvalue", "%u", 0); /* XXX */
538 PS_ADD("starttime", "%d", 0); /* XXX */
539 PS_ADD("vsize", "%ju", (uintmax_t)kp.ki_size);
540 PS_ADD("rss", "%ju", P2K((uintmax_t)kp.ki_rssize));
541 PS_ADD("rlim", "%u", 0); /* XXX */
542 PS_ADD("startcode", "%u", (unsigned)0);
543 PS_ADD("endcode", "%u", 0); /* XXX */
544 PS_ADD("startstack", "%u", 0); /* XXX */
545 PS_ADD("esp", "%u", 0); /* XXX */
546 PS_ADD("eip", "%u", 0); /* XXX */
547 PS_ADD("signal", "%d", 0); /* XXX */
548 PS_ADD("blocked", "%d", 0); /* XXX */
549 PS_ADD("sigignore", "%d", 0); /* XXX */
550 PS_ADD("sigcatch", "%d", 0); /* XXX */
551 PS_ADD("wchan", "%u", 0); /* XXX */
552 PS_ADD("nswap", "%lu", (long unsigned)0); /* XXX */
553 PS_ADD("cnswap", "%lu", (long unsigned)0); /* XXX */
554 PS_ADD("exitsignal", "%d", 0); /* XXX */
555 PS_ADD("processor", "%d", 0); /* XXX */
556 #undef PS_ADD
557 sbuf_putc(sb, '\n');
558
559 return (0);
560 }
561
562 /*
563 * Filler function for proc/pid/statm
564 */
565 static int
566 linprocfs_doprocstatm(PFS_FILL_ARGS)
567 {
568 struct kinfo_proc kp;
569 segsz_t lsize;
570
571 PROC_LOCK(p);
572 fill_kinfo_proc(p, &kp);
573 PROC_UNLOCK(p);
574
575 /*
576 * See comments in linprocfs_doprocstatus() regarding the
577 * computation of lsize.
578 */
579 /* size resident share trs drs lrs dt */
580 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
581 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
582 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
583 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
584 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
585 lsize = B2P(kp.ki_size) - kp.ki_dsize -
586 kp.ki_ssize - kp.ki_tsize - 1;
587 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
588 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
589
590 return (0);
591 }
592
593 /*
594 * Filler function for proc/pid/status
595 */
596 static int
597 linprocfs_doprocstatus(PFS_FILL_ARGS)
598 {
599 struct kinfo_proc kp;
600 char *state;
601 segsz_t lsize;
602 struct thread *td2;
603 struct sigacts *ps;
604 int i;
605
606 PROC_LOCK(p);
607 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
608
609 if (P_SHOULDSTOP(p)) {
610 state = "T (stopped)";
611 } else {
612 mtx_lock_spin(&sched_lock);
613 switch(p->p_state) {
614 case PRS_NEW:
615 state = "I (idle)";
616 break;
617 case PRS_NORMAL:
618 if (p->p_flag & P_WEXIT) {
619 state = "X (exiting)";
620 break;
621 }
622 switch(td2->td_state) {
623 case TDS_INHIBITED:
624 state = "S (sleeping)";
625 break;
626 case TDS_RUNQ:
627 case TDS_RUNNING:
628 state = "R (running)";
629 break;
630 default:
631 state = "? (unknown)";
632 break;
633 }
634 break;
635 case PRS_ZOMBIE:
636 state = "Z (zombie)";
637 break;
638 default:
639 state = "? (unknown)";
640 break;
641 }
642 mtx_unlock_spin(&sched_lock);
643 }
644
645 fill_kinfo_proc(p, &kp);
646 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
647 sbuf_printf(sb, "State:\t%s\n", state);
648
649 /*
650 * Credentials
651 */
652 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
653 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
654 p->p_pptr->p_pid : 0);
655 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
656 p->p_ucred->cr_uid,
657 p->p_ucred->cr_svuid,
658 /* FreeBSD doesn't have fsuid */
659 p->p_ucred->cr_uid);
660 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
661 p->p_ucred->cr_gid,
662 p->p_ucred->cr_svgid,
663 /* FreeBSD doesn't have fsgid */
664 p->p_ucred->cr_gid);
665 sbuf_cat(sb, "Groups:\t");
666 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
667 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
668 PROC_UNLOCK(p);
669 sbuf_putc(sb, '\n');
670
671 /*
672 * Memory
673 *
674 * While our approximation of VmLib may not be accurate (I
675 * don't know of a simple way to verify it, and I'm not sure
676 * it has much meaning anyway), I believe it's good enough.
677 *
678 * The same code that could (I think) accurately compute VmLib
679 * could also compute VmLck, but I don't really care enough to
680 * implement it. Submissions are welcome.
681 */
682 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
683 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
684 sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
685 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
686 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
687 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
688 lsize = B2P(kp.ki_size) - kp.ki_dsize -
689 kp.ki_ssize - kp.ki_tsize - 1;
690 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
691
692 /*
693 * Signal masks
694 *
695 * We support up to 128 signals, while Linux supports 32,
696 * but we only define 32 (the same 32 as Linux, to boot), so
697 * just show the lower 32 bits of each mask. XXX hack.
698 *
699 * NB: on certain platforms (Sparc at least) Linux actually
700 * supports 64 signals, but this code is a long way from
701 * running on anything but i386, so ignore that for now.
702 */
703 PROC_LOCK(p);
704 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
705 /*
706 * I can't seem to find out where the signal mask is in
707 * relation to struct proc, so SigBlk is left unimplemented.
708 */
709 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
710 ps = p->p_sigacts;
711 mtx_lock(&ps->ps_mtx);
712 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
713 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
714 mtx_unlock(&ps->ps_mtx);
715 PROC_UNLOCK(p);
716
717 /*
718 * Linux also prints the capability masks, but we don't have
719 * capabilities yet, and when we do get them they're likely to
720 * be meaningless to Linux programs, so we lie. XXX
721 */
722 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
723 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
724 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
725
726 return (0);
727 }
728
729
730 /*
731 * Filler function for proc/pid/cwd
732 */
733 static int
734 linprocfs_doproccwd(PFS_FILL_ARGS)
735 {
736 char *fullpath = "unknown";
737 char *freepath = NULL;
738
739 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
740 sbuf_printf(sb, "%s", fullpath);
741 if (freepath)
742 free(freepath, M_TEMP);
743 return (0);
744 }
745
746 /*
747 * Filler function for proc/pid/root
748 */
749 static int
750 linprocfs_doprocroot(PFS_FILL_ARGS)
751 {
752 struct vnode *rvp;
753 char *fullpath = "unknown";
754 char *freepath = NULL;
755
756 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
757 vn_fullpath(td, rvp, &fullpath, &freepath);
758 sbuf_printf(sb, "%s", fullpath);
759 if (freepath)
760 free(freepath, M_TEMP);
761 return (0);
762 }
763
764 /*
765 * Filler function for proc/pid/cmdline
766 */
767 static int
768 linprocfs_doproccmdline(PFS_FILL_ARGS)
769 {
770 struct ps_strings pstr;
771 char **ps_argvstr;
772 int error, i;
773
774 /*
775 * If we are using the ps/cmdline caching, use that. Otherwise
776 * revert back to the old way which only implements full cmdline
777 * for the currept process and just p->p_comm for all other
778 * processes.
779 * Note that if the argv is no longer available, we deliberately
780 * don't fall back on p->p_comm or return an error: the authentic
781 * Linux behaviour is to return zero-length in this case.
782 */
783
784 PROC_LOCK(p);
785 if (p->p_args && p_cansee(td, p) == 0) {
786 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
787 PROC_UNLOCK(p);
788 } else if (p != td->td_proc) {
789 PROC_UNLOCK(p);
790 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
791 } else {
792 PROC_UNLOCK(p);
793 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
794 sizeof(pstr));
795 if (error)
796 return (error);
797 if (pstr.ps_nargvstr > ARG_MAX)
798 return (E2BIG);
799 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
800 M_TEMP, M_WAITOK);
801 error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
802 pstr.ps_nargvstr * sizeof(char *));
803 if (error) {
804 free(ps_argvstr, M_TEMP);
805 return (error);
806 }
807 for (i = 0; i < pstr.ps_nargvstr; i++) {
808 sbuf_copyin(sb, ps_argvstr[i], 0);
809 sbuf_printf(sb, "%c", '\0');
810 }
811 free(ps_argvstr, M_TEMP);
812 }
813
814 return (0);
815 }
816
817 /*
818 * Filler function for proc/pid/environ
819 */
820 static int
821 linprocfs_doprocenviron(PFS_FILL_ARGS)
822 {
823 sbuf_printf(sb, "doprocenviron\n%c", '\0');
824
825 return (0);
826 }
827
828 /*
829 * Filler function for proc/pid/maps
830 */
831 static int
832 linprocfs_doprocmaps(PFS_FILL_ARGS)
833 {
834 char mebuffer[512];
835 vm_map_t map = &p->p_vmspace->vm_map;
836 vm_map_entry_t entry;
837 vm_object_t obj, tobj, lobj;
838 vm_ooffset_t off = 0;
839 char *name = "", *freename = NULL;
840 size_t len;
841 ino_t ino;
842 int ref_count, shadow_count, flags;
843 int error;
844
845 PROC_LOCK(p);
846 error = p_candebug(td, p);
847 PROC_UNLOCK(p);
848 if (error)
849 return (error);
850
851 if (uio->uio_rw != UIO_READ)
852 return (EOPNOTSUPP);
853
854 if (uio->uio_offset != 0)
855 return (0);
856
857 error = 0;
858 if (map != &curthread->td_proc->p_vmspace->vm_map)
859 vm_map_lock_read(map);
860 for (entry = map->header.next;
861 ((uio->uio_resid > 0) && (entry != &map->header));
862 entry = entry->next) {
863 name = "";
864 freename = NULL;
865 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
866 continue;
867 obj = entry->object.vm_object;
868 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object)
869 lobj = tobj;
870 ino = 0;
871 if (lobj) {
872 VM_OBJECT_LOCK(lobj);
873 off = IDX_TO_OFF(lobj->size);
874 if (lobj->type == OBJT_VNODE && lobj->handle) {
875 vn_fullpath(td, (struct vnode *)lobj->handle,
876 &name, &freename);
877 ino = ((struct vnode *)
878 lobj->handle)->v_cachedid;
879 }
880 flags = obj->flags;
881 ref_count = obj->ref_count;
882 shadow_count = obj->shadow_count;
883 VM_OBJECT_UNLOCK(lobj);
884 } else {
885 flags = 0;
886 ref_count = 0;
887 shadow_count = 0;
888 }
889
890 /*
891 * format:
892 * start, end, access, offset, major, minor, inode, name.
893 */
894 snprintf(mebuffer, sizeof mebuffer,
895 "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n",
896 (u_long)entry->start, (u_long)entry->end,
897 (entry->protection & VM_PROT_READ)?"r":"-",
898 (entry->protection & VM_PROT_WRITE)?"w":"-",
899 (entry->protection & VM_PROT_EXECUTE)?"x":"-",
900 "p",
901 (u_long)off,
902 0,
903 0,
904 (u_long)ino,
905 *name ? " " : "",
906 name
907 );
908 if (freename)
909 free(freename, M_TEMP);
910 len = strlen(mebuffer);
911 if (len > uio->uio_resid)
912 len = uio->uio_resid; /*
913 * XXX We should probably return
914 * EFBIG here, as in procfs.
915 */
916 error = uiomove(mebuffer, len, uio);
917 if (error)
918 break;
919 }
920 if (map != &curthread->td_proc->p_vmspace->vm_map)
921 vm_map_unlock_read(map);
922
923 return (error);
924 }
925
926 /*
927 * Filler function for proc/net/dev
928 */
929 static int
930 linprocfs_donetdev(PFS_FILL_ARGS)
931 {
932 char ifname[16]; /* XXX LINUX_IFNAMSIZ */
933 struct ifnet *ifp;
934
935 sbuf_printf(sb, "%6s|%58s|%s\n%6s|%58s|%58s\n",
936 "Inter-", " Receive", " Transmit", " face",
937 "bytes packets errs drop fifo frame compressed",
938 "bytes packets errs drop fifo frame compressed");
939
940 IFNET_RLOCK();
941 TAILQ_FOREACH(ifp, &ifnet, if_link) {
942 linux_ifname(ifp, ifname, sizeof ifname);
943 sbuf_printf(sb, "%6.6s:", ifname);
944 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu ",
945 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
946 sbuf_printf(sb, "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
947 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
948 }
949 IFNET_RUNLOCK();
950
951 return (0);
952 }
953
954 #if 0
955 extern struct cdevsw *cdevsw[];
956
957 /*
958 * Filler function for proc/devices
959 */
960 static int
961 linprocfs_dodevices(PFS_FILL_ARGS)
962 {
963 int i;
964
965 sbuf_printf(sb, "Character devices:\n");
966
967 for (i = 0; i < NUMCDEVSW; i++)
968 if (cdevsw[i] != NULL)
969 sbuf_printf(sb, "%3d %s\n", i, cdevsw[i]->d_name);
970
971 sbuf_printf(sb, "\nBlock devices:\n");
972
973 return (0);
974 }
975 #endif
976
977 /*
978 * Filler function for proc/cmdline
979 */
980 static int
981 linprocfs_docmdline(PFS_FILL_ARGS)
982 {
983 sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
984 sbuf_printf(sb, " ro root=302\n");
985 return (0);
986 }
987
988 #if 0
989 /*
990 * Filler function for proc/modules
991 */
992 static int
993 linprocfs_domodules(PFS_FILL_ARGS)
994 {
995 struct linker_file *lf;
996
997 TAILQ_FOREACH(lf, &linker_files, link) {
998 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
999 (unsigned long)lf->size, lf->refs);
1000 }
1001 return (0);
1002 }
1003 #endif
1004
1005 /*
1006 * Constructor
1007 */
1008 static int
1009 linprocfs_init(PFS_INIT_ARGS)
1010 {
1011 struct pfs_node *root;
1012 struct pfs_node *dir;
1013
1014 root = pi->pi_root;
1015
1016 /* /proc/... */
1017 pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1018 NULL, NULL, PFS_RD);
1019 pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1020 NULL, NULL, PFS_RD);
1021 #if 0
1022 pfs_create_file(root, "devices", &linprocfs_dodevices,
1023 NULL, NULL, PFS_RD);
1024 #endif
1025 pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1026 NULL, NULL, PFS_RD);
1027 pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1028 NULL, NULL, PFS_RD);
1029 #if 0
1030 pfs_create_file(root, "modules", &linprocfs_domodules,
1031 NULL, NULL, PFS_RD);
1032 #endif
1033 pfs_create_file(root, "mtab", &linprocfs_domtab,
1034 NULL, NULL, PFS_RD);
1035 pfs_create_link(root, "self", &procfs_docurproc,
1036 NULL, NULL, 0);
1037 pfs_create_file(root, "stat", &linprocfs_dostat,
1038 NULL, NULL, PFS_RD);
1039 pfs_create_file(root, "uptime", &linprocfs_douptime,
1040 NULL, NULL, PFS_RD);
1041 pfs_create_file(root, "version", &linprocfs_doversion,
1042 NULL, NULL, PFS_RD);
1043
1044 /* /proc/net/... */
1045 dir = pfs_create_dir(root, "net", NULL, NULL, 0);
1046 pfs_create_file(dir, "dev", &linprocfs_donetdev,
1047 NULL, NULL, PFS_RD);
1048
1049 /* /proc/<pid>/... */
1050 dir = pfs_create_dir(root, "pid", NULL, NULL, PFS_PROCDEP);
1051 pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1052 NULL, NULL, PFS_RD);
1053 pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1054 NULL, NULL, 0);
1055 pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1056 NULL, NULL, PFS_RD);
1057 pfs_create_link(dir, "exe", &procfs_doprocfile,
1058 NULL, &procfs_notsystem, 0);
1059 pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1060 NULL, NULL, PFS_RD);
1061 pfs_create_file(dir, "mem", &procfs_doprocmem,
1062 &procfs_attr, &procfs_candebug, PFS_RDWR|PFS_RAW);
1063 pfs_create_link(dir, "root", &linprocfs_doprocroot,
1064 NULL, NULL, 0);
1065 pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1066 NULL, NULL, PFS_RD);
1067 pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1068 NULL, NULL, PFS_RD);
1069 pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1070 NULL, NULL, PFS_RD);
1071
1072 return (0);
1073 }
1074
1075 /*
1076 * Destructor
1077 */
1078 static int
1079 linprocfs_uninit(PFS_INIT_ARGS)
1080 {
1081
1082 /* nothing to do, pseudofs will GC */
1083 return (0);
1084 }
1085
1086 PSEUDOFS(linprocfs, 1);
1087 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1088 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
Cache object: 4c2f5b8b80e90df08f7b1c1fd03a80f1
|