mirror of
https://github.com/subhobhai943/SUB-OS.git
synced 2026-10-25 16:52:29 +00:00
feat(kernel,gui): NT Configuration Registry + GUI Object Browser
Kernel (NT Configuration Manager): - kernel/nt/reg.c + include/kernel/nt/reg.h (new): a hive/key/value registry rooted at "\Registry", with typed values (REG_SZ/DWORD/QWORD/BINARY/MULTI_SZ, type codes matching Win32). reg_create_key/reg_open_key walk backslash paths; setters/getters, enumeration, and value->string rendering. reg_init() seeds \Registry\Machine (Hardware, System\CurrentControlSet\Control, Software\SUB-OS) and \Registry\User\.DEFAULT. Wired into the [12/14] boot step. - LazyBox `reg query|add|set|stats` explores and edits the registry. GUI: - gui/gui_apps.c: "Object Browser" -- a WinObj-style live tree view of the NT object namespace (\), flattening directories/events/semaphores/mutants with indentation, per-type colouring, ref/handle counts, live object/handle stats, and click-to-scroll. Registered in the app table (start menu). Verified live in the GUI terminal (screenshotted): registry reports 13 keys / 11 values; `reg query \Registry\Machine\Software\SUB-OS` lists Version, BuildArch (REG_SZ), GrowableHeap/ObjectManager (REG_DWORD) and InstallCookie (REG_QWORD) with correct types. Clean build on x86_64/aarch64/armv8i; 0 panics. Co-Authored-By: Claude Opus 4.8 <[email protected]> Claude-Session: https://claude.ai/code/session_01Fh5z6V7nGPbHvqVG5p4CXX
This commit is contained in:
1 parent
cb7506f027
commit
526ad8c741
8 files changed
+536
-3
No files matched your search
@@ -125,7 +125,7 @@ CORE_SRCS = kernel/main.c kernel/task.c kernel/sync.c kernel/timer.c kernel/prin
|
||||
kernel/panic.c kernel/trace.c kernel/sched.c kernel/cron.c kernel/syscall.c \
|
||||
kernel/syslog.c kernel/module.c kernel/kobject.c kernel/metrics.c kernel/namespace.c \
|
||||
kernel/signal.c kernel/workqueue.c kernel/tsc.c kernel/vt_art.c \
|
||||
kernel/sub/sub_runtime.c kernel/sub/sub_vm.c kernel/nt/ob.c \
|
||||
kernel/sub/sub_runtime.c kernel/sub/sub_vm.c kernel/nt/ob.c kernel/nt/reg.c \
|
||||
kernel/wait.c kernel/futex.c kernel/rcu.c kernel/ktest.c \
|
||||
kernel/elf.c kernel/exec.c \
|
||||
lib/string.c lib/vsprintf.c lib/bitmap.c lib/rbtree.c lib/kfifo.c lib/hashtable.c lib/font8x8.c \
|
||||
|
||||
+119
@@ -9,6 +9,7 @@
|
||||
#include <mm/pmm.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <kernel/rust.h>
|
||||
#include <kernel/nt/ob.h>
|
||||
#include <lib/string.h>
|
||||
#include <lib/printf.h>
|
||||
|
||||
@@ -649,3 +650,121 @@ void gui_app_rustlab_launch(int x, int y, int w, int h) {
|
||||
win->handle_event = rustlab_event;
|
||||
}
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// 9. NT Object Browser -- a WinObj-style view of the object namespace
|
||||
// =================================================================
|
||||
typedef struct { ob_object_t* obj; int depth; } objrow_t;
|
||||
#define OBJBROWSE_MAX_ROWS 96
|
||||
|
||||
typedef struct {
|
||||
int scroll;
|
||||
} objbrowse_data_t;
|
||||
|
||||
static int objbrowse_flatten(ob_object_t* obj, int depth, objrow_t* rows, int max, int count) {
|
||||
if (!obj || count >= max) return count;
|
||||
rows[count].obj = obj;
|
||||
rows[count].depth = depth;
|
||||
count++;
|
||||
if (obj->type == OB_TYPE_DIRECTORY) {
|
||||
int c = ob_dir_child_count(obj);
|
||||
for (int i = 0; i < c && count < max; i++) {
|
||||
count = objbrowse_flatten(ob_dir_child(obj, i), depth + 1, rows, max, count);
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static uint32_t objbrowse_type_color(ob_type_t t) {
|
||||
switch (t) {
|
||||
case OB_TYPE_DIRECTORY: return GUI_THEME_PRIMARY;
|
||||
case OB_TYPE_EVENT: return GUI_THEME_SUCCESS;
|
||||
case OB_TYPE_SEMAPHORE: return GUI_THEME_WARNING;
|
||||
case OB_TYPE_MUTANT: return GUI_THEME_ACCENT;
|
||||
default: return GUI_THEME_TEXT_MUTED;
|
||||
}
|
||||
}
|
||||
|
||||
static void objbrowse_paint(gui_window_t* win) {
|
||||
objbrowse_data_t* bd = (objbrowse_data_t*)win->user_data;
|
||||
if (!bd) return;
|
||||
|
||||
int cx = win->x + 12;
|
||||
int top = win->y + GUI_TITLEBAR_HEIGHT;
|
||||
|
||||
// Header + live stats
|
||||
uint32_t objs = 0, handles = 0, per[OB_TYPE_MAX];
|
||||
ob_get_stats(&objs, &handles, per);
|
||||
gui_gfx_draw_string_16_shadow(cx, top + 8, "NT Object Namespace \\", GUI_THEME_PRIMARY, GUI_COLOR_BLACK);
|
||||
char hdr[80];
|
||||
snprintf(hdr, sizeof(hdr), "%u objects %u handles open (scroll: click top/bottom)", objs, handles);
|
||||
gui_gfx_draw_string(cx, top + 28, hdr, GUI_THEME_TEXT_MUTED);
|
||||
|
||||
// Flatten the live namespace
|
||||
objrow_t rows[OBJBROWSE_MAX_ROWS];
|
||||
int total = objbrowse_flatten(ob_root_directory(), 0, rows, OBJBROWSE_MAX_ROWS, 0);
|
||||
|
||||
int list_top = top + 44;
|
||||
int row_h = 13;
|
||||
int visible = (win->height - (list_top - win->y) - 10) / row_h;
|
||||
if (visible < 1) visible = 1;
|
||||
|
||||
if (bd->scroll > total - visible) bd->scroll = total - visible;
|
||||
if (bd->scroll < 0) bd->scroll = 0;
|
||||
|
||||
for (int i = 0; i < visible && (bd->scroll + i) < total; i++) {
|
||||
objrow_t* r = &rows[bd->scroll + i];
|
||||
ob_object_t* o = r->obj;
|
||||
int y = list_top + i * row_h;
|
||||
int x = cx + r->depth * 14;
|
||||
|
||||
char line[96];
|
||||
if (o->type == OB_TYPE_DIRECTORY) {
|
||||
snprintf(line, sizeof(line), "%s\\", o->name);
|
||||
} else {
|
||||
snprintf(line, sizeof(line), "%s", o->name);
|
||||
}
|
||||
gui_gfx_draw_string(x, y, line, objbrowse_type_color(o->type));
|
||||
|
||||
char meta[48];
|
||||
snprintf(meta, sizeof(meta), "%-9s r=%d h=%d", ob_type_name(o->type), o->ref_count, o->handle_count);
|
||||
gui_gfx_draw_string(win->x + win->width - 180, y, meta, GUI_THEME_TEXT_DIM);
|
||||
}
|
||||
|
||||
// Scroll indicator
|
||||
if (total > visible) {
|
||||
char sc[32];
|
||||
snprintf(sc, sizeof(sc), "%d-%d / %d", bd->scroll + 1,
|
||||
(bd->scroll + visible < total) ? bd->scroll + visible : total, total);
|
||||
gui_gfx_draw_string(win->x + win->width - 90, top + 28, sc, GUI_THEME_TEXT_DIM);
|
||||
}
|
||||
}
|
||||
|
||||
static void objbrowse_event(gui_window_t* win, const gui_event_t* ev) {
|
||||
objbrowse_data_t* bd = (objbrowse_data_t*)win->user_data;
|
||||
if (!bd) return;
|
||||
|
||||
if (ev->type == GUI_EVENT_CLOSE) {
|
||||
if (win->user_data) { kfree(win->user_data); win->user_data = NULL; }
|
||||
return;
|
||||
}
|
||||
if (ev->type != GUI_EVENT_MOUSE_DOWN) return;
|
||||
|
||||
// Top third scrolls up, bottom third scrolls down.
|
||||
if (ev->rel_y < win->height / 3) {
|
||||
bd->scroll -= 3;
|
||||
} else if (ev->rel_y > (win->height * 2) / 3) {
|
||||
bd->scroll += 3;
|
||||
}
|
||||
if (bd->scroll < 0) bd->scroll = 0;
|
||||
}
|
||||
|
||||
void gui_app_objbrowse_launch(int x, int y, int w, int h) {
|
||||
gui_window_t* win = gui_wm_create_window("Object Browser", x, y, (w > 0) ? w : 460, (h > 0) ? h : 340);
|
||||
if (win) {
|
||||
objbrowse_data_t* bd = (objbrowse_data_t*)kzalloc(sizeof(objbrowse_data_t));
|
||||
win->user_data = bd;
|
||||
win->paint = objbrowse_paint;
|
||||
win->handle_event = objbrowse_event;
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -58,6 +58,7 @@ static const desktop_app_t g_apps[] = {
|
||||
{ "Paint", GUI_ICON_PAINT, gui_app_paint_launch, 200, 60, 360, 260 },
|
||||
{ "Life", GUI_ICON_FLASK, gui_app_life_launch, 240, 70, 480, 380 },
|
||||
{ "Rust Lab", GUI_ICON_INFO, gui_app_rustlab_launch, 300, 80, 420, 300 },
|
||||
{ "Objects", GUI_ICON_TASKS, gui_app_objbrowse_launch,280, 70, 460, 340 },
|
||||
{ "Clock", GUI_ICON_CLOCK, gui_app_clock_launch, 460, 120, 280, 260 },
|
||||
{ "Settings", GUI_ICON_SETTINGS, gui_app_settings_launch, 160, 60, 400, 320 },
|
||||
{ "About", GUI_ICON_INFO, gui_app_about_launch, 240, 140, 330, 170 },
|
||||
@@ -66,8 +67,8 @@ static const desktop_app_t g_apps[] = {
|
||||
|
||||
// Which of the above appear on the desktop itself.
|
||||
// Indices into g_apps[]: Terminal, Files, Monitor, Kernel Log, KTest, Life,
|
||||
// Rust Lab, Settings.
|
||||
static const int g_desktop_icons[] = { 0, 1, 2, 4, 5, 9, 10, 12 };
|
||||
// Rust Lab, Settings. (Objects lives in the start menu.)
|
||||
static const int g_desktop_icons[] = { 0, 1, 2, 4, 5, 9, 10, 13 };
|
||||
#define DESKTOP_ICON_COUNT ((int)(sizeof(g_desktop_icons) / sizeof(g_desktop_icons[0])))
|
||||
|
||||
static bool g_start_menu_open = false;
|
||||
|
||||
@@ -11,5 +11,6 @@ void gui_app_paint_launch(int x, int y, int w, int h);
|
||||
void gui_app_about_launch(int x, int y, int w, int h);
|
||||
void gui_app_life_launch(int x, int y, int w, int h);
|
||||
void gui_app_rustlab_launch(int x, int y, int w, int h);
|
||||
void gui_app_objbrowse_launch(int x, int y, int w, int h);
|
||||
|
||||
#endif // _GUI_APPS_H
|
||||
@@ -0,0 +1,77 @@
|
||||
#ifndef _KERNEL_NT_REG_H
|
||||
#define _KERNEL_NT_REG_H
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SUB-OS NT-Inspired Configuration Registry
|
||||
//
|
||||
// A hive-and-key configuration store modelled on the Windows NT Configuration
|
||||
// Manager (Cm). Keys form a tree rooted at "\Registry"; each key holds typed
|
||||
// values (REG_SZ / REG_DWORD / REG_QWORD / REG_BINARY / REG_MULTI_SZ) whose
|
||||
// type codes match the Win32 constants. Backed by kmalloc, bounded fan-out.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef enum {
|
||||
REG_NONE = 0,
|
||||
REG_SZ = 1, // null-terminated string
|
||||
REG_BINARY = 3, // raw bytes
|
||||
REG_DWORD = 4, // 32-bit
|
||||
REG_MULTI_SZ = 7, // list of strings, shown joined by '|'
|
||||
REG_QWORD = 11 // 64-bit
|
||||
} reg_type_t;
|
||||
|
||||
#define REG_NAME_MAX 48
|
||||
#define REG_STR_MAX 128
|
||||
#define REG_MAX_CHILDREN 24
|
||||
#define REG_MAX_VALUES 24
|
||||
|
||||
typedef struct reg_value {
|
||||
char name[REG_NAME_MAX];
|
||||
reg_type_t type;
|
||||
uint32_t data_len;
|
||||
union {
|
||||
uint32_t dword;
|
||||
uint64_t qword;
|
||||
char str[REG_STR_MAX];
|
||||
uint8_t bin[REG_STR_MAX];
|
||||
} data;
|
||||
} reg_value_t;
|
||||
|
||||
typedef struct reg_key {
|
||||
char name[REG_NAME_MAX];
|
||||
struct reg_key* parent;
|
||||
struct reg_key* children[REG_MAX_CHILDREN];
|
||||
int child_count;
|
||||
reg_value_t* values[REG_MAX_VALUES];
|
||||
int value_count;
|
||||
} reg_key_t;
|
||||
|
||||
void reg_init(void);
|
||||
reg_key_t* reg_root(void);
|
||||
const char* reg_type_name(reg_type_t t);
|
||||
|
||||
// Path form: "\Registry\Machine\Software\SUB-OS". create makes intermediates.
|
||||
reg_key_t* reg_create_key(const char* path);
|
||||
reg_key_t* reg_open_key(const char* path);
|
||||
|
||||
// Value setters/getters (operate on an already-open key).
|
||||
reg_value_t* reg_set_dword(reg_key_t* key, const char* name, uint32_t value);
|
||||
reg_value_t* reg_set_qword(reg_key_t* key, const char* name, uint64_t value);
|
||||
reg_value_t* reg_set_sz(reg_key_t* key, const char* name, const char* str);
|
||||
reg_value_t* reg_query_value(reg_key_t* key, const char* name);
|
||||
|
||||
// Enumeration.
|
||||
int reg_enum_key_count(reg_key_t* key);
|
||||
reg_key_t* reg_enum_key(reg_key_t* key, int index);
|
||||
int reg_enum_value_count(reg_key_t* key);
|
||||
reg_value_t* reg_enum_value(reg_key_t* key, int index);
|
||||
|
||||
// Render a value's data into a human-readable string (for reg query / GUI).
|
||||
void reg_value_to_string(const reg_value_t* v, char* out, size_t out_len);
|
||||
|
||||
void reg_get_stats(uint32_t* out_keys, uint32_t* out_values);
|
||||
|
||||
#endif // _KERNEL_NT_REG_H
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <kernel/workqueue.h>
|
||||
#include <kernel/module.h>
|
||||
#include <kernel/nt/ob.h>
|
||||
#include <kernel/nt/reg.h>
|
||||
#include <kernel/trace.h>
|
||||
#include <kernel/namespace.h>
|
||||
#include <kernel/syslog.h>
|
||||
@@ -241,6 +242,7 @@ static void subos_modular_core_boot(void) {
|
||||
metrics_init();
|
||||
cron_init();
|
||||
ob_init();
|
||||
reg_init();
|
||||
service_manager_init();
|
||||
printk(ANSI_BRIGHT_GREEN "OK\n" ANSI_RESET);
|
||||
|
||||
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
// SUB-OS NT-Inspired Configuration Registry (Cm)
|
||||
//
|
||||
// A key tree rooted at "\Registry" with typed values. Paths are backslash
|
||||
// separated and begin at the root key named "Registry". Intermediate keys are
|
||||
// created on demand by reg_create_key(); reg_open_key() only navigates.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#include <kernel/nt/reg.h>
|
||||
#include <mm/kmalloc.h>
|
||||
#include <lib/string.h>
|
||||
#include <lib/printf.h>
|
||||
#include <kernel/printk.h>
|
||||
#include <kernel/sync.h>
|
||||
#include <init/version.h>
|
||||
#include <arch/arch.h>
|
||||
|
||||
static reg_key_t* g_reg_root = NULL;
|
||||
static uint32_t g_key_count = 0;
|
||||
static uint32_t g_value_count = 0;
|
||||
static spinlock_t g_reg_lock = SPINLOCK_INIT;
|
||||
|
||||
const char* reg_type_name(reg_type_t t) {
|
||||
switch (t) {
|
||||
case REG_SZ: return "REG_SZ";
|
||||
case REG_BINARY: return "REG_BINARY";
|
||||
case REG_DWORD: return "REG_DWORD";
|
||||
case REG_MULTI_SZ: return "REG_MULTI_SZ";
|
||||
case REG_QWORD: return "REG_QWORD";
|
||||
default: return "REG_NONE";
|
||||
}
|
||||
}
|
||||
|
||||
reg_key_t* reg_root(void) { return g_reg_root; }
|
||||
|
||||
// Caller holds g_reg_lock.
|
||||
static reg_key_t* key_alloc(const char* name, reg_key_t* parent) {
|
||||
reg_key_t* k = (reg_key_t*)kzalloc(sizeof(reg_key_t));
|
||||
if (!k) return NULL;
|
||||
strncpy(k->name, name ? name : "", REG_NAME_MAX - 1);
|
||||
k->parent = parent;
|
||||
g_key_count++;
|
||||
return k;
|
||||
}
|
||||
|
||||
// Caller holds g_reg_lock.
|
||||
static reg_key_t* key_find_child(reg_key_t* key, const char* name) {
|
||||
if (!key) return NULL;
|
||||
for (int i = 0; i < key->child_count; i++) {
|
||||
if (strcmp(key->children[i]->name, name) == 0) return key->children[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Split a path and walk it, optionally creating missing keys. The first path
|
||||
// component must be "Registry" (the root key's name).
|
||||
static reg_key_t* walk_path(const char* path, bool create) {
|
||||
if (!path || !g_reg_root) return NULL;
|
||||
|
||||
char buf[192];
|
||||
strncpy(buf, path, sizeof(buf) - 1);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
|
||||
reg_key_t* cur = g_reg_root;
|
||||
char* p = buf;
|
||||
if (*p == '\\') p++;
|
||||
|
||||
// First component names the root itself.
|
||||
char* first = p;
|
||||
while (*p && *p != '\\') p++;
|
||||
if (*p == '\\') { *p = '\0'; p++; }
|
||||
if (strcmp(first, g_reg_root->name) != 0) {
|
||||
return NULL; // path is not anchored at "\Registry"
|
||||
}
|
||||
|
||||
while (*p) {
|
||||
char* seg = p;
|
||||
while (*p && *p != '\\') p++;
|
||||
if (*p == '\\') { *p = '\0'; p++; }
|
||||
if (!*seg) continue;
|
||||
|
||||
reg_key_t* child = key_find_child(cur, seg);
|
||||
if (!child) {
|
||||
if (!create) return NULL;
|
||||
if (cur->child_count >= REG_MAX_CHILDREN) return NULL;
|
||||
child = key_alloc(seg, cur);
|
||||
if (!child) return NULL;
|
||||
cur->children[cur->child_count++] = child;
|
||||
}
|
||||
cur = child;
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
reg_key_t* reg_create_key(const char* path) {
|
||||
spin_lock(&g_reg_lock);
|
||||
reg_key_t* k = walk_path(path, true);
|
||||
spin_unlock(&g_reg_lock);
|
||||
return k;
|
||||
}
|
||||
|
||||
reg_key_t* reg_open_key(const char* path) {
|
||||
spin_lock(&g_reg_lock);
|
||||
reg_key_t* k = walk_path(path, false);
|
||||
spin_unlock(&g_reg_lock);
|
||||
return k;
|
||||
}
|
||||
|
||||
// Caller holds g_reg_lock.
|
||||
static reg_value_t* value_get_or_add(reg_key_t* key, const char* name) {
|
||||
for (int i = 0; i < key->value_count; i++) {
|
||||
if (strcmp(key->values[i]->name, name) == 0) return key->values[i];
|
||||
}
|
||||
if (key->value_count >= REG_MAX_VALUES) return NULL;
|
||||
reg_value_t* v = (reg_value_t*)kzalloc(sizeof(reg_value_t));
|
||||
if (!v) return NULL;
|
||||
strncpy(v->name, name, REG_NAME_MAX - 1);
|
||||
key->values[key->value_count++] = v;
|
||||
g_value_count++;
|
||||
return v;
|
||||
}
|
||||
|
||||
reg_value_t* reg_set_dword(reg_key_t* key, const char* name, uint32_t value) {
|
||||
if (!key || !name) return NULL;
|
||||
spin_lock(&g_reg_lock);
|
||||
reg_value_t* v = value_get_or_add(key, name);
|
||||
if (v) {
|
||||
v->type = REG_DWORD;
|
||||
v->data.dword = value;
|
||||
v->data_len = sizeof(uint32_t);
|
||||
}
|
||||
spin_unlock(&g_reg_lock);
|
||||
return v;
|
||||
}
|
||||
|
||||
reg_value_t* reg_set_qword(reg_key_t* key, const char* name, uint64_t value) {
|
||||
if (!key || !name) return NULL;
|
||||
spin_lock(&g_reg_lock);
|
||||
reg_value_t* v = value_get_or_add(key, name);
|
||||
if (v) {
|
||||
v->type = REG_QWORD;
|
||||
v->data.qword = value;
|
||||
v->data_len = sizeof(uint64_t);
|
||||
}
|
||||
spin_unlock(&g_reg_lock);
|
||||
return v;
|
||||
}
|
||||
|
||||
reg_value_t* reg_set_sz(reg_key_t* key, const char* name, const char* str) {
|
||||
if (!key || !name) return NULL;
|
||||
spin_lock(&g_reg_lock);
|
||||
reg_value_t* v = value_get_or_add(key, name);
|
||||
if (v) {
|
||||
v->type = REG_SZ;
|
||||
strncpy(v->data.str, str ? str : "", REG_STR_MAX - 1);
|
||||
v->data.str[REG_STR_MAX - 1] = '\0';
|
||||
v->data_len = (uint32_t)strlen(v->data.str) + 1;
|
||||
}
|
||||
spin_unlock(&g_reg_lock);
|
||||
return v;
|
||||
}
|
||||
|
||||
reg_value_t* reg_query_value(reg_key_t* key, const char* name) {
|
||||
if (!key || !name) return NULL;
|
||||
spin_lock(&g_reg_lock);
|
||||
reg_value_t* found = NULL;
|
||||
for (int i = 0; i < key->value_count; i++) {
|
||||
if (strcmp(key->values[i]->name, name) == 0) { found = key->values[i]; break; }
|
||||
}
|
||||
spin_unlock(&g_reg_lock);
|
||||
return found;
|
||||
}
|
||||
|
||||
int reg_enum_key_count(reg_key_t* key) { return key ? key->child_count : 0; }
|
||||
reg_key_t* reg_enum_key(reg_key_t* key, int index) {
|
||||
if (!key || index < 0 || index >= key->child_count) return NULL;
|
||||
return key->children[index];
|
||||
}
|
||||
int reg_enum_value_count(reg_key_t* key) { return key ? key->value_count : 0; }
|
||||
reg_value_t* reg_enum_value(reg_key_t* key, int index) {
|
||||
if (!key || index < 0 || index >= key->value_count) return NULL;
|
||||
return key->values[index];
|
||||
}
|
||||
|
||||
void reg_value_to_string(const reg_value_t* v, char* out, size_t out_len) {
|
||||
if (!v || !out || out_len == 0) return;
|
||||
switch (v->type) {
|
||||
case REG_SZ:
|
||||
case REG_MULTI_SZ:
|
||||
snprintf(out, out_len, "%s", v->data.str);
|
||||
break;
|
||||
case REG_DWORD:
|
||||
snprintf(out, out_len, "0x%08X (%u)", v->data.dword, v->data.dword);
|
||||
break;
|
||||
case REG_QWORD:
|
||||
snprintf(out, out_len, "0x%016llX", (unsigned long long)v->data.qword);
|
||||
break;
|
||||
case REG_BINARY:
|
||||
snprintf(out, out_len, "<%u bytes>", v->data_len);
|
||||
break;
|
||||
default:
|
||||
snprintf(out, out_len, "(none)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void reg_get_stats(uint32_t* out_keys, uint32_t* out_values) {
|
||||
if (out_keys) *out_keys = g_key_count;
|
||||
if (out_values) *out_values = g_value_count;
|
||||
}
|
||||
|
||||
void reg_init(void) {
|
||||
g_key_count = 0;
|
||||
g_value_count = 0;
|
||||
|
||||
g_reg_root = key_alloc("Registry", NULL);
|
||||
if (!g_reg_root) {
|
||||
printk(KERN_ERR "REG: failed to allocate the registry root\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Standard hives.
|
||||
reg_create_key("\\Registry\\Machine");
|
||||
reg_create_key("\\Registry\\User");
|
||||
|
||||
// Hardware identification.
|
||||
reg_key_t* sys = reg_create_key("\\Registry\\Machine\\Hardware\\Description\\System");
|
||||
if (sys) {
|
||||
reg_set_sz(sys, "Identifier", "SUB-OS Modular Monolithic Kernel");
|
||||
reg_set_sz(sys, "SystemBootDevice", "\\Device\\Harddisk0\\Partition1");
|
||||
}
|
||||
|
||||
// Control set.
|
||||
reg_key_t* ctl = reg_create_key("\\Registry\\Machine\\System\\CurrentControlSet\\Control");
|
||||
if (ctl) {
|
||||
reg_set_sz(ctl, "SystemStartOptions", "NOEXECUTE=OPTIN QUIET");
|
||||
reg_set_dword(ctl, "PreemptiveScheduler", 1);
|
||||
}
|
||||
|
||||
// SUB-OS software hive.
|
||||
reg_key_t* sw = reg_create_key("\\Registry\\Machine\\Software\\SUB-OS");
|
||||
if (sw) {
|
||||
reg_set_sz(sw, "Version", kernel_get_version());
|
||||
reg_set_sz(sw, "BuildArch", arch_get_name());
|
||||
reg_set_dword(sw, "GrowableHeap", 1);
|
||||
reg_set_dword(sw, "ObjectManager", 1);
|
||||
reg_set_qword(sw, "InstallCookie", 0x5355424F53000001ULL);
|
||||
}
|
||||
|
||||
// Default user profile.
|
||||
reg_key_t* du = reg_create_key("\\Registry\\User\\.DEFAULT\\Environment");
|
||||
if (du) {
|
||||
reg_set_sz(du, "PATH", "/bin:/sbin:/usr/bin");
|
||||
reg_set_sz(du, "SHELL", "/bin/sh");
|
||||
}
|
||||
|
||||
printk(ANSI_BRIGHT_GREEN "REG: " ANSI_RESET
|
||||
"NT Configuration Registry online (%u keys, %u values under \\Registry)\n",
|
||||
g_key_count, g_value_count);
|
||||
}
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <mm/kmalloc.h>
|
||||
#include <kernel/rust.h>
|
||||
#include <kernel/nt/ob.h>
|
||||
#include <kernel/nt/reg.h>
|
||||
#include <kernel/sub_lang.h>
|
||||
#include <kernel/cpp_kernel.h>
|
||||
#include <userland/snake.h>
|
||||
@@ -587,6 +588,77 @@ static int applet_ntobj(int argc, char** argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reg_query_cmd(const char* path) {
|
||||
reg_key_t* key = reg_open_key(path);
|
||||
if (!key) {
|
||||
printk(KERN_ERR "reg: key '%s' not found\n", path);
|
||||
return 1;
|
||||
}
|
||||
printk(ANSI_BRIGHT_CYAN "%s\n" ANSI_RESET, path);
|
||||
|
||||
int vc = reg_enum_value_count(key);
|
||||
if (vc == 0) {
|
||||
printk(" (no values)\n");
|
||||
}
|
||||
for (int i = 0; i < vc; i++) {
|
||||
reg_value_t* v = reg_enum_value(key, i);
|
||||
char rendered[REG_STR_MAX + 32];
|
||||
reg_value_to_string(v, rendered, sizeof(rendered));
|
||||
printk(" " ANSI_YELLOW "%-20s" ANSI_RESET " %-11s %s\n",
|
||||
v->name, reg_type_name(v->type), rendered);
|
||||
}
|
||||
|
||||
int kc = reg_enum_key_count(key);
|
||||
for (int i = 0; i < kc; i++) {
|
||||
reg_key_t* sub = reg_enum_key(key, i);
|
||||
printk(ANSI_BRIGHT_GREEN " [%s]\n" ANSI_RESET, sub->name);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int applet_reg(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
printk("Usage: reg query <\\path>\n");
|
||||
printk(" reg add <\\path>\n");
|
||||
printk(" reg set <\\path> <name> <dword|sz> <value>\n");
|
||||
printk(" reg stats\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "stats") == 0) {
|
||||
uint32_t keys = 0, values = 0;
|
||||
reg_get_stats(&keys, &values);
|
||||
printk("Registry: %u keys, %u values under \\Registry\n", keys, values);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[1], "query") == 0) {
|
||||
return reg_query_cmd((argc >= 3) ? argv[2] : "\\Registry");
|
||||
}
|
||||
if (strcmp(argv[1], "add") == 0 && argc >= 3) {
|
||||
reg_key_t* k = reg_create_key(argv[2]);
|
||||
if (!k) { printk(KERN_ERR "reg: failed to create '%s'\n", argv[2]); return 1; }
|
||||
printk("Created key %s\n", argv[2]);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[1], "set") == 0 && argc >= 6) {
|
||||
reg_key_t* k = reg_open_key(argv[2]);
|
||||
if (!k) { printk(KERN_ERR "reg: key '%s' not found\n", argv[2]); return 1; }
|
||||
if (strcmp(argv[4], "dword") == 0) {
|
||||
reg_set_dword(k, argv[3], (uint32_t)atoi(argv[5]));
|
||||
} else if (strcmp(argv[4], "sz") == 0) {
|
||||
reg_set_sz(k, argv[3], argv[5]);
|
||||
} else {
|
||||
printk("reg: unknown type '%s' (use dword or sz)\n", argv[4]);
|
||||
return 1;
|
||||
}
|
||||
printk("Set %s\\%s\n", argv[2], argv[3]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
printk("reg: unrecognised sub-command '%s'\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int applet_rand(int argc, char** argv) {
|
||||
int count = (argc >= 2) ? atoi(argv[1]) : 4;
|
||||
printk("Random Integers: ");
|
||||
@@ -2298,6 +2370,7 @@ static const lazybox_applet_t applets[] = {
|
||||
{"rle", applet_rle, "rle <text>", "Rust RLE compress round-trip","Crypto"},
|
||||
{"objdir", applet_objdir, "objdir [\\path]", "List the NT object namespace","Kernel"},
|
||||
{"ntobj", applet_ntobj, "ntobj", "NT Object Manager stats/demo","Kernel"},
|
||||
{"reg", applet_reg, "reg query|add|set|stats", "NT configuration registry", "Kernel"},
|
||||
{"rand", applet_rand, "rand [count]", "Generate random numbers", "Crypto"},
|
||||
{"certcheck", applet_certcheck, "certcheck", "View X.509 kernel keyring", "Security"},
|
||||
{"capsh", applet_capsh, "capsh", "View process capabilities", "Security"},
|
||||
|
||||
Reference in new issue
Block a user