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