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