feat: userspace overhaul, Intel GPU driver, and more
This commit is contained in:
+32
-5
@@ -56,9 +56,9 @@ BINDIR := bin
|
||||
# Discover all programs (each subdirectory under src/ is a program).
|
||||
PROGRAMS := $(notdir $(wildcard src/*))
|
||||
|
||||
# Games are built separately (doom has its own Makefile).
|
||||
GAMES := doom
|
||||
SYSTEM_PROGRAMS := $(filter-out $(GAMES),$(PROGRAMS))
|
||||
# Programs with custom Makefiles (built separately).
|
||||
CUSTOM_BUILDS := doom fetch wiki
|
||||
SYSTEM_PROGRAMS := $(filter-out $(CUSTOM_BUILDS),$(PROGRAMS))
|
||||
|
||||
# Build targets: system programs go to bin/os/, games are handled separately.
|
||||
TARGETS := $(addprefix $(BINDIR)/os/,$(addsuffix .elf,$(SYSTEM_PROGRAMS)))
|
||||
@@ -76,12 +76,31 @@ WWWDIR := www
|
||||
WWWSRC := $(wildcard $(WWWDIR)/*.*)
|
||||
WWWDST := $(patsubst $(WWWDIR)/%,$(BINDIR)/www/%,$(WWWSRC))
|
||||
|
||||
# CA certificate bundle.
|
||||
CA_CERTS := $(BINDIR)/etc/ca-certificates.crt
|
||||
|
||||
# Home directory placeholder.
|
||||
HOMEKEEP := $(BINDIR)/home/.keep
|
||||
|
||||
.PHONY: all clean doom
|
||||
.PHONY: all clean doom fetch wiki bearssl libc
|
||||
|
||||
all: $(TARGETS) doom $(GAME_DATA) $(MANDST) $(WWWDST) $(HOMEKEEP)
|
||||
all: bearssl libc $(TARGETS) fetch wiki doom $(GAME_DATA) $(MANDST) $(WWWDST) $(CA_CERTS) $(HOMEKEEP)
|
||||
|
||||
# Build BearSSL static library.
|
||||
bearssl:
|
||||
$(MAKE) -C lib/bearssl
|
||||
|
||||
# Build shared libc static library.
|
||||
libc:
|
||||
$(MAKE) -C lib/libc
|
||||
|
||||
# Build fetch via its own Makefile (depends on bearssl and libc).
|
||||
fetch: bearssl libc
|
||||
$(MAKE) -C src/fetch
|
||||
|
||||
# Build wiki via its own Makefile (depends on bearssl and libc).
|
||||
wiki: bearssl libc
|
||||
$(MAKE) -C src/wiki
|
||||
|
||||
# Build doom via its own Makefile.
|
||||
doom:
|
||||
@@ -102,6 +121,11 @@ $(BINDIR)/www/%: $(WWWDIR)/%
|
||||
mkdir -p $(BINDIR)/www
|
||||
cp $< $@
|
||||
|
||||
# Copy CA certificate bundle into bin/etc/.
|
||||
$(CA_CERTS): data/ca-certificates.crt
|
||||
mkdir -p $(BINDIR)/etc
|
||||
cp $< $@
|
||||
|
||||
# Create empty home directory with a keep file.
|
||||
$(HOMEKEEP):
|
||||
mkdir -p $(BINDIR)/home
|
||||
@@ -115,4 +139,7 @@ $(BINDIR)/os/%.elf: src/%/main.cpp link.ld GNUmakefile
|
||||
|
||||
clean:
|
||||
rm -rf $(BINDIR) obj
|
||||
$(MAKE) -C lib/bearssl clean
|
||||
$(MAKE) -C lib/libc clean
|
||||
$(MAKE) -C src/fetch clean
|
||||
$(MAKE) -C src/doom clean
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -54,6 +54,9 @@ namespace Zenith {
|
||||
static constexpr uint64_t SYS_RECVFROM = 40;
|
||||
static constexpr uint64_t SYS_FWRITE = 41;
|
||||
static constexpr uint64_t SYS_FCREATE = 42;
|
||||
static constexpr uint64_t SYS_TERMSCALE = 43;
|
||||
static constexpr uint64_t SYS_RESOLVE = 44;
|
||||
static constexpr uint64_t SYS_GETRANDOM = 45;
|
||||
|
||||
static constexpr int SOCK_TCP = 1;
|
||||
static constexpr int SOCK_UDP = 2;
|
||||
@@ -64,6 +67,7 @@ namespace Zenith {
|
||||
uint32_t gateway; // network byte order
|
||||
uint8_t macAddress[6];
|
||||
uint8_t _pad[2];
|
||||
uint32_t dnsServer; // network byte order
|
||||
};
|
||||
|
||||
struct DateTime {
|
||||
|
||||
@@ -165,6 +165,11 @@ namespace zenith {
|
||||
return (int32_t)syscall2(Zenith::SYS_PING, (uint64_t)ip, (uint64_t)timeoutMs);
|
||||
}
|
||||
|
||||
// DNS resolve: returns IP in network byte order, or 0 on failure
|
||||
inline uint32_t resolve(const char* hostname) {
|
||||
return (uint32_t)syscall1(Zenith::SYS_RESOLVE, (uint64_t)hostname);
|
||||
}
|
||||
|
||||
// Network configuration
|
||||
inline void get_netcfg(Zenith::NetCfg* out) { syscall1(Zenith::SYS_GETNETCFG, (uint64_t)out); }
|
||||
inline int set_netcfg(const Zenith::NetCfg* cfg) { return (int)syscall1(Zenith::SYS_SETNETCFG, (uint64_t)cfg); }
|
||||
@@ -222,9 +227,24 @@ namespace zenith {
|
||||
if (rows) *rows = (int)(r >> 32);
|
||||
}
|
||||
|
||||
inline void termscale(int scale_x, int scale_y) {
|
||||
syscall2(Zenith::SYS_TERMSCALE, (uint64_t)scale_x, (uint64_t)scale_y);
|
||||
}
|
||||
|
||||
inline void get_termscale(int* scale_x, int* scale_y) {
|
||||
uint64_t r = (uint64_t)syscall2(Zenith::SYS_TERMSCALE, 0, 0);
|
||||
if (scale_x) *scale_x = (int)(r & 0xFFFFFFFF);
|
||||
if (scale_y) *scale_y = (int)(r >> 32);
|
||||
}
|
||||
|
||||
// Timekeeping (wall-clock)
|
||||
inline void gettime(Zenith::DateTime* out) { syscall1(Zenith::SYS_GETTIME, (uint64_t)out); }
|
||||
|
||||
// Random number generation
|
||||
inline int64_t getrandom(void* buf, uint32_t len) {
|
||||
return syscall2(Zenith::SYS_GETRANDOM, (uint64_t)buf, (uint64_t)len);
|
||||
}
|
||||
|
||||
// Power management
|
||||
[[noreturn]] inline void reset() {
|
||||
syscall0(Zenith::SYS_RESET);
|
||||
|
||||
Submodule
+1
Submodule programs/lib/bearssl added at 3d9be2f60b
@@ -0,0 +1,64 @@
|
||||
# Makefile for shared libc static library on ZenithOS
|
||||
# Copyright (c) 2025-2026 Daniel Hammer
|
||||
|
||||
MAKEFLAGS += -rR
|
||||
.SUFFIXES:
|
||||
|
||||
# ---- Toolchain ----
|
||||
|
||||
TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-elf-
|
||||
ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),)
|
||||
CC := $(TOOLCHAIN_PREFIX)gcc
|
||||
AR := $(TOOLCHAIN_PREFIX)ar
|
||||
else
|
||||
CC := gcc
|
||||
AR := ar
|
||||
endif
|
||||
|
||||
# ---- Paths ----
|
||||
|
||||
LIBC_INC := ../../include/libc
|
||||
OBJDIR := obj
|
||||
|
||||
# ---- Compiler flags ----
|
||||
|
||||
CFLAGS := \
|
||||
-std=gnu11 \
|
||||
-g -O2 -pipe \
|
||||
-Wall \
|
||||
-Wno-unused-parameter \
|
||||
-nostdinc \
|
||||
-ffreestanding \
|
||||
-fno-stack-protector \
|
||||
-fno-stack-check \
|
||||
-fno-PIC \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-m64 \
|
||||
-march=x86-64 \
|
||||
-mno-80387 \
|
||||
-mno-mmx \
|
||||
-mno-sse \
|
||||
-mno-sse2 \
|
||||
-mno-red-zone \
|
||||
-mcmodel=small \
|
||||
-isystem $(LIBC_INC) \
|
||||
-isystem $(shell $(CC) -print-file-name=include)
|
||||
|
||||
# ---- Target ----
|
||||
|
||||
TARGET := liblibc.a
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJDIR)/libc.o
|
||||
$(AR) rcs $@ $^
|
||||
|
||||
$(OBJDIR)/libc.o: libc.c Makefile
|
||||
@mkdir -p $(OBJDIR)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET)
|
||||
@@ -0,0 +1,662 @@
|
||||
/*
|
||||
* libc.c
|
||||
* Minimal C standard library for ZenithOS userspace programs
|
||||
* Based on the proven libc from the DOOM port.
|
||||
* Copyright (c) 2025-2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* ========================================================================
|
||||
Raw syscall wrappers (C versions matching kernel ABI)
|
||||
======================================================================== */
|
||||
|
||||
static inline long _zos_syscall0(long nr) {
|
||||
long ret;
|
||||
__asm__ volatile("syscall" : "=a"(ret) : "a"(nr)
|
||||
: "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long _zos_syscall1(long nr, long a1) {
|
||||
long ret;
|
||||
__asm__ volatile(
|
||||
"mov %[a1], %%rdi\n\t"
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(nr), [a1] "r"(a1)
|
||||
: "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long _zos_syscall4(long nr, long a1, long a2, long a3, long a4) {
|
||||
long ret;
|
||||
__asm__ volatile(
|
||||
"mov %[a1], %%rdi\n\t"
|
||||
"mov %[a2], %%rsi\n\t"
|
||||
"mov %[a3], %%rdx\n\t"
|
||||
"mov %[a4], %%r10\n\t"
|
||||
"syscall"
|
||||
: "=a"(ret)
|
||||
: "a"(nr), [a1] "r"(a1), [a2] "r"(a2), [a3] "r"(a3), [a4] "r"(a4)
|
||||
: "rcx", "r11", "rdi", "rsi", "rdx", "r8", "r9", "r10", "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Syscall numbers */
|
||||
#define SYS_EXIT 0
|
||||
#define SYS_PRINT 4
|
||||
#define SYS_PUTCHAR 5
|
||||
#define SYS_ALLOC 11
|
||||
#define SYS_FREE 12
|
||||
|
||||
/* ========================================================================
|
||||
errno
|
||||
======================================================================== */
|
||||
|
||||
int errno = 0;
|
||||
|
||||
/* ========================================================================
|
||||
string.h functions
|
||||
======================================================================== */
|
||||
|
||||
void *memcpy(void *dest, const void *src, size_t n) {
|
||||
unsigned char *d = (unsigned char *)dest;
|
||||
const unsigned char *s = (const unsigned char *)src;
|
||||
for (size_t i = 0; i < n; i++)
|
||||
d[i] = s[i];
|
||||
return dest;
|
||||
}
|
||||
|
||||
void *memset(void *s, int c, size_t n) {
|
||||
unsigned char *p = (unsigned char *)s;
|
||||
for (size_t i = 0; i < n; i++)
|
||||
p[i] = (unsigned char)c;
|
||||
return s;
|
||||
}
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n) {
|
||||
unsigned char *d = (unsigned char *)dest;
|
||||
const unsigned char *s = (const unsigned char *)src;
|
||||
if (s < d && d < s + n) {
|
||||
for (size_t i = n; i > 0; i--)
|
||||
d[i - 1] = s[i - 1];
|
||||
} else {
|
||||
for (size_t i = 0; i < n; i++)
|
||||
d[i] = s[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
int memcmp(const void *s1, const void *s2, size_t n) {
|
||||
const unsigned char *a = (const unsigned char *)s1;
|
||||
const unsigned char *b = (const unsigned char *)s2;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (a[i] != b[i])
|
||||
return a[i] < b[i] ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t strlen(const char *s) {
|
||||
size_t len = 0;
|
||||
while (s[len]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
int strcmp(const char *a, const char *b) {
|
||||
while (*a && *a == *b) { a++; b++; }
|
||||
return (unsigned char)*a - (unsigned char)*b;
|
||||
}
|
||||
|
||||
int strncmp(const char *a, const char *b, size_t n) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (a[i] != b[i] || a[i] == 0)
|
||||
return (unsigned char)a[i] - (unsigned char)b[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strcpy(char *dest, const char *src) {
|
||||
char *d = dest;
|
||||
while ((*d++ = *src++));
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *strncpy(char *dest, const char *src, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n && src[i]; i++)
|
||||
dest[i] = src[i];
|
||||
for (; i < n; i++)
|
||||
dest[i] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *strcat(char *dest, const char *src) {
|
||||
char *d = dest + strlen(dest);
|
||||
while ((*d++ = *src++));
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *strncat(char *dest, const char *src, size_t n) {
|
||||
char *d = dest + strlen(dest);
|
||||
size_t i;
|
||||
for (i = 0; i < n && src[i]; i++)
|
||||
d[i] = src[i];
|
||||
d[i] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *strchr(const char *s, int c) {
|
||||
while (*s) {
|
||||
if (*s == (char)c) return (char *)s;
|
||||
s++;
|
||||
}
|
||||
return (c == 0) ? (char *)s : NULL;
|
||||
}
|
||||
|
||||
char *strrchr(const char *s, int c) {
|
||||
const char *last = NULL;
|
||||
while (*s) {
|
||||
if (*s == (char)c) last = s;
|
||||
s++;
|
||||
}
|
||||
if (c == 0) return (char *)s;
|
||||
return (char *)last;
|
||||
}
|
||||
|
||||
int strcasecmp(const char *a, const char *b) {
|
||||
while (*a && ((*a >= 'A' && *a <= 'Z') ? *a + 32 : *a) ==
|
||||
((*b >= 'A' && *b <= 'Z') ? *b + 32 : *b)) { a++; b++; }
|
||||
int ca = (*a >= 'A' && *a <= 'Z') ? *a + 32 : *a;
|
||||
int cb = (*b >= 'A' && *b <= 'Z') ? *b + 32 : *b;
|
||||
return ca - cb;
|
||||
}
|
||||
|
||||
int strncasecmp(const char *a, const char *b, size_t n) {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
int ca = (a[i] >= 'A' && a[i] <= 'Z') ? a[i] + 32 : a[i];
|
||||
int cb = (b[i] >= 'A' && b[i] <= 'Z') ? b[i] + 32 : b[i];
|
||||
if (ca != cb || ca == 0) return ca - cb;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strstr(const char *haystack, const char *needle) {
|
||||
if (!*needle) return (char *)haystack;
|
||||
size_t nlen = strlen(needle);
|
||||
while (*haystack) {
|
||||
if (strncmp(haystack, needle, nlen) == 0)
|
||||
return (char *)haystack;
|
||||
haystack++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Forward declaration for strdup */
|
||||
void *malloc(size_t size);
|
||||
|
||||
char *strdup(const char *s) {
|
||||
size_t len = strlen(s) + 1;
|
||||
char *d = (char *)malloc(len);
|
||||
if (d) memcpy(d, s, len);
|
||||
return d;
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
ctype.h functions
|
||||
======================================================================== */
|
||||
|
||||
int isalpha(int c) { return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); }
|
||||
int isdigit(int c) { return c >= '0' && c <= '9'; }
|
||||
int isalnum(int c) { return isalpha(c) || isdigit(c); }
|
||||
int isspace(int c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; }
|
||||
int isupper(int c) { return c >= 'A' && c <= 'Z'; }
|
||||
int islower(int c) { return c >= 'a' && c <= 'z'; }
|
||||
int isprint(int c) { return c >= 0x20 && c <= 0x7E; }
|
||||
int ispunct(int c) { return isprint(c) && !isalnum(c) && c != ' '; }
|
||||
int isxdigit(int c) { return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); }
|
||||
int iscntrl(int c) { return (c >= 0 && c < 0x20) || c == 0x7F; }
|
||||
int isgraph(int c) { return c > 0x20 && c <= 0x7E; }
|
||||
int toupper(int c) { return (c >= 'a' && c <= 'z') ? c - 32 : c; }
|
||||
int tolower(int c) { return (c >= 'A' && c <= 'Z') ? c + 32 : c; }
|
||||
|
||||
/* ========================================================================
|
||||
Heap allocator (free-list, backed by SYS_ALLOC)
|
||||
======================================================================== */
|
||||
|
||||
#define HEAP_MAGIC 0x5A484541ULL /* "ZHEA" */
|
||||
|
||||
struct HeapHeader {
|
||||
uint64_t magic;
|
||||
uint64_t size;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct FreeNode {
|
||||
uint64_t size;
|
||||
struct FreeNode *next;
|
||||
};
|
||||
|
||||
static struct FreeNode g_heapHead = { 0, NULL };
|
||||
static int g_heapInit = 0;
|
||||
|
||||
static void heap_insert_free(void *ptr, uint64_t size) {
|
||||
struct FreeNode *node = (struct FreeNode *)ptr;
|
||||
node->size = size;
|
||||
node->next = g_heapHead.next;
|
||||
g_heapHead.next = node;
|
||||
}
|
||||
|
||||
static void heap_grow(uint64_t bytes) {
|
||||
uint64_t pages = (bytes + 0xFFF) / 0x1000;
|
||||
if (pages < 4) pages = 4;
|
||||
void *mem = (void *)_zos_syscall1(SYS_ALLOC, (long)(pages * 0x1000));
|
||||
if (mem != NULL)
|
||||
heap_insert_free(mem, pages * 0x1000);
|
||||
}
|
||||
|
||||
void *malloc(size_t size) {
|
||||
if (!g_heapInit) {
|
||||
heap_grow(16 * 0x1000);
|
||||
g_heapInit = 1;
|
||||
}
|
||||
|
||||
uint64_t needed = size + sizeof(struct HeapHeader);
|
||||
needed = (needed + 15) & ~15ULL;
|
||||
|
||||
struct FreeNode *prev = &g_heapHead;
|
||||
struct FreeNode *cur = g_heapHead.next;
|
||||
|
||||
while (cur != NULL) {
|
||||
if (cur->size >= needed) {
|
||||
uint64_t blockSize = cur->size;
|
||||
prev->next = cur->next;
|
||||
|
||||
if (blockSize > needed + sizeof(struct FreeNode) + 16) {
|
||||
void *rest = (void *)((uint8_t *)cur + needed);
|
||||
heap_insert_free(rest, blockSize - needed);
|
||||
}
|
||||
|
||||
struct HeapHeader *hdr = (struct HeapHeader *)cur;
|
||||
hdr->magic = HEAP_MAGIC;
|
||||
hdr->size = size;
|
||||
return (void *)((uint8_t *)hdr + sizeof(struct HeapHeader));
|
||||
}
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
heap_grow(needed);
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void free(void *ptr) {
|
||||
if (ptr == NULL) return;
|
||||
|
||||
struct HeapHeader *hdr = (struct HeapHeader *)((uint8_t *)ptr - sizeof(struct HeapHeader));
|
||||
uint64_t blockSize = hdr->size + sizeof(struct HeapHeader);
|
||||
blockSize = (blockSize + 15) & ~15ULL;
|
||||
heap_insert_free((void *)hdr, blockSize);
|
||||
}
|
||||
|
||||
void *calloc(size_t nmemb, size_t size) {
|
||||
size_t total = nmemb * size;
|
||||
void *p = malloc(total);
|
||||
if (p) memset(p, 0, total);
|
||||
return p;
|
||||
}
|
||||
|
||||
void *realloc(void *ptr, size_t size) {
|
||||
if (ptr == NULL) return malloc(size);
|
||||
if (size == 0) { free(ptr); return NULL; }
|
||||
|
||||
struct HeapHeader *hdr = (struct HeapHeader *)((uint8_t *)ptr - sizeof(struct HeapHeader));
|
||||
uint64_t old = hdr->size;
|
||||
|
||||
void *newp = malloc(size);
|
||||
if (newp == NULL) return NULL;
|
||||
|
||||
size_t copySize = old < size ? old : size;
|
||||
memcpy(newp, ptr, copySize);
|
||||
free(ptr);
|
||||
return newp;
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
stdlib.h functions
|
||||
======================================================================== */
|
||||
|
||||
int abs(int x) { return x < 0 ? -x : x; }
|
||||
long labs(long x) { return x < 0 ? -x : x; }
|
||||
|
||||
int atoi(const char *s) {
|
||||
int neg = 0, val = 0;
|
||||
while (isspace((unsigned char)*s)) s++;
|
||||
if (*s == '-') { neg = 1; s++; }
|
||||
else if (*s == '+') { s++; }
|
||||
while (isdigit((unsigned char)*s)) {
|
||||
val = val * 10 + (*s - '0');
|
||||
s++;
|
||||
}
|
||||
return neg ? -val : val;
|
||||
}
|
||||
|
||||
long strtol(const char *nptr, char **endptr, int base) {
|
||||
const char *s = nptr;
|
||||
long val = 0;
|
||||
int neg = 0;
|
||||
|
||||
while (isspace((unsigned char)*s)) s++;
|
||||
if (*s == '-') { neg = 1; s++; }
|
||||
else if (*s == '+') { s++; }
|
||||
|
||||
if (base == 0) {
|
||||
if (*s == '0' && (s[1] == 'x' || s[1] == 'X')) { base = 16; s += 2; }
|
||||
else if (*s == '0') { base = 8; s++; }
|
||||
else base = 10;
|
||||
} else if (base == 16 && *s == '0' && (s[1] == 'x' || s[1] == 'X')) {
|
||||
s += 2;
|
||||
}
|
||||
|
||||
while (*s) {
|
||||
int digit;
|
||||
if (*s >= '0' && *s <= '9') digit = *s - '0';
|
||||
else if (*s >= 'a' && *s <= 'z') digit = *s - 'a' + 10;
|
||||
else if (*s >= 'A' && *s <= 'Z') digit = *s - 'A' + 10;
|
||||
else break;
|
||||
if (digit >= base) break;
|
||||
val = val * base + digit;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (endptr) *endptr = (char *)s;
|
||||
return neg ? -val : val;
|
||||
}
|
||||
|
||||
unsigned long strtoul(const char *nptr, char **endptr, int base) {
|
||||
return (unsigned long)strtol(nptr, endptr, base);
|
||||
}
|
||||
|
||||
char *getenv(const char *name) {
|
||||
(void)name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void exit(int status) {
|
||||
_zos_syscall1(SYS_EXIT, (long)status);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void abort(void) {
|
||||
_zos_syscall1(SYS_PRINT, (long)"abort() called\n");
|
||||
_zos_syscall1(SYS_EXIT, 1);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
int system(const char *command) {
|
||||
(void)command;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
printf family — vsnprintf core
|
||||
======================================================================== */
|
||||
|
||||
struct _pf_state {
|
||||
char *buf;
|
||||
size_t pos;
|
||||
size_t max;
|
||||
};
|
||||
|
||||
static void _pf_putc(struct _pf_state *st, char c) {
|
||||
if (st->pos < st->max)
|
||||
st->buf[st->pos] = c;
|
||||
st->pos++;
|
||||
}
|
||||
|
||||
static void _pf_puts(struct _pf_state *st, const char *s) {
|
||||
while (*s) _pf_putc(st, *s++);
|
||||
}
|
||||
|
||||
static void _pf_putnum(struct _pf_state *st, unsigned long val, int base, int upper, int width, char pad, int neg, int precision) {
|
||||
char tmp[24];
|
||||
int i = 0;
|
||||
const char *digits = upper ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
|
||||
if (val == 0) {
|
||||
tmp[i++] = '0';
|
||||
} else {
|
||||
while (val > 0) {
|
||||
tmp[i++] = digits[val % base];
|
||||
val /= base;
|
||||
}
|
||||
}
|
||||
|
||||
int digitCount = i;
|
||||
int precPad = 0;
|
||||
if (precision > digitCount)
|
||||
precPad = precision - digitCount;
|
||||
|
||||
int total = (neg ? 1 : 0) + precPad + digitCount;
|
||||
|
||||
if (neg && pad == '0' && precision < 0) {
|
||||
_pf_putc(st, '-');
|
||||
}
|
||||
if (precision < 0 && pad == '0') {
|
||||
for (int w = total; w < width; w++)
|
||||
_pf_putc(st, '0');
|
||||
} else {
|
||||
for (int w = total; w < width; w++)
|
||||
_pf_putc(st, ' ');
|
||||
}
|
||||
if (neg && !(pad == '0' && precision < 0)) {
|
||||
_pf_putc(st, '-');
|
||||
}
|
||||
|
||||
for (int p = 0; p < precPad; p++)
|
||||
_pf_putc(st, '0');
|
||||
|
||||
while (i > 0)
|
||||
_pf_putc(st, tmp[--i]);
|
||||
}
|
||||
|
||||
int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) {
|
||||
struct _pf_state st;
|
||||
st.buf = buf;
|
||||
st.pos = 0;
|
||||
st.max = size > 0 ? size - 1 : 0;
|
||||
|
||||
while (*fmt) {
|
||||
if (*fmt != '%') {
|
||||
_pf_putc(&st, *fmt++);
|
||||
continue;
|
||||
}
|
||||
fmt++;
|
||||
|
||||
char pad = ' ';
|
||||
int left_align = 0;
|
||||
while (*fmt == '0' || *fmt == '-' || *fmt == '+' || *fmt == ' ') {
|
||||
if (*fmt == '0') pad = '0';
|
||||
if (*fmt == '-') { left_align = 1; pad = ' '; }
|
||||
fmt++;
|
||||
}
|
||||
|
||||
int width = 0;
|
||||
if (*fmt == '*') {
|
||||
width = va_arg(ap, int);
|
||||
fmt++;
|
||||
} else {
|
||||
while (*fmt >= '0' && *fmt <= '9') {
|
||||
width = width * 10 + (*fmt - '0');
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
|
||||
int precision = -1;
|
||||
if (*fmt == '.') {
|
||||
fmt++;
|
||||
precision = 0;
|
||||
if (*fmt == '*') {
|
||||
precision = va_arg(ap, int);
|
||||
fmt++;
|
||||
} else {
|
||||
while (*fmt >= '0' && *fmt <= '9') {
|
||||
precision = precision * 10 + (*fmt - '0');
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int is_long = 0;
|
||||
if (*fmt == 'l') { is_long = 1; fmt++; if (*fmt == 'l') { is_long = 2; fmt++; } }
|
||||
else if (*fmt == 'h') { fmt++; if (*fmt == 'h') fmt++; }
|
||||
else if (*fmt == 'z') { is_long = 1; fmt++; }
|
||||
|
||||
switch (*fmt) {
|
||||
case 'd': case 'i': {
|
||||
long val;
|
||||
if (is_long >= 1) val = va_arg(ap, long);
|
||||
else val = va_arg(ap, int);
|
||||
int neg = 0;
|
||||
unsigned long uval;
|
||||
if (val < 0) { neg = 1; uval = (unsigned long)(-val); }
|
||||
else uval = (unsigned long)val;
|
||||
if (left_align) {
|
||||
size_t before = st.pos;
|
||||
_pf_putnum(&st, uval, 10, 0, 0, pad, neg, precision);
|
||||
size_t len = st.pos - before;
|
||||
for (size_t w = len; (int)w < width; w++) _pf_putc(&st, ' ');
|
||||
} else {
|
||||
_pf_putnum(&st, uval, 10, 0, width, pad, neg, precision);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
unsigned long val;
|
||||
if (is_long >= 1) val = va_arg(ap, unsigned long);
|
||||
else val = va_arg(ap, unsigned int);
|
||||
if (left_align) {
|
||||
size_t before = st.pos;
|
||||
_pf_putnum(&st, val, 10, 0, 0, ' ', 0, precision);
|
||||
size_t len = st.pos - before;
|
||||
for (size_t w = len; (int)w < width; w++) _pf_putc(&st, ' ');
|
||||
} else {
|
||||
_pf_putnum(&st, val, 10, 0, width, pad, 0, precision);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'x': case 'X': {
|
||||
unsigned long val;
|
||||
if (is_long >= 1) val = va_arg(ap, unsigned long);
|
||||
else val = va_arg(ap, unsigned int);
|
||||
int upper = (*fmt == 'X');
|
||||
if (left_align) {
|
||||
size_t before = st.pos;
|
||||
_pf_putnum(&st, val, 16, upper, 0, pad, 0, precision);
|
||||
size_t len = st.pos - before;
|
||||
for (size_t w = len; (int)w < width; w++) _pf_putc(&st, ' ');
|
||||
} else {
|
||||
_pf_putnum(&st, val, 16, upper, width, pad, 0, precision);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': {
|
||||
void *val = va_arg(ap, void *);
|
||||
_pf_puts(&st, "0x");
|
||||
_pf_putnum(&st, (unsigned long)val, 16, 0, 0, '0', 0, -1);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
const char *s = va_arg(ap, const char *);
|
||||
if (s == NULL) s = "(null)";
|
||||
int slen = (int)strlen(s);
|
||||
if (precision >= 0 && precision < slen) slen = precision;
|
||||
if (!left_align) {
|
||||
for (int w = slen; w < width; w++) _pf_putc(&st, ' ');
|
||||
}
|
||||
for (int i = 0; i < slen; i++) _pf_putc(&st, s[i]);
|
||||
if (left_align) {
|
||||
for (int w = slen; w < width; w++) _pf_putc(&st, ' ');
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
char c = (char)va_arg(ap, int);
|
||||
_pf_putc(&st, c);
|
||||
break;
|
||||
}
|
||||
case '%':
|
||||
_pf_putc(&st, '%');
|
||||
break;
|
||||
default:
|
||||
_pf_putc(&st, '%');
|
||||
_pf_putc(&st, *fmt);
|
||||
break;
|
||||
}
|
||||
if (*fmt) fmt++;
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
if (st.pos < size)
|
||||
st.buf[st.pos] = '\0';
|
||||
else
|
||||
st.buf[size - 1] = '\0';
|
||||
}
|
||||
|
||||
return (int)st.pos;
|
||||
}
|
||||
|
||||
int snprintf(char *buf, size_t size, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int ret = vsnprintf(buf, size, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sprintf(char *buf, const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int ret = vsnprintf(buf, (size_t)-1, fmt, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char _printbuf[4096];
|
||||
|
||||
int printf(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int ret = vsnprintf(_printbuf, sizeof(_printbuf), fmt, ap);
|
||||
va_end(ap);
|
||||
_zos_syscall1(SYS_PRINT, (long)_printbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int puts(const char *s) {
|
||||
_zos_syscall1(SYS_PRINT, (long)s);
|
||||
_zos_syscall1(SYS_PUTCHAR, (long)'\n');
|
||||
return 0;
|
||||
}
|
||||
|
||||
int putchar(int c) {
|
||||
_zos_syscall1(SYS_PUTCHAR, (long)c);
|
||||
return c;
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
assert.h support
|
||||
======================================================================== */
|
||||
|
||||
void __assert_fail(const char *expr, const char *file, int line, const char *func) {
|
||||
_zos_syscall1(SYS_PRINT, (long)"Assertion failed: ");
|
||||
_zos_syscall1(SYS_PRINT, (long)expr);
|
||||
_zos_syscall1(SYS_PRINT, (long)" at ");
|
||||
_zos_syscall1(SYS_PRINT, (long)file);
|
||||
_zos_syscall1(SYS_PRINT, (long)"\n");
|
||||
(void)line; (void)func;
|
||||
abort();
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,62 @@
|
||||
.TH FETCH 1
|
||||
.SH NAME
|
||||
fetch - HTTP/HTTPS client for ZenithOS
|
||||
|
||||
.SH SYNOPSIS
|
||||
fetch [-v] <url>
|
||||
fetch [-v] <host> <port> [path]
|
||||
|
||||
.SH DESCRIPTION
|
||||
fetch performs an HTTP/1.0 GET request and prints the response
|
||||
body to the terminal. Supports both plain HTTP and HTTPS (TLS 1.2)
|
||||
connections. By default only the body is printed.
|
||||
|
||||
In URL mode, the scheme (http:// or https://) determines whether
|
||||
TLS is used. The port defaults to 80 for HTTP and 443 for HTTPS.
|
||||
|
||||
In legacy mode, the host and port are specified as separate
|
||||
arguments and the connection is always plain HTTP.
|
||||
|
||||
The host may be an IP address or a hostname. Hostnames are
|
||||
resolved via the configured DNS server.
|
||||
|
||||
If no path is given, "/" is used.
|
||||
|
||||
.SH OPTIONS
|
||||
.B -v
|
||||
Verbose mode. Print connection info, trust anchor count, TLS
|
||||
handshake progress, and the HTTP status/size header before
|
||||
the body.
|
||||
|
||||
.SH EXAMPLES
|
||||
fetch https://icanhazip.com
|
||||
Print your public IP address over HTTPS.
|
||||
|
||||
fetch http://icanhazip.com
|
||||
Same, but over plain HTTP.
|
||||
|
||||
fetch -v https://example.com
|
||||
Fetch a page with verbose output showing:
|
||||
Connecting to example.com:443 (HTTPS)...
|
||||
Loaded 128 trust anchors
|
||||
TLS handshake...
|
||||
TLS connection established
|
||||
GET /
|
||||
HTTP 200 OK (1256 bytes)
|
||||
|
||||
fetch 10.0.68.1 80 /
|
||||
Fetch from a local server by IP (legacy syntax).
|
||||
|
||||
.SH TLS SUPPORT
|
||||
HTTPS connections use BearSSL for TLS 1.2. Server certificates
|
||||
are validated against the system CA bundle at
|
||||
0:/etc/ca-certificates.crt.
|
||||
|
||||
Entropy for the TLS handshake is provided by RDTSC-seeded
|
||||
random data via the SYS_GETRANDOM syscall.
|
||||
|
||||
.SH KEYBOARD
|
||||
Ctrl+Q Abort the request
|
||||
|
||||
.SH SEE ALSO
|
||||
ping(1), nslookup(1), tcpconnect(1), shell(1), syscalls(2)
|
||||
+10
-1
@@ -67,8 +67,17 @@
|
||||
}
|
||||
zenith::close(h);
|
||||
|
||||
.SH WRITING FILES
|
||||
Files can be created and written on the ramdisk:
|
||||
|
||||
.BI int zenith::fcreate(const char* path);
|
||||
.BI int zenith::fwrite(int handle, const uint8_t* buf, uint64_t offset, uint64_t size);
|
||||
|
||||
fcreate creates a new file and returns a handle. fwrite writes
|
||||
bytes at the given offset. Changes persist only until reboot --
|
||||
the ramdisk is reloaded from the USTAR archive on each boot.
|
||||
|
||||
.SH NOTES
|
||||
The filesystem is read-only. There are no write or create calls.
|
||||
All files live on the ramdisk which is loaded at boot from a
|
||||
USTAR tar archive.
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
.TH FONTSCALE 1
|
||||
.SH NAME
|
||||
fontscale - get or set terminal font scale
|
||||
|
||||
.SH SYNOPSIS
|
||||
fontscale
|
||||
fontscale <n>
|
||||
fontscale <x> <y>
|
||||
|
||||
.SH DESCRIPTION
|
||||
Controls the terminal font scale factor. The Flanterm terminal
|
||||
emulator renders text at a configurable scale multiplier.
|
||||
Increasing the scale makes text larger, which is useful on
|
||||
high-resolution displays or real hardware where text may be
|
||||
too small to read comfortably.
|
||||
|
||||
With no arguments, prints the current scale factor and terminal
|
||||
dimensions.
|
||||
|
||||
With one argument, sets both the horizontal and vertical scale
|
||||
to the same value.
|
||||
|
||||
With two arguments, sets asymmetric horizontal and vertical
|
||||
scale factors independently.
|
||||
|
||||
Valid scale values are 1 through 8. After rescaling, the screen
|
||||
is cleared.
|
||||
|
||||
.SH OUTPUT
|
||||
fontscale
|
||||
Scale: 1x1 (160 cols x 50 rows)
|
||||
|
||||
fontscale 2
|
||||
Scale set to 2x2 (80 cols x 25 rows)
|
||||
|
||||
.SH EXAMPLES
|
||||
fontscale Show current scale and dimensions
|
||||
fontscale 2 Double the font size
|
||||
fontscale 3 2 3x horizontal, 2x vertical
|
||||
fontscale 1 Reset to default size
|
||||
|
||||
.SH SEE ALSO
|
||||
shell(1), syscalls(2)
|
||||
@@ -53,6 +53,11 @@
|
||||
shell(1) Shell commands reference
|
||||
init(1) Init system
|
||||
dhcp(1) DHCP client
|
||||
fetch(1) HTTP client
|
||||
ping(1) ICMP ping
|
||||
nslookup(1) DNS lookup
|
||||
fontscale(1) Terminal font scaling
|
||||
edit(1) Text editor
|
||||
man(1) The man command itself
|
||||
legal(7) Copyright and legal information
|
||||
syscalls(2) Overview of all syscalls
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
.TH NSLOOKUP 1
|
||||
.SH NAME
|
||||
nslookup - DNS hostname lookup
|
||||
|
||||
.SH SYNOPSIS
|
||||
nslookup <hostname>
|
||||
|
||||
.SH DESCRIPTION
|
||||
Resolves a hostname to an IPv4 address using the configured
|
||||
DNS server and prints the result.
|
||||
|
||||
The kernel DNS resolver sends a UDP query to port 53 of the
|
||||
configured DNS server and waits up to 5 seconds for a reply.
|
||||
Results are cached in an 8-entry kernel cache with TTL support.
|
||||
|
||||
.SH OUTPUT
|
||||
Server: 10.0.68.1
|
||||
Name: example.com
|
||||
Address: 93.184.216.34
|
||||
Time: 3ms
|
||||
|
||||
If the lookup fails:
|
||||
|
||||
Could not resolve: badhost.invalid
|
||||
|
||||
.SH DNS CONFIGURATION
|
||||
The DNS server address is obtained automatically via DHCP.
|
||||
It can also be viewed and set with ifconfig. The default
|
||||
is 10.0.68.1 (QEMU user-mode networking).
|
||||
|
||||
.SH EXAMPLES
|
||||
nslookup google.com
|
||||
nslookup icanhazip.com
|
||||
|
||||
.SH SEE ALSO
|
||||
ping(1), fetch(1), dhcp(1), ifconfig(1), syscalls(2)
|
||||
@@ -0,0 +1,37 @@
|
||||
.TH PING 1
|
||||
.SH NAME
|
||||
ping - send ICMP echo requests
|
||||
|
||||
.SH SYNOPSIS
|
||||
ping <host>
|
||||
|
||||
.SH DESCRIPTION
|
||||
Sends 4 ICMP echo requests to the specified host and prints
|
||||
the round-trip time for each reply.
|
||||
|
||||
The host may be an IP address or a hostname. Hostnames are
|
||||
resolved via the configured DNS server.
|
||||
|
||||
Each request has a 3-second timeout. Requests are sent at
|
||||
1-second intervals.
|
||||
|
||||
.SH OUTPUT
|
||||
PING example.com (93.184.216.34)
|
||||
Reply from 93.184.216.34: time=12ms
|
||||
Reply from 93.184.216.34: time=11ms
|
||||
Reply from 93.184.216.34: time=13ms
|
||||
Reply from 93.184.216.34: time=11ms
|
||||
|
||||
If a reply is not received within the timeout:
|
||||
|
||||
Request timed out
|
||||
|
||||
.SH EXAMPLES
|
||||
ping 10.0.68.1
|
||||
Ping the gateway by IP address.
|
||||
|
||||
ping google.com
|
||||
Ping by hostname (requires DNS).
|
||||
|
||||
.SH SEE ALSO
|
||||
nslookup(1), ifconfig(1), shell(1), syscalls(2)
|
||||
@@ -61,18 +61,24 @@
|
||||
date Show current date and time
|
||||
uptime Show system uptime
|
||||
clear Clear the screen and framebuffer
|
||||
fontscale [n] Get or set terminal font scale
|
||||
reset Reboot the system
|
||||
shutdown Shut down the system
|
||||
|
||||
.SS Network commands (0:/os/)
|
||||
ping <ip> Send ICMP echo requests
|
||||
ping <host> Send ICMP echo requests
|
||||
nslookup <host> DNS lookup
|
||||
ifconfig Show/set network configuration
|
||||
tcpconnect <ip> <port> Interactive TCP client
|
||||
tcpconnect <host> <port> Interactive TCP client
|
||||
irc IRC client
|
||||
dhcp DHCP client
|
||||
fetch HTTP client
|
||||
fetch HTTP/HTTPS client (TLS 1.2)
|
||||
wiki Wikipedia article viewer
|
||||
httpd HTTP server
|
||||
|
||||
Network commands accept both IP addresses and hostnames.
|
||||
Hostnames are resolved via the configured DNS server.
|
||||
|
||||
.SS Games (0:/games/)
|
||||
doom DOOM
|
||||
|
||||
|
||||
+37
-3
@@ -3,7 +3,7 @@
|
||||
syscalls - overview of ZenithOS system calls
|
||||
|
||||
.SH DESCRIPTION
|
||||
ZenithOS provides 41 system calls (numbers 0-40) for userspace
|
||||
ZenithOS provides 46 system calls (numbers 0-45) for userspace
|
||||
programs. Syscalls use the x86-64 SYSCALL instruction with the
|
||||
following register convention:
|
||||
|
||||
@@ -121,13 +121,22 @@
|
||||
int32_t zenith::ping(uint32_t ip, uint32_t timeoutMs);
|
||||
|
||||
.B SYS_GETNETCFG (37)
|
||||
Get the current network configuration (IP, mask, gateway, MAC).
|
||||
Get the current network configuration (IP, mask, gateway, MAC,
|
||||
DNS server).
|
||||
void zenith::get_netcfg(Zenith::NetCfg* out);
|
||||
|
||||
.B SYS_SETNETCFG (38)
|
||||
Set the network configuration (IP, mask, gateway).
|
||||
Set the network configuration (IP, mask, gateway, DNS server).
|
||||
int zenith::set_netcfg(const Zenith::NetCfg* cfg);
|
||||
|
||||
.B SYS_RESOLVE (44)
|
||||
Resolve a hostname to an IPv4 address via DNS. Sends a UDP
|
||||
query to the configured DNS server and waits up to 5 seconds
|
||||
for a reply. Returns the IP in network byte order, or 0 on
|
||||
failure. IP address strings (e.g. "10.0.0.1") are detected
|
||||
and returned directly without a DNS query.
|
||||
uint32_t zenith::resolve(const char* hostname);
|
||||
|
||||
.SH SOCKETS
|
||||
.B SYS_SOCKET (29)
|
||||
Create a socket. type=SOCK_TCP (1) or SOCK_UDP (2).
|
||||
@@ -174,6 +183,17 @@
|
||||
int zenith::recvfrom(int fd, void* buf, uint32_t maxLen,
|
||||
uint32_t* srcIp, uint16_t* srcPort);
|
||||
|
||||
.SH FILE WRITE
|
||||
.B SYS_FWRITE (41)
|
||||
Write bytes to a file at a given offset.
|
||||
int zenith::fwrite(int handle, const uint8_t* buf,
|
||||
uint64_t offset, uint64_t size);
|
||||
|
||||
.B SYS_FCREATE (42)
|
||||
Create a new file on the ramdisk. Returns a handle or negative
|
||||
on error.
|
||||
int zenith::fcreate(const char* path);
|
||||
|
||||
.SH FRAMEBUFFER
|
||||
.B SYS_FBINFO (21)
|
||||
Get framebuffer dimensions and format.
|
||||
@@ -188,11 +208,25 @@
|
||||
Get terminal dimensions (columns and rows).
|
||||
void zenith::termsize(int* cols, int* rows);
|
||||
|
||||
.B SYS_TERMSCALE (43)
|
||||
Get or set the terminal font scale factor. When scale_x is 0,
|
||||
returns the current scale as (scale_y << 32 | scale_x). When
|
||||
scale_x is non-zero, sets the font scale and returns the new
|
||||
terminal dimensions as (rows << 32 | cols).
|
||||
void zenith::termscale(int scale_x, int scale_y);
|
||||
void zenith::get_termscale(int* scale_x, int* scale_y);
|
||||
|
||||
.SH ARGUMENTS
|
||||
.B SYS_GETARGS (25)
|
||||
Get the argument string passed to this process at spawn time.
|
||||
int zenith::getargs(char* buf, uint64_t maxLen);
|
||||
|
||||
.SH RANDOM
|
||||
.B SYS_GETRANDOM (45)
|
||||
Fill a buffer with random bytes using RDTSC-seeded entropy.
|
||||
Returns the number of bytes written.
|
||||
int64_t zenith::getrandom(void* buf, uint32_t len);
|
||||
|
||||
.SH POWER MANAGEMENT
|
||||
.B SYS_RESET (26)
|
||||
Reboot the system.
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
.TH TLS-ERRORS 5
|
||||
.SH NAME
|
||||
tls-errors - BearSSL TLS and X.509 error codes
|
||||
|
||||
.SH DESCRIPTION
|
||||
ZenithOS uses BearSSL for TLS 1.2 connections. When a TLS
|
||||
operation fails, an integer error code is reported. This page
|
||||
lists all possible error codes.
|
||||
|
||||
.SH SSL/TLS ENGINE ERRORS
|
||||
|
||||
.B 0 BR_ERR_OK
|
||||
No error.
|
||||
|
||||
.B 1 BR_ERR_BAD_PARAM
|
||||
Caller-provided parameter is incorrect.
|
||||
|
||||
.B 2 BR_ERR_BAD_STATE
|
||||
Operation cannot be applied in the current engine state.
|
||||
|
||||
.B 3 BR_ERR_UNSUPPORTED_VERSION
|
||||
Incoming protocol or record version is unsupported.
|
||||
|
||||
.B 4 BR_ERR_BAD_VERSION
|
||||
Incoming record version does not match the expected version.
|
||||
|
||||
.B 5 BR_ERR_BAD_LENGTH
|
||||
Incoming record length is invalid.
|
||||
|
||||
.B 6 BR_ERR_TOO_LARGE
|
||||
Incoming record is too large, or buffer is too small for the
|
||||
handshake message to send.
|
||||
|
||||
.B 7 BR_ERR_BAD_MAC
|
||||
Decryption found invalid padding, or the record MAC is
|
||||
not correct.
|
||||
|
||||
.B 8 BR_ERR_NO_RANDOM
|
||||
No initial entropy was provided and none could be obtained
|
||||
from the OS.
|
||||
|
||||
.B 9 BR_ERR_UNKNOWN_TYPE
|
||||
Incoming record type is unknown.
|
||||
|
||||
.B 10 BR_ERR_UNEXPECTED
|
||||
Incoming record or message has wrong type for the current
|
||||
engine state.
|
||||
|
||||
.B 12 BR_ERR_BAD_CCS
|
||||
ChangeCipherSpec message from the peer has invalid contents.
|
||||
|
||||
.B 13 BR_ERR_BAD_ALERT
|
||||
Alert message from the peer has invalid contents (odd length).
|
||||
|
||||
.B 14 BR_ERR_BAD_HANDSHAKE
|
||||
Incoming handshake message decoding failed.
|
||||
|
||||
.B 15 BR_ERR_OVERSIZED_ID
|
||||
ServerHello contains a session ID larger than 32 bytes.
|
||||
|
||||
.B 16 BR_ERR_BAD_CIPHER_SUITE
|
||||
Server wants to use a cipher suite that we did not advertise,
|
||||
or we tried to advertise a cipher suite that we do not support.
|
||||
|
||||
.B 17 BR_ERR_BAD_COMPRESSION
|
||||
Server wants to use a compression method that we did not
|
||||
advertise.
|
||||
|
||||
.B 18 BR_ERR_BAD_FRAGLEN
|
||||
Server's max fragment length does not match client's.
|
||||
|
||||
.B 19 BR_ERR_BAD_SECRENEG
|
||||
Secure renegotiation failed.
|
||||
|
||||
.B 20 BR_ERR_EXTRA_EXTENSION
|
||||
Server sent an extension type that we did not announce, or
|
||||
used the same extension type more than once in ServerHello.
|
||||
|
||||
.B 21 BR_ERR_BAD_SNI
|
||||
Invalid Server Name Indication contents (when used by the
|
||||
server, this extension shall be empty).
|
||||
|
||||
.B 22 BR_ERR_BAD_HELLO_DONE
|
||||
Invalid ServerHelloDone from the server (length is not 0).
|
||||
|
||||
.B 23 BR_ERR_LIMIT_EXCEEDED
|
||||
Internal limit exceeded (e.g. server's public key is too
|
||||
large).
|
||||
|
||||
.B 24 BR_ERR_BAD_FINISHED
|
||||
Finished message from peer does not match the expected value.
|
||||
|
||||
.B 25 BR_ERR_RESUME_MISMATCH
|
||||
Session resumption attempted with a different version or
|
||||
cipher suite.
|
||||
|
||||
.B 26 BR_ERR_INVALID_ALGORITHM
|
||||
Unsupported or invalid algorithm (ECDHE curve, signature
|
||||
algorithm, hash function).
|
||||
|
||||
.B 27 BR_ERR_BAD_SIGNATURE
|
||||
Invalid signature on ServerKeyExchange or CertificateVerify.
|
||||
|
||||
.B 28 BR_ERR_WRONG_KEY_USAGE
|
||||
Peer's public key does not have the proper type or is not
|
||||
allowed for the requested operation.
|
||||
|
||||
.B 29 BR_ERR_NO_CLIENT_AUTH
|
||||
Client did not send a certificate upon request, or the client
|
||||
certificate could not be validated.
|
||||
|
||||
.B 31 BR_ERR_IO
|
||||
I/O error or premature close on the underlying transport.
|
||||
|
||||
.SH X.509 CERTIFICATE ERRORS
|
||||
|
||||
.B 32 BR_ERR_X509_OK
|
||||
X.509 validation was successful (not an error).
|
||||
|
||||
.B 33 BR_ERR_X509_INVALID_VALUE
|
||||
Invalid value in an ASN.1 structure.
|
||||
|
||||
.B 34 BR_ERR_X509_TRUNCATED
|
||||
Truncated certificate.
|
||||
|
||||
.B 35 BR_ERR_X509_EMPTY_CHAIN
|
||||
Empty certificate chain (no certificate at all).
|
||||
|
||||
.B 36 BR_ERR_X509_INNER_TRUNC
|
||||
Inner element extends beyond outer element size.
|
||||
|
||||
.B 37 BR_ERR_X509_BAD_TAG_CLASS
|
||||
Unsupported tag class (application or private).
|
||||
|
||||
.B 38 BR_ERR_X509_BAD_TAG_VALUE
|
||||
Unsupported tag value.
|
||||
|
||||
.B 39 BR_ERR_X509_INDEFINITE_LENGTH
|
||||
Indefinite length encoding found.
|
||||
|
||||
.B 40 BR_ERR_X509_EXTRA_ELEMENT
|
||||
Extraneous element in certificate.
|
||||
|
||||
.B 41 BR_ERR_X509_UNEXPECTED
|
||||
Unexpected element in certificate.
|
||||
|
||||
.B 42 BR_ERR_X509_NOT_CONSTRUCTED
|
||||
Expected constructed element, but found primitive.
|
||||
|
||||
.B 43 BR_ERR_X509_NOT_PRIMITIVE
|
||||
Expected primitive element, but found constructed.
|
||||
|
||||
.B 44 BR_ERR_X509_PARTIAL_BYTE
|
||||
BIT STRING length is not a multiple of 8.
|
||||
|
||||
.B 45 BR_ERR_X509_BAD_BOOLEAN
|
||||
BOOLEAN value has invalid length.
|
||||
|
||||
.B 46 BR_ERR_X509_OVERFLOW
|
||||
Value is off-limits (overflow).
|
||||
|
||||
.B 47 BR_ERR_X509_BAD_DN
|
||||
Invalid distinguished name.
|
||||
|
||||
.B 48 BR_ERR_X509_BAD_TIME
|
||||
Invalid date/time representation in certificate.
|
||||
|
||||
.B 49 BR_ERR_X509_UNSUPPORTED
|
||||
Certificate contains unsupported features that cannot be
|
||||
ignored.
|
||||
|
||||
.B 50 BR_ERR_X509_LIMIT_EXCEEDED
|
||||
Key or signature size exceeds internal limits.
|
||||
|
||||
.B 51 BR_ERR_X509_WRONG_KEY_TYPE
|
||||
Key type does not match that which was expected.
|
||||
|
||||
.B 52 BR_ERR_X509_BAD_SIGNATURE
|
||||
Signature is invalid.
|
||||
|
||||
.B 53 BR_ERR_X509_TIME_UNKNOWN
|
||||
Validation time is unknown (no time was set).
|
||||
|
||||
.B 54 BR_ERR_X509_EXPIRED
|
||||
Certificate is expired or not yet valid.
|
||||
|
||||
.B 55 BR_ERR_X509_DN_MISMATCH
|
||||
Issuer/subject DN mismatch in the chain.
|
||||
|
||||
.B 56 BR_ERR_X509_BAD_SERVER_NAME
|
||||
Expected server name was not found in the chain.
|
||||
|
||||
.B 57 BR_ERR_X509_CRITICAL_EXTENSION
|
||||
Unknown critical extension in certificate.
|
||||
|
||||
.B 58 BR_ERR_X509_NOT_CA
|
||||
Not a CA, or path length constraint violation.
|
||||
|
||||
.B 59 BR_ERR_X509_FORBIDDEN_KEY_USAGE
|
||||
Key Usage extension prohibits the intended usage.
|
||||
|
||||
.B 60 BR_ERR_X509_WEAK_PUBLIC_KEY
|
||||
Public key found in certificate is too small.
|
||||
|
||||
.B 62 BR_ERR_X509_NOT_TRUSTED
|
||||
Chain could not be linked to a trust anchor.
|
||||
|
||||
.SH FATAL ALERTS
|
||||
When a fatal alert is received from the peer, the error code
|
||||
is 256 + the TLS alert value. When a fatal alert is sent to
|
||||
the peer, the error code is 512 + the TLS alert value.
|
||||
|
||||
Common alert values:
|
||||
0 close_notify
|
||||
10 unexpected_message
|
||||
20 bad_record_mac
|
||||
40 handshake_failure
|
||||
42 bad_certificate
|
||||
43 unsupported_certificate
|
||||
44 certificate_revoked
|
||||
45 certificate_expired
|
||||
46 certificate_unknown
|
||||
47 illegal_parameter
|
||||
48 unknown_ca
|
||||
50 decode_error
|
||||
51 decrypt_error
|
||||
70 protocol_version
|
||||
71 insufficient_security
|
||||
80 internal_error
|
||||
86 unrecognized_name
|
||||
112 no_application_protocol
|
||||
|
||||
For example, error 296 means a handshake_failure alert was
|
||||
received (256 + 40 = 296).
|
||||
|
||||
.SH SEE ALSO
|
||||
fetch(1), syscalls(2)
|
||||
@@ -0,0 +1,64 @@
|
||||
.TH WIKI 1
|
||||
.SH NAME
|
||||
wiki - Wikipedia article viewer for ZenithOS
|
||||
|
||||
.SH SYNOPSIS
|
||||
wiki <title>
|
||||
wiki -f <title>
|
||||
wiki -s <query>
|
||||
|
||||
.SH DESCRIPTION
|
||||
wiki fetches and displays Wikipedia articles in the terminal.
|
||||
It connects to en.wikipedia.org over HTTPS (TLS 1.2) and
|
||||
uses the Wikipedia REST and Action APIs to retrieve article
|
||||
content as plain text.
|
||||
|
||||
Articles are displayed in a fullscreen interactive pager with
|
||||
color-coded headings and word-wrapped text. Multi-word titles
|
||||
are accepted as separate arguments and joined automatically.
|
||||
|
||||
.SH OPTIONS
|
||||
.B -f
|
||||
Full article mode. Display the complete article text instead
|
||||
of just the summary. Section headings are color-coded.
|
||||
|
||||
.B -s
|
||||
Search mode. Search Wikipedia for articles matching the
|
||||
query and display a numbered list of up to 10 results.
|
||||
Press a number key to view that article's summary.
|
||||
|
||||
.SH EXAMPLES
|
||||
wiki Linux
|
||||
Show a summary of the Linux article.
|
||||
|
||||
wiki -f C programming language
|
||||
Show the full text of the C programming language article.
|
||||
|
||||
wiki -s operating system
|
||||
Search for articles related to "operating system".
|
||||
|
||||
.SH TLS SUPPORT
|
||||
Connections use BearSSL for TLS 1.2. Server certificates
|
||||
are validated against the system CA bundle at
|
||||
0:/etc/ca-certificates.crt.
|
||||
|
||||
.SH KEYBOARD
|
||||
|
||||
.SS Article pager
|
||||
j / Down Scroll down one line
|
||||
k / Up Scroll up one line
|
||||
Space / PgDn Scroll down one page
|
||||
b / PgUp Scroll up one page
|
||||
g / Home Jump to top
|
||||
G / End Jump to bottom
|
||||
q Quit pager
|
||||
|
||||
.SS Search results
|
||||
1-9, 0 View article (0 = result 10)
|
||||
q Quit search
|
||||
|
||||
.SS General
|
||||
Ctrl+Q Abort during network request
|
||||
|
||||
.SH SEE ALSO
|
||||
fetch(1), ping(1), nslookup(1), shell(1)
|
||||
Binary file not shown.
Binary file not shown.
@@ -463,6 +463,7 @@ extern "C" void _start() {
|
||||
newCfg.ipAddress = offer.offeredIp;
|
||||
newCfg.subnetMask = offer.subnetMask;
|
||||
newCfg.gateway = offer.router;
|
||||
newCfg.dnsServer = offer.dns;
|
||||
zenith::set_netcfg(&newCfg);
|
||||
|
||||
// 9. Print results
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
# Makefile for fetch (HTTP/HTTPS client) on ZenithOS
|
||||
# Copyright (c) 2025-2026 Daniel Hammer
|
||||
|
||||
MAKEFLAGS += -rR
|
||||
.SUFFIXES:
|
||||
|
||||
# ---- Toolchain ----
|
||||
|
||||
TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-elf-
|
||||
ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),)
|
||||
CXX := $(TOOLCHAIN_PREFIX)g++
|
||||
else
|
||||
CXX := g++
|
||||
endif
|
||||
|
||||
# ---- Paths ----
|
||||
|
||||
BEARSSL := ../../lib/bearssl
|
||||
LIBC_LIB := ../../lib/libc
|
||||
LIBC_INC := ../../include/libc
|
||||
PROG_INC := ../../include
|
||||
LINK_LD := ../../link.ld
|
||||
BINDIR := ../../bin
|
||||
OBJDIR := obj
|
||||
|
||||
# ---- Compiler flags ----
|
||||
|
||||
CXXFLAGS := \
|
||||
-std=gnu++20 \
|
||||
-g -O2 -pipe \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-unused-parameter \
|
||||
-nostdinc \
|
||||
-ffreestanding \
|
||||
-fno-stack-protector \
|
||||
-fno-stack-check \
|
||||
-fno-PIC \
|
||||
-fno-rtti \
|
||||
-fno-exceptions \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-m64 \
|
||||
-march=x86-64 \
|
||||
-mno-80387 \
|
||||
-mno-mmx \
|
||||
-mno-sse \
|
||||
-mno-sse2 \
|
||||
-mno-red-zone \
|
||||
-mcmodel=small \
|
||||
-I $(PROG_INC) \
|
||||
-isystem $(LIBC_INC) \
|
||||
-I $(BEARSSL)/inc \
|
||||
-isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \
|
||||
-isystem ../../../kernel/freestnd-cxx-hdrs/x86_64/include
|
||||
|
||||
# ---- Linker flags ----
|
||||
|
||||
LDFLAGS := \
|
||||
-nostdlib \
|
||||
-static \
|
||||
-Wl,--build-id=none \
|
||||
-Wl,--gc-sections \
|
||||
-Wl,-m,elf_x86_64 \
|
||||
-z max-page-size=0x1000 \
|
||||
-T $(LINK_LD)
|
||||
|
||||
# ---- Libraries ----
|
||||
|
||||
LIBS := $(BEARSSL)/libbearssl.a $(LIBC_LIB)/liblibc.a
|
||||
|
||||
# ---- Target ----
|
||||
|
||||
TARGET := $(BINDIR)/os/fetch.elf
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJDIR)/main.o $(LIBS) $(LINK_LD) Makefile
|
||||
mkdir -p $(BINDIR)/os
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJDIR)/main.o $(LIBS) -o $@
|
||||
|
||||
$(OBJDIR)/main.o: main.cpp Makefile
|
||||
mkdir -p $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET)
|
||||
+705
-219
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* main.cpp
|
||||
* fontscale - Change terminal font scale
|
||||
* Copyright (c) 2025-2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <zenith/syscall.h>
|
||||
#include <zenith/string.h>
|
||||
|
||||
static int atoi(const char* s) {
|
||||
int n = 0;
|
||||
while (*s >= '0' && *s <= '9') {
|
||||
n = n * 10 + (*s - '0');
|
||||
s++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void print_int(int n) {
|
||||
char buf[16];
|
||||
int i = 0;
|
||||
if (n == 0) {
|
||||
zenith::putchar('0');
|
||||
return;
|
||||
}
|
||||
while (n > 0 && i < 15) {
|
||||
buf[i++] = '0' + (n % 10);
|
||||
n /= 10;
|
||||
}
|
||||
while (i > 0) zenith::putchar(buf[--i]);
|
||||
}
|
||||
|
||||
extern "C" void _start() {
|
||||
char args[128];
|
||||
int len = zenith::getargs(args, sizeof(args));
|
||||
|
||||
if (len <= 0 || args[0] == '\0') {
|
||||
// No args: show current scale
|
||||
int sx, sy;
|
||||
zenith::get_termscale(&sx, &sy);
|
||||
int cols, rows;
|
||||
zenith::termsize(&cols, &rows);
|
||||
|
||||
zenith::print("Font scale: ");
|
||||
print_int(sx);
|
||||
zenith::print("x");
|
||||
print_int(sy);
|
||||
zenith::print(" Terminal: ");
|
||||
print_int(cols);
|
||||
zenith::print("x");
|
||||
print_int(rows);
|
||||
zenith::putchar('\n');
|
||||
zenith::exit(0);
|
||||
}
|
||||
|
||||
// Parse arguments
|
||||
const char* p = zenith::skip_spaces(args);
|
||||
int scale_x = atoi(p);
|
||||
|
||||
// Skip past first number to find optional second
|
||||
while (*p >= '0' && *p <= '9') p++;
|
||||
p = zenith::skip_spaces(p);
|
||||
int scale_y = (*p >= '1' && *p <= '8') ? atoi(p) : scale_x;
|
||||
|
||||
if (scale_x < 1 || scale_x > 8 || scale_y < 1 || scale_y > 8) {
|
||||
zenith::print("fontscale: scale must be 1-8\n");
|
||||
zenith::exit(1);
|
||||
}
|
||||
|
||||
zenith::termscale(scale_x, scale_y);
|
||||
|
||||
// Clear and show result
|
||||
zenith::print("\033[2J\033[H");
|
||||
|
||||
int cols, rows;
|
||||
zenith::termsize(&cols, &rows);
|
||||
zenith::print("Font scale set to ");
|
||||
print_int(scale_x);
|
||||
zenith::print("x");
|
||||
print_int(scale_y);
|
||||
zenith::print(" (");
|
||||
print_int(cols);
|
||||
zenith::print("x");
|
||||
print_int(rows);
|
||||
zenith::print(")\n");
|
||||
|
||||
zenith::exit(0);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* main.cpp
|
||||
* HTTP/1.0 server for ZenithOS
|
||||
* Usage: run httpd.elf [port] (default: 80)
|
||||
* Usage: httpd [port] (default: 80)
|
||||
* Serves a built-in index page and files from the VFS
|
||||
* Copyright (c) 2025-2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
@@ -81,6 +81,9 @@ extern "C" void _start() {
|
||||
zenith::print(" Gateway: ");
|
||||
print_ip(cfg.gateway);
|
||||
zenith::putchar('\n');
|
||||
zenith::print(" DNS Server: ");
|
||||
print_ip(cfg.dnsServer);
|
||||
zenith::putchar('\n');
|
||||
zenith::exit(0);
|
||||
}
|
||||
|
||||
|
||||
+15
-12
@@ -836,23 +836,26 @@ extern "C" void _start() {
|
||||
const char* arg = skip_spaces(argbuf);
|
||||
|
||||
if (*arg == '\0') {
|
||||
zenith::print("Usage: irc.elf <server_ip> <port> <nickname> [#channel]\n");
|
||||
zenith::print("Example: run irc.elf 10.0.68.1 6667 ZenithUser #general\n");
|
||||
zenith::print("Usage: irc <server> <port> <nickname> [#channel]\n");
|
||||
zenith::print("Example: irc irc.libera.chat 6667 ZenithUser #general\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse IP
|
||||
char ipStr[32];
|
||||
// Parse host (IP or hostname)
|
||||
char hostStr[128];
|
||||
int i = 0;
|
||||
while (arg[i] && arg[i] != ' ' && i < 31) { ipStr[i] = arg[i]; i++; }
|
||||
ipStr[i] = '\0';
|
||||
while (arg[i] && arg[i] != ' ' && i < 127) { hostStr[i] = arg[i]; i++; }
|
||||
hostStr[i] = '\0';
|
||||
arg = skip_spaces(arg + i);
|
||||
|
||||
if (!parse_ip(ipStr, &irc.serverIp)) {
|
||||
zenith::print("Invalid IP address: ");
|
||||
zenith::print(ipStr);
|
||||
zenith::putchar('\n');
|
||||
return;
|
||||
if (!parse_ip(hostStr, &irc.serverIp)) {
|
||||
irc.serverIp = zenith::resolve(hostStr);
|
||||
if (irc.serverIp == 0) {
|
||||
zenith::print("Could not resolve: ");
|
||||
zenith::print(hostStr);
|
||||
zenith::putchar('\n');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse port
|
||||
@@ -910,7 +913,7 @@ extern "C" void _start() {
|
||||
|
||||
// Initial draw
|
||||
msg_add("\033[1m*** ZenithOS IRC Client\033[0m");
|
||||
msg_add_fmt("*** Connecting to %s:%d as %s...", ipStr, (int)irc.serverPort, irc.nick);
|
||||
msg_add_fmt("*** Connecting to %s:%d as %s...", hostStr, (int)irc.serverPort, irc.nick);
|
||||
ui_render();
|
||||
|
||||
// Create socket and connect
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* main.cpp
|
||||
* DNS lookup utility for ZenithOS
|
||||
* Usage: nslookup <hostname>
|
||||
* Copyright (c) 2025-2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <zenith/syscall.h>
|
||||
#include <zenith/string.h>
|
||||
|
||||
using zenith::skip_spaces;
|
||||
|
||||
static void print_ip(uint32_t ip) {
|
||||
auto print_int = [](uint32_t n) {
|
||||
if (n == 0) { zenith::putchar('0'); return; }
|
||||
char buf[4];
|
||||
int i = 0;
|
||||
while (n > 0) { buf[i++] = '0' + (n % 10); n /= 10; }
|
||||
for (int j = i - 1; j >= 0; j--) zenith::putchar(buf[j]);
|
||||
};
|
||||
|
||||
print_int(ip & 0xFF);
|
||||
zenith::putchar('.');
|
||||
print_int((ip >> 8) & 0xFF);
|
||||
zenith::putchar('.');
|
||||
print_int((ip >> 16) & 0xFF);
|
||||
zenith::putchar('.');
|
||||
print_int((ip >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
extern "C" void _start() {
|
||||
char args[256];
|
||||
int len = zenith::getargs(args, sizeof(args));
|
||||
|
||||
const char* hostname = skip_spaces(args);
|
||||
if (len <= 0 || hostname[0] == '\0') {
|
||||
zenith::print("Usage: nslookup <hostname>\n");
|
||||
zenith::print("Example: nslookup example.com\n");
|
||||
zenith::exit(0);
|
||||
}
|
||||
|
||||
// Show DNS server
|
||||
Zenith::NetCfg cfg;
|
||||
zenith::get_netcfg(&cfg);
|
||||
|
||||
zenith::print("Server: ");
|
||||
print_ip(cfg.dnsServer);
|
||||
zenith::putchar('\n');
|
||||
|
||||
zenith::print("Querying ");
|
||||
zenith::print(hostname);
|
||||
zenith::print("...\n");
|
||||
|
||||
uint64_t start = zenith::get_milliseconds();
|
||||
uint32_t ip = zenith::resolve(hostname);
|
||||
uint64_t elapsed = zenith::get_milliseconds() - start;
|
||||
|
||||
if (ip == 0) {
|
||||
zenith::print("Error: could not resolve ");
|
||||
zenith::print(hostname);
|
||||
zenith::putchar('\n');
|
||||
zenith::exit(1);
|
||||
}
|
||||
|
||||
zenith::print("Name: ");
|
||||
zenith::print(hostname);
|
||||
zenith::putchar('\n');
|
||||
zenith::print("Address: ");
|
||||
print_ip(ip);
|
||||
zenith::putchar('\n');
|
||||
|
||||
// Print timing
|
||||
zenith::print("Time: ");
|
||||
char buf[20];
|
||||
int i = 0;
|
||||
uint64_t ms = elapsed;
|
||||
if (ms == 0) { buf[i++] = '0'; }
|
||||
else { while (ms > 0) { buf[i++] = '0' + (ms % 10); ms /= 10; } }
|
||||
for (int j = i - 1; j >= 0; j--) zenith::putchar(buf[j]);
|
||||
zenith::print(" ms\n");
|
||||
|
||||
zenith::exit(0);
|
||||
}
|
||||
@@ -65,21 +65,26 @@ extern "C" void _start() {
|
||||
int len = zenith::getargs(args, sizeof(args));
|
||||
|
||||
if (len <= 0 || args[0] == '\0') {
|
||||
zenith::print("Usage: ping <ip address>\n");
|
||||
zenith::print("Usage: ping <host>\n");
|
||||
zenith::exit(1);
|
||||
}
|
||||
|
||||
uint32_t ip;
|
||||
if (!parse_ip(args, &ip)) {
|
||||
zenith::print("Invalid IP address: ");
|
||||
zenith::print(args);
|
||||
zenith::putchar('\n');
|
||||
zenith::exit(1);
|
||||
ip = zenith::resolve(args);
|
||||
if (ip == 0) {
|
||||
zenith::print("Could not resolve: ");
|
||||
zenith::print(args);
|
||||
zenith::putchar('\n');
|
||||
zenith::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
zenith::print("PING ");
|
||||
zenith::print(args);
|
||||
zenith::print(" (");
|
||||
print_ip(ip);
|
||||
zenith::putchar('\n');
|
||||
zenith::print(")\n");
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int32_t rtt = zenith::ping(ip, 3000);
|
||||
|
||||
@@ -118,11 +118,13 @@ static void cmd_help() {
|
||||
zenith::print(" date Show current date and time\n");
|
||||
zenith::print(" uptime Show uptime\n");
|
||||
zenith::print(" clear Clear the screen\n");
|
||||
zenith::print(" fontscale [n] Set terminal font scale (1-8)\n");
|
||||
zenith::print(" reset Reboot the system\n");
|
||||
zenith::print(" shutdown Shut down the system\n");
|
||||
zenith::print("\n");
|
||||
zenith::print("Network commands:\n");
|
||||
zenith::print(" ping <ip> Send ICMP echo requests\n");
|
||||
zenith::print(" nslookup DNS lookup\n");
|
||||
zenith::print(" ifconfig Show/set network configuration\n");
|
||||
zenith::print(" tcpconnect Connect to a TCP server\n");
|
||||
zenith::print(" irc IRC client\n");
|
||||
|
||||
@@ -81,25 +81,28 @@ extern "C" void _start() {
|
||||
int len = zenith::getargs(args, sizeof(args));
|
||||
|
||||
if (len <= 0 || args[0] == '\0') {
|
||||
zenith::print("Usage: tcpconnect <ip> <port>\n");
|
||||
zenith::print("Usage: tcpconnect <host> <port>\n");
|
||||
zenith::exit(1);
|
||||
}
|
||||
|
||||
// Parse IP address (up to first space)
|
||||
char ipStr[32];
|
||||
// Parse host (IP or hostname)
|
||||
char hostStr[128];
|
||||
int i = 0;
|
||||
while (args[i] && args[i] != ' ' && i < 31) {
|
||||
ipStr[i] = args[i];
|
||||
while (args[i] && args[i] != ' ' && i < 127) {
|
||||
hostStr[i] = args[i];
|
||||
i++;
|
||||
}
|
||||
ipStr[i] = '\0';
|
||||
hostStr[i] = '\0';
|
||||
|
||||
uint32_t ip;
|
||||
if (!parse_ip(ipStr, &ip)) {
|
||||
zenith::print("Invalid IP address: ");
|
||||
zenith::print(ipStr);
|
||||
zenith::putchar('\n');
|
||||
zenith::exit(1);
|
||||
if (!parse_ip(hostStr, &ip)) {
|
||||
ip = zenith::resolve(hostStr);
|
||||
if (ip == 0) {
|
||||
zenith::print("Could not resolve: ");
|
||||
zenith::print(hostStr);
|
||||
zenith::putchar('\n');
|
||||
zenith::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse port
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
# Makefile for wiki (Wikipedia client) on ZenithOS
|
||||
# Copyright (c) 2025-2026 Daniel Hammer
|
||||
|
||||
MAKEFLAGS += -rR
|
||||
.SUFFIXES:
|
||||
|
||||
# ---- Toolchain ----
|
||||
|
||||
TOOLCHAIN_PREFIX := $(shell cd ../../.. && pwd)/toolchain/local/bin/x86_64-elf-
|
||||
ifneq ($(wildcard $(TOOLCHAIN_PREFIX)gcc),)
|
||||
CXX := $(TOOLCHAIN_PREFIX)g++
|
||||
else
|
||||
CXX := g++
|
||||
endif
|
||||
|
||||
# ---- Paths ----
|
||||
|
||||
BEARSSL := ../../lib/bearssl
|
||||
LIBC_LIB := ../../lib/libc
|
||||
LIBC_INC := ../../include/libc
|
||||
PROG_INC := ../../include
|
||||
LINK_LD := ../../link.ld
|
||||
BINDIR := ../../bin
|
||||
OBJDIR := obj
|
||||
|
||||
# ---- Compiler flags ----
|
||||
|
||||
CXXFLAGS := \
|
||||
-std=gnu++20 \
|
||||
-g -O2 -pipe \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Wno-unused-parameter \
|
||||
-nostdinc \
|
||||
-ffreestanding \
|
||||
-fno-stack-protector \
|
||||
-fno-stack-check \
|
||||
-fno-PIC \
|
||||
-fno-rtti \
|
||||
-fno-exceptions \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-m64 \
|
||||
-march=x86-64 \
|
||||
-mno-80387 \
|
||||
-mno-mmx \
|
||||
-mno-sse \
|
||||
-mno-sse2 \
|
||||
-mno-red-zone \
|
||||
-mcmodel=small \
|
||||
-I $(PROG_INC) \
|
||||
-isystem $(LIBC_INC) \
|
||||
-I $(BEARSSL)/inc \
|
||||
-isystem ../../../kernel/freestnd-c-hdrs/x86_64/include \
|
||||
-isystem ../../../kernel/freestnd-cxx-hdrs/x86_64/include
|
||||
|
||||
# ---- Linker flags ----
|
||||
|
||||
LDFLAGS := \
|
||||
-nostdlib \
|
||||
-static \
|
||||
-Wl,--build-id=none \
|
||||
-Wl,--gc-sections \
|
||||
-Wl,-m,elf_x86_64 \
|
||||
-z max-page-size=0x1000 \
|
||||
-T $(LINK_LD)
|
||||
|
||||
# ---- Libraries ----
|
||||
|
||||
LIBS := $(BEARSSL)/libbearssl.a $(LIBC_LIB)/liblibc.a
|
||||
|
||||
# ---- Target ----
|
||||
|
||||
TARGET := $(BINDIR)/os/wiki.elf
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(OBJDIR)/main.o $(LIBS) $(LINK_LD) Makefile
|
||||
mkdir -p $(BINDIR)/os
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJDIR)/main.o $(LIBS) -o $@
|
||||
|
||||
$(OBJDIR)/main.o: main.cpp Makefile
|
||||
mkdir -p $(OBJDIR)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET)
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Reference in New Issue
Block a user