]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/linprocfs/linprocfs.c
Merge clang trunk r238337 from ^/vendor/clang/dist, resolve conflicts,
[FreeBSD/FreeBSD.git] / sys / compat / linprocfs / linprocfs.c
1 /*-
2  * Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
3  * Copyright (c) 1999 Pierre Beyssac
4  * Copyright (c) 1993 Jan-Simon Pendry
5  * Copyright (c) 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Jan-Simon Pendry.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *      @(#)procfs_status.c     8.4 (Berkeley) 6/15/94
40  */
41
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44
45 #include <sys/param.h>
46 #include <sys/queue.h>
47 #include <sys/blist.h>
48 #include <sys/conf.h>
49 #include <sys/exec.h>
50 #include <sys/fcntl.h>
51 #include <sys/filedesc.h>
52 #include <sys/jail.h>
53 #include <sys/kernel.h>
54 #include <sys/limits.h>
55 #include <sys/linker.h>
56 #include <sys/lock.h>
57 #include <sys/malloc.h>
58 #include <sys/msg.h>
59 #include <sys/mutex.h>
60 #include <sys/namei.h>
61 #include <sys/proc.h>
62 #include <sys/ptrace.h>
63 #include <sys/resourcevar.h>
64 #include <sys/sbuf.h>
65 #include <sys/sem.h>
66 #include <sys/smp.h>
67 #include <sys/socket.h>
68 #include <sys/syscallsubr.h>
69 #include <sys/sysctl.h>
70 #include <sys/sysent.h>
71 #include <sys/systm.h>
72 #include <sys/time.h>
73 #include <sys/tty.h>
74 #include <sys/user.h>
75 #include <sys/uuid.h>
76 #include <sys/vmmeter.h>
77 #include <sys/vnode.h>
78 #include <sys/bus.h>
79
80 #include <net/if.h>
81 #include <net/if_var.h>
82 #include <net/if_types.h>
83
84 #include <vm/vm.h>
85 #include <vm/vm_extern.h>
86 #include <vm/pmap.h>
87 #include <vm/vm_map.h>
88 #include <vm/vm_param.h>
89 #include <vm/vm_object.h>
90 #include <vm/swap_pager.h>
91
92 #include <machine/clock.h>
93
94 #include <geom/geom.h>
95 #include <geom/geom_int.h>
96
97 #if defined(__i386__) || defined(__amd64__)
98 #include <machine/cputypes.h>
99 #include <machine/md_var.h>
100 #endif /* __i386__ || __amd64__ */
101
102 #include <compat/linux/linux.h>
103 #include <compat/linux/linux_mib.h>
104 #include <compat/linux/linux_misc.h>
105 #include <compat/linux/linux_util.h>
106 #include <fs/pseudofs/pseudofs.h>
107 #include <fs/procfs/procfs.h>
108
109 /*
110  * Various conversion macros
111  */
112 #define T2J(x) ((long)(((x) * 100ULL) / (stathz ? stathz : hz)))        /* ticks to jiffies */
113 #define T2CS(x) ((unsigned long)(((x) * 100ULL) / (stathz ? stathz : hz)))      /* ticks to centiseconds */
114 #define T2S(x) ((x) / (stathz ? stathz : hz))           /* ticks to seconds */
115 #define B2K(x) ((x) >> 10)                              /* bytes to kbytes */
116 #define B2P(x) ((x) >> PAGE_SHIFT)                      /* bytes to pages */
117 #define P2B(x) ((x) << PAGE_SHIFT)                      /* pages to bytes */
118 #define P2K(x) ((x) << (PAGE_SHIFT - 10))               /* pages to kbytes */
119 #define TV2J(x) ((x)->tv_sec * 100UL + (x)->tv_usec / 10000)
120
121 /**
122  * @brief Mapping of ki_stat in struct kinfo_proc to the linux state
123  *
124  * The linux procfs state field displays one of the characters RSDZTW to
125  * denote running, sleeping in an interruptible wait, waiting in an
126  * uninterruptible disk sleep, a zombie process, process is being traced
127  * or stopped, or process is paging respectively.
128  *
129  * Our struct kinfo_proc contains the variable ki_stat which contains a
130  * value out of SIDL, SRUN, SSLEEP, SSTOP, SZOMB, SWAIT and SLOCK.
131  *
132  * This character array is used with ki_stati-1 as an index and tries to
133  * map our states to suitable linux states.
134  */
135 static char linux_state[] = "RRSTZDD";
136
137 /*
138  * Filler function for proc/meminfo
139  */
140 static int
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 = vm_cnt.v_free_count * PAGE_SIZE;
159         memused = memtotal - memfree;
160          *
161          * but it might mislead linux binaries into thinking there
162          * is very little memory left, so we cheat and tell them that
163          * all memory that isn't wired down is free.
164          */
165         memused = vm_cnt.v_wire_count * PAGE_SIZE;
166         memfree = memtotal - memused;
167         swap_pager_status(&i, &j);
168         swaptotal = (unsigned long long)i * PAGE_SIZE;
169         swapused = (unsigned long long)j * PAGE_SIZE;
170         swapfree = swaptotal - swapused;
171         memshared = 0;
172         mtx_lock(&vm_object_list_mtx);
173         TAILQ_FOREACH(object, &vm_object_list, object_list)
174                 if (object->shadow_count > 1)
175                         memshared += object->resident_page_count;
176         mtx_unlock(&vm_object_list_mtx);
177         memshared *= PAGE_SIZE;
178         /*
179          * We'd love to be able to write:
180          *
181         buffers = bufspace;
182          *
183          * but bufspace is internal to vfs_bio.c and we don't feel
184          * like unstaticizing it just for linprocfs's sake.
185          */
186         buffers = 0;
187         cached = vm_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         const char *lep;
326         char *dlep, *flep, *mntto, *mntfrom, *fstype;
327         size_t lep_len;
328         int error;
329         struct statfs *buf, *sp;
330         size_t count;
331
332         /* resolve symlinks etc. in the emulation tree prefix */
333         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path, td);
334         flep = NULL;
335         error = namei(&nd);
336         lep = linux_emul_path;
337         if (error == 0) {
338                 if (vn_fullpath(td, nd.ni_vp, &dlep, &flep) == 0)
339                         lep = dlep;
340                 vrele(nd.ni_vp);
341         }
342         lep_len = strlen(lep);
343
344         buf = NULL;
345         error = kern_getfsstat(td, &buf, SIZE_T_MAX, &count,
346             UIO_SYSSPACE, MNT_WAIT);
347         if (error != 0) {
348                 free(buf, M_TEMP);
349                 free(flep, M_TEMP);
350                 return (error);
351         }
352
353         for (sp = buf; count > 0; sp++, count--) {
354                 /* determine device name */
355                 mntfrom = sp->f_mntfromname;
356
357                 /* determine mount point */
358                 mntto = sp->f_mntonname;
359                 if (strncmp(mntto, lep, lep_len) == 0 && mntto[lep_len] == '/')
360                         mntto += lep_len;
361
362                 /* determine fs type */
363                 fstype = sp->f_fstypename;
364                 if (strcmp(fstype, pn->pn_info->pi_name) == 0)
365                         mntfrom = fstype = "proc";
366                 else if (strcmp(fstype, "procfs") == 0)
367                         continue;
368
369                 if (strcmp(fstype, "linsysfs") == 0) {
370                         sbuf_printf(sb, "/sys %s sysfs %s", mntto,
371                             sp->f_flags & MNT_RDONLY ? "ro" : "rw");
372                 } else {
373                         /* For Linux msdosfs is called vfat */
374                         if (strcmp(fstype, "msdosfs") == 0)
375                                 fstype = "vfat";
376                         sbuf_printf(sb, "%s %s %s %s", mntfrom, mntto, fstype,
377                             sp->f_flags & MNT_RDONLY ? "ro" : "rw");
378                 }
379 #define ADD_OPTION(opt, name) \
380         if (sp->f_flags & (opt)) sbuf_printf(sb, "," name);
381                 ADD_OPTION(MNT_SYNCHRONOUS,     "sync");
382                 ADD_OPTION(MNT_NOEXEC,          "noexec");
383                 ADD_OPTION(MNT_NOSUID,          "nosuid");
384                 ADD_OPTION(MNT_UNION,           "union");
385                 ADD_OPTION(MNT_ASYNC,           "async");
386                 ADD_OPTION(MNT_SUIDDIR,         "suiddir");
387                 ADD_OPTION(MNT_NOSYMFOLLOW,     "nosymfollow");
388                 ADD_OPTION(MNT_NOATIME,         "noatime");
389 #undef ADD_OPTION
390                 /* a real Linux mtab will also show NFS options */
391                 sbuf_printf(sb, " 0 0\n");
392         }
393
394         free(buf, M_TEMP);
395         free(flep, M_TEMP);
396         return (error);
397 }
398
399 /*
400  * Filler function for proc/partitions
401  */
402 static int
403 linprocfs_dopartitions(PFS_FILL_ARGS)
404 {
405         struct g_class *cp;
406         struct g_geom *gp;
407         struct g_provider *pp;
408         int major, minor;
409
410         g_topology_lock();
411         sbuf_printf(sb, "major minor  #blocks  name rio rmerge rsect "
412             "ruse wio wmerge wsect wuse running use aveq\n");
413
414         LIST_FOREACH(cp, &g_classes, class) {
415                 if (strcmp(cp->name, "DISK") == 0 ||
416                     strcmp(cp->name, "PART") == 0)
417                         LIST_FOREACH(gp, &cp->geom, geom) {
418                                 LIST_FOREACH(pp, &gp->provider, provider) {
419                                         if (linux_driver_get_major_minor(
420                                             pp->name, &major, &minor) != 0) {
421                                                 major = 0;
422                                                 minor = 0;
423                                         }
424                                         sbuf_printf(sb, "%d %d %lld %s "
425                                             "%d %d %d %d %d "
426                                              "%d %d %d %d %d %d\n",
427                                              major, minor,
428                                              (long long)pp->mediasize, pp->name,
429                                              0, 0, 0, 0, 0,
430                                              0, 0, 0, 0, 0, 0);
431                                 }
432                         }
433         }
434         g_topology_unlock();
435
436         return (0);
437 }
438
439
440 /*
441  * Filler function for proc/stat
442  */
443 static int
444 linprocfs_dostat(PFS_FILL_ARGS)
445 {
446         struct pcpu *pcpu;
447         long cp_time[CPUSTATES];
448         long *cp;
449         int i;
450
451         read_cpu_time(cp_time);
452         sbuf_printf(sb, "cpu %ld %ld %ld %ld\n",
453             T2J(cp_time[CP_USER]),
454             T2J(cp_time[CP_NICE]),
455             T2J(cp_time[CP_SYS] /*+ cp_time[CP_INTR]*/),
456             T2J(cp_time[CP_IDLE]));
457         CPU_FOREACH(i) {
458                 pcpu = pcpu_find(i);
459                 cp = pcpu->pc_cp_time;
460                 sbuf_printf(sb, "cpu%d %ld %ld %ld %ld\n", i,
461                     T2J(cp[CP_USER]),
462                     T2J(cp[CP_NICE]),
463                     T2J(cp[CP_SYS] /*+ cp[CP_INTR]*/),
464                     T2J(cp[CP_IDLE]));
465         }
466         sbuf_printf(sb,
467             "disk 0 0 0 0\n"
468             "page %u %u\n"
469             "swap %u %u\n"
470             "intr %u\n"
471             "ctxt %u\n"
472             "btime %lld\n",
473             vm_cnt.v_vnodepgsin,
474             vm_cnt.v_vnodepgsout,
475             vm_cnt.v_swappgsin,
476             vm_cnt.v_swappgsout,
477             vm_cnt.v_intr,
478             vm_cnt.v_swtch,
479             (long long)boottime.tv_sec);
480         return (0);
481 }
482
483 static int
484 linprocfs_doswaps(PFS_FILL_ARGS)
485 {
486         struct xswdev xsw;
487         uintmax_t total, used;
488         int n;
489         char devname[SPECNAMELEN + 1];
490
491         sbuf_printf(sb, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
492         mtx_lock(&Giant);
493         for (n = 0; ; n++) {
494                 if (swap_dev_info(n, &xsw, devname, sizeof(devname)) != 0)
495                         break;
496                 total = (uintmax_t)xsw.xsw_nblks * PAGE_SIZE / 1024;
497                 used  = (uintmax_t)xsw.xsw_used * PAGE_SIZE / 1024;
498
499                 /*
500                  * The space and not tab after the device name is on
501                  * purpose.  Linux does so.
502                  */
503                 sbuf_printf(sb, "/dev/%-34s unknown\t\t%jd\t%jd\t-1\n",
504                     devname, total, used);
505         }
506         mtx_unlock(&Giant);
507         return (0);
508 }
509
510 /*
511  * Filler function for proc/uptime
512  */
513 static int
514 linprocfs_douptime(PFS_FILL_ARGS)
515 {
516         long cp_time[CPUSTATES];
517         struct timeval tv;
518
519         getmicrouptime(&tv);
520         read_cpu_time(cp_time);
521         sbuf_printf(sb, "%lld.%02ld %ld.%02lu\n",
522             (long long)tv.tv_sec, tv.tv_usec / 10000,
523             T2S(cp_time[CP_IDLE] / mp_ncpus),
524             T2CS(cp_time[CP_IDLE] / mp_ncpus) % 100);
525         return (0);
526 }
527
528 /*
529  * Get OS build date
530  */
531 static void
532 linprocfs_osbuild(struct thread *td, struct sbuf *sb)
533 {
534 #if 0
535         char osbuild[256];
536         char *cp1, *cp2;
537
538         strncpy(osbuild, version, 256);
539         osbuild[255] = '\0';
540         cp1 = strstr(osbuild, "\n");
541         cp2 = strstr(osbuild, ":");
542         if (cp1 && cp2) {
543                 *cp1 = *cp2 = '\0';
544                 cp1 = strstr(osbuild, "#");
545         } else
546                 cp1 = NULL;
547         if (cp1)
548                 sbuf_printf(sb, "%s%s", cp1, cp2 + 1);
549         else
550 #endif
551                 sbuf_cat(sb, "#4 Sun Dec 18 04:30:00 CET 1977");
552 }
553
554 /*
555  * Get OS builder
556  */
557 static void
558 linprocfs_osbuilder(struct thread *td, struct sbuf *sb)
559 {
560 #if 0
561         char builder[256];
562         char *cp;
563
564         cp = strstr(version, "\n    ");
565         if (cp) {
566                 strncpy(builder, cp + 5, 256);
567                 builder[255] = '\0';
568                 cp = strstr(builder, ":");
569                 if (cp)
570                         *cp = '\0';
571         }
572         if (cp)
573                 sbuf_cat(sb, builder);
574         else
575 #endif
576                 sbuf_cat(sb, "des@freebsd.org");
577 }
578
579 /*
580  * Filler function for proc/version
581  */
582 static int
583 linprocfs_doversion(PFS_FILL_ARGS)
584 {
585         char osname[LINUX_MAX_UTSNAME];
586         char osrelease[LINUX_MAX_UTSNAME];
587
588         linux_get_osname(td, osname);
589         linux_get_osrelease(td, osrelease);
590         sbuf_printf(sb, "%s version %s (", osname, osrelease);
591         linprocfs_osbuilder(td, sb);
592         sbuf_cat(sb, ") (gcc version " __VERSION__ ") ");
593         linprocfs_osbuild(td, sb);
594         sbuf_cat(sb, "\n");
595
596         return (0);
597 }
598
599 /*
600  * Filler function for proc/loadavg
601  */
602 static int
603 linprocfs_doloadavg(PFS_FILL_ARGS)
604 {
605
606         sbuf_printf(sb,
607             "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
608             (int)(averunnable.ldavg[0] / averunnable.fscale),
609             (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
610             (int)(averunnable.ldavg[1] / averunnable.fscale),
611             (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
612             (int)(averunnable.ldavg[2] / averunnable.fscale),
613             (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
614             1,                          /* number of running tasks */
615             nprocs,                     /* number of tasks */
616             lastpid                     /* the last pid */
617         );
618         return (0);
619 }
620
621 /*
622  * Filler function for proc/pid/stat
623  */
624 static int
625 linprocfs_doprocstat(PFS_FILL_ARGS)
626 {
627         struct kinfo_proc kp;
628         char state;
629         static int ratelimit = 0;
630         vm_offset_t startcode, startdata;
631
632         sx_slock(&proctree_lock);
633         PROC_LOCK(p);
634         fill_kinfo_proc(p, &kp);
635         sx_sunlock(&proctree_lock);
636         if (p->p_vmspace) {
637            startcode = (vm_offset_t)p->p_vmspace->vm_taddr;
638            startdata = (vm_offset_t)p->p_vmspace->vm_daddr;
639         } else {
640            startcode = 0;
641            startdata = 0;
642         };
643         sbuf_printf(sb, "%d", p->p_pid);
644 #define PS_ADD(name, fmt, arg) sbuf_printf(sb, " " fmt, arg)
645         PS_ADD("comm",          "(%s)", p->p_comm);
646         if (kp.ki_stat > sizeof(linux_state)) {
647                 state = 'R';
648
649                 if (ratelimit == 0) {
650                         printf("linprocfs: don't know how to handle unknown FreeBSD state %d/%zd, mapping to R\n",
651                             kp.ki_stat, sizeof(linux_state));
652                         ++ratelimit;
653                 }
654         } else
655                 state = linux_state[kp.ki_stat - 1];
656         PS_ADD("state",         "%c",   state);
657         PS_ADD("ppid",          "%d",   p->p_pptr ? p->p_pptr->p_pid : 0);
658         PS_ADD("pgrp",          "%d",   p->p_pgid);
659         PS_ADD("session",       "%d",   p->p_session->s_sid);
660         PROC_UNLOCK(p);
661         PS_ADD("tty",           "%ju",  (uintmax_t)kp.ki_tdev);
662         PS_ADD("tpgid",         "%d",   kp.ki_tpgid);
663         PS_ADD("flags",         "%u",   0); /* XXX */
664         PS_ADD("minflt",        "%lu",  kp.ki_rusage.ru_minflt);
665         PS_ADD("cminflt",       "%lu",  kp.ki_rusage_ch.ru_minflt);
666         PS_ADD("majflt",        "%lu",  kp.ki_rusage.ru_majflt);
667         PS_ADD("cmajflt",       "%lu",  kp.ki_rusage_ch.ru_majflt);
668         PS_ADD("utime",         "%ld",  TV2J(&kp.ki_rusage.ru_utime));
669         PS_ADD("stime",         "%ld",  TV2J(&kp.ki_rusage.ru_stime));
670         PS_ADD("cutime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_utime));
671         PS_ADD("cstime",        "%ld",  TV2J(&kp.ki_rusage_ch.ru_stime));
672         PS_ADD("priority",      "%d",   kp.ki_pri.pri_user);
673         PS_ADD("nice",          "%d",   kp.ki_nice); /* 19 (nicest) to -19 */
674         PS_ADD("0",             "%d",   0); /* removed field */
675         PS_ADD("itrealvalue",   "%d",   0); /* XXX */
676         PS_ADD("starttime",     "%lu",  TV2J(&kp.ki_start) - TV2J(&boottime));
677         PS_ADD("vsize",         "%ju",  P2K((uintmax_t)kp.ki_size));
678         PS_ADD("rss",           "%ju",  (uintmax_t)kp.ki_rssize);
679         PS_ADD("rlim",          "%lu",  kp.ki_rusage.ru_maxrss);
680         PS_ADD("startcode",     "%ju",  (uintmax_t)startcode);
681         PS_ADD("endcode",       "%ju",  (uintmax_t)startdata);
682         PS_ADD("startstack",    "%u",   0); /* XXX */
683         PS_ADD("kstkesp",       "%u",   0); /* XXX */
684         PS_ADD("kstkeip",       "%u",   0); /* XXX */
685         PS_ADD("signal",        "%u",   0); /* XXX */
686         PS_ADD("blocked",       "%u",   0); /* XXX */
687         PS_ADD("sigignore",     "%u",   0); /* XXX */
688         PS_ADD("sigcatch",      "%u",   0); /* XXX */
689         PS_ADD("wchan",         "%u",   0); /* XXX */
690         PS_ADD("nswap",         "%lu",  kp.ki_rusage.ru_nswap);
691         PS_ADD("cnswap",        "%lu",  kp.ki_rusage_ch.ru_nswap);
692         PS_ADD("exitsignal",    "%d",   0); /* XXX */
693         PS_ADD("processor",     "%u",   kp.ki_lastcpu);
694         PS_ADD("rt_priority",   "%u",   0); /* XXX */ /* >= 2.5.19 */
695         PS_ADD("policy",        "%u",   kp.ki_pri.pri_class); /* >= 2.5.19 */
696 #undef PS_ADD
697         sbuf_putc(sb, '\n');
698
699         return (0);
700 }
701
702 /*
703  * Filler function for proc/pid/statm
704  */
705 static int
706 linprocfs_doprocstatm(PFS_FILL_ARGS)
707 {
708         struct kinfo_proc kp;
709         segsz_t lsize;
710
711         sx_slock(&proctree_lock);
712         PROC_LOCK(p);
713         fill_kinfo_proc(p, &kp);
714         PROC_UNLOCK(p);
715         sx_sunlock(&proctree_lock);
716
717         /*
718          * See comments in linprocfs_doprocstatus() regarding the
719          * computation of lsize.
720          */
721         /* size resident share trs drs lrs dt */
722         sbuf_printf(sb, "%ju ", B2P((uintmax_t)kp.ki_size));
723         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_rssize);
724         sbuf_printf(sb, "%ju ", (uintmax_t)0); /* XXX */
725         sbuf_printf(sb, "%ju ", (uintmax_t)kp.ki_tsize);
726         sbuf_printf(sb, "%ju ", (uintmax_t)(kp.ki_dsize + kp.ki_ssize));
727         lsize = B2P(kp.ki_size) - kp.ki_dsize -
728             kp.ki_ssize - kp.ki_tsize - 1;
729         sbuf_printf(sb, "%ju ", (uintmax_t)lsize);
730         sbuf_printf(sb, "%ju\n", (uintmax_t)0); /* XXX */
731
732         return (0);
733 }
734
735 /*
736  * Filler function for proc/pid/status
737  */
738 static int
739 linprocfs_doprocstatus(PFS_FILL_ARGS)
740 {
741         struct kinfo_proc kp;
742         char *state;
743         segsz_t lsize;
744         struct thread *td2;
745         struct sigacts *ps;
746         l_sigset_t siglist, sigignore, sigcatch;
747         int i;
748
749         sx_slock(&proctree_lock);
750         PROC_LOCK(p);
751         td2 = FIRST_THREAD_IN_PROC(p); /* XXXKSE pretend only one thread */
752
753         if (P_SHOULDSTOP(p)) {
754                 state = "T (stopped)";
755         } else {
756                 switch(p->p_state) {
757                 case PRS_NEW:
758                         state = "I (idle)";
759                         break;
760                 case PRS_NORMAL:
761                         if (p->p_flag & P_WEXIT) {
762                                 state = "X (exiting)";
763                                 break;
764                         }
765                         switch(td2->td_state) {
766                         case TDS_INHIBITED:
767                                 state = "S (sleeping)";
768                                 break;
769                         case TDS_RUNQ:
770                         case TDS_RUNNING:
771                                 state = "R (running)";
772                                 break;
773                         default:
774                                 state = "? (unknown)";
775                                 break;
776                         }
777                         break;
778                 case PRS_ZOMBIE:
779                         state = "Z (zombie)";
780                         break;
781                 default:
782                         state = "? (unknown)";
783                         break;
784                 }
785         }
786
787         fill_kinfo_proc(p, &kp);
788         sx_sunlock(&proctree_lock);
789
790         sbuf_printf(sb, "Name:\t%s\n",          p->p_comm); /* XXX escape */
791         sbuf_printf(sb, "State:\t%s\n",         state);
792
793         /*
794          * Credentials
795          */
796         sbuf_printf(sb, "Pid:\t%d\n",           p->p_pid);
797         sbuf_printf(sb, "PPid:\t%d\n",          p->p_pptr ?
798                                                 p->p_pptr->p_pid : 0);
799         sbuf_printf(sb, "Uid:\t%d %d %d %d\n",  p->p_ucred->cr_ruid,
800                                                 p->p_ucred->cr_uid,
801                                                 p->p_ucred->cr_svuid,
802                                                 /* FreeBSD doesn't have fsuid */
803                                                 p->p_ucred->cr_uid);
804         sbuf_printf(sb, "Gid:\t%d %d %d %d\n",  p->p_ucred->cr_rgid,
805                                                 p->p_ucred->cr_gid,
806                                                 p->p_ucred->cr_svgid,
807                                                 /* FreeBSD doesn't have fsgid */
808                                                 p->p_ucred->cr_gid);
809         sbuf_cat(sb, "Groups:\t");
810         for (i = 0; i < p->p_ucred->cr_ngroups; i++)
811                 sbuf_printf(sb, "%d ",          p->p_ucred->cr_groups[i]);
812         PROC_UNLOCK(p);
813         sbuf_putc(sb, '\n');
814
815         /*
816          * Memory
817          *
818          * While our approximation of VmLib may not be accurate (I
819          * don't know of a simple way to verify it, and I'm not sure
820          * it has much meaning anyway), I believe it's good enough.
821          *
822          * The same code that could (I think) accurately compute VmLib
823          * could also compute VmLck, but I don't really care enough to
824          * implement it. Submissions are welcome.
825          */
826         sbuf_printf(sb, "VmSize:\t%8ju kB\n",   B2K((uintmax_t)kp.ki_size));
827         sbuf_printf(sb, "VmLck:\t%8u kB\n",     P2K(0)); /* XXX */
828         sbuf_printf(sb, "VmRSS:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_rssize));
829         sbuf_printf(sb, "VmData:\t%8ju kB\n",   P2K((uintmax_t)kp.ki_dsize));
830         sbuf_printf(sb, "VmStk:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_ssize));
831         sbuf_printf(sb, "VmExe:\t%8ju kB\n",    P2K((uintmax_t)kp.ki_tsize));
832         lsize = B2P(kp.ki_size) - kp.ki_dsize -
833             kp.ki_ssize - kp.ki_tsize - 1;
834         sbuf_printf(sb, "VmLib:\t%8ju kB\n",    P2K((uintmax_t)lsize));
835
836         /*
837          * Signal masks
838          */
839         PROC_LOCK(p);
840         bsd_to_linux_sigset(&p->p_siglist, &siglist);
841         ps = p->p_sigacts;
842         mtx_lock(&ps->ps_mtx);
843         bsd_to_linux_sigset(&ps->ps_sigignore, &sigignore);
844         bsd_to_linux_sigset(&ps->ps_sigcatch, &sigcatch);
845         mtx_unlock(&ps->ps_mtx);
846         PROC_UNLOCK(p);
847
848         sbuf_printf(sb, "SigPnd:\t%016jx\n",    siglist.__mask);
849         /*
850          * XXX. SigBlk - target thread's signal mask, td_sigmask.
851          * To implement SigBlk pseudofs should support proc/tid dir entries.
852          */
853         sbuf_printf(sb, "SigBlk:\t%016x\n",     0);
854         sbuf_printf(sb, "SigIgn:\t%016jx\n",    sigignore.__mask);
855         sbuf_printf(sb, "SigCgt:\t%016jx\n",    sigcatch.__mask);
856
857         /*
858          * Linux also prints the capability masks, but we don't have
859          * capabilities yet, and when we do get them they're likely to
860          * be meaningless to Linux programs, so we lie. XXX
861          */
862         sbuf_printf(sb, "CapInh:\t%016x\n",     0);
863         sbuf_printf(sb, "CapPrm:\t%016x\n",     0);
864         sbuf_printf(sb, "CapEff:\t%016x\n",     0);
865
866         return (0);
867 }
868
869
870 /*
871  * Filler function for proc/pid/cwd
872  */
873 static int
874 linprocfs_doproccwd(PFS_FILL_ARGS)
875 {
876         char *fullpath = "unknown";
877         char *freepath = NULL;
878
879         vn_fullpath(td, p->p_fd->fd_cdir, &fullpath, &freepath);
880         sbuf_printf(sb, "%s", fullpath);
881         if (freepath)
882                 free(freepath, M_TEMP);
883         return (0);
884 }
885
886 /*
887  * Filler function for proc/pid/root
888  */
889 static int
890 linprocfs_doprocroot(PFS_FILL_ARGS)
891 {
892         struct vnode *rvp;
893         char *fullpath = "unknown";
894         char *freepath = NULL;
895
896         rvp = jailed(p->p_ucred) ? p->p_fd->fd_jdir : p->p_fd->fd_rdir;
897         vn_fullpath(td, rvp, &fullpath, &freepath);
898         sbuf_printf(sb, "%s", fullpath);
899         if (freepath)
900                 free(freepath, M_TEMP);
901         return (0);
902 }
903
904 /*
905  * Filler function for proc/pid/cmdline
906  */
907 static int
908 linprocfs_doproccmdline(PFS_FILL_ARGS)
909 {
910         int ret;
911
912         PROC_LOCK(p);
913         if ((ret = p_cansee(td, p)) != 0) {
914                 PROC_UNLOCK(p);
915                 return (ret);
916         }
917
918         /*
919          * Mimic linux behavior and pass only processes with usermode
920          * address space as valid.  Return zero silently otherwize.
921          */
922         if (p->p_vmspace == &vmspace0) {
923                 PROC_UNLOCK(p);
924                 return (0);
925         }
926         if (p->p_args != NULL) {
927                 sbuf_bcpy(sb, p->p_args->ar_args, p->p_args->ar_length);
928                 PROC_UNLOCK(p);
929                 return (0);
930         }
931
932         if ((p->p_flag & P_SYSTEM) != 0) {
933                 PROC_UNLOCK(p);
934                 return (0);
935         }
936
937         PROC_UNLOCK(p);
938
939         ret = proc_getargv(td, p, sb);
940         return (ret);
941 }
942
943 /*
944  * Filler function for proc/pid/environ
945  */
946 static int
947 linprocfs_doprocenviron(PFS_FILL_ARGS)
948 {
949
950         /*
951          * Mimic linux behavior and pass only processes with usermode
952          * address space as valid.  Return zero silently otherwize.
953          */
954         if (p->p_vmspace == &vmspace0)
955                 return (0);
956
957         return (proc_getenvv(td, p, sb));
958 }
959
960 static char l32_map_str[] = "%08lx-%08lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
961 static char l64_map_str[] = "%016lx-%016lx %s%s%s%s %08lx %02x:%02x %lu%s%s\n";
962 static char vdso_str[] = "      [vdso]";
963 static char stack_str[] = "      [stack]";
964
965 /*
966  * Filler function for proc/pid/maps
967  */
968 static int
969 linprocfs_doprocmaps(PFS_FILL_ARGS)
970 {
971         struct vmspace *vm;
972         vm_map_t map;
973         vm_map_entry_t entry, tmp_entry;
974         vm_object_t obj, tobj, lobj;
975         vm_offset_t e_start, e_end;
976         vm_ooffset_t off = 0;
977         vm_prot_t e_prot;
978         unsigned int last_timestamp;
979         char *name = "", *freename = NULL;
980         const char *l_map_str;
981         ino_t ino;
982         int ref_count, shadow_count, flags;
983         int error;
984         struct vnode *vp;
985         struct vattr vat;
986
987         PROC_LOCK(p);
988         error = p_candebug(td, p);
989         PROC_UNLOCK(p);
990         if (error)
991                 return (error);
992
993         if (uio->uio_rw != UIO_READ)
994                 return (EOPNOTSUPP);
995
996         error = 0;
997         vm = vmspace_acquire_ref(p);
998         if (vm == NULL)
999                 return (ESRCH);
1000
1001         if (SV_CURPROC_FLAG(SV_LP64))
1002                 l_map_str = l64_map_str;
1003         else
1004                 l_map_str = l32_map_str;
1005         map = &vm->vm_map;
1006         vm_map_lock_read(map);
1007         for (entry = map->header.next; entry != &map->header;
1008             entry = entry->next) {
1009                 name = "";
1010                 freename = NULL;
1011                 if (entry->eflags & MAP_ENTRY_IS_SUB_MAP)
1012                         continue;
1013                 e_prot = entry->protection;
1014                 e_start = entry->start;
1015                 e_end = entry->end;
1016                 obj = entry->object.vm_object;
1017                 for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
1018                         VM_OBJECT_RLOCK(tobj);
1019                         if (lobj != obj)
1020                                 VM_OBJECT_RUNLOCK(lobj);
1021                         lobj = tobj;
1022                 }
1023                 last_timestamp = map->timestamp;
1024                 vm_map_unlock_read(map);
1025                 ino = 0;
1026                 if (lobj) {
1027                         off = IDX_TO_OFF(lobj->size);
1028                         if (lobj->type == OBJT_VNODE) {
1029                                 vp = lobj->handle;
1030                                 if (vp)
1031                                         vref(vp);
1032                         }
1033                         else
1034                                 vp = NULL;
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) {
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, "%7ju %7ju %4ju %4ju %4lu %5lu %10lu %9ju ",
1150                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IBYTES),
1151                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS),
1152                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IERRORS),
1153                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS),
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                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS));
1162                                                         /* XXX-BZ rx only? */
1163                 sbuf_printf(sb, "%8ju %7ju %4ju %4ju %4lu %5ju %7lu %10lu\n",
1164                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OBYTES),
1165                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS),
1166                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OERRORS),
1167                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS),
1168                     0UL,                                /* tx_fifo_errors */
1169                     (uintmax_t )ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS),
1170                     0UL,                                /* tx_carrier_errors +
1171                                                          * tx_aborted_errors +
1172                                                          * tx_window_errors +
1173                                                          * tx_heartbeat_errors*/
1174                     0UL);                               /* tx_compressed */
1175         }
1176         IFNET_RUNLOCK();
1177         CURVNET_RESTORE();
1178
1179         return (0);
1180 }
1181
1182 /*
1183  * Filler function for proc/sys/kernel/osrelease
1184  */
1185 static int
1186 linprocfs_doosrelease(PFS_FILL_ARGS)
1187 {
1188         char osrelease[LINUX_MAX_UTSNAME];
1189
1190         linux_get_osrelease(td, osrelease);
1191         sbuf_printf(sb, "%s\n", osrelease);
1192
1193         return (0);
1194 }
1195
1196 /*
1197  * Filler function for proc/sys/kernel/ostype
1198  */
1199 static int
1200 linprocfs_doostype(PFS_FILL_ARGS)
1201 {
1202         char osname[LINUX_MAX_UTSNAME];
1203
1204         linux_get_osname(td, osname);
1205         sbuf_printf(sb, "%s\n", osname);
1206
1207         return (0);
1208 }
1209
1210 /*
1211  * Filler function for proc/sys/kernel/version
1212  */
1213 static int
1214 linprocfs_doosbuild(PFS_FILL_ARGS)
1215 {
1216
1217         linprocfs_osbuild(td, sb);
1218         sbuf_cat(sb, "\n");
1219         return (0);
1220 }
1221
1222 /*
1223  * Filler function for proc/sys/kernel/msgmni
1224  */
1225 static int
1226 linprocfs_domsgmni(PFS_FILL_ARGS)
1227 {
1228
1229         sbuf_printf(sb, "%d\n", msginfo.msgmni);
1230         return (0);
1231 }
1232
1233 /*
1234  * Filler function for proc/sys/kernel/pid_max
1235  */
1236 static int
1237 linprocfs_dopid_max(PFS_FILL_ARGS)
1238 {
1239
1240         sbuf_printf(sb, "%i\n", PID_MAX);
1241         return (0);
1242 }
1243
1244 /*
1245  * Filler function for proc/sys/kernel/sem
1246  */
1247 static int
1248 linprocfs_dosem(PFS_FILL_ARGS)
1249 {
1250
1251         sbuf_printf(sb, "%d %d %d %d\n", seminfo.semmsl, seminfo.semmns,
1252             seminfo.semopm, seminfo.semmni);
1253         return (0);
1254 }
1255
1256 /*
1257  * Filler function for proc/scsi/device_info
1258  */
1259 static int
1260 linprocfs_doscsidevinfo(PFS_FILL_ARGS)
1261 {
1262
1263         return (0);
1264 }
1265
1266 /*
1267  * Filler function for proc/scsi/scsi
1268  */
1269 static int
1270 linprocfs_doscsiscsi(PFS_FILL_ARGS)
1271 {
1272
1273         return (0);
1274 }
1275
1276 /*
1277  * Filler function for proc/devices
1278  */
1279 static int
1280 linprocfs_dodevices(PFS_FILL_ARGS)
1281 {
1282         char *char_devices;
1283         sbuf_printf(sb, "Character devices:\n");
1284
1285         char_devices = linux_get_char_devices();
1286         sbuf_printf(sb, "%s", char_devices);
1287         linux_free_get_char_devices(char_devices);
1288
1289         sbuf_printf(sb, "\nBlock devices:\n");
1290
1291         return (0);
1292 }
1293
1294 /*
1295  * Filler function for proc/cmdline
1296  */
1297 static int
1298 linprocfs_docmdline(PFS_FILL_ARGS)
1299 {
1300
1301         sbuf_printf(sb, "BOOT_IMAGE=%s", kernelname);
1302         sbuf_printf(sb, " ro root=302\n");
1303         return (0);
1304 }
1305
1306 /*
1307  * Filler function for proc/filesystems
1308  */
1309 static int
1310 linprocfs_dofilesystems(PFS_FILL_ARGS)
1311 {
1312         struct vfsconf *vfsp;
1313
1314         mtx_lock(&Giant);
1315         TAILQ_FOREACH(vfsp, &vfsconf, vfc_list) {
1316                 if (vfsp->vfc_flags & VFCF_SYNTHETIC)
1317                         sbuf_printf(sb, "nodev");
1318                 sbuf_printf(sb, "\t%s\n", vfsp->vfc_name);
1319         }
1320         mtx_unlock(&Giant);
1321         return(0);
1322 }
1323
1324 #if 0
1325 /*
1326  * Filler function for proc/modules
1327  */
1328 static int
1329 linprocfs_domodules(PFS_FILL_ARGS)
1330 {
1331         struct linker_file *lf;
1332
1333         TAILQ_FOREACH(lf, &linker_files, link) {
1334                 sbuf_printf(sb, "%-20s%8lu%4d\n", lf->filename,
1335                     (unsigned long)lf->size, lf->refs);
1336         }
1337         return (0);
1338 }
1339 #endif
1340
1341 /*
1342  * Filler function for proc/pid/fd
1343  */
1344 static int
1345 linprocfs_dofdescfs(PFS_FILL_ARGS)
1346 {
1347
1348         if (p == curproc)
1349                 sbuf_printf(sb, "/dev/fd");
1350         else
1351                 sbuf_printf(sb, "unknown");
1352         return (0);
1353 }
1354
1355
1356 /*
1357  * Filler function for proc/sys/kernel/random/uuid
1358  */
1359 static int
1360 linprocfs_douuid(PFS_FILL_ARGS)
1361 {
1362         struct uuid uuid;
1363
1364         kern_uuidgen(&uuid, 1);
1365         sbuf_printf_uuid(sb, &uuid);
1366         sbuf_printf(sb, "\n");
1367         return(0);
1368 }
1369
1370 /*
1371  * Filler function for proc/pid/auxv
1372  */
1373 static int
1374 linprocfs_doauxv(PFS_FILL_ARGS)
1375 {
1376         struct sbuf *asb;
1377         off_t buflen, resid;
1378         int error;
1379
1380         /*
1381          * Mimic linux behavior and pass only processes with usermode
1382          * address space as valid. Return zero silently otherwise.
1383          */
1384         if (p->p_vmspace == &vmspace0)
1385                 return (0);
1386
1387         if (uio->uio_resid == 0)
1388                 return (0);
1389         if (uio->uio_offset < 0 || uio->uio_resid < 0)
1390                 return (EINVAL);
1391
1392         asb = sbuf_new_auto();
1393         if (asb == NULL)
1394                 return (ENOMEM);
1395         error = proc_getauxv(td, p, asb);
1396         if (error == 0)
1397                 error = sbuf_finish(asb);
1398
1399         resid = sbuf_len(asb) - uio->uio_offset;
1400         if (resid > uio->uio_resid)
1401                 buflen = uio->uio_resid;
1402         else
1403                 buflen = resid;
1404         if (buflen > IOSIZE_MAX)
1405                 return (EINVAL);
1406         if (buflen > MAXPHYS)
1407                 buflen = MAXPHYS;
1408         if (resid <= 0)
1409                 return (0);
1410
1411         if (error == 0)
1412                 error = uiomove(sbuf_data(asb) + uio->uio_offset, buflen, uio);
1413         sbuf_delete(asb);
1414         return (error);
1415 }
1416
1417 /*
1418  * Constructor
1419  */
1420 static int
1421 linprocfs_init(PFS_INIT_ARGS)
1422 {
1423         struct pfs_node *root;
1424         struct pfs_node *dir;
1425
1426         root = pi->pi_root;
1427
1428         /* /proc/... */
1429         pfs_create_file(root, "cmdline", &linprocfs_docmdline,
1430             NULL, NULL, NULL, PFS_RD);
1431         pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
1432             NULL, NULL, NULL, PFS_RD);
1433         pfs_create_file(root, "devices", &linprocfs_dodevices,
1434             NULL, NULL, NULL, PFS_RD);
1435         pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
1436             NULL, NULL, NULL, PFS_RD);
1437         pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
1438             NULL, NULL, NULL, PFS_RD);
1439         pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
1440             NULL, NULL, NULL, PFS_RD);
1441 #if 0
1442         pfs_create_file(root, "modules", &linprocfs_domodules,
1443             NULL, NULL, NULL, PFS_RD);
1444 #endif
1445         pfs_create_file(root, "mounts", &linprocfs_domtab,
1446             NULL, NULL, NULL, PFS_RD);
1447         pfs_create_file(root, "mtab", &linprocfs_domtab,
1448             NULL, NULL, NULL, PFS_RD);
1449         pfs_create_file(root, "partitions", &linprocfs_dopartitions,
1450             NULL, NULL, NULL, PFS_RD);
1451         pfs_create_link(root, "self", &procfs_docurproc,
1452             NULL, NULL, NULL, 0);
1453         pfs_create_file(root, "stat", &linprocfs_dostat,
1454             NULL, NULL, NULL, PFS_RD);
1455         pfs_create_file(root, "swaps", &linprocfs_doswaps,
1456             NULL, NULL, NULL, PFS_RD);
1457         pfs_create_file(root, "uptime", &linprocfs_douptime,
1458             NULL, NULL, NULL, PFS_RD);
1459         pfs_create_file(root, "version", &linprocfs_doversion,
1460             NULL, NULL, NULL, PFS_RD);
1461
1462         /* /proc/net/... */
1463         dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
1464         pfs_create_file(dir, "dev", &linprocfs_donetdev,
1465             NULL, NULL, NULL, PFS_RD);
1466
1467         /* /proc/<pid>/... */
1468         dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
1469         pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
1470             NULL, NULL, NULL, PFS_RD);
1471         pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
1472             NULL, NULL, NULL, 0);
1473         pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
1474             NULL, &procfs_candebug, NULL, PFS_RD);
1475         pfs_create_link(dir, "exe", &procfs_doprocfile,
1476             NULL, &procfs_notsystem, NULL, 0);
1477         pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
1478             NULL, NULL, NULL, PFS_RD);
1479         pfs_create_file(dir, "mem", &procfs_doprocmem,
1480             &procfs_attr, &procfs_candebug, NULL, PFS_RDWR|PFS_RAW);
1481         pfs_create_link(dir, "root", &linprocfs_doprocroot,
1482             NULL, NULL, NULL, 0);
1483         pfs_create_file(dir, "stat", &linprocfs_doprocstat,
1484             NULL, NULL, NULL, PFS_RD);
1485         pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
1486             NULL, NULL, NULL, PFS_RD);
1487         pfs_create_file(dir, "status", &linprocfs_doprocstatus,
1488             NULL, NULL, NULL, PFS_RD);
1489         pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
1490             NULL, NULL, NULL, 0);
1491         pfs_create_file(dir, "auxv", &linprocfs_doauxv,
1492             NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
1493
1494         /* /proc/scsi/... */
1495         dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
1496         pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
1497             NULL, NULL, NULL, PFS_RD);
1498         pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
1499             NULL, NULL, NULL, PFS_RD);
1500
1501         /* /proc/sys/... */
1502         dir = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
1503         /* /proc/sys/kernel/... */
1504         dir = pfs_create_dir(dir, "kernel", NULL, NULL, NULL, 0);
1505         pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
1506             NULL, NULL, NULL, PFS_RD);
1507         pfs_create_file(dir, "ostype", &linprocfs_doostype,
1508             NULL, NULL, NULL, PFS_RD);
1509         pfs_create_file(dir, "version", &linprocfs_doosbuild,
1510             NULL, NULL, NULL, PFS_RD);
1511         pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
1512             NULL, NULL, NULL, PFS_RD);
1513         pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
1514             NULL, NULL, NULL, PFS_RD);
1515         pfs_create_file(dir, "sem", &linprocfs_dosem,
1516             NULL, NULL, NULL, PFS_RD);
1517
1518         /* /proc/sys/kernel/random/... */
1519         dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
1520         pfs_create_file(dir, "uuid", &linprocfs_douuid,
1521             NULL, NULL, NULL, PFS_RD);
1522
1523         return (0);
1524 }
1525
1526 /*
1527  * Destructor
1528  */
1529 static int
1530 linprocfs_uninit(PFS_INIT_ARGS)
1531 {
1532
1533         /* nothing to do, pseudofs will GC */
1534         return (0);
1535 }
1536
1537 PSEUDOFS(linprocfs, 1, 0);
1538 #if defined(__amd64__)
1539 MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1);
1540 #else
1541 MODULE_DEPEND(linprocfs, linux, 1, 1, 1);
1542 #endif
1543 MODULE_DEPEND(linprocfs, procfs, 1, 1, 1);
1544 MODULE_DEPEND(linprocfs, sysvmsg, 1, 1, 1);
1545 MODULE_DEPEND(linprocfs, sysvsem, 1, 1, 1);