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