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