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