From 31dce591f3091db1d058121401a431702e29c3e9 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Fri, 4 Sep 2026 22:03:22 +0200 Subject: [PATCH] feat: extend kmain with redirDriverThread and stderrTypePath --- src/kmain.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/src/kmain.c b/src/kmain.c index d672f90..1bfff29 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -850,6 +850,179 @@ static void redirTypeReadCommand(void) * "redirwriter >> /tmp/redir.txt" (append, same path) leaves a real tmpfs * file holding two back-to-back copies of redirwriter.c's own payload; * "redirreader < /tmp/redir.txt" then reads that file back through a + * REAL redirected stdin and compares it byte-for-byte against exactly + * that doubled payload. The actual pass/fail proof is entirely + * redirreader.c's own doing (its "payload-ok" needle only prints on an + * exact match) -- this thread's only job is to type the three commands + * and give the scheduler real time between them. + */ +static void redirDriverThread(void) +{ + threadSleep(redirDriverInitialDelayMs); + while (currentThread()->state == threadSleeping) + halt(); + + kprintf("[kbd] typing shell commands for the file redirection demo\n"); + jobctlTypeFlushLine(); + + redirTypeWriteTruncateCommand(); + threadSleep(redirDriverStepSettleMs); + while (currentThread()->state == threadSleeping) + halt(); + + redirTypeWriteAppendCommand(); + threadSleep(redirDriverStepSettleMs); + while (currentThread()->state == threadSleeping) + halt(); + + redirTypeReadCommand(); + threadSleep(redirDriverStepSettleMs); + while (currentThread()->state == threadSleeping) + halt(); + + for (;;) + halt(); +} + +/* Digit needed only by stderrDriverThread's own three commands below -- + same cross-checked-against-scancodeLower sourcing as every block above + (index 0x03 is '2', unshifted -- scancodeLower[3] == '2' in keyboard.c's + own table, no shift key involved unlike the '>'/'<' operators reused + from redirDriverThread's own scancodeMakeDot/scancodeMakeComma below). */ +#define scancodeMakeTwo 0x03 + +/* "/tmp/err.txt" -- deliberately SHORTER than redirDriverThread's own + "/tmp/redir.txt" (12 vs 14 chars): "stderrwriter"/"stderrreader" are + already one character longer than "redirwriter"/"redirreader", and the + `2>`/`2>>` operators are one/two characters longer than `>`/`>>` -- with + the same path length as the file-redirection demo, the LONGEST typed + line here ("stderrwriter 2>> /tmp/err.txt\n", 30 bytes incl. newline) + would land right at keyboard.c's 32-byte per-thread console reader ring + buffer (consoleReaderBufferSize) with almost no margin left. A first + attempt at this demo used "/tmp/stderr.txt" (15 chars) and landed + EXACTLY at (and, for the `2>>` line, one byte OVER) that 32-byte + capacity -- ringPush (ring.c) silently drops a byte on a full buffer + with no retry, so the trailing '\n' itself was lost, and the shell's + line reader never saw a line terminator until the NEXT typed command's + bytes arrived, silently concatenating three separate typed commands + into one garbled line. Shortening the path restores the same few-bytes- + of-headroom margin redirDriverThread's own commands already prove works + (its longest line is 30 bytes incl. newline against the same 32-byte + capacity) instead of running right up against the boundary. */ +static void stderrTypePath(void) +{ + injectKeyPress(scancodeMakeSlash); + injectKeyPress(scancodeMakeT); + injectKeyPress(scancodeMakeM); + injectKeyPress(scancodeMakeP); + injectKeyPress(scancodeMakeSlash); + injectKeyPress(scancodeMakeE); + injectKeyPress(scancodeMakeR); + injectKeyPress(scancodeMakeR); + injectKeyPress(scancodeMakeDot); + injectKeyPress(scancodeMakeT); + injectKeyPress(scancodeMakeX); + injectKeyPress(scancodeMakeT); +} + +static void stderrTypeWriterName(void) +{ + injectKeyPress(scancodeMakeS); + injectKeyPress(scancodeMakeT); + injectKeyPress(scancodeMakeD); + injectKeyPress(scancodeMakeE); + injectKeyPress(scancodeMakeR); + injectKeyPress(scancodeMakeR); + injectKeyPress(scancodeMakeW); + injectKeyPress(scancodeMakeR); + injectKeyPress(scancodeMakeI); + injectKeyPress(scancodeMakeT); + injectKeyPress(scancodeMakeE); + injectKeyPress(scancodeMakeR); +} + +static void stderrTypeReaderName(void) +{ + injectKeyPress(scancodeMakeS); + injectKeyPress(scancodeMakeT); + injectKeyPress(scancodeMakeD); + injectKeyPress(scancodeMakeE); + injectKeyPress(scancodeMakeR); + injectKeyPress(scancodeMakeR); + injectKeyPress(scancodeMakeR); + injectKeyPress(scancodeMakeE); + injectKeyPress(scancodeMakeA); + injectKeyPress(scancodeMakeD); + injectKeyPress(scancodeMakeE); + injectKeyPress(scancodeMakeR); +} + +static void stderrTypeWriteTruncateCommand(void) +{ + stderrTypeWriterName(); + injectKeyPress(scancodeMakeSpace); + injectKeyPress(scancodeMakeTwo); + injectShiftedKeyPress(scancodeMakeDot); + injectKeyPress(scancodeMakeSpace); + stderrTypePath(); + injectKeyPress(scancodeMakeEnter); +} + +static void stderrTypeWriteAppendCommand(void) +{ + stderrTypeWriterName(); + injectKeyPress(scancodeMakeSpace); + injectKeyPress(scancodeMakeTwo); + injectShiftedKeyPress(scancodeMakeDot); + injectShiftedKeyPress(scancodeMakeDot); + injectKeyPress(scancodeMakeSpace); + stderrTypePath(); + injectKeyPress(scancodeMakeEnter); +} + +static void stderrTypeReadCommand(void) +{ + stderrTypeReaderName(); + injectKeyPress(scancodeMakeSpace); + injectShiftedKeyPress(scancodeMakeComma); + injectKeyPress(scancodeMakeSpace); + stderrTypePath(); + injectKeyPress(scancodeMakeEnter); +} + +#define stderrDriverInitialDelayMs 5500 +#define stderrDriverStepSettleMs 300 + +/* Letter/symbol needed only by hereDriverThread's own command below -- same + cross-checked-against-scancodeLower sourcing as every block above (index + 0x23 is 'h', 0x0C is '-', both unshifted -- keyboard.c's own + scancodeLower[0x23] == 'h' and scancodeLower[0x0C] == '-'). Every other + letter the command needs (e,r,s,t,o,k) is already defined by an earlier + block above. */ +#define scancodeMakeH 0x23 +#define scancodeMakeHyphen 0x0C + +static void hereTypeCommand(void) +{ + injectKeyPress(scancodeMakeH); + injectKeyPress(scancodeMakeE); + injectKeyPress(scancodeMakeR); + injectKeyPress(scancodeMakeE); + injectKeyPress(scancodeMakeS); + injectKeyPress(scancodeMakeT); + injectKeyPress(scancodeMakeE); + injectKeyPress(scancodeMakeS); + injectKeyPress(scancodeMakeT); + injectKeyPress(scancodeMakeSpace); + injectShiftedKeyPress(scancodeMakeComma); + injectShiftedKeyPress(scancodeMakeComma); + injectShiftedKeyPress(scancodeMakeComma); + injectKeyPress(scancodeMakeSpace); + injectKeyPress(scancodeMakeH); + injectKeyPress(scancodeMakeS); + injectKeyPress(scancodeMakeHyphen); + injectKeyPress(scancodeMakeO); + injectKeyPress(scancodeMakeK); } void kmain(uint32 magic, uint64 multibootInfo)