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) install(TARGETS ${APP_NAME} DESTINATION ${LUNA_ROOT}/initrd/bin)
endfunction() endfunction()
luna_app(app.c app) luna_app(init.c init)
luna_app(hello.c hello) 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() 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 {}; return {};
} }

View File

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

View File

@ -16,7 +16,9 @@ typedef struct
#define EOF -1 #define EOF -1
extern FILE* stdout;
extern FILE* stderr; extern FILE* stderr;
#define stdout stdout
#define stderr stderr #define stderr stderr
#ifdef __cplusplus #ifdef __cplusplus
@ -29,6 +31,9 @@ extern "C"
/* Open a file and binds a stream to it. */ /* Open a file and binds a stream to it. */
FILE* fopen(const char* path, const char* mode); 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. */ /* Close a file and frees up its stream. */
int fclose(FILE* stream); int fclose(FILE* stream);
@ -62,6 +67,18 @@ extern "C"
/* Return whether the end-of-file indicator was set in stream. */ /* Return whether the end-of-file indicator was set in stream. */
int feof(FILE* 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. */ /* Clear the error and end-of-file indicators in stream. */
void clearerr(FILE* stream); void clearerr(FILE* stream);

View File

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

View File

@ -2,6 +2,7 @@
.global _start .global _start
.extern exit .extern exit
.extern libc_init
_start: _start:
# Set up end of the stack frame linked list. # Set up end of the stack frame linked list.
movq $0, %rbp movq $0, %rbp
@ -9,6 +10,8 @@ _start:
pushq %rbp # rbp=0 pushq %rbp # rbp=0
movq %rsp, %rbp movq %rsp, %rbp
call libc_init
# Run the global constructors. # Run the global constructors.
call _init 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> #include <unistd.h>
FILE* stderr = nullptr; FILE* stderr = nullptr;
FILE* stdout = nullptr;
static int fopen_parse_mode(const char* mode) static int fopen_parse_mode(const char* mode)
{ {
@ -41,13 +42,13 @@ extern "C"
if ((flags = fopen_parse_mode(mode)) < 0) return nullptr; 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)); 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; return nullptr;
} }
@ -57,6 +58,25 @@ extern "C"
return f; 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) int fclose(FILE* stream)
{ {
if (close(stream->_fd) < 0) return EOF; if (close(stream->_fd) < 0) return EOF;
@ -148,6 +168,30 @@ extern "C"
return stream->_eof; 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) void clearerr(FILE* stream)
{ {
stream->_eof = stream->_err = 0; stream->_eof = stream->_err = 0;