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