whiterose

linux unikernel
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/whiterose

commit 089d7103cd32a685355edce80e1b6abb1393f71e
parent 7dc5e716dcb08abc6b593bb4b3ae5531feaa7396
Author: Louis Solofrizzo <lsolofrizzo@online.net>
Date:   Tue, 23 Apr 2019 17:38:00 +0200

ukl: basic stdio library and lseek, readv and writev

First of all, this patches introduces three new syscalls in UKL: lseek,
readv and writev. All three are needed to implement the following stdio
functions:
- fopen
- fwrite
- fread
- fputs
- fclose
- fflush
- fseek

It is worth noting that, at the moment, none of the stdio API is thread
safe. I've also added wrappers for stdin, stdout and stderr in order to
be compliant with libc behavior.

Signed-off-by: Louis Solofrizzo <lsolofrizzo@online.net>

Diffstat:
Mfs/read_write.c | 4++--
Ainclude/ukl/stdio.h | 31+++++++++++++++++++++++++++++++
Ainclude/ukl/sys/uio.h | 9+++++++++
Minclude/ukl/ukl_internals.h | 2+-
Minclude/ukl/unistd.h | 1+
Mukl/Makefile | 2+-
Mukl/TO_PORT | 3---
Aukl/fcntl/Makefile | 1+
Mukl/fcntl/fcntl.c | 7-------
Mukl/fcntl/open.c | 24+++++++++++++++++-------
Aukl/stdio/Makefile | 1+
Aukl/stdio/__internals.c | 179+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aukl/stdio/fclose.c | 15+++++++++++++++
Aukl/stdio/fflush.c | 23+++++++++++++++++++++++
Aukl/stdio/fopen.c | 32++++++++++++++++++++++++++++++++
Aukl/stdio/fputs.c | 10++++++++++
Aukl/stdio/fread.c | 33+++++++++++++++++++++++++++++++++
Aukl/stdio/fseek.c | 41+++++++++++++++++++++++++++++++++++++++++
Aukl/stdio/fwrite.c | 42++++++++++++++++++++++++++++++++++++++++++
Aukl/stdio/internals.h | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aukl/stdio/stderr.c | 14++++++++++++++
Aukl/stdio/stdin.c | 14++++++++++++++
Aukl/stdio/stdout.c | 14++++++++++++++
Aukl/sys/Makefile | 1+
Aukl/sys/uio.c | 44++++++++++++++++++++++++++++++++++++++++++++
Aukl/unistd/Makefile | 1+
Mukl/unistd/close.c | 2+-
Aukl/unistd/lseek.c | 7+++++++
Mukl/unistd/read.c | 7-------
Mukl/unistd/write.c | 13+++++++------
30 files changed, 597 insertions(+), 35 deletions(-)

diff --git a/fs/read_write.c b/fs/read_write.c @@ -1006,7 +1006,7 @@ static ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, return ret; } -static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec, +__static_ukl ssize_t do_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, rwf_t flags) { struct fd f = fdget_pos(fd); @@ -1026,7 +1026,7 @@ static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec, return ret; } -static ssize_t do_writev(unsigned long fd, const struct iovec __user *vec, +__static_ukl ssize_t do_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, rwf_t flags) { struct fd f = fdget_pos(fd); diff --git a/include/ukl/stdio.h b/include/ukl/stdio.h @@ -0,0 +1,31 @@ +#ifndef STDIO_H +#define STDIO_H + +#include <linux/kernel.h> + +#define BUFSIZ 1024 +#define EOF (-1) + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +typedef struct _IO_FILE FILE; + +extern FILE __stdin_FILE; +extern FILE __stdout_FILE; +extern FILE __stderr_FILE; + +#define stdin (&__stdin_FILE) +#define stdout (&__stdout_FILE) +#define stderr (&__stderr_FILE) + +FILE *fopen(const char *, const char *); +size_t fwrite(const void *, size_t, size_t, FILE *); +size_t fread(void *, size_t, size_t, FILE *); +int fputs(const char *, FILE *); +int fclose(FILE *); +int fflush(FILE *); +int fseek(FILE *, long, int); + +#endif /* STDIO_H */ diff --git a/include/ukl/sys/uio.h b/include/ukl/sys/uio.h @@ -0,0 +1,9 @@ +#ifndef SYS_UIO_H +#define SYS_UIO_H + +#include <uapi/linux/uio.h> + +ssize_t writev(unsigned long fd, const struct iovec *vec, unsigned long vlen); +ssize_t readv(unsigned long fd, const struct iovec *vec, unsigned long vlen); + +#endif /* SYS_UIO_H */ diff --git a/include/ukl/ukl_internals.h b/include/ukl/ukl_internals.h @@ -4,6 +4,6 @@ #define UKL_BAD_FD(fn, d) \ printk(KERN_ERR "Trying to call " fn \ "() with bad file descriptor: %d", \ - d) + (int)d) #endif /* UKL_INTERNALS_H */ diff --git a/include/ukl/unistd.h b/include/ukl/unistd.h @@ -6,5 +6,6 @@ ssize_t write(int, const void *, size_t); ssize_t read(int, void *, size_t); int close(int); +off_t lseek(unsigned int, off_t, unsigned int); #endif /* UNISTD_H */ diff --git a/ukl/Makefile b/ukl/Makefile @@ -1,2 +1,2 @@ ukl-real-obj-m := $(addprefix ../../../../../../../..$(UKL)/,$(ukl-obj-m)) -obj-y := unistd/write.o unistd/read.o unistd/close.o fcntl/open.o fcntl/fcntl.o $(ukl-real-obj-m) +obj-y := unistd/ fcntl/ stdio/ sys/ $(ukl-real-obj-m) diff --git a/ukl/TO_PORT b/ukl/TO_PORT @@ -4,7 +4,6 @@ Syscalls to port: - fstat - lstat - poll -- lseek - mmap - mprotect - munmap @@ -15,8 +14,6 @@ Syscalls to port: - ioctl - pread64 - pwrite64 -- readv -- writev - access - pipe - select diff --git a/ukl/fcntl/Makefile b/ukl/fcntl/Makefile @@ -0,0 +1 @@ +obj-y := fcntl.o open.o diff --git a/ukl/fcntl/fcntl.c b/ukl/fcntl/fcntl.c @@ -49,13 +49,6 @@ int fcntl(int fd, int cmd, ...) return -EINVAL; } - /* - * Little trick used to mock stdin, stdout and stderr for UKL - * Don't make any sense in kernel space, since a fd could very well - * be 0. - */ - fd -= 3; - /* Read optionnals arguments */ va_start(ap, cmd); arg = va_arg(ap, unsigned long); diff --git a/ukl/fcntl/open.c b/ukl/fcntl/open.c @@ -4,11 +4,26 @@ #include <stdarg.h> #include <ukl/ukl_internals.h> +static int __fd_stdin = -1; +static int __fd_stdout = -1; +static int __fd_stderr = -1; + int open(const char *filename, int flags, ...) { umode_t mode = 0; int ret = -1; + /* + * On first call, allocate the first three file descriptor in order + * to be compliant with userspace behavior + */ + if (__fd_stdin == -1) + __fd_stdin = do_sys_open(AT_FDCWD, "/dev/console", O_RDONLY, 0); + if (__fd_stdout == -1) + __fd_stdout = do_sys_open(AT_FDCWD, "/dev/console", O_RDONLY, 0); + if (__fd_stderr == -1) + __fd_stderr = do_sys_open(AT_FDCWD, "/dev/console", O_RDONLY, 0); + /* Parse the flags */ if ((flags & O_CREAT) || (flags & O_TMPFILE) == O_TMPFILE) { va_list ap; @@ -22,12 +37,7 @@ int open(const char *filename, int flags, ...) ret = do_sys_open(AT_FDCWD, filename, flags, mode); if (ret >= 0 && (flags & O_CLOEXEC)) - fcntl(ret + 3, F_SETFD, FD_CLOEXEC); + fcntl(ret, F_SETFD, FD_CLOEXEC); - /* - * Little trick used to mock stdin, stdout and stderr for UKL - * Don't make any sense in kernel space, since a fd could very well - * be 0, so we start at 3. - */ - return ret + 3; + return ret; } diff --git a/ukl/stdio/Makefile b/ukl/stdio/Makefile @@ -0,0 +1 @@ +obj-y := fopen.o __internals.o stdin.o stdout.o stderr.o fwrite.o fputs.o fread.o fclose.o fflush.o fseek.o diff --git a/ukl/stdio/__internals.c b/ukl/stdio/__internals.c @@ -0,0 +1,179 @@ +#include <fcntl.h> +#include <unistd.h> +#include <linux/vmalloc.h> +#include "internals.h" +#include <sys/uio.h> + +int __fmodeflags(const char *mode) +{ + int flags; + + if (strchr(mode, '+')) + flags = O_RDWR; + else if (*mode == 'r') + flags = O_RDONLY; + else + flags = O_WRONLY; + + if (strchr(mode, 'x')) + flags |= O_EXCL; + if (strchr(mode, 'e')) + flags |= O_CLOEXEC; + if (*mode != 'r') + flags |= O_CREAT; + if (*mode == 'w') + flags |= O_TRUNC; + if (*mode == 'a') + flags |= O_APPEND; + return flags; +} + +FILE *__fdopen(int fd, const char *mode) +{ + FILE *f; + + if (!strchr("rwa", *mode)) { + // errno = EINVAL; + return NULL; + } + + f = vmalloc(sizeof(*f) + UNGET + BUFSIZ); + if (f == NULL) + return NULL; + + memset(f, 0, sizeof(*f)); + + /* Impose mode restrictions */ + if (!strchr(mode, '+')) + f->flags = (*mode == 'r') ? F_NOWR : F_NORD; + + /* Apply close-on-exec flag */ + if (strchr(mode, 'e')) + fcntl(fd, F_SETFD, FD_CLOEXEC); + + /* Set append mode on fd if opened for append */ + if (*mode == 'a') { + int flags = fcntl(fd, F_GETFL, 0); + + if (!(flags & O_APPEND)) + fcntl(fd, F_SETFL, flags | O_APPEND); + f->flags |= F_APP; + } + + f->fd = fd; + f->buf = (unsigned char *)f + sizeof(*f) + UNGET; + f->buf_size = BUFSIZ; + + /* Activate line buffered mode for terminals */ + f->lbf = EOF; + + f->read = __stdio_read; + f->write = __stdio_write; + f->seek = __stdio_seek; + f->close = __stdio_close; + + return f; +} + +size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) +{ + struct iovec iovs[2] = { { .iov_base = f->wbase, + .iov_len = f->wpos - f->wbase }, + { .iov_base = (void *)buf, .iov_len = len } }; + struct iovec *iov = iovs; + size_t rem = iov[0].iov_len + iov[1].iov_len; + int iovcnt = 2; + ssize_t cnt; + + while (true) { + cnt = writev(f->fd, iov, iovcnt); + if (cnt == rem) { + f->wend = f->buf + f->buf_size; + f->wpos = f->wbase = f->buf; + return len; + } + if (cnt < 0) { + f->wpos = f->wbase = f->wend = 0; + f->flags |= F_ERR; + return iovcnt == 2 ? 0 : len - iov[0].iov_len; + } + rem -= cnt; + if (cnt > iov[0].iov_len) { + cnt -= iov[0].iov_len; + iov++; + iovcnt--; + } + iov[0].iov_base = (char *)iov[0].iov_base + cnt; + iov[0].iov_len -= cnt; + } +} + +size_t __stdio_read(FILE *f, unsigned char *buf, size_t len) +{ + struct iovec iov[2] = { + { .iov_base = buf, .iov_len = len - !!f->buf_size }, + { .iov_base = f->buf, .iov_len = f->buf_size } + }; + ssize_t cnt; + + cnt = iov[0].iov_len ? readv(f->fd, iov, 2) : + read(f->fd, iov[1].iov_base, iov[1].iov_len); + if (cnt <= 0) { + f->flags |= cnt ? F_ERR : F_EOF; + return 0; + } + if (cnt <= iov[0].iov_len) + return cnt; + + cnt -= iov[0].iov_len; + f->rpos = f->buf; + f->rend = f->buf + cnt; + if (f->buf_size) + buf[len - 1] = *f->rpos++; + return len; +} + +int __stdio_close(FILE *f) +{ + return close(f->fd); +} + +off_t __stdio_seek(FILE *f, off_t off, int whence) +{ + return lseek(f->fd, off, whence); +} + +int __towrite(FILE *f) +{ + f->mode |= f->mode - 1; + if (f->flags & F_NOWR) { + f->flags |= F_ERR; + return EOF; + } + /* Clear read buffer (easier than summoning nasal demons) */ + f->rpos = f->rend = 0; + + /* Activate write through the buffer. */ + f->wpos = f->wbase = f->buf; + f->wend = f->buf + f->buf_size; + + return 0; +} + +int __toread(FILE *f) +{ + f->mode |= f->mode - 1; + + if (f->wpos != f->wbase) + f->write(f, 0, 0); + + f->wpos = f->wbase = f->wend = 0; + + if (f->flags & F_NORD) { + f->flags |= F_ERR; + return EOF; + } + + f->rpos = f->rend = f->buf + f->buf_size; + return (f->flags & F_EOF) ? EOF : 0; +} diff --git a/ukl/stdio/fclose.c b/ukl/stdio/fclose.c @@ -0,0 +1,15 @@ +#include <stdio.h> +#include "internals.h" + +#include <linux/vmalloc.h> + +int fclose(FILE *f) +{ + int r; + + r = fflush(f); + r |= f->close(f); + vfree(f->getln_buf); + vfree(f); + return r; +} diff --git a/ukl/stdio/fflush.c b/ukl/stdio/fflush.c @@ -0,0 +1,23 @@ +#include <stdio.h> +#include "internals.h" + +int fflush(FILE *f) +{ + /* If writing, flush output */ + if (f->wpos != f->wbase) { + f->write(f, 0, 0); + if (!f->wpos) { + return EOF; + } + } + + /* If reading, sync position, per POSIX */ + if (f->rpos != f->rend) + f->seek(f, f->rpos - f->rend, SEEK_CUR); + + /* Clear read and write modes */ + f->wpos = f->wbase = f->wend = 0; + f->rpos = f->rend = 0; + + return 0; +} diff --git a/ukl/stdio/fopen.c b/ukl/stdio/fopen.c @@ -0,0 +1,32 @@ +#include "internals.h" + +#include <unistd.h> +#include <fcntl.h> + +FILE *fopen(const char *filename, const char *mode) +{ + FILE *f = NULL; + int fd; + int flags; + + /* Check for valid initial mode character */ + if (!strchr("rwa", *mode)) { + // errno + return NULL; + } + + flags = __fmodeflags(mode); + fd = open(filename, flags, 0666); + if (fd < 0) + return NULL; + + if (flags & O_CLOEXEC) + fcntl(fd, F_SETFD, FD_CLOEXEC); + + f = __fdopen(fd, mode); + if (f) + return f; + + close(fd); + return NULL; +} diff --git a/ukl/stdio/fputs.c b/ukl/stdio/fputs.c @@ -0,0 +1,10 @@ +#include <stdio.h> +#include "internals.h" + +#include <linux/string.h> + +int fputs(const char *s, FILE *f) +{ + size_t l = strlen(s); + return (fwrite(s, 1, l, f) == l) - 1; +} diff --git a/ukl/stdio/fread.c b/ukl/stdio/fread.c @@ -0,0 +1,33 @@ +#include "internals.h" +#include <linux/string.h> + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +size_t fread(void *destv, size_t size, size_t nmemb, FILE *f) +{ + unsigned char *dest = destv; + size_t len = size * nmemb, l = len, k; + if (!size) + nmemb = 0; + + f->mode |= f->mode - 1; + + if (f->rpos != f->rend) { + /* First exhaust the buffer. */ + k = MIN(f->rend - f->rpos, l); + memcpy(dest, f->rpos, k); + f->rpos += k; + dest += k; + l -= k; + } + + /* Read the remainder directly */ + for (; l; l -= k, dest += k) { + k = __toread(f) ? 0 : f->read(f, dest, l); + if (!k) { + return (len - l) / size; + } + } + + return nmemb; +} diff --git a/ukl/stdio/fseek.c b/ukl/stdio/fseek.c @@ -0,0 +1,41 @@ +#include "internals.h" +#include <stdio.h> + +int __fseeko_unlocked(FILE *f, off_t off, int whence) +{ + /* Adjust relative offset for unread data in buffer, if any. */ + if (whence == SEEK_CUR && f->rend) + off -= f->rend - f->rpos; + + /* Flush write buffer, and report error on failure. */ + if (f->wpos != f->wbase) { + f->write(f, 0, 0); + if (!f->wpos) + return -1; + } + + /* Leave writing mode */ + f->wpos = f->wbase = f->wend = 0; + + /* Perform the underlying seek. */ + if (f->seek(f, off, whence) < 0) + return -1; + + /* If seek succeeded, file is seekable and we discard read buffer. */ + f->rpos = f->rend = 0; + f->flags &= ~F_EOF; + + return 0; +} + +int __fseeko(FILE *f, off_t off, int whence) +{ + int result; + result = __fseeko_unlocked(f, off, whence); + return result; +} + +int fseek(FILE *f, long off, int whence) +{ + return __fseeko(f, off, whence); +} diff --git a/ukl/stdio/fwrite.c b/ukl/stdio/fwrite.c @@ -0,0 +1,42 @@ +#include <stdio.h> +#include "internals.h" +#include <linux/string.h> + +size_t __fwritex(const unsigned char *s, size_t l, FILE *f) +{ + size_t i = 0; + + if (!f->wend && __towrite(f)) + return 0; + + if (l > f->wend - f->wpos) + return f->write(f, s, l); + + if (f->lbf >= 0) { + /* Match /^(.*\n|)/ */ + for (i = l; i && s[i - 1] != '\n'; i--) + ; + if (i) { + size_t n = f->write(f, s, i); + if (n < i) + return n; + s += i; + l -= i; + } + } + + memcpy(f->wpos, s, l); + f->wpos += l; + return l + i; +} + +size_t fwrite(const void *src, size_t size, size_t nmemb, FILE *f) +{ + size_t k, l = size * nmemb; + + if (!size) + nmemb = 0; + k = __fwritex(src, l, f); + + return k == l ? nmemb : k / size; +} diff --git a/ukl/stdio/internals.h b/ukl/stdio/internals.h @@ -0,0 +1,55 @@ +#ifndef STDIO_INTERNALS_H +#define STDIO_INTERNALS_H + +#include <stdio.h> + +#define UNGET 8 + +#define F_PERM 1 +#define F_NORD 4 +#define F_NOWR 8 +#define F_EOF 16 +#define F_ERR 32 +#define F_SVB 64 +#define F_APP 128 + +struct _IO_FILE { + unsigned flags; + unsigned char *rpos, *rend; + int (*close)(FILE *); + unsigned char *wend, *wpos; + unsigned char *mustbezero_1; + unsigned char *wbase; + size_t (*read)(FILE *, unsigned char *, size_t); + size_t (*write)(FILE *, const unsigned char *, size_t); + off_t (*seek)(FILE *, off_t, int); + unsigned char *buf; + size_t buf_size; + FILE *prev, *next; + int fd; + int pipe_pid; + long lockcount; + int mode; + volatile int lock; + int lbf; + void *cookie; + off_t off; + char *getln_buf; + void *mustbezero_2; + unsigned char *shend; + off_t shlim, shcnt; + FILE *prev_locked, *next_locked; + //struct __locale_struct *locale; +}; + +int __fmodeflags(const char *mode); +FILE *__fdopen(int fd, const char *mode); +size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len); +size_t __stdio_read(FILE *f, unsigned char *buf, size_t len); +int __stdio_close(FILE *f); +off_t __stdio_seek(FILE *f, off_t off, int whence); +size_t __fwritex(const unsigned char *s, size_t l, FILE *f); +int __towrite(FILE *f); +int __toread(FILE *f); + +#endif /* STDIO_INTERNALS_H */ diff --git a/ukl/stdio/stderr.c b/ukl/stdio/stderr.c @@ -0,0 +1,14 @@ +#include "internals.h" + +static unsigned char buf[BUFSIZ + UNGET]; +FILE __stderr_FILE = { + .buf = buf + UNGET, + .buf_size = sizeof buf - UNGET, + .fd = 2, + .flags = F_PERM | F_NORD, + .lbf = '\n', + .write = __stdio_write, + .seek = __stdio_seek, + .close = __stdio_close, + .lock = -1, +}; diff --git a/ukl/stdio/stdin.c b/ukl/stdio/stdin.c @@ -0,0 +1,14 @@ +#include "internals.h" + +static unsigned char buf[BUFSIZ + UNGET]; +FILE __stdin_FILE = { + .buf = buf + UNGET, + .buf_size = sizeof buf - UNGET, + .fd = 0, + .flags = F_PERM | F_NORD, + .lbf = '\n', + .write = __stdio_write, + .seek = __stdio_seek, + .close = __stdio_close, + .lock = -1, +}; diff --git a/ukl/stdio/stdout.c b/ukl/stdio/stdout.c @@ -0,0 +1,14 @@ +#include "internals.h" + +static unsigned char buf[BUFSIZ + UNGET]; +FILE __stdout_FILE = { + .buf = buf + UNGET, + .buf_size = sizeof buf - UNGET, + .fd = 1, + .flags = F_PERM | F_NORD, + .lbf = '\n', + .write = __stdio_write, + .seek = __stdio_seek, + .close = __stdio_close, + .lock = -1, +}; diff --git a/ukl/sys/Makefile b/ukl/sys/Makefile @@ -0,0 +1 @@ +obj-y := uio.o diff --git a/ukl/sys/uio.c b/ukl/sys/uio.c @@ -0,0 +1,44 @@ +#include <sys/uio.h> +#include <linux/fs.h> +#include <unistd.h> + +#include <ukl/ukl_internals.h> + +extern ssize_t do_writev(unsigned long fd, const struct iovec __user *vec, + unsigned long vlen, rwf_t flags); +extern ssize_t do_readv(unsigned long fd, const struct iovec __user *vec, + unsigned long vlen, rwf_t flags); + +ssize_t writev(unsigned long fd, const struct iovec *vec, unsigned long vlen) +{ + if (fd == 0) { + UKL_BAD_FD("writev", 0); + return -EINVAL; + } + + /* + * For stdout and stderr, don't bother calling the fs, let's go straight + * to our wrappers + */ + if (fd == 1 || fd == 2) { + unsigned long i; + ssize_t ret = 0; + + for (i = 0; i < vlen; i++) + ret += write(fd, vec[i].iov_base, vec[i].iov_len); + + return ret; + } + return do_writev(fd, vec, vlen, 0); +} + +ssize_t readv(unsigned long fd, const struct iovec *vec, unsigned long vlen) +{ + if (fd >= 0 && fd <= 2) + { + UKL_BAD_FD("readv", fd); + return -EINVAL; + } + + return do_readv(fd, vec, vlen, 0); +} diff --git a/ukl/unistd/Makefile b/ukl/unistd/Makefile @@ -0,0 +1 @@ +obj-y := close.o read.o write.o lseek.o diff --git a/ukl/unistd/close.c b/ukl/unistd/close.c @@ -15,5 +15,5 @@ int close(int fd) * Don't make any sense in kernel space, since a fd could very well * be 0. */ - return ksys_close(fd - 3); + return ksys_close(fd); } diff --git a/ukl/unistd/lseek.c b/ukl/unistd/lseek.c @@ -0,0 +1,7 @@ +#include <unistd.h> +#include <linux/syscalls.h> + +off_t lseek(unsigned int fd, off_t offset, unsigned int whence) +{ + return ksys_lseek(fd, offset, whence); +} diff --git a/ukl/unistd/read.c b/ukl/unistd/read.c @@ -11,12 +11,5 @@ ssize_t read(int fd, void *buf, size_t count) return -EINVAL; } - /* - * Little trick used to mock stdin, stdout and stderr for UKL - * Don't make any sense in kernel space, since a fd could very well - * be 0. - */ - fd -= 3; - return ksys_read(fd, buf, count); } diff --git a/ukl/unistd/write.c b/ukl/unistd/write.c @@ -96,12 +96,13 @@ ssize_t write(int fd, const void *buf, size_t count) console_lock_spinning_enable(); write_to_console(buf, count); console_lock_spinning_disable_and_check(); + + /* + * Console drivers does not returns the number of bytes + * written, so let's assume all went well! + */ + return count; } - /* - * Little trick used to mock stdin, stdout and stderr for UKL - * Don't make any sense in kernel space, since a fd could very well - * be 0. - */ - return ksys_write(fd - 3, buf, count); + return ksys_write(fd, buf, count); }