procfs_linux.c revision 1.85 1 /* $NetBSD: procfs_linux.c,v 1.85 2020/06/11 19:20:46 ad Exp $ */
2
3 /*
4 * Copyright (c) 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Frank van der Linden for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: procfs_linux.c,v 1.85 2020/06/11 19:20:46 ad Exp $");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/atomic.h>
44 #include <sys/time.h>
45 #include <sys/cpu.h>
46 #include <sys/kernel.h>
47 #include <sys/proc.h>
48 #include <sys/vnode.h>
49 #include <sys/exec.h>
50 #include <sys/resource.h>
51 #include <sys/resourcevar.h>
52 #include <sys/signal.h>
53 #include <sys/signalvar.h>
54 #include <sys/tty.h>
55 #include <sys/malloc.h>
56 #include <sys/mount.h>
57 #include <sys/conf.h>
58 #include <sys/sysctl.h>
59 #include <sys/kauth.h>
60 #include <sys/filedesc.h>
61
62 #include <miscfs/procfs/procfs.h>
63
64 #include <compat/linux/common/linux_exec.h>
65 #include <compat/linux32/common/linux32_sysctl.h>
66
67 #include <uvm/uvm_extern.h>
68 #include <uvm/uvm.h>
69
70 extern struct devsw_conv *devsw_conv;
71 extern int max_devsw_convs;
72
73 #define PGTOB(p) ((unsigned long)(p) << PAGE_SHIFT)
74 #define PGTOKB(p) ((unsigned long)(p) << (PAGE_SHIFT - 10))
75
76 #define LBFSZ (8 * 1024)
77
78 static void
79 get_proc_size_info(struct proc *p, struct vm_map *map, unsigned long *stext,
80 unsigned long *etext, unsigned long *sstack)
81 {
82 struct vm_map_entry *entry;
83
84 *stext = 0;
85 *etext = 0;
86 *sstack = 0;
87
88 vm_map_lock_read(map);
89
90 for (entry = map->header.next; entry != &map->header;
91 entry = entry->next) {
92 if (UVM_ET_ISSUBMAP(entry))
93 continue;
94 /* assume text is the first entry */
95 if (*stext == *etext) {
96 *stext = entry->start;
97 *etext = entry->end;
98 break;
99 }
100 }
101 #if defined(LINUX_USRSTACK32) && defined(USRSTACK32)
102 if (strcmp(p->p_emul->e_name, "linux32") == 0 &&
103 LINUX_USRSTACK32 < USRSTACK32)
104 *sstack = (unsigned long)LINUX_USRSTACK32;
105 else
106 #endif
107 #ifdef LINUX_USRSTACK
108 if (strcmp(p->p_emul->e_name, "linux") == 0 &&
109 LINUX_USRSTACK < USRSTACK)
110 *sstack = (unsigned long)LINUX_USRSTACK;
111 else
112 #endif
113 #ifdef USRSTACK32
114 if (strstr(p->p_emul->e_name, "32") != NULL)
115 *sstack = (unsigned long)USRSTACK32;
116 else
117 #endif
118 *sstack = (unsigned long)USRSTACK;
119
120 /*
121 * jdk 1.6 compares low <= addr && addr < high
122 * if we put addr == high, then the test fails
123 * so eat one page.
124 */
125 *sstack -= PAGE_SIZE;
126
127 vm_map_unlock_read(map);
128 }
129
130 /*
131 * Linux compatible /proc/meminfo. Only active when the -o linux
132 * mountflag is used.
133 */
134 int
135 procfs_domeminfo(struct lwp *curl, struct proc *p,
136 struct pfsnode *pfs, struct uio *uio)
137 {
138 char *bf;
139 int len;
140 int error = 0;
141 long filepg, anonpg, execpg, freepg;
142
143 bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
144
145 cpu_count_sync_all();
146 freepg = (long)uvm_availmem(true);
147 filepg = (long)cpu_count_get(CPU_COUNT_FILEPAGES);
148 anonpg = (long)cpu_count_get(CPU_COUNT_ANONPAGES);
149 execpg = (long)cpu_count_get(CPU_COUNT_EXECPAGES);
150
151 len = snprintf(bf, LBFSZ,
152 " total: used: free: shared: buffers: cached:\n"
153 "Mem: %8lu %8lu %8lu %8lu %8lu %8lu\n"
154 "Swap: %8lu %8lu %8lu\n"
155 "MemTotal: %8lu kB\n"
156 "MemFree: %8lu kB\n"
157 "MemShared: %8lu kB\n"
158 "Buffers: %8lu kB\n"
159 "Cached: %8lu kB\n"
160 "SwapTotal: %8lu kB\n"
161 "SwapFree: %8lu kB\n",
162 PGTOB(uvmexp.npages),
163 PGTOB(uvmexp.npages - freepg),
164 PGTOB(freepg),
165 0L,
166 PGTOB(filepg),
167 PGTOB(anonpg + filepg + execpg),
168 PGTOB(uvmexp.swpages),
169 PGTOB(uvmexp.swpginuse),
170 PGTOB(uvmexp.swpages - uvmexp.swpginuse),
171 PGTOKB(uvmexp.npages),
172 PGTOKB(freepg),
173 0L,
174 PGTOKB(freepg),
175 PGTOKB(anonpg + filepg + execpg),
176 PGTOKB(uvmexp.swpages),
177 PGTOKB(uvmexp.swpages - uvmexp.swpginuse));
178
179 if (len == 0)
180 goto out;
181
182 error = uiomove_frombuf(bf, len, uio);
183 out:
184 free(bf, M_TEMP);
185 return error;
186 }
187
188 /*
189 * Linux compatible /proc/devices. Only active when the -o linux
190 * mountflag is used.
191 */
192 int
193 procfs_dodevices(struct lwp *curl, struct proc *p,
194 struct pfsnode *pfs, struct uio *uio)
195 {
196 char *bf;
197 int offset = 0;
198 int i, error = ENAMETOOLONG;
199
200 /* XXX elad - may need filtering. */
201
202 bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
203
204 offset += snprintf(&bf[offset], LBFSZ - offset, "Character devices:\n");
205 if (offset >= LBFSZ)
206 goto out;
207
208 mutex_enter(&device_lock);
209 for (i = 0; i < max_devsw_convs; i++) {
210 if ((devsw_conv[i].d_name == NULL) ||
211 (devsw_conv[i].d_cmajor == -1))
212 continue;
213
214 offset += snprintf(&bf[offset], LBFSZ - offset,
215 "%3d %s\n", devsw_conv[i].d_cmajor, devsw_conv[i].d_name);
216 if (offset >= LBFSZ) {
217 mutex_exit(&device_lock);
218 goto out;
219 }
220 }
221
222 offset += snprintf(&bf[offset], LBFSZ - offset, "\nBlock devices:\n");
223 if (offset >= LBFSZ) {
224 mutex_exit(&device_lock);
225 goto out;
226 }
227
228 for (i = 0; i < max_devsw_convs; i++) {
229 if ((devsw_conv[i].d_name == NULL) ||
230 (devsw_conv[i].d_bmajor == -1))
231 continue;
232
233 offset += snprintf(&bf[offset], LBFSZ - offset,
234 "%3d %s\n", devsw_conv[i].d_bmajor, devsw_conv[i].d_name);
235 if (offset >= LBFSZ) {
236 mutex_exit(&device_lock);
237 goto out;
238 }
239 }
240 mutex_exit(&device_lock);
241
242 error = uiomove_frombuf(bf, offset, uio);
243 out:
244 free(bf, M_TEMP);
245 return error;
246 }
247
248 /*
249 * Linux compatible /proc/stat. Only active when the -o linux
250 * mountflag is used.
251 */
252 int
253 procfs_docpustat(struct lwp *curl, struct proc *p,
254 struct pfsnode *pfs, struct uio *uio)
255 {
256 char *bf;
257 int error;
258 int len;
259 #if defined(MULTIPROCESSOR)
260 struct cpu_info *ci;
261 CPU_INFO_ITERATOR cii;
262 #endif
263 int i;
264
265 error = ENAMETOOLONG;
266 bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
267
268 len = snprintf(bf, LBFSZ,
269 "cpu %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
270 curcpu()->ci_schedstate.spc_cp_time[CP_USER],
271 curcpu()->ci_schedstate.spc_cp_time[CP_NICE],
272 curcpu()->ci_schedstate.spc_cp_time[CP_SYS] /*+ [CP_INTR]*/,
273 curcpu()->ci_schedstate.spc_cp_time[CP_IDLE]);
274 if (len == 0)
275 goto out;
276
277 #if defined(MULTIPROCESSOR)
278 #define ALLCPUS CPU_INFO_FOREACH(cii, ci)
279 #define CPUNAME ci
280 #else
281 #define ALLCPUS ; i < 1 ;
282 #define CPUNAME curcpu()
283 #endif
284
285 i = 0;
286 for (ALLCPUS) {
287 len += snprintf(&bf[len], LBFSZ - len,
288 "cpu%d %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64
289 "\n", i,
290 CPUNAME->ci_schedstate.spc_cp_time[CP_USER],
291 CPUNAME->ci_schedstate.spc_cp_time[CP_NICE],
292 CPUNAME->ci_schedstate.spc_cp_time[CP_SYS],
293 CPUNAME->ci_schedstate.spc_cp_time[CP_IDLE]);
294 if (len >= LBFSZ)
295 goto out;
296 i += 1;
297 }
298
299 cpu_count_sync_all();
300
301 struct timeval btv;
302 getmicroboottime(&btv);
303
304 len += snprintf(&bf[len], LBFSZ - len,
305 "disk 0 0 0 0\n"
306 "page %u %u\n"
307 "swap %u %u\n"
308 "intr %"PRId64"\n"
309 "ctxt %"PRId64"\n"
310 "btime %"PRId64"\n",
311 uvmexp.pageins, uvmexp.pdpageouts,
312 uvmexp.pgswapin, uvmexp.pgswapout,
313 cpu_count_get(CPU_COUNT_NINTR),
314 cpu_count_get(CPU_COUNT_NSWTCH),
315 btv.tv_sec);
316 if (len >= LBFSZ)
317 goto out;
318
319 error = uiomove_frombuf(bf, len, uio);
320 out:
321 free(bf, M_TEMP);
322 return error;
323 }
324
325 /*
326 * Linux compatible /proc/loadavg. Only active when the -o linux
327 * mountflag is used.
328 */
329 int
330 procfs_doloadavg(struct lwp *curl, struct proc *p,
331 struct pfsnode *pfs, struct uio *uio)
332 {
333 char *bf;
334 int error;
335 int len;
336
337 error = ENAMETOOLONG;
338 bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
339
340 averunnable.fscale = FSCALE;
341 len = snprintf(bf, LBFSZ,
342 "%d.%02d %d.%02d %d.%02d %d/%d %d\n",
343 (int)(averunnable.ldavg[0] / averunnable.fscale),
344 (int)(averunnable.ldavg[0] * 100 / averunnable.fscale % 100),
345 (int)(averunnable.ldavg[1] / averunnable.fscale),
346 (int)(averunnable.ldavg[1] * 100 / averunnable.fscale % 100),
347 (int)(averunnable.ldavg[2] / averunnable.fscale),
348 (int)(averunnable.ldavg[2] * 100 / averunnable.fscale % 100),
349 1, /* number of ONPROC processes */
350 atomic_load_relaxed(&nprocs),
351 30000); /* last pid */
352 if (len == 0)
353 goto out;
354
355 error = uiomove_frombuf(bf, len, uio);
356 out:
357 free(bf, M_TEMP);
358 return error;
359 }
360
361 /*
362 * Linux compatible /proc/<pid>/statm. Only active when the -o linux
363 * mountflag is used.
364 */
365 int
366 procfs_do_pid_statm(struct lwp *curl, struct lwp *l,
367 struct pfsnode *pfs, struct uio *uio)
368 {
369 struct vmspace *vm;
370 struct proc *p = l->l_proc;
371 char *bf;
372 int error;
373 int len;
374 struct kinfo_proc2 ki;
375
376 bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
377
378 /* XXX - we use values from vmspace, since dsl says that ru figures
379 are always 0 except for zombies. See kvm_proc.c::kvm_getproc2() */
380 if ((error = proc_vmspace_getref(p, &vm)) != 0) {
381 goto out;
382 }
383
384 mutex_enter(&proc_lock);
385 mutex_enter(p->p_lock);
386
387 /* retrieve RSS size */
388 memset(&ki, 0, sizeof(ki));
389 fill_kproc2(p, &ki, false, false);
390
391 mutex_exit(p->p_lock);
392 mutex_exit(&proc_lock);
393
394 uvmspace_free(vm);
395
396 len = snprintf(bf, LBFSZ,
397 "%lu %lu %lu %lu %lu %lu %lu\n",
398 (unsigned long)(ki.p_vm_msize), /* size */
399 (unsigned long)(ki.p_vm_rssize),/* resident */
400 (unsigned long)(ki.p_uru_ixrss),/* shared */
401 (unsigned long)(ki.p_vm_tsize), /* text */
402 (unsigned long) 0, /* library (unused) */
403 (unsigned long)(ki.p_vm_dsize + ki.p_vm_ssize), /* data+stack */
404 (unsigned long) 0); /* dirty */
405
406 if (len == 0)
407 goto out;
408
409 error = uiomove_frombuf(bf, len, uio);
410 out:
411 free(bf, M_TEMP);
412 return error;
413 }
414
415 #define UTIME2TICKS(s,u) (((uint64_t)(s) * 1000000 + (u)) / 10000)
416
417 /*
418 * Linux compatible /proc/<pid>/stat. Only active when the -o linux
419 * mountflag is used.
420 */
421 int
422 procfs_do_pid_stat(struct lwp *curl, struct lwp *l,
423 struct pfsnode *pfs, struct uio *uio)
424 {
425 char *bf;
426 struct proc *p = l->l_proc;
427 int len;
428 struct rusage *cru = &p->p_stats->p_cru;
429 unsigned long stext = 0, etext = 0, sstack = 0;
430 struct timeval rt;
431 struct vmspace *vm;
432 struct kinfo_proc2 ki;
433 int error;
434
435 bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
436
437 if ((error = proc_vmspace_getref(p, &vm)) != 0) {
438 goto out;
439 }
440
441 get_proc_size_info(p, &vm->vm_map, &stext, &etext, &sstack);
442
443 mutex_enter(&proc_lock);
444 mutex_enter(p->p_lock);
445
446 memset(&ki, 0, sizeof(ki));
447 fill_kproc2(p, &ki, false, false);
448 calcru(p, NULL, NULL, NULL, &rt);
449
450 len = snprintf(bf, LBFSZ,
451 "%d (%s) %c %d %d %d %u %d "
452 "%u "
453 "%"PRIu64" %lu %"PRIu64" %lu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" "
454 "%d %d %"PRIu64" "
455 "%lld %"PRIu64" %"PRId64" %lu %"PRIu64" "
456 "%lu %lu %lu "
457 "%u %u "
458 "%u %u %u %u "
459 "%"PRIu64" %"PRIu64" %"PRIu64" %d %"PRIu64"\n",
460
461 ki.p_pid, /* 1 pid */
462 ki.p_comm, /* 2 tcomm */
463 "0RRSTZXR8"[(ki.p_stat > 8) ? 0 : (int)ki.p_stat], /* 3 state */
464 ki.p_ppid, /* 4 ppid */
465 ki.p__pgid, /* 5 pgrp */
466 ki.p_sid, /* 6 sid */
467 (ki.p_tdev != (uint32_t)NODEV) ? ki.p_tdev : 0, /* 7 tty_nr */
468 ki.p_tpgid, /* 8 tty_pgrp */
469
470 ki.p_flag, /* 9 flags */
471
472 ki.p_uru_minflt, /* 10 min_flt */
473 cru->ru_minflt,
474 ki.p_uru_majflt, /* 12 maj_flt */
475 cru->ru_majflt,
476 UTIME2TICKS(ki.p_uutime_sec, ki.p_uutime_usec), /* 14 utime */
477 UTIME2TICKS(ki.p_ustime_sec, ki.p_ustime_usec), /* 15 stime */
478 UTIME2TICKS(cru->ru_utime.tv_sec, cru->ru_utime.tv_usec), /* 16 cutime */
479 UTIME2TICKS(cru->ru_stime.tv_sec, cru->ru_stime.tv_usec), /* 17 cstime */
480
481 ki.p_priority, /* XXX: 18 priority */
482 ki.p_nice - NZERO, /* 19 nice */
483 ki.p_nlwps, /* 20 num_threads */
484
485 (long long)rt.tv_sec,
486 UTIME2TICKS(ki.p_ustart_sec, ki.p_ustart_usec), /* 22 start_time */
487 ki.p_vm_msize, /* 23 vsize */
488 PGTOKB(ki.p_vm_rssize), /* 24 rss */
489 p->p_rlimit[RLIMIT_RSS].rlim_cur, /* 25 rsslim */
490
491 stext, /* 26 start_code */
492 etext, /* 27 end_code */
493 sstack, /* 28 start_stack */
494
495 0, /* XXX: 29 esp */
496 0, /* XXX: 30 eip */
497
498 ki.p_siglist.__bits[0], /* XXX: 31 pending */
499 0, /* XXX: 32 blocked */
500 ki.p_sigignore.__bits[0], /* 33 sigign */
501 ki.p_sigcatch.__bits[0], /* 34 sigcatch */
502
503 ki.p_wchan, /* 35 wchan */
504 ki.p_uru_nvcsw,
505 ki.p_uru_nivcsw,
506 ki.p_exitsig, /* 38 exit_signal */
507 ki.p_cpuid); /* 39 task_cpu */
508
509 mutex_exit(p->p_lock);
510 mutex_exit(&proc_lock);
511
512 uvmspace_free(vm);
513
514 if (len == 0)
515 goto out;
516
517 error = uiomove_frombuf(bf, len, uio);
518 out:
519 free(bf, M_TEMP);
520 return error;
521 }
522
523 int
524 procfs_docpuinfo(struct lwp *curl, struct proc *p,
525 struct pfsnode *pfs, struct uio *uio)
526 {
527 size_t len = LBFSZ;
528 char *bf = NULL;
529 int error;
530
531 do {
532 if (bf)
533 free(bf, M_TEMP);
534 bf = malloc(len, M_TEMP, M_WAITOK);
535 } while (procfs_getcpuinfstr(bf, &len) < 0);
536
537 if (len == 0) {
538 error = 0;
539 goto done;
540 }
541
542 error = uiomove_frombuf(bf, len, uio);
543 done:
544 free(bf, M_TEMP);
545 return error;
546 }
547
548 int
549 procfs_douptime(struct lwp *curl, struct proc *p,
550 struct pfsnode *pfs, struct uio *uio)
551 {
552 char *bf;
553 int len;
554 struct timeval runtime;
555 u_int64_t idle;
556 int error = 0;
557
558 bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
559
560 microuptime(&runtime);
561 idle = curcpu()->ci_schedstate.spc_cp_time[CP_IDLE];
562 len = snprintf(bf, LBFSZ,
563 "%lld.%02lu %" PRIu64 ".%02" PRIu64 "\n",
564 (long long)runtime.tv_sec, (long)runtime.tv_usec / 10000,
565 idle / hz, (((idle % hz) * 100) / hz) % 100);
566
567 if (len == 0)
568 goto out;
569
570 error = uiomove_frombuf(bf, len, uio);
571 out:
572 free(bf, M_TEMP);
573 return error;
574 }
575
576 static int
577 procfs_format_sfs(char **mtab, size_t *mlen, char *buf, size_t blen,
578 const struct statvfs *sfs, struct lwp *curl, int suser)
579 {
580 const char *fsname;
581
582 /* Linux uses different names for some filesystems */
583 fsname = sfs->f_fstypename;
584 if (strcmp(fsname, "procfs") == 0)
585 fsname = "proc";
586 else if (strcmp(fsname, "ext2fs") == 0)
587 fsname = "ext2";
588
589 blen = snprintf(buf, blen, "%s %s %s %s%s%s%s%s%s 0 0\n",
590 sfs->f_mntfromname, sfs->f_mntonname, fsname,
591 (sfs->f_flag & ST_RDONLY) ? "ro" : "rw",
592 (sfs->f_flag & ST_NOSUID) ? ",nosuid" : "",
593 (sfs->f_flag & ST_NOEXEC) ? ",noexec" : "",
594 (sfs->f_flag & ST_NODEV) ? ",nodev" : "",
595 (sfs->f_flag & ST_SYNCHRONOUS) ? ",sync" : "",
596 (sfs->f_flag & ST_NOATIME) ? ",noatime" : "");
597
598 *mtab = realloc(*mtab, *mlen + blen, M_TEMP, M_WAITOK);
599 memcpy(*mtab + *mlen, buf, blen);
600 *mlen += blen;
601 return sfs->f_mntonname[0] == '/' && sfs->f_mntonname[1] == '\0';
602 }
603
604 int
605 procfs_domounts(struct lwp *curl, struct proc *p,
606 struct pfsnode *pfs, struct uio *uio)
607 {
608 char *bf, *mtab = NULL;
609 size_t mtabsz = 0;
610 mount_iterator_t *iter;
611 struct mount *mp;
612 int error = 0, root = 0;
613 struct cwdinfo *cwdi = curl->l_proc->p_cwdi;
614 struct statvfs *sfs;
615
616 bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
617
618 sfs = malloc(sizeof(*sfs), M_TEMP, M_WAITOK);
619 mountlist_iterator_init(&iter);
620 while ((mp = mountlist_iterator_next(iter)) != NULL) {
621 if ((error = dostatvfs(mp, sfs, curl, MNT_WAIT, 0)) == 0)
622 root |= procfs_format_sfs(&mtab, &mtabsz, bf, LBFSZ,
623 sfs, curl, 0);
624 }
625 mountlist_iterator_destroy(iter);
626 free(sfs, M_TEMP);
627
628 /*
629 * If we are inside a chroot that is not itself a mount point,
630 * fake a root entry.
631 */
632 if (!root && cwdi->cwdi_rdir)
633 (void)procfs_format_sfs(&mtab, &mtabsz, bf, LBFSZ,
634 &cwdi->cwdi_rdir->v_mount->mnt_stat, curl, 1);
635
636 free(bf, M_TEMP);
637
638 if (mtabsz > 0) {
639 error = uiomove_frombuf(mtab, mtabsz, uio);
640 free(mtab, M_TEMP);
641 }
642
643 return error;
644 }
645
646 /*
647 * Linux compatible /proc/version. Only active when the -o linux
648 * mountflag is used.
649 */
650 int
651 procfs_doversion(struct lwp *curl, struct proc *p,
652 struct pfsnode *pfs, struct uio *uio)
653 {
654 char *bf;
655 char lostype[20], losrelease[20], lversion[80];
656 const char *postype, *posrelease, *pversion;
657 const char *emulname = curlwp->l_proc->p_emul->e_name;
658 int len;
659 int error = 0;
660 int nm[4];
661 size_t buflen;
662
663 CTASSERT(EMUL_LINUX_KERN_OSTYPE == EMUL_LINUX32_KERN_OSTYPE);
664 CTASSERT(EMUL_LINUX_KERN_OSRELEASE == EMUL_LINUX32_KERN_OSRELEASE);
665 CTASSERT(EMUL_LINUX_KERN_VERSION == EMUL_LINUX32_KERN_VERSION);
666
667 bf = malloc(LBFSZ, M_TEMP, M_WAITOK);
668
669 sysctl_lock(false);
670
671 if (strncmp(emulname, "linux", 5) == 0) {
672 /*
673 * Lookup the emulation ostype, osrelease, and version.
674 * Since compat_linux and compat_linux32 can be built as
675 * modules, we use sysctl to obtain the values instead of
676 * using the symbols directly.
677 */
678
679 if (strcmp(emulname, "linux32") == 0) {
680 nm[0] = CTL_EMUL;
681 nm[1] = EMUL_LINUX32;
682 nm[2] = EMUL_LINUX32_KERN;
683 } else {
684 nm[0] = CTL_EMUL;
685 nm[1] = EMUL_LINUX;
686 nm[2] = EMUL_LINUX_KERN;
687 }
688
689 nm[3] = EMUL_LINUX_KERN_OSTYPE;
690 buflen = sizeof(lostype);
691 error = sysctl_dispatch(nm, __arraycount(nm),
692 lostype, &buflen,
693 NULL, 0, NULL, NULL, NULL);
694 if (error)
695 goto out;
696
697 nm[3] = EMUL_LINUX_KERN_OSRELEASE;
698 buflen = sizeof(losrelease);
699 error = sysctl_dispatch(nm, __arraycount(nm),
700 losrelease, &buflen,
701 NULL, 0, NULL, NULL, NULL);
702 if (error)
703 goto out;
704
705 nm[3] = EMUL_LINUX_KERN_VERSION;
706 buflen = sizeof(lversion);
707 error = sysctl_dispatch(nm, __arraycount(nm),
708 lversion, &buflen,
709 NULL, 0, NULL, NULL, NULL);
710 if (error)
711 goto out;
712
713 postype = lostype;
714 posrelease = losrelease;
715 pversion = lversion;
716 } else {
717 postype = ostype;
718 posrelease = osrelease;
719 strlcpy(lversion, version, sizeof(lversion));
720 if (strchr(lversion, '\n'))
721 *strchr(lversion, '\n') = '\0';
722 pversion = lversion;
723 }
724
725 len = snprintf(bf, LBFSZ,
726 "%s version %s (%s@localhost) (gcc version %s) %s\n",
727 postype, posrelease, emulname,
728 #ifdef __VERSION__
729 __VERSION__,
730 #else
731 "unknown",
732 #endif
733 pversion);
734
735 if (len == 0)
736 goto out;
737
738 error = uiomove_frombuf(bf, len, uio);
739 out:
740 free(bf, M_TEMP);
741 sysctl_unlock();
742 return error;
743 }
744