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