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