SchOS/cmd/schdbg/main.c
Nexoniarz 26bca020b6 licence: SchOS is GPL-2.0-or-later, no longer Apache-2.0
Nexoniarz is the sole author and SchOS was never published under
Apache-2.0, so this is a straight relicence. LICENSE is the FSF GPLv2 text,
every first-party SPDX header moves to GPL-2.0-or-later, and NOTICE,
README.md, docs/licensing.md and the site say so. projects/schfs-linux
follows the rest of the tree.

The GPL gives copyleft: a fork has to ship its source. It also lifts the
old "Linux drivers, never" rule, since GPL-2.0-only code combines with
GPL-2.0-or-later. "Or later" leaves room for GPLv3, but one binary still
has to pick one version, so docs/licensing.md now keeps Apache-2.0 and
GPLv3 code out of the kernel to keep Linux code possible there. BSD
4-clause code goes from "avoid" to "no", because the advertising clause
is GPL-incompatible.

LDLS still ships no .ko. That boundary is now project policy rather than
a legal requirement, and ldls.md, devices.md and licensing.md section 6
say so. refmod declares license=GPL, and ldls-check passes (27 checks).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 08:48:45 +02:00

139 lines
4 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
//
// schdbg -- ask the kernel a question.
//
// docs/architecture/debugging.md, milestone D2. The kernel half is /dev/dbg: write a
// line, read the answer. This is the half that makes that pleasant, and it is
// deliberately almost nothing -- because the protocol is lines of text, and a
// protocol whose client has to be clever is a protocol you cannot use when the
// client will not start.
//
// schdbg the views this kernel publishes
// schdbg dma one of them
// schdbg all all of them
// schdbg -i a prompt, for when you are asking several
//
// Everything here works equally well as:
//
// echo dma > /dev/dbg && cat /dev/dbg
//
// which is the point, and is what you fall back to on a system where this
// program is one of the things that is broken.
#include "types.h"
#include "user.h"
#include "fcntl.h"
static void
puts_(const char *s)
{
int n = 0;
while (s[n]) n++;
write(1, (void *)s, n);
}
// One question, one answer.
//
// The descriptor is opened fresh for each, because the answer is read from
// offset zero and the kernel replaces it on every write. Reusing one open
// descriptor across two questions would read the second answer from wherever
// the first one left off.
static int
ask(const char *cmd)
{
char buf[512];
int fd, n;
fd = open("/dev/dbg", O_RDWR);
if (fd < 0) {
puts_("schdbg: cannot open /dev/dbg\n");
return -1;
}
if (cmd) {
int len = 0;
while (cmd[len]) len++;
if (write(fd, (void *)cmd, len) != len) {
puts_("schdbg: the kernel would not take that command\n");
close(fd);
return -1;
}
// Back to the start. Writing moved this descriptor's offset forward by
// the length of the command, and the answer begins at zero -- so
// without this the reply arrives with its first few characters missing,
// which is subtle enough to look like a formatting bug in the view.
lseek(fd, 0, 0); /* SEEK_SET */
}
while ((n = read(fd, buf, sizeof(buf))) > 0)
write(1, buf, n);
close(fd);
return 0;
}
// A line from the terminal, without the newline. Returns 0 at end of input.
static int
readline(char *buf, int cap)
{
int n = 0;
char c;
for (;;) {
int r = read(0, &c, 1);
if (r <= 0)
return n > 0;
if (c == '\n') {
buf[n] = 0;
return 1;
}
if (n < cap - 1)
buf[n++] = c;
}
}
int
main(int argc, char *argv[])
{
if (argc > 1 && argv[1][0] == '-' && argv[1][1] == 'i') {
char line[128];
puts_("schdbg: ask the kernel something. 'help' lists the views, "
"'quit' leaves.\n");
for (;;) {
puts_("dbg> ");
if (!readline(line, sizeof(line)))
break;
if (line[0] == 0)
continue;
if (line[0] == 'q' && line[1] == 'u' && line[2] == 'i' &&
line[3] == 't' && line[4] == 0)
break;
ask(line);
}
return 0;
}
// No argument means "what can I ask", which is the question someone has
// the first time and the one an empty response would not answer.
if (argc < 2)
return ask("help") < 0 ? 1 : 0;
// Everything after the program name, rejoined with single spaces. The
// shell split it and the kernel wants a line; `schdbg vma 4` has to arrive
// as "vma 4" or the argument is silently dropped and the view quietly
// ignores the narrowing it was asked for.
{
char line[128];
int n = 0;
for (int i = 1; i < argc; i++) {
if (i > 1 && n < (int)sizeof(line) - 1)
line[n++] = ' ';
for (int j = 0; argv[i][j] && n < (int)sizeof(line) - 1; j++)
line[n++] = argv[i][j];
}
line[n] = 0;
return ask(line) < 0 ? 1 : 0;
}
}