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