1 /*-
2 * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
3 * Copyright (c) 1999 Pierre Beyssac
4 * Copyright (c) 1993 Jan-Simon Pendry
5 * Copyright (c) 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 * @(#)procfs_status.c 8.4 (Berkeley) 6/15/94
40 */
41
42 #include "opt_compat.h"
43
44 #include <sys/cdefs.h>
45 __FBSDID("$FreeBSD: src/sys/compat/linprocfs/linprocfs.c,v 1.133 2008/12/29 12:45:11 kib Exp $");
46
47 #include <sys/param.h>
48 #include <sys/queue.h>
49 #include <sys/blist.h>
50 #include <sys/conf.h>
51 #include <sys/exec.h>
52 #include <sys/fcntl.h>
53 #include <sys/filedesc.h>
54 #include <sys/jail.h>
55 #include <sys/kernel.h>
56 #include <sys/linker.h>
57 #include <sys/lock.h>
58 #include <sys/malloc.h>
59 #include <sys/mount.h>
60 #include <sys/msg.h>
61 #include <sys/mutex.h>
62 #include <sys/namei.h>
63 #include <sys/proc.h>
64 #include <sys/resourcevar.h>
65 #include <sys/sbuf.h>
66 #include <sys/sem.h>
67 #include <sys/smp.h>
68 #include <sys/socket.h>
69 #include <sys/sysctl.h>
70 #include <sys/systm.h>
71 #include <sys/time.h>
72 #include <sys/tty.h>
73 #include <sys/user.h>
74 #include <sys/vmmeter.h>
75 #include <sys/vnode.h>
76 #include <sys/vimage.h>
77
78 #include <net/if.h>
79 #include <net/vnet.h>
80
81 #include <vm/vm.h>
82 #include <vm/vm_extern.h>
83 #include <vm/pmap.h>
84 #include <vm/vm_map.h>
85 #include <vm/vm_param.h>
86 #include <vm/vm_object.h>
87 #include <vm/swap_pager.h>
88
89 #include <machine/clock.h>
90
91 #if defined(__i386__) || defined(__amd64__)
92 #include <machine/cputypes.h>
93 #include <machine/md_var.h>
94 #endif /* __i386__ || __amd64__ */
95
96 #ifdef COMPAT_LINUX32 /* XXX */
97 #include <machine/../linux32/linux.h>
98 #else
99 #include <machine/../linux/linux.h>
100 #endif
101 #include <compat/linux/linux_ioctl.h>
102 #include <compat/linux/linux_mib.h>
103 #include <compat/linux/linux_util.h>
104 #include <fs/pseudofs/pseudofs.h>
105 #include <fs/procfs/procfs.h>
106
107 /*
108 * Various conversion macros
109 */
110 #define T2J(x) (((x) * 100UL) / (stathz ? stathz : hz)) /* ticks to jiffies */
111 #define T2S(x) ((x) / (stathz ? stathz : hz)) /* ticks to seconds */
112 #define B2K(x) ((x) >> 10) /* bytes to kbytes */
113 #define B2P(x) ((x) >> PAGE_SHIFT) /* bytes to pages */
114 #define P2B(x) ((x) << PAGE_SHIFT) /* pages to bytes */
115 #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* pages to kbytes */
116
117 /**
118 * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
119 *
120 * The linux procfs state field displays one of the characters RSDZTW to
121 * denote running, sleeping in an interruptible wait, waiting in an
122 * uninterruptible disk sleep, a zombie process, process is being traced
123 * or stopped, or process is paging respectively.
124 *
125 * Our struct kinfo_proc contains the variable ki_stat which contains a
126 * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
127 *
128 * This character array is used with ki_stati-1 as an index and tries to
129 * map our states to suitable linux states.
130 */
131 static char linux_state[] = "RRSTZDD";
132
133 /*
134 * Filler function for proc/meminfo
135 */
136 static int
137 linprocfs_domeminfo(PFS_FILL_ARGS)
138 {
139 unsigned long memtotal; /* total memory in bytes */
140 unsigned long memused; /* used memory in bytes */
141 unsigned long memfree; /* free memory in bytes */
142 unsigned long memshared; /* shared memory ??? */
143 unsigned long buffers, cached; /* buffer / cache memory ??? */
144 unsigned long long swaptotal; /* total swap space in bytes */
145 unsigned long long swapused; /* used swap space in bytes */
146 unsigned long long swapfree; /* free swap space in bytes */
147 vm_object_t object;
148 int i, j;
149
150 memtotal = physmem * PAGE_SIZE;
151 /*
152 * The correct thing here would be:
153 *
154 memfree = cnt.v_free_count * PAGE_SIZE;
155 memused = memtotal - memfree;
156 *
157 * but it might mislead linux binaries into thinking there
158 * is very little memory left, so we cheat and tell them that
159 * all memory that isn't wired down is free.
160 */
161 memused = cnt.v_wire_count * PAGE_SIZE;
162 memfree = memtotal - memused;
163 swap_pager_status(&i, &j);
164 swaptotal = (unsigned long long)i * PAGE_SIZE;
165 swapused = (unsigned long long)j * PAGE_SIZE;
166 swapfree = swaptotal - swapused;
167 memshared = 0;
168 mtx_lock(&vm_object_list_mtx);
169 TAILQ_FOREACH(object, &vm_object_list, object_list)
170 if (object->shadow_count > 1)
171 memshared += object->resident_page_count;
172 mtx_unlock(&vm_object_list_mtx);
173 memshared *= PAGE_SIZE;
174 /*
175 * We'd love to be able to write:
176 *
177 buffers = bufspace;
178 *
179 * but bufspace is internal to vfs_bio.c and we don't feel
180 * like unstaticizing it just for linprocfs's sake.
181 */
182 buffers = 0;
183 cached = cnt.v_cache_count * PAGE_SIZE;
184
185 sbuf_printf(sb,
186 " total: used: free: shared: buffers: cached:\n"
187 "Mem: %lu %lu %lu %lu %lu %lu\n"
188 "Swap: %llu %llu %llu\n"
189 "MemTotal: %9lu kB\n"
190 "MemFree: %9lu kB\n"
191 "MemShared:%9lu kB\n"
192 "Buffers: %9lu kB\n"
193 "Cached: %9lu kB\n"
194 "SwapTotal:%9llu kB\n"
195 "SwapFree: %9llu kB\n",
196 memtotal, memused, memfree, memshared, buffers, cached,
197 swaptotal, swapused, swapfree,
198 B2K(memtotal), B2K(memfree),
199 B2K(memshared), B2K(buffers), B2K(cached),
200 B2K(swaptotal), B2K(swapfree));
201
202 return (0);
203 }
204
205 #if defined(__i386__) || defined(__amd64__)
206 /*
207 * Filler function for proc/cpuinfo (i386 & amd64 version)
208 */
209 static int
210 linprocfs_docpuinfo(PFS_FILL_ARGS)
211 {
212 int hw_model[2];
213 char model[128];
214 size_t size;
215 int class, fqmhz, fqkhz;
216 int i;
217
218 /*
219 * We default the flags to include all non-conflicting flags,
220 * and the Intel versions of conflicting flags.
221 */
222 static char *flags[] = {
223 "fpu", "vme", "de", "pse", "tsc",
224 "msr", "pae", "mce", "cx8", "apic",
225 "sep", "sep", "mtrr", "pge", "mca",
226 "cmov", "pat", "pse36", "pn", "b19",
227 "b20", "b21", "mmxext", "mmx", "fxsr",
228 "xmm", "sse2", "b27", "b28", "b29",
229 "3dnowext", "3dnow"
230 };
231
232 switch (cpu_class) {
233 #ifdef __i386__
234 case CPUCLASS_286:
235 class = 2;
236 break;
237 case CPUCLASS_386:
238 class = 3;
239 break;
240 case CPUCLASS_486:
241 class = 4;
242 break;
243 case CPUCLASS_586:
244 class = 5;
245 break;
246 case CPUCLASS_686:
247 class = 6;
248 break;
249 default:
250 class = 0;
251 break;
252 #else /* __amd64__ */
253 default:
254 class = 15;
255 break;
256 #endif
257 }
258
259 hw_model[0] = CTL_HW;
260 hw_model[1] = HW_MODEL;
261 model[0] = '\0';
262 size = sizeof(model);
263 if (kernel_sysctl(td, hw_model, 2, &model, &size, 0, 0, 0, 0) != 0)
264 strcpy(model, "unknown");
265 for (i = 0; i < mp_ncpus; ++i) {
266 sbuf_printf(sb,
267 "processor\t: %d\n"
268 "vendor_id\t: %.20s\n"
269 "cpu family\t: %d\n"
270 "model\t\t: %d\n"
271 "model name\t: %s\n"
272 "stepping\t: %d\n",
273 i, cpu_vendor, class, cpu, model, cpu_id & 0xf);
274 /* XXX per-cpu vendor / class / model / id? */
275 }
276
277 sbuf_cat(sb, "flags\t\t:");
278
279 if (!strcmp(cpu_vendor, "AuthenticAMD") && (class < 6)) {
280 flags[16] = "fcmov";
281 } else if (!strcmp(cpu_vendor, "CyrixInstead")) {
282 flags[24] = "cxmmx";
283 }
284
285 for (i = 0; i < 32; i++)
286 if (cpu_feature & (1 << i))
287 sbuf_printf(sb, " %s", flags[i]);
288 sbuf_cat(sb, "\n");
289 if (class >= 5) {
290 fqmhz = (tsc_freq + 4999) / 1000000;
291 fqkhz = ((tsc_freq + 4999) / 10000) % 100;
292 sbuf_printf(sb,
293 "cpu MHz\t\t: %d.%02d\n"
294 "bogomips\t: %d.%02d\n",
295 fqmhz, fqkhz, fqmhz, fqkhz);
296 }
297
298 return (0);
299 }
300 #endif /* __i386__ || __amd64__ */
301
302 /*
303 * Filler function for proc/mtab
304 *
305 * This file doesn't exist in Linux' procfs, but is included here so
306 * users can symlink /compat/linux/etc/mtab to /proc/mtab
307 */
308 static int
309 linprocfs_domtab(PFS_FILL_ARGS)
310 {
311 struct nameidata nd;
312 struct mount *mp;
313 const char *lep;
314 char *dlep, *flep, *mntto, *mntfrom, *fstype;
315 size_t lep_len;
316 int error;
317
318 /* resolve symlinks etc. in the emulation tree prefix */
319 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, linux_emul_path, td);
320 flep = NULL;
321 error = namei(&nd);
322 lep = linux_emul_path;
323 if (error == 0) {
324 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) != 0)
325 lep = dlep;
326 vrele(nd.ni_vp);
327 VFS_UNLOCK_GIANT(NDHASGIANT(&nd));
328 }
329 lep_len = strlen(lep);
330
331 mtx_lock(&mountlist_mtx);
332 error = 0;
333 TAILQ_FOREACH(mp, &mountlist, mnt_list) {
334 /* determine device name */
335 mntfrom = mp->mnt_stat.f_mntfromname;
336
337 /* determine mount point */
338 mntto = mp->mnt_stat.f_mntonname;
339 if (strncmp(mntto, lep, lep_len) == 0 &&
340 mntto[lep_len] == '/')
341 mntto += lep_len;
342
343 /* determine fs type */
344 fstype = mp->mnt_stat.f_fstypename;
345 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
346 mntfrom = fstype = "proc";
347 else if (strcmp(fstype, "procfs") == 0)
348 continue;
349
350 if (strcmp(fstype, "linsysfs") == 0) {
351 sbuf_printf(sb, "/sys %s sysfs %s", mntto,
352 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
353 } else {
354 sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
355 mp->mnt_stat.f_flags & MNT_RDONLY ? "ro" : "rw");
356 }
357 #define ADD_OPTION(opt, name) \
358 if (mp->mnt_stat.f_flags & (opt)) sbuf_printf(sb, "," name);
359 ADD_OPTION(MNT_SYNCHRONOUS, "sync");
360 ADD_OPTION(MNT_NOEXEC, "noexec");
361 ADD_OPTION(MNT_NOSUID, "nosuid");
362 ADD_OPTION(MNT_UNION, "union");
363 ADD_OPTION(MNT_ASYNC, "async");
364 ADD_OPTION(MNT_SUIDDIR, "suiddir");
365 ADD_OPTION(MNT_NOSYMFOLLOW, "nosymfollow");
366 ADD_OPTION(MNT_NOATIME, "noatime");
367 #undef ADD_OPTION
368 /* a real Linux mtab will also show NFS options */
369 sbuf_printf(sb, " 0 0\n");
370 }
371 mtx_unlock(&mountlist_mtx);
372 if (flep != NULL)
373 free(flep, M_TEMP);
374 return (error);
375 }
376
377 /*
378 * Filler function for proc/stat
379 */
380 static int
381 linprocfs_dostat(PFS_FILL_ARGS)
382 {
383 struct pcpu *pcpu;
384 long cp_time[CPUSTATES];
385 long *cp;
386 int i;
387
388 read_cpu_time(cp_time);
389 sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
390 T2J(cp_time[CP_USER]),
391 T2J(cp_time[CP_NICE]),
392 T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
393 T2J(cp_time[CP_IDLE]));
394 for (i = 0; i <= mp_maxid; ++i) {
395 if (CPU_ABSENT(i))
396 continue;
397 pcpu = pcpu_find(i);
398 cp = pcpu->pc_cp_time;
399 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
400 T2J(cp[CP_USER]),
401 T2J(cp[CP_NICE]),
402 T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
403 T2J(cp[CP_IDLE]));
404 }
405 sbuf_printf(sb,
406 "disk 0 0 0 0\n"
407 "page %u %u\n"
408 "swap %u %u\n"
409 "intr %u\n"
410 "ctxt %u\n"
411 "btime %lld\n",
412 cnt.v_vnodepgsin,
413 cnt.v_vnodepgsout,
414 cnt.v_swappgsin,
415 cnt.v_swappgsout,
416 cnt.v_intr,
417 cnt.v_swtch,
418 (long long)boottime.tv_sec);
419 return (0);
420 }
421
422 /*
423 * Filler function for proc/uptime
424 */
425 static int
426 linprocfs_douptime(PFS_FILL_ARGS)
427 {
428 long cp_time[CPUSTATES];
429 struct timeval tv;
430
431 getmicrouptime(&tv);
432 read_cpu_time(cp_time);
433 sbuf_printf(sb, "%lld.%02ld %ld.%02ld\n",
434 (long long)tv.tv_sec, tv.tv_usec / 10000,
435 T2S(cp_time[CP_IDLE]), T2J(cp_time[CP_IDLE]) % 100);
436 return (0);
437 }
438
439 /*
440 * Get OS build date
441 */
442 static void
443 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
444 {
445 #if 0
446 char osbuild[256];
447 char *cp1, *cp2;
448
449 strncpy(osbuild, version, 256);
450 osbuild[255] = '\0';
451 cp1 = strstr(osbuild, "\n");
452 cp2 = strstr(osbuild, ":");
453 if (cp1 && cp2) {
454 *cp1 = *cp2 = '\0';
455 cp1 = strstr(osbuild, "#");
456 } else
457 cp1 = NULL;
458 if (cp1)
459 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
460 else
461 #endif
462 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
463 }
464
465 /*
466 * Get OS builder
467 */
468 static void
469 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
470 {
471 #if 0
472 char builder[256];
473 char *cp;
474
475 cp = strstr(version, "\n ");
476 if (cp) {
477 strncpy(builder, cp + 5, 256);
478 builder[255] = '\0';
479 cp = strstr(builder, ":");
480 if (cp)
481 *cp = '\0';
482 }
483 if (cp)
484 sbuf_cat(sb, builder);
485 else
486 #endif
487 sbuf_cat(sb, "des@freebsd.org");
488 }
489
490 /*
491 * Filler function for proc/version
492 */
493 static int
494 linprocfs_doversion(PFS_FILL_ARGS)
495 {
496 char osname[LINUX_MAX_UTSNAME];
497 char osrelease[LINUX_MAX_UTSNAME];
498
499 linux_get_osname(td, osname);
500 linux_get_osrelease(td, osrelease);
501 sbuf_printf(sb, "%s version %s (", osname, osrelease);
502 linprocfs_osbuilder(td, sb);
503 sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
504 linprocfs_osbuild(td, sb);
505 sbuf_cat(sb, "\n");
506
507 return (0);
508 }
509
510 /*
511 * Filler function for proc/loadavg
512 */
513 static int
514 linprocfs_doloadavg(PFS_FILL_ARGS)
515 {
516
517 sbuf_printf(sb,
518 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
519 (int)(averunnable.ldavg[0] / averunnable.fscale),
520 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
521 (int)(averunnable.ldavg[1] / averunnable.fscale),
522 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
523 (int)(averunnable.ldavg[2] / averunnable.fscale),
524 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
525 1, /* number of running tasks */
526 nprocs, /* number of tasks */
527 lastpid /* the last pid */
528 );
529 return (0);
530 }
531
532 /*
533 * Filler function for proc/pid/stat
534 */
535 static int
536 linprocfs_doprocstat(PFS_FILL_ARGS)
537 {
538 struct kinfo_proc kp;
539 char state;
540 static int ratelimit = 0;
541
542 PROC_LOCK(p);
543 fill_kinfo_proc(p, &kp);
544 sbuf_printf(sb, "%d", p->p_pid);
545 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
546 PS_ADD("comm", "(%s)", p->p_comm);
547 if (kp.ki_stat > sizeof(linux_state)) {
548 state = 'R';
549
550 if (ratelimit == 0) {
551 printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
552 kp.ki_stat, sizeof(linux_state));
553 ++ratelimit;
554 }
555 } else
556 state = linux_state[kp.ki_stat - 1];
557 PS_ADD("state", "%c", state);
558 PS_ADD("ppid", "%d", p->p_pptr ? p->p_pptr->p_pid : 0);
559 PS_ADD("pgrp", "%d", p->p_pgid);
560 PS_ADD("session", "%d", p->p_session->s_sid);
561 PROC_UNLOCK(p);
562 PS_ADD("tty", "%d", 0); /* XXX */
563 PS_ADD("tpgid", "%d", kp.ki_tpgid);
564 PS_ADD("flags", "%u", 0); /* XXX */
565 PS_ADD("minflt", "%lu", kp.ki_rusage.ru_minflt);
566 PS_ADD("cminflt", "%lu", kp.ki_rusage_ch.ru_minflt);
567 PS_ADD("majflt", "%lu", kp.ki_rusage.ru_majflt);
568 PS_ADD("cmajflt", "%lu", kp.ki_rusage_ch.ru_majflt);
569 PS_ADD("utime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_utime)));
570 PS_ADD("stime", "%ld", T2J(tvtohz(&kp.ki_rusage.ru_stime)));
571 PS_ADD("cutime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_utime)));
572 PS_ADD("cstime", "%ld", T2J(tvtohz(&kp.ki_rusage_ch.ru_stime)));
573 PS_ADD("priority", "%d", kp.ki_pri.pri_user);
574 PS_ADD("nice", "%d", kp.ki_nice); /* 19 (nicest) to -19 */
575 PS_ADD("", "%d", 0); /* removed field */
576 PS_ADD("itrealvalue", "%d", 0); /* XXX */
577 /* XXX: starttime is not right, it is the _same_ for _every_ process.
578 It should be the number of jiffies between system boot and process
579 start. */
580 PS_ADD("starttime", "%lu", T2J(tvtohz(&kp.ki_start)));
581 PS_ADD("vsize", "%ju", P2K((uintmax_t)kp.ki_size));
582 PS_ADD("rss", "%ju", (uintmax_t)kp.ki_rssize);
583 PS_ADD("rlim", "%lu", kp.ki_rusage.ru_maxrss);
584 PS_ADD("startcode", "%u", (unsigned)0);
585 PS_ADD("endcode", "%u", 0); /* XXX */
586 PS_ADD("startstack", "%u", 0); /* XXX */
587 PS_ADD("kstkesp", "%u", 0); /* XXX */
588 PS_ADD("kstkeip", "%u", 0); /* XXX */
589 PS_ADD("signal", "%u", 0); /* XXX */
590 PS_ADD("blocked", "%u", 0); /* XXX */
591 PS_ADD("sigignore", "%u", 0); /* XXX */
592 PS_ADD("sigcatch", "%u", 0); /* XXX */
593 PS_ADD("wchan", "%u", 0); /* XXX */
594 PS_ADD("nswap", "%lu", kp.ki_rusage.ru_nswap);
595 PS_ADD("cnswap", "%lu", kp.ki_rusage_ch.ru_nswap);
596 PS_ADD("exitsignal", "%d", 0); /* XXX */
597 PS_ADD("processor", "%u", kp.ki_lastcpu);
598 PS_ADD("rt_priority", "%u", 0); /* XXX */ /* >= 2.5.19 */
599 PS_ADD("policy", "%u", kp.ki_pri.pri_class); /* >= 2.5.19 */
600 #undef PS_ADD
601 sbuf_putc(sb, '\n');
602
603 return (0);
604 }
605
606 /*
607 * Filler function for proc/pid/statm
608 */
609 static int
610 linprocfs_doprocstatm(PFS_FILL_ARGS)
611 {
612 struct kinfo_proc kp;
613 segsz_t lsize;
614
615 PROC_LOCK(p);
616 fill_kinfo_proc(p, &kp);
617 PROC_UNLOCK(p);
618
619 /*
620 * See comments in linprocfs_doprocstatus() regarding the
621 * computation of lsize.
622 */
623 /* size resident share trs drs lrs dt */
624 sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
625 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
626 sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
627 sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
628 sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
629 lsize = B2P(kp.ki_size) - kp.ki_dsize -
630 kp.ki_ssize - kp.ki_tsize - 1;
631 sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
632 sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
633
634 return (0);
635 }
636
637 /*
638 * Filler function for proc/pid/status
639 */
640 static int
641 linprocfs_doprocstatus(PFS_FILL_ARGS)
642 {
643 struct kinfo_proc kp;
644 char *state;
645 segsz_t lsize;
646 struct thread *td2;
647 struct sigacts *ps;
648 int i;
649
650 PROC_LOCK(p);
651 td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
652
653 if (P_SHOULDSTOP(p)) {
654 state = "T (stopped)";
655 } else {
656 PROC_SLOCK(p);
657 switch(p->p_state) {
658 case PRS_NEW:
659 state = "I (idle)";
660 break;
661 case PRS_NORMAL:
662 if (p->p_flag & P_WEXIT) {
663 state = "X (exiting)";
664 break;
665 }
666 switch(td2->td_state) {
667 case TDS_INHIBITED:
668 state = "S (sleeping)";
669 break;
670 case TDS_RUNQ:
671 case TDS_RUNNING:
672 state = "R (running)";
673 break;
674 default:
675 state = "? (unknown)";
676 break;
677 }
678 break;
679 case PRS_ZOMBIE:
680 state = "Z (zombie)";
681 break;
682 default:
683 state = "? (unknown)";
684 break;
685 }
686 PROC_SUNLOCK(p);
687 }
688
689 fill_kinfo_proc(p, &kp);
690 sbuf_printf(sb, "Name:\t%s\n", p->p_comm); /* XXX escape */
691 sbuf_printf(sb, "State:\t%s\n", state);
692
693 /*
694 * Credentials
695 */
696 sbuf_printf(sb, "Pid:\t%d\n", p->p_pid);
697 sbuf_printf(sb, "PPid:\t%d\n", p->p_pptr ?
698 p->p_pptr->p_pid : 0);
699 sbuf_printf(sb, "Uid:\t%d %d %d %d\n", p->p_ucred->cr_ruid,
700 p->p_ucred->cr_uid,
701 p->p_ucred->cr_svuid,
702 /* FreeBSD doesn't have fsuid */
703 p->p_ucred->cr_uid);
704 sbuf_printf(sb, "Gid:\t%d %d %d %d\n", p->p_ucred->cr_rgid,
705 p->p_ucred->cr_gid,
706 p->p_ucred->cr_svgid,
707 /* FreeBSD doesn't have fsgid */
708 p->p_ucred->cr_gid);
709 sbuf_cat(sb, "Groups:\t");
710 for (i = 0; i < p->p_ucred->cr_ngroups; i++)
711 sbuf_printf(sb, "%d ", p->p_ucred->cr_groups[i]);
712 PROC_UNLOCK(p);
713 sbuf_putc(sb, '\n');
714
715 /*
716 * Memory
717 *
718 * While our approximation of VmLib may not be accurate (I
719 * don't know of a simple way to verify it, and I'm not sure
720 * it has much meaning anyway), I believe it's good enough.
721 *
722 * The same code that could (I think) accurately compute VmLib
723 * could also compute VmLck, but I don't really care enough to
724 * implement it. Submissions are welcome.
725 */
726 sbuf_printf(sb, "VmSize:\t%8ju kB\n", B2K((uintmax_t)kp.ki_size));
727 sbuf_printf(sb, "VmLck:\t%8u kB\n", P2K(0)); /* XXX */
728 sbuf_printf(sb, "VmRss:\t%8ju kB\n", P2K((uintmax_t)kp.ki_rssize));
729 sbuf_printf(sb, "VmData:\t%8ju kB\n", P2K((uintmax_t)kp.ki_dsize));
730 sbuf_printf(sb, "VmStk:\t%8ju kB\n", P2K((uintmax_t)kp.ki_ssize));
731 sbuf_printf(sb, "VmExe:\t%8ju kB\n", P2K((uintmax_t)kp.ki_tsize));
732 lsize = B2P(kp.ki_size) - kp.ki_dsize -
733 kp.ki_ssize - kp.ki_tsize - 1;
734 sbuf_printf(sb, "VmLib:\t%8ju kB\n", P2K((uintmax_t)lsize));
735
736 /*
737 * Signal masks
738 *
739 * We support up to 128 signals, while Linux supports 32,
740 * but we only define 32 (the same 32 as Linux, to boot), so
741 * just show the lower 32 bits of each mask. XXX hack.
742 *
743 * NB: on certain platforms (Sparc at least) Linux actually
744 * supports 64 signals, but this code is a long way from
745 * running on anything but i386, so ignore that for now.
746 */
747 PROC_LOCK(p);
748 sbuf_printf(sb, "SigPnd:\t%08x\n", p->p_siglist.__bits[0]);
749 /*
750 * I can't seem to find out where the signal mask is in
751 * relation to struct proc, so SigBlk is left unimplemented.
752 */
753 sbuf_printf(sb, "SigBlk:\t%08x\n", 0); /* XXX */
754 ps = p->p_sigacts;
755 mtx_lock(&ps->ps_mtx);
756 sbuf_printf(sb, "SigIgn:\t%08x\n", ps->ps_sigignore.__bits[0]);
757 sbuf_printf(sb, "SigCgt:\t%08x\n", ps->ps_sigcatch.__bits[0]);
758 mtx_unlock(&ps->ps_mtx);
759 PROC_UNLOCK(p);
760
761 /*
762 * Linux also prints the capability masks, but we don't have
763 * capabilities yet, and when we do get them they're likely to
764 * be meaningless to Linux programs, so we lie. XXX
765 */
766 sbuf_printf(sb, "CapInh:\t%016x\n", 0);
767 sbuf_printf(sb, "CapPrm:\t%016x\n", 0);
768 sbuf_printf(sb, "CapEff:\t%016x\n", 0);
769
770 return (0);
771 }
772
773
774 /*
775 * Filler function for proc/pid/cwd
776 */
777 static int
778 linprocfs_doproccwd(PFS_FILL_ARGS)
779 {
780 char *fullpath = "unknown";
781 char *freepath = NULL;
782
783 vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
784 sbuf_printf(sb, "%s", fullpath);
785 if (freepath)
786 free(freepath, M_TEMP);
787 return (0);
788 }
789
790 /*
791 * Filler function for proc/pid/root
792 */
793 static int
794 linprocfs_doprocroot(PFS_FILL_ARGS)
795 {
796 struct vnode *rvp;
797 char *fullpath = "unknown";
798 char *freepath = NULL;
799
800 rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
801 vn_fullpath(td, rvp, &fullpath, &freepath);
802 sbuf_printf(sb, "%s", fullpath);
803 if (freepath)
804 free(freepath, M_TEMP);
805 return (0);
806 }
807
808 /*
809 * Filler function for proc/pid/cmdline
810 */
811 static int
812 linprocfs_doproccmdline(PFS_FILL_ARGS)
813 {
814 struct ps_strings pstr;
815 char **ps_argvstr;
816 int error, i;
817
818 /*
819 * If we are using the ps/cmdline caching, use that. Otherwise
820 * revert back to the old way which only implements full cmdline
821 * for the currept process and just p->p_comm for all other
822 * processes.
823 * Note that if the argv is no longer available, we deliberately
824 * don't fall back on p->p_comm or return an error: the authentic
825 * Linux behaviour is to return zero-length in this case.
826 */
827
828 PROC_LOCK(p);
829 if (p->p_args && p_cansee(td, p) == 0) {
830 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
831 PROC_UNLOCK(p);
832 } else if (p != td->td_proc) {
833 PROC_UNLOCK(p);
834 sbuf_printf(sb, "%.*s", MAXCOMLEN, p->p_comm);
835 } else {
836 PROC_UNLOCK(p);
837 error = copyin((void *)p->p_sysent->sv_psstrings, &pstr,
838 sizeof(pstr));
839 if (error)
840 return (error);
841 if (pstr.ps_nargvstr > ARG_MAX)
842 return (E2BIG);
843 ps_argvstr = malloc(pstr.ps_nargvstr * sizeof(char *),
844 M_TEMP, M_WAITOK);
845 error = copyin((void *)pstr.ps_argvstr, ps_argvstr,
846 pstr.ps_nargvstr * sizeof(char *));
847 if (error) {
848 free(ps_argvstr, M_TEMP);
849 return (error);
850 }
851 for (i = 0; i < pstr.ps_nargvstr; i++) {
852 sbuf_copyin(sb, ps_argvstr[i], 0);
853 sbuf_printf(sb, "%c", '\0');
854 }
855 free(ps_argvstr, M_TEMP);
856 }
857
858 return (0);
859 }
860
861 /*
862 * Filler function for proc/pid/environ
863 */
864 static int
865 linprocfs_doprocenviron(PFS_FILL_ARGS)
866 {
867
868 sbuf_printf(sb, "doprocenviron\n%c", '\0');
869 return (0);
870 }
871
872 /*
873 * Filler function for proc/pid/maps
874 */
875 static int
876 linprocfs_doprocmaps(PFS_FILL_ARGS)
877 {
878 struct vmspace *vm;
879 vm_map_t map;
880 vm_map_entry_t entry, tmp_entry;
881 vm_object_t obj, tobj, lobj;
882 vm_offset_t e_start, e_end;
883 vm_ooffset_t off = 0;
884 vm_prot_t e_prot;
885 unsigned int last_timestamp;
886 char *name = "", *freename = NULL;
887 ino_t ino;
888 int ref_count, shadow_count, flags;
889 int error;
890 struct vnode *vp;
891 struct vattr vat;
892 int locked;
893
894 PROC_LOCK(p);
895 error = p_candebug(td, p);
896 PROC_UNLOCK(p);
897 if (error)
898 return (error);
899
900 if (uio->uio_rw != UIO_READ)
901 return (EOPNOTSUPP);
902
903 error = 0;
904 vm = vmspace_acquire_ref(p);
905 if (vm == NULL)
906 return (ESRCH);
907 map = &vm->vm_map;
908 vm_map_lock_read(map);
909 for (entry = map->header.next; entry != &map->header;
910 entry = entry->next) {
911 name = "";
912 freename = NULL;
913 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
914 continue;
915 e_prot = entry->protection;
916 e_start = entry->start;
917 e_end = entry->end;
918 obj = entry->object.vm_object;
919 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
920 VM_OBJECT_LOCK(tobj);
921 if (lobj != obj)
922 VM_OBJECT_UNLOCK(lobj);
923 lobj = tobj;
924 }
925 last_t |