Pseudo-terminals, and what tmux and htop needed around them
- /dev/ptmx and /dev/pts/N: Unix98 pairs with a full line discipline, window sizes, job control and hangup (kernel/dev/pty.c). - The console speaks scroll regions, insert/delete line, SU/SD, RI/IND/NEL, DECSC/DECRC; swallows charset designations and private CSI sequences; and LF only returns the carriage under ONLCR. - setsid() drops the controlling terminal, so a pane's pty becomes its ctty. - pipe2() honours O_NONBLOCK and O_CLOEXEC (libevent's signal pipe). - File modes are stored and enforced: chmod, fchmod(at), umask, creation modes; /tmp is 1777. - /proc/stat has real user/system/idle; /proc/<pid>/task; kthread flag. - SO_PEERCRED, IOV_MAX 1024. - /proc/strace: name a program and its syscalls go to the kernel log. - World gains htop, btop, tmux, mc, ncdu, fastfetch, games, X toys, NetSurf. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
c65bfa3fa3
commit
fd9d392416
28 changed files with 1577 additions and 47 deletions
|
|
@ -194,16 +194,36 @@ static void
|
|||
gen_stat(struct sbuf *sb)
|
||||
{
|
||||
// USER_HZ, like times() -- everything that parses /proc/stat divides by 100.
|
||||
uint t = (uint)((uint64)uptime() * USER_HZ / HZ);
|
||||
//
|
||||
// Busy is what processes were charged; idle is the rest of every online
|
||||
// processor's time. Calling it all user time, as this did, is a machine at
|
||||
// 100% forever in htop and top. The charge is not kept per processor, so
|
||||
// each cpuN line is an equal share of the total -- right on average, which
|
||||
// is all a meter can show anyway.
|
||||
uint64 n = ncpu_online > 0 ? ncpu_online : 1;
|
||||
uint64 all = (uint64)uptime() * USER_HZ / HZ * n;
|
||||
uint64 user, sys;
|
||||
proc_cputime(&user, &sys);
|
||||
user = user * USER_HZ / HZ;
|
||||
sys = sys * USER_HZ / HZ;
|
||||
if (user + sys > all)
|
||||
all = user + sys;
|
||||
uint64 idle = all - user - sys;
|
||||
|
||||
// user nice system idle iowait irq softirq steal guest guest_nice
|
||||
sb_puts(sb, "cpu ");
|
||||
sb_putu(sb, t); sb_puts(sb, " 0 0 0 0 0 0 0 0 0\n");
|
||||
sb_putu(sb, user); sb_puts(sb, " 0 ");
|
||||
sb_putu(sb, sys); sb_putc(sb, ' ');
|
||||
sb_putu(sb, idle); sb_puts(sb, " 0 0 0 0 0 0\n");
|
||||
// Online, for the same reason as cpuinfo: top and friends count the cpuN
|
||||
// lines here to decide how many cores to draw.
|
||||
for (int i = 0; i < ncpu_online; i++) {
|
||||
sb_puts(sb, "cpu");
|
||||
sb_putu(sb, i);
|
||||
sb_putc(sb, ' ');
|
||||
sb_putu(sb, t); sb_puts(sb, " 0 0 0 0 0 0 0 0 0\n");
|
||||
sb_putu(sb, user / n); sb_puts(sb, " 0 ");
|
||||
sb_putu(sb, sys / n); sb_putc(sb, ' ');
|
||||
sb_putu(sb, idle / n); sb_puts(sb, " 0 0 0 0 0 0\n");
|
||||
}
|
||||
sb_kv(sb, "processes ", (uint64)proc_num(), 0);
|
||||
sb_kv(sb, "procs_running ", 1, 0);
|
||||
|
|
@ -388,12 +408,42 @@ gen_filesystems(struct sbuf *sb)
|
|||
#define PROC_BOOTDEBUG 30
|
||||
#define PROC_SLAB 20
|
||||
#define PROC_PARTITIONS 21
|
||||
#define PROC_STRACE 31
|
||||
|
||||
// Render global file `id` (a PROC_* constant) into `buf`. Returns its length.
|
||||
//
|
||||
// Split out of procread() so the /proc *filesystem* (kernel/fs/procfs.c) can
|
||||
// use the same generators: that file owns the namespace, this one owns the
|
||||
// content, and they have no other business with each other.
|
||||
// /proc/strace: the name of the program to trace, or empty. Read by exec, so
|
||||
// a change takes effect at the next program started, not in running ones.
|
||||
static char strace_name[16];
|
||||
|
||||
int
|
||||
strace_wanted(const char *name)
|
||||
{
|
||||
return strace_name[0] && strncmp(name, strace_name, sizeof(strace_name)) == 0;
|
||||
}
|
||||
|
||||
int
|
||||
proc_write_strace(int user_src, uint64 src, uint n)
|
||||
{
|
||||
char tmp[16];
|
||||
uint len = n < sizeof(tmp) - 1 ? n : sizeof(tmp) - 1;
|
||||
|
||||
if (user_src) {
|
||||
if (copy_from_user(tmp, src, len) < 0)
|
||||
return -EFAULT;
|
||||
} else {
|
||||
memmove(tmp, (char *)src, len);
|
||||
}
|
||||
while (len > 0 && (tmp[len - 1] == '\n' || tmp[len - 1] == ' '))
|
||||
len--;
|
||||
tmp[len] = 0;
|
||||
memmove(strace_name, tmp, sizeof(strace_name));
|
||||
return (int)n;
|
||||
}
|
||||
|
||||
int
|
||||
proc_gen_global(int id, char *buf, int cap)
|
||||
{
|
||||
|
|
@ -442,6 +492,10 @@ proc_gen_global(int id, char *buf, int cap)
|
|||
sb_puts(&sb, boot_debug ? "on\n" : "off\n");
|
||||
break;
|
||||
case PROC_DEVICES: gen_devices(&sb); break;
|
||||
case PROC_STRACE:
|
||||
sb_puts(&sb, strace_name);
|
||||
sb_putc(&sb, '\n');
|
||||
break;
|
||||
// The block layer renders its own table, like PCI and SchFS above.
|
||||
case PROC_PARTITIONS: sb.len = blkdev_info(buf, cap); break;
|
||||
default: return 0;
|
||||
|
|
|
|||
Loading…
Reference in a new issue