os

An operating system
git clone https://erai.gay/code/os/
Log | Files | Refs | README | LICENSE

commit 7158f14634b5d398161e7ec21cbc89364a33f557
parent 88ed74024c05650adefa7cef20a66ae775ee3348
Author: erai <erai@omiltem.net>
Date:   Sun, 26 May 2024 11:22:36 -0400

basic commands

Diffstat:
Mas.c | 2+-
Mbootstrap.sh | 65++++++++++++++++++++++++++++++-----------------------------------
Mbufio.c | 39+++++++++++++++++++++++++++++++++++++++
Mcmp.c | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcpio.c | 211+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mecho.c | 16++++++++++++++++
Ainit | 2++
Mls.c | 39+++++++++++++++++++++++++++++++++++++++
Mpxe.sh | 18+++++-------------
Mrm.c | 11+++++++++++
Msshd.c | 1-
Msyscall.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mwatch.sh | 10++++------
13 files changed, 473 insertions(+), 56 deletions(-)

diff --git a/as.c b/as.c @@ -195,7 +195,7 @@ open_output(c: *assembler, filename: *byte) { unlink(filename); - fd = open(filename, 64 + 1, (7 << 6) + (7 << 3) +7); + fd = open(filename, O_CREAT | O_WRONLY, (7 << 6) + (7 << 3) +7); if (fd < 0) { die("failed to open output"); } diff --git a/bootstrap.sh b/bootstrap.sh @@ -1,45 +1,40 @@ -#!/bin/bash - -set -ue +#!/bin/sh LIBS="bufio.c lib.c alloc.c syscall.c" -SOURCES="cc1.c type.c parse1.c lex1.c as.c ${LIBS}" -GENLEX_SOURCES="genlex.c ${LIBS}" +SOURCES="cc1.c type.c parse1.c lex1.c as.c $LIBS" +GENLEX_SOURCES="genlex.c $LIBS" -if [ -e cc1 ]; then - ./cc1 ${SOURCES} -o cc0 -else - gcc -Wall -Wextra -Wno-unused -pedantic -std=c99 ./cc0.c -o cc0 || { rm -f cc0; echo bootstrap failed; exit 1; } -fi +./cc1 $SOURCES -o cc0 || gcc -Wall -Wextra -Wno-unused -pedantic -std=c99 ./cc0.c -o cc0 || exit 1 -./cc0 ${SOURCES} -o cc1 || { rm -f cc1; echo cc0 failed; exit 1; } +./cc0 $SOURCES -o cc1 || exit 1 -./cc1 ${SOURCES} -o cc2 || { rm -f cc2; echo cc1 failed; exit 1; } +./cc1 ${SOURCES} -o cc2 || exit 1 -cmp cc1 cc2 || { echo output mismatch; exit 1; } +cmp cc1 cc2 || echo mismatch -./cc1 ${GENLEX_SOURCES} -o genlex || { rm -f genlex; echo cc1 failed; exit 1; } -./genlex < cc3.l > lex3.c || { rm -f lex3.c; echo genlex failed; exit 1; } +./cc1 ${GENLEX_SOURCES} -o genlex || exit 1 +./genlex < cc3.l > lex3.c || exit 1 -./cc1 ${LIBS} echo.c -o echo || { rm -f echo; echo echo failed; exit 1; } -./cc1 ${LIBS} cmp.c -o cmp || { rm -f cmp; echo cmp failed; exit 1; } -./cc1 ${LIBS} rm.c -o rm || { rm -f rm; echo rm failed; exit 1; } -./cc1 ${LIBS} ls.c -o ls || { rm -f ls; echo ls failed; exit 1; } -./cc1 ${LIBS} cpio.c -o cpio || { rm -f cpio; echo cpio failed; exit 1; } -./cc1 ${LIBS} sh.c -o sh || { rm -f sh; echo sh failed; exit 1; } -./cc1 ${LIBS} sshd.c -o sshd || { rm -f sshd; echo sshd failed; exit 1; } -./cc1 ${LIBS} vi.c -o vi || { rm -f vi; echo vi failed; exit 1; } +./cc1 ${LIBS} echo.c -o echo || exit 1 +./cc1 ${LIBS} cmp.c -o cmp || exit 1 +./cc1 ${LIBS} rm.c -o rm || exit 1 +./cc1 ${LIBS} ls.c -o ls || exit 1 +./cc1 ${LIBS} cpio.c -o cpio || exit 1 +./cc1 ${LIBS} sh.c -o sh || exit 1 +./cc1 ${LIBS} sshd.c -o sshd || exit 1 +./cc1 ${LIBS} vi.c -o vi || exit 1 { - echo echo - echo cmp - echo rm - echo ls - echo cpio - echo sh - echo sshd - echo vi - echo cc1 -} | ./cpio > initramfs || { rm -f initramfs; echo initramfs failed; exit 1; } - -./cc1 kernel.c -o kernel + ./echo echo + ./echo cmp + ./echo rm + ./echo ls + ./echo cpio + ./echo sh + ./echo vi + ./echo sshd + ./echo init + ./echo cc1 +} | ./cpio -o > initramfs || exit 1 + +./cc1 kernel.c -o kernel || exit 1 diff --git a/bufio.c b/bufio.c @@ -114,3 +114,42 @@ fgetc(f: *file): int { return ch; } + +fgets(f: *file, buf: *byte, len: int): int { + var i: int; + var c: int; + + if len == 1 { + buf[0] = 0:byte; + return 0; + } + + i = 0; + loop { + if i + 1 == len { + buf[i] = 0:byte; + return i; + } + + c = fgetc(f); + if c == -1 || c == '\n' { + buf[i] = 0:byte; + return i; + } + + buf[i] = c:byte; + i = i + 1; + } +} + +fputs(f: *file, s: *byte) { + var i: int; + i = 0; + loop { + if !s[i] { + break; + } + fputc(f, s[i]:int); + i = i + 1; + } +} diff --git a/cmp.c b/cmp.c @@ -1,2 +1,56 @@ main(argc: int, argv: **byte, envp: **byte) { + var a: int; + var b: int; + var alloc: alloc; + var fa: *file; + var fb: *file; + var c: int; + var i: int; + + setup_alloc(&alloc); + + if argc != 3 { + die("usage: cmp file1 file2"); + } + + a = open(argv[1], 0, 0); + if a < 0 { + fdputs(1, "failed to open: "); + fdputs(1, argv[1]); + fdputs(1, "\n"); + exit(2); + } + + b = open(argv[2], 0, 0); + if b < 0 { + fdputs(1, "failed to open: "); + fdputs(1, argv[2]); + fdputs(1, "\n"); + exit(2); + } + + fa = fopen(a, &alloc); + fb = fopen(b, &alloc); + + i = 0; + loop { + c = fgetc(fa); + + if c != fgetc(fb) { + fdputs(1, argv[1]); + fdputc(1, ' '); + fdputs(1, argv[2]); + fdputc(1, ' '); + fdputs(1, "differ: byte "); + fdputd(1, i); + fdputc(1, '\n'); + exit(1); + } + + if c == -1 { + break; + } + + i = i + 1; + } } diff --git a/cpio.c b/cpio.c @@ -1,2 +1,213 @@ +struct stat { + dev: int; + ino: int; + nlink: int; + uid_mode: int; + gid: int; + rdev: int; + size: int; + blksize: int; + blocks: int; + atime: int; + atime_nsec: int; + mtime: int; + mtime_nsec: int; + ctime: int; + ctime_nsec: int; + pad0: int; + pad1: int; + pad2: int; +} + main(argc: int, argv: **byte, envp: **byte) { + var opts: int; + var i: int; + var a: alloc; + var fd: int; + var name: *byte; + var stdin: *file; + var stdout: *file; + var stat: stat; + var buf: *byte; + var len: int; + var n: int; + var m: int; + var k: int; + var ret: int; + + setup_alloc(&a); + + i = 1; + loop { + if i >= argc { + break; + } + + if !strcmp(argv[i], "-o") { + opts = opts | 1; + } else { + die("invalid argument"); + } + + i = i + 1; + } + + stdin = fopen(0, &a); + stdout = fopen(1, &a); + + name = alloc(&a, 4096); + buf = alloc(&a, 4096); + + loop { + if stdin.eof { + break; + } + + len = fgets(stdin, name, 4096); + if len == 0 { + continue; + } + + if len == 4096 { + fflush(stdout); + fdputs(2, "name truncated: "); + fdputs(2, name); + fdputs(2, "\n"); + exit(1); + } + + fd = open(name, 0, 0); + if fd < 0 { + fflush(stdout); + fdputs(2, "failed to open: "); + fdputs(2, name); + fdputs(2, "\n"); + exit(1); + } + + if fstat(fd, (&stat):*byte) < 0 { + fflush(stdout); + fdputs(2, "stat failed: "); + fdputs(2, name); + fdputs(2, "\n"); + exit(1); + } + + // header + fputs(stdout, "070701"); + fputh(stdout, stat.ino); + fputh(stdout, stat.uid_mode & (-1 >> 32)); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, stat.nlink); + fputh(stdout, stat.mtime); + fputh(stdout, stat.size); + fputh(stdout, stat.dev >> 8); + fputh(stdout, stat.dev & 255); + fputh(stdout, stat.rdev >> 8); + fputh(stdout, (stat.rdev) & 255); + fputh(stdout, len + 1); + fputh(stdout, 0); + + fputs(stdout, name); + fputc(stdout, 0); + + // align to four bytes + falign(stdout, len + 3); + fflush(stdout); + + // copy data + n = 0; + loop { + if n == stat.size { + break; + } + + k = read(fd, buf, 4096); + if k <= 0 { + die("failed to read"); + } + + if n + k > stat.size { + k = stat.size - n; + } + + m = 0; + loop { + if m == k { + break; + } + + ret = write(1, &buf[m], k - m); + if ret < 0 { + die("failed to write"); + } + + m = m + ret; + } + + n = n + k; + } + + // align to four bytes + falign(stdout, stat.size); + fflush(stdout); + + close(fd); + } + + // trailer + fputs(stdout, "070701"); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, 0); + fputh(stdout, 11); + fputh(stdout, 0); + fputs(stdout, "TRAILER!!!"); + fputc(stdout, 0); + falign(stdout, 13); + + fflush(stdout); +} + +fputh(f: *file, x: int) { + var i: int; + + if x > (-1 >> 32) { + fflush(f); + die("too large"); + } + + i = 32; + loop { + if i == 0 { + break; + } + + i = i - 4; + + fputc(f, "0123456789abcdef"[(x >> i) & 15]:int); + } +} + +falign(f: *file, n: int) { + var len: int; + len = (4 - (n & 3)) & 3; + loop { + if len == 0 { + break; + } + + fputc(f, 0); + + len = len - 1; + } } diff --git a/echo.c b/echo.c @@ -1,2 +1,18 @@ main(argc: int, argv: **byte, envp: **byte) { + var i: int; + i = 1; + loop { + if i >= argc { + fdputc(1, '\n'); + return; + } + + fdputs(1, argv[i]); + + i = i + 1; + + if i < argc { + fdputc(1, ' '); + } + } } diff --git a/init b/init @@ -0,0 +1,2 @@ +#!/sh +/sshd diff --git a/ls.c b/ls.c @@ -1,2 +1,41 @@ main(argc: int, argv: **byte, envp: **byte) { + var fd: int; + var i: int; + var n: int; + var len: int; + var a: alloc; + var buf: *byte; + + setup_alloc(&a); + + fd = open(".", O_DIRECTORY, 0); + if fd < 0 { + exit(1); + } + + buf = alloc(&a, 4096); + + loop { + n = getdirents(fd, buf, 4096); + if n == 0 { + break; + } + + if n < 0 { + die("getdirents failed"); + } + + loop { + if i + 20 >= n { + break; + } + + fdputs(1, &buf[i + 19]); + fdputc(1, ' '); + + i = i + ((&buf[i + 16]):*int[0] & 0xffff); + } + } + + fdputc(1, '\n'); } diff --git a/pxe.sh b/pxe.sh @@ -1,13 +1,5 @@ -#!/bin/bash - -set -ue - -exec 3<>/dev/ttyACM0 - -./bootstrap.sh - -nasm -f bin pxe.asm - -cp kernel pxe /srv/tftp/ - -printf r >&3 +#!/bin/sh +./bootstrap.sh || exit 1 +nasm -f bin pxe.asm || exit 1 +cp kernel pxe /srv/tftp/ || exit 1 +printf r > /dev/ttyACM0 || exit 1 diff --git a/rm.c b/rm.c @@ -1,2 +1,13 @@ main(argc: int, argv: **byte, envp: **byte) { + var i: int; + i = 1; + loop { + if i >= argc { + return; + } + + unlink(argv[i]); + + i = i + 1; + } } diff --git a/sshd.c b/sshd.c @@ -98,7 +98,6 @@ //<- //SSH_MSG_USERAUTH_PK_OK - _rdrand(): int; main(argc: int, argv: **byte, envp: **byte) { exit(_rdrand()); diff --git a/syscall.c b/syscall.c @@ -1,5 +1,15 @@ syscall(n: int, a1: int, a2: int, a3: int, a4: int, a5: int, a6: int): int; +enum { + O_RDONLY = 0, + O_WRONLY = 1, + O_RDWR = 2, + O_CREAT = 64, + O_TRUNC = 0x200, + O_APPEND = 0x400, + O_DIRECTORY = 0x1000, +} + _start(argc: int, argv: **byte, envp: **byte) { main(argc, argv, envp); exit(0); @@ -21,14 +31,65 @@ close(fd: int): int { return syscall(3, fd, 0, 0, 0, 0, 0); } +fstat(fd: int, buf: *byte): int { + return syscall(5, fd, buf:int, 0, 0, 0, 0); +} + mmap(addr: int, len: int, prot: int, flags: int, fd: int, off: int): int { return syscall(9, addr, len, prot, flags, fd, off); } +pipe(fd: *int): int { + var buf: int; + var ret: int; + ret = syscall(22, (&buf):int, 0, 0, 0, 0, 0); + if ret == 0 { + fd[0] = buf & (-1 >> 32); + fd[1] = buf >> 32; + } + return ret; +} + +dup2(old: int, new: int): int { + return syscall(33, old, new, 0, 0, 0, 0); +} + +socket(pf: int, ty: int, pc: int): int { + return syscall(41, pf, ty, pc, 0, 0, 0); +} + +accept(fd: int): int { + return syscall(43, fd, 0, 0, 0, 0, 0); +} + +bind(fd: int, addr: *byte, len: int): int { + return syscall(49, fd, addr:int, len:int, 0, 0, 0); +} + +listen(fd: int, backlog: int): int { + return syscall(50, fd, backlog, 0, 0, 0, 0); +} + +fork(): int { + return syscall(57, 0, 0, 0, 0, 0, 0); +} + +exec(cmd: *byte, argv: **byte, envp: **byte): int { + return syscall(59, cmd:int, argv:int, envp:int, 0, 0, 0); +} + exit(n: int) { syscall(60, n, 0, 0, 0, 0, 0); } +wait(pid: int, status: *int, flags: int): int { + return syscall(61, pid, status:int, flags, 0, 0, 0); +} + unlink(name: *byte): int { return syscall(87, name: int, 0, 0, 0, 0, 0); } + +getdirents(fd: int, buf: *byte, len: int): int { + return syscall(217, fd, buf:int, len, 0, 0, 0); +} diff --git a/watch.sh b/watch.sh @@ -1,8 +1,6 @@ -#!/bin/bash +#!/bin/sh clear -cmd="${1:-./pxe.sh}" -shift -"${cmd}" "$@" -date +./pxe.sh +echo status $? : < ~/.post -exec "$0" "$@" +exec "$0"