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:
Nexoniarz 2026-10-25 02:11:10 +01:00
commit fd9d392416
28 changed files with 1577 additions and 47 deletions

View file

@ -50,6 +50,26 @@ fetchstr(addr_t addr, char **pp)
return len;
}
// /proc/strace. Which argument of a Linux syscall is a path, by number, so
// the trace can show the name rather than an address: that is most of what
// one wants from a trace of a program that will not start.
static int
path_arg(uint64 nr)
{
switch (nr) {
case 2: case 4: case 6: case 21: case 59: case 76: case 80: case 82:
case 83: case 84: case 85: case 86: case 87: case 88: case 89: case 90:
case 92: case 137: case 161:
return 0;
case 257: case 258: case 260: case 262: case 263: case 264: case 267:
case 268: case 269: case 280: case 316: case 332: case 437: case 439:
return 1;
}
return -1;
}
static void strace_call(struct trapframe *tf);
static addr_t
fetcharg(int n)
{
@ -117,6 +137,10 @@ static addr_t (*syscalls[NSYSCALLS])(void) = {
void
syscall(struct trapframe *tf)
{
if (myproc()->strace) {
strace_call(tf);
return;
}
kstack_check_canary("syscall entry");
myproc()->tf = tf;
uint64 orig = myproc()->tf->rax;
@ -139,3 +163,63 @@ syscall(struct trapframe *tf)
kstack_check_canary("syscall exit");
}
// syscall() for a traced process: the same dispatch, with a line in the log
// for each call -- the Linux number, four arguments, a path where there is
// one, and what came back. The path is copied before the call runs, since
// execve replaces the memory it is in.
static void
strace_call(struct trapframe *tf)
{
struct proc *p = myproc();
uint64 orig = tf->rax, num = orig;
uint64 a0 = tf->rdi, a1 = tf->rsi, a2 = tf->rdx, a3 = tf->r10;
char path[64];
int pa = p->syscall_map ? path_arg(orig) : -1;
path[0] = 0;
if (pa >= 0) {
addr_t u = pa == 0 ? a0 : a1;
int i;
for (i = 0; i < (int)sizeof(path) - 1; i++) {
char c;
if (copy_from_user(&c, u + i, 1) < 0 || c == 0)
break;
path[i] = c;
}
path[i] = 0;
}
// The result line is written when the call returns, so a call that never
// does would leave no trace at all. Everything that can wait gets a line
// on the way in as well.
switch (orig) {
case 0: case 2: case 7: case 23: case 35: case 43: case 45: case 47:
case 59: case 61: case 202: case 232: case 257: case 270: case 271:
case 281: case 288:
if (p->syscall_map)
kinfo("strace %d %s: %d(%lx, %lx, %lx, %lx)%s%s%s ...\n",
p->pid, p->name, (int)orig, a0, a1, a2, a3,
pa >= 0 ? " \"" : "", path, pa >= 0 ? "\"" : "");
}
kstack_check_canary("syscall entry");
p->tf = tf;
if (p->syscall_map)
num = (num < (uint64)p->map_size) ? p->syscall_map[num] : 0;
if (num > 0 && num < NSYSCALLS && syscalls[num])
tf->rax = syscalls[num]();
else
tf->rax = -ENOSYS;
// A successful execve has replaced the program: its name is the new one.
kinfo("strace %d %s: %s%d(%lx, %lx, %lx, %lx)%s%s%s = %ld\n",
p->pid, p->name, p->syscall_map ? "" : "native ", (int)orig,
a0, a1, a2, a3, pa >= 0 ? " \"" : "", path, pa >= 0 ? "\"" : "",
(long)tf->rax);
if (p->killed)
exit(W_EXITCODE(0, p->killsig ? p->killsig : SIGKILL));
deliver_signals(tf);
kstack_check_canary("syscall exit");
}