-
-
Notifications
You must be signed in to change notification settings - Fork 5
HOWTO Add a shell command
How to add a builtin to the NyxOS kernel shell. The worked example adds uptime, which prints the time since boot.
Tip
Consider whether the feature belongs in ring 3 instead. A kernel builtin runs with full privilege, cannot be piped, and grows the kernel image; a userspace program can be piped, killed, and cannot crash the machine. Add a builtin only when the command needs kernel state that no syscall exposes. See HOWTO-Write-a-userspace-program.
See also: Shell, Kernel-Data-Structures, Building, HOWTO-Write-a-userspace-program
kernel/core/kernel.c holds one table of builtins. Resolution order for a typed word:
- Match against the
commands[]table → run the builtin - Otherwise, if
/<name>.elfexists → auto-exec it in the foreground with argv forwarded - Otherwise →
command not found
FILE — kernel/core/kernel.c (the table entry type)
typedef struct {
const char* name;
void (*func)(int argc, char** argv);
const char* help;
bool hidden;
} command_t;| Field | Meaning |
|---|---|
name |
The typed word |
func |
Handler, receiving argc/argv with argv[0] = the command name |
help |
One line shown by help, and the place to document the syntax |
hidden |
true omits it from help and from tab completion |
Handlers are forward-declared above the table.
FILE — kernel/core/kernel.c
static void cmd_df(int argc, char** argv);
static void cmd_setres(int argc, char** argv);
static void cmd_uptime(int argc, char** argv); /* new */Place it near related commands — the table is grouped by topic.
FILE — kernel/core/kernel.c
static const command_t commands[] = {
/* … */
{"date", cmd_date, "Show current date and time", false},
{"uptime", cmd_uptime, "Show time since boot", false}, /* new */
/* … */
{NULL, NULL, NULL, false}
};Important
The {NULL, NULL, NULL, false} sentinel terminates the table. Adding an entry after it makes the command unreachable and breaks help.
FILE — kernel/core/kernel.c
static void cmd_uptime(int argc, char** argv) {
(void)argc; (void)argv;
uint64_t secs = tick_count / 1000; /* PIT runs at 1000 Hz */
printf("up %llu:%02llu:%02llu\n",
secs / 3600, (secs / 60) % 60, secs % 60);
}| Rule | Reason |
|---|---|
Cast unused parameters to (void)
|
The build is -Wall -Wextra and must stay warning-free |
Validate argc before touching argv[n]
|
The shell does not check arity for you |
Print errors with printf, do not panic |
A bad argument must not take the machine down |
| Keep the handler short | It runs on the compositor's stack, which is shared with the GUI |
Argument handling — the standard shape
static void cmd_setres(int argc, char** argv) {
if (argc < 3) {
printf("usage: setres <width> <height>\n");
return;
}
int w = atoi(argv[1]);
int h = atoi(argv[2]);
/* … */
}Warning
A kernel builtin runs in ring 0 on a stack shared with the compositor. Deep recursion or a large stack array can overflow it and corrupt unrelated memory. Allocate with kmalloc instead of declaring a large local.
A builtin that blocks stalls the shell — and, in the GUI, the terminal window with it. For anything long-running:
- Use
sleep(ms), never a busy loop, so other tasks get the CPU - Or spawn a kernel thread with
create_process(name, entry, arg)and return immediately - Or make it a userspace program and let the scheduler handle it
The shell runs on the compositor thread with interrupts enabled, so it can be preempted mid-operation. Anything a user process can also reach needs a lock:
preempt_disable(); /* single-core re-entrancy only */
/* … */
preempt_enable();Caution
preempt_disable() stops a context switch on the local core and means nothing to another core. On SMP, shared state needs a real spinlock. See SMP.
CODE — Rebuild and boot with a serial console
host $ make -C kernel
host $ ./run.ps1 -Mode serialnyx> uptime
up 0:01:47
nyx> help
[…]
uptime Show time since boot
[…]
Check three things: the command runs, it appears in help, and upt + Tab completes it.
Point a second entry at the same handler. fastfetch does exactly this:
{"nyxfetch", cmd_nyxfetch, "Show system info with ASCII logo", false},
{"fastfetch", cmd_nyxfetch, "Alias for nyxfetch", false},Self-tests are the project's standard way to prove a subsystem. By convention the name ends in test, the implementation returns 0 on success, and the handler prints a per-case result.
{"giftest", cmd_giftest, "GIF image decoder self-test (LZW + interlace + transparency)", false},The existing suite is listed in Shell.
- Handler forward-declared above
commands[] - Entry added before the
{NULL, …}sentinel -
helpstring states the syntax, e.g."…: cmd <arg> [opt]" -
argcvalidated before indexingargv - Unused parameters cast to
(void) - No large stack locals;
kmallocinstead - Shared state locked appropriately
- Builds with zero warnings
- Appears in
helpand in Tab completion - Shell page updated in this wiki
| Symptom | Cause | Fix |
|---|---|---|
command not found |
Entry added after the sentinel, or hidden set |
Move it before {NULL, …}
|
Missing from help and Tab completion |
hidden is true
|
Set it to false
|
Build fails with unused parameter
|
-Wextra |
Cast to (void)
|
| Machine freezes when run | Busy loop or blocking call on the compositor thread | Use sleep(ms), or spawn a thread |
| Random crashes elsewhere afterwards | Kernel stack overflow from a large local |
kmalloc the buffer |
| A userspace program shadows the name | A builtin always wins over /name.elf
|
Rename one of them |
- Shell — every existing builtin
- HOWTO-Write-a-userspace-program — usually the better option
- HOWTO-Add-a-GUI-application — for a windowed feature
- Kernel-Data-Structures — what kernel state a builtin can read
- GNU coreutils manual — a reference for conventional command behaviour
NyxOS v6.4.363 · GPL v2 · GitHub · uselessalter on Discord · nyxos@inbox.lv
NyxOS Wiki
Getting started
Kernel
Storage & network
Graphics & apps
Userspace
HOWTO
- HOWTO-Add-a-system-call
- HOWTO-Write-a-userspace-program
- HOWTO-Add-a-shell-command
- HOWTO-Add-a-GUI-application
Reference
- Syscall-Reference
- Command-Reference
- Hardware-Reference
- Format-Reference
- Kernel-Data-Structures
- Source-Tree-Reference
Project