2022-10-10 18:21:39 +00:00
# define MODULE "stdio"
2022-09-29 17:17:43 +00:00
# include "interrupts/Context.h"
# include "io/Serial.h"
2022-10-10 18:21:39 +00:00
# include "log/Log.h"
2022-10-13 20:13:04 +00:00
# include "memory/VMM.h"
2022-10-01 12:27:45 +00:00
# include "render/TextRenderer.h"
2022-10-19 15:41:23 +00:00
# include "std/errno.h"
2022-10-13 20:13:04 +00:00
# include "std/stdlib.h"
# include "sys/Syscall.h"
2022-10-19 15:13:16 +00:00
# include "sys/UserMemory.h"
2022-10-10 18:21:39 +00:00
# include "thread/Scheduler.h"
# include "thread/Task.h"
2022-10-27 05:52:57 +00:00
# include <sys/types.h>
2022-10-10 18:21:39 +00:00
2022-10-11 19:06:12 +00:00
# define OPEN_READ 1
# define OPEN_WRITE 2
2022-10-21 19:51:03 +00:00
# define OPEN_NONBLOCK 4
2022-10-22 08:28:02 +00:00
# define OPEN_CLOEXEC 8
2022-10-23 12:46:27 +00:00
# define OPEN_DIRECTORY 16
2022-10-27 05:43:55 +00:00
# define OPEN_TRUNCATED 32
# define OPEN_CREATE 64
# define OPEN_APPEND 128
2022-10-27 05:55:59 +00:00
# define OPEN_EXCL 256
2022-10-11 19:06:12 +00:00
2022-10-12 13:28:52 +00:00
# define SEEK_SET 0
# define SEEK_CUR 1
# define SEEK_END 2
2022-10-21 16:34:31 +00:00
# define FCNTL_DUPFD 0
# define FCNTL_ISTTY 1
2022-10-27 15:17:24 +00:00
# define FCNTL_GETFD 2
# define FCNTL_SETFD 3
# define FD_CLOEXEC 1
2022-10-15 08:56:06 +00:00
2022-10-17 15:01:22 +00:00
void sys_fcntl ( Context * context , int fd , int command , uintptr_t arg )
2022-10-15 08:56:06 +00:00
{
Task * current_task = Scheduler : : current_task ( ) ;
2022-10-25 16:35:17 +00:00
int err ;
Descriptor * file = current_task - > descriptor_from_fd ( fd , err ) ;
if ( ! file )
2022-10-15 08:56:06 +00:00
{
2022-10-25 16:35:17 +00:00
context - > rax = - err ;
2022-10-15 08:56:06 +00:00
return ;
}
2022-10-21 16:34:31 +00:00
if ( command = = FCNTL_DUPFD )
2022-10-15 08:56:06 +00:00
{
2022-10-27 15:17:24 +00:00
int minfd = ( int ) arg ;
if ( minfd < 0 | | minfd > = TASK_MAX_FDS )
2022-10-17 15:01:22 +00:00
{
context - > rax = - EINVAL ;
return ;
}
2022-10-27 15:17:24 +00:00
int dupfd = current_task - > alloc_fd_greater_than_or_equal ( minfd ) ;
2022-10-15 08:56:06 +00:00
if ( dupfd < 0 )
{
context - > rax = - EMFILE ;
return ;
}
2022-10-25 16:35:17 +00:00
current_task - > files [ dupfd ] = * file ;
2022-10-15 08:56:06 +00:00
context - > rax = dupfd ;
kdbgln ( " fcntl(F_DUPFD): duplicated fd %d, result is %d " , fd , dupfd ) ;
return ;
}
2022-10-21 16:34:31 +00:00
else if ( command = = FCNTL_ISTTY )
{
2022-10-25 16:35:17 +00:00
VFS : : Node * node = file - > node ( ) ;
2022-10-21 16:34:31 +00:00
if ( node - > tty ) { context - > rax = 1 ; }
else
context - > rax = - ENOTTY ;
return ;
}
2022-10-27 15:17:24 +00:00
else if ( command = = FCNTL_GETFD )
{
int flags = 0 ;
if ( file - > close_on_exec ( ) ) context - > rax | = FD_CLOEXEC ;
context - > rax = flags ;
return ;
}
else if ( command = = FCNTL_SETFD )
{
int flags = ( int ) arg ;
if ( flags & FD_CLOEXEC ) file - > set_close_on_exec ( true ) ;
else
file - > set_close_on_exec ( false ) ;
context - > rax = 0 ;
return ;
}
2022-10-15 08:56:06 +00:00
else
{
context - > rax = - EINVAL ;
return ;
}
}
2022-10-12 13:28:52 +00:00
void sys_seek ( Context * context , int fd , long offset , int whence )
{
if ( whence < SEEK_SET | | whence > SEEK_END )
{
context - > rax = - EINVAL ;
return ;
}
2022-10-25 16:35:17 +00:00
int err ;
Descriptor * file = Scheduler : : current_task ( ) - > descriptor_from_fd ( fd , err ) ;
if ( ! file )
2022-10-12 13:28:52 +00:00
{
2022-10-25 16:35:17 +00:00
context - > rax = - err ;
2022-10-12 13:28:52 +00:00
return ;
}
long new_offset ;
if ( whence = = SEEK_SET ) new_offset = offset ;
else if ( whence = = SEEK_CUR )
2022-10-25 16:35:17 +00:00
new_offset = offset + file - > offset ( ) ;
2022-10-12 13:28:52 +00:00
else if ( whence = = SEEK_END )
2022-10-25 16:35:17 +00:00
new_offset = file - > length ( ) + offset ;
2022-10-12 13:28:52 +00:00
else
__builtin_unreachable ( ) ;
if ( new_offset < 0 )
{
context - > rax = - EINVAL ; // FIXME: Is this the right error?
return ;
}
2022-10-25 16:35:17 +00:00
if ( new_offset = = file - > offset ( ) )
2022-10-15 08:56:06 +00:00
{
context - > rax = new_offset ;
return ;
}
2022-10-25 16:35:17 +00:00
int result = file - > seek ( new_offset ) ;
2022-10-12 13:28:52 +00:00
if ( result < 0 )
{
context - > rax = result ;
return ;
}
context - > rax = new_offset ;
return ;
}
2022-10-11 19:06:12 +00:00
void sys_write ( Context * context , int fd , size_t size , const char * addr )
2022-09-29 17:17:43 +00:00
{
2022-10-11 19:06:12 +00:00
if ( ! addr )
{
2022-10-12 17:25:35 +00:00
context - > rax = - EFAULT ;
2022-10-11 19:06:12 +00:00
return ;
}
2022-10-25 16:35:17 +00:00
int err ;
Descriptor * file = Scheduler : : current_task ( ) - > descriptor_from_fd ( fd , err ) ;
if ( ! file )
2022-10-11 19:06:12 +00:00
{
2022-10-25 16:35:17 +00:00
context - > rax = - err ;
2022-10-11 19:06:12 +00:00
return ;
}
2022-10-25 16:35:17 +00:00
if ( ! file - > can_write ( ) )
2022-10-11 19:06:12 +00:00
{
context - > rax = - EBADF ;
return ;
}
2022-10-25 16:35:17 +00:00
ssize_t result = file - > write ( size , ( const char * ) VMM : : get_physical ( ( uint64_t ) addr ) ) ;
2022-10-11 19:06:12 +00:00
context - > rax = ( size_t ) result ;
return ;
2022-10-10 18:21:39 +00:00
}
2022-10-27 05:52:57 +00:00
void sys_open ( Context * context , const char * filename , int flags , mode_t ) // FIXME: mode is not used.
2022-10-10 18:21:39 +00:00
{
Task * current_task = Scheduler : : current_task ( ) ;
2022-10-15 08:56:06 +00:00
int fd = current_task - > alloc_fd ( ) ;
if ( fd < 0 )
2022-10-10 18:21:39 +00:00
{
context - > rax = - EMFILE ;
return ;
}
2022-10-11 19:06:12 +00:00
2022-10-21 19:51:03 +00:00
char * kfilename = strdup_from_user ( filename ) ;
if ( ! kfilename )
2022-10-13 20:13:04 +00:00
{
context - > rax = - EFAULT ;
return ;
}
2022-10-21 19:51:03 +00:00
VFS : : Node * node = VFS : : resolve_path ( kfilename ) ;
2022-10-10 18:21:39 +00:00
if ( ! node )
{
2022-10-27 05:43:55 +00:00
bool create = ( flags & OPEN_CREATE ) > 0 ;
if ( create ) kwarnln ( " FIXME: open(O_CREAT) is not implemented " ) ;
2022-10-21 19:51:03 +00:00
kfree ( kfilename ) ;
2022-10-10 18:21:39 +00:00
context - > rax = - ENOENT ;
return ;
}
2022-10-27 05:55:59 +00:00
else
{
bool excl = ( flags & OPEN_EXCL ) > 0 ;
if ( excl )
{
kfree ( kfilename ) ;
context - > rax = - EEXIST ;
return ;
}
}
2022-10-11 19:06:12 +00:00
bool can_read = ( flags & OPEN_READ ) > 0 ;
bool can_write = ( flags & OPEN_WRITE ) > 0 ;
if ( ! can_read & & ! can_write )
{
2022-10-21 19:51:03 +00:00
kfree ( kfilename ) ;
2022-10-11 19:06:12 +00:00
context - > rax = - EINVAL ;
return ;
}
2022-10-28 15:10:28 +00:00
if ( can_read & & ! VFS : : can_read ( node , current_task - > euid , current_task - > egid ) )
{
kwarnln ( " open failed because process with uid %d and gid %d couldn't open file %s with mode %d for reading " ,
current_task - > euid , current_task - > egid , kfilename , node - > mode ) ;
kfree ( kfilename ) ;
context - > rax = - EACCES ;
return ;
}
if ( can_write & & ! VFS : : can_write ( node , current_task - > euid , current_task - > egid ) )
{
kwarnln ( " open failed because process with uid %d and gid %d couldn't open file %s with mode %d for writing " ,
current_task - > euid , current_task - > egid , kfilename , node - > mode ) ;
kfree ( kfilename ) ;
context - > rax = - EACCES ;
return ;
}
2022-10-21 19:51:03 +00:00
bool able_to_block = ( flags & OPEN_NONBLOCK ) = = 0 ;
2022-10-22 08:28:02 +00:00
bool close_on_exec = ( flags & OPEN_CLOEXEC ) > 0 ;
2022-10-21 19:51:03 +00:00
2022-10-23 12:46:27 +00:00
bool only_directory = ( flags & OPEN_DIRECTORY ) > 0 ;
2022-10-27 05:43:55 +00:00
bool truncate = ( flags & OPEN_TRUNCATED ) > 0 ;
if ( truncate )
{
kfree ( kfilename ) ;
kerrorln ( " FIXME: open(O_TRUNC) is not implemented " ) ;
context - > rax = - ENOTSUP ;
return ;
}
bool append = ( flags & OPEN_APPEND ) > 0 ;
2022-10-23 12:46:27 +00:00
if ( only_directory & & node - > type ! = VFS_DIRECTORY )
{
kfree ( kfilename ) ;
context - > rax = - ENOTDIR ;
return ;
}
2022-10-21 19:51:03 +00:00
kdbgln ( " open(): opening %s %s, allocated file descriptor %d " , kfilename ,
2022-10-11 19:06:12 +00:00
( can_read & & can_write ) ? " rw "
: can_read ? " r- "
: " -w " ,
fd ) ;
2022-10-21 19:51:03 +00:00
kfree ( kfilename ) ;
2022-10-22 08:28:02 +00:00
current_task - > files [ fd ] . open ( node , can_read , can_write , able_to_block , close_on_exec ) ;
2022-10-27 05:43:55 +00:00
if ( append & & current_task - > files [ fd ] . node ( ) - > type ! = VFS_DEVICE )
{
current_task - > files [ fd ] . seek ( ( long ) current_task - > files [ fd ] . length ( ) ) ;
}
2022-10-10 18:21:39 +00:00
context - > rax = fd ;
return ;
}
void sys_read ( Context * context , int fd , size_t size , char * buffer )
{
if ( ! buffer )
{
2022-10-12 17:25:35 +00:00
context - > rax = - EFAULT ;
2022-10-10 18:21:39 +00:00
return ;
}
2022-10-25 16:35:17 +00:00
int err ;
Descriptor * file = Scheduler : : current_task ( ) - > descriptor_from_fd ( fd , err ) ;
2022-10-25 16:58:06 +00:00
if ( ! file )
2022-10-10 18:21:39 +00:00
{
2022-10-25 16:35:17 +00:00
context - > rax = - err ;
2022-10-10 18:21:39 +00:00
return ;
}
2022-10-25 16:35:17 +00:00
if ( ! file - > is_open ( ) | | ! file - > can_read ( ) )
2022-10-10 18:21:39 +00:00
{
context - > rax = - EBADF ;
return ;
}
2022-10-25 16:35:17 +00:00
if ( VFS : : would_block ( file - > node ( ) ) )
2022-10-21 19:26:19 +00:00
{
2022-10-25 16:35:17 +00:00
if ( ! file - > able_to_block ( ) )
2022-10-21 19:51:03 +00:00
{
context - > rax = - EAGAIN ;
return ;
}
2022-10-25 16:35:17 +00:00
Task * current_task = Scheduler : : current_task ( ) ;
2022-10-21 19:26:19 +00:00
current_task - > state = current_task - > Blocking ;
2022-10-27 15:05:42 +00:00
current_task - > block_reason = BlockReason : : Reading ;
2022-10-21 19:26:19 +00:00
current_task - > blocking_read_info . fd = fd ;
current_task - > blocking_read_info . buf = ( char * ) VMM : : get_physical ( ( uint64_t ) buffer ) ; // FIXME: Handle errors.
current_task - > blocking_read_info . size = size ;
return Scheduler : : task_yield ( context ) ;
}
2022-10-25 16:35:17 +00:00
ssize_t result =
file - > read ( size , ( char * ) VMM : : get_physical ( ( uint64_t ) buffer ) ) ; // FIXME: Handle errors, and big buffers which may
// not be across continuous physical pages.
2022-10-10 18:21:39 +00:00
context - > rax = ( size_t ) result ;
return ;
}
void sys_close ( Context * context , int fd )
{
2022-10-25 16:35:17 +00:00
int err ;
Descriptor * file = Scheduler : : current_task ( ) - > descriptor_from_fd ( fd , err ) ;
2022-10-28 17:38:04 +00:00
if ( ! file )
2022-10-10 18:21:39 +00:00
{
2022-10-25 16:35:17 +00:00
context - > rax = - err ;
2022-10-10 18:21:39 +00:00
return ;
}
2022-10-11 15:19:03 +00:00
kdbgln ( " close(): releasing file descriptor %d " , fd ) ;
2022-10-25 16:35:17 +00:00
file - > close ( ) ;
2022-10-10 18:21:39 +00:00
context - > rax = 0 ;
return ;
2022-10-16 15:22:12 +00:00
}
2022-10-28 15:10:28 +00:00
void sys_mkdir ( Context * context , const char * filename , mode_t mode )
2022-10-16 15:22:12 +00:00
{
2022-10-19 15:13:16 +00:00
char * kfilename = strdup_from_user ( filename ) ;
2022-10-16 15:22:12 +00:00
if ( ! kfilename )
{
context - > rax = - EFAULT ;
return ;
}
2022-10-28 15:10:28 +00:00
Task * current_task = Scheduler : : current_task ( ) ;
2022-10-30 18:55:38 +00:00
int rc = VFS : : do_mkdir ( kfilename , current_task - > euid , current_task - > egid , mode & ( ~ current_task - > umask ) ) ;
2022-10-16 15:22:12 +00:00
kfree ( kfilename ) ;
context - > rax = rc ;
2022-10-20 17:03:24 +00:00
}
void sys_access ( Context * context , const char * path , int ) // FIXME: Use the amode argument.
{
char * kpath = strdup_from_user ( path ) ;
if ( ! VFS : : exists ( kpath ) ) { context - > rax = - ENOENT ; }
else
context - > rax = 0 ;
kfree ( kpath ) ;
2022-10-25 16:58:06 +00:00
}
void sys_dup2 ( Context * context , int fd , int fd2 )
{
int err ;
Descriptor * file1 = Scheduler : : current_task ( ) - > descriptor_from_fd ( fd , err ) ;
if ( ! file1 )
{
context - > rax = - err ;
return ;
}
2022-11-02 19:59:42 +00:00
Descriptor * file2 = Scheduler : : current_task ( ) - > descriptor_from_fd ( fd2 , err ) ; // FIXME: This will return EBADF if fd2 is not open, but we want to replace it with fd1 if it is not open.
2022-10-25 16:58:06 +00:00
if ( ! file2 )
{
context - > rax = - err ;
return ;
}
if ( file2 - > is_open ( ) ) file2 - > close ( ) ;
* file2 = * file1 ;
kinfoln ( " dup2(): overwrote fd %d with fd %d " , fd2 , fd ) ;
context - > rax = fd2 ;
2022-10-30 18:55:38 +00:00
}
void sys_umask ( Context * context , mode_t cmask )
{
Task * current_task = Scheduler : : current_task ( ) ;
context - > rax = current_task - > umask ;
current_task - > umask = cmask ;
2022-11-02 19:59:42 +00:00
}
void sys_ioctl ( Context * context , int fd , int cmd , uintptr_t arg )
{
int err ;
Descriptor * file = Scheduler : : current_task ( ) - > descriptor_from_fd ( fd , err ) ;
if ( ! file )
{
context - > rax = - err ;
return ;
}
kinfoln ( " ioctl(): fd %d, cmd %d, arg %lu " , fd , cmd , arg ) ;
context - > rax = file - > ioctl ( cmd , arg ) ;
2022-09-29 17:17:43 +00:00
}