libc: Start switching to /dev/console for console IO and add a proper init

This commit is contained in:
apio 2023-03-18 19:23:18 +01:00
parent 8c831a6906
commit 629ed9e43b
Signed by: apio
GPG Key ID: B8A7D06E42258954
10 changed files with 125 additions and 47 deletions

View File

@ -6,5 +6,5 @@ function(luna_app SOURCE_FILE APP_NAME)
install(TARGETS ${APP_NAME} DESTINATION ${LUNA_ROOT}/initrd/bin)
endfunction()
luna_app(app.c app)
luna_app(init.c init)
luna_app(hello.c hello)

View File

@ -1,39 +0,0 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
void bye()
{
printf("byeee!\n");
}
int main()
{
atexit(bye);
printf("Welcome to %s from userspace (pid %d)!\n", "Luna", getpid());
FILE* f = fopen("/etc/motd", "r");
if (!f)
{
perror("fopen");
return 1;
}
char buffer[512];
size_t nread = fread(buffer, 1, sizeof(buffer), f);
buffer[nread] = 0;
printf("/etc/motd says: %s", buffer);
fclose(f);
time_t now = time(NULL);
printf("date: %s", ctime(&now));
// FIXME: Add libc wrapper.
syscall(SYS_exec, "/bin/hello");
}

38
apps/init.c Normal file
View File

@ -0,0 +1,38 @@
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <unistd.h>
#define xmknod(path, mode, maj, min) \
if (mknod(path, mode, makedev(maj, min)) < 0) exit(255);
// Too early for console logs (/dev/console is created here!), so we have to resort to exiting with a weird exit code in
// case of failure.
static void populate_devfs()
{
if (mkdir("/dev", 0755) < 0 && errno != EEXIST) exit(255);
xmknod("/dev/console", 0666, 1, 0);
xmknod("/dev/null", 0666, 2, 0);
}
int main()
{
if (getpid() != 1)
{
printf("error: init not running as PID 1.\n");
return 1;
}
populate_devfs();
// Before this point, we don't even have an stdout and stderr. Set it up now so that child processes (and us) can
// print stuff.
stdout = fopen("/dev/console", "w");
stderr = fopen("/dev/console", "w");
fputs("Hello, world!", stderr);
}

View File

@ -66,9 +66,9 @@ static void init_vfs()
static Result<void> try_init_userspace()
{
auto app = TRY(VFS::resolve_path("/bin/app"));
auto init = TRY(VFS::resolve_path("/bin/init"));
TRY(Scheduler::new_userspace_thread(app));
TRY(Scheduler::new_userspace_thread(init));
return {};
}

View File

@ -12,6 +12,7 @@ set(SOURCES
src/atexit.cpp
src/ctype.cpp
src/time.cpp
src/init.cpp
src/sys/stat.cpp
src/sys/mman.cpp
)

View File

@ -16,7 +16,9 @@ typedef struct
#define EOF -1
extern FILE* stdout;
extern FILE* stderr;
#define stdout stdout
#define stderr stderr
#ifdef __cplusplus
@ -29,6 +31,9 @@ extern "C"
/* Open a file and binds a stream to it. */
FILE* fopen(const char* path, const char* mode);
/* Bind a stream to a file descriptor. */
FILE* fdopen(int fd, const char* mode);
/* Close a file and frees up its stream. */
int fclose(FILE* stream);
@ -62,6 +67,18 @@ extern "C"
/* Return whether the end-of-file indicator was set in stream. */
int feof(FILE* stream);
/* Write a character to stream. */
int fputc(int c, FILE* stream);
/* Write a character to stream. */
int putc(int c, FILE* stream);
/* Write a character to standard output. */
int putchar(int c);
/* Write a string to stream. */
int fputs(const char* str, FILE* stream);
/* Clear the error and end-of-file indicators in stream. */
void clearerr(FILE* stream);

View File

@ -10,6 +10,9 @@
#include <stdint.h>
#include <sys/types.h>
#define STDOUT_FILENO 0
#define STDERR_FILENO 1
#ifdef __cplusplus
extern "C"
{

View File

@ -2,6 +2,7 @@
.global _start
.extern exit
.extern libc_init
_start:
# Set up end of the stack frame linked list.
movq $0, %rbp
@ -9,6 +10,8 @@ _start:
pushq %rbp # rbp=0
movq %rsp, %rbp
call libc_init
# Run the global constructors.
call _init

11
libc/src/init.cpp Normal file
View File

@ -0,0 +1,11 @@
#include <stdio.h>
#include <unistd.h>
extern "C"
{
void libc_init()
{
stdout = fdopen(STDOUT_FILENO, "w");
stderr = fdopen(STDERR_FILENO, "w");
}
}

View File

@ -9,6 +9,7 @@
#include <unistd.h>
FILE* stderr = nullptr;
FILE* stdout = nullptr;
static int fopen_parse_mode(const char* mode)
{
@ -41,13 +42,13 @@ extern "C"
if ((flags = fopen_parse_mode(mode)) < 0) return nullptr;
int fd = open(path, flags, 0666);
if (fd < 0) return nullptr;
FILE* f = (FILE*)malloc(sizeof(FILE));
if (!f)
if (!f) { return nullptr; }
int fd = open(path, flags, 0666);
if (fd < 0)
{
close(fd);
free(f);
return nullptr;
}
@ -57,6 +58,25 @@ extern "C"
return f;
}
FILE* fdopen(int fd, const char* mode)
{
int flags;
if ((flags = fopen_parse_mode(mode)) < 0) return nullptr;
// FIXME: We do verify that fd is valid, but not that the mode is compatible.
long rc = lseek(fd, 0, SEEK_CUR);
if (rc < 0) return nullptr;
FILE* f = (FILE*)malloc(sizeof(FILE));
if (!f) { return nullptr; }
f->_fd = fd;
clearerr(f);
return f;
}
int fclose(FILE* stream)
{
if (close(stream->_fd) < 0) return EOF;
@ -148,6 +168,30 @@ extern "C"
return stream->_eof;
}
int fputc(int c, FILE* stream)
{
u8 value = (u8)c;
ssize_t rc = write(stream->_fd, &value, 1);
if (rc <= 0) return EOF;
return c;
}
int putc(int c, FILE* stream)
{
return fputc(c, stream);
}
int putchar(int c)
{
return fputc(c, stdout);
}
int fputs(const char* str, FILE* stream)
{
ssize_t rc = write(stream->_fd, str, strlen(str));
return (rc < 0) ? -1 : 0;
}
void clearerr(FILE* stream)
{
stream->_eof = stream->_err = 0;