Compare commits

..

4 Commits

13 changed files with 182 additions and 81 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");
fprintf(stderr, "init is running as PID %d\n", getpid());
}

View File

@ -14,6 +14,6 @@ Result<usize> ConsoleDevice::read(u8*, usize, usize) const
Result<usize> ConsoleDevice::write(const u8* buf, usize, usize length)
{
TextConsole::print((const char*)buf);
TextConsole::write((const char*)buf, length);
return length;
}

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

@ -172,6 +172,12 @@ namespace TextConsole
return {};
}
Result<void> write(const char* str, usize len)
{
while (len--) TRY(putchar(*str++));
return {};
}
void wprint(const wchar_t* str)
{
while (*str) putwchar(*str++);

View File

@ -14,6 +14,7 @@ namespace TextConsole
u32 background();
void move_to(u32 x, u32 y);
Result<void> print(const char* str);
Result<void> write(const char* str, usize len);
void wprint(const wchar_t* str);
Result<void> println(const char* str);
void wprintln(const wchar_t* str);

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,13 +67,28 @@ 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);
void setbuf(FILE*, char*);
int fprintf(FILE*, const char*, ...);
int vfprintf(FILE*, const char*, va_list);
/* Write formatted output to a file. */
int fprintf(FILE* stream, const char* format, ...);
/* Write formatted output to a file. */
int vfprintf(FILE* stream, const char* format, va_list ap);
/* Write formatted output into a buffer. */
int sprintf(char* buf, const char* format, ...);
@ -82,15 +102,15 @@ extern "C"
/* Write up to max bytes of formatted output into a buffer. */
int vsnprintf(char*, size_t, const char*, va_list);
/* Write formatted output to standard output. */
int vprintf(const char*, va_list ap);
/* Write formatted output to standard output. */
int printf(const char*, ...);
/* Write a string followed by a newline to standard output. */
int puts(const char* s);
/* Output a message to the console. */
int console_write(const char* msg, size_t size);
/* Write an error message to standard error. */
void perror(const char* s);

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)
{
@ -29,25 +30,19 @@ static int fopen_parse_mode(const char* mode)
extern "C"
{
int console_write(const char* str, size_t size)
{
long rc = syscall(SYS_console_write, str, size);
__errno_return(rc, int);
}
FILE* fopen(const char* path, const char* mode)
{
int flags;
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 +52,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 +162,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;
@ -187,19 +225,46 @@ extern "C"
return rc;
}
int vfprintf(FILE* stream, const char* format, va_list ap)
{
usize rc = cstyle_format(
format,
[](char c, void* f) -> Result<void> {
int rc = fputc(c, (FILE*)f);
if (rc == EOF) return err(errno);
return {};
},
stream, ap)
.value_or(-1);
if (rc == (usize)-1) return -1;
return (int)rc;
}
int fprintf(FILE* stream, const char* format, ...)
{
va_list ap;
va_start(ap, format);
int rc = vfprintf(stream, format, ap);
va_end(ap);
return rc;
}
int vprintf(const char* format, va_list ap)
{
return vfprintf(stdout, format, ap);
}
int printf(const char* format, ...)
{
va_list ap;
va_start(ap, format);
int rc = (int)cstyle_format(
format,
[](char c, void*) -> Result<void> {
console_write(&c, 1);
return {};
},
nullptr, ap)
.value();
int rc = vfprintf(stdout, format, ap);
va_end(ap);
@ -208,30 +273,22 @@ extern "C"
int puts(const char* s)
{
if (console_write(s, strlen(s)) < 0) return -1;
if (console_write("\n", 1) < 0) return -1;
if (fputs(s, stdout) < 0) return -1;
if (putchar('\n') == EOF) return -1;
return 0;
}
void perror(const char* s)
{
// FIXME: Output to stderr when available.
int err = errno;
if (s && *s) printf("%s: ", s);
printf("%s\n", strerror(err));
if (s && *s) fprintf(stderr, "%s: ", s);
fprintf(stderr, "%s\n", strerror(err));
}
}
void debug_log_impl(const char* format, va_list ap)
{
cstyle_format(
format,
[](char c, void*) -> Result<void> {
console_write(&c, 1);
return {};
},
nullptr, ap)
.value();
console_write("\n", 1);
vfprintf(stderr, format, ap);
fputc('\n', stderr);
}