// /proc — synthesised kernel status files. // // Each file is a character device node under major PROCFS_MAJOR, distinguished // by its minor number, created by init at boot. Reading one renders the whole // text into a scratch buffer and returns the slice starting at the caller's // file offset, so a normal read-until-zero loop terminates. // // SCOPE: these are the *global* files. Per-process directories (/proc//…) // are not here, because they need something this kernel does not have yet: // synthetic directories, i.e. a directory whose entries are generated at // lookup and getdents time rather than read from disk. That is a real VFS // feature touching iget/ilock/dirlookup/getdents, and it is the natural // companion to the SchFS work rather than a bolt-on to the current fs.c. // The namespace (which files exist, including one directory per process) is // kernel/fs/procfs.c; this file only generates the *content* of the global // files. `ps` and `top` work through the former. #include "types.h" #include "defs.h" #include "irq.h" #include "x86.h" #include "device.h" #include "display.h" #include "netdev.h" #include "param.h" #include "memlayout.h" #include "mmu.h" #include "spinlock.h" #include "sleeplock.h" #include "fs.h" #include "file.h" #include "proc.h" #include "uaccess.h" #include "errno.h" #include "fsstat.h" #include "schfs.h" #define PROC_BUFSZ 2048 // --- tiny formatting helpers (no snprintf in the kernel) ------------------- struct sbuf { char *p; int len; int cap; }; static void sb_putc(struct sbuf *sb, char c) { if (sb->len < sb->cap - 1) sb->p[sb->len++] = c; } static void sb_puts(struct sbuf *sb, const char *s) { while (*s) sb_putc(sb, *s++); } // A string in a fixed-width column, space-padded. cprintf has no width // specifier and neither does this buffer, so tables build their own columns. // Over-long values are allowed to run past their column rather than be // truncated: a misaligned row is easier to read than a mangled name. static void sb_pad(struct sbuf *sb, const char *s, int width) { int n = 0; while (s[n]) { sb_putc(sb, s[n]); n++; } while (n++ < width) sb_putc(sb, ' '); } // Four lowercase hex digits, zero-padded. PCI and USB identifiers are always // written this way, and a lookup table keyed on "8086:100e" does not match // "8086:100E" or "8086:10e". static void sb_puthex4(struct sbuf *sb, uint32 v) { static const char hex[] = "0123456789abcdef"; for (int i = 3; i >= 0; i--) sb_putc(sb, hex[(v >> (i * 4)) & 0xF]); } static void sb_putu(struct sbuf *sb, uint64 v) { char tmp[24]; int i = 0; if (v == 0) { sb_putc(sb, '0'); return; } while (v && i < (int)sizeof(tmp)) { tmp[i++] = '0' + (v % 10); v /= 10; } while (i--) sb_putc(sb, tmp[i]); } // "