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