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